Cees in Cyberspace

Tips & Scripts...

 

Headless WordPress via een Omweg

Headless WordPress via een Omweg

Alle WordPress gebruikers hebben wel eens iets mee gekregen over de traagheid of over de zogenaamde onveiligheid van WordPress. En natuurlijk zijn daar allerlei tools, scripts en plugins voor om dat te verhelpen, maar dat vereist toch diepere kennis en routinematig onderhoud.

Een andere oplossing zou zijn om de WordPress backend los te koppelen van “de voorkant”, de zogenaamde headless benadering. Je frontend bestaat dan niet meer uit PHP bestanden die WordPress functies aanroepen, maar uit maatwerk programmeercode die de WordPress REST API aanroepen.

Die REST API spuugt namelijk dezelfde inhoud uit, die de standaard PHP bestanden ook kunnen laten zien, zij het in een iets ander format. Het overgrote deel van deze content is publiekelijk beschikbaar, omdat die toch ook al op de website getoond zou worden.

Dus dat lijkt ideaal: het gebruikersgemak van de WordPress admin, maar met een “eigen” voorkant! In de praktijk lijkt de WordPress API er echter toch niet zo klaar voor te zijn als wordt beweerd.

Knappe URL’s

Je wilt natuurlijk op je nieuwe headless omgeving ook mooie URL’s aanroepen. Dus www.website.nl/dit-is-een-url/ in plaats van www.website.nl/?wordpressid=123. Want Google wordt blij als je woorden in je URL’s gebruikt en met WordPress zelf kan dat ook heel makkelijk via de Permalinks.

Als je op je headless omgeving een URL zoals www.website.nl/dit-is-een-url/ oproept, dan moet je echter meerdere calls doen om de juiste WordPress content te achterhalen:

je moet er eerst achter komen wat voor soort WordPress item dit is om de juiste content erbij te kunnen halen.

Is het een page, post, custom post of een term, zoals een categorie? Want de posts, de pages, de custom post types en de categorieen in WordPress hebben allemaal eigen API endpoints. Dus je moet ze allemaal op verschillende manieren ophalen; er is (nog) geen “Laat me alle items zien”-methode helaas…

Welke content wil je zien?

Maar om erachter te komen aan welk soort item bovenstaande URL referereert, moet je eerst de slug (in dit geval: ‘dit-is-een-url‘) isoleren. Want die is uniek in WordPress en zou ons dus moeten kunnen vertellen bij welk item hij hoort. Maar hoe? De slug meesturen naar een endpoint in de WordPress API?

Helaas… zo’n endpoint bestaat niet en moet je dus zelf maken. Niet zo moeilijk, maar toch een gemis…

Als het vervolgens een post blijkt te zijn met het id 123, dan roep je het endpoint wpsite.nl/wp-json/wp/v2/posts/123 aan.
Is het een pagina, dan roep je wpsite.nl/wp-json/wp/v2/pages/123 aan.

Is het geen van beiden, dan zal de slug hoogstwaarschijnlijk die van een post categorie zijn (andere taxonomies laten we gemakshalve even achterwege…) Dus zou je in theorie dus het endpoint wpsite.nl/wp-json/wp/v2/categories/123 aanroepen.

Maar dan krijg je de specificaties van de categorie met dat id en niet de berichten in die categorie. Dus zou je beter aanroepen: wpsite.nl/wp-json/wp/v2/posts/?categories=123.

Zou deze 3e call dan ook niets opleveren, dan is het waarschijnlijk een 404.

Dus je bent een aantal losse API calls verder om de juiste content te kunnen tonen in je browser.

En mocht het opgevraagde item dan uiteindelijk niet bestaan, dan heb je ook nog eens geen standaard 404-pagina, want je gebruikt WordPress headless en dus zonder een theme! Dus die 404-pagina moet je zelf maken; dat kan in WordPress (zodat je gebruikers hem zelf kunnen onderhouden), maar ook gewoon in HTML.

Lokale JSON bestanden en een custom route

De standaard WordPress REST API is simpelweg geen snelheidswonder, en als je plugins zoals Yoast of ACF toe gaat voegen (WooCommerce durfde ik niet eens te proberen), dan is het helemaal zeuren.

Een caching plugin lost dit een tikkie op, maar nog steeds niet goed genoeg (of ik ben een nerdy zeurpiet, dat kan ook).

Ik heb er uiteindelijk voor gekozen om een plugin te ontwikkelen die bij elke wijziging van een post of taxonomy het desbetreffende item wegschrijft naar een lokaal, statisch JSON bestand buiten bereik van de webserver. Vervolgens maakt dezelfde plugin een custom WordPress route aan die de JSON bestanden weer ophaalt.

Op deze manier kan je ook – door gebruik te maken van de default WordPress login – de user-gerelateerde items zoals WooCommerce orders afschermen van de publiekelijk beschikbare items zoals posts. Simpelweg: als je /orders/xyz.json wilt opvragen, dan moet je inloggen om te verifieren of jij de eigenaar bent van die order of dat jij wellicht een WordPress beheerder bent.

Met als bijkomend voordeel: je bent voor je website niet meer afhankelijk van WordPress. Dus mocht je een plugin hebben geupdated die opeens een foutmelding genereert of wordt je database traag, dan heb je daar in je frontend geen last van! Want je code leest immers al gegenereerde JSON files uit.

En mocht je de aanmaak van die JSON files te langzaam vinden, dan kun je er altijd nog voor opteren om dat via cronjobs te doen.

Roept u maar!

Heeft iemand de rechtstreekse benadering van de WordPress REST API (met Yoast en ACF) wel geimplementeerd als snelle headless oplossing? Of denk je dat mijn (beta!) plugin een oplossing zou kunnen zijn voor jouw headless issue? Ik hoor het graag…