Assign custom parameter to each post in query

I’m trying to add an incremental variable to each post that comes up in a series of queries. The purpose is to calculate a weight for each result in order to be able to order everything later.

This is what I’ve come up with so far, but I’m doing something wrong, as the weights seem to add up globally instead of for each particular post.

// 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):
$weight += 2;

// add ids to array
if ( $by_tag->have_posts() ) {
while ( $by_tag->have_posts() ) {
$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):
$weight += 1;

// add ids to array
if ( $by_category->have_posts() ) {
while ( $by_category->have_posts() ) {
$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() ) {
// [template]

2 Answers

It’s a neat idea!

The way I would tackle the problem is to create an associative array of post IDs mapped to their individual weights. Since weights are subjective – that is, the represent the value of other posts’ relationships with the post currently being displayed – it doesn’t make much sense to store these weights in the database each time you process these relationships, and thus we can’t use WP_Query‘s ordering arguments to arrange the resulting posts; so instead you’ll need to re-arrange them based on the sorted array of weights.

Unfortunately, since we can’t determine how much weight any single related post has prior to querying taxonomies, to calculate the most “valuable” posts we have to query all related posts – that is to say, using queries with arguments that limit the number of results won’t work as you can’t definitively know that those returned with have high values.

This makes this related posts operation somewhat expensive, computationally – ideally you’d eventually improve the process to store each post’s most relevant related posts and update them on occasion. This could be done by storing them in the subject post’s meta-data and only updating that list with a scheduled operation, or by storing related posts as transient data and then only update that list when the transient expires.


The (completely untested, likely not-quite-functional) function below takes a post object (representing the “subject” post) and an array mapping taxonomy names to integer values (representing how much “weight” posts should receive for sharing a term in that taxonomy with the subject). It returns a WP_Query instance with a posts array sorted according to calculated weights.

It’s somewhat different from what you are after, I think, as it takes all of the subject’s terms into consideration (which also makes it more computationally expensive) – but it should give you some ideas.

By building a 'tax_query' argument for the WP_Query instance out of all relevant taxonomies, you’re able to use one query to obtain every post that shares a relevant term with the subject instead of one for each taxonomy. It makes the code a little more confusing than using tag and category-related functions and WP_Query arguments – but reducing the number of queries is generally a worthwhile optimization.

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 ) )

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

The function can then be employed as such:

// 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 post markup -->


Leave a Comment