这是个好主意!
我解决这个问题的方法是创建一个post id的关联数组,该数组映射到它们各自的权重。由于权重是主观的-也就是说,表示其他帖子与当前显示的帖子的关系值-每次处理这些关系时,将这些权重存储在数据库中没有多大意义,因此我们无法使用WP_Query
\'排序参数以安排结果帖子;因此,您需要根据排序后的权重数组重新排列它们。
不幸的是,由于在查询分类法之前,我们无法确定任何一篇相关文章的权重,因此,要计算;“有价值的”;我们必须查询所有相关的帖子,也就是说,使用带有限制结果数量的参数的查询将不起作用,因为您无法确切地知道返回的结果具有高值。
这使得这个相关帖子的操作在计算上有点昂贵——理想情况下,您最终会改进流程,以存储每个帖子最相关的帖子,并偶尔更新它们。这可以通过将它们存储在主题帖子的meta-data 并且只使用scheduled operation, 或者将相关帖子存储为transient data 然后仅在瞬态过期时更新该列表。
下面的函数(完全未经测试,可能功能不太好)采用一个post对象(表示“subject”post)和一个数组,将分类法名称映射到整数值(表示与主题共享该分类法中的术语时,post应获得的“weight”量)。它返回一个WP_Query
具有posts
根据计算的权重排序的数组。
我认为,这与你所追求的有所不同,因为它考虑了主题的所有术语(这也使得它的计算成本更高),但它应该给你一些想法。
通过构建\'tax_query\'
的参数WP_Query
实例在所有相关分类法中,您可以使用一个查询来获取与主题共享相关术语的每篇文章,而不是针对每个分类法。与使用标记和类别相关的函数和WP_Query
参数-但是减少查询的数量通常是一个值得优化的问题。
function wpse_232759_get_term_related_query( $post = null, $shared_taxonomy_values = null, $query_args = [] ) {
$subject = get_post( $post );
$subject_id = $subject->ID;
$subject_taxonomies = get_object_taxonomies( $subject );
$subject_term_ids = [];
$post_weights = [];
if( !isset( $shared_taxonomy_values ) ) {
$shared_taxonomy_values = [
\'category\' => 1, // Sharing a category is worth 1 point by default
\'post_tag\' => 1 // Sharing a tag is worth 1 point by default
];
}
// Build a WP_Query \'tax_query\' argument to find every post that shares a tag or category
$shared_term_tax_query = [ \'relation\' => \'OR\' ];
foreach( $shared_taxonomy_values as $taxonomy_name => $shared_term_value ) {
// If the subject doesn\'t actually use this taxonomy, move on
if( !in_array( $taxonomy_name, $subject_taxonomies ) )
continue;
// Record the subject\'s term ids in this taxonomy
$subject_term_ids[ $taxonomy_name ] => array_map( function( $term ) {
return $term->term_id;
},
get_the_terms( $subject, $taxonomy_name )
);
// Add to the tax_query
$shared_term_tax_query[] = [
\'taxonomy\' => $taxonomy_name,
\'terms\' => $subject_term_ids[ $taxonomy_name ]
];
}
// Add generated query args to any supplied by the user
$query_args[ \'post__not_in\' ] = $subject_id; // Ignore the subject
$query_args[ \'tax_query\' ] = $shared_term_tax_query;
// Get all posts with a shared term in a taxonomy with value
$term_related_query = new WP_Query( $query_args );
// Increment the weight of each related post for every term it shares
foreach( $tax_related_query->posts as $object ) {
foreach( $shared_taxonomy_values as $taxonomy_name => $shared_term_value ) {
// Get an array of this post\'s term ids in this taxonomy
$object_tax_term_ids = array_map( function( $term ) {
return $term->term_id;
},
get_the_terms( $object, $taxonomy_name )
);
// Create an array containing the term ids for this taxonomy that both the subject and this post share
$shared_tax_term_ids = array_intersect( $subject_term_ids[ $taxonomy_name ], $object_tax_term_ids );
// If this post doesn\'t have a weight yet, create it and set it to "0"
if( !isset( $post_weights[ $object->ID ] ) )
$post_weights[ $object->ID ] = 0;
// Add to this post\'s weight the value for a shared term in this taxonomy multiplied by the number of shared terms
$post_weights[ $object->ID ] += $shared_term_value * count( $shared_tax_term_ids );
}
}
// Re-arrange the related posts array based on the calculated weights by using a custom sorting function
$term_related_query->posts = usort( $term_related_query->posts, function( $a, $b ) {
if( $post_weights[ $a->ID ] === $post_weights[ $b->ID ] )
return 0; // The posts have the same weight
if( $post_weights[ $a->ID ] > $post_weights[ $b->ID ] )
return 1; // Post $a has a larger weight than post $b
return -1; // Post $b has a larger weight than post $a
} );
// Return the related posts query with modified post order
return $term_related_query;
}
然后可以使用该功能:
// Get a term-related WP_Query object with posts organized by weight,
// where a shared category is worth 1 pt and a shared tag worth 2
$related_query = wpse_232759_get_term_related_query( $post, [
\'category\' => 1,
\'post_tag\' => 2
] );
// Loop through all term-related posts - display the 5 with the highest weights
if( $related_query->have_posts() ) {
while( $related_query->have_posts() && $related_query->current_post < 5 ) {
$related_query->the_post();
?>
<!-- Related post markup -->
<?php
}
}