Wie sortiert WordPress eigentlich die Pluginliste?

Wer mir folgt, der weiß, dass ich beim „Plugin Report“-Plugin mitgemacht habe. Ich baute unter anderem eine Javacsript-basierte Sortierung für die Tabelle ein. Vor ein paar Tagen erreichte mich eine Benachrichtigung von Github. Der Autor Roy Tanck fragte mich, ob ich helfen kann. Er hatte eine Supportfrage bekommen, die darauf hinweist, dass die Sortierung abweicht von der Liste auf der Pluginseite.

Und im Zuge des Debbuging bin ich über ein paar interessante Dinge gestoßen. Ich beschäftige mich heute also mal mit alphabetischer Sortierung, Übersetzung und Umlauten.

Das Langweilige zuerst: Die Lösung für die Abweichung der beiden Pluginlisten war recht schnell gefunden und hatte zwei Gründe. Der wichtige zuerst: Ich hatte schlicht und einfach vergessen eine der Spalten als Standard für die Sortierung festzulegen. Die Liste im „Plugin Report“-Plugin hat also direkt nach dem Erstellen der Tabelle gar keine Sortierung, sondern zeigt einfach die Reihenfolge, wie sie vom Verzeichnis kommt. Durch das Hinzufügen eines Attributs ist das einfach gelöst.

Mir war aber noch etwas aufgefallen. Da auch die Liste auf der Pluginseite nach dem Namen (und nicht dem Slug) sortiert, müsste jetzt eigentlich alles gleich sein. Auf meiner Testseite fiel ein Plugin jedoch komplett aus dem Raster und wurde ganz unten angezeigt. Das „Public Post Preview“-Plugin von Dominik Schilling.

Offensichtlich wird also nach dem übersetzten Namen sortiert: „Öffentliche Vorschau für Beitrage“. Das ist der zweite Grund für die Abweichungen. Aus gutem Grund gibt es eigentlich bei den Polyglots die Regel Plugin-Namen nicht zu übersetzen.

Nun ist es trotzdem verwirrend, warum WordPress das „Ö“ ganz nach unten einsortiert und nicht wie „O“ oder „Oe“ behandelt. Also schaute ich mir mal an, wie WordPress eigentlich die Pluginliste sortiert.

Zuständig dafür ist die Klasse WP_Plugins_List_Table aus class-wp-plugins-list-table.php. Darin findet sich die Funktion prepare_items und darin folgende Zeile:

uasort( $this->items, array( $this, '_order_callback' ) );

Via uasort wird eine benutzerdefinierte Vergleichsfunktion (hier _order_callback) benutzt um das Array der Plugin-Items zu sortieren.

Also weiter zu der _order_callback-Funktion:

/**
 * @global string $orderby
 * @global string $order
 * @param array $plugin_a
 * @param array $plugin_b
 * @return int
 */
public function _order_callback( $plugin_a, $plugin_b ) {
	global $orderby, $order;
		$a = $plugin_a[ $orderby ];
	$b = $plugin_b[ $orderby ];
		if ( $a === $b ) {
		return 0;
	}
		if ( 'DESC' === $order ) {
		return strcasecmp( $b, $a );
	} else {
		return strcasecmp( $a, $b );
	}
}

Wobei strcasecmp ein Vergleich von Zeichenketten ohne Unterscheidung der Groß- und Kleinschreibung ist. Mit dem Zusatzhinweis „Binary safe„.

Es werden also keine Sonderzeichen umgewandelt oder entfernt. Und der Vergleich sortiert Umlaute (und wohl auch ein ß) hinter das Alphabet ein.

Ist das denn richtig so? Da gibt es doch bestimmt eine Definition für die Deutsche Sprache. Die Wikipedia lässt mich nicht im Stich. Im Artikel zur Alphabetischen Sortierung:

Das deutsche Alphabet ergänzt das moderne lateinische Alphabet um die Umlaute Ä, Ö und Ü sowie den Buchstaben ß. Diese zusätzlichen Buchstaben können auf vier Arten einsortiert werden:

  1. Ignorieren der Umlautpunkte. Müll wird wie Mull sortiert.
  2. Gleichordnung von Grundbuchstaben, Doppelbuchstaben und Umlaut, wenn Doppelbuchstabe wie Umlaut gesprochen wird. Mull wird wie Muell oder Müll sortiert. Duell dagegen zwischen Duden und Dugast.
  3. Auflösung des Umlauts. Müll wird wie Muell vor Muffe einsortiert.
  4. Separierung als selbstständiger Buchstabe.
    1. Einordnung hinter dem Grundbuchstaben. Müll steht zwischen Muzin und Münze (und Myalgie).
    2. Einordnung am Ende des Alphabets. Müll steht hinter Mythos.

Für alle sonstigen (fremdsprachigen) diakritischen Zeichen gilt im deutschsprachigen Raum, dass sie einheitlich weggelassen werden; so auch alle Akzente, Tilde, Makron: é und e, ç und c, ñ und n, č und c, ō und o sind gleich.

Jetzt sind leider in verschiedenen Ländern sehr unterschiedliche Sortierregeln gültig und daher ist vielleicht die beste Variante es so wie WordPress zu machen und alle Sonderregeln einfach zu ignorieren anstatt komplizierte und sich widersprechende Einzelfälle abfangen zu müssen.

Für Deutsch wäre die Lösung recht simpel. Wir könnten einfach via remove_accents den Plugin-Namen (sofern nach Namen sortiert wird) umwandeln:

		
if ( 'Name' === $orderby ) {
	$a = remove_accents( $plugin_a[ $orderby ] );
	$b = remove_accents( $plugin_b[ $orderby ] );
} else {
	$a = $plugin_a[ $orderby ];
	$b = $plugin_b[ $orderby ];
}

Denn in dieser Funktion gibt es für Deutsch ein paar Sonderregeln:

// Used for locale-specific rules.
$locale = get_locale();
 
if ( in_array( $locale, array( 'de_DE', 'de_DE_formal', 'de_CH', 'de_CH_informal', 'de_AT' ), true ) ) {
$chars['Ä'] = 'Ae';
$chars['ä'] = 'ae';
$chars['Ö'] = 'Oe';
$chars['ö'] = 'oe';
$chars['Ü'] = 'Ue';
$chars['ü'] = 'ue';
$chars['ß'] = 'ss';

Doch leider scheitert dieser Ansatz schon bei der nächsten Sprache. Dänisch hat folgende Sonderregeln:

} elseif ( 'da_DK' === $locale ) {
            $chars['Æ'] = 'Ae';
            $chars['æ'] = 'ae';
            $chars['Ø'] = 'Oe';
            $chars['ø'] = 'oe';
            $chars['Å'] = 'Aa';
            $chars['å'] = 'aa';
        }

Hier basieren die Sortierregeln eher auf Aussprache und nicht auf Schreibweise und passen somit leider nicht zu der Sortierung, die aus den Transliterationen folgt:

æ kommt nach z
ø kommt nach æ
å kommt nach ø

Es wäre also leider ein viel komplexerer Ansatz notwendig, um die jeweiligen länderspezifischen Sonderregeln abzubilden. Und nach meiner Erfahrung mit der NFD/NFC-Problematik ist das WordPress-Projekt nicht in der Lage solche komplexen Projekte zu lösen. Zu gering der Mehrwert und zu aufwändig die Lösung. Obwohl ich das wirklich verstehe, so schmerzt es doch auch immer, diese Ideen sterben zu sehen.

Warum das dringend benötigte „Preferred Languages“-Feature-Plugin noch nicht im Core gelandet ist, verstehe ich in diesem Zusammenhang zum Beispiel auch nicht …

Du hast eine Idee, Anmerkung oder Kritik an meinem Artikel oder kennst eine PHP-Bibliothek, die uns hier die Arbeit abnehmen könnte und aktiv gewartet wird? Dann freue ich mich über deinen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.