web-dev-qa-db-fra.com

$ query-> query_var ['post_type'] non défini pour les pages

Répondant de ce réponse de @kaiser sur le fait de pouvoir filtrer par type de publication sur une page de recherche, je souhaitais pouvoir ajouter automatiquement tous les types de publication publics disponibles. Donc, après un peu d'aide avec @kaiser, j'ai trouvé:

function sw_custom_post_type_includes($query) {
    $args = array(
        'public'   => true
    ); 
    $output = 'names'; // names or objects, note names is the default
    $operator = 'and'; // 'and' or 'or'
    $post_types = get_post_types( $args, $output, $operator ); 
    if ( !is_search() && !in_array( get_post_type(), $post_types ) )
        return;

    $query->set( 'post_type', $post_types );
    return $query;
}
add_filter('pre_get_posts', 'sw_custom_post_type_includes');

Ce qui au début semblait bien fonctionner, mais j'ai rencontré un problème -> tout filtré par type de message correctement SAUF lorsque j'ai essayé d'utiliser &post_type=page. J'avais en fait une erreur d'index non définie pour post_type. Je ne pouvais pas comprendre pourquoi cela ne fonctionnait pas. Donc, j'ai décidé d'utiliser print_r($query->query_vars) pour voir si tout était correctement inséré. Low and behold - pour tous les types de publication SAUF pour les pages, cette variable a été définie.

J'ai conféré avec un autre dev à ce sujet et ils ont vérifié le problème. Voici ce que j'ai finalement utilisé comme solution de contournement:

function sw_custom_post_type_includes($query) {
    if(isset($_GET['post_type']) && ((!isset($query->query_vars['post_type'])) || (isset($query->query_vars['post_type']) && $query->query_vars['post_type'] != 'nav_menu_item'))) {
        $query->set('post_type', urldecode($_GET['post_type']));
    }
}
add_action('pre_get_posts', 'sw_custom_post_type_includes');

En toute honnêteté, cela semble être une solution bizarre pour quelque chose qui me déconcerte depuis quelques heures. Toute personne ayant une contribution à ce sujet sera récompensée par un high-fives virtuel.

1
Zach

Pour dissiper une certaine confusion dans les réponses précédentes, pre_get_posts n'est pas un filtre, vous n'avez donc pas besoin de retourner quoi que ce soit.

Votre seul problème que je vois est le si:

if ( !is_search() && !in_array( get_post_type(), $post_types ) )
    return;

De manière générale, get_post_type () va renvoyer false pendant pre_get_posts car le $ post global n'a pas encore été défini (généralement défini une fois que vous avez démarré la boucle).

Je ne suis pas tout à fait sûr de savoir quand vous voulez tous les types de publications publiques et quand vous ne les voulez pas. Si vous souhaitez uniquement que toutes les recherches incluent tous les types d'articles publics, il vous suffit de vérifier is_search (). Vous pouvez également vous assurer que la requête en cours de modification est la requête principale et non une requête personnalisée créée par un plugin ou un fichier de thème. Le code devrait ressembler à ceci:

function range_search_all_public_post_types( $q ) {
    if ( is_search() && is_main_query() )
        $q->set( 'post_type', get_post_types( array( 'public' => true ) ) );
}
add_action( 'pre_get_posts', 'range_search_all_public_post_types' );

C'est tout. Cela entraînera une interrogation de tous les types de publications publiques.

Si vous souhaitez que tous les types de publication soient publics sur la page d'accueil et que vous effectuiez une recherche, utilisez ceci:

function range_search_all_public_post_types( $q ) {
    if ( ( is_search() || is_home() ) && is_main_query() )
        $q->set( 'post_type', get_post_types( array( 'public' => true ) ) );
}
add_action( 'pre_get_posts', 'range_search_all_public_post_types' );

METTRE À JOUR:

Le problème que vous rencontrez est unique pour les post_types pour lesquels public_queryable est défini sur false. Vous voulez fondamentalement que tous les types publics fonctionnent même s'ils ne sont pas publiquement accessibles. Pour ce faire, utilisez ce code:

function range_search_all_public_post_types( $q ) {
    if ( is_search() && is_main_query() && '' == $q->get( 'post_type' ) && ! empty( $_GET['post_type'] ) && post_type_exists( $_GET['post_type'] ) && get_post_type_object( $_GET['post_type'] )->public )
        $q->set( 'post_type', $_GET['post_type'] );
}
add_action( 'pre_get_posts', 'range_search_all_public_post_types' );

Fondamentalement, si un post_type est dans une URL mais PAS dans QP_Query, il POURRAIT être dû au fait que ce n'est pas public_queryable, et si c'est le cas, nous le corrigeons. Voici ce qui est vérifié:

  • Est-ce une page de recherche?
  • Est-ce la requête principale?
  • N'y a-t-il pas de type post_type spécifié dans la requête?
  • Un type de post_type est-il spécifié dans l'URL?
  • Le post_type spécifié par l'URL existe-t-il?
  • Le type de post_type spécifié par l'URL est-il public?

Si toutes sont vraies, le post_type est défini sur celui de l'URL.

2
Aaron D. Campbell

Alors que je répondais à la question, où celle-ci fait suite et après avoir beaucoup commenté les questions ici, je suis presque certaine que vous avez quelque part un filtre ou une condition qui vous empêche de récupérer un résultat pour les pages. 99% de chances que ce soit votre problème Vous feriez mieux de commencer avec une installation vierge de Vanilla et d'essayer de n'exécuter que ce filtre pour prouver qu'il fonctionne. Puis entrez et commencez à supprimer/commenter tout ce qui est personnalisé, désactivez les plugins, etc. jusqu'à ce que vous sachiez ce qui se passe.

0
kaiser

tu as écrit

if ( !is_search() && !in_array( get_post_type(), $post_types ) )
    return;

si page n'est pas dans votre tableau $post_types, il y a un return; vide

En fait, je ne vois pas pourquoi vous ajoutez cette sécurité, cette fonction n’est appelée que s’il ya un besoin réel grâce au filtre pre_get_posts

Vous devriez juste changer le retour:

function sw_custom_post_type_includes($query) {
    $args = array(
        'public'   => true
    ); 
    $output = 'names'; // names or objects, note names is the default
    $operator = 'and'; // 'and' or 'or'
    $post_types = get_post_types( $args, $output, $operator ); 
    if ( !is_search() && !in_array( get_post_type(), $post_types ) )
        return $query;  //#### keep it unchanged instead of removing everything ####

    $query->set( 'post_type', $post_types );
    return $query;
}
add_filter('pre_get_posts', 'sw_custom_post_type_includes');

C'est juste une pensée, je n'ai pas essayé

0
Christian