SEO

How to Run a WordPress Content Audit (Step by Step)

WordPress content audit — featured card

A content audit is a structured review of everything you’ve published: what it earns, what it costs you, and what you’re going to do about it. Not a skim of your archive — an inventory, joined to real data, with a decision written next to every URL.

Most sites publishing for two or three years are carrying dead weight: posts that ranked once and quietly decayed, three articles that all half-answer the same question, old landing pages nobody has looked at since. None of it is a disaster alone, but together it dilutes your topical focus and spreads your internal links across pages you don’t care about.

The good news: an audit is one of the few SEO projects where the work is mostly decision-making rather than production. You already wrote the content. Here’s the process we use, in five steps.

Why bother? The four problems an audit actually solves

Content decay

Rankings are not permanent. A post that hit position 4 two years ago slides as competitors publish fresher versions and as the query itself shifts. Decay is gradual — traffic doesn’t fall off a cliff, it leaks. An audit catches the leak by comparing each URL’s performance now against a year ago.

Thin and duplicate content

Every site has them: the 300-word post written to hit a quota, near-identical announcements, tag archives with one item in them. Individually harmless; collectively they tell search engines a meaningful share of your site is low value.

Cannibalization and crawl waste

Cannibalization is two of your pages competing for the same query — the most common finding in a first audit, and the one people most often get wrong, so it gets its own section below. Crawl waste is the quieter cousin: search engines give your site finite attention, and if a large share of your URLs are archives, thin posts and old redirects, the crawler spends its time there instead of on the pages you’re trying to rank. On a 50-post blog that doesn’t matter; on a 2,000-URL site it does.

Step 1: Build the inventory

You can’t audit what you haven’t listed. The goal is one spreadsheet, one row per URL. Three ways to get it, in rough order of effort:

  • Your XML sitemap. The fastest complete source — Yoast, Rank Math and WordPress core all publish one at /sitemap_index.xml or /wp-sitemap.xml. Copy the sub-sitemap URLs into a sheet. Captures posts, pages, and custom post types you’d forgotten about.
  • The WordPress admin list. Posts → All Posts, items per page set to 999 in Screen Options. Also shows the drafts and private posts your sitemap won’t.
  • A crawler. Screaming Frog’s free tier handles 500 URLs, and adds what the other two can’t see — word count, response codes, title tags, and crucially the internal link count per URL.

Columns to start with: URL, title, post type, category, publish date, last modified date, word count. Add the data in step 2.

While you’re here, check the URLs actually resolve — old posts accumulate broken links and occasionally break themselves after a slug change. Our guide to finding and fixing broken links in WordPress covers that, and it’s cheaper during an audit than later.

Step 2: Pull the data

An audit without data is opinion. Three sources, all free.

Google Search Console

The most important one. Performance → Search results, date range set to the last 12 months, all four metric checkboxes enabled (clicks, impressions, CTR, average position), switch to the Pages tab, export. Then do it again for the previous 12 months and put both in your sheet side by side. The year-over-year delta is where decay becomes visible: a post that went from 400 clicks to 120 tells you something a single-period export never would.

Also export the Queries tab — you’ll need it for the cannibalization work.

GA4

Reports → Engagement → Pages and screens, for sessions, engagement rate and average engagement time. GA4 tells you what happens after the click, which GSC can’t: a page with decent traffic and a 12-second engagement time is a different problem from one with no traffic at all. Be sceptical on short-answer content, though — a post that answers a question in two sentences should have a short dwell time.

Publish and last-modified dates come from your inventory; inbound internal link count comes from a crawler or an internal-linking plugin. That last column matters more than people expect: a page with strong impressions, poor position and zero internal links usually doesn’t need a rewrite. It needs links.

Step 3: Score every URL into one of four buckets

Now the actual audit. Assign each URL exactly one of KEEP, UPDATE, CONSOLIDATE or REMOVE. One decision per row, no “maybe” column — a maybe column is how audits die.

Bucket Criteria Typical signals
KEEP Performing at or near its potential; no obvious defect Stable or growing clicks YoY, average position 1–5, no competing page on the same query
UPDATE Real demand exists but the page isn’t capturing it High impressions, low CTR; position 6–20; clicks down >30% YoY; last modified over 18 months ago; factually stale or thin next to what outranks it
CONSOLIDATE Overlaps another page on your own site Two or more URLs appearing for the same query in GSC; near-duplicate titles; both under-performing where one strong page would rank
REMOVE or redirect No demand, no strategic role, no realistic path to either Near-zero impressions over 12 months; outdated announcements or event pages; nothing worth merging; no backlinks or conversions

Two honest caveats. First, traffic is not the only value: a page can have twelve visits a month and still be your best converting page, or hold a few good backlinks. Check backlinks and conversions before anything goes in REMOVE. Second, anything published in the last four to six months hasn’t had a fair run — mark it “too new to judge” and leave it alone.

Keyword cannibalization: how to actually spot it

Two of your own pages compete for one query, Google splits its confidence between them, and neither ranks as well as a single consolidated page would. The reliable way to find it in Search Console:

  1. Performance → Search results → Queries tab.
  2. Click a query you care about.
  3. With that query filter still applied, switch to the Pages tab.
  4. If more than one of your URLs shows impressions for that query, you have a candidate.

The tell-tale pattern is a query where the ranking URL flips between two pages over time: compare the first half of the year to the second, and if page A ranked in spring and page B in autumn, Google isn’t confident which one you meant.

Not every overlap is a problem, though, and this is where people over-correct. It’s fine if one page is clearly dominant and the other picks up incidental impressions at position 40, and fine if the two serve genuinely different intent — a “what is X” explainer and an “X pricing” comparison will both surface for “X”, correctly.

When it is a real conflict, you have two fixes:

  • Consolidate. Pick the stronger URL (more backlinks, better historic performance), merge the unique value from the weaker page into it, and 301 the loser to the winner. Right when both pages genuinely answer the same question.
  • Differentiate. Keep both, but rewrite titles, headings and opening paragraphs so each targets a distinctly different intent, and link them to each other. Right when the pages should be different but drifted into each other.

Deleting one without a redirect is almost never right — you throw away whatever authority it accumulated.

Step 4: Work the buckets

UPDATE — refresh and republish

This is where most of your return comes from, so do it first. A refresh is not a light edit; it should meaningfully change the page:

  • Re-check the query in GSC — intent shifts, and the page may no longer match what people are asking.
  • Fix anything factually out of date: versions, prices, screenshots, deprecated features.
  • Fill the gaps — what do the top three results cover that you don’t?
  • Rewrite the title and meta description if impressions are high but CTR is low; that combination is a snippet problem, not a content problem. Our on-page SEO checklist covers what to revisit.
  • Update the modified date — don’t fake it, but when you’ve done real work let the date reflect it.

CONSOLIDATE — merge and 301

Move the unique sections from the weaker page into the stronger one, then 301 the weaker URL to the stronger. Afterwards, find every internal link pointing at the old URL and repoint it directly — redirects work, but chains of them leak a little on every hop.

REMOVE — prune deliberately

If a removed page has a close topical relative, 301 it there. If it has no relevant successor, return a 410 (Gone) rather than redirecting to the homepage — irrelevant redirects get treated as soft 404s anyway. Update your sitemap, and prune in batches: if site-wide traffic dips, you removed something pulling more weight than the data suggested.

After a consolidation round your link graph points at URLs that no longer exist or no longer matter. Repoint links that now go through redirects, then add links to the KEEP and UPDATE pages that don’t have enough — especially pages with high impressions sitting at position 8–20, where a handful of relevant internal links can push them onto page one far more cheaply than a rewrite. Anything with zero inbound links is worse off still; see how to find orphaned pages in WordPress for that case.

Doing this by hand across a few hundred posts is slow, so an internal-linking tool that maps your link graph helps: it can list orphans and suggest where to link to the pages you kept. Disclosure: JnK Linkweave is our own plugin and free on WordPress.org, though any tool reporting inbound link counts per URL will do.

Step 5: Make it a cadence, not an event

A one-off audit fixes a backlog; it doesn’t stop the backlog re-forming. Put it on a schedule instead:

  • Monthly, 20 minutes. Sort GSC pages by clicks lost year over year and look at the top five decliners. Catching decay early is far less work than catching it late.
  • Quarterly, half a day. Cannibalization check on your ten most valuable queries, refresh the two or three highest-impression lowest-CTR pages, check for new orphans.
  • Annually, one to two days. The full process above — complete inventory, full data pull, every URL re-bucketed.

One habit prevents most of the mess: before publishing anything new, search your own site for the target query. If something already covers it, improve that post instead of writing a competitor to it.

Frequently asked questions

How often should I run a WordPress content audit?

A full audit once a year is enough for most sites, with a lighter quarterly pass on your highest-value pages and a 20-minute monthly check of your biggest year-over-year decliners in Search Console. Sites publishing several posts a week benefit from a full audit every six months, because they accumulate overlap faster.

Should I delete old blog posts that get no traffic?

Only after checking the page has no backlinks, no conversions and nothing worth merging into a stronger post — and only if it’s older than about six months, since newer posts haven’t had a fair chance to rank. When you do remove one, 301 it to the closest relevant page, or return a 410 if no relevant successor exists. Deleting without either discards whatever authority the page held.

How do I know if two pages are cannibalizing each other?

In Google Search Console, open Performance → Search results, click a query in the Queries tab to filter by it, then switch to the Pages tab. If two or more of your URLs show impressions for that query — especially if the ranking URL flips between them across the year — you have a conflict. It isn’t cannibalization if one page is clearly dominant, or if the two serve genuinely different search intent.

The bottom line

A content audit is mostly bookkeeping with a decision attached to each row, and the payoff is disproportionate because you’re improving assets you already own. Build the inventory, join it to twelve months of Search Console data, force every URL into one of four buckets — then do the UPDATE bucket first. Refreshing pages already sitting at positions 6 to 20 is the fastest win on the list, every time.