web-dev-qa-db-ja.com

複数のタグによる関連記事?

関連する記事を複数のタグで表示することができればと思いました。

私が取り組んでいるサイトには、1件の投稿につき約5個のタグがあります。ほとんどの投稿には共通のタグが1つか2つあります。私が示したい関連記事には、共通のタグが3〜5個あります。

そのため、タグの数が最も多い共通の投稿を探して降順に表示することで、関連する投稿を機能させたいと思います。

3つの関連記事を表示するとします。relatedpost1には4つのタグがあり、relatedpost2には3つのタグがあり、relatedpost3には1つのタグがあります。

それも可能ですか?

現時点で私は投稿を表示する2つの方法をいじっていますが、それらは私が望むように機能していません:

最初の方法( code )は、すべてのタグが共通の投稿を表示するだけです。

<?php $orig_post = $post;
global $post;
$tags = wp_get_post_tags($post->ID);
if ($tags) {
$tag_ids = array();
foreach($tags as $individual_tag) $tag_ids[] = $individual_tag->term_id;
$args=array(
'tag__in' => $tag_ids,
'post__not_in' => array($post->ID),
'posts_per_page'=>3, // Number of related posts that will be shown.
'caller_get_posts'=>1
);
$my_query = new wp_query( $args );
if( $my_query->have_posts() ) {
echo '<div id="relatedposts"><h3>Related Posts</h3><div class="relatedbreak"></div><ul id="relatedul">';
while( $my_query->have_posts() ) {
$my_query->the_post(); ?>
<li><div class="relatedthumb"><a href="<? the_permalink()?>" rel="bookmark" title="<?php the_title(); ?>"><?php the_post_thumbnail(array(185, 185)); ?></a></div>
<div class="relatedcontent">
<center><a href="<? the_permalink()?>" rel="bookmark" title="<?php the_title(); ?>"><div class="comments_text"><?php the_title(); ?></div></center></a>
</div>
</li>
<? }
echo '</ul></div>';
}
}
$post = $orig_post;
wp_reset_query(); ?>`

2番目の方法( code )は、最初のタグが共通の投稿を表示するだけです。

<?php
//for use in the loop, list 5 post titles related to first tag on current post
$tags = wp_get_post_tags($post->ID);
if ($tags) {
echo '<div id="relatedposts"><h3>Related Posts</h3></div><div class="relatedbreak"></div>';
$first_tag = $tags[0]->term_id;
$args=array(
'tag__in' => array($first_tag),
'post__not_in' => array($post->ID),
'posts_per_page'=>3,
'caller_get_posts'=>1
);
$my_query = new WP_Query($args);
if( $my_query->have_posts() ) {
while ($my_query->have_posts()) : $my_query->the_post(); ?>
<ul id="relatedul">
<li><div class="relatedthumb"><a href="<? the_permalink()?>" rel="bookmark" title="<?php the_title(); ?>"><?php the_post_thumbnail(array(185, 185)); ?></a></div>
<a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><div class="comments_text"><?php the_title(); ?></div></a></li>
</ul>
<?php
endwhile;
}
wp_reset_query();
}
?>

どちらの方法でも吸うことができます。ランダムな投稿がランダムに表示されている(ほとんどの投稿には少なくとも1つのタグが共通しているため)か、(一部の投稿では)関連記事が表示されない.

任意の助けは大歓迎です。

4
Jacob

私は同じ考えを持っていて、私がこれをするのを助けるために小さな小さなプラグインを書きました。

function get_pew_related_data($args, $post_id, $related_id) {
    global $post, $wpdb;
    $post_id = intval( $post_id );
    if( !$post_id && $post->ID ) {
        $post_id = $post->ID;
    }

    if( !$post_id ) {
        return false;
    }

    $defaults = array(
        'taxonomy' => 'topics',
        'post_type' => array('post'),
        'max' => 5
    );
    $options = wp_parse_args( $args, $defaults );

    $transient_name = 'pew-related-' . $options['taxonomy'] . '-' . $post_id;

    if( isset($_GET['flush-related-links']) && is_user_logged_in() ) {
        echo '<p>Related links flushed! (' . $transient_name . ')</p>';
        delete_transient( $transient_name );
    }

    $output = get_transient( $transient_name );
    if( $output !== false && !is_preview() ) {
        //echo $transient_name . ' read!';
        return $output;
    } 

    $args = array(
        'fields' => 'ids',
        'orderby' => 'count',
        'order' => 'ASC'
    );
    $orig_terms_set = wp_get_object_terms( $post_id, $options['taxonomy'], $args );

    //Make sure each returned term id to be an integer.
    $orig_terms_set = array_map('intval', $orig_terms_set);

    //Store a copy that we'll be reducing by one item for each iteration. 
    $terms_to_iterate = $orig_terms_set;

    $post_args = array(
        'fields' => 'ids',
        'post_type' => $options['post_type'],
        'post__not_in' => array($post_id),
        'posts_per_page' => 50
    );
    $output = array();
    while( count( $terms_to_iterate ) > 1 ) {

        $post_args['tax_query'] = array(
            array(
                'taxonomy' => $options['taxonomy'],
                'field' => 'id',
                'terms' => $terms_to_iterate,
                'operator' => 'AND'
            )
        );

        $posts = get_posts( $post_args );

        /*
        echo '<br>';
        echo '<br>';
        echo $wpdb->last_query;
        echo '<br>';
        echo 'Terms: ' . implode(', ', $terms_to_iterate);
        echo '<br>';
        echo 'Posts: ';
        echo '<br>';
        print_r( $posts );
        echo '<br>';
        echo '<br>';
        echo '<br>';
        */

        foreach( $posts as $id ) {
            $id = intval( $id );
            if( !in_array( $id, $output) ) {
                $output[] = $id;
            }
        }
        array_pop( $terms_to_iterate );
    }

    $post_args['posts_per_page'] = 10;
    $post_args['tax_query'] = array(
        array(
            'taxonomy' => $options['taxonomy'],
            'field' => 'id',
            'terms' => $orig_terms_set
        )
    );

    $posts = get_posts( $post_args );

    foreach( $posts as $count => $id ) {
        $id = intval( $id );
        if( !in_array( $id, $output) ) {
            $output[] = $id;
        }
        if( count($output) > $options['max'] ) {
            //We have enough related post IDs now, stop the loop.
            break;
        }
    }

    if( !is_preview() ) {
        //echo $transient_name . ' set!';
        set_transient( $transient_name, $output, 24 * HOUR_IN_SECONDS );
    }

    return $output;
}

function pew_related( $args = array(), $post_id = '', $related_id = '' ) {
    $post_ids = get_pew_related_data( $args, $post_id, $related_id );

    if( !$post_ids ) {
        return false;
    }

    $defaults = array(
        'post__in' => $post_ids,
        'orderby' => 'post__in',
        'post_type' => array('post'),
        'posts_per_page' => min( array(count($post_ids), 10)),
        'related_title' => 'Related Posts'
    );
    $options = wp_parse_args( $args, $defaults );

    $related_posts = new WP_Query( $options );
    if( $related_posts->have_posts() ):
    ?>
    <h5><?=$options['related_title']?></h5>
    <div id="related-material" class="promo">
        <?php while ( $related_posts->have_posts() ):
            $related_posts->the_post();
        ?>
            <a class="post" href="<?=the_permalink();?>">
                <div class="meta">
                    <?php
                    $post_project = wp_get_object_terms($related_posts->post->ID, 'projects');
                    $project = 'Pew Research Center';
                    $project_slug = '';
                    if( isset($post_project[0]) ) {
                        $project = $post_project[0]->name;
                        $project_slug =  $post_project[0]->slug;
                    } elseif( $related_posts->post->post_type == 'fact-tank' ) {
                        $project = 'Fact Tank';
                        $project_slug = 'fact-tank';
                    }
                    ?>
                    <span class="project <?=$project_slug;?> right-seperator"><?=$project;?></span>
                    <span class="date"><?php the_time('M j, Y'); ?></span>
                </div>
                <h2><?=the_title();?></h2>
            </a>
        <?php endwhile;
            wp_reset_postdata();

         ?> 
    </ol>
    </div>
    <?php
    endif;

}

それは一般的な用語を持っている投稿を探します、そして、それらの用語は頻度によってソートされます。最初の関数はデータを取得して一時的に格納するので、結果が不必要に繰り返し実行されることはありません。 2番目の関数は出力をレンダリングするだけです。これが職場の私達の場所の1つの私達の場所の私達の関連したポストを動かすものである http://www.pewresearch.org/fact-tank/2013/08/02/both-parties-underwater-heading-into-2014-elections /

アルゴリズムは次のように機能します。

  1. 投稿からすべての用語を昇順で数えた順に表示します(人気の低いものから人気の高いものへ)
  2. この一連の用語をループして、Term1 AND Term2 AND Term3を含む投稿を探します
  3. 必要な数の投稿が表示されるか、確認できる用語が1つだけになるまで、反復のたびにリストから最も人気の低い用語を削除して結果を広げます。
  4. それでも十分な投稿がない場合は、Term1 OR Term2 OR Term3を含む投稿を探してください。
  5. 一時的に結果を保存するので、しばらくの間これらのクエリを再度実行する必要はありません。

これが役に立つことを願っています。

4
kingkool68

ありがとう@Dero。データベースのプレフィックスを正しく設定することを忘れないでください。

function exe_get_related_posts_by_common_terms( $post_id, $number_posts = 0, $taxonomy = 'post_tag', $post_type = 'post' ) {
    global $wpdb;

    $post_id = (int) $post_id;
    $number_posts = (int) $number_posts;

    $limit = $number_posts > 0 ? ' LIMIT ' . $number_posts : '';

    $related_posts_records = $wpdb->get_results(
        $wpdb->prepare(
            "SELECT tr.object_id, count( tr.term_taxonomy_id ) AS common_tax_count
             FROM {$wpdb->term_relationships} AS tr
             INNER JOIN {$wpdb->term_relationships} AS tr2 ON tr.term_taxonomy_id = tr2.term_taxonomy_id
             INNER JOIN {$wpdb->term_taxonomy} as tt ON tt.term_taxonomy_id = tr2.term_taxonomy_id
             INNER JOIN {$wpdb->posts} as p ON p.ID = tr.object_id
             WHERE
                tr2.object_id = %d
                AND tt.taxonomy = %s
                AND p.post_type = %s
             GROUP BY tr.object_id
             HAVING tr.object_id != %d
             ORDER BY common_tax_count DESC" . $limit,
            $post_id, $taxonomy, $post_type, $post_id
        )
    );

    if ( count( $related_posts_records ) === 0 )
        return false;

    $related_posts = array();

    foreach( $related_posts_records as $record )
        $related_posts[] = array(
            'post_id' => (int) $record->object_id,
            'common_tax_count' => $record->common_tax_count
        );

    return $related_posts;
}

だから、それはすべてのシステムでうまく機能します。

0
endcoreCL

query_posts()new WP_Query()がここで何の役にも立つとは思わない。データベースに直接問い合わせる必要があります。これは私があなたが必要としていると思われるものを達成するために書いた方法です。

/*
 * Returns related posts to a given post based on a specific taxonomy
 * By default, this method returns list of posts with the highest number of common tags
 *
 * var $post_id - the reference post for which we want to get the list of similar posts
 * var $number_posts - max how many related posts to return, 0 for unlimited
 * var $taxonomy - which taxonomy to use to determine related posts ( 'post_tag' or 'category' are the basic examples )
 * var $post_type - change to a custom post_type if you want to get related posts of another post type
 */
function exe_get_related_posts_by_common_terms( $post_id, $number_posts = 0, $taxonomy = 'post_tag', $post_type = 'post' ) {

    global $wpdb;

    $post_id = (int) $post_id;
    $number_posts = (int) $number_posts;

    $limit = $number_posts > 0 ? ' LIMIT ' . $number_posts : '';

    $related_posts_records = $wpdb->get_results(
        $wpdb->prepare(
            "SELECT tr.object_id, count( tr.term_taxonomy_id ) AS common_tax_count
             FROM wp_term_relationships AS tr
             INNER JOIN wp_term_relationships AS tr2 ON tr.term_taxonomy_id = tr2.term_taxonomy_id
             INNER JOIN wp_term_taxonomy as tt ON tt.term_taxonomy_id = tr2.term_taxonomy_id
             INNER JOIN wp_posts as p ON p.ID = tr.object_id
             WHERE
                tr2.object_id = %d
                AND tt.taxonomy = %s
                AND p.post_type = %s
             GROUP BY tr.object_id
             HAVING tr.object_id != %d
             ORDER BY common_tax_count DESC" . $limit,
             $post_id, $taxonomy, $post_type, $post_id
        )
    );

    if ( count( $related_posts_records ) === 0 )
        return false;

    $related_posts = array();

    foreach( $related_posts_records as $record )
        $related_posts[] = array(
            get_post( (int) $record->object_id ),
            'common_tax_count' => $record->common_tax_count
        );

    return $related_posts;

}

この方法は、デフォルトで 'post_tag'分類法に基づく単一分類法に基づいて関連する投稿を取得するように設計されています。投稿は、 一般的な用語の数の多い順にソートされています 。一度に複数の一般的な分類法の関連記事を取得するには、AND tt.taxonomy = %sAND ( tt.taxonomy = 'post_tag' OR tt.taxonomy = 'category' )のように微調整する必要があります。異なる投稿タイプの投稿を取得する場合も同じです。

0
Dero