I am using the get_terms
function to order all the terms of a custom taxonomy alphabetically. My client however has now requested that one of the terms be put at the very end (therefore not in alphabetical order). Does anyone have any suggestions on how the best way to achieve this?
-
possible duplicate of Order get_terms() By Custom Field– Howdy_McGee ♦Commented Apr 17, 2015 at 21:43
-
@Howdy_McGee sort of, but Duncan didn't say anything about having any custom field values for his terms– Stephen S.Commented Apr 17, 2015 at 22:01
-
How can this be a duplicate post. Yes, custom fields can be an option, but it is not the only option. What if the OP don't want to use custom fields.– Pieter GoosenCommented Apr 18, 2015 at 9:55
5 Answers
This can be easily done with your own custom function. What you want to do here is, get your object from get_terms()
which will hold your term objects, check if your unique key is set as a parameter and then according to that, remove that key/pair and add it to the back
Now, lets put that into code: (I have commented the code to make it easy to follow)
This is the pre PHP 5.5 version but still need at least PHP 5.4
function get_term_to_end( $taxonomy = '', $args = [] )
{
$terms = get_terms( $taxonomy, $args );
/*
* Return $terms if our new argument term_to_end is not set or empty
*/
if ( !isset( $args['term_to_end'] ) || empty( $args['term_to_end'] ) )
return $terms;
/*
* If term_to_end is set and has a value, continue to process
* Return $terms if a wp error is returned or if $terms is empty
*/
if ( is_wp_error( $terms ) || empty( $terms ) )
return $terms;
/*
* We have came this far, now we can finish this off
*/
foreach ( $terms as $term ) {
/*
* Check the term ids against our new argument term_to_end
*/
if ( $term->term_id == $args['term_to_end'] ) {
$end[] = $term;
} else {
$terms_array[] = $term;
}
}
/*
* Merge the two arrays together, adding the term_to_end right at the back
*/
$terms = array_merge( $terms_array, $end );
/*
* For uniformaty, type cast the resultant array to an object
*/
return (object) $terms;
}
If you are using PHP 5.5 +, you can use array_search
and array_column
and skip the foreach
loop inside the function
function get_term_to_end( $taxonomy = '', $args = [] )
{
$terms = get_terms( $taxonomy, $args );
/*
* Return $terms if our new argument term_to_end is not set or empty
*/
if ( !isset( $args['term_to_end'] ) || empty( $args['term_to_end'] ) )
return $terms;
/*
* If term_to_end is set and has a value, continue to process
* Return $terms if a wp error is returned or if $terms is empty
*/
if ( is_wp_error( $terms ) || empty( $terms ) )
return $terms;
/*
* We have came this far, now we can finish this off
*
* We need to convert the multidimensional objects to a multidimensional array. Lets used
* json_encode and json_decode. Now we can use
* array_search to and array_column to determine the position of the term_to_end
*/
$terms_array = json_decode( json_encode( $terms ), true );
$end_term_position = array_search( $args['term_to_end'], array_column( $terms_array, 'term_id'));
/*
* First check if $end_term_position in not false (array_search returns false on failure),
* if false, return $terms
*/
if ( !$end_term_position )
return $terms;
/*
* Get the key value pair for term_to_end, unset it from $terms and reset term_to_end pair at the back
*/
$end_term_pair[] = $terms[$end_term_position];
unset( $terms[$end_term_position] );
$new_terms_array = array_merge( (array) $terms, $end_term_pair );
/*
* We are done!! Now we can just return $new_terms_array as an object
*/
return (object) $new_terms_array;
}
Example use case:
Move term with id 15 belonging to the taxonomy mytax
to the back of the term array. Keep the default odering by name
$terms = get_term_to_end( 'mytax', ['term_to_end' => 15] );
Or
$args = [
'term_to_end' => 15
];
$terms = get_term_to_end( 'mytax, $args );
FEW NOTES ON THE ABOVE
The code above is all untested and might be buggy. I have written this on a tablet.
For older versions (pre PHP 5.4), use the first code block and simply change the new array syntax (
[]
) to the old syntax (array()
)The new parameter,
term_to_end
uses the term to move to the end term's ID. You can modify this to work with either the term name or term slug, whatever suites your need. You can also modify this to work with all of these valuesThe new function uses the exact same parameters as
get_terms()
. The only extra addition is theterm_to_end
parameterAs
get_terms
, the new function returns aWP_Error
object if a taxonomy does not exists and also returns an ampty array if no terms are found. Remember to check for these occurances in the same way you would withget_terms
If the
term_to_end
parameter is set, thefields
parameter cannot be set to anything else thanall
(which is the default). Any other value will break the function. You can modify this very easily to work properly by building in some coditional checks and changing theforeach
in the first code block or changing the use ofarray_search
in the second code blockYou can very easily change the function to move a selected term to the front if needed. You can also adjust the function to accept multiple terms to move
For any other info regarding the use of this function, please see
get_terms
EDIT
This code in now tested and working as expected.
I stumbled across similar issue lately. If you are comfortable with using a plugin, you can install Custom Taxonomy Sort. Even though it was not updated for over two years, it solved the problem for me. Basically, it allows you to sort terms manually from the dashboard.
-
The only problem with this is that the user would have to update the order whenever they added a new term, which could definitely be a pain depending on the number of terms. Commented Apr 17, 2015 at 22:14
-
Makes sense. In my case, there were only 12 terms that don't change over time. Commented Apr 17, 2015 at 22:20
-
Ah yeah. Another one I've seen for the same thing is: wordpress.org/plugins/taxonomy-terms-order Commented Apr 17, 2015 at 22:21
An idea that came to me is to add a term in your taxonomy called something like 'append' and then make the terms you want to be appended at the end of your terms list children of that term. Then it is only a matter of doing the appropriate term queries, ie get all terms with append as it's parent and then exclude them when quering for the rest. This way you maintain editorial control to this custom ordering thing and don't have to hardcode anything into your template.
-
Yes, it is an idea, but what if the user has specific terms, say like ingrediends or states which needs to be just that. Just a thought :-) Commented Apr 18, 2015 at 9:14
There may be a better way of doing this, but you could probably just do two queries. Maybe something along these lines (untested):
$loner_term = X; //put whatever the id of the term you want at end
$taxonomies = 'YOUR_TAXONOMY_NAME';
)
// get all of the alphabetical terms and exclude the one you need at the end
$alpha_args = array(
'orderby' => 'name',
'exclude' => $loner_term
);
$alpha_terms = get_terms($taxonomies, $alpha_args);
// only get the term you need to come at the end
$na_args = array(
'include' => $loner_term
);
$na_terms = get_terms($taxonomies, $na_args);
echo '<ul>';
// loop through the alphabetical terms
foreach ($alpha_terms as $alpha_term) {
echo '<li>'. $alpha_term->name.'</li>';
}
// then loop through the loner term
foreach ($na_terms as $na_term) {
echo '<li>'. $na_term->name.'</li>';
}
echo '</ul>';
EDITED to use get_terms properly!
-
-
Just another note here, please recheck your code, it is extemely buggy. You are feeding arguments to
get_terms
that does not exist, and also, you are usingget_terms
incorrectly. The syntax isget_terms( $taxonomies, $args )
, notget_terms( $args )
:-) Commented Apr 18, 2015 at 9:42 -
@PieterGoosen ahh just logged on to see what the latest with this was and it looks like I should have done so earlier. I was mainly trying to throw the idea of two queries into the ring, but definitely should have taken a bit more time on it. Commented Apr 20, 2015 at 23:43
// Define a custom order for category IDs
$custom_order = array(
13, // Category ID for 'featured'
51, // Category ID for 'all-resources'
21, // Category ID for 'resource-type'
19, // Category ID for 'service'
22 // Category ID for 'industry'
);
// Retrieve terms (categories) with specified parameters
$categories = get_terms('category', array(
'parent' => 0, // Get only top-level categories
'exclude' => $excluded_categories, // Exclude specific categories, if needed
'include' => $custom_order, // Include categories in the specified custom order
'orderby' => 'include', // Order categories based on the custom order
'hide_empty' => false, // Include categories with a count of 0 (no associated posts)
));