Archiv für den Monat: Juni 2017

Wahrscheinlich guckt wieder kein Schwein: Scheduled events

Was ist ein Scheduled Event?

Das ist im Prinzip so etwas wie ein Cron-Job, und hier höre ich alle alten Programmierer „Aha!“ rufen. Jeder kennt die Möglichkeit, in Unix/Linux zeitlich wiederkehrende Aufgaben per Cron-Job zu steuern. WordPress bietet mit den Scheduled events eine ähnliche zeitabhängige Funktionssteuerung, und das ist prinzipiell eine schicke Sache, aber es gilt ein paar Eigenheiten zu beachten. Man kann schon festlegen, zu welcher Uhrzeit eine Funktion ausgeführt werden soll, ob sie täglich oder zweimal am Tag oder wöchentlich ausgeführt werden soll und all sowas, aaaber…

Wahrscheinlich guckt wieder kein Schwein

Ein WordPress Scheduled event wird erst ausgeführt, wenn die Blogseite auch aufgerufen wird. Dann guckt WordPress nach, ob es Events gibt, deren festgelegte Uhrzeit bereits abgelaufen ist, und erst jetzt wird die geplante Aktion gegebenfalls ausgeführt. Heißt im Klartext: wenn kein Besucher auf die Webseite kommt, wird auch kein Event ausgeführt. Nein, ich veräppel euch nicht, das ist so. Schlimmstenfalls wird der Event erst genau dann ausgeführt, wenn man selber mal auf seine Webseite geht um zu gucken ob schon was passiert ist. Das ist natürlich datenverarbeitungstechnisch Bockmist, weil es dem reinen Zufall überlassen ist, wann die gewünschte Funktion nun tatsächlich ausgeführt wird.

Und, ist das so schlimm?

Das kommt darauf an. Wenn ich über einen Scheduled Event einen größeren Datenbankabgleich mit richtig vielen Datensätzen fahren will, hätte ich schon gern dass der wie geplant Nachts um 2:00 über die Bühne geht und nicht erst Morgens wenn der erste Besucher auf meiner Webseite hereinschneit. Wenn ich zu bestimmten Zeiten E-Mails mit Informationen über „Neues zum Tage“ an meine Abonennten verschicken möchte, sollen die schon zu einer bestimmten Tageszeit abgesetzt werden und nicht erst Stunden später. Das mal nur so als Beispiele.

Wir wollen mal nicht so kleinlich sein, in den meisten Fällen wird es nicht so gravierend sein, wenn eine geplante Funktion statt um 0:00 erst um 6:27 beim ersten Besucher der Webseite getriggert wird. Man muss es halt wissen, und sich genau überlegen ob es im Einzelfall etwas ausmacht, daß ein geplanter Event erst „irgendwann“ stattfinden wird, und nicht genau zur geplanten Zeit.

Wie plane ich einen Scheduled Event?

Dafür verweise ich auf diesen ausgezeichneten Artikel bei sitepoint, da steht alles in komprimierter, bestens verständlicher Form drin. Ich renne hier nur mal im Schnellgang durch.

Zuerst definieren wir die Funktion, die ausgeführt werden soll,

function mein_event(){  // Mach irgendwas.}

Wir verknüpfen die Funktion mit einem neuen Action hook:

add_action('mein_action_hook','mein_event');

Schließlich setzen wir die Parameter für den Event, dabei nutzen wir die PHP-Funktion time(), die den UNIX-Timestamp für „jetzt“ zurückgibt:

wp_schedule_event(time(), 'hourly', 'mein_action_hook');

Das alles kommt in die functions.php unseres Child-Themes, und sollte dafür sorgen, dass unsere Funktion ab sofort stündlich ausgeführt wird… jedenfalls so ungefähr, wann halt der nächste Besucher hereinschneit. Also ehrlich, mir sträuben sich da sämtliche Nackenhaare, aber anders kann es WordPress halt nicht. Da dürfen sich die Entwickler aber schon nochmal was einfallen lassen!

Workaround und Helferlein

Ja, ich habs gehört, die alten Programmierer habens alle schon eingeworfen: dann basteln wir uns halt einen Cron-Job, der unsere WordPress-Seite automatisch aufruft, sagen wir mal eine Minute nachdem der Scheduled Event fällig war. Wie das geht steht z.B. hier bei Sebastian Widmann , aber das führt mir jetzt endgültig zu weit, das kann sich jeder der möchte selber zusammenpfriemeln.

Wenn man unbedingt mit Wordpess Scheduled events arbeiten will, kommt man an einem sehr ausgefeilten und nützlichen Plugin kaum vorbei:
WP Crontrol bietet eine komfortable Benutzeroberfläche zur Steuerung von Events und Schedules und macht einem das Leben hier deutlich leichter. Ändert zwar nix an der grundlegenden Problematik von „wahrscheinlich guckt wieder kein Schwein“, aber ist zumindest sehr einleuchtend zu bedienen und hilft einem bei mehreren Scheduled Events wirklich, den Überblick zu bewahren.

Hooks – jetzt kommt Action ins Spiel

Was sind WordPress Hooks?

Das kann man googlen, und z.B. die netzialisten haben einen sehr informativen Beitrag zu dem Thema geschrieben. Sehr kurz und knapp gesagt, Hooks sind definierte Ankerpunkte im WordPress-Code, an denen man eigene Funktionen einhängen kann. Dabei unterscheidet man zwischen Action Hooks und Filter Hooks, dazu gleich mehr. Eine umfassende Liste aller WordPress Hooks hat Adam R. Brown in seiner Hook Database zusammengetragen. Auch der Codex zur Plugin API bietet umfangreiche Information zum Thema.

Unterschied zwischen Action und Filter

Ich zitiere hier mal schlicht und unbefangen den Codex:

You can sometimes accomplish the same goal with either an action or a filter. For example, if you want your plugin to change the text of a post, you might add an action function to publish_post (so the post is modified as it is saved to the database), or a filter function to the_content (so the post is modified as it is displayed in the browser screen)

Also: wenn man Beiträge gezielt verändern möchte, z.B. eine Copyright-Zeile an jeden veröffentlichten Beitrag anhängen, gibt es (mindestens) zwei Wege zum Ziel. Hier wird empfohlen: entweder man verwendet einen action-Hook auf den Event publish_post, der beim Speichern eines Beitrags in der Datenbank die Copyright-Zeile anhängt. Oder man hakt sich mit einem Filter auf the_content an den Inhalt des Beitrags ran, und hängt die Copyright-Zeile beim Anzeigen des Beitrags in der Einzelansicht an. So weit so gut – ich hab mir allerdings einen Wolf gegooglet, um ein funktionierendes Beispiel für den action hook zu finden, leider bis jetzt ohne brauchbares Ergebnis. Das mit dem Filter dagegen geht relativ easy:

Der Filter

könnte zum Beispiel so aussehen:

function copyright_nach_post_content($content){
if (is_single()) {	
	$content .= '<p>Hier kommt dein Copyright (C) EL 2017 hin </p>';
}
	return $content;
}
add_filter( "the_content", "copyright_nach_post_content" );

Dieser Code kommt in die functions.php unseres Child-Themes und zieht jedesmal, wenn ein Beitrag aufgerufen wird. Die Abfrage auf if(is_single()) stellt sicher, dass auch wirklich nur Beiträge in der Einzelansicht betroffen sind.

Der entsprechende Action-Hook

war wie oben bereits gesagt nicht aufzufinden. Dann machen wir halt was anderes, wo richtig Action drin ist:

Wir versenden eine Email, wenn ein neuer Beitrag veröffentlicht wurde

Dabei stelle ich euch die simple, aber sehr effektive Funktion wp_mail vor. Der Code sieht so aus:

add_action('publish_post', 'send_emails_on_new_post');

function send_emails_on_new_post($post)
{
    $emails = "evi.s.leu@gmx.de"; 
    $title = get_the_title($post->ID);
    $url = get_permalink($post->ID);
    $message = "Link zum Beitrag: \n{$url}";
 
    wp_mail($emails, "Neuer Beitrag! {$title}", $message); 
}

Zuerst wird der action-hook auf das Ereignis publish_post gesetzt und mit unserer Funktion verknüpft. Diese bekommt als Parameter den $post mit, darüber können wir auf die Attribute des aktuellen Beitrags zugreifen, das tun wir mit der $post->ID. Wir holen uns den Titel und den Permalink und basteln uns daraus eine kleine E-Mail-Nachricht an den oben eingesetzten Empfänger.Die Funktion wp_mail braucht ganz minimalistisch wirklich nur 3 Parameter, den Empfänger, den Betreff und den Inhalt, und schon fluppts! Der Empfänger wird jedesmal benachrichtigt, wenn ein neuer Beitrag veröffentlicht wurde.

Ein übersichtlicher Beitrag zur wp_mail-Funktion ist hier bei OSTraining zu finden, die kompletten Informationen findet ihr natürlich im Codex.