Live · Status OK
Dokumentation · OW Agenda v1.3.1

OW Agenda
Dokumentation

Die WordPress-Terminbuchung, bei der niemand deine Zeitfenster umsonst blockiert.

v1.3.1GPL-2.0-or-laterDokumentation

OW Agenda — Dokumentation

Online-Terminbuchung und der Kalender für den Praxisalltag, in WordPress, ohne Abo. Autor: OptionWeb — Julien Daniel Plugin-Startseite: https://optionweb.dev/de/addons/ow-agenda/ Lizenz: GPL-2.0-or-later Dieses Dokument deckt Version 1.3.1 ab.


Inhaltsverzeichnis

  1. Überblick
  2. Installation
  3. Schnellstart
  4. Der Buchungsablauf
  5. Die doppelte Bestätigung per E-Mail
  6. Die Freigabe der Anfragen
  7. Die Agenda-Seite
  8. Das Kundenverzeichnis
  9. Die Sitzungseinladungen
  10. E-Mails und Kalenderdatei (ICS)
  11. Erinnerungen und geplante Aufgabe
  12. Anti-Spam und Ratenbegrenzung
  13. DSGVO
  14. Shortcodes
  15. REST API
  16. Einstellungsreferenz
  17. Gespeicherte Daten
  18. Internationalisierung
  19. Deinstallation
  20. Fehlerbehebung
  21. FAQ
  22. Changelog

Überblick

OW Agenda ergänzt WordPress um ein vollständiges Terminsystem: eine öffentliche Seite, auf der Besucher zuerst ihren Tag und dann ihre Uhrzeit wählen, und eine durch Login geschützte Seite „Agenda“, die für die Bedienung am Handy gedacht ist und auf der Sie den Tag verwalten.

Alles bleibt in der Website. Kein externer Dienst, keine fremde API, kein Abo: Die Zeitfenster berechnet Ihr Server, die Termine liegen in Ihren MySQL-Tabellen, die E-Mails gehen über wp_mail() raus.

Was mitgeliefert wird (alles kostenlos, GPL-2):

  • Online-Buchung: Tag wählen, Zeitfenster wählen, kurzes Formular, DSGVO-Einwilligungsfeld
  • Double-Opt-in per E-Mail: Eine Anfrage wird erst real, nachdem ein Bestätigungslink angeklickt wurde — Bots erreichen den Kalender nie
  • Manuelle Freigabe (empfohlen) oder automatische Bestätigung, mit den Buttons Bestätigen / Ablehnen direkt in der Benachrichtigungs-E-Mail (HMAC-signierte Links, ohne Login)
  • Mobile-first-Seite „Agenda“: Tagesansicht, offene Anfragen, telefonisch vereinbarte und von Hand nachgetragene Termine, Blockieren von Zeitfenstern, Verschieben, Status erledigt / nicht erschienen
  • Kundenverzeichnis: Suchen, Anlegen, Bearbeiten, Löschen; wird automatisch aus bestätigten Terminen gespeist
  • Sitzungseinladungen: Ein privater Link lässt einen bestehenden Kunden das Datum seiner Sitzung wählen, auf einer Leistung und einer Dauer, die Sie festlegen
  • Sorgfältig gestaltete HTML-E-Mails mit ICS-Anhang (Übernahme in den Handykalender mit einer Geste), automatische Erinnerung am Vortag, Online-Absage durch den Kunden
  • Automatische Anonymisierung vergangener Termine, Bereinigung nie bestätigter Anfragen
  • Vollständige REST API unter dem Namespace owag/v1

Was es bewusst nicht tut:

  • Keine Online-Zahlung: OW Agenda vereinbart den Termin, es zieht keine Anzahlung ein (nutzen Sie WooCommerce, falls Sie das brauchen)
  • Nur ein Kalender: keine Verwaltung mehrerer Behandler oder Ressourcen; das Plugin bildet einen Terminplan ab, den der Website
  • Keine bidirektionale Synchronisierung mit Google Kalender oder Outlook: Der Kalender des Kunden wird per ICS-Datei aktualisiert (Einbahnstraße), Ihre eigenen Abwesenheiten tragen Sie als Blockierungen ein
  • Kein Leistungskatalog auf Besucherseite: Die öffentliche Buchung bezieht sich auf eine einzige Leistung (Bezeichnung und Dauer konfigurierbar); alle weiteren Leistungen laufen über die Sitzungseinladungen
  • Keine wiederkehrenden Termine, keine Videosprechstunde, kein Wartezimmer

Diese Liste ist eine Architekturentscheidung, keine versteckte Roadmap: Ein einfacher Kalender, der sich nie im Zeitfenster irrt, ist mehr wert als ein Moloch, den niemand anzufassen wagt.


Installation

Aus der .zip-Datei

  1. Laden Sie ow-agenda-1.3.1.zip herunter von https://optionweb.dev/de/addons/ow-agenda/
  2. Plugins → Installieren → Plugin hochladen
  3. Wählen Sie die Datei, klicken Sie auf Installieren und danach auf Aktivieren

Per FTP

Entpacken Sie das Archiv und legen Sie den Ordner ow-agenda in /wp-content/plugins/ ab, dann aktivieren Sie das Plugin unter Plugins.

Voraussetzungen

  • WordPress 6.3 oder neuer
  • PHP 7.4 oder neuer (8.1+ empfohlen)
  • MySQL 5.7+ / MariaDB 10.2+ — die Funktionen GET_LOCK() / RELEASE_LOCK() werden verwendet, um gleichzeitige Buchungen zu serialisieren
  • Ein funktionierender E-Mail-Versand. Das ist die einzige echte Abhängigkeit des Plugins: Der gesamte Ablauf (Bestätigung, Freigabe, Erinnerung, Absage) läuft über E-Mail. Installieren Sie auf Shared Hosting ein SMTP-Plugin, bevor Sie die Buchung live schalten.

Was installiert wird

Bei der Aktivierung legt OW Agenda drei Tabellen an:

TabelleInhalt
{prefix}_owag_appointmentsAlle Einträge des Kalenders: Online-Konsultationen, Sitzungen aus einer Einladung, von Hand eingetragene Termine, geblockte Zeitfenster
{prefix}_owag_invitesDie privaten Links „Wählen Sie das Datum Ihrer Sitzung“
{prefix}_owag_customersDas Kundenverzeichnis

… und, nur beim allerersten Mal, zwei veröffentlichte Seiten:

  • „Termin buchen“ — enthält den Shortcode [ow_agenda]
  • „Agenda“ — enthält den Shortcode [ow_agenda_admin]

Ihre IDs werden in den Optionen owag_page_booking und owag_page_admin gespeichert; das Flag owag_pages_created sorgt dafür, dass eine Deaktivierung mit anschließender Reaktivierung keine Duplikate erzeugt. Sie dürfen diese Seiten umbenennen, in ein Menü einhängen oder ihren Permalink ändern: Das Plugin verfolgt sie über ihre ID.

Die Aktivierung fügt außerdem hinzu:

  • die Berechtigung owag_manage zur Rolle Administrator — sie, und nicht manage_options, öffnet die Agenda und die administrativen REST-Routen;
  • die Standardeinstellungen in der Option owag_settings;
  • die stündlich geplante Aufgabe owag_hourly_event (erste Ausführung 5 Minuten nach der Aktivierung).

Ein HMAC-Secret (owag_admin_secret, 64 Zeichen, nicht automatisch geladen) wird bei der ersten Admin-Benachrichtigung erzeugt: Es signiert die Buttons Bestätigen / Ablehnen in den E-Mails.

Jemand anderem Zugriff geben

Die Agenda-Seite ist für jeden angemeldeten Nutzer mit owag_manage sichtbar. So öffnen Sie die Agenda für eine Assistenz, ohne ihr die Schlüssel zur Website zu geben:

// À exécuter une fois (mu-plugin, ou plugin de gestion des rôles).
$role = get_role( 'editor' );
if ( $role ) { $role->add_cap( 'owag_manage' ); }

Schnellstart

Gehen Sie nach der Aktivierung zu OW Agenda (Hauptmenü der Administration). Der Einstellungsbildschirm passt auf eine Seite; fünf Minuten genügen.

1. Die Öffnungszeiten

Tragen Sie für jeden Wochentag einen Zeitraum ein (09:00 → 18:00) und, falls Sie mittags schließen, einen zweiten (14:00 → 18:30). Ein leer gelassener Tag ist ein geschlossener Tag. Standard: Montag bis Freitag, 09:00–18:00; Samstag und Sonntag geschlossen.

Die Zeiten werden in der Zeitzone der Website interpretiert (Einstellungen → Allgemein → Zeitzone). Prüfen Sie sie, bevor Sie die Buchung öffnen: Alle Termine werden in Ortszeit gespeichert.

2. Die online buchbare Leistung

  • Bezeichnung der Konsultation — was der Besucher als Titel des Widgets sieht („Konsultation“, „Erstgespräch“, „Check-up“ …)
  • Dauer der Konsultation — standardmäßig 60 Minuten. Diese Dauer wird im Kalender blockiert.
  • Taktung der Zeitfenster — der Abstand zwischen zwei angebotenen Uhrzeiten (standardmäßig 30 Minuten). Bei einer Dauer von 60 und einer Taktung von 30 bieten Sie 9:00, 9:30, 10:00 … an, und der erste um 9:30 gebuchte Termin entfernt 9:00 und 10:00 aus der Liste.
  • Puffer zwischen zwei Terminen — Minuten zum Durchatmen, die beiderseits jedes Kandidaten-Zeitfensters hinzukommen (standardmäßig 0).

3. Die Fristen

  • Mindestvorlaufzeit für Buchungen — standardmäßig 24 h: Ein Besucher kann nicht für in einer Stunde buchen.
  • Buchungshorizont — standardmäßig 60 Tage: Darüber hinaus wird nichts mehr angeboten.
  • Online-Absage durch den Kunden — bis 24 h vor dem Termin; danach fordert die Absageseite zum Anruf auf.

4. Freigabe und E-Mails

  • Bestätigung der Anfragen: manuelle Freigabe (empfohlen) oder automatische Bestätigung.
  • Doppelte E-Mail-Bestätigung: Lassen Sie das Häkchen gesetzt. Das ist der beste Bot-Schutz des Plugins.
  • Admin-Benachrichtigungen senden an: Ihre Adresse. Standardmäßig die Administrations-E-Mail der Website.

Speichern Sie, dann öffnen Sie die Seite „Termin buchen“: Das Widget zeigt die nächsten 14 Tage und Ihre freien Zeitfenster. Sie sind online.

5. Die Agenda auf dem Handy

Öffnen Sie die Seite „Agenda“ auf Ihrem Handy, melden Sie sich an und nutzen Sie dann „Zum Startbildschirm hinzufügen“. Das Plugin veröffentlicht ein Web-App-Manifest: Die Seite öffnet sich danach im Vollbild, ohne Browserleiste, wie eine App.


Der Buchungsablauf

Auf Besucherseite ist die Buchungsseite eine eigenständige Komponente (JavaScript ohne Framework, weniger als 10 KB), die mit den öffentlichen Endpunkten owag/v1/public/* spricht.

Schritt 1 — der Tag

Beim Laden fragt das Widget die Verfügbarkeiten für 14 Tage ab heute ab und zeigt ein Band anklickbarer Tage. Ein Tag ohne freies Zeitfenster ist ausgegraut und nicht anklickbar. Der Button „Weitere Termine anzeigen“ lädt die nächsten 14 Tage, so oft wie nötig bis zum konfigurierten Horizont.

Die Daten im Widget werden in der lokalen Zeit des Browsers gebildet, nie in UTC. Das ist eine Korrektur aus 1.3.0: Bisher sah ein Besucher östlich von UTC, der die Seite kurz nach Mitternacht öffnete, die Liste am Vortag beginnen und verlor einen Tag Verfügbarkeit.

Schritt 2 — die Uhrzeit

Der Klick auf einen Tag ruft /public/slots auf und zeigt die freien Startzeiten. Ein Zeitfenster wird angeboten, wenn alle diese Bedingungen erfüllt sind:

  1. Es fällt in einen Öffnungszeitraum des betreffenden Tages;
  2. der gesamte Termin (Beginn + Dauer) passt vor den Feierabend;
  3. er beginnt nach jetzt + Mindestvorlaufzeit;
  4. der Tag liegt innerhalb des Buchungshorizonts;
  5. er überschneidet sich mit keinem aktiven Eintrag, Puffer eingerechnet — und „aktiver Eintrag“ umfasst bestätigte Termine, offene Anfragen, Blockierungen, von Hand eingetragene Telefontermine sowie noch nicht bestätigte Anfragen, die ihr Zeitfenster noch halten.

Das ist der entscheidende Punkt: Alles, was den Kalender belegt, schließt das Online-Zeitfenster. Ein telefonisch vereinbarter und im Kalender notierter Termin verschwindet sofort aus den auf der Website angebotenen Zeitfenstern.

Schritt 3 — das Formular

Vier Felder, davon drei Pflichtfelder: Name (mindestens 2 Zeichen), Telefon (mindestens 8 Ziffern), E-Mail (validiert), freie Nachricht. Ein DSGVO-Einwilligungsfeld, standardmäßig nicht angehakt, ist obligatorisch.

Das Formular führt zusätzlich zwei für den Besucher unsichtbare Felder mit — eine Bot-Falle und einen Zeitstempel des Seitenaufrufs —, beschrieben im Abschnitt Anti-Spam.

Schritt 4 — die Antwort

Je nach Konfiguration gibt es drei Ausgänge:

KonfigurationErzeugter StatusAngezeigte Meldung
Doppelte E-Mail-Bestätigung aktiv (Standard)unverified„Nur noch ein Schritt: Wir haben Ihnen soeben eine E-Mail geschickt …“
Bestätigung deaktiviert + manuelle Freigabepending„Ihre Anfrage ist eingegangen!“
Bestätigung deaktiviert + automatische Bestätigungconfirmed„Ihr Termin ist bestätigt!“

Wurde das Zeitfenster zwischen der Anzeige der Liste und dem Absenden des Formulars vergeben, erhält der Besucher eine eindeutige Meldung (owag_slot_taken, HTTP 409) und die Tagesliste lädt automatisch neu. Zwei Besucher können nicht dasselbe Zeitfenster bekommen: Der kritische Abschnitt wird über eine benannte MySQL-Sperre serialisiert, spezifisch für Ihre Datenbank und Ihr Tabellenpräfix — das hält sogar auf Shared Hosting.


Die doppelte Bestätigung per E-Mail

Das ist die Funktion, die OW Agenda von einem getarnten Kontaktformular unterscheidet.

Wenn Doppelte E-Mail-Bestätigung aktiv ist (Einstellung email_verify, standardmäßig an):

  1. Die Anfrage wird mit dem Status unverified gespeichert. Der Administrator wird nicht benachrichtigt. Der Termin erscheint nicht als zu bearbeitende Anfrage.
  2. Der Besucher erhält eine E-Mail „Nur noch ein Schritt …“ mit einem Bestätigungsbutton.
  3. Das Zeitfenster wird 45 Minuten gehalten. Bleibt die Bestätigung aus, wird es wieder für alle verfügbar — ein Bot kann Ihren Tag also nicht einfrieren.
  4. Der Klick auf den Button öffnet eine eigenständige Seite (?owag_verify=<uid>), die die Zusammenfassung des Termins und einen Button „Ich bestätige meine Anfrage“ zeigt. Die Bestätigung wird erst mit dem Klick ausgelöst: Virenscanner und Link-Prüfer, die die URLs in E-Mails aufrufen, bestätigen nichts.
  5. Die Anfrage wird dann pending (manuelle Freigabe) oder confirmed (automatische Bestätigung), der Kunde erhält die entsprechende E-Mail, und erst dann geht die Admin-Benachrichtigung raus.
  6. Nie bestätigte Anfragen werden nach 48 h gelöscht, durch die stündliche Aufgabe. Sie hinterlassen weder Spur noch personenbezogene Daten.

Wurde das Zeitfenster zwischen Versand und Klick von jemand anderem belegt (das 45-Minuten-Fenster ist abgelaufen), liefert die Bestätigung einen klaren Fehler und die Anfrage wird storniert — nie ein Geistertermin auf einem bereits belegten Zeitfenster.

Praktische Folge: Eine ungültige E-Mail-Adresse erzeugt keinen Termin. Sie verlieren keine Zeit mehr damit, Fantasienummern zurückzurufen. Der Preis dafür ist ein zusätzlicher Klick für den Kunden; die Erfahrung zeigt, dass die Abbruchquote weit unter der Quote der falschen Termine liegt, die er verhindert.

Buchungen aus einer Sitzungseinladung überspringen diesen Schritt: Der Kunde hat mit dem Klick auf den privaten Link, den er erhalten hat, bereits bewiesen, dass er sein Postfach liest.


Die Freigabe der Anfragen

Manuelle Freigabe (empfohlen)

Standardeinstellung: auto_confirm = 0. Eine bestätigte Anfrage kommt mit dem Status pending an. Dem Kunden ist nichts zugesagt, solange Sie nichts getan haben — aber das Zeitfenster ist bereits blockiert, niemand kann es Ihnen wegschnappen.

Sie erhalten eine E-Mail „Zu bestätigen: mit der vollständigen Zusammenfassung (Leistung, Datum, Name, Telefon, E-Mail, Nachricht des Kunden) und zwei Buttons:

  • Termin bestätigen — Cyan
  • Ablehnen — roter Rahmen

Die Buttons in der E-Mail: HMAC-signierte Links

Diese Buttons verlangen keinen Login. Sie verweisen mit drei Parametern auf Ihre Website: owag_admin_action (confirm oder refuse), uid (die zufällige Kennung des Termins) und sig, eine HMAC-SHA256-Signatur von uid|action, berechnet mit dem privaten Secret der Website (owag_admin_secret).

  • Die Signatur wird geprüft, bevor auch nur ein Detail angezeigt wird: Ein manipulierter Link zeigt nichts außer „Ungültiger Link“.
  • Der Vergleich nutzt hash_equals() — keine Informationslecks über die Antwortzeit.
  • Die Seite zeigt eine Zusammenfassung und einen Button; die Aktion läuft erst beim Klick. Ein Link-Scanner bestätigt also nichts an Ihrer Stelle.
  • Eine bereits bearbeitete Anfrage meldet „Bereits bearbeitet (Status: …)“ statt eines Fehlers.

Bestätigen verschickt automatisch die Bestätigungs-E-Mail an den Kunden, mit der Kalenderdatei. Ablehnen verschickt die Absage-E-Mail. In beiden Fällen ist der Kalender aktuell, bevor Sie Ihr Handy wieder weggelegt haben.

Diese Links bleiben gültig, solange der Termin offen ist. Wenn Sie die Option owag_admin_secret löschen (teilweise Wiederherstellung der Datenbank, manuelle Bereinigung), funktionieren alle bereits verschickten Links nicht mehr: Ein neues Secret wird erzeugt und die alten Signaturen passen nicht mehr. Nutzen Sie dann die Agenda-Seite.

Automatische Bestätigung

Einstellung auto_confirm = 1. Ein freies Zeitfenster wird sofort bestätigt: Der Kunde erhält seine Bestätigung mit der Kalenderdatei, Sie erhalten eine Benachrichtigung „Neuer Termin“. Empfehlenswert nur für Tätigkeiten, bei denen jedes offene Zeitfenster ein akzeptables Zeitfenster ist.

Beide Einstellungen lassen sich mit der doppelten Bestätigung kombinieren: Auch bei automatischer Bestätigung durchläuft die Anfrage zuerst unverified, wenn email_verify aktiv ist.


Die Agenda-Seite

Die Seite „Agenda“ ([ow_agenda_admin]) ist das Werkzeug für jeden Tag. Sie ist fürs Handy zuerst entworfen: große Buttons, eine Spalte, keine Tabelle, die man horizontal scrollen muss — und funktioniert selbstverständlich genauso gut auf einem Bildschirm.

Sie ist geschützt: Ein nicht angemeldeter Besucher sieht einen Login-Link, ein angemeldeter Nutzer ohne die Berechtigung owag_manage sieht „Der Zugriff ist dem Team vorbehalten“. Die Seite ist auf noindex,nofollow gesetzt: Sie landet nie bei Google.

Reiter Agenda — die Tagesansicht

Der laufende Tag, Eintrag für Eintrag, mit Uhrzeit, Dauer, Bezeichnung, Status und Herkunft (Website, Einladung, manuelle Eingabe). Navigation von Tag zu Tag, Button Heute. Zu jedem Termin:

  • Details — Kontaktdaten des Kunden, bei der Buchung hinterlassene Nachricht und ein Block mit internen Notizen (für den Kunden nie sichtbar), die gespeichert werden, ohne dass eine einzige E-Mail rausgeht
  • Bestätigen ✓ — für eine noch offene Anfrage; die Bestätigungs-E-Mail geht raus
  • Erledigt / Nicht erschienen (No-Show) — Status am Ende des Termins
  • Verschieben — neues Datum, neue Uhrzeit, gegebenenfalls geänderte Dauer. Das Plugin fragt Sie, ob der Kunde per E-Mail informiert werden soll; wenn ja, erhält er eine aktualisierte Bestätigung und eine Kalenderdatei, die den bereits auf seinem Handy vorhandenen Eintrag korrigiert
  • Termin absagen — auch hier mit der Wahl, den Kunden zu informieren oder nicht
  • Blockierung entfernen — für ein geblocktes Zeitfenster

Wenn eine Aktion eine Überschneidung erzeugt (Verschieben auf ein belegtes Zeitfenster), warnt das Plugin und fragt nach: Sie können erzwingen. Es ist Ihr Terminplan, Sie wissen, was Sie tun — der Schutzmechanismus ist nur für Besucher bindend.

Einen Termin oder eine Blockierung hinzufügen

Der Button „Termin hinzufügen“ öffnet ein einziges Formular für zwei Zwecke:

  • Termin — der Kunde hat angerufen. Name, Telefon, E-Mail (optional), Leistung, Datum, Uhrzeit, Dauer, interne Notizen. Wenn Sie eine E-Mail-Adresse eintragen und die Option anhaken, erhält der Kunde die Bestätigung mit seiner Kalenderdatei, als hätte er online gebucht. Der Termin speist außerdem das Kundenverzeichnis.
  • Blockierung (Urlaub, Pause …) — ein Grund, ein Datum, eine Uhrzeit, eine Dauer. Keine E-Mail, kein Kundendatensatz, aber das Zeitfenster verschwindet sofort aus der Online-Buchung. So tragen Sie eine Urlaubswoche ein, eine Fortbildung oder die Mittagszeit, die niemand buchen soll.

Reiter Offen

Die Liste der bestätigten Anfragen, die auf Ihre Entscheidung warten, über alle Tage hinweg (bereits vergangene Termine sind ausgeschlossen). Zwei Buttons pro Zeile: Bestätigen und Ablehnen. Das ist der erste Bildschirm, den man morgens öffnet.

Tipp: die Agenda als App

Auf der Agenda-Seite deklariert das Plugin ein Web-App-Manifest (?owag_manifest=1) mit dem Namen der Website, ihrem Icon und ihrer Themenfarbe. Unter Android wie unter iOS bietet das Browsermenü dann „Zum Startbildschirm hinzufügen“ an: Sie bekommen ein Icon, einen Vollbildstart und müssen die URL nie wieder eintippen.


Das Kundenverzeichnis

Der dritte Reiter der Agenda-Seite ist ein leichtgewichtiges, bewusst minimales Verzeichnis: Name, Telefon, E-Mail, freie Notizen.

  • Es füllt sich von selbst. Sobald ein Termin bestätigt ist (geprüfte Online-Buchung, Sitzung auf Einladung, manuelle Eingabe), wird der Kunde zunächst über seine E-Mail- Adresse, dann über seine Telefonnummer einem bestehenden Datensatz zugeordnet. Existiert er nicht, wird der Datensatz angelegt; existiert er, werden nur die leeren Felder ergänzt — das Plugin überschreibt nie, was Sie von Hand eingetragen haben.
  • Suche über Name, Telefon oder E-Mail (maximal 200 angezeigte Datensätze).
  • Manuelles Anlegen und Bearbeiten, mit einem Notizfeld für Historie, Vorlieben und Besonderheiten.
  • Zwei Kurzbefehle pro Datensatz: Neuer Termin (füllt das manuelle Eingabeformular vor) und Zu einer Sitzung einladen (füllt die Einladung vor).
  • Löschen eines Datensatzes: Vergangene Termine bleiben im Kalender, nur der Eintrag im Verzeichnis verschwindet.

Dieses Verzeichnis ist kein CRM und gibt auch nicht vor, eines zu sein. Es beantwortet eine Frage: „Wer war noch mal die Dame um 14 Uhr?“


Die Sitzungseinladungen

Der Anwendungsfall: Ein bestehender Kunde hat Anspruch auf eine Sitzung — eine Nachkontrolle, eine Nachbesserung, eine anderswo verkaufte Leistung — und Sie möchten, dass er sein Datum ohne den Umweg über die öffentliche Buchung wählt, auf einer Leistung und einer Dauer, die Sie festlegen.

Im Reiter Einladungen:

  1. Tragen Sie den Namen des Kunden und die Bezeichnung der Sitzung ein (Pflichtfelder), deren Dauer (15 bis 720 Minuten) und, wenn Sie möchten, seine E-Mail-Adresse und Telefonnummer.
  2. Wählen Sie die Gültigkeit des Links: standardmäßig 60 Tage, von 1 bis 365.
  3. Haken Sie gegebenenfalls „Link per E-Mail an den Kunden senden“ an — der Kunde erhält eine E-Mail „Wählen Sie das Datum Ihrer Sitzung“ mit Bezeichnung, Dauer, Ablaufdatum und einem Button.
  4. Andernfalls kopieren Sie den Link und schicken ihn per SMS, WhatsApp oder über den nativen Teilen-Button des Handys.

Der Link verweist mit einem privaten Token auf Ihre Buchungsseite (?owag_invite=<token>, 32 hexadezimale Zeichen aus einem kryptografischen Generator). Das Widget zeigt dann Bezeichnung und Dauer der Sitzung an, nicht die der Standardkonsultation. Der Kunde füllt dasselbe kurze Formular aus.

Regeln für einen Einladungslink:

  • Einmalige Verwendung. Sobald die Sitzung gebucht ist, antwortet der Link „Dieser Link wurde bereits verwendet“ (HTTP 410). Zwei gleichzeitige Aufrufe mit demselben Token können keine zwei Sitzungen erzeugen: Der Token wird unter derselben Sperre eingelöst wie die Buchung des Zeitfensters.
  • Befristet. Nach Ablauf fordert der Link dazu auf, Sie erneut zu kontaktieren (HTTP 410).
  • Ohne Double-Opt-in. Der Kunde hat diesen Link bereits über einen Kanal erhalten, den Sie kontrollieren: Die Sitzung wird direkt als confirmed angelegt, mit Bestätigung und Kalenderdatei.
  • Wiederverwendbar bei Absage. Wird die Sitzung abgesagt (von Ihnen oder vom Kunden), wird die Einladung freigegeben: Der Link ist wieder aktiv und die Einladung erscheint erneut in der Liste der offenen Einladungen. Das ist eine Korrektur aus 1.3.0 — bisher tötete eine Absage den Link endgültig und man musste einen neuen erzeugen.
  • Widerrufbar. Das Löschen einer Einladung aus der Liste deaktiviert den Link sofort.

E-Mails und Kalenderdatei (ICS)

Die Transaktions-E-Mails

Alle Nachrichten sind in HTML, auf einem Tabellenlayout, das mit Gmail und Outlook kompatibel ist: weiße Karte auf hellem Grund, Name der Website in der Kopfzeile, Zusammenfassungsbox mit cyanfarbenem Rand, Pillen-Buttons. Sie werden über wp_mail() verschickt, respektieren also Ihre SMTP-Konfiguration und die üblichen WordPress-Filter.

E-MailEmpfängerAuslöser
Bestätigung der AnfrageKundeOnline-Buchung, wenn die doppelte Bestätigung aktiv ist
Anfrage eingegangenKundeAnfrage bestätigt, wartet auf Ihre Entscheidung
Termin bestätigtKundeFreigabe (manuell, automatisch, Admin-Eingabe, Verschiebung) — mit ICS-Anhang
Termin abgesagtKundeAbsage durch den Kunden, Ablehnung oder Absage durch den Admin — mit ICS-Absageanhang
ErinnerungKundeAutomatisch, 12 bis 36 h vor dem Termin
Wählen Sie das Datum Ihrer SitzungKundeErstellung einer Einladung mit E-Mail-Versand
Zu bestätigen: …AdminNeue bestätigte Anfrage in Wartestellung — mit den Buttons Bestätigen / Ablehnen
Neuer Termin: …AdminNeuer bestätigter Termin (automatische Bestätigung, Einladung)
Absage durch Kunde: …AdminDer Kunde hat selbst aus seiner E-Mail heraus abgesagt

Die Adresse für Admin-Benachrichtigungen ist die Einstellung notify_email (standardmäßig die Administrations-E-Mail der Website). E-Mails an Kunden gehen nur raus, wenn die Adresse gültig ist, und nie für eine Blockierung.

Die Bestätigungs- und Absage-E-Mails erinnern den Kunden daran, dass er online absagen kann, mit der tatsächlich konfigurierten Zahl an Vorlaufstunden.

Der ICS-Anhang

Die an die Bestätigungen angehängte .ics-Datei ist das, was aus einer E-Mail einen tatsächlich im Handy des Kunden vorhandenen Termin macht: eine Geste auf dem Anhang, und der Eintrag steht in seinem Kalender, mit eigener Erinnerung.

Die Datei entspricht RFC 5545 und enthält alles, was Kalenderprogramme (Google, Outlook, Apple) brauchen, um Aktualisierungen korrekt zu verarbeiten:

  • METHOD:REQUEST bei der Erstellung und bei jeder Zeitänderung, METHOD:CANCEL bei der Absage;
  • eine stabile UID, abgeleitet aus der Kennung des Termins und der Domain der Website — sie sorgt dafür, dass eine Änderung den bestehenden Eintrag ersetzt, statt einen zweiten anzulegen;
  • eine aufsteigende SEQUENCE, abgeleitet aus dem Datum der letzten Änderung, umgerechnet auf einen absoluten Zeitpunkt: Die Umstellung auf Winterzeit kann die Revisionsnummer nicht zurücksetzen (und die Absage addiert 1, um über einer Änderung in derselben Sekunde zu bleiben);
  • ORGANIZER (Ihre Benachrichtigungsadresse) und ATTENDEE (der Kunde);
  • DTSTART / DTEND in UTC, STATUS:CONFIRMED oder STATUS:CANCELLED;
  • Zeilenumbruch bei 75 Byte, ohne je ein UTF-8-Zeichen zu zerschneiden.

Das Verschieben eines bestätigten Termins verschickt also eine neue Datei, die den beim Kunden bereits vorhandenen Eintrag korrigiert; eine Absage verschickt eine Datei, die ihn löscht. Das ist eine Korrektur aus 1.3.0: Bisher blieb die alte Uhrzeit im Kalender des Kunden stehen.

Die Datei wird über die Datei-API von WordPress in das temporäre Verzeichnis des Servers geschrieben — nie in wp-content/uploads/, das öffentlich ausgeliefert wird — und sofort nach Abschluss des Versands gelöscht, auch wenn der Versand fehlschlägt. Sie enthält Name und E-Mail-Adresse des Kunden: Sie hat auf der Platte keine Sekunde länger zu suchen als nötig.


Erinnerungen und geplante Aufgabe

Eine einzige geplante Aufgabe, owag_hourly_event, stündlich ausgeführt. Sie erledigt drei Dinge.

1. Die Erinnerung am Vortag

Die Erinnerung geht raus, wenn der Termin in 12 bis 36 Stunden beginnt. Das ist kein festes Zeitfenster, und das ist Absicht: WP-Cron wird nur beim Aufruf einer Seite ausgelöst. Eine Website ohne Abendtraffic verlor die Erinnerungen für den Folgetag endgültig. Mit einem gleitenden Fenster geht die Erinnerung bei der ersten verfügbaren Ausführung raus und holt den Rückstand auf.

Bedingungen: Termin bestätigt, E-Mail-Adresse hinterlegt, keine Blockierung, und die Erinnerung wurde noch nicht verschickt.

Jede Erinnerung wird vor dem Versand atomar reserviert (ein bedingtes UPDATE auf das Flag reminder_sent): Zwei sich überlappende Cron-Läufe können dieselbe Nachricht nicht zweimal verschicken. Schlägt der Versand fehl, wird die Reservierung zurückgegeben und die Erinnerung beim nächsten Lauf erneut versucht. Eine kurze Sperre (10 Minuten) verhindert zusätzlich, dass zwei gleichzeitige Durchläufe dieselbe Liste abarbeiten.

Das Verschieben eines Termins setzt das Flag zurück: Der Kunde erhält für die neue Uhrzeit sehr wohl eine Erinnerung.

2. Die Bereinigung nicht bestätigter Anfragen

Anfragen, die länger als 48 Stunden unverified geblieben sind, werden gelöscht. (Ihr Zeitfenster war bereits nach 45 Minuten wieder verfügbar.)

3. Die DSGVO-Anonymisierung

Siehe den Abschnitt DSGVO.

Das Sicherheitsnetz

Ein WP-Cron-Ereignis kann verschwinden: Datenbankoptimierung, teilweise Wiederherstellung, Bereinigungs-Plugin, Zurücksetzen der Option cron. OW Agenda prüft bei jedem Seitenaufruf, ob die Aufgabe geplant ist, und plant sie andernfalls neu. Erinnerungen, Bereinigung und Aufbewahrung können nicht stillschweigend aussetzen.

Einen echten System-Cron verwenden

WP-Cron hängt vom Traffic ab. Auf einer wenig besuchten Website ist ein System-Cron vorzuziehen:

// 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 und Ratenbegrenzung

Die Buchung ist ihrer Natur nach öffentlich: kein Konto, kein Login, kein Nonce möglich. Fünf unabhängige Schutzmechanismen arbeiten deshalb vorgelagert.

1. Die Bot-Falle (Honeypot)

Das Formular enthält ein Textfeld außerhalb des Sichtbereichs, für Menschen unsichtbar und für einen Bot verlockend. Das Feld muss vorhanden und leer sein. Ein ausgefülltes Feld — oder ein fehlendes, was einen direkten Aufruf der API verrät — führt zu einer trockenen Ablehnung (HTTP 403), ohne verwertbares Detail.

2. Die Ausfüllzeit

Die Seite überträgt den Zeitstempel ihrer Anzeige. Eine Übermittlung, die weniger als 4 Sekunden nach dem Laden eintrifft, wird abgelehnt. Auch hier gilt: Ein fehlender oder fehlerhafter Zeitstempel ist eine Ablehnung. In 1.3.0 wurden diese beiden Felder zur Pflicht — sie wegzulassen deaktivierte die Prüfung schlicht und einfach.

3. Das Stundenkontingent pro Adresse

5 Buchungen pro Stunde und Geltungsbereich. Bei IPv4 ist der Geltungsbereich die Adresse; bei IPv6 das /64-Präfix — dort verfügt ein Angreifer über 2⁶⁴ Adressen, die vollständige Adresse zu zählen würde nichts begrenzen.

Der Zähler wird erst nach der Validierung des Formulars erhöht: Ein Besucher, der sich dreimal hintereinander bei seiner E-Mail-Adresse vertippt, ist nicht mehr grundlos eine Stunde lang gesperrt.

4. Die Tagesobergrenze für nicht bestätigte Anfragen

Höchstens 3 auf ihre E-Mail-Bestätigung wartende Anfragen dürfen an ein und demselben Tag ein Zeitfenster halten. Ohne diese Obergrenze genügten ein paar Übermittlungen, um alle Zeitfenster eines Datums einzufrieren. Darüber hinaus wird der Besucher gebeten, später erneut zu versuchen oder einen anderen Tag zu wählen (HTTP 429).

5. Die Buchungssperre

Die Buchung eines Zeitfensters und das Einlösen einer Einladung laufen in einem kritischen Abschnitt ab, der über eine benannte MySQL-Sperre serialisiert wird; ihr Name wird aus Ihrer Datenbank und Ihrem Tabellenpräfix abgeleitet (zwei Websites auf demselben Shared Hosting blockieren sich also nicht gegenseitig). Wird die Sperre nicht binnen 5 Sekunden erlangt, liefert die Anfrage einen expliziten HTTP 503 statt eines Doppeltermins.

Diese Sperre ersetzt seit 1.3.0 eine Transaktion, die auf einem nackten SELECT beruhte: Unter REPEATABLE READ setzt er keinerlei Zeilensperre, und zwei gleichzeitige Besucher konnten dieselbe Uhrzeit buchen.

Und die doppelte Bestätigung

Das ist die wirksamste Schicht: Selbst wenn ein Bot alles Vorherige überwindet, erreicht er weder Ihren Kalender noch Ihr Postfach, denn die Admin-Benachrichtigung geht erst nach dem Klick auf einen per E-Mail erhaltenen Link raus. Siehe Die doppelte Bestätigung per E-Mail.


DSGVO

Ein Terminkalender verarbeitet potenzielle Gesundheitsdaten, Kontaktdaten und Vorgeschichten. Die Standardeinstellungen sind bewusst konservativ.

Einwilligung

Das Einwilligungsfeld ist im öffentlichen Formular obligatorisch und standardmäßig nicht angehakt: „Ich bin damit einverstanden, dass meine Kontaktdaten zur Verwaltung meines Termins verwendet werden.“ Eine Buchung ohne Einwilligung wird serverseitig abgelehnt, nicht nur im Browser.

Datenminimierung

  • Es wird keine IP-Adresse in der Datenbank gespeichert. Das Stundenkontingent nutzt einen temporären Zähler (Transient), dessen Schlüssel ein Hash des Netzwerkbereichs ist und der nach einer Stunde verfällt.
  • Kein User Agent, kein Tracker, kein vom Plugin gesetztes Cookie.
  • Es werden keine Daten an einen Drittdienst gesendet: kein CDN, kein externer Aufruf, keine Telemetrie.
  • Nie bestätigte Anfragen werden nach 48 Stunden gelöscht — sie hinterlassen keinerlei Daten.
  • Abgesagte Termine werden von der Agenda-API nicht mehr zurückgegeben: unnötige personenbezogene Daten zirkulieren nicht.

Automatische Anonymisierung

Einstellung retention_months, standardmäßig 24 Monate. Stündlich werden beendete Termine, die länger als diese Frist zurückliegen, an Ort und Stelle anonymisiert: Der Name wird durch „Anonymisiert“ ersetzt, Telefonnummer und E-Mail-Adresse werden geleert, die Nachricht des Kunden und die internen Notizen werden gelöscht. Die Zeile bleibt bestehen, was die statistische Historie der Tätigkeit erhält (wie viele Termine, wann, für welche Leistung), ohne auch nur ein personenbezogenes Datum aufzubewahren.

Setzen Sie 0, um die automatische Anonymisierung zu deaktivieren — in Kenntnis der Folgen.

Hinweis: Die Anonymisierung zielt auf Termine mit E-Mail-Adresse. Ein von Hand eingetragener Termin ohne E-Mail (nur Name und Telefon) wird von der automatischen Bereinigung nicht erfasst; löschen Sie ihn manuell, wenn Ihre Aufbewahrungsrichtlinie das verlangt.

Auskunftsrecht und Recht auf Löschung

Das Plugin hängt sich nicht in die nativen Exporteure/Löscher von WordPress ein (diese arbeiten mit Benutzerkonten, und Kunden haben keine). So bearbeiten Sie eine Anfrage:

  • Auskunft — suchen Sie die Person im Kundenverzeichnis (Name, Telefon oder E-Mail) und gehen Sie ihre Termine im Kalender durch. Datenbankadministratoren können auch direkt {prefix}_owag_appointments und {prefix}_owag_customers über die Spalte customer_email / email abfragen.
  • Löschung — löschen Sie den Eintrag im Verzeichnis und sagen Sie die betroffenen Termine ab oder lassen Sie sie anonymisieren. Eine sofortige Löschung erfolgt in der Datenbank über 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';

Verzeichnis von Verarbeitungstätigkeiten

Für Ihr Verzeichnis: Zweck Terminverwaltung; Rechtsgrundlage Einwilligung (Online-Buchung) oder Vertragserfüllung / vorvertragliche Maßnahmen (telefonisch vereinbarter Termin); Kategorien Identität, Kontaktdaten, Inhalt der Nachricht, interne Notizen; Dauer standardmäßig 24 Monate, danach Anonymisierung; Empfänger kein Auftragsverarbeiter außer Ihrem Hoster und Ihrem E-Mail-Versanddienst.


Shortcodes

[ow_agenda] — die Buchung für Besucher

Auf einer öffentlichen Seite platzieren. Kein Attribut: Leistung, Dauer und Zeiten kommen aus den Einstellungen. Der Shortcode lädt sein Stylesheet und sein Skript (zusammen weniger als 12 KB, ohne Abhängigkeiten) und rendert einen Container, der sich nach dem ersten API-Aufruf füllt.

[ow_agenda]

Dieser Shortcode wertet den URL-Parameter ?owag_invite=<token> aus: Dieselbe Seite bedient die Standardkonsultation und die Sitzungen auf Einladung.

[ow_agenda_admin] — die Verwaltungsseite

Auf einer eigenen Seite platzieren. Kein Attribut. Der Shortcode regelt den Zugriff selbst:

  • nicht angemeldeter Besucher → Login-Link, der auf die Seite zurückführt;
  • angemeldet ohne die Berechtigung owag_manage → Meldung über eingeschränkten Zugriff;
  • angemeldet mit der Berechtigung → die vollständige Oberfläche (Agenda, offene Anfragen, Kunden, Einladungen).
[ow_agenda_admin]

Beide Seiten werden bei der Aktivierung automatisch mit diesen Shortcodes angelegt. Haben Sie sie gelöscht, genügt es, eine Seite zu erstellen und den Shortcode einzufügen — denken Sie dann daran, die Option owag_page_admin (bzw. owag_page_booking) zu aktualisieren, damit die Links in den E-Mails und das Manifest an die richtige Stelle zeigen.

Die eigenständigen Seiten

Vier URL-Parameter, die auf jeder beliebigen Seite der Website abgefangen werden, erzeugen eigenständige Seiten, die außerhalb des Themes ausgeliefert werden (minimales Rendering, noindex,nofollow):

URLZweck
?owag_verify=<uid>Bestätigung der Anfrage durch den Kunden (Double-Opt-in)
?owag_cancel=<uid>Online-Absage durch den Kunden
?owag_admin_action=confirm|refuse&uid=…&sig=…Bestätigung / Ablehnung aus der Admin-E-Mail
?owag_manifest=1App-Manifest der Agenda-Seite

Diese Seiten führen beim Laden nie eine Aktion aus: Sie zeigen eine Zusammenfassung und einen Button. Kein Bot, kein E-Mail-Virenscanner, kein Browser-Prefetch kann anstelle eines Menschen einen Termin bestätigen oder absagen.


REST API

Alle Endpunkte liegen unter dem Namespace owag/v1, an der üblichen REST-Wurzel (https://example.com/wp-json/owag/v1/…).

Öffentliche Endpunkte

Keine Authentifizierung: Das sind die Routen des Buchungs-Widgets und der per E-Mail erhaltenen Links. Ihre Sicherheit beruht auf zufälligen Tokens (32 hexadezimale Zeichen aus einem kryptografischen Generator), auf HMAC-Signaturen und auf den unter Anti-Spam beschriebenen Schutzmechanismen.

MethodePfadParameterZweck
GET/public/daysfrom (Y-m-d, Standard: heute), token (Einladung, optional)Liefert label, duration und days: 14 Tage ab from, jeder mit der Zahl freier Zeitfenster
GET/public/slotsdate (Y-m-d, erforderlich), tokenLiefert slots: die freien Startzeiten (HH:MM)
POST/public/bookdate, time, name, phone, email, message, consent, website (Honeypot), ts (Zeitstempel), tokenLegt die Anfrage an; liefert status und die anzuzeigende Meldung
POST/public/verifyuidBestätigt eine Anfrage im Status unverified
POST/public/canceluidSagt einen Termin pending oder confirmed ab, im Rahmen der Vorlauffrist
POST/public/admin-actionuid, action (confirm|refuse), sigBestätigt oder lehnt aus der Admin-E-Mail heraus ab (HMAC-Signatur)

Beispiel für eine Buchung:

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é…"
}

Administrations-Endpunkte

Alle verlangen die Berechtigung owag_manage und einen gültigen WordPress-REST-Nonce (Header X-WP-Nonce).

MethodePfadParameterZweck
GET/admin/agendafrom, to (Y-m-d)events (der angefragte Zeitraum, abgesagte ausgenommen) und pending (alle kommenden offenen Anfragen)
POST/admin/appointmentkind (manual|block|consult|seance), date, time, duration (5–720 Min.), label, name, phone, email, notes, force, send_emailLegt einen manuellen Termin oder eine Blockierung an
POST/admin/appointment/{id}status (pending|confirmed|cancelled|done|noshow), name, phone, email, label, notes, date, time, duration, force, silentAktualisiert, verschiebt, ändert den Status. silent=1 unterdrückt jeden E-Mail-Versand
GET/admin/customersq (Suche)Das Verzeichnis (maximal 200 Datensätze)
POST/admin/customersname (erforderlich), phone, email, notesLegt einen Datensatz an
POST/admin/customers/{id}dieselbenAktualisiert einen Datensatz
DELETE/admin/customers/{id}Löscht einen Datensatz
GET/admin/invitesDie offenen Einladungen (nie verwendet oder freigegeben, nicht abgelaufen)
POST/admin/invitesname (erforderlich), label (erforderlich), duration (15–720), days_valid (1–365, Standard 60), email, phone, send_emailLegt eine Einladung an; liefert url und email_sent
DELETE/admin/invites/{id}Löscht eine Einladung
GET/admin/settingsDie effektiven Einstellungen
POST/admin/settingsJSON-Body (siehe Einstellungsreferenz)Speichert die Einstellungen

Jede Route deklariert ihre Zugriffskontrolle explizit; die Berechtigung wird geprüft, bevor auch nur eine Verarbeitung ausgeführt wird.

Fehlercodes

Die Fehler sind gewöhnliche WP_Error, mit einem lesbaren Code und einem HTTP-Status.

CodeHTTPBedeutung
owag_spam403Bot-Falle ausgefüllt oder Zeitstempel fehlt / zu frisch
owag_rate429Stundenkontingent für diese Adresse erreicht
owag_day_full429Zu viele auf Bestätigung wartende Anfragen an diesem Datum
owag_busy503Buchungssperre nicht erlangt — gleich erneut versuchen
owag_slot_taken409Zeitfenster zwischenzeitlich vergeben
owag_overlap409Überschneidung erkannt (Admin) — mit force erneut senden
owag_invite_invalid404Einladungstoken unbekannt
owag_invite_used410Einladung bereits eingelöst
owag_invite_expired410Einladung abgelaufen
owag_too_late403Online-Absage außerhalb der Vorlauffrist
owag_bad_sig403HMAC-Signatur ungültig
owag_not_found404Termin oder Datensatz nicht gefunden
owag_name, owag_phone, owag_email, owag_consent400Feld ungültig oder Einwilligung fehlt
owag_bad_input, owag_bad_date400Datum, Uhrzeit oder Eingabe ungültig
owag_noop400Leere Aktualisierungsanfrage
owag_insert500Schreibfehler in der Datenbank

Entwickler-Hooks

In 1.3.1 stellt OW Agenda weder Filter noch öffentliche Action bereit: Es gibt keine Erweiterungs-API zu dokumentieren, und nichts davon soll erraten werden müssen. Der einzige nutzbare Hook ist das geplante Ereignis owag_hourly_event, an das Sie Ihre eigene Wartungslogik hängen können:

add_action( 'owag_hourly_event', function () {
    // Votre traitement horaire, exécuté juste après celui du plugin.
} );

Für alles Weitere ist die REST API der Integrationspunkt: Sie stellt genau das bereit, was die Oberfläche tut, nicht mehr und nicht weniger.


Einstellungsreferenz

Alle Einstellungen liegen in einer einzigen Option, owag_settings. Lesen und Schreiben in 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,
] ) );

Standardwerte

[
    // 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',
]

Im Detail

EinstellungTypGrenzen der OberflächeWirkung
hoursArray1 oder 2 Zeiträume pro TagZwei Zeiträume erlauben die Mittagspause. Ein Zeitraum wird nur übernommen, wenn Beginn und Ende gültig sind und Beginn < Ende. Ein leerer Tag = geschlossen
slot_stepGanzzahl5 → 120 Min.Abstand der angebotenen Uhrzeiten. Je feiner, desto länger die Liste
consult_durationGanzzahl15 → 480 Min.Im Kalender für eine Online-Konsultation reservierte Dauer
bufferGanzzahl0 → 120 Min.Puffer, der beiderseits des Kandidaten-Zeitfensters angewandt wird
min_notice_hoursGanzzahl0 → 168 hVor jetzt + diese Frist wird nichts angeboten
max_advance_daysGanzzahl7 → 365 T.Horizont, jenseits dessen kein Zeitfenster mehr angeboten wird
auto_confirm0 / 1Manuelle Freigabe oder sofortige Bestätigung
email_verify0 / 1Double-Opt-in per E-Mail (aktiv lassen)
cancel_notice_hoursGanzzahl0 → 168 hDarüber hinaus wird die Online-Absage mit dem Hinweis abgelehnt, anzurufen
notify_emailE-MailEmpfänger der Admin-Benachrichtigungen; dient auch als ORGANIZER in den ICS-Dateien
retention_monthsGanzzahl0 → 120 MonateAnonymisierung beendeter Termine; 0 deaktiviert
consult_labelTextTitel, der im Buchungs-Widget angezeigt wird

Zwei nicht konfigurierbare Konstanten sollte man kennen, weil sie das Verhalten des Double-Opt-in bestimmen: Das Zeitfenster einer nicht bestätigten Anfrage wird 45 Minuten gehalten, und die Anfrage wird nach 48 Stunden gelöscht.

Das Speichern über die REST API akzeptiert dieselben Schlüssel als JSON; Ganzzahlen werden auf mindestens null gesetzt, die Benachrichtigungsadresse wird nur akzeptiert, wenn sie gültig ist, und jeder Zeitraum wird serverseitig erneut validiert.


Gespeicherte Daten

Drei Tabellen, alle mit dem Präfix Ihrer Installation. Die Zeitangaben sind DATETIME in Ortszeit der Website, nie in UTC — das macht die Abfragen lesbar und Zeitvergleiche trivial.

{prefix}_owag_appointments

SpalteTypAnmerkungen
idBIGINTPrimärschlüssel
uidCHAR(32)Eindeutiges öffentliches Token (hexadezimal, kryptografischer Generator). Dient als Schlüssel für die Links zur Bestätigung, Absage und Admin-Aktion sowie als ICS-UID
kindVARCHAR(16)consult, seance, manual, block
service_labelVARCHAR(120)Angezeigte Bezeichnung
customer_name, customer_phone, customer_emailVARCHARKontaktdaten
customer_msgTEXTVom Kunden hinterlassene Nachricht
admin_notesTEXTInterne Notizen, nie an den Kunden gesendet
start_dt, end_dtDATETIMEGrenzen des Zeitfensters (Index auf start_dt)
statusVARCHAR(16)unverified, pending, confirmed, cancelled, done, noshow
sourceVARCHAR(16)web, invite, admin
invite_idBIGINTUrsprüngliche Einladung, sofern vorhanden
reminder_sentTINYINTErinnerungs-Flag (beim Verschieben auf 0 zurückgesetzt)
created_at, updated_atDATETIMEupdated_at speist die ICS-Revisionsnummer

{prefix}_owag_invites

id, token (CHAR(32), eindeutig), Kontaktdaten des Kunden, service_label, duration_min, expires_at, appointment_id (gesetzt, wenn der Link eingelöst wird, wieder auf NULL gesetzt, wenn der Termin abgesagt wird), created_at.

{prefix}_owag_customers

id, name, phone, email, notes, created_at, updated_at. Index auf name und email.

Eine einzige Option trägt die Konfiguration (owag_settings); die übrigen sind technisch: owag_admin_secret (HMAC-Secret), owag_db_version, owag_pages_created, owag_page_booking, owag_page_admin.


Internationalisierung

Die gesamte Oberfläche ist übersetzbar: Administrationseinstellungen, Buchungs-Widget, Agenda-Seite, eigenständige Seiten, API-Meldungen und E-Mail-Vorlagen. Die Ausgangssprache ist Englisch; das Plugin deklariert die Textdomain ow-agenda und den Pfad /languages.

Das Paket liefert die Vorlage languages/ow-agenda.pot. Eine vollständige französische Übersetzung ist vorhanden, erstellt aus der Originalformulierung der Oberfläche.

Eine Übersetzung manuell installieren

Kompilieren Sie die .po-Datei und legen Sie die .mo-Datei im Übersetzungsordner von WordPress ab:

msgfmt ow-agenda-fr_FR.po -o ow-agenda-fr_FR.mo
# puis : wp-content/languages/plugins/ow-agenda-fr_FR.mo

WordPress lädt den Katalog bei der ersten übersetzten Zeichenkette; ein manueller Aufruf ist nicht nötig.

Zwei Fallstricke für Übersetzer

  • Die für JavaScript bestimmten Zeichenketten verwenden nummerierte Platzhalter (%1$s, %2$s) und nie ein nacktes %s: Der kleine Formatierer in den Skripten versteht nur diese. Ein nicht nummerierter Platzhalter würde wörtlich angezeigt.
  • Zwei Zeichenketten sind PHP-Datumsformate, keine Sätze: l, F j, Y \a\t g:i a und l j F Y \a\t H:i. Übersetzen Sie sie als Formate (Tokens umstellen, wörtliche Buchstaben mit einem Backslash maskieren). Im Französischen lautet das Format l j F Y \à H\hi.

Deinstallation

Das Deaktivieren des Plugins bewirkt genau eines: Die stündlich geplante Aufgabe wird entfernt. Ihre Daten, Ihre Einstellungen und Ihre Seiten bleiben unangetastet, und beim erneuten Aktivieren läuft alles weiter.

Das Löschen des Plugins aus WordPress heraus führt die vollständige Deinstallation aus:

  • Löschen der drei Tabellen (owag_appointments, owag_invites, owag_customers);
  • Löschen der Optionen owag_settings, owag_admin_secret, owag_db_version, owag_pages_created, owag_page_booking, owag_page_admin;
  • Entfernen der geplanten Aufgabe;
  • Entzug der Berechtigung owag_manage von der Rolle Administrator.

Die beiden bei der Aktivierung erstellten Seiten werden nicht gelöscht — sie können überarbeitet, in ein Menü gehängt oder indexiert worden sein. Verschieben Sie sie selbst in den Papierkorb, wenn Sie sie nicht mehr wollen.

Das Löschen der Tabellen ist endgültig. Exportieren Sie vorher Ihre Datenbank, wenn die Terminhistorie für Sie einen Wert hat.


Fehlerbehebung

Auf der Buchungsseite erscheint kein Zeitfenster

Gehen Sie die Liste der Reihe nach durch:

  1. Sind die Öffnungszeiten des Tages eingetragen? Ein leerer Tag ist ein geschlossener Tag.
  2. Die Mindestvorlaufzeit (standardmäßig 24 h) blendet zwangsläufig heute und einen Teil von morgen aus.
  3. Passt die Dauer in den Zeitraum? Bei einem Zeitraum 09:00–12:00 und einer Dauer von 240 Minuten kann kein Zeitfenster existieren.
  4. Der Horizont: Tage jenseits von max_advance_days werden nie angeboten.
  5. Der Puffer: Ein großzügiger Puffer kann bei vollem Terminplan alles schließen.
  6. Eine Blockierung deckt womöglich den Tag ab. Öffnen Sie die Agenda-Seite am betreffenden Tag.
  7. Die Zeitzone der Website (Einstellungen → Allgemein): Eine falsch gesetzte Zeitzone verschiebt alle Berechnungen.

Die E-Mails kommen nicht an

Das liegt fast immer an der Zustellbarkeit, nicht am Plugin.

  1. Prüfen Sie, ob der Termin auf der Agenda-Seite tatsächlich existiert: Wenn ja, hat das Plugin seine Arbeit getan.
  2. Installieren Sie ein SMTP-Plugin (Fluent SMTP, WP Mail SMTP …). Die PHP-Funktion mail() wird von der überwiegenden Mehrheit der empfangenden Server abgelehnt.
  3. Prüfen Sie SPF, DKIM und DMARC Ihrer Domain.
  4. Testen Sie die Adresse unter OW Agenda → Admin-Benachrichtigungen senden an: Eine ungültige Adresse blockiert die Benachrichtigungen stillschweigend.

Die Erinnerung am Vortag ist nicht rausgegangen

Die Erinnerung hängt von WP-Cron ab, und das hängt vom Traffic ab. Stellen Sie bei einer wenig besuchten Website auf einen echten System-Cron um (siehe Erinnerungen und geplante Aufgabe). Prüfen Sie außerdem, ob der Termin tatsächlich bestätigt ist, ob er eine E-Mail-Adresse trägt und ob es sich nicht um eine Blockierung handelt.

Die Agenda-Seite zeigt „Der Zugriff ist dem Team vorbehalten“

Dem angemeldeten Nutzer fehlt die Berechtigung owag_manage. Sie wird Administratoren bei der Aktivierung erteilt; für andere Rollen siehe Installation.

Der Button „Bestätigen“ in der E-Mail zeigt „Ungültiger Link“

Drei mögliche Ursachen: Der Link wurde vom E-Mail-Programm abgeschnitten (versuchen Sie, die vollständige URL zu kopieren), der Termin wurde bereits bearbeitet (die Meldung sagt es ausdrücklich), oder das HMAC-Secret der Website wurde neu erzeugt. Im letzten Fall nutzen Sie die Agenda-Seite: Die alten Links können konstruktionsbedingt nicht mehr eingelöst werden.

Zwei Termine landen auf demselben Zeitfenster

Seit 1.3.0 ist das über die Online-Buchung unmöglich. Allerdings kann der Admin von der Agenda-Seite aus eine Überschneidung erzwingen (das Plugin weist darauf hin und fragt nach): Prüfen Sie zuerst, ob es sich nicht um ein absichtliches Erzwingen handelt. Prüfen Sie außerdem, ob Ihre Datenbank GET_LOCK() unterstützt — ein exotisches Hosting würde bei der Buchung dann 503-Fehler liefern statt Duplikate.

Die Seiten „Termin buchen“ und „Agenda“ wurden nicht erstellt

Sie werden nur ein einziges Mal erstellt, bei der allerersten Aktivierung. Haben Sie sie gelöscht, erstellen Sie zwei Seiten mit den Shortcodes [ow_agenda] und [ow_agenda_admin] und richten Sie danach die Optionen owag_page_booking und owag_page_admin darauf aus, damit die Links in den E-Mails korrekt bleiben:

update_option( 'owag_page_booking', 42 );  // ID de votre page de réservation
update_option( 'owag_page_admin', 43 );    // ID de votre page Agenda

Die Kalenderdatei ist nicht angehängt

Die Datei wird über die Datei-API von WordPress in das temporäre Verzeichnis des Servers geschrieben. Ist dieses Verzeichnis nicht beschreibbar (Kontingent, Rechte, abgeschottetes Hosting), geht die E-Mail ohne Anhang raus, statt fehlzuschlagen. Prüfen Sie die Schreibrechte und den freien Speicherplatz.

Die Zeiten sind um eine Stunde verschoben

Einstellungen → Allgemein → Zeitzone. Wählen Sie eine Stadt (Europe/Brussels) statt eines festen UTC-Versatzes: Nur eine benannte Zeitzone beherrscht die Umstellung auf Sommerzeit.


FAQ

Ist OW Agenda wirklich kostenlos? Ja. GPL-2.0-or-later, als .zip herunterladbar von https://optionweb.dev/de/addons/ow-agenda/. Keine Pro-Version, kein Lizenzschlüssel, keine gesperrte Funktion, kein anzulegendes Konto, kein Terminkontingent.

Berücksichtigen die Online-Zeitfenster telefonisch vereinbarte Termine? Ja. Jeder Eintrag im Kalender — Online-Buchung, von Hand eingetragener Termin, Sitzung auf Einladung, Blockierung — macht seinen Zeitraum für die Online-Buchung unverfügbar.

Muss der Kunde ein Konto anlegen? Nein. Kein Konto, kein Passwort. Alle Aktionen des Kunden (Bestätigung, Absage) laufen über private Links, die er per E-Mail erhält.

Lassen sich mehrere Behandler oder mehrere Räume verwalten? Nein. OW Agenda bildet einen einzigen Terminplan ab. Für zwei unabhängige Kalender braucht es zwei Websites (oder zwei Websites eines Multisite-Netzwerks).

Synchronisiert es sich mit Google Kalender? In dem Sinn, der für den Kunden zählt: ja. Jede Bestätigung führt eine Standard-Kalenderdatei mit, die den Eintrag in Google Kalender, Outlook oder dem iPhone-Kalender anlegt — und aktualisiert und löscht. Umgekehrt liest das Plugin Ihre externen Kalender nicht: Ihre eigenen Abwesenheiten tragen Sie als Blockierungen ein.

Kann man bei der Buchung eine Anzahlung verlangen? Nein, das liegt bewusst außerhalb des Funktionsumfangs des Plugins.

Wie viele Leistungen lassen sich online anbieten? Genau eine, deren Bezeichnung und Dauer Sie wählen. Die übrigen Leistungen laufen über die Sitzungseinladungen, bei denen Sie Bezeichnung und Dauer von Fall zu Fall festlegen. Diese Entscheidung ist bewusst getroffen: Ein Leistungsmenü auf einer öffentlichen Seite vervielfacht die schlecht adressierten Anfragen.

Funktioniert es auf einer Multisite? Ja. Jede Website des Netzwerks hat ihre eigenen Tabellen, ihre eigenen Einstellungen und ihren eigenen Kalender.

Bremst das Plugin die Website aus? Nein. Außerhalb der beiden betroffenen Seiten wird kein Skript geladen; das Buchungs-Widget wiegt weniger als 12 KB, ohne jQuery und ohne Framework. Die periodische Arbeit passt in eine stündliche Aufgabe.

Was passiert, wenn ein Kunde seine E-Mail nie bestätigt? Sein Zeitfenster wird nach 45 Minuten wieder freigegeben und seine Anfrage nach 48 Stunden gelöscht. Sie erfahren davon nie etwas.

Wo ist der Support?


Changelog

1.3.1

Konformität

  • Die eigenständigen Seiten für Aktion, Bestätigung und Absage geben ihr CSS und ihr JavaScript nicht mehr inline aus: Beides sind jetzt registrierte Dateien, die über die Enqueue-API von WordPress ausgeliefert werden. Die beiden variablen Buttonfarben laufen über benutzerdefinierte CSS-Eigenschaften, und das Skript wird über wp_localize_script() konfiguriert.
  • Die Übersetzungskataloge sind nicht mehr mitgeliefert: Ausgeliefert wird nur noch languages/ow-agenda.pot, das Französische wird über die WordPress.org-Sprachpakete verteilt, die von translate.wordpress.org gespeist werden.
  • Die WordPress-Mindestversion geht zurück auf 6.3: Nichts im Paket hängt mehr von der in 6.7 eingeführten Erkennung mitgelieferter Übersetzungen ab.

REST API

  • Jede Administrationsroute deklariert ihren permission_callback nun explizit, statt ihn über array_merge() zu teilen. Die Berechtigungsprüfung wurde bereits angewandt; jetzt ist sie für die statische Analyse sichtbar.

Keine Verhaltensänderung.

1.3.0

Internationalisierung

  • Plugin vollständig übersetzbar (Textdomain ow-agenda, Englisch als Ausgangssprache): Einstellungen, öffentliche Seiten, API-Meldungen, E-Mails und JavaScript-Oberfläche.
  • Vorlage languages/ow-agenda.pot mitgeliefert und vollständige französische Übersetzung.

Sicherheit

  • Die öffentlichen Kennungen der Termine und die Einladungstokens werden von einem kryptografischen Generator erzeugt (random_bytes()). Diese Tokens sind die einzige Authentifizierung der Absage-, Bestätigungs- und Einladungslinks.
  • Bot-Falle und Zeitstempel sind zur Pflicht geworden: Sie wegzulassen deaktivierte die Anti-Spam-Prüfungen.
  • Das Stundenkontingent wird bei IPv6 nach /64-Präfix zusammengefasst, und eine Tagesobergrenze begrenzt die nicht bestätigten Anfragen — ein Besucher kann nicht mehr alle Zeitfenster eines Tages halten.
  • Das Kontingent wird erst nach der Validierung des Formulars abgezogen: Ein Tippfehler sperrt einen legitimen Besucher nicht mehr eine Stunde lang.

Zuverlässigkeit

  • Gleichzeitige Buchungen desselben Zeitfensters werden über eine benannte MySQL-Sperre serialisiert. Die vorherige Transaktion setzte keinerlei Zeilensperre: Zwei Besucher konnten dieselbe Uhrzeit buchen.
  • Die Erinnerung am Vortag nutzt ein gleitendes Fenster von 12 bis 36 h und holt ihren Rückstand auf; jeder Versand wird atomar reserviert, zwei Cron-Läufe können dieselbe Erinnerung nicht mehr zweimal verschicken.
  • Die stündliche Aufgabe plant sich automatisch neu, falls sie verschwindet: Erinnerungen, Bereinigung und Anonymisierung können nicht mehr stillschweigend aussetzen.
  • Das Verschieben eines Termins aktualisiert den Kalender des Kunden (SEQUENCE, METHOD:REQUEST, Organisator und Teilnehmer); die Absage verschickt ein METHOD:CANCEL, das den Eintrag löscht.
  • Die Daten im Widget werden in Ortszeit berechnet und nicht in UTC: kein verlorener Tag mehr für Besucher östlich von UTC.
  • Die Absage eines aus einer Einladung entstandenen Termins gibt die Einladung frei, die wieder nutzbar wird.
  • Abgesagte Termine und abgelaufene nicht bestätigte Anfragen werden nicht mehr an die Agenda zurückgegeben: weniger personenbezogene Daten in den Antworten, keine Geistertermine mehr.

1.2.1

  • Plugin-Check-Konformität: Escaping der Ausgaben, Bereinigung der Eingaben, Nonce auf den Einstellungen, Readme.
  • Die Deinstallation löscht auch die Tabelle des Kundenverzeichnisses und das HMAC-Secret.

1.2.0

  • HTML-E-Mails (Kartenlayout, Akzentfarbe der Website) für alle Benachrichtigungen.
  • Buttons Bestätigen / Ablehnen in der Admin-E-Mail (HMAC-signierte Links).
  • Kundenverzeichnis: Suchen, Anlegen, Bearbeiten, Löschen, Kurzbefehle zu einem neuen Termin und zu einer Einladung.

1.1.0

  • Doppelte Bestätigung per E-Mail gegen Bots (Zeitfenster 45 Minuten gehalten, Bereinigung nach 48 Stunden).

1.0.0

  • Erstversion: Online-Buchung, Mobile-first-Verwaltungskalender, Sitzungseinladungen, E-Mails mit Kalenderdatei und Erinnerung am Vortag.

Entwickelt von OptionWeb — Julien Daniel, Châtelet, Belgien.