Easy way to delete 70k posts and attached media?

A plugin created lots of posts that I now need to delete.
They are targetable by category (e.g. Tweet). Many also have attached images.

I wrote a php script for it*, but without pagination it gets hung up, as it does a lot of work (deletes the posts one by one). – And with pagination (say 1000 per page) it still takes multiple seconds and I’d have to refresh >50 times…

I figure a good database query could select and delete multiple posts at the same time – however I also want to delete all attached media, both in the database and the actual files.

Alternatively, handling the deletions in batches (i.e. using pagination) and maybe flush output in between to show update on whether it’s working could work.


*here’s what I have so far:

$twitter = get_cat_ID( 'Tweet' );
$instagram = get_cat_ID( 'Instagram' );
$args = array(
    'category__in' => array(
        $twitter,
        $instagram
    ),
    'post_status' => 'any',
    'posts_per_page' => 1000
);
$social_posts = new WP_Query( $args );

if ( $social_posts->have_posts() ) : ?>

    <h1>Deleting the following:</h1>
    <ul>
    <?php while ( $social_posts->have_posts() ) :
        $social_posts->the_post();
    ?>
        <li>
            <h5><?php the_title() ?></h5>
            <div class="post-content"><?php the_content(); ?></div>
        </li>
        <?php
        $post_id = get_the_ID();
        $attachments = get_attached_media( '', $post_id ); // '' => all attachment Mime types
        foreach ( $attachments as $attachment ) {
            wp_delete_attachment( $attachment->ID, true );
        }
        wp_delete_post( $post_id, true );
    endwhile;
else: ?>
    <p>Oops, there are no posts.</p>
<?php
endif;

(Testing this locally, put it in page-uninstall-social.php and created a page for it so it runs when I visit that page)

2 Answers
2

If you know how to find the posts, then we can use WP CLI to do a 2 step process.

First, grab all the post IDs in those categories using wp post list

E.g.

posts=$(wp post list --field="ID" --category__in="1,2,etc")
wp post delete $posts --force

Then we can plug the values in posts into wp post delete.

We can also use the same trick to delete the media, via the post_parent__in parameter to fetch their IDs, then deleting them.

If you can’t run WP CLI directly on the server, pull a copy down to you computer, run the commands, then replace production with the result

Leave a Comment