There are 2 functions in WordPress to let you display previous and next post links: previous_post_link
and next_post_link
. In general, they work so well and really save a bunch time when coding a theme.
Recently in one of my projects, I created several custom post types, and made the posts ordered by menu_order. In such scenario, I found the previous and next post links didn’t behave as I expected, they still return the links based on the order of post ids.
Before I started to write my own version of previous_post_link, luckily I found the filters in get_adjacent_post
could order the posts as I want. Here’s the snippet I use in my project:
At first I just added filters to change the sort, but it didn’t work. Then I realised the get_{$adjacent}_post_where
should be filtered either, to help the SQL get the right posts for us to sort.
If you are interested in how to make the prev/next post links ordered by meta value, please read this thread on StackExchange for more information.
Thanks for this! Totally helped me out 🙂
Glad it helped! 😉
Thanks. It works like Charm!!
Thank you!!!
Thanks Yoren!
I add your code in the function.php of my child theme, Its work! now is ordering by menu order but does not respect the languages (I am setting a multilanguage site), when I click next or prev load the rigth woocommerce product but from another language.
Any Ideas?
Thanks in advance
Hello again!
I read in: http://stackoverflow.com/questions/26425192/get-all-products-from-english-version-woocommerce-wpml
but I dont know how to aply that to your code. How I integrate the JOINT whit the active languague in the wp_icl_translations table??
(yes I forgot, I am using WPML as language plugin)
Hey Emiliano,
Please refer to this thread: http://wordpress.stackexchange.com/questions/73190/can-the-next-prev-post-links-be-ordered-by-menu-order-or-by-a-meta-key to see how to add JOIN statement.
Awesome!
Dropped the snippet into my functions and worked like a charm just like it is.
thank you Yoren! 🙂
Cool! Glad I could help. It was bothering me so I’m really happy it is of use to people.
So if I understand this right, after adding these filters you would just need to use the native wordpress single post navigation, right?
How would you exclude password protected posts? Couldn’t come up with a working solution yet.
Jonas, have you tried to exclude posts with password with SQL statement like this:
This is brilliant Yoren, thank you. I researched for a while but had no idea how to correctly write the DB request. I am learning a lot with your post. Thanks a lot.
Glad I can help!
Hey Yoren, can I ask you something else?
I hope it doesn’t feel like I am abusing your kindness. I definitely have a feeling that you know much more than I do and maybe you can give an insight into this.
I am using Polylang plugin, which assigns each post to a taxonomy ‘language’. While using get_adjacent_post() I want to bring only those posts that belong to the language currently displayed.
So I am writing the following:
$prev_post = get_adjacent_post( true, ”, true, ‘language’ );
$next_post = get_adjacent_post( true, ”, false, ‘language’ );
But this brings the next and previous posts from all the languages, independently from the language I am currently in.
Should I just add this filter in ‘get_previous_post_where’ as you specified in this article and specify the ‘language’ taxonomy in there? How exactly would you filter the taxonomy in the $wpdb->prepare?
And lastly, if you don’t mind explaining, how on earth did you learn to write the exact filtering for the $wpdb? I am reading https://codex.wordpress.org/Class_Reference/wpdb but it’s not exactly clear explaining how to do what. For example if I add “AND p.taxonomy = ‘language'” following your examples above, it says: [Unknown column ‘p.taxonomy’ in ‘where clause’]. How did you learn it?
Hi Jonas,
If we take a look at the
get_{$adjacent}_post_where
filter (http://adambrown.info/p/wp_hooks/hook/get_%7B$adjacent%7D_post_where?version=4.1&file=wp-includes/link-template.php), we can see that there’s a very important variable that I removed from my gist, which is a$where
at the end of the SQL statement.I can’t recall why exactly I removed it, it seemed break my query at the time of my writing. But now if put it back can fix your problem, I’d love to update my gists accordingly.
So can you try this filter function again:
And let me know the results?
BTW, I suppose in this case, the $wpdb is not the key to solve the issue, but how exactly the
get_{$adjacent}_post_where
works. I spent a lot of time to read the code and luckily managed to understand it.Let’s see if the function above can work this time, and I’d love to explain much more clearly if you still need my help. Thanks!
I made it work 😀
With your help and pointing me to the source files, I took a look at the wp-includes/link-template.php and figured in line 1514 how they were calling these taxonomies.
So this code so far seems to do the trick:
function my_previous_post_where() {
global $post, $wpdb;
return $wpdb->prepare( “WHERE p.menu_order menu_order, $post->post_type);
}
add_filter( ‘get_previous_post_where’, ‘my_previous_post_where’ );
I use it together with $prev_post = get_adjacent_post( true, ”, true, ‘taxonomy-name’ ); in my theme files.
Need to test it intensively. Thanks a lot for your help and time!
Sorry, in my excitement I pasted the wrong code 🙂
Here is the functional one (note that in the code you sent me above the $where was undefined, that’s why it wasn’t working)
Working snippet:
function my_previous_post_where() {
global $post, $wpdb;
return $wpdb->prepare( “WHERE p.menu_order menu_order, $post->post_type);
}
add_filter( ‘get_previous_post_where’, ‘my_previous_post_where’ );
Hey this is auto-correcting me the code I put! That is not the code i am sending in the comment form. Here it is: http://pastebin.com/eHR15dkw
Hey, glad you figured that out!
Thanks for the code, working great – as long as the posts are on the same level (hierarchically). I’m not seeing links to if the previous or next post would be on a parent level.
Is it possible to include those?
Thomas, from the SQL statements you can see we actually don’t specify if the prev/next post should be in the same level. So can you make sure if the “menu_order” do in the right sequence?
Hi,
I am a newbie in WordPress.. I am trying to use this code i put all the code in functions.php how can i call in single.php?
I have created a custom filed called sorting_order, the sorting is working fine on main projects page but when you click on single page the next/previous post not showing by same sorting order.
This code seems like sorting next/previous post.
Please can you help me out.
Thanks in Advance
Thanks
Atif
hello, You just need to update the sort SQL statements to integrate the extra field you’ve added in the *.postmeta table. You don’t have to be familiar with WP, if you’re good enough at MySQL, you will figure that out!
Good luck!
Hi,
Thanks for your reply.
Can you please tell how can i call this function in single.php?
Thanks
Atif
These functions need to be in
functions.php
.I put the code in functions.php. how can i call the next/previous function in single template?
Hook functions go to
function.php
while template functions go to template files, in this case should besingle.php
or so.Hi!
Thanks for this great code. I have one question though. When I’m using this code the next and prev links work for all the posts of the custom post type. What I have to include in this code to ensure that the next and prev links will be target only posts that belong to the same category?
Hi Mark, you’ll have to update the SQL statements to make it work with category (taxonomy). This would be a bit complicated and you have to be familiar with WordPress data structure. Good luck!
Hi Mark,
Did you manage to work this out as have the same issue?
Regards,
James Isles
Yoren,
Great solution! I do have a question, though:
Will this apply to ALL get_adjacent_post() calls? What if I want the prev/next links to be based on menu_order for one custom post type but use the default date-based ordering for all other post types?
Would it be something like this?
https://gist.github.com/anonymous/50d27caa1abf9e432bbea5c05ee7dd46
Hi Ben, yeah this filter will be applied to every get_adjacent_post() call. So your method looks correct to me, though I haven’t really tested it.
Hello Yoren,
Great solution! It worked like a charm, thanks for taking the time to putting this up. It came in handy for a project – portfolio I was working on.
I’m wondering this should work with database cache settings on a plugin right?
Thanks
Hi Derrick, yeah it definitely works with database cache since we totally use a WP native solution.
Woow, thanks for share!!
Thank`s. Check out the share buttons. I shared on social networks (twitter, Google, facebook), but the counter shows – zero
Hey thanks! Not sure if the counter has been broken for a while. It’s a free gadget so there’s always some issues here and there…
Oh my god I love you! I owe you a couple of beers. Being looking for this since days.
It worked like a charm! Thank you so much!
This just saved my butt. Thanks a lot, mate!
Thank you so much! You’re saving me a lot of time!
I’ve been searching for a way to do this for ages and your code works for me, BUT it’s working in reverse for some reason. On my first post it shows a PREV button and continues in the right order but in completely the wrong direction. I can’t figure out why.
Can you tell me if the products are not ordered by menu order… then how to order it alphabetically??? Thanks for your post.
Thank you SO much! Works brilliantly!