From 6e9fb5a9c45bb6c85f2adaab6db8b80552986656 Mon Sep 17 00:00:00 2001 From: marcusquinn <6428977+marcusquinn@users.noreply.github.com> Date: Mon, 24 Nov 2025 23:09:18 +0000 Subject: [PATCH] Modernize WordPress Playground testing infrastructure - Update @wp-playground/cli to v3.0.22 (from deprecated v1.0.28) - Add bin/playground-test.sh for AI assistant CLI testing - Add bin/localwp-setup.sh for LocalWP integration - Create .agents/local-testing-guide.md documentation - Update blueprints to use new installPlugin step format - Add npm scripts for playground:start/stop/status - Add npm scripts for localwp:create/sync/reset - Update GitHub Actions to use new CLI version - Use PHP 8.0 and latest WordPress in blueprints --- .agents/local-testing-guide.md | 331 ++++++++++++++++++++ .github/workflows/playground-tests.yml | 16 +- AGENTS.md | 2 + bin/localwp-setup.sh | 413 +++++++++++++++++++++++++ bin/playground-test.sh | 303 ++++++++++++++++++ package.json | 14 +- playground/blueprint.json | 32 +- playground/multisite-blueprint.json | 46 +-- 8 files changed, 1117 insertions(+), 40 deletions(-) create mode 100644 .agents/local-testing-guide.md create mode 100755 bin/localwp-setup.sh create mode 100755 bin/playground-test.sh diff --git a/.agents/local-testing-guide.md b/.agents/local-testing-guide.md new file mode 100644 index 0000000..1fc2900 --- /dev/null +++ b/.agents/local-testing-guide.md @@ -0,0 +1,331 @@ +# Local Testing Guide for AI Assistants + +This guide provides instructions for AI coding assistants to set up and run local +WordPress testing environments for this plugin. + +## Overview + +Three testing approaches are available: + +1. **WordPress Playground CLI** - Quick browser-based testing (recommended for AI) +2. **LocalWP** - Full local WordPress environment +3. **wp-env** - Docker-based WordPress environment + +Each approach has trade-offs. Choose based on the testing needs. + +## Quick Reference + +```bash +# Playground CLI (fastest for AI testing) +npm run playground:start # Start single site +npm run playground:start:multisite # Start multisite +npm run playground:stop # Stop server +npm run playground:status # Check status + +# LocalWP (full environment) +npm run localwp:create # Create single site +npm run localwp:create:multisite # Create multisite +npm run localwp:sync # Sync plugin changes +npm run localwp:reset # Reset to clean state + +# wp-env (Docker-based) +npm run start # Start wp-env +npm run stop # Stop wp-env +``` + +## WordPress Playground CLI + +Uses `@wp-playground/cli` version 3.0.22+ for instant WordPress testing. + +### When to Use + +* Quick plugin functionality testing +* Verifying admin UI changes +* Testing single site vs multisite behavior +* CI/CD pipeline testing (note: may be flaky in GitHub Actions) + +### Starting Playground + +```bash +# Single site on port 8888 +npm run playground:start + +# Multisite on port 8889 +npm run playground:start:multisite +``` + +### Accessing the Site + +After starting, the script provides access details: + +* **Single Site**: http://localhost:8888 +* **Multisite**: http://localhost:8889 +* **Admin Login**: admin / password + +### Blueprint Configuration + +Blueprints define the WordPress setup. Located in `playground/`: + +* `blueprint.json` - Single site configuration +* `multisite-blueprint.json` - Multisite configuration + +Blueprints install: +* Plugin Toggle (debugging helper) +* Kadence Blocks (testing with block plugins) + +### Stopping Playground + +```bash +npm run playground:stop +``` + +### Status Check + +```bash +npm run playground:status +``` + +Shows running processes and port usage. + +### Troubleshooting + +If Playground fails to start: + +1. Check if ports 8888/8889 are in use: `lsof -i :8888` +2. Check logs: `cat .playground.log` +3. Stop any orphaned processes: `npm run playground:stop` +4. Ensure npm dependencies are installed: `npm install` + +## LocalWP Integration + +LocalWP provides a full WordPress environment with database persistence. + +### Prerequisites + +* LocalWP installed at `/Applications/Local.app` (macOS) +* Local Sites directory at `~/Local Sites/` + +### When to Use + +* Testing database migrations +* Long-term development environment +* Testing with specific PHP/MySQL versions +* Network/multisite configuration testing +* Testing WP-CLI commands + +### Creating Sites + +LocalWP requires manual site creation through the GUI. + +```bash +npm run localwp:create +``` + +This guides you through: + +1. Opening LocalWP +2. Creating a site with standardized name +3. Syncing plugin files + +### URL Patterns + +Sites use consistent naming: + +* **Single Site**: `wp-plugin-starter-template-single.local` +* **Multisite**: `wp-plugin-starter-template-multisite.local` + +### Syncing Plugin Files + +After making code changes: + +```bash +npm run localwp:sync +``` + +This uses rsync to copy plugin files, excluding: +* node_modules +* vendor +* tests +* .git +* dist + +### Resetting + +To reset the plugin to a clean state: + +```bash +npm run localwp:reset +``` + +### Site Information + +View all LocalWP sites: + +```bash +./bin/localwp-setup.sh info +``` + +## wp-env (Docker) + +Docker-based environment using `@wordpress/env`. + +### When to Use + +* Consistent environment across machines +* PHPUnit testing +* WP-CLI operations +* CI/CD testing + +### Starting + +```bash +npm run start # or: wp-env start +``` + +### Running Tests + +```bash +npm run test:phpunit # Single site tests +npm run test:phpunit:multisite # Multisite tests +``` + +### Running WP-CLI Commands + +```bash +wp-env run cli wp plugin list +wp-env run cli wp option get siteurl +``` + +## Testing Workflows for AI Assistants + +### Verifying a Code Change + +1. Make the code change +2. Start Playground: `npm run playground:start` +3. Navigate to relevant admin page +4. Verify expected behavior +5. Stop Playground: `npm run playground:stop` + +### Testing Multisite Functionality + +1. Start multisite: `npm run playground:start:multisite` +2. Navigate to Network Admin +3. Test network-wide functionality +4. Test per-site functionality +5. Stop: `npm run playground:stop` + +### Running PHPUnit Tests + +```bash +# Single site +composer test + +# Multisite +WP_MULTISITE=1 composer test + +# Specific test file +vendor/bin/phpunit tests/phpunit/test-core.php +``` + +### Running Cypress E2E Tests + +```bash +# With Playground (headless) +npm run test:playground:single +npm run test:playground:multisite + +# With wp-env (headless) +npm run test:e2e:single +npm run test:e2e:multisite +``` + +## Environment Comparison + +| Feature | Playground CLI | LocalWP | wp-env | +|---------|---------------|---------|--------| +| Setup Time | Instant | 5-10 min | 2-5 min | +| Persistence | None | Full | Partial | +| PHP Versions | Limited | Many | Limited | +| Database | In-memory | MySQL | MySQL | +| WP-CLI | Yes | Yes | Yes | +| Multisite | Yes | Yes | Yes | +| GitHub Actions | Flaky | N/A | Works | +| Best For | Quick testing | Full dev | CI/Testing | + +## Common Issues + +### Port Already in Use + +```bash +# Check what's using the port +lsof -i :8888 + +# Kill the process if needed +kill $(lsof -t -i :8888) +``` + +### Playground Won't Start + +1. Ensure dependencies installed: `npm install` +2. Check Node.js version: `node --version` (requires 18+) +3. Check logs: `cat .playground.log` + +### LocalWP Site Not Found + +The script expects sites at: +* `~/Local Sites/wp-plugin-starter-template-single/` +* `~/Local Sites/wp-plugin-starter-template-multisite/` + +Verify the site name matches exactly. + +### wp-env Docker Issues + +```bash +# Restart Docker +wp-env stop +docker system prune -f +wp-env start +``` + +## Blueprint Reference + +Blueprints use JSON format. Key steps: + +```json +{ + "$schema": "https://playground.wordpress.net/blueprint-schema.json", + "landingPage": "/wp-admin/", + "login": true, + "features": { + "networking": true, + "phpVersion": "7.4" + }, + "steps": [ + { + "step": "defineWpConfigConsts", + "consts": { + "WP_DEBUG": true + } + }, + { + "step": "wp-cli", + "command": "wp plugin install plugin-toggle --activate" + } + ] +} +``` + +For multisite, add: + +```json +{ + "step": "enableMultisite" +} +``` + +## Resources + +* [WordPress Playground CLI](https://wordpress.github.io/wordpress-playground/) +* [WordPress Playground Blueprints](https://wordpress.github.io/wordpress-playground/blueprints) +* [LocalWP Documentation](https://localwp.com/help-docs/) +* [@wordpress/env Documentation](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) diff --git a/.github/workflows/playground-tests.yml b/.github/workflows/playground-tests.yml index 09b72c9..6003363 100644 --- a/.github/workflows/playground-tests.yml +++ b/.github/workflows/playground-tests.yml @@ -77,11 +77,9 @@ jobs: - name: Install dependencies run: npm install --legacy-peer-deps - - name: Add WordPress Playground CLI to dependencies + - name: Verify WordPress Playground CLI run: | - echo "Installing WordPress Playground CLI..." - npm install --save-dev @wp-playground/cli @wp-playground/blueprints @wp-playground/client - echo "WordPress Playground CLI installed" + echo "WordPress Playground CLI version:" npx @wp-playground/cli --version - name: Create plugin zip @@ -97,7 +95,7 @@ jobs: ls -la playground/ cat playground/blueprint.json - # Start WordPress Playground with our blueprint + # Start WordPress Playground with our blueprint (using @wp-playground/cli 3.x syntax) echo "Starting WordPress Playground server..." npx @wp-playground/cli server --blueprint playground/blueprint.json --port 8888 --login & SERVER_PID=$! @@ -157,11 +155,9 @@ jobs: - name: Install dependencies run: npm install --legacy-peer-deps - - name: Add WordPress Playground CLI to dependencies + - name: Verify WordPress Playground CLI run: | - echo "Installing WordPress Playground CLI..." - npm install --save-dev @wp-playground/cli @wp-playground/blueprints @wp-playground/client - echo "WordPress Playground CLI installed" + echo "WordPress Playground CLI version:" npx @wp-playground/cli --version - name: Create plugin zip @@ -177,7 +173,7 @@ jobs: ls -la playground/ cat playground/multisite-blueprint.json - # Start WordPress Playground with our blueprint + # Start WordPress Playground with our blueprint (using @wp-playground/cli 3.x syntax) # Use a different port for multisite to avoid conflicts with single site tests echo "Starting WordPress Playground server for multisite..." npx @wp-playground/cli server --blueprint playground/multisite-blueprint.json --port 8889 --login & diff --git a/AGENTS.md b/AGENTS.md index a33e9d1..8b7ce8b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -93,6 +93,8 @@ Always run PHPCS and PHPCBF locally before committing code to ensure it meets th For detailed instructions on releases, features, bugs, and testing, see **@.agents/release-process.md**. +For local testing with WordPress Playground, LocalWP, and wp-env, see **@.agents/local-testing-guide.md**. + ## Avoiding Cross-Repository Confusion When working in a multi-repository workspace, follow these guidelines to avoid confusion: diff --git a/bin/localwp-setup.sh b/bin/localwp-setup.sh new file mode 100755 index 0000000..d3e80d8 --- /dev/null +++ b/bin/localwp-setup.sh @@ -0,0 +1,413 @@ +#!/bin/bash + +# LocalWP Integration Script for WordPress Plugin Development +# For use by AI coding assistants and developers +# +# This script manages LocalWP sites for testing the plugin. +# Creates standardized test sites with consistent URLs. +# +# URL Patterns: +# Single site: {plugin-slug}-single.local +# Multisite: {plugin-slug}-multisite.local +# +# Usage: +# ./bin/localwp-setup.sh create [--multisite] +# ./bin/localwp-setup.sh sync +# ./bin/localwp-setup.sh reset +# ./bin/localwp-setup.sh info +# +# Examples: +# npm run localwp:create # Create single site +# npm run localwp:create:multisite # Create multisite +# npm run localwp:sync # Sync plugin files +# npm run localwp:reset # Reset to clean state + +set -e + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +PLUGIN_SLUG="wp-plugin-starter-template" +PLUGIN_TEXT_DOMAIN="wp-plugin-starter-template" + +# LocalWP paths (macOS) +LOCAL_SITES_DIR="$HOME/Local Sites" +LOCAL_APP="/Applications/Local.app" +LOCAL_WP_CLI="$LOCAL_APP/Contents/Resources/extraResources/bin/wp-cli/posix/wp" + +# Site configurations +SINGLE_SITE_NAME="${PLUGIN_SLUG}-single" +MULTISITE_NAME="${PLUGIN_SLUG}-multisite" +SINGLE_SITE_DOMAIN="${SINGLE_SITE_NAME}.local" +MULTISITE_DOMAIN="${MULTISITE_NAME}.local" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Helper functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_step() { + echo -e "${CYAN}[STEP]${NC} $1" +} + +# Check if LocalWP is installed +check_localwp() { + if [ ! -d "$LOCAL_APP" ]; then + log_error "LocalWP is not installed at $LOCAL_APP" + log_info "Download from: https://localwp.com/" + exit 1 + fi + + if [ ! -f "$LOCAL_WP_CLI" ]; then + log_error "WP-CLI not found in LocalWP installation" + exit 1 + fi + + local version=$("$LOCAL_WP_CLI" --version 2>/dev/null || echo "unknown") + log_info "LocalWP WP-CLI version: $version" +} + +# Get site path +get_site_path() { + local site_name="$1" + echo "$LOCAL_SITES_DIR/$site_name" +} + +# Get WordPress path within site +get_wp_path() { + local site_name="$1" + local site_path=$(get_site_path "$site_name") + + # LocalWP uses app/public for WordPress files + echo "$site_path/app/public" +} + +# Check if site exists +site_exists() { + local site_name="$1" + local site_path=$(get_site_path "$site_name") + [ -d "$site_path" ] +} + +# Get plugin destination path +get_plugin_path() { + local site_name="$1" + local wp_path=$(get_wp_path "$site_name") + echo "$wp_path/wp-content/plugins/$PLUGIN_SLUG" +} + +# Sync plugin files to LocalWP site +sync_plugin() { + local site_name="$1" + local plugin_dest=$(get_plugin_path "$site_name") + + if ! site_exists "$site_name"; then + log_error "Site '$site_name' does not exist" + return 1 + fi + + log_info "Syncing plugin to $site_name..." + + # Create plugin directory if it doesn't exist + mkdir -p "$plugin_dest" + + # Sync files using rsync (excludes dev files) + rsync -av --delete \ + --exclude 'node_modules' \ + --exclude 'vendor' \ + --exclude '.git' \ + --exclude 'dist' \ + --exclude 'tests' \ + --exclude 'cypress' \ + --exclude '.github' \ + --exclude '.agents' \ + --exclude '.wiki' \ + --exclude 'reference-plugins' \ + --exclude '*.zip' \ + --exclude '.playground.*' \ + --exclude 'composer.lock' \ + --exclude 'package-lock.json' \ + "$PROJECT_DIR/" "$plugin_dest/" + + log_success "Plugin synced to: $plugin_dest" +} + +# Create a new LocalWP site +create_site() { + local multisite=false + + # Parse arguments + while [[ $# -gt 0 ]]; do + case "$1" in + --multisite) + multisite=true + shift + ;; + *) + shift + ;; + esac + done + + local site_name="$SINGLE_SITE_NAME" + local domain="$SINGLE_SITE_DOMAIN" + local mode="single site" + + if [ "$multisite" = true ]; then + site_name="$MULTISITE_NAME" + domain="$MULTISITE_DOMAIN" + mode="multisite" + fi + + check_localwp + + local site_path=$(get_site_path "$site_name") + + if site_exists "$site_name"; then + log_warning "Site '$site_name' already exists at: $site_path" + log_info "Use 'npm run localwp:reset' to reset it, or 'npm run localwp:sync' to update files" + return 0 + fi + + echo "" + echo "============================================" + echo " LocalWP Site Setup ($mode)" + echo "============================================" + echo "" + echo "This script will guide you through creating a" + echo "LocalWP site for testing the plugin." + echo "" + echo "Site Details:" + echo " Name: $site_name" + echo " Domain: $domain" + echo " Path: $site_path" + echo "" + + log_step "Creating LocalWP Site" + echo "" + log_info "LocalWP doesn't have a CLI for site creation." + log_info "Please create the site manually in LocalWP:" + echo "" + echo "1. Open LocalWP application" + echo "2. Click the '+' button to create a new site" + echo "3. Use these settings:" + echo " - Site name: ${CYAN}$site_name${NC}" + echo " - Local site domain: ${CYAN}$domain${NC}" + echo " - PHP version: 8.0 or higher" + echo " - Web server: nginx (preferred)" + echo " - MySQL version: 8.0+" + + if [ "$multisite" = true ]; then + echo "" + echo "4. After site creation, convert to multisite:" + echo " - Open Site Shell in LocalWP" + echo " - Run: wp core multisite-convert --subdomains=0" + echo " - Update wp-config.php if needed" + fi + + echo "" + log_info "After creating the site, run: npm run localwp:sync" + echo "" + + # Wait for user to create site + read -p "Press Enter after you've created the site in LocalWP..." + + if site_exists "$site_name"; then + log_success "Site detected at: $site_path" + sync_plugin "$site_name" + + # Install recommended plugins + install_recommended_plugins "$site_name" + + show_site_info "$site_name" "$domain" "$multisite" + else + log_warning "Site not found at expected location" + log_info "Expected path: $site_path" + log_info "You can run 'npm run localwp:sync' later to sync files" + fi +} + +# Install recommended plugins (matching Playground blueprint) +install_recommended_plugins() { + local site_name="$1" + local wp_path=$(get_wp_path "$site_name") + + log_info "Note: Install these plugins to match Playground environment:" + echo " - Plugin Toggle (plugin-toggle)" + echo " - Kadence Blocks (kadence-blocks)" + echo "" + log_info "You can install them via LocalWP's WP Admin or Site Shell" +} + +# Show site information +show_site_info() { + local site_name="$1" + local domain="$2" + local multisite="$3" + + local site_path=$(get_site_path "$site_name") + local plugin_path=$(get_plugin_path "$site_name") + + echo "" + echo "============================================" + echo " LocalWP Site Ready" + echo "============================================" + echo " Site: $site_name" + echo " URL: http://$domain" + echo " Admin: http://$domain/wp-admin/" + echo " Plugin Path: $plugin_path" + echo "============================================" + + if [ "$multisite" = true ]; then + echo " Network Admin: http://$domain/wp-admin/network/" + echo "============================================" + fi + + echo "" + log_info "Remember to:" + echo " 1. Start the site in LocalWP" + echo " 2. Activate the plugin in WordPress admin" + echo " 3. Run 'npm run localwp:sync' after making changes" + echo "" +} + +# Reset site to clean state +reset_site() { + local site_name="${1:-$SINGLE_SITE_NAME}" + + if ! site_exists "$site_name"; then + log_error "Site '$site_name' does not exist" + exit 1 + fi + + log_warning "This will delete the plugin files and resync them." + read -p "Continue? (y/n) " -n 1 -r + echo + + if [[ $REPLY =~ ^[Yy]$ ]]; then + local plugin_path=$(get_plugin_path "$site_name") + + log_info "Removing plugin files..." + rm -rf "$plugin_path" + + log_info "Resyncing plugin..." + sync_plugin "$site_name" + + log_success "Site reset complete" + else + log_info "Reset cancelled" + fi +} + +# Sync all existing sites +sync_all() { + local synced=0 + + for site_name in "$SINGLE_SITE_NAME" "$MULTISITE_NAME"; do + if site_exists "$site_name"; then + sync_plugin "$site_name" + synced=$((synced + 1)) + fi + done + + if [ $synced -eq 0 ]; then + log_warning "No LocalWP sites found for this plugin" + log_info "Run 'npm run localwp:create' to create one" + else + log_success "Synced $synced site(s)" + fi +} + +# Show info about all sites +show_info() { + echo "" + echo "LocalWP Sites for $PLUGIN_SLUG" + echo "===============================" + + for site_name in "$SINGLE_SITE_NAME" "$MULTISITE_NAME"; do + local site_path=$(get_site_path "$site_name") + + if site_exists "$site_name"; then + echo "" + echo " ${GREEN}✓${NC} $site_name" + echo " Path: $site_path" + + local plugin_path=$(get_plugin_path "$site_name") + if [ -d "$plugin_path" ]; then + echo " Plugin: ${GREEN}Installed${NC}" + else + echo " Plugin: ${YELLOW}Not synced${NC}" + fi + else + echo "" + echo " ${YELLOW}○${NC} $site_name (not created)" + fi + done + + echo "" + echo "Commands:" + echo " npm run localwp:create Create single site" + echo " npm run localwp:create:multisite Create multisite" + echo " npm run localwp:sync Sync plugin files" + echo " npm run localwp:reset Reset plugin files" + echo "" +} + +# Main command handler +case "${1:-}" in + create) + shift + create_site "$@" + ;; + sync) + sync_all + ;; + reset) + shift + reset_site "$@" + ;; + info) + show_info + ;; + *) + echo "LocalWP Integration Script" + echo "" + echo "Usage:" + echo " $0 create [--multisite] Create a new LocalWP site" + echo " $0 sync Sync plugin files to all sites" + echo " $0 reset [site-name] Reset site plugin to clean state" + echo " $0 info Show info about LocalWP sites" + echo "" + echo "npm scripts:" + echo " npm run localwp:create Create single site" + echo " npm run localwp:create:multisite Create multisite" + echo " npm run localwp:sync Sync plugin files" + echo " npm run localwp:reset Reset plugin files" + echo "" + echo "URL Patterns:" + echo " Single site: http://${PLUGIN_SLUG}-single.local" + echo " Multisite: http://${PLUGIN_SLUG}-multisite.local" + echo "" + exit 1 + ;; +esac diff --git a/bin/playground-test.sh b/bin/playground-test.sh new file mode 100755 index 0000000..680ceb6 --- /dev/null +++ b/bin/playground-test.sh @@ -0,0 +1,303 @@ +#!/bin/bash + +# WordPress Playground CLI Testing Script +# For use by AI coding assistants and developers +# +# This script provides a simple interface to start/stop WordPress Playground +# for local testing with the plugin. Uses @wp-playground/cli 3.0.22+ +# +# Usage: +# ./bin/playground-test.sh start [--multisite] [--port PORT] +# ./bin/playground-test.sh stop +# ./bin/playground-test.sh status +# +# Examples: +# npm run playground:start # Start single site on port 8888 +# npm run playground:start:multisite # Start multisite on port 8889 +# npm run playground:stop # Stop all playground instances +# npm run playground:status # Check if playground is running + +set -e + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +PID_FILE="$PROJECT_DIR/.playground.pid" +DEFAULT_PORT=8888 +MULTISITE_PORT=8889 +PLUGIN_SLUG="wp-plugin-starter-template" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Helper functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if @wp-playground/cli is installed +check_cli() { + if ! npx @wp-playground/cli --version > /dev/null 2>&1; then + log_error "@wp-playground/cli is not installed" + log_info "Run: npm install" + exit 1 + fi + local version=$(npx @wp-playground/cli --version 2>/dev/null) + log_info "Using @wp-playground/cli version: $version" +} + +# Create plugin zip for installation +create_plugin_zip() { + log_info "Creating plugin zip..." + mkdir -p "$PROJECT_DIR/dist" + + cd "$PROJECT_DIR" + zip -r "dist/$PLUGIN_SLUG.zip" . \ + -x "node_modules/*" \ + -x "dist/*" \ + -x ".git/*" \ + -x "vendor/*" \ + -x "tests/*" \ + -x "cypress/*" \ + -x "*.zip" \ + -x ".github/*" \ + -x ".agents/*" \ + -x ".wiki/*" \ + -x "reference-plugins/*" \ + > /dev/null 2>&1 + + log_success "Plugin zip created: dist/$PLUGIN_SLUG.zip" +} + +# Start WordPress Playground +start_playground() { + local multisite=false + local port=$DEFAULT_PORT + local blueprint="$PROJECT_DIR/playground/blueprint.json" + + # Parse arguments + while [[ $# -gt 0 ]]; do + case "$1" in + --multisite) + multisite=true + port=$MULTISITE_PORT + blueprint="$PROJECT_DIR/playground/multisite-blueprint.json" + shift + ;; + --port) + port="$2" + shift 2 + ;; + *) + shift + ;; + esac + done + + # Check if already running + if [ -f "$PID_FILE" ]; then + local old_pid=$(cat "$PID_FILE") + if kill -0 "$old_pid" 2>/dev/null; then + log_warning "Playground is already running (PID: $old_pid)" + log_info "Run 'npm run playground:stop' first to restart" + exit 1 + else + rm -f "$PID_FILE" + fi + fi + + # Check port availability + if lsof -i ":$port" > /dev/null 2>&1; then + log_error "Port $port is already in use" + exit 1 + fi + + check_cli + create_plugin_zip + + local mode="single site" + if [ "$multisite" = true ]; then + mode="multisite" + fi + + log_info "Starting WordPress Playground ($mode) on port $port..." + log_info "Blueprint: $blueprint" + + # Start the server in background + cd "$PROJECT_DIR" + npx @wp-playground/cli server \ + --blueprint "$blueprint" \ + --port "$port" \ + --login \ + > "$PROJECT_DIR/.playground.log" 2>&1 & + + local server_pid=$! + echo "$server_pid" > "$PID_FILE" + + # Wait for server to be ready + log_info "Waiting for server to be ready..." + local timeout=120 + local elapsed=0 + + while ! curl -s "http://localhost:$port" > /dev/null 2>&1; do + if [ $elapsed -ge $timeout ]; then + log_error "Timeout waiting for WordPress Playground to start" + log_info "Check logs: cat $PROJECT_DIR/.playground.log" + kill "$server_pid" 2>/dev/null || true + rm -f "$PID_FILE" + exit 1 + fi + + # Check if process is still running + if ! kill -0 "$server_pid" 2>/dev/null; then + log_error "Server process died unexpectedly" + log_info "Check logs: cat $PROJECT_DIR/.playground.log" + rm -f "$PID_FILE" + exit 1 + fi + + sleep 2 + elapsed=$((elapsed + 2)) + echo -ne "\r${BLUE}[INFO]${NC} Waiting... $elapsed/$timeout seconds" + done + + echo "" + log_success "WordPress Playground is ready!" + echo "" + echo "============================================" + echo " WordPress Playground ($mode)" + echo "============================================" + echo " URL: http://localhost:$port" + echo " Admin: http://localhost:$port/wp-admin/" + echo " Login: admin / password" + echo " PID: $server_pid" + echo "============================================" + echo "" + log_info "Run 'npm run playground:stop' to stop the server" + log_info "Logs: $PROJECT_DIR/.playground.log" +} + +# Stop WordPress Playground +stop_playground() { + if [ -f "$PID_FILE" ]; then + local pid=$(cat "$PID_FILE") + if kill -0 "$pid" 2>/dev/null; then + log_info "Stopping WordPress Playground (PID: $pid)..." + kill "$pid" 2>/dev/null || true + + # Wait for process to stop + local timeout=10 + local elapsed=0 + while kill -0 "$pid" 2>/dev/null && [ $elapsed -lt $timeout ]; do + sleep 1 + elapsed=$((elapsed + 1)) + done + + # Force kill if still running + if kill -0 "$pid" 2>/dev/null; then + log_warning "Force killing process..." + kill -9 "$pid" 2>/dev/null || true + fi + + log_success "WordPress Playground stopped" + else + log_warning "Process not running" + fi + rm -f "$PID_FILE" + else + log_warning "No PID file found. Playground may not be running." + fi + + # Clean up any orphaned processes on common ports + for port in $DEFAULT_PORT $MULTISITE_PORT; do + local orphan_pid=$(lsof -t -i ":$port" 2>/dev/null || true) + if [ -n "$orphan_pid" ]; then + log_info "Found process on port $port (PID: $orphan_pid), stopping..." + kill "$orphan_pid" 2>/dev/null || true + fi + done +} + +# Check status +check_status() { + echo "" + echo "WordPress Playground Status" + echo "============================" + + if [ -f "$PID_FILE" ]; then + local pid=$(cat "$PID_FILE") + if kill -0 "$pid" 2>/dev/null; then + log_success "Running (PID: $pid)" + else + log_warning "PID file exists but process not running" + rm -f "$PID_FILE" + fi + else + log_info "Not running (no PID file)" + fi + + echo "" + echo "Port Status:" + for port in $DEFAULT_PORT $MULTISITE_PORT; do + if lsof -i ":$port" > /dev/null 2>&1; then + local port_pid=$(lsof -t -i ":$port" 2>/dev/null || echo "unknown") + echo " Port $port: ${GREEN}IN USE${NC} (PID: $port_pid)" + + # Test if it's responding + if curl -s "http://localhost:$port" > /dev/null 2>&1; then + echo " └─ HTTP: ${GREEN}OK${NC}" + else + echo " └─ HTTP: ${RED}NOT RESPONDING${NC}" + fi + else + echo " Port $port: ${YELLOW}AVAILABLE${NC}" + fi + done + echo "" +} + +# Main command handler +case "${1:-}" in + start) + shift + start_playground "$@" + ;; + stop) + stop_playground + ;; + status) + check_status + ;; + *) + echo "WordPress Playground CLI Testing Script" + echo "" + echo "Usage:" + echo " $0 start [--multisite] [--port PORT] Start WordPress Playground" + echo " $0 stop Stop WordPress Playground" + echo " $0 status Check playground status" + echo "" + echo "npm scripts:" + echo " npm run playground:start Start single site" + echo " npm run playground:start:multisite Start multisite" + echo " npm run playground:stop Stop playground" + echo " npm run playground:status Check status" + echo "" + exit 1 + ;; +esac diff --git a/package.json b/package.json index 33ce822..07c980b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,14 @@ "test:e2e:multisite": "npm run setup:multisite && sleep 5 && npm run test:multisite:headless", "test:playground:single": "cypress run --spec cypress/e2e/playground-single-site.cy.js", "test:playground:multisite": "cypress run --spec cypress/e2e/playground-multisite.cy.js", + "playground:start": "bash bin/playground-test.sh start", + "playground:start:multisite": "bash bin/playground-test.sh start --multisite", + "playground:stop": "bash bin/playground-test.sh stop", + "playground:status": "bash bin/playground-test.sh status", + "localwp:create": "bash bin/localwp-setup.sh create", + "localwp:create:multisite": "bash bin/localwp-setup.sh create --multisite", + "localwp:sync": "bash bin/localwp-setup.sh sync", + "localwp:reset": "bash bin/localwp-setup.sh reset", "test:phpunit": "composer test", "test:phpunit:multisite": "WP_MULTISITE=1 composer test", "build": "./build.sh", @@ -51,9 +59,9 @@ "homepage": "https://github.com/wpallstars/wp-plugin-starter-template-for-ai-coding#readme", "devDependencies": { "@wordpress/env": "^8.12.0", - "@wp-playground/blueprints": "^1.0.28", - "@wp-playground/client": "^1.0.28", - "@wp-playground/cli": "^1.0.28", + "@wp-playground/blueprints": "^3.0.22", + "@wp-playground/client": "^3.0.22", + "@wp-playground/cli": "^3.0.22", "cypress": "^13.17.0", "eslint": "^8.57.0", "eslint-plugin-cypress": "^2.15.1" diff --git a/playground/blueprint.json b/playground/blueprint.json index 209be64..9b1f225 100644 --- a/playground/blueprint.json +++ b/playground/blueprint.json @@ -1,10 +1,13 @@ { "$schema": "https://playground.wordpress.net/blueprint-schema.json", - "landingPage": "/wp-admin/", + "landingPage": "/wp-admin/plugins.php", "login": true, + "preferredVersions": { + "php": "8.0", + "wp": "latest" + }, "features": { - "networking": true, - "phpVersion": "7.4" + "networking": true }, "steps": [ { @@ -12,16 +15,29 @@ "consts": { "WP_DEBUG": true, "WP_DEBUG_LOG": true, - "WP_DEBUG_DISPLAY": true + "WP_DEBUG_DISPLAY": true, + "SCRIPT_DEBUG": true } }, { - "step": "wp-cli", - "command": "wp plugin install plugin-toggle --activate" + "step": "installPlugin", + "pluginData": { + "resource": "wordpress.org/plugins", + "slug": "plugin-toggle" + }, + "options": { + "activate": true + } }, { - "step": "wp-cli", - "command": "wp plugin install kadence-blocks --activate" + "step": "installPlugin", + "pluginData": { + "resource": "wordpress.org/plugins", + "slug": "kadence-blocks" + }, + "options": { + "activate": true + } } ] } diff --git a/playground/multisite-blueprint.json b/playground/multisite-blueprint.json index c24fc72..000af2f 100644 --- a/playground/multisite-blueprint.json +++ b/playground/multisite-blueprint.json @@ -1,12 +1,13 @@ { "$schema": "https://playground.wordpress.net/blueprint-schema.json", - "landingPage": "/wp-admin/network/", + "landingPage": "/wp-admin/network/plugins.php", "login": true, + "preferredVersions": { + "php": "8.0", + "wp": "latest" + }, "features": { - "networking": { - "type": "subdirectory" - }, - "phpVersion": "7.4" + "networking": true }, "steps": [ { @@ -14,7 +15,8 @@ "consts": { "WP_DEBUG": true, "WP_DEBUG_LOG": true, - "WP_DEBUG_DISPLAY": true + "WP_DEBUG_DISPLAY": true, + "SCRIPT_DEBUG": true } }, { @@ -22,23 +24,29 @@ }, { "step": "wp-cli", - "command": "wp site create --slug=testsite" + "command": "wp site create --slug=testsite --title='Test Site'" }, { - "step": "wp-cli", - "command": "wp plugin install plugin-toggle" + "step": "installPlugin", + "pluginData": { + "resource": "wordpress.org/plugins", + "slug": "plugin-toggle" + }, + "options": { + "activate": true, + "networkActivate": true + } }, { - "step": "wp-cli", - "command": "wp plugin install kadence-blocks" - }, - { - "step": "wp-cli", - "command": "wp plugin activate plugin-toggle --network" - }, - { - "step": "wp-cli", - "command": "wp plugin activate kadence-blocks --network" + "step": "installPlugin", + "pluginData": { + "resource": "wordpress.org/plugins", + "slug": "kadence-blocks" + }, + "options": { + "activate": true, + "networkActivate": true + } } ] }