WP_Query Class là một công cụ đặc biệt mạnh mẽ trong WordPress. Như bạn đã biết, mọi trang web WordPress đều có cơ sở dữ liệu lưu trữ nhiều bài đăng (thuộc nhiều post type khác nhau) tạo nên phần lớn nội dung của trang web đó. WP_Query là cách tốt nhất để tìm nạp hoặc truy xuất một danh sách các bài viết đáp ứng một số yêu cầu nhất định do mình đặt ra. Vì vậy, không ngạc nhiên khi các files trong theme wordpress sử dụng nó thường xuyên và rất nhiều plugin của WordPress cũng sử dụng WP Query.
Việc sử dụng và sức mạnh của WP_Query sẽ có ý nghĩa hơn khi chúng ta đi sâu vào tìm hiểu nó. Cùng bắt đầu nhé!
Table of Contents
WP_Query và Object-Oriented PHP
WP_Query là một class PHP có một số thuộc tính nhất định. Khi sử dụng, trong PHP, new WP_Query() tức là bạn tạo một đối tượng (hoặc thể hiện) của lớp đó.
Nếu chưa hiểu về lập trình PHP hướng đối tượng, bạn có thể sẽ phải tìm hiểu sâu hơn về nó trước khi nghiên cứu về WP_Query. Nếu bạn đã đọc hoặc đã hiểu những kiến thức cơ bản về lập trình hướng đối tượng trong PHP, hãy áp dụng những khái niệm đó cho WP_Query.
Lấy đối tượng WP_Query bạn muốn
Khi bạn tạo một đối tượng WP_Query mới, tức là bạn tạo một truy vấn tới cơ sở dữ liệu để lấy dữ liệu tất cả các bài đăng WordPress mà bạn yêu cầu.
Vì vậy, một trong những điều đầu tiên bạn cần hiểu về WP_Query là theo mặc định, khi bạn khai báo new WP_Query, bạn sẽ không sử dụng được nhiều từ nó. Thay vào đó, cách bạn tạo đối tượng – cùng với truy vấn cụ thể mà bạn chạy – là cách bạn khai thác sức mạnh của WP_Query.
Phương thức khởi tạo của WP_Query chỉ nhận một tham số, $args. Điều này phổ biến trong WordPress – bạn chỉ cần chuyển một mảng hoặc chuỗi $args có chứa thông số về những gì bạn muốn. Độ sâu của những gì có thể đưa vào $args của bạn vượt xa những gì có giá trị để chia sẻ ở đây, nhưng mình sẽ đề cập đến các điểm cơ bản.
Tham số $args chấp nhận cả mảng và chuỗi, và cú pháp hơi khác nhau giữa chúng. Theo kinh nghiệm của mình thì mình khuyên bạn nên chủ yếu xây dựng $args dưới dạng mảng, bởi vì nó dễ và can thiệp được sâu hơn so với chuỗi.
Tạo đối tượng query mới với WP_Query
Như vậy, mỗi một trang trong WordPress đều có một truy vấn mặc định để lấy dữ liệu và được lưu trong $wp_query. Tất nhiên, không chỉ có 1, chúng ta có thể tạo ra nhiều đối tượng query khác nhau với các tham số khác nhau để lấy bài viết theo ý bạn muốn. Đó là lúc chúng ta cần sử dụng Class WP_Query.
Có vẻ như WordPress sử dụng SQL_CALC_FOUND_ROWS trong hầu hết các truy vấn để thực hiện phân trang. Ngay cả khi bạn không cần phân trang. SQL_CALC_FOUND_ROWS yêu cầu MySQL thực hiện công việc bổ sung để đếm tổng số kết quả của truy vấn và điều này có thể tạo ra nhiều khác biệt nếu bạn có một lượng dữ liệu lớn.
Với các hàm get_posts và query_posts có một tham số mặc đinh để ngăn cho việc đếm kết quả truy vấn. Tham số được đặt tên là no_found_rows và nó chấp nhận các giá trị boolean – tức là true hoặc false. Nó nói với WordPress không tính tổng số kết quả của truy vấn. Đây là một ví dụ sử dụng:
query_posts ('no_found_rows=true&cat=1&numberposts=-1');Kể từ phiên bản WordPress 4.6.1 hàm get_posts đã được tự động đặt no_found_rows=true. Riêng query_posts và WP_Query thì vẫn đếm tổng số kết quả của truy vấn, vì vậy bạn vẫn nên đặt no_found_rows=true khi sử dụng chúng và không cần phân trang.
Cách sử dụng WP_Query
Như đã nói ở trên, class này nhận duy nhất một tham số dưới dạng mảng hoặc chuỗi. Chúng ta muốn tùy chỉnh để lấy bài viết thì chúng ta chỉ cần thay đổi tham số khai báo trong mảng hoặc chuỗi này là được.
Cấu trúc đoạn mã như sau:
$my_query = new WP_Query( $args );
Trong đó, $args là biến chứa tham số.
Một số ví dụ cụ thể cho các bạn dễ hiểu nhé
Lấy bài viết theo tác giả
Hiển thị bài viết của 1 tác giả nào đó khi đã biết id của tác giả. Ví dụ bên dưới id của tác giả là 123
$query = new WP_Query( array( 'author' => 123 ) );
Hiển thị bài viết của 1 tác giả nào đó khi đã biết user_nicename của tác giả. Ví dụ bên dưới user_nicename của tác giả là admin
$query = new WP_Query( array( 'author_name' => 'admin' ) );
Hiển thị bài viết từ nhiều tác giả
Ví dụ bên dưới dùng để lấy bài viết của nhiều tác giả với các id là 3,5,7,10
$query = new WP_Query( array( 'author' => '3,5,7,10' ) );
Lấy bài viết nhưng không lấy bài của tác giả có id là 10
Lấy tất cả bài viết trừ những bài của tác giả có id là 10:
$query = new WP_Query( array( 'author' => -10 ) );
Sử dụng array để lấy bài viết của nhiều tác giả
$query = new WP_Query( array( 'author__in' => array( 2, 6 ) ) );
Tương tự bạn cũng có thể loại bỏ các bài viết của nhiều tác giả khác nhau:
$query = new WP_Query( array( 'author__not_in' => array( 2, 6 ) ) );
Tương tự với category.
Lấy tất cả bài viết trong category có id là 4 (bao gồm cả các category con của category có id là 4)
$query = new WP_Query( array( 'cat' => 4 ) );
Tương tự như bên trên nhưng thay vì lấy theo id thì ta lấy theo slug của category:
$query = new WP_Query( array( 'category_name' => 'du-lich' ) );
Nếu muốn lấy bài viết của category có id là 4 thôi, không lấy các bài viết của category con của category có id là 4 thì thay vì dùng cat, ta dùng category__in
$query = new WP_Query( array( 'category__in' => 4 ) );
Cũng như vậy, để lấy bài viết ở nhiều category:
$query = new WP_Query( array( 'cat' => '2,6,17,38' ) );
Lấy bài ở nhiều category dùng slug:
$query = new WP_Query( array( 'category_name' => 'du-lich,meo-vat' ) );
Lấy dữ liệu bài viết nằm ở cả 2 category du-lich và meo-vat
$query = new WP_Query( array( 'category_name' => 'du-lich+meo-vat' ) );
Ta cũng có thể loại bỏ các category không muốn lấy bài viết bằng dấu trừ (-).
$query = new WP_Query( array( 'cat' => '-12,-34,-56' ) );
Lấy dữ liệu bài viết nằm ở cả 2 category có id là 2 và 6
$query = new WP_Query( array( 'category__and' => array( 2, 6 ) ) );
Để lấy bài viết ở category có id là 2 HOẶC 6 thì ta có thể dùng ‘cat’=>’2,6’ hoặc là category__in (cái này nó không lấy bài ở các category con):
$query = new WP_Query( array( 'category__in' => array( 2, 6 ) ) );
Tương tự có thể loại bỏ bài viết ở nhiều category khác nhau bằng cách dùng ‘category__not_in’:
$query = new WP_Query( array( 'category__not_in' => array( 2, 6 ) ) );
Tất cả các tham số trong WP_Query
Ngoài các ví dụ cụ thể bên trên, mình list ra đây tất cả các tham số có thể sử dụng của chuỗi $args khi truyền vào class WP_Query. Mời các bạn tham khảo. Lưu ý khi sử dụng phải kết hợp cho chuẩn, đừng kết hợp kiểu có cả __in và __not_in cùng id nhé :D.
$args = array( //////Author Parameters - Tham số lấy bài viết theo tác giả //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Author_Parameters 'author' => '1,2,3,', //(int) - Các ID tác giả cần lấy bài viết (thêm dấu - vào để loại trừ tác giả, ví dụ: -14, -20) 'author_name' => 'luetkemj', //(string) - Lấy bài viết dựa theo tên nick name của tác giả 'author__in' => array( 3, 4 ), //(array) - Lấy bài dựa theo ID của tác giả 'author__not_in' => array( 2, 6 ), //(array)' - Các ID của tác giả không muốn lấy bài ////// Category Parameters - Tham số lấy bài viết dựa theo category //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Category_Parameters 'cat' => 5,//(int) - Lấy bài dựa theo ID của category 'category_name' => 'staff, news', //(string) - Lấy bài dựa theo category slug 'category__and' => array( 2, 6 ), //(array) - Lấy bài mà nó mang cả hai category 2 và 6 (ID) 'category__in' => array( 2, 6 ), //(array) - ID của các category không muốn lấy bài 'category__not_in' => array( 2, 6 ), //(array) - Các ID của category không muốn lấy bài ////// Tag Parameters - Tham số lấy bài viết dựa theo tag //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Tag_Parameters 'tag' => 'cooking', //(string) - Lấy bài viết theo tag slug 'tag_id' => 5, //(int) - Lấy bài viết theo tag ID 'tag__and' => array( 2, 6), //(array) - Lấy bài viết mà nó mang cả hai tag có ID 2 và 6 'tag__in' => array( 2, 6), //(array) - Lấy tất cả bài viết trong nhiều tag ID khác nhau 'tag__not_in' => array( 2, 6), //(array) - Các tag ID không muốn lấy bài 'tag_slug__and' => array( 'red', 'blue'), //(array) - Lấy bài viết mà nó mang cả hai tag có slug red và blue 'tag_slug__in' => array( 'red', 'blue'), //(array) - Lấy bài viết trong nhiều tag slug khác nhau //////Taxonomy Parameters - Lấy bài viết dựa theo taxonomy //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Taxonomy_Parameters //Quan trọng: tax_query là tham số có thể sẽ chứa nhiều mảng lồng vào bên trong 'tax_query' => array( //(array) - Lấy bài viết dựa theo taxonomy 'relation' => 'AND', //(string) - Mối quan hệ giữa các tham số bên trong, AND hoặc OR array( 'taxonomy' => 'color', //(string) - Tên của taxonomy 'field' => 'slug', //(string) - Loại field cần xác định term của taxonomy, sử dụng 'id' hoặc 'slug' 'terms' => array( 'green', 'yellow' ), //(int/string/array) - Slug của các terms bên trong taxonomy cần lấy bài 'include_children' => true, //(bool) - Lấy category con, true hoặc false 'operator' => 'IN' //(string) - Toán tử áp dụng cho mảng tham số này. Sử dụng 'IN' hoặc 'NOT IN' ), array( 'taxonomy' => 'actor', 'field' => 'id', 'terms' => array( 113, 125, 236 ), 'include_children' => false, 'operator' => 'NOT IN' ) ), //////Post & Page Parameters - Lấy bài viết dựa vào tham số của Post hoặc Page //Tham khảo: https://codex.wordpress.org/Class_Reference/WP_Query#Post_.26_Page_Parameters 'p' => 1, //(int) - ID của post cần hiển thị 'name' => 'hello-world', //(string) - Slug của post cần hiển thị 'page_id' => 1, //(int) - ID của page cần hiển thị 'pagename' => 'sample-page', //(string) - Slug của page cần hiển thị 'pagename' => 'contact_us/canada', //(string) - Hiển thị page con bằng slug của page mẹ và page con, cách nhau bởi dấu gạch chéo 'post_parent' => 1, //(int) - Lấy page con dựa vào ID của page mẹ 'post_parent__in' => array(1,2,3) //(array) - Lấy nhiều page con dựa vào nhiều page mẹ thông qua ID 'post_parent__not_in' => array(1,2,3), //(array) - Các ID của page mẹ không muốn hiển thị page con 'post__in' => array(1,2,3), //(array) - Danh sách các post cần lấy, dùng ID 'post__not_in' => array(1,2,3), //(array) - Danh sách các post không muốn lấy, dùng ID //NOTE: Bạn không thể sử dụng 'post__in' cùng với 'post__not_in' trong một query //////Password Parameters - Lấy các bài viết dựa theo thiết lập mật khẩu của post //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Password_Parameters 'has_password' => true, //(bool) - Lấy các bài viết có đặt password //true bài viết có pass //false bài viết không có pass //null Mặc định nó sẽ lấy toàn bộ post có pass và không có pass 'post_password' => 'multi-pass', //(string) - show posts with a particular password (available with Version 3.9) //////Type - Hiển thị post dựa vào loại post //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Type_Parameters 'post_type' => array( //(string / array) - tên post type cần lấy bài viết. Mặc định là 'post' 'post', // - post. 'page', // - page. 'revision', // - revision. 'attachment', // - tập tin đính kèm. 'my-post-type', // - Tên custom post type ), 'post_type' => 'any', // - Lấy bất kỳ post type đang có trên website //////Status Parameters - Lấy các bài viết dựa theo trạng thái của nó //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Status_Parameters 'post_status' => array( //(string / array) 'publish', // - Post hoặc Page đã được publish 'pending', // - Post đang ở trạng thái Pending Review 'draft', // - Post đang trong nháp 'auto-draft', // - Các bài viết tự động lưu nháp 'future', // - Bài viết đang được đặt thời gian đăng trong tương lai 'private', // - Bài viết đang trong trạng thái riêng tư 'inherit', // - Lấy một bản revision 'trash' // - Lấy post từ thùng rác ), 'post_status' => 'any', // - Sử dụng bất kỳ trạng thái nào //////Pagination Parameters //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Pagination_Parameters 'posts_per_page' => 10, //(int) - Số lượng bài viết cần lấy ra để hiển thị trên mỗi trang. Nếu muốn hiển thị toàn bộ thì đặt giá trị là -1 'posts_per_archive_page' => 10, //(int) - Số lượng bài viết cần lấy ra hiển thị trên mỗi trang. Nhưng chỉ sử dụng cho các trang lưu trữ. 'nopaging' => false, //(bool) - Nếu muốn sử dụng phân trang thì đặt là false. True sẽ hiển thị tất cả post. Mặc định là false. 'paged' => get_query_var('paged'), //(int) - Số trang hiện tại. //NOTE: Sử dụng get_query_var('page') nếu bạn cần sử dụng nó ở một Custom Page Template // https://developer.wordpress.org/reference/functions/next_posts_link/ 'offset' => 3, // (int) - Số bài viết trước đó mà bạn muốn bỏ qua. // Warning: Thiết lập này sẽ làm cho phần phân trang bị lỗi, xem thêm: https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination // Nếu tham số 'posts_per_page' có giá trị là -1 thì offset sẽ bị bỏ qua. 'page' => get_query_var('page'), // (int) - Số trang hiện tại sử dụng cho Custom Page Template. 'ignore_sticky_posts' => false, // (boolean) - Tuỳ chọn có lấy bài viết được Sticky hay không. Nếu false thì sẽ hiển thị, true thì bỏ qua. //////Order & Orderby Parameters - Thiết lập kiểu sắp xếp các bài viết //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Order_.26_Orderby_Parameters 'order' => 'DESC', //(string) - Thiết lập hiển thị tăng dần hay giảm dần. //Possible Values: //'ASC' - Hiển thị kiểu tăng dần (1, 2, 3; a, b, c). //'DESC' - Hiển thị kiểu giảm dần (3, 2, 1; c, b, a). 'orderby' => 'date', //(string) - Thiết lập loại dữ liệu sẽ được sắp xếp. Mặc định nó sẽ là tham số 'date' để dựa vào ngày đăng bài. // Các giá trị có thể orderby là: //'none' - Không sắp xếp //'ID' - Sắp xếp bởi ID bài viết //'author' - Sắp xếp bởi tác giả //'title' - Sắp xếp bởi tiêu đề //'name' - Sắp xếp bởi slug //'date' - Sắp xếp bởi ngày tháng //'modified' - Sắp xếp bởi ngày cập nhật //'parent' - Sắp xếp bởi ID của page mẹ //'rand' - Sắp xếp ngaẫu nhiên //'comment_count' - Sắp xếp bởi số lượng bình luận //'menu_order' - Sắp xếp bởi thứ tự của trang //'meta_value' - Sắp xếp bởi giá trị meta data //'meta_value_num' - Sắp xếp bởi giá trị dạng số tự nhiên của meta data //////Date Parameters - Lấy bài viết trong khoảng thời gian cố định //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Date_Parameters 'date_query' => array( //(array) - Date parameters (available with Version 3.7). These are super powerful. check out the codex for more comprehensive code examples Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Date_Parameters array( 'year' => [THE_CURRENT_YEAR], //(int) - năm cần lấy bài (e.g. 2011). 'monthnum' => 4, //(int) - Tháng cần lấy bài (from 1 to 12). 'w' => 25, //(int) - Số tuần trong năm cần lấy bài (từ 0 đến 53). 'day' => 17, //(int) - Lấy bài dựa theo ngày trong tháng (từ 1 đến 31). 'hour' => 13, //(int) - Lấy bài dựa theo giờ trong ngày (từ 0 đến 23). 'minute' => 19, //(int) - Lấy bài dựa theo phút trong giờ (từ 0 đến 60). 'second' => 30, //(int) - Lấy bài dựa theo giây trong phút (0 đến 60). 'm' => 201404, //(int) - Tháng của năm cần lấy bài (Ví dụ: 201307). 'after' => 'January 1st, 2013', //(string/array) - Lấy bài viết sau ngày cố định. Có thể sử dụng strtotime()-compatible string, hoặc sử dụng array gồm 'year', 'month', 'day' 'before' => array( //(string/array) - Lấy bài viết trước ngày cố định. Có thể sử dụng strtotime()-compatible string, hoặc sử dụng array gồm 'year', 'month', 'day' 'year' => 2013, 'month' => 2, 'day' => 28, ), 'inclusive' => true, //(boolean) - Nếu sử dụng before và after, sử dụng 'true' nếu muốn bao gồm cả hai tham số. 'compare' => '=', //(string) - So sánh giá trị với '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Default value is '=' 'column' => 'post_date', //(string) - Cột dữ liệu mà cần gửi query đến, mặc định là 'post_date' 'relation' => 'AND', //(string) - OR hoặc AND, sử dụng khi có nhiều array trong date_query để tạo mối quan hệ ), ), //////Custom Field Parameters - Lấy bài viết dựa theo custom field //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Custom_Field_Parameters 'meta_key' => 'key', //(string) - Lấy bài dựa theo meta key của custom field 'meta_value' => 'value', //(string) - Lấy bài dựa theo giá trị của custom field 'meta_value_num' => 10, //(number) - Giá trị của custom field dạng số tự nhiên 'meta_compare' => '=', //(string) - Toán tử để so sánh với 'meta_value'. Có thể sử dụng '!=', '>', '>=', '<', or ='. Mặc định là '='. 'meta_query' => array( //(array) - Sử dụng nhiều điều kiện lấy bài viết theo custom field 'relation' => 'AND', //(string) - Mối quan hệ của các array query bên trong, sử dụng 'OR' hoặc 'AND' array( 'key' => 'color', //(string) - Tên meta key 'value' => 'blue' //(string/array) - Giá trị meta value 'type' => 'CHAR', //(string) - Loại giá trị. Có thể sử dụng 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'. Mặc định là 'CHAR'. Tham số 'type' DATE chỉ có thể hoạt động với tham số 'compare' nếu định dạng ngày tháng được sử dụng là YYYYMMDD. 'compare' => '=' //(string) - Toán tử so sánh với giá trị value trong mảng này. Có thể sử dụng '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS' (only in WP >= 3.5), and 'NOT EXISTS' (also only in WP >= 3.5). Default value is '='. ), array( 'key' => 'price', 'value' => array( 1,200 ), 'compare' => 'NOT LIKE' ) ), //////Caching Parameters //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Caching_Parameters //NOTE Caching is a good thing. Setting these to false is generally not advised. 'cache_results' => true, //(bool) Mặc định là true - Lưu cache của thông tin kết quả query 'update_post_term_cache' => true, //(bool) Default is true - Post meta information cache. 'update_post_meta_cache' => true, //(bool) Default is true - Post term information cache. 'no_found_rows' => false, //(bool) //////Search Parameter - Lấy bài viết dựa theo truy vấn tìm kiếm //Tham khảo: https://developer.wordpress.org/reference/classes/wp_query/#Search_Parameter 's' => $s, //(string) - Từ khoá tìm kiếm bài viết. $s chính là biến lưu từ khoá truy vấn tìm kiếm khi tìm thông qua form tìm kiếm. 'exact' => true, //(bool) - Tìm nội dung khớp chính xác với từ khoá tìm kiếm 'sentence' => true, //(bool) - Sử dụng tìm kiếm trong cụm từ ); $query = new WP_Query($args); if ( $query->have_posts() ) : ?> <!-- pagination here --> <!-- the loop --> <?php while ( $query->have_posts() ) : $query->the_post(); ?> <h2><?php the_title(); ?></h2> <?php endwhile; ?> <!-- end of the loop --> <!-- pagination here --> <?php wp_reset_postdata(); ?> <?php else : ?> <p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p> <?php endif;
Sử dụng WP Query và Loop (vòng lặp) để lấy bài viết
Ví dụ dưới đây sử dụng WP Query và vòng lặp để lấy bài viết của tác giả admin
$query = new WP_Query( array( 'author_name' => 'admin' ) );
Một ví dụ phức tạp hơn là lấy tất cả bài viết của tác giả admin, trong vòng 1 tuần qua, được post trong mục du-lich
<?php $args = array( 'author_name' => 'david', 'post_type' => 'post', 'tax_query' => array( array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => array( 'du-lich' ), ) ), 'date_query' => array( array( 'after' => date('F j, Y',(strtotime('7 days ago'))), 'inclusive' => true, ), ), 'posts_per_page' => -1, ); $query = new WP_Query($args); if ( $query->have_posts() ) : ?> <!-- pagination here --> <!-- the loop --> <?php while ( $query->have_posts() ) : $query->the_post(); ?> <h2><?php the_title(); ?></h2> <?php endwhile; ?> <!-- end of the loop --> <!-- pagination here --> <?php wp_reset_postdata(); ?> <?php else : ?> <p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p> <?php endif;
Tham khảo thêm thông tin về WP_Query tại WordPress Developer Resources