问题描述
我有一个工作查询,返回一组按照其 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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。