Adnan Jamil
Adnan Jamil

Reputation: 71

Get Next and Previous posts link through a custom query in WordPress

I'm trying to fetch the next and previous posts link on an article post page (single.php) through a custom query. I have tried using the previous_post_link() and next_post_link() functions but they fetch posts by ID. I have the following loop query on my index page:

$args = array(
  'post_type' => 'auction_dates',
  'paged' => $paged, 
  'posts_per_page' => 1, 
  'meta_key'    => 'date_of_auction', 
  'orderby' => 'meta_value_num', 
  'order' => 'ASC');

As you can tell, the posts are ordered by a custom field 'date_of_auction', not IDs. I want the link to the next and previous posts on my single article page to be fetched using that custom field instead of IDs. Any ideas?

Upvotes: 3

Views: 5546

Answers (2)

stamat
stamat

Reputation: 1979

previous_post_link() and next_post_link(), as the docs say, need to be within the loop. But what about post single? You open one post and even if you use the global query object it won't have the same query data as your post listing - giving you wierd and/or looping results.

For anyone still seeking an answer to this, I've created a simple function get_adjacent_posts() (don't get it confused with get_adjacent_post() native wordpress function) that will always get previous and next posts regardless of the query and the placement of the function.

All you need to do is provide query args array as a parameter and it will return an array with previous and next WP post objects.

function get_adjacent_posts($args) {
    global $post;

    $all_posts = get_posts($args);
    $len = count($all_posts);
    $np = null;
    $cp = $post;
    $pp = null;

    if ($len > 1) {
        for ($i=0; $i < $len; $i++) {
            if ($all_posts[$i]->ID === $cp->ID) {
                if (array_key_exists($i-1, $all_posts)) {
                    $pp = $all_posts[$i-1];
                } else {
                    $new_key = $len-1;
                    $pp = $all_posts[$new_key];

                    while ($pp->ID === $cp->ID) {
                        $new_key -= 1;
                        $pp = $all_posts[$new_key];
                    }
                }

                if (array_key_exists($i+1, $all_posts)) {
                    $np = $all_posts[$i+1];
                } else {
                    $new_key = 0;
                    $np = $all_posts[$new_key];

                    while ($pp->ID === $cp->ID) {
                        $new_key += 1;
                        $np = $all_posts[$new_key];
                    }
                }

                break;
            }
        }
    }

    return array('next' => $np, 'prev' => $pp);
}

Example usage:

$args = array(
    'post_type' => 'custom_post_type',
    'posts_per_page' => -1,
    'order' => 'ASC',
    'orderby' => 'title'
);

$adjacent = get_adjacent_posts($args);

$next_title = $adjacent['next']->post_title;
$next_image = get_the_post_thumbnail_url($adjacent['next']->ID, 'square');
$next_url = get_permalink($adjacent['next']);

$prev_title = $adjacent['prev']->post_title;
$prev_image = get_the_post_thumbnail_url($adjacent['next']->ID, 'square');
$prev_url = get_permalink($adjacent['prev']);

WARNING: This function is resource expensive, so do not use it if you have a lot of posts. It loads and iterates all of the posts from the provided query to find next and previous posts (as you can see in it's code).

There is a better way to do this, which is directly make calls to the database, but I'm way too lazy for that anyways, plus I never needed this code on more than 100 posts.

Hope you find it useful!

Upvotes: 3

Benoti
Benoti

Reputation: 2200

You can use the function get_adjacent_post(), this function can be use to retrieve the next and the previous post objects. The third paramater must be set to true to retrieve the previous and false for the next post. The last parameter allow to get an adjacent post in a choosen and restricted taxonomy.

$previous_adjacent_post = get_adjacent_post(true,'',true, 'product_cat');
$next_adjacent_post = get_adjacent_post(true,'',false, 'product_cat');

if(is_a($previous_adjacent_post, 'WP_Post')){
     $previous_link = get_permalink($previous_adjacent_post->ID);
     $previous_title = $previous_adjacent_post->post_title;
}
if(is_a($next_adjacent_post, 'WP_Post')){
     $next_link = get_permalink($next_adjacent_post->ID);
     $next_title = $next_adjacent_post->post_title;
}

In this example is_a() condition avoids errors when no response has been found (trying to get object from a string as the response is empty or null).

More details and examples get_adjacent_post()

You can use eventually, the filter "get_{$adjacent}_post_where": to filter by custom field.

EDIT:

With the link and explanation you add, it seems that you can do this with the plugin you use:

in_same_meta

Indicates whether or not the next/previous post must have the same custom field value as the current post. You must pass the name of the custom field to be matched. For example, if you had a custom field named ‘publisher’, and you wanted the next/previous links to lead to titles from the same publisher:

<?php next_post_link_plus( array('in_same_meta' => 'publisher') ); ?>

Please note that in_same_meta is not compatible with custom field sorting. If order_by is set to either ‘custom’ or ‘numeric’, in_same_meta is disabled.

Hope it helps !

Upvotes: 0

Related Questions