Erstellen eines eigenen WordPress Plugins

Montag, der 2. Juni 2008. Veröffentlicht von René.

Wie man, wenn man PHP programmieren kann, ein eigenes WordPress Plugin entwickelt, ist hier eigentlich sehr gut erklärt: WordPress Codex - Writing a Plugin. Und hier gibt es auch eine super Anleitungen zum Thema: DevLounge.net - How to write a WordPress Plugin. Das wichtigste was man wissen muss, um loslegen zu können, fasse ich hier trotzdem noch einmal kurz auf Deutsch zusammen. Dabei soll dieser Beitrag nur den Einstieg in die Entwicklung von WordPress-Plugins erleichtern und geht nicht auf konkrete Anwendungsfälle ein. Notwendiges Detailwissen um bestimmte Probleme zu lösen, kann man sich zum Beispiel über die “WordPress Codex“-Seite je nach Bedarf aneignen.
Alle gezeigten Beispiele können auch als Beispiel-Plugin am Ende des Beitrags heruntergeladen werden.

Namensraum

Das wichtigste: Alle Funktions- und Klassennamen sowie die Namen der Options (auf die ich gleich noch eingehen werde), sollten eindeutige Namen haben, damit es keine Überschneidungen mit anderen Plugins, oder schlimmer WordPress selbst gibt. Es empfiehlt sich einfach einen Präfix (zum Beispiel mindestens “mb_” für ein Plugin “Mein Beispiel”) zu verwenden.

Plugin: Header

Es muss eine neue PHP-Datei mit einem speziell strukturierten Kommentar ganz oben angelegt werden:

<?php
/*
Plugin Name: Mein Beispiel Plugin
Plugin URI: http://www.rene-ade.de/inhalte/anleitung-howto-tutorial-erstellen-eines-eigenen-wordpress-plugins-wordpress-plugin-selbst-schreiben.html
Description: Ein Beispiel Plugin
Version: 1.2.3
Author: Rene Ade
Author URI: http://www.rene-ade.de
*/
?>

Dieser Kommentar wird von WordPress ausgelesen und für die Anzeige im Plugin-Management verwendet.
Erstellen eines eigenen WordPress Plugins
Dateien ohne einen solchen Kommentar werden von WordPress nicht als Plugin angezeigt.

Hooks: Actions und Filter

Nach diesem Kommentar kommt dann der Code des Plugins. Um WordPress zu erweitern gibt es so genannte Hooks, unterteilt in “Actions” und “Filters”. Im WordPress Code gibt es sehr viele Stellen an denen ein Plugin über einen solchen Hook in WordPress eingreifen kann (Liste aller WordPress Hooks). An diesen Stellen benachrichtigt WordPress alle aktivierten Plugins die für diesen Hook eine Funktion hinterlegt haben die zur Ausführung kommen soll.

Wird WordPress beim Laden des Blogs initialisiert, wird zum Beispiel der Hook “init” durchlaufen. Dieser Hook ist eine “Action”, da die Plugins nur auf diese Aktion reagieren (Code ausführen) können, jedoch keine spezielle Möglichkeit zur Manipulation zur Verfügung stehet. Möchte ein Plugin Code einbringen, der beim Initialisieren eines Blogs ausgeführt werden soll, muss die auszuführende Funktion die den Code beinhaltet, wie folgt über den Funktionsnamen als Action im WordPress System registriert werden:

// Funktion die beim initialisieren des Plugins aufgerufen werden soll
function mb_meine_beispiel_funktion_action_init() {
  // tut irgend etwas
}
 
// Funktion als Init-Action registrieren
add_action( 
  'init', // Das ist der Name des Hooks
  'mb_meine_beispiel_funktion_action_init' // Das ist der Name der Funktion die ausgeführt werden soll
);

Es gibt natürlich auch Actions die beim Aktivieren und Deaktivieren eines Plugins durchlaufen werden. Diese beinhalten den Plugin-Namen im Namen der Action. Dieser sollte am besten dynamisch ermittelt werden. Dazu hier ein Beispiel:

// Funktion die beim aktivieren des Plugins aufgerufen werden soll
function mb_plugin_wird_aktiviert() {
  // ...
}
// Funktion die beim deaktivieren des Plugins aufgerufen werden soll
function mb_plugin_wird_deaktiviert() {
  // ...
}
 
// Die aktivieren/deaktivieren Funktionen registrieren
add_action( 'activate_'.plugin_basename(__FILE__),   'mb_plugin_wird_aktiviert' );
add_action( 'deactivate_'.plugin_basename(__FILE__), 'mb_plugin_wird_deaktiviert' );

Jetzt zu den Filtern: Filter funktionieren genau wie Actions, unterscheiden sich jedoch darin, das Filter einen übergebenen Wert bei Bedarf ändern können. Der änderbare Wert wird als erster Parameter an die Filter-Funktion übergeben und muss (egal ob geändert oder nicht), zwingend von dieser Funktion wieder zurückgegeben werden. Oft werden außer dem zur Änderung übergeben Parameter auch noch weitere Parameter übergeben, die für die Filter-Funktion hilfreich sein könnten. Die Parameter werden übrigens immer byValue übergeben, sind also nicht veränderbar. Folgender Code registriert einen Filter für “the_content” und hängt im Beispiel damit jedem Beitrag/Seite den Text “Hallo Welt” an den Ausgabe-Text an:

// Die Funktion die den Inhalt eines Beitrags/Seite bearbeiten soll
function mb_meine_beispiel_funktion_filter_content( $content ) {
  $content .= 'Hallo Welt'; // hängt dem Inhalt "Hallo Welt" an
  return $content; // gibt den manipulierten Inhalt zurück
}
 
// Die Funktion zum bearbeiten des Inhalts als Content-Filter registrieren
add_filter(
  'the_content', // Wieder der Name des Hooks
  'mb_meine_beispiel_funktion_filter_content' // Der Name der Funktion die den Content bearbeitet
);

Da für fast jede erdenkliche Stelle im WordPress Code eine Action oder ein Filter durchlaufen wird, kann fast alles über ein Plugin erweitert und fast jeder Inhalte verändert werden.
Hier noch einmal der Link, zu einer Liste aller WordPress Hooks: http://wphooks.flatearth.org/

Options: Konfigurationsdaten abspeichern

Wer ein Plugin mit Konfigurationsmöglichkeiten erstellt, wird die Konfiguration auch irgendwo abspeichern müssen. Das geht ganz einfach in so genannten “Options”. WordPress hat für diese Options eine Tabelle in der Datenbank in der also Daten zu einem bestimmten Schlüssel über die Funktionen add_option(…), get_option(…) und update_option(…) serialisiert abgelegt, gelesen und aktualisiert werden können. Mit delete_option(…) können die Daten wieder komplett entfernt werden. Ein Beispiel dazu ist im Widget-Beispiel weiter unten enthalten.
Bitte dran denken: Wer Daten (Options, eigene Tabellen, neue Tabellen-Spalten, …) irgendwo im WordPress-System ablegt, sollte diese später wenn das Plugin deaktiviert wird, bitte auch wieder entfernen! Die passende Action habe ich ja oben schon erwähnt.

WPDB: Datenbankabfragen

Für die meisten Abfragen gibt es bereits komfortable Funktionen wie zum Beispiel get_post(…) um das Datenobjekt eines bestimmten Posts (Beitrag oder Seite) zu bekommen, oder get_posts(…) um alle Posts auszulesen die bestimmten Kriterien entsprechen. Wer keine Funktion von WordPress finden konnte um bestimmte Werte aus der Dankenbank abzufragen, kann selbst Querys über das globale Objekt $wpdb der WPDB-Klasse ausführen.
Mit der Methode query(…) können Manipulationen an der Datenbank vorgenommen werden. Ein einzelner Wert wird am besten mit der Methode get_var(…) abgefragt, die den gewünschten Wert direkt zurückgibt. Die Methode get_row(…) gibt eine Ergebnis-Zeile als Array oder Objekt zurück. Und mit der Methode get_results(…) können umfangreichere Datenbankabfragen durchgeführt werden: Diese Methode liefert alle abgefragten Datensätze in einem Array zurück, wobei die Elemente des Arrays (wie ein einzelner Rückgabewert bei get_row(…)) auf Wunsch die Spalten einer Ergebnis-Zeile in einem Array oder als Objekt enthalten.

function mb_meine_beispiel_querys() {
  // $wpdb als global deklarieren
  global $wpdb;
 
  // Die Seite 15 der Seite 7 unterordnen
  $wpdb->query( "UPDATE $wpdb->posts SET post_parent=7 WHERE ID=15 AND post_type='page'" );
  // Den Anzeigenamen des Users mit der ID 1 auslesen und anschließend ausgeben
  $name = $wpdb->get_var( "SELECT display_name FROM $wpdb->users WHERE ID=1" );
  echo $name;
  // Den kompletten Beitrag mit der ID 3 in ein assoziatives Array einlesen und dann davon die Anzahl der Kommentare ausgeben
  $beitrag = $wpdb->get_row( "SELECT * FROM $wpdb->posts WHERE ID=3", ARRAY_A );
  echo $beitrag['comment_count'];
  // Die IDs und Titel aller Beitrags-Entwürfe in Objekte auslesen und anschließend die Titel ausgeben
  $entwuerfe = $wpdb->get_results("SELECT ID, post_title FROM $wpdb->posts WHERE post_type='post' AND post_status='draft'");
  foreach( $entwuerfe as $entwurf ) {
    echo $entwurf->post_title;
  }
}

Das WPDB-Objekt beinhaltet wie im Beispiel verwendet übrigens auch die korrekten Tabellen-Namen der WordPress Tabellen in Membervariablen.
Für die gezeigten Query-Beispiele, gibt es natürlich jeweils auch eine entsprechende WordPress-Funktion, die diese Aufgabe übernimmt und statt eigenen Querys unbedingt verwendet werden sollte. Eigene Querys sollten nur verwendet werden, wenn WordPress wirklich keine Möglichkeit bietet die Änderung/Abfrage über interne dafür vorgesehene Funktionen durchzuführen.
Wichtig: Bei der Verwendung von Benutzereingaben oder sonstigen von Benutzern manipulierbaren Daten in Querys, sollte unbedingt sichergestellt sein, dass keine SQL-Injections eingeschleust werden können!

Widgets

Erstellen eines eigenen WordPress PluginsDas Bereitstellen eines neuen Widgets für die Sidebar ist relativ einfach. Mit register_sidebar_widget(…) kann eine Funktion angegeben werden, die dann von WordPress an der Stelle aufgerufen wird, an der der HTML-Code des Widgets in der Sidebar ausgegeben werden soll. Die dazugehörende Konfigurationsoberfläche lässt sich wenn gewünscht mit register_widget_control(…) hinzufügen.
Folgender Code genügt um ein “Hallo Welt”-Widget hinzuzufügen:

// Funktion zur Ausgabe des Widgets
function mb_mein_hallowelt_widget( $args ) { // $args enthält Strings die vor/nach dem Widget und vor/nach dem Titel ausgegeben werden sollen
  // Ausgabe
  echo $args['before_widget'];
  echo $args['before_title'].'Mein "Hallo Welt"-Widget'.$args['after_title'];
  echo 'Hallo Welt!';
  echo $args['after_widget'];
}
 
// Widget Funktion im "plugins_loaded"-Hook registrieren
function mb_mein_hallowelt_widget_registrieren() {
  register_sidebar_widget( // Widget registrieren
    'Mein "Hallo Welt"-Widget', // Name des Widgets
    'mb_mein_hallowelt_widget' // Name der Funktion die den Widget Inhalt ausgibt
  );
}
add_action( 'plugins_loaded', 'mb_mein_hallowelt_widget_registrieren' );

Erstellen eines eigenen WordPress PluginsUnd hier ein Beispiel in dem ich den Inhalt eines Widgets über die Konfigurationsoberfläche editierbar mache, in einer Option speichere und im Widget dann wieder ausgebe:

// Funktion zur Ausgabe des Widgets
function mb_mein_widget_widget( $args ) { // $args enthält Strings die vor/nach dem Widget und vor/nach dem Titel ausgegeben werden sollen
  // Option lesen
  $meineoption = get_option( 'mb_meine_option' );
  // Ausgabe
  echo $args['before_widget'];
  echo $args['before_title'].'Mein Widget'.$args['after_title'];
  echo $meineoption['widgetinhalt']; // Inhalt des Widgets
  echo $args['after_widget'];
}
// Funktion zur Ausgabe der Widget-Konfiguration
function mb_mein_widget_konfiguration() {
  // Option lesen
  $meineoption = get_option( 'mb_meine_option' );
  // Option Array aktuallisieren
  if( $_POST['mb-widget-submit'] ) {
    $meineoption['widgetinhalt'] = stripslashes( $_POST['mb-widget-inhalt'] ); 
    update_option( 'mb_meine_option', $meineoption ); // Option in der Datenbank updaten
  }
  // Konfigurationsoberfläche ausgeben
  echo '<p>'.'Meine Widget Konfiguration';
    echo '<input type="text" id="mb-widget-inhalt" name="mb-widget-inhalt" value="'.$meineoption['widgetinhalt'].'" /><br />';
  echo '</p>';
  echo '<input type="hidden" name="mb-widget-submit" id="mb-widget-submit" value="1" />';
}
 
// Widget Funktionen im "plugins_loaded"-Hook registrieren
function mb_mein_widget_beispiel_registrieren() {
  // Widget registrieren
  register_sidebar_widget(
    'Mein Widget', // Name des Widgets
    'mb_mein_widget_widget' // Name der Funktion die den Widget Inhalt ausgibt
  );
  // Konfigurationsoberfläche registrieren
  register_widget_control(
    'Mein Widget', // Name des Widgets
    'mb_mein_widget_konfiguration' // Name der Funktion die den Widget Konfiguration ausgibt
    // optional kann noch die Größe angegeben werden
  );
}
add_action( 'plugins_loaded', 'mb_mein_widget_beispiel_registrieren' );
 
// Option registrieren wenn das Plugin initialisiert wird
function mb_mein_widget_beispiel_init() {
  // Option hinzufügen
  add_option( 
    'mb_meine_option', // Key der Option
    array( // Ein Array um mehrere Werte zu speichern
      'widgetinhalt' => 'Hallo Welt' // 
    )
  );
}
add_action( 'init', 'mb_mein_widget_beispiel_init' );
 
// Option wieder aus der Datenbank entfernen wenn das Plugin deaktiviert wird!
function mb_mein_widget_beispiel_deaktivieren() {
  // Option aus der Datenbank entfernen
  delete_option( 'mb_meine_option' );
}
add_action( 'deactivate_'.plugin_basename(__FILE__), 'mb_mein_widget_beispiel_deaktivieren' );

Wichtig: Die Funktion zum Registrieren eines Widgets kann erst aufgerufen werden, wenn WordPress initialisiert ist, also muss die Funktion aus einem WordPress Hook aus aufgerufen werden, und nicht direkt aus dem Script selbst! Es wird empfohlen, den im Beispiel verwendeten Hook “plugins_loaded” zu verwenden. Wird die Funktion zum Registrieren des Widgets aufgerufen, wenn WordPress noch nicht initialisiert ist, kommt es sonst zu folgendem Fehler:

Fatal error: Call to undefined function: register_sidebar_widget()

Achtung: Wer ein Widget anbieten möchte, sollte beachten dass es auch Themes gibt die keine Widgets unterstützen. Es sollte also eine Möglichkeit geschaffen werden, das Widget über einen einfachen Funktionsaufruf direkt aus dem Template-File des Themes einbinden, und konfigurieren zu können.

Administrationsoberfläche

Erstellen eines eigenen WordPress Plugins Ähnlich wie beim Hinzufügen der Widget-Konfigurationsoberfläche, können auch ganze Konfigurationsseiten in die WordPress-Administrationsoberfläche hinzugefügt werden. Mit add_menu_page(…) kann eine neue Menü-Seite eingefügt werden. Jedoch wird man in den meisten Fällen nur eine Unter-Seite in ein bestimmtes Menü einfügen wollen. Das geht mit der Funktion add_submenu_page(…). In folgendem Beispiel wird eine solche Unterseite mit dem Namen “Beispiel” zum “Verwalten”-Menü hinzugefügt:

// Funktion zur Ausgabe der Beispielseite
function mb_meine_beispielseite() {
  echo '<div class="wrap">';
    echo '<h2>Hallo Welt</h2>';
    echo 'Das ist meine Beispiel Seite';
  echo '</div>';
}
 
// Beispielseite im "admin_menu"-Hook registrieren
function mb_meine_beispielseite_registrieren() {  
  add_submenu_page( // Unterseite zum "Verwalten"-Menü hinzufügen
    'edit.php', // Die übergeordnete Seite, das "Verwalten"-Menü
    'Mein Beispiel-Plugin', // Titel der Seite, wenn die Seite angezeigt wird
    'Beispiel', // Anzeigename des Menü Unterpunkts
    10, // Benutzerlevel das erforderlich ist um die Seite aufrufen zu dürfen (10 = Nur der Admin-User) (siehe http://codex.wordpress.org/User_Levels) 
    'mb', // Eindeutiger Name für die Verlinkung
    'mb_meine_beispielseite' // Name der eigenen Funktion die den Seiten Inhalt ausgibt
  );
}
add_action( 'admin_menu', 'mb_meine_beispielseite_registrieren' );

Wichtig: Die Funktion zum Registrieren einer neuen Seite kann nur in der Action “admin_menu” aufgerufen werden. Sonst wird folgender Fehler ausgegeben:

Fatal error: Call to undefined function: add_submenu_page()

Der aktuelle Beitrag

Die globale Variable $post beinhaltet beim Betrachten eines einzelnen Beitrags übrigens immer das entsprechende Objekt. Und $posts beinhaltet beim Betrachten eines Archivs die Objekte aller angezeigten Beiträge in einem Array.

function mb_beispiel_the_loop() {
  if( is_single() || is_page() ) { // Es wird gerade ein einzelner Beitrag angezeigt
    // Es wird ein Beitrag oder eine Seite angezeigt
    echo 'Es wird gerade ein einzelner Beitrag oder eine Seite angezeigt';
    // $post als global deklarieren
    global $post;
    // den Titel des aktuellen Posts bzw der aktuellen Seite ausgeben
    echo '<li>'.$post->post_title.'</li>';
  }
  else if( is_archive() ) { // Es wird ein Archiv angezeigt
    // Es wird ein Archiv angezeigt
    echo 'Es wird gerade ein Archiv angezeigt';
    // $posts als global deklarieren
    global $posts;
    // alle Posts durchgehen
    foreach( $posts as $post ) {
      // den Titel des aktuellen Posts ausgeben
      echo '<li>'.$post->post_title.'</li>';
    }
  }
}

Beispiel-Plugin

Die hier gezeigten Beispiele können auch als komplettes Beispiel-Plugin heruntergeladen werden: Beispiel-Plugin downloaden
Im Beispiel-Plugin ruft das “Hallo Welt”-Widget zusätzlich noch die Funktion mb_beispiel_the_loop() (aus dem letzten Beispiel) auf, und gibt somit zusätzlich den Titel des aktuellen Beitrags/Seite bzw. die angezeigten Titel des aktuellen Archivs mit aus.
Die Funktion mb_meine_beispiel_querys() ist im Beispiel-Plugin zwar enthalten, wird aber nicht aufgerufen, also nicht ausgeführt.


Weiterlesen


Kategorien: Entwicklung, WordPress

Stichwörter: , , , , ,

Verwandte Beiträge:

Verlinken


  • TwitThis
  • Technorati
  • Google
  • Yigg
  • Digg
  • MisterWong.DE
  • del.icio.us
  • StumbleUpon
  • Hype
  • Webnews.de
  • blogmarks
  • Spurl
  • Sphinn
  • Simpy
  • blinkbits
  • Furl
  • Blogosphere News
  • Yahoo! Buzz
  • Live
  • MySpace
  • Facebook
  • LinkedIn
  • Wikio
  • YahooMyWeb
  • E-mail this story to a friend!

5 Kommentare zu “Erstellen eines eigenen WordPress Plugins”

  1. Von Cywhale

    Interessanter Beitrag, vor allem der Widget-Teil wird mir sicherlich zukünftig helfen.

  2. Von Reddie

    Guter Beitrag, aber das Wort “gedownloadet” tut schon sehr weh!

    Antwort: Habs korrigiert (”heruntergeladen”)…

  3. Von matthias

    danke. sehr hilfreiche erklärungen.

  4. Von Wordpress Plugins selbst schreiben

    […] Etwas sehr gut verständliches habe ich zudem heute noch bei René Ade gefunden. […]

  5. Von René

    Danke für die kurze Einführung. Hat mir sehr weitergeholfen.

Die Kommentare dieser Seite können über folgendes Feed verfolgt werden: Kommentar-Feed dieser Seite

Kommentare per eMail abonnieren

Einen Kommentar schreiben

Bei Fragen zu Software von mir bitte unbedingt die verwendete Version angeben und bei Fragen zu WordPress Plugins bitte zusätzlich auch die Version der WordPress-Installation!
Alle Kommentare werden erst nach manueller Prüfung freigegeben.

Bitte vor dem Absenden des Kommentars die Datenschutzhinweise lesen!