Answers:
让我们深入到三重奏:::query_posts
,::get_posts
并class WP_Query
理解::query_posts
好。
WP_Query
该类是在WordPress中获取数据的基石。两种方法::query_posts
和::get_posts
使用该类。
请注意,该类
WP_Query
还包含具有相同名称的方法:WP_Query::query_posts
和WP_Query::get_posts
,但实际上我们仅考虑全局方法,因此请不要感到困惑。
WP_Query
该类称为
WP_Query
早在2004年就引入了被。所有带有☂(雨伞)标记的字段都在2004年出现。后来又添加了其他字段。
这里是 WP_Query
结构:
class WP_Query (as in WordPress v4.7)
public $query; ☂
public $query_vars = array(); ☂
public $tax_query;
public $meta_query = false;
public $date_query = false;
public $queried_object; ☂
public $queried_object_id; ☂
public $request;
public $posts; ☂
public $post_count = 0; ☂
public $current_post = -1; ☂
public $in_the_loop = false;
public $post; ☂
public $comments;
public $comment_count = 0;
public $current_comment = -1;
public $comment;
public $found_posts = 0;
public $max_num_pages = 0;
public $max_num_comment_pages = 0;
public $is_single = false; ☂
public $is_preview = false; ☂
public $is_page = false; ☂
public $is_archive = false; ☂
public $is_date = false; ☂
public $is_year = false; ☂
public $is_month = false; ☂
public $is_day = false; ☂
public $is_time = false; ☂
public $is_author = false; ☂
public $is_category = false; ☂
public $is_tag = false;
public $is_tax = false;
public $is_search = false; ☂
public $is_feed = false; ☂
public $is_comment_feed = false;
public $is_trackback = false; ☂
public $is_home = false; ☂
public $is_404 = false; ☂
public $is_embed = false;
public $is_paged = false;
public $is_admin = false; ☂
public $is_attachment = false;
public $is_singular = false;
public $is_robots = false;
public $is_posts_page = false;
public $is_post_type_archive = false;
private $query_vars_hash = false;
private $query_vars_changed = true;
public $thumbnails_cached = false;
private $stopwords;
private $compat_fields = array('query_vars_hash', 'query_vars_changed');
private $compat_methods = array('init_query_flags', 'parse_tax_query');
private function init_query_flags()
WP_Query
是瑞士军刀。关于的一些事情 WP_Query
:
pre_get_posts
钩子我无法解释所有这些问题,但是其中一些是棘手的,因此让我们提供一些简短提示。
WP_Query
您可以通过传递的参数来控制The list of the arguments
---
attachment
attachment_id
author
author__in
author__not_in
author_name
cache_results
cat
category__and
category__in
category__not_in
category_name
comments_per_page
day
embed
error
feed
fields
hour
ignore_sticky_posts
lazy_load_term_meta
m
menu_order
meta_key
meta_value
minute
monthnum
name
no_found_rows
nopaging
order
p
page_id
paged
pagename
post__in
post__not_in
post_name__in
post_parent
post_parent__in
post_parent__not_in
post_type
posts_per_page
preview
s
second
sentence
static
subpost
subpost_id
suppress_filters
tag
tag__and
tag__in
tag__not_in
tag_id
tag_slug__and
tag_slug__in
tb
title
update_post_meta_cache
update_post_term_cache
w
year
WordPress 4.7中的此列表将来肯定会更改。
这是WP_Query
从参数创建对象的最小示例:
// WP_Query arguments
$args = array ( /* arguments*/ );
// creating the WP_Query object
$query = new WP_Query( $args );
// print full list of arguments WP_Query can take
print ( $query->query_vars );
WP_Query
贪婪get all you can
WordPress开发人员基于这个想法,决定尽早获取所有可能的数据,因为这对性能有好处。这就是为什么默认情况下,当查询从数据库中获取10个帖子时,它还将通过单独的查询获取这些帖子的术语和元数据。术语和元数据将被缓存(预取)。
请注意,缓存仅用于单个请求生存期。
您可以禁用缓存,如果你设置update_post_meta_cache
并update_post_term_cache
以false
在设置WP_Query
参数。禁用缓存时,仅根据需要从数据库请求数据。
对于大多数WordPress博客而言,缓存效果很好,但是在某些情况下,您可能会禁用缓存。
WP_Query
使用助手类如果您WP_Query
在此处检查字段,则有以下三个:
public $tax_query;
public $meta_query;
public $date_query;
您可以想象在将来添加新的东西。
WP_Query
含有要循环的物质在此代码中:
$query = new WP_Query( $args )
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
您可能会注意到WP_Query
具有可以迭代的内容。辅助方法也在那里。您只需设置while
循环。
注意。
for
和while
循环在语义上是等效的。
WP_Query
小学和中学在WordPress中,您有一个主查询和零个或多个辅助查询。
可能没有主查询,但这超出了本文的范围。
主查询称为主查询或常规查询。辅助查询也称为自定义查询。
WordPress WP_Rewrite
早期使用类来基于URL创建查询参数。基于这些参数,它将两个相同的对象存储在全局空间中。这两个都将保存主查询。
global $wp_query @since WordPress 1.5
global $wp_the_query @since WordPress 2.1
当我们说主要查询时,我们会想到这些变量。其他查询可以称为辅助查询或自定义查询。
使用
global $wp_query
或 完全合法$GLOBALS['wp_query']
,但是使用第二种表示法更为明显,并且省去了在函数范围内键入额外的行的麻烦。
$GLOBALS['wp_query']
和$GLOBALS['wp_the_query']
是单独的对象。$GLOBALS['wp_the_query']
应该保持冻结状态。
WP_Query
有方便的pre_get_posts
钩子。这是动作挂钩。它将适用于任何 WP_Query
实例。您这样称呼它:
add_action( 'pre_get_posts', function($query){
if ( is_category() && $query->is_main_query() ) {
// set your improved arguments
$query->set( ... );
...
}
return $query;
});
这个钩子很棒,它可以更改任何查询参数。
这是您可以阅读的内容:
在创建查询变量对象之后但在运行实际查询之前触发。
因此,此挂钩是参数管理器,但无法创建新WP_Query
对象。如果您有一个主查询和一个辅助查询,pre_get_posts
则不能创建第三个查询。或者,如果您只有一个主服务器,则无法创建辅助服务器。
请注意,如果仅需要更改主查询,则也可以使用该
request
挂钩。
WP_Query
支持嵌套循环如果您使用插件,并且从模板调用插件函数,则可能会发生这种情况。
这是展示示例,WordPress甚至对嵌套循环也具有辅助功能:
global $id;
while ( have_posts() ) : the_post();
// the custom $query
$query = new WP_Query( array( 'posts_per_page' => 5 ) );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) : $query->the_post();
echo '<li>Custom ' . $id . '. ' . get_the_title() . '</li>';
endwhile;
}
wp_reset_postdata();
echo '<li>Main Query ' . $id . '. ' . get_the_title() . '</li>';
endwhile;
自从我安装了主题单元测试数据以来,输出将是这样的:
Custom 100. Template: Sticky
Custom 1. Hello world!
Custom 10. Markup: HTML Tags and Formatting
Custom 11. Markup: Image Alignment
Custom 12. Markup: Text Alignment
Custom 13. Markup: Title With Special Characters
Main Query 1. Hello world!
即使我在自定义$ query中请求了5个帖子,它也会返回6个帖子,因为粘性帖子会继续发送。如果wp_reset_postdata
在前面的示例中没有,则输出将像这样,因为$GLOBALS['post']
将会无效。
Custom 1001. Template: Sticky
Custom 1. Hello world!
Custom 10. Markup: HTML Tags and Formatting
Custom 11. Markup: Image Alignment
Custom 12. Markup: Text Alignment
Custom 13. Markup: Title With Special Characters
Main Query 13. Markup: Title With Special Characters
WP_Query
有wp_reset_query
功能这就像一个重置按钮。$GLOBALS['wp_the_query']
应该一直被冻结,并且插件或主题永远都不能改变它。
这是做wp_reset_query
什么的:
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
get_posts
get_posts
好像
File: /wp-includes/post.php
1661: function get_posts( $args = null ) {
1662: $defaults = array(
1663: 'numberposts' => 5,
1664: 'category' => 0, 'orderby' => 'date',
1665: 'order' => 'DESC', 'include' => array(),
1666: 'exclude' => array(), 'meta_key' => '',
1667: 'meta_value' =>'', 'post_type' => 'post',
1668: 'suppress_filters' => true
1669: );
... // do some argument parsing
1685: $r['ignore_sticky_posts'] = true;
1686: $r['no_found_rows'] = true;
1687:
1688: $get_posts = new WP_Query;
1689: return $get_posts->query($r);
行号将来可能会更改。
这仅仅是一个包装周围WP_Query
是返回查询对象的职位。
该ignore_sticky_posts
设置为true手段置顶文章可能只在自然的位置显示出来。前面不会有任何粘性帖子。另一个no_found_rows
设置为true表示WordPress数据库API将不使用SQL_CALC_FOUND_ROWS
它来实现分页,从而减少了数据库上执行找到的行数的负担。
当您不需要分页时,这很方便。现在我们知道可以使用以下查询来模仿此功能:
$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );
这是相应的SQL请求:
SELECT wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 10
将我们现在所拥有的与以前SQL_CALC_FOUND_ROWS
存在的SQL请求进行比较。
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 10
没有的请求SQL_CALC_FOUND_ROWS
将会更快。
query_posts
提示:最初在2004年只有
global $wp_query
。从WordPress 2.1版本$wp_the_query
开始。提示:$GLOBALS['wp_query']
和$GLOBALS['wp_the_query']
是单独的对象。
query_posts()
是WP_Query
包装纸。它将对主WP_Query
对象的引用返回,同时将设置global $wp_query
。
File: /wp-includes/query.php
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
在PHP4中,包括对象在内的所有东西都是按值传递的。query_posts
就像这样:
File: /wp-includes/query.php (WordPress 3.1)
function &query_posts($args) {
unset($GLOBALS['wp_query']);
$GLOBALS['wp_query'] =& new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
请注意,在具有一个主查询和一个辅助查询的典型方案中,我们具有以下三个变量:
$GLOBALS['wp_the_query']
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary
假设这三个都占用1M的内存。总计将是3M的内存。如果使用query_posts
,$GLOBALS['wp_query']
将被取消设置并重新创建。
PHP5 +应该聪明地清空$GLOBALS['wp_query']
对象,就像在PHP4中我们用unset($GLOBALS['wp_query']);
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
结果query_posts
,总共消耗2M的内存,而get_posts
消耗3M的内存。
请注意,query_posts
我们并不是返回实际的对象,而是返回对该对象的引用。
来自php.net:PHP引用是一个别名,它允许两个不同的变量写入相同的值。从PHP 5开始,对象变量不再包含对象本身作为值。它仅包含一个对象标识符,该标识符使对象访问者可以找到实际的对象。当对象通过参数发送,返回或分配给另一个变量时,不同的变量不是别名:它们持有标识符的副本,该副本指向相同的对象。
同样在PHP5 +中,assign(=)运算符很聪明。它将使用浅表副本而不是硬对象副本。当我们这样写时
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
,将仅复制数据,而不是整个对象,因为它们共享相同的对象类型。
这是一个例子
print( md5(serialize($GLOBALS['wp_the_query']) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
query_posts( '' );
print( md5(serialize($GLOBALS['wp_the_query']) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
将导致:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
d6db1c6bfddac328442e91b6059210b5
尝试重置查询:
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
query_posts( '' );
wp_reset_query();
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
将导致:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
即使您使用也会造成问题 WP_Query
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
global $wp_query;
$wp_query = new WP_Query( array( 'post_type' => 'post' ) );
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
当然,解决方案将是wp_reset_query
再次使用功能。
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
global $wp_query;
$wp_query = new WP_Query( array( 'post_type' => 'post' ) );
wp_reset_query();
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
这就是为什么我认为query_posts
从内存角度来看可能会更好。但是你应该总是wp_reset_query
骗人。
我刚刚创建了一个新的跟踪票,票号#36874,以提议弃用query_posts()
。是否接受将是一个很好的问题。
真正的大问题query_posts()
是,尽管有很多关于为什么要这么做的文章,但它仍被插件和主题广泛使用。永远不要使用它。我认为WPSE上最史诗般的帖子如下:
弃用!==移除,因此弃用query_posts()
不会被质量差的开发人员和不了解WordPress且通常将质量差的教程用作指导原则的人们停止使用。正如一些证据,多少问题我们仍然来到这里,人们使用caller_get_posts
的WP_Query
?现在已经不推荐使用了很多年。
但是,在核心开发人员认为合适的任何时候,都可以删除不推荐使用的函数和参数,但这很可能永远不会发生。 query_posts()
因为这将破坏数百万个站点。因此,是的,我们可能永远不会看到完全删除query_posts()
-可能导致这样的事实,即它很可能永远不会被弃用。
虽然这是一个起点,但必须记住,在WordPress中弃用某些内容不会停止其使用。
我所筹集的票现已关闭,并标记为与4岁的票重复的票,该票已作为wontfix关闭已重新打开,仍未解决。
似乎核心开发人员正在抓住这个古老的忠实小邪恶。每个人都有兴趣,这是重复的4岁门票
[有点rant]
在这一点上,始终存在的核心哲学是什么都不是真正不推荐使用的东西。弃用通知虽然很不错,但是如果在某个时候实际上不会删除该函数,则将被忽略。有很多人不会继续发展WP_DEBUG
下去,如果没有实际的破坏,他们不会注意到通知。
OTOH手,此功能类似于goto
声明。就我个人而言,我从未使用过(对于较小的定义,然后是预期的),goto
但是我可以理解指向默认情况下并不邪恶的某些情况的论点。一样query_posts
道理,它是设置进行简单循环所需的所有全局变量的简单方法,并且在ajax或rest-api上下文中很有用。我也永远不会在那些上下文中使用它,但是我可以看到,它更多的是编码风格的问题,而不是函数本身就是邪恶的。
更深入一点,主要问题是根本需要设置全局变量。这是主要问题,而不是帮助设置它们的一个功能。
query_posts
比辅助查询要慢(阅读:不是主查询)。
query_posts
而是在WP加载时进行的无用查询