Custom Ordering for WordPress Post Link Functions

/ Wordpress / by Paul Robinson / 7 Comments
This post was published back on April 29, 2012 and may be outdated. Please use caution when following older tutorials or using older code. After reading be sure to check for newer procedures or updates to code.

The post link functions previous_post_link() and next_post_link() show a link to the next & previous posts. They are generally used on singular page templates. The functions are also fixed to pulling back the next & previous post in chronological publishing order, but what if you would like a custom order.

Why Would You Need A Custom Order?

Let’s take a product catalogue as an example. You are using a custom post type to hold products, each product holds a release date via a custom field. When you display the product via it’s singular template it would be nice to have a next & previous button to go through those products, but it should go through them in order of their release dates. Currently that’s not possible as they would be ordered by their publishing dates.

Altering The Order

This is actually pretty tricky & I would consider it fairly advanced in terms of WordPress customization. If you are familiar with MySQL you should be able to understand it fairly well. If not, hang in there & I’ll try to explain it as best I can.

First let’s set up our filters:

These are the filters we are going to use to intercept WordPress’ normal query and alter it to order how we want. I’ll do a quick run through each filter. For reference {$adjacent} just means previous or next.

  • get_{$adjacent}_post_join is the join section of the query. It determines which tables are joined onto the post table. This is generally empty unless you are using category exclusions.
  • get_{$adjacent}_post_where is the where section. It determines how to restrict the results by asking for certain values to be present.
  • get_{$adjacent}_post_sort is the ordering section. It determines how to order the results retrieved by the MySQL database.

We are going to continue using our release date example from before. Let’s continue & see if we can create some code that will allow us to retrieve the next & previous posts by the release date of the product. For reference our post meta’s key is release_date and the value must be a date in YYYY/MM/DD format since that, without using date functions, is the easiest date format to use with comparison operators in MySQL.

Let’s start with our join function.

As you can see this simply joins the postmeta table onto the posts table (selected by WordPress automatically). I’ve used the $wpdb variable to grab the table names, that way the code will still work even if the WordPress table prefix is changed. I’ve used INNER JOIN so we do not retrieve any NULL results since we do not need them. The rest is simply joining the posts table with the postmeta table via their matching fields. Please remember that I’ve used aliasing for ease so the postmeta table is now called pm from this point on.

Next is our two where functions.

This time I’ve globalized both $wpdb & $post as we will need them both in these functions. I’ve stored the release date in a variable for use in the query using the standard get_post_meta() function. Now in this function, depending on what you are doing, you may want to concatenate your extra piece of query onto WordPress’ original. The original query looks for posts with a publish date less than (previous) & greater than (next) the current posts, if you require that to be left intact or can complete your query with WordPress’ query still intact feel free to use $w .= to concatenate your query onto the original, just remember to add a space to the front of your string.

In this case I cannot keep WordPress’ original query. Instead I have asked to limit only to posts with a meta key equalling release_date and a value less than (previous) or greater than (next) the current posts release date, which we grabbed from the post meta. I’ve also asked only to return posts from the products post type and only if they are published.

You may be wondering what $wpdb->prepare is. Well since we are using a variable inside the query, and it can be entered by a external source, it is best to run it through a function to make sure it is ‘made safe’ before passing it to MySQL. The $wpdb->prepare() function provided by WordPress’ database object does exactly that.

Finally let’s move on to our sort functions.

These functions are fairly simple. I’ve simply ordered by the meta value, which we know is the release date. I’ve use descending order for previous and ascending for next. I’ve then also limited it to 1 post since we don’t need any more than that.

All Done

That’s all there is to it. With a little knowledge of MySQL & WordPress’ database schema you can pull some pretty powerful queries together & in places completely transform WordPress. Even better is the fact that it is non-destructive. All you have to do is simply comment out the add_filter() lines and it will stop your functions from working & return WordPress back to normal.

7 Comments

Author’s gravatar

What should I change if clicking on either the next or previous link goes to the first post only? I don’t need to restrict to a custom post type, I am just trying to have the function listen to a custom meta name and value. Since many values are the same, I need to concatenate the result with the original query, but am not sure how to do that.

Reply
Author’s gravatar

I have the same problem. Now both prev and next link are going to the first post. For me, I do want to use this on a custom post type, so the code should be perfect for my use. Just not getting why both links always go the first post of the standard post type… I need them to go to the previous and next post of the custom type. (products in the example above, events in my own case).

Author’s gravatar

Update: the above code has “rt_” in the filters, and “cg_” in the functions.
Replacing rt_ with cg_ fixes the problem on my custom post type single pages.
However, the prev/next links on the non-custom single pages now also go to the custom post type pages.

Is there a way to apply the above functions only to the custom post type singles, and not the regular single posts?

Reply
Author’s gravatar

Last Update: If I put the whole filter and function code in the single post type single file instead of in functions.php, it works, and doesn’t affect the rest of the site. Not sure it’s the correct way to go though, I’d say it should be possible to put it in functions.php and call it from where you want to use it. Not WP-savvy enough to know how, so this will do.

Still, thanks Paul, I googled enough, but you’re the only one who posted a working solution at all, without pushing plugins! 🙂

Reply
Author’s gravatar author

Thank you Els, I feel like such an idiot. I had copied similar code I used for a client & edited it to be a little more generic, so it would be easier to use & not reveal any specifics about the client, and I had forgotten to change the function prefixes… *major headdesk*

You are right you should be able to do it all in the functions file. All you would need to do is wrap the correct conditional around your $o .= lines in each function. So for example if you only want it to affect the portfolio post type you would do:

Basically you need it so that you only alter the value if it is the correct post type, otherwise just return the value unaltered & WP will (should) act as normal.

Hope that helps & thank you. I’m happy I could help, despite the awful mistake. 😉

Author’s gravatar

There is a problem when posts have same meta value. Next button is jumping to post with next meta value instead of a next post.

Reply
Author’s gravatar author

Hi,

Yes, I can see why that would happen. Once you are on the post that has the same meta value it would look for the next one up or down & miss the one that has the same value. I haven’t tried it but you could try changing the comparisons to ‘<=' and '>=’ and excluding the current post from the results. So it might look like:

It basically just gets posts including once that are the same as the current value forward & backward, but excludes the current post. I have a feeling this might have the problem that both the previous & next will end up going to the same post & you might get stuck jumping between them (again don’t know as it’s untested). If anyone has any thoughts on how to solve that issue though, please feel free to chip in.

Older Comments
Newer Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

I'll keep your WordPress site up-to-date and working to its best.

Find out more