問題描述

我有一個工作查詢,返回一組按照其 ID(ASC) 排序的自定義帖子。對於具有 9 個結果的查詢,可能返回例如:

4 posts (Post ID’s 1,2,3,4) with Package ID 1

3 posts (Post ID’s 5,6,7) with Package ID 2

2 posts (Post ID’s 8,9) with Package ID 3

當這些帖子顯示時,它們總是按照相同的順序。換句話説,它們按照從 ID 1 到帖子 ID 9 的順序顯示。

我想要實現的是隨機對每個子集 (由 Package ID 定義) 的結果進行排序。這樣就可以顯示帖子:

Random display of Post ID’s 1 through to 4 (eg 2,1,4,3)

Random display of Post ID’s 5 through to 7 (eg 6,5,7)

Random display of Post ID’s 8 through to 9 (eg 8,9)

所以帖子仍然按照包 ID 分組,但每個包中的帖子都是隨機顯示的。

這是我當前查詢的樣子:

$args = array( 
    'post_type' => 'custom_post_type',
    'post_status' => 'publish',
    'posts_per_page' => 9,
    'meta_key' => 'pkg_id',
    'orderby' => 'pkg_id',
    'order' => 'ASC'
);

我以為’might’ 工作但沒有:

$args = array( 
    'post_type' => 'custom_post_type',
    'post_status' => 'publish',
    'posts_per_page' => 9,
    'meta_key' => 'pkg_id',
    'orderby' => array( 'pkg_id' => 'ASC', 'rand' )
);

任何建議,因為我完全陷入困境!

最佳解決方案

沒有必要做大量的查詢來完成這一點。您仍然可以只使用一個查詢,the_posts 篩選器和一些 PHP 根據需要對代碼進行排序。

我認為這是從您在問題中閲讀的自定義查詢,因此我們可以執行以下操作:

  • 首先,我們要引入自定義 WP_Query 參數,以便我們可以將該參數用作 the_posts 過濾器的觸發器。我們將這個參數稱為 wpse_custom_sort,它將採用 true 的值來觸發過濾器

  • 接下來,我們將使用 the_posts 過濾器根據自定義字段對帖子進行排序,然後根據自定義字段隨機排序這些帖子,最後返回排序的帖子

代碼

只是幾個筆記

  • 代碼未經測試,至少需要 PHP 5.4

  • 我使用 get_post_meta()返回每個帖子的自定義字段值,因為您使用 ACF,您可能需要調整此值以使用 get_field()。我不熟悉 ACF,所以你需要對這部分進行排序。邏輯仍然保持不變

  • 只要記住,查詢自定義字段在緩存時不會產生額外的查詢,所以這是一個非常精簡,優化的方式來完成您的最終目標

以下是自定義查詢的代碼。您所需要做的就是在您的自定義頁面模板中的查詢 args 中添加額外的參數

// Run your query normally
$args = [
    'wpse_custom_sort' => true, // This parameter will trigger or the_posts filter
    // Your query args here
];
$q = new WP_Query( $args );

// Your loop as normal

現在,我們將運行我們的過濾器 (這可以進入 functions.php 或者最好進入一個自定義插件)

/**
 * Function to flatten a multidimentional array (for later use)
 * 
 * Credit to zdenko
 * @link https://gist.github.com/kohnmd/11197713
 */
function flatten_array( $arg ) 
{
    return is_array( $arg ) 
        ? 
        array_reduce( $arg, function ( $c, $a ) 
            { 
                return array_merge( $c, flatten_array( $a ) ); 
            }, [] ) 
        : 
        [$arg];
}

// The the_posts filter
add_filter( 'the_posts', function ( $posts, $q )
{
    // First we need remove our filter
    remove_filter( current_filter(), __FUNCTION__ );

    // Check if our custom parameter is set and is true, if not, bail early
    if ( true !== $q->get( 'wpse_custom_sort' ) )
        return $posts; 

    // Before we do any work, and to avoid WSOD, make sure that the flatten_array function exists
    if ( !function_exists( 'flatten_array' ) )
        return $posts;

    // Our custom parameter is available and true, lets continue
    // Loop through the posts
    $major_array = [];
    foreach ( $posts as $p ) {
        $meta = get_post_meta(
            $p->ID,
            'pkg_id',
            true
        );

        // Bail if we do not have a $meta value, just to be safe
        if ( !$meta )
            continue;

        // Sanitize the value
        $meta = filter_var( $meta, FILTER_SANITIZE_STRING );

        // Lets build our array
        $major_array[$meta][] = $p;
    }

    // Make sure we have a value for $major_array, if not, bail
    if ( !$major_array )
        return $posts;

    // Lets randomize the posts under each custom field
    $sorted = [];
    foreach ( $major_array as $field ) 
        $sorted[] = shuffle( $field );

    // Lets flatten and return the array of posts
    $posts = flatten_array( $sorted );

    return array_values( $posts );
}, 10, 2 );

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。