2

I have a weight class category, where I want to sort by weight so Heavyweight shows at the top, and Flyweight at the bottom. I have created a custom meta field called 'weight' where I store an int corresponding to the weight for the respective weight class.

Here is the code where I setup the custom tax:

register_taxonomy( 'weight-class', 'ratings',
    array(
        'labels' => array(
            'name'          =>  'Weight Class',
            'singular_name' =>  'Weight Class',
            'menu_name'     =>  'Weight Classes',
            'all_items'     =>  'All Weight Classes',
            'add_new'       =>  'Add A Weight Class',
            'add_new_item'  =>  'Add New Weight Class',
            'edit_item'     =>  'Edit Weight Class',
            'view_item'     =>  'View Weight Class',
            'view_items'    =>  'View Weight Classes'
        ),
        'hierarchical' => true,
        'show_admin_column' => true
    )
);

Here is the code where I setup the custom meta data to be created and updated:

function cb_add_term_fields( $taxonomy ) {
    echo '<div class="form-field">
        <label for="weight">Maximum Weight (LBS)</label>
        <input type="text" name="weight" id="weight" />
        <p>Must be a number. Used for sorting purposes only.</p>
    </div>';
} 
add_action( 'weight-class_add_form_fields', 'cb_add_term_fields' );

function cb_edit_term_fields( $term, $taxonomy ) {
    $value = get_term_meta( $term->term_id, 'weight', true );
    echo '<tr class="form-field">
        <th>
            <label for="weight">Maximum Weight (LBS)</label>
        </th>
        <td>
            <input name="weight" id="weight" type="text" value="'.esc_attr($value).'" />
            <p class="description">Must be a number. Used for sorting purposes only.</p>
        </td>
    </tr>';
}
add_action( 'weight-class_edit_form_fields', 'cb_edit_term_fields', 10, 2 );

function cb_save_term_fields( $term_id ) {
    update_term_meta(
      $term_id,
      'weight',
      sanitize_text_field( $_POST[ 'weight' ] )
    );
  }
  add_action( 'created_weight-class', 'cb_save_term_fields' );
  add_action( 'edited_weight-class', 'cb_save_term_fields' );

Here is the code where I setup Weight as a custom sortable column:

add_filter('manage_edit-weight-class_columns', 'add_weight_column' );
function add_weight_column( $columns ){
    $columns['weight'] = __( 'Weight' );
    return $columns;
}

add_filter( 'manage_edit-weight-class_sortable_columns', 'add_weight_column_sortable' );
function add_weight_column_sortable( $sortable ){
    $sortable[ 'weight' ] = 'weight';
    return $sortable;
}

add_filter('manage_weight-class_custom_column', 'add_weight_column_content', 10, 3 );
function add_weight_column_content( $content, $column_name, $term_id ){

    if( $column_name !== 'weight' ){
        return $content;
    }

    $term_id = absint( $term_id );
    $weight = get_term_meta( $term_id, 'weight', true );

    if( !empty( $weight ) ){
        $content .= esc_attr( $weight );
    }

    return $content;
}


add_action( 'pre_get_posts', 'weight_column_orderby' );  
function weight_column_orderby( $query ) {  
    echo "<script>console.log('" . $query->get( 'orderby' ) . "');</script>";
    if( ! is_admin() )  
        return;  

    $orderby = $query->get( 'orderby' );  

    if( 'weight' == $orderby ) {  
        $query->set('meta_key','weight');  
        $query->set('orderby','meta_value_num');
    }  
} 

Everything works great until I went to test the sort function on my taxonomy. My problem currently resides with this piece of code:

add_action( 'pre_get_posts', 'weight_column_orderby' );  
function weight_column_orderby( $query ) {  
    echo "<script>console.log('" . $query->get( 'orderby' ) . "');</script>";
    if( ! is_admin() )  
        return;  

    $orderby = $query->get( 'orderby' );  

    if( 'weight' == $orderby ) {  
        $query->set('meta_key','weight');  
        $query->set('orderby','meta_value_num');
    }  
} 

As you can see, I am using a quick script tag to print out the value of orderby in the query. No matter what column I click to sort on the taxonomy list page, the script tag above always returns "menu_order title". I click on slug or description and still get this. Is there a setting I missed somewhere? Any help would be appreciated! Thanks!

1
  • I hope I correctly understood what you're trying to do, and note that when saving the meta value, you should at least check that $_POST['weight'] is set before trying to read its value.
    – Sally CJ
    Feb 11 at 16:05

1 Answer 1

2

pre_get_posts is an action hook used for modifying the arguments passed to the WP_Query class, and if you're filtering the posts in the list table at wp-admin/edit.php, then yes, you would use that hook.

However, since you're filtering the terms in the list table at wp-admin/edit-tags.php, then the hook that you should have used is pre_get_terms, which can be used to modify the arguments passed to the WP_Term_Query class.

  • That class is used by get_terms() which is used by the class which renders the terms list table.

But then, I don't know for sure why ( maybe it's a bug in WordPress core? 🤔 ), but when sorting by meta value, i.e. when orderby is meta_value_num, meta_value, or a key in a meta_query array, it seems we need to use the parse_term_query hook instead, which runs before pre_get_terms.

And here's an example you can try, and note that unlike WP_Query, WP_Term_Query doesn't have a get() or set() method, hence I directly accessed/modified the query_vars property:

add_action( 'parse_term_query', 'weight_column_orderby' );
function weight_column_orderby( WP_Term_Query $query ) {
    // Check whether we are at wp-admin/edit-tags.php?taxonomy=weight-class
    if ( ! is_admin() ||
        ! function_exists( 'get_current_screen' ) ||
        'edit-weight-class' !== get_current_screen()->id
    ) {
        return;
    }

    $taxonomies = (array) $query->query_vars['taxonomy'];

    // Modify the args, if `weight` is the `orderby` value, and that the query
    // is for your custom `weight-class` taxonomy.
    if ( 'weight' === $query->query_vars['orderby'] &&
        in_array( 'weight-class', $taxonomies, true )
    ) {
        $query->query_vars['meta_key'] = 'weight';
        $query->query_vars['orderby']  = 'meta_value_num';
    }
}
1
  • 1
    Thank you! plugged in the 'parse_term_query' code you wrote, and it worked like a charm. Well done!
    – Mac Cooper
    Feb 14 at 18:50

Your Answer

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

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