J'ai deux types de publication personnalisés: appelons-les location
et topic
. Le type de publication personnalisé d'emplacement est hiérarchique. Tous les articles sont "attachés" à un seul endroit en utilisant post meta. Si cela compte, le type de poste topic
a une méta-boîte personnalisée contenant un menu déroulant de la locations
qui enregistre à l'aide de:
update_post_meta( $post->ID, 'my-prefix-location', $the_location );
J'aimerais que l'emplacement soit réécrit pour que leurs URL soient https://my.domain.tld/location/sub-location/sub-sub-location/topic/
.
Pour l'emplacement, j'ai essayé, lors de l'enregistrement du type de publication, d'utiliser l'argument de réécriture suivant:
'rewrite' => [ 'slug' => '/', 'with_front' => false, ],
Cela fonctionne bien pour les emplacements, mais je ne peux accéder à aucune des rubriques, même après avoir purgé manuellement les règles de réécriture. Si je les interroge avec /?id=100
, ils redirigent vers /topic/slug/
(qui n'est pas la structure d'URL que je veux) mais il en résulte un 404.
Mais même si je résous ce problème, je ne sais pas comment réécrire les URL des sujets pour qu'ils aient la structure de l'emplacement attaché en face.
Je pense que je vais devoir add_rewrite_rule()
et/ou add_rewrite_endpoint()
. Je n'ai jamais utilisé aucune de ces fonctions auparavant. Tous les pointeurs seraient appréciés. Est-ce que je m'y prends mal?
[Ajoutée]
Donc, je ne pense pas pouvoir faire ce que je veux facilement (ou même pas du tout). Ce que j'ai maintenant essayé, c'est d'avoir mes permaliens:
/topic/directory/to/my/location/page_name/
Il est assez facile d'ajouter une règle de réécriture pour ignorer tout sauf le dernier paramètre et y correspondre:
add_rewrite_rule( 'topic/(.*)/([^/]+)/?$', 'index.php?topic=$matches[2]', 'top' );
Et cela fonctionnerait bien, sauf que je veux que l'URL canonique ait (. *) La structure d'URL hiérarchique de la catégorie à laquelle le sujet est attaché et que toutes les autres URL topic/*/leaf/
soient redirigées vers celle-ci.
J'ai du mal à comprendre comment faire cela, ou même si c'est possible.
La façon dont les règles de réécriture WordPress fonctionnent (avec quelques exceptions spéciales), différents types de contenu ont une sorte d'élément unique dans leurs URL qui permet à WP d'identifier le type de contenu recherché dans la base de données avant celle-ci. va et cherche. Par exemple, étant donné l'URL:
/topic/one/two/three/
Vous ne pouvez pas dire avec certitude si three
est un emplacement ou un sujet si les deux emplacements et sujets partagent la même racine topic
.
Cela dit, la partie la plus compliquée est que vous devez résoudre cette ambiguïté manuellement. Cela présente un inconvénient: chaque demande de sujet susceptible de constituer un sujet nécessitera une requête supplémentaire dans la base de données, ce qui n'est pas un problème majeur, mais doit également être pris en compte.
Dans votre question initiale, vous avez exprimé le souhait de supprimer la base de type de publication personnalisée. La réponse que je vais donner ici utilise topic
comme base. Supprimer cela jette le type de poste page
dans tout le mix. Vous pourrez peut-être vous en sortir en utilisant cette solution, mais pour vous montrer simplement comment cela fonctionne, je ne vais pas le faire.
Ajoutez une nouvelle balise de réécriture %parent_location%
qui servira d'espace réservé pour l'emplacement d'un sujet. Cela se produit sur l'action init
avec vos règles:
add_rewrite_tag( '%parent_location%', '(.+)' );
Enregistrez vos types de post. Je vais laisser de côté les éléments de base et me concentrer sur les éléments spécifiques qui font que cela fonctionne. Tout cela se passe également sur l'action init
. N'oubliez pas de vider les règles de réécriture après les avoir ajoutées.
Pour les emplacements, le slug racine est topic
et le type de publication est hiérarchique.
$args = array(
'rewrite' => array( 'slug' => 'topic' ),
'hierarchical' => true,
// ... your other args
);
register_post_type( 'location', $args );
Pour les rubriques, nous mettons la nouvelle balise %parent_location%
rewrite dans le slug. Nous allons l'utiliser pour remplacer l'emplacement dans l'URL. Les règles de réécriture générées ne seront jamais mises en correspondance, mais cela facilitera les étapes suivantes.
$args = array(
'rewrite' => array( 'slug' => 'topic/%parent_location%' ),
// ... your other args
);
register_post_type( 'topic', $args );
Ajoutez un filtre à post_type_link
pour échanger le chemin d'emplacement contre notre balise %parent_location%
chaque fois qu'un lien permanent est demandé pour ce sujet. Regardez les commentaires pour voir ce qui se passe.
function wpd_topic_link( $link, $post ) {
// if this is a topic post
if ( $post->post_type === 'topic' ) {
// if there is location ID meta saved for this post under parent_location key
if( $location_id = get_post_meta( $post->ID, 'parent_location', true ) ){
// query for that post to make sure it exists
$location_post = get_posts( array( 'post_type' => 'location', 'p' => $location_id ) );
if( !empty( $location_post ) ){
// get the location permalink
// strip out everything except the location parts of the URL
// substitute that value for our %parent_location% placeholder
$location_link = get_permalink( $location_post[0] );
$location_path = untrailingslashit( str_replace( home_url( '/topic/' ), '', $location_link ) );
$link = str_replace( '%parent_location%', $location_path, $link );
}
}
}
return $link;
}
add_filter( 'post_type_link', 'wpd_topic_link', 20, 2 );
Désormais, lorsque vous ajoutez un article de sujet et enregistrez un ID d'emplacement valide dans la méta de l'article, vous verrez ce chemin reflété dans l'URL lors de la modification de cet article.
Filtrez request
pour rechercher toute demande d'emplacement susceptible de constituer un sujet. Lisez les commentaires pour comprendre ce qui se passe. Un autre effet secondaire à noter ici: vous ne pouvez jamais avoir un slug d’emplacement qui soit aussi un sujet.
function wpd_locations_may_be_topics( $request ){
// if the location query var is set
if( isset( $request['location'] ) ){
// location will be a parent / child hierarchy
// make it an array of URL segments
$parts = explode( '/', $request['location'] );
// it might be a topic only if there's more than a single segment
if( count( $parts ) > 1 ){
$topic_slug = end( $parts );
$maybe_topic = get_posts( array( 'post_type' => 'topic', 'name' => $topic_slug ) );
// if a topic was returned
if( !empty( $maybe_topic ) ){
// change request from location to topic
unset( $request['location'] );
$request['post_type'] = 'topic';
$request['topic'] = $topic_slug;
}
}
}
return $request;
}
add_filter( 'request', 'wpd_locations_may_be_topics' );