Wordpress - Can I add a Category Metabox to attachment?

Edit: 12/09/2017 See this answer for a more up to date solution to this: How to use taxonomies on attachments with the new Media Library?

I'm going to answer my own question here as I have managed to figure out a solution to what I've been trying to do. I came to the conclusion that it wasn't possible to get the Category Metabox enabled for attachments. However, I found that it was easy enough to get a basic field for Categories added to the attachments page by using register_taxonomy_for_object_type and add_post_type_support:

add_action('admin_init', 'reg_tax');
function reg_tax() {
   register_taxonomy_for_object_type('category', 'attachment');
   add_post_type_support('attachment', 'category');
}

The field added showed like this:

alt text

It's just a plain text field but what I found was that you could type the name of an existing category in there and it would then be successfully saved when the attachment was updated (The only odd behaviour is that it rendered back the normal version instead of the slug after saving).

Once I realised that I could save categories this way then I figured that I could get a list of all available categories as checkboxes and check the ones that had been selected. I then used a bit of jQuery to grab the values of checked categories and put all the categories' slugs into the Category field. To make this seem even more seamless I then used a simple bit of CSS to hide the table row that contained the Category field, so all you ever see are the checkboxes, like so:

alt text

Now that I can add categories to image attachments I can use something like:

get_posts('post_type=attachment&category_name=timber-fixed-windows')

And pull the categorised images into a page! Exactly what I was hoping to do, I didn't think there was going to be a way to do it but glad I managed to figure something out.

I've turned this into a plugin called WOS Media Categories which I have made available to download from my website, Suburbia.org.uk, I hope it may be of use to somebody else! Thanks again to those who commented on this and other questions I've asked here which helped figure it out!

Update: I've added a fix to enable categories to be added whilst images are uploaded using the Flash bulk uploader.


just created this, which is a complete workaround to the herky-jerk javascript linkage to the form field. Since the values of your checkboxes are passed along with the $_POST on submit, you can just grab them during the add_image_attachment_fields_to_save filter and set the post object's terms.

function register_custom_taxonomies() {
    $labels = array(
        'name' => _x( 'Image Formats', 'taxonomy general name' ),
        'singular_name' => _x( 'Image Format', 'taxonomy singular name' ),
        'search_items' =>  __( 'Search Formats' ),
        'all_items' => __( 'All Formats' ),
        'parent_item' => __( 'Parent Format' ),
        'parent_item_colon' => __( 'Parent Format:' ),
        'edit_item' => __( 'Edit Format' ), 
        'update_item' => __( 'Update Format' ),
        'add_new_item' => __( 'Add New Format' ),
        'new_item_name' => __( 'New Format Name' ),
        'menu_name' => __( 'Image Format' )
    );
    $capabilities = array(
        'manage_terms' => 'nobody',
        'edit_terms' => 'nobody',
        'delete_terms' => 'nobody'
    );
    $args = array(
        'public' => false,
        'hierarchical' => true,
        'labels' => $labels,
        'capabilities' => $capabilities,
        'show_ui' => false,
        'query_var' => 'image-format',
        'rewrite' => false
    );
    register_taxonomy('image-format', array('attachment'), $args);
}
add_action( 'init', 'register_custom_taxonomies', 1);

function add_media_categories($fields, $post) {
    $categories = get_categories(array('taxonomy' => 'image-format', 'hide_empty' => 0));
    $post_categories = wp_get_object_terms($post->ID, 'image-format', array('fields' => 'ids'));
    $all_cats .= '<ul id="media-categories-list" style="width:500px;">'; 
    foreach ($categories as $category) {
        if (in_array($category->term_id, $post_categories)) {
            $checked = ' checked="checked"';
        } else {
            $checked = '';  
        }
        $option = '<li style="width:240px;float:left;"><input type="checkbox" value="'.$category->category_nicename.'" id="'.$post->ID.'-'.$category->category_nicename.'" name="'.$post->ID.'-'.$category->category_nicename.'"'.$checked.'> ';
        $option .= '<label for="'.$post->ID.'-'.$category->category_nicename.'">'.$category->cat_name.'</label>';
        $option .= '</li>';
        $all_cats .= $option;
    }
    $all_cats .= '</ul>';

    $categories = array('all_categories' => array (
            'label' => __('Image Formats'),
            'input' => 'html',
            'html' => $all_cats
    ));
    return array_merge($fields, $categories);
}
add_filter('attachment_fields_to_edit', 'add_media_categories', null, 2);

function add_image_attachment_fields_to_save($post, $attachment) {
    $categories = get_categories(array('taxonomy' => 'image-format', 'hide_empty' => 0));
    $terms = array();
    foreach($categories as $category) {
        if (isset($_POST[$post['ID'].'-'.$category->category_nicename])) {
            $terms[] = $_POST[$post['ID'].'-'.$category->category_nicename];        
        }
    }
    wp_set_object_terms( $post['ID'], $terms, 'image-format' );
    return $post;
}
add_filter('attachment_fields_to_save', 'add_image_attachment_fields_to_save', null , 2);

(note that I am using a custom taxonomy, and not categories, so you'll have to change the $categories array to match the same array as you use when you set up your checkboxes)

Shabam, shabozzle. Enjoy.