三个最近的帖子,每个任期一个

时间:2015-10-20 作者:tnog

我正试图找出如何为自定义帖子类型编写自定义查询,并在分类法中检索最新的帖子,但有一个转折:每个唯一的术语只有一篇帖子。

如果我找到三个帖子,they would all belong to a separate term.

一个术语可能比被查询的术语有更多的最新帖子,但我希望每个帖子都属于一个唯一的术语。

我知道如何检索所有术语的帖子(见下文),但如何修改上述场景的循环?感谢您的任何建议或意见!

<?php
    // Retrieve the terms from our custom tax.
    $taxonomy = array(
                \'webcomic1_storyline\'
                );

    $args = array(
                \'orderby\' => \'ID\',
                \'order\' => \'DESC\',
                \'hide_empty\' => false,
                );

    $categories = get_terms($taxonomy,$args);

    // Loop through each term below.
    foreach ( $categories as $category ) : 
    ?>
      <div class="row">
        <section id="<?php echo $category->slug; ?>" class="large-12 columns" data-magellan-destination=\'<?php echo $category->slug; ?>\'> 
           <h3><?php echo $category->name; ?></h3>

           <ul class="work-thumb-container large-block-grid-4 small-block-grid-2">

            <?php 
              // Query below retrieves a single latest post for each term.
              $args = array(
                \'posts_per_page\' => 1,
                \'post_type\' => \'webcomic1\',
                \'webcomic1_storyline\' => $category->slug,
                \'no_found_rows\' => true,
              );

              $the_query = new WP_Query( $args );

              while ( $the_query->have_posts() ) : $the_query->the_post();
            ?>

              <li>
                  <figure class="work-thumb large-12 columns">
                    <a class="cover" href="<?php the_permalink(); ?>"></a>
                        <?php
                        if ( has_post_thumbnail() ) {
                          $image_id       = get_post_thumbnail_id();
                          $image_title    = esc_attr( get_the_title( $image_id ) );
                          $image_link     = wp_get_attachment_url( $image_id );
                          echo \'<img class="th" src="\'. $image_link .\'" alt="\'. $image_title .\'">\';
                        } else {
                          echo \'<img class="th" src="\'.get_stylesheet_directory_uri(). \'/img/shop.jpg\'. \'" alt="Overboard cover">\';
                        }
                      ?>

                    <figcaption>
                      <?php 
                      $term_list = wp_get_post_terms($post->ID, \'webcomic1_storyline\', array("fields" => "all")); ?>
                      <h3 class="teaser-title"><a href="<?php the_permalink(); ?>"><?php echo $term_list[0]->name; ?></a></h3>

                      <time class="storyline-updated teaser-time" datetime="<?php echo get_the_time(\'c\'); ?>">
                      <a href="<?php the_permalink(); ?>"> <?php echo get_the_time(\'Y\'); ?> </a> 
                      </time>
                    </figcaption>
                  </figure>
              </li>

            <?php endwhile; ?>

          </ul>
        </section>
      </div><!-- .row -->     

  <?php endforeach; ?>
</section>

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

我真的试着想出来了,我得出的结论是,真的没有其他天生的方法可以做到这一点。您的方法可能是另一条路线,但目前来看,运行起来相当昂贵。

我得出的结论是:

在一个与帖子类型和分类相关联的查询中获取所有帖子。为了流式处理查询,我们将只查询帖子ID。这将大大提高性能,因为它可以节省高达99.9%的db查询和运行这些查询所需的时间。

我们将循环查看这些帖子ID并使用get_the_terms() 获取与帖子相关的术语。应注意的是get_the_terms() 缓存,所以这也是非常精简的。

然后,我们将循环浏览帖子术语,并将它们存储在一个数组中,然后将它们与相邻帖子的术语进行比较。前三个帖子ID将保存在一个数组中。这将是最近的3篇帖子,每一篇都来自一个独特的类别。为了加速循环,我们将使用break 一旦我们找到了我们想要的

我们还将实现一些系统,以避免在每次加载页面时都运行该系统

好的,让我们来解决这个问题并编写代码。在我们开始之前,请注意几点。

重要提示:

  • 该代码完全未经测试。这可能是马车。请确保在本地测试并启用调试

  • 至少需要PHP 5.4。

    根据需要修改和滥用代码

    我们将使用一个函数,稍后可以在适当的位置调用该函数

    /**
     * Function get_unique_term_recent_posts
     *
     * Get most recent posts but each post should be from a
     * unique term
     *
     * @see http://wordpress.stackexchange.com/q/206100/31545
     * @param (string) $post type Post type to get posts from
     * @param (string) $taxonoy Taxonomy to get posts from
     * @param (int|string) $number Amount of posts to get
     * @return $unique_ids
     *
     */
    function get_unique_term_recent_posts( $post_type = \'post\', $taxonomy = \'category\', $number = 3 )
    {
        // Make sure that no empty values are passed, if so, return false
        if (    !$post_type 
             || !$taxonomy
             || !$number
        ) 
            return false;
    
        // Validate and sanitize input values
        $post_type = filter_var( $post_type, FILTER_SANITIZE_STRING );
        $taxonomy  = filter_var( $taxonomy,  FILTER_SANITIZE_STRING );
        $number    = filter_var( $number,    FILTER_VALIDATE_INT    );
    
        // Make sure that our taxonomy exist to avoid WP_Error objects when querying post terms, return false
        if ( !taxonomy_exists( $taxonomy ) )
            return false;
    
        // Save everything in a transient to avoid this being run on every page load
        if ( false === ( $unique_ids = get_transient( \'posts_list_\' . md5( $taxonomy . $post_type . $number ) ) ) ) {
    
            // Run our query to get the posts
            $args = [
                \'post_type\'      => $post_type,
                \'posts_per_page\' => -1,
                \'fields\'         => \'ids\' // only get post ids, all we need here
            ];
            $q = get_posts( $args );
    
            // Make sure we have posts before we continue, if not, return false
            if ( !$q )
                return false;
    
            // Lets update the object term cache
            update_object_term_cache( $q, $post_type );
    
            // Set up the varaible which will hold the post ID\'s
            $unique_ids = [];
            // Set up a variable which will hold term ID for comparion
            $term_id_array = [];
            // Set up a helper variable which will hold temp term ID\'s for comparion
            $term_helper_array = [];
            // Start a counter to count posts with terms from $taxonomy
            $counter = 0;
    
            // Loop through the posts, get the post terms, loop through them and build an array of post ID\'s
            foreach ( $q as $post_id ) { 
    
                // Break the foreach loop if the amount of ids in $unique_ids == $number
                if ( count( $unique_ids ) == $number )
                    break;
    
                $terms = get_object_term_cache( $post_id, $taxonomy );
    
                // If post does not have terms, skip post and continue
                if ( !$terms ) 
                    continue;
    
                /**
                 * If $term_id_array is empty, this means that this is the first post/newest
                 * post that will have a unique term, lets save the post ID
                 */
                if (    !$term_id_array
                     && $counter == 0
                )
                    $unique_ids[] = $post_id;
    
                // We do have post terms, loop through them
                foreach ( $terms as $term_key=>$term ) {
    
                    // Add all term ID\'s in array. Skip comparison on first post, just save the terms
                    if ( $counter == 0 ) {
                        $term_id_array[] = $term->term_id;
                    } else { 
    
                        if ( in_array( $term->term_id, $term_id_array ) ) {
    
                            // Reset the $term_helper_array back to an empty array
                            $term_helper_array = [];
    
                            // Break the loop if the condition evaluate to true
                            break;
                        } 
                            // Term ID not found, update the $term_helper_array with the current term ID
                            $term_helper_array[] = $term->term_id;
    
                    } //endif $counter == 0
    
                } // endforeach $terms
    
                /**
                 * If our helper array, $term_helper_array have terms, we should move them to the $term_id_array array
                 * and then reset the $term_helper_array back to an empty array. 
                 *
                 * In short, if $term_helper_array have terms, it means that the specific post has unique terms
                 * compare to the previous post being save in $unique_ids
                 */
                if ( $term_helper_array ) {
                    // If no term ID mathes an ID in the $term_id_array, save the post ID
                    $unique_ids[] = $post_id;
                    /**
                     * Merge the $term_id_array and $term_helper_array. This will hold
                     * only terms of the post that are stored in the $unique_ids array
                     */
                    $term_id_array = array_merge( $term_id_array, $term_helper_array );
    
                    // Reset the $term_helper_array back to an empty array
                    $term_helper_array = [];
                }
    
                // Update our counter
                $counter++;
    
            } // endforeach $q   
    
        set_transient( \'posts_list_\' . md5( $taxonomy . $post_type . $number ), $unique_ids, 30 * DAY_IN_SECONDS );
        }
        /**
         * We can now return $unique_ids which should hold at most 3 post ID\'s, 
         * each having a unique term    
         */
        return $unique_ids;
    }   
    
    此功能应该可以完美地用于分配了多个术语的帖子(通常情况下是这样的)。如果一个帖子a分配了术语a和术语B,而在帖子B分配了术语B和术语C,那么帖子B将不会显示在返回的ID数组中,因为您希望有两个帖子分配了唯一的术语。

    您现在可以按如下方式使用该功能:

    $post_type = \'webcomic1\';
    $taxonomy = \'webcomic1_storyline\';
    $post_ids = get_unique_term_recent_posts( $post_type, $taxonomy );
    if ( $post_ids ) {
        $args = [
            \'post__in\' => $post_ids,
            \'post_type\' => $post_type,
            \'posts_per_page\' => 3
        ];
        $q = new WP_Query( $args );
    
        if ( $q->have_posts() ) {
            while ( $q->have_posts() ) {
            $q->the_post();
    
                // Your template tags and mark up
    
            } // endwhile
            wp_reset_postdata();
        } // endif have_posts()
    } // endif $post_ids
    
    我已将瞬态设置为在30天内过期,您可以根据需要将其设置为。但要了解更多要点控制,您可能希望在发布、删除、更新或取消删除新帖子时删除此瞬态。为此,我们将在transition_post_status 钩火。他的钩子在所有先前命名的条件下开火。

    您可以执行以下操作

    add_action( \'transition_post_status\', function ()
    {
        global $wpdb;
        $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient%_posts_list_%\')" );
        $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient_timeout%_posts_list_%\')" );
    });
    
    编辑该代码现在已经过测试,并按预期运行,修复了几个bug。

    只是关于函数的性能

    在0.27秒内无瞬态->2db查询。

    在0.007秒内完成瞬态->2db查询。

    正如您所看到的,db调用保持不变,临时调用的唯一原因是为了节省内存,因为函数在没有临时调用的情况下会使用一点内存来运行,而且,使用的PHP函数也会花费大量时间来执行。因此,本质上,瞬态是用来节省时间和内存的,这在非常大的站点上非常有用

相关推荐

Increase offset while looping

我正在编写一个自定义帖子插件,它将自定义帖子分组显示为选项卡。每组4个岗位。是否可以编写一个偏移量随每次循环而增加的查询?因此,结果将是:-第一个查询显示从1到4的帖子-第二个查询显示从5到8的帖子-第三个查询显示从9到12的帖子等。 <div class=\"official-matters-tabs\"> <?php $args = array(\'post_type\' => \'official-matters\', \'showp