文章目录[隐藏]
详细教程:为WordPress网站开发线上研讨会预约与虚拟会议室管理系统
引言:线上活动管理的数字化需求
在数字化时代,线上研讨会已成为企业、教育机构和组织进行知识分享、产品发布和团队协作的重要方式。然而,许多WordPress网站所有者面临一个共同挑战:如何高效管理线上活动的预约流程和虚拟会议室?虽然市场上有一些插件可用,但它们往往功能有限、价格昂贵或不符合特定需求。
本教程将指导您通过WordPress代码二次开发,创建一个完整的线上研讨会预约与虚拟会议室管理系统。这个解决方案不仅成本效益高,而且完全可定制,能够满足您的特定需求。我们将从系统设计开始,逐步实现预约管理、虚拟会议室集成、自动通知和数据分析等功能。
第一部分:系统架构设计与环境准备
1.1 需求分析与功能规划
在开始编码之前,我们需要明确系统需求:
- 预约管理功能:用户可查看 upcoming 研讨会,选择并注册参加
- 虚拟会议室集成:自动生成或连接Zoom、Google Meet等平台会议室
- 自动化工作流:注册确认、提醒邮件、会议链接发送
- 管理后台:活动创建、参与者管理、数据分析
- 用户界面:直观的前端展示和响应式设计
1.2 开发环境配置
首先确保您的开发环境满足以下要求:
- WordPress 5.0以上版本
- PHP 7.4以上版本
- MySQL 5.6以上或MariaDB 10.0以上
- 代码编辑器(如VS Code、Sublime Text)
- 本地开发环境(如XAMPP、MAMP或Local by Flywheel)
1.3 创建自定义插件
为了避免主题更新导致代码丢失,我们将创建一个独立插件:
- 在
wp-content/plugins/目录下创建新文件夹virtual-seminar-manager - 创建主插件文件
virtual-seminar-manager.php:
<?php
/**
* Plugin Name: Virtual Seminar Manager
* Plugin URI: https://yourwebsite.com/
* Description: 完整的线上研讨会预约与虚拟会议室管理系统
* Version: 1.0.0
* Author: Your Name
* License: GPL v2 or later
* Text Domain: virtual-seminar
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('VSM_VERSION', '1.0.0');
define('VSM_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('VSM_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
require_once VSM_PLUGIN_DIR . 'includes/class-init.php';
VSM_Init::register_services();
第二部分:数据库设计与自定义帖子类型
2.1 创建数据库表
我们需要两个自定义表来存储研讨会和预约数据。在插件初始化类中添加以下代码:
// 在includes/class-init.php中
class VSM_Init {
public static function register_services() {
// 注册激活钩子
register_activation_hook(__FILE__, [self::class, 'activate']);
// 注册其他服务
add_action('init', [self::class, 'register_post_types']);
add_action('init', [self::class, 'register_taxonomies']);
}
public static function activate() {
self::create_tables();
flush_rewrite_rules();
}
private static function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 研讨会表
$seminars_table = $wpdb->prefix . 'vsm_seminars';
$sql1 = "CREATE TABLE IF NOT EXISTS $seminars_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
post_id bigint(20) NOT NULL,
start_time datetime NOT NULL,
end_time datetime NOT NULL,
max_participants int(11) DEFAULT 100,
current_participants int(11) DEFAULT 0,
meeting_platform varchar(50) DEFAULT 'zoom',
meeting_id varchar(255),
meeting_password varchar(100),
meeting_url text,
status varchar(20) DEFAULT 'scheduled',
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY post_id (post_id),
KEY start_time (start_time)
) $charset_collate;";
// 预约表
$bookings_table = $wpdb->prefix . 'vsm_bookings';
$sql2 = "CREATE TABLE IF NOT EXISTS $bookings_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
seminar_id mediumint(9) NOT NULL,
user_id bigint(20),
user_email varchar(100) NOT NULL,
user_name varchar(100) NOT NULL,
booking_time datetime DEFAULT CURRENT_TIMESTAMP,
confirmation_code varchar(32),
attendance_status varchar(20) DEFAULT 'registered',
join_time datetime,
leave_time datetime,
notes text,
PRIMARY KEY (id),
KEY seminar_id (seminar_id),
KEY user_email (user_email),
KEY confirmation_code (confirmation_code)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql1);
dbDelta($sql2);
}
}
2.2 注册自定义帖子类型
创建研讨会自定义帖子类型,使其在WordPress后台可管理:
// 在includes/class-post-types.php中
class VSM_Post_Types {
public static function register() {
// 注册研讨会帖子类型
$labels = array(
'name' => __('研讨会', 'virtual-seminar'),
'singular_name' => __('研讨会', 'virtual-seminar'),
'menu_name' => __('研讨会管理', 'virtual-seminar'),
'add_new' => __('添加新研讨会', 'virtual-seminar'),
'add_new_item' => __('添加新研讨会', 'virtual-seminar'),
'edit_item' => __('编辑研讨会', 'virtual-seminar'),
'new_item' => __('新研讨会', 'virtual-seminar'),
'view_item' => __('查看研讨会', 'virtual-seminar'),
'search_items' => __('搜索研讨会', 'virtual-seminar'),
'not_found' => __('未找到研讨会', 'virtual-seminar'),
'not_found_in_trash' => __('回收站中未找到研讨会', 'virtual-seminar')
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'seminar'),
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 25,
'menu_icon' => 'dashicons-video-alt3',
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
'show_in_rest' => true
);
register_post_type('seminar', $args);
}
}
第三部分:前端预约界面开发
3.1 创建预约短代码
为了让用户可以在任何页面添加预约界面,我们创建一个短代码:
// 在includes/class-shortcodes.php中
class VSM_Shortcodes {
public static function init() {
add_shortcode('seminar_booking', [self::class, 'seminar_booking_shortcode']);
add_shortcode('seminar_list', [self::class, 'seminar_list_shortcode']);
}
public static function seminar_booking_shortcode($atts) {
// 解析短代码属性
$atts = shortcode_atts(array(
'seminar_id' => 0,
'show_title' => 'yes'
), $atts, 'seminar_booking');
// 如果没有指定研讨会ID,尝试从当前页面获取
$seminar_id = $atts['seminar_id'];
if (!$seminar_id && get_post_type() === 'seminar') {
$seminar_id = get_the_ID();
}
if (!$seminar_id) {
return '<p class="vsm-error">' . __('未指定研讨会', 'virtual-seminar') . '</p>';
}
// 检查研讨会是否存在且可预约
$seminar_data = self::get_seminar_data($seminar_id);
if (!$seminar_data) {
return '<p class="vsm-error">' . __('研讨会不存在或已结束', 'virtual-seminar') . '</p>';
}
// 输出预约表单
ob_start();
include VSM_PLUGIN_DIR . 'templates/booking-form.php';
return ob_get_clean();
}
private static function get_seminar_data($post_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'vsm_seminars';
$seminar = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE post_id = %d AND status = 'scheduled'",
$post_id
));
if (!$seminar) {
return false;
}
// 检查是否还有空位
if ($seminar->current_participants >= $seminar->max_participants) {
return false;
}
return $seminar;
}
}
3.2 设计预约表单模板
创建templates/booking-form.php模板文件:
<?php
/**
* 研讨会预约表单模板
*/
// 确保从短代码中调用
if (!isset($seminar_data)) {
return;
}
// 获取帖子信息
$post = get_post($seminar_data->post_id);
$title = $post->post_title;
$excerpt = $post->post_excerpt;
$thumbnail = get_the_post_thumbnail($post->ID, 'medium');
// 格式化时间
$start_time = date_i18n('Y年m月d日 H:i', strtotime($seminar_data->start_time));
$end_time = date_i18n('H:i', strtotime($seminar_data->end_time));
$remaining = $seminar_data->max_participants - $seminar_data->current_participants;
// 处理表单提交
$submitted = false;
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['vsm_booking_nonce'])) {
if (wp_verify_nonce($_POST['vsm_booking_nonce'], 'vsm_booking_action')) {
$result = VSM_Booking_Handler::process_booking($_POST, $seminar_data);
if ($result['success']) {
$success = $result['message'];
$submitted = true;
} else {
$error = $result['message'];
}
}
}
?>
<div class="vsm-booking-container">
<?php if ($atts['show_title'] === 'yes') : ?>
<div class="vsm-seminar-header">
<?php if ($thumbnail) : ?>
<div class="vsm-thumbnail">
<?php echo $thumbnail; ?>
</div>
<?php endif; ?>
<h2 class="vsm-title"><?php echo esc_html($title); ?></h2>
<?php if ($excerpt) : ?>
<div class="vsm-excerpt">
<?php echo wpautop($excerpt); ?>
</div>
<?php endif; ?>
<div class="vsm-meta">
<div class="vsm-meta-item">
<span class="dashicons dashicons-calendar-alt"></span>
<span><?php echo $start_time . ' - ' . $end_time; ?></span>
</div>
<div class="vsm-meta-item">
<span class="dashicons dashicons-groups"></span>
<span><?php printf(__('剩余席位: %d/%d', 'virtual-seminar'), $remaining, $seminar_data->max_participants); ?></span>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($success) : ?>
<div class="vsm-alert vsm-success">
<?php echo $success; ?>
</div>
<?php elseif (!$submitted) : ?>
<?php if ($error) : ?>
<div class="vsm-alert vsm-error">
<?php echo $error; ?>
</div>
<?php endif; ?>
<form id="vsm-booking-form" method="post" class="vsm-booking-form">
<?php wp_nonce_field('vsm_booking_action', 'vsm_booking_nonce'); ?>
<input type="hidden" name="seminar_id" value="<?php echo $seminar_data->id; ?>">
<input type="hidden" name="post_id" value="<?php echo $seminar_data->post_id; ?>">
<div class="vsm-form-group">
<label for="vsm_user_name"><?php _e('姓名', 'virtual-seminar'); ?> *</label>
<input type="text" id="vsm_user_name" name="user_name" required
placeholder="<?php _e('请输入您的姓名', 'virtual-seminar'); ?>">
</div>
<div class="vsm-form-group">
<label for="vsm_user_email"><?php _e('电子邮箱', 'virtual-seminar'); ?> *</label>
<input type="email" id="vsm_user_email" name="user_email" required
placeholder="<?php _e('请输入您的邮箱地址', 'virtual-seminar'); ?>">
<small class="vsm-help-text"><?php _e('会议链接将发送到此邮箱', 'virtual-seminar'); ?></small>
</div>
<div class="vsm-form-group">
<label for="vsm_user_phone"><?php _e('手机号码', 'virtual-seminar'); ?></label>
<input type="tel" id="vsm_user_phone" name="user_phone"
placeholder="<?php _e('请输入您的手机号码', 'virtual-seminar'); ?>">
</div>
<div class="vsm-form-group">
<label for="vsm_user_company"><?php _e('公司/机构', 'virtual-seminar'); ?></label>
<input type="text" id="vsm_user_company" name="user_company"
placeholder="<?php _e('请输入您的公司或机构名称', 'virtual-seminar'); ?>">
</div>
<div class="vsm-form-group">
<label for="vsm_notes"><?php _e('备注或问题', 'virtual-seminar'); ?></label>
<textarea id="vsm_notes" name="notes" rows="3"
placeholder="<?php _e('如有特殊需求或问题,请在此说明', 'virtual-seminar'); ?>"></textarea>
</div>
<div class="vsm-form-group vsm-consent">
<input type="checkbox" id="vsm_consent" name="consent" required>
<label for="vsm_consent">
<?php _e('我同意接收关于此研讨会的通知和后续信息', 'virtual-seminar'); ?>
</label>
</div>
<div class="vsm-form-submit">
<button type="submit" class="vsm-submit-btn">
<?php _e('立即预约', 'virtual-seminar'); ?>
</button>
</div>
</form>
<?php endif; ?>
</div>
第四部分:虚拟会议室集成
4.1 Zoom API集成
我们将集成Zoom API来自动创建会议室。首先创建Zoom API处理类:
// 在includes/class-zoom-integration.php中
class VSM_Zoom_Integration {
private $api_key;
private $api_secret;
private $account_id; // JWT应用需要
private $client_id; // OAuth应用需要
private $client_secret; // OAuth应用需要
private $access_token;
public function __construct() {
$options = get_option('vsm_zoom_settings');
$this->api_key = $options['api_key'] ?? '';
$this->api_secret = $options['api_secret'] ?? '';
$this->account_id = $options['account_id'] ?? '';
$this->client_id = $options['client_id'] ?? '';
$this->client_secret = $options['client_secret'] ?? '';
// 获取或刷新访问令牌
$this->access_token = $this->get_access_token();
}
/**
* 获取OAuth访问令牌
*/
private function get_access_token() {
$token_data = get_transient('vsm_zoom_access_token');
if (!$token_data) {
// 使用OAuth 2.0获取新令牌
$response = wp_remote_post('https://zoom.us/oauth/token', [
'headers' => [
'Authorization' => 'Basic ' . base64_encode($this->client_id . ':' . $this->client_secret),
'Content-Type' => 'application/x-www-form-urlencoded'
],
'body' => [
'grant_type' => 'account_credentials',
'account_id' => $this->account_id
]
]);
if (!is_wp_error($response)) {
$body = json_decode(wp_remote_retrieve_body($response));
if (isset($body->access_token)) {
$token_data = $body->access_token;
// 令牌通常有效1小时,我们设置55分钟过期
set_transient('vsm_zoom_access_token', $token_data, 55 * MINUTE_IN_SECONDS);
}
}
}
return $token_data;
}
/**
* 创建Zoom会议
*/
public function create_meeting($seminar_data) {
/v2/users/me/meetings', [
'headers' => [
'Authorization' => 'Bearer ' . $this->access_token,
'Content-Type' => 'application/json'
],
'body' => json_encode([
'topic' => $seminar_data['title'],
'type' => 2, // 预定会议
'start_time' => $seminar_data['start_time'],
'duration' => $seminar_data['duration'],
'timezone' => wp_timezone_string(),
'password' => wp_generate_password(6, false), // 生成随机密码
'settings' => [
'host_video' => true,
'participant_video' => true,
'join_before_host' => false,
'mute_upon_entry' => true,
'waiting_room' => true,
'auto_recording' => 'cloud' // 可选:none, local, cloud
]
])
]);
if (is_wp_error($response)) {
return [
'success' => false,
'error' => $response->get_error_message()
];
}
$body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($body['code'])) {
return [
'success' => false,
'error' => $body['message']
];
}
return [
'success' => true,
'meeting_id' => $body['id'],
'meeting_password' => $body['password'],
'join_url' => $body['join_url'],
'start_url' => $body['start_url'] // 主持人链接
];
}
/**
* 更新Zoom会议
*/
public function update_meeting($meeting_id, $data) {
$response = wp_remote_request("https://api.zoom.us/v2/meetings/{$meeting_id}", [
'method' => 'PATCH',
'headers' => [
'Authorization' => 'Bearer ' . $this->access_token,
'Content-Type' => 'application/json'
],
'body' => json_encode($data)
]);
return !is_wp_error($response);
}
/**
* 删除Zoom会议
*/
public function delete_meeting($meeting_id) {
$response = wp_remote_request("https://api.zoom.us/v2/meetings/{$meeting_id}", [
'method' => 'DELETE',
'headers' => [
'Authorization' => 'Bearer ' . $this->access_token
]
]);
return !is_wp_error($response);
}
}
### 4.2 Google Meet集成(替代方案)
// 在includes/class-google-meet-integration.php中
class VSM_Google_Meet_Integration {
private $client;
private $service;
public function __construct() {
$this->init_client();
}
private function init_client() {
require_once VSM_PLUGIN_DIR . 'vendor/autoload.php'; // 需要Google API客户端库
$options = get_option('vsm_google_settings');
$credentials = $options['credentials'] ?? '';
if (!$credentials) {
return false;
}
try {
$this->client = new Google_Client();
$this->client->setApplicationName('Virtual Seminar Manager');
$this->client->setAuthConfig(json_decode($credentials, true));
$this->client->addScope(Google_Service_Calendar::CALENDAR);
// 检查是否有存储的令牌
$token_path = VSM_PLUGIN_DIR . 'tokens/google-token.json';
if (file_exists($token_path)) {
$access_token = json_decode(file_get_contents($token_path), true);
$this->client->setAccessToken($access_token);
}
// 如果令牌过期,刷新它
if ($this->client->isAccessTokenExpired()) {
if ($this->client->getRefreshToken()) {
$this->client->fetchAccessTokenWithRefreshToken();
file_put_contents($token_path, json_encode($this->client->getAccessToken()));
}
}
$this->service = new Google_Service_Calendar($this->client);
return true;
} catch (Exception $e) {
error_log('Google Meet初始化失败: ' . $e->getMessage());
return false;
}
}
/**
* 创建Google Calendar事件并生成Meet链接
*/
public function create_meeting($seminar_data) {
if (!$this->service) {
return [
'success' => false,
'error' => 'Google服务未初始化'
];
}
try {
// 创建日历事件
$event = new Google_Service_Calendar_Event([
'summary' => $seminar_data['title'],
'description' => $seminar_data['description'],
'start' => [
'dateTime' => $seminar_data['start_time'],
'timeZone' => wp_timezone_string(),
],
'end' => [
'dateTime' => $seminar_data['end_time'],
'timeZone' => wp_timezone_string(),
],
'conferenceData' => [
'createRequest' => [
'requestId' => uniqid(),
'conferenceSolutionKey' => [
'type' => 'hangoutsMeet'
]
]
],
'attendees' => [
['email' => $seminar_data['organizer_email']]
],
'reminders' => [
'useDefault' => false,
'overrides' => [
['method' => 'email', 'minutes' => 24 * 60], // 提前1天
['method' => 'popup', 'minutes' => 30] // 提前30分钟
]
]
]);
$created_event = $this->service->events->insert('primary', $event, [
'conferenceDataVersion' => 1
]);
return [
'success' => true,
'meeting_id' => $created_event->getId(),
'join_url' => $created_event->getHangoutLink(),
'html_link' => $created_event->getHtmlLink()
];
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
}
## 第五部分:预约处理与数据库操作
### 5.1 预约处理类
// 在includes/class-booking-handler.php中
class VSM_Booking_Handler {
public static function process_booking($data, $seminar_data) {
global $wpdb;
// 验证数据
$validation = self::validate_booking_data($data);
if (!$validation['valid']) {
return [
'success' => false,
'message' => $validation['message']
];
}
// 检查是否已预约
$bookings_table = $wpdb->prefix . 'vsm_bookings';
$existing_booking = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $bookings_table
WHERE seminar_id = %d AND user_email = %s",
$seminar_data->id,
sanitize_email($data['user_email'])
));
if ($existing_booking > 0) {
return [
'success' => false,
'message' => __('您已经预约了此研讨会', 'virtual-seminar')
];
}
// 检查是否还有空位
if ($seminar_data->current_participants >= $seminar_data->max_participants) {
return [
'success' => false,
'message' => __('研讨会名额已满', 'virtual-seminar')
];
}
// 生成确认码
$confirmation_code = wp_generate_password(12, false);
// 插入预约记录
$insert_result = $wpdb->insert(
$bookings_table,
[
'seminar_id' => $seminar_data->id,
'user_id' => is_user_logged_in() ? get_current_user_id() : 0,
'user_email' => sanitize_email($data['user_email']),
'user_name' => sanitize_text_field($data['user_name']),
'confirmation_code' => $confirmation_code,
'notes' => sanitize_textarea_field($data['notes'] ?? '')
],
['%d', '%d', '%s', '%s', '%s', '%s']
);
if (!$insert_result) {
return [
'success' => false,
'message' => __('预约失败,请稍后重试', 'virtual-seminar')
];
}
$booking_id = $wpdb->insert_id;
// 更新研讨会参与人数
$seminars_table = $wpdb->prefix . 'vsm_seminars';
$wpdb->update(
$seminars_table,
['current_participants' => $seminar_data->current_participants + 1],
['id' => $seminar_data->id],
['%d'],
['%d']
);
// 发送确认邮件
self::send_confirmation_email($booking_id, $confirmation_code, $seminar_data, $data);
// 发送给管理员的通知
self::send_admin_notification($booking_id, $seminar_data, $data);
return [
'success' => true,
'message' => __('预约成功!确认邮件已发送到您的邮箱。', 'virtual-seminar'),
'booking_id' => $booking_id,
'confirmation_code' => $confirmation_code
];
}
private static function validate_booking_data($data) {
// 验证必填字段
$required_fields = ['user_name', 'user_email', 'seminar_id'];
foreach ($required_fields as $field) {
if (empty($data[$field])) {
return [
'valid' => false,
'message' => __('请填写所有必填字段', 'virtual-seminar')
];
}
}
// 验证邮箱格式
if (!is_email($data['user_email'])) {
return [
'valid' => false,
'message' => __('请输入有效的邮箱地址', 'virtual-seminar')
];
}
// 验证同意条款
if (!isset($data['consent']) || $data['consent'] !== 'on') {
return [
'valid' => false,
'message' => __('请同意接收研讨会相关信息', 'virtual-seminar')
];
}
return ['valid' => true];
}
private static function send_confirmation_email($booking_id, $confirmation_code, $seminar_data, $user_data) {
$post = get_post($seminar_data->post_id);
$start_time = date_i18n('Y年m月d日 H:i', strtotime($seminar_data->start_time));
$to = $user_data['user_email'];
$subject = sprintf(__('研讨会预约确认: %s', 'virtual-seminar'), $post->post_title);
// 构建邮件内容
$message = sprintf(__('尊敬的 %s,', 'virtual-seminar'), $user_data['user_name']) . "nn";
$message .= sprintf(__('您已成功预约研讨会: %s', 'virtual-seminar'), $post->post_title) . "n";
$message .= sprintf(__('时间: %s', 'virtual-seminar'), $start_time) . "nn";
// 如果有会议链接,添加到邮件中
if (!empty($seminar_data->meeting_url)) {
$message .= __('会议链接: ', 'virtual-seminar') . $seminar_data->meeting_url . "n";
if (!empty($seminar_data->meeting_password)) {
$message .= __('会议密码: ', 'virtual-seminar') . $seminar_data->meeting_password . "n";
}
} else {
$message .= __('会议链接将在研讨会开始前发送给您。', 'virtual-seminar') . "n";
}
$message .= "n" . __('您的预约确认码: ', 'virtual-seminar') . $confirmation_code . "n";
$message .= __('如需取消预约,请访问: ', 'virtual-seminar') . home_url('/cancel-booking/?code=' . $confirmation_code) . "nn";
$message .= __('感谢您的参与!', 'virtual-seminar') . "n";
$message .= get_bloginfo('name');
// 设置邮件头
$headers = ['Content-Type: text/plain; charset=UTF-8'];
// 发送邮件
wp_mail($to, $subject, $message, $headers);
// 记录邮件发送日志
self::log_email_sent($booking_id, 'confirmation', $to);
}
private static function send_admin_notification($booking_id, $seminar_data, $user_data) {
$admin_email = get_option('admin_email');
$post = get_post($seminar_data->post_id);
$subject = sprintf(__('新研讨会预约: %s', 'virtual-seminar'), $post->post_title);
$message = sprintf(__('有新的研讨会预约:', 'virtual-seminar')) . "nn";
$message .= sprintf(__('研讨会: %s', 'virtual-seminar'), $post->post_title) . "n";
$message .= sprintf(__('预约人: %s', 'virtual-seminar'), $user_data['user_name']) . "n";
$message .= sprintf(__('邮箱: %s', 'virtual-seminar'), $user_data['user_email']) . "n";
$message .= sprintf(__('预约时间: %s', 'virtual-seminar'), current_time('mysql')) . "n";
$message .= sprintf(__('预约ID: %d', 'virtual-seminar'), $booking_id) . "nn";
if (!empty($user_data['user_phone'])) {
$message .= sprintf(__('电话: %s', 'virtual-seminar'), $user_data['user_phone']) . "n";
}
if (!empty($user_data['user_company'])) {
$message .= sprintf(__('公司: %s', 'virtual-seminar'), $user_data['user_company']) . "n";
}
if (!empty($user_data['notes'])) {
$message .= sprintf(__('备注: %s', 'virtual-seminar'), $user_data['notes']) . "n";
}
$message .= "n" . __('查看所有预约: ', 'virtual-seminar') . admin_url('admin.php?page=vsm-bookings&seminar_id=' . $seminar_data->id);
wp_mail($admin_email, $subject, $message);
}
private static function log_email_sent($booking_id, $type, $recipient) {
global $wpdb;
$table_name = $wpdb->prefix . 'vsm_email_logs';
$wpdb->insert(
$table_name,
[
'booking_id' => $booking_id,
'email_type' => $type,
'recipient' => $recipient,
'sent_at' => current_time('mysql')
],
['%d', '%s', '%s', '%s']
);
}
}
## 第六部分:后台管理界面
### 6.1 创建管理菜单
// 在includes/class-admin.php中
class VSM_Admin {
public static function init() {
add_action('admin_menu', [self::class, 'add_admin_menu']);
add_action('admin_enqueue_scripts', [self::class, 'enqueue_admin_scripts']);
add_action('add_meta_boxes', [self::class, 'add_seminar_meta_boxes']);
add_action('save_post_seminar', [self::class, 'save_seminar_meta'], 10, 2);
}
public static function add_admin_menu() {
// 主菜单
add_menu_page(
__('研讨会管理', 'virtual-seminar'),
__('研讨会管理', 'virtual-seminar'),
'manage_options',
'vsm-dashboard',
[self::class, 'render_dashboard'],
'dashicons-video-alt3',
30
);
// 子菜单
add_submenu_page(
'vsm-dashboard',
__('所有预约', 'virtual-seminar'),
__('所有预约', 'virtual-seminar'),
'manage_options',
'vsm-bookings',
[self::class, 'render_bookings_page']
);
add_submenu_page(
'vsm-dashboard',
__('设置', 'virtual-seminar'),
__('设置', 'virtual-seminar'),
'manage_options',
'vsm-settings',
[self::class, 'render_settings_page']
);
add_submenu_page(
'vsm-dashboard',
__('报告', 'virtual-seminar'),
__('报告', 'virtual-seminar'),
'manage_options',
'vsm-reports',
[self::class, 'render_reports_page']
);
}
public static function render_dashboard() {
global $wpdb;
// 获取统计数据
$seminars_table = $wpdb->prefix . 'vsm_seminars';
$bookings_table = $wpdb->prefix . 'vsm_bookings';
$total_seminars = $wpdb->get_var("SELECT COUNT(*) FROM $seminars_table");
$upcoming_seminars = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $seminars_table WHERE start_time > %s",
current_time('mysql')
));
$total_bookings = $wpdb->get_var("SELECT COUNT(*) FROM $bookings_table");
$today_bookings = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $bookings_table WHERE DATE(booking_time) = %s",
current_time('Y-m-d')
));
