循环浏览每个类别的帖子可以得到每个类别的相同帖子

时间:2015-04-22 作者:Bram Vanroy

对于我网站上的一个特定部分,我循环浏览了一些类别,得到了该类别中的三篇最新帖子,并列出了它们。像这样:

<?php $categories = get_categories(array(\'exclude\' => \'1, 4, 9, 10, 2899\')); ?>

<?php foreach ($categories as $category) : ?>
    <div class="subject">
        <h3><?php echo $category->cat_name; ?></h3>
        <ul>
            <?php $args = array(
                \'cat\' => $category->cat_ID,
                \'posts_per_page\' => 3
            ); ?>
            <?php if (false === ( $category_posts_query = get_transient( \'category_posts\' ) ) ) {
                $category_posts_query = new WP_Query($args);
                set_transient( \'category_posts\', $category_posts_query, 36 * HOUR_IN_SECONDS );
            }
            ?>
            <?php while($category_posts_query->have_posts()) : ?>
                <?php $category_posts_query->the_post(); ?>
                <li><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></li>
            <?php endwhile; ?>
        </ul>
    </div>
<?php wp_reset_postdata(); ?>
<?php endforeach; ?>
然而,结果并非预期的那样:所有帖子在不同类别中都是相同的,即使这些帖子不属于不同的类别:enter image description here

当我移除transient 对于缓存,所有内容都可以导出。

<?php $categories = get_categories(array(\'exclude\' => \'1, 4, 9, 10, 2899\')); ?>

<?php foreach ($categories as $category) : ?>
    <div class="subject">
        <h3><?php echo $category->cat_name; ?></h3>
        <ul>
            <?php $args = array(
                \'cat\' => $category->cat_ID,
                \'posts_per_page\' => 3
            ); ?>
            <?php $category_posts_query = new WP_Query($args); ?>
            <?php while($category_posts_query->have_posts()) : ?>
                <?php $category_posts_query->the_post(); ?>
                <li><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></li>
            <?php endwhile; ?>
        </ul>
    </div>
<?php wp_reset_postdata(); ?>
<?php endforeach; ?>
如何将更改添加到最后一个代码段中?

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

我认为你不需要设置这么多瞬态,每个类别一个。你只能用一个,这就足够了。设置瞬态非常昂贵,因为它需要额外的db查询,所以您希望减少使用。

和往常一样,我喜欢保持模板简单、简短和甜美,因此我倾向于编写自定义函数,将大部分代码移到模板之外。你可以用一个瞬间把所有的东西都放在一个函数中

您可以尝试这样的操作(需要PHP 5.4+

function get_term_post_list( $taxonomy = \'category\', $args = [], $query_args = [] )  
{
    /*
     * Check if we have a transient set
     */
    if ( false === ( $output = get_transient( \'term_list_\' . md5( $taxonomy . json_encode( $args ) . json_encode( $query_args ) ) ) ) ) {

        /*
         * Use get_terms to get an array of terms
         */
        $terms = get_terms( $taxonomy, $args );

       if ( is_wp_error( $terms ) || empty( $terms ) )
            return null;

        /*
         * We will create a string with our output
         */
        $output = \'\'; 
        foreach ( $terms as $term ) {

            $output .= \'<div class="subject">\';
            $output .= \'<h3>\' . $term->name . \'</h3>\';
            $output .= \'<ul>\';

            /*
             * Use a tax_query to make this dynamic for all taxonomies
             */
            $default_args = [
                \'no_found_rows\' => true,
                \'suppress_filters\' => true,
                \'tax_query\' => [
                    [
                        \'taxonomy\' => $taxonomy,
                        \'terms\' => $term->term_id,
                        \'include_children\' => false
                    ]
                ]
            ];
            /*
             * Merge the tax_query with the user set arguments
             */
            $merged_args = array_merge( $default_args, $query_args );

            $q = new WP_Query( $merged_args );

            while($q->have_posts()) {
                $q->the_post();

                $output .= \'<li><a href="\' . get_permalink() . \'" title="\' . apply_filters( \'the_title\', get_the_title() ) . \'">\' . apply_filters( \'the_title\', get_the_title() ) . \'</a></li>\';

            }
            wp_reset_postdata();

            $output .= \'</ul>\';
            $output .= \'</div>\';

        }
        /*
         * Set our transient, use all arguments to create a unique key for the transient name
         */
        set_transient( \'term_list_\' . md5( $taxonomy . json_encode( $args ) . json_encode( $query_args ) ), $output, 36 * HOUR_IN_SECONDS );
    }
    /*
     * $output will be atring, treat as such
     */
    return $output;
}
很少有注释第一个参数$taxonomy是从中获取术语和帖子的分类法。默认为“类别”

第二个参数是$args 这是应该传递给的参数get_terms(). 有关更多信息,请查看get_terms()

第三个参数,$query_args 是应传递给自定义查询的参数。请记住,避免使用任何与分类法相关的参数。有关详细信息,请参阅WP_Query

如果未设置第二个参数而设置了第三个参数,则将空数组传递给第二个参数

根据需要修改和滥用代码

用法现在可以在模板中使用以下功能

$post_list = get_term_post_list( \'category\', [\'exclude\' => \'1, 4, 9, 10, 2899\'], [\'posts_per_page\' => 3] );
if ( $post_list !== null ) {
    echo $post_list;
}
如果没有将任何内容传递给第二个参数,而是传递给第三个参数,则应执行以下操作(传递空数组)

$post_list = get_term_post_list( \'category\', [], [\'posts_per_page\' => 3] );
if ( $post_list !== null ) {
    echo $post_list;
}

编辑

在匆忙中,我完全忘了添加一个函数,在发布、更新、删除或取消删除新帖子时刷新瞬态。正如您的代码所示,该列表将仅在瞬态过期时更新。

要在上述post条件下冲洗瞬态,只需使用transition_post_status 钩将以下内容添加到函数中。php

add_action( \'transition_post_status\', function ()
{
        global $wpdb;
        $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient%_term_list_%\')" );
        $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient_timeout%_term_list_%\')" );
});
根据您对此答案的评论编辑2

你可能已经猜到了,我想结合使用这个with my other question. 我该怎么做呢?如果排除条款发生在get_term_post_list()? 还是应该以某种方式合并这两个功能?(因为我不需要单独使用它们。)

最好的方法是将这两个函数合并为一个函数。这是最有意义的。我已经合并了这两个函数,并使用exclude参数修改了该函数。我所做的是,现在可以通过get_terms() exclude 参数,您还可以在同一函数中设置要排除的术语段塞数组。结果将合并为一个exclude 传递给之前的参数get_terms()

这里是函数,我再次对其进行了很好的注释,以便于理解(这将进入函数。php)

function get_term_post_list( $taxonomy = \'category\', $args = [], $query_args = [], $exclude_by_slug = [] )  
{
    /*
     * Check if we have a transient set
     */
    if ( false === ( $output = get_transient( \'term_list_\' . md5( $taxonomy . json_encode( $args ) . json_encode( $query_args ) ) ) ) ) {

        /*
         * Check if any array of slugs is passed and if it is a valid array
         */
        if ( is_array( $exclude_by_slug ) && !empty( $exclude_by_slug ) ) {

            foreach ( $exclude_by_slug as $value ) {

                /*
                 * Use get_term_by to get the term ID and add ID\'s to an array
                 */
                $term_objects = get_term_by( \'slug\', $value, $taxonomy );
                $term_ids[] = (int) $term_objects->term_id;

            }

        }

        /*
         * Merge $args[\'exclude\'] and $term_ids 
         */
        if ( isset( $args[\'exclude\'] ) && isset( $term_ids ) ) {

            $excluded_args = (array) $args[\'exclude\'];
            unset( $args[\'exclude\'] );
            $args[\'exclude\'] = array_merge( $excluded_args, $term_ids );

        } elseif ( !isset( $args[\'exclude\'] ) && isset( $term_ids ) ) {

            $args[\'exclude\'] = $term_ids;

        } 

        /*
         * Use get_terms to get an array of terms
         */
        $terms = get_terms( $taxonomy, $args );

       if ( is_wp_error( $terms ) || empty( $terms ) )
            return null;

        /*
         * We will create a string with our output
         */
        $output = \'\'; 
        foreach ( $terms as $term ) {

            $output .= \'<div class="subject">\';
            $output .= \'<h3>\' . $term->name . \'</h3>\';
            $output .= \'<ul>\';

            /*
             * Use a tax_query to make this dynamic for all taxonomies
             */
            $default_args = [
                \'no_found_rows\' => true,
                \'suppress_filters\' => true,
                \'tax_query\' => [
                    [
                        \'taxonomy\' => $taxonomy,
                        \'terms\' => $term->term_id,
                        \'include_children\' => false
                    ]
                ]
            ];
            /*
             * Merge the tax_query with the user set arguments
             */
            $merged_args = array_merge( $default_args, $query_args );

            $q = new WP_Query( $merged_args );

            while($q->have_posts()) {
                $q->the_post();

                $output .= \'<li><a href="\' . get_permalink() . \'" title="\' . apply_filters( \'the_title\', get_the_title() ) . \'">\' . apply_filters( \'the_title\', get_the_title() ) . \'</a></li>\';

            }
            wp_reset_postdata();

            $output .= \'</ul>\';
            $output .= \'</div>\';

        }
        /*
         * Set our transient, use all arguments to create a unique key for the transient name
         */
        set_transient( \'term_list_\' . md5( $taxonomy . json_encode( $args ) . json_encode( $query_args ) ), $output, 36 * HOUR_IN_SECONDS );
    }
    /*
     * $output will be string, treat as such
     */
    return $output;
}
就用法而言,首先需要查看可以传递的参数

参数1-$taxonomy -> 要从中获取术语的分类法。违约category

参数2-$args -> 应传递给的参数get_terms(). 请参见get_terms() 获取可以作为数组传递的参数的完整列表。默认空数组[]

参数3-$query_args -> 要传递给的自定义参数WP_Query. 您不应该在此处传递与分类法相关的参数,因为这会导致Deafolt内置的问题tax_query. 有关可以在数组中传递的有效参数的完整列表,请参阅WP_Query. 默认空数组[]

参数4-$exclude_by_slug -> 要排除的段塞数组。请注意,这必须是有效的数组才能工作。字符串将被忽略。默认空数组[]

现在,您可以在任何模板文件中调用该函数,如下所示

$a = get_term_post_list( \'category\', [\'exclude\' => [1, 13, 42]], [\'posts_per_page\' => 3], [\'term-slug-1\', \'term-slug-2\'] );
echo $a;

$taxonomy = \'category\';
$args = [
    \'exclude\' => [1, 13, 42]
];
$query_args = [
    \'posts_per_page\' => 3
];
$exclude_by_slug = [
    \'0\' => [\'term-slug-1\', \'term-slug-2\']
];
$a = get_term_post_list( $taxonomy, $args, $query_args, $exclude_by_slug );
echo $a;
最后注意,如果不需要传递特定的参数,请记住只传递一个空数组,如

$a = get_term_post_list( \'category\', [], [], [\'term-slug-1\'] );
echo $a;
以上内容将替换问题中的所有代码

SO网友:Sumit

您的类别ID在每次循环迭代时都会更改,并且您正在设置一个公共瞬态,即使类别ID已更改,每次都会给出相同的结果。

所以你需要为每一个类别保存transient。

set_transient( \'category_posts_\' . $category->cat_ID, $category_posts_query, 36 * HOUR_IN_SECONDS );
尝试此解决方案

<?php $categories = get_categories(array(\'exclude\' => \'1, 4, 9, 10, 2899\')); ?>

<?php foreach ($categories as $category) : ?>
    <div class="subject">
        <h3><?php echo $category->cat_name; ?></h3>
        <ul>
            <?php $args = array(
                \'cat\' => $category->cat_ID,
                \'posts_per_page\' => 3
            ); ?>
            <?php if (false === ( $category_posts_query = get_transient( \'category_posts_\' . $category->cat_ID ) ) ) {
                $category_posts_query = new WP_Query($args);
                set_transient( \'category_posts_\' . $category->cat_ID, $category_posts_query, 36 * HOUR_IN_SECONDS );
            }
            ?>
            <?php while($category_posts_query->have_posts()) : ?>
                <?php $category_posts_query->the_post(); ?>
                <li><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></li>
            <?php endwhile; ?>
        </ul>
    </div>
<?php wp_reset_postdata(); ?>
<?php endforeach; ?>

结束