Live · status OK
Documentatie · OW Agenda v1.3.1

OW Agenda
Documentatie

De WordPress-afsprakenplanner die niemand je tijdsloten voor niets laat bezetten.

v1.3.1GPL-2.0-or-laterDocumentatie

OW Agenda — Documentatie

Online afspraken maken en de agenda van elke dag, in WordPress, zonder abonnement. Auteur: OptionWeb — Julien Daniel Plugin-pagina: https://optionweb.dev/nl/addons/ow-agenda/ Licentie: GPL-2.0-or-later Versie die dit document beslaat: 1.3.1


Inhoudsopgave

  1. Overzicht
  2. Installatie
  3. Snelstart
  4. Het reservatietraject
  5. De dubbele verificatie per e-mail
  6. De bevestiging van aanvragen
  7. De Agendapagina
  8. Het klantenbestand
  9. De sessie-uitnodigingen
  10. E-mails en agendabestand (ICS)
  11. Herinneringen en geplande taak
  12. Anti-spam en rate limits
  13. AVG
  14. Shortcodes
  15. REST API
  16. Instellingenreferentie
  17. Opgeslagen gegevens
  18. Internationalisatie
  19. Deïnstallatie
  20. Probleemoplossing
  21. FAQ
  22. Changelog

Overzicht

OW Agenda voegt aan WordPress een volledig afsprakensysteem toe: een publieke pagina waar de bezoeker eerst zijn dag en dan zijn uur kiest, en een met een login beveiligde pagina “Agenda”, gemaakt om vanaf een telefoon te gebruiken, waar u de dag beheert.

Alles blijft binnen de site. Geen externe dienst, geen API van derden, geen abonnement: de tijdsloten worden door uw server berekend, de afspraken leven in uw MySQL-tabellen, de e-mails vertrekken via wp_mail().

Wat er meegeleverd wordt (alles gratis, GPL-2):

  • Online reserveren: dag kiezen, tijdslot kiezen, kort formulier, AVG-toestemmingsvakje
  • Dubbele opt-in per e-mail: een aanvraag wordt pas echt na een klik op een bevestigingslink — bots raken nooit tot in de agenda
  • Handmatige bevestiging (aanbevolen) of automatische bevestiging, met de knoppen Bevestigen / Weigeren rechtstreeks in de meldingsmail (HMAC-ondertekende links, zonder in te loggen)
  • Mobile-first pagina “Agenda”: dagoverzicht, openstaande aanvragen, telefonische afspraken die u zelf toevoegt, tijdsloten blokkeren, verplaatsen, statussen gedaan / afwezig
  • Klantenbestand: zoeken, aanmaken, bewerken, verwijderen; automatisch aangevuld door de bevestigde afspraken
  • Sessie-uitnodigingen: met een privélink kiest een bestaande klant zelf de datum van zijn sessie, voor een dienst en een duur die u vastlegt
  • Verzorgde HTML-e-mails met ICS-bijlage (met één beweging in de agenda van de telefoon), automatische herinnering de dag voordien, online annulering door de klant
  • Automatische anonimisering van afgelopen afspraken, opruiming van nooit bevestigde aanvragen
  • Volledige REST API onder de namespace owag/v1

Wat hij bewust niet doet:

  • Geen online betaling: OW Agenda maakt de afspraak, hij int geen voorschot (gebruik WooCommerce als dat uw behoefte is)
  • Eén enkele agenda: geen beheer van meerdere praktijkhouders of meerdere ruimtes; de plugin beschrijft één planning, die van de site
  • Geen tweerichtingssynchronisatie met Google Agenda of Outlook: de agenda van de klant wordt bijgewerkt via een ICS-bestand (enkel heen), uw persoonlijke onbeschikbaarheden voert u in als blokkeringen
  • Geen dienstencatalogus aan bezoekerszijde: de publieke reservatie gaat over één enkele prestatie (label en duur instelbaar); de andere prestaties verlopen via de sessie-uitnodigingen
  • Geen terugkerende afspraken, geen videogesprek, geen wachtkamer

Die lijst is een architectuurkeuze, geen verborgen roadmap: een eenvoudige agenda die zich nooit van tijdslot vergist, is meer waard dan een opgeblazen systeem waar niemand aan durft te raken.


Installatie

Vanuit de .zip

  1. Download ow-agenda-1.3.1.zip van https://optionweb.dev/nl/addons/ow-agenda/
  2. Plugins → Nieuwe plugin → Plugin uploaden
  3. Kies het bestand, klik op Nu installeren en daarna op Activeren

Via FTP

Pak het archief uit en plaats de map ow-agenda in /wp-content/plugins/, activeer de plugin daarna via Plugins.

Vereisten

  • WordPress 6.3 of nieuwer
  • PHP 7.4 of nieuwer (8.1+ aanbevolen)
  • MySQL 5.7+ / MariaDB 10.2+ — de functies GET_LOCK() / RELEASE_LOCK() worden gebruikt om gelijktijdige reservaties te serialiseren
  • Werkende e-mailverzending. Dat is de enige echte afhankelijkheid van de plugin: het hele traject (verificatie, bevestiging, herinnering, annulering) verloopt via e-mail. Installeer op gedeelde hosting een SMTP-plugin voor u de agenda online zet.

Wat er geïnstalleerd wordt

Bij de activatie maakt OW Agenda drie tabellen aan:

TabelInhoud
{prefix}_owag_appointmentsAlle items in de agenda: online consultaties, sessies uit een uitnodiging, handmatig ingevoerde afspraken, geblokkeerde tijdsloten
{prefix}_owag_invitesDe privélinks “kies de datum van uw sessie”
{prefix}_owag_customersHet klantenbestand

…en, enkel de allereerste keer, twee gepubliceerde pagina’s:

  • “Een afspraak maken” — bevat de shortcode [ow_agenda]
  • “Agenda” — bevat de shortcode [ow_agenda_admin]

Hun ID’s worden bewaard in de opties owag_page_booking en owag_page_admin; de vlag owag_pages_created zorgt ervoor dat deactiveren en opnieuw activeren geen duplicaten aanmaakt. U kan die pagina’s hernoemen, in een menu zetten of hun permalink wijzigen: de plugin volgt ze op hun ID.

De activatie voegt ook toe:

  • de capability owag_manage aan de rol beheerder — die, en niet manage_options, geeft toegang tot de agenda en tot de REST-routes voor beheer;
  • de standaardinstellingen in de optie owag_settings;
  • de uurlijkse geplande taak owag_hourly_event (eerste uitvoering 5 minuten na de activatie).

Een HMAC-geheim (owag_admin_secret, 64 tekens, niet automatisch geladen) wordt aangemaakt bij de eerste beheerdersmelding: het ondertekent de knoppen Bevestigen / Weigeren in de e-mails.

Iemand anders toegang geven

De Agendapagina is zichtbaar voor elke ingelogde gebruiker die over owag_manage beschikt. Om de agenda open te stellen voor een assistente zonder haar de sleutels van de site te geven:

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

Snelstart

Ga na de activatie naar OW Agenda (hoofdmenu van het beheer). Het instellingenscherm past op één pagina; vijf minuten volstaan.

1. De openingsuren

Vul voor elke dag van de week een tijdsblok in (09:00 → 18:00) en, als u ’s middags sluit, een tweede blok (14:00 → 18:30). Een dag die u leeg laat, is een gesloten dag. Standaard: maandag tot vrijdag, 09:00–18:00; zaterdag en zondag gesloten.

De uren worden geïnterpreteerd in de tijdzone van de site (Instellingen → Algemeen → Tijdzone). Controleer die voor u de reservatie openzet: alle datums worden in lokale tijd opgeslagen.

2. De online reserveerbare prestatie

  • Label van de consultatie — wat de bezoeker als titel van de widget ziet (“Consultatie”, “Eerste afspraak”, “Doorlichting”…)
  • Duur van de consultatie — standaard 60 minuten. Het is die duur die in de agenda geblokkeerd wordt.
  • Interval van de tijdsloten — het verschil tussen twee aangeboden uren (standaard 30 minuten). Met een duur van 60 en een interval van 30 biedt u 9:00, 9:30, 10:00… aan, en de eerste afspraak om 9:30 haalt 9:00 en 10:00 uit de lijst.
  • Buffertijd tussen twee afspraken — ademruimte in minuten die aan weerszijden van elk kandidaat-tijdslot toegevoegd wordt (standaard 0).

3. De termijnen

  • Minimale reservatietermijn — standaard 24 u: een bezoeker kan niet boeken voor over een uur.
  • Reservatiehorizon — standaard 60 dagen: daarbuiten wordt niets meer aangeboden.
  • Online annulering door de klant — tot 24 u voor de afspraak; daarna vraagt de annuleringspagina om te bellen.

4. De bevestiging en de e-mails

  • Bevestiging van de aanvragen: handmatige bevestiging (aanbevolen) of automatische bevestiging.
  • Dubbele e-mailverificatie: laat dit aangevinkt. Het is de beste antibotbescherming van de plugin.
  • Beheerdersmeldingen sturen naar: uw adres. Standaard het beheerdersadres van de site.

Sla op en open dan de pagina “Een afspraak maken”: de widget toont de eerstvolgende 14 dagen en uw vrije tijdsloten. U staat online.

5. De agenda op de telefoon

Open de pagina “Agenda” op uw telefoon, log in en gebruik daarna “Toevoegen aan startscherm”. De plugin publiceert een app-manifest: de pagina opent dan schermvullend, zonder browserbalk, als een app.


Het reservatietraject

Aan bezoekerszijde is de reservatiepagina een op zichzelf staand component (JavaScript zonder framework, minder dan 10 KB) dat praat met de publieke endpoints owag/v1/public/*.

Stap 1 — de dag

Bij het laden vraagt de widget de beschikbaarheden op voor 14 dagen vanaf vandaag en toont hij een balk met aanklikbare dagen. Een dag zonder vrij tijdslot is grijs en niet aanklikbaar. De knop “Volgende data bekijken” laadt de 14 volgende dagen, zo vaak als nodig tot aan de ingestelde horizon.

De datums van de widget worden opgebouwd in lokale tijd van de browser, nooit in UTC. Dat is een correctie uit 1.3.0: voordien zag een bezoeker ten oosten van UTC die de pagina kort na middernacht opende, de lijst de dag voordien beginnen en verloor hij een dag beschikbaarheid.

Stap 2 — het uur

De klik op een dag roept /public/slots aan en toont de vrije beginuren. Een tijdslot wordt aangeboden wanneer al deze voorwaarden vervuld zijn:

  1. het valt binnen een openingsblok van de betrokken dag;
  2. de volledige afspraak (begin + duur) past voor het sluitingsuur;
  3. het begint na nu + de minimale termijn;
  4. de dag ligt binnen de reservatiehorizon;
  5. het overlapt met geen enkel actief item, buffertijd inbegrepen — en “actief item” omvat de bevestigde afspraken, de openstaande aanvragen, de blokkeringen, de handmatig ingevoerde telefonische afspraken, en de nog niet geverifieerde aanvragen die hun tijdslot nog vasthouden.

Dat is het belangrijke punt: alles wat de agenda bezet, sluit het online tijdslot af. Een afspraak die telefonisch gemaakt en in de agenda genoteerd is, verdwijnt onmiddellijk uit de tijdsloten die op de site aangeboden worden.

Stap 3 — het formulier

Vier velden, waarvan drie verplicht: naam (minstens 2 tekens), telefoon (minstens 8 cijfers), e-mail (gevalideerd), vrij bericht. Een AVG-toestemmingsvakje, standaard niet aangevinkt, is verplicht.

Het formulier bevat daarnaast twee velden die voor de bezoeker onzichtbaar zijn — een botval en een tijdstempel van het openen van de pagina — die beschreven worden in de sectie Anti-spam.

Stap 4 — het antwoord

Afhankelijk van uw configuratie zijn er drie uitkomsten:

ConfiguratieAangemaakte statusGetoond bericht
Dubbele e-mailverificatie actief (standaard)unverified“Nog één stap: er is net een e-mail naar u verstuurd…”
Verificatie uitgeschakeld + handmatige bevestigingpending“Uw aanvraag is goed ontvangen!”
Verificatie uitgeschakeld + automatische bevestigingconfirmed“Uw afspraak is bevestigd!”

Werd het tijdslot ingenomen tussen het tonen van de lijst en het versturen van het formulier, dan krijgt de bezoeker een duidelijk bericht (owag_slot_taken, HTTP 409) en wordt de dagenlijst automatisch herladen. Twee bezoekers kunnen niet hetzelfde tijdslot krijgen: de kritieke sectie wordt geserialiseerd door een named MySQL-lock, eigen aan uw database en uw tabelprefix, wat ook op gedeelde hosting standhoudt.


De dubbele verificatie per e-mail

Dit is de functie die OW Agenda onderscheidt van een vermomd contactformulier.

Wanneer Dubbele e-mailverificatie actief is (instelling email_verify, standaard aan):

  1. De aanvraag wordt opgeslagen met de status unverified. De beheerder wordt niet verwittigd. De afspraak verschijnt niet als een aanvraag om te behandelen.
  2. De bezoeker krijgt een e-mail “Nog één stap…” met een bevestigingsknop.
  3. Het tijdslot wordt 45 minuten vastgehouden. Blijft de bevestiging uit, dan komt het daarna weer vrij voor iedereen — een bot kan uw dag dus niet bevriezen.
  4. De klik op de knop opent een op zichzelf staande pagina (?owag_verify=<uid>) met de samenvatting van de afspraak en een knop “Ik bevestig mijn aanvraag”. De bevestiging vertrekt pas bij die klik: antivirussoftware en linkscanners die de URL’s uit e-mails bezoeken, bevestigen niets.
  5. De aanvraag wordt dan pending (handmatige bevestiging) of confirmed (automatische bevestiging), de klant krijgt de bijbehorende e-mail, en pas dan vertrekt de melding naar de beheerder.
  6. Nooit bevestigde aanvragen worden na 48 u verwijderd door de uurlijkse taak. Ze laten geen spoor en geen persoonsgegevens na.

Is het tijdslot tussen het versturen en de klik door iemand anders ingenomen (het venster van 45 minuten is voorbij), dan geeft de bevestiging een duidelijke fout en wordt de aanvraag geannuleerd — nooit een spookafspraak op een al bezet tijdslot.

Praktisch gevolg: een ongeldig e-mailadres levert geen enkele afspraak op. U verliest geen tijd meer met het terugbellen van verzonnen nummers. De prijs is één extra klik voor de klant; de ervaring leert dat het aantal afhakers veel lager ligt dan het aantal valse afspraken dat het voorkomt.

Reservaties uit een sessie-uitnodiging slaan deze stap over: de klant heeft al bewezen dat hij zijn mailbox leest door op de privélink te klikken die hij ontvangen heeft.


De bevestiging van aanvragen

Handmatige bevestiging (aanbevolen)

Standaardinstelling: auto_confirm = 0. Een geverifieerde aanvraag komt binnen met de status pending. Er is de klant niets beloofd zolang u niets gedaan hebt — maar het tijdslot is al geblokkeerd, niemand kan het u afsnoepen.

U krijgt een e-mail “Te bevestigen: met de volledige samenvatting (dienst, datum, naam, telefoon, e-mail, bericht van de klant) en twee knoppen:

  • De afspraak bevestigen — cyaan
  • Weigeren — rode omlijning

De knoppen in de e-mail: HMAC-ondertekende links

Die knoppen vragen geen login. Ze verwijzen naar uw site met drie parameters: owag_admin_action (confirm of refuse), uid (de willekeurige identificatie van de afspraak) en sig, een HMAC-SHA256-handtekening van uid|action berekend met het privégeheim van de site (owag_admin_secret).

  • De handtekening wordt gecontroleerd voor er ook maar één detail getoond wordt: een geknoeide link toont niets anders dan “Ongeldige link”.
  • De vergelijking gebruikt hash_equals() — geen informatielek via de responstijd.
  • De pagina toont een samenvatting en een knop; de actie wordt pas bij de klik uitgevoerd. Een linkscanner bevestigt dus niets in uw plaats.
  • Een al behandelde aanvraag geeft “Al behandeld (status: … )” in plaats van een fout.

Bevestigen stuurt automatisch de bevestigingsmail naar de klant, met het agendabestand. Weigeren stuurt de annuleringsmail. In beide gevallen is de agenda bij voor u uw telefoon hebt opgeborgen.

Die links blijven geldig zolang de afspraak in afwachting staat. Verwijdert u de optie owag_admin_secret (gedeeltelijke herstelling van de database, handmatige opkuis), dan werken alle al verstuurde links niet meer: er wordt een nieuw geheim aangemaakt en de oude handtekeningen komen niet meer overeen. Gebruik dan de Agendapagina.

Automatische bevestiging

Instelling auto_confirm = 1. Een vrij tijdslot wordt onmiddellijk bevestigd: de klant krijgt zijn bevestiging met het agendabestand, u krijgt een melding “Nieuwe afspraak”. Voorbehouden voor activiteiten waar elk open tijdslot een aanvaardbaar tijdslot is.

Beide instellingen combineren met de dubbele verificatie: zelfs bij automatische bevestiging gaat de aanvraag eerst door unverified als email_verify actief is.


De Agendapagina

De pagina “Agenda” ([ow_agenda_admin]) is het werkinstrument van elke dag. Ze is eerst voor de telefoon ontworpen: brede knoppen, één kolom, geen tabel die horizontaal moet schuiven, en ze werkt uiteraard even goed op een computerscherm.

Ze is beveiligd: een niet-ingelogde bezoeker ziet een inloglink, een ingelogde gebruiker zonder de capability owag_manage ziet “De toegang is voorbehouden aan het team”. De pagina staat op noindex,nofollow: ze zal nooit in Google terechtkomen.

Tabblad Agenda — het dagoverzicht

De lopende dag, item per item, met het uur, de duur, het label, de status en de herkomst (site, uitnodiging, handmatige invoer). Navigatie van dag naar dag, knop Vandaag. Bij elke afspraak:

  • Details — de gegevens van de klant, het bericht dat bij de reservatie achtergelaten werd, en een blok interne notities (nooit zichtbaar voor de klant) die opgeslagen worden zonder ook maar één e-mail te versturen
  • Bevestigen ✓ — voor een aanvraag die nog in afwachting staat; de bevestigingsmail vertrekt
  • Gedaan / Afwezig (no-show) — eindstatussen van de afspraak
  • Verplaatsen — nieuwe datum, nieuw uur, eventueel gewijzigde duur. De plugin vraagt of de klant per e-mail verwittigd moet worden; zo ja, dan krijgt hij een bijgewerkte bevestiging en een agendabestand dat het item corrigeert dat al op zijn telefoon staat
  • De afspraak annuleren — ook hier met de keuze om de klant al dan niet te verwittigen
  • De blokkering verwijderen — voor een geblokkeerd tijdslot

Wanneer een actie een overlapping veroorzaakt (verplaatsing naar een bezet tijdslot), waarschuwt de plugin en vraagt ze een bevestiging: u kan forceren. Het is uw planning, u weet wat u doet — het vangnet is enkel blokkerend voor bezoekers.

Een afspraak of een blokkering toevoegen

De knop “Een afspraak toevoegen” opent één formulier dat twee doelen dient:

  • Afspraak — de klant heeft u gebeld. Naam, telefoon, e-mail (optioneel), dienst, datum, uur, duur, interne notities. Vult u een e-mailadres in en vinkt u de optie aan, dan krijgt de klant de bevestiging met zijn agendabestand, alsof hij online geboekt had. De afspraak vult ook het klantenbestand aan.
  • Blokkering (verlof, pauze…) — een reden, een datum, een uur, een duur. Geen e-mail, geen klantfiche, maar het tijdslot verdwijnt onmiddellijk uit de online reservatie. Zo legt u een week verlof vast, een opleiding, of het middaguur dat u niet geboekt wil zien.

Tabblad In afwachting

De lijst van geverifieerde aanvragen die op uw beslissing wachten, over alle dagen heen (afspraken die al voorbij zijn, vallen erbuiten). Twee knoppen per regel: Bevestigen en Weigeren. Dit is het eerste scherm om ’s ochtends te openen.

Tip: de agenda als app

Op de Agendapagina declareert de plugin een webapp-manifest (?owag_manifest=1) met de naam van de site, het pictogram van de site en de themakleur. Op Android zoals op iOS biedt het browsermenu dan “Toevoegen aan startscherm” aan: u krijgt een pictogram, een schermvullende start, en u hoeft de URL nooit meer in te typen.


Het klantenbestand

Het derde tabblad van de Agendapagina is een licht bestand, bewust minimaal: naam, telefoon, e-mail, vrije notities.

  • Het vult zichzelf. Zodra een afspraak bevestigd is (geverifieerde online reservatie, sessie op uitnodiging, handmatige invoer), wordt de klant aan een bestaande fiche gekoppeld op zijn e-mail en daarna op zijn telefoon. Bestaat hij niet, dan wordt de fiche aangemaakt; bestaat hij wel, dan worden enkel de lege velden aangevuld — de plugin overschrijft nooit wat u zelf hebt ingevuld.
  • Zoeken op naam, telefoon of e-mail (maximaal 200 fiches getoond).
  • Handmatig aanmaken en bewerken, met een notitieveld voor de voorgeschiedenis, de voorkeuren, de aandachtspunten.
  • Twee snelkoppelingen per fiche: Nieuwe afspraak (vult het handmatige invoerformulier vooraf in) en Uitnodigen voor een sessie (vult de uitnodiging vooraf in).
  • Een fiche verwijderen: de afgelopen afspraken blijven in de agenda staan, alleen de fiche uit het bestand verdwijnt.

Dit bestand is geen CRM en doet ook niet alsof. Het beantwoordt één vraag: “Wie was dat weer, die dame van 14 u?”


De sessie-uitnodigingen

De use case: een bestaande klant heeft recht op een sessie — een opvolging, een bijwerking, een prestatie die elders verkocht is — en u wil dat hij zijn datum kiest zonder langs de publieke reservatie te gaan, voor een dienst en een duur die u vastlegt.

Vanuit het tabblad Uitnodigingen:

  1. Vul de naam van de klant en de titel van de sessie in (verplicht), de duur (15 tot 720 minuten) en, als u dat wenst, zijn e-mail en telefoon.
  2. Kies de geldigheidsduur van de link: standaard 60 dagen, van 1 tot 365.
  3. Vink eventueel “De link per e-mail naar de klant sturen” aan — de klant krijgt een e-mail “Kies de datum van uw sessie” met de titel, de duur, de vervaldatum en een knop.
  4. Kopieer anders de link en stuur hem via sms, WhatsApp of met de ingebouwde deelknop van de telefoon.

De link verwijst naar uw reservatiepagina met een privétoken (?owag_invite=<token>, 32 hexadecimale tekens uit een cryptografische generator). De widget toont dan de titel en de duur van de sessie, en niet die van de standaardconsultatie. De klant vult hetzelfde korte formulier in.

Regels die een uitnodigingslink beheersen:

  • Eenmalig gebruik. Zodra de sessie geboekt is, antwoordt de link “Deze link is al gebruikt” (HTTP 410). Twee gelijktijdige openingen met hetzelfde token kunnen geen twee sessies aanmaken: het token wordt verbruikt onder dezelfde lock als de reservatie van het tijdslot.
  • Gedateerd. Na de vervaldatum vraagt de link om opnieuw contact op te nemen (HTTP 410).
  • Zonder dubbele opt-in. De klant heeft die link al gekregen via een kanaal dat u beheerst: de sessie wordt rechtstreeks als confirmed aangemaakt, met bevestiging en agendabestand.
  • Hergebruikt bij annulering. Wordt de sessie geannuleerd (door u of door de klant), dan wordt de uitnodiging vrijgegeven: de link wordt weer actief en de uitnodiging duikt weer op in de lijst met open uitnodigingen. Dat is een correctie uit 1.3.0 — voordien maakte een annulering de link definitief kapot en moest u een nieuwe maken.
  • Intrekbaar. Een uitnodiging uit de lijst verwijderen, schakelt de link onmiddellijk uit.

E-mails en agendabestand (ICS)

De transactionele e-mails

Alle berichten zijn in HTML, op een tabelopmaak die compatibel is met Gmail en Outlook: witte kaart op lichte achtergrond, naam van de site in de hoofding, samenvattingskader met cyaan bies, pilvormige knoppen. Ze worden verstuurd via wp_mail() en respecteren dus uw SMTP-configuratie en de gebruikelijke WordPress-filters.

E-mailOntvangerTrigger
Bevestiging van de aanvraagKlantOnline reservatie wanneer de dubbele verificatie actief is
Aanvraag ontvangenKlantAanvraag geverifieerd, in afwachting van uw beslissing
Afspraak bevestigdKlantBevestiging (handmatig, automatisch, invoer door beheerder, verplaatsing) — met ICS-bijlage
Afspraak geannuleerdKlantAnnulering door de klant, weigering of annulering door de beheerder — met ICS-annuleringsbijlage
HerinneringKlantAutomatisch, tussen 12 en 36 u voor de afspraak
Kies de datum van uw sessieKlantAanmaak van een uitnodiging met verzending per e-mail
Te bevestigen: …BeheerderNieuwe geverifieerde aanvraag in afwachting — met de knoppen Bevestigen / Weigeren
Nieuwe afspraak: …BeheerderNieuwe bevestigde afspraak (automatische bevestiging, uitnodiging)
Annulering door de klant: …BeheerderDe klant heeft zelf geannuleerd vanuit zijn e-mail

Het adres voor beheerdersmeldingen is de instelling notify_email (standaard het beheerdersadres van de site). E-mails naar de klant vertrekken enkel als het adres geldig is, en nooit voor een geblokkeerd tijdslot.

De bevestigings- en annuleringsmails herinneren de klant eraan dat hij online kan annuleren, met het aantal uren opzeg dat effectief ingesteld is.

De ICS-bijlage

Het .ics-bestand bij de bevestigingen is wat een e-mail omzet in een afspraak die echt in de telefoon van de klant staat: één beweging op de bijlage en het item staat in zijn agenda, met zijn eigen herinnering.

Het bestand voldoet aan RFC 5545 en bevat wat nodig is opdat agendatoepassingen (Google, Outlook, Apple) de updates correct verwerken:

  • METHOD:REQUEST bij het aanmaken en bij elke wijziging van het uur, METHOD:CANCEL bij de annulering;
  • een stabiele UID afgeleid van de identificatie van de afspraak en van het domein van de site — die zorgt ervoor dat een wijziging het bestaande item vervangt in plaats van een tweede aan te maken;
  • een oplopende SEQUENCE afgeleid van de datum van laatste wijziging, herleid tot een absoluut tijdstip: de overgang naar de wintertijd kan het revisienummer niet doen teruglopen (en de annulering telt er 1 bij, om hoger te blijven dan een wijziging in dezelfde seconde);
  • ORGANIZER (uw meldingsadres) en ATTENDEE (de klant);
  • DTSTART / DTEND in UTC, STATUS:CONFIRMED of STATUS:CANCELLED;
  • regels gevouwen op 75 bytes zonder ooit een UTF-8-teken in twee te knippen.

Een verplaatsing van een bevestigde afspraak stuurt dus een nieuw bestand dat het item corrigeert dat al bij de klant staat; een annulering stuurt een bestand dat het wist. Dat is een correctie uit 1.3.0: voordien bleef het oude uur in de agenda van de klant staan.

Het bestand wordt in de tijdelijke map van de server geschreven — nooit in wp-content/uploads/, dat publiek geserveerd wordt — via de bestands-API van WordPress, en het wordt gewist zodra de verzending klaar is, ook als die mislukt. Het bevat de naam en het e-mailadres van de klant: het heeft geen seconde langer dan nodig op de schijf te staan.


Herinneringen en geplande taak

Eén enkele geplande taak, owag_hourly_event, elk uur uitgevoerd. Ze doet drie dingen.

1. De herinnering de dag voordien

De herinnering vertrekt wanneer de afspraak binnen 12 tot 36 uur begint. Dat is geen vast tijdvenster, en dat is bewust: WP-Cron wordt pas geactiveerd bij een paginabezoek. Een site zonder verkeer ’s avonds verloor de herinneringen voor de volgende dag definitief. Met een schuivend venster vertrekt de herinnering bij de eerste beschikbare uitvoering en haalt ze de achterstand in.

Voorwaarden: bevestigde afspraak, ingevuld e-mailadres, het is geen blokkering, en de herinnering is nog niet verstuurd.

Elke herinnering wordt atomair gereserveerd voor de verzending (een voorwaardelijke UPDATE op de vlag reminder_sent): twee overlappende cron-uitvoeringen kunnen niet tweemaal hetzelfde bericht versturen. Mislukt de verzending, dan wordt de reservatie teruggegeven en wordt de herinnering bij de volgende uitvoering opnieuw geprobeerd. Een korte lock (10 minuten) voorkomt bovendien dat twee gelijktijdige doorlopen dezelfde lijst afgaan.

Een afspraak verplaatsen zet de vlag terug op nul: de klant krijgt wel degelijk een herinnering voor het nieuwe uur.

2. Het opruimen van niet-bevestigde aanvragen

Aanvragen die langer dan 48 uur op unverified blijven staan, worden verwijderd. (Hun tijdslot was al na 45 minuten weer vrijgegeven.)

3. De AVG-anonimisering

Zie de sectie AVG.

Het vangnet

Een WP-Cron-event kan verdwijnen: databaseoptimalisatie, gedeeltelijke herstelling, opkuisplugin, reset van de optie cron. OW Agenda controleert bij elke paginalading of de taak wel degelijk ingepland is en plant ze anders opnieuw in. Herinneringen, opruiming en bewaartermijn kunnen niet in stilte stilvallen.

Een echte systeemcron gebruiken

WP-Cron hangt af van het verkeer. Verkies op een weinig bezochte site een systeemcron:

// 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 en rate limits

Reserveren is publiek van aard: geen account, geen login, geen nonce mogelijk. Vijf onafhankelijke beschermingen werken daarom stroomopwaarts.

1. De botval (honeypot)

Het formulier bevat een tekstveld buiten het scherm, onzichtbaar voor een mens en aanlokkelijk voor een bot. Het veld moet aanwezig én leeg zijn. Een ingevuld veld — of een ontbrekend veld, wat een rechtstreekse verzending naar de API verraadt — levert een droge weigering op (HTTP 403), zonder bruikbaar detail.

2. De invultijd

De pagina geeft de tijdstempel van haar weergave mee. Een inzending die minder dan 4 seconden na het laden binnenkomt, wordt geweigerd. Ook hier is een ontbrekende of misvormde tijdstempel een weigering: in 1.3.0 zijn die twee velden verplicht geworden — ze weglaten schakelde de controle simpelweg uit.

3. Het uurquotum per adres

5 reservaties per uur en per bereik. In IPv4 is het bereik het adres; in IPv6 is het het /64-prefix — een aanvaller beschikt daar over 2⁶⁴ adressen, het volledige adres tellen zou niets beperken.

De teller wordt pas na de validatie van het formulier verhoogd: een bezoeker die zich drie keer na elkaar van e-mailadres vergist, zit niet meer voor niets een uur geblokkeerd.

4. Het dagplafond op niet-geverifieerde aanvragen

Maximaal 3 aanvragen die op e-mailbevestiging wachten mogen op eenzelfde dag een tijdslot vasthouden. Zonder dat plafond volstonden een paar verzendingen om alle tijdsloten van één datum te bevriezen. Daarboven krijgt de bezoeker de uitnodiging om later opnieuw te proberen of een andere dag te kiezen (HTTP 429).

5. De reservatielock

Het reserveren van een tijdslot en het verbruiken van een uitnodiging gebeuren in een kritieke sectie die geserialiseerd wordt door een named MySQL-lock, waarvan de naam afgeleid is van uw database en uw tabelprefix (twee sites op dezelfde gedeelde hosting blokkeren elkaar dus niet). Wordt de lock niet binnen 5 seconden verkregen, dan geeft de aanvraag een duidelijke HTTP 503 in plaats van een dubbele afspraak.

Die lock vervangt sinds 1.3.0 een transactie die op een kale SELECT steunde: onder REPEATABLE READ legt die geen enkele rijvergrendeling, en konden twee gelijktijdige bezoekers hetzelfde uur boeken.

En de dubbele verificatie

Dat is de doeltreffendste laag: zelfs wie alles hierboven passeert, raakt als bot nooit tot in uw agenda of uw mailbox, want de melding naar de beheerder vertrekt pas na een klik op een link die per e-mail ontvangen is. Zie De dubbele verificatie per e-mail.


AVG

Een afsprakenagenda verwerkt mogelijke gezondheidsgegevens, contactgegevens en historieken. De standaardinstellingen zijn bewust behoudend.

Toestemming

Het toestemmingsvakje is verplicht en standaard niet aangevinkt op het publieke formulier: “Ik ga ermee akkoord dat mijn gegevens gebruikt worden voor het beheer van mijn afspraak.” Een reservatie zonder toestemming wordt aan serverzijde geweigerd, niet enkel in de browser.

Minimalisering

  • Er wordt geen enkel IP-adres in de database opgeslagen. Het uurquotum gebruikt een tijdelijke teller (transient) waarvan de sleutel een hash van het netwerkbereik is, na een uur opgeruimd.
  • Geen enkele user agent, geen tracker, geen cookie die door de plugin geplaatst wordt.
  • Er worden geen gegevens naar een externe dienst gestuurd: geen CDN, geen externe oproep, geen telemetrie.
  • Nooit bevestigde aanvragen worden na 48 uur verwijderd — ze laten geen gegevens achter.
  • Geannuleerde afspraken worden niet meer door de agenda-API teruggegeven: onnodige persoonsgegevens circuleren niet.

Automatische anonimisering

Instelling retention_months, standaard 24 maanden. Elk uur worden de afspraken die langer dan die termijn afgelopen zijn, ter plaatse geanonimiseerd: de naam wordt vervangen door “Geanonimiseerd”, telefoon en e-mail worden leeggemaakt, het bericht van de klant en de interne notities worden gewist. De rij blijft bestaan, wat de statistische geschiedenis van de activiteit bewaart (hoeveel afspraken, wanneer, voor welke prestatie) zonder ook maar één persoonsgegeven bij te houden.

Zet 0 om de automatische anonimisering uit te schakelen — met kennis van zaken.

Let op: de anonimisering richt zich op afspraken met een e-mailadres. Een handmatig ingevoerde afspraak zonder e-mail (enkel naam en telefoon) wordt niet bereikt door de automatische opruiming; verwijder ze handmatig als uw bewaarbeleid dat vereist.

Recht op inzage en recht op wissing

De plugin koppelt zich niet aan de ingebouwde exporteurs/wissers van WordPress (die werken op gebruikersaccounts, en klanten hebben er geen). Om een verzoek te behandelen:

  • Inzage — zoek de persoon in het klantenbestand (naam, telefoon of e-mail) en loop zijn afspraken in de agenda door. Databasebeheerders kunnen ook rechtstreeks {prefix}_owag_appointments en {prefix}_owag_customers bevragen op de kolom customer_email / email.
  • Wissing — verwijder de fiche uit het bestand en annuleer daarna de betrokken afspraken of laat ze anonimiseren. Onmiddellijk wissen gebeurt in de database op 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';

Verwerkingsregister

Voor uw register: doel beheer van de afspraken; rechtsgrond toestemming (online reservatie) of uitvoering van een overeenkomst / precontractuele maatregelen (telefonisch gemaakte afspraak); categorieën identiteit, contactgegevens, inhoud van het bericht, interne notities; bewaartermijn standaard 24 maanden, daarna anonimisering; ontvangers geen enkele verwerker buiten uw hostingprovider en uw dienst voor e-mailverzending.


Shortcodes

[ow_agenda] — de reservatie voor bezoekers

Op een publieke pagina te plaatsen. Geen attributen: de prestatie, de duur en de uren komen uit de instellingen. De shortcode laadt zijn stylesheet en zijn script (samen minder dan 12 KB, zonder afhankelijkheden) en rendert een container die zich vult na de eerste API-oproep.

[ow_agenda]

Het is deze shortcode die de URL-parameter ?owag_invite=<token> interpreteert: dezelfde pagina bedient de standaardconsultatie en de sessies op uitnodiging.

[ow_agenda_admin] — de beheerpagina

Op een aparte pagina te plaatsen. Geen attributen. De shortcode regelt de toegang zelf:

  • niet-ingelogde bezoeker → inloglink die naar de pagina terugleidt;
  • ingelogd zonder de capability owag_manage → bericht over beperkte toegang;
  • ingelogd met de capability → de volledige interface (agenda, in afwachting, klanten, uitnodigingen).
[ow_agenda_admin]

Beide pagina’s worden bij de activatie automatisch met deze shortcodes aangemaakt. Hebt u ze verwijderd, dan volstaat het een pagina te maken en de shortcode erin te plakken — denk er dan aan de optie owag_page_admin (of owag_page_booking) bij te werken zodat de links in de e-mails en het manifest naar de juiste plek wijzen.

De op zichzelf staande pagina’s

Vier URL-parameters, die op om het even welke pagina van de site onderschept worden, leveren op zichzelf staande pagina’s op die buiten het thema geserveerd worden (minimale weergave, noindex,nofollow):

URLRol
?owag_verify=<uid>Bevestiging van de aanvraag door de klant (dubbele opt-in)
?owag_cancel=<uid>Online annulering door de klant
?owag_admin_action=confirm|refuse&uid=…&sig=…Bevestiging / weigering vanuit de beheerdersmail
?owag_manifest=1App-manifest van de Agendapagina

Die pagina’s voeren nooit een actie uit bij het laden: ze tonen een samenvatting en een knop. Geen enkele bot, geen enkele e-mailantivirus, geen enkele prefetch van een browser kan een afspraak bevestigen of annuleren in de plaats van een mens.


REST API

Alle endpoints leven onder de namespace owag/v1, op de gebruikelijke REST-root (https://example.com/wp-json/owag/v1/…).

Publieke endpoints

Geen authenticatie: dit zijn de routes van de reservatiewidget en van de links die per e-mail ontvangen worden. Hun beveiliging steunt op willekeurige tokens (32 hexadecimale tekens uit een cryptografische generator), op HMAC-handtekeningen en op de beschermingen die in Anti-spam beschreven zijn.

MethodePadParametersRol
GET/public/daysfrom (Y-m-d, standaard: vandaag), token (uitnodiging, optioneel)Geeft label, duration en days terug: 14 dagen vanaf from, elk met zijn aantal vrije tijdsloten
GET/public/slotsdate (Y-m-d, verplicht), tokenGeeft slots terug: de vrije beginuren (HH:MM)
POST/public/bookdate, time, name, phone, email, message, consent, website (botval), ts (tijdstempel), tokenMaakt de aanvraag aan; geeft status terug en het bericht dat getoond moet worden
POST/public/verifyuidBevestigt een aanvraag met status unverified
POST/public/canceluidAnnuleert een pending- of confirmed-afspraak, binnen de opzegtermijn
POST/public/admin-actionuid, action (confirm|refuse), sigBevestigt of weigert vanuit de beheerdersmail (HMAC-handtekening)

Voorbeeld van een reservatie:

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

Beheer-endpoints

Ze vereisen allemaal de capability owag_manage en een geldige WordPress REST-nonce (header X-WP-Nonce).

MethodePadParametersRol
GET/admin/agendafrom, to (Y-m-d)events (het gevraagde bereik, geannuleerde afspraken uitgesloten) en pending (alle toekomstige aanvragen in afwachting)
POST/admin/appointmentkind (manual|block|consult|seance), date, time, duration (5–720 min), label, name, phone, email, notes, force, send_emailMaakt een handmatige afspraak of een blokkering aan
POST/admin/appointment/{id}status (pending|confirmed|cancelled|done|noshow), name, phone, email, label, notes, date, time, duration, force, silentWerkt bij, verplaatst, wijzigt de status. silent=1 onderdrukt elke e-mailverzending
GET/admin/customersq (zoekopdracht)Het bestand (maximaal 200 fiches)
POST/admin/customersname (verplicht), phone, email, notesMaakt een fiche aan
POST/admin/customers/{id}idemWerkt een fiche bij
DELETE/admin/customers/{id}Verwijdert een fiche
GET/admin/invitesDe open uitnodigingen (nooit gebruikt of vrijgegeven, niet vervallen)
POST/admin/invitesname (verplicht), label (verplicht), duration (15–720), days_valid (1–365, standaard 60), email, phone, send_emailMaakt een uitnodiging aan; geeft url en email_sent terug
DELETE/admin/invites/{id}Verwijdert een uitnodiging
GET/admin/settingsDe effectieve instellingen
POST/admin/settingsJSON-body (zie Instellingenreferentie)Slaat de instellingen op

Elke route declareert haar toegangscontrole expliciet; de capability wordt gecontroleerd voor er ook maar iets verwerkt wordt.

Foutcodes

De fouten zijn standaard WP_Error-objecten, met een leesbare code en een HTTP-status.

CodeHTTPBetekenis
owag_spam403Botval ingevuld, of tijdstempel ontbreekt / te recent
owag_rate429Uurquotum bereikt voor dit adres
owag_day_full429Te veel aanvragen in afwachting van bevestiging op deze datum
owag_busy503Reservatielock niet verkregen — zo dadelijk opnieuw proberen
owag_slot_taken409Tijdslot intussen ingenomen
owag_overlap409Overlapping vastgesteld (beheer) — opnieuw versturen met force
owag_invite_invalid404Onbekend uitnodigingstoken
owag_invite_used410Uitnodiging al verbruikt
owag_invite_expired410Uitnodiging vervallen
owag_too_late403Online annulering buiten de opzegtermijn
owag_bad_sig403Ongeldige HMAC-handtekening
owag_not_found404Afspraak of fiche niet gevonden
owag_name, owag_phone, owag_email, owag_consent400Ongeldig veld of ontbrekende toestemming
owag_bad_input, owag_bad_date400Ongeldige datum, ongeldig uur of ongeldige invoer
owag_noop400Lege update-aanvraag
owag_insert500Schrijffout in de database

Developer hooks

In 1.3.1 stelt OW Agenda geen enkele publieke filter of action beschikbaar: er is geen uitbreidings-API om te documenteren, en niets van wat volgt moet geraden worden. De enige bruikbare hook is het geplande event owag_hourly_event, waarop u uw eigen onderhoud kan aanhaken:

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

Voor al de rest is de REST API het integratiepunt: ze stelt precies bloot wat de interface doet, niet meer en niet minder.


Instellingenreferentie

Alle instellingen zitten in één enkele optie, owag_settings. Lezen en schrijven 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,
] ) );

Standaardwaarden

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

Detail

InstellingTypeGrenzen in de interfaceEffect
hoursarray1 of 2 blokken per dagTwee blokken maken een middagpauze mogelijk. Een blok wordt enkel bewaard als begin en einde geldig zijn en begin < einde. Een lege dag = gesloten
slot_stepinteger5 → 120 minAfstand tussen de aangeboden uren. Hoe fijner, hoe langer de lijst
consult_durationinteger15 → 480 minDuur die in de agenda gereserveerd wordt voor een online consultatie
bufferinteger0 → 120 minBuffertijd die aan weerszijden van het kandidaat-tijdslot toegepast wordt
min_notice_hoursinteger0 → 168 uEr wordt niets aangeboden voor nu + deze termijn
max_advance_daysinteger7 → 365 dHorizon waarboven geen enkel tijdslot meer aangeboden wordt
auto_confirm0 / 1Handmatige bevestiging of onmiddellijke bevestiging
email_verify0 / 1Dubbele opt-in per e-mail (actief laten)
cancel_notice_hoursinteger0 → 168 uDaarbuiten wordt de online annulering geweigerd met een bericht dat vraagt om te bellen
notify_emaile-mailOntvanger van de beheerdersmeldingen; dient ook als ORGANIZER in de ICS-bestanden
retention_monthsinteger0 → 120 maandenAnonimisering van de afgelopen afspraken; 0 schakelt uit
consult_labeltekstTitel die op de reservatiewidget getoond wordt

Twee niet-instelbare constanten verdienen het gekend te zijn, omdat ze het gedrag van de dubbele opt-in bepalen: het tijdslot van een niet-geverifieerde aanvraag wordt 45 minuten vastgehouden, en de aanvraag wordt na 48 uur verwijderd.

Opslaan via de REST API aanvaardt dezelfde sleutels in JSON; gehele getallen worden op minimaal nul gebracht, het meldingsadres wordt enkel aanvaard als het geldig is, en elk uurblok wordt aan serverzijde opnieuw gevalideerd.


Opgeslagen gegevens

Drie tabellen, allemaal met het prefix van uw installatie. De datums zijn DATETIME-waarden in lokale tijd van de site, nooit in UTC — dat maakt de queries leesbaar en de vergelijking van uren triviaal.

{prefix}_owag_appointments

KolomTypeOpmerkingen
idBIGINTPrimaire sleutel
uidCHAR(32)Uniek publiek token (hexadecimaal, cryptografische generator). Dient als sleutel voor de bevestigings-, annulerings- en beheerderslinks, en als ICS-UID
kindVARCHAR(16)consult, seance, manual, block
service_labelVARCHAR(120)Getoonde titel
customer_name, customer_phone, customer_emailVARCHARContactgegevens
customer_msgTEXTBericht dat de klant achterliet
admin_notesTEXTInterne notities, nooit naar de klant verstuurd
start_dt, end_dtDATETIMEGrenzen van het tijdslot (geïndexeerd op start_dt)
statusVARCHAR(16)unverified, pending, confirmed, cancelled, done, noshow
sourceVARCHAR(16)web, invite, admin
invite_idBIGINTOorspronkelijke uitnodiging, indien van toepassing
reminder_sentTINYINTHerinneringsvlag (teruggezet op 0 bij een verplaatsing)
created_at, updated_atDATETIMEupdated_at voedt het ICS-revisienummer

{prefix}_owag_invites

id, token (CHAR(32), uniek), contactgegevens van de klant, service_label, duration_min, expires_at, appointment_id (ingevuld wanneer de link verbruikt wordt, teruggezet op NULL als de afspraak geannuleerd wordt), created_at.

{prefix}_owag_customers

id, name, phone, email, notes, created_at, updated_at. Index op name en email.

Eén enkele optie draagt de configuratie (owag_settings); de andere zijn technisch: owag_admin_secret (HMAC-geheim), owag_db_version, owag_pages_created, owag_page_booking, owag_page_admin.


Internationalisatie

De volledige interface is vertaalbaar: beheerinstellingen, reservatiewidget, Agendapagina, op zichzelf staande pagina’s, API-berichten en e-mailsjablonen. De brontaal is het Engels; de plugin declareert het vertaaldomein ow-agenda en het pad /languages.

Het pakket levert het sjabloon languages/ow-agenda.pot. Een volledige Franse vertaling wordt meegeleverd, gemaakt op basis van de oorspronkelijke formulering van de interface.

Een vertaling handmatig installeren

Compileer de .po en plaats de .mo in de vertaalmap van WordPress:

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

WordPress laadt de catalogus bij de eerste vertaalde tekst; een handmatige oproep is niet nodig.

Twee valkuilen voor vertalers

  • De teksten die voor JavaScript bestemd zijn gebruiken genummerde placeholders (%1$s, %2$s) en nooit een kale %s: de kleine formatter in de scripts begrijpt alleen die. Een niet-genummerde placeholder zou letterlijk getoond worden.
  • Twee teksten zijn PHP-datumformaten, geen zinnen: l, F j, Y \a\t g:i a en l j F Y \a\t H:i. Vertaal ze als formaten (de tokens herschikken, letterlijke letters met een backslash escapen). Het Frans gebruikt l j F Y \à H\hi.

Deïnstallatie

De plugin deactiveren doet één ding: de uurlijkse geplande taak verwijderen. Uw gegevens, uw instellingen en uw pagina’s blijven intact, en alles vertrekt opnieuw bij de heractivatie.

De plugin verwijderen vanuit WordPress voert de volledige deïnstallatie uit:

  • verwijdering van de drie tabellen (owag_appointments, owag_invites, owag_customers);
  • verwijdering van de opties owag_settings, owag_admin_secret, owag_db_version, owag_pages_created, owag_page_booking, owag_page_admin;
  • verwijdering van de geplande taak;
  • intrekking van de capability owag_manage bij de rol beheerder.

De twee pagina’s die bij de activatie aangemaakt zijn, worden niet verwijderd — ze kunnen herwerkt zijn, in een menu staan, geïndexeerd zijn. Het is aan u om ze in de prullenbak te gooien als u ze niet meer wil.

Het verwijderen van de tabellen is definitief. Exporteer vooraf uw database als de geschiedenis van de afspraken waarde voor u heeft.


Probleemoplossing

Er verschijnt geen enkel tijdslot op de reservatiepagina

Loop de lijst in volgorde af:

  1. Zijn de uren van die dag ingevuld? Een lege dag is een gesloten dag.
  2. De minimale termijn (standaard 24 u) verbergt onvermijdelijk vandaag en een deel van morgen.
  3. Past de duur in het tijdsblok? Met een blok 09:00–12:00 en een duur van 240 minuten kan er geen enkel tijdslot bestaan.
  4. De horizon: dagen voorbij max_advance_days worden nooit aangeboden.
  5. De buffertijd: een ruime buffer op een volle planning kan alles dichtzetten.
  6. Een blokkering dekt misschien de hele dag. Open de Agendapagina op de betrokken dag.
  7. De tijdzone van de site (Instellingen → Algemeen): een verkeerd ingestelde tijdzone verschuift alle berekeningen.

De e-mails komen niet aan

Dat is bijna altijd de afleverbaarheid, niet de plugin.

  1. Controleer of de afspraak wel degelijk in de Agendapagina staat: staat ze er, dan heeft de plugin zijn werk gedaan.
  2. Installeer een SMTP-plugin (Fluent SMTP, WP Mail SMTP…). De functie mail() van PHP wordt door de overgrote meerderheid van de ontvangende servers geweigerd.
  3. Controleer SPF, DKIM en DMARC van uw domein.
  4. Test het adres in OW Agenda → Beheerdersmeldingen sturen naar: een ongeldig adres blokkeert de meldingen in stilte.

De herinnering de dag voordien is niet vertrokken

De herinnering hangt af van WP-Cron, dat van het verkeer afhangt. Schakel op een weinig bezochte site over op een echte systeemcron (zie Herinneringen en geplande taak). Controleer ook of de afspraak wel degelijk bevestigd is, of ze een e-mailadres draagt en of het geen blokkering is.

De Agendapagina toont “De toegang is voorbehouden aan het team”

De ingelogde gebruiker heeft de capability owag_manage niet. Die wordt bij de activatie aan de beheerders gegeven; voor de andere rollen, zie Installatie.

De knop “Bevestigen” in de e-mail toont “Ongeldige link”

Drie mogelijke oorzaken: de link werd door het e-mailprogramma afgekapt (probeer de volledige URL te kopiëren), de afspraak is al behandeld (het bericht vermeldt dat), of het HMAC-geheim van de site is opnieuw aangemaakt. In dat laatste geval gebruikt u de Agendapagina: de oude links kunnen per definitie niet meer gevalideerd worden.

Twee afspraken staan op hetzelfde tijdslot

Sinds 1.3.0 is dat onmogelijk via de online reservatie. Wel kan de beheerder een overlapping forceren vanaf de Agendapagina (de plugin meldt dat en vraagt een bevestiging): ga eerst na of het niet om een bewuste forcering gaat. Controleer ook of uw database GET_LOCK() wel degelijk ondersteunt — een exotische hosting zou dan 503-fouten geven bij het reserveren in plaats van duplicaten.

De pagina’s “Reserveren” en “Agenda” zijn niet aangemaakt

Ze worden maar één keer aangemaakt, bij de allereerste activatie. Hebt u ze verwijderd, maak dan twee pagina’s met de shortcodes [ow_agenda] en [ow_agenda_admin] en laat de opties owag_page_booking en owag_page_admin ernaar wijzen, zodat de links in de e-mails correct blijven:

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

Het agendabestand zit niet in bijlage

Het bestand wordt via de bestands-API van WordPress in de tijdelijke map van de server geschreven. Is die map niet beschrijfbaar (quota, rechten, dichtgetimmerde hosting), dan vertrekt de e-mail zonder bijlage in plaats van te mislukken. Controleer de schrijfrechten en de vrije schijfruimte.

De uren staan een uur verkeerd

Instellingen → Algemeen → Tijdzone. Kies een stad (Europe/Brussels) in plaats van een vaste UTC-verschuiving: alleen een benoemde tijdzone beheert de overgang naar de zomertijd.


FAQ

Is OW Agenda echt gratis? Ja. GPL-2.0-or-later, als .zip te downloaden op https://optionweb.dev/nl/addons/ow-agenda/. Geen Pro-versie, geen licentiesleutel, geen enkele functie achter slot, geen account om aan te maken, geen quotum op het aantal afspraken.

Houden de online tijdsloten rekening met telefonisch gemaakte afspraken? Ja. Elk item in de agenda — online reservatie, handmatig ingevoerde afspraak, sessie op uitnodiging, blokkering — maakt zijn tijdsspanne onbeschikbaar voor de online reservatie.

Moet de klant een account aanmaken? Nee. Geen account, geen wachtwoord. Alle acties van de klant (bevestiging, annulering) verlopen via privélinks die per e-mail ontvangen worden.

Kan men meerdere praktijkhouders of meerdere ruimtes beheren? Nee. OW Agenda beschrijft één enkele planning. Voor twee onafhankelijke agenda’s hebt u twee sites nodig (of twee sites van een multisite-netwerk).

Synchroniseert het met Google Agenda? In de richting die voor de klant telt: ja. Elke bevestiging bevat een standaard agendabestand dat het item toevoegt — en bijwerkt, en verwijdert — in Google Agenda, Outlook of de agenda van een iPhone. De plugin leest echter uw externe agenda’s niet: uw persoonlijke onbeschikbaarheden voert u in als blokkeringen.

Kan men een voorschot laten betalen bij de reservatie? Nee, dat valt bewust buiten het bereik van de plugin.

Hoeveel prestaties kan men online aanbieden? Eén enkele, waarvan u het label en de duur kiest. De andere prestaties verlopen via de sessie-uitnodigingen, waarbij u de titel en de duur geval per geval vastlegt. Die keuze is bewust: een menu met prestaties op een publieke pagina vermenigvuldigt de slecht gerichte aanvragen.

Werkt het op een multisite? Ja. Elke site van het netwerk heeft zijn eigen tabellen, zijn eigen instellingen en zijn eigen agenda.

Vertraagt de plugin de site? Nee. Er wordt geen enkel script geladen buiten de twee betrokken pagina’s; de reservatiewidget weegt minder dan 12 KB, zonder jQuery of framework. Het periodieke werk past in één uurlijkse taak.

Wat gebeurt er als een klant zijn e-mail nooit bevestigt? Zijn tijdslot komt na 45 minuten weer vrij en zijn aanvraag wordt na 48 uur verwijderd. U hoort er nooit iets over.

Waar vind ik support?


Changelog

1.3.1

Compliance

  • De op zichzelf staande actie-, verificatie- en annuleringspagina’s drukken hun CSS en hun JavaScript niet meer inline af: beide zijn voortaan bestanden die geregistreerd en geserveerd worden door de enqueue-API van WordPress. De twee variabele knopkleuren lopen via aangepaste CSS-eigenschappen, en het script wordt geconfigureerd via wp_localize_script().
  • De vertaalcatalogi zitten niet meer in het pakket: enkel languages/ow-agenda.pot wordt meegeleverd, het Frans wordt verdeeld via de WordPress.org-taalpakketten die door translate.wordpress.org gevoed worden.
  • De minimale WordPress-versie gaat terug naar 6.3: niets in het pakket hangt nog af van de detectie van meegeleverde vertalingen die in 6.7 werd ingevoerd.

REST API

  • Elke beheerroute declareert haar permission_callback voortaan expliciet in plaats van hem te delen via array_merge(). De capabilitycontrole werd al toegepast; ze is nu zichtbaar voor statische analyse.

Geen enkele gedragswijziging.

1.3.0

Internationalisatie

  • Plugin volledig vertaalbaar (domein ow-agenda, Engels als brontaal): instellingen, publieke pagina’s, API-berichten, e-mails en JavaScript-interface.
  • Sjabloon languages/ow-agenda.pot meegeleverd en volledige Franse vertaling.

Beveiliging

  • De publieke identificaties van de afspraken en de uitnodigingstokens worden gegenereerd door een cryptografische generator (random_bytes()). Die tokens zijn de enige authenticatie van de annulerings-, bevestigings- en uitnodigingslinks.
  • De botval en de tijdstempel zijn verplicht geworden: ze weglaten schakelde de anti-spamcontroles uit.
  • Het uurquotum wordt samengeteld per /64-prefix in IPv6, en een dagplafond beperkt de niet-geverifieerde aanvragen — een bezoeker kan niet langer alle tijdsloten van één dag vasthouden.
  • Het quotum wordt pas na de validatie van het formulier afgeteld: een typfout blokkeert een legitieme bezoeker niet meer een uur lang.

Betrouwbaarheid

  • Gelijktijdige reservaties van hetzelfde tijdslot worden geserialiseerd door een named MySQL-lock. De vorige transactie legde geen enkele rijvergrendeling: twee bezoekers konden hetzelfde uur boeken.
  • De herinnering de dag voordien gebruikt een schuivend venster van 12 tot 36 u en haalt haar achterstand in; elke verzending wordt atomair gereserveerd, twee cron-uitvoeringen kunnen dezelfde herinnering niet meer tweemaal versturen.
  • De uurlijkse taak plant zichzelf automatisch opnieuw in als ze verdwijnt: herinneringen, opruiming en anonimisering kunnen niet meer in stilte stilvallen.
  • Het verplaatsen van een afspraak werkt de agenda van de klant bij (SEQUENCE, METHOD:REQUEST, organisator en deelnemer); de annulering stuurt een METHOD:CANCEL die het item verwijdert.
  • De datums van de widget worden berekend in lokale tijd en niet in UTC: geen verloren dag meer voor bezoekers ten oosten van UTC.
  • De annulering van een afspraak die uit een uitnodiging voortkomt, geeft de uitnodiging vrij, die opnieuw bruikbaar wordt.
  • Geannuleerde afspraken en vervallen niet-bevestigde aanvragen worden niet meer aan de agenda teruggegeven: minder persoonsgegevens in de antwoorden, geen spookafspraken meer.

1.2.1

  • Conformiteit met Plugin Check: escaping van de output, sanitizing van de input, nonce op de instellingen, readme.
  • De deïnstallatie verwijdert ook de tabel van het klantenbestand en het HMAC-geheim.

1.2.0

  • HTML-e-mails (kaartopmaak, accentkleur van de site) voor alle meldingen.
  • Knoppen Bevestigen / Weigeren in de beheerdersmail (HMAC-ondertekende links).
  • Klantenbestand: zoeken, aanmaken, bewerken, verwijderen, snelkoppelingen naar een nieuwe afspraak en een uitnodiging.

1.1.0

  • Dubbele verificatie per e-mail tegen bots (tijdslot 45 minuten vastgehouden, opruiming na 48 uur).

1.0.0

  • Eerste versie: online reserveren, mobile-first beheeragenda, sessie-uitnodigingen, e-mails met agendabestand en herinnering de dag voordien.

Ontworpen door OptionWeb — Julien Daniel, Châtelet, België.