Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ steps:
command: |
buildkite-agent artifact download dist.tar.gz .
tar -xzf dist.tar.gz
echo "--- :wordpress: Starting wp-env"
make wp-env-start
echo "--- :performing_arts: Running E2E tests"
make test-e2e
plugins: *plugins

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ playwright-report/
.wp-env.credentials.json
wp-env/mu-plugins/*
!wp-env/mu-plugins/gutenbergkit-cors.php
!wp-env/mu-plugins/gutenbergkit-jetpack-blocks.php

# Claude
.claude/settings.local.json
3 changes: 2 additions & 1 deletion .wp-env.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"config": {
"WP_DEBUG": true,
"WP_DEBUG_LOG": true
"WP_DEBUG_LOG": true,
"WP_ENVIRONMENT_TYPE": "local"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure application passwords are enabled for the non-TLS environment.

}
}
18 changes: 10 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ preview: npm-dependencies ## Preview the production build locally
################################################################################

.PHONY: wp-env-start
wp-env-start: npm-dependencies ## Start the local WordPress environment (requires Docker; RESET=1 to regenerate credentials)
npm run wp-env start
wp-env-start: npm-dependencies ## Start the local WordPress environment (RESET=1 to regenerate credentials)
npm run wp-env start -- --runtime=playground
@RESET=$(RESET) bash bin/wp-env-setup.sh

.PHONY: wp-env-stop
Expand All @@ -153,13 +153,15 @@ wp-env-clean: ## Stop wp-env and remove all data (fresh start)
npm run wp-env destroy
@rm -f .wp-env.credentials.json

.PHONY: wp-env-logs
wp-env-logs: ## Show wp-env WordPress logs
npm run wp-env logs
.PHONY: wp-env-android
wp-env-android: ## Remap wp-env site URLs for the Android emulator and restart
@cp wp-env/android-url-override.php wp-env/mu-plugins/gutenbergkit-android-urls.php
@RESET=1 $(MAKE) wp-env-start

.PHONY: wp-env-cli
wp-env-cli: ## Run a WP-CLI command in wp-env (usage: make wp-env-cli CMD="post list")
npm run wp-env run cli wp $(CMD)
.PHONY: wp-env-android-reset
wp-env-android-reset: ## Remove the Android emulator URL remap and restart
@rm -f wp-env/mu-plugins/gutenbergkit-android-urls.php
@RESET=1 $(MAKE) wp-env-start

################################################################################
# Code Quality Targets
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">10.0.2.2</domain>
</domain-config>
</network-security-config>
</network-security-config>
89 changes: 75 additions & 14 deletions bin/wp-env-setup.sh
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in the description and code comments, these changes largely relate to circumventing WordPress Playground's lack of support for the wp-env run capability. We must instead rely upon the REST API.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
# Creates an application password for the admin user and writes the credentials
# to .wp-env.credentials.json so the demo apps can connect automatically.
#
# This script uses only REST API calls (no WP-CLI / wp-env run), so it works
# with both the Docker and Playground runtimes.
#
# Usage:
# bash bin/wp-env-setup.sh # Create credentials (skips if file exists)
# RESET=1 bash bin/wp-env-setup.sh # Recreate credentials from scratch
Expand All @@ -17,6 +20,7 @@ CREDENTIALS_FILE="$PROJECT_ROOT/.wp-env.credentials.json"

SITE_URL="http://localhost:8888"
USERNAME="admin"
PASSWORD="password"
APP_NAME="GutenbergKit"

# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -61,29 +65,86 @@ for i in $(seq 1 $MAX_RETRIES); do
done

# ---------------------------------------------------------------------------
# Ensure pretty permalinks are active so /wp-json/ works
# Create application password via REST API
#
# Uses cookie-based authentication:
# 1. Log in via wp-login.php to obtain a session cookie.
# 2. Fetch a REST nonce from admin-ajax.php.
# 3. POST to the application-passwords endpoint with the cookie + nonce.
#
# The Playground runtime may still be processing Blueprint steps (installing
# plugins, rewriting wp-config.php) when the server starts accepting requests.
# This means application passwords may not be available yet. We retry the
# entire flow until it succeeds or we exceed the retry limit.
# ---------------------------------------------------------------------------

echo "Flushing rewrite rules..."
npm run --silent wp-env run cli -- wp rewrite structure '/%postname%/' --hard 2>/dev/null
echo "Creating application password for '$USERNAME'..."

# ---------------------------------------------------------------------------
# Enable Jetpack blocks module
# ---------------------------------------------------------------------------
COOKIE_JAR=$(mktemp)
trap 'rm -f "$COOKIE_JAR"' EXIT

echo "Enabling Jetpack blocks module..."
npm run --silent wp-env run cli -- wp jetpack module activate blocks 2>/dev/null
APP_PASSWORD=""
CREATE_MAX_RETRIES=15
CREATE_RETRY_INTERVAL=2

# ---------------------------------------------------------------------------
# Create application password
# ---------------------------------------------------------------------------
for attempt in $(seq 1 $CREATE_MAX_RETRIES); do
# Reset cookie jar for each attempt.
# WordPress requires the test cookie to be present in the login request.
printf "localhost\tFALSE\t/\tFALSE\t0\twordpress_test_cookie\tWP%%20Cookie%%20check\n" > "$COOKIE_JAR"

echo "Creating application password for '$USERNAME'..."
# Step 1: Log in to get a session cookie.
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-c "$COOKIE_JAR" -b "$COOKIE_JAR" \
-d "log=$USERNAME&pwd=$PASSWORD&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F&testcookie=1" \
"$SITE_URL/wp-login.php")

APP_PASSWORD=$(npm run --silent wp-env run cli -- wp user application-password create "$USERNAME" "$APP_NAME" --porcelain 2>/dev/null)
if [ "$HTTP_STATUS" != "302" ]; then
echo " Attempt $attempt/$CREATE_MAX_RETRIES: Login returned HTTP $HTTP_STATUS (expected 302), retrying..."
sleep $CREATE_RETRY_INTERVAL
continue
fi

# Step 2: Fetch a REST nonce.
REST_NONCE=$(curl -s -b "$COOKIE_JAR" "$SITE_URL/wp-admin/admin-ajax.php?action=rest-nonce")

if [ -z "$REST_NONCE" ] || [ "$REST_NONCE" = "0" ]; then
echo " Attempt $attempt/$CREATE_MAX_RETRIES: Failed to obtain REST nonce, retrying..."
sleep $CREATE_RETRY_INTERVAL
continue
fi

# Step 3: Create the application password.
# Use ?rest_route= format so this works regardless of permalink structure.
RESPONSE=$(curl -s \
-b "$COOKIE_JAR" \
-H "X-WP-Nonce: $REST_NONCE" \
-H "Content-Type: application/json" \
-d "{\"name\":\"$APP_NAME\"}" \
"$SITE_URL/?rest_route=/wp/v2/users/me/application-passwords")

# Extract the password from the JSON response.
# The password field is only returned at creation time.
# Use Node.js for JSON parsing since it's guaranteed to be available (wp-env requires it).
APP_PASSWORD=$(echo "$RESPONSE" | node -e "
let data = '';
process.stdin.on('data', chunk => data += chunk);
process.stdin.on('end', () => {
try { process.stdout.write(JSON.parse(data).password); }
catch { process.exit(1); }
});
") || true

if [ -n "$APP_PASSWORD" ]; then
break
fi

echo " Attempt $attempt/$CREATE_MAX_RETRIES: Application password not available yet, retrying..."
sleep $CREATE_RETRY_INTERVAL
done

if [ -z "$APP_PASSWORD" ]; then
echo "Error: Failed to create application password."
echo "Error: Failed to create application password after $CREATE_MAX_RETRIES attempts."
echo "Last response: $RESPONSE"
exit 1
fi

Expand Down
45 changes: 19 additions & 26 deletions docs/code/local-wordpress.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

GutenbergKit includes a local WordPress environment powered by [`@wordpress/env`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) (wp-env). This gives developers a zero-config way to run the full editor experience locally, including theme styles, media uploads, and plugin block assets.

The environment uses the [WordPress Playground](https://wordpress.github.io/wordpress-playground/) runtime, which runs WordPress entirely in WebAssembly — no Docker required.

## Prerequisites

- [Docker](https://www.docker.com/) must be installed and running.
- Node.js and npm (already required for GutenbergKit development).

## Quick Start
Expand All @@ -17,21 +18,21 @@ make wp-env-start
This command:

1. Installs npm dependencies (if needed).
2. Starts Docker containers running WordPress at **http://localhost:8888**.
2. Starts a WordPress Playground instance at **http://localhost:8888**.
3. Creates an application password for the `admin` user.
4. Writes credentials to `.wp-env.credentials.json` (gitignored).

Once started, the **"Local WordPress"** option in both the iOS and Android demo apps will automatically connect to the local environment.

## Available Commands

| Command | Description |
| --------------------------- | -------------------------------------------------------------- |
| `make wp-env-start` | Start the environment and provision credentials |
| `make wp-env-stop` | Stop the environment (preserves data) |
| `make wp-env-clean` | Destroy the environment and remove all data |
| `make wp-env-logs` | View WordPress debug logs |
| `make wp-env-cli CMD="..."` | Run a WP-CLI command (e.g., `make wp-env-cli CMD="post list"`) |
| Command | Description |
| --------------------------- | ------------------------------------------------------- |
| `make wp-env-start` | Start the environment and provision credentials |
| `make wp-env-stop` | Stop the environment (preserves data) |
| `make wp-env-clean` | Destroy the environment and remove all data |
| `make wp-env-android` | Restart with site URL remapped for the Android emulator |
| `make wp-env-android-reset` | Restart with the default localhost site URL |

## How It Works

Expand All @@ -40,7 +41,7 @@ Once started, the **"Local WordPress"** option in both the iOS and Android demo
The `.wp-env.json` file at the project root configures the environment:

- **Gutenberg plugin** is installed for the `/wp-block-editor/v1/settings` editor settings REST API endpoint.
- **Jetpack plugin** is installed with the blocks module enabled, providing the `/wpcom/v2/editor-assets` endpoint and additional editor blocks.
- **Jetpack plugin** is installed with the blocks module auto-activated via a mu-plugin (`wp-env/mu-plugins/gutenbergkit-jetpack-blocks.php`), providing the `/wpcom/v2/editor-assets` endpoint and additional editor blocks.
- A **CORS mu-plugin** (`wp-env/mu-plugins/gutenbergkit-cors.php`) adds CORS headers to REST API responses, allowing requests from the Vite dev server, preview server, and native WebViews.
- **WP_DEBUG** and **WP_DEBUG_LOG** are enabled for development.

Expand All @@ -49,7 +50,7 @@ The `.wp-env.json` file at the project root configures the environment:
The `bin/wp-env-setup.sh` script runs automatically after `wp-env start`:

1. Waits for WordPress to be ready (health check with retries).
2. Creates an application password for the `admin` user via WP-CLI.
2. Creates an application password for the `admin` user via the REST API.
3. Generates a Base64-encoded Basic Auth header.
4. Writes credentials to `.wp-env.credentials.json`.

Expand Down Expand Up @@ -79,21 +80,21 @@ The Android emulator cannot reach `localhost` on the host machine directly. The

WordPress generates image URLs (e.g., for uploaded media) using its configured site URL, which defaults to `http://localhost:8888`. These URLs don't resolve inside the Android emulator because `localhost` points to the emulator itself.

To fix this, update WordPress's site URL constants to use `10.0.2.2` before testing media uploads:
To fix this, activate a mu-plugin that remaps URLs and restart wp-env:

```bash
make wp-env-cli CMD="config set WP_SITEURL http://10.0.2.2:8888"
make wp-env-cli CMD="config set WP_HOME http://10.0.2.2:8888"
make wp-env-android
```

This installs a mu-plugin (`gutenbergkit-android-urls.php`) that rewrites `localhost` and `127.0.0.1` to `10.0.2.2` in WordPress's site URL output, then restarts wp-env and regenerates credentials. After restarting, rebuild the Android app so the new credentials are baked into `BuildConfig`.

To revert (for browser access or iOS testing):

```bash
make wp-env-cli CMD="config set WP_SITEURL http://localhost:8888"
make wp-env-cli CMD="config set WP_HOME http://localhost:8888"
make wp-env-android-reset
```

Note: wp-env defines `WP_SITEURL` and `WP_HOME` as constants in `wp-config.php`, so `wp option update` will not work — use `wp config set` instead. Changing the site URL to `10.0.2.2` will cause the WordPress admin dashboard (`http://localhost:8888/wp-admin/`) to redirect to `10.0.2.2`, which doesn't resolve in a desktop browser.
Note: While the URL override is active, the WordPress admin dashboard (`http://localhost:8888/wp-admin/`) will redirect to `10.0.2.2`, which doesn't resolve in a desktop browser.

### Physical Devices

Expand All @@ -112,14 +113,6 @@ Access the WordPress admin dashboard at **http://localhost:8888/wp-admin/**:

## Troubleshooting

### Docker is not running

```
Error: Cannot connect to the Docker daemon
```

Make sure Docker is running before executing `make wp-env-start`.

### Port 8888 is already in use

```
Expand Down Expand Up @@ -147,6 +140,6 @@ make wp-env-start

If the demo apps show "Local WordPress not available", verify:

1. wp-env is running: `make wp-env-logs`
1. wp-env is running (`make wp-env-start`).
2. The credentials file exists: `cat .wp-env.credentials.json`
3. For Android, rebuild the app after `make wp-env-start` so credentials are baked into `BuildConfig`.
83 changes: 0 additions & 83 deletions docs/test-cases.md
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All test cases were automated or removed as unrelated to GutenbergKit's domain—e.g., post publishing belongs in host, pattern insertion/gradient selection is largely Gutenberg code.

This file was deleted.

Binary file added e2e/assets/test-audio.mp3
Binary file not shown.
Binary file added e2e/assets/test-file.pdf
Binary file not shown.
Binary file added e2e/assets/test-image-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added e2e/assets/test-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added e2e/assets/test-video.mp4
Binary file not shown.
Loading
Loading