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
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.
4. Re-save your permalinks
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]
| Attribute | Default | What it does |
|---|---|---|
siteid | (empty) | Graph site id. Required. |
listid | (empty) | Graph list id. Accepts a comma-separated list to draw several calendars at once. |
type | list | list or calendar. |
id | o365 | Prefix 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. |
columns | EndDate,EventDate,Category,ID,Location,Title,fAllDayEvent,RecurrenceID,fRecurrence,RecurrenceData,MasterSeriesItemID,Description | Passed straight into Graph’s expand=fields(select=…). |
maxresults | 1000 | Becomes $top. |
sort | EventDate asc | Becomes $orderby=fields/<value>. |
fromdate / todate | (empty) | With both set, filters fields/EventDate ge … and 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. |
timezone | Central Standard Time | Declared default. The single-event template assigns it to $o365_cal_timezone, which nothing then uses, so setting it has no effect. |
userbinding | no | yes 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. |
showprintview | yes | Adds a Print button to the calendar header (desktop layout only). |
is_cached | (empty) | yes turns on the calendar view’s month cache. |
cache_duration | 8 | Cache lifetime in hours. Only read when is_cached="yes". |
showcountdown | no | Appended to the single-event link as a countdown query parameter (static-site link mode only). |
showsocialshare | yes | Share links on the single-event page. |
showmap | yes | Embedded 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]:
| Attribute | Default | What it does |
|---|---|---|
businessdays | 1,2,3,4,5 | Days a (+)Book link appears on, 1 = Monday through 7 = Sunday. |
starttime | 09.00 | Earliest selectable time. Note the format: a dot, not a colon. |
endtime | 20 | Latest selectable time, same format. |
columns | fAllDayEvent,Title,ID,EndDate,EventDate | Fields 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 viewcalendar_tpl.php— the calendar viewroom_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.
RecurrenceDataand 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.