为查询中的每个帖子分配自定义参数

时间:2016-07-20 作者:lucian

我试图为一系列查询中出现的每个帖子添加一个增量变量。目的是计算每个结果的权重,以便以后能够排序所有内容。

这是我到目前为止所想到的,但我做错了,因为权重似乎是在全球范围内累积的,而不是针对每个特定的帖子。

// set the variables
$author_id = get_the_author_meta(\'ID\');
$tags_id = wp_get_post_tags($post->ID);  $first_tag = $tags_id[0]->term_id;
$categories_id = wp_get_post_categories($post->ID);
$weight = 0;

// loop for same tag
$by_tag = new WP_Query(array(
\'tag__in\' => $first_tag,
\'posts_per_page\' => \'5\'
));

// attempting to assign values to posts - unsuccessfully
if ($by_tag):
foreach ($by_tag as $post):
setup_postdata($post->ID);
$weight += 2;
endforeach;
endif;

// add ids to array
if ( $by_tag->have_posts() ) {
while ( $by_tag->have_posts() ) {
$by_tag->the_post(); 
$add[] = get_the_id(); 
}}

// loop for same category
$by_category = new WP_Query(array(
\'category__in\' => $categories_id,
\'posts_per_page\' => \'5\'
));

// same as before
if ($by_category):
foreach ($by_category as $post):
setup_postdata($post->ID);
$weight += 1;
endforeach;
endif;

// add ids to array
if ( $by_category->have_posts() ) {
while ( $by_category->have_posts() ) {
$by_category->the_post(); 
$add[] = get_the_id(); 
}}

// loop array of combined results 
$related = new WP_Query(array(
\'post__in\' => $add,
\'post__not_in\' => array($post->ID),
\'orderby\' => $weight,
\'order\'   => \'DESC\',
\'posts_per_page\' => \'10\'
));

// show them
if ( $related->have_posts() ) {
while ( $related->have_posts() ) {
$related->the_post(); 
// [template]
}}

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

下面是一个完整的工作代码,可供任何需要它的人使用:

$tags_id = wp_get_post_tags($post->ID);  $first_tag = $tags_id[0]->term_id;
$categories_id = wp_get_post_categories($post->ID); $first_category = $categories_id[0];

$by_tag = new WP_Query( array( \'post__not_in\' => array($post->ID), \'tag__in\' => $first_tag ) ); 
if ( $by_tag->have_posts() ) { while ( $by_tag->have_posts() ) { $by_tag->the_post();
$add[] = get_the_id();
$weight[$post->ID] += 2;
wp_reset_query(); }}

$by_category = new WP_Query( array( \'post__not_in\' => array($post->ID), \'category__in\' => $categories_id ) );
if ( $by_category->have_posts() ) { while ( $by_category->have_posts() ) { $by_category->the_post();
$add[] = get_the_id();
$weight[$post->ID] += 1;
wp_reset_query(); }}

arsort($weight);
foreach ($weight as $key => $value) {   $posts_ordered[] = $key; }
$related = new WP_Query( array( \'post__in\' => $posts_ordered,  \'orderby\' => \'post__in\',\'posts_per_page\' => \'60\') );
if ( $related->have_posts() ) { while ( $related->have_posts() ) { $related->the_post(); 
// template
}}

SO网友:bosco

这是个好主意!

我解决这个问题的方法是创建一个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
  }
}