搜索全站
建站 11 分钟阅读

WordPress 预约预订站怎么做?时段管理、冲突处理与提醒通知

预约站的核心是"不能撞单"。本文讲清时段模型、缓冲时间、冲突检测与提醒通知的完整设计,给出可复用的时段生成与冲突校验代码。

U
UFO_PF 2021-08-13 · 阅读 11 分钟
Wo 建站
阅读提示
本文约 4,126 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:两个客户约了同一个下午三点

做美容店、诊所、摄影棚、家政服务的预约站,最严重的事故不是没人约,而是撞单——两个客户都约到周一下午三点,技师只有一个,现场只能道歉赔偿。这种事故往往不是插件的问题,而是配置的问题:服务时长设了 60 分钟,但时段粒度也是 60 分钟,缓冲(清洁、准备)时间为 0,日历看起来排满了,实际根本转不过来。

另一个常见问题是时区。客户在纽约,服务方在洛杉矶,前端展示的”下午三点”到底是谁的三点?WordPress 的站点时区、数据库存储的时间戳、前端展示的本地时间,三者如果不统一,撞单会以更隐蔽的形式出现:系统里看是错开的,客户理解成同一时间。

原理分析:预约系统的核心是时段模型

概念 含义 典型值 配错会怎样
服务时长 Duration 单个预约占用的时间 30 / 60 分钟 过短导致排不下
时段粒度 Slot 可预约的起点间隔 30 分钟 与时长不匹配产生碎片
缓冲 Buffer 两次预约之间的空档 5–15 分钟 为 0 会导致实际串行失败
容量 Capacity 同一时段可接几单 1(单人服务)/ N(课程) 为 1 时并发必撞
提前/截止 Lead/Cutoff 最早最晚可约范围 提前 2 小时 / 30 天 太短会接到临时单

冲突检测的数学表达很简单:新预约区间 [start, start+duration+buffer) 与已有预约区间存在交集,即冲突。关键在于必须以 UTC 时间戳做比较,展示时才转成本地时间。把时间存成本地字符串再比较,跨时区一定会出错。

保姆级实操

步骤 1:选插件,按业务复杂度决定

单人服务(美容、摄影、咨询)用 Amelia 或 Simply Schedule Appointments 足够,界面友好、自带提醒;多服务项目 + 员工排班 + 收费,用 Bookly 或 MotoPress Appointment Booking;如果本身就在用 WooCommerce 并且要按资源计费,用 WooCommerce Bookings。不要为了”功能全”选最重的,配置成本会翻倍。

步骤 2:把服务时长、缓冲、容量一次设对

在插件的服务设置里,务必填三个值:Duration 60 分钟、Buffer 10 分钟、Capacity 1(或场地座位数)。然后确认时段粒度与时长一致或为其约数——时长 60、粒度 30 会生成大量无法利用的碎片时段。

步骤 3:设置可预约窗口

Lead time(最少提前多久)建议 2 小时,避免接到 10 分钟后的单;Cutoff(最多提前多久)建议 30–60 天,防止远期占位的无效预约导致近期排满。

步骤 4:自建时段生成与冲突检测(进阶)

如果你用自定义 CPT 自己实现,下面这段是可直接复用的时段生成 + 冲突校验逻辑。已预约记录存在 appointment 文章类型的 _slot_start(UTC 时间戳)和 _slot_end 两个 meta 里:

function mf_generate_slots( $date_ymd, $duration = 3600, $buffer = 600, $open = '09:00', $close = '18:00' ) {
    $tz   = wp_timezone();
    $base = new DateTimeImmutable( $date_ymd . ' ' . $open, $tz );
    $end  = new DateTimeImmutable( $date_ymd . ' ' . $close, $tz );
    $slots = array();
    for ( $t = $base; $t->getTimestamp() + $duration <= $end->getTimestamp(); ) {
        $slots[] = array(
            'start' => $t->getTimestamp(),
            'end'   => $t->getTimestamp() + $duration + $buffer,
        );
        $t = $t->modify( '+30 minutes' );
    }
    return $slots;
}

function mf_slot_taken( $start, $end ) {
    $q = new WP_Query( array(
        'post_type'      => 'appointment',
        'posts_per_page' => 1,
        'post_status'    => 'publish',
        'meta_query'     => array(
            'relation' => 'AND',
            array( 'key' => '_slot_start', 'value' => $end,   'compare' => '<', 'type' => 'NUMERIC' ),
            array( 'key' => '_slot_end',   'value' => $start, 'compare' => '>', 'type' => 'NUMERIC' ),
        ),
    ) );
    return $q->have_posts();
}

上面的 meta_query 就是标准的区间重叠判断:existing.start < new.end AND existing.end > new.start。

步骤 5:写入预约前再做一次原子校验

前端禁用按钮不算数,必须在服务端写入前再查一次,因为两个用户可能同时提交:

function mf_book_slot( $start, $end, $customer ) {
    if ( mf_slot_taken( $start, $end ) ) {
        return new WP_Error( 'slot_taken', '该时段已被预约,请选择其他时间。' );
    }
    $id = wp_insert_post( array(
        'post_type'   => 'appointment',
        'post_title'  => '预约 ' . wp_date( 'Y-m-d H:i', $start ),
        'post_status' => 'publish',
    ) );
    update_post_meta( $id, '_slot_start', $start );
    update_post_meta( $id, '_slot_end', $end );
    update_post_meta( $id, '_customer', sanitize_text_field( $customer ) );
    return $id;
}

高并发场景下还要给写入加锁,WordPress 可以用 wp_cache_add() 做一个短时锁,或者直接在数据库给 _slot_start 建唯一索引。

步骤 6:提醒通知按两个时间点发

提前 24 小时一封(含地址、导航链接、改约链接),提前 2 小时一封(短提醒)。用插件内置的提醒功能或 Action Scheduler(WooCommerce 自带的任务队列库)来定时发送,不要用 WP-Cron——WP-Cron 依赖访问触发,低流量站点会延迟。

步骤 7:改约与取消要留口子

给确认邮件里加一个带 token 的取消链接,客户能自助取消,空出的时段自动回到可选池。自助取消能把”放鸽子率”压低一大截。

常见踩坑

  1. 缓冲时间设为 0:理论上排满,实际上技师连轴转,客户体验崩坏,差评增多。
  2. 用本地时间字符串比较:跨时区、跨夏令时必然出错,必须存 UTC 时间戳。
  3. WP-Cron 发提醒:低流量站点半夜没人访问,提醒延迟到第二天上午,等于没发。用 Action Scheduler 或服务器真实 cron。
  4. 前端禁用时段却不在服务端校验:用户改一下 HTML 就能提交撞单。
  5. 提醒邮件进垃圾箱:预约类邮件送达率要求极高,SPF/DKIM/DMARC 必须配齐。
  6. 案例:某美容工作室的”双 booked”:服务时长设 60 分钟,时段粒度 30 分钟,缓冲 0,结果系统允许 14:00 和 14:30 两个预约,而实际服务要 70 分钟,第二个客户到店后等了 40 分钟,当场投诉并退款。调整成粒度 60、缓冲 10 后,日历排布与实际产能吻合,投诉归零。
  7. 没有自助取消入口:客户只能打电话取消,高峰期占线,放鸽子率超过 20%。

总结

预约站是否可靠,用三个指标检验:撞单率是否为 0、提醒到达率是否高于 98%、自助取消率是否高于 50%(说明客户愿意提前告知)。行动清单:先把时长、粒度、缓冲、容量四个参数一次设对并确认它们互相匹配,再把所有时间统一存成 UTC 时间戳并在展示层转换,然后在服务端做区间重叠校验而非依赖前端禁用,最后用 Action Scheduler 在两个时间点发提醒邮件并在邮件里给出自助取消链接。这套做完,预约站才敢接真实客流。邮件链路的配置可参考 外贸站邮件营销 EDM 接入,如果预约入口要做成独立投放页,见 落地页高性能制作。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。