Skip to content

Instantly share code, notes, and snippets.

@Micemade
Last active September 5, 2022 12:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Micemade/4c5eef5d5137d8879eb8ac4f295f62e6 to your computer and use it in GitHub Desktop.
Save Micemade/4c5eef5d5137d8879eb8ac4f295f62e6 to your computer and use it in GitHub Desktop.
WP CLI command for deleting old posts (and CPT's)
<?php
function micemade_wpcli_delete_before( $args, $assoc_args ) {
// If arguments array is empty, or if there aren't exactly 5 items, show error notice.
if ( empty( $args ) || count( $args ) !== 5 ) {
WP_CLI::error( __( 'Parameters: POST TYPE, POST STATUS, YEAR, MONTH and DAY are required (in this exact order). Please check your parameters. Command syntax is: wp delete-before <post_type> <post_status> <year> <month> <day> < --number=100 > < --date=post_date >.', 'micemade-fse-store' ) );
return;
}
$post_type = $args[0];
$post_status = $args[1];
$year = $args[2];
$month = $args[3];
$day = $args[4];
// Post types check - if entered post type doesn't exist - abort with error message.
if ( ! post_type_exists( $post_type ) ) {
WP_CLI::error(
sprintf(
// translators: %s: Post type.
__( 'There is no "%s" post type, please check the "post_type" parameter.', 'micemade-fse-store' ),
$post_type
)
);
return;
}
// Post status check - if post status argument doesn't match with any - abort with error message.
$statuses = get_available_post_statuses();
if ( ! in_array( $post_status, $statuses, true ) ) {
WP_CLI::error(
sprintf(
// translators: %s: Post status.
__( 'There is no "%s" post status, please check the "post status" parameter.', 'micemade-fse-store' ),
$post_status
)
);
}
// In case of "attachment" post type argument, set "inherit" status.
if ( 'attachment' === $post_type && 'inherit' !== $post_status ) {
WP_CLI::log(
sprintf(
// translators: %s: Post status.
__( 'Attachments can have only "inherit" post status. Argument "%s" changed to "inherit"', 'micemade-fse-store' ),
$post_status
)
);
$post_status = 'inherit';
}
// Checkdate params: month, day, year.
if ( ! checkdate( (int) $month, (int) $day, (int) $year ) ) {
WP_CLI::error(
sprintf(
// translators: %1$s: year, %2$s: month and %3s: day.
__( 'You entered a non valid date, which do not exist in Gregorian calendar. Year: %1$s, Month: %2$s, Day: %3$s. Please check the date you entered.', 'micemade-fse-store' ),
$year,
$month,
$day
)
);
}
// Optional: number od posts to limit, if assoc_arg "number" is defined.
$posts_num = '-1'; // All by default.
if ( isset( $assoc_args['number'] ) ) {
WP_CLI::log(
sprintf(
// translators: %s: Limit number.
__( 'Number of items to delete is limited to "%s"', 'micemade-fse-store' ),
$assoc_args['number']
)
);
$posts_num = $assoc_args['number'];
}
// Optional - post date or last edit ('post_date_gmt' or 'post_modified_gmt').
$post_date = isset( $assoc_args['date'] ) ? $assoc_args['date'] : 'post_date_gmt';
// Date query "column" argument validation.
$columns = array( 'post_date_gmt', 'post_modified_gmt', 'post_date', 'post_modified' );
if ( ! in_array( $post_date, $columns, true ) ) {
WP_CLI::error(
sprintf(
// translators: %s: Date query "column" argument.
__( 'The "%s" date argument is invalid. Accepted values are "post_date_gmt", "post_modified_gmt", "post_date", or "post_modified".', 'micemade-fse-store' ),
$post_date
)
);
}
// Get post type labels using post type object.
$post_type_obj = get_post_type_object( $post_type );
$post_type_plural = $post_type_obj->labels->name; // Post type plural label.
$post_type_singular = $post_type_obj->labels->singular_name; // Post type singular label.
// Logging - message that command is starting.
// Date format used for logging is dd.mm.year.
// Set the format by changing the order of arguments.
WP_CLI::log(
sprintf(
// translators: %1$s: Post types label, %2$s: status, %3s: day, %4$s: month, and %5$s: year.
__( '%1$s with status "%2$s", created before: %3$s.%4$s.%5$s. ready to be deleted.', 'micemade-fse-store' ),
$post_type_plural,
$post_status,
$day,
$month,
$year
)
);
// WP_Query arguments.
$query_args = array(
'fields' => 'ids', // Just post ID's. Better perfomance-wise(?).
'post_type' => $post_type, // post, product or any CPT.
'posts_per_page' => $posts_num,
'post_status' => $post_status, // publish, draft, pending ...
'date_query' => array(
'column' => $post_date,
'before' => array(
'year' => (int) $year,
'month' => (int) $month,
'day' => (int) $day,
),
),
);
// The Query.
$query = new WP_Query( $query_args );
$posts_found = $query->found_posts;
if ( 0 === $posts_found ) {
WP_CLI::warning( __( 'No items matching given parameters. Check your parameters and try again.', 'micemade-fse-store' ) );
die();
} else {
// Warning and confirmation for deleting attachments.
if ( 'attachment' === $post_type ) {
WP_CLI::confirm( __( '➡️ Deleting attachments will also permanently delete media from "wp-content/uploads" directory. Also, some newer posts might still use these attachments. Are you sure you want to proceed?', 'micemade-fse-store' ) );
}
// Last chance to give up... ;) ;).
WP_CLI::confirm(
sprintf(
// translators: %s: Number of posts found.
__( 'Found %s items. Are you really sure you want to delete them all? Please reconsider, this action cannot be reverted. This is the final warning.', 'micemade-fse-store' ),
$query->found_posts
),
$assoc_args
);
}
$successful = 0;
$failed = 0;
// The Loop.
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
$id = get_the_ID();
$title = get_the_title();
// Logging each deleted item.
WP_CLI::log(
sprintf(
// translators: %1$s: Post type label, %2$s: title, %3s: id, %4$s: published date, and %5$s: last modified date.
__( 'Deleting %1$s "%2$s" (ID: %3$s) published: %4$s, last modified: %5$s...', 'micemade-fse-store' ),
strtolower( $post_type_singular ),
$title,
$id,
get_the_date( 'd.m.Y' ),
get_the_modified_date()
)
);
// Different delete methods for attachment.
if ( 'attachment' === $post_type ) {
// Deleting from media library-a and a file from "uploads" folder.
$result = wp_delete_attachment( $id, true );
} else {
// Use function bellow if you are working with default posts.
$result = wp_delete_post( $id, true );
}
if ( $result ) {
$successful++;
WP_CLI::log(
sprintf(
// translators: %1$s: Post title, %2$s: successful count, %3s: posts found.
__( '✅ Item deleted: "%1$s", %2$s of %3$s.', 'micemade-fse-store' ),
$title,
$successful,
$posts_found
)
);
} else {
WP_CLI::log(
sprintf(
// translators: %s: Post title.
__( '❌ Error! Item "%s" could not be deleted!', 'micemade-fse-store' ),
$title
)
);
$failed++;
}
// Separator line.
WP_CLI::log( '================================' );
}
// Logging.
WP_CLI::log(
sprintf(
// translators: %1$s: Number of deleted posts, %2$s: failed message.
__( '%1$s items deleted.%2$s', 'micemade-fse-store' ),
$successful,
$failed ? __( ' Unsuccesfull deletion of ', 'micemade-fse-store' ) . $failed . __( ' items.', 'micemade-fse-store' ) : ''
)
);
}
wp_reset_postdata();
die();
}
// If WP CLI is enabled, add new command.
if ( defined( 'WP_CLI' ) && WP_CLI ) {
// Delete posts (or CPT's) older than given date.
WP_CLI::add_command( 'delete-before', 'micemade_wpcli_delete_before' );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment