Plug-in-Entwicklung für WordPress

Individuell: WordPress wird angerichtet
Kommentare

Wordpress hat sich als Blogsystem innerhalb von vier Jahren zum De-Facto-Standard der (privaten) Web-2.0-Kommunikation etabliert. Neben dem transparenten Bedienkonzept begeistern vor allem die Möglichkeiten zur einfachen Erweiterung und Anpassung an individuelle Bedürfnisse. Erfahren Sie im folgenden Artikel, wie einfach es ist, selbst ein Teil der ständig wachsenden Entwickler-Community zu werden.

Der von Tim O’Reilly geprägte Begiff Web 2.0 sollte ursprünglich nur die Unterschiede verschiedener Dienste verdeutlichen. Die Beobachtung einer veränderten Nutzung bestehender Technologien zur Bereitstellung neuer Services ließ einen Trend weg von einer einseitigen, hin zu einer bidirektionalen Kommunikation erkennen. Nutzer des Web 2.0 konnten sich also nun an Inhalten beteiligen, und so maßgeblich zu einer neuen Art der Meinungsbildung beitragen, die sich inzwischen zu einem signifikanten Marketingfaktor gemausert hat.

Inzwischen hat das moderne Marketing die Tragweite erkannt und versucht nun, diese für sich zu nutzen. Der Begriff Web 2.0 wurde unterdessen zu einer Art Innovationssiegel und Erfolgsgarantie verwurstet, sodass er zunehmend nur noch als Marketingworthülse wahrgenommen wird.

X-(Word)Press yourself

Eine der bekanntesten und erfolgreichsten Kommunikationsplattformen des Web 2.0 ist WordPress. Einen besonders wichtigen Faktor für die breite Unterstützung eines solchen Systems brachte WordPress von Anfang an mit: Es muss durch seine Einfachheit auch für weniger technisch versierte Nutzer beherrschbar sein – und hier konnte WordPress nicht nur bei den Besuchern, sondern insbesondere auch bei den Entwicklern punkten. Die Möglichkeit zur Installation von Plug-ins für weitere Zusatzfunktionalität und Anpassung an eigene Bedürfnisse wurde bei WordPress schon innerhalb der ersten Entwicklungsmonate integriert.

Im Folgenden möchte ich anhand eines konkreten Beispiels zeigen, welche Möglichkeiten von WordPress für eine tiefgreifende Erweiterung des Systems bereitgestellt werden. Zum Nachvollziehen der hier beschriebenen Schritte gehen wir von einer Standardinstallation aus (s.h. auch den folgenden Kasten WordPress: Installation).

WordPress: Installation WordPress unterliegt der GPL und benötigt für ein reibungsloses Arbeiten PHP mindestens in der Version 4.2 und MySQL ab Version 4.0. Für den Servereinsatz werden Apache und Litespeed empfohlen. Zunächst brauchen wir die zu installierenden WordPress-Dateien. Nach dem Herunterladen und Entpacken im DocumentRoot des Servers müssen wir vor der eigentlichen Installation noch die Datei wp-config-sample.php öffnen und die Zugangsdaten für die Datenbank eintragen. Die Angaben für DB_NAME, DB_USER undDB_PASSWORD werden von den meisten Hostingpaketen vorgegeben, sodass die Bestückung zu keinen Problemen führen sollte. Anschließend muss die Datei unter dem Namen wp-config.php abgespeichert werden. Jetzt kann die Installation über Aufruf der index.php gestartet werden. Die Installationsroutine möchte nun wissen, wie der Titel des Blogs und Ihre E-Mail-Adresse lautet. Die aktivierte Checkbox zur Bestätigung des Anpingens diverser Blog-Suchmaschinen sollten wir – insbesondere im Hinblick auf das noch im Folgenden zu entwickelnde Plug-in – unverändert belassen. Nach einem Klick auf WordPress Installieren legt der Installer alle notwendigen Tabellen in der Datenbank an und hat zudem für den Nutzer admin ein Zufallspasswort generiert. Diese Daten werden zur Sicherheit von WordPress in diesem Augenblick auch noch per E-Mail an die zuvor eingegebene Adresse gesendet. Mit diesen Zugangsdaten kann man sich nun unter www.meinedomain.de/wp-login.phpin das Backend einloggen. Das Passwort lässt sich anschließend über Benutzer | Autoren & Benutzer ändern.

Plug-in-Architektur

Die Entwickler haben besonderes Augenmerk auf eine klare Trennung von Systemkern und Plug-ins gelegt. WordPress erwartet die Plug-in-Dateien im Ordner /wp-content/Plug-ins. Je nach Funktionsumfang handelt es sich nur um eine einzelne Datei oder aber um mehrere Dateien, die dann oft in einem weiteren Unterordner gebündelt werden. Eine solche Plug-in-Datei enthält in der Regel das HTML-Layout für ein mögliches Interface sowie die Funktionen, die später dann im Contentbereich oder Template eingesetzt werden können. Innerhalb dieser Plug-in-Definition kommuniziert man über von WordPress bereitgestellte Funktionen, mit denen man beispielsweise über das Backend eingetragene Parameter abspeichern kann. Jede Plug-in-Definition enthält zudem Angaben über den Namen des Plug-ins, den Autor, eine Kurzbeschreibung, Versionsnummer und einen Link zur Entwickler-Homepage. Ein Teil dieser Angaben wird zur Ausgabe der Plug-in-Auswahl im WordPress-Backend benötigt. Dort können gewünschte Erweiterungen unter Plugins | Plugins vor der ersten Verwendung aktiviert und auch wieder deaktiviert werden.

Abb. 1: Erweiterungen werden unter Plug-ins übersichtlich aufgelistet

Beispiel-Plug-in: SEO to go

Zur Erweiterung des Funktionsumfangs soll im Beispiel nun ein SEO-Plug-in zur Unterstützung eines suchmaschinenfreundlicheren Aufbaus erstellt werden. Dabei gehen wir von folgenden Überlegungen aus: WordPress hat, wie viele andere Foren- oder Blogsysteme auch, einen dreistufigen Informationsaufbau: Startseite, Kategorien/Archiv und Detailseiten mit Kommentaren. Problem hierbei ist, dass nur aktuelle Artikel einen direkten Link von der Startseite zu einer oft detailreicheren Seite mit Kommentaren erhalten. Für weitere und ältere Artikel gibt es also keine direkte Verbindung. Doch genau diese benötigen Suchmaschinen für eine schnelle und zuverlässige Indexierung der Inhalte. Ein weiteres Problem ergibt sich durch die mangelhafte interne Verlinkung, die einer Seite, bzw. Artikeln eine aussagekräftige Bedeutung zuweisen kann. In diesem Zusammenhang hat vor allem der Text innerhalb eines Links eine große Bedeutung, die der Zielseite damit zugewiesen wird.

Das von uns zu erstellende Plug-in soll also direkte Links von der Startseite zu den Artikelseiten und eine höhere interne Verlinkungsdichte erzielen. Auch hier bietet sich – wie bereits in meinem Artikel zur Suchmaschinenoptimierung des phpBB-Boards in Ausgabe 02.08 beschrieben – der Einsatz einer Footer-Navigation an, die eine beliebige Anzahl von steuerbaren internen Links aufnehmen kann. Durch die Verwendung einer solchen Navigation auf jeder Seite erreicht man bereits mit nur wenigen Artikeln eine gute Verlinkungsdichte und garantiert für die Suchmaschinen kürzeste Wege zur Zielseite.

Der Aufbau des hier beschriebenen Plug-ins ist identisch mit dem crawlink-Plug-in, das auf meiner Homepage zusammen mit weiteren Informationen zum kostenfreien Download zur Verfügung steht.

[ header = Seite 2: Frisch ans BlogWerk ]

Frisch ans BlogWerk

Zur Umsetzung der beschriebenen Funktionalität werden wir uns auf eine einzelne Plug-in-Datei beschränken können. Die folgende Datei können wir mit einem einfachen Texteditor zusammenstellen. Zu Beginn benötigen wir zunächst die bereits erwähnte Beschreibung von Autor und Plug-in:

<?php
/*
Plug-in Name: meinPlugin
Plug-in URI: http://www.entwicklersei.te/Pluginseite
Description: Kurzer Beschreibungstext des Plug-ins
Author: Autorenname
Version: 1.0
Author URI: http://www.entwicklersei.te
*/
...

Backend

Da wir unser Plug-in mit diversen Parametern steuern möchten, entscheiden wir uns aus Gründen der Flexibilität nicht für eine Konfigurationsdatei, sondern eine Verwaltungsmöglichkeit über das Backend. Die Oberfläche soll über Plug-ins als Untermenü erreichbar sein. Diesen neuen Menüpunkt melden wir wie folgt an:

add_action('admin_menu', 'meinPlugin_config_page');

Diese Funktion erhält als zweiten Parameter den Namen der Funktion, die Weiteres veranlasst und jetzt noch definiert werden muss:

function meinPlugin_config_page(){
global $wpdb;
if ( function_exists('add_submenu_page') )
add_submenu_page('Plugins.php', 'meinPlugin', 'meinPlugin', 1, '', 'meinPlugin_conf');
}

Die Funktion add_submenu_page() bindet nun das eigentliche Untermenü ein. Als Parameter wird an erster Stelle die beherbergende Datei des WordPress-Systems erwartet. Da unser Menüeintrag innerhalb der Plug-in-Seite erscheinen soll, muss hier Plugins.php eingetragen werden. Es folgen der Seitentitel und der Menütitel. Mit der anschließenden 1 wird der minimale Userlevel definiert, der für einen Zugriff erforderlich ist. Der letzte Parameter enthält schließlich den Namen der Funktion, die wir für die Backend-Darstellung nutzen und im Anschluss – wie in Listing 1 gezeigt – definieren.

function meinPlugin_conf() {

// meinPlugin Konfiguration speichern
if(isset($_POST['meinPlugin_conf_save'])){
meinPlugin_conf_save();
}
$keywords = stripslashes(meinPlugin_get_option('meinPlugin_keywords'));
$headline = stripslashes(meinPlugin_get_option('meinPlugin_headline'));
$cols = stripslashes(meinPlugin_get_option('meinPlugin_cols'));
$max_items = stripslashes(meinPlugin k_get_option('meinPlugin_max_items'));
$max_chars = stripslashes(meinPlugin_get_option('meinPlugin_max_chars'));
$cats = stripslashes(meinPlugin_get_option('meinPlugin_cats'));
$output_style = stripslashes(meinPlugin_get_option('meinPlugin_output_style'));
$item_wrapper = stripslashes(meinPlugin_get_option('meinPlugin_item_wrapper'));
$more = stripslashes(meinPlugin_get_option('meinPlugin_more'));
$css = stripslashes(meinPlugin_get_option('meinPlug-in k_css'));
$infooter = stripslashes(meinPlugin_get_option('meinPlugin_infooter'));
if("1"==$output_style){$check1="checked ";} else {$check2="checked ";}
if("1"==$infooter){$check3="checked ";} else {$check4="checked ";}

// meinPlugin Konfiguration anzeigen
?>
	





Optionen

<input type="text" name="headline" value="" size="60" style="font-size:12px;">

<input type="text" name="cols" value="" size="5" style="font-size:12px;"> <input type="text" name="max_items" value="" size="5" style="font-size:12px;"> <input type="radio" name="output_style" value="1"> <input type="radio" name="output_style" value="2">
    /
  • <input type="text" name="max_chars" value="" size="5" style="font-size:12px;"> <input type="text" name="more" value="" size="20" style="font-size:12px;"> <input type="text" name="item_wrapper" value="" size="20" style="font-size:12px;"> <input type="radio" name="infooter" value="1"> On <input type="radio" name="infooter" value="0"> Off
<input type="text" name="cats" value="" size="130" style="font-size:12px;"> <input type="text" name="keywords" value="" size="130" style="font-size:12px;">

<?php }

Damit hätten wir die Ausgabe des Backend-Formulars zur Verwaltung der diversen Parameter und schon ein wenig Lese- und Speicherlogik programmiert. Gehen wir die definierten Bereiche nochmals durch:

  • Vor der eigentlichen Ausgabe wird abgefragt, ob das Formular zuvor mit neuen Werten abgeschickt wurde. Ist dies der Fall, werden die jeweiligen Werte über die FunktionmeinPlugin_conf_save() in der Datenbank abgespeichert.
  • Vor der eigentlichen Ausgabe werden alle Werte mit der Funktion meinPlugin_get_option() aus der Datenbank ausgelesen um sie im folgenden Formular einsetzen zu können.

Insgesamt finden sich hier folgende Parameter wieder: Headline als Überschrift oberhalb der zu generierenden Footer-Navigation, Spalten zur Definition der auszugebenden Spaltenanzahl, Max Links zur Begrenzung der Anzahl aller Links, HTML-Layout zur Auswahl einer – oder listenbasierten Ausgabe, Linklänge zur Begrenzung der Zeichenanzahl je Linktext und Cut-off zur Definition einer Zeichenkette, die auf einen abgeschnittenen Linktext hinweist, wenn dieser über seine maximale Zeichenanzahl hinausgeht.

  • Über Wrapper können jedem Link noch weitere Zeichen umschließend hinzugefügt werden; der Platzhalter %% steht dabei für den Link selbst.
  • Über Autofooter kann bestimmt werden, ob die Footer-Navigation automatisch in den Fußbereich eingebunden wird.

Die Parameter Categories und Keywords sind für den späteren Plug-in-Einsatz von zentraler Bedeutung, denn die hier hinterlegten Kategorien und Begriffe definieren die Links, die später in der Footer-Navigation erscheinen. Wenn beispielsweise bei Categories „Aktuell, Entwicklung“ eingetragen wird, sollen nur Links zu den Artikeln erscheinen, die diesen Kategorien zugeordnet sind. Ähnliches gilt für Keywords: Hier können mehrere Begriffe eingetragen werden, von denen mindestens einer im Titel eines Artikels erscheinen muss, wenn zu diesem ein Link in der Footer-Navigation generiert werden soll.

Insbesondere bei vielen Artikeln sollte man sich über die Definitionsmöglichkeiten auf ein paar wenige Schwerpunktthemen fokussieren, damit es der Suchmaschine bei der „Sinnfindung“ so einfach wie möglich gemacht wird. Im Folgenden müssen wir nun noch die bereits verwendeten Funktionen meinPlugin_get_option() zum Auslesen und meinPlugin_conf_save() zum Speichern der Daten definieren, siehe Listing 2.

function meinPlugin_get_option($option_name){
global $meinPlugin_options_initialized;
if($meinPlugin_options_initialized==0) {
add_option('meinPlugin_keywords', '', 'meinPlugin Parameter','yes');
add_option('meinPlugin_headline', 'Important Links', 'meinPlugin Parameter','yes');
add_option('meinPlugin_cols','4', 'meinPlugin Parameter','yes');
add_option('meinPlugin_max_items','120', 'meinPlugin Parameter','yes');
add_option('meinPlugin_max_chars','35', 'meinPlugin Parameter','yes');
add_option('meinPlugin_cats','', 'meinPlugin Parameter','yes');
add_option('meinPlugin_output_style','1', 'meinPlugin Parameter','yes');
add_option('meinPlugin_item_wrapper','%%', 'meinPlugin Parameter','yes');
add_option('meinPlugin_more','...', 'meinPlugin Parameter','yes');
add_option('meinPlugin_css','', 'meinPlugin Parameter','yes');
add_option('meinPlugin_infooter','1', 'meinPlugin Parameter','yes');
$meinPlugin_options_initialized = 1;
}
$option = get_option($option_name);
return $option;
}

Über die verwendete Funktion add_option() legt WordPress beim ersten Aufruf ein entsprechendes Feld in der Datenbank zur Aufnahme der Daten an. Neben dem Namen des zu speichernden Werts folgt als zweiter Parameter der Standardwert. Anschließend werden über get_option() die Werte ausgelesen und zurückgeliefert. Die in meinPlugin_conf_save() (Listing 3) verwendete Funktion update_option() speichert unter Angabe des Parameternamens den neuen Wert in der Datenbank ab. Damit hätten wir die Erstellung unseres neuen Backend-Bereichs abgeschlossen.

// meinPlugin_conf_save()
function meinPlugin_conf_save()
{
update_option('meinPlugin_keywords', $_POST['keywords']);
update_option('meinPlugin_headline', $_POST['headline']);
update_option('meinPlugin_cols', $_POST['cols']);
update_option('meinPlugin_max_chars', $_POST['max_chars']);
update_option('meinPlugin_max_items', $_POST['max_items']);
update_option('meinPlugin_cats', $_POST['cats']);
update_option('meinPlugin_output_style', $_POST['output_style']);
update_option('meinPlugin_item_wrapper', $_POST['item_wrapper']);
update_option('meinPlugin_more', $_POST['more']);
update_option('meinPlugin_infooter', $_POST['infooter']);
update_option('meinPlugin_css', $_POST['css']);
}

[ header = Seite 3: Frontend ]

Frontend

Nachdem alle relevanten Daten für eine Verwendung für die Ausgabe vorliegen, können wir diese nun über die Funktion aus Listing 4 vorbereiten.

function meinPlugin()
{
global $wpdb;

$keywords = trim(stripslashes(meinPlugin_get_option('meinPlugin_keywords')));
$headline = meinPlugin_get_option('meinPlugin_headline');
$max_items = meinPlugin_get_option('meinPlugin_max_items');
$max_chars = meinPlugin_get_option('meinPlugin_max_chars');
$cols = meinPlugin_get_option('meinPlugin_cols');
$cats = trim(meinPlugin_get_option('meinPlugin_cats'));
$output_style = meinPlugin_get_option('meinPlugin_output_style');
$item_wrapper = trim(meinPlugin_get_option('meinPlugin_item_wrapper'));
$more = trim(meinPlugin_get_option('meinPlugin_more'));
$infooter = meinPlugin_get_option('meinPlugin_infooter');
$css = trim(meinPlugin_get_option('meinPlugin_css'));

// SQL-Suchkriterium für Artikeltitel vorbereiten
if(""!=trim($keywords))
{
$karray=split(",",$keywords);
foreach($karray as $keyword)
{
$where_items[]="post_title LIKE '%".trim($keyword)."%'";
}
$where="AND (".implode(" OR ",$where_items).") ";
}


// Alle Ergebnisse auslesen
if(""==$cats)
{
// Query ohne Kategoriefilterung
$sql= "SELECT ID, guid, post_title FROM wp_posts ".
"WHERE post_status='publish' AND post_type='post' ".$where.
"ORDER BY post_title ASC LIMIT 0, ".$max_items;
}
else
{
// Query mit Kategoriefilterung
$karray=split(",",$cats);
foreach($karray as $cat)
{
$cat_items[].="cat_name = '".trim($cat)."'";
}
$catfilter=implode(" OR ",$cat_items);

$sql= "SELECT ID, guid, post_title FROM wp_posts p, wp_post2cat p2c, wp_categories c ".
"WHERE post_status='publish' AND post_type='post' ".$where.
"AND p2c.category_id=c.cat_ID AND p2c.post_id=p.ID ".
"AND (".$catfilter.") ".
"GROUP BY ID ORDER BY post_title ASC LIMIT 0, ".$max_items.";";
}

$a=$wpdb->get_results($sql);


// Aufbau des Contents
$content="nr".$headline."nr";

// Links vorbereiten
if(is_array($a))
{

foreach($a as $k => $v)
{
// Kategoriefilterung, wenn angegeben
if(strlen($a[$k]->post_title)>$max_chars)
{$linktext=substr($a[$k]->post_title,0,$max_chars).$more;}
else {$linktext=$a[$k]->post_title;}

$link="post_title).""
href="".$a[$k]->guid."">".strip_tags($linktext)."";

// Item-Wrapper
$link=str_replace("%%",$link,$item_wrapper);
$contentlink[]=$link;
}

// Output-Style
if(1==$output_style)
{
$o['outer']="span";
$o['inner_open']="";
$o['inner_close']="";
}
else
{
$o['outer']="ul";
$o['inner_open']="
  • "; $o['inner_close']="
  • "; } // Auf Spalten verteilen $anzahl=count($contentlink); $items_pro_spalte=$anzahl/$cols; $ccounter=1; $mcounter=1; $first=true; $content.="nr"; foreach($contentlink as $link) { if(false==$first) { if(floor(($mcounter/$items_pro_spalte))==$ccounter) { $ccounter++; $content.="nrnr"; } $mcounter++; } $content.="t".$o['inner_open'].$link.$o['inner_close']."nr"; $first=false; } $content.="nr"; } $out="nr
    ".$content."
    "; echo $out; }

    Gehen wir hier auch wieder Schritt für Schritt durch den Code:

    • Zunächst werden alle Werte über meinPlugin_get_option() aus der Datenbank ausgelesen. Unterhalb von //SQL-Suchkriterium für Artikeltitel vorbereiten erfolgt nun die Aufbereitung eines MySQL-Statements, um später die Adressen der Artikel zu finden, die mindestens einen der angegebenen Begriffe im Titel enthalten.
    • Im Block unter //Alle Ergebnisse auslesen werden nun alle relevanten Artikel bestimmt. Hier wird nochmal unterschieden zwischen //Query mit … und ohne Kategoriefilterung.
    • Im Anschluss wird unter //Aufbau des Contents der auszugebende Inhalt zusammengesetzt und über ein abschließendes echo ausgegeben.

    Im Template lässt sich nun über  die Footer-Navigation an beliebiger Stelle ausgeben. Da das Einbinden der Navigation auch automatisch erfolgen können soll, fügen wir noch ein paar Funktionen hinzu:

    function meinPlugin_active()
    {
    $currentPlugins=get_option('active_Plugins');
    if (in_array("meinplugin.php",$currentPlugins))
    {
    return (true);
    }
    return (false);
    }
    
    if (true===meinPlugin_active())
    {
    if(1==meinPlugin_get_option('meinPlugin_infooter'))
    {
    add_action('wp_footer', 'meinPlugin');
    }
    add_action('wp_head', 'add_css');
    }
    

    Über meinPlugin_active() stellen wir dem weiteren Code eine Funktion zur Verfügung, die prüfen kann, ob das Plug-in überhaupt aktiviert wurde. Falls dies der Fall ist, sucht WordPress nach einem Footerbereich. Existiert dieser, wird über add_action() unsere Funktion meinPlugin() zur Ausgabe aufgerufen. Über die letzte Zeile wird noch möglicher CSS-Code, der über das Backend hinterlegt wurde, in den Headerbereich der Ausgabeseite eingefügt.

    Da die letzte Funktion add_css() noch nicht existiert, müssen wir diese abschließend noch definieren:

    function add_css()
    {
    $css = trim(meinPlugin_get_option('meinPlugin_css'));
    if(""!=$css)
    {
    echo "nn";
    echo $css;
    echo "nn";
    }
    
    }
    ?>
    

    Geschafft! Jetzt müssen wir unsere Datei noch unter dem Namen meinplugin.php im Plug-in-Ordner von WordPress abspeichern. Nach der Aktivierung fehlt dann nur noch die Konfiguration, und unser Plug-in verrichtet seine erste Arbeitsstunde als Footer-Navigation.

    Fazit

    Die Plug-in-Entwicklung mit WordPress ist keine Zauberei: Das System bietet viele Funktionen zur einfachen internen Kommunikation, dem Speichern und Auslesen von Daten und vielem mehr. Ein Blick auf die Entwicklerdokumentation lässt erahnen, welche eigenen Ideen sich elegant und schnell umsetzen lassen.

    Nach diesem kurzen Einstieg in die Plug-in-Entwicklung kann man gut nachvollziehen, warum WordPress mit seiner wirklich flexiblen Architektur so gut ankommt.

    Unsere Redaktion empfiehlt:

    Relevante Beiträge

    Meinungen zu diesem Beitrag

    X
    - Gib Deinen Standort ein -
    - or -