文章目录[隐藏]
WordPress小批量定制插件支持客户协同设计的教程
引言:为什么需要客户协同设计插件
在WordPress网站开发中,经常会遇到需要为客户定制功能的情况。传统的开发模式往往是单向的:客户提出需求→开发者实现→客户验收。这种模式存在沟通成本高、需求理解偏差、反复修改等问题。通过开发一个支持客户协同设计的插件,我们可以让客户在开发过程中直接参与界面设计和功能配置,大大提高开发效率和客户满意度。
本教程将指导您创建一个完整的WordPress插件,支持小批量定制和客户协同设计功能。我们将构建一个简单的产品配置器作为示例,客户可以通过它自定义产品选项并实时预览效果。
插件基础结构
首先,我们需要创建插件的基本文件结构:
<?php
/**
* Plugin Name: 客户协同设计工具
* Plugin URI: https://yourwebsite.com/
* Description: 支持客户参与设计过程的小批量定制插件
* Version: 1.0.0
* Author: 您的名字
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('CCD_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('CCD_PLUGIN_URL', plugin_dir_url(__FILE__));
define('CCD_VERSION', '1.0.0');
// 初始化插件
class ClientCoDesignPlugin {
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() {
// 后台初始化
add_action('admin_init', array($this, 'admin_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'));
// 注册短代码
add_shortcode('product_configurator', array($this, 'render_configurator'));
// AJAX处理
add_action('wp_ajax_save_design', array($this, 'save_design_callback'));
add_action('wp_ajax_nopriv_save_design', array($this, 'save_design_callback'));
}
// 后续方法将在这里添加
}
// 启动插件
ClientCoDesignPlugin::get_instance();
?>
数据库设计与数据管理
协同设计插件需要存储客户的设计选择和配置。我们将创建一个自定义数据库表来存储这些信息:
// 在ClientCoDesignPlugin类中添加以下方法
/**
* 创建必要的数据库表
*/
public function create_database_tables() {
global $wpdb;
$table_name = $wpdb->prefix . 'client_designs';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
user_id mediumint(9) NOT NULL,
project_name varchar(100) NOT NULL,
design_data longtext NOT NULL,
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 status (status)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
/**
* 激活插件时创建表
*/
public static function activate_plugin() {
$plugin = new self();
$plugin->create_database_tables();
// 创建默认选项
add_option('ccd_default_options', array(
'max_designs_per_user' => 10,
'allow_guest_designs' => true,
'default_product_types' => array('T恤', '杯子', '海报')
));
}
/**
* 保存设计数据
*/
public function save_design($user_id, $project_name, $design_data) {
global $wpdb;
$table_name = $wpdb->prefix . 'client_designs';
// 检查用户是否超过最大设计数量限制
$max_designs = get_option('ccd_default_options')['max_designs_per_user'];
$user_design_count = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE user_id = %d",
$user_id
)
);
if ($user_design_count >= $max_designs) {
return new WP_Error('limit_exceeded', '已达到最大设计数量限制');
}
// 插入或更新设计数据
$result = $wpdb->replace(
$table_name,
array(
'user_id' => $user_id,
'project_name' => $project_name,
'design_data' => json_encode($design_data),
'status' => 'draft'
),
array('%d', '%s', '%s', '%s')
);
return $result ? $wpdb->insert_id : false;
}
前端配置器界面
创建一个直观的前端界面,让客户可以实时配置产品:
/**
* 渲染产品配置器短代码
*/
public function render_configurator($atts) {
// 解析短代码属性
$atts = shortcode_atts(array(
'product_type' => 'tshirt',
'show_preview' => 'true'
), $atts, 'product_configurator');
// 获取当前用户ID(访客为0)
$user_id = is_user_logged_in() ? get_current_user_id() : 0;
// 生成唯一会话ID用于访客
if ($user_id === 0) {
if (!isset($_SESSION['guest_session_id'])) {
$_SESSION['guest_session_id'] = 'guest_' . wp_generate_uuid4();
}
$session_id = $_SESSION['guest_session_id'];
}
ob_start();
?>
<div class="ccd-configurator-container" data-user-id="<?php echo esc_attr($user_id); ?>" data-product-type="<?php echo esc_attr($atts['product_type']); ?>">
<div class="ccd-header">
<h2>产品定制设计器</h2>
<p>实时调整选项,右侧预览将立即更新</p>
</div>
<div class="ccd-main-content">
<!-- 左侧配置面板 -->
<div class="ccd-control-panel">
<div class="ccd-section">
<h3>1. 基本设置</h3>
<div class="ccd-control-group">
<label for="ccd-product-color">产品颜色:</label>
<select id="ccd-product-color" class="ccd-control" data-target="preview-color">
<option value="#FF0000">红色</option>
<option value="#00FF00" selected>绿色</option>
<option value="#0000FF">蓝色</option>
<option value="#FFFF00">黄色</option>
<option value="#FFFFFF">白色</option>
</select>
</div>
<div class="ccd-control-group">
<label for="ccd-product-size">产品尺寸:</label>
<select id="ccd-product-size" class="ccd-control" data-target="preview-size">
<option value="S">小号 (S)</option>
<option value="M" selected>中号 (M)</option>
<option value="L">大号 (L)</option>
<option value="XL">加大 (XL)</option>
</select>
</div>
</div>
<div class="ccd-section">
<h3>2. 自定义文本</h3>
<div class="ccd-control-group">
<label for="ccd-custom-text">文本内容:</label>
<input type="text" id="ccd-custom-text" class="ccd-control"
data-target="preview-text"
placeholder="输入自定义文本"
maxlength="50">
</div>
<div class="ccd-control-group">
<label for="ccd-text-color">文本颜色:</label>
<input type="color" id="ccd-text-color" class="ccd-control"
data-target="preview-text-color"
value="#000000">
</div>
<div class="ccd-control-group">
<label for="ccd-text-size">文本大小:</label>
<input type="range" id="ccd-text-size" class="ccd-control"
data-target="preview-text-size"
min="12" max="72" value="24">
<span class="ccd-range-value">24px</span>
</div>
</div>
<div class="ccd-section">
<h3>3. 上传图案</h3>
<div class="ccd-control-group">
<label for="ccd-upload-image">上传图片:</label>
<input type="file" id="ccd-upload-image" class="ccd-control"
accept="image/*" style="display: none;">
<button type="button" id="ccd-upload-button" class="ccd-button">选择图片</button>
<div id="ccd-image-preview" class="ccd-image-preview"></div>
</div>
<div class="ccd-control-group">
<label for="ccd-image-opacity">图案透明度:</label>
<input type="range" id="ccd-image-opacity" class="ccd-control"
data-target="preview-image-opacity"
min="0" max="100" value="100">
<span class="ccd-range-value">100%</span>
</div>
</div>
<!-- 保存和分享按钮 -->
<div class="ccd-actions">
<button type="button" id="ccd-save-design" class="ccd-button ccd-button-primary">
<span class="dashicons dashicons-saved"></span> 保存设计
</button>
<button type="button" id="ccd-share-design" class="ccd-button ccd-button-secondary">
<span class="dashicons dashicons-share"></span> 分享设计
</button>
<button type="button" id="ccd-reset-design" class="ccd-button">
<span class="dashicons dashicons-update"></span> 重置
</button>
</div>
</div>
<!-- 右侧实时预览 -->
<div class="ccd-preview-panel">
<h3>实时预览</h3>
<div class="ccd-preview-container">
<div class="ccd-product-preview" id="ccd-product-preview">
<!-- 预览内容将通过JavaScript动态更新 -->
<div class="ccd-product-base" id="ccd-product-base">
<div class="ccd-product-text" id="ccd-product-text">示例文本</div>
<div class="ccd-product-image" id="ccd-product-image"></div>
</div>
</div>
</div>
<div class="ccd-preview-info">
<h4>设计摘要</h4>
<ul id="ccd-design-summary">
<li>颜色: <span id="summary-color">绿色</span></li>
<li>尺寸: <span id="summary-size">中号 (M)</span></li>
<li>自定义文本: <span id="summary-text">无</span></li>
</ul>
</div>
</div>
</div>
<!-- 设计保存表单 -->
<div class="ccd-save-modal" id="ccd-save-modal" style="display: none;">
<div class="ccd-modal-content">
<h3>保存您的设计</h3>
<form id="ccd-save-form">
<div class="ccd-form-group">
<label for="ccd-design-name">设计名称:</label>
<input type="text" id="ccd-design-name" required
placeholder="例如: 公司周年纪念T恤">
</div>
<div class="ccd-form-group">
<label for="ccd-design-notes">设计备注:</label>
<textarea id="ccd-design-notes" rows="3"
placeholder="添加一些备注或说明..."></textarea>
</div>
<div class="ccd-form-actions">
<button type="submit" class="ccd-button ccd-button-primary">保存设计</button>
<button type="button" id="ccd-cancel-save" class="ccd-button">取消</button>
</div>
</form>
</div>
</div>
</div>
<?php
return ob_get_clean();
}
JavaScript交互与实时预览
添加JavaScript代码以实现实时预览和AJAX交互:
// 创建文件 /assets/js/ccd-frontend.js
jQuery(document).ready(function($) {
'use strict';
// 设计配置对象
var designConfig = {
color: '#00FF00',
size: 'M',
text: '',
textColor: '#000000',
textSize: 24,
image: null,
imageOpacity: 100
};
// 初始化配置器
function initConfigurator() {
// 绑定控制事件
$('.ccd-control').on('change input', handleControlChange);
// 初始化颜色选择器
$('#ccd-text-color').on('change', updateTextColor);
// 初始化范围输入
$('input[type="range"]').on('input', function() {
$(this).next('.ccd-range-value').text($(this).val() +
($(this).attr('id') === 'ccd-text-size' ? 'px' : '%'));
});
// 图片上传
$('#ccd-upload-button').on('click', function() {
$('#ccd-upload-image').click();
});
$('#ccd-upload-image').on('change', handleImageUpload);
// 按钮事件
$('#ccd-save-design').on('click', openSaveModal);
$('#ccd-share-design').on('click', shareDesign);
$('#ccd-reset-design').on('click', resetDesign);
$('#ccd-cancel-save').on('click', closeSaveModal);
// 保存表单提交
$('#ccd-save-form').on('submit', saveDesign);
// 初始更新预览
updatePreview();
updateSummary();
}
// 处理控制变化
function handleControlChange(e) {
var $control = $(this);
var controlId = $control.attr('id');
var value = $control.val();
var target = $control.data('target');
// 更新设计配置
switch(controlId) {
case 'ccd-product-color':
designConfig.color = value;
break;
case 'ccd-product-size':
designConfig.size = value;
break;
case 'ccd-custom-text':
designConfig.text = value;
break;
case 'ccd-text-size':
designConfig.textSize = parseInt(value);
break;
case 'ccd-image-opacity':
designConfig.imageOpacity = parseInt(value);
break;
}
// 更新预览
updatePreview();
updateSummary();
}
// 更新文本颜色
function updateTextColor() {
designConfig.textColor = $(this).val();
updatePreview();
}
// 处理图片上传
function handleImageUpload(e) {
var file = e.target.files[0];
if (!file) return;
// 验证文件类型
if (!file.type.match('image.*')) {
alert('请选择图片文件');
return;
}
// 验证文件大小(最大2MB)
if (file.size > 2 * 1024 * 1024) {
alert('图片大小不能超过2MB');
return;
}
// 创建预览
var reader = new FileReader();
reader.onload = function(e) {
designConfig.image = e.target.result;
$('#ccd-image-preview').html(
'<img src="' + e.target.result + '" alt="上传的图片" style="max-width: 100px;">'
);
updatePreview();
};
reader.readAsDataURL(file);
}
// 更新预览
function updatePreview() {
// 更新产品基础颜色
$('#ccd-product-base').css('background-color', designConfig.color);
// 更新文本
var $productText = $('#ccd-product-text');
if (designConfig.text) {
$productText.text(designConfig.text);
$productText.show();
$productText.css({
'color': designConfig.textColor,
'font-size': designConfig.textSize + 'px'
});
} else {
$productText.hide();
}
// 更新图片
var $productImage = $('#ccd-product-image');
if (designConfig.image) {
$productImage.html('<img src="' + designConfig.image + '" alt="设计图案">');
$productImage.find('img').css('opacity', designConfig.imageOpacity / 100);
$productImage.show();
} else {
$productImage.hide();
}
}
// 更新设计摘要
function updateSummary() {
$('#summary-color').text(getColorName(designConfig.color));
$('#summary-size').text(getSizeName(designConfig.size));
$('#summary-text').text(designConfig.text || '无');
}
// 获取颜色名称
function getColorName(hex) {
var colors = {
'#FF0000': '红色',
'#00FF00': '绿色',
'#0000FF': '蓝色',
'#FFFF00': '黄色',
'#FFFFFF': '白色'
};
return colors[hex] || hex;
}
// 获取尺寸名称
function getSizeName(size) {
var sizes = {
'S': '小号 (S)',
'M': '中号 (M)',
'L': '大号 (L)',
'XL': '加大 (XL)'
};
return sizes[size] || size;
}
// 打开保存模态框
function openSaveModal() {
$('#ccd-save-modal').fadeIn();
$('#ccd-design-name').focus();
}
// 关闭保存模态框
function closeSaveModal() {
$('#ccd-save-modal').fadeOut();
$('#ccd-save-form')[0].reset();
}
// 分享设计
function shareDesign() {
// 生成设计快照
html2canvas(document.querySelector('#ccd-product-preview')).then(canvas => {
var imageData = canvas.toDataURL('image/png');
// 创建分享模态框
var shareModal = $(
'<div class="ccd-share-modal">' +
'<div class="ccd-modal-content">' +
'<h3>分享设计</h3>' +
'<div class="ccd-share-image">' +
'<img src="' + imageData + '" alt="设计预览">' +
'</div>' +
'<div class="ccd-share-options">' +
'<button class="ccd-button" id="ccd-download-image">下载图片</button>' +
'<button class="ccd-button" id="ccd-copy-link">复制分享链接</button>' +
'<button class="ccd-button" id="ccd-close-share">关闭</button>' +
'</div>' +
'</div>' +
'</div>'
);
$('body').append(shareModal);
// 绑定分享按钮事件
$('#ccd-download-image').on('click', function() {
var link = document.createElement('a');
link.download = '我的设计.png';
link.href = imageData;
link.click();
});
$('#ccd-copy-link').on('click', function() {
// 在实际应用中,这里应该生成一个唯一的分享链接
var shareUrl = window.location.href + '?design=' + btoa(JSON.stringify(designConfig));
navigator.clipboard.writeText(shareUrl).then(function() {
alert('分享链接已复制到剪贴板!');
});
});
$('#ccd-close-share').on('click', function() {
shareModal.remove();
});
});
}
// 重置设计
function resetDesign() {
if (confirm('确定要重置所有设置吗?')) {
designConfig = {
color: '#00FF00',
size: 'M',
text: '',
textColor: '#000000',
textSize: 24,
image: null,
imageOpacity: 100
};
// 重置表单控件
$('#ccd-product-color').val('#00FF00');
$('#ccd-product-size').val('M');
$('#ccd-custom-text').val('');
$('#ccd-text-color').val('#000000');
$('#ccd-text-size').val(24);
$('#ccd-image-opacity').val(100);
$('#ccd-upload-image').val('');
$('#ccd-image-preview').empty();
// 更新显示值
$('.ccd-range-value').each(function() {
var $input = $(this).prev('input');
$(this).text($input.val() + ($input.attr('id') === 'ccd-text-size' ? 'px' : '%'));
});
updatePreview();
updateSummary();
}
}
// 保存设计到服务器
function saveDesign(e) {
e.preventDefault();
var designName = $('#ccd-design-name').val();
if (!designName.trim()) {
alert('请输入设计名称');
return;
}
var designNotes = $('#ccd-design-notes').val();
var userId = $('.ccd-configurator-container').data('user-id');
// 显示加载状态
var $submitBtn = $(this).find('button[type="submit"]');
var originalText = $submitBtn.text();
$submitBtn.html('<span class="dashicons dashicons-update"></span> 保存中...').prop('disabled', true);
// 准备设计数据
var designData = {
config: designConfig,
name: designName,
notes: designNotes,
timestamp: new Date().toISOString(),
preview: '' // 在实际应用中,这里可以添加base64编码的预览图
};
// 发送AJAX请求
$.ajax({
url: ccd_ajax.ajax_url,
type: 'POST',
data: {
action: 'save_design',
nonce: ccd_ajax.nonce,
user_id: userId,
design_name: designName,
design_data: designData
},
success: function(response) {
if (response.success) {
alert('设计保存成功!');
closeSaveModal();
// 在实际应用中,这里可以重定向到设计管理页面
console.log('设计ID:', response.data.design_id);
} else {
alert('保存失败: ' + response.data.message);
}
},
error: function() {
alert('网络错误,请稍后重试');
},
complete: function() {
$submitBtn.text(originalText).prop('disabled', false);
}
});
}
// 初始化
initConfigurator();
});
后台管理界面
创建后台管理界面,让开发者可以管理客户的设计和配置选项:
// 在ClientCoDesignPlugin类中添加以下方法
/**
* 添加管理菜单
*/
public function add_admin_menu() {
// 主菜单
add_menu_page(
'协同设计管理',
'协同设计',
'manage_options',
'client-co-design',
array($this, 'render_admin_dashboard'),
'dashicons-art',
30
);
// 子菜单
add_submenu_page(
'client-co-design',
'设计管理',
'设计管理',
'manage_options',
'ccd-designs',
array($this, 'render_designs_page')
);
add_submenu_page(
'client-co-design',
'产品配置',
'产品配置',
'manage_options',
'ccd-products',
array($this, 'render_products_page')
);
add_submenu_page(
'client-co-design',
'设置',
'设置',
'manage_options',
'ccd-settings',
array($this, 'render_settings_page')
);
}
/**
* 渲染管理仪表板
*/
public function render_admin_dashboard() {
global $wpdb;
$table_name = $wpdb->prefix . 'client_designs';
// 获取统计数据
$total_designs = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
$active_designs = $wpdb->get_var(
$wpdb->prepare("SELECT COUNT(*) FROM $table_name WHERE status = %s", 'active')
);
$recent_designs = $wpdb->get_results(
"SELECT * FROM $table_name ORDER BY created_at DESC LIMIT 5"
);
?>
<div class="wrap ccd-admin-dashboard">
<h1>协同设计管理仪表板</h1>
<div class="ccd-stats-container">
<div class="ccd-stat-card">
<h3>总设计数</h3>
<div class="ccd-stat-number"><?php echo esc_html($total_designs); ?></div>
</div>
<div class="ccd-stat-card">
<h3>活跃设计</h3>
<div class="ccd-stat-number"><?php echo esc_html($active_designs); ?></div>
</div>
<div class="ccd-stat-card">
<h3>今日新增</h3>
<div class="ccd-stat-number">
<?php
$today = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE DATE(created_at) = %s",
current_time('Y-m-d')
)
);
echo esc_html($today);
?>
</div>
</div>
</div>
<div class="ccd-recent-designs">
<h2>最近的设计</h2>
<?php if ($recent_designs): ?>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>ID</th>
<th>设计名称</th>
<th>用户</th>
<th>状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($recent_designs as $design):
$user_info = get_userdata($design->user_id);
$username = $user_info ? $user_info->display_name : '访客';
?>
<tr>
<td><?php echo esc_html($design->id); ?></td>
<td><?php echo esc_html($design->project_name); ?></td>
<td><?php echo esc_html($username); ?></td>
<td>
<span class="ccd-status-badge ccd-status-<?php echo esc_attr($design->status); ?>">
<?php
$status_labels = array(
'draft' => '草稿',
'active' => '活跃',
'completed' => '完成'
);
echo esc_html($status_labels[$design->status] ?? $design->status);
?>
</span>
</td>
<td><?php echo esc_html(date('Y-m-d H:i', strtotime($design->created_at))); ?></td>
<td>
<button class="button button-small view-design" data-design-id="<?php echo esc_attr($design->id); ?>">
查看
</button>
<button class="button button-small edit-design" data-design-id="<?php echo esc_attr($design->id); ?>">
编辑
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<p>暂无设计数据。</p>
<?php endif; ?>
</div>
</div>
<?php
}
/**
* 渲染设计管理页面
*/
public function render_designs_page() {
global $wpdb;
$table_name = $wpdb->prefix . 'client_designs';
$per_page = 20;
$current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
$offset = ($current_page - 1) * $per_page;
// 获取筛选条件
$status_filter = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '';
$search_term = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
// 构建查询
$where_clauses = array('1=1');
$query_params = array();
if ($status_filter) {
$where_clauses[] = "status = %s";
$query_params[] = $status_filter;
}
if ($search_term) {
$where_clauses[] = "(project_name LIKE %s OR id = %s)";
$query_params[] = '%' . $wpdb->esc_like($search_term) . '%';
$query_params[] = $search_term;
}
$where_sql = implode(' AND ', $where_clauses);
// 获取总记录数
$count_query = "SELECT COUNT(*) FROM $table_name WHERE $where_sql";
if ($query_params) {
$count_query = $wpdb->prepare($count_query, $query_params);
}
$total_items = $wpdb->get_var($count_query);
// 获取当前页数据
$data_query = "SELECT * FROM $table_name WHERE $where_sql ORDER BY created_at DESC LIMIT %d OFFSET %d";
$query_params[] = $per_page;
$query_params[] = $offset;
$data_query = $wpdb->prepare($data_query, $query_params);
$designs = $wpdb->get_results($data_query);
?>
<div class="wrap">
<h1 class="wp-heading-inline">设计管理</h1>
<form method="get" class="ccd-filter-form">
<input type="hidden" name="page" value="ccd-designs">
<div class="ccd-filters">
<select name="status" class="ccd-filter-select">
<option value="">所有状态</option>
<option value="draft" <?php selected($status_filter, 'draft'); ?>>草稿</option>
<option value="active" <?php selected($status_filter, 'active'); ?>>活跃</option>
<option value="completed" <?php selected($status_filter, 'completed'); ?>>完成</option>
</select>
<input type="text" name="s" placeholder="搜索设计名称或ID"
value="<?php echo esc_attr($search_term); ?>" class="ccd-search-input">
<button type="submit" class="button">筛选</button>
<?php if ($status_filter || $search_term): ?>
<a href="<?php echo admin_url('admin.php?page=ccd-designs'); ?>" class="button">
清除筛选
</a>
<?php endif; ?>
</div>
</form>
<div class="ccd-designs-list">
<?php if ($designs): ?>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>ID</th>
<th>设计名称</th>
<th>用户</th>
<th>状态</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($designs as $design):
$user_info = get_userdata($design->user_id);
$username = $user_info ? $user_info->display_name : '访客';
$design_data = json_decode($design->design_data, true);
?>
<tr>
<td><?php echo esc_html($design->id); ?></td>
<td>
<strong><?php echo esc_html($design->project_name); ?></strong>
<?php if (!empty($design_data['notes'])): ?>
<br><small><?php echo esc_html(substr($design_data['notes'], 0, 50)); ?>...</small>
<?php endif; ?>
</td>
<td><?php echo esc_html($username); ?></td>
<td>
<select class="ccd-status-select" data-design-id="<?php echo esc_attr($design->id); ?>">
<option value="draft" <?php selected($design->status, 'draft'); ?>>草稿</option>
<option value="active" <?php selected($design->status, 'active'); ?>>活跃</option>
<option value="completed" <?php selected($design->status, 'completed'); ?>>完成</option>
</select>
</td>
<td><?php echo esc_html(date('Y-m-d H:i', strtotime($design->created_at))); ?></td>
<td><?php echo esc_html(date('Y-m-d H:i', strtotime($design->updated_at))); ?></td>
<td>
<div class="ccd-action-buttons">
<button class="button button-small ccd-view-design"
data-design-id="<?php echo esc_attr($design->id); ?>">
查看详情
</button>
<button class="button button-small ccd-export-design"
data-design-id="<?php echo esc_attr($design->id); ?>">
导出
</button>
<button class="button button-small ccd-delete-design"
data-design-id="<?php echo esc_attr($design->id); ?>"
onclick="return confirm('确定要删除这个设计吗?')">
删除
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- 分页 -->
<div class="ccd-pagination">
<?php
$total_pages = ceil($total_items / $per_page);
$base_url = admin_url('admin.php?page=ccd-designs');
if ($total_pages > 1) {
echo paginate_links(array(
'base' => add_query_arg('paged', '%#%', $base_url),
'format' => '',
'prev_text' => '«',
'next_text' => '»',
'total' => $total_pages,
'current' => $current_page,
'add_args' => array(
'status' => $status_filter,
's' => $search_term
)
));
}
?>
</div>
<?php else: ?>
<p>没有找到匹配的设计。</p>
<?php endif; ?>
</div>
</div>
<?php
}
AJAX处理与数据保存
/**
* 保存设计AJAX回调
*/
public function save_design_callback() {
// 验证nonce
