Knowledge base WordPress plugins Getting started
Setting up the Office 365 Microsoft Booking plugin
Base plugin, Azure token, licence, then a shortcode — the order the plugin actually enforces, with every [msb_booking] attribute and its default.
Published 12 August 2026
Office 365 Microsoft Booking (plugin version 5.0.0) renders a Microsoft Bookings business — its services, staff, availability and custom questions — as a booking form on a WordPress page. Every Microsoft Graph call is made server-side from PHP; the access token is never sent to the browser.
This page covers the setup order the plugin enforces. It will not render a form until all four of the steps below are done, and it fails in a different, specific way at each one.
1. Install the base Office 365 plugin first
This is not optional and not a soft dependency. The activation hook checks for
o365/o365.php; if it is not active, the plugin deactivates itself and stops with:
This plugin requires the Office 365 base plugin to be installed and activated.
The base plugin owns the settings screen (admin.php?page=o365_settings), the Azure
credential fields, the licence tab, the token tab, and the shared o365-builder and
m365-fabric styles this plugin enqueues.
2. Azure AD credentials and a token
Enter Client ID, Client Secret and Tenant ID in the base plugin’s Office 365 Settings. Until Client ID and Tenant ID are both present, the Plugins screen shows a warning row under this plugin pointing you there.
Then go to Microsoft 365 → Token Manager, where this plugin adds an Office 365 Microsoft Booking row, and click Get Token.
What that button does: a client credentials grant against
https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/token, requesting the
scope https://graph.microsoft.com/.default. There is no user sign-in and no
redirect — this is an application-permission flow, so the Graph permissions your app
registration needs must be granted with admin consent on the Azure side before the
token will be accepted by Graph.
The token is stored in the WordPress option msb_access_token, with its expiry in
msb_token_expires. On every request, if the token is within five minutes of expiry
the plugin refreshes it automatically on init — the Token Manager row says
Auto-refresh: enabled (client credentials grant) for that reason. The row also shows
Valid with the expiry timestamp, Expired, or No token, and offers Revoke
Token once one exists.
On multisite, if the base plugin’s o365_settings['shared_settings'] is yes, the
token is read from and written to site options instead of per-site options.
3. Activate the licence — per site
The licence key lives in the option o365_ms_booking_lcode and is always per-site,
even on multisite. Each subsite has to be activated separately; the licence tab says so
explicitly when it detects multisite.
Activate under Microsoft 365 → License. The key is checked against
api.wpintegrate.com before it is saved locally. An unlicensed site renders the
booking form as a single line of error text with a link to the licence tab, rather than
a form.
4. Build a shortcode
The plugin adds Booking Builder as a submenu of the Office 365 settings menu
(admin.php?page=o365_msb_builder). It is a settings panel plus a live preview iframe,
with these tabs:
- Source — Business ID and timezone. The Business ID field is a dropdown populated
from
GET /v1.0/solutions/bookingBusinesseswhen a token exists, and a plain text input when it does not. Timezone is picked from a bundled list; empty means auto-detect in the browser. - Layout — Detailed (the default template) or Compact.
- Services — which services to show, default service, default staff, and the hide-service / hide-staff toggles. These populate only after a business is selected.
- Calendar — locale, 12- or 24-hour time, first day of week, redirect URL, and “Require WordPress login”.
- Contact — hide any of name, phone, address or notes, each with a default value that is submitted in place of the hidden field. Email is always required and cannot be hidden.
- Cache — see below.
- Localization — override any of the widget’s static strings.
- Code — name and save the configuration, which gives you a short
[o365 id="N"]shortcode, or copy the full[msb_booking ...]form.
Both forms render the same widget: [o365 id="N"] looks the saved attributes up in the
base plugin’s shortcode registry and re-runs [msb_booking] with them.
The [msb_booking] shortcode
businessid is the only required attribute. Every other attribute and its default:
| Attribute | Default | What it does |
|---|---|---|
businessid | (required) | Microsoft Bookings business id |
template | long_form_tpl.php | Template file; the Compact layout is compact_tpl.php |
userbinding | no | yes requires a logged-in WordPress user |
timeformat | 12 | 12 or 24 |
cal_locale | en | Calendar locale |
firstday | 0 | 0 = Sunday … 6 = Saturday |
timezone | (empty) | Empty auto-detects |
showtimezone | yes | Show the timezone to the visitor |
service_ids | (empty) | Comma-separated; empty shows all services |
default_service | (empty) | Service preselected on load |
default_staff | (empty) | Comma-separated staff ids |
hide_service | no | Hides the service step — set default_service too |
hide_staff | no | Hides the staff picker |
hide_name / default_name | no / (empty) | |
hide_phone / default_phone | no / (empty) | |
hide_address / default_address | no / (empty) | |
hide_notes / default_notes | no / (empty) | |
show_service_image | no | See “Service images” below |
redirect_url | (empty) | Where to send the visitor after booking |
accept_payment | no | Stripe; see the note below |
text_overwrite | (empty) | JSON object of string overrides |
aboveservice, belowservice, belowstaffavail, belowcontactdetail, customsubmit | (empty) | Filenames of PHP partials to inject |
text_overwrite is JSON, so it has to be wrapped in single quotes:
[msb_booking businessid="..." text_overwrite='{"submit_button_txt":"Request appointment"}']
Templates and partials
Templates resolve child theme → parent theme → plugin, looking in
<theme>/o365-ms-booking/views/ and then templates/views/ inside the plugin. Copy
long_form_tpl.php into your child theme at that path to customise it without
touching the plugin. The five injection attributes resolve the same way (child theme
first, then plugin) and are wrapped in a div named after the attribute.
Service images
With show_service_image="yes", images are read from your active theme at
<theme>/o365-display/ms-booking/assets/<businessid>/ and are matched to services as
<service name>.png. Missing files are simply not shown.
A note on payments
The accept_payment attribute exists and its Stripe path is implemented — it creates a
PaymentIntent server-side and loads Stripe.js on the front end — but the checkbox for
it is commented out of the Booking Builder, marked “coming in next release”. Treat it
as not yet shipped.
Caching
Business, services, staff and custom-question responses from Graph are cached in WordPress transients so the widget loads fast and your tenant’s rate limits are spared. Two global options control it, both on the builder’s Cache tab:
msb_cache_enabled—yes(the default) ornomsb_cache_ttl_days— days, default7, coerced to at least 1
Cache keys are per business id (and, for services, per service_ids filter). Because
the default TTL is a week, a service or staff member you change in Microsoft Bookings
will not appear on the site until you click “Clear cache now” — that button is the
fix for “I renamed a service and the site still shows the old name”. Availability is
never cached.
Upgrading from v4.x
v5 ships a legacy compatibility layer, so the old [o365_ms_booking_view] shortcode,
its templates and its AJAX handlers keep working after the upgrade. An admin notice on
the Plugins and Office 365 screens says the layer is active and recommends
[msb_booking] for new pages; it is dismissible per user.
Legacy support is scheduled for removal in v6.0, so custom templates built on the old path should be migrated before then. You can turn the layer off early to test:
add_filter( 'o365_msb_load_legacy', '__return_false' );
Troubleshooting
Most failures surface as one line of text where the form should be. The exact wording tells you which step is missing.
“businessid is a required attribute for the booking shortcode.” — the shortcode has
no businessid. If you used [o365 id="N"], the saved configuration has no business
selected.
“Please activate your license to use the Office 365 Microsoft Booking plugin.” — no
key in o365_ms_booking_lcode on this site. On multisite the message names the
subsite; activating on another subsite does nothing for this one.
“Access token not configured. Please check the O365 plugin settings.” — step 2 was never completed, or the token was revoked. Go to Token Manager and click Get Token.
“Please log in to view the booking form.” — userbinding="yes" and the visitor is
not logged in.
“Template not found: …” — the template attribute names a file that exists in
neither the theme’s o365-ms-booking/views/ directory nor the plugin’s.
“Failed to fetch token. Check Azure AD app permissions and credentials.” — Azure rejected the client credentials grant. Wrong secret, expired secret, or wrong tenant.
“Missing Azure AD credentials. Check base O365 plugin settings (Client ID, Client Secret, Tenant ID).” — one of the three fields is blank in the base plugin.
“Base O365 plugin not active.” from the token button — the base plugin was deactivated after this one was set up.
“Graph API error 401” / “403” / “404” … — the plugin had a token and made the call,
and Microsoft Graph refused it. The number is Graph’s own HTTP status and the response
body is returned alongside it as details, so read that body: it carries Microsoft’s
error code and message, which is what actually identifies the problem. The two inputs
worth re-checking are the Business ID (it is the id from the Source dropdown, not the
display name) and whether your app registration’s Graph permissions were granted admin
consent.
Booking submission fails with “Customer creation failed: …” or “Booking failed: …” — these carry Microsoft’s own error message verbatim. Creating an appointment is a two-call sequence: the customer is created first, then the appointment. A failure at the first call means the appointment was never attempted.
The service list is empty in the Booking Builder — the preview overlay says “No services found. Set a Business ID in the Source tab”. If a business is set, check the token status in Token Manager first.
The plugin row on the Plugins screen shows a yellow warning — it names exactly which of the four setup steps is incomplete, in order, and links to the right tab. Read that before anything else.
Read next
-
WordPress plugins · Getting started
SharePoint Calendar Display: setup, shortcodes and room booking
Installing Office 365 SharePoint Calendar Display, the order the plugin requires, every attribute of [o365_sp_events] and [o365_sp_booking], and what each failure message means.
-
WordPress plugins · Embedding
Embedding Power BI Reports in WordPress
The [o365_powerbi] shortcode: the attributes it reads, the token it needs before it renders anything, and the error strings it prints when one of those is missing.
-
WordPress plugins · Authentication and access
Connecting the Office 365 plugin to an Azure app registration
The four fields on the Office 365 base plugin's General tab, what the Save button actually does with them, and why an unverified connection silently deactivates every add-on.