Câu hỏi quan trọng
Hãy đào vào bộ ba: ::query_posts
, ::get_posts
và class WP_Query
để hiểu ::query_posts
tốt hơn.
Nền tảng để nhận dữ liệu trong WordPress là WP_Query
lớp. Cả hai phương thức ::query_posts
và ::get_posts
sử dụng lớp đó.
Lưu ý rằng lớp WP_Query
cũng chứa các phương thức có cùng tên: WP_Query::query_posts
và 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_Query
cấ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_posts
cá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 can
nhà 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_cache
và update_post_term_cache
để false
trong 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_Query
cá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_Query
có 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 while
vòng lặp.
Ghi chú. for
và while
cá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_Rewrite
lớ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_query
hoặ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_posts
khô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 request
hook.
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_postdata
trong 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_Query
có wp_reset_query
chứ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_query
là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_Query
rằng lợi nhuận các bài viết đối tượng truy vấn.
Các ignore_sticky_posts
thiế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_ROWS
tồ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_Query
bao 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_posts
là 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_posts
tiêu thụ tổng cộng 2M bộ nhớ, trong khi get_posts
tiêu thụ 3M bộ nhớ.
Lưu ý trong query_posts
chú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_query
chứ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_posts
có 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_query
mẹo.