OW Agenda — Documentation
La prise de rendez-vous en ligne et l'agenda du quotidien, dans WordPress, sans abonnement. Auteur : OptionWeb — Julien Daniel Page du plugin : https://optionweb.dev/fr/addons/ow-agenda/ Licence : GPL-2.0-or-later Version couverte par ce document : 1.3.1
Table des matières
- Vue d'ensemble
- Installation
- Démarrage rapide
- Le parcours de réservation
- La double vérification par e-mail
- La validation des demandes
- La page Agenda
- Le répertoire clients
- Les invitations de séance
- E-mails et fichier calendrier (ICS)
- Rappels et tâche planifiée
- Anti-spam et limites de débit
- RGPD
- Shortcodes
- API REST
- Référence des réglages
- Données stockées
- Internationalisation
- Désinstallation
- Dépannage
- FAQ
- Changelog
Vue d'ensemble
OW Agenda ajoute à WordPress un système complet de rendez-vous : une page publique où le visiteur choisit son jour puis son heure, et une page « Agenda » protégée par connexion, pensée pour être utilisée depuis un téléphone, où vous gérez la journée.
Tout tient dans le site. Aucun service externe, aucune API tierce, aucun abonnement :
les créneaux sont calculés par votre serveur, les rendez-vous vivent dans vos tables
MySQL, les e-mails partent par wp_mail().
Ce qui est livré (tout est gratuit, GPL-2) :
- Réservation en ligne : choix du jour, choix du créneau, formulaire court, case de consentement RGPD
- Double opt-in par e-mail : une demande ne devient réelle qu'après clic sur un lien de validation — les bots n'atteignent jamais l'agenda
- Validation manuelle (recommandée) ou confirmation automatique, avec des boutons Confirmer / Refuser directement dans l'e-mail de notification (liens signés HMAC, sans connexion)
- Page « Agenda » mobile-first : vue du jour, demandes en attente, rendez-vous téléphoniques ajoutés à la main, blocage de créneaux, replanification, statuts fait / absent
- Répertoire clients : recherche, création, édition, suppression ; alimenté automatiquement par les rendez-vous validés
- Invitations de séance : un lien privé permet à un client existant de choisir la date de sa séance, sur un service et une durée que vous fixez
- E-mails HTML soignés avec pièce jointe ICS (ajout au calendrier du téléphone en un geste), rappel automatique la veille, annulation en ligne par le client
- Anonymisation automatique des rendez-vous passés, purge des demandes jamais validées
- API REST complète sous le namespace
owag/v1
Ce qu'il ne fait pas, délibérément :
- Pas de paiement en ligne : OW Agenda prend le rendez-vous, il n'encaisse pas d'acompte (utilisez WooCommerce si c'est votre besoin)
- Un seul agenda : pas de gestion multi-praticiens ni multi-ressources ; le plugin décrit un planning, celui du site
- Pas de synchronisation bidirectionnelle avec Google Agenda ou Outlook : le calendrier du client est mis à jour par fichier ICS (aller simple), vos indisponibilités personnelles se saisissent comme des blocages
- Pas de catalogue de services côté visiteur : la réservation publique porte sur une prestation unique (libellé et durée configurables) ; les autres prestations passent par les invitations de séance
- Pas de rendez-vous récurrents, pas de visioconférence, pas de salle d'attente
Cette liste est un choix d'architecture, pas une roadmap masquée : un agenda simple qui ne se trompe jamais de créneau vaut mieux qu'une usine à gaz que personne n'ose toucher.
Installation
Depuis le .zip
- Téléchargez
ow-agenda-1.3.1.zipdepuis https://optionweb.dev/fr/addons/ow-agenda/ - Extensions → Ajouter → Téléverser une extension
- Choisissez le fichier, cliquez sur Installer, puis sur Activer
Par FTP
Décompressez l'archive et déposez le dossier ow-agenda dans /wp-content/plugins/,
puis activez l'extension depuis Extensions.
Prérequis
- WordPress 6.3 ou plus récent
- PHP 7.4 ou plus récent (8.1+ recommandé)
- MySQL 5.7+ / MariaDB 10.2+ — les fonctions
GET_LOCK()/RELEASE_LOCK()sont utilisées pour sérialiser les réservations simultanées - Un envoi d'e-mails qui fonctionne. C'est la seule dépendance réelle du plugin : tout le parcours (validation, confirmation, rappel, annulation) passe par l'e-mail. Sur un hébergement mutualisé, installez un plugin SMTP avant de mettre l'agenda en ligne.
Ce qui est installé
À l'activation, OW Agenda crée trois tables :
| Table | Contenu |
|---|---|
{prefix}_owag_appointments | Tous les événements de l'agenda : consultations web, séances issues d'une invitation, rendez-vous saisis à la main, blocages de créneaux |
{prefix}_owag_invites | Les liens privés « choisissez la date de votre séance » |
{prefix}_owag_customers | Le répertoire clients |
…et, la première fois seulement, deux pages publiées :
- « Réserver un rendez-vous » — contient le shortcode
[ow_agenda] - « Agenda » — contient le shortcode
[ow_agenda_admin]
Leurs identifiants sont mémorisés dans les options owag_page_booking et
owag_page_admin ; le drapeau owag_pages_created garantit qu'une désactivation suivie
d'une réactivation ne recrée pas de doublons. Vous pouvez renommer ces pages, les
déplacer dans un menu, changer leur permalien : le plugin les suit par leur ID.
L'activation ajoute aussi :
- la capacité
owag_manageau rôle administrateur — c'est elle, et nonmanage_options, qui ouvre l'agenda et les routes REST d'administration ; - les réglages par défaut dans l'option
owag_settings; - la tâche planifiée horaire
owag_hourly_event(première exécution 5 minutes après l'activation).
Un secret HMAC (owag_admin_secret, 64 caractères, non chargé automatiquement) est
généré à la première notification admin : c'est lui qui signe les boutons
Confirmer / Refuser des e-mails.
Donner l'accès à quelqu'un d'autre
La page Agenda est visible par tout utilisateur connecté disposant de owag_manage.
Pour ouvrir l'agenda à une assistante sans lui donner les clés du site :
// À exécuter une fois (mu-plugin, ou plugin de gestion des rôles).
$role = get_role( 'editor' );
if ( $role ) { $role->add_cap( 'owag_manage' ); }
Démarrage rapide
Après activation, rendez-vous dans OW Agenda (menu principal de l'administration). L'écran de réglages tient en une page ; cinq minutes suffisent.
1. Les horaires d'ouverture
Pour chaque jour de la semaine, saisissez une plage (09:00 → 18:00) et, si vous
coupez le midi, une seconde plage (14:00 → 18:30). Un jour laissé vide est un jour
fermé. Par défaut : du lundi au vendredi, 09:00–18:00 ; samedi et dimanche fermés.
Les horaires sont interprétés dans le fuseau du site (Réglages → Général → Fuseau horaire). Vérifiez-le avant d'ouvrir la réservation : toutes les dates sont stockées en heure locale.
2. La prestation réservable en ligne
- Libellé de la consultation — ce que le visiteur voit en titre du widget (« Consultation », « Premier rendez-vous », « Bilan »…)
- Durée de la consultation — 60 minutes par défaut. C'est cette durée qui est bloquée dans l'agenda.
- Granularité des créneaux — l'écart entre deux heures proposées (30 minutes par défaut). Avec une durée de 60 et une granularité de 30, vous proposez 9:00, 9:30, 10:00… et le premier rendez-vous pris à 9:30 supprime 9:00 et 10:00 de la liste.
- Battement entre deux rendez-vous — minutes de respiration ajoutées de part et d'autre de chaque créneau candidat (0 par défaut).
3. Les délais
- Délai minimum de réservation — 24 h par défaut : un visiteur ne peut pas réserver pour dans une heure.
- Horizon de réservation — 60 jours par défaut : au-delà, plus rien n'est proposé.
- Annulation en ligne par le client — jusqu'à 24 h avant le rendez-vous ; passé ce délai, la page d'annulation invite à téléphoner.
4. La validation et les e-mails
- Confirmation des demandes : validation manuelle (recommandé) ou confirmation automatique.
- Double vérification e-mail : laissez-la cochée. C'est la meilleure protection anti-bot du plugin.
- Notifications admin envoyées à : votre adresse. Par défaut, l'e-mail d'administration du site.
Enregistrez, puis ouvrez la page « Réserver un rendez-vous » : le widget affiche les 14 prochains jours et vos créneaux libres. Vous êtes en ligne.
5. L'agenda sur le téléphone
Ouvrez la page « Agenda » sur votre téléphone, connectez-vous, puis utilisez « Ajouter à l'écran d'accueil ». Le plugin publie un manifeste d'application : la page s'ouvre alors en plein écran, sans barre de navigateur, comme une application.
Le parcours de réservation
Côté visiteur, la page de réservation est un composant autonome (JavaScript sans
framework, moins de 10 Ko) qui parle aux endpoints publics owag/v1/public/*.
Étape 1 — le jour
Au chargement, le widget demande les disponibilités sur 14 jours à partir d'aujourd'hui et affiche une bande de jours cliquables. Un jour sans créneau libre est grisé et non cliquable. Le bouton « Voir les dates suivantes » charge les 14 jours suivants, autant de fois que nécessaire jusqu'à l'horizon configuré.
Les dates du widget sont construites en heure locale du navigateur, jamais en UTC. C'est un correctif de la 1.3.0 : auparavant, un visiteur situé à l'est de UTC ouvrant la page peu après minuit voyait la liste commencer la veille et perdait une journée de disponibilité.
Étape 2 — l'heure
Le clic sur un jour appelle /public/slots et affiche les heures de début libres. Un
créneau est proposé quand toutes ces conditions sont remplies :
- il tombe dans une plage d'ouverture du jour concerné ;
- le rendez-vous entier (début + durée) tient avant la fermeture ;
- il commence après maintenant + délai minimum ;
- le jour est dans l'horizon de réservation ;
- il ne chevauche aucun événement actif, battement compris — et « événement actif » inclut les rendez-vous confirmés, les demandes en attente, les blocages, les rendez-vous téléphoniques saisis à la main, et les demandes non encore vérifiées qui retiennent encore leur créneau.
C'est le point important : tout ce qui occupe l'agenda ferme le créneau en ligne. Un rendez-vous pris au téléphone et noté dans l'agenda disparaît immédiatement des créneaux proposés sur le site.
Étape 3 — le formulaire
Quatre champs, dont trois obligatoires : nom (2 caractères minimum), téléphone (8 chiffres minimum), e-mail (validé), message libre. Une case de consentement RGPD, non cochée par défaut, est obligatoire.
Le formulaire embarque en plus deux champs invisibles pour le visiteur — un piège à robots et un horodatage d'ouverture de page — décrits dans la section Anti-spam.
Étape 4 — la réponse
Selon votre configuration, trois issues :
| Configuration | Statut créé | Message affiché |
|---|---|---|
| Double vérification e-mail active (défaut) | unverified | « Un dernier geste : un e-mail vient de vous être envoyé… » |
| Vérification désactivée + validation manuelle | pending | « Votre demande est bien reçue ! » |
| Vérification désactivée + confirmation automatique | confirmed | « Votre rendez-vous est confirmé ! » |
Si le créneau a été pris entre l'affichage de la liste et l'envoi du formulaire, le
visiteur reçoit un message explicite (owag_slot_taken, HTTP 409) et la liste des jours
se recharge automatiquement. Deux visiteurs ne peuvent pas obtenir le même créneau : la
section critique est sérialisée par un verrou nommé MySQL, propre à votre base et à
votre préfixe de tables, ce qui tient même sur un hébergement mutualisé.
La double vérification par e-mail
C'est la fonctionnalité qui distingue OW Agenda d'un formulaire de contact déguisé.
Quand Double vérification e-mail est active (réglage email_verify, activé par
défaut) :
- La demande est enregistrée avec le statut
unverified. L'administrateur n'est pas notifié. Le rendez-vous n'apparaît pas comme une demande à traiter. - Le visiteur reçoit un e-mail « Un dernier geste… » contenant un bouton de validation.
- Le créneau est retenu 45 minutes. Passé ce délai sans validation, il redevient disponible pour tout le monde — un bot ne peut donc pas geler votre journée.
- Le clic sur le bouton ouvre une page autonome (
?owag_verify=<uid>) qui affiche le récapitulatif du rendez-vous et un bouton « Je confirme ma demande ». La validation ne part qu'au clic : les antivirus et scanners de liens qui visitent les URL des e-mails ne valident rien. - La demande devient alors
pending(validation manuelle) ouconfirmed(confirmation automatique), le client reçoit l'e-mail correspondant, et c'est seulement là que la notification admin part. - Les demandes jamais validées sont supprimées au bout de 48 h par la tâche horaire. Elles ne laissent aucune trace ni aucune donnée personnelle.
Si, entre l'envoi et le clic, le créneau a été pris par quelqu'un d'autre (la fenêtre de 45 minutes est passée), la validation renvoie une erreur claire et la demande est annulée — jamais de rendez-vous fantôme sur un créneau déjà occupé.
Conséquence pratique : une adresse e-mail invalide ne produit aucun rendez-vous. Vous ne perdez plus de temps à rappeler des numéros bidon. Le prix à payer est un clic supplémentaire pour le client ; l'expérience montre que le taux d'abandon est très inférieur au taux de faux rendez-vous qu'il évite.
Les réservations issues d'une invitation de séance sautent cette étape : le client a déjà prouvé qu'il lisait sa boîte mail en cliquant sur le lien privé qu'il a reçu.
La validation des demandes
Validation manuelle (recommandée)
Réglage par défaut : auto_confirm = 0. Une demande vérifiée arrive avec le statut
pending. Rien n'est promis au client tant que vous n'avez rien fait — mais le créneau
est déjà bloqué, personne ne peut vous le doubler.
Vous recevez un e-mail « À confirmer :
- Confirmer le rendez-vous — cyan
- Refuser — contour rouge
Les boutons de l'e-mail : liens signés HMAC
Ces boutons ne demandent aucune connexion. Ils pointent vers votre site avec trois
paramètres : owag_admin_action (confirm ou refuse), uid (l'identifiant aléatoire
du rendez-vous) et sig, une signature HMAC-SHA256 de uid|action calculée avec le
secret privé du site (owag_admin_secret).
- La signature est vérifiée avant l'affichage du moindre détail : un lien trafiqué n'affiche rien d'autre que « Lien invalide ».
- La comparaison utilise
hash_equals()— pas de fuite d'information par le temps de réponse. - La page affiche un récapitulatif et un bouton ; l'action ne s'exécute qu'au clic. Un scanner de liens ne confirme donc rien à votre place.
- Une demande déjà traitée renvoie « Déjà traité (statut : … ) » plutôt qu'une erreur.
Confirmer envoie automatiquement l'e-mail de confirmation au client, avec le fichier calendrier. Refuser envoie l'e-mail d'annulation. Dans les deux cas, l'agenda est à jour avant que vous n'ayez rangé votre téléphone.
Ces liens restent valides tant que le rendez-vous est en attente. Si vous supprimez l'option
owag_admin_secret(restauration partielle de base, nettoyage manuel), tous les liens déjà envoyés cessent de fonctionner : un nouveau secret est généré et les anciennes signatures ne correspondent plus. Passez alors par la page Agenda.
Confirmation automatique
Réglage auto_confirm = 1. Un créneau libre est confirmé immédiatement : le client
reçoit sa confirmation avec le fichier calendrier, vous recevez une notification
« Nouveau rendez-vous ». À réserver aux activités où tout créneau ouvert est un créneau
acceptable.
Les deux réglages se combinent avec la double vérification : même en confirmation
automatique, la demande passe d'abord par unverified si email_verify est actif.
La page Agenda
La page « Agenda » ([ow_agenda_admin]) est l'outil de tous les jours. Elle est conçue
pour le téléphone d'abord : boutons larges, une colonne, pas de tableau à faire
défiler horizontalement, et elle fonctionne évidemment aussi bien sur un écran d'ordinateur.
Elle est protégée : un visiteur non connecté voit un lien de connexion, un utilisateur
connecté sans la capacité owag_manage voit « L'accès est réservé à l'équipe ». La page
est en noindex,nofollow : elle ne se retrouvera jamais dans Google.
Onglet Agenda — la vue du jour
La journée en cours, événement par événement, avec l'heure, la durée, le libellé, le statut et l'origine (site, invitation, saisie manuelle). Navigation d'un jour à l'autre, bouton Aujourd'hui. Sur chaque rendez-vous :
- Détails — coordonnées du client, message laissé lors de la réservation, et un bloc de notes internes (jamais visibles par le client) enregistrées sans envoyer le moindre e-mail
- Confirmer ✓ — pour une demande encore en attente ; l'e-mail de confirmation part
- Fait / Absent (no-show) — statuts de fin de rendez-vous
- Déplacer — nouvelle date, nouvelle heure, durée éventuellement modifiée. Le plugin vous demande si le client doit être prévenu par e-mail ; si oui, il reçoit une confirmation à jour et un fichier calendrier qui corrige l'événement déjà présent sur son téléphone
- Annuler le rendez-vous — avec, là encore, le choix de prévenir ou non le client
- Supprimer le blocage — pour un créneau bloqué
Quand une action crée un chevauchement (déplacement sur un créneau occupé), le plugin prévient et demande confirmation : vous pouvez forcer. C'est votre planning, vous savez ce que vous faites — le garde-fou n'est bloquant que pour les visiteurs.
Ajouter un rendez-vous ou un blocage
Le bouton « Ajouter un rendez-vous » ouvre une fiche unique qui sert deux usages :
- Rendez-vous — le client vous a appelé. Nom, téléphone, e-mail (facultatif), service, date, heure, durée, notes internes. Si vous renseignez une adresse e-mail et cochez l'option, le client reçoit la confirmation avec son fichier calendrier, comme s'il avait réservé en ligne. Le rendez-vous alimente aussi le répertoire clients.
- Blocage (congé, pause…) — un motif, une date, une heure, une durée. Aucun e-mail, aucune fiche client, mais le créneau disparaît immédiatement de la réservation en ligne. C'est ainsi qu'on pose une semaine de congés, une formation, ou le créneau de midi qu'on ne veut pas voir réservé.
Onglet En attente
La liste des demandes vérifiées qui attendent votre décision, tous jours confondus (les rendez-vous déjà passés en sont exclus). Deux boutons par ligne : Confirmer et Refuser. C'est le premier écran à ouvrir le matin.
Astuce : l'agenda comme application
Sur la page Agenda, le plugin déclare un manifeste d'application web (?owag_manifest=1)
avec le nom du site, l'icône du site et la couleur de thème. Sur Android comme sur iOS,
le menu du navigateur propose alors « Ajouter à l'écran d'accueil » : vous obtenez
une icône, un lancement plein écran, et plus jamais l'URL à retaper.
Le répertoire clients
Le troisième onglet de la page Agenda est un répertoire léger, volontairement minimal : nom, téléphone, e-mail, notes libres.
- Il se remplit tout seul. Dès qu'un rendez-vous est validé (réservation en ligne vérifiée, séance sur invitation, saisie manuelle), le client est rapproché d'une fiche existante par son e-mail, puis par son téléphone. S'il n'existe pas, la fiche est créée ; s'il existe, seuls les champs vides sont complétés — le plugin n'écrase jamais ce que vous avez saisi à la main.
- Recherche sur le nom, le téléphone ou l'e-mail (200 fiches affichées au maximum).
- Création et édition manuelles, avec un champ de notes pour l'historique, les préférences, les précautions à prendre.
- Deux raccourcis par fiche : Nouveau rendez-vous (pré-remplit la fiche de saisie manuelle) et Inviter pour une séance (pré-remplit l'invitation).
- Suppression d'une fiche : les rendez-vous passés restent dans l'agenda, seule la fiche du répertoire disparaît.
Ce répertoire n'est pas un CRM et ne prétend pas l'être. Il répond à une question : « C'est qui, déjà, la dame de 14 h ? »
Les invitations de séance
Le cas d'usage : un client existant a droit à une séance — un suivi, une retouche, une prestation vendue par ailleurs — et vous voulez qu'il choisisse sa date sans passer par la réservation publique, sur un service et une durée que vous fixez.
Depuis l'onglet Invitations :
- Renseignez le nom du client, l'intitulé de la séance (obligatoires), sa durée (15 à 720 minutes) et, si vous le souhaitez, son e-mail et son téléphone.
- Choisissez la validité du lien : 60 jours par défaut, de 1 à 365.
- Cochez éventuellement « Envoyer le lien au client par e-mail » — le client reçoit un e-mail « Choisissez la date de votre séance » avec l'intitulé, la durée, la date d'expiration et un bouton.
- Sinon, copiez le lien et envoyez-le par SMS, WhatsApp, ou par le bouton de partage natif du téléphone.
Le lien pointe vers votre page de réservation avec un jeton privé
(?owag_invite=<token>, 32 caractères hexadécimaux tirés d'un générateur
cryptographique). Le widget affiche alors l'intitulé et la durée de la séance, et non
la consultation standard. Le client remplit le même formulaire court.
Règles qui gouvernent un lien d'invitation :
- Usage unique. Une fois la séance réservée, le lien répond « Ce lien a déjà été utilisé » (HTTP 410). Deux ouvertures simultanées avec le même jeton ne peuvent pas créer deux séances : la consommation du jeton se fait sous le même verrou que la réservation du créneau.
- Daté. Passée l'expiration, le lien invite à vous recontacter (HTTP 410).
- Sans double opt-in. Le client a déjà reçu ce lien par un canal que vous maîtrisez :
la séance est créée directement en
confirmed, avec confirmation et fichier calendrier. - Recyclé en cas d'annulation. Si la séance est annulée (par vous ou par le client), l'invitation est libérée : le lien redevient actif et l'invitation réapparaît dans la liste des invitations ouvertes. C'est un correctif de la 1.3.0 — auparavant, une annulation tuait définitivement le lien et il fallait en refaire un.
- Révocable. Supprimer une invitation depuis la liste désactive le lien immédiatement.
E-mails et fichier calendrier (ICS)
Les e-mails transactionnels
Tous les messages sont en HTML, sur une mise en page en tableaux compatible Gmail et
Outlook : carte blanche sur fond clair, nom du site en en-tête, encadré récapitulatif à
liseré cyan, boutons pilule. Ils sont envoyés par wp_mail(), donc respectent votre
configuration SMTP et les filtres WordPress habituels.
| Destinataire | Déclencheur | |
|---|---|---|
| Validation de la demande | Client | Réservation web quand la double vérification est active |
| Demande reçue | Client | Demande validée, en attente de votre décision |
| Rendez-vous confirmé | Client | Confirmation (manuelle, automatique, saisie admin, déplacement) — avec pièce jointe ICS |
| Rendez-vous annulé | Client | Annulation par le client, refus ou annulation par l'admin — avec pièce jointe ICS d'annulation |
| Rappel | Client | Automatiquement, entre 12 et 36 h avant le rendez-vous |
| Choisissez la date de votre séance | Client | Création d'une invitation avec envoi par e-mail |
| À confirmer : … | Admin | Nouvelle demande vérifiée en attente — avec les boutons Confirmer / Refuser |
| Nouveau rendez-vous : … | Admin | Nouveau rendez-vous confirmé (confirmation automatique, invitation) |
| Annulation client : … | Admin | Le client a annulé lui-même depuis son e-mail |
L'adresse de notification admin est le réglage notify_email (par défaut l'e-mail
d'administration du site). Les e-mails client ne partent que si l'adresse est valide, et
jamais pour un blocage de créneau.
Les e-mails de confirmation et d'annulation rappellent au client qu'il peut annuler en ligne, avec le nombre d'heures de préavis effectivement configuré.
La pièce jointe ICS
Le fichier .ics joint aux confirmations est ce qui transforme un e-mail en rendez-vous
réellement présent dans le téléphone du client : un geste sur la pièce jointe, et
l'événement est dans son calendrier, avec son propre rappel.
Le fichier est conforme à la RFC 5545 et contient ce qu'il faut pour que les clients de calendrier (Google, Outlook, Apple) traitent correctement les mises à jour :
METHOD:REQUESTà la création et à chaque révision d'horaire,METHOD:CANCELà l'annulation ;- un
UIDstable dérivé de l'identifiant du rendez-vous et du domaine du site — c'est lui qui permet à une révision de remplacer l'événement existant au lieu d'en créer un second ; - un
SEQUENCEcroissant dérivé de la date de dernière modification, ramenée à un instant absolu : le passage à l'heure d'hiver ne peut pas faire reculer le numéro de révision (et l'annulation ajoute 1, pour rester supérieure à une révision survenue dans la même seconde) ; ORGANIZER(votre adresse de notification) etATTENDEE(le client) ;DTSTART/DTENDen UTC,STATUS:CONFIRMEDouSTATUS:CANCELLED;- pliage des lignes à 75 octets sans jamais couper un caractère UTF-8.
Un déplacement de rendez-vous confirmé envoie donc un nouveau fichier qui corrige l'événement déjà présent chez le client ; une annulation envoie un fichier qui le supprime. C'est un correctif de la 1.3.0 : auparavant l'ancien horaire restait au calendrier du client.
Le fichier est écrit dans le répertoire temporaire du serveur — jamais dans
wp-content/uploads/, qui est servi publiquement — via l'API fichiers de WordPress, et
il est effacé aussitôt l'envoi terminé, y compris si l'envoi échoue. Il porte le nom et
l'e-mail du client : il n'a rien à faire sur le disque une seconde de plus que
nécessaire.
Rappels et tâche planifiée
Une seule tâche planifiée, owag_hourly_event, exécutée toutes les heures. Elle fait
trois choses.
1. Le rappel de la veille
Le rappel part quand le rendez-vous commence dans 12 à 36 heures. Ce n'est pas une fenêtre horaire fixe, et c'est délibéré : WP-Cron ne se déclenche qu'à la visite d'une page. Un site sans trafic le soir perdait définitivement les rappels de la journée suivante. Avec une fenêtre glissante, le rappel part à la première exécution disponible et rattrape le retard.
Conditions : rendez-vous confirmé, adresse e-mail renseignée, ce n'est pas un blocage, et le rappel n'a pas déjà été envoyé.
Chaque rappel est réservé de façon atomique avant l'envoi (un UPDATE conditionnel
sur le drapeau reminder_sent) : deux exécutions de cron qui se chevauchent ne peuvent
pas envoyer deux fois le même message. Si l'envoi échoue, la réservation est rendue et le
rappel sera retenté à l'exécution suivante. Un verrou court (10 minutes) évite en plus
que deux passages simultanés parcourent la même liste.
Déplacer un rendez-vous remet le drapeau à zéro : le client reçoit bien un rappel pour le nouvel horaire.
2. La purge des demandes non validées
Les demandes restées unverified depuis plus de 48 heures sont supprimées. (Leur
créneau, lui, était déjà rendu disponible après 45 minutes.)
3. L'anonymisation RGPD
Voir la section RGPD.
Le filet de sécurité
Un événement WP-Cron peut disparaître : optimisation de base de données, restauration
partielle, plugin de nettoyage, réinitialisation de l'option cron. OW Agenda vérifie à
chaque chargement que la tâche est bien programmée et la reprogramme sinon. Rappels,
purge et rétention ne peuvent pas s'arrêter en silence.
Utiliser un vrai cron système
WP-Cron dépend du trafic. Sur un site peu visité, préférez un cron système :
// wp-config.php
define( 'DISABLE_WP_CRON', true );
# crontab -e — toutes les 15 minutes
*/15 * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron > /dev/null
Anti-spam et limites de débit
La réservation est publique par nature : pas de compte, pas de connexion, pas de nonce possible. Cinq protections indépendantes travaillent donc en amont.
1. Le piège à robots (honeypot)
Le formulaire contient un champ texte hors écran, invisible pour un humain et appétissant pour un robot. Le champ doit être présent et vide. Un champ rempli — ou absent, ce qui trahit un envoi direct à l'API — renvoie un refus sec (HTTP 403), sans détail exploitable.
2. Le temps de remplissage
La page transmet l'horodatage de son affichage. Une soumission arrivée moins de 4 secondes après le chargement est refusée. Là encore, un horodatage absent ou malformé est un refus : en 1.3.0, ces deux champs sont devenus obligatoires — les omettre désactivait purement et simplement le contrôle.
3. Le quota horaire par adresse
5 réservations par heure et par portée. En IPv4, la portée est l'adresse ; en IPv6, c'est le préfixe /64 — un attaquant y dispose de 2⁶⁴ adresses, compter l'adresse entière ne limiterait rien.
Le compteur n'est incrémenté qu'après la validation du formulaire : un visiteur qui se trompe d'e-mail trois fois de suite n'est plus bloqué une heure pour rien.
4. Le plafond quotidien de demandes non vérifiées
Au maximum 3 demandes en attente de validation e-mail peuvent retenir un créneau sur une même journée. Sans ce plafond, quelques envois suffisaient à geler tous les créneaux d'une date. Au-delà, le visiteur reçoit une invitation à réessayer plus tard ou à choisir un autre jour (HTTP 429).
5. Le verrou de réservation
La réservation d'un créneau et la consommation d'une invitation se font dans une section critique sérialisée par un verrou nommé MySQL, dont le nom est dérivé de votre base et de votre préfixe de tables (deux sites d'un même hébergement mutualisé ne se bloquent donc pas mutuellement). Si le verrou n'est pas obtenu en 5 secondes, la requête renvoie un HTTP 503 explicite plutôt qu'un double rendez-vous.
Ce verrou remplace, depuis la 1.3.0, une transaction qui reposait sur un SELECT nu :
sous REPEATABLE READ, il ne pose aucun verrou de ligne, et deux visiteurs simultanés
pouvaient réserver le même horaire.
Et la double vérification
C'est la couche la plus efficace : même en franchissant tout ce qui précède, un robot n'atteint jamais votre agenda ni votre boîte mail, puisque la notification admin n'est envoyée qu'après clic sur un lien reçu par e-mail. Voir La double vérification par e-mail.
RGPD
Un agenda de rendez-vous manipule des données de santé potentielles, des coordonnées et des historiques. Les réglages par défaut sont volontairement conservateurs.
Consentement
La case de consentement est obligatoire et non cochée par défaut sur le formulaire public : « J'accepte que mes coordonnées soient utilisées pour la gestion de mon rendez-vous. » Une réservation sans consentement est refusée côté serveur, pas seulement côté navigateur.
Minimisation
- Aucune adresse IP n'est stockée en base. Le quota horaire utilise un compteur temporaire (transient) dont la clé est un condensé de la portée réseau, purgé au bout d'une heure.
- Aucun user agent, aucun traceur, aucun cookie déposé par le plugin.
- Aucune donnée n'est envoyée à un service tiers : pas de CDN, pas d'appel externe, pas de télémétrie.
- Les demandes jamais validées sont supprimées après 48 heures — elles ne laissent aucune donnée derrière elles.
- Les rendez-vous annulés ne sont plus renvoyés par l'API de l'agenda : les données personnelles inutiles ne circulent pas.
Anonymisation automatique
Réglage retention_months, 24 mois par défaut. Chaque heure, les rendez-vous
terminés depuis plus longtemps que ce délai sont anonymisés sur place : le nom est
remplacé par « Anonymisé », le téléphone et l'e-mail sont vidés, le message du client et
les notes internes sont effacés. La ligne reste, ce qui préserve l'historique
statistique de l'activité (combien de rendez-vous, quand, pour quelle prestation) sans
conserver la moindre donnée personnelle.
Mettez 0 pour désactiver l'anonymisation automatique — en connaissance de cause.
À noter : l'anonymisation cible les rendez-vous porteurs d'une adresse e-mail. Un rendez-vous saisi à la main sans e-mail (nom et téléphone seulement) n'est pas atteint par la purge automatique ; supprimez-le manuellement si votre politique de rétention l'exige.
Droit d'accès et droit à l'effacement
Le plugin ne branche pas les exporteurs/effaceurs natifs de WordPress (ceux-ci travaillent sur des comptes utilisateurs, or les clients n'en ont pas). Pour traiter une demande :
- Accès — recherchez la personne dans le répertoire clients (nom, téléphone ou
e-mail) et parcourez ses rendez-vous dans l'agenda. Les administrateurs de base de
données peuvent aussi interroger directement
{prefix}_owag_appointmentset{prefix}_owag_customerssur la colonnecustomer_email/email. - Effacement — supprimez la fiche du répertoire, puis annulez ou laissez anonymiser
les rendez-vous concernés. Une suppression immédiate se fait en base sur
customer_email.
-- Effacement manuel des données personnelles d'une personne (adaptez le préfixe).
UPDATE wp_owag_appointments
SET customer_name = 'Anonymisé', customer_phone = '', customer_email = '',
customer_msg = NULL, admin_notes = NULL
WHERE customer_email = 'personne@example.com';
DELETE FROM wp_owag_customers WHERE email = 'personne@example.com';
Registre des traitements
Pour votre registre : finalité gestion des rendez-vous ; base légale consentement (réservation en ligne) ou exécution d'un contrat / mesures précontractuelles (rendez-vous pris par téléphone) ; catégories identité, coordonnées, contenu du message, notes internes ; durée 24 mois par défaut, puis anonymisation ; destinataires aucun sous-traitant hors votre hébergeur et votre service d'envoi d'e-mails.
Shortcodes
[ow_agenda] — la réservation visiteur
À placer sur une page publique. Aucun attribut : la prestation, la durée et les horaires viennent des réglages. Le shortcode charge sa feuille de style et son script (moins de 12 Ko au total, sans dépendance) et rend un conteneur qui se remplit après le premier appel à l'API.
[ow_agenda]
C'est ce shortcode qui interprète le paramètre d'URL ?owag_invite=<token> : la même
page sert la consultation standard et les séances sur invitation.
[ow_agenda_admin] — la page de gestion
À placer sur une page dédiée. Aucun attribut. Le shortcode gère lui-même l'accès :
- visiteur non connecté → lien de connexion renvoyant vers la page ;
- connecté sans la capacité
owag_manage→ message d'accès restreint ; - connecté avec la capacité → l'interface complète (agenda, en attente, clients, invitations).
[ow_agenda_admin]
Les deux pages sont créées automatiquement à l'activation avec ces shortcodes. Si vous
les avez supprimées, il suffit de créer une page et d'y coller le shortcode — pensez
alors à mettre à jour l'option owag_page_admin (ou owag_page_booking) pour que les
liens des e-mails et le manifeste pointent au bon endroit.
Les pages autonomes
Quatre paramètres d'URL, interceptés sur n'importe quelle page du site, produisent des
pages autonomes servies hors du thème (rendu minimal, noindex,nofollow) :
| URL | Rôle |
|---|---|
?owag_verify=<uid> | Validation de la demande par le client (double opt-in) |
?owag_cancel=<uid> | Annulation en ligne par le client |
?owag_admin_action=confirm|refuse&uid=…&sig=… | Confirmation / refus depuis l'e-mail admin |
?owag_manifest=1 | Manifeste d'application de la page Agenda |
Ces pages n'exécutent jamais d'action au chargement : elles affichent un récapitulatif et un bouton. Aucun robot, aucun antivirus de messagerie, aucun prefetch de navigateur ne peut confirmer ou annuler un rendez-vous à la place d'un humain.
API REST
Tous les endpoints vivent sous le namespace owag/v1, à la racine REST habituelle
(https://example.com/wp-json/owag/v1/…).
Endpoints publics
Aucune authentification : ce sont les routes du widget de réservation et des liens reçus par e-mail. Leur sécurité repose sur des jetons aléatoires (32 caractères hexadécimaux issus d'un générateur cryptographique), sur des signatures HMAC, et sur les protections décrites dans Anti-spam.
| Méthode | Chemin | Paramètres | Rôle |
|---|---|---|---|
GET | /public/days | from (Y-m-d, défaut : aujourd'hui), token (invitation, facultatif) | Renvoie label, duration et days : 14 jours à partir de from, chacun avec son nombre de créneaux libres |
GET | /public/slots | date (Y-m-d, requis), token | Renvoie slots : les heures de début libres (HH:MM) |
POST | /public/book | date, time, name, phone, email, message, consent, website (piège), ts (horodatage), token | Crée la demande ; renvoie status et le message à afficher |
POST | /public/verify | uid | Valide une demande unverified |
POST | /public/cancel | uid | Annule un rendez-vous pending ou confirmed, dans la limite du préavis |
POST | /public/admin-action | uid, action (confirm|refuse), sig | Confirme ou refuse depuis l'e-mail admin (signature HMAC) |
Exemple de réservation :
curl -X POST https://example.com/wp-json/owag/v1/public/book \
-H 'Content-Type: application/json' \
-d '{
"date": "2026-09-15",
"time": "14:30",
"name": "Marie Dupont",
"phone": "0470 12 34 56",
"email": "marie@example.com",
"message": "Première visite",
"consent": 1,
"website": "",
"ts": 1757942400
}'
{
"ok": true,
"status": "unverified",
"message": "Un dernier geste : un e-mail vient de vous être envoyé…"
}
Endpoints d'administration
Tous exigent la capacité owag_manage et un nonce REST WordPress valide
(en-tête X-WP-Nonce).
| Méthode | Chemin | Paramètres | Rôle |
|---|---|---|---|
GET | /admin/agenda | from, to (Y-m-d) | events (la plage demandée, annulés exclus) et pending (toutes les demandes en attente à venir) |
POST | /admin/appointment | kind (manual|block|consult|seance), date, time, duration (5–720 min), label, name, phone, email, notes, force, send_email | Crée un rendez-vous manuel ou un blocage |
POST | /admin/appointment/{id} | status (pending|confirmed|cancelled|done|noshow), name, phone, email, label, notes, date, time, duration, force, silent | Met à jour, déplace, change le statut. silent=1 supprime tout envoi d'e-mail |
GET | /admin/customers | q (recherche) | Le répertoire (200 fiches maximum) |
POST | /admin/customers | name (requis), phone, email, notes | Crée une fiche |
POST | /admin/customers/{id} | idem | Met à jour une fiche |
DELETE | /admin/customers/{id} | — | Supprime une fiche |
GET | /admin/invites | — | Les invitations ouvertes (jamais utilisées ou libérées, non expirées) |
POST | /admin/invites | name (requis), label (requis), duration (15–720), days_valid (1–365, défaut 60), email, phone, send_email | Crée une invitation ; renvoie url et email_sent |
DELETE | /admin/invites/{id} | — | Supprime une invitation |
GET | /admin/settings | — | Les réglages effectifs |
POST | /admin/settings | corps JSON (voir Référence des réglages) | Enregistre les réglages |
Chaque route déclare explicitement son contrôle d'accès ; la capacité est vérifiée avant l'exécution du moindre traitement.
Codes d'erreur
Les erreurs sont des WP_Error standard, avec un code lisible et un statut HTTP.
| Code | HTTP | Signification |
|---|---|---|
owag_spam | 403 | Piège à robots rempli, ou horodatage manquant / trop récent |
owag_rate | 429 | Quota horaire atteint pour cette adresse |
owag_day_full | 429 | Trop de demandes en attente de validation sur cette date |
owag_busy | 503 | Verrou de réservation non obtenu — réessayer dans un instant |
owag_slot_taken | 409 | Créneau pris entre-temps |
owag_overlap | 409 | Chevauchement détecté (admin) — renvoyer avec force |
owag_invite_invalid | 404 | Jeton d'invitation inconnu |
owag_invite_used | 410 | Invitation déjà consommée |
owag_invite_expired | 410 | Invitation expirée |
owag_too_late | 403 | Annulation en ligne hors délai de préavis |
owag_bad_sig | 403 | Signature HMAC invalide |
owag_not_found | 404 | Rendez-vous ou fiche introuvable |
owag_name, owag_phone, owag_email, owag_consent | 400 | Champ invalide ou consentement manquant |
owag_bad_input, owag_bad_date | 400 | Date, heure ou saisie invalide |
owag_noop | 400 | Requête de mise à jour vide |
owag_insert | 500 | Échec d'écriture en base |
Crochets développeur
En 1.3.1, OW Agenda n'expose ni filtre ni action publique : il n'y a pas d'API
d'extension à documenter, et rien de ce qui suit ne doit être deviné. Le seul crochet
utilisable est l'événement planifié owag_hourly_event, sur lequel vous pouvez brancher
votre propre entretien :
add_action( 'owag_hourly_event', function () {
// Votre traitement horaire, exécuté juste après celui du plugin.
} );
Pour tout le reste, l'API REST est le point d'intégration : elle expose exactement ce que fait l'interface, ni plus ni moins.
Référence des réglages
Tous les réglages tiennent dans une seule option, owag_settings. Lecture et
écriture en PHP :
$s = owag_settings(); // réglages effectifs (défauts + enregistrés)
$duree = (int) $s['consult_duration'];
update_option( 'owag_settings', array_merge( owag_settings(), [
'consult_duration' => 45,
'buffer' => 10,
] ) );
Valeurs par défaut
[
// Horaires : clé = 1 (lundi) … 7 (dimanche), valeur = liste de plages [début, fin]
'hours' => [
'1' => [ [ '09:00', '18:00' ] ],
'2' => [ [ '09:00', '18:00' ] ],
'3' => [ [ '09:00', '18:00' ] ],
'4' => [ [ '09:00', '18:00' ] ],
'5' => [ [ '09:00', '18:00' ] ],
'6' => [], // samedi fermé
'7' => [], // dimanche fermé
],
'slot_step' => 30, // granularité des créneaux proposés (minutes)
'consult_duration' => 60, // durée d'une consultation (minutes)
'buffer' => 0, // battement autour de chaque rendez-vous (minutes)
'min_notice_hours' => 24, // délai minimum avant réservation
'max_advance_days' => 60, // horizon maximum de réservation
'auto_confirm' => 0, // 0 = validation manuelle, 1 = confirmation automatique
'email_verify' => 1, // double vérification par e-mail
'cancel_notice_hours' => 24, // préavis d'annulation en ligne par le client
'notify_email' => get_option( 'admin_email' ),
'retention_months' => 24, // anonymisation des RDV passés (0 = jamais)
'consult_label' => 'Consultation',
]
Détail
| Réglage | Type | Bornes de l'interface | Effet |
|---|---|---|---|
hours | tableau | 1 ou 2 plages par jour | Deux plages permettent la coupure de midi. Une plage n'est retenue que si début et fin sont valides et que début < fin. Un jour vide = fermé |
slot_step | entier | 5 → 120 min | Espacement des heures proposées. Plus il est fin, plus la liste est longue |
consult_duration | entier | 15 → 480 min | Durée réservée dans l'agenda pour une consultation web |
buffer | entier | 0 → 120 min | Battement appliqué de part et d'autre du créneau candidat |
min_notice_hours | entier | 0 → 168 h | Rien n'est proposé avant maintenant + ce délai |
max_advance_days | entier | 7 → 365 j | Horizon au-delà duquel plus aucun créneau n'est proposé |
auto_confirm | 0 / 1 | — | Validation manuelle ou confirmation immédiate |
email_verify | 0 / 1 | — | Double opt-in par e-mail (à laisser actif) |
cancel_notice_hours | entier | 0 → 168 h | Au-delà, l'annulation en ligne est refusée avec un message invitant à téléphoner |
notify_email | — | Destinataire des notifications admin ; sert aussi d'ORGANIZER dans les fichiers ICS | |
retention_months | entier | 0 → 120 mois | Anonymisation des rendez-vous terminés ; 0 désactive |
consult_label | texte | — | Titre affiché sur le widget de réservation |
Deux constantes non configurables méritent d'être connues, parce qu'elles gouvernent le comportement du double opt-in : le créneau d'une demande non vérifiée est retenu 45 minutes, et la demande est supprimée après 48 heures.
L'enregistrement par l'API REST accepte les mêmes clés en JSON ; les entiers sont ramenés à zéro minimum, l'adresse de notification n'est acceptée que si elle est valide, et chaque plage horaire est revalidée côté serveur.
Données stockées
Trois tables, toutes préfixées par le préfixe de votre installation. Les dates sont des
DATETIME en heure locale du site, jamais en UTC — c'est ce qui rend les requêtes
lisibles et les comparaisons d'horaires triviales.
{prefix}_owag_appointments
| Colonne | Type | Notes |
|---|---|---|
id | BIGINT | Clé primaire |
uid | CHAR(32) | Jeton public unique (hexadécimal, générateur cryptographique). Sert de clé aux liens de validation, d'annulation et d'action admin, et d'UID ICS |
kind | VARCHAR(16) | consult, seance, manual, block |
service_label | VARCHAR(120) | Intitulé affiché |
customer_name, customer_phone, customer_email | VARCHAR | Coordonnées |
customer_msg | TEXT | Message laissé par le client |
admin_notes | TEXT | Notes internes, jamais envoyées au client |
start_dt, end_dt | DATETIME | Bornes du créneau (indexées sur start_dt) |
status | VARCHAR(16) | unverified, pending, confirmed, cancelled, done, noshow |
source | VARCHAR(16) | web, invite, admin |
invite_id | BIGINT | Invitation d'origine, le cas échéant |
reminder_sent | TINYINT | Drapeau de rappel (remis à 0 en cas de déplacement) |
created_at, updated_at | DATETIME | updated_at alimente le numéro de révision ICS |
{prefix}_owag_invites
id, token (CHAR(32), unique), coordonnées du client, service_label,
duration_min, expires_at, appointment_id (renseigné quand le lien est consommé,
remis à NULL si le rendez-vous est annulé), created_at.
{prefix}_owag_customers
id, name, phone, email, notes, created_at, updated_at. Index sur name et
email.
Une seule option porte la configuration (owag_settings) ; les autres sont techniques :
owag_admin_secret (secret HMAC), owag_db_version, owag_pages_created,
owag_page_booking, owag_page_admin.
Internationalisation
L'ensemble de l'interface est traduisible : réglages d'administration, widget de
réservation, page Agenda, pages autonomes, messages de l'API et gabarits d'e-mails. La
langue source est l'anglais ; le plugin déclare le domaine de traduction
ow-agenda et le chemin /languages.
Le paquet livre le gabarit languages/ow-agenda.pot. Une traduction française
complète est fournie, produite à partir de la formulation d'origine de l'interface.
Installer une traduction manuellement
Compilez le .po et déposez le .mo dans le dossier des traductions de WordPress :
msgfmt ow-agenda-fr_FR.po -o ow-agenda-fr_FR.mo
# puis : wp-content/languages/plugins/ow-agenda-fr_FR.mo
WordPress charge le catalogue à la première chaîne traduite ; aucun appel manuel n'est nécessaire.
Deux pièges pour les traducteurs
- Les chaînes destinées au JavaScript utilisent des marqueurs numérotés
(
%1$s,%2$s) et jamais un%snu : le petit formateur embarqué dans les scripts ne comprend que ceux-là. Un marqueur non numéroté serait affiché littéralement. - Deux chaînes sont des formats de date PHP, pas des phrases :
l, F j, Y \a\t g:i aetl j F Y \a\t H:i. Traduisez-les comme des formats (réordonner les jetons, échapper les lettres littérales par un antislash). Le français utilisel j F Y \à H\hi.
Désinstallation
Désactiver le plugin ne fait qu'une chose : supprimer la tâche planifiée horaire. Vos données, vos réglages et vos pages restent intacts, et tout repart à la réactivation.
Supprimer le plugin depuis WordPress exécute la désinstallation complète :
- suppression des trois tables (
owag_appointments,owag_invites,owag_customers) ; - suppression des options
owag_settings,owag_admin_secret,owag_db_version,owag_pages_created,owag_page_booking,owag_page_admin; - suppression de la tâche planifiée ;
- retrait de la capacité
owag_managedu rôle administrateur.
Les deux pages créées à l'activation ne sont pas supprimées — elles peuvent avoir été retravaillées, mises au menu, indexées. À vous de les mettre à la corbeille si vous n'en voulez plus.
La suppression des tables est définitive. Exportez votre base avant si l'historique des rendez-vous a une valeur pour vous.
Dépannage
Aucun créneau n'apparaît sur la page de réservation
Passez la liste dans l'ordre :
- Les horaires du jour sont-ils renseignés ? Un jour vide est un jour fermé.
- Le délai minimum (24 h par défaut) masque forcément aujourd'hui et une partie de demain.
- La durée tient-elle dans la plage ? Avec une plage 09:00–12:00 et une durée de 240 minutes, aucun créneau ne peut exister.
- L'horizon : les jours au-delà de
max_advance_daysne sont jamais proposés. - Le battement : un battement large sur un planning chargé peut tout fermer.
- Un blocage couvre peut-être la journée. Ouvrez la page Agenda au jour concerné.
- Le fuseau horaire du site (Réglages → Général) : un fuseau mal réglé décale tous les calculs.
Les e-mails n'arrivent pas
C'est presque toujours la délivrabilité, pas le plugin.
- Vérifiez que le rendez-vous existe bien dans la page Agenda : s'il y est, le plugin a fait son travail.
- Installez un plugin SMTP (Fluent SMTP, WP Mail SMTP…). La fonction
mail()de PHP est rejetée par l'immense majorité des serveurs de réception. - Vérifiez SPF, DKIM et DMARC de votre domaine.
- Testez l'adresse dans OW Agenda → Notifications admin envoyées à : une adresse invalide bloque silencieusement les notifications.
Le rappel de la veille n'est pas parti
Le rappel dépend de WP-Cron, qui dépend du trafic. Sur un site peu visité, basculez sur un vrai cron système (voir Rappels et tâche planifiée). Vérifiez aussi que le rendez-vous est bien confirmé, qu'il porte une adresse e-mail et que ce n'est pas un blocage.
La page Agenda affiche « L'accès est réservé à l'équipe »
L'utilisateur connecté n'a pas la capacité owag_manage. Elle est donnée aux
administrateurs à l'activation ; pour les autres rôles, voir
Installation.
Le bouton « Confirmer » de l'e-mail affiche « Lien invalide »
Trois causes possibles : le lien a été tronqué par le client de messagerie (essayez de copier l'URL complète), le rendez-vous a déjà été traité (le message le précise), ou le secret HMAC du site a été régénéré. Dans ce dernier cas, passez par la page Agenda : les anciens liens ne peuvent plus être validés, par construction.
Deux rendez-vous se retrouvent sur le même créneau
Depuis la 1.3.0, c'est impossible par la réservation en ligne. En revanche, l'admin
peut forcer un chevauchement depuis la page Agenda (le plugin le signale et demande
confirmation) : vérifiez d'abord qu'il ne s'agit pas d'un forçage volontaire. Vérifiez
aussi que votre base supporte bien GET_LOCK() — un hébergement exotique renverrait
alors des erreurs 503 à la réservation plutôt que des doublons.
Les pages « Réserver » et « Agenda » n'ont pas été créées
Elles ne sont créées qu'une fois, à la toute première activation. Si vous les avez
supprimées, créez deux pages avec les shortcodes [ow_agenda] et [ow_agenda_admin],
puis pointez-y les options owag_page_booking et owag_page_admin pour que les liens des
e-mails restent corrects :
update_option( 'owag_page_booking', 42 ); // ID de votre page de réservation
update_option( 'owag_page_admin', 43 ); // ID de votre page Agenda
Le fichier calendrier n'est pas joint
Le fichier est écrit dans le répertoire temporaire du serveur via l'API fichiers de WordPress. Si ce répertoire n'est pas accessible en écriture (quota, droits, hébergement verrouillé), l'e-mail part sans pièce jointe plutôt que d'échouer. Vérifiez les droits d'écriture et l'espace disque.
Les horaires sont décalés d'une heure
Réglages → Général → Fuseau horaire. Choisissez une ville (Europe/Brussels) plutôt
qu'un décalage UTC fixe : seul un fuseau nommé gère le passage à l'heure d'été.
FAQ
OW Agenda est-il vraiment gratuit ?
Oui. GPL-2.0-or-later, téléchargeable en .zip depuis
https://optionweb.dev/fr/addons/ow-agenda/. Pas de version Pro, pas de clé de licence,
pas de fonctionnalité verrouillée, pas de compte à créer, pas de quota de rendez-vous.
Les créneaux en ligne tiennent-ils compte des rendez-vous pris par téléphone ? Oui. Tout événement de l'agenda — réservation web, rendez-vous saisi à la main, séance sur invitation, blocage — rend sa plage horaire indisponible à la réservation en ligne.
Le client doit-il créer un compte ? Non. Aucun compte, aucun mot de passe. Toutes les actions du client (validation, annulation) passent par des liens privés reçus par e-mail.
Peut-on gérer plusieurs praticiens ou plusieurs salles ? Non. OW Agenda décrit un seul planning. Pour deux agendas indépendants, il faut deux sites (ou deux sites d'un réseau multisite).
Est-ce que ça se synchronise avec Google Agenda ? Dans le sens qui compte pour le client : oui. Chaque confirmation embarque un fichier calendrier standard qui ajoute — et met à jour, et supprime — l'événement dans Google Agenda, Outlook ou le calendrier d'iPhone. En revanche, le plugin ne lit pas vos agendas externes : vos indisponibilités personnelles se saisissent comme des blocages.
Peut-on faire payer un acompte à la réservation ? Non, c'est hors du périmètre assumé du plugin.
Combien de prestations peut-on proposer en ligne ? Une seule, dont vous choisissez le libellé et la durée. Les autres prestations passent par les invitations de séance, qui vous laissent fixer l'intitulé et la durée au cas par cas. Ce choix est délibéré : un menu de prestations sur une page publique multiplie les demandes mal ciblées.
Fonctionne-t-il sur un multisite ? Oui. Chaque site du réseau a ses propres tables, ses propres réglages et son propre agenda.
Le plugin ralentit-il le site ? Non. Aucun script n'est chargé en dehors des deux pages concernées ; le widget de réservation pèse moins de 12 Ko, sans jQuery ni framework. Le travail périodique tient en une tâche horaire.
Que se passe-t-il si un client ne valide jamais son e-mail ? Son créneau est rendu disponible au bout de 45 minutes et sa demande est supprimée au bout de 48 heures. Vous n'en entendez jamais parler.
Où trouver le support ?
- Portail de support : https://optionweb.dev/fr/addons/support/
- E-mail : support@optionweb.dev
- Documentation : https://optionweb.dev/fr/addons/ow-agenda/
Changelog
1.3.1
Conformité
- Les pages autonomes d'action, de vérification et d'annulation n'impriment plus leur CSS
ni leur JavaScript en ligne : les deux sont désormais des fichiers enregistrés et servis
par l'API d'enqueue de WordPress. Les deux couleurs de bouton variables passent par des
propriétés CSS personnalisées, et le script est configuré via
wp_localize_script(). - Les catalogues de traduction ne sont plus embarqués : seul
languages/ow-agenda.potest livré, le français étant distribué par les paquets de langue WordPress.org alimentés par translate.wordpress.org. - La version minimale de WordPress revient à 6.3 : plus rien dans le paquet ne dépend de la découverte des traductions embarquées introduite en 6.7.
API REST
- Chaque route d'administration déclare désormais son
permission_callbackexplicitement au lieu de le partager viaarray_merge(). Le contrôle de capacité était déjà appliqué ; il est maintenant visible pour l'analyse statique.
Aucun changement de comportement.
1.3.0
Internationalisation
- Plugin entièrement traduisible (domaine
ow-agenda, anglais comme langue source) : réglages, pages publiques, messages de l'API, e-mails et interface JavaScript. - Gabarit
languages/ow-agenda.potlivré et traduction française complète.
Sécurité
- Les identifiants publics des rendez-vous et les jetons d'invitation sont générés par un
générateur cryptographique (
random_bytes()). Ces jetons sont la seule authentification des liens d'annulation, de validation et d'invitation. - Le piège à robots et l'horodatage sont devenus obligatoires : les omettre désactivait les contrôles anti-spam.
- Le quota horaire est agrégé par préfixe /64 en IPv6, et un plafond quotidien limite les demandes non vérifiées — un visiteur ne peut plus retenir tous les créneaux d'une journée.
- Le quota n'est décompté qu'après validation du formulaire : une faute de frappe ne bloque plus un visiteur légitime pendant une heure.
Fiabilité
- Les réservations simultanées d'un même créneau sont sérialisées par un verrou nommé MySQL. La transaction précédente ne posait aucun verrou de ligne : deux visiteurs pouvaient réserver le même horaire.
- Le rappel de la veille utilise une fenêtre glissante de 12 à 36 h et rattrape son retard ; chaque envoi est réservé de façon atomique, deux exécutions de cron ne peuvent plus envoyer deux fois le même rappel.
- La tâche horaire se reprogramme automatiquement si elle disparaît : rappels, purge et anonymisation ne peuvent plus s'arrêter en silence.
- Le déplacement d'un rendez-vous met à jour le calendrier du client (
SEQUENCE,METHOD:REQUEST, organisateur et participant) ; l'annulation envoie unMETHOD:CANCELqui supprime l'événement. - Les dates du widget sont calculées en heure locale et non en UTC : plus de journée perdue pour les visiteurs à l'est de UTC.
- L'annulation d'un rendez-vous issu d'une invitation libère l'invitation, qui redevient utilisable.
- Les rendez-vous annulés et les demandes non validées expirées ne sont plus renvoyés à l'agenda : moins de données personnelles dans les réponses, plus de rendez-vous fantômes.
1.2.1
- Conformité Plugin Check : échappement des sorties, nettoyage des entrées, nonce sur les réglages, readme.
- La désinstallation supprime aussi la table du répertoire clients et le secret HMAC.
1.2.0
- E-mails HTML (mise en page en carte, couleur d'accent du site) pour toutes les notifications.
- Boutons Confirmer / Refuser dans l'e-mail admin (liens signés HMAC).
- Répertoire clients : recherche, création, édition, suppression, raccourcis vers un nouveau rendez-vous et une invitation.
1.1.0
- Double vérification par e-mail contre les robots (créneau retenu 45 minutes, purge après 48 heures).
1.0.0
- Version initiale : réservation en ligne, agenda d'administration mobile-first, invitations de séance, e-mails avec fichier calendrier et rappel de la veille.
Conçu par OptionWeb — Julien Daniel, Châtelet, Belgique.