Ziel ist es, Inhalte gleichen Typs, die in zahlreichen WordPress-Posts verstreut sind, auf einer Übersichtsseite zusammenzufassen. Folgende Typen sind z.B. denkbar:
- alle Bilder, die in den Posts enthalten sind bzw. Bilder mit einer bestimmten ID oder Klasse
- alle Tabellen bzw. Tabellen mit einer bestimmten ID oder Klasse
- alle Überschriften bzw. Überschriften einer bestimmten Ebene (h1, h2 usw.)
Die Übersichtsseite soll sozusagen als Bild-, Tabellen-, oder Inhaltsverzeichnis dienen. In meinem Blog "Blaustern Fotografie" gibt es z.B. eine Bildzusammenfassung (siehe Abbildung unten).
Es wird ein Plugin benötigt, welches automatisch den HTML-Code aller Posts durchsucht und die HTML-Elemente des gewünschten Typs zusammenfasst. Der Anwendungsfall soll wie folgt aussehen:
- Der Nutzer legt einen neuen Post oder eine neue Page an, in der die Übersicht eingefügt werden soll.
- Der Nutzer klickt im Admin-Bereich einen speziellen Button an, der sich über dem WordPress-Editor neben dem Button "Add Media" befindet.
- Der Browser sendet daraufhin einen AJAX-Request an den Server, um den HTML-Code für das (Bild-)Verzeichnis anzufordern.
- Der HTML-Code für das Verzeichnis wird an den Browser gesendet und automatisch in den WordPress-Editor eingefügt.
- Der Nutzer kann das Verzeichnis ggf. bearbeiten und speichert anschließend den Post bzw. die Page.
Das Plugin, welches ich zu diesem Zweck entwickle, nenne ich 'specific_directory'. Zuerst lege ich einen neuen Ordner mit diesem Namen an. In dem Ordner erstelle ich eine neue php-Datei ‘specific_directory.php’. Für den Aufbau dieser Datei gibt es einige Konventionen, auf die ich nicht näher eingehen werde (es geht u.a. um Lizenzinformationen und Namenskonventionen). Wenn Sie aber vorhaben, ein Plugin zu veröffentlichen, beachten Sie bitte die Hinweise im WordPress Codex.
Im Folgenden beschreibe ich die Entwicklung des Plugins am Beispiel eines Bildverzeichnisses.
1. Einfügen eines Buttons über dem Editor und Definieren des Ereignis-Handlers
Im Admin-Bereich befinden sich über dem Editor die sogenannten "Media-Buttons" (z.B. der Button "Add Media"). WordPress stellt die Aktion 'media_buttons' bereit. Für sie lässt sich eine Funktion registrieren, die einen oder mehrere "Media-Buttons" hinzufügt. In der PHP-Datei füge ich folgenden Code ein:
add_action('media_buttons', 'specific_directory_image_button');
function specific_directory_image_button() {
echo '<a class="button" id="specific_directory_images_button"
title="Insert image directory">Insert image directory</a>';
}
Die ID und die Beschriftung (title) sollten Sie an Ihren Anwendungsfall anpassen.
Als nächstes muss definiert werden, was beim Anklicken des Buttons mit der ID 'specific_directory_images_button' passiert. Das Anklicken geschieht auf Clientseite im Browser des Benutzers, daher muss die Ereignisbehandlung im Javascript-Code erfolgen. Ich lege eine neue Javascript-Datei mit dem Namen 'specific_directory.js' an. Der folgende Javascript-Code basiert auf der jQuery-API.
jQuery(document).ready(function() {
$('#specific_directory_images_button').click(function(){
var data = {
'action': 'specific_directory_getimages'
};
jQuery.post(ajax_object.ajax_url, data, function(response) {
tinymce.execCommand('mceInsertContent', false, response);
});
});
});
Beim Klick auf den Button wird ein Ajax-Post-Request ausgelöst. Die Adresse, an die der Request geschickt wird, ist in der Eigenschaft 'ajax_url' im Objekt 'ajax_object' abgespeichert. Die Initialisierung des Objekts mit den richtigen Werten wird vom PHP-Code aus gesteuert, den ich weiter unten gleich zeigen werde. Als Post-Parameter wird der Aktionsname 'specific_directory_getimages' mitgeschickt. Dieser Aktion wird im PHP-Code die Funktion zur Erstellung des Verzeichnisses zugeordnet (siehe Abschnitt 2).
Zu beachten ist auch der dritte Parameter der post-Funktion: Es wird eine Funktion angegeben, die bei erfolgreichem Abschluss des Requests ausgeführt werden soll. Der Parameter 'response' dieser Funktion ist die Antwort des Servers, d.h. in meinem Fall der generierte HTML-Code des Verzeichnisses.
Der WordPress-Editor ist ein tinyMCE-Editor. Seine Javascript-Bibliothek stellt ein Kommando 'mceInsertContent' bereit, um automatisch Inhalt in den Editor einzufügen. Im Codeabschnitt oben wird gezeigt, wie die 'response' in den Editor eingefügt wird.
Zurück zur PHP-Datei. Damit beim Laden der Admin-Seite meine Javascript-Datei überhaupt an den Client ausgeliefert wird, muss das Skript registriert werden. Dies geschieht über die Aktion 'admin_enqueue_scripts':
add_action('admin_enqueue_scripts', 'specific_directory_add_script' );
function specific_directory_add_script(){
wp_enqueue_script( 'specific_directory_js', plugin_dir_url( __FILE__ ) .
'specific_directory.js', array('jquery'));
wp_localize_script( 'specific_directory_js', 'ajax_object',
array( 'ajax_url' => admin_url( 'admin-ajax.php' )) );
}
Für das Skript vergebe ich den Titel 'specific_directory_js'. Es ist zu beachten, dass als dritter Parameter von 'wp_enqueue_script' die Bibliothek 'jquery' angegeben wird. Damit wird definiert, dass mein Skript von jQuery abhängig ist. Demzufolge muss das jQuery-Skript von WordPress an den Browser ausgeliefert werden, bevor mein Skript ausgeführt wird.
Mit Hilfe der Funktion 'wp_localize_script' erstelle ich ein Javascript-Objekt mit dem Namen 'ajax_object' und einer Eigenschaft 'ajax_url'. Deren Wert setze ich auf den Pfad zum zentralen Ajax-Verteiler 'admin-ajax.php', der über die WordPress-Funktion 'admin_url' ermittelt werden kann.
Grundsätzlich werden alle Ajax-Requests, die aus dem Admin-Bereich stammen, an 'admin-ajax.php' geschickt. Wenn ich also per Javascript einen benutzerdefinierten Ajax-Request abschicken möchte, muss ich die URL dieser Datei kennen. Ich hätte auch auf den Aufruf von 'wp_localize_script' verzichten und stattdessen die Initialisierung des Javascript-Objekts direkt in der Javascript-Datei vornehmen können. Die URL zur admin-ajax.php hätte ich dann allerdings herausfinden und statisch eintragen müssen. Die oben gezeigte Variante ist im Vergleich dazu flexibler, da sie auch bei einer Änderung der URL gültig bleibt.
2. Implementierung der PHP-Funktion zum Aggregieren von Daten aus sämtlichen Posts
Weiter oben habe ich bereits erwähnt, dass ich 'specific_directory_getimages' als Aktionsname für meinen Ajax-Request gewählt habe. Um diese Aktion in WordPress zu registrieren, rufe ich im PHP-Code einfach die Funktion 'add_action' auf und gebe als ersten Parameter den Aktionsnamen mit dem Präfix 'wp_ajax' und als zweiten Parameter den Namen der zugeordneten PHP-Funktion an. WordPress kümmert sich darum, dass ein Ajax-Request mit meinem Aktionsnamen an die angegebene PHP-Funktion weitergeleitet wird.
add_action('wp_ajax_specific_directory_getimages', 'specific_directory_getimages_callback' );
An dieser Stelle zeige ich die PHP-Funktion zur Erstellung des Verzeichnisses. Diese Funktion müssen Sie für Ihren eigenen Anwendungsfall anpassen. In meinem Fall enthält der Algorithmus im Wesentlichen die folgenden Schritte:
- Ich ermittle die Liste mit allen Posts (wichtig: 'posts_per_page' -1 setzen).
- Jeden einzelnen Postinhalt lade ich in ein DOMDocument-Objekt, um mich bequem durch das Document Object Model (DOM) bewegen zu können.
- Für jeden einzelnen Post ermittle ich eine Liste mit Bild-Elementen (Elemente mit Tag-Name 'img').
- Für jedes Bildelement, welches eine ID besitzt, wird ein HTML-Schnipsel generiert und ausgegeben. Es besteht aus dem Bild selbst, welches in einem Link zu dem Post, der das Bild enthält, verpackt ist. Allerdings liefere ich das Bild nicht in voller Größe aus. WordPress generiert beim Hochladen von Bildern über die Media-Library automatisch einige Varianten des Bildes in kleineren Auflösungen. Da ich die Bilder im Bildverzeichnis als kleine Kacheln darstellen möchte, ergänze ich bei den Bildnamen den Suffix "-300x200".
- Ich lösche jeden Post nach der Analyse mit 'wp_cache_delete' aus dem WordPress-Cache. Damit möchte ich Speicherproblemen vorbeugen.
function specific_directory_getimages_callback() {
$posts = get_posts(array('posts_per_page' => -1));
echo '<div class="my_images_gallery">';
foreach($posts as $post)
{
$doc = new DOMDocument();
$doc->loadHTML($post->post_content);
$tags = $doc->getElementsByTagName('img');
foreach($tags as $tag){
if($tag->hasAttribute("id")){
$id_val = $tag->getAttribute("id");
$path = pathinfo(parse_url($tag->getAttribute("src"))['path']);
$src_val0 = $path['dirname'] . '/';
$src_val1 = $path['filename'];
$src_val2 = strtolower($path['extension']);
?>
<a href=' <?php echo get_permalink($post).'#'.$id_val ?> '>
<img src='<?php echo $src_val0 . $src_val1 . '-300x200.' . $src_val2 ?> '>
</a>
<?php
}
}
wp_cache_delete( $post->ID, 'posts' );
wp_cache_delete( $post->ID, 'post_meta' );
}
echo '</div>';
wp_die();
}
Die zur Darstellung der Bilder benötigten CSS-Angaben habe ich in der Datei styles.css meines Themes hinterlegt. Ein besserer Stil wäre es sicherlich, im Plugin-Ordner eine separate CSS-Datei mit den benötigten Angaben zu hinterlegen und diese über die Aktion 'wp_enqueue_scripts' im PHP-Code zu registrieren. Ein Beispiel dafür finden Sie bei MasterBlogster.
3. Installation des Plugins
Der Plugin-Ordner, der die PHP- und Javascript-Dateien enthält, muss nun in eine zip-Datei verpackt werden. Diese zip-Datei lässt sich bei WordPress im Plugins-Bereich hochladen und aktivieren.
Links
WordPress Codex "Ajax in Plugins" --> Anleitung zum Einsatz von Ajax bei der Plugin-Entwicklung