web-dev-qa-db-fra.com

Réécrire les règles pour le type de message personnalisé 'attaché' à un autre type de message personnalisé

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.

1
Nathan Johnson

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.

Étape 1

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%', '(.+)' );

Étape 2

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 );

Étape 3

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.

Étape 4

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' );
1
Milo