1

I'm trying to combine several loops into one and sort the final results by relevance.

For the former part, I did this:

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

// loop for same author
$by_author = new WP_Query (array(
    'author'         => $author_id,
    'posts_per_page' => '5'
));

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

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

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

// 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),
    'posts_per_page' => '10',
    'orderby' => $weight[$post->ID],
    'order'   => 'DESC'
));

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

This is working nicely combining the loops into one. For the latter part, what I'm trying to do next is to add an incremental "weight" value to each post as they come up so as to later sort them with something like 'orderby' => $weight,.

For example, if a post comes up in "same author" it gets 3 points, if another one comes up in same tag it gets 2 points and so on. If it comes up in more than one loop, it should get the combined points i.e. 3+2+1=6 hence be boosted to the top of the final query.

I have tried to add a counter to each preliminary loop, like $weight = +3 etc, but this only adds everything up for every post, not individually.

I also tried inserting something like this at the end of each preliminary loop...

$weight = 0;
if ($by_author){
    foreach ($by_author as $post){
        setup_postdata($post);
        $weight = +10;
        add_post_meta($post->ID, 'incr_number', $weight, true);
        update_post_meta($post->ID, 'incr_number', $weight);
    }
}

... and this to the final one

echo get_post_meta($post->ID,'incr_number',true);

But it still doesnt do it right. It assigns a global value, while I want them to be different depending on the actual main posts one is reading.

So is there a way to do this?

2
  • I wouldn't suggest doing database calls (add_post_meta, update_post_meta, etc) in the loop. Your site will blow up in a hurry. Commented Jul 21, 2016 at 17:50
  • Indeed, that part was completely inept and useless. Simply building the array with the id as key and weight as value is all it takes to properly assign the scores. Am still struggling to have the thing sort, though. Commented Jul 21, 2016 at 17:55

1 Answer 1

2
+200

If I understand your question right, I think your last solution was close. Instead of a global $weight parameter, however, I think you need to build an array of $weights that's unique to each post:

$weights[$post.id] += 10;

Then, you could sort that array and get your most heavily weighted post IDs from there.

Sign up to request clarification or add additional context in comments.

7 Comments

Indeed, this seems the way to go - so If I get it right, what it does is store the post ID as 'key' instead of 'value' in the array, with 'value' being the weight itself? I still have a hard time figuring how to sort things out in the final query.
Yes, that's what I'd envisioned. You can see examples of sorting from high to low here, even with examples showing how to get the key (post ID): php.net/manual/en/function.arsort.php
Apparently, all I needed to do was to add a $weight[$post->ID] += 3; etc. after each get_the_id(); and now it does the job properly, no foreach necessary at all. Sorting is indeed tricky, with 'orderby' => $weight[$post->ID] not doing anything.
Yep, just got that working with some help, with arsort($weight); foreach ($weight as $key => $value) { $posts_ordered[] $key; } and then 'post__in' => $posts_ordered, 'orderby' => 'post__in', now it's working fine - thanks.
"You may award your bounty in 19 hours" - I guess I'll need to come back again :D
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.