web-dev-qa-db-fra.com

Pagination interrompue lors de la fusion des résultats de la recherche avec WP_Query supplémentaire

Sur la page de résultats de recherche (search.php), j'aimerais effectuer un WP_Query supplémentaire pour conserver un ordre spécifique de types de résultats de recherche, par exemple. les résultats de recherche des auteurs doivent toujours être affichés avant les autres résultats -

Les premières pages doivent contenir les résultats de l'auteur, les autres résultats doivent être affichés uniquement sur les pages suivantes (non mélangées sur chaque page).

global $wp_query; //holds the results of the initial search query

$authorposts = $wp_query->posts;    
$query = new WP_Query( 'year=2012&monthnum=12&day=12' );
$otherposts = $query->posts;

$wp_query->posts = array_merge( $authorposts, $otherposts  );
$wp_query->post_count = count( $wp_query->posts );

if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
  //show results loop...

Les problèmes apparaissent avec le comportement de la pagination - alors que le $authorposts semble paginer correctement, c’est-à-dire que les numéros de page corrects pour les publications d’auteurs et la pagination ne fonctionnent que comme ceux existants. Cependant, le $otherposts apparaît en bas de chaque page, juste en dessous des publications de l'auteur. Et ils sont les mêmes sur chaque page! De plus, le nombre de pages reflète uniquement le nombre de la première requête.

J'ai également essayé de fusionner avec l'opérateur plus:

$wp_query->posts = $authorposts + $otherposts;

mais dans ce scénario, le $otherposts n'apparaît pas du tout et le nombre de pages reste le même (nombre de pages pour les publications de l'auteur).

Tous les exemples ayant des objectifs similaires utilisant deux requêtes distinctes que j'ai vues se ressemblaient énormément -

Je me demande donc si la manière dont je peux étendre les résultats de la requête de recherche d'origine avec ce WP_Query supplémentaire est suffisante ou s'il me manque des champs $wp_query pour être remplis (correctement)? Quelle est la bonne façon de faire cela?

Mise à jour: Il est à noter que j'utilise le plug-in WP-PageNavi pour la pagination, mais que cela ne devrait pas être pertinent en premier lieu en tant que première page. est déjà rendu faux. Et il est également initialisé avec l'objet de requête: wp_pagenavi( array( 'query' => $wp_query ));

1
david

Je pense que la seule solution est de sauter la pagination SQL et de la gérer uniquement via php. Mon idée implique 2 fonctions, une accrochée à pre_get_posts, la seconde à filtrer the_posts.

La première fonction fait 2 choses:

  1. désélectionne la valeur paginée pour la recherche, ainsi toutes les publications sont renvoyées à partir de la requête SQL.
  2. enregistrer la valeur paged demandée dans la variable globale, de cette façon peut être utilisée dans la deuxième fonction qui s'exécute plus tard

Voici la fonction:

function filter_my_search_query( $query ) {
  if ( is_search() && $query->is_main_query() && ! is_admin() ) {
    global $the_original_paged;
    $the_original_paged = $query->get('paged') ? $query->get('paged') : 1;
    $query->set('paged', NULL );
    $query->set('nopaging', TRUE );
  }
}
add_action('pre_get_posts', 'filter_my_search_query', 1);

Maintenant, la requête de recherche renvoie tous les articles, sans pagination, et le paginé requis est enregistré dans la variable globale $the_original_paged.

Ainsi, nous pouvons filtrer the_posts en fusionnant les publications supplémentaires souhaitées, puis obtenir uniquement les publications correctes en fonction de la page requise et des paramètres par page, et enfin réinitialiser les propriétés paged et autres $wp_query pour laisser le lien de pagination fonctionner:

function add_posts_to_search_query( $posts ) {
  global $wp_query, $the_original_paged;
  if ( ! is_main_query() || is_admin() || ! is_search() || is_null($the_original_paged) )
      return $posts;
  // the wanted posts per page here setted on general settings
  $perpage = get_option('posts_per_page'); 
  remove_filter( 'the_posts', 'add_posts_to_search_query' );
  $new = new WP_Query( 'year=2012&monthnum=12&day=12&nopaging=1' );
  $merged = array_merge( $posts, $new->posts );
  $wp_query->found_posts += $new->found_posts;
  // getting the right posts based on current page and posts per page
  $wp_query->posts = array_slice($merged, ( $perpage * ($the_original_paged-1) ), $perpage );
  // set the paged and other wp_query properties to the right value, to make pagination work
  $wp_query->set('paged', $the_original_paged);
  $wp_query->post_count = count($wp_query->posts);
  $wp_query->max_num_pages = ceil( $wp_query->found_posts / $perpage ); 
  unset($the_original_paged); // clean up global variable
  return $wp_query->posts; 
}
add_filter('the_posts', 'add_posts_to_search_query');
2
gmazzap

Filtrez la requête principale pour inclure les publications supplémentaires. Vous pouvez ajouter des paramètres de requête avec pre_get_posts ou modifier le SQL avec posts_request ou posts_where.

Filtrer posts_results ou the_posts pour organiser les messages retournés.

function filter_posts_where($where)
{
    $where .= 'OR …' /* post_date is 2012-12-12 */;

    return $where;
}

function filter_the_posts($posts)
{
    usort($posts, 'compare_posts');

    return $posts;
}

function compare_posts($a, $b)
{
    // compare "author" and dates?
    if     /* … */ return  1;
    elseif /* … */ return -1;
    else           return  0;
}
1
sam

Je ne pouvais pas résoudre complètement tous les problèmes impliqués dans cette question, mais pour référence, je poste l'état actuel ici:

function SQ_the_posts($posts, $q = false) {
    if( is_search() && is_main_query() ){

            global $wp_query;

            $authorposts = $wp_query->posts;
            $paged = get_query_var('paged');

            remove_filter( 'the_posts', 'SQ_the_posts' );
            $query = new WP_Query( 'year=2012&monthnum=12&day=12' );
            add_filter( 'the_posts', 'SQ_the_posts' );

            $otherposts = $query->posts;
            $mergedPosts = array_merge( $authorposts, $otherposts  );

            $wp_query->found_posts += $query->found_posts;
            $initialMaxNumPages = $wp_query->max_num_pages;
            if ($paged > $initialMaxNumPages) {
                    $wp_query->posts = $otherposts;
                    $wp_query->post_count = $query->post_count;
                    $posts = $otherposts;
            }

            $wp_query->max_num_pages = ($wp_query->found_posts > 0) ? $wp_query->found_posts / 10 : 0;
            $wp_query->max_num_pages += ($wp_query->found_posts % 10) ? 1 : 0;          
    }
    return $posts;
}
add_filter( 'the_posts', 'SQ_the_posts' );

Ce que ça fait:

  • Requêtes de l'auteur et autres posts
  • Calcule le nombre correct de pages pour les deux requêtes
  • Génère le rendu des dix premiers éléments de la seconde requête lorsque le max_num_pages de la première requête est dépassé

Ce qui ne fonctionne pas:

  • Si, par exemple, la première requête (requête de recherche d'auteur) aboutit à 9 pages et que la seconde requête renvoie 5 pages, la pagination affiche correctement 14 pages. Mais lorsque je clique sur la page 10, la pagination indique "page 10 sur 5", car les 9 pages de la première requête ne sont plus disponibles sur cette page. Est-ce qu'il y a un moyen de réparer ceci?
  • La deuxième requête doit être améliorée pour que la page en cours soit traduite dans son équavalent de pagination correct, par ex. page 10 pour le total des requêtes signifie un paramètre paginé de "1" pour la seconde requête.

Je suis toujours étonné qu'il n'y ait pas d'approche facile. Au cas où quelqu'un serait capable de résoudre ces problèmes en fonction de ma réponse (copier + coller), je serais heureux de le marquer comme accepté!

0
david