Introduction to WordPress Term Meta and WP_Term
In WordPress, you can easily save metadata for your posts, pages and other custom content types, however saving metadata for use with your taxonomies used to be an overly complex process (I even wrote a previous article about it here!).
To get it all to work you would need to save your term metadata as a field inside your wp_options
table for each piece of data, meaning potentially you could have hundreds, if not thousands of extra entries if you had a decent amount of terms or just several customized taxonomies.
However, since WordPress 4.4 and beyond, terms are now objects, the same as posts, pages and custom content types. This change makes it much easier to add, remove and update your metadata.
The Backstory with Term Meta
The community has been pushing for an easy way to control term metadata since way back in WordPress 2.8. It’s been a slow process, but finally terms have been re-designed from the ground up to use a class structure. This plus a few different changes in WordPress 4.4 means that terms in a taxonomy (such as ‘tags’, ‘categories’ or custom) can now have their own meta easily assigned to them.
Metadata Manipulation the Old Way
Before WordPress 4.4 there was no clear-cut way to easily save metadata for term items, this was an inherent limitation on terms from how it was constructed. If you were extending taxonomies or terms you would have to save your data directly as a site option using update_option
. This wasn’t ideal (as it cluttered up the options table).
I’ve written about extending taxonomies before, however the basics of it was when you were ready to save your metadata you would call a function that looked somthing like this:
//saving new fields for category
function save_extra_taxonomy_fields($term_id){
$term = get_term($term_id);
$term_slug = $term->slug;
//collect category image id from posted values
$term_category_image_id = isset($_POST['category_image_id']) ? sanitize_text_field($_POST['category_image_id']) : '';
//update value and save it as an option
update_option('category_image_id_' . $term_slug, $term_category_image_id);
}
add_action('create_category','save_extra_taxonomy_fields');
In the above example we execute the function attached to the create_category
hook (that triggers when we create a new category term). This will look for our value and after sanitizing will save it as an option. While this works it’s not very pretty.
Adding, Updating and Removing Term Meta
To work with term meta you will use the add_term_meta
, update_term_meta
and delete_term_meta
functions. These functions when combined with new UI elements will let you save and update new metadata for your terms.
Adding Term Meta
Adding metadata for a term involves the add_term_meta
function. You need to specify three parameters with an optional fourth.
$term_id
– ID of the term you want to save this metadata to$meta_key
– Key name of the metadata. This is how you will reference the data$meta_value
– The data itself (remember to sanitize)$unique
(optional) – If the metadata key should be unique. By default this is set tofalse
and means that if another key has the same name the function it will override it. Set this totrue
to ensure uniqueness.
As an example imagine that for each term in our category
taxonomy we want to assign a new piece of metadata based on how many posts are assigned to this category. With WordPress 4.4 we can loop through all of the terms and save this new metadata (for use later in our theme or plugins).
function add_featured_to_categories(){
//get all terms from the category taxonomy
$taxonomy_name = 'category';
$term_args = array(
'orderby' => 'name',
'hide_empty' => false,
'fields' => 'ids'
);
$terms = get_terms($taxonomy_name, $term_args);
if($terms){
$term_key = 'term_size';
$term_value = 'empty';
$term_unique = true;
//go through all terms and set the new term meta
foreach($terms as $term_id){
$term = get_term($term_id, $taxonomy_name);
$term_count = $term->count;
//determine new meta value
if($term_count > 10){
$term_value = 'big';
}else if($term_count >= 5 && $term_count < 10){
$term_value = 'medium';
}else if($term_count >= 1 && $term_count < 5){
$term_value = 'small';
}
//save meta value
add_term_meta($term_id, $term_key, $term_value, $term_unique);
}
}
}
add_action('init', 'add_featured_to_categories');
Reading Term Meta
We can read saved term meta by using the get_term_meta
function. This function works in a similar way to the get_post_meta
function that is used to get metadata from posts. To use this function to need to specify one mandatory parameter, with an optional two parameters available.
$term_id
– The ID of the term to fetch metadata from$key
(optional) – A single specified key you want to return. If not specified then all metadata is returned.$single
(optional) – If a single value will be returned or a key or value pair. Defaults to a single value.
Let’s look at another scenario where you might find this useful.
Consider a situation in which we already have term meta saved for each of our terms in our category
taxonomy. This saved data contains the URL to an image that should be displayed when we are viewing the term. We want to display this image as a banner below our term description or title, but above our listing of posts.
//given a term, collect its saved image to be displayed
function display_term_meta_image($term_id, $term_taxonomy){
//get supplied term
$term = get_term($term_id, $term_taxonomy);
if($term){
$term_image_id = get_term_meta($term_id, 'term_image_id', true);
if($term_image_id){
//get the medium image size for display
$term_image = wp_get_attachment_image_src($term_image_id, 'medium', false);
echo '<img src="' . $term_image[0] . '" title="' . $term->name . ' image"/>';
}
}
}
Now inside our category.php
or other child theme template file, we can modify the functionality where our term data is displayed.
In my situation with Twenty Fourteen
I’m editing the category.php
file and calling our new function right after the display of the terms description info.
//get the current object (term)
$term_obj = get_queried_object();
//display meta data image for term
if(function_exists('display_term_meta_image')){
display_term_meta_image($term_obj->term_id, $term_obj->taxonomy);
}
This will display our photo right under the description like this:
Deleting Term Meta
We can remove term metadata just the same as we could for posts. When we use the delete_term_meta
function we need to supply two mandatory parameters with an option third if we require.
$term_id
– The ID of the term to work on.$meta_key
– The meta key that will be removed from the term.$meta_value
(optional) – Only delete the metadata if the value matches this value. Use this when you only want this data removed when it matches a set value.
Once again let’s look at a scenario in which you might use this. Imagine your half way through a big project and you’ve already saved several pieces of meta data to each category term. You’ve found that some of this data you no longer need so you should probably clear it so that it doesn’t clutter up your database.
//removed metadata we no longer need for each category term
function delete_old_meta_data_from_category(){
//get all category terms
$terms = get_terms('category', array('hide_empty' => false, 'fields' => 'ids'));
if($terms){
//list of allowed term keys
$allowed_term_keys = array('term_image_id', 'term_size');
//go through all category terms
foreach($terms as $term_id){
$term_meta = get_term_meta($term_id);
//go through all meta for each term
foreach($term_meta as $meta_key => $meta_value){
//if this meta key doesn't exist in our allowed term keys, delete it
if(!array_key_exists($meta_key, $allowed_term_keys)){
delete_term_meta($term_id, $meta_key);
}
}
}
}
}
add_action('init', 'delete_old_meta_data_from_category');
This function will go through and remove any additional metadata we didn’t specify in our $allowed_term_keys
variable, cutting down on wasted space in the database (useful for when we have dozens of metadata entries we no longer need).
Backwards Compatibility with WordPress 4.3 and Older
If you were really keen on moving forward with these new meta functions but wanted to cover yourself against older versions, you could create some conditional functionality to ensure it all works.
//add a piece of metadata for a term
function add_term_meta_compat($term_id, $term_key, $term_value){
if(function_exists('add_term_meta')){ //WP4.4+
add_term_meta($term_id, $term_key, $term_value, true);
}else{ //Pre WP4.4
//get term object and data
$term_object = get_term($term_id);
$term_taxonomy = $term_object->taxonomy;
//build final key to save (tax + termid + key)
$term_final_key = ($term_taxonomy . '_' . $term_id . '_' . $term_key);
//ensure key isn't longer than 64 characters (max limit)
$term_final_key = strlen($term_final_key > 64) ? substr($term_final_key, 0, 63) : $term_final_key;
//add our new option
add_option($term_final_key, $term_value);
}
}
We start by calling function_exists
to ensure that the new add_term_meta
function is defined. This will only be true for WordPress 4.4 and newer. If we have support we use the simple add_term_meta
function to assign metadata to our term.
If we don’t have support we grab the term object itself (by the passed in term ID) and from that we extract the $term_taxonomy
data and use it to build our final key value. Since we are saving into the options table we need to ensure the key is unique, we do this by adding the taxonomy name, the term ID and finally the term key into one variable. We must ensure the key isn’t greater than 64 characters long and if so trim it down. Once we’ve done all of this we can call our add_option
function to save our value.
As you can see, this gets a bit long, but you do get added flexibility to support older and newer WordPress versions.
Wrapping It All Up
Using these new meta functions should enable you to more easily extend your terms to provide unique functionality. For example, you might want to add a banner image to the top of your terms or provide metadata so you can conditionally display your terms differently (such as loading a new template file based on what term is being displayed).
With the flexibility and ease of the new term meta functions you can start implementing this in your new projects today!