文章目录[隐藏]
WordPress文创商品柔性组合与捆绑销售插件教程
引言:为什么需要柔性组合与捆绑销售插件
在文创商品电商领域,顾客往往希望购买相关主题的商品组合,如"故宫文创套装"或"艺术家系列产品"。传统的WordPress电商解决方案通常只支持固定捆绑销售,缺乏灵活性。柔性组合与捆绑销售插件允许商家创建动态产品组合,顾客可以自由选择组合中的商品,享受定制化购物体验的同时提升客单价。
本教程将详细介绍如何使用和定制一个WordPress文创商品柔性组合插件,包含完整的代码实现和配置指南。
插件功能概述
我们的插件将实现以下核心功能:
- 动态产品组合创建:管理员可以创建可定制的产品组合
- 灵活定价策略:支持固定价格、折扣比例或自定义计算
- 库存管理:实时检查组合内商品的库存状态
- 前端交互界面:用户友好的产品选择界面
- 购物车集成:将组合商品作为单个项目加入购物车
插件基础结构
首先,我们创建插件的基本文件结构:
<?php
/**
* Plugin Name: 文创商品柔性组合销售
* Plugin URI: https://yourwebsite.com/
* Description: 为WordPress文创商品提供柔性组合与捆绑销售功能
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: flexible-bundle
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('FB_VERSION', '1.0.0');
define('FB_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('FB_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
add_action('plugins_loaded', 'fb_init_plugin');
function fb_init_plugin() {
// 检查WooCommerce是否激活
if (!class_exists('WooCommerce')) {
add_action('admin_notices', 'fb_woocommerce_missing_notice');
return;
}
// 加载核心类
require_once FB_PLUGIN_DIR . 'includes/class-bundle-product.php';
require_once FB_PLUGIN_DIR . 'includes/class-bundle-admin.php';
require_once FB_PLUGIN_DIR . 'includes/class-bundle-frontend.php';
// 初始化组件
new FB_Bundle_Product();
new FB_Bundle_Admin();
new FB_Bundle_Frontend();
}
// WooCommerce缺失提示
function fb_woocommerce_missing_notice() {
?>
<div class="notice notice-error">
<p><?php _e('文创商品柔性组合插件需要WooCommerce才能正常工作。', 'flexible-bundle'); ?></p>
</div>
<?php
}
?>
创建组合产品类型
我们需要创建一个新的产品类型来处理捆绑销售:
<?php
// 文件路径: includes/class-bundle-product.php
class FB_Bundle_Product {
public function __construct() {
add_action('init', array($this, 'register_bundle_product_type'));
add_filter('product_type_selector', array($this, 'add_bundle_product_type'));
add_action('woocommerce_product_options_general_product_data', array($this, 'bundle_product_settings'));
add_action('woocommerce_process_product_meta', array($this, 'save_bundle_product_settings'));
}
// 注册新的产品类型
public function register_bundle_product_type() {
class WC_Product_Bundle extends WC_Product {
public function __construct($product) {
$this->product_type = 'bundle';
parent::__construct($product);
}
// 获取组合价格
public function get_price($context = 'view') {
$price = $this->get_prop('price', $context);
return $price ? $price : 0;
}
}
}
// 在产品类型选择器中添加"组合产品"
public function add_bundle_product_type($types) {
$types['bundle'] = __('文创组合产品', 'flexible-bundle');
return $types;
}
// 添加组合产品设置字段
public function bundle_product_settings() {
global $post;
echo '<div class="options_group show_if_bundle">';
// 组合产品包含的商品
woocommerce_wp_text_input(array(
'id' => '_bundle_products',
'label' => __('包含的商品ID', 'flexible-bundle'),
'description' => __('输入可加入组合的商品ID,用逗号分隔', 'flexible-bundle'),
'desc_tip' => true,
'type' => 'text',
'placeholder' => '例如: 123, 456, 789'
));
// 定价方式
woocommerce_wp_select(array(
'id' => '_bundle_pricing_type',
'label' => __('定价方式', 'flexible-bundle'),
'options' => array(
'fixed' => __('固定价格', 'flexible-bundle'),
'discount' => __('折扣比例', 'flexible-bundle'),
'dynamic' => __('动态计算', 'flexible-bundle')
)
));
// 折扣比例(如果选择折扣定价)
woocommerce_wp_text_input(array(
'id' => '_bundle_discount',
'label' => __('折扣比例 (%)', 'flexible-bundle'),
'description' => __('应用于组合总价的折扣', 'flexible-bundle'),
'desc_tip' => true,
'type' => 'number',
'custom_attributes' => array(
'step' => '1',
'min' => '0',
'max' => '100'
)
));
// 最小选择数量
woocommerce_wp_text_input(array(
'id' => '_bundle_min_selection',
'label' => __('最少选择商品数', 'flexible-bundle'),
'type' => 'number',
'custom_attributes' => array(
'step' => '1',
'min' => '1'
)
));
// 最大选择数量
woocommerce_wp_text_input(array(
'id' => '_bundle_max_selection',
'label' => __('最多选择商品数', 'flexible-bundle'),
'type' => 'number',
'custom_attributes' => array(
'step' => '1',
'min' => '1'
)
));
echo '</div>';
// 添加JavaScript控制字段显示
?>
<script type='text/javascript'>
jQuery(document).ready(function() {
// 显示/隐藏折扣字段
function toggleDiscountField() {
var pricingType = jQuery('#_bundle_pricing_type').val();
if (pricingType === 'discount') {
jQuery('#_bundle_discount_field').show();
} else {
jQuery('#_bundle_discount_field').hide();
}
}
jQuery('#_bundle_pricing_type').change(toggleDiscountField);
toggleDiscountField();
});
</script>
<?php
}
// 保存组合产品设置
public function save_bundle_product_settings($post_id) {
$product = wc_get_product($post_id);
if ($product->is_type('bundle')) {
// 保存组合商品ID
if (isset($_POST['_bundle_products'])) {
update_post_meta($post_id, '_bundle_products', sanitize_text_field($_POST['_bundle_products']));
}
// 保存定价方式
if (isset($_POST['_bundle_pricing_type'])) {
update_post_meta($post_id, '_bundle_pricing_type', sanitize_text_field($_POST['_bundle_pricing_type']));
}
// 保存折扣比例
if (isset($_POST['_bundle_discount'])) {
update_post_meta($post_id, '_bundle_discount', floatval($_POST['_bundle_discount']));
}
// 保存最小选择数量
if (isset($_POST['_bundle_min_selection'])) {
update_post_meta($post_id, '_bundle_min_selection', intval($_POST['_bundle_min_selection']));
}
// 保存最大选择数量
if (isset($_POST['_bundle_max_selection'])) {
update_post_meta($post_id, '_bundle_max_selection', intval($_POST['_bundle_max_selection']));
}
}
}
}
?>
前端产品选择界面
创建用户选择组合商品的前端界面:
<?php
// 文件路径: includes/class-bundle-frontend.php
class FB_Bundle_Frontend {
public function __construct() {
// 在产品页面显示组合选择器
add_action('woocommerce_before_add_to_cart_button', array($this, 'display_bundle_selector'));
// 验证添加到购物车的组合
add_filter('woocommerce_add_to_cart_validation', array($this, 'validate_bundle_add_to_cart'), 10, 3);
// 将组合商品添加到购物车
add_action('woocommerce_add_to_cart', array($this, 'add_bundle_to_cart'), 10, 6);
// 在购物车中显示组合详情
add_filter('woocommerce_get_item_data', array($this, 'display_bundle_items_in_cart'), 10, 2);
}
// 显示组合选择器
public function display_bundle_selector() {
global $product;
if (!$product->is_type('bundle')) {
return;
}
$bundle_products = get_post_meta($product->get_id(), '_bundle_products', true);
$product_ids = explode(',', str_replace(' ', '', $bundle_products));
if (empty($product_ids)) {
return;
}
$min_selection = get_post_meta($product->get_id(), '_bundle_min_selection', true) ?: 1;
$max_selection = get_post_meta($product->get_id(), '_bundle_max_selection', true) ?: count($product_ids);
?>
<div class="bundle-selector" id="bundle-selector-<?php echo $product->get_id(); ?>">
<h3><?php _e('选择组合商品', 'flexible-bundle'); ?></h3>
<p class="bundle-description">
<?php printf(__('请选择 %d 到 %d 件商品组成您的专属组合', 'flexible-bundle'), $min_selection, $max_selection); ?>
</p>
<div class="bundle-products-grid">
<?php foreach ($product_ids as $product_id) :
$bundle_product = wc_get_product($product_id);
if (!$bundle_product) continue;
?>
<div class="bundle-product-item">
<label>
<input type="checkbox"
name="bundle_items[]"
value="<?php echo $product_id; ?>"
data-price="<?php echo $bundle_product->get_price(); ?>"
class="bundle-item-checkbox">
<div class="bundle-product-image">
<?php echo $bundle_product->get_image('thumbnail'); ?>
</div>
<div class="bundle-product-info">
<h4><?php echo $bundle_product->get_name(); ?></h4>
<p class="price"><?php echo $bundle_product->get_price_html(); ?></p>
</div>
</label>
</div>
<?php endforeach; ?>
</div>
<div class="bundle-summary">
<h4><?php _e('组合摘要', 'flexible-bundle'); ?></h4>
<div class="selected-items-list"></div>
<div class="bundle-total">
<strong><?php _e('组合总价:', 'flexible-bundle'); ?></strong>
<span class="bundle-total-price">¥0.00</span>
</div>
<div class="bundle-discount-info" style="display:none;">
<small class="discount-amount"></small>
</div>
</div>
<input type="hidden" name="bundle_config" id="bundle-config" value="">
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
var bundleId = <?php echo $product->get_id(); ?>;
var minSelection = <?php echo $min_selection; ?>;
var maxSelection = <?php echo $max_selection; ?>;
var pricingType = '<?php echo get_post_meta($product->get_id(), "_bundle_pricing_type", true); ?>';
var discount = <?php echo get_post_meta($product->get_id(), "_bundle_discount", true) ?: 0; ?>;
var selectedItems = [];
// 更新组合摘要
function updateBundleSummary() {
var total = 0;
var itemsList = '';
selectedItems.forEach(function(item) {
total += item.price;
itemsList += '<div class="selected-item">' + item.name + ' - ¥' + item.price.toFixed(2) + '</div>';
});
// 应用定价策略
var finalPrice = total;
var discountInfo = '';
if (pricingType === 'fixed') {
finalPrice = <?php echo $product->get_price(); ?>;
discountInfo = '<small>原价: ¥' + total.toFixed(2) + ',节省: ¥' + (total - finalPrice).toFixed(2) + '</small>';
} else if (pricingType === 'discount' && discount > 0) {
var discountAmount = total * (discount / 100);
finalPrice = total - discountAmount;
discountInfo = '<small>' + discount + '%折扣,节省: ¥' + discountAmount.toFixed(2) + '</small>';
}
// 更新显示
$('.selected-items-list').html(itemsList);
$('.bundle-total-price').text('¥' + finalPrice.toFixed(2));
if (discountInfo) {
$('.bundle-discount-info').show().find('.discount-amount').html(discountInfo);
}
// 更新隐藏字段
$('#bundle-config').val(JSON.stringify({
items: selectedItems.map(item => item.id),
total: finalPrice
}));
}
// 处理复选框变化
$('.bundle-item-checkbox').change(function() {
var productId = $(this).val();
var productName = $(this).closest('.bundle-product-item').find('h4').text();
var productPrice = parseFloat($(this).data('price'));
if ($(this).is(':checked')) {
// 检查是否超过最大选择数量
if (selectedItems.length >= maxSelection) {
$(this).prop('checked', false);
alert('最多只能选择 ' + maxSelection + ' 件商品');
return;
}
selectedItems.push({
id: productId,
name: productName,
price: productPrice
});
} else {
selectedItems = selectedItems.filter(item => item.id != productId);
}
updateBundleSummary();
});
// 添加到购物车前的验证
$('form.cart').on('submit', function(e) {
if (selectedItems.length < minSelection) {
alert('请至少选择 ' + minSelection + ' 件商品');
e.preventDefault();
return false;
}
if (selectedItems.length > maxSelection) {
alert('最多只能选择 ' + maxSelection + ' 件商品');
e.preventDefault();
return false;
}
});
});
</script>
<style>
.bundle-products-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
margin: 20px 0;
}
.bundle-product-item {
border: 2px solid #eee;
border-radius: 5px;
padding: 10px;
transition: border-color 0.3s;
}
.bundle-product-item:hover {
border-color: #007cba;
}
.bundle-product-item label {
cursor: pointer;
display: block;
}
.bundle-product-image {
text-align: center;
margin-bottom: 10px;
}
.bundle-summary {
background: #f8f8f8;
padding: 15px;
border-radius: 5px;
margin-top: 20px;
}
.selected-item {
padding: 5px 0;
border-bottom: 1px solid #ddd;
}
.bundle-total {
margin-top: 10px;
padding-top: 10px;
border-top: 2px solid #ddd;
font-size: 1.2em;
}
</style>
<?php
}
// 验证组合添加到购物车
public function validate_bundle_add_to_cart($passed, $product_id, $quantity) {
$product = wc_get_product($product_id);
if ($product->is_type('bundle') && isset($_POST['bundle_config'])) {
$config = json_decode(stripslashes($_POST['bundle_config']), true);
if (empty($config['items']) || count($config['items']) < 1) {
wc_add_notice(__('请至少选择一件商品组成组合', 'flexible-bundle'), 'error');
return false;
}
}
return $passed;
}
// 将组合添加到购物车
public function add_bundle_to_cart($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data) {
if (isset($_POST['bundle_config'])) {
['bundle_config']), true);
// 将组合配置保存到购物车项目数据中
WC()->cart->cart_contents[$cart_item_key]['bundle_config'] = $config;
}
}
// 在购物车中显示组合详情
public function display_bundle_items_in_cart($item_data, $cart_item) {
if (isset($cart_item['bundle_config']) && !empty($cart_item['bundle_config']['items'])) {
$item_data[] = array(
'name' => __('包含商品', 'flexible-bundle'),
'value' => $this->get_bundle_items_list($cart_item['bundle_config']['items'])
);
// 显示组合优惠信息
if (isset($cart_item['bundle_config']['original_total'])) {
$savings = $cart_item['bundle_config']['original_total'] - $cart_item['bundle_config']['total'];
if ($savings > 0) {
$item_data[] = array(
'name' => __('节省', 'flexible-bundle'),
'value' => wc_price($savings)
);
}
}
}
return $item_data;
}
// 获取组合商品列表HTML
private function get_bundle_items_list($item_ids) {
$items = array();
foreach ($item_ids as $item_id) {
$product = wc_get_product($item_id);
if ($product) {
$items[] = $product->get_name();
}
}
return implode(', ', $items);
}
}
?>
## 后台管理界面增强
<?php
// 文件路径: includes/class-bundle-admin.php
class FB_Bundle_Admin {
public function __construct() {
// 添加组合销售报告页面
add_action('admin_menu', array($this, 'add_bundle_reports_page'));
// 在订单详情中显示组合信息
add_action('woocommerce_admin_order_item_headers', array($this, 'display_bundle_order_header'));
add_action('woocommerce_admin_order_item_values', array($this, 'display_bundle_order_items'), 10, 3);
// 添加批量操作
add_filter('bulk_actions-edit-product', array($this, 'add_bulk_actions'));
add_filter('handle_bulk_actions-edit-product', array($this, 'handle_bulk_actions'), 10, 3);
}
// 添加组合销售报告页面
public function add_bundle_reports_page() {
add_submenu_page(
'woocommerce',
__('组合销售报告', 'flexible-bundle'),
__('组合销售', 'flexible-bundle'),
'manage_woocommerce',
'bundle-reports',
array($this, 'render_reports_page')
);
}
// 渲染报告页面
public function render_reports_page() {
?>
<div class="wrap">
<h1><?php _e('文创商品组合销售报告', 'flexible-bundle'); ?></h1>
<div class="bundle-stats-container">
<div class="bundle-stat-card">
<h3><?php _e('总组合销售额', 'flexible-bundle'); ?></h3>
<p class="stat-value"><?php echo $this->get_total_bundle_sales(); ?></p>
</div>
<div class="bundle-stat-card">
<h3><?php _e('最受欢迎组合', 'flexible-bundle'); ?></h3>
<p class="stat-value"><?php echo $this->get_popular_bundle(); ?></p>
</div>
<div class="bundle-stat-card">
<h3><?php _e('平均组合客单价', 'flexible-bundle'); ?></h3>
<p class="stat-value"><?php echo $this->get_average_bundle_value(); ?></p>
</div>
</div>
<h2><?php _e('组合销售趋势', 'flexible-bundle'); ?></h2>
<div id="bundle-sales-chart" style="width:100%; height:400px;"></div>
<h2><?php _e('最近组合订单', 'flexible-bundle'); ?></h2>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php _e('订单号', 'flexible-bundle'); ?></th>
<th><?php _e('组合产品', 'flexible-bundle'); ?></th>
<th><?php _e('包含商品', 'flexible-bundle'); ?></th>
<th><?php _e('金额', 'flexible-bundle'); ?></th>
<th><?php _e('日期', 'flexible-bundle'); ?></th>
</tr>
</thead>
<tbody>
<?php $this->display_recent_bundle_orders(); ?>
</tbody>
</table>
</div>
<style>
.bundle-stats-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 20px 0;
}
.bundle-stat-card {
background: white;
border: 1px solid #ccd0d4;
border-radius: 4px;
padding: 20px;
text-align: center;
}
.bundle-stat-card .stat-value {
font-size: 24px;
font-weight: bold;
color: #007cba;
margin: 10px 0 0;
}
</style>
<script>
// 使用Chart.js显示销售图表
jQuery(document).ready(function($) {
// 这里可以添加AJAX请求获取图表数据
console.log('组合销售图表加载...');
});
</script>
<?php
}
// 获取总组合销售额
private function get_total_bundle_sales() {
global $wpdb;
$total = $wpdb->get_var("
SELECT SUM(meta.meta_value)
FROM {$wpdb->prefix}woocommerce_order_itemmeta meta
INNER JOIN {$wpdb->prefix}woocommerce_order_items items ON meta.order_item_id = items.order_item_id
WHERE meta.meta_key = '_bundle_total'
");
return wc_price($total ?: 0);
}
// 显示最近组合订单
private function display_recent_bundle_orders() {
global $wpdb;
$orders = $wpdb->get_results("
SELECT items.order_id, items.order_item_name, meta.meta_value as bundle_items
FROM {$wpdb->prefix}woocommerce_order_items items
INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta meta ON items.order_item_id = meta.order_item_id
WHERE items.order_item_type = 'line_item'
AND meta.meta_key = '_bundle_items'
ORDER BY items.order_id DESC
LIMIT 10
");
foreach ($orders as $order) {
$order_obj = wc_get_order($order->order_id);
$bundle_items = maybe_unserialize($order->bundle_items);
?>
<tr>
<td><a href="<?php echo get_edit_post_link($order->order_id); ?>">#<?php echo $order->order_id; ?></a></td>
<td><?php echo $order->order_item_name; ?></td>
<td><?php echo is_array($bundle_items) ? implode(', ', $bundle_items) : $bundle_items; ?></td>
<td><?php echo $order_obj->get_total(); ?></td>
<td><?php echo $order_obj->get_date_created()->date_i18n(); ?></td>
</tr>
<?php
}
}
// 添加批量操作
public function add_bulk_actions($bulk_actions) {
$bulk_actions['convert_to_bundle'] = __('转换为组合产品', 'flexible-bundle');
return $bulk_actions;
}
// 处理批量操作
public function handle_bulk_actions($redirect_to, $doaction, $post_ids) {
if ($doaction !== 'convert_to_bundle') {
return $redirect_to;
}
foreach ($post_ids as $post_id) {
wp_set_object_terms($post_id, 'bundle', 'product_type');
update_post_meta($post_id, '_bundle_pricing_type', 'discount');
update_post_meta($post_id, '_bundle_discount', 10);
}
$redirect_to = add_query_arg('converted_to_bundle', count($post_ids), $redirect_to);
return $redirect_to;
}
}
?>
## 插件优化与扩展建议
### 1. 性能优化
<?php
// 文件路径: includes/class-bundle-optimization.php
class FB_Bundle_Optimization {
public static function init() {
// 添加组合数据缓存
add_action('save_post_product', array(__CLASS__, 'clear_bundle_cache'));
// 优化数据库查询
add_filter('posts_where', array(__CLASS__, 'optimize_bundle_queries'));
}
// 清除组合缓存
public static function clear_bundle_cache($post_id) {
$product = wc_get_product($post_id);
if ($product->is_type('bundle')) {
wp_cache_delete('bundle_data_' . $post_id, 'flexible_bundle');
}
}
// 获取带缓存的组合数据
public static function get_cached_bundle_data($bundle_id) {
$cache_key = 'bundle_data_' . $bundle_id;
$data = wp_cache_get($cache_key, 'flexible_bundle');
if (false === $data) {
$data = array(
'products' => get_post_meta($bundle_id, '_bundle_products', true),
'pricing_type' => get_post_meta($bundle_id, '_bundle_pricing_type', true),
'discount' => get_post_meta($bundle_id, '_bundle_discount', true),
);
wp_cache_set($cache_key, $data, 'flexible_bundle', HOUR_IN_SECONDS);
}
return $data;
}
}
?>
### 2. 国际化支持
创建语言文件 `languages/flexible-bundle-zh_CN.po`:
WordPress文创商品柔性组合插件翻译文件
msgid ""
msgstr ""
"Project-Id-Version: Flexible Bundle 1.0.0n"
"POT-Creation-Date: 2024-01-20n"
"PO-Revision-Date: 2024-01-20n"
"Language-Team: Your Teamn"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
msgid "文创组合产品"
msgstr "文创组合产品"
msgid "选择组合商品"
msgstr "选择组合商品"
msgid "请选择 %d 到 %d 件商品组成您的专属组合"
msgstr "请选择 %d 到 %d 件商品组成您的专属组合"
## 安装与配置指南
### 步骤1:安装插件
1. 将插件文件夹上传到 `/wp-content/plugins/` 目录
2. 在WordPress后台激活插件
3. 确保WooCommerce已安装并激活
### 步骤2:创建组合产品
1. 进入产品 → 添加新产品
2. 在产品类型中选择"文创组合产品"
3. 配置组合选项:
- 输入可选的商品ID
- 设置定价策略
- 配置选择数量限制
### 步骤3:前端配置
1. 确保主题支持WooCommerce模板
2. 如有需要,可通过CSS自定义组合选择器样式
3. 测试组合购买流程
### 步骤4:监控与分析
1. 查看组合销售报告
2. 分析最受欢迎的组合
3. 根据销售数据调整组合策略
## 常见问题解答
### Q1:组合中的商品缺货怎么办?
A:插件会自动检查库存状态,缺货商品将无法被选择。
### Q2:能否设置时间限定的组合促销?
A:可以通过添加促销时间字段扩展插件功能。
### Q3:如何导出组合销售数据?
A:插件提供了报告页面,也可通过WooCommerce原生导出功能。
### Q4:是否支持订阅产品的组合?
A:当前版本主要支持普通商品,订阅产品支持需要额外开发。
## 结语
通过本教程,您已经学会了如何创建和定制一个完整的WordPress文创商品柔性组合与捆绑销售插件。这个插件不仅提供了灵活的销售方式,还能显著提升文创商品的客单价和客户满意度。您可以根据实际需求进一步扩展功能,如添加智能推荐算法、社交媒体分享组合功能等。
记住,良好的用户体验和合理的定价策略是组合销售成功的关键。定期分析销售数据,优化组合配置,将帮助您的文创电商业务获得更好的发展。
