Das Putzlowitsch Test- und SEO-Blog

Das neue WordPress 2.7

Ja, ich habe es getan. Ich habe hier auf WordPress 2.7 upgedated. Wenn es schief gegangen wäre, und es ist auch erstmal schief gegangen, wäre es nicht so schlimm gewesen. Das hier ist ja nur das „WordPress bei Strato Testblog“, also zum Testen. Gut, es haben sich in der Zeit seit dem ersten Artikel (der noch nicht mal von mir ist) im Juni 2007 doch einige Beiträge angesammelt, es sind auch durchaus nützliche Plugins enstanden, aber wenn es schief gegangen wäre, hätte ich das verkraften können.

Ja, ich habe auch vorher die Datenbank mit phpMyAdmin gesichert, die neuen WordPress-Dateien per FTP in ein neues Verzeichnis auf dem Server hochgeladen, mit meinem xcopy-Skript alle relevanten Daten der laufenden WP-Installtion (2.5.1) in das neue Verzeichnis übertragen. So hatte ich mein komplettes, altes WordPress sowohl auf Datei- als auch Datenbankeben als Sicherungskopie noch in der Hinterhand, dachte ich zumindest.

Das schöne an dem Kopier-Update-Verfahren ist, man kann einfach durch Umbenennen des Serververzeichnisses auf die neue Version umschalten, und im Fehlerfall auch wieder zurück.
Aber nach dem erforderlichen Datenbank-Update sah alles prima aus. Die neue Adminoberfläche im Backend gefällt mir ausgesprochen gut. Da wollte ich natürlich gleich einen Artikel schreiben, gesagt getan. Doch plötzlich, wie aus heiterem Himmel kommt ein Fehler 500 (schwerer Serverfehler), der schlimmste Fehler, den man sich im Web so vorstellen kann.
Als leidgeprüfter Strato-Nutzer ist man aber auch durch einen 500er nicht wirklich zu erschrecken, den gab es früher oft, wenn man als WP-Neueinsteiger ganz unbeschwert die Permalinks aktiviert hatte. Das war ohne funktionierendes mod_rewrite keine gute Idee. Aber auch das ist nun bei Strato kein Thema mehr.

Weiter lesen (2. Teil)

Keine Kommentare »

WordPress 2.5 – Shortcode und die Bildergalerie

Neue Features

In WordPress ab Version 2.5 wurde die Attachment-Verwaltung erheblich erweitert und verbessert. Sie firmiert nun unter dem Schlagwort Mediathek. Eine wesentliche Erleichterung ist meiner Meinung nach die Möglichkeit, mehrere Dateien (z.B. Bilder) auswählen und in einem Rutsch hochladen zu können. Ein weiteres Highlight sind die sogenannten Shortcodes, kleine Textbausteine, die bei der Ausgabe in viele schöne Sachen verwandelt werden können. Die Shortcodes sin aber eher etwas für Plugin-Entwickler, der normale Nutzer hat erstmal nichts davon.
Einen solchen Shortcode liefert WordPress aber bereits mit, es ist eine einfache Bilder-Galerie.

Die Worpress-Bildergalerie

Aus Anwendersicht ist das mit den Shortcodes ganz einfach, man fügt das gewünschte Kürzel, gegebenfalls mit Parametern, einfach in eckigen Klammern an der Stelle im Text ein, wo die Ausgabe erfolgen soll. Für die WP-Bildergalerie sieht das z.B. so aus:

[gallery columns='2']

Bei der Anzeige das Artikels wird dann dieser Shortcode z.B. durch eine Bildergalerie ersetzt:

So könnte es aussehen. Die Ausgabe läßt sich durch ein paar Parameter steuern, so legt der Parameter ‚columns‘ z.B. fest, wieviele Spalten die Galerie verwenden soll (Standardwert ist 3). Im Beispiel habe ich 2 Spalten eingestellt.
Alle Parameter und die Verwendung des Gallery-Shortcodes sind im WP-Codex beschrieben.

Erweiterung – Der Link

Eine wie ich meine wichtige Sache haben die Entwickler aber vergessen. In der Standard-Galerie wird vom Vorschaubild immer auf die Bilderseite (Beispiel Bild 1) verlinkt, nicht auf das Bild selbst. Das ist so im PHP-Quelltext fest „verdrahtet“. Dabei wäre es kein großes Sache gewesen auch dafür einen Parameter vorzusehen. Aber was nicht ist, kann man glücklicherweise mit einem Plugin nachrüsten. So habe ich einfach die originale gallery_shortcode-Funktion genommen und um den Parameter attlink erweitert. Das Plugin selbst und eine Kurze Beschreibung findet man auf meiner Plugin-Seite „123 Extended Gallery„.

Und noch etwas habe ich verändert. Im Originalcode wird der CSS-Teil zur Formatierung der Galerie direkt in den Artikel geschrieben. Das ist alles andere als HTML-konform. So habe ich den CSS-Teil rausgezogen und in den Header verlegt, dahin wo soetwas hingehört. Einziger kleiner Nachteil, die CSS-Sachen werden immer im Header ausgegeben, auch wenn später im Artikel gar keine Galerie vorhanden ist. Aber damit kann ich leben.

Ein Kommentar »

Hinweis für WordPress-Plugin-Programmierer

Das einfachste Plugin für WordPress besteht nur aus einer PHP-Datei, da gibt es auch keine Probleme. Wenn man aber das Plugin modular gestaltet, eventuell noch Grafiken, Stylesheets oder JavaScript-Dateien laden will, fangen die Schwierigkeiten an.

Das Nachladen von PHP-Modulen ist noch relativ einfach, sofern sich die Dateien im selben Verzeichnis wie das Hauptmodul befinden. Da reicht ein einfaches

include( 'modul-2.php');

und man muß sich keine Gedanken über Pfade und Verzeichnisse machen.

Anders ist es bei Grafik-, CSS- oder Javascript-Dateien. Hier wird eine gültige URL benötigt, also muß man das Verzeichnis wissen, in dem sich das Plugin befindet. Und zwar nicht den absoluten Pfad auf dem Server, sondern den Pfad bezogen auf die Webseiten-Adresse. Häufig sieht man dann so etwas:

$css = get_option( 'siteurl' ).'/wp-content/plugins/my-plugin/my-style.css';

Es wird also einfach davon ausgegangen, daß Plugins immer im Verzeichnis ‚wp-content/plugins‘ liegen. Das müssen sie aber nicht, denn in WordPress ist dafür extra die Konstante PLUGINDIR vorgesehen.

Diese wird in der wp-settings.php wie folgt definiert:

if ( !defined('PLUGINDIR') )
	define('PLUGINDIR', 'wp-content/plugins'); // no leading slash, no trailing slash

Das if ( !defined(‚PLUGINDIR‘) ) läßt erahnen, daß es durchaus vorgesehen ist, hier auch vorab ein anderes Verzeichnis zu definieren. Ganau davon mache ich Gebrauch, indem ich ein abweichendes Plugin-Verzeichnis in der wp-config.php definieren. Das ist eine einfache Möglichkeit, sich ein wenig vor Angriffen auf Schwachstellen in Plugins zu schützen. Denn auch die meisten Angreifer gehen davon aus, daß sie Plugins in Verzeichnis ‚wp-content/plugins‘ liegen, sofern sie überhaupt so intelligent sind.

Wenn nun ein Plugin selbst einfach ‚wp-content/plugins‘ anstelle von PLUGINDIR verwendet, sind Schwierigkeiten vorprogrammiert. Deshalb, liebe Plugin-Programmierer, verwendet bitte immer PLUGINDIR, um Pfade zusammenzusetzen. Für das obige Beispiel könnte das etwa so aussehen:

$css = get_option( 'siteurl' ).'/'. PLUGINDIR.'/my-plugin/my-style.css';

Ich verwende z.B. folgende Funktion, damit ich auch unabhängig davon bin, in welchem Unterverzeichnis innerhalb des Pluginverzeichnisses die Dateien liegen:

// ermittelt das Pluginverzeichnis
function plw123_plugin_basedir( $file ) {
	$file = str_replace('\\','/',$file); // Windows Verzeichnistrenner "umkippen"
	$file = preg_replace('|/+|','/', $file); // doppelte Schrägstriche entfernen
	$file = preg_replace('|^.*/' . PLUGINDIR . '/|','',$file); // relativen Pfad zum Plugin-Dir ermitteln
	return '/'.PLUGINDIR."/$file/";
}

...

$pluginPath = plw123_plugin_basedir( dirname(__FILE__) );
$css = get_option( 'siteurl' ).$pluginPath.'my-style.css';
8 Kommentare »

GROUP BY auf ein Unique Field kann durchaus sinnvoll sein

Kürzlich hatte ich einen Beitrag zu dem Problem mit WordPress und der Sortierreihenfolge bei MySQL 5.0.51 (wie es derzeit bei Strato verwendet wird) geschrieben und mich dort über das vermeintlich unsinnige GROUP BY mit einem eindeutigen Feld (ID) ausgelassen. Für eine einfache SQL-Abfrage, wie dort beim ersten Beispiel, ist das auch durchaus richtig, da ist das „GROUP BY id“ tatsächlich sinnfrei.

Bei WordPress ab Version 2.1 wurde das dann auch geändert, hier wird dieses GROUP BY mit der ID nur noch dann eingefügt, wenn es tatsächlich benötigt wird, nämlich wenn man die Abfrage auf bestimmte Kategorien oder Tags einschränken will. Das könnte z.B. etwa so aussehen:

<?php  query_posts( $query_string.'&cat=1,2,3' ); ?>

Hier will man zum Beispiel nur Artikel anzeigen, die in Kategorie 1, 2 oder 3 enthalten sind. Wenn nun ein Artikel mehreren Kategorien zugeordnet ist, würde das dazu führen, daß dieser Artikel auch mehrmals in der Liste steht und das will man ja nicht. Genau hier bewirkt das GROUP BY id, daß jeder Artikel nur einmal auftaucht. Man hätte das zwar ebenso mit DISTINCT erreicht, aber WP macht es halt mit GROUP BY. Letztendlich ergibt sich daraus ein Problem, welches aber einer fehlerhaften Implementierung von MySQL 5.0.51 zuzuschreiben ist.

Da ich bei mir nicht mit Kategorien oder Tags in den Abfragen arbeite, war mir das bisher auch nicht klar. Erst ein Beitrag im wordpress.org Forum hat mir die Augen geöffnet (Dank an Otto42 für die erhellenden Worte :-).

Was bedeutet das nun für die Praxis? Ganz klar, das Problem kann nur durch ein Update von MySQL behoben werden, da ist dann der Webhoster in der Pflicht. Nun ist es aber nicht ganz einfach, goße Hoster wie Strato dazu zu bewegen, zumal es MySQL 5.0.53 wohl auch noch nicht gibt.
In der Zwischenzeit kann erstmal mein Plugin helfen, welches das GROUP BY id in ein GROUP BY post_date „verbiegt“. Einen kleinen Nachteil hat das aber. Wenn es zwei oder mehrere Artikel mit auf die Sekunde übereinstimmendem Veröffentlichungszeitpunkt gibt, wird nur einer von diesen dargestellt.

Keine Kommentare »

WordPress und die suboptimale MySQL-Optimierung (5.0.51)

Problem

Es ist ja lobenswert, daß Strato relativ schnell die MySQL-Versionen aktualisiert, vor ein paar Tagen von 5.0.45 auf 5.0.51. Man sollte auch denken, daß es dadurch mit Applikationen keine Probleme geben dürfte. Nich so diesmal, denn plötzlich stimmte bei so manchen WordPressinstalltionen die Sortierreihenfolge der Beiträge nicht mehr, wie mehrere Nutzer im WP-Deutschlanforum beklagten. Aber nicht nur Strato war davon betroffen, auch bei 1&1 und anderen Hostern gab es Probleme.

Normalerweise kommen ja die neuesten Artikel zuerst, es wird also absteigen nach Datum sortiert. Nun waren aber plötzlich die ältesten Beiträge ganz oben, als scheinbar eine umgekehrte, also aufsteigende Sortierung. Und niemand hatte bewußt etwas verändert, also keine Plugins installiert oder die Themedateien bzw. die Konfiguration angepaßt. Also konnte es nur am Hoster liegen. Da ich hier bei Schnurpsel diesen Effekt nicht beobachten konnte, dachte ich zunächst doch an irgendein Plugin, bis ich mal spaßeshalber mein WordPress-2.0.x-Testbolg aufgrufen hatte. Und siehe da, auch hier waren die Beiträge plötzlich nicht mehr in der gewünschten Reihenfolge. Da ich dort aber wirklich seit Monaten nichts verändert hatte und nur ein paar eigene Plugins verwende, mußte es doch irgendeine andere Ursache haben. Zumindest hatte ich jetzt die Chance, der Sache auf den Grund zu gehen.

Hintergrund

Meine erster Schritt war, mir mal die von WP generierte SQL-Abfrage anzusehen. Meine Vermutung war zunächst, daß irgendwo die Sortierung (ORDER BY post_date) verloren geht. So sieht die SQL-Abfrage aus:

SELECT DISTINCT *
 FROM wp20_posts
 WHERE 1 =1
 AND post_date_gmt <= '2008-01-11 22:03:59'
 AND (
  post_status = 'publish'
  OR post_author =1
  AND post_status != 'draft'
  AND post_status != 'static' 
 )
 AND post_status != 'attachment'
 GROUP BY wp20_posts.ID
 ORDER BY post_date DESC
 LIMIT 0 , 10

Vom komischen WHERE 1=1 mal abgesehen gab es zumindest keine Auffälligkeiten, die Sortierung ist auch drin aber was soll bitte das GROUP BY wp20_posts.ID? Das Feld ID ist ein Autoinkrement-Feld, also immer eindeutig (UNIQUE) und somit kann es da nie zwei- oder mehrmals den selben Wert geben, also kann auch nichts gruppiert werden. Mit GROUP BY feldname werden normalerweise Datensätze zusammengefaßt, die in dem oder den angegebenen Feldern die selben Werte enthalten. Ein Blick in den Quelltext gibt dann Aufschluß, dieses GROUP BY ist beim Zusammensetzen des SQL-Strings fest codiert und muß daher immer belegt werden, damit die Abfrage syntaktisch richtig ist:

"SELECT $distinct * FROM $wpdb->posts $join WHERE 1=1" . $where . " GROUP BY " . $groupby . " ORDER BY " . $orderby . " $limits";

Wenn keine echte Gruppierung verwendet wird, wird dafür einfach als Dummy-Wert das Feld ID eingesetzt. Normalerweise kein Probem, weil ja eben dadurch nichts gruppiert wird. Und genau deshalb wird sowas auch vom SQL-Server letztendlich wegoptimiert, daß heißt, es steht zwar da, kommt aber nicht zur Anwendung. Außerdem bewirkt ein GROUP BY auch implizit eine Sortierung nach den dort angegebenen Feldern. Und genau hier liegt das Problem.

Wurde bei MySQL vor Version 5.0.51 mit dem GROUP BY für eindeutige Felder auch die implizite Sortierung wegoptimiert, ist das in der neuen Version nun anders. Hier bleit diese Sortierung erhalten, auch wenn keine Gruppierung stattfindet. In den Release-Notes findet man den entsprechenden Hinweis zu diesem Fehler (30596).

Lösung

Betroffen ist, sofern nicht durch Plugins Gruppierungen hinzugefügt oder verändert werden, nur WordPress Version 2.0.x, zu WP 1.x kann ich nichts sagen. Bei WordPress ab Version 2.1 wurde das Verhalten geändert, so daß GROUP BY nur noch dann in den SQL-String eingebaut wird, wenn wirklich eine Gruppierung verwendet werden soll.
Nachtrag: Auch in WordPress ab Version 2.1 kann das Problem auftreten, wenn man etwas mit Kategorien oder Tags (ab 2.3) verändert, also z.B. nur bestimmte Kategorien in die Anzeige einbeziehen will:

<?php query_posts( $query_string.'&cat=1,2,3' ); ?>

Falls man keine spezielle Kategorie- oder Tagkonfiguration verwendet, ergibt sich auch direkt die erste Lösungsmöglichkeit, nämlich auf die neuste WordPress-Version (derzeit 2.3.2) zu aktualisieren.
Falls man das aus irgendeinem Grund nicht möchte oder das Kategorie-/Tagproblem auftritt, ist die zweite Lösung ein Plugin, welches das GROUP BY auf einen nicht störenden Wert zurechtbiegt.
Als WordPress-Plugin sehen die paar Zeilen PHP-Code dann so aus:

<?php
/*
Plugin Name: 123 No Group By ID
Plugin URI: http://schnurpsel.de/wordpress-und-die-suboptimale-mysql-optimierung-5051-74/
Description: Ändert bei WP das GROUP BY id in GROUP BY post_date (Problem ab MySQL 5.0.51).
Author: Ingo Henze
Version: 0.12
Author URI: http://putzlowitsch.de/
*/ 

	// GROUP BY auswerten
	function plw123ngb_posts_groupby( $groupby ) {
		if( preg_match( "/(|[ ,.])id(|[ ,])/i", $groupby ) ) {
			// sonst GROUP BY auf post_date setzen	
			$groupby = 'post_date';
		}
		return $groupby;
	}

	add_filter( 'posts_groupby', 'plw123ngb_posts_groupby' );
?>

Mann kann den Quelltext hier einfach rauskopieren, in einer Datei speichern, auf den Server in das Pluginverzeichnis kopieren und aktivieren. Oder man nimmt das fertige Plugin als ZIP-Datei.

Download: 123 No Group By ID 0.12

Sofern in der "GROUP BY"-Felderliste das Feld ID auftaucht, wird alles durch POST_DATE ersetzt. Das ist zwar so ein bißchen eine "Holzhammermethode", sollte aber in den meisten Fällen keine Nebenwirkungen zeigen. Probleme könnten nur dann auftreten, falls ein Plugin auch irgendwelche Gruppierungen vornimmt und dabei ebenfalls das Feld ID mit einbezieht. Zudem würde für den eher unwahrscheinlichen Fall, daß es zwei oder mehrere Beiträge mit exakt dem selben Veröffentlichungszeitpunkt gibt, nur einer von diesen angezeigt werden.

42 Kommentare »