← Back to notes
snippet 1 min read PHP 7.4+ WP 5.8+

How to Create a Custom WP-CLI Command in 5 Minutes

Register a small, namespaced WP-CLI command that reports and optionally deletes old draft posts.

Updated Sep 17, 2026 #wordpress #wp-cli #automation #php #snippet

WP-CLI commands are a practical way to turn repeated WordPress maintenance tasks into safe, repeatable terminal workflows. This example creates wp site cleanup-drafts, which lists draft posts older than a date and supports a --dry-run mode before deletion.

Put the file in an active plugin or an automatically loaded MU plugin. WP-CLI loads the command only when the WP_CLI constant is available.

The command

wp-cli/site-cleanup-command.php
<?php
if ( defined( 'WP_CLI' ) && WP_CLI ) {
class My_Site_Cleanup_Drafts_Command {
/**
* Remove or report old drafts.
*
* ## OPTIONS
*
* --before=<date>
* : Delete drafts published before this date, for example 2024-01-01.
*
* [--dry-run]
* : Report matching drafts without deleting them.
*
* ## EXAMPLES
*
* wp site cleanup-drafts --before=2024-01-01 --dry-run
* wp site cleanup-drafts --before=2024-01-01
*/
public function __invoke( $args, $assoc_args ) {
$before = isset( $assoc_args['before'] ) ? $assoc_args['before'] : '';
if ( ! $before || ! strtotime( $before ) ) {
WP_CLI::error( 'Pass a valid --before date, such as 2024-01-01.' );
}
$query = new WP_Query( array(
'post_type' => 'post',
'post_status' => 'draft',
'posts_per_page' => 100,
'fields' => 'ids',
'date_query' => array(
array( 'before' => gmdate( 'Y-m-d', strtotime( $before ) ) ),
),
) );
$dry_run = isset( $assoc_args['dry-run'] );
$count = 0;
foreach ( $query->posts as $post_id ) {
$title = get_the_title( $post_id );
if ( $dry_run ) {
WP_CLI::log( sprintf( '%d: %s', $post_id, $title ) );
} else {
wp_delete_post( $post_id, true );
}
$count++;
}
$message = $dry_run ? 'drafts would be removed' : 'drafts removed';
WP_CLI::success( sprintf( '%d %s.', $count, $message ) );
}
}
WP_CLI::add_command( 'site cleanup-drafts', 'My_Site_Cleanup_Drafts_Command' );
}

Run it safely

Start with the dry run:

Terminal window
wp site cleanup-drafts --before=2024-01-01 --dry-run

Review the IDs and titles. Only then run the command without --dry-run. The example caps the query at 100 records per invocation so a large cleanup does not create one unbounded request; change the query to use pagination if the site has more than 100 matching drafts.

The WP-CLI command cookbook and WP_CLI::add_command() reference cover command registration, arguments, and documentation blocks. For scheduled maintenance that runs without a terminal, see the WP-Cron cleanup snippet.