干扰Orderby相关性的元查询

时间:2019-05-03 作者:RachieVee

我正在尝试使用pre_get_posts 钩住并设置orderby 相关参数。我还想把优先帖子,这是基于帖子元_prioritize_s 在结果中放在第一位。之后的所有帖子都会像往常一样以相关性为基础。

以下是我一直在处理的代码:

//runs on pre_get_posts
function modify_search_results_order( $query ) {
        if ( $query->is_main_query() && is_search() && ! is_admin() ) {

            $query->query_vars[\'order\']        = \'DESC\';
            $query->query_vars[\'orderby\']      = \'relevance\';
            $query->query_vars[\'post_status\']  = \'publish\';
//          $query->query_vars[\'meta_query\']   = [
//              \'relation\' => \'OR\',
//              array(
//                  \'key\'     => \'_prioritize_s\',
//                  \'compare\' => \'EXISTS\'
//              ),
//              array(
//                  \'key\'     => \'_prioritize_s\',
//                  \'compare\' => \'NOT EXISTS\'
//              )
//          ];
        }

        return $query;
    }
我原来有orderby 设置为meta_value relevance 而且它确实将优先帖子放在了最上面,而meta\\u查询没有注释。然而,它并没有为之后的帖子保持完整的相关性排序。似乎元查询正在影响总体顺序。

我觉得我可能需要一些定制的东西,比如数据库查询?似乎我不想通过设置$query->query_vars. 有人能帮忙吗?提前感谢!

<小时>UPDATE: 由于我还没有弄清楚如何修改上面发布的代码,我正在尝试另一种解决方案。如果这样做不对,请告诉我。如果不使用上述代码,我可以使用found_posts 钩子在我的pre_get_posts 函数已经完成了它的魔术。然而,我唯一的问题是应该给我的第二个参数,当我知道结果应该不止这些时,查询只给我10篇帖子。为什么即使我设置了posts_per_page-1 在我的pre_get_posts 作用

function modify_search_results_prioritized( $found_posts, $wp_query ) {
        if ( is_search() ) {
            //this says 10 - why?
            error_out($wp_query->query_vars[\'posts_per_page\']);
        }

        return $found_posts;
    }

2 个回复
最合适的回答,由SO网友:RachieVee 整理而成

所以在@Nicolai发现WP源中的blurb确认我不能在orderby 如果我订购relevance 我不得不走另一条路。然而,只有在我不喜欢分页的情况下,此路径才有效。也许有一种方法可以把它放回去,但我现在正在研究一种不同的解决方案,我不再需要停留在我的问题中的代码上。

所以我保留了修改查询的函数pre_get_posts 并删除了有关post meta/meta查询的任何内容:

function modify_search_results_order( $query ) {
        if ( $query->is_main_query() && is_search() && ! is_admin() ) {
            $get_expired_events = Event_Helpers::get_expired_event_ids();

            $query->query_vars[\'posts_per_page\'] = - 1;
            $query->query_vars[\'order\']          = \'DESC\';
            $query->query_vars[\'is_search\']      = true;
            $query->query_vars[\'post__not_in\']   = $get_expired_events;
            $query->query_vars[\'orderby\']        = \'relevance\';
            $query->query_vars[\'post_status\']    = \'publish\';
        }

        return $query;
    }
然后在我的搜索模板中,调用一个函数,在pre_get_posts 要查找优先帖子,请将其从主查询中取消设置,然后将其放回顶部:

//in search.php
$wp_query->posts = Search_Modify_Query::rearrange_search_query_for_priority_relevance( $wp_query->posts );

//in PHP Class
public static function rearrange_search_query_for_priority_relevance( $query ) {
        //get prioritized ids
        $get_prioritized = self::get_priority_search_post_ids();
        $get_results_ids = [];

        if ( ! is_array( $get_prioritized ) || ! $get_prioritized ) {
            return $query;
        }

        //save all ids from current search results query
        foreach ( $query as $key => $post ) {
            $get_results_ids[ $key ] = $post->ID;
        }

        if ( ! $get_results_ids ) {
            return $query;
        }

        //check if there are priority posts in results
        if ( array_intersect( $get_prioritized, $get_results_ids ) ) {
            $priority_matches = array_intersect( $get_results_ids, $get_prioritized );
            $priority_query   = false;

            //if there are priority matches, pluck them out to put them on top
            if ( $priority_matches ) {
                foreach ( $priority_matches as $key => $priority_match ) {
                    //save these into new array first
                    $priority_query[ $key ] = $query[ $key ];
                    //then unset them from main query
                    unset( $query[ $key ] );
                }

                if ( $priority_query && is_array( $priority_query ) ) {
                    //then re-add them on top of main query
                    return array_merge( $priority_query, $query );
                } else {
                    return $query;
                }
            }
        }

        return $query;
    }
这很好,但因为我需要所有的结果来与我的“priority post”ID和结果ID进行比较,所以我必须设置posts_per_page 至-1。因此,尽管它可以工作,除非我找到一种方法来恢复分页或编写自定义内容,否则搜索结果将显示所有搜索结果。php,无论是5还是500。不过,我还是把这段代码放在这里,以防从长远来看对其他人有所帮助。

但对于我的情况,我决定进行两个单独的查询,并且我确认我们不关心是否有重复的。因此,我将只查询与主搜索结果查询上方的搜索词匹配的优先级帖子。

SO网友:Nicolai Grossherr

只是想详细说明我们在评论中所讨论的内容。我知道您已经为您的用例解决了这个问题,所以这更多是为了完整性和概念验证的目的。未测试,有关更多信息,请参阅代码注释。

add_action( \'pre_get_posts\', \'prioritized_before_rest\' );
function prioritized_before_rest( $q ) {
  if ( ! is_admin() && $q->is_main_query() && $q->is_search() ) {   
    // get the search term
    $search_term = $q->get( \'s\' );
    // get the prioritized items
    $prioritized = new WP_Query( [ 
      // it is a search, so it is ordered by relevance
      \'s\' => $search_term,
      // I assumed that is your condition
      \'meta_query\' => [ [ 
        \'key\' => \'_prioritize_s\',
        \'compare\' => \'EXISTS\',
       ], ],
      // we want them all
      \'posts_per_page\' => -1,
      // but only ids
      \'fields\' => \'ids\',
    ] );
    // array of ids
    $prioritized_ids = $prioritized->posts;

    $rest = new WP_Query( [ 
      \'s\' => $search_term,
      // get the rest by excluding above queried priorizied items
      \'post__not_in\' => $prioritized_ids,
      \'posts_per_page\' => -1,
      \'fields\' => \'ids\',
    ] );
    $rest_ids = $rest->posts;

    // merge above queried ids, order matters
    $prioritized_before_rest = array_merge( $prioritized_ids, $rest_ids );

    // use merged array, this alone does nothing 
    // but to get all posts as would the unaltered query
    $q->set( \'post__in\', $prioritized_before_rest );
    // we can set orderby to post__in though to preserve the order 
    // established with above queries and merging the arrays
    // this keeps standard posts_per_page setting and pagination alive
    $q->set( \'orderby\', \'post__in\' );
  }
}