web-dev-qa-db-ja.com

カテゴリごとの投稿をループ処理すると、各カテゴリに同じ投稿が表示されます

私のウェブサイトの特定のセクションでは、いくつかのカテゴリをループして、そのカテゴリ内の3つの最新の投稿を取得してそれらをリストします。そのようです:

<?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; ?>

この最後のスニペットに追跡を追加するにはどうすればよいですか。

1
Bram Vanroy

各カテゴリに1つずつ、非常に多くのトランジェントを設定する必要はないと思います。使用できるのは1つだけです。それで十分です。トランジェントは追加のdbクエリを必要とするため、設定するのはかなりコストがかかるため、使用を減らすことをお勧めします。

いつものように、私は自分のテンプレートをシンプルで短く、そしてきれいにしておくことを好みます、それで私は私のテンプレートの外にコードの大部分を移動するためにカスタム関数を書く傾向があります。 1つのトランジェントですべてを1つの関数にまとめることができます

あなたはこのようなことを試すことができます(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は、用語と投稿を取得するための分類法です。デフォルトは 'category'です。

  • 2番目のパラメータは$argsで、これはget_terms()に渡すべき引数です。詳細については、 get_terms() を確認してください。

  • 3番目のパラメータ$query_argsは、カスタムクエリに渡す必要がある引数です。分類法に関連するパラメーターは使用しないでください。詳しくは、 WP_Query を参照してください。

  • 2番目のパラメータが設定されておらず、3番目のパラメータが設定されている場合は、2番目のパラメータに空の配列を渡します。

  • あなたが適当と思うようにコードを修正して悪用する

使用法

テンプレートの中で以下のように関数を使うことができます

$post_list = get_term_post_list( 'category', ['exclude' => '1, 4, 9, 10, 2899'], ['posts_per_page' => 3] );
if ( $post_list !== null ) {
    echo $post_list;
}

もし2番目のパラメータにではなく3番目のパラメータに何も渡さないのであれば、次のようにするべきです(空の配列を渡す)

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

編集

急いで、私は新しい投稿が公開された、更新された、削除された、または元に戻されたときに一時的なものをフラッシュする機能を追加することを全く忘れていました。あなたのコードがそうであるように、リストは一時的な期限が切れるときにだけ更新されます。

上記のpost条件でトランジェントをフラッシュするには、単にtransition_post_statusフックを使います。 functions.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

あなたのコメントからこの回答へ

ご想像のとおり、私はこれを と他の質問 と組み合わせて使用​​したいと思いました。どのようにしてそれをしますか?用語の除外はget_term_post_list()で行われるべきですか?それともどういうわけか2つの機能をマージする必要がありますか? (別に必要ないので)

これを実現するための最善の方法は、2つの機能を1つにまとめることです。それが最も理にかなっているでしょう。 2つの機能をマージし、excludeパラメーターを使用して機能を変更しました。私がしたことは、get_terms()excludeパラメータを介してexcludeにterm idの配列を追加することができます。また、同じ関数内で、除外するterm slugsの配列を設定することもできます。結果はget_terms()に渡される前に一つのexcludeパラメータにマージされます

ここに関数がありますが、やはりわかりやすいようにコメントしました(これはfunctions.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に渡されるカスタム引数tax_queryのdeafultビルドで問題が発生するため、ここでは分類法に関連するパラメーターを渡さないでください。配列で渡すことができる有効な引数の完全なリストは 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;

OR

$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;

上記のすべてがあなたの質問のすべてのあなたのコードを置き換えます

2
Pieter Goosen

あなたのカテゴリはループの繰り返しごとにIDが変更されていて、カテゴリIDが変更されていても毎回同じ結果が得られる共通のトランジェントを設定しています。

だからあなたはすべてのカテゴリの一時的なものを節約する必要があります。

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; ?>
0
Sumit