Add Metadata to Categories – WordPress

If you’re reading this chances are you have the same problem I had.

How do I add custom metadata to a category?

I needed to add a simple dropdown to categories in order to set them as featured. Then I wanted to use this featured field to show them in the home page in a specific location.

Well, after a lot of reading I didn’t find any blog post or tutorial that was clean. I’ve found plugins and big chunks of code, unbearable.

I’ll do my best to explain you the main functions you need to achieve this:

Custom Metadata Category WordPress

Plugin or functions.php?

First of all you need to decide if you want to create a plugin or add this code to your functions.php file. For my project I decided to use the functions.php since it’s a custom code specific for this project, unlikely to be reused in the same way.

How to use the bits of code below?

I’ll explain part by part but you can copy them all and paste them in order inside your functions.php file, I’ll probably work (at the time of the writing we had WordPress 3.8).

Add your new field to the Edit form

We’ll add a new TR with our dropdown. Pay special attention to the select name and id, which is called: term_meta[featured] (our new metadata field is featured).

<?php
function xg_edit_featured_category_field( $term ){
    $term_id = $term->term_id;
    $term_meta = get_option( "taxonomy_$term_id" );        
?>
    <tr class="form-field">
        <th scope="row">
            <label for="term_meta[featured]"><?php echo _e('Home Featured') ?></label>
            <td>
                <select name="term_meta[featured]" id="term_meta[featured]">
                    <option value="0" <?=($term_meta['featured'] == 0) ? 'selected': ''?>><?php echo _e('No'); ?></option>
                    <option value="1" <?=($term_meta['featured'] == 1) ? 'selected': ''?>><?php echo _e('Yes'); ?></option>
                </select>                  
            </td>
        </th>
    </tr>
<?php
}

So the code above does nothing on it’s own, we need to use add_action to hook it up:

 // Add the dropdown to the Edit form
     
 add_action( 'category_edit_form_fields', 'xg_edit_featured_category_field' );

Right now, if you Edit a category you’ll see something like this:

Edit Category Custom Metadata WordPress

Save the metadata

So basically now we have a form which doesn’t get stored in the database. Not very useful, right?

We need to tell WordPress to save this custom metadata on the save action, if he finds it:

 // Save the field
   
  function xg_save_tax_meta( $term_id ){
 
        if ( isset( $_POST['term_meta'] ) ) {
             
            $term_meta = array();

            // Be careful with the intval here. If it's text you could use sanitize_text_field()
            $term_meta['featured'] = isset ( $_POST['term_meta']['featured'] ) ? intval( $_POST['term_meta']['featured'] ) : '';
   
            // Save the option array.
            update_option( "taxonomy_$term_id", $term_meta );
     
        }
    } // save_tax_meta
   
add_action( 'edited_category', 'xg_save_tax_meta', 10, 2 );

With this, the Edit category process works.

What about the Create Category Form?

You can also add the field to the create form. However the HTML wrappers are not the same: for the edit form you wrap the fields on a TR but in the create form you need a DIV.

Because I didn’t want to duplicate my HTML field I just didn’t add it to the create form. In case you want to do it, here’s how:

// Add the dropdown to the Create form

add_action( 'category_add_form_fields', 'xg_edit_featured_category_field' );
add_action( 'create_category', 'xg_save_tax_meta', 10, 2 );

Custom Columns for the Category list

This final step is optional, perhaps you don’t need it. However, I think it’s nice to present this new field in the category list (like in the first screenshot at the top).

How do we do that?

First of all add the column header:

// Add column to Category list
   
    function xg_featured_category_columns($columns)
    {
        return array_merge($columns,
                  array('featured' =>  __('Home Featured')));
    }
   
    add_filter('manage_edit-category_columns' , 'xg_featured_category_columns');

This code just ouputs the Home Featured column, with no values in it.

With the following snippet we’ll retrieve the metadata from the database:

// Add the value to the column

function xg_featured_category_columns_values( $deprecated, $column_name, $term_id) {

    if($column_name === 'featured'){
       
        $term_meta = get_option( "taxonomy_$term_id" );
       
        if($term_meta['featured'] === 1){
           
            echo _e('Yes');
        }else{
            echo _e('No');
        }  
    }
}

add_action( 'manage_category_custom_column' , 'xg_featured_category_columns_values', 10, 3 );

That’s it. I hope I explained myself, make sure to check the WordPress Codex if you have any issue with the functions.

4 Responses to “Add Metadata to Categories – WordPress”

  1. Jared July 24, 2014 at 9:35 am #

    Awesome post man, your my hero!!!

    I just have one question, how do I retrieve the data on the front-end?

    Thanks again!

    • Rick July 24, 2014 at 9:45 am #

      Hi Jared,

      Use the get_option function. Here’s a snippet following my post example:

      $post_categories = get_the_category(get_the_ID());
                     
      // You might have more than one
      // I'll get the first for the sake of the example
      $term = get_option( "taxonomy_" . $post_categories[0]->term_id );

      print_r($term['featured']);

      Useful links:

      http://codex.wordpress.org/Function_Reference/get_the_category
      http://codex.wordpress.org/Function_Reference/get_option

      Cheers,

      Rick

      • Jared July 24, 2014 at 9:49 am #

        Thanks again Rick, I just stumbled across “get_option”, when looking in the database for the new meta :)

        Your a legend – appreciate the help!

      • Rick July 24, 2014 at 9:50 am #

        You’re welcome Jared!

Leave a Reply

Add <code> Some Code </code> by using this tags.