Content decay review board for your WordPress pages

Replace the monthly decay spreadsheet with a live board of pages losing search traffic, moving each one from spotted to refreshed and monitored.

App
Google Search ConsoleWordPressGoogle AnalyticsMarketingResearch & MonitoringContent Generation
PromptCreate

Build me a content decay review board for my WordPress site. Every month my content team rebuilds the same spreadsheet of pages that are losing ground in Google search, argues over which ones to rewrite, and then loses track of what happened after the rewrite. I want an app that replaces that ritual: a board of published pages grouped into lanes by refresh status, where each page carries its own numbers, an owner, notes, and a history.

Discover the account identifiers rather than asking me to paste them. Use Google Search Console List Sites and use the returned siteUrl string verbatim, because an inexact property string silently returns empty data instead of an error. Use Google Analytics List Account Summaries to find the numeric GA4 property id. If either credential can reach more than one property, let me pick from a dropdown and remember the choice.

Get the search data from Google Search Console with Search Analytics Query using the page dimension, called twice: a current window of the last 28 days and a prior window covering the 28 days immediately before it. End the current window three days before today rather than at today, because Search Console data lags two to three days and the freshest days come back artificially low. For each page produce clicks now versus clicks before, impressions now versus impressions before, the absolute and percentage change in each, and the drift in average position, where a rising position number means the page slipped down the results. Search Analytics only returns rows with at least one impression, so a page that appears in the prior window and is absent from the current one has fallen out of the data entirely rather than sitting at a clean zero. Treat that as a total loss, mark it on the row as dropped out of the data, and do not let it silently disappear from the board.

Get the CMS side from WordPress with List Posts filtered to published posts, capturing id, title, link, slug, publish date, last modified date, author and categories for each one. Page through the whole archive rather than assuming one request covers it: request the maximum per page and keep going while the page number is under the total page count returned in the response headers. Remember that WordPress returns title, content and excerpt as objects with a rendered property, not as plain strings. Use Retrieve a Post when you need the full body of a single post for the drawer or for the brief agent.

Get engagement from Google Analytics with Run Report (GA4) using the landing page dimension over the same current window, pulling sessions and the conversion metric the property exposes, which is key events on newer properties and conversions on older ones. This is the supporting signal that separates a page that lost its ranking from one people still land on but never act on.

Join the three sources by matching the WordPress post URL to the page URL that Search Console and Google Analytics report. Normalise both sides before comparing: strip the protocol and domain, drop query strings and fragments, and treat trailing slashes as equivalent. Show a small count of rows that failed to match so I can see the coverage instead of silently losing pages.

Bake in the decay rule that actually matters. Flag a page for refresh when clicks fell meaningfully, default around 20 percent or more, while impressions held flat or rose, default meaning impressions are down no more than 5 percent. That combination says demand for the topic is still there and the ranking is what slipped, which is the case a rewrite can fix. Pages where clicks and impressions both fell still belong on the board, but label them as a demand decline rather than a ranking decline so nobody wastes a rewrite on them. Exclude any page published in the last 90 days, since it is still ramping and has not settled into a stable ranking. Exclude pages under a minimum impressions floor in the prior window, defaulting to around 100 impressions and adjustable in the UI, so noise does not outrank real problems. Make all three thresholds editable from the board.

The main surface is the board itself, with four lanes: Watching, Needs refresh, In progress, and Refreshed and monitoring. Every qualifying page starts in Watching, and anything matching the decay rule gets a clear flag proposing a move to Needs refresh, which a person confirms by dragging the row across. Each row shows the page URL and title, clicks for the last 28 days versus the prior 28 with the delta, the impressions trend, the average position drift, the matched WordPress post with its last modified date and how long ago that was, the assigned owner, and a short note. Refresh status, owner, and notes are persisted in the app and must survive a data refresh, so moving a row and coming back tomorrow shows the same lane, the same owner, and the same note against freshly pulled numbers. Let me filter the board to a single owner, sort each lane by clicks lost, and see a count per lane.

Clicking a row opens a drawer for that page. Call Search Analytics Query again scoped to that single page using the query dimension with a page filter, for both the current and prior windows, then split the results into queries the page is holding, meaning it appears in both windows, and queries it has slipped on, meaning it had meaningful impressions before and has fallen away or dropped out. Show clicks, impressions and average position for each query in both windows, and note in the drawer that a query disappearing means it fell below the one impression floor rather than proving the page was deindexed. Alongside the query detail, show the page's Google Analytics sessions and conversions, the matched WordPress post with a link to edit it, the owner and notes fields, the current refresh brief if one exists, and the history of lane changes with dates.

Every row gets a Draft refresh brief button that starts a background agent for that page. The agent re-reads that page's query mix from Search Console with Search Analytics Query across both windows, retrieves the current post body from WordPress with Retrieve a Post, and looks over the rest of the published archive with List Posts to find related pages worth linking to. It works out which topics the page has lost ground on by comparing the query sets, then writes a refresh brief: what the page used to win on and no longer does, the sections to add or expand and what each should cover, headings and questions to answer, stale facts and dates to update, internal links to add with suggested anchor text and the target post, and what to leave alone because it still works. The brief has to be readable by a writer with no SEO background, so plain language and no jargon.

The brief lands back on the app row so the board is where the work lives. Show the agent run state on the row as queued, running, done or failed with the error reason, and persist both the run state and the finished brief so I can close the app, come back later, and still read briefs from earlier runs. Once a brief exists, offer an optional follow-up button that saves it into WordPress as a draft post using Create a Post with draft status, titled so it is obviously the refresh brief for that page and carrying the original post's categories. The agent must never edit, overwrite or publish the live page. Nothing goes live from this app.

The Refreshed and monitoring lane is what makes the loop close, so treat it properly. When a row moves into that lane, stamp the refresh date and snapshot the clicks, impressions and average position at that moment as the baseline. From then on the row shows check-ins at 30, 60 and 90 days after the refresh, each comparing the current 28 day window against that stored baseline, badged as recovered, flat, or still falling. A page still falling at the 90 day check-in should prompt a move back into Needs refresh rather than quietly sitting there. Persist the baseline with the row so the comparison stays honest even as the underlying data window rolls forward.

Be upfront in the UI about the limits of the data. Show the date the search data is current to and state that Google Search Console lags two to three days, that its history only goes back about 16 months so older comparisons are unavailable, and that it only reports rows with at least one impression so a missing page or query means it fell below that floor rather than proving anything about indexing. Put these where the numbers are, not buried in a settings page, because the team will be making rewrite decisions off them in a monthly review meeting.

What does this prompt do?

  • Lays every published page out in four lanes, Watching, Needs refresh, In progress, and Refreshed and monitoring, so the monthly decay review has a real home instead of a spreadsheet somebody rebuilds by hand
  • Puts the numbers that decide each call on the row itself: clicks over the last 28 days against the 28 before, the impressions trend, how far the average search position has drifted, and when the matching post was last edited
  • Flags only the pages worth rewriting, the ones where clicks fell while impressions held flat or rose, because that means people are still searching and your ranking is what slipped, and leaves out anything published in the last 90 days that is still finding its feet
  • Opens any row to show the search terms that page is holding and the ones it lost, plus its visits and conversions, with a Draft refresh brief button that has an assistant write the rewrite plan, suggested sections and internal links included, straight back onto the row

What do I need to use this?

  • A WordPress site you can log into as an editor or administrator
  • A Google Search Console account where that site is already verified
  • A Google Analytics account collecting traffic for the same site
  • At least several months of published history, since the comparison needs a before period and an after period to measure
  • The names of whoever owns content refreshes on your team, so rows can be assigned

How can I customize it?

  • Switch the comparison from 28 days to 90 if your topics move slowly and a month of data is too noisy to read
  • Tune the thresholds that flag a page for refresh, both how far clicks have to fall and how much traffic a page needs before it counts at all
  • Rename the lanes to match how your team actually works, and filter the board down to one owner or one section of the site
  • Choose whether a finished brief stays inside the app for the writer to work from or gets saved into WordPress as a draft post

FAQs

What is content decay?
It is the slow slide of an older page down the search results over months, rather than a sudden drop from a penalty. The signs are clicks drifting down and average position creeping up on a page that used to perform, which is exactly what this board puts side by side for you.
Why does the board flag some declining pages and not others?
It flags pages where clicks fell but impressions held flat or rose. That combination means people are still searching for the topic and your ranking is what slipped, which a rewrite can fix. Pages where impressions fell too are still visible on the board, but they are usually a demand problem rather than something a refresh will solve.
Why are my newest pages missing from the board?
Anything published in the last 90 days is left out on purpose. A new page has not settled into a stable ranking yet, and including it would fill the board with normal early movement instead of real decay.
How current is the search data, and how far back does it go?
Google Search Console runs about two to three days behind, so the board ends its comparison a few days back rather than at today, and it shows the date the data is current to. Search history only goes back roughly 16 months, so comparisons older than that are not available.
Will this change my live pages?
No. The assistant writes a brief that lands on the row inside the app, and the optional follow-up saves it into WordPress as a draft post. Nothing edits or republishes a live page, so your writer stays in control of what actually goes out.

Related templates

Agency reporting board that builds each client's Slides deck

See every client's month, numbers and report status on one board, then generate their branded Google Slides deck in a single click.

Google Slides
Google Analytics
Google Sheets
+1
App
One console for every SEO client's search performance

Every client site on one grid with the biggest drops first, plus a one-click monthly recap written up and posted to that client's channel.

Google Search Console
Google Docs
Slack
App
Check in bulk which of your pages Google has actually indexed

Paste a batch of URLs or pull them from your sitemaps, then see coverage, canonicals and crawl dates for every page in one sortable table.

Google Search Console
Linear
App
Build every client's monthly marketing report in one click

See every client's traffic, ad spend and search numbers on one screen, then let an agent write and design this month's report for you to approve.

Gamma
Google Analytics
Google Ads
+2
App
Find and refresh the Ghost posts quietly losing traffic

See every published post ranked by how much search traffic it has lost, then let an agent draft a refreshed version you approve before publishing.

Ghost
Google Search Console
Google Analytics
App
Gravity Forms conversion dashboard with dead form alerts

See submissions, page views, and a real conversion rate for every form on your WordPress site, with dead and declining forms flagged for you.

Gravity Forms
Google Analytics
Slack Bot
App

Stop rebuilding the content decay spreadsheet every month.

Give your content team one board where every declining page gets an owner, a brief, and a refresh date you can check back on.