Can I add a Category Metabox to attachment?

I am using register_taxonomy_for_object_type() to add the Category taxonomy field to Media uploads (attachments). I’m using this code to do so:

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

This works and adds a simple text field for Category to the Media page when viewing an image. What I really want is to make it display the actual Categories Metabox so that I can choose the Categories I want to use rather than just type them into the plain field. I’ve also found that putting the slug for a category into this text field such as my-category-name ends up displaying as the actual category name like My Category Name when it’s saved, which makes the simple text field even less of a useful option.

Read More

I’ve been looking at the add_post_type_support() function for adding Metaboxes and have seen it used for Custom Post Types, I just can’t see if it’s possible to add the same for attachments.

Related posts

Leave a Reply

5 comments

  1. 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.

  2. 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.

  3. This is difficult/complicated if you want to use WordPress’ default category box. For one thing, the metabox doesn’t return the output, it just echoes it. On top of that, it wouldn’t give you the correct input field name, so it wouldn’t save. One idea might be to use a jQuery UI Autocomplete to replicate the tags box’s functionality.

    However, if you want to play around with the media editor’s fields, you can hook into 'attachment_fields_to_edit' and edit the array of fields. The filter passes two arguments to the callback: first argument is the array of fields, second is the attachment post object. See here for more details:

    http://phpxref.ftwr.co.uk/wordpress/nav.html?wp-admin/includes/media.php.source.html#l1025

  4. I’ve created a plugin using @RickCurran’s WOS Media Categories as a starting point. However, WOS Media Categories, like other plugins that add category support to media, doesnt actually add a metabox, I’ve done just that.

    overall view

    Its necessarily simplified form the metaboxes on posts and pages, but I did include a filtering ability that makes it easy to use.

    filterable categories

    I am actually generating the entire category metabox that you see on pages and posts, but hiding the bits that dont work on the media page because of both a lack of styling and the missing javascript.

    I welcome any thoughts anyone might have as to how to make the metabox fully functional – something I intend to do in a later version.

  5. Great plugin Rick – very helpful.

    If you move the onclick trigger inline instead of binding it to onload (and make a few other minor tweaks), it’ll work on the Flash bulk uploader as well. With the current version the Flash loads after the jQuery load event so the objects don’t exist yet.

    revised js:

     function wos_category_click(cat){
        var container = jQuery(cat).closest("tbody");
        var cat_checked = jQuery(container).find("tr.all_categories input:checked");
        var cat_arr = jQuery(cat_checked).map(function() {
            return jQuery(this).val();
        }).get().join();
        jQuery(container).find("tr.category > td.field > input.text").val(cat_arr);
    }
    

    add onclick to input in php file:

    <input type="checkbox" onclick="wos_category_click(this)" class="wos-categories-cb"....
    

    add bulk uploader form id to css file:

    form#media-single-form tr.category,form#file-form tr.category {
    display:none; 
    

    }