web-dev-qa-db-fra.com

Quand/pourquoi '$ query-> get (' tax_query ');' retourner vide?

D'abord le code:

function itsme_better_editions( $query ) {
    if ( $query->is_category() && $query->is_main_query() ) {
        $query->set( 'post_type', array( 'post' ) );

        // Get current tax query
        $tax_query = $query->get( 'tax_query' );

        $tax_query['relation'] = 'OR';

        $tax_query[] = array(
            'taxonomy' => 'category',
            'field' => 'slug',
            'terms' => 'intl',
            'operator' => 'IN'
        );

        $query->set( 'tax_query', $tax_query );
    }
    return $query;
}
add_filter( 'pre_get_posts', 'itsme_better_editions' );

Tout me semble correct, sauf que $query->get( 'tax_query' ); semble renvoyer un tableau vide ou non, c’est-à-dire que la condition suivante renvoie true:

if( !empty($tax_query) || is_array($tax_query) ) {
   // whatever
}

C'est casser des trucs, j'ai réalisé plus tard .

Les bons messages sont affichés dans l'archive, c.-à-d. Les messages appartenant à la catégorie actuelle OR sont classés dans la catégorie 'International (intl)'. C'est ce que je veux.

Mais le terme objet désigne la catégorie 'intl' (il en va de même dans les archives de balises; au lieu du terme objet désignant la balise actuelle, il pointe vers la catégorie 'intl'). Par exemple, si je visite les archives de la catégorie 'UK (uk)', le message 'International' au lieu de 'UK'.

Ce n'est qu'un des problèmes que j'ai remarqués jusqu'à présent. Je ne sais pas quoi d'autre est cassé.

Quel est le problème avec la fonction?


PS: Et comme $query->get( 'tax_query' ); retournait un tableau vide ou non, je devais le remplir manuellement de la manière suivante:

/*
 * Show posts assigned to 'International (intl)' Edition
 * in all editions.
 */
function itsme_better_editions( $query ) {
    if( $query->is_category() && $query->is_main_query() ) {

        $query->set( 'post_type', array( 'post' ) );

        // NOT WORKING!!!
        //$tax_query = $query->get( 'tax_query' );

        // Equivalent of original `$tax_query` START.
        $get_original_category = get_query_var( 'category_name' );
        $original_category = get_term_by( 'slug', $get_original_category, 'category' );
        if( $original_category && !is_wp_error( $original_category ) ) {
            $itsme_original_category = $get_original_category;
        }

        $tax_query[] = array(
            'taxonomy' => 'category',
            'field' => 'slug',
            'terms' => $original_category,
            'operator' => 'IN'
        );
        // Equivalent of original `$tax_query` END.

        $tax_query['relation'] = 'OR';

        $tax_query[] = array(
            'taxonomy' => 'category',
            'field' => 'slug',
            'terms' => 'intl',
            'operator' => 'IN'
        );

        $query->set( 'tax_query', $tax_query );
    }
    return $query;
}
add_filter( 'pre_get_posts', 'itsme_better_editions' );

OU remplacez simplement la requête comme suit:

/*
 * Show posts assigned to 'International (intl)' Edition
 * in all editions.
 */
function itsme_better_editions( $query ) {
    if( $query->is_category() && $query->is_main_query() ) {

        // Get original/actual category of the category archive
        $get_original_category = get_query_var( 'category_name' );
        $original_category = get_term_by( 'slug', $get_original_category, 'category' );
        if( $original_category && !is_wp_error( $original_category ) ) {
            $itsme_original_category = $get_original_category;
        }

        if( isset($itsme_original_category) ) {

            $query->set( 'post_type', array( 'post' ) );

            $query->set( "category_name", "{$itsme_original_category}, intl" );

        }

    }
}
add_action( 'pre_get_posts', 'itsme_better_editions' );

Cela fonctionne, mais pourquoi devrais-je le faire de cette façon? $tax_query = $query->get( 'tax_query' ); n'est-il pas censé renvoyer le tax_query d'origine?


Comment reproduire le problème

1. Créez deux catégories: UK (uk) et International (intl). Créez 2 messages et attribuez-les à 'UK' uniquement; 1 sous 'International' seulement.

Maintenant, example.com/category/uk/ montre 2 posts; et example.com/category/intl/ montre 1.

2. Ajoutez maintenant la première fonction (premier bloc de code) dans le fichier functions.php de votre thème et visitez example.com/category/uk/. Vous verrez que le nom de la catégorie de la page (<?php single_cat_title(); ?>) est indiqué par 'International'. Pourquoi? Si je ne me trompe pas, car $ query-> get ('tax_query'); semble retourner vide, pas un tableau.

3. Remplacez la fonction dans functions.php par la deuxième ou la troisième fonction ci-dessus. Maintenant, tout devrait fonctionner comme prévu.

PS: Oui, je me suis testé avec le thème par défaut (vingt-treize) et il persiste. Donc, vous seriez capable de reproduire le problème parfaitement.

3
its_me

Autant que je sache, $query->get pour la requête principale fonctionne uniquement avec des vars de requête publics, c'est-à-dire des vars pouvant être déclenchés via une URL, mais rien n'empêche d'accéder directement à la propriété tax_query de la requête, mais notez que c'est un objet, une instance de WP_Tax_Query et les arguments de taxonomie actuellement recherchés se trouvent dans la propriété queries de cet objet.

En accédant à cette propriété, vous évitez d'exécuter une autre requête avec get_term_by dans votre fonction. Comme effet secondaire, single_cat_title affichera le titre correct:

function itsme_better_editions( $query ) {

  if ( $query->is_category() && $query->is_main_query() ) {

    $query->set( 'post_type', array( 'post' ) );

    $tax_query_obj = clone $query->tax_query;

    $tax_query_obj->queries[] = array(
      'taxonomy' => 'category',
      'field' => 'slug',
      'terms' => 'intl',
      'operator' => 'IN'
    );

    $tax_query = array('relation' => 'OR');

    foreach ( $tax_query_obj->queries as $q ) {
      $tax_query[] = $q;
    }

    $query->set('tax_query', $tax_query);
  }

}

add_action( 'pre_get_posts', 'itsme_better_editions' );

Notez que vous utilisez également le filtre sur les requêtes de l'administrateur, si ce n'est pas ce que vous souhaitez, ajoutez && ! is_admin() dans la première if conditionnelle dans la fonction.

PS: un conseil: lorsque vous utilisez 'pre_get_posts', vous pouvez utiliser add_action au lieu de add_filter et ne rien renvoyer, car la requête est transmise en tant que référence.

6
gmazzap

$tax_query = $query->get( 'tax_query' ); retournera l'original tax_query s'il en passe un dans la requête. Par exemple:

function itsme_better_editions( $query ) {
  $query->set( 'post_type', array( 'post' ) );

  // Get current tax query
  $tax_query = $query->get( 'tax_query' );
  var_dump($tax_query); die;
}
add_action( 'pre_get_posts', 'itsme_better_editions' );

$t = new WP_Query(
  array(
    'post_type' => 'post',
    'tax_query' => array(
      array(
        'taxonomy' => 'category',
        'field' => 'slug',
        'terms' => 'intl',
        'operator' => 'IN'
      )
    )
  )
);

Toutefois, si vous videz $wp_query sur une archive de catégorie ou effectuez un test similaire sur la requête principale, il n'y a pas de tax_query comme vous l'avez déjà découvert. En effet, pour certaines des requêtes par défaut, l’objet WP_Query, construit ce tax_query à partir d’autres paramètres de requête longtemps après que pre_get_posts a été exécuté . C'est pourquoi $tax_query = $query->get( 'tax_query' ); est vide.

2
s_ha_dum