=== WST Post Expiration ===
Contributors: webtatsu
Tags: expiration, unpublish, schedule, editorial workflow, cron
Requires at least: 7.0
Tested up to: 7.1
Requires PHP: 8.2
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Set an expiration date and time on a post. Once that time passes, the post is moved back to draft automatically.

== Description ==

WST Post Expiration adds an expiration date and time to your posts. Once that time passes, the post switches from published to draft automatically. It keeps announcements and campaign pages with a fixed run time from staying public after they are over.

The date is set where you already work: the block editor sidebar, the classic editor meta box, or Quick Edit on the post list. An "Expiration" column is added to the post list, so you can see at a glance which posts expire and when.

= How it works =

* Each post with an expiration date gets its own single WP-Cron event, scheduled for exactly that time
* An hourly fallback picks up posts whose event was lost (after a site copy, damaged cron data, and the like)
* An expiration date that is already in the past is handled on the next cron run
* An expired post becomes a `draft`. The target status can be changed with the `wst_post_expiration_new_status` filter
* Clearing the field removes the scheduled event

= Features =

* One expiration date and time per post
* Set it from the block editor sidebar, the classic editor, or Quick Edit
* An "Expiration" column on the post list
* Choose which post types can have an expiration date (posts, pages, and custom post types)
* A "Scheduled events" section on the settings screen shows the posts with an expiration date and the events registered for them, with a "Reschedule" button to repair a mismatch
* Times are evaluated in the site timezone (Settings > General)
* Developer hooks: `wst_post_expiration_new_status` (filter), `wst_post_expiration_expired` (action), `wst_post_expiration_settings_capability` (filter)

= Capabilities =

* Setting the expiration date of a post requires permission to edit that post
* Changing the plugin settings requires administrator permissions (`manage_options`). Use the `wst_post_expiration_settings_capability` filter to change this

= Before you start =

* Expiration relies on WP-Cron. On a low traffic site, cron only runs when someone visits, so the change may be applied a little late. Calling `wp-cron.php` from a server-side cron job makes it exact.
* Moving a post to draft is a real status change. To bring it back, publish it again. The expiration date stays on the post, so it fires again while that time is in the past. Clear or update the date as well.
* Deactivating the plugin removes every scheduled event. The dates stay on the posts, so activating it again schedules them once more.

== Installation ==

1. Upload the plugin files to `/wp-content/plugins/wst-post-expiration`, or install it from the Plugins > Add New screen.
2. Activate the plugin from the Plugins screen.
3. Open the "Post Expiration" menu in wp-admin and choose the post types that can have an expiration date.
4. Edit a post of one of those post types and set the date from the sidebar, the classic editor, or Quick Edit.

== Frequently Asked Questions ==

= What happens when a post reaches its expiration date? =

Its status changes from published to draft. The content, the title, and everything else stay as they are.

= Can it move the post to the trash or make it private instead of a draft? =

Yes, with code. Return `private`, `pending`, `trash`, or any registered status from the `wst_post_expiration_new_status` filter.

`trash` goes through the standard WordPress trash handling. When the trash is disabled (`EMPTY_TRASH_DAYS` is `0`), the post is kept as a draft instead of being deleted permanently.

= I set a time, but nothing changed right away =

Expiration runs through WP-Cron, which fires when someone visits the site. On a quiet site it waits for the next visit. Calling `wp-cron.php` from a server-side cron job removes the delay.

= Which timezone is used? =

The site timezone (Settings > General). The date and time you enter is treated as local site time.

= Does it work with pages and custom post types? =

Yes. The "Enabled post types" setting lets you pick which post types can have an expiration date.

= What happens when I deactivate the plugin? =

Every scheduled expiration event is removed. The dates stay on the posts, so activating the plugin again schedules them once more.

== Screenshots ==

1. The expiration field in the block editor sidebar
2. The settings screen: enabled post types and scheduled events
3. The "Expiration" column and the Quick Edit field on the post list

== Changelog ==

= 1.0.0 =
* Initial release

== Upgrade Notice ==

= 1.0.0 =
Initial release.
