How to order by post meta name in wp admin?

I am trying to order by post meta name which I added for post. Post meta is “_merchant_id” an I know how to sort by merchan_id but I don’t know how to sort by merchant name.

I am sorting by merchant id like this:

Read More
public function column_orderby( $vars ) {
        if ( isset( $vars['orderby'] ) && is_admin() ) {
            switch ( $vars['orderby'] ) {
case 'merchant':
 $vars = array_merge( $vars, array(
     'meta_key' => '_merchant_id',
     'orderby' => 'meta_value_num'
 ) );

break;
...

Merchant is another post type (“merchant”). How can I sort by merchant name?

UPDATE (improved explanation by screenshot):

enter image description here

Related posts

Leave a Reply

3 comments

  1. I assume merchant name is another meta field and not the title for that post type? If so, here is a way to organize your admin edit.php area

    // Add a column in admin edit.php to display the Merchant post type data you want shown
    add_filter('manage_merchant_posts_columns', 'admin_merchant_columns');
    function admin_merchant_columns( $posts_columns ) {
        $posts_columns = array(
            'cb' => '<input type="checkbox" />', // the checkbox to select the line item
            'title' => __( 'Name' ), // post title
            'merchant_name' => __( 'Merchant Name' ), // where merchant_name is your meta key for that field
            '_merchant_id' => __( 'Merchant ID' ) // merchant id meta key
        );
    
        return $posts_columns;
    }
    
    // Fill the column with the appropriate items
    add_action( 'manage_merchant_posts_custom_column', 'manage_merchant_columns', 10, 2 );
    function manage_merchant_columns( $column, $post_id ) {
        global $post;
        switch( $column ) {
            case 'merchant_name' :
                $merchant_name = get_post_meta( $post_id, 'merchant_name'); 
                if ( empty( $merchant_name ) )
                    echo ( '' );
                else
                    print join( $merchant_name, ', ' );
    
                break;
            case '_merchant_id' :
                $_merchant_id = get_post_meta( $post_id, '_merchant_id'); 
                if ( empty( $_merchant_id ) )
                    echo ( '' );
                else
                    print join( $_merchant_id, ', ' );
    
                break;
    
            default :
                break;
        }
    }
    
    // add ability to sort by merchant name
    add_filter( 'manage_edit-merchant_sortable_columns', 'sort_by_merchant_name' );
    function sort_by_merchant_name( $columns ) {
        $columns['merchant_name'] = 'merchant_name';
        return $columns;
    }
    
    add_action( 'load-edit.php', 'sort_by_merchant_name_load' );
    function sort_by_merchant_name_load() {
        add_filter( 'request', 'sort_merchant' ); // where "merchant" is your custom post type slug
    }
    
    function sort_merchants( $vars ) {
        if ( isset( $vars['post_type'] ) && 'merchant' == $vars['post_type'] ) { // where "merchant" is your custom post type slug
            if ( isset( $vars['orderby'] ) && 'merchant_name' == $vars['orderby'] ) {
                $vars = array_merge(
                    $vars,
                    array(
                        'meta_key' => 'merchant_name',
                        'orderby' => 'meta_value'
                    )
                );
            }
        }
        return $vars;
    }
    
  2. The meta values and names are not useable in admin area on default.

    But you can enahnce the query to use it in the loop, the query like the example in your question. To add the meta values use the follow small snippet in plugin.

    add_filter( 'query_vars', 'fb_query_vars_admin' );
    /**
     * If needed: Allow meta queries in the admin
     */
    function fb_query_vars_admin( $query_vars ) {
    
        // break off, if not in admin area
        if ( ! is_admin() )
            return $query_vars;
    
        $query_vars[] = 'meta_key'; // my key of custom field
        $query_vars[] = 'meta_value'; // my value of custom field
    
        return $query_vars;
    }
    

    A other alternative is to hook in the query and change the query directly.

    add_filter( 'parse_query', 'fb_custom_post_sort' );
    function fb_custom_post_sort($query) {
    
        if ( ! is_admin() )
            return $query;
    
        global $current_screen;
        if ( isset( $current_screen ) && 'post' === $current_screen->post_type ) {
            $query->query_vars['orderby']  = 'meta_value';
            $query->query_vars['meta_key'] = '_merchant_id';
            $query->query_vars['order']    = 'ASC';
        }
    }
    
  3. I hope that my solution will be useful to somebody.

     public function column_orderby( $vars ) {
    
    
            if ( isset( $vars['orderby'] ) && is_admin() ) {
                switch ( $vars['orderby'] ) {
    
                ...
    
                case 'merchant':
    
    
                    GLOBAL $wpdb, $query;
    
    
                    $vars = array_merge( 
                        $vars, array(
                        'meta_key' => '_merchant_id',
                        'orderby' => 'meta_value_num'
                        ) 
                    );
    
                    add_filter('posts_clauses', 'e_order_by_mechant_name',10,2);
    
    
                    break;
    
                ...
            }
    
            return $vars;
    }
    
    
    function e_order_by_mechant_name( $clauses, $query ) {
        global $wpdb;
        if ( ! $query->is_main_query()
            || ! is_admin()
    
        ){
            return $clauses;
        }
    
        //Get sort order
        $order_dir = $query->get('order');
        $order_dir = ('asc' == $order_dir ? 'ASC' : 'DESC');
    
        //Join user table onto the postmeta table
        $clauses['join'] .= " LEFT JOIN {$wpdb->prefix}posts merchants ON {$wpdb->prefix}postmeta.meta_value = merchants.ID";
    
        //Replace orderby
        $clauses['orderby']  = " merchants.post_title $order_dir";
    
        return $clauses;
    }