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.