Guide

Schema SEO testing strategy

This document outlines the comprehensive testing strategy for validating the prc-schema-seo plugin before it replaces Yoast SEO in production. The goal is to ensure SEO parity, prevent traffic loss, and maintain search engine ranking stability.


Table of Contents

  1. Overview
  2. Available CLI Tools
  3. Pre-Launch Testing Phases
  4. Phase 1: Data Migration Validation
  5. Phase 2: Meta Tag Parity Testing
  6. Phase 3: Schema.org Validation
  7. Phase 4: Performance Benchmarking
  8. Phase 5: Integration Testing
  9. Phase 6: Visual/Manual Testing
  10. Automated Test Suite
  11. Production Rollout Strategy
  12. Monitoring & Rollback Plan
  13. Testing Checklists

Overview

Critical SEO Elements to Validate

ElementImpactPriority
Title tagsDirect ranking factorCritical
Meta descriptionsClick-through rateCritical
Canonical URLsDuplicate content preventionCritical
Robots directivesIndexation controlCritical
Open Graph tagsSocial sharing appearanceHigh
Twitter Card tagsSocial sharing appearanceHigh
JSON-LD SchemaRich snippets, knowledge graphHigh
Primary termsURL structure, breadcrumbsMedium
Sitemap exclusionsCrawl efficiencyMedium

Risk Assessment

RiskMitigation
Missing meta tagsCompare tool validation against production
Different schema outputSchema comparison and Google Rich Results testing
Broken canonical URLsAutomated URL validation
Noindex/nofollow changesRobots directive comparison
Performance degradationBenchmark testing with cold/warm cache
Yoast data lossDry-run migration + verification

Available CLI Tools

The plugin provides several WP-CLI commands for testing and validation:

Comparison Commands

# Compare single post SEO output against production
wp prc seo compare <post_id>
wp prc seo compare <post_id> --format=json
wp prc seo compare <post_id> --diff-only
wp prc seo compare <post_id> --format=full

# Batch compare multiple posts
wp prc seo compare-batch
wp prc seo compare-batch --post-type=post --limit=100
wp prc seo compare-batch --format=json > comparison-results.json

Migration Commands

# Check migration status
wp prc seo migration-status

# Preview Yoast data without migrating
wp prc seo preview-yoast <post_id>

# Migrate with dry-run (no database changes)
wp prc seo migrate-post <post_id> --dry-run
wp prc seo migrate-posts --dry-run --limit=100

# Execute migration
wp prc seo migrate-post <post_id>
wp prc seo migrate-posts --post-type=post --batch-size=100
wp prc seo migrate-term <term_id> --taxonomy=category
wp prc seo migrate-terms --taxonomy=category

# Clean leftover Yoast placeholders from migrated PRC SEO data
wp prc seo clean-yoast-placeholders
wp prc seo clean-yoast-placeholders --dry-run=false --include-terms

# Delete leftover Yoast wp_options rows (after migration is complete)
wp prc seo clean-yoast-options
wp prc seo clean-yoast-options --dry-run=false --known-only
wp prc seo clean-yoast-options --dry-run=false

Performance Commands

# Benchmark schema/meta generation
wp prc seo benchmark --post=<post_id>
wp prc seo benchmark --post=<post_id> --iterations=5
wp prc seo benchmark --term=<term_id> --taxonomy=category

Pre-Launch Testing Phases

┌─────────────────────────────────────────────────────────────────────────────┐
│                        TESTING TIMELINE                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Phase 1: Migration     Phase 2: Meta Tags    Phase 3: Schema               │
│  ─────────────────      ───────────────────   ─────────────                  │
│  • Dry-run migration    • Compare vs prod     • JSON-LD validation          │
│  • Data verification    • All meta types      • Rich Results Test           │
│  • Edge cases           • 404/redirects       • Type coverage               │
│                                                                              │
│  Phase 4: Performance   Phase 5: Integration  Phase 6: Visual               │
│  ───────────────────    ───────────────────   ─────────────                  │
│  • Benchmark cold/warm  • Sitemap check       • SERP preview                │
│  • Memory profiling     • Caching layers      • Social preview              │
│  • Load testing         • REST API            • Editor UI                   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Phase 1: Data Migration Validation

Objectives

  • Ensure all Yoast SEO data migrates correctly to PRC Schema SEO format
  • Validate no data loss occurs during migration
  • Identify edge cases requiring manual attention

Test Procedures

1.1 Migration Status Assessment

# Get overview of migration scope
wp prc seo migration-status

# Expected output shows counts of:
# - Posts with Yoast meta
# - Posts with PRC meta (already migrated)
# - Posts pending migration

1.2 Dry-Run Migration Testing

# Test migration on sample posts without saving
wp prc seo migrate-posts --dry-run --limit=50

# Review specific high-traffic posts
wp prc seo preview-yoast <high-traffic-post-id>
wp prc seo migrate-post <high-traffic-post-id> --dry-run

1.3 Data Field Mapping Verification

Yoast FieldPRC FieldValidation
_yoast_wpseo_titletitleExact match or pattern equivalent
_yoast_wpseo_metadescdescriptionExact match
_yoast_wpseo_canonicalcanonical_urlURL validation
_yoast_wpseo_meta-robots-noindexnoindexBoolean conversion
_yoast_wpseo_opengraph-titleog_titleExact match
_yoast_wpseo_opengraph-descriptionog_descriptionExact match
_yoast_wpseo_opengraph-imageog_imageAttachment ID match
_yoast_wpseo_primary_categoryprimary_terms.categoryTerm ID match

1.4 Edge Case Testing

Test these specific scenarios:

# Posts with custom canonical URLs
wp db query "SELECT post_id FROM wp_postmeta WHERE meta_key = '_yoast_wpseo_canonical' AND meta_value != ''" --skip-column-names | while read id; do
  wp prc seo migrate-post $id --dry-run
done

# Posts marked as noindex
wp db query "SELECT post_id FROM wp_postmeta WHERE meta_key = '_yoast_wpseo_meta-robots-noindex' AND meta_value = '1'" --skip-column-names | head -10 | while read id; do
  wp prc seo compare $id --diff-only
done

# Posts with custom OG images
wp db query "SELECT post_id FROM wp_postmeta WHERE meta_key = '_yoast_wpseo_opengraph-image-id'" --skip-column-names | head -10 | while read id; do
  wp prc seo preview-yoast $id
done

Success Criteria

  • 100% of posts with Yoast data show successful dry-run migration
  • Primary category mappings verified for sample posts
  • Custom canonical URLs preserved
  • Noindex flags correctly converted
  • No migration errors logged

Phase 2: Meta Tag Parity Testing

Objectives

  • Verify all meta tags match production Yoast output
  • Identify any missing or changed meta values
  • Validate robots directives are consistent

Test Procedures

2.1 Single Post Comparison

# Compare high-traffic posts
wp prc seo compare <post_id> --format=full

# Review comparison summary
wp prc seo compare <post_id>
# Look for:
# - Matching: should be high
# - Different: should be zero or explained
# - Local only: new fields we're adding
# - Production only: fields we might be missing

2.2 Batch Comparison

# Compare recent posts
wp prc seo compare-batch --post-type=post --limit=100 --format=json > comparison-posts.json

# Compare pages
wp prc seo compare-batch --post-type=page --limit=50 --format=json > comparison-pages.json

# Analyze results
cat comparison-posts.json | jq '.summary'
cat comparison-posts.json | jq '.results[] | select(.status == "partial")'

2.3 Meta Tag Checklist

For each compared post, verify:

Meta TagCheck
<title>Matches or follows acceptable pattern
<meta name="description">Content and length match
<link rel="canonical">URL exactly matches
<meta name="robots">Directives match (index,follow or noindex,follow)
<meta property="og:title">Matches or falls back correctly
<meta property="og:description">Matches or falls back correctly
<meta property="og:image">Same image or valid fallback
<meta property="og:url">Matches canonical
<meta property="og:type">article for posts, website otherwise
<meta name="twitter:card">summary_large_image or summary

2.4 Special Page Testing

Test these critical pages manually:

# Homepage
wp prc seo compare <homepage-id> --format=full

# Category archives (use term-specific commands if available)
# These require manual front-end verification

# Author/staff pages
wp prc seo compare <staff-page-id> --format=full

# Search results page (manual verification needed)

Success Criteria

  • 95%+ meta tag match rate across batch comparison
  • All critical pages show matching or acceptable meta tags
  • No unexpected noindex changes
  • Canonical URLs 100% match for all compared posts

Phase 3: Schema.org Validation

Objectives

  • Verify JSON-LD schema output matches expected structure
  • Validate schema with Google Rich Results Test
  • Ensure all required schema types are present

Test Procedures

3.1 Schema Type Coverage

Compare schema types between local and production:

# Full comparison shows schema types
wp prc seo compare <post_id> --format=full

# Look for schema types in output:
# Local types: Article, Organization, WebSite, WebPage, BreadcrumbList
# Production types: (same set expected)

3.2 Google Rich Results Testing

For sample posts, test schema validity:

  1. Generate local schema output:
wp prc seo compare <post_id> --format=json | jq '.local.schema' > local-schema.json
  1. Test in Google Rich Results Test: https://search.google.com/test/rich-results
  2. Compare with production URL results

3.3 Schema Element Verification

Schema TypeRequired PropertiesValidation
Organizationname, url, logo, sameAsAll present
WebSitename, url, potentialActionSearchAction configured
Articleheadline, author, datePublished, dateModifiedAll populated
NewsArticleSame as Article + publisherPublisher is Organization
Personname, url, image (for staff)Linked correctly
BreadcrumbListitemListElementValid hierarchy
WebPagename, urlPresent for pages
CollectionPagename, urlPresent for archives

3.4 Schema Comparison Script

#!/bin/bash
# schema-compare.sh - Compare schema output for multiple posts

POST_IDS=(123 456 789 1011)  # Replace with actual high-traffic post IDs

for id in "${POST_IDS[@]}"; do
  echo "=== Post ID: $id ==="
  wp prc seo compare $id --format=json | jq '{
    post_id: .post_id,
    local_schema_types: .local.schema["@graph"] | map(.["@type"]) | sort,
    production_schema_types: .production.schema["@graph"] | map(.["@type"]) | sort,
    types_match: .comparison.schema.types_match
  }'
  echo ""
done

Success Criteria

  • Schema types match between local and production for 95%+ of posts
  • All schema passes Google Rich Results Test validation
  • Organization schema includes all social profiles
  • Article schema includes proper author linking
  • BreadcrumbList uses primary term correctly

Phase 4: Performance Benchmarking

Objectives

  • Ensure schema/meta generation doesn't degrade page load
  • Validate caching effectiveness
  • Establish performance baseline for monitoring

Test Procedures

4.1 Cold vs Warm Cache Testing

# Benchmark typical post
wp prc seo benchmark --post=<post_id> --iterations=5

# Expected output (JSON):
# {
#   "metrics": {
#     "post": {
#       "schema": {
#         "cold_ms": ~130,
#         "warm_avg_ms": <1,
#         "cache_ratio": >100
#       },
#       "meta": {
#         "cold_ms": ~10,
#         "warm_avg_ms": <1
#       }
#     }
#   }
# }

4.2 Term Page Benchmarking

# Benchmark category page
wp prc seo benchmark --term=<category_id> --taxonomy=category --iterations=5

4.3 Heavy Content Testing

Test posts with many terms to validate worst-case performance:

# Find posts with many categories
wp db query "SELECT object_id, COUNT(*) as cnt FROM wp_term_relationships tr JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy = 'category' GROUP BY object_id ORDER BY cnt DESC LIMIT 5"

# Benchmark heavy posts
wp prc seo benchmark --post=<heavy_post_id> --iterations=3

4.4 Performance Acceptance Thresholds

MetricThresholdAction if Exceeded
Schema cold generation< 200msInvestigate optimization
Schema warm retrieval< 1msCheck cache configuration
Meta tags cold< 20msAcceptable
Meta tags warm< 1msCheck cache configuration
Memory (cold schema)< 3MBProfile memory usage
Cache ratio> 50xValidate cache TTL

Success Criteria

  • Warm cache retrieval < 1ms for schema and meta
  • Cold generation acceptable for amortized performance
  • No memory leaks detected across iterations
  • Cache invalidation works correctly on post save

Phase 5: Integration Testing

Objectives

  • Verify integration with other platform components
  • Test REST API functionality
  • Validate sitemap exclusion logic

Test Procedures

5.1 REST API Testing

# Verify SEO data in REST response
wp post list --post_type=post --field=ID --format=csv | head -5 | while read id; do
  echo "Post $id:"
  wp eval "echo json_encode(get_post_meta($id, '_prc_seo_data', true), JSON_PRETTY_PRINT);"
  echo ""
done

# Test REST endpoint directly
curl -s "https://localhost/wp-json/wp/v2/posts/<id>" | jq '.prc_seo_data'

5.2 Sitemap Integration

# Verify noindex posts are excluded from sitemap
wp db query "SELECT post_id FROM wp_postmeta WHERE meta_key = '_prc_seo_data' AND meta_value LIKE '%\"noindex\":true%'" --skip-column-names | while read id; do
  echo "Checking noindex post $id in sitemap..."
  # Verify post is not in sitemap
done

5.3 Cache Invalidation Testing

# Update a post and verify cache clears
wp post update <post_id> --post_title="Updated Title $(date +%s)"

# Immediately check if cached values are invalidated
wp cache get schema_<post_id> prc_schema_seo_output
# Should return empty/error indicating cache was cleared

5.4 Primary Term Integration

# Verify primary term in breadcrumbs
wp eval "
  \$post_id = <post_id>;
  \$seo_data = get_post_meta(\$post_id, '_prc_seo_data', true);
  print_r(\$seo_data['primary_terms'] ?? 'No primary terms set');
"

Success Criteria

  • REST API returns complete SEO data
  • Noindex posts excluded from sitemaps
  • Cache invalidates on content updates
  • Primary terms used in breadcrumb schema

Phase 6: Visual/Manual Testing

Objectives

  • Verify editor UI functionality
  • Test social sharing previews
  • Validate rendered output in browser

Test Procedures

6.1 Block Editor Testing

TestStepsExpected Result
SEO Panel OpensEdit post → Click "SEO" panelPanel displays with all fields
Title FieldEnter custom titleTitle saves and shows in preview
Description FieldEnter description > 160 charsCharacter count updates
Schema Type SelectionChange schema typeSaves correctly
Noindex ToggleEnable noindexRobots meta updates
Primary Term SelectionSelect primary categoryBreadcrumb updates
OG Image SelectionChoose OG imageImage URL in meta tags

6.2 Site Editor Testing

TestStepsExpected Result
Template Defaults PanelOpen Site Editor → SettingsSEO panel visible
Title PatternSet pattern with tokensPattern saves
Default Schema TypeSelect per-template typeApplied to new posts
Noindex ListAdd URL patternsMatched URLs noindexed

6.3 Front-End Verification

For sample posts, verify in browser:

  1. View Page Source
    • Search for <title> tag
    • Search for application/ld+json
    • Verify meta tags in <head>
  2. Browser Dev Tools
    • Network tab: Verify no SEO-related errors
    • Console: Check for JavaScript errors
  3. Social Sharing Debug Tools
  4. Google Tools

Success Criteria

  • All editor UI elements functional
  • Meta tags visible in page source
  • Social previews render correctly
  • Schema validates in Rich Results Test
  • No console errors related to SEO

Automated Test Suite

Playwright E2E Tests

The plugin includes Playwright tests that can be extended. VIP dev-env and Playwright are centralized at the monorepo root, and these specs live at tests/prc-schema-seo/:

# Run all schema-seo specs
npm run vip:start
npm test -- tests/prc-schema-seo/

# Run a single spec
npm test -- tests/prc-schema-seo/test-template.spec.ts

Create these test files in tests/:

tests/seo-meta-tags.spec.ts

import { test, expect } from '@wordpress/e2e-test-utils-playwright';

test.describe('SEO Meta Tags', () => {
	test('Post has correct meta tags', async ({ page, requestUtils }) => {
		// Create test post with known SEO data
		const post = await requestUtils.createPost({
			title: 'SEO Test Post',
			status: 'publish',
			meta: {
				_prc_seo_data: JSON.stringify({
					title: 'Custom SEO Title',
					description: 'Custom meta description for testing',
				}),
			},
		});

		// Visit the post
		await page.goto(`/?p=${post.id}`);

		// Verify meta tags
		const title = await page.locator('title').textContent();
		expect(title).toContain('Custom SEO Title');

		const description = await page
			.locator('meta[name="description"]')
			.getAttribute('content');
		expect(description).toBe('Custom meta description for testing');
	});

	test('Noindex post has robots noindex', async ({ page, requestUtils }) => {
		const post = await requestUtils.createPost({
			title: 'Noindex Test Post',
			status: 'publish',
			meta: {
				_prc_seo_data: JSON.stringify({
					noindex: true,
				}),
			},
		});

		await page.goto(`/?p=${post.id}`);

		const robots = await page
			.locator('meta[name="robots"]')
			.getAttribute('content');
		expect(robots).toContain('noindex');
	});
});

tests/schema-output.spec.ts

import { test, expect } from '@wordpress/e2e-test-utils-playwright';

test.describe('Schema Output', () => {
	test('Post has valid JSON-LD schema', async ({ page, requestUtils }) => {
		const post = await requestUtils.createPost({
			title: 'Schema Test Post',
			content: 'Test content for schema validation',
			status: 'publish',
		});

		await page.goto(`/?p=${post.id}`);

		// Get JSON-LD script content
		const schemaScript = await page
			.locator('script[type="application/ld+json"]')
			.textContent();
		const schema = JSON.parse(schemaScript);

		// Verify schema structure
		expect(schema['@context']).toBe('https://schema.org');
		expect(schema['@graph']).toBeInstanceOf(Array);

		// Verify Article schema present
		const article = schema['@graph'].find(
			(item: any) => item['@type'] === 'Article'
		);
		expect(article).toBeDefined();
		expect(article.headline).toBe('Schema Test Post');
	});
});

Running Full Test Suite

# Start test environment
npm run vip:start

# Run all SEO tests
npm run test -w @prc/schema-seo

# Generate test report
# Reports saved to tests/artifacts/reports/

Production Rollout Strategy

┌─────────────────────────────────────────────────────────────────────────────┐
│                        ROLLOUT PHASES                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Week 1: Staging           Week 2: Canary           Week 3: Full Rollout    │
│  ─────────────────         ─────────────────        ──────────────────      │
│  • Deploy to staging       • Enable on 5% traffic   • Enable 100%           │
│  • Full test suite         • Monitor Search Console • Disable Yoast         │
│  • Team review             • Compare rankings       • Document learnings    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Pre-Deployment Checklist

  • All migration dry-runs successful
  • Batch comparison shows 95%+ match rate
  • Performance benchmarks within thresholds
  • E2E tests passing
  • Manual testing completed for critical pages
  • Rollback plan documented and tested

Deployment Steps

  1. Pre-deployment
    # Final migration status check
    wp prc seo migration-status
    
    # Run final batch comparison
    wp prc seo compare-batch --limit=500 --format=json > pre-deploy-comparison.json
  2. Deploy
    • Activate prc-schema-seo plugin
    • Deactivate Yoast SEO (but don't delete yet)
  3. Immediate Validation
    # Verify homepage
    wp prc seo compare <homepage_id>
    
    # Verify recent posts
    wp prc seo compare-batch --limit=20
  4. Monitoring Period
    • Monitor for 48-72 hours
    • Check Search Console for crawl errors
    • Review any user-reported issues

Monitoring & Rollback Plan

Key Metrics to Monitor

MetricSourceAlert Threshold
Crawl errorsGoogle Search Console>10 new errors
Index coverageGoogle Search Console>5% drop
Page load timeVIP monitoring>500ms increase
404 errorsServer logsUnusual spike
Schema errorsRich Results TestAny validation failures

Rollback Procedure

If critical issues are discovered:

  1. Immediate Actions
    # Deactivate PRC Schema SEO
    wp plugin deactivate prc-schema-seo
    
    # Reactivate Yoast SEO
    wp plugin activate wordpress-seo
  2. Cache Clear
    # Clear object cache
    wp cache flush
    
    # Clear edge cache (VIP-specific)
    # Follow VIP cache purge procedures
  3. Verification
    • Verify Yoast meta tags appearing
    • Check sample pages for correct output
    • Monitor for immediate error reduction

Post-Rollback Analysis

Document and investigate:

  • Which specific posts/pages had issues
  • What was different about the output
  • Root cause analysis
  • Fixes needed before retry

Testing Checklists

Pre-Migration Checklist

  • Backup database
  • Document current Yoast settings
  • Run wp prc seo migration-status
  • Identify high-traffic posts for priority testing
  • Create comparison baseline with compare-batch

Post-Migration Checklist

  • Verify migration statistics
  • Spot-check 10 random posts
  • Test all post types (post, page, staff, etc.)
  • Verify primary term mappings
  • Check noindex posts maintained status

Pre-Launch Checklist

  • All automated tests passing
  • Batch comparison 95%+ match rate
  • Performance benchmarks acceptable
  • Manual testing completed
  • Stakeholder sign-off obtained
  • Rollback plan documented
  • Monitoring alerts configured

Post-Launch Checklist (Day 1)

  • Homepage meta tags verified
  • Recent posts verified
  • Schema validates in Rich Results Test
  • No new crawl errors in Search Console
  • Page load times unchanged
  • No user-reported issues

Post-Launch Checklist (Week 1)

  • Search Console index coverage stable
  • Click-through rates stable
  • Rankings stable for key terms
  • Social sharing previews correct
  • No ongoing issues reported

Appendix: Quick Reference Commands

Daily Validation Commands

# Quick health check
wp prc seo compare-batch --limit=10

# Check migration status
wp prc seo migration-status

# Benchmark performance
wp prc seo benchmark --post=$(wp post list --post_type=post --posts_per_page=1 --field=ID)

Troubleshooting Commands

# Debug specific post
wp prc seo compare <post_id> --format=full

# Check raw SEO data
wp post meta get <post_id> _prc_seo_data

# Preview what Yoast had
wp prc seo preview-yoast <post_id>

# Force cache clear
wp cache delete schema_<post_id> prc_schema_seo_output
wp cache delete meta_tags_<post_id> prc_schema_seo_output

Bulk Operations

# Compare all published posts of a type
wp post list --post_type=post --post_status=publish --field=ID | while read id; do
  wp prc seo compare $id --diff-only 2>/dev/null
done

# Find posts with differences
wp prc seo compare-batch --limit=1000 --format=json | jq '.results[] | select(.status == "partial") | {id: .post_id, title: .post_title}'

Document History

VersionDateChanges
1.02024-XX-XXInitial testing strategy

Contact

For questions about this testing strategy:

  • Plugin maintainer: See plugin README
  • PRC Platform team: Internal channels

Was this helpful?