skip to Main Content

Dears,

I want to delete the old post automatically without using a plugin and the Snippets will be the choice, I want to delete any post older than one day from a special category an using this Snippet but nothing deleted:

// Automatically delete posts older than x days
function delete_old_posts($category_id = 62) {
    $days = 1; // Change this value to the desired number of days
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'date_query'     => array(
            array(
                'before' => $days . ' days ago',
                'inclusive' => true,
            ),
        ),
    'tax_query' => array(
      array(
        'taxonomy' => 'slug', // Replace 'category' with your actual taxonomy slug if different
        'field' => 'id',
        'terms' => array($category_id), // Array of category IDs to target
      ),
    ),
    );
    $old_posts = new WP_Query($args);

    if ($old_posts->have_posts()) :
        while ($old_posts->have_posts()) : $old_posts->the_post();
            wp_delete_post(get_the_ID(), true);
        endwhile;
    endif;
    wp_reset_postdata();
}
add_action('wp', 'delete_old_posts');

3

Answers


  1. No straightforward solution:

    There is no straightforward solution in WP, you have to use custom SQL.

    Basic understanding of post and term table and their relationship:

    • Table wp_terms stores term names with Primary Key (PK) associated ID
    • Table wp_term_relationships is a relationship table between posts & their taxonomy/terms
    • Table wp_term_taxonomy is a relationship table between term and their associated taxonomies

    SQL:

    Caution always first check the SQL through SELECT statement before using non-revokable action like deleting records.

    Select:

    SELECT
        *
    FROM
        wp_posts wp
    WHERE
        post_date <= DATE_SUB(NOW(), INTERVAL 6 HOUR)
        AND
        post_type = 'post'
        AND
        ID IN (
        SELECT
            wtr.object_id
        FROM
            wp_term_taxonomy wtt
        JOIN wp_terms wt ON
            wtt.term_id = wt.term_id
        JOIN wp_term_relationships wtr ON
            wt.term_id = wtr.term_taxonomy_id
        WHERE
            wtt.taxonomy = 'category'
            AND wt.slug = 'temp');
    

    Delete:

    If you’re satisfied with the output of SELECT statement, then change it to DELETE statement like below.

    DELETE
    FROM
        wp_posts wp
    WHERE
        post_date <= DATE_SUB(NOW(), INTERVAL 6 HOUR)
        AND
        post_type = 'post'
        AND
        ID IN (
        SELECT
            wtr.object_id
        FROM
            wp_term_taxonomy wtt
        JOIN wp_terms wt ON
            wtt.term_id = wt.term_id
        JOIN wp_term_relationships wtr ON
            wt.term_id = wtr.term_taxonomy_id
        WHERE
            wtt.taxonomy = 'category'
            AND wt.slug = 'temp');
    
    Login or Signup to reply.
  2. You can use this:

    <?php 
    function delete_posts_by_category_and_age_atakanau() {
        // Set the category ID of the posts to be deleted
        $category_id=11;
    
        // Calculate the date 1 day ago
        $one_day_ago = date('Y-m-d H:i:s', strtotime('-1 day'));
        
        global $wpdb;
        // Get posts ID older than 1 day with the given category ID
        $query = $wpdb->prepare(
                "SELECT posts.ID
                FROM {$wpdb->posts} posts
                INNER JOIN {$wpdb->term_relationships} term_relationships ON (posts.ID = term_relationships.object_id)
                WHERE posts.post_type = 'post'
                AND posts.post_status = 'publish'
                AND term_relationships.term_taxonomy_id = %d
                AND posts.post_date < %s",
                $category_id,
                $one_day_ago
            );
        $posts_to_delete = $wpdb->get_results($query);
    
        // Loop through the posts to delete
        foreach ($posts_to_delete as $post) {
            // Use wp_delete_post to delete each post
            wp_delete_post($post->ID, true); // Set second parameter to true to bypass the trash
        }
    }
    add_action('plugins_loaded', 'delete_posts_by_category_and_age_atakanau');
    

    I recommend using it in a child theme instead of a snippet. The hook may not be triggered with the snippet. Or you can call the function directly.

    Login or Signup to reply.
  3. TLDR;

    Grab the te_delete_old_posts() function if using independently and no need for the cron parts if that is not required.

    // Function to set up a daily custom event.
    function te_setup_daily_post_deletion_event() {
        if (!wp_next_scheduled('te_daily_post_deletion_hook')) {
            wp_schedule_event(time(), 'daily', 'te_daily_post_deletion_hook');
        }
    }
    add_action('wp', 'te_setup_daily_post_deletion_event');
    
    // Function to delete old posts.
    function te_delete_old_posts() {
        $category_id = 62; // Set your category ID.
       
        $days = 1; // Posts older than this number of days will be deleted.
    
        $query_date = date('Y-m-d', strtotime("-$days days"));
    
        $args = array(
            'post_type'      => 'post',
            'posts_per_page' => -1,
            'fields'         => 'ids', // Retrieve only the IDs for efficiency.
            'date_query'     => array(
                array(
                    'before' => $query_date,
                    'inclusive' => false, // set to true if previous day is considered a day old
                ),
            ),
            'tax_query' => array(
                array(
                    'taxonomy' => 'category',
                    'field'    => 'term_id',
                    'terms'    => array($category_id),
                ),
            ),
        );
    
        $old_posts = get_posts($args); // Get a nice lean memory efficient list of post ID's
    
        if (!empty($old_posts)) {
            foreach ($old_posts as $post_id) {
                wp_delete_post($post_id, true);
            }
        }
    }
    // Used for the cronjob method
    add_action('te_daily_post_deletion_hook', 'te_delete_old_posts');
    

    Make sure your Query returns the required result:

    In the example below I extracted the main query component so you can add to a function and run it.

    The date initially passed does not come out as expected. $query_date is used to get the correct date using PHP date/strtotime functions with no time residue.

    Also I am telling the query to provide only ID’s of the results so that it will be efficient than getting entire post objects.

    Finally I am using get_posts() so that we can get an clean array of Post ID’s to loop thru, and not have to deal with WP_Query().

        $category_id = 62; // Set your category ID.
       
        $days = 1; // Posts older than this number of days will be deleted.
    
        $query_date = date('Y-m-d', strtotime("-$days days"));
    
        $args = array(
            'post_type'      => 'post',
            'posts_per_page' => -1,
            'fields'         => 'ids', // Retrieve only the IDs for efficiency.
            'date_query'     => array(
                array(
                    'before' => $query_date,
                    'inclusive' => false, // set to true if previous day is considered a day old
                ),
            ),
            'tax_query' => array(
                array(
                    'taxonomy' => 'category',
                    'field'    => 'term_id',
                    'terms'    => array($category_id),
                ),
            ),
        );
    
        $old_posts = get_posts($args); // Get array of post ID's
    
        if (!empty($old_posts)) {
            foreach ($old_posts as $post_id) {
               echo $post_id . " " get_the_title($post_id);
            }
        }
    

    Running just this code you can verify that you are getting the expected results, and tweak the query if not.

    Is this a Recurring event:

    If this process is a recurring event which it sounded like from the description. It should go in WP cronjob so that the process does not keep running each time a page loads as you had in the ‘wp’ hook. I am guessing that must have been for testing or you were planning on doing this manually.

    function te_setup_daily_post_deletion_event() {
        if (!wp_next_scheduled('te_daily_post_deletion_hook')) {
            wp_schedule_event(time(), 'daily', 'te_daily_post_deletion_hook');
        }
    }
    add_action('wp', 'te_setup_daily_post_deletion_event');
    

    Running with WP-CLI

    If you do not wish to use a cronjob and want to run this manually, add the function te_delete_old_posts() in your themes function.php or in a custom plugin and you can use one of the two methods bellow to run the function.

    wp eval "te_delete_old_posts();"
    

    Hit enter after typing the function name inside the shell

    wp shell
    wp> te_delete_old_posts()
    

    Always use wp_delete_post() to delete Posts:

    Your script is a pretty good start, and you seemed to be on the right track. WordPress creates data in a few tables when you create a posts and it is important that proper cleanup happens when you delete a post. wp_delete_post() does just that.

    And as mentioned use the code I provided for testing and make sure you are getting results first, if something is not working.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search