Tuesday, March 29, 2016

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.

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 to false and means that if another key has the same name the function it will override it. Set this to true 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:

    wp term meta banner

    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!


    Source: Introduction to WordPress Term Meta and WP_Term

    No comments:

    Post a Comment