Skip to content
Search is changing. Stay curious.SEO / AI / Practical know-how
DgTrendz
DgTrendz / Article

Build a Before-and-After SEO Check for WordPress Updates

Illustration of before-and-after SEO checklists for a WordPress update.

How do you check whether a WordPress update changed your SEO setup? Capture the same important pages before and after the update, then compare their HTTP responses, canonical URLs, robots directives, titles, headings, internal links, and main content. Check both the original HTML and the DOM after JavaScript runs. Investigate unexpected differences before deploying the update to production.

This guide builds a small Python and Playwright checker for that job. It answers a practical question: “The site still loads, but did the update change something search engines or readers depend on?”

The accompanying experiment uses controlled local pages that simulate changes a WordPress site might experience. It does not test an installed WordPress site, attribute a defect to a plugin, or measure Google indexing or rankings. The fixtures deliberately introduce faults so you can see what the checker detects and what it misses.

What should you compare before and after a WordPress update?

Start with signals that affect access, page identity, and the content people can reach.

Signal Question to answer Initial action
HTTP status and redirects Does an important URL now fail or land somewhere different? Stop for new error responses; review changed destinations
Robots meta tags and X-Robots-Tag Did a new indexing restriction appear? Stop and inspect the exact directive and its scope
Canonical URL Does the page still identify the intended preferred URL? Review any unexpected change
Title and H1 Did a template replace, remove, or duplicate important text? Review against the planned update
Internal link targets Did the page lose a route to important content? Review the removed targets
Main content Did the selected article or product description disappear or change substantially? Stop for major loss; review smaller changes

“Stop” here means pause the release for investigation. It does not mean Google has imposed a penalty. These are proposed deployment rules, not Google’s thresholds.

If you need background before running the script, start with DgTrendz’s technical SEO guide.

Why check both the original HTML and the rendered page?

JavaScript can change a page after the server sends it. A canonical URL in the original HTML can differ from the one in the rendered DOM. A browser-only check can also overlook an initial noindex tag that a script later removes.

Google explains that an initial noindex can cause rendering to be skipped, so removing that tag with JavaScript may not work as intended. Its guidance also recommends consistent canonical information. Source: Google’s JavaScript SEO documentation.

Our checker reads the original navigation response and then inspects that same browser navigation after rendering. It saves both sets of signals. Playwright runs Chromium; it does not reproduce Google’s crawling, rendering schedule, or indexing decisions.

The test flow

Follow this sequence:

Back up → choose pages → capture twice → validate the baseline → update staging → capture again → review differences → fix and retest → deploy → repeat on production.

1. Back up and record the change

Take a recoverable backup of the database and files. Record the WordPress, theme, and affected plugin versions, plus the time of the update. WordPress recommends backing up before updating. Source: Updating WordPress.

Use staging for the first test. Keep its authentication or other access protections in place. Do not expose staging or remove its intended noindex just to make a test pass. This starter script uses anonymous browsing; password-protected staging needs an authentication adaptation before use.

Apply one component update at a time where practical. If you change the theme, SEO plugin, caching configuration, and page content together, the report cannot identify which change caused a difference.

2. Choose representative URLs

Include the homepage, a standard post, a category archive, a business-critical landing page, and a product page if you run a store. Add pages using special templates or JavaScript components affected by the update. Include important organic landing pages from your own analytics rather than relying only on this generic list.

Create paths.txt, one existing path per line:

/
/blog/
/about-us/

Replace or extend those examples with actual paths. This is a selected-URL check, not a complete website crawl.

3. Install the checker

The companion test kit [download URL pending before publication] contains seo_check.py, run_lab.py, requirements.txt, sample paths, and the experiment’s JSON and CSV evidence. The commands below assume you have extracted that kit and opened a terminal in its folder.

Create a Python virtual environment:

python -m venv .venv

On Windows PowerShell, activate it with:

.\.venv\Scripts\Activate.ps1

On macOS or Linux:

source .venv/bin/activate

Then install the dependencies and Chromium:

python -m pip install -r requirements.txt
python -m playwright install chromium

If PowerShell blocks activation, use .\.venv\Scripts\python.exe in place of python. Linux installations may also need browser system dependencies. Follow Playwright’s installation instructions and browser setup documentation for your operating system.

4. Capture the baseline twice

Use the same host for both captures:

python seo_check.py capture --base https://staging.example.com --paths paths.txt --selector main --out before.json
python seo_check.py capture --base https://staging.example.com --paths paths.txt --selector main --out repeat.json
python seo_check.py diff before.json repeat.json --out baseline.csv

Replace the example hostname with your own accessible test environment. The script’s default content selector is main; your theme might need .entry-content or another selector. Choose a selector that identifies one intended content region. The checker uses its first match.

Open the JSON snapshots before trusting the baseline. Confirm that the expected content was found and that the status, title, canonical, and indexing directives are appropriate. Two identical bad snapshots are still bad. An existing noindex, missing content region, or error page does not become acceptable because it stayed unchanged.

Why capture twice? A clock inside the article, randomized recommendations, or personalized navigation can create differences even when WordPress has not changed. Resolve or document these differences before testing an update.

Use consistent cache handling, locale, and consent conditions. Warm the relevant pages after a cache purge in both phases. The script starts a fresh browser context per page, using a desktop viewport and an ordinary Chromium user agent.

For asynchronous templates, you can use --ready-selector .article-ready and --wait-ms 2000. Use those same options in every capture. A longer wait is not proof that all content has finished loading; choose a meaningful readiness condition for your site.

5. Update staging and capture again

Apply the planned update, repeat the agreed cache process, and run:

python seo_check.py capture --base https://staging.example.com --paths paths.txt --selector main --out after.json
python seo_check.py diff before.json after.json --out report.csv

The CSV reports the path, severity, changed field, and before/after values. It records the full redirect URL/status sequence for each navigation, as well as the final URL.

Do not compare production’s baseline directly with staging’s after snapshot. Different hosts can produce different canonicals, links, and indexing rules. This checker rejects that comparison. Compare each environment against itself.

What happened in the controlled experiment?

The lab uses 13 local HTTP fixtures: ten deliberately changed cases that the checker is designed to detect, one unchanged control, one harmless footer change, and one visual failure outside its detection scope. Each page was captured before the change, again without any change, and after the simulated update.

Run the experiment yourself:

python run_lab.py

The script starts a local loopback server, runs the captures, asserts expected findings, saves the evidence, and closes the server. It does not change your WordPress site.

Controlled case Observed result What it tells us
Unchanged page No findings The stable control did not generate a difference
Footer year changed outside main No findings An irrelevant text change was excluded from the content comparison
New meta noindex BLOCK in original and rendered signals Both snapshots exposed the restriction
New X-Robots-Tag noindex BLOCK A response-header restriction was detected
JavaScript changed the canonical REVIEW in rendered canonical The original canonical alone would not reveal this change
Navigation link removed REVIEW in original and rendered link sets The removed destination appeared in the report
H1 removed REVIEW A heading change needs contextual review
Most article text removed BLOCK The text-loss heuristic fired
HTTP 200 changed to 503 BLOCK An availability regression was detected
New redirect to another page REVIEW The changed chain and final destination were recorded
Title changed REVIEW Expected editorial changes still require a decision
Initial noindex removed by JavaScript BLOCK in original HTML only Checking only the final DOM would miss the initial restriction
Main content hidden with CSS No findings: known miss DOM text remained present even though visitors could not see it

All ten intended detectable cases produced their expected findings: 21 report rows, comprising seven BLOCK and 14 REVIEW findings. A single case can generate more than one row because original and rendered signals are tracked separately. The repeated baseline produced no differences. These results establish behavior on the supplied fixtures, not a general detection rate across WordPress sites. No plugin was upgraded in this experiment.

The recorded environment was Python 3.12.6, Playwright 1.58.0, Beautiful Soup 4.14.3, and Chromium 145.0.7632.6 on Windows 10. Each lab capture used a 100 ms post-load wait because these fixtures run their changes synchronously; the site checker defaults to 1,000 ms. This successful local run is not a statement of official Windows 10 support. Use a platform supported by your chosen Playwright release.

The most useful finding is the known miss: a clean DOM comparison does not prove a page is visually usable. The CSS-hidden fixture is deliberately retained in the kit to make that limitation reproducible.

Which findings should stop the release?

The starter rules produce three labels:

The 50% threshold is our configurable heuristic. It is not a Google recommendation or a content-quality score. Shortening an article intentionally can trigger it; deleting a critical paragraph smaller than that threshold still needs review.

Canonical changes receive REVIEW because some are intentional. If an update sends every article’s canonical to the homepage, treat that as a release blocker after checking the evidence. A canonical is a preference signal, not proof of which URL Google will select. Source: Google’s canonicalization guidance.

Read the actual robots directive before acting. The starter header check is conservative: a restriction scoped to another bot can still trigger a finding. Verify the affected user agent instead of automatically removing the directive.

For command-line automation, diff exits with 1 for BLOCK findings and 2 for capture errors. It exits 0 otherwise, including reports containing REVIEW findings. A successful command therefore still requires reviewing the CSV. Invalid inputs or mismatched settings also fail with a nonzero exit.

How should you investigate a difference?

Open the affected URL, inspect the original response and rendered DOM, and match the finding to the change log. Check the same template on other pages to establish scope.

For a new noindex, inspect the rendered tag, original tag, and response header separately. For a changed canonical, check the SEO plugin configuration and template output. For a removed link, confirm whether the destination remains reachable from important navigation or contextual links. For missing text, inspect the selected content region and the browser view.

Fix the configuration or code and recapture. Keep the original before snapshot so the fix is compared against the approved baseline. Use a known-good backup or rollback only with the appropriate database compatibility and security considerations; a report does not make every downgrade safe.

After deploying an approved update, compare production against its own pre-update snapshot. Staging results cannot prove that production’s cache, configuration, or access rules are identical.

What does this SEO check miss?

This is a regression checker for selected signals. It does not validate everything about the page.

It does not test CSS visibility, mobile layouts, accessibility, Core Web Vitals, robots.txt, sitemap membership, structured data, hreflang, meta descriptions, or whether linked destinations return errors. It does not inspect content inside shadow DOM or embedded frames. It tracks unique internal link destinations, so losing one of several links to the same URL may not appear as a change. Anchor text, link placement, and nofollow changes are outside this version’s scope.

Only the first matching main-content element is compared. CSS-hidden text still counts. Stable pre-existing errors remain possible. Different cookies, locations, or delayed scripts may produce different output from the tested session.

Pair the report with a visual check, broader crawl checks where needed, and Google’s URL Inspection tools for relevant public pages. Google’s recorded indexing state and a local browser snapshot answer different questions.

Common questions about WordPress updates and SEO

Can a WordPress plugin update affect SEO even if the page still loads?

Yes. A page can return HTTP 200 while its title, canonical, indexing directives, or internal links change. This experiment demonstrates those failure modes with simulated pages; it does not show that a particular plugin causes them.

Do I need to wait for rankings to change before checking?

No. You can inspect page output immediately after an update. A before-and-after test detects observable changes without waiting for Google to crawl or reprocess the page. It cannot predict the eventual ranking effect.

Does an unchanged report mean my WordPress SEO is correct?

No. It means the tracked signals did not change under the tested conditions. Existing mistakes, untested URLs, and visual failures may still be present. Validate the baseline and keep the checker limitations visible.

Should staging have the same robots directives as production?

Not necessarily. Staging may intentionally restrict indexing or require authentication. Preserve those protections and compare each environment against itself. Check production’s intended public indexing behavior separately after release.

Can this report explain a traffic drop?

It can supply evidence of a technical change near an update. That timing alone does not establish causation. Confirm affected pages and inspect Search Console and analytics alongside the report before attributing a traffic change to the update.

Will this workflow help AI systems find or cite my pages?

It can help detect accidental changes to the content and access signals those systems may depend on. It cannot guarantee crawling, indexing, or citation by any AI service. For Google’s AI search features, Google says its existing SEO foundations remain relevant and does not require special AI markup. Source: AI features and your website.

A release checklist you can reuse

The useful question after an update is specific: “What changed on these pages, was that change intended, and what evidence have we checked?” The snapshots and report give you a repeatable way to answer it.

Continue exploring the library