文章目录[隐藏]
WordPress文创插件实现柔性产品定制选项器开发教程
一、前言:为什么需要柔性产品定制选项器
在文创产品销售领域,消费者越来越追求个性化和独特性。传统的固定产品选项已无法满足市场需求,柔性产品定制成为文创电商的重要发展方向。通过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: cultural-product-customizer
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('CPC_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('CPC_PLUGIN_URL', plugin_dir_url(__FILE__));
define('CPC_VERSION', '1.0.0');
// 初始化插件
class CulturalProductCustomizer {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// 插件激活时执行
register_activation_hook(__FILE__, array($this, 'activate'));
// 插件停用时执行
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
// 初始化
add_action('init', array($this, 'init'));
// 管理员菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 加载脚本和样式
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
}
public function activate() {
// 创建必要的数据库表
$this->create_database_tables();
// 设置默认选项
$this->set_default_options();
// 刷新重写规则
flush_rewrite_rules();
}
public function deactivate() {
// 清理临时数据
flush_rewrite_rules();
}
public function init() {
// 加载文本域
load_plugin_textdomain('cultural-product-customizer', false, dirname(plugin_basename(__FILE__)) . '/languages');
// 注册自定义文章类型
$this->register_custom_post_types();
}
// 其他方法将在后续部分实现
}
// 启动插件
CulturalProductCustomizer::get_instance();
?>
三、数据库设计与选项配置系统
为了实现灵活的选项配置,我们需要设计一个可扩展的数据库结构:
<?php
// 创建数据库表
private function create_database_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'cpc_product_options';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
product_id bigint(20) NOT NULL,
option_type varchar(50) NOT NULL,
option_name varchar(255) NOT NULL,
option_label varchar(255) NOT NULL,
option_values text NOT NULL,
is_required tinyint(1) DEFAULT 0,
display_order int(11) DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY product_id (product_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 创建选项值表
$values_table = $wpdb->prefix . 'cpc_option_values';
$sql2 = "CREATE TABLE IF NOT EXISTS $values_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
option_id mediumint(9) NOT NULL,
value_key varchar(100) NOT NULL,
value_label varchar(255) NOT NULL,
price_adjustment decimal(10,2) DEFAULT 0.00,
image_url varchar(500) DEFAULT NULL,
display_order int(11) DEFAULT 0,
PRIMARY KEY (id),
KEY option_id (option_id)
) $charset_collate;";
dbDelta($sql2);
}
// 注册自定义文章类型
private function register_custom_post_types() {
// 文创产品自定义文章类型
register_post_type('cultural_product',
array(
'labels' => array(
'name' => __('文创产品', 'cultural-product-customizer'),
'singular_name' => __('文创产品', 'cultural-product-customizer')
),
'public' => true,
'has_archive' => true,
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
'menu_icon' => 'dashicons-art',
'rewrite' => array('slug' => 'cultural-products'),
'show_in_rest' => true,
)
);
}
?>
四、后台选项管理界面开发
创建后台管理界面,让商家可以轻松配置产品选项:
<?php
// 添加管理员菜单
public function add_admin_menu() {
add_menu_page(
__('文创产品定制', 'cultural-product-customizer'),
__('文创定制', 'cultural-product-customizer'),
'manage_options',
'cpc-dashboard',
array($this, 'render_dashboard_page'),
'dashicons-admin-customizer',
30
);
add_submenu_page(
'cpc-dashboard',
__('产品选项管理', 'cultural-product-customizer'),
__('选项管理', 'cultural-product-customizer'),
'manage_options',
'cpc-options',
array($this, 'render_options_page')
);
add_submenu_page(
'cpc-dashboard',
__('设置', 'cultural-product-customizer'),
__('设置', 'cultural-product-customizer'),
'manage_options',
'cpc-settings',
array($this, 'render_settings_page')
);
}
// 渲染选项管理页面
public function render_options_page() {
// 检查权限
if (!current_user_can('manage_options')) {
wp_die(__('您没有权限访问此页面。', 'cultural-product-customizer'));
}
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['cpc_save_option'])) {
$this->save_product_option($_POST);
}
// 获取所有产品
$products = get_posts(array(
'post_type' => 'cultural_product',
'posts_per_page' => -1,
'post_status' => 'publish'
));
// 获取已保存的选项
$product_id = isset($_GET['product_id']) ? intval($_GET['product_id']) : 0;
$options = $this->get_product_options($product_id);
// 渲染页面
?>
<div class="wrap">
<h1><?php echo esc_html__('产品选项管理', 'cultural-product-customizer'); ?></h1>
<div class="cpc-admin-container">
<!-- 产品选择器 -->
<div class="cpc-product-selector">
<label for="cpc-product-select"><?php _e('选择产品:', 'cultural-product-customizer'); ?></label>
<select id="cpc-product-select" onchange="window.location.href='?page=cpc-options&product_id='+this.value">
<option value="0"><?php _e('-- 选择产品 --', 'cultural-product-customizer'); ?></option>
<?php foreach ($products as $product): ?>
<option value="<?php echo $product->ID; ?>" <?php selected($product_id, $product->ID); ?>>
<?php echo esc_html($product->post_title); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php if ($product_id): ?>
<!-- 选项表单 -->
<form method="post" class="cpc-options-form">
<input type="hidden" name="product_id" value="<?php echo $product_id; ?>">
<div id="cpc-options-container">
<?php foreach ($options as $index => $option): ?>
<div class="cpc-option-group" data-index="<?php echo $index; ?>">
<h3><?php _e('选项组', 'cultural-product-customizer'); ?> #<?php echo $index + 1; ?></h3>
<div class="cpc-form-row">
<label><?php _e('选项类型:', 'cultural-product-customizer'); ?></label>
<select name="options[<?php echo $index; ?>][type]" class="cpc-option-type">
<option value="select" <?php selected($option['type'], 'select'); ?>><?php _e('下拉选择', 'cultural-product-customizer'); ?></option>
<option value="radio" <?php selected($option['type'], 'radio'); ?>><?php _e('单选按钮', 'cultural-product-customizer'); ?></option>
<option value="checkbox" <?php selected($option['type'], 'checkbox'); ?>><?php _e('复选框', 'cultural-product-customizer'); ?></option>
<option value="text" <?php selected($option['type'], 'text'); ?>><?php _e('文本输入', 'cultural-product-customizer'); ?></option>
<option value="image" <?php selected($option['type'], 'image'); ?>><?php _e('图片选择', 'cultural-product-customizer'); ?></option>
</select>
</div>
<div class="cpc-form-row">
<label><?php _e('选项名称:', 'cultural-product-customizer'); ?></label>
<input type="text" name="options[<?php echo $index; ?>][name]"
value="<?php echo esc_attr($option['name']); ?>"
placeholder="例如: color, size">
</div>
<div class="cpc-form-row">
<label><?php _e('显示标签:', 'cultural-product-customizer'); ?></label>
<input type="text" name="options[<?php echo $index; ?>][label]"
value="<?php echo esc_attr($option['label']); ?>"
placeholder="例如: 选择颜色, 选择尺寸">
</div>
<!-- 选项值区域 -->
<div class="cpc-option-values">
<h4><?php _e('选项值:', 'cultural-product-customizer'); ?></h4>
<?php foreach ($option['values'] as $value_index => $value): ?>
<div class="cpc-value-row">
<input type="text"
name="options[<?php echo $index; ?>][values][<?php echo $value_index; ?>][key]"
value="<?php echo esc_attr($value['key']); ?>"
placeholder="值键名">
<input type="text"
name="options[<?php echo $index; ?>][values][<?php echo $value_index; ?>][label]"
value="<?php echo esc_attr($value['label']); ?>"
placeholder="显示标签">
<input type="number" step="0.01"
name="options[<?php echo $index; ?>][values][<?php echo $value_index; ?>][price]"
value="<?php echo esc_attr($value['price']); ?>"
placeholder="价格调整">
<button type="button" class="button cpc-remove-value"><?php _e('删除', 'cultural-product-customizer'); ?></button>
</div>
<?php endforeach; ?>
</div>
<button type="button" class="button cpc-add-value"><?php _e('添加选项值', 'cultural-product-customizer'); ?></button>
<button type="button" class="button button-danger cpc-remove-option"><?php _e('删除此选项', 'cultural-product-customizer'); ?></button>
</div>
<?php endforeach; ?>
</div>
<button type="button" id="cpc-add-option" class="button button-primary"><?php _e('添加新选项', 'cultural-product-customizer'); ?></button>
<div class="cpc-form-actions">
<input type="submit" name="cpc_save_option" class="button button-primary" value="<?php _e('保存选项', 'cultural-product-customizer'); ?>">
</div>
</form>
<?php endif; ?>
</div>
</div>
<?php
}
?>
五、前端定制器界面实现
前端定制器是用户直接交互的部分,需要良好的用户体验:
<?php
// 前端定制器短码
public function register_shortcodes() {
add_shortcode('cultural_product_customizer', array($this, 'render_product_customizer'));
}
// 渲染产品定制器
public function render_product_customizer($atts) {
$atts = shortcode_atts(array(
'product_id' => 0,
), $atts, 'cultural_product_customizer');
$product_id = intval($atts['product_id']);
if (!$product_id) {
return '<p>' . __('请指定产品ID。', 'cultural-product-customizer') . '</p>';
}
// 获取产品选项
$options = $this->get_product_options($product_id);
if (empty($options)) {
return '<p>' . __('该产品暂无定制选项。', 'cultural-product-customizer') . '</p>';
}
ob_start();
?>
<div class="cpc-product-customizer" data-product-id="<?php echo $product_id; ?>">
<div class="cpc-customizer-container">
<!-- 产品预览区域 -->
<div class="cpc-preview-area">
<div class="cpc-product-base">
<?php echo get_the_post_thumbnail($product_id, 'large'); ?>
</div>
<div class="cpc-customizations"></div>
</div>
<!-- 选项控制区域 -->
<div class="cpc-controls-area">
<h3><?php _e('定制您的产品', 'cultural-product-customizer'); ?></h3>
<form id="cpc-customization-form">
<?php foreach ($options as $index => $option): ?>
<div class="cpc-option-control" data-option-type="<?php echo esc_attr($option['type']); ?>">
<label class="cpc-option-label">
<?php echo esc_html($option['label']); ?>
<?php if ($option['required']): ?>
<span class="cpc-required">*</span>
<?php endif; ?>
</label>
<div class="cpc-option-input">
<?php switch ($option['type']):
case 'select': ?>
<select name="options[<?php echo esc_attr($option['name']); ?>]"
class="cpc-option-select"
<?php echo $option['required'] ? 'required' : ''; ?>>
<option value=""><?php _e('请选择', 'cultural-product-customizer'); ?></option>
<?php foreach ($option['values'] as $value): ?>
<option value="<?php echo esc_attr($value['key']); ?>"
data-price="<?php echo esc_attr($value['price']); ?>"
data-image="<?php echo esc_attr($value['image']); ?>">
<?php echo esc_html($value['label']); ?>
<?php if ($value['price'] != 0): ?>
(<?php echo $value['price'] > 0 ? '+' : ''; ?><?php echo get_woocommerce_currency_symbol() . $value['price']; ?>)
<?php endif; ?>
</option>
<?php endforeach; ?>
</select>
<?php break;
case 'radio': ?>
<div class="cpc-radio-group">
<?php foreach ($option['values'] as $value): ?>
<label class="cpc-radio-label">
<input type="radio"
name="options[<?php echo esc_attr($option['name']); ?>]"
value="<?php echo esc_attr($value['key']); ?>"
data-price="<?php echo esc_attr($value['price']); ?>"
data-image="<?php echo esc_attr($value['image']); ?>"
<?php echo $option['required'] ? 'required' : ''; ?>>
<span class="cpc-radio-text">
<?php echo esc_html($value['label']); ?>
<?php if ($value['price'] != 0): ?>
<span class="cpc-price-adjustment">
(<?php echo $value['price'] > 0 ? '+' : ''; ?><?php echo get_woocommerce_currency_symbol() . $value['price']; ?>)
</span>
<?php endif; ?>
</span>
</label>
<?php endforeach; ?>
</div>
<?php break;
case 'image': ?>
<div class="cpc-image-selector">
<?php foreach ($option['values'] as $value): ?>
<div class="cpc-image-option"
data-value="<?php echo esc_attr($value['key']); ?>"
data-price="<?php echo esc_attr($value['price']); ?>">
<?php if (!empty($value['image'])): ?>
<img src="<?php echo esc_url($value['image']); ?>"
alt="<?php echo esc_attr($value['label']); ?>">
<?php endif; ?>
<span class="cpc-image-label"><?php echo esc_html($value['label']); ?></span>
</div>
<?php endforeach; ?>
</div>
<?php break;
case 'text': ?>
<input type="text"
name="options[<?php echo esc_attr($option['name']); ?>]"
class="cpc-text-input"
placeholder="<?php _e('请输入', 'cultural-product-customizer'); ?>"
<?php echo $option['required'] ? 'required' : ''; ?>>
<?php break;
case 'checkbox': ?>
<div class="cpc-checkbox-group">
<?php foreach ($option['values'] as $value): ?>
<label class="cpc-checkbox-label">
<input type="checkbox"
name="options[<?php echo esc_attr($option['name']); ?>][]"
value="<?php echo esc_attr($value['key']); ?>"
data-price="<?php echo esc_attr($value['price']); ?>"
data-image="<?php echo esc_attr($value['image']); ?>">
<span class="cpc-checkbox-text">
<?php echo esc_html($value['label']); ?>
<?php if ($value['price'] != 0): ?>
<span class="cpc-price-adjustment">
(<?php echo $value['price'] > 0 ? '+' : ''; ?><?php echo get_woocommerce_currency_symbol() . $value['price']; ?>)
</span>
<?php endif; ?>
</span>
</label>
<?php endforeach; ?>
</div>
<?php break;
endswitch; ?>
</div>
<?php if (!empty($option['description'])): ?>
<p class="cpc-option-description"><?php echo esc_html($option['description']); ?></p>
<?php endif; ?>
</div>
<?php endforeach; ?>
<!-- 价格汇总 -->
<div class="cpc-price-summary">
<h4><?php _e('价格详情', 'cultural-product-customizer'); ?></h4>
<div class="cpc-base-price">
<span><?php _e('基础价格:', 'cultural-product-customizer'); ?></span>
<span class="cpc-base-price-amount"><?php echo get_woocommerce_currency_symbol(); ?><span id="cpc-base-price">0.00</span></span>
</div>
<div class="cpc-options-price">
<span><?php _e('选项加价:', 'cultural-product-customizer'); ?></span>
<span class="cpc-options-price-amount"><?php echo get_woocommerce_currency_symbol(); ?><span id="cpc-options-total">0.00</span></span>
</div>
<div class="cpc-total-price">
<span><?php _e('总计:', 'cultural-product-customizer'); ?></span>
<span class="cpc-total-price-amount"><?php echo get_woocommerce_currency_symbol(); ?><span id="cpc-final-price">0.00</span></span>
</div>
</div>
<!-- 添加到购物车 -->
<div class="cpc-add-to-cart">
<input type="hidden" name="customizations" id="cpc-customizations-data">
<button type="button" id="cpc-update-preview" class="button">
<?php _e('更新预览', 'cultural-product-customizer'); ?>
</button>
<button type="submit" id="cpc-add-to-cart" class="button button-primary">
<?php _e('添加到购物车', 'cultural-product-customizer'); ?>
</button>
</div>
</form>
</div>
</div>
</div>
<?php
return ob_get_clean();
}
?>
六、JavaScript交互与实时预览功能
实现前端JavaScript交互逻辑,提供实时预览和价格计算:
// 文件: assets/js/frontend-customizer.js
jQuery(document).ready(function($) {
'use strict';
// 初始化定制器
function initProductCustomizer() {
const $customizer = $('.cpc-product-customizer');
if (!$customizer.length) return;
const productId = $customizer.data('product-id');
let basePrice = 0;
let optionsTotal = 0;
// 获取基础价格
$.ajax({
url: cpc_ajax.ajax_url,
type: 'POST',
data: {
action: 'cpc_get_product_price',
product_id: productId,
security: cpc_ajax.nonce
},
success: function(response) {
if (response.success) {
basePrice = parseFloat(response.data.price);
$('#cpc-base-price').text(basePrice.toFixed(2));
updateTotalPrice();
}
}
});
// 选项变更事件
$customizer.on('change', '.cpc-option-select, .cpc-radio-group input, .cpc-text-input', handleOptionChange);
$customizer.on('click', '.cpc-image-option', handleImageSelect);
$customizer.on('change', '.cpc-checkbox-group input', handleCheckboxChange);
// 更新预览按钮
$('#cpc-update-preview').on('click', updateProductPreview);
// 添加到购物车
$('#cpc-add-to-cart').on('click', addToCart);
// 处理选项变更
function handleOptionChange() {
const $option = $(this).closest('.cpc-option-control');
const optionType = $option.data('option-type');
const optionName = $option.find('[name^="options"]').attr('name').match(/[(.*?)]/)[1];
let selectedValue = '';
let priceAdjustment = 0;
switch (optionType) {
case 'select':
const $select = $option.find('select');
selectedValue = $select.val();
priceAdjustment = parseFloat($select.find('option:selected').data('price') || 0);
break;
case 'radio':
const $selectedRadio = $option.find('input:checked');
selectedValue = $selectedRadio.val();
priceAdjustment = parseFloat($selectedRadio.data('price') || 0);
break;
case 'text':
selectedValue = $option.find('input').val();
// 文本选项可以设置每字符价格
priceAdjustment = selectedValue.length * 0.5; // 示例:每字符0.5元
break;
}
// 更新价格
updateOptionPrice(optionName, priceAdjustment);
updateTotalPrice();
}
// 处理图片选择
function handleImageSelect() {
const $option = $(this).closest('.cpc-option-control');
const $allOptions = $option.find('.cpc-image-option');
// 移除其他选项的选中状态
$allOptions.removeClass('selected');
// 设置当前选项为选中
$(this).addClass('selected');
const optionName = $option.find('[name^="options"]').attr('name').match(/[(.*?)]/)[1];
const priceAdjustment = parseFloat($(this).data('price') || 0);
const imageUrl = $(this).find('img').attr('src');
// 更新价格
updateOptionPrice(optionName, priceAdjustment);
updateTotalPrice();
// 更新预览
if (imageUrl) {
updatePreviewImage(optionName, imageUrl);
}
}
// 处理复选框变更
function handleCheckboxChange() {
const $option = $(this).closest('.cpc-option-control');
const optionName = $option.find('[name^="options"]').attr('name').match(/[(.*?)]/)[1];
let totalAdjustment = 0;
$option.find('input:checked').each(function() {
totalAdjustment += parseFloat($(this).data('price') || 0);
});
// 更新价格
updateOptionPrice(optionName, totalAdjustment);
updateTotalPrice();
}
// 更新选项价格
function updateOptionPrice(optionName, adjustment) {
// 存储每个选项的价格调整
if (!window.cpcOptionPrices) {
window.cpcOptionPrices = {};
}
window.cpcOptionPrices[optionName] = adjustment;
// 重新计算总选项价格
optionsTotal = 0;
for (const key in window.cpcOptionPrices) {
optionsTotal += window.cpcOptionPrices[key];
}
$('#cpc-options-total').text(optionsTotal.toFixed(2));
}
// 更新总价格
function updateTotalPrice() {
const totalPrice = basePrice + optionsTotal;
$('#cpc-final-price').text(totalPrice.toFixed(2));
}
// 更新产品预览
function updateProductPreview() {
const customizations = {};
// 收集所有选项值
$('.cpc-option-control').each(function() {
const $control = $(this);
const optionType = $control.data('option-type');
const optionName = $control.find('[name^="options"]').attr('name').match(/[(.*?)]/)[1];
let value = '';
switch (optionType) {
case 'select':
value = $control.find('select').val();
break;
case 'radio':
value = $control.find('input:checked').val();
break;
case 'text':
value = $control.find('input').val();
break;
case 'checkbox':
const values = [];
$control.find('input:checked').each(function() {
values.push($(this).val());
});
value = values.join(',');
break;
case 'image':
value = $control.find('.cpc-image-option.selected').data('value');
break;
}
if (value) {
customizations[optionName] = value;
}
});
// 发送AJAX请求更新预览
$.ajax({
url: cpc_ajax.ajax_url,
type: 'POST',
data: {
action: 'cpc_update_preview',
product_id: productId,
customizations: customizations,
security: cpc_ajax.nonce
},
success: function(response) {
if (response.success) {
// 更新预览区域
$('.cpc-customizations').html(response.data.preview_html);
}
}
});
}
// 添加到购物车
function addToCart() {
const customizations = {};
let isValid = true;
// 验证必填选项
$('.cpc-option-control').each(function() {
const $control = $(this);
const isRequired = $control.find('.cpc-required').length > 0;
const optionType = $control.data('option-type');
if (isRequired) {
let hasValue = false;
switch (optionType) {
case 'select':
hasValue = !!$control.find('select').val();
break;
case 'radio':
hasValue = $control.find('input:checked').length > 0;
break;
case 'text':
hasValue = !!$control.find('input').val().trim();
break;
case 'checkbox':
hasValue = $control.find('input:checked').length > 0;
break;
case 'image':
hasValue = $control.find('.cpc-image-option.selected').length > 0;
break;
}
if (!hasValue) {
isValid = false;
$control.addClass('cpc-error');
} else {
$control.removeClass('cpc-error');
}
}
// 收集数据
const optionName = $control.find('[name^="options"]').attr('name').match(/[(.*?)]/)[1];
let value = '';
switch (optionType) {
case 'select':
value = $control.find('select').val();
break;
case 'radio':
value = $control.find('input:checked').val();
break;
case 'text':
value = $control.find('input').val();
break;
case 'checkbox':
const values = [];
$control.find('input:checked').each(function() {
values.push($(this).val());
});
value = values.join(',');
break;
case 'image':
value = $control.find('.cpc-image-option.selected').data('value');
break;
}
if (value) {
customizations[optionName] = value;
}
});
if (!isValid) {
alert('请填写所有必填选项');
return;
}
// 添加到购物车
$.ajax({
url: cpc_ajax.ajax_url,
type: 'POST',
data: {
action: 'cpc_add_to_cart',
product_id: productId,
customizations: customizations,
options_total: optionsTotal,
security: cpc_ajax.nonce
},
success: function(response) {
if (response.success) {
// 显示成功消息
alert('产品已添加到购物车!');
// 可选:跳转到购物车页面
if (response.data.redirect) {
window.location.href = response.data.redirect;
}
} else {
alert('添加失败:' + response.data.message);
}
}
});
}
// 更新预览图片
function updatePreviewImage(optionName, imageUrl) {
const $preview = $('.cpc-customizations');
let $layer = $preview.find(`.cpc-layer-${optionName}`);
if (!$layer.length) {
$layer = $('<div>', {
class: `cpc-preview-layer cpc-layer-${optionName}`,
css: {
position: 'absolute',
top: 0,
left: 0,
'z-index': 10
}
}).appendTo($preview);
}
$layer.html(`<img src="${imageUrl}" alt="${optionName}" style="max-width: 100%;">`);
}
}
// 初始化
initProductCustomizer();
});
七、与WooCommerce集成
将定制器与WooCommerce购物车和订单系统集成:
<?php
// 集成WooCommerce
public function integrate_woocommerce() {
// 检查WooCommerce是否激活
if (!class_exists('WooCommerce')) {
return;
}
// 添加到购物车处理
add_action('woocommerce_add_to_cart', array($this, 'handle_custom_product_add_to_cart'), 10, 6);
// 在购物车中显示定制选项
add_filter('woocommerce_get_item_data', array($this, 'display_customizations_in_cart'), 10, 2);
// 将定制数据保存到订单项
add_action('woocommerce_checkout_create_order_line_item', array($this, 'save_customizations_to_order_item'), 10, 4);
// 在订单详情中显示定制选项
add_action('woocommerce_order_item_meta_end', array($this, 'display_customizations_in_order'), 10, 3);
// 价格计算
add_action('woocommerce_before_calculate_totals', array($this, 'calculate_custom_product_price'), 10, 1);
}
// 处理添加到购物车
public function handle_custom_product_add_to_cart($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data) {
// 检查是否有定制数据
if (isset($_POST['customizations']) && !empty($_POST['customizations'])) {
$customizations = json_decode(stripslashes($_POST['customizations']), true);
if ($customizations) {
WC()->cart->cart_contents[$cart_item_key]['customizations'] = $customizations;
// 保存选项总价
if (isset($_POST['options_total'])) {
WC()->cart->cart_contents[$cart_item_key]['options_total'] = floatval($_POST['options_total']);
}
}
}
}
// 在购物车中显示定制选项
public function display_customizations_in_cart($item_data, $cart_item) {
if (isset($cart_item['customizations']) && is_array($cart_item['customizations'])) {
foreach ($cart_item['customizations'] as $key => $value) {
if (!empty($value)) {
// 获取选项标签
$option_label = $this->get_option_label($cart_item['product_id'], $key);
$item_data[] = array(
'name' => $option_label ?: ucfirst(str_replace('_', ' ', $key)),
'value' => $this->format_customization_value($cart_item['product_id'], $key, $value)
);
}
}
}
return $item_data;
}
// 保存定制数据到订单项
public function save_customizations_to_order_item($item, $cart_item_key, $values, $order) {
if (isset($values['customizations'])) {
$item->add_meta_data('_customizations', $values['customizations']);
}
if (isset($values['options_total'])) {
$item->add_meta_data('_options_total', $values['options_total']);
}
}
// 计算定制产品价格
public function calculate_custom_product_price($cart) {


