web-dev-qa-db-fra.com

Faire en sorte que les permaliens de type de message personnalisé hiérarchique fonctionnent exactement comme des pages

J'ai creusé toutes les questions ici sur les permaliens de type de message personnalisé, mais la plupart des problèmes semblent résulter soit de problèmes de réécriture de la taxonomie personnalisée, soit de l'absence évidente de flush_rewrite_rules (). Mais dans mon cas, j'utilise uniquement un type de publication personnalisé (pas de taxonomie), défini pour être hiérarchique (afin que je puisse affecter des relations parent-enfant), avec le "support" approprié pour les attributs metabox, etc., etc. J'ai écrasé les règles de réécriture de mille manières différentes. J'ai essayé différentes structures permalink. Mais les URL enfants génèrent toujours 404!

J'avais à l'origine des types de publication personnalisés indépendants pour les éléments "parent" et "enfant" (à l'aide de p2p), et je n'aurais probablement eu aucune difficulté à utiliser une taxonomie pour le groupe "parental" - je sais que ceux-ci seraient sémantiquement plus précis. Mais pour le client, il est plus facile pour lui de visualiser la hiérarchie lorsque les "posts" sont affichés dans l’administrateur, comme les pages: un simple arbre dans lequel les enfants apparaissent sous le parent, précédé du "-", et bon ordre. Il est également possible d’utiliser diverses méthodes d’assignation d’ordre via drag-n-drop. Le regroupement via taxonomie (ou p2p) donne une liste simple de "posts" dans les listes des administrateurs, ce qui n’est tout simplement pas aussi évident visuellement.

Donc, ce que je recherche, c'est littéralement exactement le même comportement que les "pages" principales, mais avec mon type de message personnalisé. J'ai enregistré le type de message juste comme prévu, et dans l'admin cela fonctionne parfaitement - je peux assigner un parent et un menu_order pour chaque bulletin "post", ils apparaissent correctement dans les listes d'édition:

Spring 2012
— First Article
— Second Article

Et leurs permaliens apparaissent pour être construits correctement. En fait, si je change quelque chose à propos de la structure, ou même si je modifie le slug de réécriture lors de l’enregistrement du type de message, ils se mettent automatiquement à jour correctement. Je sais donc que quelque chose fonctionne:

http://mysite.com/parent-page/child-page/                  /* works for pages! */
http://mysite.com/post-type/parent-post/child-post/        /* should work? */
http://mysite.com/newsletter/spring-2012/                  /* works! */
http://mysite.com/newsletter/spring-2012/first-article/    /* 404 */
http://mysite.com/newsletter/spring-2012/second-article/   /* 404 */

J'ai également créé des "pages" de base standard avec des relations hiérarchiques, et elles ont exactement la même apparence dans l'administrateur, mais elles fonctionnent également sur le serveur frontal (les URL parent et enfant fonctionnent bien).

Ma structure de permalien est définie sur:

http://mysite.com/%postname%/

J'ai également essayé ceci (simplement parce que beaucoup d'autres réponses semblaient indiquer que c'était nécessaire, même si cela n'avait aucun sens dans mon cas):

http://mysite.com/%category%/%postname%/

Mon registre CPT soutient notamment:

$args = array(
    'public'                => true,
    'publicly_queryable'    => true,
    'show_ui'               => true,
    'has_archive'           => 'newsletter',
    'hierarchical'          => true,
    'query_var'             => true,
    'supports'              => array( 'title', 'editor', 'thumbnail', 'page-attributes' ),
    'rewrite'               => array( 'slug' => 'newsletter', 'with_front' => false ),

La seule différence visible entre mon type de message personnalisé children et normal page children est que mon CPT a le slug au début de la structure de permalien, suivi du slug parent/enfant. (où les pages commencent seulement par les slugs parent/enfant, pas de "préfixe"). Pourquoi ce serait salir les choses, je ne sais pas. De nombreux articles semblent indiquer que c'est exactement ainsi que devraient se comporter de tels permaliens CPT hiérarchiques - mais le mien, bien que joliment formé, ne fonctionne pas.

Ce qui me déconcerte aussi, c’est que j’examine les query_vars de cette page 404 - elles semblent contenir les valeurs correctes pour WP pour "trouver" mes pages enfants, mais quelque chose ne fonctionne pas.

$wp_query object WP_Query {46}
public query_vars -> array (58)
'page' => integer 0
'newsletter' => string(25) "spring-2012/first-article"
'post_type' => string(10) "newsletter"
'name' => string(13) "first-article"
'error' => string(0) ""
'm' => integer 0
'p' => integer 0
'post_parent' => string(0) ""
'subpost' => string(0) ""
'subpost_id' => string(0) ""
'attachment' => string(0) ""
'attachment_id' => integer 0
'static' => string(0) ""
'pagename' => string(13) "first-article"
'page_id' => integer 0
[...]

J'ai essayé cela avec différents thèmes, y compris vingt-douze, juste pour m'assurer que ce n'est pas un modèle manquant de ma part.

À l'aide de Rewrite Rules Inspector, voici ce qui apparaît pour l'URL: http://mysite.com/newsletter/spring-2012/first-article/

newsletter/(.+?)(/[0-9]+)?/?$   
       newsletter: spring-2012/first-article
           page: 
(.?.+?)(/[0-9]+)?/?$    
       pagename: newsletter/spring-2012/first-article
           page: 

comment il est affiché sur une autre page d'inspecteur:

RULE:
newsletter/(.+?)(/[0-9]+)?/?$
REWRITE:
index.php?newsletter=$matches[1]&page=$matches[2]
SOURCE:
newsletter

Cette sortie de réécriture m'amènerait à croire que le permalien "non joli" suivant fonctionnerait:

http://mysite.com/?newsletter=spring-2012&page=first-article

Ce n'est pas 404, mais il montre l'élément CPT parent "newsletter", pas l'enfant. La demande ressemble à ceci:

Array
(
    [page] => first-article
    [newsletter] => spring-2012
    [post_type] => newsletter
    [name] => spring-2012
)
15
somatic

Ainsi, après avoir confirmé que je pouvais obtenir le comportement hiérarchique attendu de la page avec une installation complètement propre et une seule déclaration CPT, je savais que la faute se trouvait quelque part dans mon propre plugin que j'utilisais pour gérer la création de CPT (très complexe, gère les métaboxes personnalisés, les taxonomies , etc). Le problème était que, malgré tous les conseils pour vérifier les problèmes de réécriture ou de requête, je ne voyais rien de mal en apparence. J'ai vérifié chaque filtre et chaque crochet, visualisant la requête à chaque point et ne voyant rien qui pourrait causer le 404.

Il me restait donc la tâche de désactiver/activer manuellement chacune des 9 grandes classes, puis de trouver au moins 2 d'entre elles responsables de la 404, de passer en revue chaque fonction une par une et de les désactiver/de les activer, puis de tracer la ligne. par ligne au sein de ces fonctions - une tentative de force brute pour voir exactement ce qui causait la 404, même si je ne savais pas pourquoi.

C'est à ce moment-là que j'ai découvert qu'il y avait une conséquence à utiliser $query->get_queried_object(). Il semblerait que l'utilisation de cette fonction wrapper modifie en fait $ query lui-même, ce que je pensais être renvoyé inchangé à la fin de ma fonction. Trois filtres de deux classes impliquées ont modifié la requête: parse_query, posts_orderby, posts_join - et toutes les fonctions de rappel appelaient $query->get_queried_object() sur l'argument $query passé pour exécuter ensuite des tests conditionnels et parfois modifier les vars de requête (comme pour un ordre de tri spécial). cas). Curieusement, ces fonctions ont bien fonctionné comme elles avaient été conçues, malgré mon utilisation de la fonction. Je n'ai jamais rien remarqué de mal avec la requête $ retournée auparavant!

D'une manière ou d'une autre, après plus d'un an de développement et d'utilisation sur des dizaines de sites de production réels, cette erreur ne m'avait jamais causé d'effets néfastes. Ce n’est que lorsque je me suis aventuré dans des CPT hiérarchiques que cette petite différence a brisé les choses. Cela fait partie de ce qui m'a jeté si dur avec cela - autant que je sache, mes filtres de requête étaient dignes de confiance!

J'avoue que je ne sais toujours pas exactement pourquoi l'appel de cette fonction ne rompt que ce petit aspect des pages enfants de CPT - et pourtant, il n'a jamais manifesté d'autres problèmes! Mais il était clair que son utilisation dans un rappel de filtre endommageait le $query renvoyé d'une manière ou d'une autre. En supprimant cet appel, mes erreurs 404 ont disparu.

Merci pour tous les conseils - j'aimerais pouvoir partager la prime, car chaque réponse m'a éclairé, même si la solution ultime était quelque peu indépendante. Cela a été une leçon pédagogique de ne pas faire aveuglément confiance à votre code, même si cela fonctionne pour vous de manière fiable depuis longtemps, ou si cela ne produit aucune erreur évidente.

Parfois, comme le graphique de Kaiser l'indique si bien, il suffit de commencer à lancer des interrupteurs jusqu'à ce que les lumières se rallument. Dans mon cas, je devais intégrer la même stratégie de dépannage aux lignes individuelles d'une fonction avant de pouvoir voir le problème.

1
somatic

C'est la première fois que je participe à Stack Exchange, mais je vais essayer de voir si je peux vous aider à vous orienter dans la bonne direction.

Par défaut, les CPT hiérarchiques se comportent exactement comme vous l'avez décrit. Le préfixe slug unique, "newsletter" dans ce cas, est d'indiquer au moteur de réécriture comment identifier les demandes de différents types de publication.

Ces arguments d'enregistrement CPT semblent corrects, mais lorsqu'un CPT est demandé, la requête pagename ne doit pas avoir de valeur et la requête name doit être identique à newsletter ici, de sorte qu'il semble y avoir un conflit quelque part dans votre configuration.

Pour vous aider à déboguer, installez et activez le plugin Rewrite Rules Inspector , puis visitez l'écran sous " Outils -> Rewrite Rules ."

  1. Lorsque vous consultez la liste, vous devez répertorier toutes les règles de la newsletter CPT avant toute autre règles de réécriture de pages. Vérifiez que c'est le cas en parcourant la colonne " Source ".
  2. Si cela se vérifie, entrez l'URL de votre CPT "premier article" dans le champ " URL correspondante " et cliquez sur le bouton "Filtrer" pour voir quelle règle correspond. Il doit correspondre à une règle de bulletin d'information et à une règle de page, mais la règle de bulletin d'information doit être prioritaire.

Si cela ne révèle aucun problème, recherchez la colonne post_name dans wp_posts pour rechercher d'autres publications avec le slug "premier article" pour voir s'il peut y avoir une collision. Faites une recherche sur "newsletter" aussi, juste pour être sûr.

Ajoutez l'extrait de code suivant pour inspecter vos vars de requête plus tôt dans la requête afin de vérifier ceux qui sont définis par la correspondance de règle de réécriture (visitez le CPT enfant au début du processus). Si la variable pagename n'apparaît pas ici, elle sera définie ultérieurement par quelque chose dans la requête:

add_filter( 'request', 'se77513_display_query_vars', 1 );

function se77513_display_query_vars( $query_vars ) {
    echo '<pre>' . print_r( $query_vars, true ) . '</pre>';

    return $query_vars;
}

Tous les plugins/fonctions qui modifient les vars de requête peuvent être à l'origine d'un conflit, alors désactivez-les si vous voyez toujours des problèmes. Videz également vos règles de réécriture après chaque étape, en particulier si la requête correspond à une règle incorrecte dans la deuxième étape ci-dessus (laissez l'écran "Permalinks" ouvert dans un onglet séparé et actualisez-le).

14
Brady Vercher

Le parent/Child permalien Fonctionne hors de la boîte tant que vous définissez

'hierarchical'=> true,
'supports' => array('page-attributes' ....

Mettre à jour:

Je viens de le tester à nouveau et cela fonctionne comme prévu, avec ce cas de test:

add_action('init','test_post_type_wpa77513');
function test_post_type_wpa77513(){
    $args = array(
        'public' => true,
        'publicly_queryable' => true,
        'show_ui' => true, 
        'show_in_menu' => true, 
        'query_var' => true,
        'rewrite' => true,
        'capability_type' => 'post',
        'has_archive' => true, 
        'hierarchical' => true,
        'supports' => array( 'title', 'editor', 'thumbnail', 'page-attributes' )
    ); 

    register_post_type( 'newsletter', $args );
}

et lien permanent défini sur /%postname%/ Je reçois très bien le bulletin d’information/le parent/l’enfant.

5
Bainternet

En plus de demander "Avez-vous essayé de l'éteindre et de le rallumer?" , je dois aussi demander "Avez-vous des plugins actifs et votre thème fait-il quelque chose pour les permaliens (par exemple : enregistrement de taxonomie, types de publication, ajout de règles de réécriture, etc.)?

Si tel est le cas: est-ce toujours le cas après avoir désactivé tous les plug-ins et basculé vers TwentyEleven? enter image description here

Pour déboguer plus loin, allez sur GitHub et prenez Toschos "Rewrite" Plugin . Ensuite, basculez vers le dépôt officiel du plugin sur wp.org et saisissez le plugin MonkeyManRewriteAnalyzer . J'ai même écrit une petite extension pour coller les deux un peu ensemble. Cela vous donnera beaucoup de détails sur votre configuration.

3
kaiser