Last Mover Advantage: Why WordPress Is Expensive for AI Development
WordPress can't be rewritten simpler without breaking the ecosystem. 25 years of legacy code makes it expensive for AI to reason about. Modern static frameworks approach the same problem with hindsight.
Last Mover Advantage: Why WordPress Is Expensive for AI Development
Last month, Lee Robinson (VP of Product at Vercel) deleted his $56,000 headless CMS and moved to markdown files. Most analysis focused on “simplicity” or “modern workflows.”
They missed the real question: How do you architect for maximum AI utility?
When AI handles implementation, you focus on judgment - UI decisions, design taste, user experience. When the stack is too complex for AI to reason about accurately, you get dragged back into implementation details.
WordPress’s complexity tax: Forces you to focus on implementation (debugging, cache layers, plugin conflicts, database states).
Astro’s flat architecture: AI can reason accurately and predict outcomes → you stay in judgment mode.
The difference in where you spend your time is measurable.
The Measurements
Claude Sonnet 4.5 context window: 200,000 tokens
WordPress 6.x core PHP code: ~3.5MB Estimated tokens: ~875,000 tokens (4.3x over context limit)
A typical Astro site I build: ~400KB of source code Measured tokens: ~100,000 tokens (measured from megangredesky.com)
WordPress core doesn’t fit in the context window. When the AI can’t see the full system, it can’t predict behavior accurately. The cost shows up in every task.
What “Can’t Fit” Actually Costs
WordPress development stack:
- Docker container (runtime environment)
- MySQL database (hidden state)
- wp-cli (command abstraction)
- WordPress core (875K tokens)
- Active plugins (behavior modifiers)
- Theme functions (hooks/filters)
- Dev vs production differences
Each layer adds uncertainty. The AI must reason about:
- Current database state (can’t observe directly)
- Which plugins are active (changes behavior)
- Docker container state (varies)
- Cache layers (hidden)
- Environment differences (dev vs production)
The AI can’t see most of these layers. It has to guess.
Astro development stack:
- Source code (fits in context)
- Static build (deterministic)
- Output HTML (predictable)
The AI sees everything. No hidden state.
How AI Reasoning Actually Works
To understand why one system is cheaper to reason about, you need to see how the AI thinks through a problem in each environment.
WordPress: Reasoning Under Uncertainty
Task: “Add a custom field to display author bio on blog posts”
AI’s reasoning process:
Step 1: Assess what I can observe
- I can see theme files (partial - only current theme)
- I can’t see the database schema
- I can’t see which plugins are active
- I can’t see what hooks/filters are registered
- I can’t see cache configuration
Step 2: Make assumptions
// AI must write defensive code because it's guessing
if (function_exists('get_post_meta')) {
$author_bio = get_post_meta($post->ID, 'author_bio', true);
// But wait - is there a plugin that filters this?
// I can't see the filter chain
// Is this cached? I don't know
// Will this work in production? Can't verify
}
Step 3: Propose generic solution
- “Try adding a custom field using WordPress admin”
- “Check if your theme supports custom fields”
- “You may need to clear cache”
- All hedged language because I can’t see the system
Step 4: Test reveals assumptions were wrong
- Custom post type uses different meta key structure
- Plugin already handles author bio differently
- Cache wasn’t cleared
- Had to iterate 5 times to find actual implementation
Cost of reasoning:
- Can’t see full system → Must assume → Generic solutions → Multiple iterations
- Every assumption is a potential error
- Every layer of uncertainty compounds the guessing
Astro: Reasoning With Full Observation
Same task: “Add author bio to blog posts”
AI’s reasoning process:
Step 1: Observe the entire system
// I can see src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
schema: z.object({
title: z.string(),
author: z.string(),
// I see exactly what fields exist
})
});
Step 2: I know exactly what to do
// Add authorBio to schema
const blog = defineCollection({
schema: z.object({
title: z.string(),
author: z.string(),
authorBio: z.string().optional(), // Add this
})
});
// I can see all blog post files
// I know exactly which ones to update
// I know the build will validate the schema
// No database, no cache, no plugins to check
Step 3: Propose specific solution
- “Add
authorBio: z.string().optional()to schema at src/content/config.ts:12” - “Update 3 blog posts at src/content/blog/*.md”
- “Add
{post.data.authorBio}to BlogPost component at src/components/BlogPost.astro:28” - All specific file paths and line numbers because I can see everything
Step 4: It works first try
- Schema validates at build time
- No hidden state to corrupt behavior
- No cache to clear
- Deterministic: same input = same output
Cost of reasoning:
- Can see full system → Know exact state → Specific solutions → Single iteration
- Zero assumptions
- Zero uncertainty
The Difference In Cognitive Cost
WordPress AI reasoning:
Observe partial system
→ Make assumptions about hidden state
→ Write defensive code with guards
→ Propose generic solution with hedges
→ Test reveals wrong assumptions
→ Iterate with new assumptions
→ Repeat until solution found
Astro AI reasoning:
Observe complete system
→ Know exact state
→ Write precise code
→ Propose specific solution with confidence
→ It works
This is why “expensive to reason about” is literal:
- WordPress: 7 reasoning steps per task (most are guessing)
- Astro: 2 reasoning steps per task (observation → solution)
The cost compounds:
- Every uncertainty adds a branch in reasoning
- Every assumption multiplies potential errors
- Every iteration burns time and tokens
- WordPress forces the AI to think harder and guess more
Real Example: Update 15 Blog Posts
Client request: “Add new office address to all blog posts”
WordPress workflow:
- AI proposes: Query posts via WP_Query
- Test in Docker environment
- Doesn’t work (forgot custom post meta)
- AI proposes: Add meta query
- Test again
- Partially works (plugin modifies meta on save)
- AI proposes: Bypass plugin with direct DB update
- Test again
- Works but cache not cleared
- AI proposes: Add wp_cache_flush()
Total: 10 iterations, 2 hours Why: AI can’t predict plugin behavior, database schema, or cache layers
Astro workflow:
grep -r "old address" content/blog/- AI edits 15 markdown files
- Build runs
- Done
Total: 1 iteration, 10 minutes Why: AI sees all files, knows build is deterministic
The Hidden Costs: Learning How to Work
Over 18 months with WordPress, I had to build operational playbooks just to know what works:
Docker local vs dev server:
- When is local Docker preferred?
- When does it become a bottleneck?
- This decision doesn’t exist in Astro
WordPress MCP didn’t stick:
- Tried the WordPress MCP server
- It broke too often
- WordPress REST API via curl became my actual SOP
- Had to learn this through trial and error
Playbook development as hidden cost:
- Document: “This pathway works, this one wastes effort”
- Build institutional knowledge to navigate unpredictability
- Expensive meta-work just to know how to work
Astro comparison:
- One-time setup cost
- Then things just work
- No playbook needed - stack is simple enough to trust
The cost isn’t just slower tasks. It’s spending effort learning how to navigate complexity itself.
The WordPress Optimizations We Found
To be fair: We didn’t just complain about WordPress. We hunted for efficiencies.
Over 18 months of WordPress development, we discovered patterns that significantly reduced the AI iteration cost. These aren’t theoretical - they’re battle-tested from actual client work.
Optimization 1: Twenty Twenty-Five Child Theme + Tailwind v4 CDN
The breakthrough:
- Use TT5 as parent theme (modern, well-maintained)
- Create child theme with systematic CSS overrides
- Deliver Tailwind v4 via CDN (not pre-compiled locally)
- Work WITH block themes instead of fighting them
What this solved:
- 15-minute setup time (vs hours of config)
- Component-centered architecture
- Modular design patterns
- No build step required
The architecture:
// functions.php
function enqueue_tailwind() {
wp_enqueue_script('tailwindcss-cdn',
'https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4',
array(), '4.0', false);
}
Key insight: Child theme inherits parent’s block structure, we control styling via CSS specificity + Tailwind utilities.
Optimization 2: PHP Templates + Pure Tailwind (Bypass Blocks Entirely)
The even bigger breakthrough:
- Replace
.htmlblock templates with.phptemplates - Use pure Tailwind classes (no block CSS conflicts)
- Classic Editor + ACF fields for structured content
- Complete design control
What this solved:
- No CSS conflicts with WordPress blocks
- Consistent styling across all components
- Better performance (no block CSS generation)
- Clear separation: WordPress handles data, Tailwind handles design
Template comparison:
// Before: Block theme template (archive.html)
<!-- wp:group {"style":{"spacing":{"margin":{"top":"0"}}}} -->
<main class="wp-block-group">
<!-- wp:pattern {"slug":"theme/query-loop"} /-->
</main>
<!-- /wp:group -->
// After: PHP template with Tailwind (archive.php)
<div class="min-h-screen bg-gradient-to-br from-neutral-50 to-neutral-100">
<section class="relative py-20 px-4 sm:px-6 lg:px-8">
<div class="max-w-6xl mx-auto">
<h1 class="text-4xl md:text-6xl font-heading text-neutral-900 mb-6">
<?php the_title(); ?>
</h1>
<?php
while (have_posts()) {
the_post();
get_template_part('template-parts/content');
}
?>
</div>
</section>
</div>
Results from Walt Opie project:
- Reduced from 8 templates to 6 core templates
- Eliminated template conflicts
- Achieved consistent Tailwind styling
- Content creators got familiar WordPress experience
- Developers got complete design control
Optimization 3: Operational Playbooks
What we documented:
- Docker local vs dev server decision matrix
- WordPress REST API via curl (MCP server too fragile)
- CSS specificity patterns for block theme overrides
- Component patterns library (hero sections, grids, navigation)
- WCAG-compliant color combinations
The efficiency gain: These optimizations worked. They reduced iteration counts from ~10 attempts to ~3-5 attempts for common tasks.
But here’s the key insight: Even with these optimizations, WordPress was still 3-5x more expensive than Astro.
Why Even Optimizations Can’t Close the Gap
The optimizations helped. But they couldn’t eliminate the underlying complexity.
What the optimizations fixed:
- Reduced CSS conflicts
- Cleaner component patterns
- Faster setup for new projects
- Better developer experience
What they couldn’t fix:
- WordPress core still doesn’t fit in context window (875K tokens)
- Database state still hidden from AI observation
- Plugin interactions still non-deterministic
- Docker abstraction layer still adds uncertainty
- 25 years of legacy code still there
The honest comparison:
Optimized WordPress:
- Setup: 15 minutes (child theme approach)
- Iteration cost: 3-5 attempts per task (down from 10)
- Learning curve: Requires documented playbooks
- Stack complexity: 7 layers (reduced conflicts, but layers remain)
- Context window: Still exceeds by 4.3x
Astro:
- Setup: 10 minutes (project scaffold)
- Iteration cost: 1-2 attempts per task
- Learning curve: Minimal (stack is simple enough to trust)
- Stack complexity: 1 layer
- Context window: Fits comfortably (50% of available space)
The gap narrowed, but never closed.
Even with modern WordPress approaches (TT5, Tailwind v4 CDN, PHP templates), the fundamental issue remains: the AI has to think harder and guess more because the underlying system complexity is still there.
The Journey: What Actually Tipped the Balance
Here’s what actually happened over 18 months:
Phase 1: Optimized WordPress extensively
- Child theme architecture
- Tailwind v4 integration
- PHP templates over block themes
- Component patterns library
- Operational playbooks
Results: It worked. Reduced iteration counts from 10→3-5 attempts. Made WordPress development with AI significantly better.
Phase 2: Security exposure became untenable
This wasn’t theoretical. WordPress sites face:
- Constant vulnerability patches
- Active predators scanning for exposed admin panels
- Plugin vulnerabilities (third-party code you don’t control)
- Database exposed to attack surface
- Ongoing security vigilance required
The hidden cost: Security operations consume attention that should go to building features.
Phase 3: Forced migration to headless architecture
Security requirements pushed us to:
- WordPress backend (headless CMS)
- Astro frontend (static site)
Why: Astro’s static architecture has essentially zero attack surface:
- No database to breach
- No admin panel exposed
- No server-side execution
- No plugin vulnerabilities
Phase 4: The gap became undeniable
Once we experienced Astro for the frontend, the difference was impossible to ignore:
- WordPress backend (optimized): 3-5 iterations per task
- Astro frontend: 1-2 iterations per task
- More importantly: With Astro, I stayed in judgment mode (UI decisions, design). With WordPress, I got dragged back into implementation (debugging, cache, state).
What tipped the balance:
- Security exposure (practical forcing function)
- Experiencing the simpler alternative (revealed the gap)
- Where you spend your time (judgment vs implementation)
Worth it to avoid vulnerabilities and predators.
This wasn’t dogmatic. We gave WordPress every possible advantage, made it work reasonably well, and then external constraints revealed the fundamental difference.
Why WordPress Can’t Fix This
WordPress is excellently maintained. Active development, regular security updates, massive community support.
The problem: WordPress can’t be rewritten simpler without destroying the ecosystem.
The backwards compatibility trap:
- 43% of the web runs WordPress
- Millions of sites depend on it
- Plugin ecosystem has thousands of extensions
- Breaking backwards compatibility would destroy the ecosystem
The result:
- Old solutions stay in the codebase forever
- Can’t remove legacy approaches even when better ones exist
- Technical debt accumulates indefinitely
- Success creates architectural lock-in
This is why “well-maintained” doesn’t mean “simple”:
- Maintenance = keeping everything working
- “Working” includes supporting 20-year-old plugins
- Every new feature adds to what exists
- Nothing gets removed
Less Legacy Code = Cheaper to Think About
WordPress carries 25 years of solutions to problems that either:
- Have better solutions now
- Or aren’t even problems anymore
Yesterday’s problems WordPress solved:
- Non-technical users need GUIs → WordPress admin
- Dynamic content requires databases → MySQL architecture
- Extensibility needs plugins → Hooks/filters system
- Backward compatibility → Can’t remove old code
- Performance without CDNs → Complex caching layers
Today’s reality for a small business site:
- Markdown + Git is version control
- Static builds work fine
- Netlify/Vercel handle deployment
- CDNs are standard
- Modern frameworks have built-in security
WordPress still carries all those solutions even though many aren’t needed anymore. That’s what makes it expensive to think about - for humans AND for AI.
The Compounding Cost
The complexity cost compounds with every task.
WordPress development:
- Task 1: Add feature → 5 iterations
- Task 5: Update CSS → 5 iterations (same stack complexity)
- Task 10: Fix bug → 5 iterations (AI can’t learn non-deterministic system)
The cost never decreases because:
- Database state changes between operations
- Plugin behavior isn’t predictable
- Docker container state varies
- System is non-deterministic → AI can’t learn patterns
Astro development:
- Task 1: Add feature → 3 iterations
- Task 5: Update CSS → 2 iterations (AI learned patterns)
- Task 10: Fix bug → 1 iteration (AI knows the system)
The cost decreases because:
- Same input produces same output
- No database state to track
- No container variance
- System is deterministic → AI learns and improves
What This Means for Component Selection
The question isn’t “Should I use WordPress?”
The question is: “Can my AI pair programmer see enough of my system to work effectively?”
Evaluate components by:
- Does it fit in the context window?
- Can AI observe the full system state?
- Is behavior deterministic (same input = same output)?
- Can it evolve, or is it locked by backwards compatibility?
If your stack:
- Exceeds context window limits
- Has hidden state AI can’t observe
- Includes non-deterministic behavior
- Is locked by backwards compatibility
Then your AI will be:
- Imprecise (defensive code, generic suggestions)
- Slow (more iterations to get it right)
- Non-learning (can’t improve because system is unpredictable)
And the cost will compound with every task.
The Numbers
WordPress + Docker + plugins:
- Core: ~875K tokens (4.3x over context limit)
- Abstraction layers: 7
- System determinism: Low
- AI learning curve: Flat
- Development cost: Constant high cost per task
Astro site:
- Total: ~100K tokens (fits in 50% of context)
- Abstraction layers: 1
- System determinism: High
- AI learning curve: Positive
- Development cost: Decreases with each task
Measured difference: 12x iteration reduction (2 hours → 10 minutes for batch updates)
The Principle
Choose components that solve today’s problems, not yesterday’s.
Less legacy code = less to think about = cheaper development with AI.
WordPress isn’t poorly maintained. It’s architecturally locked by its own success. It can’t be simplified without breaking millions of sites.
Modern static frameworks approach the same problems with the advantage of hindsight - no database by default, component-based, built for CDNs and edge deployment.
Dean Keesey builds websites for therapy practices. After migrating three sites from WordPress to Astro, measured iteration counts dropped 12x. The difference: AI can see the entire system and trust improves with every task.
Written by Dean Keesey