【问题标题】:query_posts() should be avoided?应该避免 query_posts() 吗?
【发布时间】:2014-10-24 13:42:34
【问题描述】:

我读到应该避免使用query_posts(),而应使用wp_query()pre_get_posts()。我对弄乱循环没有信心,也不完全理解法典。

下面的代码是否使用 query_posts() ?如果是,并且由于应该避免使用query_posts(),您能否建议一种不使用query_posts() 但仍能完成同样事情的方法?

functions.php 中的此代码用于按随机或按价格对帖子进行排序。

function my_custom_query($query){
 if ( $query->is_home() && $query->is_main_query() ) {

   $sort= $_GET['sort'];

   if($sort == "pricelow"){
     $query->set( 'meta_key', 'price' );
     $query->set( 'orderby', 'meta_value_num' );
     $query->set( 'order', 'ASC' );
    }

  if($sort == "random"){
     $query->set( 'orderby', 'rand' );
    }

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

.
链接 A(随机)和链接 B(价格)使用此代码发布在我的菜单中。因此,网站的访问者只需单击链接即可对帖子进行排序。

<a href="http://website.com/?sort=A">Random</a>
<a href="http://website.com/?sort=B">Price</a>

【问题讨论】:

    标签: php wordpress


    【解决方案1】:

    创建一个新的 WP_Query() 对象总是好的。

    $sort= $_GET['sort'];
    
       if($sort == "pricelow"){
         $sort_args = array('meta_key' => 'price', 'orderby' => 'meta_value_num', 'order', 'ASC');
         $new_query = new WP_Query($sort_args);
        }
    
        blah blah blah...
    

    不不不,对此感到抱歉。我没有看到 pre_get_posts 钩子。

    您问题中的代码非常适合挂钩查询。如WordPress Plugin API/Action Reference/pre_get_posts中所述:

    pre_get_posts 在设置 WP_Query 之前运行。

    所以它将默认的 WP_Query() 挂在你想要的位置(在你的代码中,它会根据 GET 请求更改 WP_Query)。

    在您的模板文件中,使用 new WP_Query($args)。

    【讨论】:

    • 只是为了清楚......我的问题中的代码不应该被使用 - 是因为它使用 query_posts() 吗?你说你一开始没有看到 pre_get_posts 钩子,为什么这会改变事情 - 它是否使我的问题中的代码可以使用?
    • 是的,您的代码看起来很安全,因为 WordPress 的文档是这样说的(检查我的答案中的链接)。顺便说一句,您没有在代码中使用 query_posts() 函数,而是使用了 $query 对象。
    • 哦,好的,谢谢您清除它。一个问题 - 我不需要使用你的代码..... $new_query = new WP_Query($sort_args); .....对吗?
    • 简短回答:是的。如果您想在您的functions.php 中挂钩特定查询,您的代码很好。在模板文件(如 home.php、single.php、page.php 等)中,您不得更改 WordPress 的 $query 对象。
    【解决方案2】:

    我已经在 WPSE 上对这个主题做了非常详细的解释,为了它可能对 SO 用户产生的价值和好处,这里是从 WPSE 上的那个问题复制的完整帖子。出于兴趣,这里是 WPSE 上完整帖子的链接:Some doubts about how the main query and the custom query works in this custom theme?

    您的实际问题基本上是何时运行自定义查询以及何时使用主查询。让我们把它分成三个部分

    第一部分

    何时运行自定义查询(这不是一个确定的列表)

    • 创建自定义内容滑块

    • 在页面中创建特色内容区域

    • 如果您需要显示帖子,请在 page.php 模板上

    • 如果您需要静态首页上的自定义内容

    • 显示相关、热门或信息性帖子

    • 主查询范围之外的任何其他次要或补充内容

    何时使用主查询。

    显示主要内容

    • 在你的首页和后台设置为博客页面的页面

    • 所有存档页面,包括archive.php、category.php、author.php、taxonomy.php、tag.php和date.php等模板

    第二部分

    要选择所有精选帖子,我使用此行创建一个新的 WP_Query 对象,该对象定义具有特定标签的查询:

    因此,据我了解,这不是 WordPres 主查询,而是我创建的新查询。据我了解,当我想执行此类操作时,最好创建一个新查询(如已完成)而不使用主查询

    正确。这超出了主查询的范围。这是无法使用主查询创建的次要或补充内容。您应该始终使用WP_Queryget_posts 来创建您的自定义查询。

    切勿使用 query_posts 创建自定义查询,甚至任何其他查询。我的重点。

    注意:此功能不适用于插件或主题。正如稍后解释的,有更好、性能更高的选项来更改主查询。 query_posts() 是通过用新的查询实例替换页面的主查询来修改页面的主查询的过于简单和有问题的方法。它效率低下(重新运行 SQL 查询)并且在某些情况下会彻底失败(尤其是在处理帖子分页时)。

    继续

    好的,我继续显示所有没有特色标签的帖子,为此我使用这段代码 sn-p 相反地修改主查询:

    query_posts( array( 'tag__not_in' => array ( $term->term_id )));
    

    所以我认为这非常可怕。是真的吗?

    这都是错误的,很遗憾你的说法是正确的。如前所述,切勿使用query_posts。它运行一个全新的查询,这对性能不利,并且在大多数情况下会破坏分页,这是分页正常工作的主要查询的组成部分。

    这是你的主要内容,所以你应该使用带有默认循环的主查询,它应该看起来像这样,这就是你所需要的

    <?php
        if (have_posts()) :
            // Start the Loop.
            while (have_posts()) : the_post();
    get_template_part('content', get_post_format());
    
            endwhile;
        else :
            // If no content, include the "No posts found" template.
            get_template_part('content', 'none');
    
        endif;
    ?>
    

    你可以完全摆脱这部分,删除它,刻录它,然后忘记它

    <?
    // get the term using the slug and the tag taxonomy
    $term = get_term_by( 'slug', 'featured', 'post_tag' );
    // pass the term_id to tag__not_in
    query_posts( array( 'tag__not_in' => array ( $term->term_id )));
    ?>
    

    好的,一旦你这样做了,你会看到来自功能标签的帖子使用主查询和默认循环出现在你的主页中。

    从主页中删除此标签的正确方法是使用pre_get_posts。这是更改主查询的正确方法,也是您应该始终用来更改主要内容循环的钩子。

    所以,pre_get_posts 的代码是正确的,这是您应该使用的函数。只是一件事,请始终检查您是否不在管理页面上,因为pre_get_posts 也会更改后端。所以这是在functions.php中使用的正确代码,用于从主页中删除标记为featured的帖子

    function exclude_featured_tag( $query ) {
        if ( !is_admin() && $query->is_home() && $query->is_main_query() ) {
            $query->set( 'tag__not_in', 'array(ID OF THE FEATURED TAG)' );
        }
    }
    add_action( 'pre_get_posts', 'exclude_featured_tag' );
    

    第三部分

    额外的阅读材料,将来会有所帮助

    【讨论】:

    • 感谢分享这个彼得。一些问题。您说“检查您是否不在管理页面上”,但什么是管理页面? ----- 如果在 single.php 中您有一个主循环和一个辅助循环(用于相关文章),您将使用此代码进行第二个循环: ----- $the_query = new WP_Query( $args ); - - - 正确的?另外,您是否使用 wp_reset_postdata() 重置第二个循环?我需要重置两个循环还是只重置第二个循环?
    • 管理页面是指任何后端页面。您对相关帖子的假设是完全正确的,这应该是一个自定义查询,是的,您需要重置每个自定义查询,否则您会破坏同一页面上的其他查询。无需重置主查询,即内置。
    猜你喜欢
    • 2012-10-14
    • 1970-01-01
    • 2012-02-25
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2010-12-30
    • 2013-05-19
    相关资源
    最近更新 更多