Bulk-update the WordPress taxonomies metadata programatically

The following code allows you to update metadata, including for SEO plugins like RankMath and Yoast. While the RankMath functionality has been tested and confirmed, the Yoast integration is unverified.

This script enables you to import data directly from a CSV file into WordPress.

Usage

  1. Backup your site
  2. Place the script file and CSV file inside your website root.
  3. Run this command from your website’s root (assuming you have wp-cli installed on your server):
    wp --require=./[you script filename].php import-taxonomy-metadata --file=./[your CSV filename].csv

The CSV file should have this structure:

post_type,taxonomy,taxonomy_name,taxonomy_seo_title,taxonomy_seo_description,taxonomy_description
work,work_post_type,portfolio,Innovative projects & branding showcase,"Explore our portfolio of bespoke web design, development, and branding projects, crafted to elevate your business’s online presence.","<p>Our <strong>Portfolio</strong> is a testament to our commitment to delivering tailor-made web solutions that drive success for small to medium-sized businesses. </p>

Script for WP-CLI

#!/usr/bin/env wp-cli
<?php
/**
 * WP-CLI script to update taxonomy metadata from a CSV file using slugs
 *
 * Usage:
 * 1. Backup your site
 * 2. place the script file (this file) and CSV file inside your website root
 * 3. Run this command (assuming you have wp-cli installed on your server):
 * wp --require=./[you script filename].php import-taxonomy-metadata --file=./[your CSV filename].csv
 *
 * CSV Columns:
 * post_type, taxonomy_slug, term_slug, taxonomy_seo_title, taxonomy_seo_description, taxonomy_description
 */
if ( ! defined( 'WP_CLI' ) ) {
    return;
}
WP_CLI::add_command( 'import-taxonomy-metadata', function( $args, $assoc_args ) {
    // Check if file path is provided
    if ( ! isset( $assoc_args['file'] ) ) {
        WP_CLI::error( 'Please provide a file using the --file parameter.' );
        return;
    }
    $file = $assoc_args['file'];
    // Check if the file exists
    if ( ! file_exists( $file ) ) {
        WP_CLI::error( "The file {$file} does not exist." );
        return;
    }
    // Open the CSV file
    if ( ( $handle = fopen( $file, 'r' ) ) !== FALSE ) {
        // Get the header row
        $headers = fgetcsv( $handle, 1000, ',' );
        // Loop through each row in the CSV
        while ( ( $data = fgetcsv( $handle, 1000, ',' ) ) !== FALSE ) { 
            // Map columns to data
            $post_type              = $data[0]; // Post type (e.g., 'post', 'product')
            $taxonomy_slug          = $data[1]; // Taxonomy slug (e.g., 'category', 'post_tag')
            $term_slug              = $data[2]; // Term slug (e.g., 'technology', 'web-design')
            
            // SEO titles for RankMath and Yoast
            $rankmath_seo_title     = $data[3] . ' %sep% %sitename%'; // RankMath uses %sep% and %sitename%
            $yoast_seo_title        = $data[3] . ' %%sep%% %%sitename%%'; // Yoast uses %%sep%% and %%sitename%% <-- this doesn't seem to work, though
            
            $taxonomy_seo_description = $data[4]; // SEO Description (same for both RankMath and Yoast)
            $taxonomy_description   = $data[5]; // Default term description
            // Get the term by its slug and taxonomy
            $term = get_term_by( 'slug', $term_slug, $taxonomy_slug );
            if ( $term ) {
                // Term exists, update its metadata and description
                wp_update_term( $term->term_id, $taxonomy_slug, [
                    'description' => $taxonomy_description
                ]);
                // Update RankMath SEO Title and Description
                update_term_meta( $term->term_id, 'rank_math_title', $rankmath_seo_title );
                update_term_meta( $term->term_id, 'rank_math_description', $taxonomy_seo_description );
                // Update Yoast SEO Title and Description
                update_term_meta( $term->term_id, '_yoast_wpseo_title', $yoast_seo_title );
                update_term_meta( $term->term_id, '_yoast_wpseo_metadesc', $taxonomy_seo_description );
                WP_CLI::success( "Updated taxonomy term '{$term_slug}' in '{$taxonomy_slug}' for post type '{$post_type}'" );
            } else {
                // If term doesn't exist, warn and skip
                WP_CLI::warning( "Taxonomy term '{$term_slug}' in '{$taxonomy_slug}' does not exist for post type '{$post_type}', skipping." );
            }
        }
        fclose( $handle );
    } else {
        WP_CLI::error( "Failed to open file {$file}" );
    }
});