I have a custom post type - Demo Tours

And for that CPT I created a Custom Taxonomy - Demo Tour Categories. Each Demo Tour may have one or more category. Each category has Custom Field - Category Image/Video

On front end, the query gets all the custom taxonomy entries (Tour Categories) display the category Image and Description on the left, and the Demo Tours that belong to that category listed on the right. Pretty basic and works like a charm.

The problem is, I must control the list order of Demo categories (and the demo tours that belong to them). Now the orderby is by their ID.

But I want to add a Custom field - Order Number to Custom Taxonomy - Demo Categories, and on front end I want to display them depending on the Order Number.

Custom Fields created with ACF plugin and the Custom Post Types created with Pods Admin plugin.

I have really spent a significant time on web to find a solution but nothing matches exactly what I need.

I believe the problem is my approach but can't really put my finger on the problem.

Please show me a way :)

Here is my code : (briefly)

first I get the terms :

$terms = get_terms(
  'taxonomy'   => 'tour_category',
  'hide_empty' => true,

then I loop them to show a header with Category names (like a menu)

 foreach($terms as $term) {                   
   echo ' <a class="demo_cat_link" href="#' . $term->slug . '">' . $term->name .  '<li class="demo_cat"></li></a>'; 

then I display the categories on the left

          $i = 0;
          foreach ($terms as $terms => $term) { 
            $i++ != 0 ? $fClass = "fade" : $fClass = "" ;
            $cat_id = $term->term_id;
            $cat_video = get_field('featured_video', $term->taxonomy . '_' . $term->term_id ); 
            $cat_order = get_field('tour_category_list_order', $term->taxonomy . '_' . $term->term_id ); 
                <div class="loop_left_section">
                  <div class="tour_cat_thumb <?=$fClass?>">
                    <video class="demo_featured" width="620" autoplay="autoplay" loop="loop" muted="">
                      <source type="video/mp4" src="<?php echo $cat_video; ?>">
                  </div> <? // tour_cat_thumb ?>
                  <h2><?php echo $term->name; ?></h2>
                  <p><?php echo $term->description; ?></p>
                </div> <? // loop_left_section ?>

and the demo tours on the right

<div class="loop_right_section">
                    $args = array(
                      'post_type' => 'demotours',
                      'tax_query' => array(
                            'taxonomy' => 'tour_category',
                            'field' => 'slug',
                            'terms' => $term->slug,                            
                    $loop = new WP_Query($args);
                    if($loop->have_posts()) {            
                      while($loop->have_posts()) : $loop->the_post();
                        $demo_tour_link = ( get_field('demo_tour_link', get_the_ID() ) ? get_field('demo_tour_link', get_the_ID() ) : "#" );
                        echo '<a href="'.$demo_tour_link.'" class="tour_link">
                          <div class="demo_tour_wrap">
                            <h3>' . get_the_title() . '</h3>
                            <p>'. get_the_excerpt() . '</p>
                </div> <? // loop_right_section ?>    
  • so essentially, you're asking how to sort/re-order the $terms array? You'd have to do this immediately after your get_terms call, using the standard PHP array sorting functions, and you'll probably need a sorting function to check the term meta with the order value you've added ( custom fields === meta, meta is the internal/real name )
    – Tom J Nowell
    Commented Feb 10, 2023 at 12:20
  • @TomJNowell - thanks for your comment. It helped me to move to the correct direction. I will post the answer which I found reading your comment. Commented Feb 11, 2023 at 19:29

2 Answers 2


Use usort with a custom callback, like this:

function compare_term_order_numbers( \WP_Term $a, \WP_Term $b ) : int {
    $order_number_a = get_field( 'order_number', $a );
    $order_number_b = get_field( 'order_number', $b );
    return strcmp( $order_number_a, $order_number_b );

usort($terms, 'compare_terms' );

Note that this assumes get_field returns a plain string, not an object, that each term has the order_number set and it isn't empty, and that $terms is an array of terms, not an error object or false/null.

More information at: https://www.php.net/manual/en/function.usort.php


Thanks to Tom J Nowell I found the solution. It was so simple that I felt a little shame not being able to figure it out myself.

First we need a function to 'insert' our custom taxonomy custom field to our WP Object. In this case the CPT is 'tour_category' and the Custom Field is 'order_number'

function terms()
      return array_map(function($term) {
          $term->order_number = get_field('order_number', $term);
          return $term;
        }, get_terms([
          'taxonomy' => 'tour_category',
          'orderby'=> 'order_number',
          'order' => 'DESC'

then, we use it in our loop:

$my= terms();
$num = array_column($my, 'order_number');
array_multisort($num, SORT_ASC, $my);

foreach($my as $term) { .... }   
  • I wouldn't do it this way as the $term->order_number part is going to generate warnings and possible errors on newer versions of PHP, I actually thought you'd find usort and the custom callback option. Also $term is an object, not an array so array_column might generate a PHP warning too
    – Tom J Nowell
    Commented Feb 12, 2023 at 12:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.