Einen Inhalt eines Inhaltstyps über eine andere Titelform anzeigen
Veröffentlicht: – Kommentar hinterlassen
… oder um es mit technischen Begrifflichkeiten auszusprechen: Ein einzelner Post eines Post Types soll über einen anderen Slug angezeigt werden. Über die Google-Suche habe ich hier leider keine sinnvollen Treffer gefunden, denn als Ergebnis erhielt ich lediglich Anleitung dazu, wie man die Titelform des gesamten Inhaltstyps verändern kann.
In meinem konkreten Fall ging es darum, dass eine Produktauflistung standardmäßig unter /produkt/produktname
erreichbar ist, wobei produkt
hier der Name des Inhaltstyps ist. Für ein einzelnes Produkt sollte die URL-Struktur aber anders aussehen: /portfolio/produktname
.
Die Eingabe im Backend für eine eigene Titelform für ein einzelnes Produkt erfolgt dabei über ein Postmeta-Feld.
Um das gewünschte Verhalten zu erreichen, musste ich an zwei Stellen ansetzen: Zum einen musste ich den Link zum Produkt ändern, damit er von get_permalink
und ähnlichem bereits in abgeänderter Form gezogen wurde und damit auf Archivseiten, in Kategorien etc. bereits korrekt war. Dafür gibt es glücklicherweise den Filter post_type_link
, über den ich schlicht die Standard-Titelform durch die individuelle austausche:
/**
* Replace the permalink of a single post by a custom slug.
*
* @param string $post_link The post permalink
* @param \WP_Post $post The post object
* @return string The updated post permalink
*/
function my_replace_single_post_slug( string $post_link, WP_Post $post ): string {
$custom_slug = get_field( 'slug', $post->ID );
$default_slug = get_option( 'my_product_slug' ) ?? _x( 'product', 'post type slug', 'textdomain' );
if ( $custom_slug ) {
$post_link = str_replace( '/' . preg_quote( $default_slug ) . '/', '/' . $custom_slug . '/', $post_link );
}
return $post_link;
}
add_filter( 'post_type_link', 'my_replace_single_post_slug', 10, 2 );
Code-Sprache: PHP (php)
Da ich den Benutzern auch über die allgemeine Titelform die Kontrolle gebe, ist diese in der Option my_product_slug
abgespeichert (oder es gibt einen Fallback auf den Standard).
Der spannendere Teil war jedoch, diesen Link auch funktionierend zu bekommen. Denn ein veränderter Link allein führt nicht dazu, dass WordPress automatisch weiß, was es dahinter für Inhalt anzeigen soll. Das wird über die sogenannten „Rewrite Rules“ bzw. Umschreibungsregeln definiert.
Im Grunde wird für jede individuelle Titelform eines jeden Produkts eine Umschreibungsregel angelegt und diese zu Beginn eingefügt, damit sie bevorzugt behandelt wird. Daraufhin wird der Cache für diese Umschreibungsregeln erneuert:
/**
* Set custom rewrite rules for post with custom slug.
*
* @param \WP_Post $post The post object
*/
function my_set_rewrite_rules( WP_Post $post ): void {
$custom_slug = get_field( 'slug', $post->ID );
if ( ! $custom_slug ) {
return;
}
$default_slug = mb_strtolower( _x( 'Products', 'Post Type General Name', 'textdomain' ) );
$rules = get_option( 'rewrite_rules', [] );
$rules_added = false;
foreach ( $rules as $link => $rule ) {
if ( strpos( $link, $default_slug ) === false ) {
continue;
}
add_rewrite_rule( str_ireplace( $default_slug, $custom_slug, $link ), $rule, 'top' );
$rules_added = true;
}
if ( $rules_added ) {
flush_rewrite_rules( false );
}
}
add_action( 'rest_after_insert_product', 'set_rewrite_rules' );
Code-Sprache: PHP (php)
Anmerkungen
Grundsätzlich funktioniert das Verhalten damit so, wie ich es mir wünschte. Dennoch hier ein paar Anmerkungen zu möglichen Problemen:
Die zweite Funktion verwendet die Action rest_after_insert_product
, die nur bei einer Beitragsaktualisierung über die API ausgeführt wird, also beispielsweise beim Speichern über den Block-Editor. Die eigentlich von mir gewünschte Action wp_insert_post
konnte ich nicht verwenden, da zu diesem Zeitpunkt die Metadaten, also beispielsweise eine individuell hinzugefügte Titelform, noch nicht in der Datenbank gespeichert sind und man daher nur über Umwege an dessen aktuellen Wert käme.
Wenn die individuelle Titelform erneut geändert wird, bleiben die alten Umschreibungsregeln noch bestehen. Das könnte man lösen, indem man bei der Aktualisierung des entsprechenden Meta-Feldes immer noch die zugehörigen alten Umschreibungsregeln entfernt.
Alle anderen Inhalte des Inhaltstyps sind ebenfalls unter den individuellen Titelformen erreichbar. Da sie aber nirgendwo im Quellcode entsprechend hinterlegt sind, noch sich deren kanonische URL verändert, sollte das kein Problem darstellen.