It is pretty common knowledge that custom meta fields can be added to posts, pages and custom post types, but did you know that you can add custom meta fields to post tags, categories, and custom taxonomies as well? It’s actually pretty simple, though relatively undocumented. So in this quick tutorial I’m going to walk you through the process of added some custom meta fields to taxonomy. These meta fields can be used for a variety of purposes, but one of my favorites is the Taxonomy Images plugin by Michael Fields.

With WordPress 4.4, there will be a native “terms metadata” table in WordPress, so this is no longer a necessary or valid method of adding customer metadata to terms.

See here for more information: https://make.wordpress.org/core/2015/09/04/taxonomy-term-metadata-proposal/

Adding custom meta fields to a taxonomy requires three separate functions: one to add the field to the Add New page; one to add the field to the Edit Term page; and one to save the values of the custom field from both pages. This first function will add a custom field to the Add New page for the default Category taxonomy.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
// Add term page
function pippin_taxonomy_add_new_meta_field() {
	// this will add the custom meta field to the add new term page
	?>
	<div class="form-field">
		<label for="term_meta[custom_term_meta]"><?php _e( 'Example meta field', 'pippin' ); ?></label>
		<input type="text" name="term_meta[custom_term_meta]" id="term_meta[custom_term_meta]" value="">
		<p class="description"><?php _e( 'Enter a value for this field','pippin' ); ?></p>
	</div>
<?php
}
add_action( 'category_add_form_fields', 'pippin_taxonomy_add_new_meta_field', 10, 2 );

There is nothing special about this function. It’s just an HTML form that uses the same layout as the default WordPress add new term page fields. One thing to note, however, is that I have setup the name of the input to be an array. This is important for our save function. If the field name was not an array, then we’d have to save each field individually in the save function, but as an array, we can simply loop through the fields and save each one automatically.

Also take note of the add_action():

add_action( 'category_add_form_fields', 'pippin_taxonomy_add_new_meta_field', 10, 2 );

The first parameter is what determines the taxonomy that this field gets added to. It uses this format: {$taxonomy_name}_add_form_fields. So if you wanted to add the field to your “genres” taxonomy, you would use:

add_action( 'genres_add_form_fields', 'pippin_taxonomy_add_new_meta_field', 10, 2 );

You will now have a field that looks like this on the Add New term page:

The second function we need is the one that adds the HTML to our taxonomy Edit Term page. It looks very similar, though the HTML layout is a little different, and we also have to do a check to see if the meta field has any data saved already, so that we can populate the field on load.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// Edit term page
function pippin_taxonomy_edit_meta_field($term) {
 
	// put the term ID into a variable
	$t_id = $term->term_id;
 
	// retrieve the existing value(s) for this meta field. This returns an array
	$term_meta = get_option( "taxonomy_$t_id" ); ?>
	<tr class="form-field">
	<th scope="row" valign="top"><label for="term_meta[custom_term_meta]"><?php _e( 'Example meta field', 'pippin' ); ?></label></th>
		<td>
			<input type="text" name="term_meta[custom_term_meta]" id="term_meta[custom_term_meta]" value="<?php echo esc_attr( $term_meta['custom_term_meta'] ) ? esc_attr( $term_meta['custom_term_meta'] ) : ''; ?>">
			<p class="description"><?php _e( 'Enter a value for this field','pippin' ); ?></p>
		</td>
	</tr>
<?php
}
add_action( 'category_edit_form_fields', 'pippin_taxonomy_edit_meta_field', 10, 2 );

First, we have passed the $term parameter to our function. This variable will contain the database object for our term. The only information we need for our function is the term ID, so we put that into a variable to make things easy. We then use the get_option() function to retrieve the value of out term meta. Note, all term meta is stored in an array in the option named “taxonomy_{$term_id}”. So to get the value of our specific meta field, we’d use $term_meta[‘custom_term_meta’];

The results of this function will look like this:

Next is our save function. This will take the value entered in the field and store it in the taxonomy option.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Save extra taxonomy fields callback function.
function save_taxonomy_custom_meta( $term_id ) {
	if ( isset( $_POST['term_meta'] ) ) {
		$t_id = $term_id;
		$term_meta = get_option( "taxonomy_$t_id" );
		$cat_keys = array_keys( $_POST['term_meta'] );
		foreach ( $cat_keys as $key ) {
			if ( isset ( $_POST['term_meta'][$key] ) ) {
				$term_meta[$key] = $_POST['term_meta'][$key];
			}
		}
		// Save the option array.
		update_option( "taxonomy_$t_id", $term_meta );
	}
}  
add_action( 'edited_category', 'save_taxonomy_custom_meta', 10, 2 );  
add_action( 'create_category', 'save_taxonomy_custom_meta', 10, 2 );

The function takes the ID of our term as a parameter. A quick check if performed to make sure that data is being sent from our custom field, and if it is, the current value of the field is retrieved from the database. Next, each of our custom fields (remember, we can setup more than one in a single array) is looped through. In the loop, each of the field values is inserted into the $term_meta array. Once the loop is complete, the taxonomy option is updated, storing our field values in the database.

Just like with the first two functions, the save function is tied to our particular taxonomy with an add_action() hook, and, again with the genres example, if you attached your fields to a taxonomy called “genres”, then you would use these hooks:

add_action( 'edited_genres', 'save_taxonomy_custom_meta', 10, 2 );  
add_action( 'create_genres', 'save_taxonomy_custom_meta', 10, 2 );

That’s it! The process is really pretty simple.

If you’d like to see a real world example of what you can do with these kind of meta fields (I already mentioned a plugin at the top), check out the Fotos theme by my buddy AJ Clarke. He has password protected photo galleries. The password is set via a taxonomy custom field for the gallery categories. I had the pleasure of building the system for him, so I can tell you first hand how well it works. I’d highly encourage you check it out.

  1. Bruce

    Very nicely written and explained. You have a real talent for ‘workflow’ in your tutorials, as well as tying in real world examples.

    And this is a very useful bit to know too.
    Thanks!

    • Pippin

      Thank you, Bruce.

  2. Bill

    I agree with Bruce. The real world examples help tie it all together. Thanks for the tutorial.

    • Pippin

      You’re welcome.

  3. ali khan

    Nicely explained and working very well!!

  4. richieitchy

    How easy was that. What a fantastic, simply explained tutorial.

  5. job78

    Hello,

    Thank you so much for this great tutorial.

    I’d like to list my taxonomies in a page by displaying next to the taxonomy’s name the value of the metadata. In my case, I need to display an image near to every taxonomy, without installing a plugin.

    May you have an idea on how to do it ?

    • Pippin

      Would it work for you to just save the URL of the image inside of the meta field, then display it in the template?

    • job78

      In fact, I don’t know how to echo the meta field value in template.

      I’m using this function to display name of taxonomies:

      $terms = get_terms('albums');
      echo '';
      foreach ($terms as $term) {
      echo 'slug, 'albums').'">'.$term->name.'';
      }
      echo '';

      May you know how to output the value of the meta field in this function ?

    • job78

      Sorry, some of my HTML tags have been converted in the comment form. Here is the function I talked about:
      http://pastebin.com/0nHJarjQ

    • Pippin

      You will get the term meta option using this:

      $term_meta = get_option( “taxonomy_$t_id” );

      So then if your meta option is called “image”, you would echo it like this:

      echo $term_meta[‘image’];

    • job78

      That’s what I tried in fact, but it returns nothing. Here is my code.

  6. cfabrice

    Hello
    I even have a more basic problem. I used your article to add a custom meta field to a custom taxonomy (auteurs). and It works – i can see it and fill it and save things in it. But I don’t know how to display it in my site. I tried to add some code in my taxonomy archive page under the taxonomy description but with without success. It was in the line of “echo (‘custom_term_meta’);”
    Can you give some help on displaying this custom meta field ?
    it will be filled with some html text in my case.
    Thank you

    • Pippin

      First of all, you need to know the ID of the term for the term meta you want to display. Once you know that, you can do this:


      $term_meta = get_option( "taxonomy_{term_id}" );
      echo $term_meta['custom_term_meta'];

      Make sure you replace {term_id} with the ID number of your term.

  7. cfabrice

    I played with some code i found on the internet and the following did the job.
    I guess the beginning is to get the current term id !
    Thank you, Your plugins are great and I’m learning a lot from your site !

    term_id;
    $term_data = get_option("taxonomy_$t_ID");
    if (isset($term_data['custom_term_meta'])){
    echo ''.$term_data['custom_term_meta'].'';
    }
    ?>

  8. cfabrice

    I’m sorry, but every time i paste some code it gets ripped off even if I put code tags around !!!


    $term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ));
    $t_ID = $term->term_id;
    $term_data = get_option("taxonomy_$t_ID");
    if (isset($term_data['custom_term_meta'])){
    echo ''.$term_data['custom_term_meta'].'';
    }

    • Pippin

      That code will work great.

      When posting code in comments, you have to convert all > and < signs. If there are more than a couple, then use a hosted service such as http://snippi.com

    • Luke

      Hey there,

      Thanks for this amazing tutorial. I’m struggling to echo the contents of my new meta field into my theme’s index loop. What would I need to add to the above code, if anything, to make that work? (For simplicity, I’ve left the original code placed in functions.php as it was in the tutorial).

    • Pippin

      Can you show me what you have that isn’t working? It’s probably just a small thing you’re doing wrong.

    • Luke

      Here’s my functions file (should be a replica of what you have):
      http://snippi.com/s/qxkykcb

      Here’s how I’m trying to call it in my index file:
      http://snippi.com/s/kxsd28x

      I’ll essentially be calling this data in three different locations: inside the loop, outside the loop in the categories listing, and on each category page. I’m hoping to use the solution for the loop to help me figure out the other two echo’s.

      Thanks so much for taking a look at this!!!!!!!!!!

    • Pippin

      Looks like the problem is with your term ID variable names. In your index file, line 17 sets up $t_ID, but then in the next line, when setting up $term_meta, you use {term_id}, which should be $t_ID.

    • Luke

      Thanks for your reply Pippin. I changed the code to the following per your suggestion but I’m still getting nothing:

      http://snippi.com/s/ln1n1df

      One thing I’ve just thought of – would running the site locally (through MAMP) have anything to do with the issue?

    • Luke

      Hello everyone,

      I’ve (finally) figured it out. Since the custom meta I’m setting up is based on categories, you can use the following code to get the custom meta based on the category id: http://snippi.com/s/sovrs6c

      I’m no expert in PHP, so do let me know if this piece of code could use improvement. Nonetheless, it works just fine for me and I hope this is helpful to anyone attempting to call custom field data from your categories.

      Thanks for your guidance Pippin, and if you’d be so inclined as to double check my solution for any potential errors I’d greatly appreciate it. :}

    • Pippin

      Great! Sorry for not getting back to you sooner. I was at WordCamp Kansas City all weekend.

      Your solution looks just fine.

  9. Ciscoeira

    Hi, thanks for the example.
    I would like to know if it is possible to remove a field from that form like slug or description.

    • Pippin

      You could do it with CSS, but I would not do it any other way, just to ensure you don’t break other functions.

  10. aqeel

    Feeling a bit stupid here (learning this for the first time). How would I display the $term_data[‘custom_term_meta’] for the example you have shown?

    • Pippin

      Assuming you know the ID of the term, then like this:


      $term_meta = get_option( "taxonomy_{term_id}" );
      echo $term_meta['custom_term_meta'];

  11. WPexplorer

    Thanks for the back-link friend! I am actually thinking of using these as a way so users can “order” their custom taxonomies in a portfolio categories. Thoughts?

    • Pippin

      No problem! Using this to order terms in a taxonomy would definitely work. Basically every term would get a number and then the terms are displayed lowest to highest (or high to low).

  12. cfabrice

    I have another question: is there any way to specify the type of field for this custom fields ?
    I just realized that when displayed, the content of the field is not correct. the ‘ gets a slash added and the link to gets a few slash. So is there a way to have a bigger field than just one line of text ?, the top would be to have the equivalent of the content field of a post, several line with the tinyMce editor above !! but just correct html would be great already, i can always paste it inside !
    Any idea ?

    • Pippin

      The field type is simply determined by the HTML that you use when setting up the field. So to have a textarea, for example, you would do something like this:

      1
      
      <textarea name="term_meta[custom_term_meta]" id="term_meta[custom_term_meta]"><?php echo esc_attr( $term_meta['custom_term_meta'] ) ? esc_attr( $term_meta['custom_term_meta'] ) : ''; ?></textarea>

      And if you wanted that to be a rich editor, you could do this:

      1
      2
      
      <?php wp_editor($term_meta['custom_term_meta'], 'term_meta[custom_term_meta]'); ?>
      <textarea name="term_meta[custom_term_meta]" id="term_meta[custom_term_meta]"><?php echo esc_attr( $term_meta['custom_term_meta'] ) ? esc_attr( $term_meta['custom_term_meta'] ) : ''; ?></textarea>
  13. cfabrice

    Thank you !
    I changed the code from this: http://snippi.com/s/b4fshf8
    to this: http://snippi.com/s/vm2rcoz
    I get indeed a html editor in the add term and edit term pages. But the problem is that the previous text field keeps showing up under the text area and that if I enter data in the text area it is not saved. It is still the old text field that get saved.
    For example, if I enter something in the text area, nothing shows up on the page or in the simple text field when I go back to the edit term page. But if i put something in the text field, it gets displayed on the page (but wrongly: “l’éditeur” becomes “l\’éditeur”…) and when go back to the edit term page, I have my addition displayed in both the text area and the simple text field – see screeshot here: http://cl.ly/1U0Q1p0v3j0N3p0P0X3R
    I’m still using the same code as in my previous question/comment from january 23rd.
    Do you have an idea why it is like that ?
    By the way, I saw that you have a plugin that extends the variety of possible custom fields type for custom post types, it would be amazing to do the something similar for custom taxonomies… 😉
    Thank you anyway…

    • Pippin

      Hmm, okay, I will try to put together a working code sample for you. It will have to wait until tomorrow though.

    • Pippin

      Ok, I figured out what you have to do:

      1
      
      wp_editor($term_meta['custom_term_meta'], 'term_meta[custom_term_meta]', array('textarea_name' => 'term_meta[custom_term_meta]'));

      You don’t actually need to create the textarea at all. The wp_editor() function does it for you.

  14. cfabrice

    Oh yes !
    It works indeed. and the data of the custom meta field gets saved.
    The only left problem is those backslash caracters appearing for example as soon as there is an apostrophe: “pippin’s plugin” becomes “pippin\’s plugin” and the link to gets messed up: the url of “www.google.com” – http://www.goole.com becomes http://localhost/%22http://www.google.com/%22
    Furthermore, everytime I saved a modification, a backslash is added… (-> pippin\\\\\\\’s plugin !)
    Thank you anyway…

    • Pippin

      To fix the slashes, to this:

      1
      
      wp_editor(stripslashes($term_meta['custom_term_meta']), 'term_meta[custom_term_meta]', array('textarea_name' => 'term_meta[custom_term_meta]'));

      And then in the save function, use this:

      1
      
      $term_meta[$key] = addslashes($_POST['term_meta'][$key]);
  15. cfabrice

    You’re great !
    Thank you very much !
    It was saved and displayed properly in the wordpress admin but not on author the public page
    So I added this strip lashes function to the code used to display this custom meta field in my taxonomy template. And it worked…
    Hopefully it will be useful for someone (and save you some work 😉 )
    even if there most probably is a better and simpler way to code it – http://snippi.com/s/g7euqma
    Thanks again – it is great support !

    • Pippin

      Great!

  16. alpheus

    Does this support adding multiple custom fields or would I need to repaste the code multiple times and change the cb function names?

    • Pippin

      Yes, you can add as many fields as you want.

    • alpheus

      Thanks for the quick reply and thanks for writing a great article! For others that are wanting to add more than one field, this is what I did with Pippin’s original code. You only need to modify the add term and edit term code, and the save code is already good as is. Code pastie: http://pastie.org/3551248

    • Pippin

      Yep, that’s how to do it 🙂

  17. alpheus

    When deleting a term, will also delete the data (option) from the database? Basically it would be nice if it removed the data that was associated with a term when deleting a term so the database remains clean.

    • Pippin

      I believe they are deleted, yes.

  18. David

    Thanks, this was a huge help for me.

  19. clutchnyc

    This tutorial was fantastic. Thank you!

  20. jam

    Do you have any clue, why the update_option is not wordking at all? Display ing works well, but after I click Update on taxonomy term, the meta value is not inserted into database table _options.

    This is my code http://pastebin.com/PrgzxU6R

    • Pippin

      It could be related to line 33 where you are echoing the term meta. Add “exit;” after that line then save the data. If the data is getting interpreted correctly then the value of your field will be outputted.

  21. jam

    i remove the echo, nothing changes.It was left there for testing purposes, but after removing nothing changes. I have no clue how to debug it and find out where is the problem. The New version http://pastebin.com/DYHkRwWE

    • Pippin

      Ah, I see the problem. You are not defining a name for the textarea. Add this as the third parameter of your wp_editor() function:

      array('textarea_name' => 'term_meta[custom_term_meta]')
    • jam

      It did not wok even with the default example with input field.

      I changed now to this and does not work 🙁
      wp_editor($term_meta[‘custom_term_meta’], ‘term_meta[custom_term_meta]’,array(‘textarea_name’ => ‘term_meta[custom_term_meta]’));

  22. jam

    I found the probelm- Problem are in wp-aoptions table. It is not updating only on of the terms. Others updating, so need to figure out why.

    • Pippin

      Do you mean that none of the terms are updating, or just not the term meta option?

    • jam

      One term did not update its meta field. When I changed the term slug, it
      updated. May be it was related with WPML plugin and bunch of term plugins I tested before.

    • Pippin

      If you create a brand new term does it make a difference?

  23. jam

    Yes, then it works without problems. The problem I think, was related to bunch of plugins Ive tested and the Multilanguage plugin WPML. But now everything works fine. Thanks!

    • Pippin

      Great, I’m glad it works now!

  24. Ricardo Contesse

    Dear,

    Where do i put the functions? On functions.php?

    Thanks, Best.

    Ricardo Contesse

    • Pippin

      Yep, functions.php will work just fine.

  25. Jean-Pierre

    I’d like to use this to add a drop-down list for active/in-active to my custom taxonomies. I honestly have no idea where to start.

    http://pastebin.com/ceNJEz0h

    I get the feeling that I should create an array then run a loop instead of having a static select tag but I could be wrong.

    • Pippin

      What you have looks fine at first glance. Is there a particular part of it you’re not sure about?

  26. Jean-Pierre

    The form shows up in the menu’s just fine. It just isn’t saving once I define a new category or update an existing one.

    • Pippin

      If you copy my code exactly (essentially undoing the modifications you made), does it work?

    • Jean-Pierre

      It does, the only thing is that I want a dropdown list instead of a text field because there are only two possible options.

      I tried using a for loop to generate the options with an array for the option names but that didn’t work either. I’m not sure what the term_meta[custom_term_meta] means or how to use that with a $selected variable.

      $seleced = ‘selected’;
      As in if (term_meta[custom_term_meta] == ‘active’) echo $selected;

    • Pippin

      Show me just the code for the drop down.

  27. dans7919

    Pippin,

    Just wanted to say I found your tutorial very informative.

    I even have something to share. the get_{$taxonomy} filter will let you update the taxonomy object before it’s returned to other functions. Thus you don’t have to do anything special in the theme.

    add_filter( “get_$taxonomy”, “my_$taxonomy_filter”);

    my_$taxonomy_filter($term, $taxonomy) {
    $term->customMeta = get_option($taxonomy . ‘_’ . $term->term_id, ”);
    return $term;
    }

    • Pippin

      Nice! I was not aware of that function/filter. Thanks for sharing!

  28. elliottrichmond

    Sweet tutorial. I noticed that the data is saved to the options table as a large array, is there a way to either add the data to a separate table eg wp_terms_custommeta? I have a site with a large number of custom post types that all include a custom taxonomy where I what to add a twitter #hashtag and twitter user account to the custom taxonomies and there will be thousands – I would imagine that much data in a single field might become a problem?

    • Pippin

      That’s just the way that WP saves taxonomy options, though I do think a separate table for term meta would be better. There really isn’t, however, any problem with saving tons of option in the wp_options table. It’s designed to allow that.

  29. Junkfood

    Hi Pippin following your code i have created extra field for my taxonomy, you can show me how i can add image for every singol term using wp uploads functions?

    This is my function for create “peoples” taxonomy : http://pastie.org/4289333

    and this your code i have modified adding social network profile link : http://pastie.org/4289338

    You can also me explane how i can show extra field on my theme frontend ?

    • Pippin

      Sorry, your comment got marked as spam accidentally.

      Adding the upload functions is a complete tutorial on it’s own, sorry.

Comments are closed.