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.
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.
-
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 );
-
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 useupdate_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 );
'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_term()
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:
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 ) {
$new_term_id = wp_get_split_term( $featured_tag_id, 'post_tag' );
if ( $new_term_id ) {
$featured_tag_ids[ $index ] = $new_term_id;
}
}
// Resave.
update_option( 'featured_tags', $featured_tag_ids );
}
Note that wp_get_split_term()
takes two parameters - $old_term_id
and $taxonomy
- and returns an integer. If you need to retrieve a list of all split terms associated with an old term ID, regardless of taxonomy, use wp_get_split_terms( $old_term_id )
.
@markjaquith - Gah, apparently you don't get email notification of Gist comments. Sorry I missed this last week.
I think the Markdown is fixed now.
Regarding multiple runs:
_split_shared_term()
directly, and it's not mentioned in any of the docs. That being said, it's idempotent in the sense that it will bail if it finds that there's nothing to split, as will be the case in a previously split term. Old term IDs are not deleted, and new term IDs come fromINSERT
statements, so they'll always be incremented and minty fresh.$term_id
and$taxonomy
as necessary to determine whether action is required on each instance.wp_get_split_terms()
just fetches stuff from the db, so there's no risk of dupes there or anything.So no, I think we're good as far as multiple runs go.