Có vẻ như một nửa số hướng dẫn trong Codex và cộng đồng viết blog (blogosphere) sử dụng query_posts() và nửa số còn lại sử dụng WP_Query. Vấn đề ở đây là gì?
Xem qua cái này longer analysis – prosti Dec 25 ’16 at 23:26
Contents
8 câu trả lời
Câu trả lời chính xác nhất
- query_posts() là cách cực kỳ đơn giản và hay xảy ra nhiều vấn đề dùng để sửa truy vấn chính của một trang bằng cách thay thế nó bởi ví dụ truy vấn mới. Nó không hiệu quả (re-runs SQL queries) và sẽ hoàn toàn thất bại trong một số trường hợp (đặc biệt là khi làm việc với các bài viết có đánh số trang). Bất kì WP code hiện đại nào cũng sử dụng nhiều phương pháp đáng tin cậy hơn, như việc tận dụng pre_get_posts hook, cho mục đích này. TL;DR không sử dụng query_posts() bao giờ;
- get_posts() rất giống trong sử dụng và nó chấp nhận các đối số giống nhau (với một số sắc thái, như các giá trị mặc định khác nhau), nhưng nó trả về một loạt các bài viết, các biến số toàn cục (global variable) không bị sửa đổi và nó an toàn khi sử dụng ở bất cứ đâu;
- WP_query có sức mạnh cả phía sau hậu trường, nhưng bạn cũng có thể tạo và làm việc với đối tượng riêng của nó. Nó phức tạp hơn một chút, nhưng ít giới hạn hơn, và cũng an toàn để sử dụng ở bất cứ đâu.
Trả lời bởi Rarst
@jjeaton query_posts() là chức năng bao hàm nhỏ (wrapper function) cho WP_Query, điều duy nhất nó có thêm (theo sơ đồ) là overwriting global $wp_query – Rarst Aug 8 ’11 at 15:39
@jjeaton thay query_posts() bằng WP_Query thì hiệu suất sẽ không khác nhau, truy vấn của trang gốc sẽ vẫn chạy bởi vì đó là một phần của core load. Những truy vấn này vẫn sẽ chạy thậm chí nếu tệp mẫu của bạn không có vòng lặp nào. – Rarst Aug 8 ’11 at 17:15
Tôi có cảm giác rằng đây là bài viết xuất sắc và được ủng hộ nhiều nhất trên WPSE. Có lẽ là ở trong Codex nữa. – kaiser♦ Sep 16 ’11 at 0:03
Tôi chỉ muốn thêm vào mô tả rõ nhất của tôi về vấn đề “hiệu suất của query_posts()”: Việc sử dụng query_posts() hay WP_Query trong một tệp mẫu có chi phí hiệu suất (performnace cost) giống nhau: Đó là truy vấn bạn vừa thực hiện. Vấn đề được thảo luận trong bài viết codex đó là nếu chính xác bạn muốn thay thế truy vấn thì nên lọc query_posts() gốc bằng bộ lọc ‘parse_query’. Với cách này, bạn chỉ có duy nhất một truy vấn gốc mong muốn, thay vì làm một truy vấn thứ hai để rồi lại thay thế nó một cách khó khăn. query_posts() không bao giờ là cách giải quyết cho vấn đề này – jerclarke Apr 19 ’12 at 22:24
Có một cách giải thích cực kì tuyệt vời về query_posts được viết bởi John James Jacoby trong blog developer.wordpress.com, nó hơn xa các câu trả lời này. Điểm chính ở đây là: query_posts không hề sửa đổi vòng lặp chính, nó thay thế chính nó sau khi đã chạy xong. Cách tốt nhất để sửa đổi vòng lặp chính đó là sử dụng bộ lọc pre_get_posts. developer.wordpress.com/2012/05/14/… – Dan Gayle Jun 9 ’12 at 23:10
Câu trả lời có 51 bình chọn
query_posts – Bạn đừng bao giờ dùng query_posts. Ngoại trừ những gì mà @Rarst đã nói, vấn đề lớn nhất của query_posts là nó phá vỡ đối tượng truy vấn chính (main query object) (được lưu trữ trong $wp_query). Nhiều plugin và mã tùy chỉnh (custom code) phụ thuộc vào đối tượng truy vấn chính (main query object), vì vậy phá vỡ đối tượng truy vấn chính có nghĩa là bạn đang phá vỡ các chức năng của plugin và mã tùy chỉnh (custom code). Lấy ví dụ một chức năng rất quan trọng là chức năng đánh số trang, vì vậy nếu bạn phá vỡ truy vấn chính thì bạn sẽ phá vỡ chức năng đánh số trang.
Để chứng minh query_posts tệ như thế nào, hãy thử như dưới đây với một số mẫu và so sánh kết quả:
var_dump( $wp_query );
query_posts( ‘&posts_per_page=-1’ );
var_dump( $wp_query );
get_posts và WP_Query là những hướng đi đúng nhất để xây dựng các truy vấn phụ (secondary queries) (ví dụ như bài đăng liên quan, các thanh trượt, nội dung nổi bật). Cần lưu ý rằng bạn không nên dùng cái có lợi cho truy vấn chính trên trang chủ, trang riêng lẻ hay bất cứ loại trang lưu trữ nào, bởi vì nó sẽ phá vỡ chức năng của trang. Nếu bạn cần chỉnh sửa truy vấn chính, hãy sử dụng pre_get_posts thay vì một truy vấn tùy chỉnh (custom query). Đối với các trang tĩnh và trang thực, hãy xem Using pre_get_posts on true pages and static front pages
Về bản chất, WP_Query được dùng bởi truy vấn chính và cả get_posts, nhưng mặc dù get_posts() sử dụng WP_Query, vẫn có một vài điểm khác nhau như sau:
- get_posts nhanh hơn WP_Query. Nó phụ thuộc vào tổng số trang của trang web. Lý do của việc này là get_posts chuyển ‘no_found_rows’ => true theo mặc định thành WP_Query, nó bỏ qua hoặc phân tách việc phân trang. Với ‘no_found_rows’ => true, theo những gì đã được mặc định WP_Query có các bài viết đã được truy vấn và sau đó dừng lại để tiếp tục tìm kiếm tất cả các bài viết phù hợp với truy vấn để tính toán phân trang. Vì lý do này, chỉ nên dùng get_posts với những truy vấn không đánh trang. Việc đánh trang get_posts thực sự sẽ gây lộn xộn. WP_Query nên được dùng cho tất cả các truy vấn được phân trang.
- get_posts không bị ảnh hưởng bởi các bộ lọc posts_* trong khi WP_Query thì bị ảnh hưởng bởi các bộ lọc này. Lý do là get_posts chuyển ‘no_found_rows’ => true theo mặc định thành WP_Query.
- get_posts có một số thông số bổ sung như include, exclude, numberposts và category. Những tham số này được thay đổi thành các tham số hợp lệ dành cho WP_Query trước khi được chuyển đến WP_Query. include được chuyển thành post__in, exclude thành post__not_in, category thành cat and numberposts thành posts_per_page. Chỉ có một lưu ý là, tất cả các tham số mà có thể chuyển sang WP_Query đều làm việc với get_posts. Bạn có thể không cần quan tâm tới và không sử dụng các thông số mặc định của get_posts.
- get_posts chỉ trả về thuộc tính $posts của WP_Query trong khi WP_Query trả về đối tượng hoàn chỉnh. Đối tượng này khá hữu ích khi làm việc với các điều kiện, đánh số trang và các thông tin hữu ích khác có thể được sử dụng trong vòng lặp.
- get_posts không sử dụng vòng lặp, thay vào đó là vòng lặp foreach để hiện thị các bài viết. Cũng không có thẻ mẫu nào (template tag) khả dụng theo mặc định. setup_postdata( $post ) được sử dụng để làm cho các thẻ mẫu (template tag) trở nên khả dụng. WP_Query sử dụng vòng lặp và các thẻ mẫu mặc định sẵn có.
- get_posts chuyển ‘ignore_sticky_posts’ => 1 thành WP_Query, vì vậy get_posts mặc định không chú ý đến các bài viết dính (sticky posts).
Dựa vào những gì được trình bày ở trên, việc sử dụng get_posts hay WP_Query là tùy thuộc ở bạn và việc chính xác bạn cần cái gì từ truy vấn. Những gì được trình bày ở trên sẽ giúp bạn đưa ra được lựa chọn của mình.
Được trả lời bởi Pieter Goosen
Tôi ước gì có thể ấn thích các câu trả lời. Câu trả lời của bạn đã giải thích cho tôi rất nhiều điều. – Patrik Alienus Jun 12 ’17 at 7:17
Giải thích quá tuyệt vời! “chỉ nên dùng get_posts với những truy vấn không đánh trang. Việc đánh trang get_posts thực sự sẽ gây lộn xộn. WP_Query nên được dùng cho tất cả các truy vấn được phân trang.” Đây là những điều cơ bản mà mọi người phải biết. – Bullyen Apr 19 at 19:27
Câu trả lời có 29 bình chọn
Sự khác nhau cơ bản là query_posts() thực sự chỉ nên dùng để chỉnh sửa vòng lặp hiện tại. Một khi bạn đã hoàn thành thì cần thiết lập lại vòng lặp. Phương pháp này cũng dễ hiều hơn, đơn giản là vì truy vấn của bạn về cơ bản là một chuỗi URL mà bạn chuyển đến hàm, giống như là:
query_posts(‘meta_key=color&meta_value=blue’);
Mặt khác, WP_Query là một công cụ mục đích chung (general purpose tool) và nó trực tiếp viết các truy vấn MySQL hơn so với query_posts(). Bạn cũng có thể sử dụng nó bất cứ đâu (không chỉ trong vòng lặp) và nó không can thiệp vào bất kỳ truy vấn bài đăng hiện đang chạy nào (currently running post queries).
Tôi thường sử dụng WP_Query nhiều hơn khi điều đó xảy ra.Thực sự thì điều đó phụ thuộc vào từng trường hợp cụ thể mà bạn gặp phải.
Được trả lời bởi nickmjones
Câu trả lời có 12 bình chọn
Đơn giản là không cần thiết phải sử dụng query_posts(). Tất cả những gì nó làm là khởi tạo một đối tượng WP_Query mới và giao lại đối tượng mới này cho global wp_query.
Để tham khảo, dưới đây là hàm query_posts () thực tế:
function query_posts($query) {
$GLOBALS[‘wp_query’] = new WP_Query();
return $GLOBALS[‘wp_query’]->query($query);
}
Khởi tạo đối tượng WP_Query của bạn nếu bạn muốn tạo tập lệnh truy vấn tùy chỉnh chuyên sâu (in depth custom query script). Hoặc sử dụng get_posts () nếu tất cả những gì bạn cần làm là một vài thao tác đơn giản.
Trong những trường hợp khác, tôi khuyến khích cao bạn nên tự làm lấy, xem thử wp_includes / query.php và đọc qua WP_Query class.
Trả lời bởi RebelPhoenix
Câu trả lời có 12 bình chọn
Đảm bảo rằng bạn sử dụng wp_reset_query () sau khi sử dụng query_posts () vì nó cũng sẽ ảnh hưởng đến kết quả truy vấn khác.
Trả lời bởi Bindiya Patoliya
Câu trả lời có 8 bình chọn
Nếu tôi nhớ không nhầm về quyền đọc, về cơ bản “vòng lặp” đang thực hiện WP_Query trong các tệp lõi, nhưng theo một cách dễ hiểu hơn.
Trả lời bởi tw2113