是否按多个标签关联帖子?

时间:2013-05-02 作者:Jacob

我很好奇是否可以通过多个标签显示相关帖子。

我正在工作的网站每个帖子大约有5个标签。大多数帖子共有1个或2个标签。我想展示的相关帖子共有3-5个标签。

因此,我希望相关帖子能够通过查找具有最多共同标签的帖子并按降序显示来发挥作用。

假设我显示了3个相关帖子:relatedpost1有4个公共标记,relatedpost2有3个公共标记,relatedpost3有1个公共标记。

甚至有可能做到这一点吗?

目前,我正在尝试两种显示帖子的方式,但它们并没有发挥我所希望的作用:

第一种方法(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(); ?>`
第二种方法(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();
}
?>
两种方式都很糟糕;我要么得到相当随机的帖子显示(因为我的大多数帖子至少有一个共同的标签),要么(对于一些帖子)没有得到相关的帖子(因为他们的共同标签是标签4或5)。

任何帮助都将不胜感激。

3 个回复
最合适的回答,由SO网友:kingkool68 整理而成

我也有同样的想法,并编写了一个小插件来帮助我做到这一点。

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;

}
它会查找具有常见术语的帖子,这些术语按频率排序,因此使用最少的术语排在最流行的术语之前。第一个函数获取数据并将其存储在瞬态中,这样结果就不会不必要地反复运行。第二个函数只是渲染输出。这就是我们在工作中的一个网站上发布相关帖子的动力http://www.pewresearch.org/fact-tank/2013/08/02/both-parties-underwater-heading-into-2014-elections/

算法的工作原理如下:

从帖子中按count升序(从最不受欢迎到最受欢迎)获取所有术语,循环查看这组术语,并查找包含Term1、Term2和Term3的帖子。每次迭代都会从列表中删除最不受欢迎的术语,扩大结果,直到我们获得所需的帖子数量,或者我们只剩下一个术语要检查

SO网友:Dero

我不认为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\\u tag”分类法。帖子按数量排序common terms from highest to lowest. 要同时获取多个常用分类法的相关帖子,您需要调整AND tt.taxonomy = %s 大概是AND ( tt.taxonomy = \'post_tag\' OR tt.taxonomy = \'category\' ). 如果您想获取不同帖子类型的帖子,同样的方法也适用。

SO网友:endcoreCL

谢谢@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;
}
因此,它在所有系统上都非常有效。

结束

相关推荐

Next/Prev posts on same page

WordPress用户您好,我在建立wordpress网站时遇到了一个问题,我不知道该怎么办。目前,我正在“新闻”页面上显示2篇来自“新闻”类别的帖子。在这个页面的底部,我想要一个上一页/下一页按钮,显示同一类别的下一篇或前两篇文章。所以我在想我该怎么做。所以我找到了这个代码:previous_posts_link(\'Newer Entries »\') next_posts_link(\'« Older Entries\'); 这显示了一个我所期望的链接。但两个链接都不起作用(页面重