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
Method 1: WordPress Admin (Recommended)
- Go to Plugins > Add New in your WordPress dashboard
- Search for "Modern Hotel Booking"
- Click Install Now and then Activate
Method 2: Manual Upload
- Download the plugin zip file
- Go to Plugins > Add New > Upload Plugin
- Select the zip file and click Install Now
- Click Activate Plugin
Method 3: FTP Upload
- Extract the
modern-hotel-booking.zip file on your computer
- Upload the extracted folder to
/wp-content/plugins/ via FTP
- Go to Plugins in your WordPress dashboard
- 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:
- Go to Hotel Booking > Room Types
- Click Add New
- 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 |
- 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:
- Go to Hotel Booking > Rooms
- Click Add New
- 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) |
- 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:
- Navigate to your WordPress Admin dashboard.
- 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.
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):
- Edit the page where you want the booking form
- Click the + button to add a block
- Search for "Hotel: Booking Form"
- Drag the block onto the page
- Configure block settings in the sidebar (optional)
- 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:
- Edit the page
- Click the + button to add a block
- Search for "Hotel: Room Calendar"
- Drag the block onto the page
- Select the room from the dropdown in block settings
- 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. |
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).
A compact search box for sidebars or footers.
- Go to Appearance > Widgets
- Find "MHBO: Booking Search" widget
- Drag it to your desired widget area
- 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.
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
- Go to Hotel Booking > Bookings
- 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 |
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
- Go to Hotel Booking > Settings > License
- Enter your Pro License Key
- Click Activate License
- 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:
- Go to Hotel Booking > Settings > Payments
- Enable Stripe by checking the box
- Select Mode:
- Test - For development (use test cards)
- Live - For production (real transactions)
- Enter your API keys from Stripe Dashboard:
- Publishable Key - Safe for frontend
- Secret Key - Encrypted in database
- 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:
- Go to Hotel Booking > Settings > Payments
- Enable PayPal by checking the box
- Select Mode (Sandbox or Live)
- Enter credentials from PayPal Developer:
- Client ID - Public identifier
- Secret - Encrypted in database
- Click Test Credentials to verify
3.2.3 Pay on Arrival
Allow guests to book now and pay at arrival.
Setup:
- Go to Hotel Booking > Settings > Payments
- Enable Pay on Arrival
- 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
- Go to Hotel Booking > Settings > Tax
- Select Tax Mode (Disabled/VAT/Sales Tax)
- Enter Accommodation Tax Rate (for room charges)
- Enter Extras Tax Rate (for add-ons, may differ)
- 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:
- Go to Hotel Booking > Pricing Rules
- Click Add New Rule
- 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:
- Go to Hotel Booking > Settings > Advanced Pricing
- Select Weekend Days (Fri/Sat/Sun)
- Select Weekend Modifier Type (
multiplier, percent, or fixed)
- 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:
- Go to Hotel Booking > Pricing Rules
- Add a new rule for your holiday dates
- Select Adjustment Type (
Fixed or Percentage)
- 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.
- Go to Hotel Booking > Settings > General
- 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):
- Go to Hotel Booking > Settings > General
- Find Hotel Timezone.
- 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:
- Go to Hotel Booking > Inventory (Calendar View).
- Click Bulk Update.
- Select Date Range: July 1st to July 31st.
- Check Days of Week: Saturday.
- Enter Custom Price: 250.
- Click Apply & Save.
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:
- Go to Hotel Booking > Settings > Payments.
- Enable Compulsory Service Fee.
- Set Fee Type to
Percentage.
- Set Value to
5.00 (for 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
- Go to Hotel Booking > Rooms in your WordPress dashboard
- Find the room (e.g., "Room 101") and click the iCal icon in its Actions column
- 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.
- At the top of the iCal page, find the Deployment Export URL field
- Click Copy URL — the URL is now in your clipboard
- Log in to Airbnb → Calendar for your listing → Availability Settings → Connect Calendars → Import 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.
-
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
-
Back on the MHBO iCal page, scroll down to Import External Calendars
-
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
-
Click Connect Calendar
-
The platform badge (Airbnb / Booking.com) is set automatically — no dropdown needed
-
The connection appears in the table with status Pending
Step 4 — Trigger the first sync
- In the connections table, click the refresh (↻) icon next to the connection you just added
- Wait a few seconds, then reload the page
- The status should change to Synced (green check) and show the number of events imported
- 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
- Go to Hotel Booking > Rooms
- Locate the room you want to connect and click its iCal action icon in the row Actions column
- 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:
- Log in to Airbnb → Calendar for your listing
- Click Availability → Connect Calendars (or "Import Calendar")
- 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:
- In the Import External Calendars section, find the form below the connections table
- 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)
- Click Connect Calendar
- The platform is auto-detected (Airbnb, Booking.com, Travelminit, Szallas.hu, etc.) — no dropdown needed
- 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:
- Log in to Airbnb → Calendar for your listing
- Click Availability Settings → Export Calendar
- Copy the
.ics URL shown
Getting your iCal URL from Booking.com:
- Log in to Booking.com Extranet → Rates & Availability
- Click Synchronise Calendars → Export Calendar (iCal)
- 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:
- Go to Hotel Booking > PRO Features > iCal Sync
- 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). |
- 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:
- Deploy the updated plugin files to your production server (via FTP, Git, or your deployment tool).
- Visit Settings → Permalinks in WP Admin and click Save Changes to ensure a clean rewrite flush.
- 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.
- 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.
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.
- Your MHBO export URL is already synced to Airbnb (Airbnb accepts any domain)
- In Booking.com Extranet → Rates & Availability → Synchronise Calendars → Add calendar connection
- Paste your Airbnb listing's calendar export URL (Calendar → Availability Settings → Export Calendar)
- 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.
- Go to Hotel Booking > Settings > Themes
- 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:
- Go to Hotel Booking > Settings > GDPR & Privacy
- Check the box for Enable Pro Privacy Suite to activate data retention and cookie controls.
Consent Checkbox (Art. 7):
- Enable Require Privacy Consent to add a mandatory checkbox to your booking form.
- Select your Terms & Conditions Page from the dropdown.
- 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. |
- 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.
Instead of editing each day individually, use the Bulk Update button:
- Scope Selection: Choose to update a "Room Type" (affects all rooms of that type) or an "Individual Room".
- Date Range: Define your target window (e.g., "Dec 20 - Jan 5").
- Day Filter: Only apply changes to specific days (e.g., only Fridays and Saturdays).
- 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:
- Go to Hotel Booking > Settings > Communications.
- Enable Attach Invoice to Confirmation Email.
- 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.
- Go to Hotel Booking > Bookings.
- Click View on a booking with a deposit.
- 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).
- 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:
- The AI asks for their email and Booking ID.
- A secure One-Time Password (OTP) is sent to their email.
- 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:
- Click and drag across the calendar cells from the start date to the end date
- The Bulk Edit Panel opens, showing the date range
- Fill in the fields you want to change (leave others blank to leave them unchanged)
- 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:
- Click the Multi-select button in the top-right corner of the calendar toolbar
- The button turns highlighted to confirm the mode is active
- Click individual day cells to add or remove them from your selection
- 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:
- Click Edit Selected in the selection bar
- Fill in only the fields you want to change
- Click Apply to All Selected
- 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:
- Export the JSON file
- Edit the file in any text editor — change prices, add new override entries, adjust pricing rules, or update
base_price
- Click Import JSON and select your edited file
- 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
- Resolve any conflicts using the radio buttons
- 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:
- Open the Room Type calendar
- Click-drag from the first to last date of the peak window
- Enter the peak price in the Bulk Edit panel
- Click Apply
Blocking a room for maintenance:
- Open the Individual Room calendar (not the type)
- Click-drag the maintenance dates
- Set Availability → Blocked
- Click Apply
- 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:
- Open the Room Type calendar
- Use Multi-select to pick the specific dates (e.g., Fri–Mon of a bank holiday)
- Click Edit Selected
- Set Min Stay → 3, leave all other fields blank
- Click Apply to All Selected
Annual pricing backup:
- On both the Room Type and each Individual Room calendar, click Export JSON
- Store the files in your backup folder or cloud storage
- 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:
- Go to Hotel Booking > Bookings.
- Find the reservation you wish to bill and click Edit.
- Scroll to the bottom of the page to find the Actions Dock.
- 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.
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:
- 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.
- 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.
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:
- Identity Request: The guest asks for their booking info.
- OTP Dispatch: The system sends a unique 6-digit code to the guest's registered email address (valid for 20 minutes).
- Verification: The guest enters the code in the chat.
- 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
- Go to Hotel Booking → Settings → Coupons.
- Toggle Enable Coupon System to On.
- (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.
- 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
- Click Add Coupon.
- Fill in the fields in the modal (see Coupon Fields Reference).
- 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
- Guest selects room(s) and dates on the booking form.
- A Coupon Code field appears below the price summary (above the payment section).
- Guest types their code and clicks Apply.
- If valid, a green confirmation message shows: "Coupon applied: SUMMER20 — $20.00 off".
- The price summary and tax breakdown update in real time to reflect the discount.
- 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
- A guest tells the AI: "Do you have any discount codes?" or "Apply my promo code SUMMER20."
- The AI calls the
apply_promo_code tool internally.
- The tool validates the coupon using the same server-side rules (expiry, min spend, room type, usage limit).
- If valid, the coupon is applied to the guest's booking session.
- 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:
- Coupon discount is subtracted from the full booking total.
- The deposit percentage is then calculated on the discounted total.
- 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
- Go to Hotel Booking > Settings > API > Webhooks.
- Enable Webhooks: Toggle the master switch to activate the listener.
- Webhook URL: Enter the endpoint of your external application (e.g.,
https://api.myapp.com/webhooks/mhbo).
- Webhook Secret: This is the shared secret used for HMAC-SHA256 signature verification.
- 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
Solutions:
- Clear cache (plugins, CDN, browser)
- Check for JavaScript errors in browser console
- Verify theme compatibility (try default theme)
- Check PHP error logs
Availability Not Updating
Solutions:
- Check booking statuses (cancelled bookings may still block)
- Verify iCal sync isn't creating conflicts
- Check database for orphaned bookings
6.2 Payment Problems
Stripe Payment Fails
Solutions:
-
Verify API keys are correct (test vs live mode)
-
Check Stripe Dashboard for declined reason
-
Ensure SSL certificate is valid
-
Verify currency is supported by Stripe
-
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:
- Verify tax mode (VAT vs Sales Tax)
- Check if rates are set correctly
- Verify rounding mode settings
6.4 Email Delivery Problems
Solutions:
- Check "Notification Email" setting is correct
- Test with WordPress email test plugin
- Verify email isn't in spam folder
- Consider SMTP plugin for better deliverability
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:
- Go to Hotel Booking > Settings
- Find the Performance section
- 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:
- Click the Sync Now (↻) button in the connection's Actions column to trigger an immediate sync
- 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.
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:
- Validate your feed at icalendar.org/validator.html to confirm it passes standard validation
- Open the Export URL in a private/incognito browser window to confirm it is publicly accessible (not behind a login or maintenance mode)
- 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:
- Verify your MHBO Export URL is saved correctly in Airbnb's calendar settings (Calendar → Availability Settings → Connected Calendars)
- Wait up to 3 hours after a new booking before expecting Airbnb to reflect the blocked dates
- You can request a manual refresh from Airbnb's connected calendars settings
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:
- Log in to Booking.com Extranet → Rates & Availability → Synchronise Calendars → Export Calendar (iCal)
- Copy the
.ics URL
- In MHBO: Hotel Booking > Rooms → iCal icon → Import External Calendars → add the URL
- 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.
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:
- Check this documentation
- Verify system requirements are met
- Test with default WordPress theme
- Disable other plugins to check for conflicts
- 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