WP_Query: nhận 3 bài đăng ngẫu nhiên từ 10 bài mới nhất


7

Làm việc trên một trang web có rất nhiều bài đăng, tôi cần hiển thị 3 bài đăng từ một danh mục cụ thể, nhưng tất cả chúng đều phải từ 10 bài mới nhất được xuất bản trên trang. Tôi có thể lấy 3 bài đăng hoàn toàn ngẫu nhiên (có xu hướng kéo các bài đăng rất cũ) hoặc lấy 10 bài đăng (nhưng tôi không biết cách ngẫu nhiên thứ tự và chỉ hiển thị 3).

Cho đến nay, tôi có truy vấn này:

$args = array(
    'post_type' => 'post',
    'category_name' => 'mycategory',
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC',
    'meta_key' => '_thumbnail_id',
    'no_found_rows' => 'true'
);
$query = new WP_Query( $args );

cùng với nỗ lực này để có được 3 bài đăng ngẫu nhiên từ 10 câu hỏi:

$randomPosts = shuffle( $query ); 
$randomPosts = array_slice( $randomPosts, 0, 3 );

Nhưng coi kết quả là một mảng không hoạt động, vì nó thực sự là một đối tượng.
Suy nghĩ duy nhất khác của tôi là sử dụng 'posts_per_page' = 3với 'orderby' => 'rand'để lấy 3 bài viết ngẫu nhiên và thêm một 'date_query'hạn chế nó đến 6 tháng qua. Điều đó sẽ gần, nhưng tốt nhất là hạn chế truy vấn trong 10 bài đăng gần đây nhất (tất cả chúng có thể được xuất bản 3 ngày trước hoặc 5 tháng trước, chúng được xuất bản cùng nhau trong các giai đoạn không đồng đều).

Đâu là cách tiếp cận lí tưởng nhất?
Truy vấn 10 bài đăng mới nhất như tôi đang làm, sau đó chuyển đổi đối tượng thành một mảng, xáo trộn và cắt lát và chuyển đổi nó trở lại một đối tượng hoặc có cách nào đơn giản hơn, hiệu quả hơn để thực hiện mục tiêu?

Câu trả lời:


12

Có một cách với:

$args = [
    'post_type'             => 'post',
    'posts_per_page'        => 10,
    'orderby'               => 'date',
    'order'                 => 'DESC',
    'no_found_rows'         => 'true',
    '_shuffle_and_pick'     => 3 // <-- our custom argument
];

$query = new \WP_Query( $args );

trong đó _shuffle_and_pickthuộc tính tùy chỉnh được hỗ trợ bởi plugin demo này:

<?php
/**
 * Plugin Name: Support for the _shuffle_and_pick WP_Query argument.
 */
add_filter( 'the_posts', function( $posts, \WP_Query $query )
{
    if( $pick = $query->get( '_shuffle_and_pick' ) )
    {
        shuffle( $posts );
        $posts = array_slice( $posts, 0, (int) $pick );
    }
    return $posts;
}, 10, 2 );

Tuyệt vời, điều đó đã làm chính xác những gì tôi cần. Cảm ơn bạn!
WebElaine

Rất vui khi biết nó hoạt động cho bạn @WebElaine
birgire 20/03/2017

Điều này thực sự rất đơn giản và gọn gàng. Tôi hy vọng khách hàng của tôi sẽ không bao giờ gặp bạn vì tôi có thể sẽ nghỉ việc. haha
Christine Cooper

1
Điều này thật tuyệt vời - hoạt động như một sự quyến rũ, cảm ơn! BTW - là dấu gạch chéo ngược trước WP_Querylỗi chính tả hoặc là một số mẹo hữu ích mà tôi không biết.
squarecandy

1
@squarecandy cảm ơn bình luận của bạn. Khi chúng tôi sử dụng một không gian tên tùy chỉnh trong plugin của mình, thì chúng tôi cần "gạch chéo ngược" lớp WP_Query vì không có không gian tên WordPress đặc biệt.
bạch dương

5

Rõ ràng bạn có thể lấy tất cả các bài đăng và chọn ngẫu nhiên kết quả với PHP như thể hiện trong câu trả lời này . Hoặc, bạn cũng có thể thực hiện ngẫu nhiên với SQL.

Xử lý ngẫu nhiên trong cơ sở dữ liệu:

Không có chức năng (hoặc đối số) được xây dựng trong WordPress để đạt được điều đó, tuy nhiên, bạn có thể sử dụng posts_requestbộ lọc để thay đổi truy vấn SQL ban đầu được thiết lập WP_Queryđể đạt được sự ngẫu nhiên từ cơ sở dữ liệu.

Bạn có thể sử dụng CODE sau trong functions.phptệp của chủ đề đang hoạt động hoặc làm plugin tùy chỉnh mới:

<?php
/**
 *  Plugin Name: Randomize Posts
 *  Plugin URI: https://wordpress.stackexchange.com/a/260877/110572
 *  Description: Randomize posts basd on '_randomize_posts_count' query argument
 *  Author: Fayaz
 *  Version: 1.0
 *  Author URI: http://fmy.me/
 */

function wpse260713_randomize_posts( $sql_query, $query ) {
    $rand = (int) $query->get( '_randomize_posts_count' );
    if( $rand ) {
        $found_rows = '';
        if( stripos( $sql_query, 'SQL_CALC_FOUND_ROWS' ) !== FALSE ) {
            $found_rows = 'SQL_CALC_FOUND_ROWS';
            $sql_query = str_replace( 'SQL_CALC_FOUND_ROWS ', '', $sql_query );
        }
        $sql_query = sprintf( 'SELECT %s wp_posts.* from ( %s ) wp_posts ORDER BY rand() LIMIT %d', $found_rows, $sql_query, $rand );
    }
    return $sql_query;
}
add_filter( 'posts_request', 'wpse260713_randomize_posts', 10, 2 );

Sau đó, bạn có thể sử dụng truy vấn như sau:

$args = array(
    'post_type' => 'post',
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC',
    'meta_key' => '_thumbnail_id',
    'no_found_rows' => 'true',
    '_randomize_posts_count' => 3
);
$query = new WP_Query( $args );

Phân tích so sánh:

  • Phương pháp này sẽ chỉ mang lại số lượng bài viết tối đa được xác định _randomize_posts_counttừ cơ sở dữ liệu, trái ngược với việc mang lại tất cả các kết quả và ngẫu nhiên hóa ở cuối PHP. Vì vậy, nó được tối ưu hóa tốt hơn cho giao tiếp dữ liệu với cơ sở dữ liệu. Điều này tốt hơn nếu máy chủ cơ sở dữ liệu của bạn tách biệt với máy chủ web của bạn.

  • Nếu bộ đệm truy vấn không được bật , thì giải pháp này sẽ nhanh hơn nhiều khi sự khác biệt giữa số lượng bài đăng ngẫu nhiên được hiển thị so với tổng số lựa chọn bài đăng là lớn. Ví dụ: nếu bạn đang hiển thị 3 bài đăng ngẫu nhiên từ hầu hết 200 bài đăng gần đây, thì phương pháp này sẽ nhanh hơn rất nhiều.

  • Nếu bộ đệm truy vấn được bật , thì phương thức của Birgire sẽ nhanh hơn vì nó sẽ tránh các yêu cầu SQL sau này. Tuy nhiên, đối với kích thước mẫu lớn hơn, nó vẫn có thể chậm hơn vì bạn sẽ phải lưu trữ nhiều thông tin trong bộ đệm truy vấn.

  • Tốt nhất nếu bạn xem xét kích thước mẫu một cách cẩn thận và chọn giải pháp phù hợp với trường hợp sử dụng của bạn tốt hơn.

Lưu ý: Các phương pháp ngẫu nhiên rất chậm (và thường không thể mở rộng) so với CODE chung, do đó, cho dù bạn chọn phương pháp nào, hãy thận trọng hơn khi kích thước ngẫu nhiên mẫu của bạn lớn đáng kể (như hàng ngàn).


1
Rất vui khi thấy các cách tiếp cận khác. ps: có nhiều cách giải quyết thú vị cho việc đặt hàng ngẫu nhiên chậm. Tôi chỉ nhớ lại chơi với một người ở đây dựa trên một bài viết thú vị ở đây của Josh Hartman. Tuy nhiên, một cách tiếp cận khác chỉ là lưu trữ (không quá nhiều) id với API tạm thời và chọn các id ngẫu nhiên từ đó ;-)
birgire

1
Tôi sẽ phải dành thời gian để xác định tùy chọn nào chạy hiệu quả nhất. Tôi đánh giá cao các chi tiết tuyệt vời mà bạn bao gồm!
WebElaine

Cảm ơn những liên kết @birgire, sẽ hữu ích cho nhiều người.
Fayaz

3

Công việc tuyệt vời của Fayaz và birgire - chuyên gia nhiều hơn tôi có thể nghĩ ra - nhưng tôi nghĩ có một cách dễ dàng hơn, trừ khi tôi không hiểu câu hỏi (hoàn toàn có thể!): 1) sử dụng get_posts () hoặc, dễ nhất , wp_get_recent_posts (), cả hai đều trả về mảng theo mặc định, chấp nhận WP Query $ args và cũng sử dụng no_found_rows = true theo mặc định, 2) xáo trộn mảng, 3) sau đó cắt ba mảng.

Đó là cách tôi tự giải quyết một vấn đề tương tự như vấn đề này, tại thời điểm mà tôi hiểu gần như không có gì, so với trạng thái hiểu biết hiện tại của tôi gần với những gì tôi đã hiểu. Tuy nhiên, mã của birgire và Fayaz rất tuyệt, vì vậy xin vui lòng đi với người này hay người kia!


Cảm ơn đã thêm phương pháp thay thế này. Cả 3 câu trả lời đều đáp ứng mục tiêu và tôi thích thực tế là bạn không yêu cầu thêm chức năng mới vào chủ đề!
WebElaine
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.