2026年8月23日
2026年8月23日
WooCommerce Bookingsのエラーを解決する方法
はじめに
WooCommerce Bookingsで商品ページの予約カレンダーが表示されない・特定の日付を選択しても「この日付は利用できません」と表示され予約できない・予約完了後に確認メールが届かない・バッファータイムが設定通りに機能しないといった問題は、タイムゾーン設定のズレ・予約可能期間の設定ミス・リソースの競合が原因です。
症状・原因
- 商品ページに「予約カレンダー」ウィジェットが表示されず、通常のカートボタンのみ表示される
- カレンダーで日付を選択するとすべての時間帯が「利用不可」になっている
- 予約が完了してもユーザーへの確認メールと管理者への通知メールが届かない
- 1時間の予約後に30分のバッファーを設定したが連続予約が入ってしまう
解決手順
ステップ1:WooCommerce Bookingsの状態を確認する
# WooCommerce Bookingsの設定を確認
wp eval "
// バージョン確認
if (defined('WOOCOMMERCE_BOOKINGS_VERSION')) {
echo 'WC Bookings version: ' . WOOCOMMERCE_BOOKINGS_VERSION . PHP_EOL;
}
// タイムゾーン設定確認
echo 'WP Timezone: ' . get_option('timezone_string') . PHP_EOL;
echo 'PHP Timezone: ' . date_default_timezone_get() . PHP_EOL;
echo 'Current time: ' . current_time('Y-m-d H:i:s') . PHP_EOL;
// 予約可能な商品を確認
\$bookable_products = get_posts([
'post_type' => 'product',
'posts_per_page' => 10,
'meta_key' => '_wc_booking_duration',
]);
echo 'Bookable products: ' . count(\$bookable_products) . PHP_EOL;
foreach (\$bookable_products as \$p) {
\$duration = get_post_meta(\$p->ID, '_wc_booking_duration', true);
\$min_date = get_post_meta(\$p->ID, '_wc_booking_min_date', true);
\$max_date = get_post_meta(\$p->ID, '_wc_booking_max_date', true);
\$buffer = get_post_meta(\$p->ID, '_wc_booking_buffer_period', true);
printf(' Product #%d | %s | Duration: %s min | Buffer: %s min | Min: %s days | Max: %s days' . PHP_EOL,
\$p->ID, \$p->post_title, \$duration, \$buffer, \$min_date, \$max_date);
}
// 最近の予約を確認
\$bookings = get_posts([
'post_type' => 'wc_booking',
'posts_per_page' => 5,
'post_status' => 'any',
]);
echo 'Recent bookings: ' . count(\$bookings) . PHP_EOL;
foreach (\$bookings as \$b) {
printf(' #%d | Status: %s | Start: %s' . PHP_EOL,
\$b->ID, \$b->post_status,
get_post_meta(\$b->ID, '_booking_start', true));
}
"
ステップ2:予約の作成と管理をカスタマイズする
// functions.php: WC Bookings予約管理
// ① 予約作成時のカスタム処理
add_action('woocommerce_booking_created', function(int $booking_id): void {
$booking = new WC_Booking($booking_id);
$order = $booking->get_order();
error_log(sprintf('[WCB] Booking #%d created | Product: %d | Start: %s | Customer: %s',
$booking_id,
$booking->get_product_id(),
$booking->get_start_date(),
$order ? $order->get_billing_email() : 'N/A'
));
// 予約に追加メモを付ける
$booking->update_meta('_custom_booking_note', '自動処理済み');
});
// ② 予約ステータス変更時の処理
add_action('woocommerce_booking_status_changed', function(int $booking_id, string $old_status, string $new_status): void {
error_log(sprintf('[WCB] Booking #%d: %s → %s', $booking_id, $old_status, $new_status));
// 予約がキャンセルされたらリソースを解放
if ($new_status === 'cancelled') {
$booking = new WC_Booking($booking_id);
$person_id = $booking->get_person_id();
if ($person_id) {
// リソースのロックを解除するカスタム処理
delete_transient('booking_lock_' . $person_id . '_' . $booking->get_start());
}
}
}, 10, 3);
// ③ 予約可能スロットをプログラムで確認
function check_booking_availability(int $product_id, string $date): array {
$product = new WC_Product_Booking($product_id);
if (!$product) return ['available' => false, 'slots' => []];
$slots = $product->get_available_slots($date);
$duration = (int) get_post_meta($product_id, '_wc_booking_duration', true);
return [
'available' => !empty($slots),
'slots' => $slots,
'duration' => $duration,
];
}
ステップ3:カレンダー表示の問題を修正する
// functions.php: カレンダー表示カスタマイズ
// ① 予約可能な最小日数を動的に変更
add_filter('woocommerce_booking_get_min_date', function(array $min_date, object $product): array {
// 当日予約を許可しない(最低1日前まで)
$min_date['value'] = 1;
$min_date['unit'] = 'day';
return $min_date;
}, 10, 2);
// ② 予約可能な最大日数を変更
add_filter('woocommerce_booking_get_max_date', function(array $max_date, object $product): array {
// 最大90日先まで予約可能
$max_date['value'] = 90;
$max_date['unit'] = 'day';
return $max_date;
}, 10, 2);
// ③ 特定の曜日を予約不可にする
add_filter('wc_bookings_is_date_fully_booked', function(bool $fully_booked, int $start, int $end, object $product): bool {
// 日曜日(0)と土曜日(6)は予約不可
$day_of_week = (int) date('w', $start);
if (in_array($day_of_week, [0, 6], true)) {
return true; // 予約不可として扱う
}
return $fully_booked;
}, 10, 4);
// ④ 祝日を予約不可に設定
add_filter('wc_bookings_is_date_fully_booked', function(bool $fully_booked, int $start): bool {
$holidays = [
'2024-01-01', '2024-01-08', '2024-02-11', // 元旦・成人の日・建国記念日
'2024-03-20', '2024-04-29', '2024-05-03',
];
$date = date('Y-m-d', $start);
return $fully_booked || in_array($date, $holidays, true);
}, 11, 2);
ステップ4:予約メールと通知をカスタマイズする
// functions.php: 予約メール設定
// ① 予約確認メールをカスタマイズ
add_filter('woocommerce_email_subject_customer_booking', function(string $subject, object $booking): string {
return sprintf('[%s] ご予約確認 #%d', get_bloginfo('name'), $booking->get_id());
}, 10, 2);
// ② 予約リマインダーメールをスケジュール
add_action('woocommerce_booking_confirmed', function(int $booking_id): void {
$booking = new WC_Booking($booking_id);
$start_time = $booking->get_start();
// 予約1日前にリマインダーをスケジュール
$reminder_time = $start_time - DAY_IN_SECONDS;
if ($reminder_time > time()) {
wp_schedule_single_event($reminder_time, 'send_booking_reminder', [$booking_id]);
}
});
add_action('send_booking_reminder', function(int $booking_id): void {
$booking = new WC_Booking($booking_id);
$order = $booking->get_order();
if (!$order) return;
wp_mail(
$order->get_billing_email(),
'明日のご予約のご確認',
sprintf('明日 %s のご予約をお忘れなく。', $booking->get_start_date()),
['Content-Type: text/html; charset=UTF-8']
);
});
// ③ 予約キャンセル時の返金処理
add_action('woocommerce_booking_cancelled', function(int $booking_id): void {
$booking = new WC_Booking($booking_id);
$order = $booking->get_order();
if (!$order) return;
// 予約の3日以上前のキャンセルは全額返金
$days_until = ($booking->get_start() - time()) / DAY_IN_SECONDS;
if ($days_until >= 3) {
$refund = wc_create_refund([
'amount' => $order->get_total(),
'order_id' => $order->get_id(),
'reason' => '予約キャンセル(3日以上前)',
]);
error_log(sprintf('[WCB] Auto-refund for booking #%d: %s', $booking_id,
is_wp_error($refund) ? $refund->get_error_message() : 'success'));
}
});
ステップ5:予約データの一括操作
# 予約の状態を一括確認・操作
wp eval "
// ステータス別の予約数を確認
\$statuses = ['confirmed', 'pending', 'cancelled', 'complete', 'in-cart', 'was-in-cart'];
echo '=== Booking Status Summary ===' . PHP_EOL;
foreach (\$statuses as \$status) {
\$count = get_posts([
'post_type' => 'wc_booking',
'post_status' => 'wc-' . \$status,
'numberposts' => -1,
'fields' => 'ids',
]);
printf(' %-20s: %d' . PHP_EOL, \$status, count(\$count));
}
// 期限切れ(過去)の予約を確認
\$past_bookings = get_posts([
'post_type' => 'wc_booking',
'post_status' => 'wc-confirmed',
'numberposts' => 10,
'meta_query' => [[
'key' => '_booking_end',
'value' => current_time('timestamp'),
'compare' => '<',
'type' => 'NUMERIC',
]],
]);
echo 'Past confirmed bookings not marked complete: ' . count(\$past_bookings) . PHP_EOL;
"
注意事項
- WooCommerce Bookingsのカレンダーが表示されない場合は、まずブラウザの開発者ツールでJavaScriptエラーがないか確認してください。次に「WooCommerce → 設定 → 予約」でタイムゾーン設定がWordPressのタイムゾーン設定と一致しているか確認してください
- バッファータイムが機能しない場合は、
_wc_booking_buffer_periodメタフィールドの値(分単位)が正しく設定されているかget_post_meta()で確認してください。Bookingsの管理画面では「バッファー期間」の単位(分/時間)の設定ミスが多くあります - 大量の予約データがある場合、
WC_Product_Booking::get_available_slots()の実行に時間がかかりページ表示が遅くなります。Bookingキャッシュを有効化するか、よく参照される商品の空き状況をTransientでキャッシュしてください
まとめ
WooCommerce Bookings修復は①_wc_booking_duration・_wc_booking_buffer_periodメタの確認・タイムゾーンの整合性確認、②woocommerce_booking_createdフックで予約作成ログ・woocommerce_booking_status_changedフックでキャンセル時リソース解放、③woocommerce_booking_get_min_date/get_max_dateフィルターで予約可能期間調整・wc_bookings_is_date_fully_bookedフィルターで祝日・週末を予約不可に設定、④woocommerce_booking_confirmedフックで1日前リマインダーをWP-Cronでスケジュール・woocommerce_booking_cancelledフックでキャンセルポリシーに基づく自動返金、⑤ステータス別集計SQLで予約状況を一括管理する手順で解決します。