文章目录
-
- 在当今数字化时代,网站功能多样化已成为吸引用户、提升用户体验的关键因素。WordPress作为全球最受欢迎的内容管理系统,其强大的可扩展性为开发者提供了无限可能。通过插件开发,我们可以在不修改核心代码的前提下,为网站添加各种定制化功能。 本教程将详细讲解如何开发一个集活动日历与票务验票核销系统于一体的WordPress插件。这个插件不仅可以帮助网站管理者轻松发布和管理活动,还能实现电子票务的生成、验证和核销功能,适用于各类活动主办方、会议组织者和票务销售平台。
-
- 在开始开发之前,我们需要准备以下环境: 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel WordPress安装:最新版本的WordPress(建议5.6以上) 代码编辑器:VS Code、PHPStorm或Sublime Text 浏览器开发者工具:用于调试前端代码
- 首先,在WordPress的wp-content/plugins目录下创建一个新文件夹,命名为event-ticket-system。在该文件夹中创建以下基础文件: event-ticket-system/ ├── event-ticket-system.php (主插件文件) ├── includes/ │ ├── class-database.php (数据库处理类) │ ├── class-events.php (活动管理类) │ ├── class-tickets.php (票务管理类) │ └── class-checkin.php (验票核销类) ├── admin/ │ ├── css/ (后台样式) │ ├── js/ (后台脚本) │ └── admin-pages.php (后台页面) ├── public/ │ ├── css/ (前端样式) │ ├── js/ (前端脚本) │ └── shortcodes.php (短代码处理) ├── templates/ (模板文件) ├── assets/ (静态资源) └── languages/ (国际化文件)
- 打开event-ticket-system.php文件,添加以下基础代码: <?php /** * Plugin Name: 活动日历与票务系统 * Plugin URI: https://yourwebsite.com/event-ticket-system * Description: 一个完整的活动日历与电子票务验票核销系统 * Version: 1.0.0 * Author: 你的名字 * Author URI: https://yourwebsite.com * License: GPL v2 or later * Text Domain: event-ticket-system * Domain Path: /languages */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('ETS_VERSION', '1.0.0'); define('ETS_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('ETS_PLUGIN_URL', plugin_dir_url(__FILE__)); define('ETS_PLUGIN_BASENAME', plugin_basename(__FILE__)); // 自动加载类文件 spl_autoload_register(function ($class_name) { $prefix = 'ETS_'; $base_dir = ETS_PLUGIN_DIR . 'includes/'; $len = strlen($prefix); if (strncmp($prefix, $class_name, $len) !== 0) { return; } $relative_class = substr($class_name, $len); $file = $base_dir . 'class-' . strtolower(str_replace('_', '-', $relative_class)) . '.php'; if (file_exists($file)) { require_once $file; } }); // 初始化插件 function ets_init_plugin() { // 检查依赖 if (!function_exists('register_post_type')) { add_action('admin_notices', function() { echo '<div class="notice notice-error"><p>活动票务系统需要WordPress 5.0或更高版本。</p></div>'; }); return; } // 初始化数据库 ETS_Database::init(); // 初始化其他组件 if (is_admin()) { require_once ETS_PLUGIN_DIR . 'admin/admin-pages.php'; } // 加载前端功能 require_once ETS_PLUGIN_DIR . 'public/shortcodes.php'; // 加载文本域 load_plugin_textdomain('event-ticket-system', false, dirname(ETS_PLUGIN_BASENAME) . '/languages'); } add_action('plugins_loaded', 'ets_init_plugin'); // 激活插件时执行的操作 function ets_activate_plugin() { require_once ETS_PLUGIN_DIR . 'includes/class-database.php'; ETS_Database::create_tables(); // 设置默认选项 add_option('ets_version', ETS_VERSION); add_option('ets_currency', 'CNY'); add_option('ets_timezone', 'Asia/Shanghai'); // 刷新重写规则 flush_rewrite_rules(); } register_activation_hook(__FILE__, 'ets_activate_plugin'); // 停用插件时执行的操作 function ets_deactivate_plugin() { // 清理临时数据 // 注意:这里不删除数据表,以防数据丢失 flush_rewrite_rules(); } register_deactivation_hook(__FILE__, 'ets_deactivate_plugin');
-
- 在includes/class-database.php中,我们创建数据库表: <?php class ETS_Database { public static function init() { // 确保数据库表存在 self::create_tables(); } public static function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $table_prefix = $wpdb->prefix . 'ets_'; // 活动表 $events_table = $table_prefix . 'events'; $events_sql = "CREATE TABLE IF NOT EXISTS $events_table ( id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, post_id bigint(20) UNSIGNED NOT NULL, title varchar(255) NOT NULL, description text, start_date datetime NOT NULL, end_date datetime NOT NULL, venue varchar(255), address text, capacity int(11) DEFAULT 0, booked int(11) DEFAULT 0, price decimal(10,2) DEFAULT 0.00, currency varchar(10) DEFAULT 'CNY', 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 post_id (post_id), KEY start_date (start_date), KEY status (status) ) $charset_collate;"; // 票务表 $tickets_table = $table_prefix . 'tickets'; $tickets_sql = "CREATE TABLE IF NOT EXISTS $tickets_table ( id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, event_id bigint(20) UNSIGNED NOT NULL, ticket_number varchar(100) NOT NULL, attendee_name varchar(255) NOT NULL, attendee_email varchar(255) NOT NULL, attendee_phone varchar(50), quantity int(11) DEFAULT 1, total_price decimal(10,2) DEFAULT 0.00, payment_status varchar(20) DEFAULT 'pending', payment_method varchar(50), transaction_id varchar(100), checkin_status tinyint(1) DEFAULT 0, checkin_time datetime, checkin_by bigint(20) UNSIGNED, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY ticket_number (ticket_number), KEY event_id (event_id), KEY attendee_email (attendee_email), KEY checkin_status (checkin_status) ) $charset_collate;"; // 票务类型表 $ticket_types_table = $table_prefix . 'ticket_types'; $ticket_types_sql = "CREATE TABLE IF NOT EXISTS $ticket_types_table ( id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, event_id bigint(20) UNSIGNED NOT NULL, name varchar(255) NOT NULL, description text, price decimal(10,2) NOT NULL, quantity int(11) DEFAULT 0, sold int(11) DEFAULT 0, sale_start datetime, sale_end datetime, status varchar(20) DEFAULT 'active', created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY event_id (event_id), KEY status (status) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($events_sql); dbDelta($tickets_sql); dbDelta($ticket_types_sql); } }
- 在includes/class-events.php中创建活动管理类: <?php class ETS_Events { public function __construct() { add_action('init', array($this, 'register_event_post_type')); add_action('add_meta_boxes', array($this, 'add_event_meta_boxes')); add_action('save_post', array($this, 'save_event_meta_data')); add_filter('manage_event_posts_columns', array($this, 'add_event_columns')); add_action('manage_event_posts_custom_column', array($this, 'manage_event_columns'), 10, 2); } // 注册自定义文章类型:活动 public function register_event_post_type() { $labels = array( 'name' => __('活动', 'event-ticket-system'), 'singular_name' => __('活动', 'event-ticket-system'), 'menu_name' => __('活动管理', 'event-ticket-system'), 'add_new' => __('添加活动', 'event-ticket-system'), 'add_new_item' => __('添加新活动', 'event-ticket-system'), 'edit_item' => __('编辑活动', 'event-ticket-system'), 'new_item' => __('新活动', 'event-ticket-system'), 'view_item' => __('查看活动', 'event-ticket-system'), 'search_items' => __('搜索活动', 'event-ticket-system'), 'not_found' => __('未找到活动', 'event-ticket-system'), 'not_found_in_trash' => __('回收站中无活动', 'event-ticket-system'), ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'show_in_menu' => true, 'query_var' => true, 'rewrite' => array('slug' => 'event'), 'capability_type' => 'post', 'has_archive' => true, 'hierarchical' => false, 'menu_position' => 5, 'menu_icon' => 'dashicons-calendar-alt', 'supports' => array('title', 'editor', 'thumbnail', 'excerpt'), 'show_in_rest' => true, ); register_post_type('event', $args); // 注册活动分类 $category_labels = array( 'name' => __('活动分类', 'event-ticket-system'), 'singular_name' => __('活动分类', 'event-ticket-system'), 'search_items' => __('搜索分类', 'event-ticket-system'), 'all_items' => __('所有分类', 'event-ticket-system'), 'parent_item' => __('父分类', 'event-ticket-system'), 'parent_item_colon' => __('父分类:', 'event-ticket-system'), 'edit_item' => __('编辑分类', 'event-ticket-system'), 'update_item' => __('更新分类', 'event-ticket-system'), 'add_new_item' => __('添加新分类', 'event-ticket-system'), 'new_item_name' => __('新分类名称', 'event-ticket-system'), 'menu_name' => __('活动分类', 'event-ticket-system'), ); register_taxonomy('event_category', 'event', array( 'labels' => $category_labels, 'hierarchical' => true, 'public' => true, 'show_ui' => true, 'show_admin_column' => true, 'show_in_rest' => true, 'query_var' => true, 'rewrite' => array('slug' => 'event-category'), )); } // 添加活动元数据框 public function add_event_meta_boxes() { add_meta_box( 'event_details', __('活动详情', 'event-ticket-system'), array($this, 'render_event_details_meta_box'), 'event', 'normal', 'high' ); add_meta_box( 'ticket_settings', __('票务设置', 'event-ticket-system'), array($this, 'render_ticket_settings_meta_box'), 'event', 'normal', 'high' ); } // 渲染活动详情元数据框 public function render_event_details_meta_box($post) { wp_nonce_field('event_details_nonce', 'event_details_nonce_field'); $start_date = get_post_meta($post->ID, '_event_start_date', true); $end_date = get_post_meta($post->ID, '_event_end_date', true); $venue = get_post_meta($post->ID, '_event_venue', true); $address = get_post_meta($post->ID, '_event_address', true); $capacity = get_post_meta($post->ID, '_event_capacity', true); ?> <div class="event-details-container"> <table class="form-table"> <tr> <th><label for="event_start_date"><?php _e('开始时间', 'event-ticket-system'); ?></label></th> <td> <input type="datetime-local" id="event_start_date" name="event_start_date" value="<?php echo esc_attr($start_date); ?>" class="regular-text" required> </td> </tr> <tr> <th><label for="event_end_date"><?php _e('结束时间', 'event-ticket-system'); ?></label></th> <td> <input type="datetime-local" id="event_end_date" name="event_end_date" value="<?php echo esc_attr($end_date); ?>" class="regular-text" required> </td> </tr> <tr> <th><label for="event_venue"><?php _e('活动地点', 'event-ticket-system'); ?></label></th> <td> <input type="text" id="event_venue" name="event_venue" value="<?php echo esc_attr($venue); ?>" class="regular-text"> </td> </tr> <tr> <th><label for="event_address"><?php _e('详细地址', 'event-ticket-system'); ?></label></th> <td> <textarea id="event_address" name="event_address" rows="3" class="large-text"><?php echo esc_textarea($address); ?></textarea> </td> </tr> <tr> <th><label for="event_capacity"><?php _e('活动容量', 'event-ticket-system'); ?></label></th> <td> <input type="number" id="event_capacity" name="event_capacity" value="<?php echo esc_attr($capacity); ?>" min="0" class="small-text"> <p class="description"><?php _e('0表示无限制', 'event-ticket-system'); ?></p> </td> </tr> </table> </div> <?php } // 保存活动元数据 public function save_event_meta_data($post_id) { if (!isset($_POST['event_details_nonce_field']) || !wp_verify_nonce($_POST['event_details_nonce_field'], 'event_details_nonce')) { return; } if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (!current_user_can('edit_post', $post_id)) { return; } $fields = array( 'event_start_date', 'event_end_date', 'event_venue', 'event_address', 'event_capacity' ); foreach ($fields as $field) { if (isset($_POST[$field])) { update_post_meta($post_id, '_' . $field, sanitize_text_field($_POST[$field])); } } // 同步到自定义数据库表 $this->sync_event_to_custom_table($post_id); } // 同步活动数据到自定义表 private function sync_event_to_custom_table($post_id) { global $wpdb; $post = get_post($post_id); if ($post->post_type !== 'event') { return; } $table_name = $wpdb->prefix . 'ets_events'; $event_data = array( 'post_id' => $post_id, 'title' => $post->post_title, 'description' => $post->post_content, 'start_date' => get_post_meta($post_id, '_event_start_date', true),
-
- 在includes/class-tickets.php中创建票务管理类: <?php class ETS_Tickets { private $db; public function __construct() { global $wpdb; $this->db = $wpdb; add_action('wp_ajax_ets_purchase_ticket', array($this, 'handle_ticket_purchase')); add_action('wp_ajax_nopriv_ets_purchase_ticket', array($this, 'handle_ticket_purchase')); add_action('wp_ajax_ets_generate_ticket', array($this, 'generate_ticket')); add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts')); } // 生成唯一票号 public function generate_ticket_number($event_id) { $prefix = 'TICKET'; $timestamp = time(); $random = mt_rand(1000, 9999); return $prefix . '-' . $event_id . '-' . $timestamp . '-' . $random; } // 处理购票请求 public function handle_ticket_purchase() { // 验证nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'ets_ticket_nonce')) { wp_send_json_error(array('message' => __('安全验证失败', 'event-ticket-system'))); } // 验证必填字段 $required_fields = array('event_id', 'ticket_type_id', 'attendee_name', 'attendee_email', 'quantity'); foreach ($required_fields as $field) { if (empty($_POST[$field])) { wp_send_json_error(array('message' => sprintf(__('缺少必填字段: %s', 'event-ticket-system'), $field))); } } $event_id = intval($_POST['event_id']); $ticket_type_id = intval($_POST['ticket_type_id']); $attendee_name = sanitize_text_field($_POST['attendee_name']); $attendee_email = sanitize_email($_POST['attendee_email']); $attendee_phone = isset($_POST['attendee_phone']) ? sanitize_text_field($_POST['attendee_phone']) : ''; $quantity = intval($_POST['quantity']); $payment_method = isset($_POST['payment_method']) ? sanitize_text_field($_POST['payment_method']) : 'online'; // 检查活动是否存在 $event = $this->get_event($event_id); if (!$event) { wp_send_json_error(array('message' => __('活动不存在', 'event-ticket-system'))); } // 检查票务类型 $ticket_type = $this->get_ticket_type($ticket_type_id); if (!$ticket_type || $ticket_type->event_id != $event_id) { wp_send_json_error(array('message' => __('票务类型无效', 'event-ticket-system'))); } // 检查余票 if ($ticket_type->quantity > 0 && ($ticket_type->sold + $quantity) > $ticket_type->quantity) { wp_send_json_error(array('message' => __('余票不足', 'event-ticket-system'))); } // 计算总价 $total_price = $ticket_type->price * $quantity; // 开始事务 $this->db->query('START TRANSACTION'); try { // 更新已售数量 $update_result = $this->db->update( $this->db->prefix . 'ets_ticket_types', array('sold' => $ticket_type->sold + $quantity), array('id' => $ticket_type_id), array('%d'), array('%d') ); if (!$update_result) { throw new Exception(__('更新票务数据失败', 'event-ticket-system')); } // 创建票务记录 $ticket_data = array(); for ($i = 0; $i < $quantity; $i++) { $ticket_number = $this->generate_ticket_number($event_id); $ticket_data[] = array( 'event_id' => $event_id, 'ticket_type_id' => $ticket_type_id, 'ticket_number' => $ticket_number, 'attendee_name' => $attendee_name, 'attendee_email' => $attendee_email, 'attendee_phone' => $attendee_phone, 'quantity' => 1, 'total_price' => $ticket_type->price, 'payment_status' => 'pending', 'payment_method' => $payment_method, 'created_at' => current_time('mysql') ); } // 批量插入票务记录 foreach ($ticket_data as $data) { $insert_result = $this->db->insert( $this->db->prefix . 'ets_tickets', $data, array('%d', '%d', '%s', '%s', '%s', '%s', '%d', '%f', '%s', '%s', '%s') ); if (!$insert_result) { throw new Exception(__('创建票务记录失败', 'event-ticket-system')); } $ticket_id = $this->db->insert_id; // 发送确认邮件 $this->send_ticket_confirmation_email($ticket_id, $data['ticket_number']); } // 提交事务 $this->db->query('COMMIT'); // 返回成功响应 wp_send_json_success(array( 'message' => __('购票成功!请查收确认邮件。', 'event-ticket-system'), 'ticket_numbers' => array_column($ticket_data, 'ticket_number') )); } catch (Exception $e) { // 回滚事务 $this->db->query('ROLLBACK'); wp_send_json_error(array('message' => $e->getMessage())); } } // 发送票务确认邮件 private function send_ticket_confirmation_email($ticket_id, $ticket_number) { $ticket = $this->get_ticket_by_number($ticket_number); if (!$ticket) { return false; } $event = $this->get_event($ticket->event_id); $attendee_email = $ticket->attendee_email; $subject = sprintf(__('【%s】活动票务确认', 'event-ticket-system'), get_bloginfo('name')); $message = sprintf(__('尊敬的 %s:', 'event-ticket-system'), $ticket->attendee_name) . "nn"; $message .= __('感谢您购买活动票务,以下是您的票务信息:', 'event-ticket-system') . "nn"; $message .= __('活动名称:', 'event-ticket-system') . $event->title . "n"; $message .= __('活动时间:', 'event-ticket-system') . $event->start_date . "n"; $message .= __('活动地点:', 'event-ticket-system') . $event->venue . "n"; $message .= __('票务号码:', 'event-ticket-system') . $ticket->ticket_number . "n"; $message .= __('购票数量:', 'event-ticket-system') . $ticket->quantity . "n"; $message .= __('总金额:', 'event-ticket-system') . $ticket->total_price . ' ' . $event->currency . "nn"; $message .= __('验票二维码:', 'event-ticket-system') . "n"; $message .= site_url('/check-ticket?code=' . urlencode($ticket->ticket_number)) . "nn"; $message .= __('注意事项:', 'event-ticket-system') . "n"; $message .= __('1. 请妥善保管此邮件,活动当天凭票务二维码入场', 'event-ticket-system') . "n"; $message .= __('2. 如需退票,请在活动开始前24小时联系客服', 'event-ticket-system') . "n"; $message .= __('3. 如有疑问,请回复此邮件咨询', 'event-ticket-system') . "nn"; $message .= __('祝您活动愉快!', 'event-ticket-system') . "n"; $message .= get_bloginfo('name') . "n"; $message .= date('Y-m-d'); $headers = array('Content-Type: text/plain; charset=UTF-8'); return wp_mail($attendee_email, $subject, $message, $headers); } // 获取活动信息 private function get_event($event_id) { $table_name = $this->db->prefix . 'ets_events'; return $this->db->get_row($this->db->prepare( "SELECT * FROM $table_name WHERE id = %d", $event_id )); } // 获取票务类型 private function get_ticket_type($ticket_type_id) { $table_name = $this->db->prefix . 'ets_ticket_types'; return $this->db->get_row($this->db->prepare( "SELECT * FROM $table_name WHERE id = %d", $ticket_type_id )); } // 根据票号获取票务信息 private function get_ticket_by_number($ticket_number) { $table_name = $this->db->prefix . 'ets_tickets'; return $this->db->get_row($this->db->prepare( "SELECT * FROM $table_name WHERE ticket_number = %s", $ticket_number )); } // 加载前端脚本 public function enqueue_frontend_scripts() { if (is_singular('event')) { wp_enqueue_script( 'ets-ticket-script', ETS_PLUGIN_URL . 'public/js/ticket-purchase.js', array('jquery'), ETS_VERSION, true ); wp_localize_script('ets-ticket-script', 'ets_ajax', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('ets_ticket_nonce') )); wp_enqueue_style( 'ets-ticket-style', ETS_PLUGIN_URL . 'public/css/ticket-style.css', array(), ETS_VERSION ); } } }
- 在includes/class-checkin.php中创建验票核销类: <?php class ETS_Checkin { private $db; public function __construct() { global $wpdb; $this->db = $wpdb; add_action('admin_menu', array($this, 'add_checkin_page')); add_action('wp_ajax_ets_check_ticket', array($this, 'check_ticket')); add_action('wp_ajax_ets_validate_ticket', array($this, 'validate_ticket')); add_action('init', array($this, 'register_checkin_shortcode')); } // 添加验票管理页面 public function add_checkin_page() { add_submenu_page( 'edit.php?post_type=event', __('验票核销', 'event-ticket-system'), __('验票核销', 'event-ticket-system'), 'manage_options', 'event-checkin', array($this, 'render_checkin_page') ); } // 渲染验票页面 public function render_checkin_page() { ?> <div class="wrap"> <h1><?php _e('活动票务验票核销系统', 'event-ticket-system'); ?></h1> <div class="checkin-container"> <div class="checkin-scanner"> <h2><?php _e('扫码验票', 'event-ticket-system'); ?></h2> <div id="qr-scanner" style="width: 400px; height: 300px; margin: 20px 0;"> <!-- QR扫码器将在这里渲染 --> </div> <div class="manual-checkin"> <h3><?php _e('手动输入票号', 'event-ticket-system'); ?></h3> <input type="text" id="manual-ticket-number" placeholder="<?php _e('输入票务号码', 'event-ticket-system'); ?>" style="width: 300px;"> <button id="manual-check-btn" class="button button-primary"><?php _e('验证', 'event-ticket-system'); ?></button> </div> </div> <div class="checkin-results"> <h2><?php _e('验票结果', 'event-ticket-system'); ?></h2> <div id="checkin-result" style="padding: 20px; border: 1px solid #ddd; min-height: 200px;"> <?php _e('等待验票...', 'event-ticket-system'); ?> </div> <div class="checkin-stats"> <h3><?php _e('今日统计', 'event-ticket-system'); ?></h3> <?php $this->display_daily_stats(); ?> </div> </div> </div> <div class="recent-checkins"> <h2><?php _e('最近验票记录', 'event-ticket-system'); ?></h2> <?php $this->display_recent_checkins(); ?> </div> </div> <script> jQuery(document).ready(function($) { // 初始化QR扫码器 initQRScanner(); // 手动验票 $('#manual-check-btn').click(function() { var ticketNumber = $('#manual-ticket-number').val(); if (ticketNumber) { validateTicket(ticketNumber); } }); // 回车键触发验票 $('#manual-ticket-number').keypress(function(e) { if (e.which == 13) { $('#manual-check-btn').click(); } }); }); function initQRScanner() { // 这里可以集成第三方QR扫码库,如Html5Qrcode console.log('QR扫码器初始化'); } function validateTicket(ticketNumber) { jQuery.ajax({ url: ajaxurl, type: 'POST', data: { action: 'ets_validate_ticket', ticket_number: ticketNumber, nonce: '<?php echo wp_create_nonce("ets_checkin_nonce"); ?>' }, success: function(response) { if (response.success) { $('#checkin-result').html(response.data.message); if (response.data.checked_in) { $('#checkin-result').addClass('success').removeClass('error'); } else { $('#checkin-result').addClass('error').removeClass('success'); } } else { $('#checkin-result').html(response.data).addClass('error'); } } }); } </script> <style> .checkin-container { display: flex; gap: 30px; margin: 20px 0; } .checkin-scanner { flex: 1; } .checkin-results { flex: 1; } .success { background-color: #d4edda; border-color: #c3e6cb; color: #155724; } .error { background-color: #f8d7da; border-color: #f5c6cb; color: #721c24; } </style> <?php } // 验证票务 public function validate_ticket() { // 验证nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'ets_checkin_nonce')) { wp_send_json_error(__('安全验证失败', 'event-ticket-system')); } $ticket_number = sanitize_text_field($_POST['ticket_number']); if (empty($ticket_number)) { wp_send_json_error(__('请输入票务号码', 'event-ticket-system')); } // 查询票务信息 $ticket = $this->get_ticket_details($ticket_number); if (!$ticket) { wp_send_json_error(__('票务号码无效', 'event-ticket-system')); } // 检查是否已验票 if ($ticket->checkin_status) { $message = sprintf( __('该票务已于 %s 验票通过<br>验票人员:%s', 'event-ticket-system'), $ticket->checkin_time, get_userdata($ticket->checkin_by)->display_name ); wp_send_json_success(array( 'message' => $message, 'checked_in' => true, 'ticket' => $ticket )); } // 检查活动是否已开始 $event = $this->get_event($ticket->event_id); $current_time = current_time('mysql'); if (strtotime($current_time) < strtotime($event->start_date)) { wp_send_json_error(__('活动尚未开始', 'event-ticket-system')); } // 执行验票 $result = $this->perform_checkin($ticket->id); if ($result) { $message = sprintf( __('验票成功!<br>票务号码:%s<br>参会人:%s<br>验票时间:%s', 'event-ticket-system'), $ticket->ticket_number, $ticket->attendee_name, current_time('mysql') ); wp_send_json_success(array( 'message' => $message, 'checked_in' => false,
在当今数字化时代,网站功能多样化已成为吸引用户、提升用户体验的关键因素。WordPress作为全球最受欢迎的内容管理系统,其强大的可扩展性为开发者提供了无限可能。通过插件开发,我们可以在不修改核心代码的前提下,为网站添加各种定制化功能。
本教程将详细讲解如何开发一个集活动日历与票务验票核销系统于一体的WordPress插件。这个插件不仅可以帮助网站管理者轻松发布和管理活动,还能实现电子票务的生成、验证和核销功能,适用于各类活动主办方、会议组织者和票务销售平台。
在开始开发之前,我们需要准备以下环境:
- 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
- WordPress安装:最新版本的WordPress(建议5.6以上)
- 代码编辑器:VS Code、PHPStorm或Sublime Text
- 浏览器开发者工具:用于调试前端代码
首先,在WordPress的wp-content/plugins目录下创建一个新文件夹,命名为event-ticket-system。在该文件夹中创建以下基础文件:
event-ticket-system/
├── event-ticket-system.php (主插件文件)
├── includes/
│ ├── class-database.php (数据库处理类)
│ ├── class-events.php (活动管理类)
│ ├── class-tickets.php (票务管理类)
│ └── class-checkin.php (验票核销类)
├── admin/
│ ├── css/ (后台样式)
│ ├── js/ (后台脚本)
│ └── admin-pages.php (后台页面)
├── public/
│ ├── css/ (前端样式)
│ ├── js/ (前端脚本)
│ └── shortcodes.php (短代码处理)
├── templates/ (模板文件)
├── assets/ (静态资源)
└── languages/ (国际化文件)
打开event-ticket-system.php文件,添加以下基础代码:
<?php
/**
* Plugin Name: 活动日历与票务系统
* Plugin URI: https://yourwebsite.com/event-ticket-system
* Description: 一个完整的活动日历与电子票务验票核销系统
* Version: 1.0.0
* Author: 你的名字
* Author URI: https://yourwebsite.com
* License: GPL v2 or later
* Text Domain: event-ticket-system
* Domain Path: /languages
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('ETS_VERSION', '1.0.0');
define('ETS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('ETS_PLUGIN_URL', plugin_dir_url(__FILE__));
define('ETS_PLUGIN_BASENAME', plugin_basename(__FILE__));
// 自动加载类文件
spl_autoload_register(function ($class_name) {
$prefix = 'ETS_';
$base_dir = ETS_PLUGIN_DIR . 'includes/';
$len = strlen($prefix);
if (strncmp($prefix, $class_name, $len) !== 0) {
return;
}
$relative_class = substr($class_name, $len);
$file = $base_dir . 'class-' . strtolower(str_replace('_', '-', $relative_class)) . '.php';
if (file_exists($file)) {
require_once $file;
}
});
// 初始化插件
function ets_init_plugin() {
// 检查依赖
if (!function_exists('register_post_type')) {
add_action('admin_notices', function() {
echo '<div class="notice notice-error"><p>活动票务系统需要WordPress 5.0或更高版本。</p></div>';
});
return;
}
// 初始化数据库
ETS_Database::init();
// 初始化其他组件
if (is_admin()) {
require_once ETS_PLUGIN_DIR . 'admin/admin-pages.php';
}
// 加载前端功能
require_once ETS_PLUGIN_DIR . 'public/shortcodes.php';
// 加载文本域
load_plugin_textdomain('event-ticket-system', false, dirname(ETS_PLUGIN_BASENAME) . '/languages');
}
add_action('plugins_loaded', 'ets_init_plugin');
// 激活插件时执行的操作
function ets_activate_plugin() {
require_once ETS_PLUGIN_DIR . 'includes/class-database.php';
ETS_Database::create_tables();
// 设置默认选项
add_option('ets_version', ETS_VERSION);
add_option('ets_currency', 'CNY');
add_option('ets_timezone', 'Asia/Shanghai');
// 刷新重写规则
flush_rewrite_rules();
}
register_activation_hook(__FILE__, 'ets_activate_plugin');
// 停用插件时执行的操作
function ets_deactivate_plugin() {
// 清理临时数据
// 注意:这里不删除数据表,以防数据丢失
flush_rewrite_rules();
}
register_deactivation_hook(__FILE__, 'ets_deactivate_plugin');
在includes/class-database.php中,我们创建数据库表:
<?php
class ETS_Database {
public static function init() {
// 确保数据库表存在
self::create_tables();
}
public static function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_prefix = $wpdb->prefix . 'ets_';
// 活动表
$events_table = $table_prefix . 'events';
$events_sql = "CREATE TABLE IF NOT EXISTS $events_table (
id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
post_id bigint(20) UNSIGNED NOT NULL,
title varchar(255) NOT NULL,
description text,
start_date datetime NOT NULL,
end_date datetime NOT NULL,
venue varchar(255),
address text,
capacity int(11) DEFAULT 0,
booked int(11) DEFAULT 0,
price decimal(10,2) DEFAULT 0.00,
currency varchar(10) DEFAULT 'CNY',
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 post_id (post_id),
KEY start_date (start_date),
KEY status (status)
) $charset_collate;";
// 票务表
$tickets_table = $table_prefix . 'tickets';
$tickets_sql = "CREATE TABLE IF NOT EXISTS $tickets_table (
id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
event_id bigint(20) UNSIGNED NOT NULL,
ticket_number varchar(100) NOT NULL,
attendee_name varchar(255) NOT NULL,
attendee_email varchar(255) NOT NULL,
attendee_phone varchar(50),
quantity int(11) DEFAULT 1,
total_price decimal(10,2) DEFAULT 0.00,
payment_status varchar(20) DEFAULT 'pending',
payment_method varchar(50),
transaction_id varchar(100),
checkin_status tinyint(1) DEFAULT 0,
checkin_time datetime,
checkin_by bigint(20) UNSIGNED,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY ticket_number (ticket_number),
KEY event_id (event_id),
KEY attendee_email (attendee_email),
KEY checkin_status (checkin_status)
) $charset_collate;";
// 票务类型表
$ticket_types_table = $table_prefix . 'ticket_types';
$ticket_types_sql = "CREATE TABLE IF NOT EXISTS $ticket_types_table (
id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
event_id bigint(20) UNSIGNED NOT NULL,
name varchar(255) NOT NULL,
description text,
price decimal(10,2) NOT NULL,
quantity int(11) DEFAULT 0,
sold int(11) DEFAULT 0,
sale_start datetime,
sale_end datetime,
status varchar(20) DEFAULT 'active',
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY event_id (event_id),
KEY status (status)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($events_sql);
dbDelta($tickets_sql);
dbDelta($ticket_types_sql);
}
}
在includes/class-events.php中创建活动管理类:
<?php
class ETS_Events {
public function __construct() {
add_action('init', array($this, 'register_event_post_type'));
add_action('add_meta_boxes', array($this, 'add_event_meta_boxes'));
add_action('save_post', array($this, 'save_event_meta_data'));
add_filter('manage_event_posts_columns', array($this, 'add_event_columns'));
add_action('manage_event_posts_custom_column', array($this, 'manage_event_columns'), 10, 2);
}
// 注册自定义文章类型:活动
public function register_event_post_type() {
$labels = array(
'name' => __('活动', 'event-ticket-system'),
'singular_name' => __('活动', 'event-ticket-system'),
'menu_name' => __('活动管理', 'event-ticket-system'),
'add_new' => __('添加活动', 'event-ticket-system'),
'add_new_item' => __('添加新活动', 'event-ticket-system'),
'edit_item' => __('编辑活动', 'event-ticket-system'),
'new_item' => __('新活动', 'event-ticket-system'),
'view_item' => __('查看活动', 'event-ticket-system'),
'search_items' => __('搜索活动', 'event-ticket-system'),
'not_found' => __('未找到活动', 'event-ticket-system'),
'not_found_in_trash' => __('回收站中无活动', 'event-ticket-system'),
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'event'),
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 5,
'menu_icon' => 'dashicons-calendar-alt',
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
'show_in_rest' => true,
);
register_post_type('event', $args);
// 注册活动分类
$category_labels = array(
'name' => __('活动分类', 'event-ticket-system'),
'singular_name' => __('活动分类', 'event-ticket-system'),
'search_items' => __('搜索分类', 'event-ticket-system'),
'all_items' => __('所有分类', 'event-ticket-system'),
'parent_item' => __('父分类', 'event-ticket-system'),
'parent_item_colon' => __('父分类:', 'event-ticket-system'),
'edit_item' => __('编辑分类', 'event-ticket-system'),
'update_item' => __('更新分类', 'event-ticket-system'),
'add_new_item' => __('添加新分类', 'event-ticket-system'),
'new_item_name' => __('新分类名称', 'event-ticket-system'),
'menu_name' => __('活动分类', 'event-ticket-system'),
);
register_taxonomy('event_category', 'event', array(
'labels' => $category_labels,
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_rest' => true,
'query_var' => true,
'rewrite' => array('slug' => 'event-category'),
));
}
// 添加活动元数据框
public function add_event_meta_boxes() {
add_meta_box(
'event_details',
__('活动详情', 'event-ticket-system'),
array($this, 'render_event_details_meta_box'),
'event',
'normal',
'high'
);
add_meta_box(
'ticket_settings',
__('票务设置', 'event-ticket-system'),
array($this, 'render_ticket_settings_meta_box'),
'event',
'normal',
'high'
);
}
// 渲染活动详情元数据框
public function render_event_details_meta_box($post) {
wp_nonce_field('event_details_nonce', 'event_details_nonce_field');
$start_date = get_post_meta($post->ID, '_event_start_date', true);
$end_date = get_post_meta($post->ID, '_event_end_date', true);
$venue = get_post_meta($post->ID, '_event_venue', true);
$address = get_post_meta($post->ID, '_event_address', true);
$capacity = get_post_meta($post->ID, '_event_capacity', true);
?>
<div class="event-details-container">
<table class="form-table">
<tr>
<th><label for="event_start_date"><?php _e('开始时间', 'event-ticket-system'); ?></label></th>
<td>
<input type="datetime-local" id="event_start_date" name="event_start_date"
value="<?php echo esc_attr($start_date); ?>" class="regular-text" required>
</td>
</tr>
<tr>
<th><label for="event_end_date"><?php _e('结束时间', 'event-ticket-system'); ?></label></th>
<td>
<input type="datetime-local" id="event_end_date" name="event_end_date"
value="<?php echo esc_attr($end_date); ?>" class="regular-text" required>
</td>
</tr>
<tr>
<th><label for="event_venue"><?php _e('活动地点', 'event-ticket-system'); ?></label></th>
<td>
<input type="text" id="event_venue" name="event_venue"
value="<?php echo esc_attr($venue); ?>" class="regular-text">
</td>
</tr>
<tr>
<th><label for="event_address"><?php _e('详细地址', 'event-ticket-system'); ?></label></th>
<td>
<textarea id="event_address" name="event_address" rows="3" class="large-text"><?php echo esc_textarea($address); ?></textarea>
</td>
</tr>
<tr>
<th><label for="event_capacity"><?php _e('活动容量', 'event-ticket-system'); ?></label></th>
<td>
<input type="number" id="event_capacity" name="event_capacity"
value="<?php echo esc_attr($capacity); ?>" min="0" class="small-text">
<p class="description"><?php _e('0表示无限制', 'event-ticket-system'); ?></p>
</td>
</tr>
</table>
</div>
<?php
}
// 保存活动元数据
public function save_event_meta_data($post_id) {
if (!isset($_POST['event_details_nonce_field']) ||
!wp_verify_nonce($_POST['event_details_nonce_field'], 'event_details_nonce')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
$fields = array(
'event_start_date',
'event_end_date',
'event_venue',
'event_address',
'event_capacity'
);
foreach ($fields as $field) {
if (isset($_POST[$field])) {
update_post_meta($post_id, '_' . $field, sanitize_text_field($_POST[$field]));
}
}
// 同步到自定义数据库表
$this->sync_event_to_custom_table($post_id);
}
// 同步活动数据到自定义表
private function sync_event_to_custom_table($post_id) {
global $wpdb;
$post = get_post($post_id);
if ($post->post_type !== 'event') {
return;
}
$table_name = $wpdb->prefix . 'ets_events';
$event_data = array(
'post_id' => $post_id,
'title' => $post->post_title,
'description' => $post->post_content,
'start_date' => get_post_meta($post_id, '_event_start_date', true),
在includes/class-tickets.php中创建票务管理类:
<?php
class ETS_Tickets {
private $db;
public function __construct() {
global $wpdb;
$this->db = $wpdb;
add_action('wp_ajax_ets_purchase_ticket', array($this, 'handle_ticket_purchase'));
add_action('wp_ajax_nopriv_ets_purchase_ticket', array($this, 'handle_ticket_purchase'));
add_action('wp_ajax_ets_generate_ticket', array($this, 'generate_ticket'));
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts'));
}
// 生成唯一票号
public function generate_ticket_number($event_id) {
$prefix = 'TICKET';
$timestamp = time();
$random = mt_rand(1000, 9999);
return $prefix . '-' . $event_id . '-' . $timestamp . '-' . $random;
}
// 处理购票请求
public function handle_ticket_purchase() {
// 验证nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'ets_ticket_nonce')) {
wp_send_json_error(array('message' => __('安全验证失败', 'event-ticket-system')));
}
// 验证必填字段
$required_fields = array('event_id', 'ticket_type_id', 'attendee_name', 'attendee_email', 'quantity');
foreach ($required_fields as $field) {
if (empty($_POST[$field])) {
wp_send_json_error(array('message' => sprintf(__('缺少必填字段: %s', 'event-ticket-system'), $field)));
}
}
$event_id = intval($_POST['event_id']);
$ticket_type_id = intval($_POST['ticket_type_id']);
$attendee_name = sanitize_text_field($_POST['attendee_name']);
$attendee_email = sanitize_email($_POST['attendee_email']);
$attendee_phone = isset($_POST['attendee_phone']) ? sanitize_text_field($_POST['attendee_phone']) : '';
$quantity = intval($_POST['quantity']);
$payment_method = isset($_POST['payment_method']) ? sanitize_text_field($_POST['payment_method']) : 'online';
// 检查活动是否存在
$event = $this->get_event($event_id);
if (!$event) {
wp_send_json_error(array('message' => __('活动不存在', 'event-ticket-system')));
}
// 检查票务类型
$ticket_type = $this->get_ticket_type($ticket_type_id);
if (!$ticket_type || $ticket_type->event_id != $event_id) {
wp_send_json_error(array('message' => __('票务类型无效', 'event-ticket-system')));
}
// 检查余票
if ($ticket_type->quantity > 0 && ($ticket_type->sold + $quantity) > $ticket_type->quantity) {
wp_send_json_error(array('message' => __('余票不足', 'event-ticket-system')));
}
// 计算总价
$total_price = $ticket_type->price * $quantity;
// 开始事务
$this->db->query('START TRANSACTION');
try {
// 更新已售数量
$update_result = $this->db->update(
$this->db->prefix . 'ets_ticket_types',
array('sold' => $ticket_type->sold + $quantity),
array('id' => $ticket_type_id),
array('%d'),
array('%d')
);
if (!$update_result) {
throw new Exception(__('更新票务数据失败', 'event-ticket-system'));
}
// 创建票务记录
$ticket_data = array();
for ($i = 0; $i < $quantity; $i++) {
$ticket_number = $this->generate_ticket_number($event_id);
$ticket_data[] = array(
'event_id' => $event_id,
'ticket_type_id' => $ticket_type_id,
'ticket_number' => $ticket_number,
'attendee_name' => $attendee_name,
'attendee_email' => $attendee_email,
'attendee_phone' => $attendee_phone,
'quantity' => 1,
'total_price' => $ticket_type->price,
'payment_status' => 'pending',
'payment_method' => $payment_method,
'created_at' => current_time('mysql')
);
}
// 批量插入票务记录
foreach ($ticket_data as $data) {
$insert_result = $this->db->insert(
$this->db->prefix . 'ets_tickets',
$data,
array('%d', '%d', '%s', '%s', '%s', '%s', '%d', '%f', '%s', '%s', '%s')
);
if (!$insert_result) {
throw new Exception(__('创建票务记录失败', 'event-ticket-system'));
}
$ticket_id = $this->db->insert_id;
// 发送确认邮件
$this->send_ticket_confirmation_email($ticket_id, $data['ticket_number']);
}
// 提交事务
$this->db->query('COMMIT');
// 返回成功响应
wp_send_json_success(array(
'message' => __('购票成功!请查收确认邮件。', 'event-ticket-system'),
'ticket_numbers' => array_column($ticket_data, 'ticket_number')
));
} catch (Exception $e) {
// 回滚事务
$this->db->query('ROLLBACK');
wp_send_json_error(array('message' => $e->getMessage()));
}
}
// 发送票务确认邮件
private function send_ticket_confirmation_email($ticket_id, $ticket_number) {
$ticket = $this->get_ticket_by_number($ticket_number);
if (!$ticket) {
return false;
}
$event = $this->get_event($ticket->event_id);
$attendee_email = $ticket->attendee_email;
$subject = sprintf(__('【%s】活动票务确认', 'event-ticket-system'), get_bloginfo('name'));
$message = sprintf(__('尊敬的 %s:', 'event-ticket-system'), $ticket->attendee_name) . "nn";
$message .= __('感谢您购买活动票务,以下是您的票务信息:', 'event-ticket-system') . "nn";
$message .= __('活动名称:', 'event-ticket-system') . $event->title . "n";
$message .= __('活动时间:', 'event-ticket-system') . $event->start_date . "n";
$message .= __('活动地点:', 'event-ticket-system') . $event->venue . "n";
$message .= __('票务号码:', 'event-ticket-system') . $ticket->ticket_number . "n";
$message .= __('购票数量:', 'event-ticket-system') . $ticket->quantity . "n";
$message .= __('总金额:', 'event-ticket-system') . $ticket->total_price . ' ' . $event->currency . "nn";
$message .= __('验票二维码:', 'event-ticket-system') . "n";
$message .= site_url('/check-ticket?code=' . urlencode($ticket->ticket_number)) . "nn";
$message .= __('注意事项:', 'event-ticket-system') . "n";
$message .= __('1. 请妥善保管此邮件,活动当天凭票务二维码入场', 'event-ticket-system') . "n";
$message .= __('2. 如需退票,请在活动开始前24小时联系客服', 'event-ticket-system') . "n";
$message .= __('3. 如有疑问,请回复此邮件咨询', 'event-ticket-system') . "nn";
$message .= __('祝您活动愉快!', 'event-ticket-system') . "n";
$message .= get_bloginfo('name') . "n";
$message .= date('Y-m-d');
$headers = array('Content-Type: text/plain; charset=UTF-8');
return wp_mail($attendee_email, $subject, $message, $headers);
}
// 获取活动信息
private function get_event($event_id) {
$table_name = $this->db->prefix . 'ets_events';
return $this->db->get_row($this->db->prepare(
"SELECT * FROM $table_name WHERE id = %d",
$event_id
));
}
// 获取票务类型
private function get_ticket_type($ticket_type_id) {
$table_name = $this->db->prefix . 'ets_ticket_types';
return $this->db->get_row($this->db->prepare(
"SELECT * FROM $table_name WHERE id = %d",
$ticket_type_id
));
}
// 根据票号获取票务信息
private function get_ticket_by_number($ticket_number) {
$table_name = $this->db->prefix . 'ets_tickets';
return $this->db->get_row($this->db->prepare(
"SELECT * FROM $table_name WHERE ticket_number = %s",
$ticket_number
));
}
// 加载前端脚本
public function enqueue_frontend_scripts() {
if (is_singular('event')) {
wp_enqueue_script(
'ets-ticket-script',
ETS_PLUGIN_URL . 'public/js/ticket-purchase.js',
array('jquery'),
ETS_VERSION,
true
);
wp_localize_script('ets-ticket-script', 'ets_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ets_ticket_nonce')
));
wp_enqueue_style(
'ets-ticket-style',
ETS_PLUGIN_URL . 'public/css/ticket-style.css',
array(),
ETS_VERSION
);
}
}
}
在includes/class-checkin.php中创建验票核销类:
<?php
class ETS_Checkin {
private $db;
public function __construct() {
global $wpdb;
$this->db = $wpdb;
add_action('admin_menu', array($this, 'add_checkin_page'));
add_action('wp_ajax_ets_check_ticket', array($this, 'check_ticket'));
add_action('wp_ajax_ets_validate_ticket', array($this, 'validate_ticket'));
add_action('init', array($this, 'register_checkin_shortcode'));
}
// 添加验票管理页面
public function add_checkin_page() {
add_submenu_page(
'edit.php?post_type=event',
__('验票核销', 'event-ticket-system'),
__('验票核销', 'event-ticket-system'),
'manage_options',
'event-checkin',
array($this, 'render_checkin_page')
);
}
// 渲染验票页面
public function render_checkin_page() {
?>
<div class="wrap">
<h1><?php _e('活动票务验票核销系统', 'event-ticket-system'); ?></h1>
<div class="checkin-container">
<div class="checkin-scanner">
<h2><?php _e('扫码验票', 'event-ticket-system'); ?></h2>
<div id="qr-scanner" style="width: 400px; height: 300px; margin: 20px 0;">
<!-- QR扫码器将在这里渲染 -->
</div>
<div class="manual-checkin">
<h3><?php _e('手动输入票号', 'event-ticket-system'); ?></h3>
<input type="text" id="manual-ticket-number" placeholder="<?php _e('输入票务号码', 'event-ticket-system'); ?>" style="width: 300px;">
<button id="manual-check-btn" class="button button-primary"><?php _e('验证', 'event-ticket-system'); ?></button>
</div>
</div>
<div class="checkin-results">
<h2><?php _e('验票结果', 'event-ticket-system'); ?></h2>
<div id="checkin-result" style="padding: 20px; border: 1px solid #ddd; min-height: 200px;">
<?php _e('等待验票...', 'event-ticket-system'); ?>
</div>
<div class="checkin-stats">
<h3><?php _e('今日统计', 'event-ticket-system'); ?></h3>
<?php $this->display_daily_stats(); ?>
</div>
</div>
</div>
<div class="recent-checkins">
<h2><?php _e('最近验票记录', 'event-ticket-system'); ?></h2>
<?php $this->display_recent_checkins(); ?>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// 初始化QR扫码器
initQRScanner();
// 手动验票
$('#manual-check-btn').click(function() {
var ticketNumber = $('#manual-ticket-number').val();
if (ticketNumber) {
validateTicket(ticketNumber);
}
});
// 回车键触发验票
$('#manual-ticket-number').keypress(function(e) {
if (e.which == 13) {
$('#manual-check-btn').click();
}
});
});
function initQRScanner() {
// 这里可以集成第三方QR扫码库,如Html5Qrcode
console.log('QR扫码器初始化');
}
function validateTicket(ticketNumber) {
jQuery.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'ets_validate_ticket',
ticket_number: ticketNumber,
nonce: '<?php echo wp_create_nonce("ets_checkin_nonce"); ?>'
},
success: function(response) {
if (response.success) {
$('#checkin-result').html(response.data.message);
if (response.data.checked_in) {
$('#checkin-result').addClass('success').removeClass('error');
} else {
$('#checkin-result').addClass('error').removeClass('success');
}
} else {
$('#checkin-result').html(response.data).addClass('error');
}
}
});
}
</script>
<style>
.checkin-container {
display: flex;
gap: 30px;
margin: 20px 0;
}
.checkin-scanner {
flex: 1;
}
.checkin-results {
flex: 1;
}
.success {
background-color: #d4edda;
border-color: #c3e6cb;
color: #155724;
}
.error {
background-color: #f8d7da;
border-color: #f5c6cb;
color: #721c24;
}
</style>
<?php
}
// 验证票务
public function validate_ticket() {
// 验证nonce
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'ets_checkin_nonce')) {
wp_send_json_error(__('安全验证失败', 'event-ticket-system'));
}
$ticket_number = sanitize_text_field($_POST['ticket_number']);
if (empty($ticket_number)) {
wp_send_json_error(__('请输入票务号码', 'event-ticket-system'));
}
// 查询票务信息
$ticket = $this->get_ticket_details($ticket_number);
if (!$ticket) {
wp_send_json_error(__('票务号码无效', 'event-ticket-system'));
}
// 检查是否已验票
if ($ticket->checkin_status) {
$message = sprintf(
__('该票务已于 %s 验票通过<br>验票人员:%s', 'event-ticket-system'),
$ticket->checkin_time,
get_userdata($ticket->checkin_by)->display_name
);
wp_send_json_success(array(
'message' => $message,
'checked_in' => true,
'ticket' => $ticket
));
}
// 检查活动是否已开始
$event = $this->get_event($ticket->event_id);
$current_time = current_time('mysql');
if (strtotime($current_time) < strtotime($event->start_date)) {
wp_send_json_error(__('活动尚未开始', 'event-ticket-system'));
}
// 执行验票
$result = $this->perform_checkin($ticket->id);
if ($result) {
$message = sprintf(
__('验票成功!<br>票务号码:%s<br>参会人:%s<br>验票时间:%s', 'event-ticket-system'),
$ticket->ticket_number,
$ticket->attendee_name,
current_time('mysql')
);
wp_send_json_success(array(
'message' => $message,
'checked_in' => false,


