Als ich letztes Wochenende in Philadelphia beim WordCamp US war, hatte ich einige Beiträge für den Adventskalender vorgeschrieben. Da ich meine Artikel immer um 9 Uhr morgen veröffentlichen wollte, dies aber um 3 Uhr nachts Ortszeit gewesen wäre, habe ich die Artikel „geplant“, damit sie pünktlich online gehen. Leider hat das an zwei Tagen nicht funktioniert, was mir erst sehr spät mitgeteilt wurde.
Woran es genau lag, kann ich leider aktuell nicht sagen. Es kam aber die Frage auf, wie die Artikel veröffentlicht werden und wie hierbei der Reihenfolge ist. Das möchte ich heute versuchen rauszufinden und euch berichten.
Automatisierung mit WP-CRON
Die Basis für das zeitgesteuerte Veröffentlichen ist ein sogenannter Cronjob. Dies sind Vorgänge, die in einem bestimmten Intervall ausgeführt werden. Ein solcher Cronjob kann beispielsweise direkt auf einem Webserver. Dies kann ein Nutzer entweder über den Befehl crontab
tun, oder aber über eine Administrationsoberfläche seines Hosters.
Da allerdings nicht alle Hostingangebote diese Möglichkeit bieten, hat WordPress einen eigenen Mechanismus dafür im Angebot, die wp_cron()
Funktion. Hiermit lassen sich ähnlich wie mit crontab
wiederkehrende Aufgaben zu einem bestimmten Zeitpunkt ausführen.
Intervalle definieren
Auf Unix-Systemen kann ein Cronjob in der Regel nur minimal einmal pro Minute ausgeführt werden. WordPress bietet drei Standardintervalle an, in denen Aufgaben ausgeführt werden können:
- hourly
- twicedaily
- daily
Es ist allerdings auch in WordPress möglich, ein eigenes Intervall (wie etwa minütlich) einzuführen. Hier ein Beispiel für ein Intervall von 1 Minute:
add_filter( 'cron_schedules', 'wp_cron_minutely_add_cron_schedules' ); function wp_cron_minutely_add_cron_schedules( $schedules ) { if ( ! isset( $schedules['1min'] ) ) { $schedules['1min'] = array( 'interval' => 60, 'display' => esc_html__( 'Every minute', 'wp-cron-minutely' ), ); } return $schedules; }
Die Zeitangabe für das Intervall ist immer in Sekunden. Es ist also sogar möglich, ein Intervall von minimal 1 Sekunde zu definieren. Dies sollte man aber vermutlich aufgrund der negativen Auswirkungen auf die Performance der Seite eher vermeiden.
Eine wiederkehrende Aufgabe definieren
Nachdem wir nun gesehen haben, welche Intervalle es gibt und wie man eigene definieren kann, sehen wir und nun an, wie man eine Aufgabe in einem solchen Intervall ausführen lässt. Zuerst einmal definieren wir eine neue Action (diese sollte nicht dem Namen einer bereits bestehenden Aktion entsprechen):
add_action( 'wp_cron_minutely_cron_hook', 'wp_cron_minutely_cron_exec' );
Wir haben also nun eine Action definiert und eine Callback-Funktion, die beim Aufruf dieser Aktion ausgeführt werden soll. Nun müssen wir noch den zeitlichen Aufruf dieser Aktion festlegen. Hierzu verwenden wir die Funktion wp_schedule_event() inklusive unserem selbst definierten Intervall:
if ( ! wp_next_scheduled( 'wp_cron_minutely_cron_hook' ) ) { wp_schedule_event( time(), '1min', 'wp_cron_minutely_cron_hook' ); }
Zuletzt müssen wir nur noch die Callback-Funktion definieren. Hier ein einfaches Beispiel:
function wp_cron_minutely_cron_exec() { if ( $calls = get_option( 'wp_cron_minutely_cron_hook_calls' ) ) { update_option( 'wp_cron_minutely_cron_hook_calls', $calls + 1 ); } else { add_option( 'wp_cron_minutely_cron_hook_calls', 1 ); } }
Die Funktion zählt also lediglich eine Option bei jedem Aufruf um 1 hoch. Da die Funktion innerhalb eines normalen WordPress Requests aufgerufen wird, könnt ihr innerhalb der Funktion auf fast alle WordPress Funktionen zurückgreifen.
Aufgabe wieder entfernen
Falls ihr eine Aufgabe definiert, dann solltet ihr darauf achten, dass ihr sie auch wieder entfernt, sobald sie nicht mehr benötigt wird. Denn ansonsten wird sie dauerhaft ausgeführt. Habt ihr beispielsweise eine solche Aufgabe in einem Plugin definiert, dann bietet es sich an, beim Deaktivieren des Plugins die Aufgabe wieder zu entfernen:
register_deactivation_hook( __FILE__, 'wp_cron_minutely_deactivate' ); function wp_cron_minutely_deactivate() { $timestamp = wp_next_scheduled( 'wp_cron_minutely_cron_hook' ); wp_unschedule_event( $timestamp, 'wp_cron_minutely_cron_hook' ); }
Auch wenn die Action und die Callback-Funktion nach der Deaktivierung ohnehin nicht mehr verfügbar sind und „nichts passiert“, sollte man trotzdem immer hinter sich aufräumen.
Zeitpunkt der Ausführung der Aufgabe
Nun kommen wir zu der spannenden Frage zu Beginn des Artikels zurück. Wann genau wird diese wiederkehrende Aufgabe nun ausgeführt und hat sie somit direkten Einfluss auf die aktuelle Anfrage? Gerade beim zeitlich gesteuerten Veröffentlichen von Beiträgen eine wichtige Frage, denn entweder sieht der Besucher dann direkt den neuen Beitrag oder aber erst nach einem erneuten Laden der Seite.
Ich konnte zwar leider nicht rausfinden wieso, aber Beiträge werden direkt beim ersten Laden der Seite nach dem Erreichen des eingestellten Zeitpunkts angezeigt. Eventuell ist der Prozess einfach so schnell fertig, dass er vor der Abfrage an die Datenbank schon fertig ist.
Denn der Aufruf von „wp_cron“ passiert auf der „init“ Action. Wird hierbei festgestellt, dass eine Aufgabe ausgeführt werden soll, dann wird ein separater Request an die „wp-cron.php“ ausgeführt, damit der aktuelle Seitenaufruf nicht unterbrochen wird.
Wer nun aufgepasst hat, wird also gemerkt haben, dass solche Aufgaben nur dann ausgeführt werden, wenn auch ein Besucher auf die Seite kommt. Möchtet ihr also sicherstellen, dass eine Aufgabe auch dann aufgerufen wird, wenn gerade kein Besucher auf der Seite ist, dann solltet ihr die „wp-cron.php“ über einen normalen Cronjob aufrufen oder über einen der diversen Webdienste für die Ausführung von Cronjobs.
Fazit
Ich hoffe ich konnte euch mit dem Artikel eine kleine Einführung geben, wie man in WordPress wiederkehrende Aufgaben definieren kann. Für weitere Informationen seht ihr euch am besten die Anleitung im Developer Handbook an.
Selbstverständlich habe ich euch auch dieses Mal wieder aus dem Code des Artikels ein kleines Plugin gebastelt und als GIST zur Verfügung gestellt. Also probiert es einfach mal selbst aus. Und wenn ihr mir sagen könnt, wieso ein geplanter Beitrag gleich beim ersten Laden der Seite angezeigt wird, dann hinterlasst doch bitte einen Kommentar mit der Erklärung 🙂
Hallo Bernhard.
Danke für Deinen interessanten Bericht.
Ich halte es im Übrigen mit meinen WP-Sites so, dass ich WP-Cron über die Config ausschalte (aus Performancegründen) und über einen externen „echten“ Cron die Site bzw. „wp-cron.php“ (bespielsweise zweimal am Tag) aufrufe.
Grüße Mario