应该避免使用query_posts()吗?

时间:2014-08-30 21:42:50

标签: php wordpress wp-query

我正在读取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>

2 个答案:

答案 0 :(得分:4)

我已就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查询)并且在某些情况下会彻底失败(特别是在处理帖子分页时)。

继续前进

  

好的,继续我显示所有没有精选标签的帖子,为此我使用此代码片段,相反修改主要查询:

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中使用的正确代码,用于从主页中删除标记为精选的帖子

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' );

第三部分

将来有用的额外阅读材料

答案 1 :(得分: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)。

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