正如我所说,这是可行的,但我们需要仔细规划,因为这是一项相当繁重的行动。在我的测试安装中,只有13篇文章,每个分类法有3个术语,访问db 20次,完成操作需要0.03613秒。我尝试了几种解决方案,而这一种是迄今为止最快的。
我们稍后将研究一种解决方法,以节省db调用和加载时间。首先让我们看看整个操作是什么样子以及它是如何工作的
PREPHASE
在我们开始之前,请注意几点。本规范的制定基于以下内容
每个帖子在这两种分类法中必须至少有一个术语。如果一篇文章只有一个属于这两种分类法之一的术语,那么代码将失败
在我的测试安装中,我的帖子类型是cameras
, 我的分类法是brands
和event_cat
, 因此,请确保相应地更改此选项
它的工作原理
STEP 1
在数组中添加分类法。这将用于获取与这两个分类法相关的所有术语
$taxonomies = [ \'event_cat\', \'brands\' ];
STEP 2
如步骤1所述,您需要按照分类法获取所有术语。
get_terms()
将用于检索术语。将跳过空术语
$terms = get_terms( $taxonomy );
STEP 3
下一步是获取属于特定术语的所有职位。术语slug和分类名称将用于
tax_query
在里面
get_posts
检索帖子。由于您不需要任何post数据,因此只需检索post ID
$args = array(
\'post_type\' => \'cameras\',
\'fields\' => \'ids\',
\'tax_query\' => array(
array(
\'taxonomy\' => $taxonomy,
\'field\' => \'slug\',
\'terms\' => $term->slug,
),
),
);
$posts = get_posts( $args );
STEP 4
现在将使用post ID、术语名称和分类名称创建一个数组,该数组将用于创建我们的列表
foreach ( $posts as $post ) {
$all_posts[$post][$taxonomy] = $term->name;
}
您的创建数组将如下所示
array(13) {
[586]=>
array(2) {
["event_cat"]=>
string(6) "3 star"
["brands"]=>
string(7) "Classic"
}
[582]=>
array(2) {
["event_cat"]=>
string(6) "3 star"
["brands"]=>
string(7) "Romance"
}
[331]=>
array(2) {
["event_cat"]=>
string(6) "3 star"
["brands"]=>
string(7) "Classic"
}
[329]=>
array(2) {
["event_cat"]=>
string(6) "3 star"
["brands"]=>
string(6) "Comedy"
}
[585]=>
array(2) {
["event_cat"]=>
string(6) "4 star"
["brands"]=>
string(7) "Romance"
}
[583]=>
array(2) {
["event_cat"]=>
string(6) "4 star"
["brands"]=>
string(7) "Romance"
}
[401]=>
array(2) {
["event_cat"]=>
string(6) "4 star"
["brands"]=>
string(7) "Classic"
}
[330]=>
array(2) {
["event_cat"]=>
string(6) "4 star"
["brands"]=>
string(6) "Comedy"
}
[328]=>
array(2) {
["event_cat"]=>
string(6) "4 star"
["brands"]=>
string(6) "Comedy"
}
[587]=>
array(2) {
["event_cat"]=>
string(6) "5 star"
["brands"]=>
string(7) "Romance"
}
[584]=>
array(2) {
["event_cat"]=>
string(6) "5 star"
["brands"]=>
string(7) "Romance"
}
[581]=>
array(2) {
["event_cat"]=>
string(6) "5 star"
["brands"]=>
string(6) "Comedy"
}
[327]=>
array(2) {
["event_cat"]=>
string(6) "5 star"
["brands"]=>
string(6) "Comedy"
}
}
STEP 5
此新数组将作为将显示的列表的基础。使用此数组要做的第一件事是使用它创建一个新数组,该数组将使用
ratings
术语作为键和
genre
术语作为值
$group_ratings = [];
foreach ( $all_posts as $value ) {
$group_ratings[$value[\'event_cat\']][] = $value[\'brands\'];
}
您的
$group_ratings
现在看起来像这样
array(3) {
["3 star"]=>
array(4) {
[0]=>
string(7) "Classic"
[1]=>
string(7) "Romance"
[2]=>
string(7) "Classic"
[3]=>
string(6) "Comedy"
}
["4 star"]=>
array(5) {
[0]=>
string(7) "Romance"
[1]=>
string(7) "Romance"
[2]=>
string(7) "Classic"
[3]=>
string(6) "Comedy"
[4]=>
string(6) "Comedy"
}
["5 star"]=>
array(4) {
[0]=>
string(7) "Romance"
[1]=>
string(7) "Romance"
[2]=>
string(6) "Comedy"
[3]=>
string(6) "Comedy"
}
}
STEP 6
因为你需要
5 star
首先出现的术语和
1 star
最后一个术语,我们可以使用
krsort
相应地对数组排序
krsort($group_ratings);
STEP 7
现在将通过
foreach
环现在将使用
array_count_values
, 然后,生成的数组将按数组值和键值进行排序
array_multisort
. 分类让我有点头疼,所以我不得不去寻求帮助。我找到了
here 感谢@theark
foreach ( $group_ratings as $key=>$value ) {
echo $key;
$counted_values = array_count_values($value);
array_multisort(array_values($counted_values), SORT_DESC, array_keys($counted_values), SORT_ASC, $counted_values);
//MORE TO COME
STEP 8
最后,现在可以显示列表。保存术语名称的数组键将用作术语名称,保存术语post计数的数组值将用于显示该特定术语的post计数
foreach ( $counted_values as $counted_values_keys=>$counted_value ) {
echo \'<li>\' . $counted_values_keys . \' (\' . $counted_value . \') </li>\';
}
正如我所说,这项工作相当繁重。为了加快速度,您需要利用
transients. 我们要做的是存储
$group_ratings
. 这是保存所有重要信息的变量
这将显著减少db调用量和加载时间。对于瞬态,仅记录2 db的点击,总时间仅为0.00098秒。请注意,我已将瞬时到期时间设置为24小时,您可以根据需要修改此时间。设置的好时机将取决于您添加新帖子的频率
ALL TOGETHER NOW!!
下面是完整代码的外观
if ( false === ( $group_ratings = get_transient( \'term_list\' ) ) ) {
$taxonomies = [ \'event_cat\', \'brands\' ];
$all_posts = [];
foreach ( $taxonomies as $taxonomy ) {
$terms = get_terms( $taxonomy );
foreach ( $terms as $term ) {
$args = array(
\'post_type\' => \'cameras\',
\'fields\' => \'ids\',
\'tax_query\' => array(
array(
\'taxonomy\' => $taxonomy,
\'field\' => \'slug\',
\'terms\' => $term->slug,
),
),
);
$posts = get_posts( $args );
foreach ( $posts as $post ) {
$all_posts[$post][$taxonomy] = $term->name;
}
unset($post);
}
}
$group_ratings = [];
foreach ( $all_posts as $value ) {
$group_ratings[$value[\'event_cat\']][] = $value[\'brands\'];
}
krsort($group_ratings);
set_transient( \'term_list\', $group_ratings, 24 * HOUR_IN_SECONDS );
}
echo \'<ul>\';
foreach ( $group_ratings as $key=>$value ) {
echo $key;
$counted_values = array_count_values($value);
array_multisort(array_values($counted_values), SORT_DESC, array_keys($counted_values), SORT_ASC, $counted_values);
foreach ( $counted_values as $counted_values_keys=>$counted_value ) {
echo \'<li>\' . $counted_values_keys . \' (\' . $counted_value . \') </li>\';
}
}
echo \'</ul>\';
您只需要根据需要对其进行样式设置和修改。下面是您的列表
BUT WAIT, WE\'RE NOT DONE
还有最后一步。只有在过渡期到期时,才会更新过渡期。如果在过渡期有效期间发布新帖子,这将是一个问题。您所做的更改只有在瞬态过期并更新后才会显示。
您需要做的是在发布新帖子时以某种方式删除临时帖子。可以使用transition_post_status
此处由@tosho in描述的挂钩this post
我们需要稍微修改该代码,以便仅在发布新帖子时,以及在以特定帖子类型发布新帖子时,才会删除瞬态。这就是代码的样子(进入functions.php,只需记住更改post类型名称)
add_action( \'transition_post_status\', \'a_new_post\', 10, 3 );
function a_new_post( $new_status, $old_status, $post )
{
if ( \'publish\' !== $new_status or \'publish\' === $old_status )
return;
if ( \'cameras\' !== $post->post_type )
return; // restrict the filter to a specific post type
delete_transient( \'term_list\' );
}
WE\'RE DONE!!!