Title: ContentTimer — Content Expiry &amp; Automation
Author: Muhammad Siddiqui
Published: <strong>September 22, 2026</strong>
Last modified: September 22, 2026

---

Search plugins

![](https://ps.w.org/contenttimer/assets/banner-772x250.png?rev=3706528)

![](https://ps.w.org/contenttimer/assets/icon-256x256.png?rev=3706528)

# ContentTimer — Content Expiry & Automation

 By [Muhammad Siddiqui](https://profiles.wordpress.org/muhammadsiddiqui/)

[Download](https://downloads.wordpress.org/plugin/contenttimer.1.2.1.zip)

 * [Details](https://wordpress.org/plugins/contenttimer/#description)
 * [Reviews](https://wordpress.org/plugins/contenttimer/#reviews)
 *  [Installation](https://wordpress.org/plugins/contenttimer/#installation)
 * [Development](https://wordpress.org/plugins/contenttimer/#developers)

 [Support](https://wordpress.org/support/plugin/contenttimer/)

## Description

ContentTimer schedules the end of a piece of content as easily as WordPress schedules
its beginning.

Set an expiry date on a post, choose what should happen when that moment arrives,
and ContentTimer takes care of the rest — then records exactly what it did.

**Set it once. ContentTimer handles it automatically.**

#### What it does

 * Give any post, page or public custom post type an expiry date and time
 * Choose the action: move to draft, make private, move to trash, unpublish, or 
   redirect
 * Build reusable rules that apply to whole groups of content
 * Watch everything from one dashboard, and check the log for what happened
 * Run an expiry check by hand at any time

#### A worked example

A “Summer Sale 2026” landing page should stop being reachable at midnight on 30 
September.

 1. Open the page, set the expiry date and time in the ContentTimer panel
 2. Choose the Redirect action and enter `/shop/`
 3. Save

At midnight, ContentTimer redirects the page to `/shop/` with a 301 and writes a
log entry recording the result. Nothing else in your site changes.

#### Expiry actions included

 * **Move to Draft** — back to Draft, fully editable
 * **Make Private** — stays published, visible only to people who can read private
   posts
 * **Move to Trash** — recoverable; nothing is deleted permanently
 * **Unpublish** — removed from the public site and marked Pending Review
 * **Redirect** — 301, 302 or 307 to another page or an external URL

#### Rules

A rule applies an action to everything that matches it, so you do not have to touch
each post. A rule can fire on a fixed date and time, or a set number of days after
each item was published — useful for job listings, event pages and time-limited 
offers.

Conditions narrow a rule down by post type, category or tag, author, or post status.

#### Built to stay out of the way

 * No processing on front-end page loads
 * Work is batched, so a site with thousands of posts stays responsive
 * All timestamps respect the site timezone, including across daylight saving changes
 * Duplicate cron runs cannot apply a destructive action twice

### Free and Pro

Everything described above is in the free plugin, with no artificial limits — unlimited
rules included.

ContentTimer Pro is a separate add-on that adds four more expiry actions — 410 Gone,
remove from search (noindex), replace the content with a notice, and change to any
custom post status — plus an email warning before content expires and a summary 
email after each run. The free plugin is fully functional without it and contains
no hidden or disabled premium code: the Pro capabilities listed in Settings are 
described as unavailable because they genuinely are not present in this download.

A licence is entered under **ContentTimer  Settings  License**. If the licence server
cannot be reached, Pro keeps working for 14 days while the plugin retries, so an
outage never costs a paying customer the features they bought. An expired or deactivated
licence takes effect immediately.

### Privacy

ContentTimer stores expiry settings in post meta, rules and log entries in two database
tables, and its settings in a WordPress option. Logs record the title, type, action
and result of each expiry, so an administrator can see what happened. No visitor
data and no personal data are collected.

**External services**

ContentTimer makes no external requests at all unless you enter a ContentTimer Pro
licence key.

If you do, the plugin contacts the Lemon Squeezy licence API (`api.lemonsqueezy.
com`) when you press Activate License, Re-check licence or Deactivate License, and
once a day afterwards to confirm the licence is still valid. Only two things are
sent: the licence key you entered, and this site’s domain name so the activation
can be released later. No content and no personal data are transmitted. Removing
the licence key stops all external requests.

If you then press Download ContentTimer Pro, the plugin asks the ContentTimer delivery
service (`update.contenttimer.com`) to authorise that download. It is sent your 
licence key, its activation id, this site’s domain name and the ContentTimer version
you are running, and it replies with a temporary download link your browser then
follows. The plugin never downloads or installs the add-on for you — you install
the file yourself. Nothing is sent to this service unless you press that button,
and the ContentTimer Pro add-on, if you install it, checks the same service for 
its own updates.

Lemon Squeezy is the payment provider. Checkout happens entirely on their site; 
ContentTimer never sees or stores card details. Pressing an Upgrade to Pro button
simply opens a Lemon Squeezy checkout page in a new tab.

Lemon Squeezy terms: https://www.lemonsqueezy.com/terms — privacy policy: https://
www.lemonsqueezy.com/privacy

**What is stored**

The licence record holds only what the licence needs: the key, its status, expiry
date, activation instance id, activation counts, product and plan names, and the
time of the last check. Customer names, email addresses and order details are deliberately
not stored.

**Optional webhook**

Site owners who run their own Lemon Squeezy store may configure a webhook so subscription
changes are picked up promptly. The endpoint is disabled unless a signing secret
is present in `wp-config.php`, and every request must carry a valid HMAC-SHA256 
signature. A webhook is never treated as authoritative on its own: it only prompts
ContentTimer to re-check the licence through the API.

## Screenshots

[⌊The ContentTimer dashboard: content counters, recent expiry activity and quick
actions.⌉⌊The ContentTimer dashboard: content counters, recent expiry activity and
quick actions.⌉[

The ContentTimer dashboard: content counters, recent expiry activity and quick actions.

[⌊The Content screen: everything ContentTimer manages, filterable by expiry state.⌉⌊
The Content screen: everything ContentTimer manages, filterable by expiry state.⌉[

The Content screen: everything ContentTimer manages, filterable by expiry state.

[⌊Adding an expiry rule with conditions, an action and a schedule.⌉⌊Adding an expiry
rule with conditions, an action and a schedule.⌉[

Adding an expiry rule with conditions, an action and a schedule.

[⌊The expiry log, showing what ran, when, and whether it succeeded.⌉⌊The expiry 
log, showing what ran, when, and whether it succeeded.⌉[

The expiry log, showing what ran, when, and whether it succeeded.

[⌊Settings, including which content types ContentTimer manages.⌉⌊Settings, including
which content types ContentTimer manages.⌉[

Settings, including which content types ContentTimer manages.

## Installation

 1. Upload the `contenttimer` folder to `/wp-content/plugins/`, or install through 
    Plugins  Add New
 2. Activate ContentTimer through the Plugins screen
 3. Open **ContentTimer  Settings** and choose which content types to manage
 4. Set an expiry on a post, or create a rule under **ContentTimer  Rules**

No further configuration is required. Defaults are sensible for a typical site.

## FAQ

### Does ContentTimer delete my content?

No. The Move to Trash action uses the normal WordPress trash, from which content
can be restored. Nothing is ever deleted permanently, and uninstalling the plugin
never touches your posts or pages.

### What happens if WP-Cron does not run?

Expiry runs on the next request that triggers WordPress cron. If `DISABLE_WP_CRON`
is set on your site, ContentTimer says so on its dashboard, and you can either point
a real server cron at `wp-cron.php` or use the **Run Expiry Check** button.

### Can the same action run twice by mistake?

No. Each run takes a lock, each item’s state is re-read immediately before the action
runs, and every action checks whether the change is already in place. A repeated
run records a “skipped” log entry instead of acting again.

### I run my own store. How do I configure checkout and webhooks?

Add the relevant constants to `wp-config.php`. None are required for the free plugin
to work:

    ```
    define( 'CONTENTTIMER_LS_STORE', 'yourstore' );          // yourstore.lemonsqueezy.com
    define( 'CONTENTTIMER_LS_VARIANT_MONTHLY', '123456' );
    define( 'CONTENTTIMER_LS_VARIANT_YEARLY', '123457' );
    define( 'CONTENTTIMER_LS_WEBHOOK_SECRET', 'your-signing-secret' );
    define( 'CONTENTTIMER_LS_ENVIRONMENT', 'test' );         // omit for live
    ```

The webhook URL is shown on the License tab once a signing secret is present.

### Which timezone are the dates in?

The timezone configured in Settings  General. Dates are stored in UTC internally
and converted for display, so daylight saving changes do not shift your schedules.

### Where do redirects point?

Anywhere you like: a path on your own site such as `/shop/`, or a full `https://`
address. Destinations using any other scheme are rejected, and a destination that
points back at the same content is refused so no redirect loop can be created.

### Does it work with custom post types?

Yes. Every public custom post type registered by your theme or another plugin can
be enabled from ContentTimer  Settings.

### Will it slow down my site?

No. ContentTimer does no work on normal front-end requests. The only front-end code
is the redirect check, which reads post meta WordPress has already loaded and adds
no database query.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“ContentTimer — Content Expiry & Automation” is open source software. The following
people have contributed to this plugin.

Contributors

 *   [ Muhammad Siddiqui ](https://profiles.wordpress.org/muhammadsiddiqui/)

[Translate “ContentTimer — Content Expiry & Automation” into your language.](https://translate.wordpress.org/projects/wp-plugins/contenttimer)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/contenttimer/), check
out the [SVN repository](https://plugins.svn.wordpress.org/contenttimer/), or subscribe
to the [development log](https://plugins.trac.wordpress.org/log/contenttimer/) by
[RSS](https://plugins.trac.wordpress.org/log/contenttimer/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.2.1

 * Fix: the Schedule expiry dialog rendered without the plugin palette, so the Save
   expiry button showed white text on a white background and the toggle stayed grey
   when switched on.
 * Fix: fields inside the Schedule expiry dialog now size the same way as the rest
   of the admin screens.

#### 1.2.0

 * New: once a licence is active, the License tab offers an authorised download 
   of the ContentTimer Pro add-on, and shows its installed version and status once
   it is present.
 * The free plugin never downloads or installs executable code: the download is 
   a link you choose to follow, and the package is installed by you in the usual
   way.

#### 1.1.0

 * New: licensing foundation for ContentTimer Pro — activate, re-check and deactivate
   a Lemon Squeezy licence from Settings  License.
 * New: centralised feature gate, so Pro access is decided in one place and enforced
   server-side rather than by hiding controls.
 * New: Upgrade to Pro checkout links and a Manage Subscription link, both driven
   by configuration rather than hard-coded ids.
 * New: optional Lemon Squeezy webhook endpoint with signature verification and 
   duplicate protection.
 * New: a 14-day grace period so a licence server outage does not interrupt a paying
   customer.
 * Free functionality is unchanged. No existing feature has been moved behind a 
   licence.

#### 1.0.4

 * Fixed: paging past the end of a list left an empty screen with no way back. Each
   list now offers a link to the first page.
 * Fixed: the daily log-cleanup event was not restored if it went missing while 
   automatic expiry was switched off.
 * Fixed: uninstalling left the guided tour’s per-user flag behind.
 * Housekeeping: readme now records the WordPress version actually tested against.

#### 1.0.3

 * Fixed: re-scheduling content that had previously been redirected left the old
   redirect in place, so the page stayed unreachable. Scheduling a new expiry now
   lifts it.
 * Fixed: toolbar controls on the Content and Logs screens wrapped onto separate
   lines instead of sitting inline.
 * Fixed: the three condition fields on the rule form were misaligned, and their
   labels are now proper accessible names rather than hidden markup.
 * Fixed: fields on the License tab ran together with no spacing.
 * Fixed: the header described actions that are only in the Pro add-on.
 * Added: the tables are recreated automatically if they go missing while the schema
   version still says they exist.
 * Changed: log retention deletes in bounded passes rather than one large query.
 * Polish: clearer Already Expired icon, compact upgrade card on the dashboard, 
   Posts and Pages listed first among content types, schedule fields grouped under
   the option they belong to.

#### 1.0.2

 * Fixed: the dashboard counters described the size of the site rather than ContentTimer’s
   own work. The first card now reports content that is actually scheduled to expire,
   with the library size shown as context.
 * Fixed: content sent to the trash by an expiry disappeared from the plugin entirely,
   so a successful run appeared to have done nothing. Trashed content now stays 
   visible and counted on the Expired view.
 * Fixed: expiry driven by a rule was never reflected on the dashboard or the Content
   screen. Every execution is now recorded against the content, whatever triggered
   it.
 * Fixed: only one rule could ever act on a given piece of content. Each rule now
   tracks its own history, so several rules can apply in turn without blocking one
   another.
 * Fixed: rules ran in an unpredictable order when they shared an expiry moment.
 * Fixed: every expiry created a post revision, filling the author’s revision history
   with status-only entries and adding around nine database queries per item.
 * New: the Title and Expiry Date columns on the Content screen can be sorted.
 * Deleting a rule now clears the markers it left on content.

#### 1.0.1

 * New: a guided tour of the plugin, shown on first visit and available any time
   from the “Take a tour” button in the header.
 * Fixed: the admin menu icon rendered at the wrong size because its data URI was
   not in the format WordPress requires for SVG menu icons.
 * Fixed: row action menus on the Content screen appeared already open. They are
   now closed by default rather than relying on the hidden attribute winning a cascade.
 * Fixed: Quick Actions, Current Plan and the Pro card had no inner padding, so 
   their contents sat flush against the card edge.
 * Fixed: the Add New button on the Content screen shared a cramped row with the
   filter tabs; the tabs now have their own row.
 * Fixed: a rule could act on a content type that had been removed from “Content
   types to manage”.

#### 1.0.0

 * First release.
 * Per-content expiry date, time and action.
 * Rules with post type, taxonomy, author and status conditions.
 * Fixed-date and relative (“days after publishing”) schedules.
 * Actions: move to draft, make private, move to trash, unpublish, redirect.
 * Dashboard, content list, rules, logs and settings screens.
 * Batched, locked, idempotent expiry engine with WP-Cron scheduling.
 * CSV export of the expiry log.

## Meta

 *  Version **1.2.1**
 *  Last updated **1 day ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 5.8 or higher **
 *  Tested up to **7.1.2**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [content expiry](https://wordpress.org/plugins/tags/content-expiry/)[post expiry](https://wordpress.org/plugins/tags/post-expiry/)
   [redirect](https://wordpress.org/plugins/tags/redirect/)[scheduled](https://wordpress.org/plugins/tags/scheduled/)
   [unpublish](https://wordpress.org/plugins/tags/unpublish/)
 *  [Advanced View](https://wordpress.org/plugins/contenttimer/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/contenttimer/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/contenttimer/reviews/)

## Contributors

 *   [ Muhammad Siddiqui ](https://profiles.wordpress.org/muhammadsiddiqui/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/contenttimer/)