文章目录[隐藏]
WordPress文创插件开发:柔性产品配置器与可视化定制教程
引言:文创产品定制化的市场需求
随着个性化消费时代的到来,文创产品的定制化需求日益增长。无论是文化机构、博物馆、艺术工作室还是文创品牌,都希望通过在线平台为客户提供个性化的产品定制服务。WordPress作为全球最流行的内容管理系统,为文创产品的在线定制提供了理想的平台基础。
本文将详细介绍如何开发一个WordPress文创插件,实现柔性产品配置器和可视化定制功能。通过本教程,您将学会创建一个完整的文创产品定制系统,让用户能够在线设计并预览自己的定制产品。
插件架构设计
1. 插件基础结构
首先,我们需要创建插件的基本文件结构:
wp-content/plugins/cultural-creator/
├── cultural-creator.php # 主插件文件
├── includes/
│ ├── class-product-configurator.php
│ ├── class-visual-editor.php
│ ├── class-ajax-handler.php
│ └── class-database.php
├── assets/
│ ├── css/
│ ├── js/
│ └── images/
├── templates/
│ ├── configurator-frontend.php
│ └── admin-settings.php
└── languages/
2. 主插件文件初始化
<?php
/**
* Plugin Name: 文创产品定制器
* Plugin URI: https://example.com/cultural-creator
* Description: 为WordPress网站提供文创产品可视化定制功能
* Version: 1.0.0
* Author: 文创开发者
* License: GPL v2 or later
* Text Domain: cultural-creator
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('CC_VERSION', '1.0.0');
define('CC_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('CC_PLUGIN_URL', plugin_dir_url(__FILE__));
// 自动加载类文件
spl_autoload_register(function ($class) {
$prefix = 'CulturalCreator_';
$base_dir = CC_PLUGIN_DIR . 'includes/';
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
$relative_class = substr($class, $len);
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
if (file_exists($file)) {
require $file;
}
});
// 初始化插件
function cultural_creator_init() {
// 检查WordPress版本
if (version_compare(get_bloginfo('version'), '5.0', '<')) {
add_action('admin_notices', function() {
echo '<div class="notice notice-error"><p>文创产品定制器需要WordPress 5.0或更高版本</p></div>';
});
return;
}
// 初始化核心类
$configurator = new CulturalCreator_ProductConfigurator();
$visual_editor = new CulturalCreator_VisualEditor();
$ajax_handler = new CulturalCreator_AjaxHandler();
// 注册激活和停用钩子
register_activation_hook(__FILE__, ['CulturalCreator_Database', 'install_tables']);
register_deactivation_hook(__FILE__, ['CulturalCreator_Database', 'deactivate']);
}
add_action('plugins_loaded', 'cultural_creator_init');
数据库设计与产品配置器
1. 数据库表结构
<?php
// includes/class-database.php
class CulturalCreator_Database {
public static function install_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_prefix = $wpdb->prefix . 'cc_';
// 产品表
$products_table = $table_prefix . 'products';
$sql_products = "CREATE TABLE IF NOT EXISTS $products_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
slug varchar(100) NOT NULL,
base_price decimal(10,2) DEFAULT '0.00',
base_image varchar(500),
product_type varchar(50) DEFAULT 'mug',
customizable_areas text,
status tinyint(1) DEFAULT 1,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY slug (slug)
) $charset_collate;";
// 设计元素表
$elements_table = $table_prefix . 'design_elements';
$sql_elements = "CREATE TABLE IF NOT EXISTS $elements_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
product_id mediumint(9) NOT NULL,
element_type varchar(50) NOT NULL,
element_name varchar(255) NOT NULL,
element_data text,
position_x int DEFAULT 0,
position_y int DEFAULT 0,
width int DEFAULT 100,
height int DEFAULT 100,
z_index int DEFAULT 1,
is_locked tinyint(1) DEFAULT 0,
PRIMARY KEY (id),
KEY product_id (product_id)
) $charset_collate;";
// 用户设计表
$designs_table = $table_prefix . 'user_designs';
$sql_designs = "CREATE TABLE IF NOT EXISTS $designs_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
user_id bigint(20) unsigned,
session_id varchar(100),
product_id mediumint(9) NOT NULL,
design_data text NOT NULL,
preview_image varchar(500),
total_price decimal(10,2) DEFAULT '0.00',
status varchar(20) DEFAULT 'draft',
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY session_id (session_id),
KEY product_id (product_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_products);
dbDelta($sql_elements);
dbDelta($sql_designs);
}
}
2. 产品配置器核心类
<?php
// includes/class-product-configurator.php
class CulturalCreator_ProductConfigurator {
private $product_id;
private $product_data;
public function __construct($product_id = null) {
if ($product_id) {
$this->product_id = $product_id;
$this->load_product_data();
}
}
/**
* 加载产品数据
*/
private function load_product_data() {
global $wpdb;
$table_name = $wpdb->prefix . 'cc_products';
$this->product_data = $wpdb->get_row(
$wpdb->prepare("SELECT * FROM $table_name WHERE id = %d", $this->product_id)
);
}
/**
* 获取可定制区域配置
* @return array 可定制区域配置数组
*/
public function get_customizable_areas() {
if (!$this->product_data) {
return [];
}
$areas = json_decode($this->product_data->customizable_areas, true);
// 默认区域配置
$default_areas = [
'front' => [
'name' => '正面',
'width' => 400,
'height' => 300,
'position' => ['x' => 50, 'y' => 50],
'allow_text' => true,
'allow_image' => true,
'allow_shape' => true
],
'back' => [
'name' => '背面',
'width' => 400,
'height' => 300,
'position' => ['x' => 500, 'y' => 50],
'allow_text' => true,
'allow_image' => true,
'allow_shape' => false
]
];
return wp_parse_args($areas, $default_areas);
}
/**
* 计算定制产品价格
* @param array $design_elements 设计元素数组
* @return float 总价格
*/
public function calculate_price($design_elements) {
$base_price = $this->product_data->base_price;
$total_price = floatval($base_price);
foreach ($design_elements as $element) {
switch ($element['type']) {
case 'text':
// 文字按长度和字体复杂度计价
$text_price = strlen($element['content']) * 0.1;
if (isset($element['font']) && $element['font'] !== 'default') {
$text_price += 2.0;
}
$total_price += $text_price;
break;
case 'image':
// 图片按尺寸和复杂度计价
$image_price = 5.0;
if (isset($element['width']) && $element['width'] > 200) {
$image_price += 3.0;
}
$total_price += $image_price;
break;
case 'shape':
// 图形按复杂度计价
$shape_price = 3.0;
if (isset($element['complexity']) && $element['complexity'] === 'high') {
$shape_price += 4.0;
}
$total_price += $shape_price;
break;
}
}
return round($total_price, 2);
}
}
可视化编辑器实现
1. 前端可视化编辑器
// assets/js/visual-editor.js
class CulturalCreatorVisualEditor {
constructor(config) {
this.config = config;
this.canvas = null;
this.ctx = null;
this.elements = [];
this.selectedElement = null;
this.isDragging = false;
this.dragOffset = { x: 0, y: 0 };
this.init();
}
/**
* 初始化编辑器
*/
init() {
this.createCanvas();
this.loadProductTemplate();
this.setupEventListeners();
this.setupToolbar();
this.render();
}
/**
* 创建画布
*/
createCanvas() {
const container = document.getElementById(this.config.containerId);
// 创建画布元素
this.canvas = document.createElement('canvas');
this.canvas.width = this.config.width || 800;
this.canvas.height = this.config.height || 600;
this.canvas.style.border = '1px solid #ddd';
this.canvas.style.backgroundColor = '#f9f9f9';
container.appendChild(this.canvas);
this.ctx = this.canvas.getContext('2d');
}
/**
* 加载产品模板
*/
loadProductTemplate() {
// 绘制产品基础轮廓
this.ctx.fillStyle = '#ffffff';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制可定制区域
const areas = this.config.customizableAreas;
Object.keys(areas).forEach(areaKey => {
const area = areas[areaKey];
// 绘制区域边界
this.ctx.strokeStyle = '#4a90e2';
this.ctx.lineWidth = 2;
this.ctx.setLineDash([5, 5]);
this.ctx.strokeRect(
area.position.x,
area.position.y,
area.width,
area.height
);
// 添加区域标签
this.ctx.fillStyle = '#4a90e2';
this.ctx.font = '14px Arial';
this.ctx.fillText(
area.name,
area.position.x + 5,
area.position.y - 5
);
this.ctx.setLineDash([]);
});
}
/**
* 添加文本元素
* @param {Object} options 文本选项
*/
addTextElement(options) {
const defaultOptions = {
id: 'text_' + Date.now(),
content: '新文本',
x: 100,
y: 100,
fontSize: 24,
fontFamily: 'Arial',
color: '#000000',
area: 'front'
};
const textElement = { ...defaultOptions, ...options, type: 'text' };
this.elements.push(textElement);
this.render();
return textElement.id;
}
/**
* 添加图片元素
* @param {Object} options 图片选项
*/
addImageElement(options) {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
const imageElement = {
id: 'image_' + Date.now(),
image: img,
x: options.x || 150,
y: options.y || 150,
width: options.width || 100,
height: options.height || 100,
src: options.src,
area: options.area || 'front',
type: 'image'
};
this.elements.push(imageElement);
this.render();
};
img.src = options.src;
}
/**
* 渲染所有元素
*/
render() {
// 清除画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 重新绘制产品模板
this.loadProductTemplate();
// 绘制所有元素
this.elements.forEach(element => {
this.drawElement(element);
});
// 绘制选中元素的控制点
if (this.selectedElement) {
this.drawSelectionBox(this.selectedElement);
}
}
/**
* 绘制单个元素
* @param {Object} element 元素对象
*/
drawElement(element) {
this.ctx.save();
switch (element.type) {
case 'text':
this.ctx.font = `${element.fontSize}px ${element.fontFamily}`;
this.ctx.fillStyle = element.color;
this.ctx.fillText(element.content, element.x, element.y);
break;
case 'image':
if (element.image && element.image.complete) {
this.ctx.drawImage(
element.image,
element.x,
element.y,
element.width,
element.height
);
}
break;
}
this.ctx.restore();
}
/**
* 设置事件监听器
*/
setupEventListeners() {
this.canvas.addEventListener('mousedown', this.handleMouseDown.bind(this));
this.canvas.addEventListener('mousemove', this.handleMouseMove.bind(this));
this.canvas.addEventListener('mouseup', this.handleMouseUp.bind(this));
this.canvas.addEventListener('click', this.handleClick.bind(this));
}
/**
* 处理鼠标按下事件
* @param {Event} e 鼠标事件
*/
handleMouseDown(e) {
const rect = this.canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 检查是否点击了元素
for (let i = this.elements.length - 1; i >= 0; i--) {
const element = this.elements[i];
if (this.isPointInElement(x, y, element)) {
this.selectedElement = element;
this.isDragging = true;
// 计算拖拽偏移量
this.dragOffset.x = x - element.x;
this.dragOffset.y = y - element.y;
this.render();
break;
}
}
}
/**
* 检查点是否在元素内
* @param {number} x X坐标
* @param {number} y Y坐标
* @param {Object} element 元素对象
* @returns {boolean} 是否在元素内
*/
isPointInElement(x, y, element) {
switch (element.type) {
case 'text':
this.ctx.font = `${element.fontSize}px ${element.fontFamily}`;
const width = this.ctx.measureText(element.content).width;
return x >= element.x &&
x <= element.x + width &&
y >= element.y - element.fontSize &&
y <= element.y;
case 'image':
return x >= element.x &&
x <= element.x + element.width &&
y >= element.y &&
y <= element.y + element.height;
}
return false;
}
/**
* 获取设计数据
* @returns {Object} 设计数据
*/
getDesignData() {
return {
elements: this.elements.map(el => {
const elementCopy = { ...el };
// 移除图像对象,只保留URL
if (elementCopy.type === 'image' && elementCopy.image) {
elementCopy.src = elementCopy.src;
delete elementCopy.image;
}
return elementCopy;
}),
canvasWidth: this.canvas.width,
canvasHeight: this.canvas.height,
productId: this.config.productId
};
}
}
2. WordPress短代码集成
<?php
// 在class-product-configurator.php中添加短代码方法
/**
* 注册产品配置器短代码
*/
public function register_shortcode() {
add_shortcode('cultural_configurator', [$this, 'render_configurator']);
}
/**
* 渲染产品配置器
* @param array $atts 短代码属性
* @return string HTML内容
*/
public function render_configurator($atts) {
$atts = shortcode_atts([
'product_id' => 0,
'width' => '800',
'height' => '600'
], $atts);
if (!$atts['product_id']) {
return '<p>请指定产品ID</p>';
}
// 加载产品数据
$this->product_id = intval($atts['product_id']);
$this->load_product_data();
if (!$this->product_data) {
return '<p>产品不存在</p>';
}
// 获取可定制区域
$customizable_areas = $this->get_customizable_areas();
// 生成唯一ID
$editor_id = 'cc-editor-' . uniqid();
// 输出HTML结构
ob_start();
?>
<div class="cultural-creator-container">
<div class="cc-editor-wrapper">
<div id="<?php echo esc_attr($editor_id); ?>" class="cc-visual-editor"></div>
<div class="cc-toolbar">
<div class="cc-tool-group">
<h4>添加元素</h4>
<button class="cc-btn cc-add-text" data-type="text">
<span class="dashicons dashicons-text"></span> 添加文字
</button>
<button class="cc-btn cc-add-image" data-type="image">
<span class="dashicons dashicons-format-image"></span> 添加图片
</button>
<button class="cc-btn cc-add-shape" data-type="shape">
<span class="dashicons dashicons-shapes"></span> 添加图形
</button>
</div>
<div class="cc-tool-group cc-properties-panel" style="display:none;">
<h4>属性设置</h4>
<div class="cc-properties-content"></div>
</div>
<div class="cc-tool-group">
<h4>操作</h4>
<button class="cc-btn cc-save-design">
<span class="dashicons dashicons-saved"></span> 保存设计
</button>
<button class="cc-btn cc-reset-design">
<span class="dashicons dashicons-update"></span> 重置
</button>
<button class="cc-btn cc-preview-3d">
<span class="dashicons dashicons-visibility"></span> 3D预览
</button>
</div>
</div>
</div>
<div class="cc-sidebar">
<div class="cc-price-summary">
<h3>价格明细</h3>
<div class="cc-price-breakdown">
<div class="cc-price-item">
<span>基础价格</span>
<span class="cc-price-amount">¥<?php echo number_format($this->product_data->base_price, 2); ?></span>
</div>
<div class="cc-price-item cc-customization-cost">
<span>定制费用</span>
<span class="cc-price-amount">¥0.00</span>
</div>
<div class="cc-price-total">
<span>总计</span>
<span class="cc-total-amount">¥<?php echo number_format($this->product_data->base_price, 2); ?></span>
</div>
</div>
</div>
<div class="cc-design-options">
<h3>设计选项</h3>
<div class="cc-option-group">
<label>选择区域:</label>
<select class="cc-area-selector">
<?php foreach ($customizable_areas as $area_key => $area): ?>
<option value="<?php echo esc_attr($area_key); ?>">
<?php echo esc_html($area['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="cc-option-group">
<label>上传图片:</label>
<input type="file" class="cc-image-upload" accept="image/*" style="display:none;">
<button class="cc-btn cc-upload-btn">选择图片</button>
<div class="cc-upload-preview"></div>
</div>
<div class="cc-text-options" style="display:none;">
<h4>文字设置</h4>
<input type="text" class="cc-text-input" placeholder="输入文字内容">
<select class="cc-font-selector">
<option value="Arial">Arial</option>
<option value="SimSun">宋体</option>
<option value="Microsoft YaHei">微软雅黑</option>
<option value="KaiTi">楷体</option>
</select>
<input type="color" class="cc-text-color" value="#000000">
<input type="range" class="cc-font-size" min="12" max="72" value="24">
</div>
</div>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
// 初始化可视化编辑器
const editorConfig = {
containerId: '<?php echo esc_js($editor_id); ?>',
productId: <?php echo intval($atts['product_id']); ?>,
width: <?php echo intval($atts['width']); ?>,
height: <?php echo intval($atts['height']); ?>,
customizableAreas: <?php echo wp_json_encode($customizable_areas); ?>
};
window.ccEditor = new CulturalCreatorVisualEditor(editorConfig);
// 绑定工具栏事件
$('.cc-add-text').on('click', function() {
const area = $('.cc-area-selector').val();
const textId = ccEditor.addTextElement({
content: '双击编辑文字',
area: area,
x: 100,
y: 100
});
// 显示文字设置面板
$('.cc-text-options').show();
$('.cc-properties-panel').show();
$('.cc-properties-content').html(`
<div class="cc-property-item">
<label>文字内容:</label>
<input type="text" class="cc-edit-text" value="双击编辑文字">
</div>
<div class="cc-property-item">
<label>字体大小:</label>
<input type="range" class="cc-edit-fontsize" min="12" max="72" value="24">
</div>
<div class="cc-property-item">
<label>字体颜色:</label>
<input type="color" class="cc-edit-color" value="#000000">
</div>
`);
});
// 保存设计
$('.cc-save-design').on('click', function() {
const designData = ccEditor.getDesignData();
$.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type: 'POST',
data: {
action: 'cc_save_design',
nonce: '<?php echo wp_create_nonce('cc_save_design_nonce'); ?>',
design_data: designData
},
success: function(response) {
if (response.success) {
alert('设计保存成功!');
// 更新价格
$('.cc-customization-cost .cc-price-amount').text('¥' + response.data.customization_cost);
$('.cc-total-amount').text('¥' + response.data.total_price);
} else {
alert('保存失败:' + response.data);
}
}
});
});
});
</script>
<?php
return ob_get_clean();
}
## AJAX处理与数据保存
### 1. AJAX处理器类
<?php
// includes/class-ajax-handler.php
class CulturalCreator_AjaxHandler {
public function __construct() {
$this->init_hooks();
}
/**
* 初始化AJAX钩子
*/
private function init_hooks() {
// 保存设计
add_action('wp_ajax_cc_save_design', [$this, 'save_design']);
add_action('wp_ajax_nopriv_cc_save_design', [$this, 'save_design']);
// 加载设计
add_action('wp_ajax_cc_load_design', [$this, 'load_design']);
add_action('wp_ajax_nopriv_cc_load_design', [$this, 'load_design']);
// 上传图片
add_action('wp_ajax_cc_upload_image', [$this, 'upload_image']);
add_action('wp_ajax_nopriv_cc_upload_image', [$this, 'upload_image']);
// 获取产品数据
add_action('wp_ajax_cc_get_product', [$this, 'get_product_data']);
add_action('wp_ajax_nopriv_cc_get_product', [$this, 'get_product_data']);
}
/**
* 保存用户设计
*/
public function save_design() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'cc_save_design_nonce')) {
wp_die('安全验证失败');
}
$design_data = json_decode(stripslashes($_POST['design_data']), true);
if (!$design_data || !isset($design_data['productId'])) {
wp_send_json_error('无效的设计数据');
}
global $wpdb;
$table_name = $wpdb->prefix . 'cc_user_designs';
// 获取用户ID或会话ID
$user_id = is_user_logged_in() ? get_current_user_id() : null;
$session_id = isset($_COOKIE['cc_session']) ? $_COOKIE['cc_session'] : $this->generate_session_id();
// 计算价格
$configurator = new CulturalCreator_ProductConfigurator($design_data['productId']);
$customization_cost = $configurator->calculate_price($design_data['elements']);
$base_price = floatval($configurator->product_data->base_price);
$total_price = $base_price + $customization_cost;
// 生成预览图
$preview_image = $this->generate_preview_image($design_data);
// 保存到数据库
$result = $wpdb->insert(
$table_name,
[
'user_id' => $user_id,
'session_id' => $session_id,
'product_id' => $design_data['productId'],
'design_data' => json_encode($design_data, JSON_UNESCAPED_UNICODE),
'preview_image' => $preview_image,
'total_price' => $total_price,
'status' => 'draft'
],
['%d', '%s', '%d', '%s', '%s', '%f', '%s']
);
if ($result) {
// 设置会话cookie
if (!isset($_COOKIE['cc_session'])) {
setcookie('cc_session', $session_id, time() + 30 * DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN);
}
wp_send_json_success([
'design_id' => $wpdb->insert_id,
'customization_cost' => number_format($customization_cost, 2),
'total_price' => number_format($total_price, 2),
'preview_url' => $preview_image
]);
} else {
wp_send_json_error('保存失败');
}
}
/**
* 生成预览图片
* @param array $design_data 设计数据
* @return string 图片URL
*/
private function generate_preview_image($design_data) {
// 这里简化处理,实际应该使用GD库或ImageMagick生成图片
$upload_dir = wp_upload_dir();
$filename = 'cc-preview-' . uniqid() . '.png';
$filepath = $upload_dir['path'] . '/' . $filename;
$fileurl = $upload_dir['url'] . '/' . $filename;
// 在实际应用中,这里应该使用canvas生成图片
// 为了简化,我们创建一个占位图片
$image = imagecreatetruecolor(400, 300);
$bg_color = imagecolorallocate($image, 240, 240, 240);
$text_color = imagecolorallocate($image, 100, 100, 100);
imagefill($image, 0, 0, $bg_color);
imagestring($image, 5, 150, 140, '设计预览', $text_color);
imagepng($image, $filepath);
imagedestroy($image);
return $fileurl;
}
/**
* 生成会话ID
* @return string 会话ID
*/
private function generate_session_id() {
return md5(uniqid() . $_SERVER['REMOTE_ADDR'] . time());
}
/**
* 上传图片
*/
public function upload_image() {
if (!wp_verify_nonce($_POST['nonce'], 'cc_upload_image_nonce')) {
wp_die('安全验证失败');
}
if (!function_exists('wp_handle_upload')) {
require_once(ABSPATH . 'wp-admin/includes/file.php');
}
$uploadedfile = $_FILES['image'];
$upload_overrides = ['test_form' => false];
$movefile = wp_handle_upload($uploadedfile, $upload_overrides);
if ($movefile && !isset($movefile['error'])) {
// 创建WordPress附件
$attachment = [
'post_mime_type' => $movefile['type'],
'post_title' => preg_replace('/.[^.]+$/', '', basename($movefile['file'])),
'post_content' => '',
'post_status' => 'inherit'
];
$attach_id = wp_insert_attachment($attachment, $movefile['file']);
// 生成缩略图
require_once(ABSPATH . 'wp-admin/includes/image.php');
$attach_data = wp_generate_attachment_metadata($attach_id, $movefile['file']);
wp_update_attachment_metadata($attach_id, $attach_data);
wp_send_json_success([
'url' => $movefile['url'],
'id' => $attach_id
]);
} else {
wp_send_json_error($movefile['error']);
}
}
}
## 管理后台与产品管理
### 1. 管理界面
<?php
// 在插件主文件中添加管理菜单
add_action('admin_menu', 'cultural_creator_admin_menu');
function cultural_creator_admin_menu() {
add_menu_page(
'文创产品定制器',
'文创定制',
'manage_options',
'cultural-creator',
'cultural_creator_admin_page',
'dashicons-art',
30
);
add_submenu_page(
'cultural-creator',
'产品管理',
'产品管理',
'manage_options',
'cultural-creator-products',
'cultural_creator_products_page'
);
add_submenu_page(
'cultural-creator',
'设计管理',
'设计管理',
'manage_options',
'cultural-creator-designs',
'cultural_creator_designs_page'
);
add_submenu_page(
'cultural-creator',
'设置',
'设置',
'manage_options',
'cultural-creator-settings',
'cultural_creator_settings_page'
);
}
function cultural_creator_admin_page() {
?>
<div class="wrap">
<h1>文创产品定制器</h1>
<div class="cc-admin-dashboard">
<div class="cc-stats-container">
<div class="cc-stat-card">
<h3>总产品数</h3>
<p class="cc-stat-number"><?php echo cultural_creator_get_product_count(); ?></p>
</div>
<div class="cc-stat-card">
<h3>总设计数</h3>
<p class="cc-stat-number"><?php echo cultural_creator_get_design_count(); ?></p>
</div>
<div class="cc-stat-card">
<h3>今日设计</h3>
<p class="cc-stat-number"><?php echo cultural_creator_get_today_designs(); ?></p>
</div>
</div>
<div class="cc-quick-actions">
<h2>快速操作</h2>
<a href="<?php echo admin_url('admin.php?page=cultural-creator-products&action=add'); ?>"
class="button button-primary">
添加新产品
</a>
<a href="<?php echo admin_url('admin.php?page=cultural-creator-designs'); ?>"
class="button">
查看所有设计
</a>
</div>
</div>
</div>
<?php
}
function cultural_creator_products_page() {
$action = isset($_GET['action']) ? $_GET['action'] : 'list';
switch ($action) {
case 'add':
case 'edit':
include CC_PLUGIN_DIR . 'templates/admin-product-edit.php';
break;
case 'list':
default:
include CC_PLUGIN_DIR . 'templates/admin-product-list.php';
break;
}
}
## 样式优化与响应式设计
/ assets/css/frontend.css /
.cultural-creator-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.cc-editor-wrapper {
flex: 1;
min-width: 300px;
}
.cc-visual-editor {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.cc-toolbar {
background: #f5f5f5;
padding: 15px;
border-radius: 8px;
margin-top: 15px;
}
.cc-tool-group {
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #ddd;
}
.cc-tool-group:last-child {
border-bottom: none;
margin


