Patton Leak Detection: 25-Page Site Build in a Single Session
### Summary
Built and deployed a complete 25-page WordPress website for Patton Leak Detection (pattonleakdetection.com) — a dedicated leak detection sub-brand of Patton Plumbing, Heating & AC — across a single extended Claude Code session. The site includes a homepage, 5 core pages, 6 service pages (1,500-2,000 words each), 7 city-specific service area pages, 3 long-form blog posts, a full JSON-LD schema mu-plugin, SureRank SEO meta on every page, FluentForm booking forms, nginx security headers, Cloudflare CDN config, and a custom performance mu-plugin. Final Lighthouse scores: Performance 87, SEO 100, Accessibility 96, Best Practices 92.
### Why This Build Matters
Patton Plumbing has a 4.9-star rating with 1,900+ Google reviews but ranked nowhere for leak detection keywords in Memphis. Competitors BullsEye Leak Detection and American Leak Detection owned positions #1-2 organically. The goal: stand up a purpose-built leak detection site that could compete immediately — with real content, proper schema, and local SEO from day one. Not a template. Not a placeholder. A complete, production-grade website.
### What Was Built
| Category | Count | Details |
|----------|-------|---------|
| **Core pages** | 6 | Home, About, Contact, Reviews, FAQ (15+ questions), Privacy Policy |
| **Service pages** | 6 | Slab Leak, Pool & Spa, Underground Pipe, Water Line, Commercial, Residential |
| **Service area pages** | 7 | Memphis, Germantown, Collierville, Bartlett, Arlington, Covington, Brownsville |
| **Blog posts** | 3 | Slab leak signs guide, cost guide, pool leak DIY test |
| **Utility pages** | 3 | Services hub, Service Areas hub, Blog index |
| **Total** | 25 | All published, indexed, schema-validated |
Every service page follows a consistent 8-section template: hero with dual CTAs, educational explainer, warning signs card grid with Font Awesome icons, step-by-step detection process, "Why Choose Patton" differentiators, FAQ section using native `wp:details` blocks (for automatic schema extraction), service areas grid, and final CTA. Each is 1,500-2,000 words of Memphis-specific content — clay soil conditions, MLGW billing references, Memphis Sand Aquifer, neighborhood-specific callouts (Cooper-Young, Central Gardens, Midtown, Whitehaven).
The 3 blog posts total approximately 5,000 words combined, each with embedded FAQ sections, Font Awesome duotone icons, and dual CTA buttons.
### Infrastructure Stack
Everything was deployed remotely — no manual WordPress admin clicks:
| Layer | Tool | Details |
|-------|------|---------|
| **Content** | WordPress REST API + WP-CLI via SSH | Pages via REST, meta via WP-CLI eval-file |
| **Hosting** | Laravel Forge | PHP 8.4-FPM, managed nginx |
| **CDN** | Cloudflare | Full Strict SSL, HSTS, Brotli, HTTP/3 |
| **DNS** | Cloudflare | A record + www CNAME, orange-cloud proxied |
| **Theme** | GeneratePress + GP Premium | System sans-serif stack, full-width layout, no sidebars |
| **Forms** | FluentForm Pro | "Request Service" (7 fields) + "Free Estimate" (4 fields) |
| **SEO** | SureRank Pro | Custom title/description/focus keyword on all 25 pages |
| **Schema** | Custom mu-plugin (`pld-schema.php`) | Organization, LocalBusiness, Service, FAQPage, BlogPosting, BreadcrumbList, WebSite |
| **Performance** | Custom mu-plugin (`pld-performance.php`) | Dashicons dequeue, FA preconnect hints |
| **Security** | Nginx headers via Forge API | CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy, directory browsing blocked |
| **Verification** | Chrome MCP | Visual screenshots at each milestone |
### Content Authoring Approach
The 6 service pages were drafted by parallel background agents, each generating full Gutenberg block markup with Memphis-local content. The 7 city pages used a similar template-with-local-variation approach — each city gets unique content about its housing stock, plumbing characteristics, and local risk factors rather than boilerplate find-and-replace. Blog posts were authored directly in the main thread after sub-agent Bash permissions proved unreliable, using Python `urllib` to POST JSON payloads to the REST API (curl had encoding issues with special characters; Cloudflare blocked Python's default User-Agent, solved with `User-Agent: curl/8.7.1`).
### Bugs Squashed Along the Way
| Issue | Root Cause | Fix |
|-------|-----------|-----|
| SureRank sitemap 301 redirect loop | SureRank's `template_redirect` hook fires before any filter can intercept; nginx `try_files` sends `.xml` to WordPress, which redirects | Deployed static `sitemap.xml` to webroot — nginx serves it directly, bypassing WordPress entirely |
| WordPress rewrite rules corrupted | `rewrite_rules` option stored as string instead of array | `delete_option` + `$wp_rewrite->flush_rules(false)` — regenerated 149 rules as proper array |
| `pld-performance.php` fatal error | `cat >>` appended code with duplicate `php` tag | Rewrote entire file and SCP'd clean version |
| Blog post REST API failures | curl couldn't handle special characters in JSON; Python urllib blocked by Cloudflare | Switched to Python with `User-Agent: curl/8.7.1` header |
| Stale page cache after updates | WP-Optimize serving cached versions | `wp cache flush && wp transient delete --all` after content updates |
| GP layout meta not applying | WP-CLI `wp eval` fails with PHP namespaces (backslash escaping) | Write PHP to file, SCP to server, `wp eval-file /tmp/script.php` |
### Schema Architecture
The `pld-schema.php` mu-plugin outputs page-specific JSON-LD, following the same pattern as `thd-schema.php`:
| Page Type | Schema Types |
|-----------|-------------|
| Every page | Organization + BreadcrumbList |
| Homepage | + WebSite + LocalBusiness (Plumber + LeakDetectionService, 22 cities in areaServed, aggregateRating 4.9/1912) |
| Service pages | + Service (per service type) + FAQPage (auto-extracted from wp:details blocks) |
| City pages | + LocalBusiness (geo-specific) + Service (available services in that city) |
| Blog posts | + BlogPosting + FAQPage (if wp:details present) |
### Lighthouse Results
| Page | Performance | SEO | Accessibility | Best Practices |
|------|-------------|-----|---------------|----------------|
| Homepage | 87 | 100 | 96 | 92 |
| Slab Leak Detection | 84 | 100 | 100 | 92 |
| Blog Post | 88 | 100 | 100 | 92 |
All targets met (Performance 85+, SEO 95+, Accessibility 90+, Best Practices 90+). Key optimizations: dashicons removed for logged-out users, Font Awesome preconnect/dns-prefetch hints, system font stack (no Google Fonts to load), lazy loading below-fold images.
### The Speed Factor
This is the third site built using the Forge API + WP-CLI + REST API pipeline in a single day (after CSB LAW and Peel Law Firm). But those were 5-7 page attorney sites with similar structure. Patton Leak Detection is a different animal:
- **25 pages** vs 5-7
- **6 long-form service pages** at 1,500-2,000 words each with unique Memphis-specific content
- **7 city pages** each with localized housing/plumbing/risk content
- **3 blog posts** totaling ~5,000 words with FAQ sections
- **Full schema mu-plugin** with 5 schema types and page-type detection
- **CSP headers, nginx security config, Cloudflare CDN** — production-grade infrastructure
- **Sitemap debugging** — a multi-hour investigation into SureRank's nginx incompatibility
The traditional timeline for a site of this scope — 25 pages of original content, schema markup, SEO configuration, security hardening, performance optimization, and CDN setup — would be measured in weeks. A fast freelancer might do it in 5-7 business days. An agency would quote 2-4 weeks. This was done in a single continuous session using Claude Code, with every page containing real, locally-relevant content rather than template filler.
### File Inventory
| File | Location | Purpose |
|------|----------|---------|
| `pld-schema.php` | `mu-plugins/` on server | JSON-LD structured data (14.5KB) |
| `pld-performance.php` | `mu-plugins/` on server | Dashicons removal + FA preconnect |
| `thd-auto-login.php` | `mu-plugins/` on server | THDCRM auto-login integration |
| `sitemap.xml` | Webroot on server | Static XML sitemap (25 URLs) |
| nginx config | Forge-managed | Security headers, CSP, directory blocking |
*Reflection: The bottleneck was never content generation — it was infrastructure debugging. Writing 25 pages of localized content took less cumulative time than diagnosing the SureRank sitemap redirect loop. The static sitemap workaround feels inelegant but is actually more reliable than any WordPress-generated sitemap on nginx (no PHP execution, no redirect logic, just a file). The REST API + Python urllib pattern for publishing (with the curl User-Agent trick to bypass Cloudflare) is now the most reliable content deployment method — more reliable than curl itself, which chokes on certain JSON character sequences. For future builds: always deploy content via Python, not curl; always check rewrite_rules is an array after any plugin activation; and if a plugin's sitemap doesn't work on nginx, skip the debugging and go straight to a static file.*