├── .mcp.json ├── apache-config.conf ├── .env.example ├── fix_mcp.sh ├── .gitignore ├── wp-content ├── themes │ └── my-custom-theme │ │ ├── footer.php │ │ ├── index.php │ │ ├── header.php │ │ ├── style.css │ │ └── functions.php └── plugins │ └── custom-post-types │ └── custom-post-types.php ├── .htaccess ├── docker-compose.yml ├── Dockerfile ├── setup_ssh_and_deploy.sh ├── wp-config.php ├── migrate_now.sh ├── README.md ├── .claude ├── wordpress_deployment_workflow.md └── CLAUDE.md ├── create_droplet_with_ssh.py ├── AGENTS.md ├── CLAUDE.md └── .codex └── AGENTS.md /.mcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "playwright": { 4 | "command": "npx", 5 | "args": ["@playwright/mcp@latest"], 6 | "env": {} 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /apache-config.conf: -------------------------------------------------------------------------------- 1 | 2 | ServerAdmin webmaster@localhost 3 | DocumentRoot /var/www/html 4 | 5 | 6 | Options FollowSymLinks 7 | AllowOverride All 8 | Require all granted 9 | 10 | 11 | ErrorLog ${APACHE_LOG_DIR}/error.log 12 | CustomLog ${APACHE_LOG_DIR}/access.log combined 13 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Digital Ocean API Configuration 2 | DO_API_TOKEN=your_digital_ocean_api_token_here 3 | 4 | # Jina AI API Key for research and scraping 5 | JINA_API_KEY=your_jina_api_key_here 6 | 7 | # MySQL Passwords (optional - will be generated if not provided) 8 | MYSQL_ROOT_PASSWORD= 9 | WP_DB_PASSWORD= 10 | 11 | # Droplet Configuration (optional) 12 | DROPLET_REGION=nyc3 13 | DROPLET_SIZE=s-1vcpu-1gb -------------------------------------------------------------------------------- /fix_mcp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create .mcp.json file for Playwright MCP configuration 4 | cat > .mcp.json << 'EOF' 5 | { 6 | "mcpServers": { 7 | "playwright": { 8 | "command": "npx", 9 | "args": ["@playwright/mcp@latest"], 10 | "env": {} 11 | } 12 | } 13 | } 14 | EOF 15 | 16 | echo "✅ Created .mcp.json with Playwright MCP configuration" 17 | echo "When you run 'claude' in this directory, you'll be prompted to approve the Playwright MCP." -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Environment variables 2 | .env 3 | .env.local 4 | 5 | # Credentials 6 | .droplet_info 7 | .ssh_key_id 8 | 9 | # WordPress files 10 | wp-content/uploads/* 11 | wp-content/cache/ 12 | wp-content/upgrade/ 13 | wp-content/backup*/ 14 | 15 | # Database 16 | *.sql 17 | mysql_data/ 18 | 19 | # Docker volumes 20 | wordpress_data/ 21 | db_data/ 22 | 23 | # OS files 24 | .DS_Store 25 | Thumbs.db 26 | 27 | # Editor files 28 | .vscode/ 29 | .idea/ 30 | *.swp 31 | *.swo 32 | 33 | # Logs 34 | *.log 35 | wp-content/debug.log 36 | 37 | # Temporary files 38 | *.tmp 39 | *.bak 40 | *.backup -------------------------------------------------------------------------------- /wp-content/themes/my-custom-theme/footer.php: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /wp-content/themes/my-custom-theme/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 | 7 |
> 8 |

9 | 10 |

11 |
12 | 13 |
14 |
15 | 16 | 17 | 18 |

19 | 20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /wp-content/themes/my-custom-theme/header.php: -------------------------------------------------------------------------------- 1 | 2 | > 3 | 4 | 5 | 6 | 7 | 8 | > 9 | 10 | 11 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | # BEGIN WordPress 2 | # The directives (lines) between "BEGIN WordPress" and "END WordPress" are 3 | # dynamically generated, and should only be modified via WordPress filters. 4 | # Any changes to the directives between these markers will be overwritten. 5 | 6 | RewriteEngine On 7 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 8 | RewriteBase / 9 | RewriteRule ^index\.php$ - [L] 10 | RewriteCond %{REQUEST_FILENAME} !-f 11 | RewriteCond %{REQUEST_FILENAME} !-d 12 | RewriteRule . /index.php [L] 13 | 14 | 15 | # END WordPress 16 | 17 | # Security Headers 18 | 19 | Header set X-Content-Type-Options "nosniff" 20 | Header set X-Frame-Options "SAMEORIGIN" 21 | Header set X-XSS-Protection "1; mode=block" 22 | 23 | 24 | # Protect wp-config.php 25 | 26 | order allow,deny 27 | deny from all 28 | 29 | 30 | # Disable directory browsing 31 | Options -Indexes 32 | 33 | # Protect .htaccess 34 | 35 | order allow,deny 36 | deny from all 37 | -------------------------------------------------------------------------------- /wp-content/themes/my-custom-theme/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Theme Name: My Custom Theme 3 | Theme URI: https://example.com/ 4 | Author: Your Name 5 | Author URI: https://example.com/ 6 | Description: Custom WordPress theme for Digital Ocean deployment 7 | Version: 1.0.0 8 | License: GPL v2 or later 9 | Text Domain: my-custom-theme 10 | */ 11 | 12 | :root { 13 | --primary-color: #0073aa; 14 | --secondary-color: #005a87; 15 | --text-color: #333; 16 | --light-gray: #f5f5f5; 17 | --border-color: #e0e0e0; 18 | } 19 | 20 | * { 21 | margin: 0; 22 | padding: 0; 23 | box-sizing: border-box; 24 | } 25 | 26 | body { 27 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; 28 | font-size: 16px; 29 | line-height: 1.6; 30 | color: var(--text-color); 31 | } 32 | 33 | .container { 34 | max-width: 1200px; 35 | margin: 0 auto; 36 | padding: 0 20px; 37 | } 38 | 39 | .site-header { 40 | background: var(--primary-color); 41 | color: white; 42 | padding: 20px 0; 43 | } 44 | 45 | .site-main { 46 | padding: 40px 0; 47 | min-height: 500px; 48 | } 49 | 50 | .entry-title { 51 | font-size: 32px; 52 | margin-bottom: 20px; 53 | } 54 | 55 | .entry-content { 56 | line-height: 1.8; 57 | } 58 | 59 | .site-footer { 60 | background: var(--text-color); 61 | color: white; 62 | padding: 30px 0; 63 | text-align: center; 64 | } -------------------------------------------------------------------------------- /wp-content/themes/my-custom-theme/functions.php: -------------------------------------------------------------------------------- 1 | __('Primary Menu', 'my-custom-theme'), 18 | 'footer' => __('Footer Menu', 'my-custom-theme'), 19 | )); 20 | } 21 | add_action('after_setup_theme', 'my_custom_theme_setup'); 22 | 23 | function my_custom_theme_scripts() { 24 | wp_enqueue_style('my-custom-theme-style', get_stylesheet_uri(), array(), '1.0.0'); 25 | 26 | if (is_singular() && comments_open() && get_option('thread_comments')) { 27 | wp_enqueue_script('comment-reply'); 28 | } 29 | } 30 | add_action('wp_enqueue_scripts', 'my_custom_theme_scripts'); 31 | 32 | function my_custom_theme_widgets_init() { 33 | register_sidebar(array( 34 | 'name' => __('Sidebar', 'my-custom-theme'), 35 | 'id' => 'sidebar-1', 36 | 'description' => __('Add widgets here.', 'my-custom-theme'), 37 | 'before_widget' => '
', 38 | 'after_widget' => '
', 39 | 'before_title' => '

', 40 | 'after_title' => '

', 41 | )); 42 | } 43 | add_action('widgets_init', 'my_custom_theme_widgets_init'); -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | wordpress: 5 | build: . 6 | container_name: wp-dev 7 | ports: 8 | - "80:80" 9 | environment: 10 | WORDPRESS_DB_HOST: mysql:3306 11 | WORDPRESS_DB_NAME: wordpress 12 | WORDPRESS_DB_USER: wordpress 13 | WORDPRESS_DB_PASSWORD: wordpress_password 14 | volumes: 15 | - ./wp-content:/var/www/html/wp-content 16 | - ./wp-config.php:/var/www/html/wp-config.php 17 | - ./.htaccess:/var/www/html/.htaccess 18 | depends_on: 19 | - mysql 20 | networks: 21 | - wordpress-network 22 | 23 | mysql: 24 | image: mysql:8.0.42 25 | container_name: wp-mysql 26 | environment: 27 | MYSQL_ROOT_PASSWORD: root_password 28 | MYSQL_DATABASE: wordpress 29 | MYSQL_USER: wordpress 30 | MYSQL_PASSWORD: wordpress_password 31 | volumes: 32 | - mysql_data:/var/lib/mysql 33 | - ./mysql-init:/docker-entrypoint-initdb.d 34 | ports: 35 | - "3306:3306" 36 | command: > 37 | --default-authentication-plugin=mysql_native_password 38 | --character-set-server=utf8mb4 39 | --collation-server=utf8mb4_unicode_ci 40 | networks: 41 | - wordpress-network 42 | 43 | phpmyadmin: 44 | image: phpmyadmin:latest 45 | container_name: wp-phpmyadmin 46 | environment: 47 | PMA_HOST: mysql 48 | UPLOAD_LIMIT: 64M 49 | ports: 50 | - "8080:80" 51 | depends_on: 52 | - mysql 53 | networks: 54 | - wordpress-network 55 | 56 | volumes: 57 | mysql_data: 58 | 59 | networks: 60 | wordpress-network: 61 | driver: bridge -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ENV DEBIAN_FRONTEND=noninteractive 4 | 5 | # Install Apache, PHP 8.3, and extensions matching DO stack 6 | RUN apt-get update && apt-get install -y \ 7 | software-properties-common \ 8 | curl \ 9 | wget \ 10 | && add-apt-repository ppa:ondrej/php \ 11 | && apt-get update && apt-get install -y \ 12 | apache2 \ 13 | php8.3 \ 14 | php8.3-cli \ 15 | php8.3-common \ 16 | php8.3-mysql \ 17 | php8.3-xml \ 18 | php8.3-xmlrpc \ 19 | php8.3-curl \ 20 | php8.3-gd \ 21 | php8.3-imagick \ 22 | php8.3-mbstring \ 23 | php8.3-zip \ 24 | php8.3-intl \ 25 | php8.3-bz2 \ 26 | php8.3-bcmath \ 27 | php8.3-soap \ 28 | libapache2-mod-php8.3 \ 29 | && apt-get clean \ 30 | && rm -rf /var/lib/apt/lists/* 31 | 32 | # Enable Apache modules 33 | RUN a2enmod rewrite headers expires deflate ssl 34 | 35 | # Configure PHP settings to match DO 36 | RUN echo "upload_max_filesize = 64M" >> /etc/php/8.3/apache2/php.ini && \ 37 | echo "post_max_size = 64M" >> /etc/php/8.3/apache2/php.ini && \ 38 | echo "max_execution_time = 300" >> /etc/php/8.3/apache2/php.ini && \ 39 | echo "max_input_time = 300" >> /etc/php/8.3/apache2/php.ini && \ 40 | echo "memory_limit = 256M" >> /etc/php/8.3/apache2/php.ini 41 | 42 | # Download and install WordPress 43 | RUN cd /tmp && \ 44 | wget https://wordpress.org/wordpress-6.8.1.tar.gz && \ 45 | tar xzvf wordpress-6.8.1.tar.gz && \ 46 | cp -R wordpress/* /var/www/html/ && \ 47 | rm -rf /var/www/html/index.html && \ 48 | rm -rf /tmp/wordpress* 49 | 50 | # Set proper permissions 51 | RUN chown -R www-data:www-data /var/www/html && \ 52 | find /var/www/html -type d -exec chmod 755 {} \; && \ 53 | find /var/www/html -type f -exec chmod 644 {} \; 54 | 55 | # Apache configuration 56 | COPY apache-config.conf /etc/apache2/sites-available/000-default.conf 57 | 58 | EXPOSE 80 59 | 60 | CMD ["apache2ctl", "-D", "FOREGROUND"] -------------------------------------------------------------------------------- /setup_ssh_and_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Setup SSH keys and deploy WordPress to Digital Ocean 4 | set -e 5 | 6 | echo "================================================" 7 | echo "WordPress Automated Deployment Setup" 8 | echo "================================================" 9 | 10 | # Generate SSH key if it doesn't exist 11 | SSH_KEY_PATH="$HOME/.ssh/wordpress_deploy" 12 | if [ ! -f "$SSH_KEY_PATH" ]; then 13 | echo "Generating SSH key..." 14 | ssh-keygen -t ed25519 -f "$SSH_KEY_PATH" -N "" -C "wordpress-deploy" 15 | echo "✅ SSH key generated at $SSH_KEY_PATH" 16 | fi 17 | 18 | # Read the public key 19 | PUBLIC_KEY=$(cat "$SSH_KEY_PATH.pub") 20 | 21 | # Add SSH key to Digital Ocean via API 22 | echo "Adding SSH key to Digital Ocean..." 23 | python3 << EOF 24 | import requests 25 | import json 26 | import os 27 | 28 | # Load API token 29 | api_token = os.getenv('DO_API_TOKEN') 30 | if not api_token: 31 | with open('.env', 'r') as f: 32 | for line in f: 33 | if line.startswith('DO_API_TOKEN='): 34 | api_token = line.split('=')[1].strip() 35 | break 36 | 37 | headers = { 38 | 'Authorization': f'Bearer {api_token}', 39 | 'Content-Type': 'application/json' 40 | } 41 | 42 | # Check if key already exists 43 | response = requests.get('https://api.digitalocean.com/v2/account/keys', headers=headers) 44 | ssh_keys = response.json().get('ssh_keys', []) 45 | 46 | public_key = """$PUBLIC_KEY""" 47 | key_name = "wordpress-deploy-key" 48 | 49 | # Find existing key 50 | key_id = None 51 | for key in ssh_keys: 52 | if key['name'] == key_name: 53 | key_id = key['id'] 54 | print(f"SSH key already exists with ID: {key_id}") 55 | break 56 | 57 | # Add key if it doesn't exist 58 | if not key_id: 59 | data = { 60 | 'name': key_name, 61 | 'public_key': public_key 62 | } 63 | response = requests.post('https://api.digitalocean.com/v2/account/keys', headers=headers, json=data) 64 | if response.status_code == 201: 65 | key_id = response.json()['ssh_key']['id'] 66 | print(f"✅ SSH key added with ID: {key_id}") 67 | else: 68 | print(f"❌ Failed to add SSH key: {response.text}") 69 | exit(1) 70 | 71 | # Save key ID 72 | with open('.ssh_key_id', 'w') as f: 73 | f.write(str(key_id)) 74 | EOF 75 | 76 | echo "" 77 | echo "================================================" 78 | echo "SSH Setup Complete!" 79 | echo "================================================" 80 | echo "" 81 | echo "Now you can create droplets with SSH access:" 82 | echo "1. Run: python3 create_droplet_with_ssh.py" 83 | echo "2. The droplet will have your SSH key pre-installed" 84 | echo "3. Migration will work automatically" 85 | echo "" 86 | echo "SSH Key: $SSH_KEY_PATH" -------------------------------------------------------------------------------- /wp-config.php: -------------------------------------------------------------------------------- 1 | wordpress_backup.sql 21 | 22 | # 2. Update URLs in database 23 | echo "2. Updating URLs..." 24 | sed -i.bak "s|http://localhost|http://$DROPLET_IP|g" wordpress_backup.sql 25 | 26 | # 3. Package wp-content 27 | echo "3. Packaging wp-content..." 28 | tar -czf wp-content.tar.gz wp-content/ 29 | 30 | # 4. Transfer files 31 | echo "4. Transferring files..." 32 | scp -i $SSH_KEY -o StrictHostKeyChecking=no wp-content.tar.gz root@$DROPLET_IP:/tmp/ 33 | scp -i $SSH_KEY -o StrictHostKeyChecking=no wordpress_backup.sql root@$DROPLET_IP:/tmp/ 34 | 35 | # 5. Install on droplet 36 | echo "5. Installing on droplet..." 37 | ssh -i $SSH_KEY -o StrictHostKeyChecking=no root@$DROPLET_IP << ENDSSH 38 | # Backup existing 39 | cd /var/www/html 40 | if [ -d "wp-content" ]; then 41 | mv wp-content wp-content.orig 42 | fi 43 | 44 | # Extract our wp-content 45 | tar -xzf /tmp/wp-content.tar.gz 46 | 47 | # Import database 48 | mysql -u root -p$MYSQL_ROOT_PASS wordpress < /tmp/wordpress_backup.sql 49 | 50 | # Update database URLs 51 | mysql -u root -p$MYSQL_ROOT_PASS wordpress << EOSQL 52 | UPDATE wp_options SET option_value = 'http://$DROPLET_IP' WHERE option_name = 'siteurl'; 53 | UPDATE wp_options SET option_value = 'http://$DROPLET_IP' WHERE option_name = 'home'; 54 | UPDATE wp_posts SET guid = REPLACE(guid, 'http://localhost', 'http://$DROPLET_IP'); 55 | UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://localhost', 'http://$DROPLET_IP'); 56 | UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, 'http://localhost', 'http://$DROPLET_IP'); 57 | EOSQL 58 | 59 | # Set permissions 60 | chown -R www-data:www-data /var/www/html 61 | find /var/www/html -type d -exec chmod 755 {} \; 62 | find /var/www/html -type f -exec chmod 644 {} \; 63 | 64 | # Set permalinks and flush rewrite rules 65 | cd /var/www/html 66 | wp --allow-root rewrite structure '/%postname%/' 67 | wp --allow-root rewrite flush 68 | 69 | # Ensure .htaccess is writable and has correct rules 70 | chmod 664 /var/www/html/.htaccess 71 | cat > /var/www/html/.htaccess <<'HTACCESS' 72 | # BEGIN WordPress 73 | 74 | RewriteEngine On 75 | RewriteBase / 76 | RewriteRule ^index\.php$ - [L] 77 | RewriteCond %{REQUEST_FILENAME} !-f 78 | RewriteCond %{REQUEST_FILENAME} !-d 79 | RewriteRule . /index.php [L] 80 | 81 | # END WordPress 82 | HTACCESS 83 | chown www-data:www-data /var/www/html/.htaccess 84 | 85 | # Restart Apache 86 | systemctl restart apache2 87 | 88 | echo "Migration complete!" 89 | ENDSSH 90 | 91 | # Clean up 92 | rm -f wp-content.tar.gz wordpress_backup.sql wordpress_backup.sql.bak 93 | 94 | echo "================================================" 95 | echo "✅ Migration Complete!" 96 | echo "================================================" 97 | echo "Your site with custom theme is now at: http://$DROPLET_IP" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WordPress Claude Code Wizard 🚀 2 | 3 | Automated WordPress development and deployment pipeline for Digital Ocean. Develop locally with Docker, deploy to production with one command. 4 | 5 | ## Features 6 | 7 | - **Identical Stack to DO**: Ubuntu 22.04, Apache 2.4.52, PHP 8.3, MySQL 8.0.42 8 | - **Custom Theme**: Ready-to-develop theme in `wp-content/themes/my-custom-theme/` 9 | - **Custom Post Types Plugin**: Portfolio and Testimonials CPTs 10 | - **One-Click Deployment**: Automated migration script to Digital Ocean 11 | - **Environment-Aware Config**: wp-config.php works on both local and production 12 | 13 | - Try SEO Grove: [SEO Grove](https://seogrove.ai/pre-registration) 14 | - Join my Skool to say thanks: [My Skool](https://www.skool.com/iss-ai-automation-school-6342) 15 | 16 | 17 | ## Quick Start 18 | 19 | ### 1. Setup Environment 20 | ```bash 21 | # Clone the repository 22 | git clone https://github.com/IncomeStreamSurfer/wordpress-claude-code-wizard.git 23 | cd wordpress-claude-code-wizard 24 | 25 | # Copy and configure .env 26 | cp .env.example .env 27 | # Edit .env and add your Digital Ocean API token 28 | ``` 29 | 30 | ### 2. Local Development 31 | ```bash 32 | # Start WordPress locally 33 | docker-compose up -d 34 | 35 | # Access at http://localhost 36 | # phpMyAdmin at http://localhost:8080 37 | ``` 38 | 39 | ### 3. Deploy to Digital Ocean 40 | ```bash 41 | # One-time SSH setup 42 | ./setup_ssh_and_deploy.sh 43 | 44 | # Create droplet and deploy 45 | python3 create_droplet_with_ssh.py 46 | 47 | # Wait 5-10 minutes for installation 48 | # Then migrate your local WordPress 49 | ./migrate_now.sh 50 | ``` 51 | 52 | ## Development Workflow 53 | 54 | ### Working on Your Custom Theme 55 | - Theme files: `wp-content/themes/my-custom-theme/` 56 | - Changes are reflected immediately (no restart needed) 57 | 58 | ### Working on Custom Post Types 59 | - Plugin files: `wp-content/plugins/custom-post-types/` 60 | - After activation, you'll see Portfolio and Testimonials in the admin menu 61 | 62 | ## Post-Deployment 63 | 64 | After deployment: 65 | 1. Your site is live at `http://YOUR_DROPLET_IP` 66 | 2. Point your domain's A record to the droplet IP 67 | 3. Set up SSL: 68 | ```bash 69 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP 70 | certbot --apache 71 | ``` 72 | 73 | ## File Structure 74 | ``` 75 | . 76 | ├── docker-compose.yml # Docker configuration 77 | ├── Dockerfile # Custom Apache/PHP image 78 | ├── wp-config.php # Environment-aware config 79 | ├── .htaccess # Apache rules 80 | ├── setup_ssh_and_deploy.sh # SSH key setup 81 | ├── create_droplet_with_ssh.py # Droplet creation 82 | ├── migrate_now.sh # Migration script 83 | ├── wp-content/ 84 | │ ├── themes/ 85 | │ │ └── my-custom-theme/ # Your custom theme 86 | │ └── plugins/ 87 | │ └── custom-post-types/ # CPT plugin 88 | └── .claude/ # Claude's workflow memory 89 | ``` 90 | 91 | ## Database Access 92 | 93 | **Local Development:** 94 | - Host: localhost:3306 95 | - Database: wordpress 96 | - User: wordpress 97 | - Password: wordpress_password 98 | 99 | **phpMyAdmin:** http://localhost:8080 100 | 101 | ## Requirements 102 | 103 | - Docker & Docker Compose 104 | - Python 3 with pip 105 | - Digital Ocean account with API token 106 | - 10-15 minutes for complete deployment 107 | 108 | ## Security Notes 109 | 110 | - Change all default passwords before production 111 | - Update `wp-config.php` salts (done automatically during deployment) 112 | - Enable firewall on Digital Ocean: `ufw allow 22,80,443/tcp && ufw enable` 113 | - Keep WordPress, themes, and plugins updated 114 | 115 | ## How It Works 116 | 117 | 1. **Docker** provides identical environment to production 118 | 2. **SSH keys** are automatically configured for passwordless access 119 | 3. **Cloud-init** installs WordPress on the droplet 120 | 4. **Migration script** transfers your themes, plugins, and content 121 | 5. **URL updates** are handled automatically 122 | 123 | From local development to live production in minutes! 124 | -------------------------------------------------------------------------------- /.claude/wordpress_deployment_workflow.md: -------------------------------------------------------------------------------- 1 | # WordPress to Digital Ocean Automated Deployment Workflow 2 | 3 | ## Overview 4 | This is a complete CI/CD pipeline for deploying local WordPress development to Digital Ocean droplets automatically. When users clone this repo, Claude can execute this entire workflow without manual intervention. 5 | 6 | ## Prerequisites Check 7 | 1. Docker and Docker Compose installed 8 | 2. Python 3 with pip 9 | 3. Digital Ocean API token in `.env` file 10 | 11 | ## Complete Automated Workflow 12 | 13 | ### Phase 1: Local WordPress Setup 14 | ```bash 15 | # 1. Start local WordPress development environment 16 | docker-compose up -d 17 | 18 | # 2. Verify containers are running 19 | docker ps | grep wp- 20 | ``` 21 | 22 | ### Phase 2: SSH Key Setup (One-time) 23 | ```bash 24 | # 1. Run SSH setup script 25 | ./setup_ssh_and_deploy.sh 26 | 27 | # This script will: 28 | # - Generate SSH keypair at ~/.ssh/wordpress_deploy 29 | # - Upload public key to Digital Ocean via API 30 | # - Save SSH key ID to .ssh_key_id file 31 | ``` 32 | 33 | ### Phase 3: Create Digital Ocean Droplet 34 | ```bash 35 | # 1. Run droplet creation with SSH access 36 | python3 create_droplet_with_ssh.py 37 | 38 | # This will: 39 | # - Create Ubuntu 22.04 droplet 40 | # - Install WordPress via cloud-init 41 | # - Configure MySQL with generated passwords 42 | # - Enable SSH access with your key 43 | # - Save credentials to .droplet_info 44 | ``` 45 | 46 | ### Phase 4: Wait for WordPress Installation 47 | ```bash 48 | # Check cloud-init status (takes 5-10 minutes) 49 | ssh -i ~/.ssh/wordpress_deploy root@$(cat .droplet_info | python3 -c "import json,sys; print(json.load(sys.stdin)['ip_address'])") "cloud-init status --wait" 50 | ``` 51 | 52 | ### Phase 5: Migrate Local WordPress to Droplet 53 | ```bash 54 | # Run migration script 55 | ./migrate_to_droplet.sh 56 | 57 | # This will: 58 | # - Export local WordPress database 59 | # - Package wp-content directory 60 | # - Transfer to droplet via SCP 61 | # - Import database 62 | # - Update wp-config.php 63 | # - Set proper permissions 64 | ``` 65 | 66 | ## File Structure Required 67 | ``` 68 | wordpress-deployment/ 69 | ├── .env # DO_API_TOKEN=your_token_here 70 | ├── docker-compose.yml # Local WordPress stack 71 | ├── Dockerfile # Custom WordPress image 72 | ├── wp-config.php # Environment-aware config 73 | ├── .htaccess # Apache rules 74 | ├── wp-content/ # Themes and plugins 75 | │ ├── themes/ 76 | │ │ └── my-custom-theme/ 77 | │ └── plugins/ 78 | │ └── custom-post-types/ 79 | ├── create_droplet_with_ssh.py # Creates DO droplet with SSH 80 | ├── setup_ssh_and_deploy.sh # SSH key setup 81 | ├── migrate_to_droplet.sh # Migration script 82 | └── .claude/ # Claude's memory 83 | └── wordpress_deployment_workflow.md 84 | 85 | ``` 86 | 87 | ## Environment Variables (.env) 88 | ```bash 89 | DO_API_TOKEN=your_digital_ocean_api_token 90 | DROPLET_REGION=nyc3 # Optional 91 | DROPLET_SIZE=s-1vcpu-1gb # Optional 92 | MYSQL_ROOT_PASSWORD= # Optional, auto-generated if empty 93 | WP_DB_PASSWORD= # Optional, auto-generated if empty 94 | ``` 95 | 96 | ## Key Scripts Explanation 97 | 98 | ### setup_ssh_and_deploy.sh 99 | - Generates ED25519 SSH keypair 100 | - Uploads to DO via API 101 | - Stores key ID for droplet creation 102 | 103 | ### create_droplet_with_ssh.py 104 | - Creates Ubuntu 22.04 droplet 105 | - Includes SSH key for passwordless access 106 | - Runs cloud-init script to install LAMP + WordPress 107 | - Outputs JSON to .droplet_info 108 | 109 | ### migrate_to_droplet.sh 110 | - Reads .droplet_info for connection details 111 | - Uses SSH key for authentication 112 | - Exports local database 113 | - Transfers wp-content 114 | - Updates configuration for production 115 | 116 | ## Automated Execution Commands 117 | 118 | For a fresh clone from GitHub, execute in order: 119 | 120 | ```bash 121 | # 1. Install Python dependencies 122 | pip3 install python-dotenv requests 123 | 124 | # 2. Copy and configure environment 125 | cp .env.example .env 126 | # Edit .env and add DO_API_TOKEN 127 | 128 | # 3. Start local WordPress 129 | docker-compose up -d 130 | 131 | # 4. Setup SSH (one-time) 132 | ./setup_ssh_and_deploy.sh 133 | 134 | # 5. Create and deploy 135 | python3 create_droplet_with_ssh.py 136 | 137 | # 6. Wait for installation (5-10 minutes) 138 | sleep 300 139 | 140 | # 7. Migrate WordPress 141 | ./migrate_to_droplet.sh 142 | ``` 143 | 144 | ## Troubleshooting Commands 145 | 146 | ```bash 147 | # Check droplet info 148 | cat .droplet_info | python3 -m json.tool 149 | 150 | # Check SSH access 151 | ssh -i ~/.ssh/wordpress_deploy root@$(cat .droplet_info | python3 -c "import json,sys; print(json.load(sys.stdin)['ip_address'])") "echo 'SSH OK'" 152 | 153 | # Check WordPress installation 154 | curl -I http://$(cat .droplet_info | python3 -c "import json,sys; print(json.load(sys.stdin)['ip_address'])") 155 | 156 | # View cloud-init logs 157 | ssh -i ~/.ssh/wordpress_deploy root@$(cat .droplet_info | python3 -c "import json,sys; print(json.load(sys.stdin)['ip_address'])") "tail -50 /var/log/cloud-init-output.log" 158 | 159 | # Delete droplet (cleanup) 160 | python3 -c " 161 | import requests, json, os 162 | api_token = os.getenv('DO_API_TOKEN') 163 | with open('.droplet_info') as f: 164 | droplet_id = json.load(f)['droplet_id'] 165 | headers = {'Authorization': f'Bearer {api_token}'} 166 | requests.delete(f'https://api.digitalocean.com/v2/droplets/{droplet_id}', headers=headers) 167 | " 168 | ``` 169 | 170 | ## Success Indicators 171 | 1. Local WordPress accessible at http://localhost 172 | 2. SSH key registered with DO (check .ssh_key_id exists) 173 | 3. Droplet created (check .droplet_info exists) 174 | 4. WordPress accessible at http://DROPLET_IP 175 | 5. Migration completes without errors 176 | 177 | ## Time Estimates 178 | - SSH setup: 10 seconds 179 | - Droplet creation: 1-2 minutes 180 | - WordPress installation: 5-10 minutes (due to apt upgrade) 181 | - Migration: 1-2 minutes 182 | - **Total: ~10-15 minutes** 183 | 184 | ## Notes for Claude 185 | - Always check for .env file with DO_API_TOKEN 186 | - Ensure Docker is running before migration 187 | - Wait for cloud-init to complete before migrating 188 | - Use SSH key authentication (-i ~/.ssh/wordpress_deploy) 189 | - Read .droplet_info for connection details 190 | - The workflow is idempotent - can be re-run safely -------------------------------------------------------------------------------- /wp-content/plugins/custom-post-types/custom-post-types.php: -------------------------------------------------------------------------------- 1 | _x('Portfolio', 'Post type general name', 'custom-post-types'), 26 | 'singular_name' => _x('Portfolio Item', 'Post type singular name', 'custom-post-types'), 27 | 'menu_name' => _x('Portfolio', 'Admin Menu text', 'custom-post-types'), 28 | 'add_new' => __('Add New', 'custom-post-types'), 29 | 'add_new_item' => __('Add New Portfolio Item', 'custom-post-types'), 30 | 'edit_item' => __('Edit Portfolio Item', 'custom-post-types'), 31 | 'new_item' => __('New Portfolio Item', 'custom-post-types'), 32 | 'view_item' => __('View Portfolio Item', 'custom-post-types'), 33 | 'view_items' => __('View Portfolio', 'custom-post-types'), 34 | 'search_items' => __('Search Portfolio', 'custom-post-types'), 35 | 'not_found' => __('No portfolio items found', 'custom-post-types'), 36 | 'not_found_in_trash' => __('No portfolio items found in Trash', 'custom-post-types'), 37 | ); 38 | 39 | $args = array( 40 | 'labels' => $labels, 41 | 'public' => true, 42 | 'publicly_queryable' => true, 43 | 'show_ui' => true, 44 | 'show_in_menu' => true, 45 | 'query_var' => true, 46 | 'rewrite' => array('slug' => 'portfolio'), 47 | 'capability_type' => 'post', 48 | 'has_archive' => true, 49 | 'hierarchical' => false, 50 | 'menu_position' => 5, 51 | 'menu_icon' => 'dashicons-portfolio', 52 | 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'), 53 | 'show_in_rest' => true, 54 | ); 55 | 56 | register_post_type('portfolio', $args); 57 | } 58 | 59 | public function register_portfolio_taxonomies() { 60 | // Portfolio Categories 61 | $labels = array( 62 | 'name' => _x('Portfolio Categories', 'taxonomy general name', 'custom-post-types'), 63 | 'singular_name' => _x('Portfolio Category', 'taxonomy singular name', 'custom-post-types'), 64 | 'search_items' => __('Search Categories', 'custom-post-types'), 65 | 'all_items' => __('All Categories', 'custom-post-types'), 66 | 'edit_item' => __('Edit Category', 'custom-post-types'), 67 | 'update_item' => __('Update Category', 'custom-post-types'), 68 | 'add_new_item' => __('Add New Category', 'custom-post-types'), 69 | 'new_item_name' => __('New Category Name', 'custom-post-types'), 70 | 'menu_name' => __('Categories', 'custom-post-types'), 71 | ); 72 | 73 | $args = array( 74 | 'hierarchical' => true, 75 | 'labels' => $labels, 76 | 'show_ui' => true, 77 | 'show_admin_column' => true, 78 | 'query_var' => true, 79 | 'rewrite' => array('slug' => 'portfolio-category'), 80 | 'show_in_rest' => true, 81 | ); 82 | 83 | register_taxonomy('portfolio_category', array('portfolio'), $args); 84 | 85 | // Portfolio Tags 86 | $labels = array( 87 | 'name' => _x('Portfolio Tags', 'taxonomy general name', 'custom-post-types'), 88 | 'singular_name' => _x('Portfolio Tag', 'taxonomy singular name', 'custom-post-types'), 89 | 'search_items' => __('Search Tags', 'custom-post-types'), 90 | 'all_items' => __('All Tags', 'custom-post-types'), 91 | 'edit_item' => __('Edit Tag', 'custom-post-types'), 92 | 'update_item' => __('Update Tag', 'custom-post-types'), 93 | 'add_new_item' => __('Add New Tag', 'custom-post-types'), 94 | 'new_item_name' => __('New Tag Name', 'custom-post-types'), 95 | 'menu_name' => __('Tags', 'custom-post-types'), 96 | ); 97 | 98 | $args = array( 99 | 'hierarchical' => false, 100 | 'labels' => $labels, 101 | 'show_ui' => true, 102 | 'show_admin_column' => true, 103 | 'query_var' => true, 104 | 'rewrite' => array('slug' => 'portfolio-tag'), 105 | 'show_in_rest' => true, 106 | ); 107 | 108 | register_taxonomy('portfolio_tag', array('portfolio'), $args); 109 | } 110 | 111 | public function register_testimonial_post_type() { 112 | $labels = array( 113 | 'name' => _x('Testimonials', 'Post type general name', 'custom-post-types'), 114 | 'singular_name' => _x('Testimonial', 'Post type singular name', 'custom-post-types'), 115 | 'menu_name' => _x('Testimonials', 'Admin Menu text', 'custom-post-types'), 116 | 'add_new' => __('Add New', 'custom-post-types'), 117 | 'add_new_item' => __('Add New Testimonial', 'custom-post-types'), 118 | 'edit_item' => __('Edit Testimonial', 'custom-post-types'), 119 | 'new_item' => __('New Testimonial', 'custom-post-types'), 120 | 'view_item' => __('View Testimonial', 'custom-post-types'), 121 | 'view_items' => __('View Testimonials', 'custom-post-types'), 122 | 'search_items' => __('Search Testimonials', 'custom-post-types'), 123 | 'not_found' => __('No testimonials found', 'custom-post-types'), 124 | 'not_found_in_trash' => __('No testimonials found in Trash', 'custom-post-types'), 125 | ); 126 | 127 | $args = array( 128 | 'labels' => $labels, 129 | 'public' => true, 130 | 'publicly_queryable' => true, 131 | 'show_ui' => true, 132 | 'show_in_menu' => true, 133 | 'query_var' => true, 134 | 'rewrite' => array('slug' => 'testimonials'), 135 | 'capability_type' => 'post', 136 | 'has_archive' => true, 137 | 'hierarchical' => false, 138 | 'menu_position' => 6, 139 | 'menu_icon' => 'dashicons-format-quote', 140 | 'supports' => array('title', 'editor', 'thumbnail', 'custom-fields'), 141 | 'show_in_rest' => true, 142 | ); 143 | 144 | register_post_type('testimonial', $args); 145 | } 146 | } 147 | 148 | // Initialize the plugin 149 | new CustomPostTypes(); 150 | 151 | // Flush rewrite rules on activation 152 | register_activation_hook(__FILE__, function() { 153 | $cpt = new CustomPostTypes(); 154 | $cpt->register_portfolio_post_type(); 155 | $cpt->register_portfolio_taxonomies(); 156 | $cpt->register_testimonial_post_type(); 157 | flush_rewrite_rules(); 158 | }); 159 | 160 | // Flush rewrite rules on deactivation 161 | register_deactivation_hook(__FILE__, function() { 162 | flush_rewrite_rules(); 163 | }); -------------------------------------------------------------------------------- /create_droplet_with_ssh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Create Digital Ocean Droplet with SSH access and WordPress 4 | """ 5 | 6 | import requests 7 | import json 8 | import time 9 | import sys 10 | import os 11 | from pathlib import Path 12 | 13 | # Load .env 14 | try: 15 | from dotenv import load_dotenv 16 | load_dotenv() 17 | except ImportError: 18 | pass 19 | 20 | def get_ssh_key_id(): 21 | """Get the SSH key ID from file or API""" 22 | if os.path.exists('.ssh_key_id'): 23 | with open('.ssh_key_id', 'r') as f: 24 | return int(f.read().strip()) 25 | return None 26 | 27 | def create_wordpress_droplet(): 28 | api_token = os.getenv('DO_API_TOKEN') 29 | if not api_token: 30 | print("❌ DO_API_TOKEN not found") 31 | sys.exit(1) 32 | 33 | headers = { 34 | 'Authorization': f'Bearer {api_token}', 35 | 'Content-Type': 'application/json' 36 | } 37 | 38 | # Get SSH key ID 39 | ssh_key_id = get_ssh_key_id() 40 | if not ssh_key_id: 41 | print("❌ No SSH key found. Run: ./setup_ssh_and_deploy.sh first") 42 | sys.exit(1) 43 | 44 | # Generate passwords 45 | import secrets 46 | import string 47 | chars = string.ascii_letters + string.digits 48 | mysql_root_pass = ''.join(secrets.choice(chars) for _ in range(16)) 49 | wp_db_pass = ''.join(secrets.choice(chars) for _ in range(16)) 50 | 51 | # Droplet configuration 52 | name = f"wordpress-{int(time.time())}" 53 | region = os.getenv('DROPLET_REGION', 'nyc3') 54 | size = os.getenv('DROPLET_SIZE', 's-1vcpu-1gb') 55 | 56 | # User data script to install WordPress 57 | user_data = f"""#!/bin/bash 58 | # Install WordPress on Ubuntu 22.04 59 | export DEBIAN_FRONTEND=noninteractive 60 | 61 | # Update system 62 | apt-get update && apt-get upgrade -y 63 | 64 | # Install Apache, PHP 8.3, MySQL 65 | apt-get install -y software-properties-common 66 | add-apt-repository -y ppa:ondrej/php 67 | apt-get update 68 | 69 | # Install packages 70 | apt-get install -y apache2 mysql-server \\ 71 | php8.3 php8.3-cli php8.3-common php8.3-mysql \\ 72 | php8.3-xml php8.3-xmlrpc php8.3-curl php8.3-gd \\ 73 | php8.3-imagick php8.3-mbstring php8.3-zip \\ 74 | php8.3-intl php8.3-bz2 php8.3-bcmath php8.3-soap \\ 75 | libapache2-mod-php8.3 76 | 77 | # Configure MySQL 78 | mysql <> /tmp/salts 101 | sed -i "/AUTH_KEY/d; /SECURE_AUTH_KEY/d; /LOGGED_IN_KEY/d; /NONCE_KEY/d" /var/www/html/wp-config.php 102 | sed -i "/AUTH_SALT/d; /SECURE_AUTH_SALT/d; /LOGGED_IN_SALT/d; /NONCE_SALT/d" /var/www/html/wp-config.php 103 | sed -i "/define( 'DB_COLLATE'/r /tmp/salts" /var/www/html/wp-config.php 104 | 105 | # Set permissions 106 | chown -R www-data:www-data /var/www/html 107 | find /var/www/html -type d -exec chmod 755 {{}} \\; 108 | find /var/www/html -type f -exec chmod 644 {{}} \\; 109 | 110 | # Enable Apache modules 111 | a2enmod rewrite 112 | 113 | # Configure Apache virtual host with AllowOverride 114 | cat > /etc/apache2/sites-available/wordpress.conf <<'APACHECONF' 115 | 116 | ServerAdmin webmaster@localhost 117 | DocumentRoot /var/www/html 118 | 119 | 120 | Options Indexes FollowSymLinks 121 | AllowOverride All 122 | Require all granted 123 | 124 | 125 | ErrorLog ${{APACHE_LOG_DIR}}/error.log 126 | CustomLog ${{APACHE_LOG_DIR}}/access.log combined 127 | 128 | APACHECONF 129 | 130 | # Enable the new site and disable default 131 | a2dissite 000-default.conf 132 | a2ensite wordpress.conf 133 | 134 | # Create .htaccess 135 | cat > /var/www/html/.htaccess <<'HTACCESS' 136 | # BEGIN WordPress 137 | 138 | RewriteEngine On 139 | RewriteBase / 140 | RewriteRule ^index\\.php$ - [L] 141 | RewriteCond %{{REQUEST_FILENAME}} !-f 142 | RewriteCond %{{REQUEST_FILENAME}} !-d 143 | RewriteRule . /index.php [L] 144 | 145 | # END WordPress 146 | HTACCESS 147 | 148 | chown www-data:www-data /var/www/html/.htaccess 149 | chmod 644 /var/www/html/.htaccess 150 | 151 | # Install WP-CLI 152 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 153 | chmod +x wp-cli.phar 154 | mv wp-cli.phar /usr/local/bin/wp 155 | 156 | # Restart Apache with new configuration 157 | systemctl restart apache2 158 | 159 | # Mark as ready 160 | touch /root/.wordpress_ready 161 | echo "MySQL Root: {mysql_root_pass}" > /root/credentials.txt 162 | echo "WP DB Pass: {wp_db_pass}" >> /root/credentials.txt 163 | """ 164 | 165 | # Create droplet 166 | droplet_data = { 167 | 'name': name, 168 | 'region': region, 169 | 'size': size, 170 | 'image': 'ubuntu-22-04-x64', 171 | 'ssh_keys': [ssh_key_id], # Use SSH key 172 | 'backups': False, 173 | 'ipv6': True, 174 | 'monitoring': True, 175 | 'tags': ['wordpress', 'automated'], 176 | 'user_data': user_data 177 | } 178 | 179 | print(f"Creating droplet: {name}") 180 | print(f"Region: {region}, Size: {size}") 181 | print(f"Using SSH key ID: {ssh_key_id}") 182 | 183 | response = requests.post('https://api.digitalocean.com/v2/droplets', 184 | headers=headers, json=droplet_data) 185 | 186 | if response.status_code != 202: 187 | print(f"❌ Failed to create droplet: {response.text}") 188 | sys.exit(1) 189 | 190 | droplet = response.json()['droplet'] 191 | droplet_id = droplet['id'] 192 | 193 | print(f"✅ Droplet created with ID: {droplet_id}") 194 | print("Waiting for droplet to become active...") 195 | 196 | # Wait for droplet to be active 197 | for _ in range(60): 198 | time.sleep(5) 199 | response = requests.get(f'https://api.digitalocean.com/v2/droplets/{droplet_id}', 200 | headers=headers) 201 | if response.status_code == 200: 202 | droplet = response.json()['droplet'] 203 | if droplet['status'] == 'active': 204 | break 205 | 206 | # Get IP address 207 | ip_address = None 208 | for network in droplet['networks']['v4']: 209 | if network['type'] == 'public': 210 | ip_address = network['ip_address'] 211 | break 212 | 213 | # Save droplet info 214 | droplet_info = { 215 | 'droplet_id': droplet_id, 216 | 'droplet_name': name, 217 | 'ip_address': ip_address, 218 | 'mysql_root_pass': mysql_root_pass, 219 | 'wp_db_pass': wp_db_pass, 220 | 'region': region, 221 | 'size': size, 222 | 'ssh_access': True 223 | } 224 | 225 | with open('.droplet_info', 'w') as f: 226 | json.dump(droplet_info, f, indent=2) 227 | 228 | print("\n================================================") 229 | print("✅ WordPress Droplet Created with SSH Access!") 230 | print("================================================") 231 | print(f"IP Address: {ip_address}") 232 | print(f"SSH Access: ssh -i ~/.ssh/wordpress_deploy root@{ip_address}") 233 | print(f"\nMySQL Root Pass: {mysql_root_pass}") 234 | print(f"WordPress DB Pass: {wp_db_pass}") 235 | print("\nWordPress will be ready in 2-3 minutes") 236 | print("\nNext: Run ./migrate_to_droplet.sh to migrate your local WordPress") 237 | 238 | if __name__ == '__main__': 239 | create_wordpress_droplet() -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | # WordPress Claude Code Wizard - Complete Workflow & Development Guide 8 | 9 | ## 🚨 MANDATORY: ONE-SHOT COMPLETE EXECUTION 10 | 11 | **YOU MUST COMPLETE THE ENTIRE WORKFLOW IN ONE SHOT. DO NOT STOP PARTWAY.** 12 | **DO NOT deliver partial work. DO NOT stop after Phase 1. DO NOT skip steps.** 13 | **COMPLETE MEANS: Research → Build Website → Test with Playwright → Fix ALL issues → DONE** 14 | **The website must be FULLY FUNCTIONAL at http://localhost before you stop.** 15 | 16 | **DO NOT REPORT BACK TO THE USER OR ASK THEM ANYTHING UNTIL YOU HAVE:** 17 | - A fully built website running at http://localhost 18 | - All directory entries created and populated 19 | - All taxonomy pages working 20 | - Navigation menus fully populated 21 | - ZERO 404 errors verified by Playwright 22 | - Ready to run ./migrate_now.sh 23 | 24 | **The user hired you to BUILD A WEBSITE, not to show research or ask questions.** 25 | 26 | ## ⚠️ CRITICAL REQUIREMENT: ZERO 404 ERRORS 27 | 28 | **EVERY website you build MUST have ZERO 404 errors. Use Playwright MCP to verify EVERY SINGLE link.** 29 | **Headers and footers ALWAYS have broken links if you don't check them systematically.** 30 | **Do not deliver a website until Playwright confirms every link works.** 31 | 32 | ## 🎯 Main Workflow Process - COMPLETE ALL PHASES 33 | 34 | When building a directory website, you MUST complete ALL phases in one continuous workflow: 35 | 36 | ### Phase 1: Deep Research & Comprehensive Data Collection 37 | 38 | **GOAL: Create pages so information-rich that visitors never need to leave your site** 39 | 40 | 1. **Research each individual entry exhaustively using Jina AI** 41 | - Scrape the company's main website completely 42 | - Find and scrape their pricing pages, feature lists, documentation 43 | - Search for reviews, comparisons, alternatives 44 | - Gather technical specifications, integrations, use cases 45 | - Find case studies, success stories, testimonials 46 | - Collect founder information, company history, funding details 47 | - Get support options, contact methods, social media links 48 | - Retry any failed scrapes until you have EVERYTHING 49 | 50 | 2. **Build massive JSON datasets for each entry** 51 | Each individual page JSON should contain: 52 | ```json 53 | { 54 | "basics": { 55 | "name", "tagline", "description" (500+ words), 56 | "founded", "headquarters", "employees", "funding" 57 | }, 58 | "detailed_features": [ 59 | {"name", "description" (100+ words), "category", "importance"} 60 | ], 61 | "pricing": { 62 | "model", "free_tier", "starter_price", "tiers": [ 63 | {"name", "price", "features" (20+), "limits", "best_for"} 64 | ] 65 | }, 66 | "use_cases": [ 67 | {"title", "description" (200+ words), "industry", "company_size"} 68 | ], 69 | "pros_cons": { 70 | "pros": [{"title", "explanation" (50+ words)}], 71 | "cons": [{"title", "explanation" (50+ words)}] 72 | }, 73 | "integrations": [ 74 | {"name", "type", "description", "documentation_url"} 75 | ], 76 | "alternatives": [ 77 | {"name", "comparison" (100+ words), "when_to_choose"} 78 | ], 79 | "reviews": { 80 | "average_rating", "total_reviews", 81 | "rating_breakdown": {"5": %, "4": %, "3": %, "2": %, "1": %}, 82 | "expert_reviews": [{"source", "rating", "summary" (200+ words)}] 83 | }, 84 | "technical_specs": { 85 | "platforms", "languages", "api", "security", "compliance" 86 | }, 87 | "support": { 88 | "channels", "response_time", "documentation_quality", "community" 89 | }, 90 | "media": { 91 | "logo", "screenshots" (10+), "videos", "diagrams" 92 | } 93 | } 94 | ``` 95 | 96 | 3. **Create comprehensive taxonomy archive pages** 97 | 98 | **For Category/Type taxonomy pages (e.g., /categories/crm-software/, /types/italian-restaurants/, /specialties/anxiety-therapy/):** 99 | - Comprehensive overview of the category (1000+ words) 100 | - Complete buyer's/selection guide 101 | - Key features to look for 102 | - Common use cases and who needs this 103 | - Price range analysis and what affects cost 104 | - Industry trends and future outlook 105 | - Comparison methodology explanation 106 | - Top 10-20 entries with detailed previews 107 | - Quick comparison table 108 | - 20-30 FAQs about this category 109 | - Related categories and how they differ 110 | - Expert opinions and industry insights 111 | - Glossary of category-specific terms 112 | - Statistics and market data 113 | - ALL entries in this category listed below with rich cards 114 | 115 | **For Location pages (e.g., /locations/new-york/):** 116 | - Complete local market analysis (1000+ words) 117 | - Local regulations and requirements 118 | - Average prices in this area vs national 119 | - Transportation and parking information 120 | - Neighborhood-by-neighborhood breakdown 121 | - Local insurance providers accepted 122 | - Emergency services in the area 123 | - Community resources and support groups 124 | - Local statistics and demographics 125 | - ALL providers in this location with detailed cards 126 | - Nearby locations for comparison 127 | - Local events and workshops 128 | 129 | **For Combined taxonomy pages (e.g., /crm-software-for-startups/, /italian-restaurants-manhattan/, /anxiety-therapists-new-york/):** 130 | - Everything from both individual taxonomies combined 131 | - Specific local/niche context 132 | - Why this combination matters (e.g., "Why startups need different CRM") 133 | - Unique considerations for this intersection 134 | - Price analysis for this specific combination 135 | - Top 10 detailed comparisons with scoring methodology 136 | - Map visualization (if location-based) 137 | - Availability/wait times analysis 138 | - Quick filter and sort options 139 | - ALL matching entries with rich information cards 140 | 141 | 4. **Collect extensive imagery** 142 | - Product screenshots (10+ per entry) 143 | - Logo variations 144 | - Feature demonstration images 145 | - Comparison charts and infographics 146 | - Industry-relevant stock photos from Unsplash 147 | - Create custom diagrams where needed 148 | 149 | ### Phase 2: Website Development (THIS IS NOT OPTIONAL - YOU MUST BUILD THE WEBSITE) 150 | 151 | **DO NOT STOP AFTER RESEARCH. BUILD THE ACTUAL WEBSITE NOW.** 152 | 153 | 1. **Start with local WordPress Docker environment** 154 | - Run `docker-compose up -d` 155 | - Access at http://localhost 156 | 157 | 2. **Build the custom theme with FULL SEO optimization** 158 | - Create detailed, complex CSS (not simple/short) 159 | - Modern, clean, modular design 160 | - Implement all directory pages from JSON data 161 | - Add comprehensive animations and interactions 162 | - Ensure responsive design with multiple breakpoints 163 | 164 | 3. **Generate ALL ranking pages with maximized SEO** 165 | - Create "Best X in Y" pages for every location/category combination - THIS IS ESSENTIAL ON LOCATION PAGES 166 | - Maximize meta titles (60 chars) for each page - use words like Best X in Y or something else to help rank for those keywords 167 | - Maximize meta descriptions (160 chars) for each page 168 | - Create unique, comprehensive H1 titles 169 | - Write detailed, SEO-optimized descriptions for every page 170 | - Build internal linking structure between related pages 171 | 172 | 4. **Create 5-7 horizontal template variations** 173 | - Grid layout with filters 174 | - Card-based design with hover effects 175 | - List view with detailed information 176 | - Comparison table layout 177 | - Map-based directory view 178 | - Featured/spotlight layout 179 | - Masonry/Pinterest style layout 180 | 181 | 5. **Build mega header navigation** 182 | - Multi-level dropdown menus 183 | - Search functionality 184 | - Category quick links 185 | - Location selector 186 | - Sticky header on scroll 187 | - Mobile-optimized hamburger menu 188 | 189 | 6. **Implement review system (not basic comments)** 190 | - Custom review form for each directory entry 191 | - Frame as "Leave a Review" for product/service 192 | - Star rating system 193 | - Review categories (quality, service, value, etc.) 194 | - Review moderation queue 195 | - Display average ratings 196 | - Sort reviews by helpful/recent/rating 197 | 198 | 7. **Add contact form** 199 | - Professional contact form with validation 200 | - Multiple contact reasons dropdown 201 | - File upload capability 202 | - Anti-spam measures 203 | - Email notification system 204 | 205 | 8. **Import directory data from JSON** 206 | - Create custom post types for directory entries 207 | - Import JSON data into WordPress 208 | - Set up taxonomy/category structure 209 | - Generate all location/category pages automatically 210 | 211 | 9. **Test thoroughly locally** 212 | - Check all pages and permalinks 213 | - Verify images load correctly 214 | - Test responsive design 215 | - Validate all SEO elements 216 | - Test review submission 217 | - Test contact form 218 | 219 | ### Phase 2.5: MANDATORY Playwright Verification - CHECK EVERY SINGLE LINK 220 | 221 | **⛔ STOP! DO NOT SKIP THIS! YOU MUST CHECK EVERY SINGLE LINK WITH PLAYWRIGHT!** 222 | 223 | **THE WEBSITE IS NOT COMPLETE UNTIL PLAYWRIGHT VERIFIES ZERO 404s** 224 | 225 | Use the pre-configured Playwright MCP to verify EVERY link works. Do not just check "a few" links. 226 | Do not just check "some" pages. CHECK THEM ALL. The header and footer ALWAYS have broken links 227 | if you don't verify them properly! 228 | 229 | 1. **MANDATORY: Extract and Test EVERY Header Link** 230 | ``` 231 | Use playwright mcp to: 232 | 1. Navigate to http://localhost 233 | 2. Extract ALL href attributes from the header navigation 234 | 3. Create a list of EVERY SINGLE link found 235 | 4. Visit EACH link one by one 236 | 5. Verify EACH loads without 404 237 | 6. If ANY link returns 404, FIX IT IMMEDIATELY 238 | 239 | Example: If header has Home, About, Services, Blog, Contact, Categories dropdown with 240 | 10 categories, Location dropdown with 20 locations - that's 35 links to check. 241 | CHECK ALL 35. Not 5. Not 10. ALL 35. 242 | ``` 243 | 244 | 2. **MANDATORY: Extract and Test EVERY Footer Link** 245 | ``` 246 | Use playwright mcp to: 247 | 1. Scroll to footer 248 | 2. Extract ALL href attributes from the footer 249 | 3. Visit EVERY SINGLE footer link 250 | 4. Do not assume they work - TEST THEM 251 | 5. Common broken footer links: Privacy Policy, Terms, Sitemap 252 | 6. CREATE these pages if they don't exist 253 | ``` 254 | 255 | 3. **MANDATORY: Test EVERY Directory Entry** 256 | ``` 257 | DO NOT test "a few examples" - test EVERY SINGLE ONE: 258 | - Get the full list of all directory entries 259 | - Visit each one: /companies/company-1/, /companies/company-2/, etc. 260 | - If you have 50 entries, test all 50 261 | - Each must load with proper content, not 404 262 | ``` 263 | 264 | 4. **MANDATORY: Test EVERY Taxonomy Page** 265 | ``` 266 | Test EVERY SINGLE taxonomy page that should exist: 267 | - EVERY category: /categories/[slug]/ for each category 268 | - EVERY location: /locations/[slug]/ for each location 269 | - EVERY tag: /tags/[slug]/ for each tag 270 | - EVERY combination page if they exist 271 | - Do not test "some" - test EVERY SINGLE ONE 272 | ``` 273 | 274 | 5. **MANDATORY: Systematic Link Extraction and Testing** 275 | ``` 276 | Use playwright mcp to run this systematic check: 277 | 278 | // Extract ALL links from the site 279 | const allLinks = await page.evaluate(() => { 280 | return Array.from(document.querySelectorAll('a[href]')) 281 | .map(a => a.href) 282 | .filter(href => href.startsWith('http://localhost')); 283 | }); 284 | 285 | // Test EVERY SINGLE link 286 | for (const link of allLinks) { 287 | await page.goto(link); 288 | // Check for 404 or error 289 | // Log any broken links 290 | } 291 | 292 | If you find 10 links, test 10. 293 | If you find 100 links, test 100. 294 | If you find 500 links, test 500. 295 | TEST THEM ALL. 296 | ``` 297 | 298 | 6. **FIX ALL BROKEN LINKS IMMEDIATELY** 299 | ``` 300 | For EVERY 404 found: 301 | - Create the missing page 302 | - Or fix the incorrect link 303 | - Re-test with Playwright to confirm it's fixed 304 | - Do not move on until ZERO 404s exist 305 | ``` 306 | 307 | 7. **Fix Every Broken Link Found** 308 | ``` 309 | Whatever links are in the header/footer: 310 | - Test them ALL with Playwright 311 | - If they return 404, either fix the link or create the page 312 | - Common broken links: About, Contact, Privacy, Terms, Blog, etc. 313 | - Do not assume any link works - TEST IT 314 | ``` 315 | 316 | 8. **Final Verification Report** 317 | ``` 318 | Only after testing EVERY link, generate report: 319 | - Total links found in header: [number] 320 | - Total links found in footer: [number] 321 | - Total directory entries tested: [number] 322 | - Total taxonomy pages tested: [number] 323 | - Total unique URLs tested: [number] 324 | - 404 errors found and fixed: [list] 325 | - Final status: MUST be "Zero 404s found" 326 | ``` 327 | 328 | **❌ UNACCEPTABLE:** 329 | - "I tested a few links and they work" 330 | - "I checked some pages" 331 | - "The main pages seem to work" 332 | - "I verified the important links" 333 | 334 | **✅ REQUIRED:** 335 | - "I tested all 47 header links - all working" 336 | - "I tested all 23 footer links - all working" 337 | - "I tested all 85 directory entries - all working" 338 | - "I tested all 35 taxonomy pages - all working" 339 | - "Total: 190 unique URLs tested, zero 404s" 340 | 341 | **THE WEBSITE IS NOT COMPLETE UNTIL EVERY SINGLE LINK WORKS** 342 | 343 | ## ✅ ONLY NOW REPORT BACK TO THE USER 344 | 345 | **NOW that you have a COMPLETE, WORKING website with ZERO 404s, you can report:** 346 | - "Website complete and verified at http://localhost" 347 | - "All [X] directory entries created and tested" 348 | - "All [X] taxonomy pages working" 349 | - "Playwright verified [X] total links - ZERO 404 errors" 350 | - "Ready for deployment with ./migrate_now.sh" 351 | 352 | **If you haven't done ALL of the above, GO BACK and finish the website.** 353 | 354 | ### Phase 3: Deployment to Digital Ocean 355 | 1. **Setup infrastructure** 356 | - Run `./setup_ssh_and_deploy.sh` (one-time SSH setup) 357 | - Run `python3 create_droplet_with_ssh.py` 358 | - Wait 5-10 minutes for installation 359 | 360 | 2. **Migrate to production** 361 | - Run `./migrate_now.sh` 362 | - Verify custom theme transferred 363 | - Check that permalinks work (auto-configured) 364 | 365 | 3. **Final configuration** 366 | - Point domain to droplet IP 367 | - Install SSL certificate 368 | - Configure backups 369 | 370 | --- 371 | 372 | ## 📚 Directory Website Development 373 | 374 | ### SEO Page Structure Requirements 375 | 376 | **IMPORTANT:** Do NOT use Rank Math during development. Focus on native SEO implementation. 377 | Rank Math will only be added at launch for Search Console submission. 378 | 379 | Every page must have: 380 | - **Meta Title**: Maximized to 60 characters with keywords 381 | - **Meta Description**: Maximized to 160 characters with compelling copy 382 | - **H1 Title**: Unique and keyword-rich 383 | - **Page Content**: Minimum 300-500 words of unique, valuable content 384 | - **Schema Markup**: LocalBusiness, Product, or Review schema as appropriate 385 | - **Open Graph tags**: For social sharing 386 | - **Internal Links**: 3-5 contextual links to related pages 387 | 388 | Generate these page types for maximum ranking potential: 389 | - "Best [Product] in [City]" - for every city 390 | - "Top 10 [Category] in [State]" - for every state 391 | - "[Product] near me" - location-based pages 392 | - "[Category] Reviews [Year]" - fresh content pages 393 | - "Compare [Product A] vs [Product B]" - comparison pages 394 | - "[Product] for [Use Case]" - intent-based pages 395 | - "Cheap/Affordable [Product] in [Location]" - price-focused pages 396 | 397 | ### Review System Framework 398 | 399 | Frame reviews contextually based on the directory type: 400 | - For restaurants: "[Cuisine] lovers who dined at [Restaurant] can leave a review" 401 | - For products: "[Product] users who tried [Brand] can share their experience" 402 | - For services: "Customers who used [Service] from [Company] can rate their experience" 403 | - For venues: "Visitors who went to [Venue] can share their thoughts" 404 | 405 | Review form should include: 406 | - Overall star rating (1-5 stars) 407 | - Category-specific ratings (e.g., Quality, Service, Value, Location) 408 | - Written review with minimum 50 characters 409 | - Photo upload option 410 | - "Would you recommend?" Yes/No 411 | - Verified purchase/visit checkbox 412 | - Helpful/Not Helpful voting on other reviews 413 | 414 | ### Research Phase with Jina AI 415 | 416 | When building directory websites, use Jina AI for comprehensive research: 417 | 418 | ```bash 419 | # Search for information (use s.jina.ai) 420 | curl "https://s.jina.ai/?q=YOUR_SEARCH_TERM" \ 421 | -H "Authorization: Bearer $JINA_API_KEY" 422 | 423 | # Scrape individual pages (use r.jina.ai) 424 | curl "https://r.jina.ai/https://example.com/page" \ 425 | -H "Authorization: Bearer $JINA_API_KEY" 426 | ``` 427 | 428 | **Important Research Guidelines:** 429 | - Create detailed JSON for each directory page 430 | - If a page 404s or doesn't scrape properly, retry the scrape 431 | - DO NOT use Jina to scrape CSS from design sites 432 | 433 | ### Finding Royalty-Free Images 434 | 435 | ```bash 436 | # Search for Unsplash images using Jina 437 | curl "https://s.jina.ai/?q=YOUR_IMAGE_DESCRIPTION+unsplash" \ 438 | -H "Authorization: Bearer $JINA_API_KEY" 439 | 440 | # Then scrape the found Unsplash pages for non-premium images 441 | curl "https://r.jina.ai/https://unsplash.com/photos/..." \ 442 | -H "Authorization: Bearer $JINA_API_KEY" 443 | ``` 444 | 445 | ### Directory Page JSON Format 446 | 447 | Each directory entry should have comprehensive data: 448 | 449 | ```json 450 | { 451 | "id": "unique-identifier", 452 | "name": "Company/Service Name", 453 | "category": "Technology Category", 454 | "description": "Detailed description...", 455 | "features": ["feature1", "feature2", "..."], 456 | "pricing": { 457 | "model": "subscription/one-time/freemium", 458 | "tiers": [...] 459 | }, 460 | "images": { 461 | "logo": "url-from-unsplash", 462 | "screenshots": ["url1", "url2"], 463 | "hero": "hero-image-url" 464 | }, 465 | "metadata": { 466 | "founded": "year", 467 | "headquarters": "location", 468 | "employees": "range", 469 | "funding": "amount" 470 | }, 471 | "links": { 472 | "website": "url", 473 | "documentation": "url", 474 | "pricing": "url" 475 | }, 476 | "tags": ["tag1", "tag2"], 477 | "lastUpdated": "timestamp" 478 | } 479 | ``` 480 | 481 | ### CSS Development Guidelines 482 | 483 | **IMPORTANT:** Create extremely detailed and complex CSS files that are well-thought-out: 484 | 485 | - Don't write short, simple CSS - make it comprehensive 486 | - Include detailed animations and transitions 487 | - Add hover states, focus states, and active states 488 | - Create responsive breakpoints for all screen sizes 489 | - Include print styles and accessibility features 490 | - Use CSS custom properties for theming 491 | - Add detailed comments explaining complex sections 492 | - Implement sophisticated grid and flexbox layouts 493 | - Include fallbacks for older browsers 494 | 495 | Example of detailed CSS approach: 496 | ```css 497 | /* Component: Directory Card 498 | Purpose: Display individual directory entries 499 | States: default, hover, active, disabled, loading 500 | Breakpoints: mobile-first approach with 5 breakpoints 501 | Accessibility: WCAG 2.1 AA compliant */ 502 | 503 | .directory-card { 504 | /* Base styles with extensive properties */ 505 | /* Multiple transition effects */ 506 | /* Complex shadow systems */ 507 | /* Detailed spacing scales */ 508 | } 509 | ``` 510 | 511 | ## 🚀 Quick Deploy Workflow 512 | 513 | When a user clones this repository and wants to deploy WordPress to Digital Ocean, 514 | execute these commands in order: 515 | 516 | ```bash 517 | # 1. Setup environment 518 | cp .env.example .env 519 | # User must edit .env and add DO_API_TOKEN and JINA_API_KEY 520 | 521 | # 2. Install Python dependencies 522 | pip3 install python-dotenv requests 523 | 524 | # 3. Start local WordPress 525 | docker-compose up -d 526 | 527 | # 4. Setup SSH keys (one-time) 528 | ./setup_ssh_and_deploy.sh 529 | 530 | # 5. Create Digital Ocean droplet 531 | python3 create_droplet_with_ssh.py 532 | 533 | # 6. Wait for installation (5-10 minutes) 534 | sleep 300 535 | 536 | # 7. Migrate local WordPress to droplet 537 | ./migrate_now.sh 538 | ``` 539 | 540 | ## 📁 Project Structure 541 | 542 | ``` 543 | wordpress-claude-code-wizard/ 544 | ├── .env # DO_API_TOKEN goes here 545 | ├── docker-compose.yml # Local WordPress environment 546 | ├── Dockerfile # Custom Apache/PHP image 547 | ├── wp-config.php # Environment-aware configuration 548 | ├── setup_ssh_and_deploy.sh # SSH key automation 549 | ├── create_droplet_with_ssh.py # Droplet creation script 550 | ├── migrate_now.sh # Migration script 551 | └── wp-content/ 552 | ├── themes/ 553 | │ └── my-custom-theme/ # Starter theme 554 | └── plugins/ 555 | └── custom-post-types/ # CPT plugin 556 | ``` 557 | 558 | ## 🎨 WordPress Development Guide 559 | 560 | ### Theme Development 561 | 562 | Users can modify the custom theme in `wp-content/themes/my-custom-theme/`: 563 | 564 | ```bash 565 | # Create new page template 566 | cat > wp-content/themes/my-custom-theme/page-about.php << 'EOF' 567 | 571 |
572 |
573 |

574 | 575 |
576 |
577 | 578 | EOF 579 | 580 | # Create custom single post template 581 | cat > wp-content/themes/my-custom-theme/single.php << 'EOF' 582 | 583 |
584 |
585 |

586 |
Posted on
587 | 588 |
589 |
590 | 591 | EOF 592 | 593 | # Create archive template 594 | cat > wp-content/themes/my-custom-theme/archive.php << 'EOF' 595 | 596 |
597 |

598 | 599 |
600 |

601 | 602 |
603 | 604 |
605 | 606 | EOF 607 | ``` 608 | 609 | ### Adding Navigation Menus 610 | 611 | Add to `wp-content/themes/my-custom-theme/functions.php`: 612 | 613 | ```php 614 | // Register multiple menu locations 615 | register_nav_menus(array( 616 | 'primary' => __('Primary Menu', 'my-custom-theme'), 617 | 'footer' => __('Footer Menu', 'my-custom-theme'), 618 | 'social' => __('Social Links Menu', 'my-custom-theme'), 619 | )); 620 | 621 | // Add menu support 622 | add_theme_support('menus'); 623 | ``` 624 | 625 | Display menus in theme templates: 626 | 627 | ```php 628 | // In header.php 629 | 'primary')); ?> 630 | 631 | // In footer.php 632 | 'footer')); ?> 633 | ``` 634 | 635 | ### WP-CLI Commands (Inside Docker Container) 636 | 637 | ```bash 638 | # Access the WordPress container 639 | docker exec -it wp-dev bash 640 | 641 | # Install WP-CLI (if not already installed) 642 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 643 | chmod +x wp-cli.phar 644 | mv wp-cli.phar /usr/local/bin/wp 645 | 646 | # Create pages 647 | wp post create --post_type=page --post_title='Home' --post_status=publish 648 | wp post create --post_type=page --post_title='About Us' --post_status=publish 649 | wp post create --post_type=page --post_title='Services' --post_status=publish 650 | wp post create --post_type=page --post_title='Contact' --post_status=publish 651 | wp post create --post_type=page --post_title='Blog' --post_status=publish 652 | 653 | # Set static homepage 654 | wp option update page_on_front 2 # Use page ID 655 | wp option update show_on_front page 656 | wp option update page_for_posts 5 # Blog page ID 657 | 658 | # Create menu 659 | wp menu create "Main Menu" 660 | wp menu location assign main-menu primary 661 | wp menu item add-post main-menu 2 # Add pages to menu 662 | wp menu item add-post main-menu 3 663 | wp menu item add-post main-menu 4 664 | 665 | # Install popular plugins 666 | wp plugin install contact-form-7 --activate 667 | wp plugin install wordpress-seo --activate 668 | wp plugin install elementor --activate 669 | wp plugin install woocommerce --activate 670 | wp plugin install updraftplus --activate 671 | 672 | # Create users 673 | wp user create john john@example.com --role=editor --user_pass=password123 674 | wp user create jane jane@example.com --role=author --user_pass=password123 675 | 676 | # Update site options 677 | wp option update blogname "My Awesome Site" 678 | wp option update blogdescription "A WordPress site built with Claude Code Wizard" 679 | wp option update timezone_string "America/New_York" 680 | 681 | # Set permalinks 682 | wp rewrite structure '/%postname%/' 683 | wp rewrite flush 684 | ``` 685 | 686 | ### Custom Post Types 687 | 688 | The included plugin already creates Portfolio and Testimonial post types. To add 689 | more: 690 | 691 | ```php 692 | // Add to wp-content/plugins/custom-post-types/custom-post-types.php 693 | 694 | public function register_team_post_type() { 695 | $args = array( 696 | 'labels' => array( 697 | 'name' => 'Team Members', 698 | 'singular_name' => 'Team Member', 699 | ), 700 | 'public' => true, 701 | 'has_archive' => true, 702 | 'supports' => array('title', 'editor', 'thumbnail'), 703 | 'menu_icon' => 'dashicons-groups', 704 | 'show_in_rest' => true, 705 | ); 706 | register_post_type('team', $args); 707 | } 708 | // Add to __construct(): add_action('init', array($this, 709 | 'register_team_post_type')); 710 | ``` 711 | 712 | ### Advanced Theme Features 713 | 714 | ```php 715 | // Add to functions.php 716 | 717 | // Custom image sizes 718 | add_theme_support('post-thumbnails'); 719 | add_image_size('hero', 1920, 600, true); 720 | add_image_size('team-member', 400, 400, true); 721 | 722 | // Widget areas 723 | function my_widgets_init() { 724 | register_sidebar(array( 725 | 'name' => 'Homepage Widgets', 726 | 'id' => 'homepage-widgets', 727 | 'before_widget' => '
', 728 | 'after_widget' => '
', 729 | )); 730 | } 731 | add_action('widgets_init', 'my_widgets_init'); 732 | 733 | // Custom logo support 734 | add_theme_support('custom-logo', array( 735 | 'height' => 100, 736 | 'width' => 400, 737 | 'flex-height' => true, 738 | 'flex-width' => true, 739 | )); 740 | 741 | // Gutenberg support 742 | add_theme_support('align-wide'); 743 | add_theme_support('editor-styles'); 744 | add_theme_support('wp-block-styles'); 745 | ``` 746 | 747 | ## 🔧 Troubleshooting Commands 748 | 749 | ```bash 750 | # Check if Docker containers are running 751 | docker ps | grep wp- 752 | 753 | # View Docker logs 754 | docker-compose logs wordpress 755 | 756 | # Restart containers 757 | docker-compose restart 758 | 759 | # Access MySQL directly 760 | docker exec -it wp-mysql mysql -u wordpress -pwordpress_password wordpress 761 | 762 | # Check droplet status 763 | cat .droplet_info | python3 -m json.tool 764 | 765 | # SSH to droplet 766 | ssh -i ~/.ssh/wordpress_deploy root@$(cat .droplet_info | python3 -c "import 767 | json,sys; print(json.load(sys.stdin)['ip_address'])") 768 | 769 | # View WordPress error logs on droplet 770 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "tail -f /var/log/apache2/error.log" 771 | 772 | # Check cloud-init status 773 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "cloud-init status" 774 | 775 | # Delete droplet (cleanup) 776 | python3 -c " 777 | import requests, json, os 778 | api_token = os.getenv('DO_API_TOKEN') 779 | with open('.droplet_info') as f: 780 | droplet_id = json.load(f)['droplet_id'] 781 | headers = {'Authorization': f'Bearer {api_token}'} 782 | response = 783 | requests.delete(f'https://api.digitalocean.com/v2/droplets/{droplet_id}', 784 | headers=headers) 785 | print('Droplet deleted' if response.status_code == 204 else 'Failed') 786 | " 787 | ``` 788 | 789 | ### 🚨 Fixing 404 Errors on Pages 790 | 791 | If you encounter 404 errors on pages after deployment, the scripts now handle this 792 | automatically. However, if you still have issues: 793 | 794 | ```bash 795 | # SSH to droplet 796 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP 797 | 798 | # Check if permalinks are set correctly 799 | wp --allow-root rewrite structure 800 | 801 | # Manually set permalinks and flush 802 | wp --allow-root rewrite structure '/%postname%/' 803 | wp --allow-root rewrite flush 804 | 805 | # Verify Apache configuration 806 | cat /etc/apache2/sites-enabled/wordpress.conf 807 | # Should show: AllowOverride All 808 | 809 | # Check .htaccess exists and is correct 810 | cat /var/www/html/.htaccess 811 | 812 | # Restart Apache 813 | systemctl restart apache2 814 | ``` 815 | 816 | **Note:** The deployment scripts now automatically: 817 | - Install WP-CLI on the server 818 | - Configure Apache with AllowOverride All 819 | - Set permalinks to /%postname%/ 820 | - Create proper .htaccess file 821 | - Flush rewrite rules after migration 822 | 823 | ## 📊 Production Deployment Checklist 824 | 825 | Before deploying to production: 826 | 827 | 1. ✅ Update passwords in wp-config.php 828 | 2. ✅ Set WP_DEBUG to false 829 | 3. ✅ Update salts (automatic during migration) 830 | 4. ✅ Install SSL certificate (certbot --apache) 831 | 5. ✅ Configure domain DNS 832 | 6. ✅ Enable firewall (ufw) 833 | 7. ✅ Set up backups 834 | 8. ✅ Configure email settings 835 | 836 | ## 🎯 Complete Workflow Summary 837 | 838 | 1. **Clone repo** → Get complete WordPress development environment 839 | 2. **Docker up** → Local WordPress running instantly 840 | 3. **Develop** → Theme, plugins, content - everything 841 | 4. **Setup SSH** → One-time automated key configuration 842 | 5. **Create droplet** → Automated via API with WordPress installation 843 | 6. **Migrate** → Transfer everything to production 844 | 7. **Point domain** → Update DNS A record 845 | 8. **SSL** → Run certbot for HTTPS 846 | 9. **Live** → Production WordPress site running! 847 | 848 | ## 💡 Key Features This Provides 849 | 850 | - **Zero DevOps knowledge required** - Just need DO API token 851 | - **Perfect environment parity** - Docker matches production exactly 852 | - **Complete WordPress control** - Full admin access, all features 853 | - **Real VPS** - Not shared hosting, full server control 854 | - **One-command deployment** - Actually automated, not marketing speak 855 | - **Cost effective** - $6/month for production site 856 | - **No vendor lock-in** - Standard WordPress on standard Ubuntu 857 | - **Version controlled** - Everything in Git 858 | - **Instant local development** - Changes visible immediately 859 | - **Professional workflow** - Local → Staging → Production capable 860 | 861 | ## 🚨 Important Notes 862 | 863 | - Always test locally before deploying 864 | - Keep backups of production database 865 | - Use strong passwords in production 866 | - Update WordPress, themes, and plugins regularly 867 | - Monitor server resources on Digital Ocean 868 | - The migration script replaces the entire WordPress installation 869 | - Custom plugins/themes in wp-content are preserved 870 | - Database is completely replaced with local version 871 | 872 | ## 🔄 Updating Production Site 873 | 874 | To update your production site after local changes: 875 | 876 | ```bash 877 | # Make changes locally 878 | # Test everything at http://localhost 879 | 880 | # Re-run migration to update production 881 | ./migrate_now.sh 882 | 883 | # Your production site is now updated with all local changes 884 | ``` 885 | 886 | This is a complete local-to-production WordPress development and deployment 887 | pipeline that doesn't exist anywhere else in this form! -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | # WordPress Claude Code Wizard - Complete Workflow & Development Guide 8 | 9 | ## 🚨 MANDATORY: ONE-SHOT COMPLETE EXECUTION 10 | 11 | **YOU MUST COMPLETE THE ENTIRE WORKFLOW IN ONE SHOT. DO NOT STOP PARTWAY.** 12 | **DO NOT deliver partial work. DO NOT stop after Phase 1. DO NOT skip steps.** 13 | **COMPLETE MEANS: Research → Build Website → Test with Playwright → Fix ALL issues → DONE** 14 | **The website must be FULLY FUNCTIONAL at http://localhost before you stop.** 15 | 16 | **DO NOT REPORT BACK TO THE USER OR ASK THEM ANYTHING UNTIL YOU HAVE:** 17 | - A fully built website running at http://localhost 18 | - All directory entries created and populated 19 | - All taxonomy pages working 20 | - Navigation menus fully populated 21 | - ZERO 404 errors verified by Playwright 22 | - Ready to run ./migrate_now.sh 23 | 24 | **The user hired you to BUILD A WEBSITE, not to show research or ask questions.** 25 | 26 | ## ⚠️ CRITICAL REQUIREMENT: ZERO 404 ERRORS 27 | 28 | **EVERY website you build MUST have ZERO 404 errors. Use Playwright MCP to verify EVERY SINGLE link.** 29 | **Headers and footers ALWAYS have broken links if you don't check them systematically.** 30 | **Do not deliver a website until Playwright confirms every link works.** 31 | 32 | ## 🎯 Main Workflow Process - COMPLETE ALL PHASES 33 | 34 | When building a directory website, you MUST complete ALL phases in one continuous workflow: 35 | 36 | ### Phase 1: Deep Research & Comprehensive Data Collection 37 | 38 | **GOAL: Create pages so information-rich that visitors never need to leave your site** 39 | 40 | 1. **Research each individual entry exhaustively using Jina AI** 41 | - Scrape the company's main website completely 42 | - Find and scrape their pricing pages, feature lists, documentation 43 | - Search for reviews, comparisons, alternatives 44 | - Gather technical specifications, integrations, use cases 45 | - Find case studies, success stories, testimonials 46 | - Collect founder information, company history, funding details 47 | - Get support options, contact methods, social media links 48 | - Retry any failed scrapes until you have EVERYTHING 49 | 50 | 2. **Build massive JSON datasets for each entry** 51 | Each individual page JSON should contain: 52 | ```json 53 | { 54 | "basics": { 55 | "name", "tagline", "description" (500+ words), 56 | "founded", "headquarters", "employees", "funding" 57 | }, 58 | "detailed_features": [ 59 | {"name", "description" (100+ words), "category", "importance"} 60 | ], 61 | "pricing": { 62 | "model", "free_tier", "starter_price", "tiers": [ 63 | {"name", "price", "features" (20+), "limits", "best_for"} 64 | ] 65 | }, 66 | "use_cases": [ 67 | {"title", "description" (200+ words), "industry", "company_size"} 68 | ], 69 | "pros_cons": { 70 | "pros": [{"title", "explanation" (50+ words)}], 71 | "cons": [{"title", "explanation" (50+ words)}] 72 | }, 73 | "integrations": [ 74 | {"name", "type", "description", "documentation_url"} 75 | ], 76 | "alternatives": [ 77 | {"name", "comparison" (100+ words), "when_to_choose"} 78 | ], 79 | "reviews": { 80 | "average_rating", "total_reviews", 81 | "rating_breakdown": {"5": %, "4": %, "3": %, "2": %, "1": %}, 82 | "expert_reviews": [{"source", "rating", "summary" (200+ words)}] 83 | }, 84 | "technical_specs": { 85 | "platforms", "languages", "api", "security", "compliance" 86 | }, 87 | "support": { 88 | "channels", "response_time", "documentation_quality", "community" 89 | }, 90 | "media": { 91 | "logo", "screenshots" (10+), "videos", "diagrams" 92 | } 93 | } 94 | ``` 95 | 96 | 3. **Create comprehensive taxonomy archive pages** 97 | 98 | **For Category/Type taxonomy pages (e.g., /categories/crm-software/, /types/italian-restaurants/, /specialties/anxiety-therapy/):** 99 | - Comprehensive overview of the category (1000+ words) 100 | - Complete buyer's/selection guide 101 | - Key features to look for 102 | - Common use cases and who needs this 103 | - Price range analysis and what affects cost 104 | - Industry trends and future outlook 105 | - Comparison methodology explanation 106 | - Top 10-20 entries with detailed previews 107 | - Quick comparison table 108 | - 20-30 FAQs about this category 109 | - Related categories and how they differ 110 | - Expert opinions and industry insights 111 | - Glossary of category-specific terms 112 | - Statistics and market data 113 | - ALL entries in this category listed below with rich cards 114 | 115 | **For Location pages (e.g., /locations/new-york/):** 116 | - Complete local market analysis (1000+ words) 117 | - Local regulations and requirements 118 | - Average prices in this area vs national 119 | - Transportation and parking information 120 | - Neighborhood-by-neighborhood breakdown 121 | - Local insurance providers accepted 122 | - Emergency services in the area 123 | - Community resources and support groups 124 | - Local statistics and demographics 125 | - ALL providers in this location with detailed cards 126 | - Nearby locations for comparison 127 | - Local events and workshops 128 | 129 | **For Combined taxonomy pages (e.g., /crm-software-for-startups/, /italian-restaurants-manhattan/, /anxiety-therapists-new-york/):** 130 | - Everything from both individual taxonomies combined 131 | - Specific local/niche context 132 | - Why this combination matters (e.g., "Why startups need different CRM") 133 | - Unique considerations for this intersection 134 | - Price analysis for this specific combination 135 | - Top 10 detailed comparisons with scoring methodology 136 | - Map visualization (if location-based) 137 | - Availability/wait times analysis 138 | - Quick filter and sort options 139 | - ALL matching entries with rich information cards 140 | 141 | 4. **Collect extensive imagery** 142 | - Product screenshots (10+ per entry) 143 | - Logo variations 144 | - Feature demonstration images 145 | - Comparison charts and infographics 146 | - Industry-relevant stock photos from Unsplash 147 | - Create custom diagrams where needed 148 | 149 | ### Phase 2: Website Development (THIS IS NOT OPTIONAL - YOU MUST BUILD THE WEBSITE) 150 | 151 | **DO NOT STOP AFTER RESEARCH. BUILD THE ACTUAL WEBSITE NOW.** 152 | 153 | 1. **Start with local WordPress Docker environment** 154 | - Run `docker-compose up -d` 155 | - Access at http://localhost 156 | 157 | 2. **Build the custom theme with FULL SEO optimization** 158 | - Create detailed, complex CSS (not simple/short) 159 | - Modern, clean, modular design 160 | - Implement all directory pages from JSON data 161 | - Add comprehensive animations and interactions 162 | - Ensure responsive design with multiple breakpoints 163 | 164 | 3. **Generate ALL ranking pages with maximized SEO** 165 | - Create "Best X in Y" pages for every location/category combination - THIS IS ESSENTIAL ON LOCATION PAGES 166 | - Maximize meta titles (60 chars) for each page - use words like Best X in Y or something else to help rank for those keywords 167 | - Maximize meta descriptions (160 chars) for each page 168 | - Create unique, comprehensive H1 titles 169 | - Write detailed, SEO-optimized descriptions for every page 170 | - Build internal linking structure between related pages 171 | 172 | 4. **Create 5-7 horizontal template variations** 173 | - Grid layout with filters 174 | - Card-based design with hover effects 175 | - List view with detailed information 176 | - Comparison table layout 177 | - Map-based directory view 178 | - Featured/spotlight layout 179 | - Masonry/Pinterest style layout 180 | 181 | 5. **Build mega header navigation** 182 | - Multi-level dropdown menus 183 | - Search functionality 184 | - Category quick links 185 | - Location selector 186 | - Sticky header on scroll 187 | - Mobile-optimized hamburger menu 188 | 189 | 6. **Implement review system (not basic comments)** 190 | - Custom review form for each directory entry 191 | - Frame as "Leave a Review" for product/service 192 | - Star rating system 193 | - Review categories (quality, service, value, etc.) 194 | - Review moderation queue 195 | - Display average ratings 196 | - Sort reviews by helpful/recent/rating 197 | 198 | 7. **Add contact form** 199 | - Professional contact form with validation 200 | - Multiple contact reasons dropdown 201 | - File upload capability 202 | - Anti-spam measures 203 | - Email notification system 204 | 205 | 8. **Import directory data from JSON** 206 | - Create custom post types for directory entries 207 | - Import JSON data into WordPress 208 | - Set up taxonomy/category structure 209 | - Generate all location/category pages automatically 210 | 211 | 9. **Test thoroughly locally** 212 | - Check all pages and permalinks 213 | - Verify images load correctly 214 | - Test responsive design 215 | - Validate all SEO elements 216 | - Test review submission 217 | - Test contact form 218 | 219 | ### Phase 2.5: MANDATORY Playwright Verification - CHECK EVERY SINGLE LINK 220 | 221 | **⛔ STOP! DO NOT SKIP THIS! YOU MUST CHECK EVERY SINGLE LINK WITH PLAYWRIGHT!** 222 | 223 | **THE WEBSITE IS NOT COMPLETE UNTIL PLAYWRIGHT VERIFIES ZERO 404s** 224 | 225 | Use the pre-configured Playwright MCP to verify EVERY link works. Do not just check "a few" links. 226 | Do not just check "some" pages. CHECK THEM ALL. The header and footer ALWAYS have broken links 227 | if you don't verify them properly! 228 | 229 | 1. **MANDATORY: Extract and Test EVERY Header Link** 230 | ``` 231 | Use playwright mcp to: 232 | 1. Navigate to http://localhost 233 | 2. Extract ALL href attributes from the header navigation 234 | 3. Create a list of EVERY SINGLE link found 235 | 4. Visit EACH link one by one 236 | 5. Verify EACH loads without 404 237 | 6. If ANY link returns 404, FIX IT IMMEDIATELY 238 | 239 | Example: If header has Home, About, Services, Blog, Contact, Categories dropdown with 240 | 10 categories, Location dropdown with 20 locations - that's 35 links to check. 241 | CHECK ALL 35. Not 5. Not 10. ALL 35. 242 | ``` 243 | 244 | 2. **MANDATORY: Extract and Test EVERY Footer Link** 245 | ``` 246 | Use playwright mcp to: 247 | 1. Scroll to footer 248 | 2. Extract ALL href attributes from the footer 249 | 3. Visit EVERY SINGLE footer link 250 | 4. Do not assume they work - TEST THEM 251 | 5. Common broken footer links: Privacy Policy, Terms, Sitemap 252 | 6. CREATE these pages if they don't exist 253 | ``` 254 | 255 | 3. **MANDATORY: Test EVERY Directory Entry** 256 | ``` 257 | DO NOT test "a few examples" - test EVERY SINGLE ONE: 258 | - Get the full list of all directory entries 259 | - Visit each one: /companies/company-1/, /companies/company-2/, etc. 260 | - If you have 50 entries, test all 50 261 | - Each must load with proper content, not 404 262 | ``` 263 | 264 | 4. **MANDATORY: Test EVERY Taxonomy Page** 265 | ``` 266 | Test EVERY SINGLE taxonomy page that should exist: 267 | - EVERY category: /categories/[slug]/ for each category 268 | - EVERY location: /locations/[slug]/ for each location 269 | - EVERY tag: /tags/[slug]/ for each tag 270 | - EVERY combination page if they exist 271 | - Do not test "some" - test EVERY SINGLE ONE 272 | ``` 273 | 274 | 5. **MANDATORY: Systematic Link Extraction and Testing** 275 | ``` 276 | Use playwright mcp to run this systematic check: 277 | 278 | // Extract ALL links from the site 279 | const allLinks = await page.evaluate(() => { 280 | return Array.from(document.querySelectorAll('a[href]')) 281 | .map(a => a.href) 282 | .filter(href => href.startsWith('http://localhost')); 283 | }); 284 | 285 | // Test EVERY SINGLE link 286 | for (const link of allLinks) { 287 | await page.goto(link); 288 | // Check for 404 or error 289 | // Log any broken links 290 | } 291 | 292 | If you find 10 links, test 10. 293 | If you find 100 links, test 100. 294 | If you find 500 links, test 500. 295 | TEST THEM ALL. 296 | ``` 297 | 298 | 6. **FIX ALL BROKEN LINKS IMMEDIATELY** 299 | ``` 300 | For EVERY 404 found: 301 | - Create the missing page 302 | - Or fix the incorrect link 303 | - Re-test with Playwright to confirm it's fixed 304 | - Do not move on until ZERO 404s exist 305 | ``` 306 | 307 | 7. **Fix Every Broken Link Found** 308 | ``` 309 | Whatever links are in the header/footer: 310 | - Test them ALL with Playwright 311 | - If they return 404, either fix the link or create the page 312 | - Common broken links: About, Contact, Privacy, Terms, Blog, etc. 313 | - Do not assume any link works - TEST IT 314 | ``` 315 | 316 | 8. **Final Verification Report** 317 | ``` 318 | Only after testing EVERY link, generate report: 319 | - Total links found in header: [number] 320 | - Total links found in footer: [number] 321 | - Total directory entries tested: [number] 322 | - Total taxonomy pages tested: [number] 323 | - Total unique URLs tested: [number] 324 | - 404 errors found and fixed: [list] 325 | - Final status: MUST be "Zero 404s found" 326 | ``` 327 | 328 | **❌ UNACCEPTABLE:** 329 | - "I tested a few links and they work" 330 | - "I checked some pages" 331 | - "The main pages seem to work" 332 | - "I verified the important links" 333 | 334 | **✅ REQUIRED:** 335 | - "I tested all 47 header links - all working" 336 | - "I tested all 23 footer links - all working" 337 | - "I tested all 85 directory entries - all working" 338 | - "I tested all 35 taxonomy pages - all working" 339 | - "Total: 190 unique URLs tested, zero 404s" 340 | 341 | **THE WEBSITE IS NOT COMPLETE UNTIL EVERY SINGLE LINK WORKS** 342 | 343 | ## ✅ ONLY NOW REPORT BACK TO THE USER 344 | 345 | **NOW that you have a COMPLETE, WORKING website with ZERO 404s, you can report:** 346 | - "Website complete and verified at http://localhost" 347 | - "All [X] directory entries created and tested" 348 | - "All [X] taxonomy pages working" 349 | - "Playwright verified [X] total links - ZERO 404 errors" 350 | - "Ready for deployment with ./migrate_now.sh" 351 | 352 | **If you haven't done ALL of the above, GO BACK and finish the website.** 353 | 354 | ### Phase 3: Deployment to Digital Ocean 355 | 1. **Setup infrastructure** 356 | - Run `./setup_ssh_and_deploy.sh` (one-time SSH setup) 357 | - Run `python3 create_droplet_with_ssh.py` 358 | - Wait 5-10 minutes for installation 359 | 360 | 2. **Migrate to production** 361 | - Run `./migrate_now.sh` 362 | - Verify custom theme transferred 363 | - Check that permalinks work (auto-configured) 364 | 365 | 3. **Final configuration** 366 | - Point domain to droplet IP 367 | - Install SSL certificate 368 | - Configure backups 369 | 370 | --- 371 | 372 | ## 📚 Directory Website Development 373 | 374 | ### SEO Page Structure Requirements 375 | 376 | **IMPORTANT:** Do NOT use Rank Math during development. Focus on native SEO implementation. 377 | Rank Math will only be added at launch for Search Console submission. 378 | 379 | Every page must have: 380 | - **Meta Title**: Maximized to 60 characters with keywords 381 | - **Meta Description**: Maximized to 160 characters with compelling copy 382 | - **H1 Title**: Unique and keyword-rich 383 | - **Page Content**: Minimum 300-500 words of unique, valuable content 384 | - **Schema Markup**: LocalBusiness, Product, or Review schema as appropriate 385 | - **Open Graph tags**: For social sharing 386 | - **Internal Links**: 3-5 contextual links to related pages 387 | 388 | Generate these page types for maximum ranking potential: 389 | - "Best [Product] in [City]" - for every city 390 | - "Top 10 [Category] in [State]" - for every state 391 | - "[Product] near me" - location-based pages 392 | - "[Category] Reviews [Year]" - fresh content pages 393 | - "Compare [Product A] vs [Product B]" - comparison pages 394 | - "[Product] for [Use Case]" - intent-based pages 395 | - "Cheap/Affordable [Product] in [Location]" - price-focused pages 396 | 397 | ### Review System Framework 398 | 399 | Frame reviews contextually based on the directory type: 400 | - For restaurants: "[Cuisine] lovers who dined at [Restaurant] can leave a review" 401 | - For products: "[Product] users who tried [Brand] can share their experience" 402 | - For services: "Customers who used [Service] from [Company] can rate their experience" 403 | - For venues: "Visitors who went to [Venue] can share their thoughts" 404 | 405 | Review form should include: 406 | - Overall star rating (1-5 stars) 407 | - Category-specific ratings (e.g., Quality, Service, Value, Location) 408 | - Written review with minimum 50 characters 409 | - Photo upload option 410 | - "Would you recommend?" Yes/No 411 | - Verified purchase/visit checkbox 412 | - Helpful/Not Helpful voting on other reviews 413 | 414 | ### Research Phase with Jina AI 415 | 416 | When building directory websites, use Jina AI for comprehensive research: 417 | 418 | ```bash 419 | # Search for information (use s.jina.ai) 420 | curl "https://s.jina.ai/?q=YOUR_SEARCH_TERM" \ 421 | -H "Authorization: Bearer $JINA_API_KEY" 422 | 423 | # Scrape individual pages (use r.jina.ai) 424 | curl "https://r.jina.ai/https://example.com/page" \ 425 | -H "Authorization: Bearer $JINA_API_KEY" 426 | ``` 427 | 428 | **Important Research Guidelines:** 429 | - Create detailed JSON for each directory page 430 | - If a page 404s or doesn't scrape properly, retry the scrape 431 | - DO NOT use Jina to scrape CSS from design sites 432 | 433 | ### Finding Royalty-Free Images 434 | 435 | ```bash 436 | # Search for Unsplash images using Jina 437 | curl "https://s.jina.ai/?q=YOUR_IMAGE_DESCRIPTION+unsplash" \ 438 | -H "Authorization: Bearer $JINA_API_KEY" 439 | 440 | # Then scrape the found Unsplash pages for non-premium images 441 | curl "https://r.jina.ai/https://unsplash.com/photos/..." \ 442 | -H "Authorization: Bearer $JINA_API_KEY" 443 | ``` 444 | 445 | ### Directory Page JSON Format 446 | 447 | Each directory entry should have comprehensive data: 448 | 449 | ```json 450 | { 451 | "id": "unique-identifier", 452 | "name": "Company/Service Name", 453 | "category": "Technology Category", 454 | "description": "Detailed description...", 455 | "features": ["feature1", "feature2", "..."], 456 | "pricing": { 457 | "model": "subscription/one-time/freemium", 458 | "tiers": [...] 459 | }, 460 | "images": { 461 | "logo": "url-from-unsplash", 462 | "screenshots": ["url1", "url2"], 463 | "hero": "hero-image-url" 464 | }, 465 | "metadata": { 466 | "founded": "year", 467 | "headquarters": "location", 468 | "employees": "range", 469 | "funding": "amount" 470 | }, 471 | "links": { 472 | "website": "url", 473 | "documentation": "url", 474 | "pricing": "url" 475 | }, 476 | "tags": ["tag1", "tag2"], 477 | "lastUpdated": "timestamp" 478 | } 479 | ``` 480 | 481 | ### CSS Development Guidelines 482 | 483 | **IMPORTANT:** Create extremely detailed and complex CSS files that are well-thought-out: 484 | 485 | - Don't write short, simple CSS - make it comprehensive 486 | - Include detailed animations and transitions 487 | - Add hover states, focus states, and active states 488 | - Create responsive breakpoints for all screen sizes 489 | - Include print styles and accessibility features 490 | - Use CSS custom properties for theming 491 | - Add detailed comments explaining complex sections 492 | - Implement sophisticated grid and flexbox layouts 493 | - Include fallbacks for older browsers 494 | 495 | Example of detailed CSS approach: 496 | ```css 497 | /* Component: Directory Card 498 | Purpose: Display individual directory entries 499 | States: default, hover, active, disabled, loading 500 | Breakpoints: mobile-first approach with 5 breakpoints 501 | Accessibility: WCAG 2.1 AA compliant */ 502 | 503 | .directory-card { 504 | /* Base styles with extensive properties */ 505 | /* Multiple transition effects */ 506 | /* Complex shadow systems */ 507 | /* Detailed spacing scales */ 508 | } 509 | ``` 510 | 511 | ## 🚀 Quick Deploy Workflow 512 | 513 | When a user clones this repository and wants to deploy WordPress to Digital Ocean, 514 | execute these commands in order: 515 | 516 | ```bash 517 | # 1. Setup environment 518 | cp .env.example .env 519 | # User must edit .env and add DO_API_TOKEN and JINA_API_KEY 520 | 521 | # 2. Install Python dependencies 522 | pip3 install python-dotenv requests 523 | 524 | # 3. Start local WordPress 525 | docker-compose up -d 526 | 527 | # 4. Setup SSH keys (one-time) 528 | ./setup_ssh_and_deploy.sh 529 | 530 | # 5. Create Digital Ocean droplet 531 | python3 create_droplet_with_ssh.py 532 | 533 | # 6. Wait for installation (5-10 minutes) 534 | sleep 300 535 | 536 | # 7. Migrate local WordPress to droplet 537 | ./migrate_now.sh 538 | ``` 539 | 540 | ## 📁 Project Structure 541 | 542 | ``` 543 | wordpress-claude-code-wizard/ 544 | ├── .env # DO_API_TOKEN goes here 545 | ├── docker-compose.yml # Local WordPress environment 546 | ├── Dockerfile # Custom Apache/PHP image 547 | ├── wp-config.php # Environment-aware configuration 548 | ├── setup_ssh_and_deploy.sh # SSH key automation 549 | ├── create_droplet_with_ssh.py # Droplet creation script 550 | ├── migrate_now.sh # Migration script 551 | └── wp-content/ 552 | ├── themes/ 553 | │ └── my-custom-theme/ # Starter theme 554 | └── plugins/ 555 | └── custom-post-types/ # CPT plugin 556 | ``` 557 | 558 | ## 🎨 WordPress Development Guide 559 | 560 | ### Theme Development 561 | 562 | Users can modify the custom theme in `wp-content/themes/my-custom-theme/`: 563 | 564 | ```bash 565 | # Create new page template 566 | cat > wp-content/themes/my-custom-theme/page-about.php << 'EOF' 567 | 571 |
572 |
573 |

574 | 575 |
576 |
577 | 578 | EOF 579 | 580 | # Create custom single post template 581 | cat > wp-content/themes/my-custom-theme/single.php << 'EOF' 582 | 583 |
584 |
585 |

586 |
Posted on
587 | 588 |
589 |
590 | 591 | EOF 592 | 593 | # Create archive template 594 | cat > wp-content/themes/my-custom-theme/archive.php << 'EOF' 595 | 596 |
597 |

598 | 599 |
600 |

601 | 602 |
603 | 604 |
605 | 606 | EOF 607 | ``` 608 | 609 | ### Adding Navigation Menus 610 | 611 | Add to `wp-content/themes/my-custom-theme/functions.php`: 612 | 613 | ```php 614 | // Register multiple menu locations 615 | register_nav_menus(array( 616 | 'primary' => __('Primary Menu', 'my-custom-theme'), 617 | 'footer' => __('Footer Menu', 'my-custom-theme'), 618 | 'social' => __('Social Links Menu', 'my-custom-theme'), 619 | )); 620 | 621 | // Add menu support 622 | add_theme_support('menus'); 623 | ``` 624 | 625 | Display menus in theme templates: 626 | 627 | ```php 628 | // In header.php 629 | 'primary')); ?> 630 | 631 | // In footer.php 632 | 'footer')); ?> 633 | ``` 634 | 635 | ### WP-CLI Commands (Inside Docker Container) 636 | 637 | ```bash 638 | # Access the WordPress container 639 | docker exec -it wp-dev bash 640 | 641 | # Install WP-CLI (if not already installed) 642 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 643 | chmod +x wp-cli.phar 644 | mv wp-cli.phar /usr/local/bin/wp 645 | 646 | # Create pages 647 | wp post create --post_type=page --post_title='Home' --post_status=publish 648 | wp post create --post_type=page --post_title='About Us' --post_status=publish 649 | wp post create --post_type=page --post_title='Services' --post_status=publish 650 | wp post create --post_type=page --post_title='Contact' --post_status=publish 651 | wp post create --post_type=page --post_title='Blog' --post_status=publish 652 | 653 | # Set static homepage 654 | wp option update page_on_front 2 # Use page ID 655 | wp option update show_on_front page 656 | wp option update page_for_posts 5 # Blog page ID 657 | 658 | # Create menu 659 | wp menu create "Main Menu" 660 | wp menu location assign main-menu primary 661 | wp menu item add-post main-menu 2 # Add pages to menu 662 | wp menu item add-post main-menu 3 663 | wp menu item add-post main-menu 4 664 | 665 | # Install popular plugins 666 | wp plugin install contact-form-7 --activate 667 | wp plugin install wordpress-seo --activate 668 | wp plugin install elementor --activate 669 | wp plugin install woocommerce --activate 670 | wp plugin install updraftplus --activate 671 | 672 | # Create users 673 | wp user create john john@example.com --role=editor --user_pass=password123 674 | wp user create jane jane@example.com --role=author --user_pass=password123 675 | 676 | # Update site options 677 | wp option update blogname "My Awesome Site" 678 | wp option update blogdescription "A WordPress site built with Claude Code Wizard" 679 | wp option update timezone_string "America/New_York" 680 | 681 | # Set permalinks 682 | wp rewrite structure '/%postname%/' 683 | wp rewrite flush 684 | ``` 685 | 686 | ### Custom Post Types 687 | 688 | The included plugin already creates Portfolio and Testimonial post types. To add 689 | more: 690 | 691 | ```php 692 | // Add to wp-content/plugins/custom-post-types/custom-post-types.php 693 | 694 | public function register_team_post_type() { 695 | $args = array( 696 | 'labels' => array( 697 | 'name' => 'Team Members', 698 | 'singular_name' => 'Team Member', 699 | ), 700 | 'public' => true, 701 | 'has_archive' => true, 702 | 'supports' => array('title', 'editor', 'thumbnail'), 703 | 'menu_icon' => 'dashicons-groups', 704 | 'show_in_rest' => true, 705 | ); 706 | register_post_type('team', $args); 707 | } 708 | // Add to __construct(): add_action('init', array($this, 709 | 'register_team_post_type')); 710 | ``` 711 | 712 | ### Advanced Theme Features 713 | 714 | ```php 715 | // Add to functions.php 716 | 717 | // Custom image sizes 718 | add_theme_support('post-thumbnails'); 719 | add_image_size('hero', 1920, 600, true); 720 | add_image_size('team-member', 400, 400, true); 721 | 722 | // Widget areas 723 | function my_widgets_init() { 724 | register_sidebar(array( 725 | 'name' => 'Homepage Widgets', 726 | 'id' => 'homepage-widgets', 727 | 'before_widget' => '
', 728 | 'after_widget' => '
', 729 | )); 730 | } 731 | add_action('widgets_init', 'my_widgets_init'); 732 | 733 | // Custom logo support 734 | add_theme_support('custom-logo', array( 735 | 'height' => 100, 736 | 'width' => 400, 737 | 'flex-height' => true, 738 | 'flex-width' => true, 739 | )); 740 | 741 | // Gutenberg support 742 | add_theme_support('align-wide'); 743 | add_theme_support('editor-styles'); 744 | add_theme_support('wp-block-styles'); 745 | ``` 746 | 747 | ## 🔧 Troubleshooting Commands 748 | 749 | ```bash 750 | # Check if Docker containers are running 751 | docker ps | grep wp- 752 | 753 | # View Docker logs 754 | docker-compose logs wordpress 755 | 756 | # Restart containers 757 | docker-compose restart 758 | 759 | # Access MySQL directly 760 | docker exec -it wp-mysql mysql -u wordpress -pwordpress_password wordpress 761 | 762 | # Check droplet status 763 | cat .droplet_info | python3 -m json.tool 764 | 765 | # SSH to droplet 766 | ssh -i ~/.ssh/wordpress_deploy root@$(cat .droplet_info | python3 -c "import 767 | json,sys; print(json.load(sys.stdin)['ip_address'])") 768 | 769 | # View WordPress error logs on droplet 770 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "tail -f /var/log/apache2/error.log" 771 | 772 | # Check cloud-init status 773 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "cloud-init status" 774 | 775 | # Delete droplet (cleanup) 776 | python3 -c " 777 | import requests, json, os 778 | api_token = os.getenv('DO_API_TOKEN') 779 | with open('.droplet_info') as f: 780 | droplet_id = json.load(f)['droplet_id'] 781 | headers = {'Authorization': f'Bearer {api_token}'} 782 | response = 783 | requests.delete(f'https://api.digitalocean.com/v2/droplets/{droplet_id}', 784 | headers=headers) 785 | print('Droplet deleted' if response.status_code == 204 else 'Failed') 786 | " 787 | ``` 788 | 789 | ### 🚨 Fixing 404 Errors on Pages 790 | 791 | If you encounter 404 errors on pages after deployment, the scripts now handle this 792 | automatically. However, if you still have issues: 793 | 794 | ```bash 795 | # SSH to droplet 796 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP 797 | 798 | # Check if permalinks are set correctly 799 | wp --allow-root rewrite structure 800 | 801 | # Manually set permalinks and flush 802 | wp --allow-root rewrite structure '/%postname%/' 803 | wp --allow-root rewrite flush 804 | 805 | # Verify Apache configuration 806 | cat /etc/apache2/sites-enabled/wordpress.conf 807 | # Should show: AllowOverride All 808 | 809 | # Check .htaccess exists and is correct 810 | cat /var/www/html/.htaccess 811 | 812 | # Restart Apache 813 | systemctl restart apache2 814 | ``` 815 | 816 | **Note:** The deployment scripts now automatically: 817 | - Install WP-CLI on the server 818 | - Configure Apache with AllowOverride All 819 | - Set permalinks to /%postname%/ 820 | - Create proper .htaccess file 821 | - Flush rewrite rules after migration 822 | 823 | ## 📊 Production Deployment Checklist 824 | 825 | Before deploying to production: 826 | 827 | 1. ✅ Update passwords in wp-config.php 828 | 2. ✅ Set WP_DEBUG to false 829 | 3. ✅ Update salts (automatic during migration) 830 | 4. ✅ Install SSL certificate (certbot --apache) 831 | 5. ✅ Configure domain DNS 832 | 6. ✅ Enable firewall (ufw) 833 | 7. ✅ Set up backups 834 | 8. ✅ Configure email settings 835 | 836 | ## 🎯 Complete Workflow Summary 837 | 838 | 1. **Clone repo** → Get complete WordPress development environment 839 | 2. **Docker up** → Local WordPress running instantly 840 | 3. **Develop** → Theme, plugins, content - everything 841 | 4. **Setup SSH** → One-time automated key configuration 842 | 5. **Create droplet** → Automated via API with WordPress installation 843 | 6. **Migrate** → Transfer everything to production 844 | 7. **Point domain** → Update DNS A record 845 | 8. **SSL** → Run certbot for HTTPS 846 | 9. **Live** → Production WordPress site running! 847 | 848 | ## 💡 Key Features This Provides 849 | 850 | - **Zero DevOps knowledge required** - Just need DO API token 851 | - **Perfect environment parity** - Docker matches production exactly 852 | - **Complete WordPress control** - Full admin access, all features 853 | - **Real VPS** - Not shared hosting, full server control 854 | - **One-command deployment** - Actually automated, not marketing speak 855 | - **Cost effective** - $6/month for production site 856 | - **No vendor lock-in** - Standard WordPress on standard Ubuntu 857 | - **Version controlled** - Everything in Git 858 | - **Instant local development** - Changes visible immediately 859 | - **Professional workflow** - Local → Staging → Production capable 860 | 861 | ## 🚨 Important Notes 862 | 863 | - Always test locally before deploying 864 | - Keep backups of production database 865 | - Use strong passwords in production 866 | - Update WordPress, themes, and plugins regularly 867 | - Monitor server resources on Digital Ocean 868 | - The migration script replaces the entire WordPress installation 869 | - Custom plugins/themes in wp-content are preserved 870 | - Database is completely replaced with local version 871 | 872 | ## 🔄 Updating Production Site 873 | 874 | To update your production site after local changes: 875 | 876 | ```bash 877 | # Make changes locally 878 | # Test everything at http://localhost 879 | 880 | # Re-run migration to update production 881 | ./migrate_now.sh 882 | 883 | # Your production site is now updated with all local changes 884 | ``` 885 | 886 | This is a complete local-to-production WordPress development and deployment 887 | pipeline that doesn't exist anywhere else in this form! -------------------------------------------------------------------------------- /.codex/AGENTS.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | # WordPress Claude Code Wizard - Complete Workflow & Development Guide 8 | 9 | ## 🚨 MANDATORY: ONE-SHOT COMPLETE EXECUTION 10 | 11 | **YOU MUST COMPLETE THE ENTIRE WORKFLOW IN ONE SHOT. DO NOT STOP PARTWAY.** 12 | **DO NOT deliver partial work. DO NOT stop after Phase 1. DO NOT skip steps.** 13 | **COMPLETE MEANS: Research → Build Website → Test with Playwright → Fix ALL issues → DONE** 14 | **The website must be FULLY FUNCTIONAL at http://localhost before you stop.** 15 | 16 | **DO NOT REPORT BACK TO THE USER OR ASK THEM ANYTHING UNTIL YOU HAVE:** 17 | - A fully built website running at http://localhost 18 | - All directory entries created and populated 19 | - All taxonomy pages working 20 | - Navigation menus fully populated 21 | - ZERO 404 errors verified by Playwright 22 | - Ready to run ./migrate_now.sh 23 | 24 | **The user hired you to BUILD A WEBSITE, not to show research or ask questions.** 25 | 26 | ## ⚠️ CRITICAL REQUIREMENT: ZERO 404 ERRORS 27 | 28 | **EVERY website you build MUST have ZERO 404 errors. Use Playwright MCP to verify EVERY SINGLE link.** 29 | **Headers and footers ALWAYS have broken links if you don't check them systematically.** 30 | **Do not deliver a website until Playwright confirms every link works.** 31 | 32 | ## 🎯 Main Workflow Process - COMPLETE ALL PHASES 33 | 34 | When building a directory website, you MUST complete ALL phases in one continuous workflow: 35 | 36 | ### Phase 1: Deep Research & Comprehensive Data Collection 37 | 38 | **GOAL: Create pages so information-rich that visitors never need to leave your site** 39 | 40 | 1. **Research each individual entry exhaustively using Jina AI** 41 | - Scrape the company's main website completely 42 | - Find and scrape their pricing pages, feature lists, documentation 43 | - Search for reviews, comparisons, alternatives 44 | - Gather technical specifications, integrations, use cases 45 | - Find case studies, success stories, testimonials 46 | - Collect founder information, company history, funding details 47 | - Get support options, contact methods, social media links 48 | - Retry any failed scrapes until you have EVERYTHING 49 | 50 | 2. **Build massive JSON datasets for each entry** 51 | Each individual page JSON should contain: 52 | ```json 53 | { 54 | "basics": { 55 | "name", "tagline", "description" (500+ words), 56 | "founded", "headquarters", "employees", "funding" 57 | }, 58 | "detailed_features": [ 59 | {"name", "description" (100+ words), "category", "importance"} 60 | ], 61 | "pricing": { 62 | "model", "free_tier", "starter_price", "tiers": [ 63 | {"name", "price", "features" (20+), "limits", "best_for"} 64 | ] 65 | }, 66 | "use_cases": [ 67 | {"title", "description" (200+ words), "industry", "company_size"} 68 | ], 69 | "pros_cons": { 70 | "pros": [{"title", "explanation" (50+ words)}], 71 | "cons": [{"title", "explanation" (50+ words)}] 72 | }, 73 | "integrations": [ 74 | {"name", "type", "description", "documentation_url"} 75 | ], 76 | "alternatives": [ 77 | {"name", "comparison" (100+ words), "when_to_choose"} 78 | ], 79 | "reviews": { 80 | "average_rating", "total_reviews", 81 | "rating_breakdown": {"5": %, "4": %, "3": %, "2": %, "1": %}, 82 | "expert_reviews": [{"source", "rating", "summary" (200+ words)}] 83 | }, 84 | "technical_specs": { 85 | "platforms", "languages", "api", "security", "compliance" 86 | }, 87 | "support": { 88 | "channels", "response_time", "documentation_quality", "community" 89 | }, 90 | "media": { 91 | "logo", "screenshots" (10+), "videos", "diagrams" 92 | } 93 | } 94 | ``` 95 | 96 | 3. **Create comprehensive taxonomy archive pages** 97 | 98 | **For Category/Type taxonomy pages (e.g., /categories/crm-software/, /types/italian-restaurants/, /specialties/anxiety-therapy/):** 99 | - Comprehensive overview of the category (1000+ words) 100 | - Complete buyer's/selection guide 101 | - Key features to look for 102 | - Common use cases and who needs this 103 | - Price range analysis and what affects cost 104 | - Industry trends and future outlook 105 | - Comparison methodology explanation 106 | - Top 10-20 entries with detailed previews 107 | - Quick comparison table 108 | - 20-30 FAQs about this category 109 | - Related categories and how they differ 110 | - Expert opinions and industry insights 111 | - Glossary of category-specific terms 112 | - Statistics and market data 113 | - ALL entries in this category listed below with rich cards 114 | 115 | **For Location pages (e.g., /locations/new-york/):** 116 | - Complete local market analysis (1000+ words) 117 | - Local regulations and requirements 118 | - Average prices in this area vs national 119 | - Transportation and parking information 120 | - Neighborhood-by-neighborhood breakdown 121 | - Local insurance providers accepted 122 | - Emergency services in the area 123 | - Community resources and support groups 124 | - Local statistics and demographics 125 | - ALL providers in this location with detailed cards 126 | - Nearby locations for comparison 127 | - Local events and workshops 128 | 129 | **For Combined taxonomy pages (e.g., /crm-software-for-startups/, /italian-restaurants-manhattan/, /anxiety-therapists-new-york/):** 130 | - Everything from both individual taxonomies combined 131 | - Specific local/niche context 132 | - Why this combination matters (e.g., "Why startups need different CRM") 133 | - Unique considerations for this intersection 134 | - Price analysis for this specific combination 135 | - Top 10 detailed comparisons with scoring methodology 136 | - Map visualization (if location-based) 137 | - Availability/wait times analysis 138 | - Quick filter and sort options 139 | - ALL matching entries with rich information cards 140 | 141 | 4. **Collect extensive imagery** 142 | - Product screenshots (10+ per entry) 143 | - Logo variations 144 | - Feature demonstration images 145 | - Comparison charts and infographics 146 | - Industry-relevant stock photos from Unsplash 147 | - Create custom diagrams where needed 148 | 149 | ### Phase 2: Website Development (THIS IS NOT OPTIONAL - YOU MUST BUILD THE WEBSITE) 150 | 151 | **DO NOT STOP AFTER RESEARCH. BUILD THE ACTUAL WEBSITE NOW.** 152 | 153 | 1. **Start with local WordPress Docker environment** 154 | - Run `docker-compose up -d` 155 | - Access at http://localhost 156 | 157 | 2. **Build the custom theme with FULL SEO optimization** 158 | - Create detailed, complex CSS (not simple/short) 159 | - Modern, clean, modular design 160 | - Implement all directory pages from JSON data 161 | - Add comprehensive animations and interactions 162 | - Ensure responsive design with multiple breakpoints 163 | 164 | 3. **Generate ALL ranking pages with maximized SEO** 165 | - Create "Best X in Y" pages for every location/category combination - THIS IS ESSENTIAL ON LOCATION PAGES 166 | - Maximize meta titles (60 chars) for each page - use words like Best X in Y or something else to help rank for those keywords 167 | - Maximize meta descriptions (160 chars) for each page 168 | - Create unique, comprehensive H1 titles 169 | - Write detailed, SEO-optimized descriptions for every page 170 | - Build internal linking structure between related pages 171 | 172 | 4. **Create 5-7 horizontal template variations** 173 | - Grid layout with filters 174 | - Card-based design with hover effects 175 | - List view with detailed information 176 | - Comparison table layout 177 | - Map-based directory view 178 | - Featured/spotlight layout 179 | - Masonry/Pinterest style layout 180 | 181 | 5. **Build mega header navigation** 182 | - Multi-level dropdown menus 183 | - Search functionality 184 | - Category quick links 185 | - Location selector 186 | - Sticky header on scroll 187 | - Mobile-optimized hamburger menu 188 | 189 | 6. **Implement review system (not basic comments)** 190 | - Custom review form for each directory entry 191 | - Frame as "Leave a Review" for product/service 192 | - Star rating system 193 | - Review categories (quality, service, value, etc.) 194 | - Review moderation queue 195 | - Display average ratings 196 | - Sort reviews by helpful/recent/rating 197 | 198 | 7. **Add contact form** 199 | - Professional contact form with validation 200 | - Multiple contact reasons dropdown 201 | - File upload capability 202 | - Anti-spam measures 203 | - Email notification system 204 | 205 | 8. **Import directory data from JSON** 206 | - Create custom post types for directory entries 207 | - Import JSON data into WordPress 208 | - Set up taxonomy/category structure 209 | - Generate all location/category pages automatically 210 | 211 | 9. **Test thoroughly locally** 212 | - Check all pages and permalinks 213 | - Verify images load correctly 214 | - Test responsive design 215 | - Validate all SEO elements 216 | - Test review submission 217 | - Test contact form 218 | 219 | ### Phase 2.5: MANDATORY Playwright Verification - CHECK EVERY SINGLE LINK 220 | 221 | **⛔ STOP! DO NOT SKIP THIS! YOU MUST CHECK EVERY SINGLE LINK WITH PLAYWRIGHT!** 222 | 223 | **THE WEBSITE IS NOT COMPLETE UNTIL PLAYWRIGHT VERIFIES ZERO 404s** 224 | 225 | Use the pre-configured Playwright MCP to verify EVERY link works. Do not just check "a few" links. 226 | Do not just check "some" pages. CHECK THEM ALL. The header and footer ALWAYS have broken links 227 | if you don't verify them properly! 228 | 229 | 1. **MANDATORY: Extract and Test EVERY Header Link** 230 | ``` 231 | Use playwright mcp to: 232 | 1. Navigate to http://localhost 233 | 2. Extract ALL href attributes from the header navigation 234 | 3. Create a list of EVERY SINGLE link found 235 | 4. Visit EACH link one by one 236 | 5. Verify EACH loads without 404 237 | 6. If ANY link returns 404, FIX IT IMMEDIATELY 238 | 239 | Example: If header has Home, About, Services, Blog, Contact, Categories dropdown with 240 | 10 categories, Location dropdown with 20 locations - that's 35 links to check. 241 | CHECK ALL 35. Not 5. Not 10. ALL 35. 242 | ``` 243 | 244 | 2. **MANDATORY: Extract and Test EVERY Footer Link** 245 | ``` 246 | Use playwright mcp to: 247 | 1. Scroll to footer 248 | 2. Extract ALL href attributes from the footer 249 | 3. Visit EVERY SINGLE footer link 250 | 4. Do not assume they work - TEST THEM 251 | 5. Common broken footer links: Privacy Policy, Terms, Sitemap 252 | 6. CREATE these pages if they don't exist 253 | ``` 254 | 255 | 3. **MANDATORY: Test EVERY Directory Entry** 256 | ``` 257 | DO NOT test "a few examples" - test EVERY SINGLE ONE: 258 | - Get the full list of all directory entries 259 | - Visit each one: /companies/company-1/, /companies/company-2/, etc. 260 | - If you have 50 entries, test all 50 261 | - Each must load with proper content, not 404 262 | ``` 263 | 264 | 4. **MANDATORY: Test EVERY Taxonomy Page** 265 | ``` 266 | Test EVERY SINGLE taxonomy page that should exist: 267 | - EVERY category: /categories/[slug]/ for each category 268 | - EVERY location: /locations/[slug]/ for each location 269 | - EVERY tag: /tags/[slug]/ for each tag 270 | - EVERY combination page if they exist 271 | - Do not test "some" - test EVERY SINGLE ONE 272 | ``` 273 | 274 | 5. **MANDATORY: Systematic Link Extraction and Testing** 275 | ``` 276 | Use playwright mcp to run this systematic check: 277 | 278 | // Extract ALL links from the site 279 | const allLinks = await page.evaluate(() => { 280 | return Array.from(document.querySelectorAll('a[href]')) 281 | .map(a => a.href) 282 | .filter(href => href.startsWith('http://localhost')); 283 | }); 284 | 285 | // Test EVERY SINGLE link 286 | for (const link of allLinks) { 287 | await page.goto(link); 288 | // Check for 404 or error 289 | // Log any broken links 290 | } 291 | 292 | If you find 10 links, test 10. 293 | If you find 100 links, test 100. 294 | If you find 500 links, test 500. 295 | TEST THEM ALL. 296 | ``` 297 | 298 | 6. **FIX ALL BROKEN LINKS IMMEDIATELY** 299 | ``` 300 | For EVERY 404 found: 301 | - Create the missing page 302 | - Or fix the incorrect link 303 | - Re-test with Playwright to confirm it's fixed 304 | - Do not move on until ZERO 404s exist 305 | ``` 306 | 307 | 7. **Fix Every Broken Link Found** 308 | ``` 309 | Whatever links are in the header/footer: 310 | - Test them ALL with Playwright 311 | - If they return 404, either fix the link or create the page 312 | - Common broken links: About, Contact, Privacy, Terms, Blog, etc. 313 | - Do not assume any link works - TEST IT 314 | ``` 315 | 316 | 8. **Final Verification Report** 317 | ``` 318 | Only after testing EVERY link, generate report: 319 | - Total links found in header: [number] 320 | - Total links found in footer: [number] 321 | - Total directory entries tested: [number] 322 | - Total taxonomy pages tested: [number] 323 | - Total unique URLs tested: [number] 324 | - 404 errors found and fixed: [list] 325 | - Final status: MUST be "Zero 404s found" 326 | ``` 327 | 328 | **❌ UNACCEPTABLE:** 329 | - "I tested a few links and they work" 330 | - "I checked some pages" 331 | - "The main pages seem to work" 332 | - "I verified the important links" 333 | 334 | **✅ REQUIRED:** 335 | - "I tested all 47 header links - all working" 336 | - "I tested all 23 footer links - all working" 337 | - "I tested all 85 directory entries - all working" 338 | - "I tested all 35 taxonomy pages - all working" 339 | - "Total: 190 unique URLs tested, zero 404s" 340 | 341 | **THE WEBSITE IS NOT COMPLETE UNTIL EVERY SINGLE LINK WORKS** 342 | 343 | ## ✅ ONLY NOW REPORT BACK TO THE USER 344 | 345 | **NOW that you have a COMPLETE, WORKING website with ZERO 404s, you can report:** 346 | - "Website complete and verified at http://localhost" 347 | - "All [X] directory entries created and tested" 348 | - "All [X] taxonomy pages working" 349 | - "Playwright verified [X] total links - ZERO 404 errors" 350 | - "Ready for deployment with ./migrate_now.sh" 351 | 352 | **If you haven't done ALL of the above, GO BACK and finish the website.** 353 | 354 | ### Phase 3: Deployment to Digital Ocean 355 | 1. **Setup infrastructure** 356 | - Run `./setup_ssh_and_deploy.sh` (one-time SSH setup) 357 | - Run `python3 create_droplet_with_ssh.py` 358 | - Wait 5-10 minutes for installation 359 | 360 | 2. **Migrate to production** 361 | - Run `./migrate_now.sh` 362 | - Verify custom theme transferred 363 | - Check that permalinks work (auto-configured) 364 | 365 | 3. **Final configuration** 366 | - Point domain to droplet IP 367 | - Install SSL certificate 368 | - Configure backups 369 | 370 | --- 371 | 372 | ## 📚 Directory Website Development 373 | 374 | ### SEO Page Structure Requirements 375 | 376 | **IMPORTANT:** Do NOT use Rank Math during development. Focus on native SEO implementation. 377 | Rank Math will only be added at launch for Search Console submission. 378 | 379 | Every page must have: 380 | - **Meta Title**: Maximized to 60 characters with keywords 381 | - **Meta Description**: Maximized to 160 characters with compelling copy 382 | - **H1 Title**: Unique and keyword-rich 383 | - **Page Content**: Minimum 300-500 words of unique, valuable content 384 | - **Schema Markup**: LocalBusiness, Product, or Review schema as appropriate 385 | - **Open Graph tags**: For social sharing 386 | - **Internal Links**: 3-5 contextual links to related pages 387 | 388 | Generate these page types for maximum ranking potential: 389 | - "Best [Product] in [City]" - for every city 390 | - "Top 10 [Category] in [State]" - for every state 391 | - "[Product] near me" - location-based pages 392 | - "[Category] Reviews [Year]" - fresh content pages 393 | - "Compare [Product A] vs [Product B]" - comparison pages 394 | - "[Product] for [Use Case]" - intent-based pages 395 | - "Cheap/Affordable [Product] in [Location]" - price-focused pages 396 | 397 | ### Review System Framework 398 | 399 | Frame reviews contextually based on the directory type: 400 | - For restaurants: "[Cuisine] lovers who dined at [Restaurant] can leave a review" 401 | - For products: "[Product] users who tried [Brand] can share their experience" 402 | - For services: "Customers who used [Service] from [Company] can rate their experience" 403 | - For venues: "Visitors who went to [Venue] can share their thoughts" 404 | 405 | Review form should include: 406 | - Overall star rating (1-5 stars) 407 | - Category-specific ratings (e.g., Quality, Service, Value, Location) 408 | - Written review with minimum 50 characters 409 | - Photo upload option 410 | - "Would you recommend?" Yes/No 411 | - Verified purchase/visit checkbox 412 | - Helpful/Not Helpful voting on other reviews 413 | 414 | ### Research Phase with Jina AI 415 | 416 | When building directory websites, use Jina AI for comprehensive research: 417 | 418 | ```bash 419 | # Search for information (use s.jina.ai) 420 | curl "https://s.jina.ai/?q=YOUR_SEARCH_TERM" \ 421 | -H "Authorization: Bearer $JINA_API_KEY" 422 | 423 | # Scrape individual pages (use r.jina.ai) 424 | curl "https://r.jina.ai/https://example.com/page" \ 425 | -H "Authorization: Bearer $JINA_API_KEY" 426 | ``` 427 | 428 | **Important Research Guidelines:** 429 | - Create detailed JSON for each directory page 430 | - If a page 404s or doesn't scrape properly, retry the scrape 431 | - DO NOT use Jina to scrape CSS from design sites 432 | 433 | ### Finding Royalty-Free Images 434 | 435 | ```bash 436 | # Search for Unsplash images using Jina 437 | curl "https://s.jina.ai/?q=YOUR_IMAGE_DESCRIPTION+unsplash" \ 438 | -H "Authorization: Bearer $JINA_API_KEY" 439 | 440 | # Then scrape the found Unsplash pages for non-premium images 441 | curl "https://r.jina.ai/https://unsplash.com/photos/..." \ 442 | -H "Authorization: Bearer $JINA_API_KEY" 443 | ``` 444 | 445 | ### Directory Page JSON Format 446 | 447 | Each directory entry should have comprehensive data: 448 | 449 | ```json 450 | { 451 | "id": "unique-identifier", 452 | "name": "Company/Service Name", 453 | "category": "Technology Category", 454 | "description": "Detailed description...", 455 | "features": ["feature1", "feature2", "..."], 456 | "pricing": { 457 | "model": "subscription/one-time/freemium", 458 | "tiers": [...] 459 | }, 460 | "images": { 461 | "logo": "url-from-unsplash", 462 | "screenshots": ["url1", "url2"], 463 | "hero": "hero-image-url" 464 | }, 465 | "metadata": { 466 | "founded": "year", 467 | "headquarters": "location", 468 | "employees": "range", 469 | "funding": "amount" 470 | }, 471 | "links": { 472 | "website": "url", 473 | "documentation": "url", 474 | "pricing": "url" 475 | }, 476 | "tags": ["tag1", "tag2"], 477 | "lastUpdated": "timestamp" 478 | } 479 | ``` 480 | 481 | ### CSS Development Guidelines 482 | 483 | **IMPORTANT:** Create extremely detailed and complex CSS files that are well-thought-out: 484 | 485 | - Don't write short, simple CSS - make it comprehensive 486 | - Include detailed animations and transitions 487 | - Add hover states, focus states, and active states 488 | - Create responsive breakpoints for all screen sizes 489 | - Include print styles and accessibility features 490 | - Use CSS custom properties for theming 491 | - Add detailed comments explaining complex sections 492 | - Implement sophisticated grid and flexbox layouts 493 | - Include fallbacks for older browsers 494 | 495 | Example of detailed CSS approach: 496 | ```css 497 | /* Component: Directory Card 498 | Purpose: Display individual directory entries 499 | States: default, hover, active, disabled, loading 500 | Breakpoints: mobile-first approach with 5 breakpoints 501 | Accessibility: WCAG 2.1 AA compliant */ 502 | 503 | .directory-card { 504 | /* Base styles with extensive properties */ 505 | /* Multiple transition effects */ 506 | /* Complex shadow systems */ 507 | /* Detailed spacing scales */ 508 | } 509 | ``` 510 | 511 | ## 🚀 Quick Deploy Workflow 512 | 513 | When a user clones this repository and wants to deploy WordPress to Digital Ocean, 514 | execute these commands in order: 515 | 516 | ```bash 517 | # 1. Setup environment 518 | cp .env.example .env 519 | # User must edit .env and add DO_API_TOKEN and JINA_API_KEY 520 | 521 | # 2. Install Python dependencies 522 | pip3 install python-dotenv requests 523 | 524 | # 3. Start local WordPress 525 | docker-compose up -d 526 | 527 | # 4. Setup SSH keys (one-time) 528 | ./setup_ssh_and_deploy.sh 529 | 530 | # 5. Create Digital Ocean droplet 531 | python3 create_droplet_with_ssh.py 532 | 533 | # 6. Wait for installation (5-10 minutes) 534 | sleep 300 535 | 536 | # 7. Migrate local WordPress to droplet 537 | ./migrate_now.sh 538 | ``` 539 | 540 | ## 📁 Project Structure 541 | 542 | ``` 543 | wordpress-claude-code-wizard/ 544 | ├── .env # DO_API_TOKEN goes here 545 | ├── docker-compose.yml # Local WordPress environment 546 | ├── Dockerfile # Custom Apache/PHP image 547 | ├── wp-config.php # Environment-aware configuration 548 | ├── setup_ssh_and_deploy.sh # SSH key automation 549 | ├── create_droplet_with_ssh.py # Droplet creation script 550 | ├── migrate_now.sh # Migration script 551 | └── wp-content/ 552 | ├── themes/ 553 | │ └── my-custom-theme/ # Starter theme 554 | └── plugins/ 555 | └── custom-post-types/ # CPT plugin 556 | ``` 557 | 558 | ## 🎨 WordPress Development Guide 559 | 560 | ### Theme Development 561 | 562 | Users can modify the custom theme in `wp-content/themes/my-custom-theme/`: 563 | 564 | ```bash 565 | # Create new page template 566 | cat > wp-content/themes/my-custom-theme/page-about.php << 'EOF' 567 | 571 |
572 |
573 |

574 | 575 |
576 |
577 | 578 | EOF 579 | 580 | # Create custom single post template 581 | cat > wp-content/themes/my-custom-theme/single.php << 'EOF' 582 | 583 |
584 |
585 |

586 |
Posted on
587 | 588 |
589 |
590 | 591 | EOF 592 | 593 | # Create archive template 594 | cat > wp-content/themes/my-custom-theme/archive.php << 'EOF' 595 | 596 |
597 |

598 | 599 |
600 |

601 | 602 |
603 | 604 |
605 | 606 | EOF 607 | ``` 608 | 609 | ### Adding Navigation Menus 610 | 611 | Add to `wp-content/themes/my-custom-theme/functions.php`: 612 | 613 | ```php 614 | // Register multiple menu locations 615 | register_nav_menus(array( 616 | 'primary' => __('Primary Menu', 'my-custom-theme'), 617 | 'footer' => __('Footer Menu', 'my-custom-theme'), 618 | 'social' => __('Social Links Menu', 'my-custom-theme'), 619 | )); 620 | 621 | // Add menu support 622 | add_theme_support('menus'); 623 | ``` 624 | 625 | Display menus in theme templates: 626 | 627 | ```php 628 | // In header.php 629 | 'primary')); ?> 630 | 631 | // In footer.php 632 | 'footer')); ?> 633 | ``` 634 | 635 | ### WP-CLI Commands (Inside Docker Container) 636 | 637 | ```bash 638 | # Access the WordPress container 639 | docker exec -it wp-dev bash 640 | 641 | # Install WP-CLI (if not already installed) 642 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 643 | chmod +x wp-cli.phar 644 | mv wp-cli.phar /usr/local/bin/wp 645 | 646 | # Create pages 647 | wp post create --post_type=page --post_title='Home' --post_status=publish 648 | wp post create --post_type=page --post_title='About Us' --post_status=publish 649 | wp post create --post_type=page --post_title='Services' --post_status=publish 650 | wp post create --post_type=page --post_title='Contact' --post_status=publish 651 | wp post create --post_type=page --post_title='Blog' --post_status=publish 652 | 653 | # Set static homepage 654 | wp option update page_on_front 2 # Use page ID 655 | wp option update show_on_front page 656 | wp option update page_for_posts 5 # Blog page ID 657 | 658 | # Create menu 659 | wp menu create "Main Menu" 660 | wp menu location assign main-menu primary 661 | wp menu item add-post main-menu 2 # Add pages to menu 662 | wp menu item add-post main-menu 3 663 | wp menu item add-post main-menu 4 664 | 665 | # Install popular plugins 666 | wp plugin install contact-form-7 --activate 667 | wp plugin install wordpress-seo --activate 668 | wp plugin install elementor --activate 669 | wp plugin install woocommerce --activate 670 | wp plugin install updraftplus --activate 671 | 672 | # Create users 673 | wp user create john john@example.com --role=editor --user_pass=password123 674 | wp user create jane jane@example.com --role=author --user_pass=password123 675 | 676 | # Update site options 677 | wp option update blogname "My Awesome Site" 678 | wp option update blogdescription "A WordPress site built with Claude Code Wizard" 679 | wp option update timezone_string "America/New_York" 680 | 681 | # Set permalinks 682 | wp rewrite structure '/%postname%/' 683 | wp rewrite flush 684 | ``` 685 | 686 | ### Custom Post Types 687 | 688 | The included plugin already creates Portfolio and Testimonial post types. To add 689 | more: 690 | 691 | ```php 692 | // Add to wp-content/plugins/custom-post-types/custom-post-types.php 693 | 694 | public function register_team_post_type() { 695 | $args = array( 696 | 'labels' => array( 697 | 'name' => 'Team Members', 698 | 'singular_name' => 'Team Member', 699 | ), 700 | 'public' => true, 701 | 'has_archive' => true, 702 | 'supports' => array('title', 'editor', 'thumbnail'), 703 | 'menu_icon' => 'dashicons-groups', 704 | 'show_in_rest' => true, 705 | ); 706 | register_post_type('team', $args); 707 | } 708 | // Add to __construct(): add_action('init', array($this, 709 | 'register_team_post_type')); 710 | ``` 711 | 712 | ### Advanced Theme Features 713 | 714 | ```php 715 | // Add to functions.php 716 | 717 | // Custom image sizes 718 | add_theme_support('post-thumbnails'); 719 | add_image_size('hero', 1920, 600, true); 720 | add_image_size('team-member', 400, 400, true); 721 | 722 | // Widget areas 723 | function my_widgets_init() { 724 | register_sidebar(array( 725 | 'name' => 'Homepage Widgets', 726 | 'id' => 'homepage-widgets', 727 | 'before_widget' => '
', 728 | 'after_widget' => '
', 729 | )); 730 | } 731 | add_action('widgets_init', 'my_widgets_init'); 732 | 733 | // Custom logo support 734 | add_theme_support('custom-logo', array( 735 | 'height' => 100, 736 | 'width' => 400, 737 | 'flex-height' => true, 738 | 'flex-width' => true, 739 | )); 740 | 741 | // Gutenberg support 742 | add_theme_support('align-wide'); 743 | add_theme_support('editor-styles'); 744 | add_theme_support('wp-block-styles'); 745 | ``` 746 | 747 | ## 🔧 Troubleshooting Commands 748 | 749 | ```bash 750 | # Check if Docker containers are running 751 | docker ps | grep wp- 752 | 753 | # View Docker logs 754 | docker-compose logs wordpress 755 | 756 | # Restart containers 757 | docker-compose restart 758 | 759 | # Access MySQL directly 760 | docker exec -it wp-mysql mysql -u wordpress -pwordpress_password wordpress 761 | 762 | # Check droplet status 763 | cat .droplet_info | python3 -m json.tool 764 | 765 | # SSH to droplet 766 | ssh -i ~/.ssh/wordpress_deploy root@$(cat .droplet_info | python3 -c "import 767 | json,sys; print(json.load(sys.stdin)['ip_address'])") 768 | 769 | # View WordPress error logs on droplet 770 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "tail -f /var/log/apache2/error.log" 771 | 772 | # Check cloud-init status 773 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "cloud-init status" 774 | 775 | # Delete droplet (cleanup) 776 | python3 -c " 777 | import requests, json, os 778 | api_token = os.getenv('DO_API_TOKEN') 779 | with open('.droplet_info') as f: 780 | droplet_id = json.load(f)['droplet_id'] 781 | headers = {'Authorization': f'Bearer {api_token}'} 782 | response = 783 | requests.delete(f'https://api.digitalocean.com/v2/droplets/{droplet_id}', 784 | headers=headers) 785 | print('Droplet deleted' if response.status_code == 204 else 'Failed') 786 | " 787 | ``` 788 | 789 | ### 🚨 Fixing 404 Errors on Pages 790 | 791 | If you encounter 404 errors on pages after deployment, the scripts now handle this 792 | automatically. However, if you still have issues: 793 | 794 | ```bash 795 | # SSH to droplet 796 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP 797 | 798 | # Check if permalinks are set correctly 799 | wp --allow-root rewrite structure 800 | 801 | # Manually set permalinks and flush 802 | wp --allow-root rewrite structure '/%postname%/' 803 | wp --allow-root rewrite flush 804 | 805 | # Verify Apache configuration 806 | cat /etc/apache2/sites-enabled/wordpress.conf 807 | # Should show: AllowOverride All 808 | 809 | # Check .htaccess exists and is correct 810 | cat /var/www/html/.htaccess 811 | 812 | # Restart Apache 813 | systemctl restart apache2 814 | ``` 815 | 816 | **Note:** The deployment scripts now automatically: 817 | - Install WP-CLI on the server 818 | - Configure Apache with AllowOverride All 819 | - Set permalinks to /%postname%/ 820 | - Create proper .htaccess file 821 | - Flush rewrite rules after migration 822 | 823 | ## 📊 Production Deployment Checklist 824 | 825 | Before deploying to production: 826 | 827 | 1. ✅ Update passwords in wp-config.php 828 | 2. ✅ Set WP_DEBUG to false 829 | 3. ✅ Update salts (automatic during migration) 830 | 4. ✅ Install SSL certificate (certbot --apache) 831 | 5. ✅ Configure domain DNS 832 | 6. ✅ Enable firewall (ufw) 833 | 7. ✅ Set up backups 834 | 8. ✅ Configure email settings 835 | 836 | ## 🎯 Complete Workflow Summary 837 | 838 | 1. **Clone repo** → Get complete WordPress development environment 839 | 2. **Docker up** → Local WordPress running instantly 840 | 3. **Develop** → Theme, plugins, content - everything 841 | 4. **Setup SSH** → One-time automated key configuration 842 | 5. **Create droplet** → Automated via API with WordPress installation 843 | 6. **Migrate** → Transfer everything to production 844 | 7. **Point domain** → Update DNS A record 845 | 8. **SSL** → Run certbot for HTTPS 846 | 9. **Live** → Production WordPress site running! 847 | 848 | ## 💡 Key Features This Provides 849 | 850 | - **Zero DevOps knowledge required** - Just need DO API token 851 | - **Perfect environment parity** - Docker matches production exactly 852 | - **Complete WordPress control** - Full admin access, all features 853 | - **Real VPS** - Not shared hosting, full server control 854 | - **One-command deployment** - Actually automated, not marketing speak 855 | - **Cost effective** - $6/month for production site 856 | - **No vendor lock-in** - Standard WordPress on standard Ubuntu 857 | - **Version controlled** - Everything in Git 858 | - **Instant local development** - Changes visible immediately 859 | - **Professional workflow** - Local → Staging → Production capable 860 | 861 | ## 🚨 Important Notes 862 | 863 | - Always test locally before deploying 864 | - Keep backups of production database 865 | - Use strong passwords in production 866 | - Update WordPress, themes, and plugins regularly 867 | - Monitor server resources on Digital Ocean 868 | - The migration script replaces the entire WordPress installation 869 | - Custom plugins/themes in wp-content are preserved 870 | - Database is completely replaced with local version 871 | 872 | ## 🔄 Updating Production Site 873 | 874 | To update your production site after local changes: 875 | 876 | ```bash 877 | # Make changes locally 878 | # Test everything at http://localhost 879 | 880 | # Re-run migration to update production 881 | ./migrate_now.sh 882 | 883 | # Your production site is now updated with all local changes 884 | ``` 885 | 886 | This is a complete local-to-production WordPress development and deployment 887 | pipeline that doesn't exist anywhere else in this form! -------------------------------------------------------------------------------- /.claude/CLAUDE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | # WordPress Claude Code Wizard - Complete Workflow & Development Guide 8 | 9 | ## 🚨 MANDATORY: ONE-SHOT COMPLETE EXECUTION 10 | 11 | **YOU MUST COMPLETE THE ENTIRE WORKFLOW IN ONE SHOT. DO NOT STOP PARTWAY.** 12 | **DO NOT deliver partial work. DO NOT stop after Phase 1. DO NOT skip steps.** 13 | **COMPLETE MEANS: Research → Build Website → Test with Playwright → Fix ALL issues → DONE** 14 | **The website must be FULLY FUNCTIONAL at http://localhost before you stop.** 15 | 16 | **DO NOT REPORT BACK TO THE USER OR ASK THEM ANYTHING UNTIL YOU HAVE:** 17 | - A fully built website running at http://localhost 18 | - All directory entries created and populated 19 | - All taxonomy pages working 20 | - Navigation menus fully populated 21 | - ZERO 404 errors verified by Playwright 22 | - Ready to run ./migrate_now.sh 23 | 24 | **The user hired you to BUILD A WEBSITE, not to show research or ask questions.** 25 | 26 | ## ⚠️ CRITICAL REQUIREMENT: ZERO 404 ERRORS 27 | 28 | **EVERY website you build MUST have ZERO 404 errors. Use Playwright MCP to verify EVERY SINGLE link.** 29 | **Headers and footers ALWAYS have broken links if you don't check them systematically.** 30 | **Do not deliver a website until Playwright confirms every link works.** 31 | 32 | ## 🎯 Main Workflow Process - COMPLETE ALL PHASES 33 | 34 | When building a directory website, you MUST complete ALL phases in one continuous workflow: 35 | 36 | ### Phase 1: Deep Research & Comprehensive Data Collection 37 | 38 | **GOAL: Create pages so information-rich that visitors never need to leave your site** 39 | 40 | 1. **Research each individual entry exhaustively using Jina AI** 41 | - Scrape the company's main website completely 42 | - Find and scrape their pricing pages, feature lists, documentation 43 | - Search for reviews, comparisons, alternatives 44 | - Gather technical specifications, integrations, use cases 45 | - Find case studies, success stories, testimonials 46 | - Collect founder information, company history, funding details 47 | - Get support options, contact methods, social media links 48 | - Retry any failed scrapes until you have EVERYTHING 49 | 50 | 2. **Build massive JSON datasets for each entry** 51 | Each individual page JSON should contain: 52 | ```json 53 | { 54 | "basics": { 55 | "name", "tagline", "description" (500+ words), 56 | "founded", "headquarters", "employees", "funding" 57 | }, 58 | "detailed_features": [ 59 | {"name", "description" (100+ words), "category", "importance"} 60 | ], 61 | "pricing": { 62 | "model", "free_tier", "starter_price", "tiers": [ 63 | {"name", "price", "features" (20+), "limits", "best_for"} 64 | ] 65 | }, 66 | "use_cases": [ 67 | {"title", "description" (200+ words), "industry", "company_size"} 68 | ], 69 | "pros_cons": { 70 | "pros": [{"title", "explanation" (50+ words)}], 71 | "cons": [{"title", "explanation" (50+ words)}] 72 | }, 73 | "integrations": [ 74 | {"name", "type", "description", "documentation_url"} 75 | ], 76 | "alternatives": [ 77 | {"name", "comparison" (100+ words), "when_to_choose"} 78 | ], 79 | "reviews": { 80 | "average_rating", "total_reviews", 81 | "rating_breakdown": {"5": %, "4": %, "3": %, "2": %, "1": %}, 82 | "expert_reviews": [{"source", "rating", "summary" (200+ words)}] 83 | }, 84 | "technical_specs": { 85 | "platforms", "languages", "api", "security", "compliance" 86 | }, 87 | "support": { 88 | "channels", "response_time", "documentation_quality", "community" 89 | }, 90 | "media": { 91 | "logo", "screenshots" (10+), "videos", "diagrams" 92 | } 93 | } 94 | ``` 95 | 96 | 3. **Create comprehensive taxonomy archive pages** 97 | 98 | **For Category/Type taxonomy pages (e.g., /categories/crm-software/, /types/italian-restaurants/, /specialties/anxiety-therapy/):** 99 | - Comprehensive overview of the category (1000+ words) 100 | - Complete buyer's/selection guide 101 | - Key features to look for 102 | - Common use cases and who needs this 103 | - Price range analysis and what affects cost 104 | - Industry trends and future outlook 105 | - Comparison methodology explanation 106 | - Top 10-20 entries with detailed previews 107 | - Quick comparison table 108 | - 20-30 FAQs about this category 109 | - Related categories and how they differ 110 | - Expert opinions and industry insights 111 | - Glossary of category-specific terms 112 | - Statistics and market data 113 | - ALL entries in this category listed below with rich cards 114 | 115 | **For Location pages (e.g., /locations/new-york/):** 116 | - Complete local market analysis (1000+ words) 117 | - Local regulations and requirements 118 | - Average prices in this area vs national 119 | - Transportation and parking information 120 | - Neighborhood-by-neighborhood breakdown 121 | - Local insurance providers accepted 122 | - Emergency services in the area 123 | - Community resources and support groups 124 | - Local statistics and demographics 125 | - ALL providers in this location with detailed cards 126 | - Nearby locations for comparison 127 | - Local events and workshops 128 | 129 | **For Combined taxonomy pages (e.g., /crm-software-for-startups/, /italian-restaurants-manhattan/, /anxiety-therapists-new-york/):** 130 | - Everything from both individual taxonomies combined 131 | - Specific local/niche context 132 | - Why this combination matters (e.g., "Why startups need different CRM") 133 | - Unique considerations for this intersection 134 | - Price analysis for this specific combination 135 | - Top 10 detailed comparisons with scoring methodology 136 | - Map visualization (if location-based) 137 | - Availability/wait times analysis 138 | - Quick filter and sort options 139 | - ALL matching entries with rich information cards 140 | 141 | 4. **Collect extensive imagery** 142 | - Product screenshots (10+ per entry) 143 | - Logo variations 144 | - Feature demonstration images 145 | - Comparison charts and infographics 146 | - Industry-relevant stock photos from Unsplash 147 | - Create custom diagrams where needed 148 | 149 | ### Phase 2: Website Development (THIS IS NOT OPTIONAL - YOU MUST BUILD THE WEBSITE) 150 | 151 | **DO NOT STOP AFTER RESEARCH. BUILD THE ACTUAL WEBSITE NOW.** 152 | 153 | 1. **Start with local WordPress Docker environment** 154 | - Run `docker-compose up -d` 155 | - Access at http://localhost 156 | 157 | 2. **Build the custom theme with FULL SEO optimization** 158 | - Create detailed, complex CSS (not simple/short) 159 | - Modern, clean, modular design 160 | - Implement all directory pages from JSON data 161 | - Add comprehensive animations and interactions 162 | - Ensure responsive design with multiple breakpoints 163 | 164 | 3. **Generate ALL ranking pages with maximized SEO** 165 | - Create "Best X in Y" pages for every location/category combination - THIS IS ESSENTIAL ON LOCATION PAGES 166 | - Maximize meta titles (60 chars) for each page - use words like Best X in Y or something else to help rank for those keywords 167 | - Maximize meta descriptions (160 chars) for each page 168 | - Create unique, comprehensive H1 titles 169 | - Write detailed, SEO-optimized descriptions for every page 170 | - Build internal linking structure between related pages 171 | 172 | 4. **Create 5-7 horizontal template variations** 173 | - Grid layout with filters 174 | - Card-based design with hover effects 175 | - List view with detailed information 176 | - Comparison table layout 177 | - Map-based directory view 178 | - Featured/spotlight layout 179 | - Masonry/Pinterest style layout 180 | 181 | 5. **Build mega header navigation** 182 | - Multi-level dropdown menus 183 | - Search functionality 184 | - Category quick links 185 | - Location selector 186 | - Sticky header on scroll 187 | - Mobile-optimized hamburger menu 188 | 189 | 6. **Implement review system (not basic comments)** 190 | - Custom review form for each directory entry 191 | - Frame as "Leave a Review" for product/service 192 | - Star rating system 193 | - Review categories (quality, service, value, etc.) 194 | - Review moderation queue 195 | - Display average ratings 196 | - Sort reviews by helpful/recent/rating 197 | 198 | 7. **Add contact form** 199 | - Professional contact form with validation 200 | - Multiple contact reasons dropdown 201 | - File upload capability 202 | - Anti-spam measures 203 | - Email notification system 204 | 205 | 8. **Import directory data from JSON** 206 | - Create custom post types for directory entries 207 | - Import JSON data into WordPress 208 | - Set up taxonomy/category structure 209 | - Generate all location/category pages automatically 210 | 211 | 9. **Test thoroughly locally** 212 | - Check all pages and permalinks 213 | - Verify images load correctly 214 | - Test responsive design 215 | - Validate all SEO elements 216 | - Test review submission 217 | - Test contact form 218 | 219 | ### Phase 2.5: MANDATORY Playwright Verification - CHECK EVERY SINGLE LINK 220 | 221 | **⛔ STOP! DO NOT SKIP THIS! YOU MUST CHECK EVERY SINGLE LINK WITH PLAYWRIGHT!** 222 | 223 | **THE WEBSITE IS NOT COMPLETE UNTIL PLAYWRIGHT VERIFIES ZERO 404s** 224 | 225 | Use the pre-configured Playwright MCP to verify EVERY link works. Do not just check "a few" links. 226 | Do not just check "some" pages. CHECK THEM ALL. The header and footer ALWAYS have broken links 227 | if you don't verify them properly! 228 | 229 | 1. **MANDATORY: Extract and Test EVERY Header Link** 230 | ``` 231 | Use playwright mcp to: 232 | 1. Navigate to http://localhost 233 | 2. Extract ALL href attributes from the header navigation 234 | 3. Create a list of EVERY SINGLE link found 235 | 4. Visit EACH link one by one 236 | 5. Verify EACH loads without 404 237 | 6. If ANY link returns 404, FIX IT IMMEDIATELY 238 | 239 | Example: If header has Home, About, Services, Blog, Contact, Categories dropdown with 240 | 10 categories, Location dropdown with 20 locations - that's 35 links to check. 241 | CHECK ALL 35. Not 5. Not 10. ALL 35. 242 | ``` 243 | 244 | 2. **MANDATORY: Extract and Test EVERY Footer Link** 245 | ``` 246 | Use playwright mcp to: 247 | 1. Scroll to footer 248 | 2. Extract ALL href attributes from the footer 249 | 3. Visit EVERY SINGLE footer link 250 | 4. Do not assume they work - TEST THEM 251 | 5. Common broken footer links: Privacy Policy, Terms, Sitemap 252 | 6. CREATE these pages if they don't exist 253 | ``` 254 | 255 | 3. **MANDATORY: Test EVERY Directory Entry** 256 | ``` 257 | DO NOT test "a few examples" - test EVERY SINGLE ONE: 258 | - Get the full list of all directory entries 259 | - Visit each one: /companies/company-1/, /companies/company-2/, etc. 260 | - If you have 50 entries, test all 50 261 | - Each must load with proper content, not 404 262 | ``` 263 | 264 | 4. **MANDATORY: Test EVERY Taxonomy Page** 265 | ``` 266 | Test EVERY SINGLE taxonomy page that should exist: 267 | - EVERY category: /categories/[slug]/ for each category 268 | - EVERY location: /locations/[slug]/ for each location 269 | - EVERY tag: /tags/[slug]/ for each tag 270 | - EVERY combination page if they exist 271 | - Do not test "some" - test EVERY SINGLE ONE 272 | ``` 273 | 274 | 5. **MANDATORY: Systematic Link Extraction and Testing** 275 | ``` 276 | Use playwright mcp to run this systematic check: 277 | 278 | // Extract ALL links from the site 279 | const allLinks = await page.evaluate(() => { 280 | return Array.from(document.querySelectorAll('a[href]')) 281 | .map(a => a.href) 282 | .filter(href => href.startsWith('http://localhost')); 283 | }); 284 | 285 | // Test EVERY SINGLE link 286 | for (const link of allLinks) { 287 | await page.goto(link); 288 | // Check for 404 or error 289 | // Log any broken links 290 | } 291 | 292 | If you find 10 links, test 10. 293 | If you find 100 links, test 100. 294 | If you find 500 links, test 500. 295 | TEST THEM ALL. 296 | ``` 297 | 298 | 6. **FIX ALL BROKEN LINKS IMMEDIATELY** 299 | ``` 300 | For EVERY 404 found: 301 | - Create the missing page 302 | - Or fix the incorrect link 303 | - Re-test with Playwright to confirm it's fixed 304 | - Do not move on until ZERO 404s exist 305 | ``` 306 | 307 | 7. **Fix Every Broken Link Found** 308 | ``` 309 | Whatever links are in the header/footer: 310 | - Test them ALL with Playwright 311 | - If they return 404, either fix the link or create the page 312 | - Common broken links: About, Contact, Privacy, Terms, Blog, etc. 313 | - Do not assume any link works - TEST IT 314 | ``` 315 | 316 | 8. **Final Verification Report** 317 | ``` 318 | Only after testing EVERY link, generate report: 319 | - Total links found in header: [number] 320 | - Total links found in footer: [number] 321 | - Total directory entries tested: [number] 322 | - Total taxonomy pages tested: [number] 323 | - Total unique URLs tested: [number] 324 | - 404 errors found and fixed: [list] 325 | - Final status: MUST be "Zero 404s found" 326 | ``` 327 | 328 | **❌ UNACCEPTABLE:** 329 | - "I tested a few links and they work" 330 | - "I checked some pages" 331 | - "The main pages seem to work" 332 | - "I verified the important links" 333 | 334 | **✅ REQUIRED:** 335 | - "I tested all 47 header links - all working" 336 | - "I tested all 23 footer links - all working" 337 | - "I tested all 85 directory entries - all working" 338 | - "I tested all 35 taxonomy pages - all working" 339 | - "Total: 190 unique URLs tested, zero 404s" 340 | 341 | **THE WEBSITE IS NOT COMPLETE UNTIL EVERY SINGLE LINK WORKS** 342 | 343 | ## ✅ ONLY NOW REPORT BACK TO THE USER 344 | 345 | **NOW that you have a COMPLETE, WORKING website with ZERO 404s, you can report:** 346 | - "Website complete and verified at http://localhost" 347 | - "All [X] directory entries created and tested" 348 | - "All [X] taxonomy pages working" 349 | - "Playwright verified [X] total links - ZERO 404 errors" 350 | - "Ready for deployment with ./migrate_now.sh" 351 | 352 | **If you haven't done ALL of the above, GO BACK and finish the website.** 353 | 354 | ### Phase 3: Deployment to Digital Ocean 355 | 1. **Setup infrastructure** 356 | - Run `./setup_ssh_and_deploy.sh` (one-time SSH setup) 357 | - Run `python3 create_droplet_with_ssh.py` 358 | - Wait 5-10 minutes for installation 359 | 360 | 2. **Migrate to production** 361 | - Run `./migrate_now.sh` 362 | - Verify custom theme transferred 363 | - Check that permalinks work (auto-configured) 364 | 365 | 3. **Final configuration** 366 | - Point domain to droplet IP 367 | - Install SSL certificate 368 | - Configure backups 369 | 370 | --- 371 | 372 | ## 📚 Directory Website Development 373 | 374 | ### SEO Page Structure Requirements 375 | 376 | **IMPORTANT:** Do NOT use Rank Math during development. Focus on native SEO implementation. 377 | Rank Math will only be added at launch for Search Console submission. 378 | 379 | Every page must have: 380 | - **Meta Title**: Maximized to 60 characters with keywords 381 | - **Meta Description**: Maximized to 160 characters with compelling copy 382 | - **H1 Title**: Unique and keyword-rich 383 | - **Page Content**: Minimum 300-500 words of unique, valuable content 384 | - **Schema Markup**: LocalBusiness, Product, or Review schema as appropriate 385 | - **Open Graph tags**: For social sharing 386 | - **Internal Links**: 3-5 contextual links to related pages 387 | 388 | Generate these page types for maximum ranking potential: 389 | - "Best [Product] in [City]" - for every city 390 | - "Top 10 [Category] in [State]" - for every state 391 | - "[Product] near me" - location-based pages 392 | - "[Category] Reviews [Year]" - fresh content pages 393 | - "Compare [Product A] vs [Product B]" - comparison pages 394 | - "[Product] for [Use Case]" - intent-based pages 395 | - "Cheap/Affordable [Product] in [Location]" - price-focused pages 396 | 397 | ### Review System Framework 398 | 399 | Frame reviews contextually based on the directory type: 400 | - For restaurants: "[Cuisine] lovers who dined at [Restaurant] can leave a review" 401 | - For products: "[Product] users who tried [Brand] can share their experience" 402 | - For services: "Customers who used [Service] from [Company] can rate their experience" 403 | - For venues: "Visitors who went to [Venue] can share their thoughts" 404 | 405 | Review form should include: 406 | - Overall star rating (1-5 stars) 407 | - Category-specific ratings (e.g., Quality, Service, Value, Location) 408 | - Written review with minimum 50 characters 409 | - Photo upload option 410 | - "Would you recommend?" Yes/No 411 | - Verified purchase/visit checkbox 412 | - Helpful/Not Helpful voting on other reviews 413 | 414 | ### Research Phase with Jina AI 415 | 416 | When building directory websites, use Jina AI for comprehensive research: 417 | 418 | ```bash 419 | # Search for information (use s.jina.ai) 420 | curl "https://s.jina.ai/?q=YOUR_SEARCH_TERM" \ 421 | -H "Authorization: Bearer $JINA_API_KEY" 422 | 423 | # Scrape individual pages (use r.jina.ai) 424 | curl "https://r.jina.ai/https://example.com/page" \ 425 | -H "Authorization: Bearer $JINA_API_KEY" 426 | ``` 427 | 428 | **Important Research Guidelines:** 429 | - Create detailed JSON for each directory page 430 | - If a page 404s or doesn't scrape properly, retry the scrape 431 | - DO NOT use Jina to scrape CSS from design sites 432 | 433 | ### Finding Royalty-Free Images 434 | 435 | ```bash 436 | # Search for Unsplash images using Jina 437 | curl "https://s.jina.ai/?q=YOUR_IMAGE_DESCRIPTION+unsplash" \ 438 | -H "Authorization: Bearer $JINA_API_KEY" 439 | 440 | # Then scrape the found Unsplash pages for non-premium images 441 | curl "https://r.jina.ai/https://unsplash.com/photos/..." \ 442 | -H "Authorization: Bearer $JINA_API_KEY" 443 | ``` 444 | 445 | ### Directory Page JSON Format 446 | 447 | Each directory entry should have comprehensive data: 448 | 449 | ```json 450 | { 451 | "id": "unique-identifier", 452 | "name": "Company/Service Name", 453 | "category": "Technology Category", 454 | "description": "Detailed description...", 455 | "features": ["feature1", "feature2", "..."], 456 | "pricing": { 457 | "model": "subscription/one-time/freemium", 458 | "tiers": [...] 459 | }, 460 | "images": { 461 | "logo": "url-from-unsplash", 462 | "screenshots": ["url1", "url2"], 463 | "hero": "hero-image-url" 464 | }, 465 | "metadata": { 466 | "founded": "year", 467 | "headquarters": "location", 468 | "employees": "range", 469 | "funding": "amount" 470 | }, 471 | "links": { 472 | "website": "url", 473 | "documentation": "url", 474 | "pricing": "url" 475 | }, 476 | "tags": ["tag1", "tag2"], 477 | "lastUpdated": "timestamp" 478 | } 479 | ``` 480 | 481 | ### CSS Development Guidelines 482 | 483 | **IMPORTANT:** Create extremely detailed and complex CSS files that are well-thought-out: 484 | 485 | - Don't write short, simple CSS - make it comprehensive 486 | - Include detailed animations and transitions 487 | - Add hover states, focus states, and active states 488 | - Create responsive breakpoints for all screen sizes 489 | - Include print styles and accessibility features 490 | - Use CSS custom properties for theming 491 | - Add detailed comments explaining complex sections 492 | - Implement sophisticated grid and flexbox layouts 493 | - Include fallbacks for older browsers 494 | 495 | Example of detailed CSS approach: 496 | ```css 497 | /* Component: Directory Card 498 | Purpose: Display individual directory entries 499 | States: default, hover, active, disabled, loading 500 | Breakpoints: mobile-first approach with 5 breakpoints 501 | Accessibility: WCAG 2.1 AA compliant */ 502 | 503 | .directory-card { 504 | /* Base styles with extensive properties */ 505 | /* Multiple transition effects */ 506 | /* Complex shadow systems */ 507 | /* Detailed spacing scales */ 508 | } 509 | ``` 510 | 511 | ## 🚀 Quick Deploy Workflow 512 | 513 | When a user clones this repository and wants to deploy WordPress to Digital Ocean, 514 | execute these commands in order: 515 | 516 | ```bash 517 | # 1. Setup environment 518 | cp .env.example .env 519 | # User must edit .env and add DO_API_TOKEN and JINA_API_KEY 520 | 521 | # 2. Install Python dependencies 522 | pip3 install python-dotenv requests 523 | 524 | # 3. Start local WordPress 525 | docker-compose up -d 526 | 527 | # 4. Setup SSH keys (one-time) 528 | ./setup_ssh_and_deploy.sh 529 | 530 | # 5. Create Digital Ocean droplet 531 | python3 create_droplet_with_ssh.py 532 | 533 | # 6. Wait for installation (5-10 minutes) 534 | sleep 300 535 | 536 | # 7. Migrate local WordPress to droplet 537 | ./migrate_now.sh 538 | ``` 539 | 540 | ## 📁 Project Structure 541 | 542 | ``` 543 | wordpress-claude-code-wizard/ 544 | ├── .env # DO_API_TOKEN goes here 545 | ├── docker-compose.yml # Local WordPress environment 546 | ├── Dockerfile # Custom Apache/PHP image 547 | ├── wp-config.php # Environment-aware configuration 548 | ├── setup_ssh_and_deploy.sh # SSH key automation 549 | ├── create_droplet_with_ssh.py # Droplet creation script 550 | ├── migrate_now.sh # Migration script 551 | └── wp-content/ 552 | ├── themes/ 553 | │ └── my-custom-theme/ # Starter theme 554 | └── plugins/ 555 | └── custom-post-types/ # CPT plugin 556 | ``` 557 | 558 | ## 🎨 WordPress Development Guide 559 | 560 | ### Theme Development 561 | 562 | Users can modify the custom theme in `wp-content/themes/my-custom-theme/`: 563 | 564 | ```bash 565 | # Create new page template 566 | cat > wp-content/themes/my-custom-theme/page-about.php << 'EOF' 567 | 571 |
572 |
573 |

574 | 575 |
576 |
577 | 578 | EOF 579 | 580 | # Create custom single post template 581 | cat > wp-content/themes/my-custom-theme/single.php << 'EOF' 582 | 583 |
584 |
585 |

586 |
Posted on
587 | 588 |
589 |
590 | 591 | EOF 592 | 593 | # Create archive template 594 | cat > wp-content/themes/my-custom-theme/archive.php << 'EOF' 595 | 596 |
597 |

598 | 599 |
600 |

601 | 602 |
603 | 604 |
605 | 606 | EOF 607 | ``` 608 | 609 | ### Adding Navigation Menus 610 | 611 | Add to `wp-content/themes/my-custom-theme/functions.php`: 612 | 613 | ```php 614 | // Register multiple menu locations 615 | register_nav_menus(array( 616 | 'primary' => __('Primary Menu', 'my-custom-theme'), 617 | 'footer' => __('Footer Menu', 'my-custom-theme'), 618 | 'social' => __('Social Links Menu', 'my-custom-theme'), 619 | )); 620 | 621 | // Add menu support 622 | add_theme_support('menus'); 623 | ``` 624 | 625 | Display menus in theme templates: 626 | 627 | ```php 628 | // In header.php 629 | 'primary')); ?> 630 | 631 | // In footer.php 632 | 'footer')); ?> 633 | ``` 634 | 635 | ### WP-CLI Commands (Inside Docker Container) 636 | 637 | ```bash 638 | # Access the WordPress container 639 | docker exec -it wp-dev bash 640 | 641 | # Install WP-CLI (if not already installed) 642 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 643 | chmod +x wp-cli.phar 644 | mv wp-cli.phar /usr/local/bin/wp 645 | 646 | # Create pages 647 | wp post create --post_type=page --post_title='Home' --post_status=publish 648 | wp post create --post_type=page --post_title='About Us' --post_status=publish 649 | wp post create --post_type=page --post_title='Services' --post_status=publish 650 | wp post create --post_type=page --post_title='Contact' --post_status=publish 651 | wp post create --post_type=page --post_title='Blog' --post_status=publish 652 | 653 | # Set static homepage 654 | wp option update page_on_front 2 # Use page ID 655 | wp option update show_on_front page 656 | wp option update page_for_posts 5 # Blog page ID 657 | 658 | # Create menu 659 | wp menu create "Main Menu" 660 | wp menu location assign main-menu primary 661 | wp menu item add-post main-menu 2 # Add pages to menu 662 | wp menu item add-post main-menu 3 663 | wp menu item add-post main-menu 4 664 | 665 | # Install popular plugins 666 | wp plugin install contact-form-7 --activate 667 | wp plugin install wordpress-seo --activate 668 | wp plugin install elementor --activate 669 | wp plugin install woocommerce --activate 670 | wp plugin install updraftplus --activate 671 | 672 | # Create users 673 | wp user create john john@example.com --role=editor --user_pass=password123 674 | wp user create jane jane@example.com --role=author --user_pass=password123 675 | 676 | # Update site options 677 | wp option update blogname "My Awesome Site" 678 | wp option update blogdescription "A WordPress site built with Claude Code Wizard" 679 | wp option update timezone_string "America/New_York" 680 | 681 | # Set permalinks 682 | wp rewrite structure '/%postname%/' 683 | wp rewrite flush 684 | ``` 685 | 686 | ### Custom Post Types 687 | 688 | The included plugin already creates Portfolio and Testimonial post types. To add 689 | more: 690 | 691 | ```php 692 | // Add to wp-content/plugins/custom-post-types/custom-post-types.php 693 | 694 | public function register_team_post_type() { 695 | $args = array( 696 | 'labels' => array( 697 | 'name' => 'Team Members', 698 | 'singular_name' => 'Team Member', 699 | ), 700 | 'public' => true, 701 | 'has_archive' => true, 702 | 'supports' => array('title', 'editor', 'thumbnail'), 703 | 'menu_icon' => 'dashicons-groups', 704 | 'show_in_rest' => true, 705 | ); 706 | register_post_type('team', $args); 707 | } 708 | // Add to __construct(): add_action('init', array($this, 709 | 'register_team_post_type')); 710 | ``` 711 | 712 | ### Advanced Theme Features 713 | 714 | ```php 715 | // Add to functions.php 716 | 717 | // Custom image sizes 718 | add_theme_support('post-thumbnails'); 719 | add_image_size('hero', 1920, 600, true); 720 | add_image_size('team-member', 400, 400, true); 721 | 722 | // Widget areas 723 | function my_widgets_init() { 724 | register_sidebar(array( 725 | 'name' => 'Homepage Widgets', 726 | 'id' => 'homepage-widgets', 727 | 'before_widget' => '
', 728 | 'after_widget' => '
', 729 | )); 730 | } 731 | add_action('widgets_init', 'my_widgets_init'); 732 | 733 | // Custom logo support 734 | add_theme_support('custom-logo', array( 735 | 'height' => 100, 736 | 'width' => 400, 737 | 'flex-height' => true, 738 | 'flex-width' => true, 739 | )); 740 | 741 | // Gutenberg support 742 | add_theme_support('align-wide'); 743 | add_theme_support('editor-styles'); 744 | add_theme_support('wp-block-styles'); 745 | ``` 746 | 747 | ## 🔧 Troubleshooting Commands 748 | 749 | ```bash 750 | # Check if Docker containers are running 751 | docker ps | grep wp- 752 | 753 | # View Docker logs 754 | docker-compose logs wordpress 755 | 756 | # Restart containers 757 | docker-compose restart 758 | 759 | # Access MySQL directly 760 | docker exec -it wp-mysql mysql -u wordpress -pwordpress_password wordpress 761 | 762 | # Check droplet status 763 | cat .droplet_info | python3 -m json.tool 764 | 765 | # SSH to droplet 766 | ssh -i ~/.ssh/wordpress_deploy root@$(cat .droplet_info | python3 -c "import 767 | json,sys; print(json.load(sys.stdin)['ip_address'])") 768 | 769 | # View WordPress error logs on droplet 770 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "tail -f /var/log/apache2/error.log" 771 | 772 | # Check cloud-init status 773 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP "cloud-init status" 774 | 775 | # Delete droplet (cleanup) 776 | python3 -c " 777 | import requests, json, os 778 | api_token = os.getenv('DO_API_TOKEN') 779 | with open('.droplet_info') as f: 780 | droplet_id = json.load(f)['droplet_id'] 781 | headers = {'Authorization': f'Bearer {api_token}'} 782 | response = 783 | requests.delete(f'https://api.digitalocean.com/v2/droplets/{droplet_id}', 784 | headers=headers) 785 | print('Droplet deleted' if response.status_code == 204 else 'Failed') 786 | " 787 | ``` 788 | 789 | ### 🚨 Fixing 404 Errors on Pages 790 | 791 | If you encounter 404 errors on pages after deployment, the scripts now handle this 792 | automatically. However, if you still have issues: 793 | 794 | ```bash 795 | # SSH to droplet 796 | ssh -i ~/.ssh/wordpress_deploy root@YOUR_IP 797 | 798 | # Check if permalinks are set correctly 799 | wp --allow-root rewrite structure 800 | 801 | # Manually set permalinks and flush 802 | wp --allow-root rewrite structure '/%postname%/' 803 | wp --allow-root rewrite flush 804 | 805 | # Verify Apache configuration 806 | cat /etc/apache2/sites-enabled/wordpress.conf 807 | # Should show: AllowOverride All 808 | 809 | # Check .htaccess exists and is correct 810 | cat /var/www/html/.htaccess 811 | 812 | # Restart Apache 813 | systemctl restart apache2 814 | ``` 815 | 816 | **Note:** The deployment scripts now automatically: 817 | - Install WP-CLI on the server 818 | - Configure Apache with AllowOverride All 819 | - Set permalinks to /%postname%/ 820 | - Create proper .htaccess file 821 | - Flush rewrite rules after migration 822 | 823 | ## 📊 Production Deployment Checklist 824 | 825 | Before deploying to production: 826 | 827 | 1. ✅ Update passwords in wp-config.php 828 | 2. ✅ Set WP_DEBUG to false 829 | 3. ✅ Update salts (automatic during migration) 830 | 4. ✅ Install SSL certificate (certbot --apache) 831 | 5. ✅ Configure domain DNS 832 | 6. ✅ Enable firewall (ufw) 833 | 7. ✅ Set up backups 834 | 8. ✅ Configure email settings 835 | 836 | ## 🎯 Complete Workflow Summary 837 | 838 | 1. **Clone repo** → Get complete WordPress development environment 839 | 2. **Docker up** → Local WordPress running instantly 840 | 3. **Develop** → Theme, plugins, content - everything 841 | 4. **Setup SSH** → One-time automated key configuration 842 | 5. **Create droplet** → Automated via API with WordPress installation 843 | 6. **Migrate** → Transfer everything to production 844 | 7. **Point domain** → Update DNS A record 845 | 8. **SSL** → Run certbot for HTTPS 846 | 9. **Live** → Production WordPress site running! 847 | 848 | ## 💡 Key Features This Provides 849 | 850 | - **Zero DevOps knowledge required** - Just need DO API token 851 | - **Perfect environment parity** - Docker matches production exactly 852 | - **Complete WordPress control** - Full admin access, all features 853 | - **Real VPS** - Not shared hosting, full server control 854 | - **One-command deployment** - Actually automated, not marketing speak 855 | - **Cost effective** - $6/month for production site 856 | - **No vendor lock-in** - Standard WordPress on standard Ubuntu 857 | - **Version controlled** - Everything in Git 858 | - **Instant local development** - Changes visible immediately 859 | - **Professional workflow** - Local → Staging → Production capable 860 | 861 | ## 🚨 Important Notes 862 | 863 | - Always test locally before deploying 864 | - Keep backups of production database 865 | - Use strong passwords in production 866 | - Update WordPress, themes, and plugins regularly 867 | - Monitor server resources on Digital Ocean 868 | - The migration script replaces the entire WordPress installation 869 | - Custom plugins/themes in wp-content are preserved 870 | - Database is completely replaced with local version 871 | 872 | ## 🔄 Updating Production Site 873 | 874 | To update your production site after local changes: 875 | 876 | ```bash 877 | # Make changes locally 878 | # Test everything at http://localhost 879 | 880 | # Re-run migration to update production 881 | ./migrate_now.sh 882 | 883 | # Your production site is now updated with all local changes 884 | ``` 885 | 886 | This is a complete local-to-production WordPress development and deployment 887 | pipeline that doesn't exist anywhere else in this form! --------------------------------------------------------------------------------