OP的答案启发我快速编写这个函数,它不是资源密集型函数,而且速度非常快。我还决定尝试OP描述的另一种方法
为了实现这一点,我使用了Transient API 以及post_updated
行动
逻辑要获取帖子的位置,首先需要获取所有帖子并确定帖子在数组中的位置,然后添加1
到其当前位置/键(请记住,数组从0
在每次加载页面时,这是一个非常昂贵的操作,如果您有数百或数千篇帖子,它会变得非常慢
因此,我的想法是使用一个瞬态来存储生成的post位置。我已经让过渡期在365天内到期,你可以随意设置。
我之所以决定这么久,是因为以下想法:
只有在以下情况下,特定职位的职位才会发生变化:
帖子被删除之前的帖子,或
取消删除之前已删除的帖子
如果您希望在帖子状态中包含其他更改,则可以扩展此选项。然而,当一篇新文章发表时,我会排除在外。这永远不会对以前的帖子产生任何影响
每当一个帖子被删除或取消删除时,都需要删除所有的帖子位置,并给每个帖子一个新的帖子位置。因此,这意味着您必须删除电流瞬变,并用新值替换它。当第一次打开post或瞬态不存在时,将设置新值。
我的SQL不是很好,所以我从this answer 删除或取消删除post id时删除所有瞬态
下面是代码(我已经对代码进行了注释,解释了发生的情况和原因。)
所有这些都会用到您的功能中。php
function display_post_number() {
$query_object = get_queried_object(); // More safe that $post global
$id = $query_object->ID;
$transient_id = \'post_number_\' . $id; // Give every post a unique transient
if ( false === ( $post_number = get_transient( $transient_id ) ) ) {
$post_args = [
\'post_type\' => $query_object->post_type, // Set the current post\'s type as post type
\'fields\' => \'ids\', // Only get post ID\'s
\'posts_per_page\' => -1,
\'order\' => \'ASC\', //Get posts from first to last
];
$q = get_posts( $post_args );
$post_number = array_search( $id, $q ) + 1; //Use array_search to get post position and add 1
set_transient( $transient_id, $post_number, 365 * DAY_IN_SECONDS );
}
echo $post_number;
}
add_action( \'post_updated\', function ( $post, $post_after, $post_before ) {
if (
$post_after->post_status == \'trash\' && $post_before->post_status == \'publish\'
|| $post_after->post_status == \'publish\' && $post_before->post_status == \'trash\'
) { // Only delete the transients if a post is deleted or undeleted
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient%_post_number_%\')" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient_timeout%_post_number_%\')" );
}
}, 10, 3 );
然后您可以使用
display_post_number()
在你的单曲里。php显示帖子编号
EDIT 1
如果你需要展示
Post X of Y
您可以按如下方式调整代码。
function display_post_number() {
$query_object = get_queried_object(); // More safe that $post global
$id = $query_object->ID;
$transient_id = \'post_number_\' . $id; // Give every post a unique transient
if ( false === ( $text = get_transient( $transient_id ) ) ) {
$post_args = [
\'post_type\' => $query_object->post_type, // Set the current post\'s type as post type
\'fields\' => \'ids\', // Only get post ID\'s
\'posts_per_page\' => -1,
\'order\' => \'ASC\', //Get posts from first to last
];
$q = get_posts( $post_args );
$total_posts = count( $q ); // Get total posts
$post_number = array_search( $id, $q ) + 1; //Use array_search to get post position and add 1
$text = \'You are currently viewing post #\' . $post_number . \' of \' . $total_posts;
set_transient( $transient_id, $text, 365 * DAY_IN_SECONDS );
}
echo $text;
}
然后,而不是使用
post_updated
挂钩,利用
transition_post_status
每当某个职位的状态发生变化时删除该职位,因为每次职位状态发生变化时,职位数量都会发生变化。
add_action( \'transition_post_status\', function ( $new_status, $old_status, $post )
{
if ( \'publish\' !== $new_status or \'publish\' === $old_status )
return;
if ( \'post\' !== $post->post_type )
return; // restrict the filter to a specific post type
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient%_post_number_%\')" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient_timeout%_post_number_%\')" );
}, 10, 3 );
EDIT 2
来自您的评论
找出哪些操作“昂贵”的好方法是什么?我喜欢自己编写一些精简、快速的代码,但要找出可能会减慢速度的原因并不总是那么容易。一般来说,人们应该注意/避免什么?
确实没有一般规则。要明白我的意思,请明白this post 我刚做完。在那篇文章中,我展示了在特定情况下,四个自定义查询比单个查询更快,但在另一种情况下,它可以反转。所以,这完全取决于情况和你想做什么。正如我常说的,100个构造良好的查询可能比一个整块查询更快
知道的唯一方法是测试,这真的很容易。实际上,我已经在我的开发站点上为自己创建了一个测试页面,只是为了测试。您可以使用任何页面/模板。这是我的页面
<?php
/**
* Template Name: TEST Page
*/
get_header(); ?>
<div id="main-content" class="main-content">
<div id="primary" class="content-area">
<div id="content" class="site-content" role="main">
<?php
timer_start();
/**-----------------------------------------------------------------------------
*
* DON\'T EDIT ABOVE THIS LINE
*
*------------------------------------------------------------------------------*/ ?>
<?php
// Add all your code to test in this section
?>
<?php /**-------------------------------------------------------------------------
*
* DON\'T EDIT BELOW THIS LINE
*
*------------------------------------------------------------------------------*/ ?>
<p><?php echo get_num_queries(); ?> queries in <?php timer_stop(1, 5); ?> seconds. </p>
<!--#page-content-->
</div><!-- #content -->
</div><!-- #primary -->
<?php get_sidebar( \'content\' ); ?>
</div><!-- #main-content -->
<?php
get_footer();
这里重要的功能如下,您可以阅读
当您第一次设置页面时,请运行它并记录默认的查询量。在我的测试现场
11 queries in 0.00000 seconds.
, 所以我知道我需要从所有测试数据中减去11。(
旁注:不要使用已安装的缓存插件进行测试,也不要使用瞬态进行测试。原因是,一旦设置了瞬态,您需要在每次页面刷新时手动将其从数据库中删除,这相当简单。始终最后添加)我做了两次测试,共有26篇帖子,下面是结果。仅仅是几条简短的注释,我已经从要测试的代码中删除了瞬态,并且我已经从粘贴在这里的结果中减去了11。我还删除了category参数。
TEST 1
我添加了你的代码updateNumbers();
代替// Add all your code to test in this section
结果-83 queries in 0.13476 seconds.
TEST 2
答案中的链接代码结果-133 queries in 0.16016 seconds.
TEST 3
我的代码没有瞬态display_post_number()
. 结果-1 queries in 0.00293 seconds.
TEST 4
我的瞬态代码。请注意额外的查询,但减少了时间,因此,如您所见,两个查询可能比一个更快:-)结果-2 queries in 0.00098 seconds.
总之,减少并不总是更快。真正了解的唯一方法是测试,正如你所看到的,证据就在数字中。我希望这对你有帮助