Skip to content

Instantly share code, notes, and snippets.

@mboynes
Last active December 7, 2015 19:57
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mboynes/7b8818936b06145ac68b to your computer and use it in GitHub Desktop.
Save mboynes/7b8818936b06145ac68b to your computer and use it in GitHub Desktop.
Term split update examples

Preparing Plugins for Term Splitting

Historically, two terms in different taxonomies with the same slug (for instance, a tag and a category sharing the slug "news") have shared a single term ID. Beginning in WordPress 4.2, when one of these shared terms is updated, it will be split: the updated term will be assigned a new term ID.

In the vast majority of situations, this update will be seamless and uneventful. However, some plugins and themes store term IDs in options, post meta, user meta, or elsewhere. WP 4.2 will include two different tools to help authors of these plugins and themes with the transition.

The 'split_shared_term' action

When a shared term is assigned a new term ID, a new 'split_shared_term' action is fired. Plugins and themes that store term IDs should hook to this action to perform necessary migrations. The documentation for the hook is as follows:

/**
 * Fires after a previously shared taxonomy term is split into two separate terms.
 *
 * @since 4.2.0
 *
 * @param int    $term_id          ID of the formerly shared term.
 * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
 * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
 * @param string $taxonomy         Taxonomy for the split term.
 */

Here are a few examples of how plugin and theme authors can leverage this action to ensure that stored term IDs are updated.

  1. Updating a term ID stored in an option Let's say your plugin stores an option called 'featured_tags' that contains an array of term IDs (update_option( 'featured_tags', array( 4, 6, 10 ) )). In this example, we'll hook to 'split_shared_term', check whether the updated term ID is in the array, and update if necessary.

    /**
     * Update featured tags when a term gets split.
     * 
     * @param int    $term_id          ID of the formerly shared term.
     * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
     * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
     * @param string $taxonomy         Taxonomy for the split term.
     */
    function my_featured_tags_split_shared_term( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
    	// We only care about tags, so we'll first verify that the term is a tag.
    	if ( 'post_tag' == $taxonomy ) {
    		// Get the current featured tags.
    		$featured_tags = get_option( 'featured_tags' );
    
    		// If the updated term is in the array, note the array key.
    		$found_term = array_search( $term_id, $featured_tags );
    		if ( false !== $found_term ) {
    			// The updated term is a featured tag! Replace it in the array, and resave. 
    			$featured_tags[ $found_term ] = $new_term_id;
    			update_option( 'featured_tags', $featured_tags );
    		}
    	}
    }
    add_action( 'split_shared_term', 'my_featured_tags_split_shared_term', 10, 4 );
  2. Updating a term ID stored in post meta Sometimes a plugin might store term ids in post meta. In this case, we'll use a get_posts() query to locate posts with the meta key "primary_category" and a meta value matching the split term ID. Once we've identified the posts, we'll use update_post_meta() to change the values.

    /**
     * Check primary categories when a term gets split to see if any of them
     * need to be updated.
     *
     * @param int    $term_id          ID of the formerly shared term.
     * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
     * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
     * @param string $taxonomy         Taxonomy for the split term.
     */
    function my_primary_category_split_shared_term( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
    	// Ignore all updates except those to categories
    	if ( 'category' == $taxonomy ) {
    		// Find all the posts where the primary category matches the old term ID.
    		$post_ids = get_posts( array(
    			'fields'     => 'ids',
    			'meta_key'   => 'primary_category',
    			'meta_value' => $term_id,
    		) );
    
    		// If we found posts, update the term ID stored in post meta.
    		if ( $post_ids ) {
    			foreach ( $post_ids as $post_id ) {
    				update_post_meta( $post_id, 'primary_category', $new_term_id, $term_id );
    			}
    		}
    	}
    }
    add_action( 'split_shared_term', 'my_primary_category_split_shared_term', 10, 4 );

The wp_get_split_terms() function

'split_shared_term' is the preferred method for processing term ID changes. However, there may be cases - such as a delayed plugin update - where terms are split, without your plugin getting a chance to hook to the 'split_shared_term' action. WP 4.2 stores information about taxonomy terms that have been split, and provides the wp_get_split_terms() utility function to retrieve this information.

Consider the case above, where your plugin stores term IDs in an option called 'featured_tags'. You may want to build a function that validates these tag IDs (perhaps to be run on plugin update), to be sure that none of the featured tags has been split:

    ```php
function my_featured_tags_check_for_split_terms() {
	$featured_tag_ids = get_option( 'featured_tags', array() );

	// Check to see whether any IDs correspond to post_tag terms that have been split.
	foreach ( $featured_tag_ids as $index => $featured_tag_id ) {
		$split_terms = wp_get_split_terms( $featured_tag_id, 'post_tag' );

		if ( ! empty( $split_terms ) ) {
			foreach ( $split_terms as $split_term ) {
				// Replace the old ID with the new one.
				$featured_tag_ids[ $index ] = $split_term['new_term_id'];
			}
		}
	}

	// Resave.
	update_option( 'featured_tags', $featured_tag_ids );
}
```
@nacin
Copy link

nacin commented Jan 7, 2015

Could be worth explaining a bit more what a shared term is, perhaps with a before/after example, too. I don't think the first sentence is enough for someone who isn't familiar with this. It is very possible that the person who did this in their plugin has no idea whatsoever that WP ever shares term IDs.

Also, would be worth noting that they can add this code to their plugin now*, and it'll kick in when split_shared_term goes into effect.

  • But obviously only once we decide to go for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment