I'm trying to figure out how to set the max number of posts allowed across the site, but keep it fluid by sending old posts to the bin when a new post is over the limit.

(I'm trying to stop the database being flooded and slowing the whole site down)

For example: I have a jobs board that will be importing large amounts of posts fairly regularly, but I only want a maximum of 1000 posts on the site. Old posts are obselete so as soon as someone adds post number 1001 the oldest post would be moved to the bin.

I've found a snippet that limits the number of non-admin posts:

function limit_user_by_post_count(){
    $user = get_current_user_id();
    if (!current_user_can( 'manage_options')) { 
        //not an admin - so impose the limit
        $user_post_count = count_user_posts($user);
            header("Location: /wp-admin/edit.php");

But it does so by redirecting the user to the all posts page (& stopping them from posting anything new) and I'm not really well versed enough to modify it to send the oldest post to the bin?

  • You could either remove old posts while importing new posts, or setup a cron job to clean up the database once a day/week. The idea is to setup a count query using $wpdb, get the total count of posts for a specific post type, and if the count is greater than 1000, get the difference, and update the post status to "trash". That would still keep those posts in the database, but you could let wordpress handle the trash can clean up by setting the trash days limit. Link -> codex.wordpress.org/Trash_status
    – gdaniel
    Jun 11, 2015 at 15:26

1 Answer 1


Here is an idea but before we go into details, here are VERY VERY IMPORTANT notes


  • Take a database back up before running this code. It is advisable to run this on a local install first for testing purposes.

  • Note on wp_trash_post(), from the codex

    If trash is disabled, the post or page is permanently deleted.

  • I have tested the code, and it works. You can however make changes to it to suite your needs. As it stands, the code should only delete posts when a new post is published


What we need to do is

  • Run a custom function to delete posts when ever a new post is published. For this, we will use the transition_post_status hook. Just one note, this hook fires when a post is published, trashed, updated and untrashed. We will need to restrict our custom function to only run when a post is published. This line, if ( $new_status == 'publish' && $old_status != 'publish' ) will take care of that

  • Use get_posts() to get all the published posts. You can adjust this to suite your needs. We only need the post ids, so this is what we will get. It makes the query really fast and does not eat up resources

  • The returned array of posts from get_posts() needs to be counted, and if there are more than a 1000 posts, we need to get the post ids after the first thousand posts. we will use array_slice here

  • We need to run wp_trash_post if we have more than 1000 posts to trash these posts. If you need to delete everything attached to the post as well, you can use wp_delete_post here instead of wp_trash_post. You can just uncomment this line, wp_delete_post( $trash_post ); in the code and comment this line out wp_trash_post( $trash_post );. Do not run both at the same time


The code is well commented as well, so it will be easy to follow. Just one note, you will need a minimum of PHP5.4+ installed on your server due to the use of new array syntax. Also note, closures needs a minimum of PHP5.3

add_action( 'transition_post_status', function ( $new_status, $old_status, $post )
    // Run this only when a new post is publish to save on unnecessary waste of resources
    if ( $new_status == 'publish' && $old_status != 'publish' ) {
         * Use get_posts() to count all the posts published, get only post ids to improve performance
         * This array of post ids will also be used to get the post ids of posts to be trashed
        $total_posts = get_posts( ['posts_per_page' => -1, 'fields' => 'ids'] );
        // Count the amount of posts in the returned array from get_posts
        $count = count( $total_posts );
        // Run the following only if we have more than a thousand posts
        if ( $count > 1000 ) {
            // Get all post id after the first 1000 posts
            $set_to_trash = array_slice( $total_posts, 1000 );
            foreach ( $set_to_trash as $trash_post ) {
                // Use wp_trash_post to trash the posts 
                wp_trash_post( $trash_post  );
               // You can also use wp_delete_post here to delete everything attached to the post
               //wp_delete_post( $trash_post );
            // Unset $trash_post for safety
            unset( $trash_post );
}, 10, 3 );


You can set your installation to permanently delete trashed posts by adding the following line to wp-config.php

define('EMPTY_TRASH_DAYS', 0 );

Just note, this will permanently delete posts and they cannot be recovered

  • Worked. I also added a 'post_type' array to get_posts() to reflect it on my custom post type. my job board is now fluid! Thanks so much!
    – eddallen
    Jun 12, 2015 at 14:54
  • Perfect. Glad it worked. Enjoy :-) Jun 13, 2015 at 3:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.