文章目录
-
- 在数字化时代,线上研讨会已成为企业、教育机构和组织进行知识分享、产品发布和团队协作的重要方式。然而,许多WordPress网站所有者面临一个共同挑战:如何高效管理线上活动的预约流程和虚拟会议室?虽然市场上有一些插件可用,但它们往往功能有限、价格昂贵或不符合特定需求。 本教程将指导您通过WordPress代码二次开发,创建一个完整的线上研讨会预约与虚拟会议室管理系统。这个解决方案不仅成本效益高,而且完全可定制,能够满足您的特定需求。我们将从系统设计开始,逐步实现预约管理、虚拟会议室集成、自动通知和数据分析等功能。
-
- 在开始编码之前,我们需要明确系统需求: 预约管理功能:用户可查看 upcoming 研讨会,选择并注册参加 虚拟会议室集成:自动生成或连接Zoom、Google Meet等平台会议室 自动化工作流:注册确认、提醒邮件、会议链接发送 管理后台:活动创建、参与者管理、数据分析 用户界面:直观的前端展示和响应式设计
- 首先确保您的开发环境满足以下要求: WordPress 5.0以上版本 PHP 7.4以上版本 MySQL 5.6以上或MariaDB 10.0以上 代码编辑器(如VS Code、Sublime Text) 本地开发环境(如XAMPP、MAMP或Local by Flywheel)
- 为了避免主题更新导致代码丢失,我们将创建一个独立插件: 在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();
-
- 我们需要两个自定义表来存储研讨会和预约数据。在插件初始化类中添加以下代码: // 在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); } }
- 创建研讨会自定义帖子类型,使其在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); } }
-
- 为了让用户可以在任何页面添加预约界面,我们创建一个短代码: // 在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; } }
- 创建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>
在数字化时代,线上研讨会已成为企业、教育机构和组织进行知识分享、产品发布和团队协作的重要方式。然而,许多WordPress网站所有者面临一个共同挑战:如何高效管理线上活动的预约流程和虚拟会议室?虽然市场上有一些插件可用,但它们往往功能有限、价格昂贵或不符合特定需求。
本教程将指导您通过WordPress代码二次开发,创建一个完整的线上研讨会预约与虚拟会议室管理系统。这个解决方案不仅成本效益高,而且完全可定制,能够满足您的特定需求。我们将从系统设计开始,逐步实现预约管理、虚拟会议室集成、自动通知和数据分析等功能。
在开始编码之前,我们需要明确系统需求:
- 预约管理功能:用户可查看 upcoming 研讨会,选择并注册参加
- 虚拟会议室集成:自动生成或连接Zoom、Google Meet等平台会议室
- 自动化工作流:注册确认、提醒邮件、会议链接发送
- 管理后台:活动创建、参与者管理、数据分析
- 用户界面:直观的前端展示和响应式设计
首先确保您的开发环境满足以下要求:
- WordPress 5.0以上版本
- PHP 7.4以上版本
- MySQL 5.6以上或MariaDB 10.0以上
- 代码编辑器(如VS Code、Sublime Text)
- 本地开发环境(如XAMPP、MAMP或Local by Flywheel)
为了避免主题更新导致代码丢失,我们将创建一个独立插件:
- 在
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();
我们需要两个自定义表来存储研讨会和预约数据。在插件初始化类中添加以下代码:
// 在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);
}
}
创建研讨会自定义帖子类型,使其在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);
}
}
为了让用户可以在任何页面添加预约界面,我们创建一个短代码:
// 在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;
}
}
创建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>
我们将集成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')
));


