A client recently asked me to change the order of a list of categories displayed in a sidebar. I opened the proper file, located the call to
get_terms that collected the terms, and finally visited the Codex to find the proper argument to alter. To my astonishment, there was no way to order the category terms in a user specified manner. The terms could only be ordered by name or ID. It then dawned on me that, of course there is no argument that would sort the terms by a user specified order; there is nothing in the category admin that allows the user to even specify an order in the first place. Menus, widgets, and pages all have drag and drop or input fields that allow the user to specify the order to display the particular items. Within the category management, there is no way to do this. I was able to solve this problem, but it was much more complex than I initially thought it would be. (Note: If you are only interested in
quickly being able to sort your taxonomy terms, jump to the bottom of the page for a link to a plugin that will handle this for you.)
This tutorial will show you how to sort categories by a specific user determined order. This tutorial will first teach you how to add the metadata to each category to specify the order and then how to filter the
get_terms function to order the terms in the desired manner.
Creating the User Input Fields
To begin, we need to add a way for users to specify the order of the categories. WordPress pages manage page order with a text input called “Order” in each page.
I will be using this as a model for handling the category order in this tutorial. In order to accomplish this, term metadata needs to be added to the category terms. For a primer on adding metadata to taxonomy terms, please refer to my previous article on the subject.
To begin, install the excellent Simple Term Meta plugin. This plugin will add a table to the WordPress database to manage term metadata, as well as make available a number of easy to use functions that make dealing with term metadata a breeze.
First, hook functions that display the order inputs on the category add and edit pages.
This code will place the contents of the
category_metabox_add function in the “Add New Category” screen and the contents of the
category_metabox_edit function in the “Edit Category” screen. The next step is to write these functions.
These two functions add a new text input field to the Add and Edit Categories screens. The last thing needed is to save the “Order” fields on submit. This is accomplished by first hooking a save function to run when the categories are added or edit.
And second, by defining that function.
If everything is working correctly, a new field in the “Add New Category” screen will be available.
Additionally, a new field in the “Edit Category” screen will be available.
At this point, order metadata can be associated with each category. It can be added at the time of adding or editing a category. As a test example, imagine entering the following three categories:
By default, WordPress will sort these categories by ID. For this example, imagine entering these categories in the following order:
The list would be sorted in that manner. Let’s imagine that in this example the desired sort order is:
To prepare for this sort, enter the “Order” metadata for each term as shown in the image below.
The order metadata will not have an effect on the current sorting of the variables until the next step is complete.
Modifying get_terms To Sort By Order
Now that the order has been specified, modification of the
get_terms function can be made via a filter in order to change the sort order of the terms. Immediately prior to returning the terms in the
get_terms, the “get_terms” filter is applied. As such, this offers an ideal place to alter the order of the terms.
To begin, a function that does this sorting needs to be associated with the filter.
Prior to returning the terms in the call to the get_terms function, the
custom_term_sort function will be executed. This function will be responsible for sorting the terms according to the order metadata. The following two function handle this heavy lifting.
There is a lot going on here, so let me explain this step by step.
The first bit of code ensures that errors are not thrown when
get_terms is called in unusual places. Then, dummy arrays are set up to collect and differentiate terms that have order metadata from those without order metadata.
Next, a loop is initiated that cycles through the terms.
The code then tests to make sure that the term is an object. Since
get_terms returns the terms as objects, something has gone seriously wrong if any term is not an object. As such, the else clause to the if statement sets the
$empty variable to true which will later control what is returned from the function. The structure of this check is as follows.
Now, if the term is an object, the “tax-order” property is added to it; however, before simply adding this property to the object, a test is done to ensure that “tax-order” metadata exists. If it does exist, the property is added and the term is added to the
$ordered_terms array. If not, the “tax-order” property is added to the object with a value of “0” and the term is added to the
$unordered_terms because no order has been specified for the term. It is important to make sure to properly handle the terms that do not have an ordered specified to ensure that they are not lost when
get_terms is filtered.
The next bit of code finally sorts the array of objects by the “tax-order” property, but before doing so, two important checks are performed. First, if the
$empty variable is “true”, the array of terms is not sorted. If you recall, the
$empty variable is set to “true” if just one of the terms is not an object. If this is the case, the original array of terms is returned and the custom sort is not performed. The next check ensures that there are term objects to sort. If at least 1 term has the “tax-order” property, and has subsequently been placed in the
$ordered_terms array, the sort will be performed. If not, the original array of terms is returned. If the two conditions are met, the
quickSort function is executed on the array of terms. I will not discuss the
quickSort function other than mention that it is an excellent function written by Paul Dixon that sorts an array of objects by a property of the object.
Finally, the array of ordered items is merged with the array of unordered items and returned.
With that, the categories are sorted using the order metadata. As such, the original example would now sort as specified into the following order:
Adding This To Your Project
To make your life a little easier, you can simply grab the code from pastebin, which is ready to be copied and pasted to a functions.php file or a plugin. Just remember to install the Simple Term Meta plugin in order for the code to work.
And to make your life even easier, I recently released a plugin that will do all of this and more for you. My Custom Taxonomy Sort handles adding an order field to each taxonomy page and automatically sorts the terms by the desired order. It works properly in WordPress 3.1 and 3.2 and is ready to download now!