Bei vielen Kundenprojekten gibt es die Notwendigkeit eigene Inhaltstypen zu hinzuzufügen. In der Regel erstelle ich diese über den wp scaffold post-type
Befehl der WP-CLI. Das erstellt die notwendigen PHP Funktionen inkl. eines Arrays von Labels, die dann übersetzt werden können. In der einfachsten Form kann man einen eigenen Inhaltstyp wie folgt registrieren:
function optn_register_post_type() {
register_post_type(
'sponsor',
array(
'label' => __( 'Sponsor', 'optn' ),
'public' => true,
'has_archive' => true,
'show_ui' => true,
)
);
}
add_action( 'init', 'optn_register_post_type' );
Wann man das has_archive
Flag auf true setzt, erhält man automatisch eine Archivseite für den Inhaltstyp. Wenn man ein paar Einträge angelegt hat und diese Seite aufruft, erhält man eine Liste der Einträge sortiert nach dem Veröffentlichungsdatum, genau wie bei Beträge:
Inhaltstyp nach Namen sortieren
Für den neuen Inhaltstypen Sponsor wollen wir nun nicht nach dem Veröffentlichungsdatum, sondern nach dem Namen sortieren. Wie erreichen wir dies? Nun, das ist recht einfach. Mit einem pre_get_posts
Hook wie dem folgendem lässt sich das umsetzen:
function optn_pre_get_posts_order_by_name( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( is_post_type_archive( 'sponsor' ) ) {
$query->set( 'orderby', 'name' );
$query->set( 'order', 'ASC' );
}
}
add_action( 'pre_get_posts', 'optn_pre_get_posts_order_by_name' );
Dies setzt die Archiv-Query des Inhaltstyps auf eine aufsteigende Sortierung nach Namen (welcher in der Spalte post_title
in der Datenbank gespeichert ist). Nun sieht die Übersicht wie folgt aus:
Perfekt! Genau das, was wir wollten. Öffnen wir nun zum Test einen Sponsor:
Unter dem Inhalt der Sponsor-Seite ist die „Beitragsnavigation“ zu sehen, mit der man zum vorherigen oder nächsten Sponsors weiterblättern kann. Wenn man die beiden Links allerdings mit dem vorherigen Screenshot vergleicht, dann sieht man sehr gut, dass der „Previous Sponsors“ zu „Jetpack“ und der „Next Sponsors“ zu „WooCommerce“ verlinken sollte. Wieso wirkt sich die neue Sortierreihenfolge also nicht auf die Beitragsnavigation aus?
Sortieren der Beitragsnavigation nach den Namen
Innerhalb der the_post_navigation
Funktion, welche verwendet wird um diese beiden Links auszugeben, werden die beiden Funktionen get_previous_post_link
und get_next_post_link
are aufgerufen, um den Link zum vorherigen/nächsten Eintrag zu erhalten. Wenn wir uns die Datenbank-Abfrage ansehen, die dabei verwendet wird, erhalten wir die folgende:
SELECT p.ID
FROM wp_posts AS p
WHERE p.post_date < '2020-08-22 09:00:00'
AND p.post_type = 'sponsor'
AND (p.post_status = 'publish'
OR p.post_status = 'private')
ORDER BY p.post_date DESC
LIMIT 1;
Hier ist zu sehen, dass der Link zu vorherigen Eintrag gesucht wird, indem der Eintrags/Sponsor mit dem nächstkleineren Veröffentlichungsdatum gesucht wird.
Glücklicherweise gibt es Filter, um dieses Verhalten zu ändern. Um die Abfrage anzupassen, müssen wir den WHERE
Teil und der ORDER BY
Teil der Abfrage anpassen. Dies ist die Lösung für den WHERE
Teil:
function optn_get_adjacent_post_where( $where, $in_same_term, $excluded_terms, $taxonomy, $post ) {
if ( 'sponsor' !== $post->post_type ) {
return $where;
}
return preg_replace( '/p.post_date (.) ([^A-Z]+)/', "p.post_title $1 '{$post->post_title}' ", $where );
}
add_filter( 'get_previous_post_where', 'optn_get_adjacent_post_where', 10, 5 );
add_filter( 'get_next_post_where', 'optn_get_adjacent_post_where', 10, 5 );
Statt ein Callback-Funktion für sowohl get_previous_post_where
als auch get_next_post_where
zu schreiben, verwende ich eine einzelne Funktion. Da eventuell auch andere Plugin eine der beiden Hooks verwendet, können wir nicht unbedingt einfach die Rückgabe komplett überschreiben. Daher verwende ich einen regulären Ausdruck, um nur die Teile zu überschreben, wie notwendig sind. Wir suchen also nach p.post_date
und dem Vergleichsoperator sowie dem Datum (hierbei verwenden wir eine Capture-Group, die alle nichtalphabetischen Zeichen findet, um mit verschiedenen Datumsformaten umgehen zu können). Wir ersetzen dann die Stellen mit der Spalte p.post_title
, nach der wir sortieren wollen, dem zuvor ermittelten Vergleichsoperator sowie dem Beitragstitel des aktuellen Beitrags/Sponsor.
Falls ich euch fragt, ob das wirklich funktioniert, das tut es! MySQL ermittelt den korrekte „alphanumerisch kleineren String“, genau wie in einer Sortierung.
Der ORDER BY
Teil ist sehr viel einfacher. Hier müssen wir lediglich die Spalte, nach der sortiert werden soll, ersetzen. Die Sortierrichtung behalten wir wie im Original bei:
function optn_get_adjacent_post_sort( $order_by, $post, $order ) {
if ( 'sponsor' !== $post->post_type ) {
return $order_by;
}
return preg_replace( '/p.post_date/', 'p.post_title', $order_by );
}
add_filter( 'get_previous_post_sort', 'optn_get_adjacent_post_sort', 10, 3 );
add_filter( 'get_next_post_sort', 'optn_get_adjacent_post_sort', 10, 3 );
Nach der Anpassung sollte unsere gesamte SQL-Abfrage wie folgt aussehen:
SELECT p.ID
FROM wp_posts AS p
WHERE p.post_title < 'Siteground'
AND p.post_type = 'sponsor'
AND (p.post_status = 'publish'
OR p.post_status = 'private')
ORDER BY p.post_title DESC
LIMIT 1;
Öffnen wir nun erneut die Einzelansicht, erhalten wir endlich die korrekten Links für den vorherigen/nächsten Eintrag:
Fazit
Die Reihenfolge einer Inhaltstyps auf der Archivseite zu ändern ist wirklich sehr einfach. Aber das ist unter Umständen nicht genug in allen Fällen. Ein Beispiel hierfür ist die Beitragsnavigation, es könnte aber noch andere Stellen geben, an denen die neue Sortierung angepasst werden muss. Ich hoffe also, dass euch dieser Beitrag dabei helfen kann, in ähnlichen Fällen eine Lösung zu finden.
Falls ihr das Ganz mal selbst ausprobieren und den Code anpassen möchtet, dann findet ihr ein funktionsfähiges Plugins zu diesem Beispiel im folgenden GIST.