← Back to all docs
Last updated: May 28, 2026 · 162.5 KB Download .md

Version 2.4.2 | Documentation (2026 Edition)

Welcome to Modern Hotel Booking, the complete reservation system for WordPress. This guide covers everything from initial setup to advanced Pro features including payment processing, AI assistance, and VAT/TAX management.


Table of Contents

Part 1: Getting Started

1.1 Installation & Activation
1.2 Quick Start Guide
1.3 System Requirements

Part 2: Free Version User Guide

2.1 Setting Up Your Hotel
2.2 Configuration
2.3 Displaying the Booking System
2.4 Managing Bookings
2.5 Business Information & Communication
2.6 Granular Permissions (Abilities API)

Part 3: Pro Version User Guide

3.1 Activating Your License
3.2 Payment Gateways
3.3 VAT/TAX System
3.4 Advanced Pricing Rules

Part 4: Multilingual Support

4.1 Supported Translation Plugins
4.2 Setting Up Multilingual Content
4.3 Multilingual Email Templates

Part 5: Developer Reference

5.1 REST API
5.2 Webhooks & HMAC Security
5.3 Action Hooks
5.4 Filter Hooks

Part 6: Troubleshooting

6.1 Common Issues
6.2 Payment Problems
6.3 Tax Calculation Issues
6.4 Email Delivery Problems
6.5 Performance Optimization
6.6 iCal Sync Issues
6.7 Getting Support


Part 1: Getting Started

1.1 Installation & Activation

  1. Go to Plugins > Add New in your WordPress dashboard
  2. Search for "Modern Hotel Booking"
  3. Click Install Now and then Activate

Method 2: Manual Upload

  1. Download the plugin zip file
  2. Go to Plugins > Add New > Upload Plugin
  3. Select the zip file and click Install Now
  4. Click Activate Plugin

Method 3: FTP Upload

  1. Extract the modern-hotel-booking.zip file on your computer
  2. Upload the extracted folder to /wp-content/plugins/ via FTP
  3. Go to Plugins in your WordPress dashboard
  4. Find "Modern Hotel Booking" and click Activate

Post-Activation

After activation, a new menu item Hotel Booking will appear in your WordPress admin sidebar. The plugin automatically creates the necessary database tables.

1.2 Quick Start Guide

Get your hotel booking system running in 5 steps:

Step Action Location
1 Create Room Types Hotel Booking > Room Types
2 Add Individual Rooms Hotel Booking > Rooms
3 Configure Settings Hotel Booking > Settings
4 Display the Form Add block or shortcode to a page
5 Test a Booking Make a test reservation

1.3 System Requirements

Requirement Minimum Recommended
WordPress 6.6+ 7.0+
PHP 8.0 8.2+
MySQL 5.7 8.0+
Memory Limit 128MB 256MB

Required PHP Extensions:

  • OpenSSL (for payment encryption)
  • JSON
  • cURL (for payment APIs and iCal sync)

Recommended Extensions:

  • BCMath (for higher financial precision in invoicing)

Part 2: Free Version User Guide

The free version of Modern Hotel Booking provides everything you need to take reservations, manage rooms, and send email notifications.

2.1 Setting Up Your Hotel

Before accepting bookings, you must define your room inventory.

2.1.1 Room Types

Room Types are categories (e.g., "Standard Double", "Deluxe Suite", "Family Room") that define base pricing and capacity.

To create a Room Type:

  1. Go to Hotel Booking > Room Types
  2. Click Add New
  3. Configure the following fields:
Field Description Example
Name Display name "Deluxe Suite"
Description Details shown to guests "Spacious suite with ocean view..."
Base Price Per-night rate 150.00
Max Adults Maximum adult occupancy 2
Max Children Maximum child occupancy 2
Amenities Feature checkboxes Wi-Fi, AC, TV, Minibar
Featured Image Representative photo Upload image
  1. Click Publish to save

2.1.2 Individual Rooms

Individual Rooms are the actual physical rooms guests will stay in.

To create an Individual Room:

  1. Go to Hotel Booking > Rooms
  2. Click Add New
  3. Configure the following:
Field Description Example
Room Number/Name Unique identifier "Room 101" or "The Blue Cottage"
Assign Type Select Room Type Deluxe Suite
Status Availability Available
Custom Price Override base price (optional)
  1. Click Publish to save

2.2 Configuration

Go to Hotel Booking > Settings to configure global options.

2.2.1 General Settings

Setting Description Default
Check-in Time Standard arrival time 14:00
Check-out Time Standard departure time 11:00
Hotel Timezone (Pro Only) The local timezone of your property. This is critical for properties in regions where the server clock differs from local time. It ensures that "Same-day Turnover" and availability windows are calculated against your local clock. Version 2.4.2+ uses high-precision parsing to ensure iCal dates never shift, even in positive UTC offsets (e.g., UTC+2/3). WordPress Default
Notification Email Admin email for alerts [email protected]
Same-day Turnover Prevent same-day check-in/checkout Enabled
Booking Page The page where the booking form block/shortcode is placed -
Booking Page URL (Override) Custom URL to bypass the selected Booking Page -
Enable Children Management Allow selecting children on the booking form Disabled
Custom Guest Fields Define custom fields to collect additional guest information -
Save Data on Uninstall Persist booking data and settings upon plugin deletion (useful during upgrades) Enabled
Show Powered By Link Display a discretly branded link at the bottom of the booking form Enabled

2.2.2 Currency Settings

Setting Description Options
Currency Code ISO 4217 code USD, EUR, GBP, RON, etc.
Currency Symbol Display symbol $, €, £, lei
Symbol Position Before or after Before / After

2.2.3 Email Templates

Customize emails sent to guests for each booking status.

Available Statuses:

  • Pending - Booking received, awaiting confirmation
  • Confirmed - Booking confirmed
  • Cancelled - Booking cancelled

Available Placeholders:

Placeholder Replaced With
{customer_name} Guest's full name
{booking_id} Unique booking ID
{status} Current booking status
{check_in} Check-in date
{check_out} Check-out date
{total_price} Total booking amount
{room_name} Name of the booked room
{guests} Number of adult guests
{children} Number of child guests
{children_ages} Ages of all child guests
{nights} Number of nights
{phone} Guest phone number
{email} Guest email address
{special_requests} Guest special requests
{custom_fields} Custom field values
{payment_details} Payment confirmation section
{tax_breakdown} Tax breakdown section

2.2.3.1 Premium HTML Template Example (Pro Tip)

For a professional, modern look that matches your property's branding, you can use the following HTML template. This is particularly useful for the Pending Booking status at Hotel Booking > Settings > Emails.

Recommended Subject: Your booking at Beach House - {check_in} - {check_out}

Template HTML:

<div
  style="background-color: #f4f7f9;padding: 20px 10px;font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif"
>
  <div
    style="max-width: 650px;margin: 0 auto;background-color: #ffffff;border: 1px solid #e2e8f0;border-radius: 16px;overflow: visible"
  >
    <div style="padding: 20px;border-bottom: 1px solid #f1f5f9">
      <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td style="padding-bottom: 10px">
            <img
              src="https://beachhouse.ro/wp-content/uploads/cropped-beach-house-guest-house-1.jpg"
              alt="Beach House Logo"
              style="width: 100%;max-width: 160px;height: auto"
            />
          </td>
          <td
            align="right"
            style="font-size: 12px;color: #64748b;line-height: 1.4"
          >
            <strong style="color: #0f172a;font-size: 14px">Beach House</strong
            ><br />
            Strada D4, Nr. 57, Năvodari<br />
            CT 905701, România<br />
            +40737501765<br />
            <a
              href="https://beachhouse.ro/en/"
              style="color: #0077b6;text-decoration: none"
              >https://beachhouse.ro/</a
            ><br />
          </td>
        </tr>
      </table>
    </div>

    <div style="padding: 30px">
      <p style="font-size: 16px;margin-top: 0">
        Hi <strong>{customer_name}</strong>,
      </p>
      <p>Thank you for booking at <strong>Beach House</strong>!</p>

      <div
        style="background-color: #fff9db;border-left: 4px solid #fcc419;padding: 15px;margin: 25px 0;border-radius: 4px"
      >
        <strong style="color: #856404"
          >Your booking has not yet been confirmed.</strong
        ><br />
        <span style="font-size: 14px;color: #665c33">
          Please wait for an additional confirmation email or phone call from
          us.</span
        >
      </div>

      <h3
        style="color: #0077b6;border-bottom: 2px solid #f0f4f8;padding-bottom: 10px;margin-bottom: 20px;font-size: 18px"
      >
        Your details:
      </h3>

      <table
        width="100%"
        border="0"
        cellspacing="0"
        cellpadding="0"
        style="font-size: 14px;line-height: 1.8;color: #333"
      >
        <tr>
          <td style="color: #64748b"><strong>Booking ID:</strong></td>
          <td style="text-align: right">
            #{booking_id} <small style="color: #94a3b8">({status})</small>
          </td>
        </tr>
        <tr>
          <td style="color: #64748b">Name:</td>
          <td style="text-align: right">{customer_name}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Room:</td>
          <td style="text-align: right">{room_name}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Check-in:</td>
          <td style="text-align: right">{check_in} ({check_in_time})</td>
        </tr>
        <tr>
          <td style="color: #64748b">Check-out:</td>
          <td style="text-align: right">{check_out} ({check_out_time})</td>
        </tr>
        <tr>
          <td style="color: #64748b">Nights:</td>
          <td style="text-align: right">{nights}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Guests:</td>
          <td style="text-align: right">
            {guests} Adults, {children} Children
          </td>
        </tr>
        <tr>
          <td style="color: #64748b">Age of kids:</td>
          <td style="text-align: right">{children_ages}</td>
        </tr>
        <tr>
          <td style="color: #64748b">E-mail:</td>
          <td style="text-align: right">{customer_email}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Tel:</td>
          <td style="text-align: right">{customer_phone}</td>
        </tr>
        <tr>
          <td style="color: #64748b"></td>
          <td style="text-align: right">{custom_fields}</td>
        </tr>
      </table>

      <table
        width="100%"
        border="0"
        cellspacing="0"
        cellpadding="0"
        style="margin-top: 25px"
      >
        <tr>
          <td style="font-size: 13px">
            <p style="margin: 0;color: #475569">
              Looking forward to your arrival!
            </p>
            <p style="margin: 3px 0 0 0;font-weight: bold">Beach House</p>
          </td>
          <td align="right" style="vertical-align: bottom">
            <a
              href="https://wa.me/40737501765"
              style="background-color: #25D366;color: #ffffff;padding: 8px 14px;text-decoration: none;border-radius: 6px;font-weight: bold;font-size: 12px"
              >WhatsApp</a
            >
          </td>
        </tr>
      </table>

      #### 2.2.3.1 Premium HTML Email Templates (Pro Examples) For a
      professional, modern look that matches your property's branding, you can
      use these HTML templates at **Hotel Booking > Settings > Emails**. #####
      A. Pending Booking **Recommended Subject:** `Your booking at Beach House -
      {check_in} - {check_out}` **Message Body:** ```html
      <div
        style="background-color: #f4f7f9;padding: 20px 10px;font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif"
      >
        <div
          style="max-width: 650px;margin: 0 auto;background-color: #ffffff;border: 1px solid #e2e8f0;border-radius: 16px;overflow: visible"
        >
          <div style="padding: 20px;border-bottom: 1px solid #f1f5f9">
            <table width="100%" border="0" cellspacing="0" cellpadding="0">
              <tr>
                <td style="padding-bottom: 10px">
                  <img
                    src="https://beachhouse.ro/wp-content/uploads/cropped-beach-house-guest-house-1.jpg"
                    alt="Beach House Logo"
                    style="width: 100%;max-width: 160px;height: auto"
                  />
                </td>
                <td
                  align="right"
                  style="font-size: 12px;color: #64748b;line-height: 1.4"
                >
                  <strong style="color: #0f172a;font-size: 14px"
                    >Beach House</strong
                  ><br />
                  Strada D4, Nr. 57, Năvodari<br />
                  CT 905701, România<br />
                  +40737501765<br />
                  <a
                    href="mailto:[email protected]"
                    style="color: #0077b6;text-decoration: none"
                    >[email protected]</a
                  ><br />
                  <a
                    href="https://beachhouse.ro/en/"
                    style="color: #0077b6;text-decoration: none"
                    >https://beachhouse.ro/</a
                  ><br />
                </td>
              </tr>
            </table>
          </div>

          <div style="padding: 30px">
            <p style="font-size: 16px;margin-top: 0">
              Hi <strong>{customer_name}</strong>,
            </p>
            <p>Thank you for booking at <strong>Beach House</strong>!</p>

            <div
              style="background-color: #fff9db;border-left: 4px solid #fcc419;padding: 15px;margin: 25px 0;border-radius: 4px"
            >
              <strong style="color: #856404"
                >Rezervarea nu este confirmată automat.</strong
              ><br />
              <span style="font-size: 14px;color: #665c33"
                >Your booking has not yet been confirmed. Please wait for an
                additional confirmation email or phone call from us.</span
              >
            </div>

            <h3
              style="color: #0077b6;border-bottom: 2px solid #f0f4f8;padding-bottom: 10px;margin-bottom: 20px;font-size: 18px"
            >
              Your details:
            </h3>

            <table
              width="100%"
              border="0"
              cellspacing="0"
              cellpadding="0"
              style="font-size: 14px;line-height: 1.8;color: #333"
            >
              <tr>
                <td style="color: #64748b"><strong>Booking ID:</strong></td>
                <td style="text-align: right">
                  #{booking_id} <small style="color: #94a3b8">({status})</small>
                </td>
              </tr>
              <tr>
                <td style="color: #64748b">Name:</td>
                <td style="text-align: right">{customer_name}</td>
              </tr>
              <tr>
                <td style="color: #64748b">Room:</td>
                <td style="text-align: right">{room_name}</td>
              </tr>
              <tr>
                <td style="color: #64748b">Check-in:</td>
                <td style="text-align: right">{check_in} ({check_in_time})</td>
              </tr>
              <tr>
                <td style="color: #64748b">Check-out:</td>
                <td style="text-align: right">
                  {check_out} ({check_out_time})
                </td>
              </tr>
              <tr>
                <td style="color: #64748b">Nights:</td>
                <td style="text-align: right">{nights}</td>
              </tr>
              <tr>
                <td style="color: #64748b">Guests:</td>
                <td style="text-align: right">
                  {guests} Adults, {children} Children
                </td>
              </tr>
              <tr>
                <td style="color: #64748b">Age of kids:</td>
                <td style="text-align: right">{children_ages}</td>
              </tr>
              <tr>
                <td style="color: #64748b">E-mail:</td>
                <td style="text-align: right">{customer_email}</td>
              </tr>
              <tr>
                <td style="color: #64748b">Tel:</td>
                <td style="text-align: right">{customer_phone}</td>
              </tr>
              <tr>
                <td style="color: #64748b"></td>
                <td style="text-align: right">{custom_fields}</td>
              </tr>
            </table>

            <table
              width="100%"
              border="0"
              cellspacing="0"
              cellpadding="0"
              style="margin-top: 25px"
            >
              <tr>
                <td style="font-size: 13px">
                  <p style="margin: 0;color: #475569">
                    Looking forward to your arrival!
                  </p>
                  <p style="margin: 3px 0 0 0;font-weight: bold">Beach House</p>
                </td>
                <td align="right" style="vertical-align: bottom">
                  <a
                    href="https://wa.me/40737501765"
                    style="background-color: #25D366;color: #ffffff;padding: 8px 14px;text-decoration: none;border-radius: 6px;font-weight: bold;font-size: 12px"
                    >WhatsApp</a
                  >
                </td>
              </tr>
            </table>

            <div
              style="margin-top: 30px;border-top: 1px solid #f1f5f9;padding-top: 20px"
            ></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
B. Confirmed Booking

Recommended Subject: Your booking at Beach House is CONFIRMED - {check_in} - {check_out} Message Body:

<div
  style="background-color: #f4f7f9;padding: 20px 10px;font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif"
>
  <div
    style="max-width: 650px;margin: 0 auto;background-color: #ffffff;border: 1px solid #e2e8f0;border-radius: 16px;overflow: visible"
  >
    <div style="padding: 20px;border-bottom: 1px solid #f1f5f9">
      <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td style="padding-bottom: 10px">
            <img
              src="https://beachhouse.ro/wp-content/uploads/cropped-beach-house-guest-house-1.jpg"
              alt="Beach House Logo"
              style="width: 100%;max-width: 160px;height: auto"
            />
          </td>
          <td
            align="right"
            style="font-size: 12px;color: #64748b;line-height: 1.4"
          >
            <strong style="color: #0f172a;font-size: 14px">Beach House</strong
            ><br />
            Strada D4, Nr. 57, Năvodari<br />
            CT 905701, România<br />
            +40737501765<br />
            <a
              href="mailto:[email protected]"
              style="color: #0077b6;text-decoration: none"
              >[email protected]</a
            ><br />
            <a
              href="https://beachhouse.ro/en/"
              style="color: #0077b6;text-decoration: none"
              >https://beachhouse.ro/</a
            ><br />
          </td>
        </tr>
      </table>
    </div>

    <div style="padding: 30px">
      <p style="font-size: 16px;margin-top: 0">
        Hi <strong>{customer_name}</strong>,
      </p>
      <p>Thanks for making a reservation at <strong>Beach House</strong>!</p>

      <div
        style="background-color: #ccffcc;border-left: 4px solid #009900;padding: 15px;margin: 25px 0;border-radius: 4px"
      >
        <strong style="color: #00cc00">Your booking is confirmed.</strong><br />
        <span style="font-size: 14px;color: #003300"
          >We are happy to confirm your booking!</span
        >
      </div>

      <h3
        style="color: #0077b6;border-bottom: 2px solid #f0f4f8;padding-bottom: 10px;margin-bottom: 20px;font-size: 18px"
      >
        Your details:
      </h3>

      <table
        width="100%"
        border="0"
        cellspacing="0"
        cellpadding="0"
        style="font-size: 14px;line-height: 1.8;color: #333"
      >
        <tr>
          <td style="color: #64748b"><strong>Booking ID:</strong></td>
          <td style="text-align: right">
            #{booking_id} <small style="color: #94a3b8">({status})</small>
          </td>
        </tr>
        <tr>
          <td style="color: #64748b">Name:</td>
          <td style="text-align: right">{customer_name}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Room:</td>
          <td style="text-align: right">{room_name}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Check-in:</td>
          <td style="text-align: right">{check_in} ({check_in_time})</td>
        </tr>
        <tr>
          <td style="color: #64748b">Check-out:</td>
          <td style="text-align: right">{check_out} ({check_out_time})</td>
        </tr>
        <tr>
          <td style="color: #64748b">Nights:</td>
          <td style="text-align: right">{nights}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Guests:</td>
          <td style="text-align: right">
            {guests} Adults, {children} Children
          </td>
        </tr>
        <tr>
          <td style="color: #64748b">Age of kids:</td>
          <td style="text-align: right">{children_ages}</td>
        </tr>
        <tr>
          <td style="color: #64748b">E-mail:</td>
          <td style="text-align: right">{customer_email}</td>
        </tr>
        <tr>
          <td style="color: #64748b">Tel:</td>
          <td style="text-align: right">{customer_phone}</td>
        </tr>
        <tr>
          <td style="color: #64748b"></td>
          <td style="text-align: right">{custom_fields}</td>
        </tr>
      </table>

      <table
        width="100%"
        border="0"
        cellspacing="0"
        cellpadding="0"
        style="margin-top: 30px"
      >
        <tr>
          <td>
            <p style="margin: 0;font-size: 14px;color: #475569">
              Many Thanks, see you soon!
            </p>
            <p style="margin: 5px 0 0 0;font-weight: bold">Beach House</p>
          </td>
          <td style="text-align: right;vertical-align: bottom">
            <a
              href="https://wa.me/40737501765"
              style="background-color: #25D366;color: #ffffff;padding: 8px 15px;text-decoration: none;border-radius: 6px;font-weight: bold;font-size: 13px"
              >WhatsApp</a
            >
          </td>
        </tr>
      </table>

      <div
        style="margin-top: 30px;border-top: 1px solid #f1f5f9;padding-top: 20px"
      ></div>
    </div>
  </div>
</div>
C. Cancelled Booking

Recommended Subject: Canceling your booking at Beach House - {check_in} - {check_out} Message Body:

<div
  style="background-color: #f4f7f9;padding: 20px 10px;font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif"
>
  <div
    style="max-width: 650px;margin: 0 auto;background-color: #ffffff;border: 1px solid #e2e8f0;border-radius: 16px;overflow: visible"
  >
    <div style="padding: 20px;border-bottom: 1px solid #f1f5f9">
      <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td style="padding-bottom: 10px">
            <img
              src="https://beachhouse.ro/wp-content/uploads/cropped-beach-house-guest-house-1.jpg"
              alt="Beach House Logo"
              style="width: 100%;max-width: 160px;height: auto"
            />
          </td>
          <td
            align="right"
            style="font-size: 12px;color: #64748b;line-height: 1.4"
          >
            <strong style="color: #0f172a;font-size: 14px">Beach House</strong
            ><br />
            Strada D4, Nr. 57, Năvodari<br />
            CT 905701, România<br />
            +40737501765<br />
            <a
              href="mailto:[email protected]"
              style="color: #0077b6;text-decoration: none"
              >[email protected]</a
            ><br />
            <a
              href="https://beachhouse.ro/en/"
              style="color: #0077b6;text-decoration: none"
              >https://beachhouse.ro/</a
            ><br />
          </td>
        </tr>
      </table>
    </div>

    <div style="padding: 30px">
      <p style="font-size: 16px;margin-top: 0">
        Hi <strong>{customer_name}</strong>,
      </p>
      <p>Thanks for making a booking at <strong>Beach House</strong>!</p>

      <div
        style="background-color: #ff9999;border-left: 4px solid #cc0000;padding: 15px;margin: 25px 0;border-radius: 4px"
      >
        <strong style="color: #ff0000"
          >We are very sorry to reject your booking! {check_in} -
          {check_out}</strong
        ><br />
        <span style="font-size: 14px;color: #800000"
          >We already have another reservation or another issue for your
          requested travel period.</span
        >
      </div>

      <table
        width="100%"
        border="0"
        cellspacing="0"
        cellpadding="0"
        style="margin-top: 30px"
      >
        <tr>
          <td>
            <p style="margin: 0;font-size: 14px;color: #475569">
              We would be very happy to welcome you any time soon.
            </p>
            <p style="margin: 5px 0 0 0;font-weight: bold">Beach House</p>
          </td>
          <td style="text-align: right;vertical-align: bottom">
            <a
              href="https://wa.me/40737501765"
              style="background-color: #25D366;color: #ffffff;padding: 8px 15px;text-decoration: none;border-radius: 6px;font-weight: bold;font-size: 13px"
              >WhatsApp</a
            >
          </td>
        </tr>
      </table>

      <div
        style="margin-top: 30px;border-top: 1px solid #f1f5f9;padding-top: 20px"
      ></div>
    </div>
  </div>
</div>

[!TIP] > Dynamic Payment Summary Integration: Note the unclosed <div> at the very end of every template. This is a deliberate technique—it allows the plugin to automatically "join" the generated Booking Payment Summary (totals, taxes, and deposit info) into the styled email container. This ensures that the system-generated pricing table inherits your brand's layout and padding seamlessly.

2.2.4 Frontend Labels

Translate or customize every label on the booking form.

Multilingual Format (qTranslate-X):

[:en]Check In[:ro]Check-in[:de]Anreise[:fr]Arrivée[:]

2.6 Granular Permissions (Abilities API)

As of Version 2.4.2, Modern Hotel Booking integrates with the modern WordPress Abilities API (native to WordPress 7.0+) to provide granular control over administrative access and conversational AI capabilities. This allows you to delegate specific tasks to different staff members and regulate AI assistant behaviors without granting full Administrator privileges.

2.6.1 Administrative Abilities

These abilities govern access to the WordPress admin dashboard:

Ability Internal Name Description
Manage Bookings mhbo_manage_bookings View, edit, confirm, or cancel reservations.
View Analytics mhbo_view_analytics Access the Analytics dashboard and financial reports.
Manage Settings mhbo_manage_settings Configure plugin global options, payments, and AI.

By default, the Administrator role is granted all administrative abilities. You can use a role management plugin (like User Role Editor) to grant these specific mhbo_ capabilities to other roles (e.g., "Editor" or "Shop Manager").

2.6.2 AI Concierge Capabilities (WP 7.0+)

In WordPress 7.0+, guest actions performed via the AI Concierge are mapped to specific custom Abilities registered on the wp_abilities_api_init hook. The system checks against these permissions prior to executing any agentic action:

Free Version Abilities:

  • mhbo_ai_hotel_info: Query general hotel details and business information.
  • mhbo_ai_check_availability: Search room availability and fetch base night rates.
  • mhbo_ai_room_details: Retrieve specific room features, amenities, and image listings.
  • mhbo_ai_policies: Access check-in, checkout, and cancellation policy information.
  • mhbo_ai_get_knowledge_base: Read custom cached knowledge base structures.
  • mhbo_ai_local_tips: Return local guide recommendations (restaurants, transport).
  • mhbo_ai_get_business_card: Retrieve payment instructions and professional contact cards.
  • mhbo_ai_create_booking_link: Generate pre-filled checkout redirection links.

Pro Version Abilities:

  • mhbo_ai_create_booking: Draft direct booking reservations.
  • mhbo_ai_modify_booking: Update dates, guests, or room parameters on existing active bookings.
  • mhbo_ai_cancel_booking: Process guest-initiated cancellations.
  • mhbo_ai_apply_promo: Evaluate and apply discount coupons to active bookings.
  • mhbo_ai_guest_history: Retrieve booking log histories for returning verified guests.

2.6.3 WordPress Abilities Explorer

WordPress 7.0+ introduces a built-in Abilities Explorer to help administrators inspect, test, and manage registered capabilities and AI tools. Since Modern Hotel Booking registers all its AI Concierge capabilities as native WordPress Abilities, they will automatically appear here.

How to Access the Explorer

To view and manage registered abilities:

  1. Navigate to your WordPress Admin dashboard.
  2. Go to Tools > Abilities Explorer (wp-admin/tools.php?page=ai-abilities-explorer).

Using the Explorer with Modern Hotel Booking

Within the Abilities Explorer, you can perform the following actions:

  • Browse Categories: Inspect abilities grouped under the custom categories registered by our plugin: Hotel Information, Booking Management, and Guest Services.
  • Inspect Schema definitions: Click on any ability (e.g., mhbo/check-availability or mhbo/get-room-details) to view its structured JSON Schema. You can verify input schemas (parameters the AI client can send) and output schemas (structure of returned data).
  • Test Capabilities: Use the interactive "Test Ability" tab inside the Explorer to manually trigger an ability. For example, you can query a room's details or test a check-availability payload without having to start a chat session.
  • Verify Permissions & Visibility: View the active permission_callback for each ability, as well as metadata like Model Context Protocol (MCP) public visibility status.

2.3 Displaying the Booking System

The plugin provides both Gutenberg blocks and shortcodes for displaying the booking system.

2.3.1 Hotel: Booking Form

Block Name: modern-hotel-booking/booking-form

A full-featured booking form that allows guests to:

  • Select check-in and check-out dates
  • Choose number of adults and children
  • Select a room from available options
  • See pricing in real-time
  • Complete the booking request

Using Block Editor (Recommended):

  1. Edit the page where you want the booking form
  2. Click the + button to add a block
  3. Search for "Hotel: Booking Form"
  4. Drag the block onto the page
  5. Configure block settings in the sidebar (optional)
  6. Publish the page

Block Attributes:

Attribute Type Default Description
roomId number 0 Pre-select a specific room. Set to 0 for manual selection.
anchor string - Unique HTML ID for the block (used for anchor links).

[!TIP] > Live Preview: The Booking Form now features a live Gutenberg preview that renders the actual form interface directly in the editor, allowing you to see exactly how your guests will experience the reservation flow.

2.3.2 Hotel: Room Calendar

Block Name: modern-hotel-booking/room-calendar

Displays a read-only calendar showing room availability dates. Perfect for:

  • Showing a specific room's availability
  • Displaying booked vs. available dates
  • Helping guests plan their stay

Using Block Editor:

  1. Edit the page
  2. Click the + button to add a block
  3. Search for "Hotel: Room Calendar"
  4. Drag the block onto the page
  5. Select the room from the dropdown in block settings
  6. Publish the page

Block Attributes:

Attribute Type Default Description
roomId number 0 Select which room's availability to display (required).
anchor string - Unique HTML ID for the block.

2.3.3 Booking Form Shortcode

Shortcode: [mhbo_booking_form] or [modern_hotel_booking] (legacy alias)

Alternative to using blocks. Accepts same parameters as block settings.

Shortcode Parameters:

| room_id | Pre-select a specific room | [mhbo_booking_form room_id="123"] | | show_calendar | Show availability calendar | [mhbo_booking_form show_calendar="yes"] |

2.3.4 AI Concierge Shortcode

Shortcode: [mhbo_ai_concierge]

Embed the AI virtual assistant directly on any page. This is particularly useful for dedicated support or "Ask Marina" pages.

Shortcode Parameters:

Parameter Description Example
variant floating or inline [mhbo_ai_concierge variant="inline"]
position bottom-right or bottom-left [mhbo_ai_concierge position="bottom-left"]
welcome_message Override the default greeting [mhbo_ai_concierge welcome_message="Hi there!"]
theme (Pro) Custom UI theme name [mhbo_ai_concierge theme="glass"]

2.3.5 Room Calendar Shortcode

Shortcode: [mhbo_room_calendar room_id="123"]

Display availability for a specific room. Replace 123 with the Room ID (found in the Rooms list).

2.3.5 Booking Search Widget

A compact search box for sidebars or footers.

  1. Go to Appearance > Widgets
  2. Find "MHBO: Booking Search" widget
  3. Drag it to your desired widget area
  4. Set the Title (e.g., "Book Your Stay")

[!TIP] > Widget Performance: The widget operates exceptionally fast as a "read-only dispatcher." It simply captures dates and dynamically redirects users to your primary booking page to process the calculation, preventing fragmented booking logic across your website.

2.3.7 Business Information Blocks & Shortcodes

The plugin provides several specialized blocks to display your property's professional identity and offline payment methods efficiently.

Available Blocks:

  • Hotel: Company Profile (modern-hotel-booking/company-info)
  • Hotel: Chat on WhatsApp (modern-hotel-booking/whatsapp-button)
  • Hotel: Bank Transfer Details (modern-hotel-booking/banking-details)
  • Hotel: Pay via Revolut (modern-hotel-booking/revolut-details)
  • Hotel: Business Contact Card (modern-hotel-booking/business-card)

Block Attributes (Gutenberg):

Block Attribute Type Default Description
Company Profile layout string "vertical" vertical or horizontal layout.
showLogo boolean true Show/hide property logo.
showAddress boolean true Show/hide physical address.
Chat on WhatsApp style string "button" button, link, or floating.
text string - Custom button text.
message string - Pre-filled guest message.
Bank Details layout string "card" card or list view.
showInstructions boolean true Show/hide transfer labels.
Pay via Revolut layout string "card" card or list view.
showQR boolean true Show/hide Payment QR code.
showLink boolean true Show/hide Revolut.me link.
Business Card sections string "all" Comma-separated list of items.

Additional Shortcodes:

Shortcode Description Example
[mhbo_company_info] Display company details [mhbo_company_info layout="horizontal"]
[mhbo_whatsapp] WhatsApp chat link/button [mhbo_whatsapp text="Contact Us"]
[mhbo_banking_details] Bank transfer information [mhbo_banking_details layout="card"]
[mhbo_revolut_details] Revolut payment info [mhbo_revolut_details show_qr="yes"]
[mhbo_business_card] Combined business card [mhbo_business_card sections="company,whatsapp"]
[mhbo_payment_methods] Bank + Revolut grid [mhbo_payment_methods]

2.4 Managing Bookings

  1. Go to Hotel Booking > Bookings
  2. View all bookings with status indicators

Booking Actions:

Action Description
View See complete guest details, pricing, and dates
Edit Modify booking details
Confirm Change status from Pending to Confirmed
Cancel Cancel the booking
Add Notes Private admin notes (not visible to guests)
Resend Email Resend confirmation email to guest

2.5 Business Information & Communication

Configuring your property's professional identity and offline payment methods is managed in Hotel Booking > Settings > Business.

2.5.1 Company Profile

Fill in your legal company name, physical address, registration numbers, and upload your high-resolution logo. This data can be displayed on your website using the [mhbo_company_info] shortcode or the Company Info Gutenberg block.

2.5.2 WhatsApp Integration

Enable direct communication with your guests.

  • Phone Number: Enter in international format (e.g., +34600000000).
  • Display Styles:
    • Inline Button: Fits anywhere in your content.
    • Floating Button: Sticky button in the corner of the screen.
    • Text Link: Simple hyperlink with a WhatsApp icon.
  • Default Message: Pre-fill the guest's message (e.g., "Hello, I have a question about my booking...").

2.5.3 Pay on Arrival & Offline Payments

If you accept offline payments, use these sections to provide your secure details.

  • Bank Transfer: Supports IBAN, SWIFT/BIC, and custom reference prefixes (e.g., BOOKING-{id}).
  • Revolut: Provide your Revolut.me link and upload a custom Payment QR Code for instant mobile transfers.
  • Instructions: Use the rich-text editor to provide detailed payment or verification steps for your guests.

Part 3: Pro Version User Guide

Unlock advanced automation, payments, and analytics with a Pro license.

3.1 Activating Your License

  1. Go to Hotel Booking > Settings > License
  2. Enter your Pro License Key
  3. Click Activate License
  4. New tabs appear: Payments, Tax, API, GDPR, Extras, Themes

3.1.1 License Verification & Resilience

To prevent sudden deactivation of Pro features during network outages, temporary server downtime, or external API failures, the plugin implements an Adaptive License Verification system:

  • Adaptive Checking Intervals: The verification engine dynamically scales check frequencies. A healthy license with a distant expiration date is checked every 45 days. As expiration approaches or if the license health status changes, the interval scales down to 14 days, 7 days, and finally daily checks.
  • Fail-Safe Network Retries: If a scheduled license check fails due to network dropouts or API errors, the system does not immediately revoke Pro privileges. Instead, it schedules 3 retries spaced 6 hours apart.
  • Extended Grace Periods: If all retries fail, a grace period begins. This grace period scales between 3 and 21 days based on license health and client loyalty, ensuring ample time to resolve billing or network issues before any Pro functionality is restricted.

3.2 Payment Gateways

Accept credit cards and automate confirmations with integrated payment processing.

3.2.1 Stripe Integration

Stripe provides secure credit card processing with Apple Pay and Google Pay support. The MHBO engine uses a Server-Side Intent model to ensure transaction integrity and seamless recovery for 3D Secure (3DS) authentication redirects.

Setup Instructions:

  1. Go to Hotel Booking > Settings > Payments
  2. Enable Stripe by checking the box
  3. Select Mode:
    • Test - For development (use test cards)
    • Live - For production (real transactions)
  4. Enter your API keys from Stripe Dashboard:
    • Publishable Key - Safe for frontend
    • Secret Key - Encrypted in database
  5. Click Test Credentials to verify

Stripe Test Card Numbers:

Card Number Result
4242 4242 4242 4242 Success
4000 0000 0000 0002 Decline
4000 0000 0000 9995 Insufficient funds

Apple Pay & Google Pay:

When Stripe is enabled, the booking form automatically displays Apple Pay and Google Pay buttons for compatible devices. Requirements:

  • HTTPS (SSL certificate)
  • Domain verification in Stripe Dashboard
  • Compatible browser/device

3.2.2 PayPal Integration

Setup Instructions:

  1. Go to Hotel Booking > Settings > Payments
  2. Enable PayPal by checking the box
  3. Select Mode (Sandbox or Live)
  4. Enter credentials from PayPal Developer:
    • Client ID - Public identifier
    • Secret - Encrypted in database
  5. Click Test Credentials to verify

3.2.3 Pay on Arrival

Allow guests to book now and pay at arrival.

Setup:

  1. Go to Hotel Booking > Settings > Payments
  2. Enable Pay on Arrival
  3. Enter instructions shown to guests

Behavior:

  • Payment status set to "pending" until collected

[!IMPORTANT] > Enterprise-Grade Security: All sensitive API keys (Stripe Secret, PayPal Secret) are stored in the database using high-security AES-256-CBC encryption. This ensures that even if the database is compromised, your financial credentials remain protected.

3.2.4 Real-time Availability & Fraud Prevention

Modern Hotel Booking incorporates advanced server-side protections:

  • Atomic Availability Locking: The system performs a final real-time availability check milliseconds before processing payment, preventing race conditions. It utilizes native MySQL advisory locks (GET_LOCK) to guarantee that only one guest can secure the final room of a specific type at any given millisecond. This bypasses all caching layers for maximum accuracy.
  • Financial Integrity (Anti-Tamper): Every booking total is recalculated server-side using the Pricing engine immediately during the checkout process. This ensures that any malicious modification of pricing data via the browser console or URL parameters is automatically detected and corrected before payment.
  • 3DS Recovery & Persistence: In rare cases where guests are redirected for 3D Secure verification, the plugin uses a state-aware recovery mechanism to safely persist guest data (including children's ages and extras) until the payment is fully confirmed by the Stripe webhook.
  • Server-to-Server Verification: PayPal and Stripe orders are verified directly with their respective APIs to ensure the transaction amount matches the booking total.
  • Rate Limiting (Brute Force Protection): Form submissions are strictly rate-limited to 5 requests per minute per IP address, preventing spam automated bots from filling your database.

Payment Statuses:

Status Description Color
Pending Awaiting payment Yellow
Processing Payment in progress Blue
Completed Payment received Green
Failed Payment attempt failed Red
Refunded Payment returned Gray

3.3 VAT/TAX System

Comprehensive tax management for hotels worldwide.

3.3.1 Tax Modes Explained

Mode Description Example
Disabled No tax calculation Price = $100
VAT (Inclusive) Tax included in displayed price Display $100, includes $16.67 VAT at 20%
Sales Tax (Exclusive) Tax added on top of price Display $100 + $20 tax = $120 total

3.3.2 Configuring Tax Rates

  1. Go to Hotel Booking > Settings > Tax
  2. Select Tax Mode (Disabled/VAT/Sales Tax)
  3. Enter Accommodation Tax Rate (for room charges)
  4. Enter Extras Tax Rate (for add-ons, may differ)
  5. Add Tax Registration Number (displayed on invoices)

Country-Specific Reference Rates:

Country Standard VAT Reduced (Hotels)
Romania 21% 11%
Germany 19% 7%
France 20% 10%
Italy 22% 10%
Spain 21% 10%
UK 20% 5%

Note: Rates may change. Verify current rates with local authorities.

3.3.3 Multilingual Tax Labels

Translate tax labels for multilingual sites:

[:en]VAT[:ro]TVA[:de]MwSt[:fr]TVA[:]

3.4 Advanced Pricing Rules

3.4.1 Seasonal Pricing

Create date-based pricing adjustments.

To Create a Seasonal Rule:

  1. Go to Hotel Booking > Pricing Rules
  2. Click Add New Rule
  3. Configure:
Setting Description
Name Rule name (e.g., "Summer Season")
Start Date First day of the season
End Date Last day of the season
Adjustment Type Fixed or Percentage
Amount Price change amount

Adjustment Types:

Type Example Result
Fixed Increase +$50 $100 becomes $150
Fixed Decrease -$20 $100 becomes $80
Percentage Increase +20% $100 becomes $120
Percentage Decrease -15% $100 becomes $85

3.4.2 Weekend & Holiday Multipliers

Weekend Pricing:

  1. Go to Hotel Booking > Settings > Advanced Pricing
  2. Select Weekend Days (Fri/Sat/Sun)
  3. Select Weekend Modifier Type (multiplier, percent, or fixed)
  4. Set Weekend Modifier Amount (e.g., 1.2 for a 20% multiplier increase, 20 for a 20% percent increase, or 50 for a $50 fixed increase)

Holiday Pricing:

  1. Go to Hotel Booking > Pricing Rules
  2. Add a new rule for your holiday dates
  3. Select Adjustment Type (Fixed or Percentage)
  4. Set the Amount

3.4.3 Global Stay Limits

New in v2.4.0, you can set property-wide stay constraints that apply to all bookings unless overridden by a specific Room Type rule.

  1. Go to Hotel Booking > Settings > General
  2. Locate the Global Stay Limits section:
    • Global Minimum Stay: Minimum consecutive nights required for any booking.
    • Global Maximum Stay: Maximum consecutive nights allowed (use 0 for no limit).

[!TIP] > Priority Logic: If a Room Type has a 3-night minimum and the Global limit is 1-night, the Room Type (3-night) will prevail. Specificity always wins over global rules.

3.4.4 Custom Hotel Timezone

To ensure your calendar, availability rules, and iCal sync are perfectly aligned with your physical property (even if your server is in a different region):

  1. Go to Hotel Booking > Settings > General
  2. Find Hotel Timezone.
  3. Select your local timezone from the dropdown.

All check-in/out times and date-based rules will now be computed using this physical location's clock.

3.4.5 Financial Precision (BCMath)

To ensure accounting-grade accuracy, the pricing engine utilizes the PHP BCMath extension for all currency calculations. This prevents common floating-point rounding errors often found in simpler booking systems. If your server does not have BCMath enabled, a high-precision fallback is automatically active.

[!NOTE] Pricing rules have priorities. Weekend modifiers are applied to the base rate first, and then Seasonal/Holiday rules are applied on top of that result.

[!TIP] For per-day precision — setting a specific price, blocking a date, or applying min/max stay restrictions on a single night — use the Admin Calendar Editor (see section 3.11). Calendar overrides always win over seasonal rules.

3.4.6 Multi-Select Pricing Override Example

To set a specific price for all room types on every Saturday in July:

  1. Go to Hotel Booking > Inventory (Calendar View).
  2. Click Bulk Update.
  3. Select Date Range: July 1st to July 31st.
  4. Check Days of Week: Saturday.
  5. Enter Custom Price: 250.
  6. Click Apply & Save.

3.5 Booking Extras & Add-ons

Upsell services during checkout. From Hotel Booking > Extras, you can manage optional or mandatory services.

3.5.1 Mandatory Fees (Cleaning, Resort, etc.)

You can mark any extra as Compulsory. These items are automatically added to every booking and cannot be removed by the guest.

  • Example: A $50 "Cleaning Fee" per booking.
  • Example: A $10 "City Tax" per person.

3.5.2 Compulsory Service Fee (Percentage)

For a general service charge applied to the entire reservation:

  1. Go to Hotel Booking > Settings > Payments.
  2. Enable Compulsory Service Fee.
  3. Set Fee Type to Percentage.
  4. Set Value to 5.00 (for 5%).
  5. This fee is calculated on the Gross Total before taxes are applied.

Pricing Models:

Model Calculation Example
Per Booking One-time fee $50 transfer
Per Person × Total Guests $15 × 4 guests = $60
Per Day × Nights $10 × 3 nights = $30
Per Person Per Day × Guests × Nights $5 × 4 × 3 = $60

3.6 iCal Sync Manager

Prevent double bookings by syncing with external OTA platforms in both directions. The system is per-room — each physical room has its own export URL and its own set of inbound connections, giving you independent control and key rotation without affecting other rooms.

[!IMPORTANT] > Pro Feature Only: The iCal Synchronization interface is physically absent from the Free distribution of the plugin. This functionality is exclusive to the Pro version.

Supported Platforms (auto-detected from the URL — no manual selection needed):

Platform Badge Color Detected From
Airbnb Red airbnb.com in URL
Booking.com Navy booking.com or admin.booking in URL
Google Calendar Blue google.com or calendar.google in URL
Custom / Other Grey Any other HTTPS URL

Complete Setup Walkthrough (Do This for Each Room)

This is the full process from zero to two-way sync for one room. Repeat for every room you list on external platforms.

What two-way sync means:

  • Your site → OTA: When a guest books directly on your site, those dates become blocked on the OTA platform (Airbnb, etc.).
  • OTA → Your site: When a guest books on the OTA, those dates become blocked on your site.

Both directions must be configured. The steps below cover both.

[!IMPORTANT] > Booking.com restriction (March 2025): Booking.com no longer accepts iCal feeds from personal or custom-domain websites. Pasting your MHBO Export URL into Booking.com's extranet will return "This iCal URL isn't valid." This is a Booking.com policy decision — the feed itself is valid. See Section 3.6.9 — Booking.com Limitation & Workarounds for your options. The import direction (Booking.com → MHBO) still works and should always be configured.


Step 1 — Open the room's iCal page

  1. Go to Hotel Booking > Rooms in your WordPress dashboard
  2. Find the room (e.g., "Room 101") and click the iCal icon in its Actions column
  3. The iCal Sync page for that room opens

Step 2 — Copy your Export URL and give it to Airbnb

This tells Airbnb about your direct bookings so it blocks those dates on their calendar.

  1. At the top of the iCal page, find the Deployment Export URL field
  2. Click Copy URL — the URL is now in your clipboard
  3. Log in to Airbnb → Calendar for your listing → Availability SettingsConnect CalendarsImport Calendar → paste URL → Save

Airbnb re-polls this URL approximately every 2–3 hours. After saving, wait up to 3 hours before assuming something is wrong.

[!WARNING] > Booking.com cannot import this URL. Since March 2025, Booking.com rejects iCal feeds from any non-OTA website. Skip this step for Booking.com — see Section 3.6.9 for the available workarounds.


Step 3 — Get the OTA's iCal URL and add it to MHBO

This tells your site about OTA bookings.

  1. Go to your OTA platform and find its iCal export URL:

    Airbnb: Calendar → Availability Settings → Export Calendar → copy the .ics URL

    Booking.com: Extranet → Rates & Availability → Synchronise Calendars → Export Calendar (iCal) → copy the .ics URL

  2. Back on the MHBO iCal page, scroll down to Import External Calendars

  3. In the form below the connections table:

    • Connection Label: type a descriptive name, e.g. Airbnb Room 101
    • iCal Feed URL: paste the .ics URL you just copied
  4. Click Connect Calendar

  5. The platform badge (Airbnb / Booking.com) is set automatically — no dropdown needed

  6. The connection appears in the table with status Pending


Step 4 — Trigger the first sync

  1. In the connections table, click the refresh (↻) icon next to the connection you just added
  2. Wait a few seconds, then reload the page
  3. The status should change to Synced (green check) and show the number of events imported
  4. Any existing OTA bookings now appear in your Hotel Booking > Bookings list as external reservations

Step 5 — Confirm it's working

  • Open the Export URL in your browser — you should see valid iCal text starting with BEGIN:VCALENDAR
  • Validate the feed at icalendar.org/validator.html if you see a rejection error from any OTA
  • The automatic background sync (MHBO pulling OTA feeds) runs every 1 hour by default

Realistic sync time expectations:

Direction Platform How long to expect
OTA → MHBO (import) Airbnb, Booking.com Up to 1 hour (your MHBO cron frequency)
MHBO → Airbnb (export) Airbnb Airbnb re-polls every 2–3 hours; plan for up to 3 hours
MHBO → Booking.com (export) Booking.com Blocked since March 2025 — see Section 3.6.9

[!IMPORTANT] iCal sync is never instant. There is always a window — up to 3 hours for Airbnb, up to 24 hours for Booking.com's own calendar refresh — where a double booking is possible. For high-volume properties, a real-time channel manager API connection eliminates this risk.

[!TIP] > Repeat for each room and each platform. If Room 101 is listed on both Airbnb and Booking.com, you will have two connections in the table — one for each platform — both sharing the same single Export URL.


3.6.1 Step 1 — Open a Room's iCal Page

  1. Go to Hotel Booking > Rooms
  2. Locate the room you want to connect and click its iCal action icon in the row Actions column
  3. The iCal Sync page opens (heading: "iCal Sync — Room [number]")

[!NOTE] Every room is configured independently. Repeat these steps for each physical room you list on Airbnb or Booking.com.


3.6.2 Step 2 — Export: Share Your Availability With OTAs

The Deployment Export URL at the top of the iCal page is the HTTPS feed your OTA platforms will poll to learn which dates are already booked on your site.

About the export URL:

  • Format: https://yoursite.com/mhbo-ical/room-{id}.ics?key={24-char-token}
  • Each room has its own unique key — rotating one room's key does not affect any other room
  • The key is auto-generated on first access and stored permanently
  • The ICS feed is object-cached for 1 hour to reduce server load; the cache clears automatically when a booking changes

To copy the export URL: Click the Copy URL button to the right of the URL field. The button flashes "Copied!" for 2 seconds.

Giving your MHBO calendar to Airbnb:

  1. Log in to Airbnb → Calendar for your listing
  2. Click AvailabilityConnect Calendars (or "Import Calendar")
  3. Paste your MHBO Export URL and save

Airbnb will begin polling the feed automatically. Re-polling happens approximately every 2–3 hours; you can also trigger a manual refresh from Airbnb's calendar settings.

Giving your MHBO calendar to Booking.com:

[!CAUTION] > This direction is blocked by Booking.com (since March 2025). Booking.com validates iCal import URLs by domain and rejects any URL not from a recognized OTA platform. You will receive the error "This iCal URL isn't valid — please try again" regardless of whether your feed is technically correct. This is not a bug in MHBO — the feed is RFC 5545 compliant. See Section 3.6.9 — Booking.com Limitation & Workarounds for alternatives.


3.6.3 Step 3 — Import: Pull OTA Bookings into MHBO

Connections you add here instruct the plugin to fetch the OTA's calendar on a schedule and create external bookings for any occupied dates, blocking them from new reservations.

To add a new connection:

  1. In the Import External Calendars section, find the form below the connections table
  2. Fill in:
    • Connection Label — a descriptive name, e.g. Airbnb Room 101 or Travelminit Suite
    • iCal Feed URL (HTTPS) — the .ics URL provided by the OTA (see below)
  3. Click Connect Calendar
  4. The platform is auto-detected (Airbnb, Booking.com, Travelminit, Szallas.hu, etc.) — no dropdown needed
  5. The new connection appears in the table with status Pending until the first sync completes

[!IMPORTANT] Only HTTPS URLs pointing to public OTA calendars are accepted. Private IP ranges, localhost, and non-HTTPS URLs are rejected by the SSRF protection layer.

Getting your iCal URL from Airbnb:

  1. Log in to Airbnb → Calendar for your listing
  2. Click Availability SettingsExport Calendar
  3. Copy the .ics URL shown

Getting your iCal URL from Booking.com:

  1. Log in to Booking.com Extranet → Rates & Availability
  2. Click Synchronise CalendarsExport Calendar (iCal)
  3. Copy the .ics URL shown

3.6.4 Reading the Connections Table

Column What you see
Platform Color-coded badge: Airbnb (red), Booking.com (navy), Google Cal (blue), Custom (grey)
Connection Name The label you entered. If the last sync failed, the error message appears in red beneath the name
Status Green check = Synced · Red warning = Failed · Amber clock = Pending
Last Sync Relative time ("3 hours ago") plus the number of calendar events imported
Actions Refresh icon (↻) = Sync Now · Trash icon = Disconnect

3.6.5 Syncing Manually

Sync a single connection:
Click the refresh (↻) icon in the Actions column for that row. The page reloads with the result shown in the status column.

Force sync all connections for this room:
Click the Force Global Sync button at the bottom of the iCal page. This triggers an immediate pass over every connection belonging to the current room.


3.6.6 Automatic Background Sync

The plugin uses WordPress Cron to sync all connections automatically once configured. No ongoing manual action is required. The Automatic Sync Settings panel provides granular control over sync frequency, failure handling, and notifications.

Configuring the sync schedule:

  1. Go to Hotel Booking > PRO Features > iCal Sync
  2. The Automatic Sync Settings card is displayed at the top of the page. Configure:
Setting Options Default Description
Enable Auto-Sync On / Off On When enabled, all iCal connections across all rooms are synced automatically on the chosen schedule.
Sync Interval 5 min · 15 min · Hourly ⭐ · 1 hour · 6 hours · Daily Hourly How frequently the plugin fetches external calendars. See guidance below.
Next Scheduled Sync (read-only) Displays the exact date and time of the next scheduled cron run so you can verify the schedule is active.
Auto-Retry on Failure On / Off On When enabled, failed syncs are automatically retried with exponential backoff (1h → 2h → 4h) to avoid hammering unresponsive endpoints.
Email Notifications On / Off Off Send email alerts when sync failures exceed the threshold. Enter the notification email address in the field below the checkbox.
Notification Email Email address Admin email The email address that receives sync failure and success notifications.
Failure Email Threshold 1–10 3 Number of consecutive failures before an alert email is sent.
Conflict Resolution Local Wins · External Wins Local Wins Determines which booking takes priority when the same dates exist in both the local database and the OTA feed.
Notify on Success On / Off Off Send an email after every successful sync cycle (useful for monitoring during initial setup).
  1. Click Save Settings — a green ✓ Saved indicator appears next to the button

Choosing the Right Sync Interval

[!TIP] > 💡 Recommended: Hourly — This is the optimal setting for most properties. It balances real-time accuracy with server performance. Airbnb and Booking.com typically update their own calendars every 1–2 hours, so syncing more frequently than hourly provides diminishing returns.

Interval Best For Server Impact Notes
5 minutes High-traffic properties with 10+ rooms and frequent OTA bookings 🔴 High Only use if double-bookings are a critical business risk. Requires a real system cron.
15 minutes Properties with 5–10 rooms and moderate OTA traffic 🟡 Medium Good compromise for busy listings.
Hourly ⭐ Most properties (1–10 rooms) 🟢 Low Recommended default. Matches the refresh cadence of major OTAs.
Every 1 hour Same as Hourly 🟢 Low Alias for the Hourly schedule.
Every 6 hours Low-volume properties or seasonal listings 🟢 Very low Suitable for properties with infrequent OTA bookings.
Daily Archive/test properties 🟢 Minimal Only for properties where real-time sync is not important.

[!IMPORTANT] > Conflict Resolution: "Local Wins" preserves your MHBO booking when the same date appears in both the local database and the OTA feed. Use "External Wins" only when the OTA is the single source of truth and you never create bookings directly in MHBO. Under "External Wins", if an external booking overlaps with multiple smaller local bookings, all conflicting local bookings will be automatically cancelled. This conflict resolution strictly adheres to your global Same-day Turnover settings to prevent back-to-back overlaps.

[!NOTE] WordPress Cron is triggered by site traffic. On low-traffic sites, add a true system cron entry that calls curl https://yoursite.com/wp-cron.php?doing_wp_cron every 5–15 minutes to ensure the sync fires reliably.


3.6.7 Security Architecture

  • SSRF Protection: Every import URL is validated through Security::is_safe_url() before any HTTP request is made. Private IP ranges (127.x, 10.x, 192.168.x, etc.) are unconditionally blocked.
  • SSL Verification: All outbound requests enforce sslverify: true. Feeds served over HTTP or with invalid certificates are rejected.
  • Per-Room Key Isolation: Each room's export URL uses a distinct 24-character alphanumeric token. Rotating one room's key leaves all other rooms unaffected.
  • SEQUENCE Tracking: The plugin tracks RFC 5545 SEQUENCE numbers to detect when an OTA has modified an existing event, preventing stale data from overwriting a newer local booking.
  • Orphan Cleanup: If an external booking is removed from the OTA's calendar (e.g., a cancellation on their side), MHBO automatically cancels the corresponding internal shadow booking on the next sync.
  • Zero-Cache Feed Architecture: The export feed (ICS) utilizes DONOTCACHEPAGE and nocache_headers() to bypass all caching layers (Nginx, Varnish, Cloudflare, and WP plugins). This ensures OTAs always receive real-time availability.
  • Input Sanitization: All data arriving from external ICS feeds is sanitized and processed through BookingProcessor::process() — raw database inserts from feed data are never performed.

3.6.8 Troubleshooting iCal Sync

See also Section 6.6 — iCal Sync Issues for a full diagnostics table.

Symptom Likely Cause Fix
Status stuck on Pending No sync has run yet Click the Sync Now (↻) button or wait for the next cron cycle
Status Failed with error message Network error, invalid URL, or OTA changed the feed format Read the inline error; verify the URL still opens in a browser
Export URL returns an empty calendar No bookings exist for that room Expected — add a test booking to confirm the feed works
Export URL returns 404 / Not Found Rewrite rule not registered The plugin now self-heals this automatically on the next page load. If the issue persists, go to Settings > Permalinks and click Save Changes
Airbnb still shows dates as available Airbnb has not re-polled yet Wait up to 3 hours; Airbnb polls every 2–3 hours
Booking.com says "This iCal URL isn't valid" March 2025 policy — Booking.com blocks custom-site URLs See Section 3.6.9 — no fix exists on the MHBO side
Duplicate bookings appearing Conflict set to "External Wins" with existing local bookings Switch Conflict Resolution to "Local Wins"
Booking.com bookings not appearing in MHBO Booking.com export URL not added as a connection Add Booking.com's .ics export URL in Import External Calendars
Dates shifted by one day UTC vs. Local offset mismatch Ensure Hotel Timezone is set correctly in General Settings. Version 2.4.2 fixes this via substring date parsing.

[!IMPORTANT] > After updating the plugin files on production, follow these steps to ensure the iCal export URLs work correctly:

  1. Deploy the updated plugin files to your production server (via FTP, Git, or your deployment tool).
  2. Visit Settings → Permalinks in WP Admin and click Save Changes to ensure a clean rewrite flush.
  3. Verify the export URL by opening https://yoursite.com/mhbo-ical/room-{id}.ics?key={token} in a browser — you should see valid iCal text starting with BEGIN:VCALENDAR.
  4. Check the Automatic Sync Settings panel at Hotel Booking > PRO Features > iCal Sync and confirm the "Next Scheduled Sync" field shows a future date/time.

The plugin now includes a self-healing mechanism: if the iCal rewrite rule is missing from the WordPress rewrite rules database, it will be automatically restored on the next page load without manual intervention.


3.6.9 Booking.com Limitation & Workarounds

The Problem

Since March 2025, Booking.com validates iCal import URLs by checking the source domain, not the feed content. Only URLs from a recognised OTA whitelist are accepted. Custom-domain URLs — including your MHBO Export URL — are rejected with "This iCal URL isn't valid — please try again" regardless of how well-formed the feed is.

This is a Booking.com policy decision. The feed itself is RFC 5545 compliant and passes third-party validators like icalendar.org/validator.html.

Confirmed Accepted Domains (Booking.com whitelist, April 2026)

These are the OTA platforms whose iCal export URLs Booking.com will accept for import. All others are rejected.

Platform Domain Free to use
Airbnb airbnb.com ✅ Yes
VRBO / HomeAway vrbo.com, homeaway.com ✅ Yes
TripAdvisor tripadvisor.com ✅ Yes
Expedia expedia.com ✅ Yes
Trip.com trip.com ✅ Yes
Google Calendar calendar.google.com ❌ Not confirmed — see below
iOS / iCloud Calendar icloud.com ❌ Not on whitelist
Personal / custom websites any other domain ❌ Blocked

[!NOTE] > Why Google Calendar is not a viable relay: Google Calendar does accept our MHBO iCal URL as a subscription, but it only refreshes subscribed feeds every 24–48 hours and this interval cannot be reduced by the user. This would create a 3-hop chain (MHBO → Google Calendar → Booking.com) with a combined worst-case delay of 3+ days. Even if Google Calendar URLs pass Booking.com's validation (unconfirmed), the propagation delay makes it impractical for preventing double bookings. iOS Calendar has the same problem.

Additional Constraint: Property Structure

Booking.com's iCal sync tool is only available on properties with:

  • 20 room types or fewer, AND
  • Maximum 1 unit per room type

If your Booking.com listing uses multiple units per room type (e.g., "3× Standard Room"), the "Sync Calendars" option may not appear in your extranet. In that case, manual blocking or a channel manager are your only options.

What Still Works

Direction Status Notes
Booking.com → MHBO (import) Works Add Booking.com's .ics export URL as a connection in MHBO. MHBO fetches it on your cron schedule.
MHBO → Airbnb (export) Works Airbnb accepts iCal URLs from any domain. Re-polls every 2–3 hours.
MHBO → VRBO (export) Works VRBO also accepts any iCal URL. Re-polls every 4–6 hours.
MHBO → Booking.com (export direct) Blocked Custom domain rejected since March 2025.

Workaround Options

Option A — Airbnb relay (free — best option)

If your property is listed on Airbnb, this is the recommended free workaround.

  1. Your MHBO export URL is already synced to Airbnb (Airbnb accepts any domain)
  2. In Booking.com Extranet → Rates & Availability → Synchronise Calendars → Add calendar connection
  3. Paste your Airbnb listing's calendar export URL (Calendar → Availability Settings → Export Calendar)
  4. Booking.com accepts it (Airbnb is on the whitelist)

This creates: MHBO → Airbnb → Booking.com Combined delay: ~4–6 hours (Airbnb polls MHBO every 2–3 h + Booking.com polls Airbnb every 1–24 h)

Option B — VRBO or TripAdvisor relay (free — if listed there)

Same principle as Option A. If you list on VRBO, TripAdvisor, or Expedia, their calendar export URLs are accepted by Booking.com. Use whichever OTA you already have.

Option C — Manual date blocking (free, zero-delay)

When a direct booking arrives on your site, immediately log in to Booking.com Extranet and block those dates manually in the availability calendar. No delay, no double-booking risk. Practical for properties with low direct booking volume.

Option D — Booking.com Pulse app (free)

The Booking.com Pulse mobile app (iOS/Android) lets you block and unblock dates on your phone in under 30 seconds. For properties with a moderate direct booking rate this is often the fastest response path.

Option E — Channel manager API (paid, real-time)

Services like Smoobu, Hostaway, Lodgify, and Rentals United connect to Booking.com via their official Connectivity API rather than iCal. This gives true real-time, two-way sync with no polling delay and no domain restrictions. Entry-level plans start around $10–20/month. Recommended for any property receiving more than 5–10 direct bookings per month.

[!NOTE] Booking.com's own iCal export URL (copied from Extranet → Sync Calendars → Export) works normally and is unaffected by this restriction. Always configure the MHBO import direction to pull Booking.com bookings into your site — that direction has no domain restriction.


3.7 Theme Customizer

Match the booking form and calendar to your website's brand.

  1. Go to Hotel Booking > Settings > Themes
  2. Select a Theme Preset:
    • Default (Blue)
    • Midnight (Dark)
    • Emerald (Green)
    • Oceanic (Teal)
    • Sunset (Orange)
    • Royal (Purple)
    • Custom Theme

Custom Theme: If you select the "Custom Theme" preset, you can pick specific colors:

  • Primary Color: Used for buttons and highlights
  • Secondary Color: Used for secondary text and borders
  • Accent Color: Used for active states and selections

Custom CSS: Regardless of your theme preset, you can add Custom CSS in this section for granular visual control over the form and calendar blocks.

3.8 GDPR Compliance Suite

The Modern Hotel Booking Pro version includes a dedicated suite of tools to ensure your hotel complies with EU GDPR and global data privacy laws.

Enabling Privacy Features:

  1. Go to Hotel Booking > Settings > GDPR & Privacy
  2. Check the box for Enable Pro Privacy Suite to activate data retention and cookie controls.

Consent Checkbox (Art. 7):

  1. Enable Require Privacy Consent to add a mandatory checkbox to your booking form.
  2. Select your Terms & Conditions Page from the dropdown.
  3. Configure your Consent Text per language. Use [privacy_policy] to link to your WordPress native privacy policy and [terms_and_conditions] to link to the page selected above.
    • Example: I accept the [privacy_policy] and [terms_and_conditions].

Automated Data Retention & Erasure:

  • Under Automated Data Retention, set the number of days you want to keep booking records.
  • How it works: A daily background task (cron job) will automatically scan for bookings older than your chosen threshold.
  • Tax Compliance (Art. 17(3)): When bookings are "erased", the plugin safely anonymizes all Personally Identifiable Information (PII) like names and emails, but retains the financial totals and tax records required by accounting laws.
  • Zero IP Retention: The plugin does not save guest IP addresses in the database. When enforcing rate limits, IPs are temporarily hashed and stored as fleeting transients (60 seconds) strictly for security protection.

Data Export & Erasure Requests (Art. 15 & 17):

  • The plugin hooks into the native WordPress Tools > Export Personal Data and Tools > Erase Personal Data.
  • When handling a guest's request for their data, simply use the native WP tools to generate their booking history or to trigger the anonymization of their records.

3.9 Analytics Dashboard

Access: Go to Hotel Booking > Analytics

The Pro Analytics dashboard provides high-level business intelligence and data visualization for your property.

3.9.1 Core Metrics & KPIs

Metric Definition Importance
ADR Average Daily Rate. Total room revenue divided by occupied rooms. Measures the average income per room per day.
RevPAR Revenue Per Available Room. Total room revenue divided by total inventory. The ultimate measure of property performance and yield.
Occupancy % Percentage of rooms sold vs. total available. High occupancy combined with high ADR indicates peak performance.
Lead Time Average days between booking date and check-in. Helps plan marketing and staffing for upcoming blocks.

3.9.2 Visualization Widgets

  • Revenue Trends: Interactive chart showing potential revenue (booked) vs. collected revenue (paid).
  • Occupancy Heatmap: Visual calendar showing peak demand periods.
  • Booking Sources: Breakdown of Direct vs. iCal (Airbnb, Booking.com) reservations.
  • Room Performance: Comparison of which room types generate the most revenue.

3.9.3 Forecast Analysis

The plugin includes a 30-Day Predictive Engine that scans your current bookings and historical availability to project future revenue and occupancy. This allows property managers to adjust pricing strategies before high-demand periods arrive.

3.9.4 Professional Reporting & Exports

Export raw data for external accounting, auditing, or custom reporting:

  • Financial CSV: Line-by-line breakdown of every booking, extra, and partial payment.
  • Tax/VAT Report: Summarized report of tax collected by rate (Accommodation vs. Extras). Essential for quarterly filings.
  • Occupancy Report: Detailed night-by-night breakdown of room utilization.
  • Transaction Log: Complete audit trail of all payment gateway success/failure events.

3.11 Admin Calendar Pricing & Availability Editor

The Admin Calendar (found under Hotel Booking > Inventory) is the most powerful tool for granular control over your property's yield.

3.11.1 The Bulk Update Tool

Instead of editing each day individually, use the Bulk Update button:

  1. Scope Selection: Choose to update a "Room Type" (affects all rooms of that type) or an "Individual Room".
  2. Date Range: Define your target window (e.g., "Dec 20 - Jan 5").
  3. Day Filter: Only apply changes to specific days (e.g., only Fridays and Saturdays).
  4. Override Values:
    • Price: Set a fixed nightly rate.
    • Availability: Block out dates (Set to Closed) or open them up.
    • Min/Max Stay: Force longer stays during peak dates.

3.11.2 Import/Export

The Calendar Editor supports JSON Synchronization. You can export your pricing overrides as a master file and import them back to restore specific pricing setups for the next year.

3.12 Professional Invoicing System

Generate, print, and automate guest invoices directly from the booking manager.

3.12.1 Automatic Invoicing

To send invoices automatically:

  1. Go to Hotel Booking > Settings > Communications.
  2. Enable Attach Invoice to Confirmation Email.
  3. Guests will receive a beautifully formatted HTML/PDF invoice immediately after their booking is confirmed.

3.12.2 Manual Management

From the Bookings List, click on any reservation and select Generate Invoice.

  • Print Version: Opens a print-friendly view with a "Print" command triggered.
  • Payment Methods: If the booking has an outstanding balance, the invoice automatically includes your Bank Transfer and Revolut details (configured in Section 2.5).

The Deposit system allows you to collect a portion of the booking total at checkout, with the remaining balance collected later (either on-site or via a manual payment link).

3.10.1 Configuration

To configure deposits, go to Hotel Booking > Settings > Deposits.

Setting Description
Enable Deposits Toggle the entire deposit system on or off.
Deposit Type Choose how the deposit is calculated: Percentage, Fixed, or First Night's Rate.
Deposit Value The numerical value for Percentage or Fixed types.
Non-Refundable If checked, the deposit is explicitly marked as non-refundable in emails.
Refund Deadline Number of days before check-in when a refundable deposit becomes non-refundable.
Allow Guest Choice If enabled, guests can choose to pay the deposit OR the full amount at checkout.

3.10.2 Guest Experience

When deposits are enabled, the booking form displays a clear Payment Options section. This interface ensures that guests understand their financial commitment before proceeding to checkout.

The Interface:

  • Interactive Radio Cards: Guests select their preferred payment method using large, high-contrast cards. These provide a tactile and modern experience compared to standard dropdowns or radio buttons.
  • Dynamic Pricing: The cards automatically update to show the exact amount due today.
    • Pay Deposit Now: Displays the portion of the total required to secure the room.
    • Pay in Full: Displays the complete reservation total.
  • Policy Transparency: If a deposit is configured as non-refundable, this information is displayed directly within the card, ensuring the guest is fully aware of the cancellation terms before paying.
  • Responsive Layout: The payment cards utilize a flexible grid system. They appear side-by-side on desktop but automatically stack on mobile and tablet viewports to maintain maximum legibility and ease of use.

[!TIP] > Testing the Guest View: To see exactly how these cards appear to your guests, go to Settings > Deposits and enable "Allow Guest Choice". Then, visit your booking page and select a room to trigger the payment options step.

3.10.3 Managing Balances

Administrators can track and update balances directly from the booking details page.

  1. Go to Hotel Booking > Bookings.
  2. Click View on a booking with a deposit.
  3. The Payment Summary box shows:
    • Payment Type: (Deposit vs Full)
    • Deposit Paid: The amount captured at checkout.
    • Remaining Balance: The amount still owed.
    • Balance Status: (Uncollected vs Collected).
  4. Click Mark Balance Collected once you receive the final payment. This adds a private note to the booking for audit trails.

[!TIP] > Email Automation: Use the {deposit_details} placeholder in your email templates to automatically include a professional summary of the deposit paid, balance remaining, and refund deadline in guest notifications.


3.14.3 AI Resilience & Cost Optimization (2026 Edition)

The AI Concierge is equipped with a high-availability Resilience Layer designed to maintain service stability during API outages or heavy demand spikes, while ensuring the most cost-effective operation.

1. Tiered Circuit Breaker

If the AI provider (e.g., Google Gemini) experiences high demand or temporary errors, the system triggers a Stateful Circuit Breaker:

  • Tier 1 (Transient): 15-second "cool-down" to allow capacity to reset.
  • Tier 2 (Active): 60-second block during persistent fluctuations.
  • Tier 3 (Outage): 15-minute "hard block" protecting your server resources during broad service outages.

Guests will see a professional "System Busy" message rather than a technical error, preserving the user experience.

2. Economic Fallback Cascade

The system automatically cascades through available models from cheapest to most capable. The verified May 2026 priority order is:

Priority Model Tier Notes
1 Gemini 3.5 Flash Stable Newest GA, recommended primary
2 Gemini 3.1 Flash-Lite Stable Lowest cost stable option
3 Gemini 3 Flash Preview Preview Computer Use support
4 Gemini 3.1 Pro Preview Preview Flagship preview capability
5 Gemini 2.5 Flash-Lite Stable Ultralight stable fallback
6 Gemini 2.5 Flash Stable Proven stable last resort

[!NOTE] > Deprecated models including the legacy gemini-1.5 and gemini-2.0 families are retired. The gemini-3.1-flash-lite-preview model reached EOL on May 25, 2026 and is automatically migrated to gemini-3.5-flash. If you see model-not-found errors, please use the Reset Engine Lock button to clear the resilience cache.

Models are dynamically deprioritized for 5 minutes if they return errors, ensuring the system transparently finds the best available price/performance ratio in real-time.

3. Cost Transparency & Billing Notice

[!IMPORTANT] > Dynamic Fallback Costs: While the system is optimized to use the most cost-efficient models (e.g., Gemini 3.5 Flash), it is designed to prioritize service continuity. During significant API outages or heavy regional demand, the AI Concierge may automatically cascade to more capable — and more expensive — secondary models.

Key Considerations:

  • Primary Selection: Setting Gemini 3.5 Flash as your primary model is the recommended way to minimize daily costs while utilizing the latest GA capabilities.
  • Cascade Implications: If the primary model fails, the system will temporarily use higher-tier models (up to Gemini 3.1 Pro Preview) to ensure your guests still receive a response. This may result in higher token usage fees during that period.
  • Monitoring: Use the Service Health dashboard in AI Concierge → General Settings to monitor active "Demand Spikes" and circuit breaker status. Click Reset Engine Lock to manually clear cooldowns after an outage resolves.

3.14.4 AI Security & Identity Verification (OTP)

To protect sensitive guest information and ensure the integrity of your reservations, the AI Concierge implements a "Zero-Trust" Identity Handshake.

Protected Actions: The AI WILL NOT perform the following actions without first verifying the guest's identity via a 6-digit One-Time Password (OTP) sent to their registered email:

  • Resending booking confirmation emails.
  • Retrieving guest stay history.
  • Modifying an existing reservation (dates, room types, extras).
  • Canceling an existing reservation.

Security Parameters:

  • Verification Codes: A cryptographically secure 6-digit numeric code.
  • Expiration: Codes are valid for exactly 20 minutes. If the code expires, a new one must be requested.
  • Lockout Policy: To prevent brute-force attacks, the AI Concierge will lock the verification process after 10 failed attempts in a single session. If locked, the guest must restart the chat.

[!IMPORTANT] > Transactional Email Requirement: For OTP to function, your WordPress site must be capable of sending emails. We strongly recommend using a dedicated SMTP provider (SendGrid, Mailgun, etc.) to ensure instant delivery of verification codes.

Administrators do not need to configure this; it is active by default for all Pro-tier installations to ensure compliance with enterprise security

3.14 AI Concierge System

The AI Concierge is your property's 24/7 intelligent receptionist. Guests can interact via the floating widget on your website using text or high-quality voice synthesis.

3.14.1 Key Capabilities

  • Property Q&A: Answers questions about amenities, check-in times, and local rules based on your "Hotel Info" settings.
  • Real-time Availability: Checks the live Pricing engine to see if rooms are open for specific dates.
  • Direct Reservations: The AI can guide a guest through the entire booking process and hand them over to the payment gateway once they've selected a room.

3.14.2 Voice & Text Support

Guests can toggle between Text and Voice mode.

  • Voice Mode: Uses advanced text-to-speech to read responses aloud.
  • Multilingual: The AI automatically responds in the language the guest uses, supporting all 15 locales of the plugin.

3.14.3 Booking Access (OTP Secure)

For guests with existing bookings:

  1. The AI asks for their email and Booking ID.
  2. A secure One-Time Password (OTP) is sent to their email.
  3. Once verified, the AI can provide check-in instructions, WiFi codes, or update their notes.

3.14.10 AI Concierge Analytics

Monitor your AI's performance in Hotel Booking > Analytics > AI Concierge.

  • Engagement Rate: How many visitors chat with the AI.
  • Handover Rate: How many chats result in a direct booking intent.
  • Common Questions: Aggregated data on what your guests are asking most.

The Pro version includes a dedicated Analytics tab within the AI Concierge dashboard. This provides:

  • Session Logs: View anonymous transcripts of guest interactions to identify common questions.
  • Conversion Tracking: Measure how many AI conversations result in a completed booking.
  • Sentiment Analysis: Understand guest satisfaction trends over time.
  • Model Usage: Monitor token consumption across primary and fallback providers.

3.11 Admin Calendar Pricing & Availability Editor

The Admin Calendar is a Pro-only visual editor that lets you set exact prices, block dates, and apply stay restrictions on any individual day — at either the Room Type level or the Individual Room level. Changes appear on the guest-facing booking form immediately.

3.11.1 How to Access

The calendar is available from two places:

Starting point Navigation
Room Type calendar Hotel Booking > Room Types → click the Calendar icon next to any type
Individual Room calendar Hotel Booking > Rooms → click the Calendar icon next to any room

The page header badge tells you which scope you are editing:

  • Room Type — overrides apply to every room of that type simultaneously
  • Individual Room — overrides apply to that single room only (highest priority)

3.11.2 Pricing Priority Order

Every night's price is computed by passing through a waterfall of five layers, lowest to highest priority. A higher layer always wins over a lower one.

Priority Layer Where it is set
1 (lowest) Room Type base price Room Types > Base Price field
2 Room custom price Rooms > Custom Price field (overrides the type base price for that room only)
3 Seasonal / Weekend / Holiday rules Hotel Booking > Pricing Rules + Settings > Advanced Pricing
4 Room Type calendar override Calendar Editor on the Room Type page
5 (highest) Individual Room calendar override Calendar Editor on the Individual Room page

Example: A room type has a base price of 150 RON. A seasonal rule raises it to 180 RON for summer. A room-type calendar override sets 2 August to 220 RON. An individual room calendar override sets that same room on 2 August to 195 RON. The guest pays 195 RON — the individual room override wins.

[!NOTE] If a calendar override sets only min_stay (and no price), the price still flows through all layers below it. Each field is independent — null means "inherit from lower layers", not "zero".

3.11.3 The Calendar View

The calendar opens in Month view by default. Each day cell shows:

  • The Resolved Effective Price for that night (bold if a manual override is set, standard if inherited).
  • Status Indicator (Colored border/background).
  • Restriction Badges: Min / Max (stay length), ↓X (No Check-in), ↑X (No Check-out).

[!NOTE] > Timezone Awareness: The calendar operates based on your WordPress site's timezone. A "day" begins at 00:00 and ends at 23:59. If you have guests arriving from different timezones, ensure your site settings match your property's local time to prevent "same-day turnover" conflicts.

3.11.4 Visual Status Legend

The calendar uses high-contrast visual cues to help you audit your inventory at a glance:

Visual Icon / Style Meaning Priority
Purple Border Individual Room Override. A price or stay restriction is set on this specific room. Highest
Blue Border Room Type Override. A rule is applied to all rooms of this type. High
Striped Background Fully Blocked. The room is marked as unavailable for this date. Overrides all
Green Highlight Available. The room is open for reservations. Base
Grey Highlight Booked. A confirmed reservation exists for this date. N/A

3.11.5 Effective Price Detection

The calendar performs a "dry run" of the pricing engine for every day displayed. The number you see on each date is the Effective Price — the final amount the guest will pay after all seasonal rules, weekend multipliers, and overrides are applied. This gives you 100% confidence in your pricing strategy before it goes live.

3.11.6 Intelligent JSON Import

When bulk-importing pricing data via JSON, the system includes a Conflict Resolver:

  • Existing Data Detected: If you import overrides into a calendar that already has data, the system will highlight the conflicts.
  • Smart Merge: You can choose to "Keep Existing" (skip duplicates) or "Overdrive All" (overwrite existing overrides with the new file).
  • Validation: All imported dates are validated for ISO compliance and room association to prevent database corruption.

Use the prev / next arrows or today button to navigate months.


3.11.7 Editing a Single Day

Click any day cell to open the Day Panel on the right.

Field What it does Leave blank to…
Nightly Price Override the price for this one night Inherit from the pricing stack
Availability Open / Blocked / Inherit Inherit (stay available)
Min Stay Minimum consecutive nights required to book this date Apply no minimum
Max Stay Maximum consecutive nights allowed Apply no maximum
No Check-in (CTA) Guests cannot start a stay on this date Allow arrivals
No Check-out (CTD) Guests cannot end a stay on this date Allow departures
Admin Note Internal reference (never visible to guests) No note

Click Save Changes to apply. Click Clear to remove the override entirely (the date reverts to the pricing stack).

[!TIP] To block a date completely, set Availability to Blocked. Guests will not be able to select it as a check-in or check-out date.


3.11.8 Bulk Editing a Date Range

To set the same values across a range of consecutive dates:

  1. Click and drag across the calendar cells from the start date to the end date
  2. The Bulk Edit Panel opens, showing the date range
  3. Fill in the fields you want to change (leave others blank to leave them unchanged)
  4. Click Apply to Range

All dates in the range receive exactly the fields you filled in. Fields left blank are not touched — they keep whatever value each day already had.


3.11.9 Multi-Select Mode

Multi-select lets you apply changes to any arbitrary set of dates — dates that do not need to be contiguous.

Activating multi-select:

  1. Click the Multi-select button in the top-right corner of the calendar toolbar
  2. The button turns highlighted to confirm the mode is active
  3. Click individual day cells to add or remove them from your selection
  4. To add a range, click-and-drag — all dates in the drag are toggled in/out of the selection

Selection bar:

Once at least one date is selected, a bar appears below the calendar showing the count of selected days and two actions:

  • Edit Selected — opens a bulk panel for all selected dates (same fields as the range panel)
  • Clear — deselects everything without saving

Applying the edit:

  1. Click Edit Selected in the selection bar
  2. Fill in only the fields you want to change
  3. Click Apply to All Selected
  4. The panel closes, a toast confirms the save, and the calendar refreshes

To exit multi-select mode, click the Multi-select button again or click Clear.

[!NOTE] Multi-select mode and single-day click mode are mutually exclusive. While multi-select is active, clicking a day adds it to the selection rather than opening a day panel.


3.11.10 Export JSON

The Export JSON button (toolbar, top-right) downloads a complete pricing snapshot of this room type or room as a JSON file. The file is human-readable and suitable for offline editing or backup storage.

What the export contains:

Section Contents
base_price The current base or custom price for this entity
pricing_rules All seasonal rules that affect this scope, including global rules (marked rule_scope: "global") and type/room-specific rules
overrides Every manual day override saved in the calendar editor, deduplicated per date
daily_prices 365 days of resolved effective prices starting from today — the exact price a guest would pay on each night after the full pricing stack is applied
weekend_pricing Current weekend pricing settings (reference only)
holiday_pricing Current holiday pricing settings and dates (reference only)

The filename is automatically formatted: mhbo-rates-{scope}-{id}-YYYY-MM-DD.json

[!TIP] The daily_prices array is the fastest way to audit your pricing for the coming year. Open the file in any text editor or import it into a spreadsheet (convert JSON → CSV) to check every night at a glance.


3.11.11 Import JSON

The Import JSON button (toolbar, top-right) restores or updates data from a previously exported (or manually edited) file.

Supported workflow:

  1. Export the JSON file
  2. Edit the file in any text editor — change prices, add new override entries, adjust pricing rules, or update base_price
  3. Click Import JSON and select your edited file
  4. A Preview dialog opens before anything is written

Preview dialog:

The preview shows exactly what will change:

  • Valid records — number of override entries that will be processed
  • New dates — override entries for dates that don't yet exist in the database
  • Conflicts — dates that already have an override with different values. For each conflict you choose: Keep existing or Use incoming
  • Pricing rules to replace — count of type/room-specific rules that will be replaced (global rules in the file are always skipped)
  • Base price change — if the file's base_price differs from the current stored value, the preview warns you with the old and new amounts
  1. Resolve any conflicts using the radio buttons
  2. Click Import to apply

What each field does on import:

JSON field Import behaviour
overrides[] Each entry is written (upserted) to the database. Conflict resolution applies per date.
pricing_rules[] where rule_scope: "type" or "room" All existing rules for this scope are deleted and replaced with the imported rules
pricing_rules[] where rule_scope: "global" Ignored — global rules are shared across all room types and are never modified by a single-room import
base_price Updated in the database if the value differs from the current one
daily_prices[] Ignored — always recomputed live from the pricing stack
weekend_pricing / holiday_pricing Ignored — these are global settings not scoped to one room type

[!IMPORTANT] Importing pricing rules is a replace operation for the scope, not a merge. All existing type-specific or room-specific rules are deleted and the imported rules are written from scratch. Global rules (visible in the file for reference) are never touched.

[!TIP] To restore a room type's complete pricing state after an accidental deletion, export from a backup file and import it. The overrides, pricing_rules, and base_price are all restored in a single operation.


3.11.12 Typical Workflows

Setting a peak-season nightly rate for the next 3 months:

  1. Open the Room Type calendar
  2. Click-drag from the first to last date of the peak window
  3. Enter the peak price in the Bulk Edit panel
  4. Click Apply

Blocking a room for maintenance:

  1. Open the Individual Room calendar (not the type)
  2. Click-drag the maintenance dates
  3. Set Availability → Blocked
  4. Click Apply
  5. Those dates are blocked only for that room; other rooms of the same type remain open

Enforcing a 3-night minimum over a long weekend:

  1. Open the Room Type calendar
  2. Use Multi-select to pick the specific dates (e.g., Fri–Mon of a bank holiday)
  3. Click Edit Selected
  4. Set Min Stay → 3, leave all other fields blank
  5. Click Apply to All Selected

Annual pricing backup:

  1. On both the Room Type and each Individual Room calendar, click Export JSON
  2. Store the files in your backup folder or cloud storage
  3. To restore, import each file back to the corresponding calendar

3.12 Professional Invoicing System

The Modern Hotel Booking Pro version includes a comprehensive invoicing system designed to provide your guests with professional, accurate billing summaries for their stays.

3.12.1 How to Access

Invoices are generated individually per booking and can be accessed directly from the booking management interface:

  1. Go to Hotel Booking > Bookings.
  2. Find the reservation you wish to bill and click Edit.
  3. Scroll to the bottom of the page to find the Actions Dock.
  4. You will see two primary options:
    • 📥 Download Invoice: Generates a print-ready HTML invoice that opens in a new tab and triggers your browser's print dialog.
    • 📧 Email Invoice: Automatically dispatches the invoice as a professional HTML email directly to the guest's registered email address.

3.12.2 Financial Accuracy & Logic

The invoicing engine is synchronized with the plugin's real-time financial stack, ensuring 100% parity between what you see in the Admin dashboard and what the guest receives.

Amount Outstanding Calculation: The invoice uses a "smart balance" model to show guests exactly what they still owe: [Total Price] - [Deposits Received] - [Partial Payments] = [Amount Outstanding]

Key Features:

  • Deposit Awareness: If a booking requires a deposit that has not yet been received, the invoice adds an explicit Deposit Required row in the summary.
  • Dynamic VAT/Tax Breakdown: If taxes are enabled, the invoice perfectly splits VAT amounts between accommodation and extras, matching the registered rates in your settings.
  • Reference Numbers: Includes the unique Booking ID (Ref #) as the primary identifying number.

3.12.3 Professional Branding & Info

To ensure your invoices look professional and meet legal requirements, make sure to configure your property details in Hotel Booking > Settings > Business.

  • Property Logo: Uploaded via the Company tab, this will appear in the top-left of the invoice.
  • Company Address: Your full legal address.
  • Registration Numbers: Your Trade or VAT registration numbers (appears in the header).
  • Tax Registration: Ensure your tax ID is also mirrored in the Tax settings tab for footer display.

3.12.4 Smart Conditional Rendering

The invoice is intelligent enough to adapt its layout based on the booking's financial state:

  • Fully Paid Bookings: For bookings marked as status_completed or where the remaining balance is zero, the invoice automatically hides the Revolut and Bank Transfer instruction blocks to avoid confusion.
  • Pending Bookings: For bookings awaiting payment, the invoice includes professional payment cards (Revolut/Banking) in the footer, using the data configured in your Business settings.

[!TIP] > Multilingual Invoices: When emailing an invoice, the system automatically detects the Booking Language set during the reservation process and renders the invoice labels accordingly, ensuring your global guests receive documentation in their preferred language.


3.13 Performance & Cache Management

Modern Hotel Booking Pro includes a multi-layered caching engine designed for high-traffic environments and enterprise-scale properties.

3.13.1 Scaling Architecture

The plugin detects your server environment and automatically chooses the most efficient data storage method:

  1. External Object Cache (Redis/Memcached): If your hosting provides an object cache (detected via wp_using_ext_object_cache), the plugin uses it for sub-millisecond data retrieval.
  2. Transient Fallback (Database): If no object cache is available, the plugin uses the WordPress Transients API to store expensive calculations in the database.

3.13.2 Optimization Tabs

Go to Hotel Booking > Settings > Performance to manage your site's speed:

  • Enable Smart Caching: Toggles the caching of room availability, pricing rules, and room type structures.
  • Micro-Cache (Calendar): The visual calendar uses a special 60-second micro-cache that is automatically invalidated the moment a booking is created or modified.
  • Object Cache Status: A real-time indicator showing whether your site is currently using a High-Performance external cache.

3.13.3 Cache Maintenance

  • Clear All Cache: Use this button after making major architectural changes (like changing your tax mode or adding dozens of new rooms) to ensure all frontend fragments are refreshed.
  • Automated Invalidation: You rarely need to clear cache manually. The plugin includes "Dirty State" detection that invalidates relevant cache keys whenever you click Save or Update on any room, rule, or setting.

3.13.4 Advanced Availability Resilience (Race Protection)

For high-concurrency properties, Version 2.4.2 introduces Atomic Availability Locking. When multiple guests attempt to book the last available room at the exact same millisecond, the system utilizes MySQL native locks (GET_LOCK) to ensure:

  • Only one transaction succeeds.
  • Zero double-bookings even during flash sales or demand spikes.
  • Real-time inventory accuracy that bypasses standard page caching.

3.13.5 High-Performance AJAX Flow

The booking form now utilizes a Single-Page Submission model.

  • No Page Refreshes: Fragments of the page are updated via AJAX, maintaining the guest's scroll position and chat session state.
  • Resilient Nonces: Security tokens are automatically refreshed in the background, preventing "Session Expired" errors on long-dwell bookings.

3.14 AI Concierge System

(Flagship Feature — Version 2.4.2)

The Modern Hotel Booking AI Concierge is a next-generation guest assistant that acts as a 24/7 virtual receptionist. It uses advanced RAG (Retrieval-Augmented Generation) to understand your hotel's inventory, policies, and special details directly from your site content.

3.14.1 Dashboard Navigation

The AI settings are organized into specialized tabs for easier management:

  • General: Master switch, provider connections (Primary & Fallback), and Knowledge Base status.
  • Assistant Persona: Custom instructions, AI name, welcome message, and local concierge guide.
  • Appearance: Branding colors, widget position, and Pro theme selection.
  • AI Discovery (GEO): Management of llms.txt and llms-full.txt manifests.
  • Analytics (Pro): Detailed performance metrics, booking conversion tracking, and session logs.

3.14.2 Core Configuration

Feature Description
Primary AI Recommended: Gemini 3.5 Flash (Economic) or GPT-5.5 / Claude 4.6 for complex, agentic reasoning.
Model Selection Select from pre-optimized May 2026 flagging presets or use Manual Override.
Reasoning Effort (GPT-5.4, GPT-5.5 & Claude 4.6 only) Adjust the model's 'Thinking' intensity to balance accuracy vs. token cost.
Knowledge Base Automatically indexed from your Room Types, Rooms, and Pages. Use the Status Badge to check for data freshness.
Persona Name Customize the AI's name (e.g., "Marina, the Virtual Host").
Fall-Fast Logic Automatically detects provider outages and switches to the Fallback without guest interruption.

3.14.3 Tiered Reliability & WP 7.0 Native AI Cascade

Version 2.4.2 introduces a robust, multi-path "Cascading Provider" architecture to ensure 100% availability by integrating directly with native WordPress 7.0+ AI features:

  • Unified Prompt Cascade:
    • Path 1 (WP 7.0 Core): Runs through the native WordPress core wp_ai_client_prompt() builder API. This is the preferred pathway for simple text generation when no custom tools or functions are needed.
    • Path 2 (Standalone SDK): Falls back to the bundled \WordPress\AI\Client SDK (with Jetpack autoloader checks) if tool-calling/abilities are required or when running on WordPress versions older than 7.0.
    • Path 3 (Direct API Gateway): Executes direct HTTP POST requests to Gemini v1beta, OpenAI, or Anthropic endpoints if core APIs or SDK pathways are unavailable or lack configuration.
  • WP_Error & Missing Connector Fallback: If the native wp_ai_client_prompt() builder returns a WP_Error (e.g., if the site-wide Connector under Settings → Connectors is misconfigured, not set up, or fails to connect), the plugin automatically catches the error, logs it, and falls back to Path 2/3 using the local API keys configured in the plugin settings.
  • Unconditional Fallback Key Input: To facilitate this, the Primary AI Connection input fields (Provider, API Key, Model) remain visible and editable in the settings UI even when the native WP 7.0+ AI Client is detected, serving as the explicit fallback credentials.
  • Fail-Fast Auto-Fallback: If the primary AI endpoint (e.g., Gemini) hits a quota limit or service timeout, the system instantly switches to your secondary configured fallback (e.g., OpenAI) without interrupting the guest.
  • Service Locking: Temporary outage locks are placed on failing endpoints to prevent redundant connection timeouts, immediately routing subsequent queries through active fallback systems.

3.14.4 Premium Guest Experience (v3.0)

The 2026 flagship update introduces a state-of-the-art interaction layer:

  • Real-Time Streaming (SSE): The Concierge now utilizes Server-Sent Events (SSE) to deliver responses in real-time. Instead of waiting for a full paragraph, guests see words appear token-by-token, mimicking a live human conversation.
  • Glassmorphic "Thought Bar": While the AI "thinks" or executes a tool (like checking availability), a subtle, translucent thought bar appears to keep the guest informed of the progress.
  • Premium Typography: The widget automatically enqueues the modern 'Outfit' Google Font for a high-end, rounded aesthetic.

3.14.5 Intelligent Guest Memory

Your AI Concierge now features a "long-term memory" for guest interactions:

  • Persistent Context: The system automatically remembers the guest's Name, Email, and Phone number using secure WordPress Transients.
  • Cross-Session Recall: If a guest provides their details and then refreshes the page or returns later (within 2 hours), the AI will still remember them, allowing for a seamless "Welcome back, Les!" experience.
  • Persistent DB Sessions (Pro): Pro users benefit from a permanent database table for chat history, ensuring that a guest's conversation history is preserved even across different devices or browsers after they log in or verify their identity.
  • Pre-filled Bookings: Because the AI remembers these details, any booking link it generates will be automatically pre-filled with the guest's contact information, significantly increasing conversion rates.

3.14.6 Zero-Trust Identity Handshake (OTP)

For sensitive operations—such as retrieving existing booking details or modifying a reservation—the AI Concierge enforces a 6-digit OTP verification protocol:

  1. Identity Request: The guest asks for their booking info.
  2. OTP Dispatch: The system sends a unique 6-digit code to the guest's registered email address (valid for 20 minutes).
  3. Verification: The guest enters the code in the chat.
  4. Authorized Access: Only after a successful handshake does the AI disclose PII or perform modifications. This prevents social engineering and unauthorized data leaks.

3.14.7 Automated Resilience & Stability

To ensure 100% reliability during peak periods, the AI Concierge includes an automated protection suite:

  • Demand Protection (Retry Logic): If the AI provider (Gemini/OpenAI) is experiencing "High Demand" (HTTP 503), the plugin will automatically perform a 3-stage exponential backoff retry. It will wait a few seconds and try again internally before ever showing an error to the guest.
  • Transient Error Handling: Brief service hiccups are handled gracefully with a "Model busy, retrying..." status, keeping the guest engaged while the system heals itself.

3.14.8 Intelligent Room Splitting (v2.3.7)

For guests requesting multiple rooms or complex group stays, the AI Concierge now utilizes a Sequential Selection Model:

  • Pre-flight Availability: The AI first checks if the total number of requested rooms is available for the period.
  • Guided Selection: Instead of overwhelming the guest, the AI guides them through selecting each room one-by-one (e.g., "Great! Let's start with Room 1 of 3. Which type would you prefer?").
  • State Persistence: The AI tracks the progress of the multi-room booking and provides a final summary link that encapsulates the entire group request.

3.14.9 Proactive Engagement (Einstein NBA)

The "Einstein" proactive service engine allows the bot to engage guests based on their behavior:

  • Context-Aware Greetings: If a guest dwells on a page for a configurable time (default 45s), the bot auto-opens with a greeting tailored to that page.
  • Booking Intent Scoring: The system analyzes guest messages for intent. When intent is high, it automatically surfaces a "Book Now" CTA button or escalation bar (WhatsApp/Email/Phone).
  • Auto-Locale Detection: The chat widget automatically detects the guest's language via Polylang, WPML, or qTranslate-X.

3.14.10 AI Discovery Manifests (llms.txt)

To ensure your hotel is accurately represented in AI-powered search engines (Perplexity, ChatGPT Search, Gemini), Modern Hotel Booking v2.4.0 generates specialized manifests:

  • llms.txt: A summary of your hotel's core details, pricing, and booking links.
  • llms-full.txt: A secondary, detailed manifest containing your entire Knowledge Base.
  • Auto-Sync (Pro): When enabled, the manifests are automatically updated whenever you change your hotel business info or core settings.

3.14.11 Advanced Model Context Protocol (MCP)

For professional hospitality environments, the plugin exposes an MCP Server endpoint. This allows external AI agents (used by travel agencies or corporate bookers) to securely query your real-time inventory and room details using the 2026 industry-standard protocol.

3.14.12 WP 7.0 Native Abilities API Integration

Modern Hotel Booking complies with the WordPress 7.0 native Abilities framework, allowing standard client-side and server-side AI agents to discover and interact with the hotel's custom tools.

  • Categorized Abilities: To ensure logical classification, all 13 plugin abilities are registered within specific categories on the wp_abilities_api_categories_init action hook:
    • hotel-information: Governs static queries like fetching hotel info, room details, local tips, policies, and business contact cards.
    • booking-management: Handles stateful actions including checking availability, generating booking links, and creating/modifying/cancelling bookings.
    • guest-services: Covers guest history checks and applying promotional discount coupons.
  • REST Discovery: Each ability is registered with the show_in_rest => true metadata flag and translatable label descriptors. This exposes the abilities to the native WordPress REST endpoint (/wp-json/wp-abilities/v1/), allowing browser-based AI scripts using @wordpress/abilities to auto-discover available tools.
  • Access and Type Safety: Guests access guest-facing abilities with guest-level permissions, while administrative mutations (like retrieving guest history) enforce zero-trust OTP handshakes. All inputs and outputs are verified against strict JSON Schemas.

3.14.13 User Privacy & Security

  • Data Locality: All Knowledge Base storage is local to your WordPress database.
  • Sanitized Prompts: Guest PII is never sent to AI providers unless specifically required for tool execution (e.g., creating a booking draft).
  • Manage Options: All administrative AI actions (KB refresh, synchronization) require the manage_options capability.

3.15 Coupon System

PRO feature. Requires an active PRO license. The coupon system is disabled automatically on free builds.

The Coupon System lets you offer guests fixed-amount or percentage discounts at checkout. Coupons can be restricted by date, minimum spend, room type, and usage limit. The AI Concierge can apply coupons on a guest's behalf when both global and per-coupon AI access are enabled.


3.15.1 Enabling the Coupon System

  1. Go to Hotel Booking → Settings → Coupons.
  2. Toggle Enable Coupon System to On.
  3. (Optional) Toggle AI Concierge Can Apply Coupons — controls whether the AI is allowed to apply coupons at all. You can also control this per coupon.
  4. Click Save Settings.

When disabled, the coupon field is hidden from the booking form and the AI cannot apply coupons regardless of individual coupon settings.


3.15.2 Creating & Managing Coupons

Navigate to Hotel Booking → Settings → Coupons (or the Coupons submenu under Hotel Booking PRO). The coupon list table shows all coupons with their status, type, value, uses, and expiry.

Creating a Coupon

  1. Click Add Coupon.
  2. Fill in the fields in the modal (see Coupon Fields Reference).
  3. Click Save Coupon.

Editing a Coupon

Click the Edit (pencil) icon next to any coupon. The same modal opens pre-filled. Click Save Coupon to update.

Deleting a Coupon

Click the Delete (trash) icon. A confirmation dialog appears. Deletion is permanent.

Generating a Code

In the modal, click Generate next to the Code field to auto-generate a random 8-character uppercase alphanumeric code (e.g. SUMMER8K).


3.15.3 Coupon Fields Reference

Field Required Description
Code Yes The code guests enter at checkout. Case-insensitive. Max 50 characters.
Discount Type Yes fixed — deducts a flat currency amount. percent — deducts a percentage of the booking total.
Discount Value Yes The amount (e.g. 20 for $20 off, or 15 for 15% off). Must be > 0.
Max Percentage Cap No (Percentage type only.) The maximum currency amount the discount can reach. Leave blank for uncapped.
Min Booking Total No Guests must reach this spend before the coupon activates. Leave blank (or 0) for no minimum.
Expiry Date No YYYY-MM-DD. Coupon stops working after midnight on this date. Leave blank for no expiry.
Max Uses No Total number of times the coupon can be redeemed across all guests. 0 = unlimited.
Allowed Room Types No Restrict to specific room types. Leave blank to allow all rooms. Accepts a comma-separated list (selected from checkboxes).
Active Yes Toggle the coupon on or off without deleting it. Inactive coupons are rejected at checkout.
AI Accessible No Whether the AI Concierge is allowed to apply this specific coupon. Defaults to Yes. Requires the global AI coupon toggle to also be on.
Description / Notes No Internal admin note. Not shown to guests.

3.15.4 Guest Checkout Experience

Entering a Code

  1. Guest selects room(s) and dates on the booking form.
  2. A Coupon Code field appears below the price summary (above the payment section).
  3. Guest types their code and clicks Apply.
  4. If valid, a green confirmation message shows: "Coupon applied: SUMMER20 — $20.00 off".
  5. The price summary and tax breakdown update in real time to reflect the discount.
  6. A "Remove" link lets the guest undo the coupon before paying.

What Guests See in Confirmation

  • Booking Confirmation Email: A "Coupon Savings" line appears in the price breakdown showing the code and discount amount.
  • Tax Breakdown Modal: A green "Coupon Savings" line is shown before the grand total.
  • Admin Booking View: The booking record shows coupon_code and coupon_discount in the booking details.
  • Admin Edit Stability: Saving a booking in the admin dashboard (e.g., to update notes or guest names) automatically preserves and re-applies the stored coupon logic. This ensures that the discounted service fee and totals are never accidentally overwritten with pre-discount values.

Security

The coupon code is carried through the booking form as a hidden field. The server always re-validates and recalculates the discount — the client-submitted discount amount is never trusted. A guest cannot manipulate the discount by editing the form.


3.15.5 AI Concierge & Coupons

When both the global AI coupon toggle (Settings → Coupons) and the per-coupon AI Accessible flag are enabled, the AI Concierge can apply coupons on behalf of guests.

How It Works

  1. A guest tells the AI: "Do you have any discount codes?" or "Apply my promo code SUMMER20."
  2. The AI calls the apply_promo_code tool internally.
  3. The tool validates the coupon using the same server-side rules (expiry, min spend, room type, usage limit).
  4. If valid, the coupon is applied to the guest's booking session.
  5. If invalid, the AI explains why (e.g. "That code has expired" or "This code requires a minimum booking of $150").

Access Control

Setting Effect
Global Enable Coupon System = Off AI cannot apply any coupons
Global AI Concierge Can Apply Coupons = Off AI cannot apply any coupons, even if individual coupons have AI = Yes
Per-coupon AI Accessible = No AI cannot apply that specific coupon, even if the global AI toggle is on

This two-level gate means you can enable the AI for most promotional codes while keeping certain coupons (e.g. staff or wholesale codes) exclusive to direct entry.


3.15.6 Taxes, Deposits & Payment Gateways

How Discounts Interact with Tax

The coupon discount is applied to the gross booking total first, before tax is calculated. Tax is then computed on the discounted total only — guests never pay tax on the portion that was discounted.

Service Fee Recalculation: As of Version 2.4.2, the plugin includes Recalculation Integrity. When a coupon is applied, the Service Fee (e.g., 4% of subtotal) is automatically re-computed on the discounted amount. Example: If a 10% coupon is applied to a $400 stay, the 4% service fee will be calculated on $360 ($14.40) instead of the original $400 ($16.00).

Internally, when a coupon is applied, all taxable line items (room rate, extras, service fee) are scaled proportionally by the discount ratio, and Tax::calculate_booking_tax() is called again on the adjusted amounts. This ensures the tax breakdown shown to the guest exactly matches the tax charged.

How Discounts Interact with Deposits

When the Deposit & Partial Payments feature is active:

  1. Coupon discount is subtracted from the full booking total.
  2. The deposit percentage is then calculated on the discounted total.
  3. The guest pays the reduced deposit; the remainder is the reduced balance due.

Payment Gateways

Coupons work with all three payment gateways:

Gateway Behaviour
Stripe Server recalculates discounted total before creating the PaymentIntent. The coupon code is stored in Stripe metadata for reference. Webhook fallback path also re-validates and applies the coupon before recording the booking.
PayPal Server recalculates discounted total before creating the PayPal order. The coupon code is stored in the PayPal order's custom_id field.
Pay on Arrival Discount is applied and recorded at the time of booking submission. No payment is processed online, but the discounted total is stored and shown in all confirmations.

3.15.7 Troubleshooting Coupons

Symptom Likely Cause Fix
Coupon field not showing on booking form Coupon system is disabled Go to Settings → Coupons, enable the system
"Invalid or expired coupon code" Code is wrong, expired, or inactive Check code spelling; verify Expiry Date and Active status in admin
"Minimum booking amount not met" Guest's total is below the Min Booking Total Guest must book more, or edit the coupon's minimum
"Coupon not valid for selected room type" Room type restriction is set Edit the coupon and check Allowed Room Types
"Coupon usage limit reached" Max Uses has been hit Increase Max Uses or create a new coupon
AI says it cannot apply coupons Global AI toggle is off, or per-coupon AI Accessible is No Check both settings
Discount not showing in email coupon_discount is 0.00 or missing Verify the coupon was applied before payment; check booking record in admin
Tax not recalculated after discount Booking was made before coupon system was active Existing bookings are not retroactively adjusted
Coupon applied twice Guest submitted form twice before confirmation loaded The uses_count increment uses an atomic SQL check — a second use by the same guest after the first booking is recorded will not double-count

Part 4: Multilingual Support

4.1 Supported Translation Plugins

Plugin Detection Support Level
qTranslate-X Automatic Full (Recommended)
WPML Automatic String Translation
Polylang Automatic String Translation

4.1.1 v2.3.1 Localization Parity

As of Version 2.4.2, the plugin has achieved 100% semantic parity across 15 supported locales. This means every single professional label, from invoice headers to advanced pricing error messages, is included in the translation inventory.

Supported Standard Locales (v2.3.5):

Locale Code Coverage
English en_US 100%
Romanian ro_RO 100%
French fr_FR 100%
Italian it_IT 100%
Spanish es_ES 100%
German de_DE 100%
Russian ru_RU 100%
Bulgarian bg_BG 100%
Hungarian hu_HU 100%
Turkish tr_TR 100%
Polish pl_PL 100%
Greek el_GR 100%
Ukrainian uk_UA 100%
Dutch nl_NL 100%
Danish da_DK 100%
Swedish sv_SE 100%

4.1.2 SEO & Multilingual Consistency

The booking system generates Semantic HTML5 that search engines can easily parse. When using qTranslate-X or WPML, the plugin automatically:

  • Updates the lang attributes for form elements.
  • Generates localized ARIA labels for accessibility.
  • Ensures metadata (Title/Meta descriptions) associated with the Booking Page reflects the current active language.

4.2 Setting Up Multilingual Content

Room Types & Rooms:

[:en]Deluxe Suite[:ro]Suită Deluxe[:de]Deluxe Suite[:]

Frontend Labels:

[:en]Check In[:ro]Check-in[:de]Anreise[:]

4.3 Multilingual Email Templates

Email templates support multilingual content. Emails are sent in the language used during booking.


Part 5: Developer Reference

5.1 REST API

Authentication: Generate API keys at Settings > API. Sensitive endpoints (like creating bookings) require this key.

Security:

  • API Key Header: X-MHBO-API-KEY (Required for POST requests).
  • Nonce Protection: Public read-only endpoints require a X-WP-Nonce header for CSRF protection.
  • Rate Limiting: Public API access is limited to 60 requests per minute per IP to prevent brute-force attacks.

Endpoints:

Method Endpoint Description
GET /wp-json/mhbo/v1/rooms List all room types
GET /wp-json/mhbo/v1/availability Check room availability
POST /wp-json/mhbo/v1/bookings Create a booking (API key required)
GET /wp-json/mhbo/v1/bookings/{id} Get booking details (Admin only)
GET /wp-json/mhbo/v1/bookings/{reference} Get booking via 64-char token

Example Request:

curl -X POST https://yoursite.com/wp-json/mhbo/v1/bookings \
  -H "Content-Type: application/json" \
  -H "X-MHBO-API-KEY: your_api_key" \
  -d '{
    "room_id": 123,
    "check_in": "2026-06-15",
    "check_out": "2026-06-18",
    "customer_name": "John Doe",
    "customer_email": "[email protected]"
  }'

The Pro version includes a secure webhook system to notify your external applications of booking events in real-time.

5.2.1 Configuration

  1. Go to Hotel Booking > Settings > API > Webhooks.
  2. Enable Webhooks: Toggle the master switch to activate the listener.
  3. Webhook URL: Enter the endpoint of your external application (e.g., https://api.myapp.com/webhooks/mhbo).
  4. Webhook Secret: This is the shared secret used for HMAC-SHA256 signature verification.
  5. Enable Debug Logging: If enabled, the plugin will log every delivery attempt, including request payloads and server responses.

5.2.2 Delivery Logs & Troubleshooting

Manage your webhook health from the Delivery History section in settings:

  • Status Indicators:
    • ● 200: Success. The external server accepted the payload.
    • ● 4xx: Client Error. Check your endpoint URL or permissions.
    • ● 5xx: Server Error. Your external server encountered an issue.
  • Payload Viewer: Click the chevron to view the Pretty Printed JSON response from your server.
  • Clear History: Use the "Clear History" button to reset logs and free up database space.
  • Test Webhook: Trigger a mock booking_created event to verify your connection.

5.2.3 HMAC Security & Verification

Every payload is cryptographically signed using your Webhook Secret as the shared secret.

  • Signature Header: X-MHBO-Signature
  • Event Header: X-MHBO-Event (e.g., booking_created, booking_status_changed, payment_completed).

Signature Verification (PHP):

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_MHBO_SIGNATURE'] ?? '';
$webhook_secret = 'your_secret_from_settings'; // Do not share!

$expected = hash_hmac('sha256', $payload, $webhook_secret);

if (hash_equals($expected, $signature)) {
    // Webhook is authentic and untampered
}

[!IMPORTANT] > SSRF Protection: All webhook URLs are strictly validated server-side to prevent Server-Side Request Forgery, ensuring your server only communicates with legitimate external endpoints.

5.3 Action Hooks

// After booking is created
do_action('mhbo_booking_created', $booking_id);

// After booking status change
do_action('mhbo_booking_status_changed', $booking_id, $old_status, $new_status);

// After payment completed
do_action('mhbo_payment_completed', $booking_id, $payment_data);

5.4 Filter Hooks

// Modify calculate stay base price
add_filter('mhbo_calculate_stay_price', function($base_price, $room_id, $date) {
    // Example: Increase base price by $20 during special dates
    return $base_price + 20.00;
}, 10, 3);

Part 6: Troubleshooting

6.1 Common Issues

Booking Form Not Appearing

Solutions:

  1. Clear cache (plugins, CDN, browser)
  2. Check for JavaScript errors in browser console
  3. Verify theme compatibility (try default theme)
  4. Check PHP error logs

Availability Not Updating

Solutions:

  1. Check booking statuses (cancelled bookings may still block)
  2. Verify iCal sync isn't creating conflicts
  3. Check database for orphaned bookings

6.2 Payment Problems

Stripe Payment Fails

Solutions:

  1. Verify API keys are correct (test vs live mode)

  2. Check Stripe Dashboard for declined reason

  3. Ensure SSL certificate is valid

  4. Verify currency is supported by Stripe

  5. Check server firewall for blocked callbacks

6.2.2 Stripe/PayPal Modal Initialization

Problem: Payment buttons (Stripe/PayPal) do not appear or fail to load inside the booking modal. Reason: In versions prior to 2.3.7, payment scripts sometimes failed to bind to the dynamic DOM elements injected by the modal. Solution: v2.3.7 introduces a "Context-Aware Initialization" engine. If you still encounter issues, ensure your theme doesn't have "Lazy Load" enabled for JavaScript, as this can delay the payment gateway handshake.

6.2.3 AI Concierge Issues

Status 429: "Monthly spending cap reached"

  • Cause: Google AI Studio billing is restricted to $0.00 by default.
  • Solution: Visit the Google Cloud Console Billing page and set a non-zero spending cap (e.g., $5.00) to activate the Paid Tier and remove rate limits.

Status 502: "Bad Gateway" (Local Environments)

  • Cause: Long "thinking" cycles can cause local development proxies (like Local by Flywheel) to drop the connection.
  • Solution: The plugin automatically defaults to a 40-second timeout for optimized resilience. Ensure your local max_execution_time is set to at least 60s.

6.2.4 License Activation Restricted

Problem: "Maximum activation attempts exceeded." Reason: Security hardening prevents brute-force attempts on license keys. Solution: Wait 1 minute and ensure your license key is typed correctly. If the issue persists, contact support.

6.2.4 Webhook SSRF Violation

Problem: Webhook URL is not accepted or request is not sent. Reason: The system blocks private IP addresses (localhost, 192.168.x.x, etc.) for webhook URLs as a security measure. Solution: Ensure your Webhook URL points to a public, secure (HTTPS) endpoint.

6.3 Tax Calculation Issues

Solutions:

  1. Verify tax mode (VAT vs Sales Tax)
  2. Check if rates are set correctly
  3. Verify rounding mode settings

6.4 Email Delivery Problems

Solutions:

  1. Check "Notification Email" setting is correct
  2. Test with WordPress email test plugin
  3. Verify email isn't in spam folder
  4. Consider SMTP plugin for better deliverability

6.5 Performance Optimization

Built-in Object Caching

The plugin includes an optional caching layer for improved performance.

What Gets Cached:

  • Room availability queries (5-minute expiry)
  • Pricing rules (1-hour expiry)
  • Room type data (1-hour expiry)

Configuration:

  1. Go to Hotel Booking > Settings
  2. Find the Performance section
  3. Enable/disable caching

[!TIP] > Smart Calendar Caching: The visual calendar display uses a micro-cache algorithm (1-minute expiration) with immediate forced invalidation (Cache::invalidate_calendar_cache()) upon any successful booking change. This strategy provides sub-second page loads without sacrificing real-time booking accuracy.

For Developers:

// Clear all plugin caches
\MHBO\Core\Cache::flush();

// Clear cache for specific room
\MHBO\Core\Cache::invalidate_room($room_id);

PHP JIT (Optional)

PHP JIT can improve performance for complex calculations. Enable in php.ini:

opcache.enable=1
opcache.jit=tracing
opcache.jit_buffer_size=64M

6.6 iCal Sync Issues

Export URL Returns Empty Calendar

Cause: No bookings exist yet for that room — the ICS feed correctly outputs an empty VCALENDAR when there is nothing to report.

Fix: Create a test booking for the room, then reload the export URL. You should see a VEVENT block.

Export URL Returns 404 or "Not Found"

Cause: WordPress Pretty Permalinks have not been flushed since the plugin was activated.

Fix: Go to Settings > Permalinks and click Save Changes (no changes needed — just saving flushes the rewrite rules).

Status Shows "Pending" and Never Changes

Cause: Either no sync has run yet (wait for the next cron cycle) or WordPress Cron is not firing due to low traffic.

Fix:

  1. Click the Sync Now (↻) button in the connection's Actions column to trigger an immediate sync
  2. For persistent cron issues, add a system cron task: curl https://yoursite.com/wp-cron.php?doing_wp_cron every 5–15 minutes

Status Shows "Failed" With an Error Message

Common error messages and their causes:

Error Cause
cURL error 6: Could not resolve host The OTA URL is unreachable from your server
cURL error 60: SSL certificate problem The OTA's SSL certificate is invalid or expired
SSRF: unsafe URL The URL resolves to a private/internal IP — only public OTA URLs are allowed
Empty response body The OTA returned an empty feed — the listing may have been deleted or the URL changed
No VEVENT blocks found The OTA returned a valid calendar but with no events — the listing may have no future bookings

Fix: Verify the URL still opens in your browser and returns valid iCal data. If the OTA changed your export URL, delete the connection and re-add it with the new URL.

Booking.com Says "This iCal URL Isn't Valid"

Cause: Since March 2025, Booking.com validates iCal import URLs by domain. Any URL from a custom/personal website — including a valid MHBO .ics feed — is rejected. This is not a bug in the plugin; the feed is RFC 5545 compliant.

What to check first:

  1. Validate your feed at icalendar.org/validator.html to confirm it passes standard validation
  2. Open the Export URL in a private/incognito browser window to confirm it is publicly accessible (not behind a login or maintenance mode)
  3. Ensure there are no leading/trailing spaces in the pasted URL

If validation passes and the URL is publicly accessible, the rejection is confirmed to be Booking.com's domain-whitelist policy — not a technical error. See Section 3.6.9 for workarounds (manual blocking, Airbnb relay, Pulse app, channel manager).

Airbnb Still Shows Dates as Available After Sync

Cause: Airbnb does not poll your export URL in real time. Airbnb re-polls imported calendars approximately every 2–3 hours.

Fix:

  1. Verify your MHBO Export URL is saved correctly in Airbnb's calendar settings (Calendar → Availability Settings → Connected Calendars)
  2. Wait up to 3 hours after a new booking before expecting Airbnb to reflect the blocked dates
  3. You can request a manual refresh from Airbnb's connected calendars settings

Booking.com Bookings Not Appearing in MHBO

Cause: The import direction (Booking.com → MHBO) needs to be configured separately. Booking.com's restriction only prevents them from importing your URL — you can still import theirs.

Fix:

  1. Log in to Booking.com Extranet → Rates & Availability → Synchronise Calendars → Export Calendar (iCal)
  2. Copy the .ics URL
  3. In MHBO: Hotel Booking > Rooms → iCal icon → Import External Calendars → add the URL
  4. Click Connect Calendar, then Sync Now

Booking.com's extranet also has an "Import now" button under Synchronise Calendars to force an immediate refresh of any calendars they are importing from other OTAs.

Duplicate Bookings Appearing After Adding Booking.com Connection

Cause: If you configured the Airbnb-relay workaround (MHBO → Airbnb → Booking.com) AND separately added Booking.com's export feed into MHBO, the same booking may appear twice.

Fix: Ensure Conflict Resolution is set to Local Wins. The first booking processed wins; subsequent imports of the same UID are skipped.

Duplicate Bookings Appearing

Cause: Conflict Resolution is set to "External Wins" and the same date range exists in both MHBO and the OTA feed.

Fix: Go to Hotel Booking > PRO Features > iCal Sync > Settings and switch Conflict Resolution to Local Wins. Then manually cancel or delete any duplicate bookings from the Bookings list.

Receiving Failure Alert Emails

Cause: The configured failure threshold was reached (default: 3 consecutive failures). The plugin automatically schedules a retry after each failure.

Fix: Check the connection's inline error message for the root cause. Once the feed URL is valid again, click Sync Now — a successful sync resets the failure counter.


6.7 Getting Support

Before Contacting Support:

  1. Check this documentation
  2. Verify system requirements are met
  3. Test with default WordPress theme
  4. Disable other plugins to check for conflicts
  5. Gather error logs and screenshots

Support Channels:

Information to Include:

  • WordPress version
  • PHP version
  • Plugin version
  • Description of issue
  • Steps to reproduce
  • Error messages or screenshots

Document Version: 2.4.2 (L10n/iCal/Modal Remediation) Last Updated: April 25, 2026
License: GPLv2 or later