web-dev-qa-db-fra.com

Comment taxer la requête X nombre de posts liés par tag en premier, puis par catégorie si pas assez dans les tags

Question

Comment sortir les messages liés aux tags en premier, puis SI il y a moins de 4 messages liés aux tags, remplissez le reste des 4 tâches avec des messages liés à la catégorie?

Scénario

Parfois, une publication a très peu de balises, ou les balises avec lesquelles elle est libellée ont très peu de publications. Lorsque vous indiquez "messages liés par balise", la zone est soit très clairsemée avec 1 ou 2 messages, soit carrément vide.

Pour résoudre ce problème, il serait bon d'afficher des publications de catégories apparentées, s'il n'y a pas suffisamment de publications reliées à des balises pour satisfaire posts_per_page => X.

Donc, quelque chose comme ça:


Scénario A - S'il existe plus de 4 publications liées aux balises, alors:

Related Posts:

Show the below posts:

1. tag-related post #1
2. tag-related post #2
3. tag-related post #3
4. tag-related post #4

Do Not show the below posts:

5. tag-related post #5
6. tag-related post #6
7. tag-related post #7
...

Scénario B - S'il n'y a que 2 publications liées aux balises, alors:

Related Posts:

Show the below posts:

1. tag-related post #1
2. tag-related post #2  
3. category-related post #1
4. category-related post #2

Do Not show the below posts:

5. category-related post #3
6. category-related post #4
7. category-related post #5
...

Ce que j'ai essayé

La requête fiscale que j'utilise:

// start of the tax_query arguments
$args = array( 'posts_per_page'=>4, 'post__not_in' => array($post->ID), 'tax_query' => array( 'relation' => 'OR' ) );

// get current post tags
$tags = wp_get_object_terms( $post->ID, 'post_tag', array( 'fields' => 'ids' ) );

if ( !empty( $tags ) ) {
    $args['tax_query'][] = array(
        'taxonomy' => 'post_tag',
        'field'    => 'id',
        'terms'    => $tags
    );
}

// get current post categories
$categories = wp_get_object_terms( $post->ID, 'category', array( 'fields' => 'ids' ) );

if ( !empty( $categories ) ) {
    $args['tax_query'][] = array(
        'taxonomy' => 'category',
        'field'    => 'id',
        'terms'    => $categories
    );
}

// the query
$related_query = new WP_Query( $args );

Si je comprends bien, cette requête fiscale indique "récupérez les publications qui sont dans les mêmes catégories, puis les publications dans les mêmes tags, puis affichez les publications jusqu'à ce que 4 soient affichées à l'écran".

Pourtant, il continue à afficher en premier (et il y en a beaucoup) des articles de catégorie, ce qui satisfait à la règle des 4 articles sur les écrans et laisse de côté les articles les plus importants liés aux tags. J'ai essayé de déplacer le code, en utilisant AND au lieu de OR, ce qui n'a pas fonctionné et n'a aucun sens pour moi de toute façon.

J'ai également vu ces messages: WordPress - produire une liste de messages filtrés par balises, puis catégorie et messages de requête Wordpress par balise et catégorie , mais ils concernent la production d'une liste de messages filtrés par tag ET catégorie. J'ai besoin de messages d'abord liés par balise, et si 4 ou plus, alors éditez simplement les 4 premiers. Si moins de 4, éditez autant de messages liés à la catégorie pour répondre aux critères de 4 messages.

Il est clair que je ne comprends pas bien la requête et/ou le problème. Toute aide serait la bienvenue.

SOLUTION

La solution de Peter fonctionne parfaitement - merci Peter!

Je me suis un peu plus inspiré de cela pour mes propres besoins et, en utilisant votre code remarquablement commenté, j'ai également pu exclure les "publications récentes" de cette requête - woohoo!

3
Andre Bulatov

Vous ne pouvez pas faire cela dans une requête, c'est un peu trop avancé pour ce que WP_Query peut faire à ce moment-là. Nous devrons exécuter au moins deux ( je vais utiliser 3 ) requêtes ici pour obtenir ce que vous voulez.

Première interrogation

La première requête interrogera les publications selon post_tag, ce qui exclura également la publication actuelle. Nous n'obtiendrons que des post-ID

Deuxième requête

Cette requête gérera les messages "de remplissage" qui proviendront de la taxonomie category. Pour que cette requête réussisse, nous aurons besoin de ce qui suit

  • Exclure la publication actuelle et les publications de la première requête pour éviter les publications en double

  • Obtenez le nombre de messages dans la première requête, soustrayez-le de 4, puis utilisez cette différence pour définir le nombre de messages qui doivent être récupérés par la requête this.

Nous allons également simplement obtenir des post-ID ici

TROISIÈME QUERY

Afin de préserver l'intégrité de l'objet de requête, nous allons combiner tous les ID de la requête précédente et interroger les objets de publication finaux. Vous pensez peut-être que c'est cher, mais ce n'est pas le cas. Étant donné que les deux premières requêtes utilisent get_posts() et n'obtiennent que les identifiants de publication, elles sont très rapides. En interrogeant uniquement les identifiants, nous ne mettons pas non plus à jour les caches, ce qui rend ces requêtes encore plus rapides.

SOLUTION

Je préfère créer une fonction pour des éléments aussi volumineux que le code, car elle garde mes modèles propres. S'il vous plaît noter, le suivant est non testé et nécessite PHP 5.4

function get_max_related_posts( $taxonomy_1 = 'post_tag', $taxonomy_2 = 'category', $total_posts = 4 )
{
    // First, make sure we are on a single page, if not, bail
    if ( !is_single() )
        return false;

    // Sanitize and vaidate our incoming data
    if ( 'post_tag' !== $taxonomy_1 ) {
        $taxonomy_1 = filter_var( $taxonomy_1, FILTER_SANITIZE_STRING );
        if ( !taxonomy_exists( $taxonomy_1 ) )
            return false;
    }

    if ( 'category' !== $taxonomy_2 ) {
        $taxonomy_2 = filter_var( $taxonomy_2, FILTER_SANITIZE_STRING );
        if ( !taxonomy_exists( $taxonomy_2 ) )
            return false;
    }

    if ( 4 !== $total_posts ) {
        $total_posts = filter_var( $total_posts, FILTER_VALIDATE_INT );
            if ( !$total_posts )
                return false;
    }

    // Everything checks out and is sanitized, lets get the current post
    $current_post = sanitize_post( $GLOBALS['wp_the_query']->get_queried_object() );

    // Lets get the first taxonomy's terms belonging to the post
    $terms_1 = get_the_terms( $current_post, $taxonomy_1 );

    // Set a varaible to hold the post count from first query
    $count = 0;
    // Set a variable to hold the results from query 1
    $q_1   = [];

    // Make sure we have terms
    if ( $terms_1 ) {
        // Lets get the term ID's
        $term_1_ids = wp_list_pluck( $terms_1, 'term_id' );

        // Lets build the query to get related posts
        $args_1 = [
            'post_type'      => $current_post->post_type,
            'post__not_in'   => [$current_post->ID],
            'posts_per_page' => $total_posts,
            'fields'         => 'ids',
            'tax_query'      => [
                [
                    'taxonomy'         => $taxonomy_1,
                    'terms'            => $term_1_ids,
                    'include_children' => false
                ]
            ],
        ];
        $q_1 = get_posts( $args_1 );
        // Count the total amount of posts
        $q_1_count = count( $q_1 );

        // Update our counter
        $count = $q_1_count;
    }

    // We will now run the second query if $count is less than $total_posts
    if ( $count < $total_posts ) {
        $terms_2 = get_the_terms( $current_post, $taxonomy_2 );
        // Make sure we have terms
        if ( $terms_2 ) {
            // Lets get the term ID's
            $term_2_ids = wp_list_pluck( $terms_2, 'term_id' );

            // Calculate the amount of post to get
            $diff = $total_posts - $count;

            // Create an array of post ID's to exclude
            if ( $q_1 ) {
                $exclude = array_merge( [$current_post->ID], $q_1 );
            } else {
                $exclude = [$current_post->ID];
            }

            $args_2 = [
                'post_type'      => $current_post->post_type,
                'post__not_in'   => $exclude,
                'posts_per_page' => $diff,
                'fields'         => 'ids',
                'tax_query'      => [
                    [
                        'taxonomy'         => $taxonomy_2,
                        'terms'            => $term_2_ids,
                        'include_children' => false
                    ]
                ],
            ];
            $q_2 = get_posts( $args_2 );

            if ( $q_2 ) {
                // Merge the two results into one array of ID's
                $q_1 = array_merge( $q_1, $q_2 );
            }
        }
    }

    // Make sure we have an array of ID's
    if ( !$q_1 )
        return false;

    // Run our last query, and output the results
    $final_args = [
        'ignore_sticky_posts' => 1,
        'post_type'           => $current_post->post_type,
        'posts_per_page'      => count( $q_1 ),
        'post__in'            => $q_1,
        'order'               => 'ASC',
        'orderby'             => 'post__in',
        'suppress_filters'    => true,
        'no_found_rows'       => true
    ];
    $final_query = new WP_Query( $final_args );

    return $final_query;
}

Vous pouvez maintenant utiliser la fonction comme suit dans votre modèle unique

$query = get_max_related_posts();
if ( $query ) {

    while ( $query->have_posts() ) {
        $query->the_post();

            echo get_the_title() . '</br>';

    }
    wp_reset_postdata();
}

Quelques notes

  • Les valeurs par défaut sont déjà définies sur post_tag, category et 4 pour les trois paramètres respectivement. Vous devez donc passer des valeurs à la fonction lorsque vous l'appelez.

  • Si vous devez permuter les taxonomies, définir des taxonomies différentes ou définir des publications par page autres que 4, transmettez-les simplement dans le bon ordre à la fonction.

    $query = get_max_related_posts( 'tax_1', 'tax_2', 6 );
    
3
Pieter Goosen