Title: Unstale &#8211; Refresh Old Posts with AI, Fact-Check &amp; Republish
Author: Web &amp; SEO
Published: <strong>August 2, 2026</strong>
Last modified: September 7, 2026

---

Search plugins

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

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

# Unstale – Refresh Old Posts with AI, Fact-Check & Republish

 By [Web & SEO](https://profiles.wordpress.org/webandseofr/)

[Download](https://downloads.wordpress.org/plugin/unstale.1.14.4.zip)

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

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

## Description

Your best posts stopped bringing traffic. Not from a penalty: the prices, the statistics
and the year references inside them grew outdated while fresher pages took the rankings.
A content refresh fixes that, and Unstale runs one with real AI, through the AI 
provider you already connected to WordPress.

Point it at a published post. It reads the post, searches the live web, checks every
figure and price against what it finds, rewrites the text, updates the SEO metas,
adds internal links, and hands you the result as a diff to approve. Then it republishes
with a fresh date, without breaking your URLs.

#### What one content refresh actually does

 * **Live web research.** The refresh searches the web while it runs, so the rewrite
   is based on what is true today and not on what the model remembers.
 * **Fact-check of every number.** Outdated figures, prices and dates are fact-checked
   against the sources the refresh just read. A step that cannot verify a claim 
   says so in the journal instead of inventing one.
 * **Rewrite at the level you choose.** Minimal fixes typos, facts, internal links
   and the date. Balanced adds the SEO work: optimized metas, JSON-LD when no SEO
   plugin already emits it, key-takeaway callouts, readability.
 * **Internal linking.** Up to 15 relevant internal links per refresh, with natural,
   varied anchors, one link per target page.
 * **Pages built with Elementor, Divi or SeedProd.** The refresh reads the text 
   out of the builder’s own data, sends only that text through, and writes it back
   where it came from, so your layout and your styling are untouched. A page built
   with a builder Unstale does not support is flagged before anything runs instead
   of being rewritten behind your back.
 * **A journal per article.** Every step, every token count and the real cost, each
   on its own line.

#### Find out what has gone stale, for free

Knowing a refresh works is one thing. Knowing which of your 400 posts needs one 
is another. The Content health screen lists your published content that has not 
been updated in a while, oldest first, split into three age ranges so you can see
how much of your archive has drifted.

It reads nothing but your own database, so looking costs you nothing and needs no
AI provider connected. When you are ready, select what you want from that screen
and send it off in one batch. Unstale shows the total your provider will bill before
anything starts, and names anything it left out of the batch along with the reason.

#### Find out what competes with itself, for free

Two posts that cover the same ground do not rank together, they rank against each
other, and the newer or thinner one usually loses. The same Content health screen
scans your published content and groups the posts that overlap too closely, so you
see the competition before Google decides it for you.

The scan compares your own text with itself, on your own server: no AI provider 
needed, nothing sent anywhere, and it costs nothing to run. Each group names the
post Unstale would keep, and why. With an AI provider connected, an optional AI 
pass reads every group in context and tells two posts that merely share vocabulary
from two posts that genuinely chase the same query.

#### You keep the keys, and you keep the bill

Since WordPress 7.0, providers and credentials live in Settings > Connectors and
are managed by WordPress itself. Unstale uses whatever you set up there, so this
plugin stores no API key of its own and never sees your credentials.

Your WordPress talks to that provider directly. Your content, published or draft,
never passes through our servers. We do not see it.

You pay your provider directly, at its own rates, and nothing to us per refresh.
No credits, no monthly quota, no cap on how many old posts you refresh. Unstale 
shows an estimated cost before each launch and logs the real one after.

#### Nothing goes live without you

Every refresh waits in a review queue with a side-by-side diff of the current post
and the proposed one. You approve it or you discard it. An optional full-auto mode
exists for people who want it, off by default. Approved changes are applied as a
normal WordPress revision, so one click rolls them back when revisions are enabled
on your site.

#### Republishing that does not break your URLs

Republishing plugins usually warn you not to use them when your permalinks contain
the post date, because bumping the date moves the URL. Unstale skips the bump automatically
when your permalink structure uses the core date tags. To keep dated URLs and still
refresh the date, switch to the %unstale_year%, %unstale_monthnum% and %unstale_day%
tags: they freeze the original date in the URL for good. Republication also carries
position control, randomized timing, allowed days and time windows.

#### Works with what you already run

Unstale fits the stack you have instead of asking you to change it, and none of 
this needs a setting: it detects what is active and adapts.

 * **Page builders: Elementor, Divi and SeedProd.** The refresh rewrites the text
   inside the page the builder already built and puts it back in the builder’s own
   data, so your layout, your styling, your images and your builder settings come
   back exactly as they were. On a SeedProd page that uses blocks from SeedProd 
   Pro, the new text lands in the builder and the live page waits for you to reopen
   it and save, which the journal tells you plainly.
 * **SEO plugins: Yoast SEO, Rank Math, All in One SEO and SEOPress.** The rewritten
   meta title and description go straight into that plugin’s own fields, not into
   a second set of fields your theme would ignore. Unstale also stops emitting its
   own JSON-LD while one of them is active, so a refreshed post never ends up carrying
   two Article schemas. With no SEO plugin installed, Unstale writes the metas and
   the structured data itself.
 * **Cache plugins: WP Rocket, W3 Total Cache, LiteSpeed Cache, WP Super Cache, 
   WP Fastest Cache and SG Optimizer.** Once a refresh is published, Unstale purges
   the post through that plugin’s own public purge API so the new version is live
   at once. The purge is always aimed at the refreshed post, never a full-site flush,
   so the rest of your cache stays warm. Anything not on that list, a CDN for instance,
   hooks onto the unstale_purged action.
 * **Editors and content types.** Gutenberg and the Classic editor both, on posts,
   pages and public custom post types.

#### What Unstale does not do

It does not write new articles. It works only on posts you already published, which
is the point: the traffic is easier to win back on an evergreen post that once ranked
than on a new one nobody has read. It does not read Search Console and does not 
rank your archive by traffic lost, so you choose which old posts to refresh, one
by one or in batches from the Content health screen. And there is no account to 
create anywhere.

Two refresh levels are free: Minimal and Balanced, and so is sending a batch off
from the Content health screen. The Strong and Maximal levels, scheduled automation
and per-category rules are part of [Unstale Pro](https://unstale.ai/). Automation
of the free levels is available through the REST API (unstale/v1) and WP-CLI (wp
unstale refresh).

Unstale is developed by [Web & SEO Ltd](https://webandseo.dev/), the company that
owns and operates unstale.ai.

### External services

This plugin relies on one external service.

#### The Unstale model catalog (unstale.ai)

What it is: a public, static JSON file at https://unstale.ai/api/v1/models.json 
listing the supported model ids, their prices per million tokens and their notes.
It exists so that a new provider model becomes available in your settings without
waiting for a plugin update, and so the plugin can show you a cost estimate before
each refresh.

What is sent, and when: nothing but the HTTP request itself. It is an unauthenticated
GET, fired by a single scheduled task once every 24 hours. No content, no credentials,
no personal data, no site identifier is transmitted, and there is no manual refresh
button that could trigger it more often. If the request fails the plugin keeps using
the catalog bundled in the plugin files.

This service is provided by Unstale: [Terms](https://unstale.ai/terms), [Privacy](https://unstale.ai/privacy)

#### A note on AI providers

Unstale does not contact Anthropic, OpenAI or Google itself and declares none of
them as its own external service. Prompts are handed to the WordPress AI Client,
which routes them to the provider you connected in Settings > Connectors. That provider,
its terms and its billing are the relationship between you and them, set up in WordPress
and not in this plugin.

## Screenshots

[⌊Content health: which published content has gone stale, and by how much⌉⌊Content
health: which published content has gone stale, and by how much⌉[

Content health: which published content has gone stale, and by how much

[⌊Side-by-side diff before approval⌉⌊Side-by-side diff before approval⌉[

Side-by-side diff before approval

[⌊Review queue with per-job actions⌉⌊Review queue with per-job actions⌉[

Review queue with per-job actions

[⌊Settings: connected AI provider, model cards, and what each refresh level costs
per 1,000 words⌉⌊Settings: connected AI provider, model cards, and what each refresh
level costs per 1,000 words⌉[

Settings: connected AI provider, model cards, and what each refresh level costs 
per 1,000 words

[⌊Journal: every refresh with its token counts and real cost, exportable to CSV⌉⌊
Journal: every refresh with its token counts and real cost, exportable to CSV⌉[

Journal: every refresh with its token counts and real cost, exportable to CSV

[⌊The Unstale block under the post editor: start a refresh, then read what it changed⌉⌊
The Unstale block under the post editor: start a refresh, then read what it changed⌉[

The Unstale block under the post editor: start a refresh, then read what it changed

[⌊Get started: the five posts that have waited longest, and one button to queue 
them all⌉⌊Get started: the five posts that have waited longest, and one button to
queue them all⌉[

Get started: the five posts that have waited longest, and one button to queue them
all

## Installation

 1. Install and activate the plugin. WordPress 7.0 or newer is required.
 2. Go to Settings > Connectors and connect an AI provider if you have not already.
    Unstale will tell you if none is connected.
 3. Go to Unstale > Settings, pick a default model and refresh level.
 4. In the Posts list, click “Refresh with Unstale” on any published post. Review the
    estimated cost, confirm, then approve the proposed rewrite in Unstale > Review 
    queue.

## FAQ

### How much does a refresh cost?

You pay your AI provider directly, per token. Unstale shows an estimate BEFORE each
launch and logs the real cost after. For a 1000-word article at the Balanced level
the estimate runs from roughly $0.08 on the cheapest model in the catalogue to roughly
$0.73 on the dearest, depending on the model you pick. That estimate bounds the 
worst case (it assumes every web search the level allows is spent), so the cost 
logged after the run is lower: on the cheapest model, measured runs land around 
two cents.

Models whose provider grants a monthly allowance of free web searches are estimated
with that allowance applied, and the confirmation screen says so. A site that refreshes
enough articles in one month to exhaust the allowance will pay for the searches 
beyond it, which the estimate does not yet track.

Web search fees are part of the estimate shown before a refresh, but not of the 
cost logged after it. None of the three provider plugins passes the number of searches
back to WordPress today, so the plugin cannot price them once the run is over. The
journal says so instead of showing a zero, and the estimate remains the honest figure
for that part of the bill.

### How is this different from a plugin that just changes the publish date?

A date bump moves an old post back to the top of your feeds, but the text stays 
exactly as outdated as it was. Unstale rewrites the content first: it researches
the subject on the live web, corrects the figures and prices that aged, updates 
the metas and the internal links, and only then republishes. The date bump is the
last step of the job, not the whole job.

### Can I try it on a single post before touching my archive?

Yes, and that is the default path. The Posts list has no bulk action: you refresh
one post at a time, review the diff, and approve or discard. Nothing sweeps your
archive unless you ask for it, either by ticking the posts you want on the Content
health screen, from WP-CLI (wp unstale refresh –all, which asks you to confirm first,
because every job spends money at your provider), or through the scheduled rules
in Unstale Pro.

### Does my content go through your servers?

No. WordPress calls the provider you connected, directly. The only request to unstale.
ai is the public model catalog (no content, no personal data).

### Which API key does it use?

None of its own. Since WordPress 7.0, credentials live in Settings > Connectors 
and are managed by WordPress. Unstale never sees, stores or transmits them. If you
used an older version of this plugin, the API keys it had stored are deleted automatically
when you update.

### Can it publish without my approval?

Not by default. Every refresh waits in the review queue with a side-by-side diff.
You can enable full-auto publishing in the settings if you want it.

### My permalinks contain the post date. Will the date bump break my URLs?

No: the bump is skipped automatically when your permalink structure uses the core
date tags. To keep dated URLs AND bump dates, switch your structure to the %unstale_year%,%
unstale_monthnum% and %unstale_day% tags: they freeze the original date in the URL
forever. If you deactivate Unstale later, the plugin automatically restores the 
core date tags so your site keeps routing (posts whose date was bumped will then
use the bumped date in their URL). Deleting the plugin files manually without deactivating
skips that safety net: re-save your permalink structure in that case.

### Does it work with my page builder, my SEO plugin and my cache plugin?

Page builders: Elementor, Divi and SeedProd. The refresh rewrites the text inside
the page the builder already built, so nothing about your layout moves. Unstale 
asks you to confirm before refreshing any builder-built page, whichever builder 
it is, so nothing is ever rewritten behind your back.

SEO plugins: Yoast SEO, Rank Math, All in One SEO and SEOPress. The meta title and
description go into their own fields, and Unstale stops emitting its own structured
data so you never get two Article schemas on one post. With no SEO plugin, Unstale
writes both itself.

Cache plugins: WP Rocket, W3 Total Cache, LiteSpeed Cache, WP Super Cache, WP Fastest
Cache and SG Optimizer. Only the refreshed post is purged, never your whole cache.
A cache or CDN outside that list plugs onto the unstale_purged action.

None of it needs configuring: Unstale detects what is active on your site and adapts.

### Which models are supported?

Whichever models the provider you connected exposes. Unstale ships model cards for
Claude Sonnet 5 (default), GPT-5.6 Terra and Gemini 3.8 Flash, with pricing and 
ratings to help you choose. All three are generally available, so the model you 
pick is the model that runs; if the catalog ever marks one as preview, Unstale runs
its fallback instead and states the substitution on the model card and in the job
log. The catalog is updated remotely: when a provider ships a new model, it appears
in your settings without a plugin update.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“Unstale – Refresh Old Posts with AI, Fact-Check & Republish” is open source software.
The following people have contributed to this plugin.

Contributors

 *   [ Web & SEO ](https://profiles.wordpress.org/webandseofr/)

[Translate “Unstale – Refresh Old Posts with AI, Fact-Check & Republish” into your language.](https://translate.wordpress.org/projects/wp-plugins/unstale)

### Interested in development?

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

## Changelog

#### 1.14.4

 * Fixed: a step that failed twice in the same paid way went on to buy a third attempt
   that could only fail the same way. Retrying is the right answer when the trouble
   is passing, a provider under load or a connection that never answers, and those
   attempts are not billed because nothing came back. It is the wrong answer once
   the model has answered and its answer could not be used, because the next attempt
   sends exactly the same thing again. Measured on a real site: one post burned 
   nine paid rewrite calls over three manual retries and produced nothing at all.
   Unstale now stops after the second paid failure of the same kind, and the job
   log says why, instead of leaving a batch that will never go through looking like
   a network problem. Failures that cost nothing, a blocked connection for instance,
   keep all three attempts as before, and a retry you start yourself always begins
   again with the full budget, which is what you want right after installing a fix.

#### 1.14.3

 * Fixed: a long post could fail its refresh over and over with “The answer from
   the model was cut off at the output limit”, and retrying never helped. Unstale
   splits a long post into batches before rewriting it, and it sized each batch 
   in words, counted after stripping every tag and every HTML comment. On a post
   built with blocks, a large part of a batch was therefore invisible to that budget
   while still having to be rewritten in full. Measured on a real site: four batches
   of 700 to 785 words weighed 11149, 10003, 11132 and 21080 bytes, and the heaviest
   one asked for more of an answer than the model was allowed to give. Because the
   split is the same on every attempt, that batch came back identical every time,
   which is why retrying could not fix it. Batches are now sized on what actually
   gets sent, so one can no longer quietly grow to twice the size of its neighbours.
 * Fixed: the room allowed for a rewritten batch was shared with the model’s thinking,
   and a model that thinks before it writes spends it there first. Same batch and
   same request on a real site: one attempt was cut short after 540 tokens of answer,
   the next one finished in 3450. That is why a batch of refreshes often needed 
   one or more retries even on posts that eventually went through. The room allowed
   is now twice as large, which costs nothing extra: only the answer is billed, 
   never the room.
 * Fixed: updating Unstale while a long post was halfway through its rewrite could
   publish that post with one passage duplicated and another missing. The batches
   already rewritten only make sense for the split that produced them, and this 
   release changes that split. Unstale now records the split alongside its progress
   and starts the rewrite over when the two no longer match.

#### 1.14.2

 * Fixed: when the AI checked a group and found no cannibalization, Content cannibalization
   announced it as “AI could not confirm this group”, which reads as a tool that
   broke rather than a check that ran. The AI had run: it read the posts, decided
   they do not compete for the same query, and the sentence shown under the group
   is its reason. That is the whole point of this check, since the first pass groups
   posts on shared vocabulary alone and the AI is what tells apart the ones that
   really compete. A verdict now reads as a verdict, and the three sentences that
   do announce a breakdown stay clearly apart from it.
 * Fixed: roughly one verdict in seven was paid for and never delivered. Unstale
   allowed 1024 output tokens for one verdict, and a model that thinks before it
   writes spends that room on the thinking, so the answer stopped mid-sentence and
   was reported as an answer that could not be read. Measured on a real site with
   three long posts: two calls out of thirteen were cut short at 1024, none out 
   of twelve at 4096. The room allowed for an answer is now four times larger. The
   price shown before you click does not change, because it is now worked out from
   the output these checks actually produce instead of from the ceiling they are
   allowed.

#### 1.14.1

 * Fixed: Confirm with AI, on the Content cannibalization section, answered “This
   cannibalization group no longer exists” for every group on screen, from the first
   click. The list Unstale keeps between a scan and that click is thrown away whenever
   any post on the site is saved, published, unpublished or deleted, by anyone and
   by any plugin: a refresh published by the Pro automation, a revision, a form 
   entry stored as a post. One such event between the scan and the click was enough
   for the check to find nothing to confirm, and to say so about groups still on
   screen and still there to be computed. The check now recomputes the groups when
   that list is gone, exactly as the scan already did, and finds each group by the
   posts it holds rather than by its position in a list that may have changed shape
   since. A group whose composition really did change is noted under its own card
   and the check moves on to the next one, instead of stopping the whole run on 
   the first.
 * Fixed: the Excluded tab on Content health listed every item of a content type
   Unstale never refreshes, one line each, and counted them as excluded items. A
   site with two thousand affiliate links stored as their own content type read “
   2,000+ more items are excluded” above a tab capped at a hundred pages, with the
   exclusions you can actually undo buried under them. A content type with no search
   surface is one decision, not two thousand: such types now appear once each, with
   a count, in their own table under the list, and the count above the list covers
   only what you can reintegrate, your own exclusions and the noindex ones.

#### 1.14.0

 * Fixed: Confirm with AI, on the Content cannibalization section, answered “AI 
   could not confirm this group” for every group and gave no reason. The model had
   refused nothing: its answer was cut off before it began. Unstale allowed 200 
   tokens for a verdict, and a model that thinks before it writes spends that room
   on the thinking, so the visible answer stopped after a few characters and was
   read as a refusal. The cap is now 1024 tokens, and an answer that is cut short
   or cannot be read is shown as a failure with its cause, never as a verdict. Measured
   on a real site: given room, the same model rejected a group of four single-plugin
   reviews and a group of three yearly retrospectives, each with a sentence saying
   why, which is exactly what this check exists to do.
 * Fixed: the AI check asked for the catalog’s recommended model instead of the 
   one you chose in the settings. On a site with a single provider connected it 
   landed on the right model by chance; with two, the click would have gone to the
   other provider at the other price while the estimate named yours.
 * Fixed: the cannibalization scan grouped content that Content health already excludes:
   pages your SEO plugin marks noindex, and posts you excluded by hand. A page search
   engines do not index competes with nothing, and a post you excluded is not one
   to consolidate. Both now stay out of the scan, a post excluded after a scan drops
   out of its group, and the Pro weekly sweep applies the same rule.
 * Fixed: after a scan, titles in the cannibalization cards could show raw HTML 
   entities, an ampersand written as a code for instance. They now read as text.
 * Fixed: a server reply that was not JSON, a maintenance page or a firewall answering
   in place of WordPress, was read as an empty verdict and shown as “could not confirm”.
   It is now reported as a failed request.

#### 1.13.0

 * New: a notice tells you when your default refresh level is one your plan no longer
   allows. Deactivate or remove the Pro add-on while Strong or Maximal is your default
   and every refresh stops: row actions, the REST API and WP-CLI all refuse, and
   no screen said why. The notice names the level and says what actually repairs
   it, which is to choose a level and save, not merely to open the settings screen.
   It changes nothing on its own. A setting you chose is not rewritten behind your
   back.
 * Fixed: the settings screen shows the refresh level you actually saved. When your
   plan locked the level you had picked, the slider slid back to Balanced on its
   own while the database still held Strong, so the screen said one thing and your
   site did another. Saving any unrelated setting on that page then wrote Balanced
   over your choice. The slider now reflects what is stored, even a locked level,
   and saving a locked level overwrites nothing: Unstale keeps your setting and 
   names the reason it cannot be used.
 * Fixed: a model that leaves the catalog now stops the job instead of quietly calling
   another provider. A site that had chosen a Google model could end up calling 
   Anthropic without asking for it, without being told, and without necessarily 
   having connected it. The estimate showed the other model’s price, and the log,
   the review queue and the API could name a model that never ran. A retired model
   is now refused by name, and what gets logged and billed is what actually ran.
 * Fixed: the bulk refresh screen stops on a level your plan has locked, instead
   of sending you to check your AI provider. It priced an estimate at that level,
   every item then failed, and the notice blamed the provider for what was a plan
   problem.
 * Fixed: an Elementor floating button, the WhatsApp or contact button that hovers
   over your pages, is no longer treated as refreshable content. It sat in Content
   health with an active Refresh link and could be picked as an internal-link target.
   What removes it is a property any content type declares for itself, not a list
   of plugin names, so every page builder that registers an interface widget as 
   public content is covered: a type its own developer keeps out of navigation menus
   is not editorial content. WooCommerce products declare the opposite and stay.

#### 1.12.0

 * New: content your SEO plugin marks noindex is now left out of Content health.
   A page you have told search engines not to index is not a page worth spending
   a refresh on, and until now it sat in the list with an active Refresh link. Unstale
   reads that setting from Yoast SEO, All in One SEO, SEOPress and Rank Math. Each
   one was read against its own source and then measured on a real site, because
   the four disagree in ways that matter: three of them let a single post say “index”
   and override a site-wide or per-type noindex, one of them does not, and one stores
   a value whose name says index while it means the opposite. Anything Unstale cannot
   read for certain stays in the list. Hiding a page you are actually trying to 
   rank is the worse mistake of the two, so every doubt is settled in favour of 
   showing it, and settings that apply to your archives, tag pages or attachments
   are never read as if they applied to your posts.
 * New: an Excluded tab on the Content health screen, listing what Unstale never
   refreshes and who decided it. Three reasons show up there: a content type with
   no search surface, a post you excluded by hand, and a noindex set in your SEO
   plugin. The noindex rows name the plugin that set it, so a verdict you did not
   expect can be traced back to the screen it came from instead of leaving you to
   guess. Posts you excluded by hand keep their Reintegrate link right there in 
   the tab. The tab only covers content old enough to be checked, so it is not a
   list of every noindex page on your site, and it says so.
 * Fixed: refusing to refresh an excluded post sent you to the wrong screen. The
   message said to reintegrate it from Content health, which is exactly where an
   excluded post no longer appears. It now names your posts list, where the Reintegrate
   link actually is.

#### 1.11.0

 * New: an Exclude link, next to Refresh, in your posts list and on the Content 
   health screen. Some posts should never be refreshed: a landing page tuned by 
   hand, a legal notice, an article whose wording was signed off. Excluding one 
   takes it out of the Content health screen and out of every list Unstale draws
   its work from, and a refresh started on it anyway is refused rather than run,
   so a bulk action or a job queued earlier cannot walk over your decision. An excluded
   post still shows in your posts list, where the link reads Reintegrate: nothing
   here is one-way.
 * Fixed: content types with no search surface no longer appear as posts to refresh,
   nor as internal-link targets. Popup Maker popups, Elementor templates and the
   Elementor Default Kit showed up on Content health with an active Refresh link,
   and Unstale could place a link to one of them inside a published article. The
   criterion that removes them was measured on a real site rather than guessed: 
   a type must be viewable and not excluded from search. WooCommerce products pass
   both halves and stay. Attachments are dropped on their own terms, a media file
   not being editorial content.
 * Fixed: a bulk refresh that refuses a post now says why. When the post was of 
   a type Unstale does not refresh, it failed without a word.

#### 1.10.0

 * New: a refresh now checks the figures it added itself. The fact-check has always
   run on your original article, before the rewrite, so a price, a percentage or
   a date that the rewrite introduced reached the review screen without ever having
   been held against a source, underneath a count of checked facts that read as 
   a green light for the whole proposal. Unstale now takes the passages carrying
   a figure your original article did not have, searches the web for each one, and
   lists on the review screen the added figures that are outdated or that no source
   confirms, with a source link next to each. It runs at every level, Minimal included,
   because a refresh adds figures there too. It calls no model at all when the refresh
   added none, so a rewrite that only rephrases costs exactly what it cost before.
   The estimate you approve before a refresh now covers the searches this step can
   make, which is why it reads higher than it did on 1.9.1.
 * Fixed: the line counting checked facts now says what it looked at. It reads “
   5 claims checked in the original article” rather than “5 claims checked”, because
   that check runs before the rewrite and says nothing about the text shown underneath
   it. What the refresh added gets its own line, right below, so the two counts 
   can no longer be taken for one.
 * Fixed: the Journal no longer reports 0 searches for refreshes that did search
   the web. Not one of the AI provider plugins passes that count on to WordPress
   today, so zero was never a measurement, on a plugin whose live web search is 
   the point. The Journal now says the count was not reported by the provider plugin,
   and the cost recorded beside it is documented as a floor rather than the whole
   bill: the search fee is in the estimate you approve before a refresh, not in 
   the cost logged after it. The day a provider plugin reports the count, it shows
   up on its own, with nothing to change on your side.

#### 1.9.1

 * Fixed: when the catalog replaces a model with a newer one from the same family,
   your site now follows the upgrade instead of staying behind. A site set to Gemini
   3.7 Flash moves to Gemini 3.8 Flash, and the day Claude Sonnet 5 replaces Sonnet
   4.8 a site set to the older one moves to Sonnet 5. The move stays inside the 
   family: a replacement that would send you to a different provider, one you may
   hold no credentials for, is refused rather than followed. Your setting is rewritten
   once, so the settings screen, the job log and the cost estimate all name the 
   model that actually runs. A model that is simply unknown is left alone, because
   turning a fallback into a saved choice you never made would be worse than leaving
   it visible.

#### 1.9.0

 * Fixed: a refresh could change how your article speaks to its reader. An article
   written in the informal address came back formal, on a level whose instructions
   ask the model to speak to the persona the page describes: nothing told it which
   address the article already used, so it chose one. Unstale now measures the voice
   of your article before rewriting it, the form of address and the person it speaks
   in, and holds every step that writes to what it found. That includes the step
   that writes your meta description, which is the part Google shows and the part
   that addresses the reader most directly. An article whose voice cannot be measured
   is rewritten exactly as it was before, and so is any refresh queued before this
   version.
 * New: the Unstale block under the editor now tells you, before you start, whether
   the refresh will move the post’s publish date. The setting has always been there,
   under Republication between two time fields, and nothing said what it would do
   until it had done it. Reasons that depend on the post or on the moment are still
   settled when the refresh republishes, because they cannot be known in advance
   and announcing them would promise wrongly.
 * Fixed: the model catalog now records when a model is renamed. Gemini 3.7 Flash
   became Gemini 3.8 Flash on 4 September, and for part of that day a site that 
   had chosen it fell back to the recommended model instead: a different provider,
   and about three times the cost per refresh. The catalog was corrected the same
   day for every site, with no update needed. From this version a renamed model 
   keeps your choice and its own rate on the cost screen, and the job log names 
   the reason for any substitution rather than reporting a preview that does not
   exist.

#### 1.8.3

 * Fixed: on a site made of short pages, such as product sheets or answers to a 
   single question, Content health found few competing posts and could miss two 
   pages that said the same thing word for word. Every pair was measured against
   the length of a full page, so a short post never had enough to give and could
   not reach the mark whatever it said. A pair is now measured against the shorter
   of the two posts, so short pages that cover the same ground are found the way
   long ones already were. Posts long enough to fill a comparison are scored exactly
   as before, so nothing Unstale already found on your site moves. Pages carrying
   too little distinctive text to say anything either way are still left out rather
   than guessed at.

#### 1.8.2

 * Fixed: on a site written in a language that does not put spaces between words,
   Content health found very few competing posts, and often none at all. Unstale
   compares character sequences instead of words for those languages, but it decided
   when to switch by counting characters per word, and Chinese never reached the
   mark: Chinese punctuates, so every comma cut the text into pieces short enough
   to pass for ordinary words. Thai did not reach it either. Japanese did, but only
   past a length that was there to protect German compound words, so shorter Japanese
   posts stayed invisible whatever they said. Unstale now looks at the writing system
   itself, so Chinese, Japanese, Thai, Lao, Khmer and Burmese are compared properly
   at any length. Korean, which does separate its words, is unchanged, and so is
   every language written with spaces.

#### 1.8.1

 * Fixed: on the Content health screen, a group of more than 25 posts that share
   a vocabulary is a template rather than competition. Product listings, location
   pages and archives are built from one layout, so Unstale never sends such a group
   to the optional AI pass and never charges you for a verdict on it. The screen
   did not say so: it showed “AI could not confirm this group.”, word for word what
   it shows when the model has looked at a group and disagreed. A template therefore
   read as a verdict that had never been asked for, which is the most reassuring
   way to be wrong. These groups now say that the pages share a layout rather than
   a topic, and that no model was called. A group the AI genuinely could not confirm,
   and a provider that failed to answer, still say exactly what they said before.

#### 1.8.0

 * New: the Content health screen now also finds published posts that compete with
   each other over the same topic, grouped together with the post Unstale would 
   keep and why. The comparison runs on your own site, with no AI provider needed
   and at no cost: it looks only at your own text, never at anyone’s rankings. With
   an AI provider connected, an optional AI pass on each group tells two posts that
   merely share vocabulary from two that genuinely target the same query, and says
   in one line why it disagrees when it does, before you decide what to do about
   it. The screen tells you what that pass would cost before you start it, and calls
   no model until you say so.
 * If you use the Unstale Pro add-on, groups found by its weekly sweep now show 
   on this screen too, whatever content types you are allowed to edit. Until now
   the sweep could report a group by notice that the screen itself would not list.
   Needs Unstale Pro 1.3.0 or newer; without the add-on nothing changes.

#### 1.7.0

 * New: a Get started screen, which opens by itself the first time you activate 
   Unstale. It lists the five posts that have gone longest without an update, with
   their age, and one button that queues all five. Nothing is spent from that button:
   it hands you the same estimate screen every other launch goes through, so you
   still see the cost and confirm before any model is called. If no AI provider 
   is connected yet, the five posts are shown anyway, with a link to connect one:
   you see what Unstale would work on before being asked for anything. The screen
   stays in the Unstale menu as Get started, so you can come back to it whenever
   you want a batch ready to launch.

#### 1.6.0

 * New: a Restore button in the Unstale block, on a post whose refresh has been 
   published. It puts the post back as it was before that refresh: the text, the
   publish date the refresh moved, and the SEO title and description it wrote. Field
   by field, and only what the refresh itself changed: anything you edited since
   stays yours, and the confirmation screen names exactly what will go back rather
   than quietly overwriting the rest.
 * New: a notice across the admin when refreshes are waiting for your review. A 
   refresh that finishes while you are working elsewhere no longer waits unnoticed.
   With one waiting, the notice opens its diff directly; with several, it opens 
   the review queue. It stays off the Unstale screens, which already list that queue.
 * New: the Unstale column in the posts list now colours the age of the last refresh,
   on the same thresholds as the Content health screen. One glance down the list
   shows what has drifted, without opening another screen. The colour only repeats
   what the cell already says in words, so nothing is lost if you do not see it.
 * New: an Export CSV button on the Journal, which carries whatever filter you are
   looking at. Costs come out as plain numbers a spreadsheet can add up, and the
   file holds only the posts you are allowed to edit.
 * New: the refresh level slider in Settings now shows what each level costs per
   1,000 words, and the figure follows both the slider and the model you pick. The
   levels reserved for Unstale Pro show their cost too, so you can see what they
   would cost before deciding.

#### 1.5.1

 * New: if you use the Unstale Pro add-on, the Unstale block under the editor now
   tells you what the automation decides for the post you have open: which category
   rule governs it, the refresh level that rule imposes, and when the next scheduled
   pass runs. Above all it says when a rule excludes the post, which until now was
   invisible: you could believe a post was covered by the automation while nothing
   would ever pick it up. Needs Unstale Pro 1.0.3 or newer; without the add-on, 
   or on an older one, the block looks exactly as it did.

#### 1.5.0

 * New: an Unstale block under the post editor, above the one your SEO plugin puts
   there. Pick a refresh level, start the refresh and follow it step by step without
   leaving the page you are writing on, in both the block editor and the classic
   editor.
 * New: once a refresh is ready, that same block lists everything it did to the 
   post: how its length changed, which outdated facts were corrected and against
   which source, the new meta title and description, the structured data, every 
   internal link placed with its anchor, and the blocks inserted into the body.
 * New: on the free plugin, picking Strong or Maximal opens a note saying what that
   level would add to the post you have open, naming the secondary queries, the 
   reader profile, the content gaps and the products Unstale already found for it.
   With no refresh run yet it says what those levels do without putting numbers 
   on it: nothing is invented to make the case. The note stays out of the way until
   you ask for it, and it does not exist at all once a Pro licence unlocks those
   levels.

#### 1.4.2

 * Fixed: on the Content health screen, every post that had never been refreshed
   carried an empty line inside its Unstale cell. The Refresh link dropped to the
   bottom of the cell and the row stretched to match. A site that has just installed
   the plugin has refreshed nothing yet, so the whole table showed it, and Content
   health is the first Unstale screen a new site opens.

#### 1.4.1

 * Fixed: the model catalogue shipped with the plugin still expected Claude Sonnet
   5 to get more expensive on 1 September. Anthropic made its $2 / $10 per million
   tokens permanent on 10 August and cancelled that increase. Sites already pick
   up the correction from the online catalogue within a day; this puts it in the
   plugin itself, so a fresh install starts with the right figure.
 * New: if you use the Unstale Pro add-on, its licence key field now appears in 
   Unstale > Settings, next to the refresh levels it unlocks, instead of only under
   its own Licence menu. Nothing changes without the add-on.

#### 1.4.0

 * Fixed: on a site using All in One SEO, a refresh wrote its new title and description
   where nothing ever read them. AIOSEO has kept its data in its own table since
   version 4, and the fields Unstale was writing are only read once, when migrating
   from version 3. Your pages did not move, and the journal still reported success.
   Unstale now writes through AIOSEO’s own interface, and All in One SEO joins Yoast,
   Rank Math and SEOPress in the supported list.
 * Fixed: the cost announced before a refresh was far too high on Google models,
   by about fifteen times. Two separate causes. The token estimate was calibrated
   on a provider that bills web search results as input tokens, which Google does
   not. And the free monthly search allowance some providers grant was never taken
   into account, although the plugin already knew about it. On a 500-word article
   at the Balanced level, the estimate went from 24 cents to 4, against 2 cents 
   actually measured.
 * Fixed: Elementor, Divi and SeedProd pages no longer raise a page builder warning.
   Those three are exactly what a refresh knows how to handle without moving your
   layout, so sending them to a notice that said the result may be unexpected told
   you the opposite of the truth. The warning is now kept for a builder Unstale 
   has no adapter for, and it says what would really happen: the refresh would rewrite
   the standard WordPress content, not the page your visitors see.
 * Fixed: a page builder section holding a script or a style block could carry that
   code into the rewritten text. The block is now removed with its contents.
 * Improved: the cost question in this readme now gives the real range across the
   catalogue instead of a single guess, and says when web searches are covered by
   a provider’s free monthly allowance.

#### 1.3.2

 * Fixed: on a site running PHP 8.1, Unstale did not work at all. One of its files
   used a piece of syntax that …

## Meta

 *  Version **1.14.4**
 *  Last updated **58 minutes ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 7.0 or higher **
 *  Tested up to **7.1**
 *  PHP version ** 8.1 or higher **
 *  Language
 * [English (US)](https://wordpress.org/plugins/unstale/)
 * Tags
 * [content refresh](https://co.wordpress.org/plugins/tags/content-refresh/)[evergreen content](https://co.wordpress.org/plugins/tags/evergreen-content/)
   [fact check](https://co.wordpress.org/plugins/tags/fact-check/)[old posts](https://co.wordpress.org/plugins/tags/old-posts/)
   [republish](https://co.wordpress.org/plugins/tags/republish/)
 *  [Advanced View](https://co.wordpress.org/plugins/unstale/advanced/)

## Ratings

No reviews have been submitted yet.

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

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

## Contributors

 *   [ Web & SEO ](https://profiles.wordpress.org/webandseofr/)

## Support

Got something to say? Need help?

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