sortable custom column in media library

trying to make a custom column sortable in the media library. Found lots of examples for posts, and users but can’t get them to work on the media library page.

function wpse_hook_isv_columns() {
    add_action('manage_media_custom_column', 'isv_custom_media_column_content',10,2);
    add_filter('manage_media_columns', 'isv_custom_media_column_headings');
    add_filter('manage_media_imwidth_sortable_columns', 'imwidth_column_register_sortable' );
}
add_action( 'admin_init', 'wpse_hook_isv_columns' );


function isv_custom_media_column_headings($defaults) {
   $defaults['isv_width'] = __( 'Width', 'imwidth' );
   $defaults['isv_height']    = 'Height';
   return $defaults;
}

function isv_custom_media_column_content($column_name,$id) {
   $meta = wp_get_attachment_metadata($id);
   switch ($column_name) {         
      case 'isv_width':
         $imWidth = get_post_meta($id, "_im_width", true);
         if(  $imWidth ) : 

            echo $imWidth .' ('.$meta['width'].')';
         else : //  add meta value if not there...

            update_post_meta($id, '_im_width', $meta['width']);
            echo $meta['width'].' (updated)';
         endif;          
         break;

      case 'isv_height':
         $desc = get_the_content();
         echo $meta['height'] ? $meta['height'] : $none;
         break;
   }
}

// Register the column as sortable ???
function imwidth_column_register_sortable( $columns ) {
    $custom = array(
          // meta column id => sortby value used in query
          'imwidth'    => 'Width',
    );
    return wp_parse_args($custom, $columns);
}

// This example i found works!

function registerdate($columns) {
    $columns['registerdate'] = __('Registered', 'registerdate');
    return $columns;
}
add_filter('manage_users_columns', 'registerdate');

function registerdate_columns( $value, $column_name, $user_id ) {
    if ( 'registerdate' != $column_name )
       return $value;
    $user = get_userdata( $user_id );
    $registerdate = $user->user_registered;
    return $registerdate;
}
add_action('manage_users_custom_column',  'registerdate_columns', 10, 3);

function registerdate_column_sortable($columns) {
      $custom = array(
      // meta column id => sortby value used in query
      'registerdate'    => 'registered',
      );
  return wp_parse_args($custom, $columns);
}
add_filter( 'manage_users_sortable_columns', 'registerdate_column_sortable' );

how can i make isv_width sortable? Any help appreciated!

Related posts

Leave a Reply

3 comments

  1. You cannot do a sort on the attachment meta data specifically because it’s stored in a serialized string.

    Whilst WP_Query can sort on meta values it can’t sort on data that’s serialized. For example wp_get_attachment_metadata fetches and unserializes that for you inside the column callback, but MySQL queries can’t sort on that type of data.

    Short answer: Not possible due to how the width and height are stored.


    Follow-up:

    Of course, if you setup the image height or width as seperate meta values you can then query on that, or should be able to at least, using a couple more hook(in addition to what you have).. manage_upload_sortable_columns and request.

    // These would go inside your admin_init hook
    add_filter( 'manage_upload_sortable_columns', 'isv_column_register_sortable' );
    add_filter( 'request', 'isv_column_orderby' );
    
    function isv_column_orderby( $vars ) {
        if ( isset( $vars['orderby'] ) && 'Width' == $vars['orderby'] ) {
            $vars = array_merge( $vars, array(
                'meta_key' => '_im_width',
                'orderby' => 'meta_value_num'
            ) );
        }
        return $vars;
    }
    function isv_column_register_sortable( $columns ) {
        $columns['isv_width'] = 'Width';
        return $columns;
    }
    

    If it helps more, Scribu gave an example of creating new sortable columns here. Note, the hook for the media listing is upload and not media for the sortable columns(because the hook is the screen id).

    I tested this alongside your code and it did work, minus the sort order being off, because i don’t have the _im_width key associated with media in my install.

    I hope that’s enough info to work from, and be sure to check the link to Scribu’s page if you want to see a more complete example of sortable columns.

  2. Full Working Code

    /*
     * Add Sortable Width and Height Columns to the Media Library
     *
     */
    
    if( is_admin() )
    {
        add_filter( 'manage_upload_columns', 'wpse_35680_size_columns_register' );
        add_action( 'manage_media_custom_column', 'wpse_35680_size_columns_display', 10, 2 );
        add_filter( 'manage_upload_sortable_columns', 'wpse_35680_size_columns_sortable' );
        add_filter( 'wp_generate_attachment_metadata', 'wpse_35680_update_imagesize_meta_data', 10, 2);
        add_action( 'pre_get_posts', 'wpse_35680_size_columns_do_sort' );
    }
    
    
    /*
     * Adding Width and Height columns
     *
     */
    
    function wpse_35680_size_columns_register( $columns ) 
    {
        $columns['_width'] = 'Width';
        $columns['_height'] = 'Height';
    
        return $columns;
    }
    
    
    /*
     * Display the columns
     *
     */
    
    function wpse_35680_size_columns_display( $column_name, $post_id ) 
    {
        if( '_width' != $column_name && '_height' != $column_name || !wp_attachment_is_image( $post_id ) )
            return;
    
        list( $url, $width, $height ) = wp_get_attachment_image_src( $post_id, 'full' );
    
        if( '_width' == $column_name )
            echo get_post_meta($post_id, '_width', true);
    
        if( '_height' == $column_name )
            echo get_post_meta($post_id, '_height', true);
    }
    
    
    /*
     * Registering columns as sortable
     *
     */
    
    function wpse_35680_size_columns_sortable( $columns ) 
    {
        $columns['_width'] = '_width';
        $columns['_height'] = '_height';
    
        return $columns;
    }
    
    
    /*
     * Save Image Attachments meta data on save
     *
     */
    
    function wpse_35680_update_image_meta_data( $image_data, $att_id ) 
    {
        $width  = $image_data['width'];
        $height = $image_data['height'];
    
        update_post_meta( $att_id, '_width', $width );
        update_post_meta( $att_id, '_height', $height );
    
        return $image_data;
    }
    
    
    /*
     * Sort the columns
     *
     */
    
    function wpse_35680_size_columns_do_sort(&$query)
    {
        global $current_screen;
        if( 'upload' != $current_screen->id )
            return;
            
        $is_width = (isset( $_GET['orderby'] ) && '_width' == $_GET['orderby']);
        $is_height = (isset( $_GET['orderby'] ) && '_height' == $_GET['orderby']);
        if( !$is_width && !$is_height )
            return;
        
        if ( '_width' == $_GET['orderby'] ) 
        {
            $query->set('meta_key', '_width');
            $query->set('orderby', 'meta_value_num');
        }
        
        if ( '_height' == $_GET['orderby'] ) 
        {
            $query->set('meta_key', '_height');
            $query->set('orderby', 'meta_value_num');
        }   
    }
    

    Workaround for Updating All Images in the Posts Table

    /*
     * Update ALL attachments metada with Width and Height
     *
     * Important: Run Only Once
     * 
     */
    //add_action('admin_init','wpse_35680_run_only_once');
    function wpse_35680_run_only_once()
    {   
        global $wpdb;
        $attachments = $wpdb->get_results( "SELECT ID FROM $wpdb->posts WHERE post_mime_type LIKE '%image%'" );
        foreach( $attachments as $att )
        {
            list( $url, $width, $height ) = wp_get_attachment_image_src( $att->ID, 'full' );
            update_post_meta( $att->ID, '_width', $width );
            update_post_meta( $att->ID, '_height', $height );
        }
    }
    

    Assembled with the invaluable input from Rarst, Bainternet, kaiser, t31os and scribu throughout this Stack

  3. First: If you’re adding stuff to hooks or filters, you should allways wrap the action calls in a separate function and hook it (in your case:) to admin_init:

    function wpse_hook_isv_columns()
    {
        add_action('manage_media_custom_column', 'isv_custom_media_column_content',10,2);
        add_filter('manage_media_columns', 'isv_custom_media_column_headings');
    }
    add_action( 'admin_init', 'wpse_hook_isv_columns' );
    // or:
    if ( is_admin() )
        add_action( 'init', 'wpse_hook_isv_columns' );
    

    Else you can’t be shure they load early enough.

    Also: Why are you calling $desc = get_the_content(); and not using it?

    You should also use a string instead of None that is sortable and sort before the number “0” or after the letter “Z”. Else it would be – in case of sorting – right in the middle of the sorting results…

    Sidenote: If you check the Codex about translation, then you’ll see all gettext functions having a second Parameter. That’s the textdomain, nothing else. So your __('Width','domain'); will probably have your themes/plugins textdomain, hm? 🙂