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
- Überblick
- Installation
- Schnellstart
- Der Buchungsablauf
- Die doppelte Bestätigung per E-Mail
- Die Freigabe der Anfragen
- Die Agenda-Seite
- Das Kundenverzeichnis
- Die Sitzungseinladungen
- E-Mails und Kalenderdatei (ICS)
- Erinnerungen und geplante Aufgabe
- Anti-Spam und Ratenbegrenzung
- DSGVO
- Shortcodes
- REST API
- Einstellungsreferenz
- Gespeicherte Daten
- Internationalisierung
- Deinstallation
- Fehlerbehebung
- FAQ
- 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
- Laden Sie
ow-agenda-1.3.1.zipherunter von https://optionweb.dev/de/addons/ow-agenda/ - Plugins → Installieren → Plugin hochladen
- 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:
| Tabelle | Inhalt |
|---|---|
{prefix}_owag_appointments | Alle Einträge des Kalenders: Online-Konsultationen, Sitzungen aus einer Einladung, von Hand eingetragene Termine, geblockte Zeitfenster |
{prefix}_owag_invites | Die privaten Links „Wählen Sie das Datum Ihrer Sitzung“ |
{prefix}_owag_customers | Das 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_managezur Rolle Administrator — sie, und nichtmanage_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:
- Es fällt in einen Öffnungszeitraum des betreffenden Tages;
- der gesamte Termin (Beginn + Dauer) passt vor den Feierabend;
- er beginnt nach jetzt + Mindestvorlaufzeit;
- der Tag liegt innerhalb des Buchungshorizonts;
- 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:
| Konfiguration | Erzeugter Status | Angezeigte 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 Freigabe | pending | „Ihre Anfrage ist eingegangen!“ |
| Bestätigung deaktiviert + automatische Bestätigung | confirmed | „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):
- Die Anfrage wird mit dem Status
unverifiedgespeichert. Der Administrator wird nicht benachrichtigt. Der Termin erscheint nicht als zu bearbeitende Anfrage. - Der Besucher erhält eine E-Mail „Nur noch ein Schritt …“ mit einem Bestätigungsbutton.
- 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.
- 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. - Die Anfrage wird dann
pending(manuelle Freigabe) oderconfirmed(automatische Bestätigung), der Kunde erhält die entsprechende E-Mail, und erst dann geht die Admin-Benachrichtigung raus. - 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:
- 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_secretlö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:
- 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.
- Wählen Sie die Gültigkeit des Links: standardmäßig 60 Tage, von 1 bis 365.
- 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.
- 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
confirmedangelegt, 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.
| Empfänger | Auslöser | |
|---|---|---|
| Bestätigung der Anfrage | Kunde | Online-Buchung, wenn die doppelte Bestätigung aktiv ist |
| Anfrage eingegangen | Kunde | Anfrage bestätigt, wartet auf Ihre Entscheidung |
| Termin bestätigt | Kunde | Freigabe (manuell, automatisch, Admin-Eingabe, Verschiebung) — mit ICS-Anhang |
| Termin abgesagt | Kunde | Absage durch den Kunden, Ablehnung oder Absage durch den Admin — mit ICS-Absageanhang |
| Erinnerung | Kunde | Automatisch, 12 bis 36 h vor dem Termin |
| Wählen Sie das Datum Ihrer Sitzung | Kunde | Erstellung einer Einladung mit E-Mail-Versand |
| Zu bestätigen: … | Admin | Neue bestätigte Anfrage in Wartestellung — mit den Buttons Bestätigen / Ablehnen |
| Neuer Termin: … | Admin | Neuer bestätigter Termin (automatische Bestätigung, Einladung) |
| Absage durch Kunde: … | Admin | Der 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:REQUESTbei der Erstellung und bei jeder Zeitänderung,METHOD:CANCELbei 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) undATTENDEE(der Kunde);DTSTART/DTENDin UTC,STATUS:CONFIRMEDoderSTATUS: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_appointmentsund{prefix}_owag_customersüber die Spaltecustomer_email/emailabfragen. - 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):
| URL | Zweck |
|---|---|
?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=1 | App-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.
| Methode | Pfad | Parameter | Zweck |
|---|---|---|---|
GET | /public/days | from (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/slots | date (Y-m-d, erforderlich), token | Liefert slots: die freien Startzeiten (HH:MM) |
POST | /public/book | date, time, name, phone, email, message, consent, website (Honeypot), ts (Zeitstempel), token | Legt die Anfrage an; liefert status und die anzuzeigende Meldung |
POST | /public/verify | uid | Bestätigt eine Anfrage im Status unverified |
POST | /public/cancel | uid | Sagt einen Termin pending oder confirmed ab, im Rahmen der Vorlauffrist |
POST | /public/admin-action | uid, action (confirm|refuse), sig | Bestä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).
| Methode | Pfad | Parameter | Zweck |
|---|---|---|---|
GET | /admin/agenda | from, to (Y-m-d) | events (der angefragte Zeitraum, abgesagte ausgenommen) und pending (alle kommenden offenen Anfragen) |
POST | /admin/appointment | kind (manual|block|consult|seance), date, time, duration (5–720 Min.), label, name, phone, email, notes, force, send_email | Legt 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, silent | Aktualisiert, verschiebt, ändert den Status. silent=1 unterdrückt jeden E-Mail-Versand |
GET | /admin/customers | q (Suche) | Das Verzeichnis (maximal 200 Datensätze) |
POST | /admin/customers | name (erforderlich), phone, email, notes | Legt einen Datensatz an |
POST | /admin/customers/{id} | dieselben | Aktualisiert einen Datensatz |
DELETE | /admin/customers/{id} | — | Löscht einen Datensatz |
GET | /admin/invites | — | Die offenen Einladungen (nie verwendet oder freigegeben, nicht abgelaufen) |
POST | /admin/invites | name (erforderlich), label (erforderlich), duration (15–720), days_valid (1–365, Standard 60), email, phone, send_email | Legt eine Einladung an; liefert url und email_sent |
DELETE | /admin/invites/{id} | — | Löscht eine Einladung |
GET | /admin/settings | — | Die effektiven Einstellungen |
POST | /admin/settings | JSON-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.
| Code | HTTP | Bedeutung |
|---|---|---|
owag_spam | 403 | Bot-Falle ausgefüllt oder Zeitstempel fehlt / zu frisch |
owag_rate | 429 | Stundenkontingent für diese Adresse erreicht |
owag_day_full | 429 | Zu viele auf Bestätigung wartende Anfragen an diesem Datum |
owag_busy | 503 | Buchungssperre nicht erlangt — gleich erneut versuchen |
owag_slot_taken | 409 | Zeitfenster zwischenzeitlich vergeben |
owag_overlap | 409 | Überschneidung erkannt (Admin) — mit force erneut senden |
owag_invite_invalid | 404 | Einladungstoken unbekannt |
owag_invite_used | 410 | Einladung bereits eingelöst |
owag_invite_expired | 410 | Einladung abgelaufen |
owag_too_late | 403 | Online-Absage außerhalb der Vorlauffrist |
owag_bad_sig | 403 | HMAC-Signatur ungültig |
owag_not_found | 404 | Termin oder Datensatz nicht gefunden |
owag_name, owag_phone, owag_email, owag_consent | 400 | Feld ungültig oder Einwilligung fehlt |
owag_bad_input, owag_bad_date | 400 | Datum, Uhrzeit oder Eingabe ungültig |
owag_noop | 400 | Leere Aktualisierungsanfrage |
owag_insert | 500 | Schreibfehler 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
| Einstellung | Typ | Grenzen der Oberfläche | Wirkung |
|---|---|---|---|
hours | Array | 1 oder 2 Zeiträume pro Tag | Zwei 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_step | Ganzzahl | 5 → 120 Min. | Abstand der angebotenen Uhrzeiten. Je feiner, desto länger die Liste |
consult_duration | Ganzzahl | 15 → 480 Min. | Im Kalender für eine Online-Konsultation reservierte Dauer |
buffer | Ganzzahl | 0 → 120 Min. | Puffer, der beiderseits des Kandidaten-Zeitfensters angewandt wird |
min_notice_hours | Ganzzahl | 0 → 168 h | Vor jetzt + diese Frist wird nichts angeboten |
max_advance_days | Ganzzahl | 7 → 365 T. | Horizont, jenseits dessen kein Zeitfenster mehr angeboten wird |
auto_confirm | 0 / 1 | — | Manuelle Freigabe oder sofortige Bestätigung |
email_verify | 0 / 1 | — | Double-Opt-in per E-Mail (aktiv lassen) |
cancel_notice_hours | Ganzzahl | 0 → 168 h | Darüber hinaus wird die Online-Absage mit dem Hinweis abgelehnt, anzurufen |
notify_email | — | Empfänger der Admin-Benachrichtigungen; dient auch als ORGANIZER in den ICS-Dateien | |
retention_months | Ganzzahl | 0 → 120 Monate | Anonymisierung beendeter Termine; 0 deaktiviert |
consult_label | Text | — | Titel, 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
| Spalte | Typ | Anmerkungen |
|---|---|---|
id | BIGINT | Primärschlüssel |
uid | CHAR(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 |
kind | VARCHAR(16) | consult, seance, manual, block |
service_label | VARCHAR(120) | Angezeigte Bezeichnung |
customer_name, customer_phone, customer_email | VARCHAR | Kontaktdaten |
customer_msg | TEXT | Vom Kunden hinterlassene Nachricht |
admin_notes | TEXT | Interne Notizen, nie an den Kunden gesendet |
start_dt, end_dt | DATETIME | Grenzen des Zeitfensters (Index auf start_dt) |
status | VARCHAR(16) | unverified, pending, confirmed, cancelled, done, noshow |
source | VARCHAR(16) | web, invite, admin |
invite_id | BIGINT | Ursprüngliche Einladung, sofern vorhanden |
reminder_sent | TINYINT | Erinnerungs-Flag (beim Verschieben auf 0 zurückgesetzt) |
created_at, updated_at | DATETIME | updated_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 aundl 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 Formatl 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_managevon 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:
- Sind die Öffnungszeiten des Tages eingetragen? Ein leerer Tag ist ein geschlossener Tag.
- Die Mindestvorlaufzeit (standardmäßig 24 h) blendet zwangsläufig heute und einen Teil von morgen aus.
- Passt die Dauer in den Zeitraum? Bei einem Zeitraum 09:00–12:00 und einer Dauer von 240 Minuten kann kein Zeitfenster existieren.
- Der Horizont: Tage jenseits von
max_advance_dayswerden nie angeboten. - Der Puffer: Ein großzügiger Puffer kann bei vollem Terminplan alles schließen.
- Eine Blockierung deckt womöglich den Tag ab. Öffnen Sie die Agenda-Seite am betreffenden Tag.
- 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.
- Prüfen Sie, ob der Termin auf der Agenda-Seite tatsächlich existiert: Wenn ja, hat das Plugin seine Arbeit getan.
- Installieren Sie ein SMTP-Plugin (Fluent SMTP, WP Mail SMTP …). Die PHP-Funktion
mail()wird von der überwiegenden Mehrheit der empfangenden Server abgelehnt. - Prüfen Sie SPF, DKIM und DMARC Ihrer Domain.
- 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?
- Support-Portal: https://optionweb.dev/de/addons/support/
- E-Mail: support@optionweb.dev
- Dokumentation: https://optionweb.dev/de/addons/ow-agenda/
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_callbacknun explizit, statt ihn überarray_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.potmitgeliefert 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 einMETHOD: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.