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

Knowledge base 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.

Published 12 August 2026

  • sharepoint
  • calendar
  • booking
  • rooms
  • shortcode
  • microsoft graph

Office 365 SharePoint Calendar Display (plugin file o365-wp-sp-calendar-display.php, version 3.2) renders a SharePoint calendar list on a WordPress page as a list or a full calendar, and provides a separate room-booking calendar that collects requests through Contact Form 7.

It reads SharePoint through Microsoft Graph with an app-only token — a client credentials token held by WordPress, not by the visitor. Everyone who can see the page sees the same events, whether or not they are signed in to anything.

Order of operations

The plugin refuses to work if you do these out of order, and it refuses in different places each time, so it is worth doing them in this sequence.

1. Install and configure the o365 base plugin first

This is an add-on. Activating it while the base plugin o365/o365.php is inactive stops activation dead with:

This plugin requires o365 base plugin.

And if the base plugin is installed but not yet configured (option o365_base_plugin_is_verify is 0), activation deactivates this plugin again and prints:

ERROR: This plugin needs to be configured on the settings page >> General tab, before proceeding.

The base plugin adds a top-level admin menu labelled Microsoft 365 in the sidebar (its page title reads Office 365 Settings) with Settings, Add-Ons, License and Premium Plans below it. On the settings page you save the Azure app registration’s client_id, client_secret and tenant_name — all of which live in the single o365_settings option. From tenant_name the base plugin derives application_tenant_domain_name as <tenant_name>.onmicrosoft.com, which is the tenant this plugin then asks for tokens against.

2. Enter the licence key

Until you do, both shortcodes render nothing but a sentence:

Please enter the Office365 SharePoint Calendar Display Plugin activation key.

The key goes on Microsoft 365 → License, in the row labelled Office 365 Sharepoint Calendar Display. Press Activate. That stores the key in o365_sp_calendar_lcode and sets o365_sp_calendar_verify_auth to yes; the gate in both shortcodes is that second option. Delete License clears them again, and every admin page shows a yellow nag pointing at admin.php?page=o365_license while the licence is unset.

3. Let the plugin fetch a Graph token

With no token stored, an error notice appears on every admin screen:

Office 365 Sharepoint Calendar Display Plugin doesn’t have an access token. Click here to go to the token manager.

The token is fetched by loading Microsoft 365 itself (admin.php?page=o365_settings) — that page load is what hooks the token routine. The plugin then POSTs to https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token with grant_type=client_credentials and scope=https://graph.microsoft.com/.default, and redirects back to the settings page with either o365_token_message=Successfully get Sharepoint calendar access token or o365_token_message=Error while getting access token in the query string.

.default means the plugin asks for exactly the application permissions your app registration already has admin consent for — it never requests an individual scope by name. So the permissions must be granted on the Azure side first. The plugin builds the admin-consent URL

https://login.microsoftonline.com/<tenant>/adminconsent?client_id=<client_id>&state=o365_calendar_identifier&redirect_uri=<your wp-admin URL>

but the redirect to it is commented out in the source, so nothing sends your admin there automatically. Consent has to be granted in Azure, or by visiting that URL by hand. See Azure app registration setup.

The token is stored in sp_calendar_access_token with an expiry of one hour in sp_calendar_access_token_expires_timestamp, and is renewed on any request made within five minutes of expiry. Deactivating the plugin deletes all three token options, so a deactivate/reactivate cycle means step 3 again.

The plugin auto-creates a page titled SP Event and registers rewrite rules under /sp-event/... to render single events on it. It never flushes the rewrite rules, so until you open Settings → Permalinks and save, the “Read More” links out of the list view will 404.

Displaying a calendar

[o365_sp_events siteid="SITE_ID" listid="LIST_ID" type="calendar" id="o365cal1"]

siteid and listid are Microsoft Graph identifiers, not URLs — the plugin calls https://graph.microsoft.com/v1.0/sites/<siteid>/lists/<listid>/items directly. If either is empty nothing is requested.

type selects the renderer: list (the default) or calendar. The list view paginates — it follows Graph’s @odata.nextLink behind a Load More control, and shows “No More Result Found” when the last page is in. The calendar view is FullCalendar with month, week, day and list-month views.

Every attribute of [o365_sp_events]

AttributeDefaultWhat it does
siteid(empty)Graph site id. Required.
listid(empty)Graph list id. Accepts a comma-separated list to draw several calendars at once.
typelistlist or calendar.
ido365Prefix for this instance’s DOM ids and for its saved options. Give every shortcode on a page — and across the site — a distinct value.
template(empty)Filename of a template to use instead of the default.
columnsEndDate,EventDate,Category,ID,Location,Title,fAllDayEvent,RecurrenceID,fRecurrence,RecurrenceData,MasterSeriesItemID,DescriptionPassed straight into Graph’s expand=fields(select=…).
maxresults1000Becomes $top.
sortEventDate ascBecomes $orderby=fields/<value>.
fromdate / todate(empty)With both set, filters fields/EventDate geand fields/EndDate le ….
month(empty)YYYY-MM. Filters to that whole month. Ignored if fromdate/todate are set.
eventtype(empty)Any non-empty value filters to events from today onward.
category(empty)Adds and fields/Category eq '<value>' to whichever filter is in play.
color(empty)Comma-separated colours, one per id in listid. Falls back to #3a87ad.
timediff(empty)Whole hours added to every start and end before display. This is the only timezone control that actually moves times.
timezoneCentral Standard TimeDeclared default. The single-event template assigns it to $o365_cal_timezone, which nothing then uses, so setting it has no effect.
userbindingnoyes requires a logged-in WordPress user; anonymous visitors get “First need to login to wordpress.” instead of the calendar.
mthviewdaylimit(empty)Sets FullCalendar’s eventLimit in month view. Empty means no limit.
showprintviewyesAdds a Print button to the calendar header (desktop layout only).
is_cached(empty)yes turns on the calendar view’s month cache.
cache_duration8Cache lifetime in hours. Only read when is_cached="yes".
showcountdownnoAppended to the single-event link as a countdown query parameter (static-site link mode only).
showsocialshareyesShare links on the single-event page.
showmapyesEmbedded Google map of the event’s Location on the single-event page.
addthis / addthis_id / addthis_tool_id(empty)AddThis share widget on the single-event page.
cf7id(empty)Contact Form 7 form id.
url(empty)Carried through the AJAX payload; not used to address SharePoint.

Two shortcodes sharing an id overwrite each other: the attributes are serialised into an option named <id>_o365_sp_cal_shortcode_option, which is what the single-event page reads back. The same string also prefixes the DOM element ids, so duplicates break the JavaScript as well.

Caching

Only the calendar view caches. With is_cached="yes" it writes one file per page and month into the plugin’s own cache/ directory, named <page_id>_<YYYY-MM>.json, and records the write time in an option named <page_id>_<YYYY-MM>. The list view always hits Graph.

Room booking

[o365_sp_booking siteid="SITE_ID" listid="LIST_ID" cf7id="123" businessdays="1,2,3,4,5" starttime="09.00" endtime="17.00"]

Understand what this does before you promise it to anyone: it does not write to SharePoint. It draws a FullCalendar view of the list, labels every existing item Reserved, lets the visitor drag out a free slot in day view, fills hidden fields with that slot, and submits a Contact Form 7 form. Turning that request into an actual booking is a human step, or whatever automation you attach to CF7.

Attributes specific to [o365_sp_booking]:

AttributeDefaultWhat it does
businessdays1,2,3,4,5Days a (+)Book link appears on, 1 = Monday through 7 = Sunday.
starttime09.00Earliest selectable time. Note the format: a dot, not a colon.
endtime20Latest selectable time, same format.
columnsfAllDayEvent,Title,ID,EndDate,EventDateFields requested from Graph.
colorcolumn(empty)A list column whose value picks the event colour.
color(empty)Value:#rrggbb pairs, comma separated, matched against colorcolumn.
hidebasedcol / hidebasedval(empty)Set both and only items whose hidebasedcol value is in the comma-separated hidebasedval list are drawn.
cf7id(empty)Contact Form 7 form id. Required — without it the popup contains the text “Please add contact form id in shortcode.”

The time checks are client-side alerts, in this order: a slot starting earlier than “now” on today’s date, then a start before starttime, then an end after endtime, each of which cancels the selection with a message naming the boundary.

Custom templates

Both shortcodes look in your child theme before the plugin, at o365-display/sp-cal/views/ inside the theme directory. Drop a file there with the same name as the one you want to replace and it wins:

  • list_tpl.php — the list view
  • calendar_tpl.php — the calendar view
  • room_booking_tpl.php — the booking calendar

Or pass template="my-file.php" and it is resolved from the same theme folder first, then from the plugin’s own templates/views/list/ or templates/views/calendar/.

The single-event page template overrides the same way, at o365-display/sp-cal/pages/o365-sp-calendar-single-event.php.

Troubleshooting

“Tenant name or Sharepoint token data not defined.Please O365 check base plugin setting tab.” — the shortcode ran but either sp_calendar_access_token or tenant_name is empty. Almost always the token: check for the missing-token admin notice, then reload Microsoft 365 to trigger a fetch.

“Please enter the Office365 SharePoint Calendar Display Plugin activation key.”o365_sp_calendar_verify_auth is unset or false. Licence key, step 2.

“First need to login to wordpress.” — you set userbinding="yes" and the visitor is anonymous.

“No Records Found.” / “No records found!!!” — the request succeeded and came back empty. The usual causes are a filter you did not mean to apply (month, fromdate / todate, category, or eventtype) and a list whose date columns are not the standard EventDate / EndDate this plugin filters and sorts on.

“ERROR: Please Try Again!!!” as a browser alert — the admin-ajax.php request itself failed. Look at the network response for that request: a Graph error (expired token, missing application permission, a site or list id that does not resolve) surfaces here rather than as a readable message on the page.

Nothing renders at all, no message — check that siteid and listid are both present. With either missing the AJAX handler returns without a payload.

Events are consistently a few hours out — that is timediff, or the lack of it. The plugin does not convert timezones; it adds the whole number of hours you give it.

Stale events in the calendar view. If you turned on is_cached, be aware that the expiry path records the cached file under a different directory from the one it writes to, so an expired file is not reliably deleted and the stale copy keeps being served. The reliable fix is the Clean Cache button on the base plugin’s settings page, which deletes every file in the plugin’s cache/ directory. If you cannot afford stale data, leave is_cached off — the list view never caches.

“Read More” links 404 — the /sp-event/... rewrite rules are registered but never flushed. Open Settings → Permalinks and save.

What this plugin does not do

  • It does not create or edit SharePoint list items. Both shortcodes are read-only against Graph; the booking flow ends in an email from Contact Form 7.
  • It does not filter events per visitor. One app-only token serves every request, so anything in the list is public to anyone who can load the page. userbinding="yes" gates the page, not the data.
  • It does not expand recurring events on the server. RecurrenceData and friends are requested as raw list columns and handled, where at all, in the view.

Read next

  • 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.

  • 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.

Back to the knowledge base