Using WordPress? Every integration here is also available as a plugin. Browse the plugin store →

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

  • bookings
  • appointments
  • setup
  • shortcode
  • wordpress

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/bookingBusinesses when 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.
  • LayoutDetailed (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:

AttributeDefaultWhat it does
businessid(required)Microsoft Bookings business id
templatelong_form_tpl.phpTemplate file; the Compact layout is compact_tpl.php
userbindingnoyes requires a logged-in WordPress user
timeformat1212 or 24
cal_localeenCalendar locale
firstday00 = Sunday … 6 = Saturday
timezone(empty)Empty auto-detects
showtimezoneyesShow 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_servicenoHides the service step — set default_service too
hide_staffnoHides the staff picker
hide_name / default_nameno / (empty)
hide_phone / default_phoneno / (empty)
hide_address / default_addressno / (empty)
hide_notes / default_notesno / (empty)
show_service_imagenoSee “Service images” below
redirect_url(empty)Where to send the visitor after booking
accept_paymentnoStripe; 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_enabledyes (the default) or no
  • msb_cache_ttl_days — days, default 7, 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

Back to the knowledge base