WordPress Snippets für Custom Post Status

In WordPress gibt es Custom Post Types, Custom Fields, Custom Taxonomies und auch Custom Post Status, um neben Draft, Future, Pending, Private, Publish und Trash eigene Custom Post Status bereitzustellen. Leider wird das Thema in den letzten Jahren sehr stiefmütterlich behandelt und man kann schnell Eindruck gewinnen, dass man am liebsten Custom Post Status komplett aus dem Core entfernen würde. So werden Custom Post Status nicht mehr wirklich in Gutenberg berücksichtigt und ein Ticket, dass Custom Post Status automatisch in die UI bringen soll, ist seit geschlagenen 11 Jahren offen!

Trotzdem haben Post Status meiner Meinung nach einen entscheidenden Vorteil: Sie werden direkt in der wp_posts Tabelle in der post_status Spalte mit einem Index gespeichert. Filtern oder sortieren anhand dieser Spalte ist damit extrem schnell und erfordert kein JOIN zu einer anderen Tabelle, z.B. wp_postmeta im Fall von Custom Post Fields.

Wir nutzen für abgelaufene Angebote bei Travel-Dealz einen Custom Post Status suspended. Dieser ist ‚public‘ => true und wird damit im Frontend den Lesern angezeigt. Somit gibt es Beiträge die ganz normal publish und damit gültig sind und suspended die als abgelaufen markiert sind. Gleichzeitig sortieren wir unsere Beiträge auf der Startseite oder in den Kategorien nach dem Post Status, damit gültige Angebote immer als erstes angezeigt werden.

Nach Post Status sortieren

Wie bereits oben beschrieben, sortieren wir unsere Beiträge nach dem Post Status, indem wir den ORDER BY Teil des SQL-Query ein post_status ASC voranstellen.

function orderby_post_status_main_query( $orderby_statement, $wp_query ) {
	if ( ! is_admin() && $wp_query->is_main_query() && ! $wp_query->is_singular() && ! $wp_query->is_feed ) {
		$orderby_statement = 'post_status ASC, ' . $orderby_statement;
	}
	return $orderby_statement;

}
add_filter( 'posts_orderby', 'orderby_post_status_main_query', 10, 2 );Code-Sprache: PHP (php)

Darauf folgt dann die normale Sortierung i.d.R. nach dem Post Date.

Editor „Publish“ vorgaukeln

Leider unterscheidet Gutenberg bzw. der Block Editor nicht zwischen public Custom Post Status. Zwar crashed Gutenberg auch nicht mehr, wenn ein Custom Post Status übermittelt wird, aber er geht standardmäßig von einem ‚public‚ => false Custom Post Status aus, was dazu führt, dass es so aussieht, als wäre der Artikel nicht veröffentlicht, sondern ein Entwurf.

Da wir serverseitig entscheiden, ob ein Beitrag gültig d.h. publish oder abgelaufen d.h. suspended ist, gaukel ich bei Abfrage über die REST API dem Editor einfach vor, dass ein Beitrag den Post Status publish hat, auch wenn er abgelaufen ist. Dazu manipuliere ich die Ausgabe der API:

function api_without_custom_post_status( $response, $post, $request ) {

	if ( 'suspended' === $response->data['status'] ) {
		$response->data['status'] = 'publish';
	}

	return $response;

}
foreach ( [ 'post', 'my_custom_post_status' ] as $post_type) {
	add_filter( "rest_prepare_{$post_type}", 'api_without_custom_post_status', 10, 3 );Code-Sprache: PHP (php)

Schön wäre es natürlich, wenn die API und auch Gutenberg Custom Post Status unterstützen würde aber dafür müsste erst einmal die REST API Custom Post Status unterstützen und erst anschließend wird es auch in Gutenberg einfließen. Ich habe die Hoffnung aber ehrlich gesagt aufgegeben und begnüge mich mit dem Workaround.

Embeds möglich machen

Dass Custom Post Status von WordPress eher stiefmütterlich behandelt werden, findet man an mehreren Stellen im Code. So auch bei den Embeds. Statt zu checken, ob der aktuelle Post Status public ist, wird einfach nur in der get_oembed_response_data Funktion gecheckt, ob der aktuelle Post Status = publish ist. Sonst wird kein Embed ausgegeben:

if ( 'publish' !== get_post_status( $post ) ) {
    return false;
}Code-Sprache: PHP (php)

Mein Ticket dazu im WordPress Trace inkl. Fix & Unit Tests wird leider immer wieder von Release zu Release weitergeschoben, was mich immer wieder ärgert und mit leider echt die Motivation genommen hat, mehr zum WordPress Core beizutragen.

Das zu umgehen ist leider nicht so trivial. Es gibt aber einen Filter für get_post_status, den wir missbrauchen können. Damit das nur Embeds trifft, müssen wir checken, ob die aktuellen Query Variablen embed enthalten und embed true ist:

function change_public_post_status_for_embeds( $post_status ) {
	global $wp;
	if (
		isset( $wp->query_vars['embed'] ) &&
		true === $wp->query_vars['embed'] &&
		true === get_post_status_object( $post_status )->public
	) {
		$post_status = 'publish';
	}


	return $post_status;

}
add_filter( 'get_post_status', 'change_public_post_status_for_embeds' );Code-Sprache: PHP (php)

Damit sind dann auch wieder Embeds mit Custom Post Status möglich.

Fazit

Leider ist es echt nicht unaufwändig einen eigenen Post Status in WordPress zu etablieren. Man stößt immer wieder an Ecken und Kanten. Trotzdem finde ich meinen Custom Post Status sehr praktisch und gehe dafür den Mehraufwand ein. Ich hoffe, ich konnte euch damit etwas helfen, falls ihr an derselben Stelle steht.

Schreibe einen Kommentar

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