{"id":360030,"date":"2026-09-01T17:01:48","date_gmt":"2026-09-01T17:01:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/ow-agenda\/"},"modified":"2026-09-01T17:01:15","modified_gmt":"2026-09-01T17:01:15","slug":"ow-agenda","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/ow-agenda\/","author":23487360,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.3.1","stable_tag":"1.3.1","tested":"7.1","requires":"6.3","requires_php":"7.4","requires_plugins":null,"header_name":"OW Agenda","header_author":"OptionWeb \u2014 Julien Daniel","header_description":"Online appointment booking and schedule management: visitor bookings, private invite links, mobile-first admin, ICS emails and reminders.","assets_banners_color":"34353b","last_updated":"2026-09-01 17:01:15","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/optionweb.dev\/plugins\/ow-agenda","header_author_uri":"https:\/\/optionweb.dev","rating":0,"author_block_rating":0,"active_installs":0,"downloads":38,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.3.1":{"tag":"1.3.1","author":"optionweb","date":"2026-09-01 17:01:15","revision":3676546}},"upgrade_notice":{"1.3.1":"<p>Compliance release: inline CSS and JavaScript on the standalone pages are now enqueued, translation catalogues are delivered through WordPress.org language packs, and REST permission checks are declared explicitly. No behavioural changes.<\/p>","1.3.0":"<p>Security and reliability release. Cryptographic tokens, effective anti-spam, no more double-booking, reminders that cannot be lost, and calendar updates that actually reach the customer. The interface is now fully translatable (French included).<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3676546,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3676546,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3676546,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3676546,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.3.1"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[5595,8132,269,416,268],"plugin_category":[40],"plugin_contributors":[264722],"plugin_business_model":[],"class_list":["post-360030","plugin","type-plugin","status-publish","hentry","plugin_tags-agenda","plugin_tags-appointments","plugin_tags-booking","plugin_tags-calendar","plugin_tags-scheduling","plugin_category-calendar-and-events","plugin_contributors-optionweb","plugin_committers-optionweb"],"banners":{"banner":"https:\/\/ps.w.org\/ow-agenda\/assets\/banner-772x250.png?rev=3676546","banner_2x":"https:\/\/ps.w.org\/ow-agenda\/assets\/banner-1544x500.png?rev=3676546","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/ow-agenda\/assets\/icon-128x128.png?rev=3676546","icon_2x":"https:\/\/ps.w.org\/ow-agenda\/assets\/icon-256x256.png?rev=3676546","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>OW Agenda provides a complete appointment system for a care center or any service business:<\/p>\n\n<ul>\n<li><strong>Online booking<\/strong> \u2014 visitors book a consultation on a dedicated page (pick a day, pick a time, short form, GDPR consent checkbox).<\/li>\n<li><strong>Email double opt-in<\/strong> \u2014 a request only becomes real after the visitor clicks a validation link: bots and pranksters never reach the agenda.<\/li>\n<li><strong>Admin validation<\/strong> \u2014 manual (recommended) or automatic; Confirm \/ Refuse buttons right inside the notification email (HMAC-signed links, no login required).<\/li>\n<li><strong>Mobile-first management<\/strong> \u2014 a login-protected \"Agenda\" page: day view, pending requests, phone-call appointments added manually, slot blocking, rescheduling, done \/ no-show statuses.<\/li>\n<li><strong>Customer directory<\/strong> \u2014 search, manual creation, editing, deletion; automatically populated from validated appointments.<\/li>\n<li><strong>Session invitations<\/strong> \u2014 a private link lets an existing customer pick the date of their own session (service and duration predefined by the admin).<\/li>\n<li><strong>Polished HTML emails<\/strong> \u2014 validation, confirmation with an ICS attachment (one-tap add to the customer's phone calendar), cancellation, day-before reminder, admin notifications.<\/li>\n<li><strong>GDPR<\/strong> \u2014 explicit consent, automatic anonymization of past appointments, deletion of never-validated requests.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>ow-agenda<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install the ZIP via Plugins \u2192 Add New.<\/li>\n<li>Activate the plugin.<\/li>\n<li>The \"Book an appointment\" and \"Agenda\" pages are created automatically.<\/li>\n<li>Configure opening hours, durations and emails in the <strong>OW Agenda<\/strong> menu.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20online%20slots%20take%20phone%20appointments%20into%20account%3F\"><h3>Do online slots take phone appointments into account?<\/h3><\/dt>\n<dd><p>Yes: every event in the agenda (web booking, manual appointment, blocked slot) makes its time range unavailable for online booking.<\/p><\/dd>\n<dt id=\"how%20do%20i%20manage%20the%20agenda%20from%20a%20phone%3F\"><h3>How do I manage the agenda from a phone?<\/h3><\/dt>\n<dd><p>Open the \"Agenda\" page on your phone, log in, then use \"Add to Home Screen\": it then behaves like an app.<\/p><\/dd>\n<dt id=\"can%20customers%20cancel%20by%20themselves%3F\"><h3>Can customers cancel by themselves?<\/h3><\/dt>\n<dd><p>Yes, through the link in their emails, up to the configured notice period (24 hours by default). Past that, the page invites them to call.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Compliance: the standalone action, verification and cancellation pages no longer print their CSS and JavaScript inline. Both are now registered files served through the WordPress enqueue API, with the two variable button colours passed as CSS custom properties and the script configured through <code>wp_localize_script()<\/code>.<\/li>\n<li>Compliance: translation catalogues are no longer bundled. Only <code>languages\/ow-agenda.pot<\/code> ships; French is delivered through the WordPress.org language packs fed by translate.wordpress.org.<\/li>\n<li>Compatibility: the minimum WordPress version returns to 6.3, as nothing in the package depends on the bundled-translation discovery introduced in 6.7 any more.<\/li>\n<li>REST: every administration route now declares its <code>permission_callback<\/code> explicitly instead of sharing it through <code>array_merge()<\/code>. The capability check was already enforced; it is now visible to static analysis as well.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Internationalization: the whole plugin is now translatable. Every user-facing string \u2014 admin settings, standalone booking and cancellation pages, REST messages, all e-mail templates and the JavaScript interface \u2014 uses the <code>ow-agenda<\/code> text domain with English as the source language. <code>Domain Path: \/languages<\/code> is declared and <code>languages\/ow-agenda.pot<\/code> ships for translators.<\/li>\n<li>Localization: a full French translation has been produced from the original interface wording and submitted to translate.wordpress.org, so French sites get it through the standard WordPress language packs.<\/li>\n<li>Security: appointment <code>uid<\/code> and invitation tokens are now generated with <code>random_bytes()<\/code> instead of <code>wp_generate_uuid4()<\/code>. These tokens are the sole authentication for public cancellation, e-mail verification and invitation booking, and the previous generator relied on a non-cryptographic PRNG.<\/li>\n<li>Security: the public booking endpoint no longer accepts a missing honeypot or a missing timestamp \u2014 both silently disabled the anti-spam checks. The hourly quota is now aggregated per IPv6 \/64 instead of per address, and a per-day cap limits unverified requests so a single visitor can no longer hold every slot of a day.<\/li>\n<li>Security: the rate limit is applied after form validation, so a visitor who mistypes their e-mail is no longer locked out for an hour without any appointment being created.<\/li>\n<li>Fixed: concurrent bookings of the same slot are now serialised with a named MySQL lock. The previous transaction issued a plain <code>SELECT<\/code>, which takes no row lock under REPEATABLE READ, so two simultaneous visitors could both book the same time.<\/li>\n<li>Fixed: the day-before reminder used a fixed evening window and could be lost for good when no visitor triggered WP-Cron that evening. It now uses a sliding window (12 to 36 hours before the appointment) and catches up on the next cron run. Each reminder is claimed atomically before sending, so overlapping cron runs can no longer send it twice.<\/li>\n<li>Fixed: the hourly cron event is re-scheduled automatically if it disappears, so reminders, purge and GDPR anonymisation cannot stop silently.<\/li>\n<li>Fixed: rescheduling a confirmed appointment now updates the customer's calendar. The ICS attachment carries a <code>SEQUENCE<\/code>, <code>METHOD:REQUEST<\/code>, organiser and attendee, and cancellations send a <code>METHOD:CANCEL<\/code> file that removes the event.<\/li>\n<li>Fixed: the booking widget built its dates in UTC, so visitors east of UTC opening the page shortly after midnight saw the list start on the previous day and lost a day of availability.<\/li>\n<li>Fixed: cancelling an appointment created from a private invitation now releases that invitation, which becomes usable and visible again instead of staying permanently dead.<\/li>\n<li>Fixed: cancelled appointments and expired unverified requests are no longer returned to the agenda view, removing needless personal data from the REST response and phantom appointments from the admin calendar.<\/li>\n<li>Removed: a leftover style rule from a client project that hid a third-party floating button on every page of the site.<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Plugin Check compliance: output escaping, input sanitization, settings nonce, wp_delete_file(), readme.<\/li>\n<li>Uninstall: also removes the customers table and the HMAC secret.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>HTML emails (clean card layout, site accent color) for every notification.<\/li>\n<li>Confirm \/ Refuse buttons in the admin email (HMAC-signed links).<\/li>\n<li>Customer directory: search, create, edit, delete, shortcuts to new appointment and invitation.<\/li>\n<li>Footer layout fix on the agenda page.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Email double opt-in against bots (slot held 45 minutes, purge after 48 hours).<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release: online booking, mobile-first admin agenda, session invitations, ICS emails and day-before reminder.<\/li>\n<\/ul>","raw_excerpt":"Online appointment booking with a mobile-first agenda: visitor bookings, manual appointments, customer directory, HTML emails and reminders.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/360030","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=360030"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/optionweb"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=360030"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=360030"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=360030"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=360030"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=360030"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=360030"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}