已排序查询中的随机排序

时间:2016-05-11 作者:David Clough

我有一个工作查询,它返回一组按包ID(ASC)排序的自定义帖子。对于具有9个结果的查询,可能会返回以下结果,例如:

4个贴子(贴子ID为1,2,3,4),包ID为1

3个贴子(贴子ID为5、6、7),包ID为2

2个贴子(贴子ID为8,9),包ID为3

显示这些帖子时,它们的顺序始终相同。换言之,它们是按照Post ID 1到Post ID 9的顺序显示的。

我试图实现的是对每个子集(由包ID定义)的结果进行随机排序。通过这种方式,帖子将显示为:

随机显示Post ID的1到4(例如2,1,4,3)

随机显示Post ID的5到7(例如6、5、7)

随机显示Post ID的8到9(例如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\'
);
我认为“可能”有用,但没有:

$args = array( 
    \'post_type\' => \'custom_post_type\',
    \'post_status\' => \'publish\',
    \'posts_per_page\' => 9,
    \'meta_key\' => \'pkg_id\',
    \'orderby\' => array( \'pkg_id\' => \'ASC\', \'rand\' )
);
任何建议,因为我完全被难住了!

4 个回复
最合适的回答,由SO网友:Pieter Goosen 整理而成

为了完成这一点,不需要执行高估的查询量。您仍然可以使用only 一个查询,the_posts 过滤器和一些PHP可以根据需要对代码进行排序。

我认为这是我在你的问题中读到的自定义查询,因此我们可以执行以下操作:

首先,我们想介绍一种定制WP_Query 参数,以便我们可以使用该参数作为the_posts 滤器我们将此参数称为nwpse_custom_sort 它的值为true 为了触发过滤器

接下来,我们将使用the_posts 过滤根据自定义字段对帖子进行排序,然后根据自定义字段对这些帖子进行随机排序,最后返回已排序的帖子

虽然代码只是一些注释

该代码未经测试,至少需要PHP 5.4

我用过get_post_meta() 要在使用ACF时返回每篇文章的自定义字段值,可能需要将其调整为使用get_field(). 我不熟悉ACF,所以您需要对该部分进行排序。尽管如此,逻辑仍将保持不变

请记住,查询自定义字段不会在缓存时产生额外的查询,因此这是一种非常精简、优化的方法,可以实现您的最终目标

这是自定义查询的代码。基本上只需将额外的参数添加到自定义页面模板中的查询参数中

// 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 );

SO网友:birgire

如果我们使用:

$args = array( 
    \'post_type\'      => \'custom_post_type\',
    \'post_status\'    => \'publish\',
    \'posts_per_page\' => 9,
    \'meta_key\'       => \'pkg_id\',
    \'orderby\'        => array( \'pkg_id\' => \'ASC\', \'rand\' => \'DESC\' )
);
然后我们得到订单部分:

ORDER BY wp_postmeta.meta_value ASC, RAND() DESC
这似乎可行,但不需要DESC。

但请注意RAND() 不能很好地扩展。在这种情况下,@PieterGoosen的方法可能更适合您。

SO网友:ngearing

单次查询不可能,您必须执行3个单独的查询,每个查询针对不同的“包ID”,并将这些查询按rand排序。

$args1 = array(
    \'post_type\' => \'custom_post_type\',
    \'orderby\' => \'rand\',
    \'meta_query\' => array(
        array(
            \'key\' => \'pkg_id\',
            \'value\' => 1, // you will have to check if this is correct
        )
    )
);

$args2 = array(
    \'post_type\' => \'custom_post_type\',
    \'orderby\' => \'rand\',
    \'meta_query\' => array(
        array(
            \'key\' => \'pkg_id\',
            \'value\' => 2, // you will have to check if this is correct
        )
    )
);

$args3 = array(
    \'post_type\' => \'custom_post_type\',
    \'orderby\' => \'rand\',
    \'meta_query\' => array(
        array(
            \'key\' => \'pkg_id\',
            \'value\' => 3, // you will have to check if this is correct
        )
    )
);
这将把你的帖子分为“包裹ID”,并将每组按随机顺序排列

SO网友:chrwald

Pieter Goosen答案的一个补充。

我不得不在最后修改他的代码,因为shuffle($field)返回的是boolen,而不是shuffled数组本身。所以我得到的是布尔数组,而不是(后)数组。为了得到预期的结果,我做了以下工作:

  //Instead of 
    foreach ( $major_array as $field ) 
        //Shuffle returns boolean, so $sorted will be a
        $sorted[] = shuffle( $field );  

 // I went with
    foreach ( $major_array as $field ) {
        shuffle( $field );   // 1. Shuffle $field, which is an array
        $sorted[] = $field;  // Then add this 
    }

相关推荐

浏览器刷新时删除数据库条目,AJAX PHP jQuery

我有一个表单,在通过ajax提交表单时更新数据库表中的列。一切都很好,数据库表列可以获取信息,但一旦刷新浏览器,信息就会从数据库中删除。如果meta\\u值不存在,但meta\\u值也在提交表单时创建的数据库中,则PHP将执行数据库更新。我希望信息保留在数据库中,直到或除非meta\\u值被删除或不存在。任何见解都将不胜感激。PHPadd_action(\'wp_ajax_hide_this\', \'hide_this_by_id\'); add_action(\'wp_ajax_nopriv_