Faire fonctionner les permaliens de type de publication personnalisés hiérarchiques comme les pages

16

J'ai creusé toutes les questions ici sur les permaliens de type de message personnalisé, mais la plupart semblent être soit des problèmes avec les réécritures de taxonomie personnalisées, soit le manque évident 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 attribuer des relations parent-enfant), avec le "support" approprié pour les attributs metabox, etc., etc. I 'ai vidé les règles de réécriture de mille façons différentes. J'ai essayé différentes structures de permaliens. Mais les URL enfants aboutissent toujours à 404!

J'avais à l'origine des types de publication personnalisés indépendants pour les éléments "parent" et "enfant" (en utilisant p2p), et je n'aurais probablement eu aucun problème à 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 "publications" sont affichées dans l'administrateur, tout comme les pages: un simple arbre où les enfants apparaissent sous le parent, préfixé d'un "-", et dans le bon ordre. En outre, diverses méthodes d'attribution de l'ordre par glisser-déposer peuvent être utilisées. Le regroupement via la taxonomie (ou p2p) se traduit par une liste plate de "publications" dans les listes d'administration, 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 publication personnalisé. J'ai enregistré le type de publication comme prévu, et dans l'administrateur, cela fonctionne parfaitement - je peux attribuer un parent et un menu_order pour chaque newsletter "publication", ils apparaissent correctement dans les listes de modification:

Spring 2012
 First Article
 Second Article

Et leurs permaliens semblent être construits correctement. En fait, si je change quoi que ce soit sur la structure, ou même modifie le slug de réécriture lors de l'enregistrement du type de message, ils se mettent automatiquement à jour correctement, donc je sais 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 des «pages» de base standard avec des relations hiérarchiques créées, et elles ont la même apparence dans l'administration, mais elles fonctionnent également sur le front-end (les URL parent et enfant fonctionnent bien).

Ma structure de permalien est définie sur:

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

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

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

Mon registre CPT args comprend:

$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 mes enfants de type de message personnalisé et les enfants de page normaux , c'est que mon CPT a le slug au début de la structure de permalien, puis suivi par les slugs parent / enfant (où les pages commencent simplement par les slugs parent / enfant, pas de "préfixe"). Pourquoi cela salirait les choses, je ne sais pas. De nombreux articles semblent indiquer que c'est exactement la façon dont ces permaliens CPT hiérarchiques devraient se comporter - mais le mien, bien que bien formé, ne fonctionne pas.

Ce qui me déroute également, c'est quand j'examine les query_vars pour cette page 404 - ils semblent contenir les valeurs correctes pour que WP "trouve" 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, dont vingt-douze, juste pour être sûr que ce n'est pas un modèle manquant de ma part.

En utilisant l'inspecteur de règles de réécriture, 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 son 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 me ferait 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 "bulletin" du CPT parent, pas l'enfant. La demande ressemble à ceci:

Array
(
    [page] => first-article
    [newsletter] => spring-2012
    [post_type] => newsletter
    [name] => spring-2012
)
somatique
la source

Réponses:

15

C'est ma première participation ici sur Stack Exchange, mais je vais essayer et 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 de slug unique, «newsletter» dans ce cas, est de laisser le moteur de réécriture savoir comment distinguer les demandes de différents types de publication.

Ces arguments d'enregistrement CPT semblent corrects, mais lorsqu'un CPT est demandé, la pagenamerequête var ne doit pas avoir de valeur et la namerequête var doit être la même newsletterqu'ici, il semble donc qu'il y ait un conflit quelque part dans votre configuration.

Pour aider au débogage, installez et activez le plug - in d'inspecteur de règles de réécriture , puis visitez l'écran dans " Outils -> Règles de réécriture ".

  1. En consultant la liste, toutes vos règles pour la newsletter CPT doivent être répertoriées avant toute règle de réécriture de page. Vérifiez que c'est le cas en scannant la colonne " Source ".
  2. Si cela se vérifie, saisissez l'URL de votre CPT "premier article" dans le champ " Correspondance URL " et cliquez sur le bouton "Filtrer" pour voir quelle règle correspond. Il doit correspondre à une règle de newsletter et à une règle de page, mais la règle de newsletter doit être la première.

Si cela ne révèle aucun problème, recherchez dans la post_namecolonne wp_postspour trouver d'autres messages avec le slug "premier article" pour voir s'il pourrait y avoir une collision. Effectuez également une recherche pour "newsletter", juste pour être sûr.

Ajoutez l'extrait de code suivant pour inspecter vos variables de requête au début de la demande pour vérifier et voir lesquelles sont définies par la correspondance de règle de réécriture (visitez le CPT enfant sur le front end). Si le pagenamevar n'apparaît pas ici, il est défini par quelque chose plus tard dans la demande:

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 variables de requête peuvent provoquer un conflit, désactivez-les si vous voyez toujours des problèmes. Rincez également vos règles de réécriture après chaque étape, surtout si la demande correspondait à une mauvaise règle à la deuxième étape ci-dessus (gardez l'écran "Permaliens" ouvert dans un onglet séparé et actualisez-le simplement).

Brady Vercher
la source
J'ai édité la question pour afficher la sortie de l'inspecteur de règles de réécriture, car ces commentaires ne permettent pas un formatage suffisant. Les règles pour le CPT s'affichent en haut de la liste, avant toute chose - mais vous ne savez pas lesquelles des règles ci-dessous sont des règles de "page" (pas claires). En outre, aucune collision dans la post_namecolonne.
somatique
avez-vous des réflexions sur la bonne structure de permalien? J'y suis retourné /%postname%/depuis que l'inclusion /%category%/ne semble que semer la confusion dans l'inspecteur de réécriture. J'ai même vu des gens affirmer qu'il /%category%/est magiquement mappé pour que les CPT signifient "parent", bien que je ne trouve pas cela vrai.
somatique
Cette sortie semble provenir d'un plugin différent, c'est pourquoi vous ne voyez pas la "source" de la règle. Quoi qu'il en soit, il semble que votre règle corresponde parfaitement. J'ai modifié ma réponse pour inclure un extrait de code afin d'inspecter les variables de requête plus tôt dans la demande pour s'assurer qu'elles sont définies correctement.
Brady Vercher
Quant à la structure du permalien, je ne suis pas fan de l'inclusion de la catégorie. C'est juste une autre partie mobile qui n'aide en rien, et les messages peuvent appartenir à plusieurs catégories. S'il y a une chance que vous changiez la structure du permalien à l'avenir ou que vous souhaitiez qu'un autre CPT se charge sans préfixe de slug, je recommanderais "d'espacer le nom" de votre structure avec quelque chose de fixe et d'unique comme /blog/%postname%/.
Brady Vercher
c'est le bon plugin, mais il y a deux pages: "analyseur de réécriture" et "règles de réécriture", toutes deux proposant une URL de test. J'ai essayé l'autre page et elle a montré la source comme "programme" pour le premier groupe en retrait et "page" pour le second.
somatique
5

Le parent/Childpermalien fonctionne dès la sortie de la boîte tant que vous définissez

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

Mise à 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 permalien défini pour que /%postname%/je reçoive très bien le bulletin d'information / parent / enfant.

Bainternet
la source
mon code ci-dessus ne l'a pas montré, mais je l'ai page-attributesdans les supports (qui ne sont vraiment que pour montrer la métabox pour attribuer la filiation, ne devrait pas affecter les permaliens) - mais pour obtenir des 404. Quelle structure de permalien doit être définie? ou est-ce important?
somatique
@somatic je viens de le tester à nouveau et son fonctionnement fonctionne bien, quant au permalien, je ne sais pas si cela devrait avoir de l'importance, mais de toute façon j'ai mis à jour ma réponse.
Bainternet
Je peux confirmer que, avec l'ajout d'un tableau d'arguments pour les «étiquettes» (sans lequel CPT n'apparaîtra pas dans admin), cet exemple de base fonctionne sur une installation vanilla de WP3.5 avec twentlytwelve. Mais je remarque quelques différences clés dans vos register_post_type$ args: j'ai utilisé 'rewrite' => array( 'slug' => 'newsletter', 'with_front' => false ), où vous avez utilisé juste true. Vous avez également simplement passé truepour has_archive, où j'ai passé la limace. Cependant, quand j'ai égalé vos arguments, j'ai quand même eu 404 ... Toujours en train de chercher où je me trompe.
somatique
3

En plus de demander »Avez-vous essayé de l'éteindre et de le rallumer?« , Je dois également demander «Avez-vous des plugins actifs et votre thème fait-il quoi que ce soit aux permaliens (par exemple: enregistrement de la taxonomie, types de messages, ajout de règles de réécriture , etc.)?

Si oui: cela se produit-il toujours, après avoir désactivé tous les plug-ins et passé à TwentyEleven? entrez la description de l'image ici

Pour déboguer davantage, rendez-vous sur GitHub et récupérez le plugin Toschos "Rewrite" . Passez ensuite au dépôt de plugin officiel 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.

kaiser
la source
eh bien, si je désactive tout , je n'aurai pas le type de message personnalisé qui fait l'objet de cette question ... mais oui, j'ai essayé même avec le thème de vingt-douze. Je suis toujours en train de fouiller dans les quelques bouchons nécessaires pour voir ce qui modifie la requête, car d'après ce que je peux voir, les permaliens eux-mêmes sont bien formés.
somatique
@somatic Bien sûr, ne désactivez pas le vôtre :)
kaiser
@somatic Voir la mise à jour.
kaiser
1

Donc, après avoir confirmé que je pouvais obtenir le comportement de page hiérarchique attendu avec une installation complètement propre et juste une seule déclaration CPT, je savais que la faute se situait quelque part dans mon propre plugin que j'utilise pour gérer la création de CPT (très complexe, gère les métaboxes personnalisées, 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. J'ai vérifié chaque filtre et crochet, affichant la requête à chaque point et ne voyant rien qui provoquerait 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 à l'origine du 404, de parcourir chaque fonction une par une et de les désactiver / activer, puis de tracer la ligne par ligne dans ces fonctions - une tentative de force brute pour voir exactement ce qui causait le 404, même si je ne savais pas pourquoi.

C'est alors 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 réellement $ query lui-même, ce que je pensais renvoyer tel quel à la fin de ma fonction. Trois filtres à travers 2 classes ont été impliqués qui a modifié la requête: parse_query, posts_orderby, posts_join- et toutes les fonctions de rappel appelaient $query->get_queried_object()le passé $queryarg à puis exécuter des tests conditionnels et parfois modifier la requête vars (comme pour les cas d'ordre de tri spécial). Curieusement, ces fonctions fonctionnaient bien à ce pour quoi elles étaient 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 en direct, je n'avais jamais ressenti d'effets négatifs de cette erreur. Ce n'est que lorsque je me suis aventuré dans les CPT hiérarchiques que cette petite différence a soudainement brisé les choses. Cela fait partie de ce qui m'a énormément compliqué avec cela - autant que je sache, mes filtres de requête étaient fiables!

J'avoue que je ne sais toujours pas exactement pourquoi appeler cette fonction casse juste ce petit aspect des pages enfants CPT - et pourtant je n'ai jamais manifesté d'autres problèmes! Mais il était clair que son utilisation dans un rappel de filtre a altéré le retour en $queryquelque sorte. En supprimant cet appel, mes erreurs 404 ont disparu.

Merci pour tous les conseils - j'aimerais pouvoir partager la prime, car j'ai acquis un aperçu de chaque réponse, même si la solution ultime n'était pas du tout liée. Cela a été une leçon éducative pour ne pas faire confiance aveuglément à votre code, même s'il fonctionne pour vous de manière fiable depuis longtemps, ou s'il ne produit aucune erreur évidente.

Parfois, comme le tableau de Kaiser incarne si bien, il vous suffit de commencer à lancer des interrupteurs jusqu'à ce que les lumières s'allument. Dans mon cas, j'ai dû suivre la même stratégie de dépannage jusqu'aux lignes individuelles d'une fonction avant de pouvoir voir le problème.

somatique
la source
Vous pouvez également utiliser la fonction wrapper get_queried_object()sans intercepter l' $wpdbobjet.
kaiser
mais $queryqu'est- ce que cela saisit? J'utilise ceci dans un filtre pour parse_query, et j'ai besoin d'obtenir spécifiquement l'objet interrogé d'un spécifique $queryqui est passé du filtre ...
somatique
J'ai juste essayé d'utiliser l'enveloppe à l'intérieur de mon filtre pour parse_query. Il a de nouveau provoqué les mêmes erreurs 404. Je dois trouver un moyen de reproduire ce qui get_queried_object()fait sans encrasser ces filtres ...
somatique
-2

Utilisez-vous la version la plus récente de WP? Je suppose que c'est la première question (comme lorsque vous appelez le support technique et qu'ils vous demandent si votre ordinateur est branché!), Car j'ai lu que ce problème était résolu dans la mise à jour de la version la plus récente.

Il y a un article sur digwp.com qui résout ce problème (http://digwp.com/2011/06/dont-use-postname/). Apparemment, WP ne peut pas facilement faire la différence entre les publications et les pages, et si vous démarrez vos URL avec une option textuelle, WP déclenche un indicateur qui crée une règle pour chaque page / publication que vous avez. Si vous avez beaucoup de contenu sur votre site, cela peut entraîner un grand nombre de demandes et votre serveur expirera probablement, ce qui entraînera un tas de 404 même si les pages sont là.

Donc. Si vous utilisez d'abord une structure basée sur des nombres, puis votre structure basée sur du texte, je parierais que votre problème 404 serait résolu. Maintenant, compte tenu des problèmes de référencement, je n'utiliserais pas de structure de date, mais prendre cette décision sera assez logique pour vous.

Melanie Sumner
la source
2
Je suis sur 3.5. Depuis WP3.3.1, ce problème sur digiwp est corrigé.
somatique