Skip to content

Instantly share code, notes, and snippets.

@scottnelle
Last active May 10, 2024 15:26
Show Gist options
  • Save scottnelle/949085150fbc76d4dccf061559be8a23 to your computer and use it in GitHub Desktop.
Save scottnelle/949085150fbc76d4dccf061559be8a23 to your computer and use it in GitHub Desktop.
A template WP CLI command and subcommand for iterating through batches of posts and doing something. Includes a progress bar.
<?php
/**
* WP CLI Command: commandname
*
* @package commandname
*/
WP_CLI::add_command( 'commandname', 'Commandname_CLI_Command' );
/**
* A custom CLI command main class.
*
*/
class Commandname_CLI_Command extends WP_CLI_Command {
/**
* Prevent memory leaks from growing out of control
*/
private function contain_memory_leaks() {
global $wpdb, $wp_object_cache;
$wpdb->queries = [];
if ( ! is_object( $wp_object_cache ) ) {
return;
}
$wp_object_cache->group_ops = [];
$wp_object_cache->stats = [];
$wp_object_cache->memcache_debug = [];
$wp_object_cache->cache = [];
if ( method_exists( $wp_object_cache, '__remoteset' ) ) {
$wp_object_cache->__remoteset();
}
}
// Add subcommand(s) here.
/**
* Migrate WP SEO post meta to the Yoast SEO equivalent.
*
* ## OPTIONS
*
* [--live-run]
* : Whether changes will be made to the database.
*
* ## EXAMPLES
* wp commandname migrate_seo_meta
* wp commandname migrate_seo_meta --live-run
*
* @param array $args Positional args.
* @param array $assoc_args Associative args.
*/
public function migrate_seo_meta( array $args, array $assoc_args ): void {
$live_run = $assoc_args['live-run'] ?? false;
$batch_size = 50;
$args = [
'post_type' => 'any',
'post_status' => 'any',
'posts_per_page' => $batch_size,
'offset' => 0,
];
$stats = [
'titles' => 0,
'descriptions' => 0,
'keywords' => 0,
];
if ( $live_run ) {
WP_CLI::line( 'This is a live run. Post metadata will be copied from the WP SEO plugin to the Yoast SEO plugin.' );
} else {
WP_CLI::line( 'This is a dry run. No data will be migrate. To complete a live run, use the `--live-run` flag.' );
}
// Iterate through all posts, updating post meta.
do {
// Perform the query with the args.
$query = new WP_Query( $args );
// Set up a progress bar on the first iteration.
if ( 0 === $args['offset'] ) {
$progress = \WP_CLI\Utils\make_progress_bar( 'Scanning for SEO meta to update', $query->max_num_pages );
}
// Iterate through posts making updates.
foreach ( $query->posts as $post ) {
$title = get_post_meta( $post->ID, '_meta_title', true );
$description = get_post_meta( $post->ID, '_meta_description', true );
$keywords = get_post_meta( $post->ID, '_meta_keywords', true );
if ( ! empty( $title ) ) {
$stats['titles']++;
if ( $live_run ) {
update_post_meta( $post->ID, '_yoast_wpseo_title', $title );
}
}
if ( ! empty( $description ) ) {
$stats['descriptions']++;
if ( $live_run ) {
update_post_meta( $post->ID, '_yoast_wpseo_metadesc', $description );
}
}
if ( ! empty( $keywords ) ) {
$stats['keywords']++;
if ( $live_run ) {
update_post_meta( $post->ID, '_yoast_wpseo_focuskw', $keywords );
}
}
}
// Update offset value to prepare for the next batch.
$args['offset'] += $batch_size;
$progress->tick();
sleep( 1 ); // Rest between batches.
} while ( $query->post_count === $batch_size );
// Report the results.
$progress->finish();
WP_CLI::success( "Found {$stats['titles']} titles, {$stats['descriptions']} descriptions, and {$stats['keywords']} keyword fields to migrate." );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment