If you use WP for a lot more than just publishing a blog and using the ready made themes and plugins, then I bet you know a whole lotta stuff can be done with the normal list of posts on your blog index. One such thing (and a highly desirable feature) is to be able to reorder your posts according to the various ordering options that are available with ‘query_posts‘ (or ‘WP_Query‘ for that matter). Usually, if you’re to modify the loop to display the posts ordered in a specific manner, you’d create a new ‘WP_Query’ object or pass the parameters to ‘query_posts’ and invoke it right before the loop starts. But using a simple technique that is already used by WP, we’ll learn how to reorder the posts list, by modifying ‘query_posts’ right from the frontend, using jQuery.
Checkout the demo: Demo
Prerequisites:
1. Obviously, you should know WP a little deeper on the technical terms. Precisely, knowledge of ‘The_Loop‘ and ‘query_posts / WP_Query‘ is required.
2. Basic jQuery.
Done nuf’ talking, let’s get code stained!
I assume you’ve used WP’s default ‘Categories’ widget. This widget displays the categories as a dropdown or as a list. When displaying the categories as a dropdown, selecting a category from the dropdown automatically redirects you to the archive page of that category. We’re going to use the same trick to get our job done. Checkout the ‘default-widgets.php’ file from the wp-includes folder in your WP installation for the Javascript we’re going to use (line no. 444).
Make a new template, name it ‘Ordered posts’. Add the following code in it:
[php]
<?php
/*
* Template Name: Ordered Posts
*/
get_header(); ?>
<div id="content">
<?php query_posts(‘order=DESC’); ?>
<?php if ( have_posts() ){ ?>
<?php while ( have_posts() ) : the_post() ?>
<div <?php echo post_class(); ?>>
<h3><?php the_title(); ?> | <small><?php the_time(‘F jS, Y’); ?></small></h3>
<?php the_excerpt(‘Read more…’); ?>
</div>
<?php endwhile; ?>
<?php } ?>
</div>
<?php
get_sidebar();
get_footer();
[/php]
This is pretty simple. We’re making a new template to display the posts, and the default order is date descending. We need to call ‘query_posts’ explicitly with one parameter to display all posts, or the loop will display the content of the current page. We’ll change this very soon. Next, we display the title, the date posted and the excerpt for each post.
Create a new page through the dashboard, name it ‘Reorder Posts’ and assign it this template. Visit this page and you have the posts displayed in the default order i. e. recent ones first.
Now modify the template, and add the following code to it, just after [html]<div id="content">[/html] and before [php]<?php query_posts(‘order=DESC’); ?>[/php]
Code:
[html]
<div id="sorter-container">
<select id="order-by">
<option value="date-desc" <?php echo (!isset($order) || $order == ” || $order == ‘date-desc’)? ‘selected="selected"’:”; ?>>Date Desc. (default)</option>
<option value="date-asc" <?php echo ($order == ‘date-asc’)? ‘selected="selected"’:”; ?>>Date Asc</option>
<option value="date-mod" <?php echo ($order == ‘date-mod’)? ‘selected="selected"’:”; ?>>Date Modified</option>
<option value="title-desc" <?php echo ($order == ‘title-desc’)? ‘selected="selected"’:”; ?>>Title Desc.</option>
<option value="title-asc" <?php echo ($order == ‘title-asc’)? ‘selected="selected"’:”; ?>>Title Asc.</option>
<option value="comment" <?php echo ($order == ‘comment’)? ‘selected="selected"’:”; ?>>Comments Count</option>
</select>
</div>
[/html]
This will add the dropdown with the various ordering options to select from, right above our posts list. The embedded php code checks what value is currently assigned to the ‘$order’ variable, and keeps the respective option from the drop down selected.
The options that we’re adding are:
- Date Asc. – Order according the ascending order of date published (the very first post will appear first).
- Date Desc.(default) – The default order, recent one appears first.
- Date Modified – The post which was modified recently, appears first.
- Title Desc. – Alphabetically descending order of the title, Z…A.
- Title Asc. – Alphabetically ascending order of the title, A…Z.
- Comment Count – The most commented appear first.
We get to the appropriate redirection part using the Javascript/jQuery code. Modify the template again, and add the following code, just after [html]<div id=’sorter-container’>…</ div>[/html] and before [php]<?php query_posts(‘order=DESC’); ?>[/php]
Code:
[html]
<script type="text/javascript">
var orderby = jQuery(‘#order-by’);
var str;
orderby.change(function(){
str = jQuery(this).val();
window.location.href = "<?php echo home_url(); ?>/reorder-posts/?o="+str;
});
</script>
[/html]
This code is straight forward. When we select an option (which triggers the ‘onchange’ event, handled by ‘change‘ in jQuery) from the dropdown, we’re redirected to the current page with the selected option’s value as a url parameter, ‘o’. We need to handle this parameter using php.
( Please use the correct page slug here. I named my page as ‘Reorder Posts’, hence got the slug as ‘reorder-posts’.)
To handle the url parameter ‘o’, update the template and add the following code just after [php] get_header() ?>[/php] and just before [html]<div id="content">[/html].
[php]
<?php
if( isset($_GET[‘o’]) && $_GET[‘o’] != ”)
{
$order = $_GET[‘o’];
switch($order)
{
case ‘date-asc’: $orderby = ‘order=ASC’;
$msg = ‘Date Ascending’;
break;
case ‘date-desc’: $orderby = ‘order=DESC’;
$msg = ‘Date Descending(default)’;
break;
case ‘date-mod’: $orderby = ‘orderby=modified’;
$msg = ‘Date Modified’;
break;
case ‘title-asc’: $orderby = ‘orderby=title&order=ASC’;
$msg = ‘Title A-Z’;
break;
case ‘title-desc’: $orderby = ‘orderby=title&order=DESC’;
$msg = ‘Title Z-A’;
break;
case ‘comment’: $orderby = ‘orderby=comment_count’;
$msg = ‘Comment Count’;
break;
}
}
else
{
$orderby = ‘order=DESC’;
$msg = ‘Date Descending (default)’;
}
?>
[/php]
This checks if the url parameter ‘o’, is set and not blank, then assigns its value to the ‘$order’ variable. Depending on the value of ‘o’, form the arguments variable, ‘$orderby’ that should be passed to ‘query_posts’ to order the posts accordingly. If it isn’t set or set to something that we haven’t handled, then fall back to the default, date descending. We also form an appropriate message to display.
Change ‘query_posts(‘order=DESC’)’ to ‘query_posts($orderby)’ as
[php]<?php query_posts($orderby); ?>[/php]
Add the message that tells how the posts are ordered currently, just after the [html]<script>…</script>[/html].
Code:
[html]
<h2 id="sort-heading">Posts ordered by:<?php echo $msg; ?></h2>
[/html]
All done! Visit this page in your blog/site, and try selecting an option from the drop down. It will reorder posts accordingly! Instead of creating a new template, you can even use this code to modify your ‘index.php’ to have re-order able posts list right on your blog’s index/home. Optionally you can set this page as the home page for your blog. Just make sure you change the url used for redirection in the Javascript code accordingly.
Check the demo here: Demo.
Comments, suggestions are welcome!
I have been looking for something like this for quite awhile now and – this is a very elegant solution! –
I ended up using it as a conditional function for just my category archives – so I didn’t need to make a template or set up a page and select a template –
and then I replaced the ‘reorder-posts’ location with category so it became:
window.location.href = “/category//?o=”+str;
});
Anyways – it is a really nifty piece of code – thanks!
Hi,
You’re welcome!
As far as the URL is valid, the code could be used in many ways, like the one you used ! The template was just one way to do it (and to ensure that those who’re not yet fully into WP don’t end up with a broken index.php or some other default template file!).
Thanks!
I have been searching intensively for a way to sort my WP Post… to no avail.
I am very grateful to have found this amazing tutorial. Thank you sooo much for making this.
🙂
You’re welcome friend !
Love the tutorial, is there anyway that you can apply the query to a single custom post type.
Have tried several variations of
‘portfolio’, ‘$orderby’ ) );?>
instead of
which pulls all of my regular posts into the portfolio.
Can you create a paste of your code and give me the link? I’ll be able to help you better if I get to see the code you’re trying.
Hi Rutwick,
I got it working after a bit of messing around
here is the code I ended up using so my pagination
would still work. It was the “” around the args that done the trick.
$paged = (get_query_var(‘paged’)) ? get_query_var(‘paged’) : 1;
query_posts(“‘orderby=$orderby&post_type=portfolio&paged=$paged'”);
Thanks for getting back to me though.
Love the tutorial, it will add extra value to a project I am currently working on.
I was wondering however if there is any way that I could create two lists that interact with each other.
For example the first list would allow the user to view posts by most viewed or commented. The second list would allow them to filter this first selection by tag.
Cheers
Tonyk
A little play around with if/else on the $_POSTed variables should get you there!
[…] I have tried the solutions here – http://ak.net84.net/php/filter-dropdown-for-wordpress/ – and here – http://blog.rutwick.com/use-jquery-to-reorder-your-wp-posts-on-the-fly […]
Hi rutwick,
I have been wanting to do this for months, but never could figure it out…so glad to stumble across your website.
I have almost got it working, everything is in place but the page doesnt refresh and load the new url like example.com/top-rated/?o=title-asc. I can select the different options in the drop down menu…but nothing happens.
Im really sorry for posting my full page/code, but do you think you could take a look and see what you think?
Thanks in advance 🙂
var orderby = jQuery(‘#order-by’);
var str;
orderby.change(function(){
str = jQuery(this).val();
window.location.href = “/top-rated/?o=”+str;
});
Posts ordered by:
<option value="date-desc" >Date Desc. (default)
<option value="date-asc" >Date Asc
<option value="date-mod" >Date Modified
<option value="title-desc" >Title Desc.
<option value="title-asc" >Title Asc.
<option value="comment" >Comments Count
<div >
<a href="”class=”img_hover_trans”>
<a href="”> |
<?php
get_sidebar();
get_footer();
Hi,
Sorry for the delay in responding. I was wondering if you got this working. I think your jQuery could be a reason why this fails.
Rutwick
Hi, I tried to view the demo of this, but unfortunately there is not demo of this code in action via the site you listed. It appears to be a portfolio website in the works. If you could repost the demo for this code, it would really mean a lot to me! 🙂
Hi Ian,
Sure I’ll post a demo of it! Thanks for bringing it to my notice!
-Rutwick
Thx rutwick, works perfect, i’m wondering if there is any easy way for doing the same without reloading the page?
Hi James,
Then you’ll have to use AJAX!