WordPress Logo

Convert Taxonomy Options to Term Meta

WordPress 4.4 introduced Taxonomy Term Meta. Until this version, meta had to be stored as an Option. Most tutorials would tell you to give it a prefix followed by the ‘term_id’ so you can grab the data easily later. I already had a site with lots of populated meta. What I needed was a conversion script to move meta from an Option into real Term Meta.

/**
 * Convert Taxonomy Options to Term Meta
 */
$taxonomy = 'my_taxonomy';
$option_prefix = 'taxonomy_';

$taxonomy_terms = get_terms( $taxonomy, array( 'hide_empty' => false ) );
$counter = 0;

foreach ( $taxonomy_terms as $term )
{
    $term_id = $term->term_id;
    $option = get_option( $option_prefix . $term_id );

    if ( !empty( $option ) )
    {
        $counter++;

        foreach ( $option as $meta_key => $meta_value )
        {
            delete_term_meta( $term_id, $meta_key );

            if ( !empty( $meta_value ) )
                update_term_meta( $term_id, $meta_key, $meta_value, true );
        }
    }
}

echo "Processed " . $counter . " Taxonomy Term Options";

$counter = 0;

foreach ( $taxonomy_terms as $term )
{
    $term_meta = get_term_meta( $term->term_id );

    if ( !empty( $term_meta ) )
        $counter++;
}

echo " >> [ " . $counter . " ] Taxonomy Terms now have Term Meta.";

I found a couple of interesting quirks with Term Meta while converting my site.

The first is that if you run get_term_meta( $term->term_id ) it will present you with an array of arrays. The value is stored as the first key of these sub-arrays. Where you might have had $term_meta[‘my_key’] for your option, you now need $term_meta[‘my_key’][0]. If the value returned is an array, it will need to be unserialized. This only applies if you want all Term Meta for a taxonomy. If you use get_term_meta( $term->term_id, ‘my_key’, true ) it will automatically perform both these tasks to return a single meta key.

Another difference shows itself when saving values. An Option will overwrite the value (array) in most cases. However the update function for Term Meta will only update individual meta keys. You need to iterate through and store them individually. However this is no bueno when using checkboxes. If the checkbox is unchecked, it will not be present in the postdata. Below is my generic save function for Term Meta, it will delete a value if it was stored previously but is no longer available.

/**
 * Save Term Meta
 */
add_action( 'create_my_taxonomy', 'tsg_save_term_meta', 10, 2 );
add_action( 'edited_my_taxonomy', 'tsg_save_term_meta', 10, 2 );

function tsg_save_term_meta( $term_id )
{
    $term_meta = $_POST['term_meta'];

    if ( !empty( $term_meta ) )
    {
        $term_meta_old = get_term_meta( $term_id );
        foreach ( $term_meta_old as $meta_key => $meta_value )
            if ( !array_key_exists( $meta_key, $term_meta ) )
                delete_term_meta( $term_id, $meta_key );

        foreach ( $term_meta as $meta_key => $meta_value )
            update_term_meta( $term_id, $meta_key, $meta_value );
    }
}

When you’re all finished converting and everything is sweet. You’ll probably want to clean up your options table. Use this function at your own risk.

/**
 * Delete All Taxonomy Term Options - USE AT YOUR OWN RISK
 */
global $wpdb;

$wpdb->query( $wpdb->prepare("
        DELETE FROM " . $wpdb->prefix . "options
        WHERE option_name LIKE %s
    ",
    array( 'taxonomy\_%' )
));