Free SEO audit + custom 90-day roadmap — claim yours →
Service

WordPress SEO: on WordPress, what is stored is not what is served

Block editor, builders, plugin sitemaps and archive families — named settings, measured on the rendered page.

Managed programmes — from $699/mo at the current Founding Pilot rate (standard $999/mo), by written proposal

What you'll get

  • Comprehensive technical & content audit
  • Custom 90-day roadmap with milestones
  • Senior strategist & dedicated PM
  • Monthly live reporting & strategy call
  • Done-for-you execution (no DIY)

What is actually WordPress-specific about WordPress SEO

Most WordPress sites serve more URLs than they have pages, more sitemaps than anyone decided on, and more structured-data emitters than the owner knows about. That is what this page is about: the defaults that produce that state, and what they cost. If your question is the broader one — whether to invest in search at all, or which channel to fund first — start at SEO services instead.

One mechanism sits underneath every problem on this page: on WordPress, what is stored is not what is served.

The block editor stores serialised block markup, not finished HTML. Divi stores shortcodes. Elementor and comparable builders store their own structures in post meta. ACF fields store content that never appears in the post body at all. At render time the theme’s templates and template parts, plus every plugin filter hooked to the content, then inject headings, breadcrumbs, canonical tags, meta robots directives and JSON-LD — material that exists in no post record anywhere. You can confirm this on your own install in under a minute: open any block-built post in the code editor (Options → Code editor) and you will see the stored string is a run of HTML comments — <!-- wp:paragraph --> and friends — that WordPress parses back out on render. The stored string is an instruction, not the page.

The consequence is not academic. A post whose stored content is empty can render fifteen hundred words. A post with fifteen hundred stored words can render a duplicated H1 and two conflicting Article blocks. Neither state is visible in the database, in an export, or on a plugin’s dashboard — a plugin’s green light describes what that plugin emitted, not what the response body contains after every other layer has taken its turn.

So we start every WordPress engagement by fetching your URLs the way a crawler does and diffing the response against what the CMS holds. That is also an honest disqualifier: if a previous agency reported on stored content, post word counts, or a plugin’s own score, they measured the wrong artefact. We will show you the difference on one of your own URLs before you buy anything.

The WordPress defaults that quietly cost you

1. Archives nobody asked for: tag, author, date, pagination, feeds, search — and attachment pages on older installs

One published post can generate a dozen indexable URLs nobody created: one per tag, an author archive, year, month and day archives, paginated variants of each archive, feed URLs, and — if the theme exposes it — internal search results. On a site installed before WordPress 6.4, add an attachment page for every uploaded image. On a content site of any age, this is where index bloat actually comes from. These URLs are not forbidden; the problem is that nobody has ever decided which of them are destinations.

The treatment is a decision per URL family, not a blanket sweep. A curated tag archive linked from navigation should stay. A date archive on a site that publishes twice a month is a near-duplicate list with no query behind it. Author archives earn their place on multi-author publications and almost nowhere else.

Attachment pages are the family where the right answer depends on how old your install is. Until WordPress 6.4, every uploaded file got a page of its own: a whole URL whose only content is one image in the theme’s wrapper. WordPress 6.4 introduced a wp_attachment_pages_enabled option, documented in the 6.4 dev note of October 2023: set to 0 on new installations, so those URLs redirect to the attachment file itself, and set to 1 on every existing site upgraded across 6.4, so that nothing changed underneath anyone. The upgrade path is the point: a site built in 2019 and kept fully up to date is running the current release today and still serving attachment pages, because core preserved the old behaviour rather than removing live URLs. Nor is the option a historical footnote — current core still reads it in redirect_canonical() before deciding whether an attachment URL renders as a page or redirects to the file. One command tells you which state you are in — wp option get wp_attachment_pages_enabled — and the same option changes it. If your install post-dates 6.4 there is nothing here to fix, and we will say so rather than bill for it.

The mechanism most often got wrong is the suppression itself. Blocking a URL in robots.txt prevents its noindex directive from being seen, because a crawler that cannot fetch the page cannot read the tag telling it to drop the page — Google’s documentation on blocking indexing says so directly. An archive family you want removed has to stay crawlable long enough to be re-crawled and dropped. We also decline to oversell this: on a few hundred URLs, removing archives is a duplication and clarity decision, not a crawl-budget one. Crawl budget binds at scale, and claiming otherwise on a 200-page site is theatre.

2. Two sitemaps, and a decision nobody made

Since WordPress 5.5, core itself generates and serves an XML sitemap at /wp-sitemap.xml by default — see the core announcement. Every major SEO plugin also generates its own, usually at /sitemap_index.xml or /sitemap.xml. Whether your install is actually serving both is a two-request check rather than an assumption: fetch /wp-sitemap.xml and your plugin’s sitemap URL and see what each returns. Some SEO plugins switch core’s off when their own is enabled — Yoast SEO does, as the comment thread on that same core announcement records. Where that has not happened, you are publishing two lists built by different rules: one carrying the taxonomy and author archives you spent last quarter removing, and one that does not.

Only one can be the authoritative statement of what you want indexed, and robots.txt is where you declare which. Core ships no settings screen for its own sitemap: switching it off is the wp_sitemaps_enabled filter, or a plugin that applies that filter for you. The fix is cheap, and it is a decision rather than a tactic: pick the sitemap that reflects your indexation policy, disable or redirect the other, declare the survivor in robots.txt, and make sure the two never disagree about a URL.

3. Three schema emitters: theme, SEO plugin, page builder

The familiar version of this is two SEO plugins fighting, which is real and is covered for store stacks on our WooCommerce SEO page. The WordPress-wide version is commoner and much harder to see: modern themes emit structured data, page builders emit structured data, and the SEO plugin emits structured data. A site running exactly one SEO plugin can still serve two Organization nodes and two Article nodes with different values, because three independent layers each believe they own the job.

What that costs is worth stating precisely, because the usual claim is wrong. Conflicting markup is not a penalty. It weakens entity resolution — an engine working out who published this, and what this page is, must reconcile contradictory assertions — and it risks rich-result eligibility when the markup describes something the page does not display, which Google’s structured data policies treat as a violation rather than a missed optimisation. On WordPress the repair is not output filtering. It is to find which layer registers each emitter — the theme’s own schema functions, the builder’s settings, the plugin’s schema module — choose one owner per entity type, and switch the others off at source.

4. Which layer actually owns your canonical tag

WordPress core emits a canonical of its own on singular URLs, through rel_canonical(). Theme templates, the SEO plugin, pagination handling and translation or AMP plugins can each emit another. Where two layers filter the same value, the last filter to run wins and the earlier decision disappears without a warning; where two layers each print their own tag on wp_head, the response carries two canonical elements. We regularly find pages serving two canonical elements, or one pointing at a paginated variant, or a self-referencing canonical on a URL that should not be indexed at all. Because a canonical is a signal that Google may choose to override, a contradictory one does not fail loudly — it is quietly disregarded, and you keep reporting a fix that never took effect. Which layer emitted it is a render-time question; it cannot be answered from a settings screen.

The emitter map is the deliverable that resolves both of the last two sections. On a stock WordPress stack it looks like this:

Signal Layers that can emit it on WordPress Who should own it
Title tag Core, where the theme declares title-tag support; theme templates; SEO plugin; some builders SEO plugin, one source
Canonical Core rel_canonical(), theme, SEO plugin, pagination, translation and AMP plugins SEO plugin, one source
Meta robots Core, via the wp_robots filter (max-image-preview); theme; SEO plugin SEO plugin, core defaults left intact
Organization and WebSite schema Theme, SEO plugin, builder — core emits none Exactly one emitter, site-wide
Article or BlogPosting schema Theme, SEO plugin, builder — core emits none Exactly one emitter, per template
BreadcrumbList schema Theme, SEO plugin, builder — core has no breadcrumb API Whichever layer renders the visible breadcrumb
XML sitemap Core (/wp-sitemap.xml, since 5.5), SEO plugin One, and the one declared in robots.txt

5. Builder output is a portability problem, not just a weight problem

The standard complaint about page builders is DOM weight and stylesheet bloat, and that is fair. The more expensive problem is that builder content is not portable. Divi shortcodes render as raw shortcode text once Divi is disabled. Builder-stored layouts are meaningless without the builder, and content in ACF fields does not travel with the post body. A site that has been through two builders typically carries three content layers in the database, and an audit reading one of them describes a page no visitor has seen. We do not recommend ripping out a working builder — that is a rebuild dressed as an SEO project — but we do insist on knowing which layer produces each part of the rendered page before anyone touches it.

What we measured on 569 WordPress home pages

We do not have to speculate about how common these defaults are, because we can cut our own census. Our AI Search Readiness Benchmark fetched 2,596 Wikidata-listed Indian business hosts on 3 September 2026; 1,948 responded. WordPress core has emitted a max-image-preview:large robots directive by default since version 5.7, via wp_robots_max_image_preview_large(), so that directive on a home page is a usable WordPress fingerprint. It matched 569 of the 1,948. Within that cut:

  • 485 of 569 (85.2%) declare a sitemap in robots.txt, against 803 of the 1,379 non-matching hosts (58.2%) — WordPress sites declare sitemaps far more often because the CMS did it for them, not because anyone chose one.
  • 196 of 569 (34.4%) serve two or more separate JSON-LD blocks on the home page, and 111 serve three or more. That is the multiple-emitter pattern, visible from outside.
  • 134 of 569 serve no JSON-LD at all, and 222 expose no Organization entity — on a platform where the theme alone usually emits one.
  • 226 of 569 carry no exact self-referencing canonical on the home page.
  • Median time to first byte was 1,033 ms for the WordPress cut against 662 ms for the rest, and 168 of the 569 exceeded 1,800 ms.

Four limitations travel with those figures. The Wikidata frame over-represents companies notable enough to have an entry. The robots-directive fingerprint under-counts twice over: it misses any WordPress site whose plugin or theme rewrites the robots meta, and it misses any site with search-engine visibility discouraged, because wp_robots_max_image_preview_large() only adds the directive when the blog_public option is set — so 569 is a floor, not a count. We read server-delivered HTML only, so anything injected by JavaScript is invisible and every “no structured data” figure is an upper bound. And the instrument records distinct schema types rather than repeated nodes, so this dataset cannot tell you how many sites emit the same type twice — which is why the duplicate-schema section above cites a mechanism and not a percentage. The census CSV is published with the report and every figure here recomputes from it.

Performance: WordPress fails on loading, not on responsiveness

The reflexive prescription for a slow WordPress site is a caching plugin, and it so often disappoints because caching addresses one subpart of one metric. Largest Contentful Paint decomposes into time to first byte, resource load delay, resource load duration and element render delay. On a typical WordPress stack the damage is spread across all four: server response on shared hosting or an uncached admin-ajax call; a hero image the theme lazy-loads and so delays; render-blocking theme and builder stylesheets loaded before anything paints; web fonts that hold text back. A page cache improves the first subpart, on cached requests only.

Our census supports the shape of that: median TTFB of 1,033 ms for the WordPress cut against 662 ms for the rest, on one uncached request per host. That is a single subpart measured on one page per site, and we will not extrapolate it into a field pass rate we did not measure. This service is about where those four subparts break on one specific theme-plus-builder-plus-host stack — yours — rather than about the metrics in the abstract.

Migrations, permalinks and theme changes

Three WordPress changes routinely destroy traffic, and all three are survivable if planned. Changing the permalink structure rewrites every URL at once; without a rule-based redirect map generated from the old structure rather than a hand-typed list, you lose the lot. Changing theme moves schema, breadcrumbs and heading structure into a different emitter. Changing SEO plugin moves titles, canonicals and per-post directives between plugin-specific meta keys. We treat all three as change-controlled work: capture the rendered state of a URL sample, make the change, diff the rendered state again, and fix what moved before anyone announces the launch.

What we do

1. Render-diff your URLs

We fetch a representative sample the way a crawler does and compare the served response against the stored content and the plugin’s reported state. This produces the defect list the engagement works from.

2. URL-family inventory and archive decisions

Every URL family the install generates — post types, taxonomies, author, date, pagination, feeds, search, and attachment pages where the install still serves them — gets a documented decision: index, noindex, or remove. We read wp_attachment_pages_enabled rather than assuming which side of 6.4 you are on, and we implement suppression in the order that actually works, keeping URLs crawlable while they are dropped.

3. One authoritative sitemap

We establish which sitemap system reflects your indexation policy, disable or redirect the other, align it with robots.txt, and confirm the two no longer disagree about any URL.

4. Emitter map for schema, canonical and meta robots

We identify which layer emits each signal, assign one owner per signal, and disable the duplicates at source rather than patching output. This is the change that most often unlocks rich results on sites whose markup validated all along.

5. LCP composition on your actual stack

We measure the subparts rather than the score: server response on your host, whether the theme lazy-loads the element that turns out to be largest, render-blocking theme and builder CSS, font loading. Then we fix the subpart that dominates, which is frequently not the one a caching plugin’s dashboard highlights.

6. Change control and measurement by URL family

Reporting is segmented by the families in step two, so a fall in tag-archive impressions reads as the intended outcome rather than a scare, and a real loss on money pages shows immediately instead of being averaged away.

What can and cannot be measured

  • Measurable: which URL families the install generates, which of them are indexed, and how that changes; duplicate canonical, schema and robots directives on a given rendered URL; structured-data validity; whether the core sitemap and the plugin sitemap agree; LCP subpart timings; impressions and clicks per family in Search Console.
  • Partially observable: field Core Web Vitals data, which needs enough real traffic to populate and lags the fix by weeks; and de-indexing timing, which depends on re-crawl rates nobody controls.
  • Not promisable: that removing archives lifts revenue traffic on a small site — the mechanism is duplication and clarity, not crawl budget; that a plugin change alone moves rankings; or any specific position, on any timeline.

If you are not on plain WordPress

If you sell through WooCommerce, the store stack has its own failure modes — filtered and attribute URLs, product taxonomy duplication, variable-product markup, database-level performance — covered on WooCommerce SEO. On Shopify, see Shopify SEO; on Magento, Magento SEO. If your problem is platform-independent — crawl, indexation, canonicalisation and architecture as they apply on any CMS — that is technical SEO. This page is the WordPress-specific layer: the defaults, the emitters, and the render behaviour of the CMS itself.

When WordPress SEO is worth buying

It is worth buying when Search Console reports far more indexed URLs than you have pages; when you changed theme, builder or SEO plugin in the last year; when structured data validates but no rich result appears; when a caching plugin failed to make the site feel faster; or when a migration is coming and you want the redirect and emitter work done before launch rather than after.

It is worth less if your site is small, technically clean, and simply has no content depth or nothing linking to it. Then the constraint is not the CMS, and we will say so rather than sell you the wrong service. A twelve-page brochure site with three plugins and no archive problem does not need this engagement; it needs SEO services, or nothing yet.

Questions buyers ask

Isn’t WordPress already SEO-friendly out of the box?

WordPress is search-friendly in that it produces clean URLs, semantic templates and an XML sitemap without being asked. It is not search-optimised, because its defaults were chosen for publishing: it makes every tag, author and date archive separately addressable — plus every uploaded image, on any install that predates WordPress 6.4 — and it lets the theme, the page builder and the SEO plugin each write their own canonical tags and structured data. The platform gives you a good starting position and no opinion at all about which of the URLs it generates should exist. That is why a WordPress site usually needs decisions made rather than repairs performed.

Do I need Yoast Premium or Rank Math Pro, and is that what I’m paying you for?

A premium SEO plugin licence is not what you are paying us for, and neither Yoast Premium nor Rank Math Pro is required for anything on this page. An SEO plugin is a control surface, not a strategy: it exposes settings for titles, canonicals, robots directives and schema, and premium tiers mostly add redirect management, internal-linking suggestions and support. The free tier of either can express every decision described here. What you are paying us for is the decisions — which URL families should be indexed, which layer owns your canonical, which sitemap is authoritative, which LCP subpart dominates — and the render-level verification that each one took effect. We do not resell plugin licences and take no affiliate commission on them.

We use Elementor or Divi. Is the page builder hurting our SEO?

A page builder such as Elementor or Divi is not inherently hurting your SEO, and removing a working builder is rarely justified as an SEO project. Builders cause three specific, fixable problems on WordPress: they add render-blocking CSS and DOM depth, which affects Largest Contentful Paint; some emit their own structured data, which then conflicts with the theme’s and the SEO plugin’s; and they store content in a format that is not the rendered page — Divi as shortcodes, Elementor as post meta — so any audit reading stored post content mis-measures builder-built pages. All three are addressable while keeping the builder. Rebuilding away from one is a development decision with a real cost, and it should be justified on its own terms rather than sold as SEO.

Why does Search Console show thousands of pages I never created?

Search Console shows thousands of pages you never created because WordPress generated them for you. Each post produces URLs for every tag and category assigned to it, plus author, year, month and day archives, paginated variants of each archive, feed URLs, and often internal search results. If the site was installed before WordPress 6.4, every uploaded image has a page of its own as well — core disabled attachment pages for new installations in 6.4, but left them switched on for every site upgraded across that release. None of these required an author to do anything. The fix is not one setting: it is a decision per URL family about whether it is a genuine destination, implemented so those pages stay crawlable while they are de-indexed — because blocking them in robots.txt prevents the noindex directive from ever being read.

Should I switch SEO plugins, and will it break my rankings?

Switching SEO plugins does not break rankings by itself; an incomplete migration of the data does. Titles, meta descriptions, canonical overrides, per-post noindex flags and schema settings live under plugin-specific meta keys, and importers move most but not all of them. The new plugin then falls back silently to its own defaults for whatever did not transfer, which can flip a deliberate noindex back to indexable or replace a hand-written title with a template. If your current configuration works and nothing is unmet, staying put is a legitimate answer. If you do switch, capture the rendered <head> of a URL sample before and after, and diff the two.

Why is my WordPress site still slow after installing a caching plugin?

A WordPress site stays slow after a caching plugin is installed because a page cache improves one subpart of one metric, and only on requests that hit the cache. Largest Contentful Paint has four subparts — time to first byte, resource load delay, resource load duration and element render delay — and a page cache mainly addresses the first. If your largest element is a hero image the theme lazy-loads, or your theme and builder ship render-blocking stylesheets, or your web fonts hold text back, the cache changes none of it. The diagnosis has to name which subpart dominates on your pages before a fix is chosen, which is why “install a caching plugin” is a guess rather than a plan.

How is this different from your technical SEO service?

Technical SEO is the platform-independent discipline: crawling, indexation, canonicalisation, architecture and performance as concepts that apply on any CMS. WordPress SEO is that discipline applied to what this specific CMS does by default and at render time — core’s own sitemap, the archive URL families it generates, the theme and builder and plugin each emitting schema and canonical tags, and the gap between stored and rendered content. If you are on WordPress, this is the more specific engagement. If you are on a bespoke or headless stack, technical SEO is the right one.

Next steps

The fastest way to find out whether any of this applies to you is to let us look. Our free audit runs the render-diff described above against your domain and reports what we actually find — which sitemaps you serve and which one robots.txt declares, which layers emit your schema and canonical tags, which URL families are indexed and whether your install still serves attachment pages, and which LCP subpart dominates — with a prioritised 90-day roadmap, within 72 hours, no commitment. Our pricing is published in full, setup fee included, and scope is confirmed in a written proposal before anything is billed.

Built for growing businesses across industries · ✓ Published refund policy · ✓ 90-day initial term, then month-to-month

See real customer results →

Ready to start?

Free audit + custom 90-day roadmap in 72 hours — or talk to a strategist.

Run Free Audit → Book a demo See pricing

Related services

Website Design

Design as the decision layer: architecture, templates, states and WCAG conformance, with redesigns that do not…

Website Development

Development with a fixed sequence and a real handover: you own the code, the domain and…