「WordPressに予約フォームを付けたい」で始まる相談は、最初の見積りが一番安く、実装が進むにつれて重くなります。理由ははっきりしていて、予約という機能が「日付を受け取って送信する」処理ではなく、「その日時が受けられるかどうかを判定する」処理だからです。判定に絡む条件が1つ増えるたびに、既製プラグインの設定画面でできることの外側へはみ出していきます。既製で足りるのか、改修で済むのか、自作に切り替えるべきなのか。実際に詰まった要件を先に並べたほうが、この線引きは早く決まります。
既製プラグインで止まる要件は、だいたい同じ
予約プラグインが苦手にする条件には、はっきりした傾向があります。最初にぶつかるのは「定休日は曜日単位でしか設定できない」という制約です。毎週水曜が休み、は設定できても、今月28日だけ臨時休業、が入れられない。これは実装の手抜きではなく、多くのプラグインが曜日をキーにして受付可能な時間帯を持っているからで、単発の日付を差し込むには別のデータ構造が必要になります。
次が枠の管理です。「その時間帯の枠が埋まったら自動的に選べなくする」という要件は、予約を1件ずつ独立したデータとして持つ設計だと成立しません。同じ時間帯にいくつまで受けるかという上限を、店舗や担当ごとに保持する仕組みが要ります。実際にこの要望が出た案件では、当時使っていたプラグインが対応しておらず、新規開発の見積りとして切り出しました。
3つ目が、複数の条件を掛け合わせた判定です。ある案件では「今この瞬間に予約できるスタッフだけを一覧に出す」という要望でした。文章にすると一行ですが、判定に必要なのは受付の時間帯、そのスタッフの出勤状況、そして選ばれたメニューの最短所要時間の3つで、しかもページを開いた瞬間の時刻で毎回計算し直す必要があります。見た目の単純さと工数がここまで乖離する要件は、予約まわりでは珍しくありません。
選択肢は4つある
| やり方 | 足りる要件 | 限界が来る場所 |
|---|---|---|
| 既製の予約プラグインをそのまま使う | 曜日単位の定休日、固定の受付時間帯、単純な枠 | 臨時休業、担当ごとの条件、メニュー別の所要時間 |
| 既製プラグインをフックとCSSで調整する | 管理画面の表示調整、項目の出し分け、軽い挙動の変更 | プラグイン側のDOMや関数構造が更新で変わると壊れる |
| 既存のフォーム基盤に判定を足す | 日付の制限、送信前後のバリデーション、通知の分岐 | 予約データを一覧・集計したくなった時点で限界 |
| 判定ロジックを自作する | 担当ごと・曜日ごと・メニューごとの複合条件 | 作った分だけ保守が発生する |
2番目について補足すると、既製プラグインの見た目を変えるときにプラグイン本体のファイルを直接編集するのは避けてください。次の更新で確実に元へ戻ります。管理画面の不要な要素を隠す程度なら、admin_head フックからCSSを流し込む形にすれば更新に耐えます。ただしこの方法にも弱点があって、プラグイン側がバージョンアップでクラス名やDOM構造を変えると、隠していた要素が突然復活します。CSSセレクタに依存する調整は、更新のたびに確認が要る前提で入れてください。
既にある「紐付けの単位」に乗せると早く終わる
店舗ごとに曜日別の受付時間を設定できるようにしたい、という案件がありました。素直に考えるとカスタム投稿タイプで「店舗」を作り、そこに設定を持たせる形になりますが、そのサイトは既に店舗がWordPressのユーザーとして登録されていて、店舗ページも /raiten?store={user_login} という形でユーザーに紐づいていました。
そこで、新しい器を作らずにユーザーメタへ曜日別の受付可能時間を保存する形にしました。カスタム投稿タイプも専用テーブルも増やしていません。予約システムを載せる前に、そのサイトが既に何を単位にデータを持っているか——ユーザーなのか、カテゴリーなのか、タームなのか——を確認すると、作らずに済むものが見つかります。既存の器に乗せられるかをまず疑うという進め方は予約に限らず、請求書と見積書をWebで発行する仕組みを小規模向けに作るで書いた入力画面の置き場所の話とまったく同じ判断です。
この案件で明確になったのが、初期値をどちらに倒すかという設計判断です。当初は「9:00〜22:30」を初期値にしていました。ところが、設定をまだ入れていない店舗が実態と違う時間帯で公開されてしまいます。そこで「時間指定なし=終日受付可」に変更しました。未設定を制限なしとして扱えば、設定漏れが「本当は営業しているのに予約を取りこぼす」という事故になりません。予約の初期値は安全側に倒す、という原則はここから来ています。
曜日別の設定でもう1つ注意が要るのは、設定した値と表示される値がずれることです。土曜に11:00〜15:00と入れたのに画面上は11:00〜17:00と出る、といったずれが実際に起きました。曜日のインデックスのオフセットや、終了時刻の取り違えが混入しやすい箇所です。全曜日について設定値と表示値を突き合わせないと見つかりません。検証は、設定が空の店舗ではなく実データが入っている店舗で行ってください。
過去日を選ばせない、は3層で塞ぐ
来店予約フォームで過去の日付が選べてしまう、という修正を受けたことがあります。同じ系統の実装を持つ2サイトをまとめて対応して、実質半日ほどの作業でした。ここで確認しておきたいのは、対策を1か所で済ませてはいけないという点です。
HTML5の input[type=date] に min 属性を付けると、カレンダーのUI上は過去日を選べなくなります。ところがこれはブラウザによってUIで抑止されるだけで、値をPOSTすること自体は防げません。開発者ツールを開けば書き換えられますし、そもそも min に静的な日付をハードコードしてしまうと、翌日以降は何の意味もなくなります。date('Y-m-d') のように動的に生成するか、Contact Form 7なら [date* your-date min:today] の形で書きます。
業務で使う予約フォームなら、UIでの抑止に加えてサーバー側のバリデーションを必ず入れてください。Contact Form 7であれば wpcf7_validate_date のフィルタで受け止められます。この「表示でも塞ぎ、送信でも塞ぐ」という二段構えは、曜日単位の休業日でも同じです。予約不可の曜日は時間の選択肢も出さない、かつフォームの受け付けもしない。片方だけだと、POSTを直接投げられて予約が入る穴が残ります。
他社が改変したプラグインを引き継ぐとき
オンラインレッスンの予約プラグインで「チケットの残数がマイナスでも予約できてしまう」という不具合を調査した案件があります。原因は、残数のチェックが empty() で書かれていたことでした。empty() はゼロを偽と判定しますが、マイナス値は真として通します。残数、在庫、ポイントの判定で empty($ticket) という記述を見つけたら、$ticket <= 0 に直すのが定石です。同じ形のバグは他の現場でも繰り返し出てきます。
厄介なのはここからで、そのプラグインは前の担当者によって改変されていました。改変版はプラグイン開発元のサポート対象外なので、公式に問い合わせても回答は得られません。ただし「オリジナル版でこの処理はどのファイルにあるか」を聞くだけなら答えてもらえることが多く、実際にこの問い合わせで class/my-ticket.php の extend_can_reservation() と reservation() の2関数を一発で特定できました。改変前後の比較材料としては、オリジナルの配布ZIP、サーバー上に残っている .bak ファイル、そしてコード内のコメントが使えます。コメントには改変者名や改変日が残っていることがあり、grepで洗い出すと影響範囲の見当が付きます。
この案件では納品後に副作用が出ました。残数のチェックを追加したことで、キャンセル処理まで同じ判定関数を通っていて、残数がゼロだとキャンセルもできなくなっていたのです。制限を足したときは、逆方向の操作——キャンセル、返却、取り消し——が巻き添えになっていないかを必ず確認してください。もう1つ、「1回に1件ずつ予約する」前提で書かれた処理を「複数同時に予約できる」ように改変すると、残数チェックが1件分しか効かない構造的な問題が生まれます。ループ単位の判定を一括処理に置き換える必要があり、これは改変を引き継ぐ時点で想定しておくべき工数です。
設定漏れが「バグ」に見える
有料テーマの子テーマに予約可否の判定を実装し、あわせてオプション設定画面を付けた案件があります。表示人数やリンク先を依頼者自身で変えられるようにするための画面でしたが、ここで初期値を実装していない項目がありました。結果として、出勤していないはずのスタッフが予約可能として表示され、一覧ページではエラーが出ます。実装の不具合にしか見えませんが、原因は未設定の項目がゼロや空文字として扱われたことでした。
オプション画面を用意するなら、全項目にデフォルト値を実装してください。これは親切設計ではなく、事故を防ぐための必須要件です。似た話で、「予約できるはずの枠が出ない」「出ないはずの枠が出る」という報告を受けたときの一次容疑者も、実装バグではなく設定値です。この案件ではメニューごとの最短所要時間の設定が原因で、別の店舗で再発したときも同じでした。コードを疑う前に設定画面を開いてください。
よくある質問
予約プラグインは無料のものでどこまで足りますか
曜日単位の休業日、固定の受付時間帯、1枠1件という前提であれば、無料のもので十分に運用できます。限界が来るのは、担当者ごとに条件が違う場合、メニューによって所要時間が変わる場合、そして単発の臨時休業を入れたい場合です。この3つのいずれかが要件に入った時点で、有料版か改修か自作かの検討に移ります。
プラグインを改修するのと、自作するのはどちらが安いですか
短期では改修が安く、長期では条件によります。改修は既存の機能をそのまま使えるぶん初期費用を抑えられますが、改変したプラグインは開発元のサポート対象から外れ、以後の更新も自力で追う前提になります。判定ロジックだけを自作して、フォームや通知は既製に任せる、という分け方が現実的な落としどころになることが多いです。
予約データを後から集計したくなりそうです
その見込みがあるなら、最初にデータの持ち方を決めてください。フォームプラグインの送信ログとして予約を保持している構成は、一覧や集計を作る段になって全部やり直しになります。予約を独立したデータとして持ち、日付・担当・メニュー・状態を列として設計しておけば、後から管理画面を足せます。既存の古い仕組みを抱えている場合の判断はEC-CUBE・CakePHP・Movable Typeの古いシステム、延命か作り直しかも併せてご覧ください。
予約と会員機能を両方載せたいのですが
載せられますが、順番を決めてください。会員の識別ができていないと、予約の「誰が」が確定しません。会員管理を先に固め、そのIDに予約を紐づける形にすると素直に組めます。会員側の設計は会員限定サイトの作り方、会員管理・決済・閲覧制御をどう組むかで詳しく書いています。
予約の要件は、設定画面で足りるのか作らないと無理なのかが、ヒアリングの段階でほぼ判別できます。いま挙がっている条件を並べていただければ、どこまで既製で足りるかをお伝えします。
