{"id":307966,"date":"2026-05-15T21:02:09","date_gmt":"2026-05-15T21:02:09","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/sdaweb-calendar-sync-for-google-calendar\/"},"modified":"2026-09-21T18:49:45","modified_gmt":"2026-09-21T18:49:45","slug":"sdaweb-gcal-sync","status":"publish","type":"plugin","link":"https:\/\/twd.wordpress.org\/plugins\/sdaweb-gcal-sync\/","author":23453481,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.23.5","stable_tag":"0.23.5","tested":"7.1.2","requires":"6.5","requires_php":"7.4","requires_plugins":null,"header_name":"SDAweb Calendar Sync for Google Calendar","header_author":"SDAweb - Rune Stake Stavdal, Vinjar Romsvik, Christer Andvik","header_description":"Display events from one or more Google Calendars on your WordPress site. Six views, hover popovers, ICS subscribe, mobile-aware, theme-aware, accessible by default, no third-party relays.","assets_banners_color":"","last_updated":"2026-09-21 18:49:45","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/sdaweb.no","rating":0,"author_block_rating":0,"active_installs":50,"downloads":2300,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.10.0":{"tag":"0.10.0","author":"rstake","date":"2026-05-24 14:44:22","revision":3546348},"0.10.1":{"tag":"0.10.1","author":"rstake","date":"2026-05-24 15:02:33","revision":3546362},"0.11.0":{"tag":"0.11.0","author":"rstake","date":"2026-05-24 16:32:30","revision":3546426},"0.11.1":{"tag":"0.11.1","author":"rstake","date":"2026-05-24 16:41:10","revision":3546433},"0.12.0":{"tag":"0.12.0","author":"rstake","date":"2026-05-24 17:04:08","revision":3546443},"0.12.1":{"tag":"0.12.1","author":"rstake","date":"2026-05-24 17:45:00","revision":3546472},"0.12.2":{"tag":"0.12.2","author":"rstake","date":"2026-05-24 17:59:57","revision":3546493},"0.12.8":{"tag":"0.12.8","author":"rstake","date":"2026-05-24 19:20:36","revision":3546548},"0.12.9":{"tag":"0.12.9","author":"rstake","date":"2026-05-24 20:41:27","revision":3546591},"0.13.0":{"tag":"0.13.0","author":"rstake","date":"2026-05-24 21:49:49","revision":3546644},"0.13.4":{"tag":"0.13.4","author":"rstake","date":"2026-05-25 14:11:37","revision":3547723},"0.14.0":{"tag":"0.14.0","author":"rstake","date":"2026-06-06 18:30:58","revision":3563306},"0.14.1":{"tag":"0.14.1","author":"rstake","date":"2026-06-06 19:15:26","revision":3563327},"0.14.2":{"tag":"0.14.2","author":"rstake","date":"2026-06-06 19:25:48","revision":3563332},"0.14.6":{"tag":"0.14.6","author":"rstake","date":"2026-06-07 14:39:06","revision":3563747},"0.15.0":{"tag":"0.15.0","author":"rstake","date":"2026-06-07 20:25:20","revision":3563887},"0.15.1":{"tag":"0.15.1","author":"rstake","date":"2026-06-07 22:17:53","revision":3563975},"0.16.0":{"tag":"0.16.0","author":"rstake","date":"2026-06-07 23:24:04","revision":3564013},"0.16.1":{"tag":"0.16.1","author":"rstake","date":"2026-06-07 23:36:56","revision":3564018},"0.16.3":{"tag":"0.16.3","author":"rstake","date":"2026-06-08 08:00:29","revision":3564274},"0.16.4":{"tag":"0.16.4","author":"rstake","date":"2026-06-08 10:06:27","revision":3564469},"0.17.0":{"tag":"0.17.0","author":"rstake","date":"2026-06-08 18:59:35","revision":3565086},"0.18.0":{"tag":"0.18.0","author":"rstake","date":"2026-06-08 19:51:35","revision":3565129},"0.18.1":{"tag":"0.18.1","author":"rstake","date":"2026-06-08 20:44:05","revision":3565206},"0.19.0":{"tag":"0.19.0","author":"rstake","date":"2026-06-09 13:48:09","revision":3566095},"0.20.0":{"tag":"0.20.0","author":"rstake","date":"2026-06-10 15:16:53","revision":3567712},"0.21.1":{"tag":"0.21.1","author":"rstake","date":"2026-06-13 15:04:13","revision":3571169},"0.21.4":{"tag":"0.21.4","author":"rstake","date":"2026-06-13 20:47:18","revision":3571330},"0.21.6":{"tag":"0.21.6","author":"rstake","date":"2026-06-20 13:03:42","revision":3579802},"0.22.0":{"tag":"0.22.0","author":"rstake","date":"2026-06-21 18:46:30","revision":3580914},"0.22.1":{"tag":"0.22.1","author":"rstake","date":"2026-08-07 10:03:37","revision":3637685},"0.22.5":{"tag":"0.22.5","author":"rstake","date":"2026-08-13 19:30:03","revision":3646079},"0.22.6":{"tag":"0.22.6","author":"rstake","date":"2026-08-13 20:51:16","revision":3646210},"0.23.0":{"tag":"0.23.0","author":"rstake","date":"2026-09-14 15:09:25","revision":3695475},"0.23.1":{"tag":"0.23.1","author":"rstake","date":"2026-09-20 17:10:47","revision":3704491},"0.23.2":{"tag":"0.23.2","author":"rstake","date":"2026-09-20 20:13:16","revision":3704587},"0.23.3":{"tag":"0.23.3","author":"rstake","date":"2026-09-20 20:41:51","revision":3704604},"0.23.4":{"tag":"0.23.4","author":"rstake","date":"2026-09-20 21:47:49","revision":3704649},"0.23.5":{"tag":"0.23.5","author":"rstake","date":"2026-09-21 18:49:45","revision":3706163},"0.8.5":{"tag":"0.8.5","author":"rstake","date":"2026-05-15 21:07:45","revision":3533430},"0.8.6":{"tag":"0.8.6","author":"rstake","date":"2026-05-15 21:25:16","revision":3533443},"0.9.0":{"tag":"0.9.0","author":"rstake","date":"2026-05-19 19:33:45","revision":3537881},"0.9.1":{"tag":"0.9.1","author":"rstake","date":"2026-05-19 20:17:49","revision":3537905},"0.9.2":{"tag":"0.9.2","author":"rstake","date":"2026-05-20 13:10:50","revision":3539361},"0.9.3":{"tag":"0.9.3","author":"rstake","date":"2026-05-24 12:45:14","revision":3546249},"0.9.4":{"tag":"0.9.4","author":"rstake","date":"2026-05-24 12:57:53","revision":3546265},"0.9.5":{"tag":"0.9.5","author":"rstake","date":"2026-05-24 13:23:53","revision":3546283}},"upgrade_notice":{"0.23.5":"<p>Busy Month\/Week\/Day\/mini calendars no longer lose their last days to the &quot;Max events&quot; limit. View-switcher links get their names back for screen readers on phones. No more fatal error on servers without mbstring.<\/p>","0.23.4":"<p>Upcoming now shows today&#039;s all-day events and running multi-day events; Day view shows multi-day events; events ending at midnight no longer spill into the next day. &quot;Hide past events&quot; now works and is switched off on existing displays so nothing changes.<\/p>","0.23.3":"<p>Security hardening: the Google API key is no longer shown in admin debug details when WP_DEBUG is on. Also keeps the saved events when Google answers with something that is not calendar data.<\/p>","0.23.2":"<p>Fixes view switching (dead &quot;+N more&quot; and popovers after switching to Month, broken Back button, stale mini calendar), &quot;Refresh now&quot; not reaching visitors, and calendars broken by a configuration import (repaired automatically).<\/p>","0.23.1":"<p>Privacy fix: the Subscribe (ICS) feed now respects the display&#039;s search and hide filters. Also keeps showing the last saved events when Google is unreachable, and fixes a page-truncation bug from unusual event titles. Recommended for all sites.<\/p>","0.23.0":"<p>Only ordinary events are shown now: birthdays, Gmail reservations and Workspace working-location \/ out-of-office entries no longer appear on public calendars. Service-account scope narrowed to events.readonly; no action needed.<\/p>","0.22.1":"<p>Fixes the Upcoming (compact list) view showing multi-day all-day events as single-day. It now shows the date range instead of &quot;All day&quot;. Front-end fix.<\/p>","0.21.6":"<p>Fixes the styled hover popover falling back to the browser&#039;s plain tooltip after paging between months via the arrow navigation. Front-end fix; the styled popover now survives instant month navigation (and browser back\/forward).<\/p>","0.21.4":"<p>Fixes the Upcoming view showing fewer events than &quot;Maximum events to show&quot; when the calendar has events earlier the same day. Front-end fix; the view now reliably shows the configured number of upcoming events.<\/p>","0.21.3":"<p>The Displays editor&#039;s Live preview now shows a &quot;Showing N events&quot; count of what it rendered (the same as the front-end), so you can confirm a display&#039;s event count at a glance. Admin-only; no front-end change.<\/p>","0.21.2":"<p>Clearer Upcoming options: &quot;Event time size&quot; greys out (with a reason) when the meta line is off, and the event-name size\/weight controls are renamed to avoid confusion with the time control. Admin-only; no front-end change.<\/p>","0.21.1":"<p>Accessibility polish on the Displays view-filter: each button now announces its section count to screen readers, with correct singular\/plural. Admin-only; no front-end change.<\/p>","0.21.0":"<p>The Displays editor&#039;s view chips become a single filter bar that truly hides (not dims) settings that don&#039;t apply to the chosen view, with per-view counts and a live status line. Admin-only; all fields still save while filtered. No front-end change.<\/p>","0.20.0":"<p>Splits &quot;Event chip style&quot; into two independent settings \u2014 &quot;List view: event row style&quot; and &quot;Month view: event chip style&quot; \u2014 so you can style both views on one display. Existing displays, blocks, and shortcodes migrate automatically with no visual change.<\/p>","0.19.1":"<p>Fixes List view styling (week-heading pills + event accent bars) vanishing after an instant view-swap; a stray focus box around a heading after a swap on iOS \/ touch; and the Month\/Week\/Day\/Mini prev\/next arrows could switch the view instead of just changing the period.<\/p>","0.19.0":"<p>Polishes the List view&#039;s week\/day section headings (clearer typography) and removes a stray focus box that could appear around the first heading after an instant view-swap. Visual refinement only \u2014 no settings to change.<\/p>","0.18.1":"<p>Adds an optional dedicated colour for the Upcoming &quot;Today \/ Tomorrow&quot; pill. Default is unchanged (the pill follows the event colour) until you set it.<\/p>","0.18.0":"<p>Adds two opt-in Upcoming-view options: a time\/All-day text size and a dedicated date-badge colour. Defaults are unchanged, so existing displays look exactly the same until you set them.<\/p>","0.17.0":"<p>Adds three opt-in Upcoming-view options: date-badge size, Today\/Tomorrow labels, and day\/week grouping. Defaults are unchanged, so existing displays look exactly the same until you enable them.<\/p>","0.16.4":"<p>Adds an admin &quot;Event text size&quot; (and optional weight) control for the Upcoming view. Defaults are unchanged, so existing displays look exactly the same until you opt in.<\/p>","0.16.3":"<p>Completes the 0.16.2 fix for the mobile\/instant-view-swap path: the toggle date guard now lives in the shared anchor resolver, and the render cache is version-keyed so an upgrade self-busts stale HTML. Clear the calendar render cache once after updating.<\/p>","0.16.2":"<p>Bug fix: the view-toggle links could send a view switch to a garbage date (with no events) on the default no-date render, locking every view onto it. Toggles now follow the same resolved date as the grid and Prev\/Today\/Next, with a guard against out-of-range dates. No action required.<\/p>","0.16.1":"<p>New per-display &quot;Link event titles&quot; toggle \u2014 turn it off to show event titles as plain text (no link) when the Google event page isn&#039;t useful to visitors. Default on; existing displays unchanged.<\/p>","0.16.0":"<p>Internal hardening: the per-Display settings now flow through one shared schema, preventing the recurring class of &quot;works in the admin preview but not on the front-end&quot; bugs. No action required.<\/p>","0.15.1":"<p>Bug fix: the per-display Chip text color setting now applies on the front-end (not just in the admin preview). Also redacts the API key from error-log lines and tidies up leftover options on uninstall. No action required.<\/p>","0.15.0":"<p>Bug fix: long unspaced event titles no longer overflow the box in the Cards view. Also bundles the 0.14.x additions \u2014 Upcoming &quot;Link placement&quot; control, optional date-badge style, and the touch-device tagged-link fix. No action required.<\/p>"},"ratings":[],"assets_icons":{"icon.svg":{"filename":"icon.svg","revision":3533428,"resolution":false,"location":"assets","locale":false}},"assets_banners":[],"assets_blueprints":{},"all_blocks":{"sdaweb-gcal\/calendar":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"sdaweb-gcal\/calendar","version":"0.23.5","title":"SDAweb Calendar","category":"widgets","description":"Display events from one or more Google Calendars. Choose a saved display or configure inline.","icon":"calendar-alt","keywords":["calendar","google","events","schedule"],"supports":{"html":false,"align":["wide","full"],"spacing":{"margin":true,"padding":true}},"attributes":{"displayId":{"type":"string","default":""},"calendars":{"type":"string","default":""},"view":{"type":"string","default":"list"},"days":{"type":"number","default":30},"daysBack":{"type":"number","default":0},"anchorDate":{"type":"string","default":""},"startDate":{"type":"string","default":""},"endDate":{"type":"string","default":""},"dateFormat":{"type":"string","default":""},"timeFormat":{"type":"string","default":""},"rangeMode":{"type":"string","default":"rolling"},"rangePreset":{"type":"string","default":""},"max":{"type":"number","default":50},"group":{"type":"string","default":"day"},"showEnd":{"type":"boolean","default":false},"showEventDate":{"type":"boolean","default":false},"showCalendar":{"type":"boolean","default":false},"calendarLabelMode":{"type":"string","default":""},"showFeedLegend":{"type":"boolean","default":false},"labels":{"type":"object","default":{}},"showLocation":{"type":"boolean","default":false},"showDescription":{"type":"boolean","default":false},"descriptionWords":{"type":"number","default":30},"hideAllDay":{"type":"boolean","default":false},"hideCancelled":{"type":"boolean","default":true},"hidePast":{"type":"boolean","default":false},"search":{"type":"string","default":""},"timezone":{"type":"string","default":""},"primaryColor":{"type":"string","default":""},"accentColor":{"type":"string","default":""},"darkMode":{"type":"string","default":"auto"},"linkTarget":{"type":"string","default":"same"},"viewToggle":{"type":"boolean","default":false},"viewToggleViews":{"type":"string","default":"list,month,card"},"viewTogglePosition":{"type":"string","default":"top-right"},"timeFormatMode":{"type":"string","default":"site"},"firstDayOfWeek":{"type":"string","default":"site"},"showWeekNumbers":{"type":"boolean","default":false},"recurrenceIndicator":{"type":"string","default":"icon"},"icsSubscribe":{"type":"string","default":"none"},"listWeekHeading":{"type":"string","default":"number"},"listHeadingStyle":{"type":"string","default":"relative"},"mobileDegrade":{"type":"string","default":"auto"},"miniDefaultPanel":{"type":"string","default":"today_upcoming"},"miniUpcomingMax":{"type":"number","default":30},"miniFullUrl":{"type":"string","default":""},"miniFullLabel":{"type":"string","default":""},"todayColor":{"type":"string","default":""},"linkColor":{"type":"string","default":""},"eventColorOverride":{"type":"string","default":""},"eventHover":{"type":"string","default":"rich"},"todayStyle":{"type":"string","default":"column"},"timePlacement":{"type":"string","default":"beside_date"},"listChipStyle":{"type":"string"},"monthChipStyle":{"type":"string"},"chipStyle":{"type":"string"},"listHeadingPosition":{"type":"string","default":"inline"},"cardGrouping":{"type":"string","default":"none"},"monthOverflowAction":{"type":"string","default":"popover"},"showSearch":{"type":"boolean","default":false},"showDatePicker":{"type":"boolean","default":false},"locale":{"type":"string","default":""},"maxEvents":{"type":"number","default":5},"showTitle":{"type":"boolean","default":false},"titleText":{"type":"string","default":""},"showLinkToFullCalendar":{"type":"boolean","default":false},"linkUrl":{"type":"string","default":""},"showMeta":{"type":"boolean","default":true}},"textdomain":"sdaweb-gcal-sync","editorScript":"file:.\/index.js","editorStyle":"file:.\/editor.css","render":"file:.\/render.php"}},"tagged_versions":["0.10.0","0.10.1","0.11.0","0.11.1","0.12.0","0.12.1","0.12.2","0.12.8","0.12.9","0.13.0","0.13.4","0.14.0","0.14.1","0.14.2","0.14.6","0.15.0","0.15.1","0.16.0","0.16.1","0.16.3","0.16.4","0.17.0","0.18.0","0.18.1","0.19.0","0.20.0","0.21.1","0.21.4","0.21.6","0.22.0","0.22.1","0.22.5","0.22.6","0.23.0","0.23.1","0.23.2","0.23.3","0.23.4","0.23.5","0.8.5","0.8.6","0.9.0","0.9.1","0.9.2","0.9.3","0.9.4","0.9.5"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Month grid with multi-day event ribbons and today highlight.","2":"Upcoming view with filled date badges and Today \/ Tomorrow labels.","3":"Mini-month compact grid with tap-to-expand event panel.","4":"Hover popover with event date, time, location, and click-through link.","5":"ICS subscribe dropdown \u2014 add events to Google, Apple, or Outlook in one tap.","6":"Admin colour picker showing live WCAG contrast warnings."}},"plugin_section":[],"plugin_tags":[5595,416,1486,4743,4062],"plugin_category":[40],"plugin_contributors":[257114,256141],"plugin_business_model":[],"class_list":["post-307966","plugin","type-plugin","status-publish","hentry","plugin_tags-agenda","plugin_tags-calendar","plugin_tags-events","plugin_tags-google-calendar","plugin_tags-schedule","plugin_category-calendar-and-events","plugin_contributors-rstake","plugin_contributors-sdaweb","plugin_committers-rstake"],"banners":[],"icons":{"svg":"https:\/\/ps.w.org\/sdaweb-gcal-sync\/assets\/icon.svg?rev=3533428","icon":"https:\/\/ps.w.org\/sdaweb-gcal-sync\/assets\/icon.svg?rev=3533428","icon_2x":false,"generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>SDAweb Calendar Sync turns any Google Calendar into a polished, on-brand events display on your WordPress site \u2014 without duplicate data entry. Keep scheduling in Google Calendar the way you already do; the plugin pulls those events in and keeps your site in sync automatically.<\/p>\n\n<p>It's for anyone who already runs their events in Google Calendar and wants them to look like a native part of their site instead of an embedded iframe \u2014 businesses, teams, venues, clubs, communities, and organisations of every kind.<\/p>\n\n<p>Insert a calendar with a Gutenberg block, a shortcode, or a classic widget. All three share one render pipeline, so the output is identical however you add it.<\/p>\n\n<h4>Six ways to show your calendar<\/h4>\n\n<ul>\n<li><strong>List \/ Agenda<\/strong> \u2014 chronological, optionally grouped by day, week, or month<\/li>\n<li><strong>Month grid<\/strong> \u2014 classic 7\u00d76 calendar with multi-day event ribbons spanning across cells, today highlight (cell or whole-column style), optional ISO 8601 week-number column, and per-feed pastel chips<\/li>\n<li><strong>Card grid<\/strong> \u2014 upcoming events as styled cards, responsive<\/li>\n<li><strong>Week<\/strong> \u2014 7 day columns, today highlighted<\/li>\n<li><strong>Day<\/strong> \u2014 single-day agenda<\/li>\n<li><strong>Mini-month<\/strong> \u2014 compact dot-density grid for sidebars and widgets, with a tap-to-expand event panel showing today + next upcoming events and a \"Load more\" button<\/li>\n<\/ul>\n\n<p>Switch between views with one setting, or expose a visitor-facing view-toggle pill so visitors can switch themselves. Under the hood every view shares the same data layer, the same CSS-variable system, and the same accessibility baseline.<\/p>\n\n<h4>Smart UX out of the box<\/h4>\n\n<ul>\n<li><strong>Hover popover on event chips<\/strong> (Month, Week, Mini) \u2014 a floating card with date, time, location, calendar, recurrence summary, and a click-through link, so visitors get the full event detail without leaving the page. Desktop hover + keyboard focus only; touch users keep direct click-through.<\/li>\n<li><strong>Mobile auto-degrade Month \u2192 Mini<\/strong> \u2014 below ~600px the full grid is replaced by the compact Mini-month view, so phone visitors get a clean, tappable calendar with no extra work from you. One wrapper, two layouts, no JS swap.<\/li>\n<li><strong>ICS subscribe dropdown<\/strong> \u2014 one tap to add your events to a visitor's own calendar: Google Calendar (web), Apple Calendar \/ Outlook (webcal), Android Google Calendar app (intent), and Copy-link with toast confirmation. Mobile becomes a bottom sheet.<\/li>\n<li><strong>Live search<\/strong> + <strong>jump-to-date picker<\/strong> \u2014 optional chrome controls so visitors can filter or navigate quickly.<\/li>\n<li><strong>Multi-day event ribbons<\/strong> \u2014 week-spanning bars with arrow indicators when an event continues beyond the visible row.<\/li>\n<li><strong>Recurring event indicator<\/strong> \u2014 small \u21bb icon with a plain-language cadence summary in the tooltip (\"Repeats weekly until 31 December 2026\").<\/li>\n<li><strong>Per-display locale override<\/strong> \u2014 render a calendar in a specific language (e.g. nb_NO) even when the site language differs, so you can run a localized calendar on a site that's in another language.<\/li>\n<\/ul>\n\n<h4>Two authentication paths<\/h4>\n\n<ul>\n<li><strong>API key<\/strong> \u2014 for calendars marked \"Make available to public\" in Google Calendar. One field, paste, done.<\/li>\n<li><strong>Service Account JSON<\/strong> \u2014 for <strong>private<\/strong> calendars without per-user OAuth. Upload the JSON, share the calendar with the service-account email, you're set.<\/li>\n<\/ul>\n\n<p>Credentials are encrypted at rest using a key derived from your site's authentication salt. They are never echoed back into the admin UI \u2014 only the masked value and (for service accounts) the public service-account email are shown.<\/p>\n\n<h4>Theme-aware out of the box<\/h4>\n\n<p>The plugin reads your active theme's <code>theme.json<\/code> color palette and uses your <code>primary<\/code>, <code>accent<\/code>, <code>foreground<\/code>, and <code>background<\/code> colors automatically. Per-display overrides let you set custom primary, accent, today-highlight, and link colors and force light\/dark mode without touching code. Every design token is exposed as a CSS custom property so a developer can fully restyle the calendar from their theme stylesheet.<\/p>\n\n<h4>Five built-in theme presets<\/h4>\n\n<p>One-click coordinated colour bundles: <strong>Default<\/strong> (clean blue), <strong>Warm earth<\/strong> (cream + deep red), <strong>High contrast<\/strong> (solid black on white for AAA-stricter sites), <strong>Forest<\/strong> (deep green), <strong>Sunset<\/strong> (warm coral + amber).<\/p>\n\n<h4>Accessibility built in<\/h4>\n\n<p>WCAG 2.2 AA baseline with several AAA touches:<\/p>\n\n<ul>\n<li>Live contrast warnings on every colour picker \u2014 the admin UI shows the WCAG ratio against both light and dark surfaces with pass\/fail markers as you choose colours<\/li>\n<li>Automatic high-contrast overlay via <code>prefers-contrast: more<\/code><\/li>\n<li>Focus-visible halo: a 4px white ring behind the primary outline so focus stays visible against any chip background<\/li>\n<li><code>prefers-reduced-motion<\/code> honored everywhere<\/li>\n<li>ARIA roles and labels on the month grid, navigation, popovers, and view-toggle<\/li>\n<li>Semantic HTML throughout<\/li>\n<li>RTL-aware via CSS logical properties<\/li>\n<li>Tabular numerals for day numbers and time labels so single- and double-digit values don't drift<\/li>\n<\/ul>\n\n<h4>Built for the WordPress.org standard<\/h4>\n\n<ul>\n<li>Block editor first-class \u2014 server-side rendered, ServerSideRender preview, all the standard <code>InspectorControls<\/code><\/li>\n<li>Shortcode and classic widget on the same render pipeline<\/li>\n<li>No bundled core libraries (no jQuery on front-end, no Guzzle, no Carbon, no Monolog)<\/li>\n<li>No third-party authentication relay \u2014 your credentials only ever talk directly to googleapis.com<\/li>\n<li>Translation ready via translate.wordpress.org once the plugin is published and indexed (no bundled <code>.po<\/code>\/<code>.mo<\/code> \u2014 WordPress auto-loads locale files into <code>wp-content\/languages\/plugins\/<\/code> per the WP Plugin Handbook), plurals via <code>_n()<\/code>, JS strings via <code>wp_localize_script<\/code><\/li>\n<li>Free and GPLv2<\/li>\n<\/ul>\n\n<h4>For developers<\/h4>\n\n<p>Extension hooks are documented in <code>docs\/hooks.md<\/code> inside the plugin folder. The first-release set includes filters for event data, event URLs, query args, cache TTL, render output, palette resolution, plus actions for refresh and uninstall lifecycle.<\/p>\n\n<h3>Third-Party Services<\/h3>\n\n<p>This plugin connects to the Google Calendar API to retrieve events from calendars you configure.<\/p>\n\n<ul>\n<li>Service: Google Calendar API v3<\/li>\n<li>Website: https:\/\/developers.google.com\/calendar<\/li>\n<li>Terms of Service: https:\/\/developers.google.com\/terms<\/li>\n<li>Privacy Policy: https:\/\/policies.google.com\/privacy<\/li>\n<\/ul>\n\n<p>Data sent: the calendar ID(s) you configure, plus either your API key or a JSON Web Token signed with your service account credentials. Event data is returned to your server and cached locally as WordPress transients. No event data is sent to any third party.<\/p>\n\n<p>The ICS subscribe feature, when enabled, serves a self-hosted iCalendar (.ics) feed from your own site \u2014 built from the same calendar data already fetched via the Google Calendar API above \u2014 so subscribers can add it in Google Calendar, Apple Calendar, Outlook, or any other app that supports calendar subscriptions. No data is sent to any third party beyond the Google Calendar API connection already disclosed.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin to your <code>\/wp-content\/plugins\/<\/code> directory, or install it from the Plugins screen in WordPress.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Go to <strong>Settings \u2192 SDAweb Calendar Sync<\/strong> to add your first calendar.<\/li>\n<li>Choose API key (public calendars) or Service Account (private calendars), follow the in-app setup guide, save.<\/li>\n<li>Create a display, choose a view, and copy its shortcode \u2014 or insert the <strong>SDAweb Calendar<\/strong> block in a page.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20a%20google%20account%20to%20use%20this%20plugin%3F\"><h3>Do I need a Google account to use this plugin?<\/h3><\/dt>\n<dd><p>You need a Google Cloud project to generate either an API key (for public calendars) or a service account (for private calendars). The plugin's Help tab walks you through both setups in 7\u20138 steps each. Setup is one-time per site.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20send%20my%20data%20anywhere%20other%20than%20google%3F\"><h3>Does this plugin send my data anywhere other than Google?<\/h3><\/dt>\n<dd><p>No. Calendar data is fetched directly from <code>googleapis.com<\/code> using the Google Calendar API. The plugin does not contact any SDAweb-controlled servers, analytics endpoints, or third-party relays. There is no telemetry.<\/p><\/dd>\n<dt id=\"can%20i%20display%20a%20private%20%28non-public%29%20calendar%3F\"><h3>Can I display a private (non-public) calendar?<\/h3><\/dt>\n<dd><p>Yes. Use the Service Account authentication option. The plugin shows you the service account email; share your private calendar with that email in Google Calendar's sharing settings, and the plugin can read it.<\/p><\/dd>\n<dt id=\"how%20often%20does%20the%20plugin%20refresh%20events%3F\"><h3>How often does the plugin refresh events?<\/h3><\/dt>\n<dd><p>A WP-Cron job refreshes registered calendars in the background every 15 minutes. Cache lifetime is configurable upward in the plugin settings (15 minutes is the enforced minimum). You can also click \"Refresh now\" on any calendar in the admin to fetch immediately.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20caching%20plugins%3F\"><h3>Does it work with caching plugins?<\/h3><\/dt>\n<dd><p>Yes \u2014 the calendar HTML is part of the page output, so any page-cache plugin caches it like any other content. The cache will refresh on its own schedule. If you need immediate refresh after a calendar change, purge the page cache.<\/p><\/dd>\n<dt id=\"can%20i%20add%20multiple%20calendars%20to%20one%20display%3F\"><h3>Can I add multiple calendars to one display?<\/h3><\/dt>\n<dd><p>Yes. Each display picks one or more registered calendars and merges them. Events are color-coded by calendar. A multi-feed legend strip can be enabled above the events; chips can be styled solid (single-feed) or pastel (multi-feed legibility).<\/p><\/dd>\n<dt id=\"will%20it%20work%20with%20my%20theme%3F\"><h3>Will it work with my theme?<\/h3><\/dt>\n<dd><p>The plugin reads your active theme's <code>theme.json<\/code> color palette automatically, so calendar colors match the site by default with zero configuration. If you use a classic theme without <code>theme.json<\/code> (or want to override), every color is exposed as a CSS variable that you can override from your theme stylesheet. Five built-in theme presets give you coordinated palettes with one click.<\/p><\/dd>\n<dt id=\"is%20the%20plugin%20accessible%3F\"><h3>Is the plugin accessible?<\/h3><\/dt>\n<dd><p>Yes \u2014 built-in. WCAG 2.2 AA baseline includes <code>prefers-reduced-motion<\/code> and <code>prefers-contrast: more<\/code> support, <code>:focus-visible<\/code> outlines with a white halo (visible on any background), ARIA labelling on the month grid, navigation, popovers, and view-toggle, semantic HTML throughout, RTL-aware via CSS logical properties, and live contrast warnings in the colour-picker UI as you choose values.<\/p><\/dd>\n<dt id=\"can%20i%20show%20the%20calendar%20in%20a%20different%20language%20than%20the%20rest%20of%20the%20site%3F\"><h3>Can I show the calendar in a different language than the rest of the site?<\/h3><\/dt>\n<dd><p>Yes. Each display has an optional Locale override field \u2014 set it to <code>nb_NO<\/code>, <code>sv_SE<\/code>, etc. and that calendar renders weekday names, month names, and built-in labels in that language regardless of the site's language. Useful when an English site hosts Norwegian-audience content.<\/p><\/dd>\n<dt id=\"where%20are%20the%20extension%20hooks%20documented%3F\"><h3>Where are the extension hooks documented?<\/h3><\/dt>\n<dd><p>In <code>docs\/hooks.md<\/code> inside the plugin folder. The plugin commits to keeping documented hooks stable within a major version.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<p>The most recent releases are listed here. The complete history is in\n    docs\/CHANGELOG.md bundled with the plugin.<\/p>\n\n<h4>0.23.5<\/h4>\n\n<ul>\n<li>Fixed: a busy Month, Week, Day or mini calendar silently lost its last days. \"Max events\" (default 50) was applied to the calendar grids as well, so everything after the 50th event of the period was left out. The grids now always show every event in their date range; \"Max events\" applies to List and Cards, as its new description says. If a calendar of yours had more events than the limit, the missing ones appear after this update.<\/li>\n<li>Accessibility: on phones the view switcher (List \/ Month \/ Cards \u2026) shows icons only, and the hidden labels were removed in a way that also hid them from screen readers, so VoiceOver and TalkBack announced five unnamed links. The labels are now hidden visually only. Nothing changes on screen.<\/li>\n<li>Fixed: on a server without PHP's mbstring extension the mini calendar (also used as the phone version of every Month display), the Upcoming list and any display with a saved search filter stopped with a fatal error. They now work without it; on servers that have mbstring \u2014 nearly all \u2014 nothing changes.<\/li>\n<li>Fixed: a calendar or display whose name WordPress cannot turn into plain letters \u2014 a name starting with an emoji, or written in Cyrillic, Greek, Chinese, Japanese \u2026 \u2014 was saved under an address the plugin could not find again: it could not be edited or deleted, and its shortcode showed nothing. New ones get a usable address (\"\ud83d\udcc5 Kalender\" \u2192 <code>kalender<\/code>), renaming a display does too, and records already stuck are repaired automatically on update. Names in Norwegian and other Latin-alphabet languages were never affected.<\/li>\n<\/ul>\n\n<h4>0.23.4<\/h4>\n\n<ul>\n<li>Fixed: the Upcoming view left out all-day events happening today (so the \"Today\" pill could never appear on one) and dropped a multi-day event \u2014 a weekend camp, a week of meetings \u2014 from the list on its first morning. All-day events now stay until their last day is over, and so do timed events that run for a day or more. Ordinary timed events still leave the list when they begin, as before.<\/li>\n<li>Fixed: the Day view listed only events that start on that day, so the Saturday of a Friday\u2013Sunday event said \"No events today\" while Week, Month and Cards showed it. Day now lists every event that covers the day.<\/li>\n<li>Fixed: a timed event ending at exactly midnight (a concert 20:00\u201300:00) was drawn as a two-day event: a two-day ribbon in Month, a dot on the next day in the mini calendar, a second entry in Week and Cards, and a date range in the hover popover. It is now a one-day event everywhere.<\/li>\n<li>Fixed: \"Hide past events\" (List and Cards) had no effect in an ordinary display, and in a display starting in the future it hid events that were still going on. It now hides events that have finished and keeps one that is still running. Because the option was ticked by default while it did nothing, it is switched OFF on all existing displays during the update, so your calendars look exactly as before; tick it again where you want finished events hidden. New displays and blocks start with it off.<\/li>\n<\/ul>\n\n<h4>0.23.3<\/h4>\n\n<ul>\n<li>Security hardening: with WP_DEBUG switched on, a failed connection test or refresh of an API-key calendar showed the full Google request address, including the API key, in the \"Debug (WP_DEBUG)\" details of the admin screen \u2014 easy to pass on by accident in a screenshot for a support request. The key was always hidden in the error log; it is now removed before the address leaves the connection code at all, which also covers other code that listens for fetch failures. If you have shared such a screenshot, consider replacing the key in Google Cloud Console.<\/li>\n<li>Fixed: an answer from Google that was technically successful but not calendar data (an error page from a proxy, an empty or cut-off response) was treated as \"no events\": the empty result was cached as fresh and replaced the saved copy that 0.23.1 keeps for outages. It is now treated as a failed fetch, so visitors keep seeing the saved events. A calendar that genuinely has no events in the period is still simply empty.<\/li>\n<\/ul>","raw_excerpt":"Display your Google Calendar events on your site in six views. Theme-aware, accessible, mobile-ready, no duplicate entry.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/307966","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=307966"}],"author":[{"embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/rstake"}],"wp:attachment":[{"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=307966"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=307966"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=307966"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=307966"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=307966"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/twd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=307966"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}