Cache Warmer automatisch starten
Wanneer je echter je plugins update, dan zullen veel caching plugins de cache leeg gooien. In één keer is je hele site dus ‘niet meer gecachet’ en zal de bezoeker een flink wat tragere site ervaren. Dat wil je natuurlijk voorkomen.
Gelukkig wordt dit ook ondersteunt door de Cache warmer website. Je krijgt namelijk een hoogst persoonlijke ‘eigen URL’ waarmee je direct de ‘opwarm job’ voor jouw website op kan starten.
Toch zit hier een kleine valkuil in. Ten eerste, je moet natuurlijk wel die URL opstarten, wanneer je je plugins hebt geupdate. Maar nog veel belangrijker, het is mogelijk, dat jij ‘automatische updates’ aan hebt staan. En dan vinden al die updates plaats zonder dat jij ervan op de hoogte bent.
Gelukkig is dat allemaal oplosbaar met een klein codefragment.
Laten we eerst eens kijken, hoe zo’n ‘URL voor Cache Warmer’ eruit ziet.
https://app.cache-warmer.com/webhook/cachewarmer/1234/AbC_dEfgHoJklMno_loRGXc_8ThFvjVVWIkSAt28
Deze URL moeten we dus aanroepen. Hoe doe je dat in PHP? Dat is eigenlijk ook weer kinderlijk eenvoudig. Voor het openen van externe URL’s die niet op de site zelf aanwezig zijn heeft WordPress een tweetal functies. wp_remote_get() en wp_remote_post().
Dit zijn typisch functies die je gebruikt om een zogenaamde ‘webhook’ aan te roepen. Een URL die informatie doorgeeft of ophaalt. Met de ‘wp_remote_get’ gebruik je parameters die deel uitmaken van de query string van de URL, dus bijvoorbeeld ‘https://mijnurl.com/?name=Wilko’. Bij een wp_remote_post, is de informatie die je door wilt geven deel van de body van je post.
In ons geval geven we helemaal geen informatie door via de URL. De URL zelf bevat alle informatie. Het is dus lood om oud ijzer of we wp_remote_post of wp_remote_get gebruiken. Maar omdat de wp_remote_get net een heel klein beetje minder overhead heeft, kiezen we voor de wp_remote_get.
Waar roepen we de code aan?
Je weet nu de functie, en je weet welke URL je moet gebruiken. Dus wanneer je helemaal nieuw bent in het programmeren met WordPress zou je wellicht denken, dat de volgende code zou kunnen werken.
<?php
define('MY_WARMER_URL','https://app.cache-warmer.com/de-opgegeven-url');
$response = wp_remote_get(MY_WARMER_URL);
Maar… wanneer wordt deze code aangeroepen?
Zoals je in eerdere snippets hebt gelezen, WordPress zit vol met ‘hooks’, momenten in het programma waarop je in kan haken, om WordPress op het juiste moment de juiste dingen te laten doen.
En het ‘juiste moment’ is in ons geval, wanneer WordPress klaar is met het updaten van alle plugins binnen het huidige update proces. Het maakt hierbij niet uit, of deze updates met de hand of automatisch zijn gestart.
De ‘upgrader_process_complete’ action
Alle magie gebeurt tijdens de ‘upgrader_process_complete’ action. Deze actie wordt aangeroepen voor iedere plugin die geupgrade wordt. Hier schuilen echter een aantal addertjes onder het gras.
Omdat deze functie bij iedere update aangeroepen zal worden, krijg je per update een aanroep van de action. Wanneer je bij iedere aanroep van de action ook de webhoop riching cache warmer op zou starten, zou je toch wel een groot aantal jobs opstarten, meer dan je wilt.
Dit kan je op een aantal manieren voorkomen. En dat doe je door gebruik te maken van ‘Transients’. Een ’transient in WordPress is een tijdelijke variabele die wordt opgeslagen in de database. Zo’n transient lijkt eigenlijk best wel een beetje op een cache: Wanneer de geldigheidsduur voorbij is, houdt de variabele op te bestaan.
Voor onze oplossing gaan we zo’n transient bekijken, maar voor we dit doen, bestuderen we eerst even twee scenarios.
Scenario 1 – Aan het einde van alle updates wordt de webhook aangeroepen
In dit eerste scenario worden eerst alle plugins geupdate. Aan het einde van iedere update wordt gekeken, of dit de laatste plugin was in de lijst die een update nodig had, en als dit zo is wordt de webhook aangeroepen.
Dit is in principe de mooiste oplossing, maar faalt in een aantal situaties.
- Allereerst wanneer je om welke reden dan ook slechts één plugin update, dan zal er een ‘lijst met niet geupdate plugins’ open blijven staan en zal de webhook niet worden aangeroepen, terwijl de cache wel is geïnvalideerd.
- Omgekeerd, wanneer je om welke reden dan ook één of enkele plugins uit wilt sluiten van een update, heb je eenzelfde situatie bij de hand. Het aantal geupdate plugins is ongelijk aan het aantal wat geupdate zou moeten worden.
- En als derde situatie, wanneer om wat voor reden een plugin niet geupdate kan worden, bijvoorbeeld een commerciële plugin waarvan de server tijdelijk niet bereikbaar is, of een plugin waarvan de licentie verlengd moet worden, dan hebben we weer hetzelfde verhaal. Cache is geïnvalideerd, maar de warmer zal niet worden aangeroepen.
Dit zijn situaties die ik in de huidige code van WordPress niet zou weten hoe op te lossen, en daarom gaan we het op een iets minder mooie, maar nog steeds wel efficiënte wijze oplossen.
Scenario 2 – We starten direct met het ‘opwarmen’
Na iedere update kijken we of er een transient met de naam ‘wxp_called_cache_warmer’ bestaat. Bestaat deze, dan roepen we de cache warmer URL niet aan, bestaat hij niet, dan geven we de transient een waarde van ’true’ en een verlooptijd die gelijk is aan 200% van je gemiddelde ‘update tijd’ wanneer je een groot aantal plugins moet updated. Dit is natuurlijk sterk afhankelijk van de plugins (grootte, aantal en gemiddelde update frequentie) die je hebt.
Omdat cache warmer meestal toch enkele minuten nodig heeft om op te starten, zullen er misschien een paar pagina’s, maar in ieder geval niet veel worden gemist. Om je een idee te geven, gemiddeld duurt bij mij een serie plugin updates 10 minuten. Na het activeren van cache warmer duurt het zo’n 8-12 minuten voor de eerste pagina’s worden ‘opgewarmd’.
In mijn geval heb ik dus de verlooptijd van mijn transients op 20 minuten ingesteld. Mocht er dus na 20 minuten opnieuw een plugin geupdate worden, dan zal de aanroep naar cache warmer wel plaats vinden, anders niet.
Maar nu genoeg gekletst, laten we eens met wat code beginnen.
<?php
// Pas de constante aan aan jouw URL:
define('MY_WARMER_URL','https://app.cache-warmer.com/de-opgegeven-url');
add_action('upgrader_process_complete', 'wxp_all_plugins_updated_action', 10, 2);
function wxp_all_plugins_updated_action($upgrader_object, $options) {
if ($options['action'] == 'update' && $options['type'] == 'plugin') {
if (get_transient('wxp_called_cache_warmer') !== true)) {
//Dit is dus de eerste plugin in de lijst die we updaten, we roepen cache warmer aan
$response = wp_remote_get(MY_WARMER_URL); //let op, geen quotes!
if (is_wp_error($response)) {
error_log('Webhook failed ' . $response->get_error_message());
} else {
set_transient('wxp_called_cache_warmer',true, 20*60);
}
}
}
}
Wat doen we hier precies? Laten we eens naar een aantal belangrijke regels kijken
Regel 4:
Hier definieren we de URL, zodat deze makkelijk in de code te gebruiken is. Wanneer je meerdere snippets hebt die deze URL gebruiken, is een betere plaats om deze niet hier maar in je wp-config.php te gebruiken, waar hij beschikbaar is voor alle functies.
regel 9:
In het array ‘$options’ komt informatie mee over wat er op dit moment geupdate is. Dat kan ‘core’, ‘plugin’, ‘language’ of ’theme’ zijn. We willen deze code alleen in het geval van een plugin update uitvoeren. Wanneer we dit weg zouden laten. En alleen bij een ‘update’ niet bij een ‘install’.
regel 11:
Als er geen transient met de waarde ’true’ is, dan starten starten we de webhook regel 13).
regel 15:
Als zich een fout heeft voorgedaan, kortom, de webhook is niet uitgevoerd, dan loggen we de foutmelding in de errorlog. We laten de transient met rust.
regel 17:
Als het goed is gegaan, dan stellen we de transient in op 20*60 seconden, ofwel 20 minuten.
Merk hierbij op, dat omdat we rond regel 15 geen transient zetten, bij de volgende plugin upgrade opnieuw gepoogd wordt om de webhook uit te voeren. Mocht het dus niet gelukt zijn door bijvoorbeeld een drukke server, dan wordt er net zo vaak opnieuw geprobeerd als er plugins in de update lijst staan.
Ik hoop dat je veel plezier van deze integratie zal hebben. En natuurlijk, je kan het idee achter deze code natuurlijk ook gebruiken voor andere acties die zouden moeten gebeuren na het updaten van je plugins.