Câu hỏi quan trọng
Hãy đào vào bộ ba: ::query_posts, ::get_postsvà class WP_Queryđể hiểu ::query_poststốt hơn.
Nền tảng để nhận dữ liệu trong WordPress là WP_Querylớp. Cả hai phương thức ::query_postsvà ::get_postssử dụng lớp đó.
Lưu ý rằng lớp WP_Querycũng chứa các phương thức có cùng tên: WP_Query::query_postsvà WP_Query::get_posts, nhưng chúng tôi thực sự chỉ xem xét các phương thức toàn cầu, vì vậy đừng nhầm lẫn.

Hiểu biết về WP_Query
Lớp được gọi WP_Queryđã được giới thiệu trở lại vào năm 2004. Tất cả các trường có dấu ☂ (ô) xuất hiện trở lại vào năm 2004. Các trường bổ sung đã được thêm vào sau đó.
Đây là WP_Querycấu trúc:
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 là con dao quân đội Thụy Sĩ.
Một số điều về WP_Query:
- đó là thứ bạn có thể kiểm soát thông qua các đối số bạn vượt qua
- nó là tham lam theo mặc định
- nó giữ chất để lặp
- nó được lưu trong không gian toàn cầu x2
- Nó có thể là chính hay phụ
- nó sử dụng các lớp trợ giúp
- nó có một
pre_get_postscái móc tiện dụng
- nó thậm chí còn hỗ trợ cho các vòng lặp lồng nhau
- nó giữ chuỗi truy vấn SQL
- nó giữ số lượng kết quả
- nó giữ kết quả
- nó giữ danh sách tất cả các đối số truy vấn có thể
- nó giữ các cờ mẫu
- ...
Tôi không thể giải thích tất cả những điều này, nhưng một số trong số này là khó khăn, vì vậy hãy cung cấp các mẹo ngắn.
WP_Query là thứ bạn có thể kiểm soát thông qua các đối số bạn vượt qua
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
Danh sách này từ WordPress phiên bản 4.7 chắc chắn sẽ thay đổi trong tương lai.
Đây sẽ là ví dụ tối thiểu tạo WP_Queryđối tượng từ các đối số:
// 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 là tham lam
Được tạo ra dựa trên ý tưởng Các get all you cannhà phát triển WordPress đã quyết định sớm nhận được tất cả dữ liệu có thể vì điều này tốt cho hiệu suất . Đây là lý do tại sao theo mặc định khi truy vấn lấy 10 bài đăng từ cơ sở dữ liệu, nó cũng sẽ nhận được các điều khoản và siêu dữ liệu cho các bài đăng này thông qua các truy vấn riêng biệt. Điều khoản và siêu dữ liệu sẽ được lưu trữ (tìm nạp trước).
Lưu ý bộ nhớ đệm chỉ dành cho vòng đời yêu cầu duy nhất.
Bạn có thể vô hiệu hóa bộ nhớ đệm nếu bạn thiết lập update_post_meta_cachevà update_post_term_cacheđể falsetrong khi thiết lậpWP_Query đối số. Khi bộ nhớ đệm bị vô hiệu hóa, dữ liệu sẽ chỉ được yêu cầu từ cơ sở dữ liệu theo yêu cầu.
Đối với phần lớn các blog WordPress bộ nhớ đệm hoạt động tốt, nhưng có một số trường hợp khi bạn có thể vô hiệu hóa bộ đệm.
WP_Query sử dụng các lớp trợ giúp
Nếu bạn đã kiểm tra WP_Querycác trường ở đó, bạn có ba:
public $tax_query;
public $meta_query;
public $date_query;
Bạn có thể tưởng tượng thêm mới trong tương lai.

WP_Query giữ chất cho vòng lặp
Trong mã này:
$query = new WP_Query( $args )
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
bạn có thể nhận thấy WP_Querycó chất bạn có thể lặp lại. Các phương pháp trợ giúp cũng có. Bạn chỉ cần đặt whilevòng lặp.
Ghi chú. forvà whilecác vòng lặp tương đương về mặt ngữ nghĩa.
WP_Query tiểu học và trung học
Trong WordPress, bạn có một truy vấn chính và không hoặc nhiều truy vấn phụ .
Có thể không có truy vấn chính, nhưng điều này nằm ngoài phạm vi của bài viết này.
Truy vấn chính được gọi là truy vấn chính hoặc truy vấn thông thường . Truy vấn phụ cũng được gọi là truy vấn tùy chỉnh .
WordPress sử dụng WP_Rewritelớp sớm để tạo các đối số truy vấn dựa trên URL. Dựa trên những lập luận này, nó lưu trữ hai đối tượng giống hệt nhau trong không gian toàn cầu. Cả hai sẽ giữ truy vấn chính.
global $wp_query @since WordPress 1.5
global $wp_the_query @since WordPress 2.1
Khi chúng ta nói truy vấn chính, chúng ta nghĩ về các biến này. Các truy vấn khác có thể được gọi là thứ cấp hoặc tùy chỉnh.
Nó là hoàn toàn hợp pháp để sử dụng global $wp_queryhoặc $GLOBALS['wp_query'] , nhưng việc sử dụng ký hiệu thứ hai đáng chú ý hơn nhiều và tiết kiệm việc nhập một dòng bổ sung bên trong phạm vi của các chức năng.
$GLOBALS['wp_query']và $GLOBALS['wp_the_query']là những đối tượng riêng biệt. $GLOBALS['wp_the_query']nên vẫn đông lạnh.
WP_Query có ích pre_get_posts móc .
Đây là móc hành động. Nó sẽ áp dụng cho bất kỳ WP_Query trường hợp. Bạn gọi nó như:
add_action( 'pre_get_posts', function($query){
if ( is_category() && $query->is_main_query() ) {
// set your improved arguments
$query->set( ... );
...
}
return $query;
});
Móc này là tuyệt vời và nó có thể thay đổi bất kỳ đối số truy vấn.
Đây là những gì bạn có thể đọc :
Bắn sau khi đối tượng biến truy vấn được tạo, nhưng trước khi truy vấn thực tế được chạy.
Vì vậy, hook này là trình quản lý đối số nhưng không thể tạo WP_Queryđối tượng mới . Nếu bạn có một truy vấn chính và một truy vấn phụ, pre_get_postskhông thể tạo truy vấn thứ ba. Hoặc nếu bạn chỉ có một chính, nó không thể tạo thứ cấp.
Lưu ý trong trường hợp bạn cần thay đổi truy vấn chính, bạn cũng có thể sử dụng requesthook.
WP_Query hỗ trợ các vòng lặp lồng nhau
Kịch bản này có thể xảy ra nếu bạn sử dụng plugin và bạn gọi các chức năng của plugin từ mẫu.
Dưới đây là ví dụ giới thiệu WordPress có các chức năng trợ giúp ngay cả đối với các vòng lặp lồng nhau:
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;
Đầu ra sẽ như thế này kể từ khi tôi cài đặt dữ liệu thử nghiệm đơn vị chủ đề :
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!
Mặc dù tôi đã yêu cầu 5 bài đăng trong truy vấn $ tùy chỉnh, nó sẽ trả về cho tôi sáu bài viết, bởi vì bài đăng dính sẽ đi cùng. Nếu không có wp_reset_postdatatrong ví dụ trước, đầu ra sẽ như thế này, vì $GLOBALS['post']sẽ không hợp lệ.
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_Querycó wp_reset_querychức năng
Đây giống như một nút đặt lại. $GLOBALS['wp_the_query']nên được đóng băng mọi lúc và các plugin hoặc chủ đề không bao giờ thay đổi nó.
Đây là những gì wp_reset_querylàm:
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
Nhận xét về get_posts
get_posts giống như
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);
Số dòng có thể thay đổi trong tương lai.
Nó chỉ là một wrapper xung quanh WP_Queryrằng lợi nhuận các bài viết đối tượng truy vấn.
Các ignore_sticky_poststhiết lập để phương tiện đúng các bài viết dính có thể xuất hiện chỉ ở một vị trí tự nhiên. Sẽ không có bài viết dính ở phía trước. Cái khác no_found_rowsđược đặt thành true có nghĩa là API cơ sở dữ liệu WordPress sẽ không sử dụng SQL_CALC_FOUND_ROWSđể triển khai phân trang, giảm tải cho cơ sở dữ liệu để thực thi các hàng tìm thấy số lượng .
Điều này rất hữu ích khi bạn không cần phân trang. Bây giờ chúng tôi hiểu rằng chúng tôi có thể bắt chước chức năng này với truy vấn này:
$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );
Đây là yêu cầu SQL tương ứng:
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
So sánh những gì chúng ta có bây giờ với yêu cầu SQL trước đây SQL_CALC_FOUND_ROWStồn tại.
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
Yêu cầu không có SQL_CALC_FOUND_ROWS sẽ nhanh hơn.
Nhận xét về query_posts
Mẹo: Lúc đầu năm 2004 chỉ có global $wp_query. Kể từ phiên bản WordPress 2.1 $wp_the_query. Mẹo: $GLOBALS['wp_query']và $GLOBALS['wp_the_query']là các đối tượng riêng biệt.
query_posts()là WP_Querybao bọc. Nó trả về tham chiếu đến WP_Queryđối tượng chính , đồng thời nó sẽ đặt global $wp_query.
File: /wp-includes/query.php
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
Trong PHP4, mọi thứ, bao gồm các đối tượng, được truyền bằng giá trị. query_postslà như thế này:
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);
}
Xin lưu ý trong kịch bản điển hình với một truy vấn chính và một truy vấn phụ, chúng tôi có ba biến sau:
$GLOBALS['wp_the_query']
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary
Giả sử mỗi người trong số ba người này chiếm 1M bộ nhớ. Tổng cộng sẽ là 3M bộ nhớ. Nếu chúng ta sử dụng query_posts, $GLOBALS['wp_query']sẽ không được đặt và tạo lại.
PHP5 + nên làm trống $GLOBALS['wp_query']đối tượng một cách thông minh , giống như trong PHP4, chúng ta đã làm điều đó vớiunset($GLOBALS['wp_query']);
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
Kết quả là query_poststiêu thụ tổng cộng 2M bộ nhớ, trong khi get_poststiêu thụ 3M bộ nhớ.
Lưu ý trong query_postschúng tôi không trả về đối tượng thực tế, mà là một tham chiếu đến đối tượng.
Từ php.net : Tham chiếu PHP là bí danh, cho phép hai biến khác nhau ghi vào cùng một giá trị. Kể từ PHP 5, một biến đối tượng không chứa chính đối tượng đó là giá trị nữa. Nó chỉ chứa một định danh đối tượng cho phép người truy cập đối tượng tìm thấy đối tượng thực tế. Khi một đối tượng được gửi bằng đối số, được trả về hoặc được gán cho một biến khác, các biến khác nhau không phải là bí danh: chúng giữ một bản sao của mã định danh, trỏ đến cùng một đối tượng.
Ngoài ra trong PHP5 + toán tử gán (=) là thông minh. Nó sẽ sử dụng bản sao nông và bản sao đối tượng không cứng. Khi chúng ta viết như thế này $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];chỉ có dữ liệu sẽ được sao chép chứ không phải toàn bộ đối tượng vì chúng chia sẻ cùng loại đối tượng.
Đây là một ví dụ
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'] ) ) );
Sẽ có kết quả:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
d6db1c6bfddac328442e91b6059210b5
Cố gắng đặt lại truy vấn:
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'] ) ) );
Sẽ có kết quả:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
Bạn có thể tạo ra vấn đề ngay cả khi bạn sử dụng 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'] ) ) );
Tất nhiên, giải pháp sẽ là sử dụng wp_reset_querychức năng một lần nữa.
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'] ) ) );
Đây là lý do tại sao tôi nghĩ query_postscó thể tốt hơn từ quan điểm bộ nhớ. Nhưng bạn nên luôn luôn làm wp_reset_querymẹo.