Auto delete attachments that are older than x days

Are you really sure you want to do this? What about all of the posts that these “old” attachments are used in? For attachments that are used for things like “featured image”, WP will take of that for you. However, for uses of an attachment in post_content, e.g.

<img src="https://wordpress.stackexchange.com/questions/258966/img_attachment_url" />
<a href="pdf_attachment_url">download PDF</a>

you’ll end up with “broken” links.

But, if you’re really sure, you can do it using WP-Cron.

A quick-and-dirty solution, that probably doesn’t do everything you’d need it to do,
would look something like (note: I haven’t actually tested this code, because obviously, I don’t want to delete old attachments in any site I currently maintain):

    // using this $num_days global is a kind of a hack but it makes sure that
    // all of the places where we need X we have the same value
    // if you were to encapsulate this code into a class
    // then you could set it as a class const
    global $num_days ;
    $num_days = 10 ;

    // hook into cron_scedules to add our "every X days"
    add_filter ('cron_schedules', 'add_my_schedule') ;
    // add our cron hook
    add_action ('my_cron_hook', 'my_cron_func') ;

    // if our hook is not currently scheduled, then schedule it
    if (!wp_next_scheduled ('my_cron_hook')) {
        wp_schedule_event (time (), "$num_days_days", 'my_cron_hook') ;
    }

    /**
     * add our "every X days" to the available schedules
     */
    function
    add_my_schedule ($schedules)
    {
        global $num_days ;

        $schedules["$num_days_days"] = array (
            'interval' => $num_days * DAY_IN_SECONDS,
            'display'  => esc_html__("Every $num_days Days"),
            ) ;

        return ($schedules) ;
    }

    /**
     * this is the func that will be called when the cron job executes
     */
    function
    my_cron_func ()
    {
        global $num_days, $post ;

        // query for attachments added more than $num_days ago
        $args = array (
            'post_type' => 'attachment',
            'post_status' => 'inherit',
            'date_query' => array (
                // see https://codex.wordpress.org/Class_Reference/WP_Query#Date_Parameters
                // for more info on this 'before' date_query syntax
                'before' => "$num_days days ago",
                ),
            'posts_per_page' => -1,
            ) ;
        $old_attachments = new WP_Query ($args) ;

        while ($old_attachments->have_posts ()) {
            $old_attachments->the_post () ;

            wp_delete_attachment ($post->ID, true) ;
            }

        // probably not necessary to call wp_reset_postdata(),
        // since we're in a cron job, but doesn't hurt
        wp_reset_postdata () ;
    }

Be sure you unschedule the cron job when/if you no longer need it. I’ll leave it as an “exercise for the reader” to figure out how to do that (hint, see Unscheduling Tasks for more info).