How to Delete Posts of a Custom Post Type Efficiently

How many times did you want to delete some test data?

You can paste the following snippet into your functions.php file (temporarily) or in a custom plugin.

You need to update my_custom_post_type to match your custom post type.

Then login as admin and then access your site e.g. example.com/?admin_del_cpt_posts and you’ll see the post ids as they are being deletion. So cool.

The code processes up to 250 records at a time and outputs data as soon as it’s done deleting a single record.
This is done so the server doesn’t crash due to lack of memory.

If you have more records you can just reload the page multiple times. If you really have lots of records you can adjust numberposts variable to let’s say 1000 and keep reloading.

if you’re feeling really brave then you can set it to -1 so it can process all of the records.

<?php

/**
 * Backup! This really deletes posts.
 * Data Loss Warning: This script permanently deletes data. Once executed, the deletion cannot be undone.
 * It is essential to fully understand the impact of this operation. Use this script only if you are certain that you want to
 * permanently remove the specified data.
 *
 * If you are not comfortable with scripts or if your site contains critical data, consult with a professional developer
 * or your web hosting support team before proceeding.
 * 
 * Make sure you change 'my_custom_post_type' below
 * @link https://wpsandbox.net/851
 */

//
if (isset($_REQUEST['admin_del_cpt_posts'])) {
    add_action('init', 'orb_post1234_delete_cpt_efficiently', 20);
}

/**
 * Backup! This really deletes posts.
 * @return void
 */
function orb_post1234_delete_cpt_efficiently()
{
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die("Login as admin and try again.");
    }

    /**
     * 
     * @desc
     */
    $all_posts = get_posts( array(
        'fields' => 'ids',
        'post_type' => 'my_custom_post_type',
        'numberposts' => 250,
        'post_status' => 'any',
    ) );

    ini_set('implicit_flush', 1);
    ini_set('output_buffering', 0);
    ini_set('zlib.output_compression', 0);
    header("Content-Type: text/plain");

    // https://stackoverflow.com/questions/20316338/intermittently-echo-out-data-with-long-running-php-script
    if (function_exists('apache_setenv')) {
        apache_setenv( 'no-gzip', 1 );
    }

    $total = count($all_posts);
    echo sprintf("Found: %d post(s)\n", $total);

    foreach ($all_posts as $idx => $post_id) {
        $current = $idx + 1;
        echo sprintf("[$current/$total] Deleting #%d", $post_id);

        $res = wp_delete_post( $post_id, true );

        if (empty($res)) {
            echo " failed";
        } else {
            echo " ok";
        }

        echo "\n";

        ob_flush();
        flush();
    }

    die();
}

This code is efficient because it only queries the IDs of those custom post types and then proceeds to the deletion.
We don’t need anything other than the ID.

the 2nd parameter (true) of wp_delete_post() function when true doesn’t put the deleted item in the trash where it can be restored.

Leave a Comment

Your email address will not be published. Required fields are marked *