How to automatically expire content in WordPress
WordPress does not include a built-in expiry setting for published posts or pages. You can create a custom workflow using post metadata and WP-Cron, but a content-expiration plugin is the faster and safer option for most sites.
- 01Choose what expiry means
- 02Build the manual workflow
- 03Make cron run reliably
- 04Test before relying on it
- 05Use the fast way
What you need
- A WordPress site with administrator access
- A clear expiry action, such as draft or trash
- Access to WP-Cron or a server cron job for reliable timing
- A backup before changing post status automatically
Choose what expiry means
Decide what should happen when content reaches its expiry date. Moving a post or page to Draft is usually the safest choice because it removes the public version without deleting the content. Sending it to the Trash is more destructive and may permanently delete it later, depending on your WordPress trash settings.
Also decide whether expired content should redirect, display an update notice, or simply disappear. This matters for promotions, event pages and time-sensitive information because removing a page can leave visitors and search engines with a missing URL.
Build the manual workflow
WordPress has no standard expiry-date control for already published posts or pages. The manual route requires a small custom plugin that stores an expiry date as post metadata, then schedules a one-time event with wp_schedule_single_event(). When that event runs, its callback can change the post with wp_update_post() or move it to the Trash with wp_trash_post().
The callback must be connected to the scheduled action, and the code should prevent duplicate events when an expiry date is edited. Put this logic in a custom plugin rather than a theme, so changing themes does not remove the expiry system.
Make cron run reliably
WP-Cron is triggered by page loads rather than running continuously. If nobody visits the site when an expiry is due, the task can run late; this is the problem that commonly appears on a quiet site or breaks on a Friday when no one checks the dashboard.
For important deadlines, configure your hosting provider's system cron to request wp-cron.php on a regular schedule. If you do that, WordPress recommends disabling its page-load cron trigger with DISABLE_WP_CRON to avoid running both systems unnecessarily.
Test before relying on it
Create a test post with an expiry a few minutes in the future and confirm that the chosen action happens. Test both a post and a page if you need both, then test what happens when you change the expiry date or save the content again.
If you have WP-CLI, inspect scheduled events with wp cron event list, run a due event with wp cron event run, and check the cron system with wp cron test. Also review Tools → Site Health for loopback failures, which can stop scheduled events from running.
Use the fast way
For most sites, install PublishPress Future, activate it, and configure the expiry behaviour in its settings. Edit a post or page, set its expiration date, choose the follow-up action, and update the content. This avoids maintaining custom metadata, cron callbacks and duplicate-event checks yourself.
Use Draft as the default action until you are certain that Trash or another follow-up action is appropriate. Check one test item manually after the first scheduled expiry, especially if the site has low traffic or a caching, security or hosting setup that may interfere with WP-Cron.
Let PublishPress Future do it
Schedules content expiration and follow-up actions, ideal for keeping time-sensitive posts and pages current without manual cleanup.
Sources
- developer.wordpress.org /reference/functions/wp_schedule_single_event/?utm_source=op…
- developer.wordpress.org /plugins/cron/?trk=article-ssr-frontend-pulse_little-text-bl…
- developer.wordpress.org /plugins/cron/hooking-wp-cron-into-the-system-task-scheduler…
- developer.wordpress.org /plugins/cron/simple-testing/?utm_source=openai
Questions
- Can WordPress expire published content without a plugin?
- Not from the standard editor, no. WordPress can schedule content to publish, but it does not provide a normal expiry-date field for published posts or pages. The manual alternative is custom code that stores an expiry value, schedules a WP-Cron event and changes the post status when the event runs. That route is suitable if you maintain custom plugins and can test cron jobs properly.
- Will WordPress expire content at the exact time I choose?
- Not necessarily when using default WP-Cron. WP-Cron checks scheduled work when the site receives a request, so a low-traffic site can process an expiry late. A real server cron job that calls WordPress regularly is more predictable. Loopback failures, disabled cron and hosting security rules can also stop scheduled tasks from running, so test the setup before relying on it for a deadline.
- Should expired content be moved to Draft or Trash?
- Move expired content to Draft unless you are certain it should be deleted. Draft keeps the content available for review and prevents accidental loss. Trash removes it from normal public use but may lead to permanent deletion later. If the URL has backlinks or search visibility, consider keeping the page and showing an expiry notice or redirecting visitors instead of deleting it.
- Can I expire pages and custom post types as well as posts?
- Yes, provided the workflow supports those post types. A custom implementation must query and update the correct post type, while a plugin should expose the supported types in its settings or editor panel. Test each type separately because templates, permissions, custom fields and caching can change what visitors see after the post status is changed.
- Why did an expired post stay published?
- The scheduled task probably did not run, or the expiry callback did not find the correct post. Check whether WP-Cron is disabled, whether the site has loopback errors, and whether a server cron job is calling <code>wp-cron.php</code> if you use one. Also check the scheduled event and the saved expiry timezone. A task that runs late is usually a cron or hosting problem, not a post-editor problem.