文章目录[隐藏]
实战教程:为你的网站集成在线预约与日程管理
引言:为什么网站需要在线预约与日程管理功能
在数字化时代,用户体验已成为网站成功的关键因素之一。无论是服务型企业、医疗机构、教育机构还是自由职业者,能够提供便捷的在线预约功能,不仅能显著提升客户满意度,还能大幅提高工作效率。想象一下,一位潜在客户访问您的网站,对您的服务感兴趣,却需要打电话或发邮件才能预约,这种额外的步骤可能导致客户流失。
WordPress作为全球最流行的内容管理系统,拥有超过40%的网站市场份额。其强大的可扩展性使得我们可以通过代码二次开发,为网站添加各种实用功能。本教程将详细指导您如何为WordPress网站集成在线预约与日程管理功能,无需依赖昂贵的第三方插件,完全自主控制数据与用户体验。
第一部分:准备工作与环境搭建
1.1 开发环境要求
在开始之前,请确保您的开发环境满足以下要求:
- WordPress 5.0或更高版本
- PHP 7.4或更高版本(推荐PHP 8.0+)
- MySQL 5.6或更高版本
- 基本的HTML、CSS、JavaScript知识
- 对WordPress主题开发有一定了解
1.2 创建开发用子主题
为了避免直接修改主题文件导致更新时丢失更改,我们首先创建一个子主题:
- 在WordPress的
wp-content/themes/目录下创建新文件夹,命名为my-custom-booking-theme - 在该文件夹中创建
style.css文件,添加以下内容:
/*
Theme Name: 我的预约主题
Template: twentytwentythree
Version: 1.0
Description: 用于在线预约功能的子主题
*/
/* 在这里添加自定义样式 */
- 创建
functions.php文件,用于添加自定义功能:
<?php
// 子主题的functions.php文件
// 添加父主题样式表
add_action('wp_enqueue_scripts', 'my_theme_enqueue_styles');
function my_theme_enqueue_styles() {
wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');
wp_enqueue_style('child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'));
}
// 在这里添加自定义功能
?>
- 在WordPress后台激活这个子主题。
1.3 安装必要的开发工具
为了高效开发,建议安装以下工具:
- 代码编辑器(如VS Code、Sublime Text等)
- 本地开发环境(如XAMPP、MAMP或Local by Flywheel)
- 浏览器开发者工具
- Git版本控制系统(可选但推荐)
第二部分:数据库设计与数据模型
2.1 设计预约数据表结构
我们需要创建自定义数据库表来存储预约信息。在WordPress中,我们可以使用dbDelta()函数来创建和更新表结构。
在子主题的functions.php文件中添加以下代码:
// 创建预约数据表
function create_booking_tables() {
global $wpdb;
$table_name = $wpdb->prefix . 'bookings';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
customer_name varchar(100) NOT NULL,
customer_email varchar(100) NOT NULL,
customer_phone varchar(20),
service_type varchar(100) NOT NULL,
booking_date date NOT NULL,
booking_time time NOT NULL,
duration int NOT NULL DEFAULT 60,
status varchar(20) DEFAULT 'pending',
notes text,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY booking_date (booking_date),
KEY status (status)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 创建服务类型表
$services_table = $wpdb->prefix . 'booking_services';
$services_sql = "CREATE TABLE $services_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
service_name varchar(100) NOT NULL,
description text,
duration int NOT NULL DEFAULT 60,
price decimal(10,2),
is_active tinyint(1) DEFAULT 1,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta($services_sql);
// 创建员工/资源表
$staff_table = $wpdb->prefix . 'booking_staff';
$staff_sql = "CREATE TABLE $staff_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
staff_name varchar(100) NOT NULL,
email varchar(100),
services text, // 可提供的服务ID,用逗号分隔
working_hours text, // JSON格式的工作时间
is_active tinyint(1) DEFAULT 1,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta($staff_sql);
}
add_action('after_setup_theme', 'create_booking_tables');
2.2 设计日程管理数据模型
除了预约信息,我们还需要管理日程可用性:
// 创建可用时间段表
function create_availability_tables() {
global $wpdb;
$table_name = $wpdb->prefix . 'booking_availability';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
staff_id mediumint(9),
date date NOT NULL,
start_time time NOT NULL,
end_time time NOT NULL,
max_bookings int DEFAULT 1,
booked_count int DEFAULT 0,
is_available tinyint(1) DEFAULT 1,
PRIMARY KEY (id),
KEY date (date),
KEY staff_id (staff_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
add_action('after_setup_theme', 'create_availability_tables');
第三部分:创建预约前端界面
3.1 设计预约表单短代码
我们将创建一个短代码,可以在任何页面或文章中添加预约表单:
// 预约表单短代码
function booking_form_shortcode($atts) {
ob_start();
// 获取短代码属性
$atts = shortcode_atts(array(
'service_id' => '',
'staff_id' => '',
), $atts);
// 加载预约表单
include(get_stylesheet_directory() . '/templates/booking-form.php');
return ob_get_clean();
}
add_shortcode('booking_form', 'booking_form_shortcode');
3.2 创建预约表单HTML模板
在子主题目录下创建templates文件夹,然后创建booking-form.php文件:
<div class="booking-container">
<div class="booking-progress">
<div class="step active" data-step="1">选择服务</div>
<div class="step" data-step="2">选择时间</div>
<div class="step" data-step="3">填写信息</div>
<div class="step" data-step="4">确认预约</div>
</div>
<form id="booking-form" method="post" action="<?php echo admin_url('admin-ajax.php'); ?>">
<!-- 步骤1:选择服务 -->
<div class="booking-step step-1 active">
<h3>选择服务类型</h3>
<div class="service-options">
<?php
global $wpdb;
$services_table = $wpdb->prefix . 'booking_services';
$services = $wpdb->get_results("SELECT * FROM $services_table WHERE is_active = 1");
foreach($services as $service) {
echo '<div class="service-option" data-service-id="' . $service->id . '">';
echo '<h4>' . esc_html($service->service_name) . '</h4>';
echo '<p>' . esc_html($service->description) . '</p>';
echo '<div class="service-meta">';
echo '<span class="duration">' . $service->duration . '分钟</span>';
if($service->price) {
echo '<span class="price">¥' . number_format($service->price, 2) . '</span>';
}
echo '</div>';
echo '</div>';
}
?>
</div>
<button type="button" class="btn-next" data-next-step="2">下一步</button>
</div>
<!-- 步骤2:选择日期和时间 -->
<div class="booking-step step-2">
<h3>选择预约时间</h3>
<div class="date-selector">
<div class="month-navigation">
<button type="button" class="prev-month"><</button>
<h4 class="current-month"></h4>
<button type="button" class="next-month">></button>
</div>
<div class="calendar"></div>
</div>
<div class="time-slots">
<h4>可用时间段</h4>
<div class="slots-container"></div>
</div>
<div class="step-buttons">
<button type="button" class="btn-prev" data-prev-step="1">上一步</button>
<button type="button" class="btn-next" data-next-step="3">下一步</button>
</div>
</div>
<!-- 步骤3:填写个人信息 -->
<div class="booking-step step-3">
<h3>填写个人信息</h3>
<div class="form-group">
<label for="customer_name">姓名 *</label>
<input type="text" id="customer_name" name="customer_name" required>
</div>
<div class="form-group">
<label for="customer_email">邮箱 *</label>
<input type="email" id="customer_email" name="customer_email" required>
</div>
<div class="form-group">
<label for="customer_phone">电话</label>
<input type="tel" id="customer_phone" name="customer_phone">
</div>
<div class="form-group">
<label for="notes">备注</label>
<textarea id="notes" name="notes" rows="3"></textarea>
</div>
<div class="step-buttons">
<button type="button" class="btn-prev" data-prev-step="2">上一步</button>
<button type="button" class="btn-next" data-next-step="4">下一步</button>
</div>
</div>
<!-- 步骤4:确认预约 -->
<div class="booking-step step-4">
<h3>确认预约信息</h3>
<div class="booking-summary">
<div class="summary-item">
<strong>服务:</strong>
<span id="summary-service"></span>
</div>
<div class="summary-item">
<strong>日期:</strong>
<span id="summary-date"></span>
</div>
<div class="summary-item">
<strong>时间:</strong>
<span id="summary-time"></span>
</div>
<div class="summary-item">
<strong>姓名:</strong>
<span id="summary-name"></span>
</div>
<div class="summary-item">
<strong>邮箱:</strong>
<span id="summary-email"></span>
</div>
<div class="summary-item">
<strong>电话:</strong>
<span id="summary-phone"></span>
</div>
</div>
<div class="step-buttons">
<button type="button" class="btn-prev" data-prev-step="3">上一步</button>
<button type="submit" class="btn-submit">提交预约</button>
</div>
</div>
<!-- 隐藏字段 -->
<input type="hidden" name="action" value="submit_booking">
<input type="hidden" name="service_id" id="service_id">
<input type="hidden" name="booking_date" id="booking_date">
<input type="hidden" name="booking_time" id="booking_time">
<input type="hidden" name="nonce" value="<?php echo wp_create_nonce('booking_nonce'); ?>">
</form>
<!-- 成功/错误消息 -->
<div id="booking-message" class="hidden"></div>
</div>
3.3 添加预约表单样式
在子主题的style.css文件中添加样式:
/* 预约系统样式 */
.booking-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f9f9f9;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.booking-progress {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
position: relative;
}
.booking-progress:before {
content: '';
position: absolute;
top: 15px;
left: 0;
right: 0;
height: 2px;
background: #ddd;
z-index: 1;
}
.booking-progress .step {
position: relative;
z-index: 2;
background: #fff;
padding: 10px 20px;
border-radius: 20px;
border: 2px solid #ddd;
text-align: center;
min-width: 120px;
}
.booking-progress .step.active {
border-color: #0073aa;
background: #0073aa;
color: white;
}
.booking-step {
display: none;
}
.booking-step.active {
display: block;
}
.service-options {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.service-option {
padding: 20px;
border: 2px solid #ddd;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
}
.service-option:hover {
border-color: #0073aa;
transform: translateY(-2px);
}
.service-option.selected {
border-color: #0073aa;
background: #f0f8ff;
}
.service-meta {
display: flex;
justify-content: space-between;
margin-top: 10px;
color: #666;
}
.date-selector {
margin-bottom: 30px;
}
.month-navigation {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.calendar {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 5px;
}
.calendar-day {
padding: 10px;
text-align: center;
border: 1px solid #ddd;
cursor: pointer;
border-radius: 4px;
}
.calendar-day:hover {
background: #f0f0f0;
}
.calendar-day.available {
background: #e8f5e9;
border-color: #4caf50;
}
.calendar-day.selected {
background: #4caf50;
color: white;
}
.calendar-day.unavailable {
background: #ffebee;
color: #999;
cursor: not-allowed;
}
.time-slots {
margin-bottom: 30px;
}
.slots-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.time-slot {
padding: 10px 20px;
border: 2px solid #ddd;
border-radius: 4px;
cursor: pointer;
}
.time-slot:hover {
border-color: #0073aa;
}
.time-slot.selected {
background: #0073aa;
color: white;
border-color: #0073aa;
}
.time-slot.unavailable {
background: #f5f5f5;
color: #999;
cursor: not-allowed;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.booking-summary {
background: white;
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
}
.summary-item {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.step-buttons {
display: flex;
justify-content: space-between;
}
button {
padding: 12px 24px;
background: #0073aa;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #005a87;
}
button.btn-prev {
background: #6c757d;
}
button.btn-prev:hover {
background: #545b62;
}
#booking-message {
padding: 15px;
margin-top: 20px;
border-radius: 4px;
display: none;
}
#booking-message.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
display: block;
}
#booking-message.error {
background: #f8d7da;
color: #721c24;
实战教程:为你的网站集成在线预约与日程管理(续)
第四部分:实现预约功能后端逻辑
4.1 处理AJAX预约提交
在functions.php中添加处理预约提交的代码:
// 处理预约提交
add_action('wp_ajax_submit_booking', 'handle_booking_submission');
add_action('wp_ajax_nopriv_submit_booking', 'handle_booking_submission');
function handle_booking_submission() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'booking_nonce')) {
wp_send_json_error('安全验证失败,请刷新页面重试。');
}
// 验证必填字段
$required_fields = ['customer_name', 'customer_email', 'service_id', 'booking_date', 'booking_time'];
foreach ($required_fields as $field) {
if (empty($_POST[$field])) {
wp_send_json_error('请填写所有必填字段。');
}
}
// 验证邮箱格式
if (!is_email($_POST['customer_email'])) {
wp_send_json_error('请输入有效的邮箱地址。');
}
// 验证日期格式
$booking_date = DateTime::createFromFormat('Y-m-d', $_POST['booking_date']);
if (!$booking_date) {
wp_send_json_error('日期格式不正确。');
}
// 检查日期是否在未来
$today = new DateTime();
if ($booking_date < $today) {
wp_send_json_error('不能预约过去的日期。');
}
global $wpdb;
$bookings_table = $wpdb->prefix . 'bookings';
// 检查该时间段是否已被预约
$existing_booking = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $bookings_table
WHERE booking_date = %s
AND booking_time = %s
AND status IN ('pending', 'confirmed')",
$_POST['booking_date'],
$_POST['booking_time']
));
if ($existing_booking > 0) {
wp_send_json_error('该时间段已被预约,请选择其他时间。');
}
// 插入预约数据
$insert_data = array(
'customer_name' => sanitize_text_field($_POST['customer_name']),
'customer_email' => sanitize_email($_POST['customer_email']),
'customer_phone' => sanitize_text_field($_POST['customer_phone'] ?? ''),
'service_id' => intval($_POST['service_id']),
'booking_date' => $_POST['booking_date'],
'booking_time' => $_POST['booking_time'],
'duration' => intval($_POST['duration'] ?? 60),
'notes' => sanitize_textarea_field($_POST['notes'] ?? ''),
'status' => 'pending'
);
$result = $wpdb->insert($bookings_table, $insert_data);
if ($result) {
$booking_id = $wpdb->insert_id;
// 发送确认邮件
send_booking_confirmation_email($booking_id, $insert_data);
// 发送管理员通知
send_admin_notification_email($booking_id, $insert_data);
wp_send_json_success(array(
'message' => '预约提交成功!我们已发送确认邮件到您的邮箱。',
'booking_id' => $booking_id
));
} else {
wp_send_json_error('预约提交失败,请稍后重试。');
}
}
// 发送确认邮件给客户
function send_booking_confirmation_email($booking_id, $booking_data) {
$to = $booking_data['customer_email'];
$subject = '您的预约确认 - ' . get_bloginfo('name');
$message = '<html><body>';
$message .= '<h2>预约确认</h2>';
$message .= '<p>尊敬的 ' . $booking_data['customer_name'] . ',</p>';
$message .= '<p>感谢您的预约,以下是您的预约详情:</p>';
$message .= '<table border="0" cellpadding="10">';
$message .= '<tr><td><strong>预约编号:</strong></td><td>' . $booking_id . '</td></tr>';
$message .= '<tr><td><strong>服务类型:</strong></td><td>' . get_service_name($booking_data['service_id']) . '</td></tr>';
$message .= '<tr><td><strong>预约日期:</strong></td><td>' . $booking_data['booking_date'] . '</td></tr>';
$message .= '<tr><td><strong>预约时间:</strong></td><td>' . $booking_data['booking_time'] . '</td></tr>';
$message .= '<tr><td><strong>预计时长:</strong></td><td>' . $booking_data['duration'] . '分钟</td></tr>';
$message .= '</table>';
$message .= '<p>如需修改或取消预约,请通过以下方式联系我们:</p>';
$message .= '<p>电话:' . get_option('business_phone') . '</p>';
$message .= '<p>邮箱:' . get_option('admin_email') . '</p>';
$message .= '</body></html>';
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>'
);
wp_mail($to, $subject, $message, $headers);
}
// 发送管理员通知
function send_admin_notification_email($booking_id, $booking_data) {
$to = get_option('admin_email');
$subject = '新预约通知 - 预约编号:' . $booking_id;
$message = '<html><body>';
$message .= '<h2>新预约通知</h2>';
$message .= '<p>您收到一个新的预约请求:</p>';
$message .= '<table border="0" cellpadding="10">';
$message .= '<tr><td><strong>预约编号:</strong></td><td>' . $booking_id . '</td></tr>';
$message .= '<tr><td><strong>客户姓名:</strong></td><td>' . $booking_data['customer_name'] . '</td></tr>';
$message .= '<tr><td><strong>客户邮箱:</strong></td><td>' . $booking_data['customer_email'] . '</td></tr>';
$message .= '<tr><td><strong>客户电话:</strong></td><td>' . $booking_data['customer_phone'] . '</td></tr>';
$message .= '<tr><td><strong>服务类型:</strong></td><td>' . get_service_name($booking_data['service_id']) . '</td></tr>';
$message .= '<tr><td><strong>预约日期:</strong></td><td>' . $booking_data['booking_date'] . '</td></tr>';
$message .= '<tr><td><strong>预约时间:</strong></td><td>' . $booking_data['booking_time'] . '</td></tr>';
$message .= '<tr><td><strong>备注:</strong></td><td>' . $booking_data['notes'] . '</td></tr>';
$message .= '</table>';
$message .= '<p><a href="' . admin_url('admin.php?page=booking-management') . '">点击这里管理预约</a></p>';
$message .= '</body></html>';
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>'
);
wp_mail($to, $subject, $message, $headers);
}
// 获取服务名称
function get_service_name($service_id) {
global $wpdb;
$services_table = $wpdb->prefix . 'booking_services';
return $wpdb->get_var($wpdb->prepare(
"SELECT service_name FROM $services_table WHERE id = %d",
$service_id
));
}
4.2 实现可用时间段查询
// 获取可用时间段
add_action('wp_ajax_get_available_slots', 'get_available_time_slots');
add_action('wp_ajax_nopriv_get_available_slots', 'get_available_time_slots');
function get_available_time_slots() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'booking_nonce')) {
wp_send_json_error('安全验证失败。');
}
$date = sanitize_text_field($_POST['date']);
$service_id = intval($_POST['service_id']);
// 验证日期格式
$booking_date = DateTime::createFromFormat('Y-m-d', $date);
if (!$booking_date) {
wp_send_json_error('日期格式不正确。');
}
// 获取服务时长
global $wpdb;
$services_table = $wpdb->prefix . 'booking_services';
$service = $wpdb->get_row($wpdb->prepare(
"SELECT duration FROM $services_table WHERE id = %d",
$service_id
));
if (!$service) {
wp_send_json_error('服务不存在。');
}
$service_duration = $service->duration;
// 获取当天的预约情况
$bookings_table = $wpdb->prefix . 'bookings';
$bookings = $wpdb->get_results($wpdb->prepare(
"SELECT booking_time, duration FROM $bookings_table
WHERE booking_date = %s
AND status IN ('pending', 'confirmed')",
$date
));
// 获取营业时间设置(这里可以扩展为从数据库读取)
$business_hours = array(
'start' => '09:00:00',
'end' => '18:00:00',
'lunch_start' => '12:00:00',
'lunch_end' => '13:00:00'
);
// 生成时间段
$time_slots = generate_time_slots($business_hours, $service_duration, $bookings);
wp_send_json_success(array(
'date' => $date,
'slots' => $time_slots
));
}
// 生成时间段
function generate_time_slots($business_hours, $service_duration, $existing_bookings) {
$slots = array();
// 将时间转换为分钟数便于计算
$start_minutes = time_to_minutes($business_hours['start']);
$end_minutes = time_to_minutes($business_hours['end']);
$lunch_start = time_to_minutes($business_hours['lunch_start']);
$lunch_end = time_to_minutes($business_hours['lunch_end']);
// 创建已预约时间段的映射
$booked_slots = array();
foreach ($existing_bookings as $booking) {
$booking_start = time_to_minutes($booking->booking_time);
$booking_end = $booking_start + $booking->duration;
for ($time = $booking_start; $time < $booking_end; $time += 15) {
$booked_slots[$time] = true;
}
}
// 生成时间段
$current_time = $start_minutes;
while ($current_time + $service_duration <= $end_minutes) {
// 跳过午休时间
if ($current_time >= $lunch_start && $current_time < $lunch_end) {
$current_time = $lunch_end;
continue;
}
// 检查时间段是否可用
$is_available = true;
for ($check_time = $current_time; $check_time < $current_time + $service_duration; $check_time += 15) {
if (isset($booked_slots[$check_time]) ||
($check_time >= $lunch_start && $check_time < $lunch_end)) {
$is_available = false;
break;
}
}
if ($is_available) {
$slot_time = minutes_to_time($current_time);
$slots[] = array(
'time' => $slot_time,
'display' => format_time_display($slot_time),
'available' => true
);
}
$current_time += 15; // 15分钟间隔
}
return $slots;
}
// 时间转换辅助函数
function time_to_minutes($time) {
list($hours, $minutes) = explode(':', $time);
return intval($hours) * 60 + intval($minutes);
}
function minutes_to_time($minutes) {
$hours = floor($minutes / 60);
$mins = $minutes % 60;
return sprintf('%02d:%02d:00', $hours, $mins);
}
function format_time_display($time) {
return date('g:i A', strtotime($time));
}
第五部分:创建后台管理界面
5.1 添加管理菜单
// 添加预约管理菜单
add_action('admin_menu', 'register_booking_admin_menu');
function register_booking_admin_menu() {
add_menu_page(
'预约管理',
'预约管理',
'manage_options',
'booking-management',
'render_booking_management_page',
'dashicons-calendar-alt',
30
);
add_submenu_page(
'booking-management',
'所有预约',
'所有预约',
'manage_options',
'booking-management',
'render_booking_management_page'
);
add_submenu_page(
'booking-management',
'服务管理',
'服务管理',
'manage_options',
'booking-services',
'render_services_management_page'
);
add_submenu_page(
'booking-management',
'日程设置',
'日程设置',
'manage_options',
'booking-settings',
'render_booking_settings_page'
);
add_submenu_page(
'booking-management',
'预约统计',
'预约统计',
'manage_options',
'booking-statistics',
'render_booking_statistics_page'
);
}
// 渲染预约管理页面
function render_booking_management_page() {
global $wpdb;
$bookings_table = $wpdb->prefix . 'bookings';
$services_table = $wpdb->prefix . 'booking_services';
// 处理批量操作
if (isset($_POST['bulk_action']) && isset($_POST['booking_ids'])) {
$action = sanitize_text_field($_POST['bulk_action']);
$booking_ids = array_map('intval', $_POST['booking_ids']);
if ($action === 'delete') {
foreach ($booking_ids as $id) {
$wpdb->delete($bookings_table, array('id' => $id));
}
echo '<div class="notice notice-success"><p>已删除选中的预约。</p></div>';
} elseif (in_array($action, ['pending', 'confirmed', 'cancelled', 'completed'])) {
$wpdb->query($wpdb->prepare(
"UPDATE $bookings_table SET status = %s WHERE id IN (" . implode(',', $booking_ids) . ")",
$action
));
echo '<div class="notice notice-success"><p>已更新选中的预约状态。</p></div>';
}
}
// 处理单个操作
if (isset($_GET['action']) && isset($_GET['booking_id'])) {
$action = sanitize_text_field($_GET['action']);
$booking_id = intval($_GET['booking_id']);
switch ($action) {
case 'confirm':
$wpdb->update($bookings_table, array('status' => 'confirmed'), array('id' => $booking_id));
break;
case 'cancel':
$wpdb->update($bookings_table, array('status' => 'cancelled'), array('id' => $booking_id));
break;
case 'delete':
$wpdb->delete($bookings_table, array('id' => $booking_id));
break;
}
wp_redirect(admin_url('admin.php?page=booking-management'));
exit;
}
// 获取预约数据
$per_page = 20;
$current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
$offset = ($current_page - 1) * $per_page;
// 构建查询条件
$where_conditions = array('1=1');
$query_params = array();
if (!empty($_GET['status'])) {
$where_conditions[] = 'status = %s';
$query_params[] = sanitize_text_field($_GET['status']);
}
if (!empty($_GET['date_from'])) {
$where_conditions[] = 'booking_date >= %s';
$query_params[] = sanitize_text_field($_GET['date_from']);
}
if (!empty($_GET['date_to'])) {
$where_conditions[] = 'booking_date <= %s';
$query_params[] = sanitize_text_field($_GET['date_to']);
}
if (!empty($_GET['search'])) {
$search_term = '%' . $wpdb->esc_like(sanitize_text_field($_GET['search'])) . '%';
$where_conditions[] = '(customer_name LIKE %s OR customer_email LIKE %s OR customer_phone LIKE %s)';
$query_params[] = $search_term;
$query_params[] = $search_term;
$query_params[] = $search_term;
}
$where_clause = implode(' AND ', $where_conditions);
// 获取总数
$total_query = "SELECT COUNT(*) FROM $bookings_table WHERE $where_clause";
if (!empty($query_params)) {
$total_query = $wpdb->prepare($total_query, $query_params);
}
$total_bookings = $wpdb->get_var($total_query);
// 获取数据
