将帖子编号设置为单个帖子

时间:2014-11-21 作者:charlenemasters

我有一个函数,我正在使用它对类别中的帖子进行编号。这是我的职责。php,如下所示:

function get_episode_number($postID){
$options = get_option(\'theme-opts\'); 
$opts_cat = isset($options[\'opts-category\']) ? $options[\'opts-category\'] : \'\'; /* passes category from theme options */

$postNumberQuery = new WP_Query(array ( 
    \'orderby\' => \'date\', 
    \'order\' => \'ASC\', 
    \'post_type\' => \'post\',
    \'posts_per_page\' => \'-1\', 
    \'cat\' => $opts_cat 
));
$counter = 1;
$postCount = 0;

if( $postNumberQuery->have_posts() ) :
    while ( $postNumberQuery->have_posts() ) :
        $postNumberQuery->the_post();
        if ( $postID == get_the_ID() ){
            $postCount = $counter;
        } else {
            $counter++;
        }
    endwhile;
endif;
wp_reset_postdata();
return $postCount;
}
当我在另一个自定义wp\\U查询循环中使用此函数时wp_reset_postdata() 似乎不仅重置了自定义函数中的查询,还重置了我在其中使用的查询。代码如下:

<?php 
        $paged = ( get_query_var( \'page\' ) ) ? absint( get_query_var( \'page\' ) ) : 1;

        $l_args = array(
            \'cat\' => $opts_cat,
            \'post_type\' => \'post\',
            \'posts_per_page\' => 2,
            \'paged\' => $paged,
        );
        $landing_p = new WP_Query( $l_args );
        /* The following line creates the main loop. */
        if ($landing_p->have_posts()) : while ($landing_p->have_posts()) : $landing_p->the_post(); ?>            
        <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <div class="inside">
                <?php the_post_thumbnail(\'square\'); ?>

                <div class="hover bottom">
                    <?php
                        $currentID = get_the_ID(); ?>
                    <?php $episodeNum = get_episode_number($currentID); ?>
                    <span class="episode"><?php echo __(\'Episode\', \'lang\'); ?> <?php echo $episodeNum; ?></span>
                    <a href="<?php the_permalink(); ?>"><h2><?php the_title(); ?></h2></a> 
                </div><!-- .hover-bottom -->
            </div><!-- .inside -->
        </div><!-- .post -->
        <?php 
        endwhile;
        wp_reset_postdata();
        endif; ?>
Thethe_permalink()the_title() 不再从$landing\\u p查询中检索。相反,它们显示页面的标题和永久链接。只有当我使用get_episode_number() . 所以wp_reset_postdata() 似乎正在重置两个查询。我的问题是wp_reset_postdata() 从函数和是一种确保其效果不会因为缺少更好的词而“溢出”的方法。欢迎任何指点。谢谢

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

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.

总之,减少并不总是更快。真正了解的唯一方法是测试,正如你所看到的,证据就在数字中。我希望这对你有帮助

SO网友:charlenemasters

感谢@PieterGoosen和@Milo建议在后端做所有事情

找到答案here 并将其调整为使用get_posts 适合我的需要。我的最终代码是:

function updateNumbers() {
$options = get_option(\'theme-opts\'); 
$opts_cat = isset($options[\'opts-category\']) ? $options[\'opts-category\'] : \'\';
$args = array( 
    \'posts_per_page\' => -1, 
    \'category\' => $opts_cat,
    \'orderby\' => \'date\',
    \'order\' => \'ASC\',
    \'post_type\' => \'post\'
);
$pageposts = get_posts( $args );
$counts = 0 ;
if ($pageposts):
    foreach ($pageposts as $post):
        setup_postdata($post);
        $counts++;
        add_post_meta($post->ID, \'incr_number\', $counts, true);
        update_post_meta($post->ID, \'incr_number\', $counts);
    endforeach;
endif;
}  
add_action ( \'publish_post\', \'updateNumbers\' );
add_action ( \'deleted_post\', \'updateNumbers\' );
add_action ( \'edit_post\', \'updateNumbers\' );
然后<?php echo get_post_meta($post->ID,\'incr_number\',true); ?> 显示数字。再次感谢!

结束

相关推荐

使用新的WP-Query()从循环中过滤后期格式;

嗨,我目前正在为我的博客构建一个主题。下面的代码指向最新的帖子(特色帖子)。因为这将有一个不同的风格比所有其他职位。然而我想过滤掉帖子格式:链接使用我在循环中定义的WP查询,因为它给我带来了更多的灵活性。我该怎么做呢? <?php $featured = new WP_Query(); $featured->query(\'showposts=1\'); ?> <?php while ($featured->have_post