This plugin was built specifically for the 84em.com website and its unique functionalities.
It is not intended for use on any other website.
If you chose to use & install it, you do so at your own risk.
Want a version that you can run on your own site? Contact 84EM.
A WordPress plugin that automatically generates SEO-optimized Local Pages for each US state and city using Claude AI and WP-CLI, designed specifically for 84em.com.
This plugin creates unique, locally-focused landing pages for WordPress development services in all 50 US states and their major cities. Each page targets location-specific keywords while incorporating geographic relevance and automatic interlinking to avoid duplicate content penalties.
- Hierarchical Post Type: Creates "Local Pages" with parent-child relationships (states → cities)
- Comprehensive Coverage: 50 state pages + 300 city pages (6 cities per state) = 350 total pages
- WP-CLI Integration: Complete command-line management interface with progress bars
- Claude AI Content: Generates unique content using Claude Sonnet 4
- Automatic Interlinking: City names link to city pages, service keywords link to contact page
- SEO Optimization: Built-in SEO meta data and structured LD-JSON schema
- Geographic Relevance: Each page focuses on local cities and geographic context
- Bulk Operations: Create, update, or delete multiple pages efficiently
- Call-to-Action Integration: Automatic CTA placement with contact links
- WordPress Block Editor: Content generated in Gutenberg block format
- Rate Limiting: Respects API limits with configurable delays and duration tracking
- Progress Indicators: Real-time feedback on API requests and processing
- XML Sitemap Generation: Generate XML sitemaps for all local pages with WP-CLI
- Index Page Generation: Create or update a master index page with alphabetized state list
- Schema Regeneration: Fix LD-JSON schema issues without regenerating page content
- Keyword Link Updates: Update service keyword links when URLs change without API calls
- WordPress 6.8 or higher
- PHP 8.2 or higher
- WP-CLI 2.0 or higher
- Claude API key from Anthropic
This repository uses the official Anthropic Claude Code Security Review GitHub Action to automatically review all pull requests for security vulnerabilities.
- AI-Powered Analysis: Claude analyzes code changes for security vulnerabilities
- Automated PR Comments: Security findings are posted directly on pull requests
- Language Agnostic: Works with PHP, JavaScript, TypeScript, and more
- False Positive Filtering: Focuses on high-confidence vulnerabilities
- Dependency Scanning: Additional checks for vulnerable dependencies
-
Add Claude API Key: Add your Anthropic API key as a GitHub secret named
ANTHROPIC_API_KEY
# Using GitHub CLI gh secret set ANTHROPIC_API_KEY # Or add manually in repository Settings → Secrets → Actions
-
That's it! The workflow automatically triggers on all pull requests
- SQL injection, XSS, command injection vulnerabilities
- Authentication and authorization flaws
- Hardcoded secrets and API keys
- Insecure cryptographic implementations
- Path traversal and file operation security
- Dependency vulnerabilities (composer and npm)
# Check for dependency vulnerabilities locally
composer audit
npm audit
# Run PHP syntax checks
find . -name "*.php" -not -path "./vendor/*" -exec php -l {} +
-
Upload Plugin Files
# Upload to your WordPress plugins directory /wp-content/plugins/84em-local-pages/
-
Activate Plugin
- Go to WordPress Admin → Plugins
- Find "84EM Local Pages Generator"
- Click "Activate"
-
Verify WP-CLI Access
wp --info
wp 84em local-pages --set-api-key
# You will be prompted to securely paste your API key
wp 84em local-pages --generate-all
# Creates 50 state pages + 300 city pages = 350 total pages
wp 84em local-pages --generate-index
wp 84em local-pages --generate-sitemap
# Check created pages
wp post list --post_type=local --format=count
# Check hierarchical structure
wp post list --post_type=local --format=table
# Check index page
wp post list --post_type=page --name=wordpress-development-services-usa --format=table
Generate/Create Everything:
# Generate all states and cities (350 pages)
wp 84em local-pages --generate-all
# Generate states only (50 pages)
wp 84em local-pages --generate-all --states-only
Update Existing Pages:
# Update all existing states and cities
wp 84em local-pages --update-all
# Update existing states only
wp 84em local-pages --update-all --states-only
Set Claude API Key:
wp 84em local-pages --set-api-key
# Interactive prompt - paste your key securely without shell history
Validate API Key:
wp 84em local-pages --validate-api-key
Generate/Update States:
# All states (legacy command)
wp 84em local-pages --state=all
# Specific states
wp 84em local-pages --state="California"
wp 84em local-pages --state="California,New York,Texas"
Update Existing States:
# All states
wp 84em local-pages --update --state=all
# Specific states
wp 84em local-pages --update --state="California,New York"
Generate/Update Cities:
# All cities for a state
wp 84em local-pages --state="California" --city=all
# All cities for a state AND update state page
wp 84em local-pages --state="California" --city=all --complete
# Specific cities
wp 84em local-pages --state="California" --city="Los Angeles"
wp 84em local-pages --state="California" --city="Los Angeles,San Diego,San Francisco"
Delete States:
# All states
wp 84em local-pages --delete --state=all
# Specific states
wp 84em local-pages --delete --state="California,New York"
Delete Cities:
# All cities for a state
wp 84em local-pages --delete --state="California" --city=all
# Specific cities
wp 84em local-pages --delete --state="California" --city="Los Angeles,San Diego"
Generate Index Page:
wp 84em local-pages --generate-index
Generate XML Sitemap:
wp 84em local-pages --generate-sitemap
Update Keyword Links (Refresh service keyword links without API calls):
# Update keyword links in all pages
wp 84em local-pages --update-keyword-links
# Update keyword links in state pages only
wp 84em local-pages --update-keyword-links --states-only
Regenerate LD-JSON Schemas (Fix schema issues without regenerating content):
# All pages
wp 84em local-pages --regenerate-schema
# States only
wp 84em local-pages --regenerate-schema --states-only
# Specific state and its cities
wp 84em local-pages --regenerate-schema --state="California"
# Specific state only (no cities)
wp 84em local-pages --regenerate-schema --state="California" --state-only
# Specific city
wp 84em local-pages --regenerate-schema --state="California" --city="Los Angeles"
Show Available Commands:
wp 84em local-pages
The plugin creates a hierarchical structure:
State Page (Parent)
├── City 1 Page (Child)
├── City 2 Page (Child)
├── City 3 Page (Child)
├── City 4 Page (Child)
├── City 5 Page (Child)
└── City 6 Page (Child)
# State pages
https://84em.com/wordpress-development-services-california/
https://84em.com/wordpress-development-services-texas/
# City pages (child pages)
https://84em.com/wordpress-development-services-california/los-angeles/
https://84em.com/wordpress-development-services-california/san-diego/
https://84em.com/wordpress-development-services-texas/houston/
https://84em.com/wordpress-development-services-texas/dallas/
- State Analysis: Plugin identifies the state and its 6 largest cities
- Hierarchical Creation: Creates state page first, then child city pages
- Claude Prompt: Sends structured prompts to Claude AI API with location-specific context
- Content Creation: Generates unique content for each location
- Automatic Interlinking: Links city names to city pages, service keywords to contact page
- CTA Integration: Adds call-to-action blocks before each H2 heading
- SEO Integration: Adds optimized titles, meta descriptions, and LD-JSON Schema data
- Post Creation: Saves as hierarchical "local" custom post type with clean URLs
State Pages (300-400 words):
- Geographic relevance with state and major city mentions
- Service focus on WordPress development capabilities
- City names automatically linked to their respective city pages
- Service keywords automatically linked to contact page
City Pages (250-350 words):
- City-specific benefits and local business context
- Geographic references to the city and state
- Service keywords automatically linked to contact page
- Parent-child relationship with state page
State Pages:
- ✅ City names → Link to city pages
- ✅ Service keywords → Link to https://84em.com/contact/
City Pages:
- ✅ Service keywords → Link to https://84em.com/contact/
State Pages:
- SEO Title: "Expert WordPress Development Services in [State] | 84EM"
- Meta Description: State and city-specific description
- LD-JSON Schema: LocalBusiness schema with city containment
City Pages:
- SEO Title: "Expert WordPress Development Services in [City], [State] | 84EM"
- Meta Description: City and state-specific description
- LD-JSON Schema: LocalBusiness schema with city focus
- Inline CTAs: 2-3 contextual links throughout content linking to /contact/
- Prominent CTA Blocks: Placed before every H2 heading
- Styled Buttons: "Start Your WordPress Project" with custom styling
- Natural Integration: CTAs flow naturally within content
- Create Anthropic Account: Visit console.anthropic.com
- Generate API Key: Create new API key in dashboard
- Configure Billing: Set up payment method for usage-based pricing
- Set Rate Limits: Configure appropriate limits for your needs
- Full Generation (350 pages): $14-28 per complete run
- State Pages Only (50 pages): $2-4 per run
- Individual Updates: $0.04-0.08 per page
- Monthly Maintenance: $20-40 depending on update frequency
'model' => 'claude-sonnet-4-20250514'
'max_tokens' => 4000
'timeout' => 600 seconds
'rate_limit' => 1 second delay between requests
- Name: Local Pages
- Slug: local (but URLs don't include /local/)
- Hierarchical: Yes (supports parent-child relationships)
- Public: Yes
- Archive: Yes
- REST API: Enabled
- Supports: Title, editor, thumbnail, excerpt, custom fields
State Pages:
_local_page_state
: State name (e.g., "California")_local_page_cities
: Comma-separated 6 largest cities_genesis_title
: SEO title_genesis_description
: SEO meta descriptionschema
: LD-JSON structured data
City Pages:
_local_page_state
: State name (e.g., "California")_local_page_city
: City name (e.g., "Los Angeles")_genesis_title
: SEO title_genesis_description
: SEO meta descriptionschema
: LD-JSON structured data
- All content generated in Gutenberg block syntax
- Proper block markup for paragraphs, headings, and CTAs
- Bold headings with
<strong>
tags - Clean, structured HTML output
- Smart block detection prevents duplicate wrapping (v3.0.1+)
- Full compatibility with WordPress Block Editor for editing
- Emphasizes 84EM's 100% remote operations
- No mentions of on-site visits or local offices
- Focus on technical expertise and proven remote delivery
- Factual tone without hyperbole
The generate-index
command creates or updates a master index page that serves as a navigation hub for all state pages. This page provides an alphabetized directory of all US states with direct links to their respective state pages.
- Page Slug:
wordpress-development-services-usa
- Page Title:
WordPress Development Services in USA | 84EM
- Page Type: Standard WordPress page (not custom post type)
- URL:
https://84em.com/wordpress-development-services-usa/
- Automatic State Discovery: Uses WP_Query to find all published state pages
- Alphabetical Sorting: States are automatically sorted A-Z for easy navigation
- Smart Create/Update: Detects existing page and updates content, or creates new page
- SEO Optimized: Includes meta description and SEO title
- WordPress Block Format: Content generated in Gutenberg block syntax
- Professional Content: Includes service overview and call-to-action
# 1. Set API key
wp 84em local-pages --set-api-key
# 2. Generate everything (350 pages)
wp 84em local-pages --generate-all
# 3. Generate supporting pages
wp 84em local-pages --generate-index
wp 84em local-pages --generate-sitemap
# 4. Verify results
wp post list --post_type=local --format=count
# Update all existing content
wp 84em local-pages --update-all
# Refresh supporting pages
wp 84em local-pages --generate-index
wp 84em local-pages --generate-sitemap
# Test with a few states first
wp 84em local-pages --state="California,New York,Texas"
# Generate cities for specific states
wp 84em local-pages --state="California" --city=all
wp 84em local-pages --state="New York" --city=all
# Update specific locations
wp 84em local-pages --update --state="California"
wp 84em local-pages --state="California" --city="Los Angeles,San Diego"
# Check for failed pages
wp post list --post_type=local --post_status=draft --format=table
# Check page counts
wp post list --post_type=local --format=count
# Regenerate specific failed locations
wp 84em local-pages --update --state="California"
wp 84em local-pages --state="California" --city="Los Angeles"
# Monitor error logs
tail -f /path/to/wordpress/wp-content/debug.log
"Claude API key not found"
# Solution: Set the API key
wp 84em local-pages --set-api-key
"Failed to generate content for [Location]"
- Check API key validity with
--validate-api-key
- Verify internet connection
- Check Anthropic service status
- Review API usage limits
"Parent state page not found"
- Create state page first before generating city pages
- Use
--generate-all
to create everything in proper order
"Invalid state name" or "City not found in [State]"
- Use full state names (e.g., "California", not "CA")
- Check spelling and capitalization
- City names must match the predefined list in the plugin
"cURL timeout errors"
// Add to wp-config.php
define('WP_HTTP_TIMEOUT', 120);
"Memory limit exceeded"
// Add to wp-config.php
define('WP_MEMORY_LIMIT', '512M');
Enable detailed logging:
// In wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
View plugin logs:
tail -f /wp-content/debug.log | grep "84EM"
- Real-time progress bars for bulk operations
- API request duration tracking
- Individual location processing indicators
- Clear success/failure messaging with emojis
- Comprehensive statistics showing created/updated counts
- Monitor Progress: Built-in progress indicators show real-time status
- Hierarchical Processing: States are created first, then their cities
- Rate Limiting: Plugin includes 1-second delays between API calls
- Memory Management: Increase PHP memory limits for large operations
- Error Handling: Graceful failures with detailed logging
The plugin works with most caching plugins, but consider:
- Clear cache after bulk updates
- Exclude Local Pages from aggressive caching
- Warm cache for new pages automatically
- Keys encrypted using AES-256-CBC encryption with WordPress salts
- Encryption key derived from WordPress AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, and NONCE_KEY
- Only encrypted data stored in database - no plaintext API keys
- Cryptographically secure initialization vector (IV) for each encryption
- Not exposed in frontend or logs
- Interactive Entry: API keys are entered via secure prompt, not command arguments
- No Shell History: Keys don't appear in bash/shell command history
- Hidden Input: Terminal echo is disabled during key entry for privacy
- Format Validation: Warns if key doesn't match expected Claude API format
- All user inputs sanitized and validated
- WP-CLI commands require appropriate permissions
- Post content properly escaped before display
- Built-in delays prevent API abuse
- Configurable timeout settings
- Graceful handling of API failures
# Check total page count
wp post list --post_type=local --format=count
# List all local pages with hierarchy
wp post list --post_type=local --format=table
# Check for drafts (potential failures)
wp post list --post_type=local --post_status=draft --format=table
# Count state vs city pages
wp post list --post_type=local --meta_key=_local_page_city --format=count
wp post list --post_type=local --meta_key=_local_page_state --format=count
# Export all local pages
wp export --post_type=local
# Backup database
wp db export 84em-local-pages-backup-$(date +%Y%m%d).sql
# Export existing local pages
wp export --post_type=local --dir=/backups/local-pages/
# Restore from database backup
wp db import 84em-local-pages-backup-20250130.sql
# Or import specific posts
wp import /backups/local-pages/local-pages-export.xml
The plugin uses GitHub Actions for automated multi-environment deployments with comprehensive validation, backup, and rollback capabilities.
- Branch:
main
- Trigger: PR merge to main or manual workflow dispatch
- Workflow:
.github/workflows/deploy-prod.yml
- URL:
https://84em.com
- Branch:
staging
- Trigger: PR merge to staging or manual workflow dispatch
- Workflow:
.github/workflows/deploy-staging.yml
- URL:
https://staging.84em.com
- Branch:
dev
- Trigger: PR merge to dev or manual workflow dispatch
- Workflow:
.github/workflows/deploy-dev.yml
- URL:
https://dev.84em.com
The deployment system uses a reusable workflow architecture:
- ✅ Pre-deployment validation: PHP syntax check, security scanning, version verification
- ✅ Automatic backups: Timestamped backups before each deployment
- ✅ Health checks: REST API endpoint validation after deployment
- ✅ Automatic rollback: Restores from backup on deployment failure
- ✅ Version validation: Ensures correct plugin version is deployed
- ✅ Progress notifications: Real-time status updates during deployment
- ✅ Deployment summary: Comprehensive report after deployment
-
Validation Phase
- PHP syntax validation
- Security vulnerability scanning
- Composer dependency check
- Version consistency check
-
Backup Phase (Production/Staging only)
- Creates timestamped backup
- Verifies backup integrity
- Stores backup path for rollback
-
Deployment Phase
- Syncs files via rsync
- Excludes development files (.git, tests, etc.)
- Preserves server-specific configurations
-
Verification Phase
- Health check endpoint validation
- Version match verification
- Plugin activation check
-
Rollback Phase (on failure)
- Automatic restoration from backup
- Notification of rollback status
Secret | Description | Example |
---|---|---|
DEPLOY_SSH_KEY |
SSH private key for server access | -----BEGIN RSA PRIVATE KEY-----... |
DEPLOY_HOST |
Server hostname or IP address | server.example.com or 192.168.1.1 |
DEPLOY_USER |
SSH username for deployment | deploy or www-data |
DEPLOY_PATH |
Remote plugin directory path | /var/www/html/wp-content/plugins/84em-local-pages |
Secret | Description | Default |
---|---|---|
DEPLOY_PORT |
Custom SSH port | 22 |
BACKUP_PATH |
Backup directory path | ~/backups |
HEALTH_CHECK_URL |
Health check endpoint | Auto-generated |
SLACK_WEBHOOK_URL |
Slack notifications | None |
SMTP_SERVER |
Email server for notifications | None |
SMTP_PORT |
Email server port | 587 |
SMTP_USERNAME |
Email username | None |
SMTP_PASSWORD |
Email password | None |
NOTIFICATION_EMAIL |
Recipient email address | None |
For multi-environment deployments, use prefixed secrets:
Production:
PROD_DEPLOY_HOST
PROD_DEPLOY_USER
PROD_DEPLOY_PATH
HEALTH_CHECK_URL
Staging:
STAGING_DEPLOY_HOST
STAGING_DEPLOY_USER
STAGING_DEPLOY_PATH
STAGING_HEALTH_CHECK_URL
Development:
DEV_DEPLOY_HOST
DEV_DEPLOY_USER
DEV_DEPLOY_PATH
DEV_HEALTH_CHECK_URL
# Production deployment
git checkout main
git merge feature-branch
git push origin main
# Deployment triggers automatically on PR merge
# Staging deployment
git checkout staging
git merge feature-branch
git push origin staging
# Deployment triggers automatically on PR merge
# Development deployment
git checkout dev
git merge feature-branch
git push origin dev
# Deployment triggers automatically on PR merge
- Navigate to repository's Actions tab
- Select the appropriate workflow:
Deploy to Production
Deploy to Staging
Deploy to Dev
- Click Run workflow
- Configure options:
- force_deploy: Skip validation checks (use with caution)
- skip_backup: Skip backup creation (emergency fixes only)
- Click Run workflow button
# Watch deployment progress
gh run watch
# View deployment logs
gh run view --log
# Check deployment status
gh run list --workflow=deploy-prod.yml
- Encrypted secrets: All credentials stored as GitHub secrets
- Security scanning: Automated vulnerability detection before deployment
- Dangerous function detection: Scans for eval(), exec(), system(), etc.
- Credential pattern detection: Prevents hardcoded API keys and passwords
- File permission validation: Ensures proper file/directory permissions
- Deployment hash verification: Validates file integrity after deployment
- Automatic rollback: Restores previous version on deployment failure
- SSH key authentication: No password-based authentication
- Restricted rsync: Excludes sensitive files (.env, .git, etc.)
Deployment fails at validation phase:
- Check PHP syntax:
php -l src/**/*.php
- Run security scan locally
- Verify composer.json is valid
Health check fails:
- Ensure plugin is activated
- Check
HEALTH_CHECK_URL
secret is correct - Verify REST API is accessible
- Test endpoint:
curl https://yourdomain.com/wp-json/84em-local-pages/v1/health
Rollback triggered:
- Check deployment logs for specific error
- Verify file permissions on server
- Ensure sufficient disk space
- Check WordPress error logs
SSH connection fails:
- Verify
DEPLOY_SSH_KEY
format - Check
DEPLOY_HOST
andDEPLOY_PORT
- Ensure
DEPLOY_USER
has correct permissions - Test SSH connection manually
Access detailed logs through GitHub Actions:
- Go to Actions tab
- Click on the workflow run
- Select the job to view
- Expand steps for detailed output
If automatic rollback fails:
# Manual SSH to server
ssh user@server
# Navigate to backup directory
cd ~/backups
# Find latest backup
ls -la | grep 84em-local-pages
# Restore manually
rm -rf /path/to/wp-content/plugins/84em-local-pages
cp -r 84em-local-pages-backup-TIMESTAMP /path/to/wp-content/plugins/84em-local-pages
# Verify plugin works
wp plugin list --status=active
- Plugin Issues: 84EM offers no warranty nor provides any support for this plugin
- API Issues: Check Anthropic Status
- WordPress Issues: WordPress.org Support
- WP-CLI Issues: WP-CLI Documentation
The plugin includes a comprehensive WP-CLI-based testing framework with 10 test suites covering all major functionality.
# Run all test suites
wp 84em local-pages --test --all
# Run a specific test suite
wp 84em local-pages --test --suite=api-client
- encryption - API key encryption and security
- data-structures - Service keywords and states data
- content-processing - Content processing and linking
- cli-args - WP-CLI argument parsing
- ld-json - Schema.org structured data
- container - Dependency injection container
- api-client - Claude API client with retry logic
- content-generators - State and city content generation
- error-handling - Error handling and recovery
- security - Security and input sanitization
For detailed testing documentation, test writing guidelines, and examples, see TESTING.md.
The plugin provides a simple REST API health check endpoint for deployment verification.
GET /wp-json/84em-local-pages/v1/health
- Verify plugin is active after deployment
- Simple monitoring for uptime services
- GitHub Actions deployment verification
Always returns HTTP 200 with minimal JSON response if the plugin is working:
{
"status": "ok"
}
- name: Health Check
run: |
response=$(curl -s -o /dev/null -w "%{http_code}" "${{ secrets.HEALTH_CHECK_URL }}")
if [[ "$response" == "200" ]]; then
echo "✅ Health check passed"
else
echo "❌ Health check failed"
exit 1
fi
HEALTH_CHECK_URL
: Production health check URLSTAGING_HEALTH_CHECK_URL
: Staging health check URLDEV_HEALTH_CHECK_URL
: Development health check URL
Proprietary software developed for 84EM. All rights reserved.