Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a605cbe
Sync branch [skip ci]
pirate-bot May 19, 2026
83a702e
Sync branch [skip ci]
pirate-bot May 19, 2026
cb8f57a
fix: preserve selected page status and template across maintenance mo…
Alexia-Soare Jul 16, 2026
2c25e1a
fix: never overwrite user-owned pages when applying a maintenance tem…
Alexia-Soare Jul 17, 2026
941315a
fix: harden maintenance page bootstrap and template import
Alexia-Soare Jul 17, 2026
820e2b3
fix: never resurrect or re-trash a trashed maintenance page selection
Alexia-Soare Jul 17, 2026
f79bbc5
test: cover the full issue #523 workflow through the select-page handler
Alexia-Soare Jul 17, 2026
41961be
ci: run PHPUnit on PHP 7.4, required by the latest WordPress test suite
Alexia-Soare Jul 17, 2026
383dfda
test: drop the issue number from the test name and comments
Alexia-Soare Jul 20, 2026
e8a06d6
fix: restore abandoned selections, clean up trashed pages, record ato…
Alexia-Soare Jul 21, 2026
c51c768
Sync branch [skip ci]
pirate-bot Jul 21, 2026
e438144
fix: remove trailing comma for PHP 7.1 compatibility
girishpanchal30 Jul 22, 2026
8be83d3
fix: update PHPUnit job to support multiple PHP and WP versions
girishpanchal30 Jul 22, 2026
475d3dc
fix: reset template import status on request failure
girishpanchal30 Jul 22, 2026
82a968a
fix: handle missing import step error alert
girishpanchal30 Jul 22, 2026
5b1f2e4
fix: improve bot avatar and chat layout on mobile
girishpanchal30 Jul 22, 2026
c5e408c
fix: remove trailing comma for PHP compatibility
girishpanchal30 Jul 23, 2026
617cb0d
feat: add wp-env, PHPUnit and Playwright testing setup with Copilot s…
Alexia-Soare Jul 24, 2026
9b6fd08
Merge remote-tracking branch 'origin/development' into fix/523-preser…
Alexia-Soare Jul 28, 2026
0aede9e
fix: satisfy PHPStan on the page-state additions
Alexia-Soare Jul 28, 2026
dab296c
fix: never override user status changes and keep the state record atomic
Alexia-Soare Jul 28, 2026
97d3836
fix: keep a private status the user chooses while maintenance is active
Alexia-Soare Jul 29, 2026
68873ca
fix: keep the page status when overwriting a generated page with a te…
Alexia-Soare Jul 29, 2026
418148e
fix: route every selection change through one take-over lifecycle
Alexia-Soare Jul 29, 2026
66f5f3d
fix: hand the selected page back when the design tab is reset
Alexia-Soare Jul 29, 2026
d8c833d
Merge pull request #524 from Codeinwp/fix/523-preserve-selected-page-…
selul Jul 29, 2026
3d11f36
Merge pull request #531 from Codeinwp/bugfix/506
selul Jul 29, 2026
f75b76f
Merge pull request #529 from Codeinwp/bugfix/527
selul Jul 29, 2026
8aea4d3
Merge development into bugfix/526 and resolve workflow conflict
Copilot Jul 29, 2026
ac50c64
ci: set least-privilege token permissions in PHP tests workflow
Copilot Jul 29, 2026
ac6813d
Merge pull request #528 from Codeinwp/bugfix/526
selul Jul 29, 2026
ef4d270
Sync branch: merge master into development
selul Jul 29, 2026
fe9e02d
Merge pull request #538 from Codeinwp/sync/master-to-development-533
selul Jul 29, 2026
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
9 changes: 9 additions & 0 deletions .distignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,12 @@ assets/vue
yarn.lock
.eslintrc
CONTRIBUTING.md
AGENTS.md
phpstan.neon
phpstan-baseline.neon
.wp-env.json
.wp-env.override.json
.phpunit.result.cache
artifacts
playwright-report
test-results
4 changes: 2 additions & 2 deletions .github/workflows/build-dev-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
node-version: [20.x]
outputs:
branch-name: ${{ steps.retrieve-branch-name.outputs.branch_name }}
git-sha-8: ${{ steps.retrieve-git-sha-8.outputs.sha8 }}
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
- name: Install composer deps
run: composer install --no-dev --prefer-dist --no-progress --no-suggest
- name: Install yarn deps
run: yarn install --frozen-lockfile
run: yarn install --frozen-lockfile --ignore-engines
- name: Build files
run: yarn run build
- name: Create zip
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "Copilot Setup Steps"

on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml

jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read

# These steps run before the Copilot coding agent starts, so the agent
# boots into a checkout with a running wp-env instance and both test
# suites (npm run test:unit:php:base / npm run test:e2e) ready to use.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "22"
cache: "yarn"
- name: Install JS deps
run: |
yarn install --frozen-lockfile --ignore-engines
- name: Install Playwright
run: |
npx playwright install --with-deps chromium
- name: Setup PHP with tools
uses: shivammathur/setup-php@v2
with:
php-version: "7.4"
extensions: simplexml, mysql, mbstring, curl
tools: wp-cli
- name: Install composer deps
run: composer install --no-progress
- name: Start the WordPress environment via wp-env
run: |
yarn run env:start
4 changes: 2 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
node-version: [20.x]
steps:
- uses: actions/checkout@master
- name: Build files using ${{ matrix.node-version }}
Expand All @@ -19,7 +19,7 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: Build
run: |
yarn install --frozen-lockfile
yarn install --frozen-lockfile --ignore-engines
yarn run build
composer install --no-dev --prefer-dist --no-progress --no-suggest
- name: WordPress Plugin Deploy
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Test E2E

on:
pull_request:
types: [opened, synchronize, ready_for_review]

concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
e2e:
name: Playwright
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: "yarn"
- name: Setup PHP version
uses: shivammathur/setup-php@v2
with:
php-version: "7.4"
- name: Install composer
run: composer install --prefer-dist --no-progress
- name: Install JS deps
run: |
yarn install --frozen-lockfile --ignore-engines
- name: Install Playwright
run: |
npx playwright install --with-deps chromium
- name: Setup WP Env
run: |
yarn run env:start
- name: Run Playwright tests
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: true
run: |
yarn run test:e2e
- name: Upload tests artifacts
if: failure()
uses: actions/upload-artifact@v7
with:
name: artifacts-e2e
path: ./artifacts
retention-days: 3
39 changes: 33 additions & 6 deletions .github/workflows/test-php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
phplint:
name: PHP Lint
Expand All @@ -15,9 +17,9 @@ jobs:
- name: Setup PHP version
uses: shivammathur/setup-php@v2
with:
php-version: '7.2'
# the modern sniffer stack needs PHP 7.4+ and a current composer
php-version: '7.4'
extensions: simplexml
tools: composer:v2.1
- name: Checkout source code
uses: actions/checkout@v2
- name: Get Composer Cache Directory
Expand All @@ -36,9 +38,33 @@ jobs:
- name: Run PHPCS
run: composer run lint

phpstan:
name: PHPStan
runs-on: ubuntu-latest
steps:
- name: Setup PHP version
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
extensions: simplexml
- name: Checkout source code
uses: actions/checkout@v6
- name: Install composer
run: composer install --prefer-dist --no-progress
- name: PHPStan Static Analysis
run: composer run phpstan

phpunit:
name: PHPUnit
name: PHPUnit (PHP ${{ matrix.php-version }}, WP ${{ matrix.wp-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- php-version: '7.2'
wp-version: '6.4'
- php-version: '7.4'
wp-version: 'latest'
services:
mysql:
image: mysql:5.7
Expand All @@ -51,16 +77,17 @@ jobs:
- name: Setup PHP version
uses: shivammathur/setup-php@v2
with:
php-version: '7.2'
# the latest WordPress test suite requires PHP 7.4+
php-version: '7.4'
extensions: simplexml, mysql
tools: phpunit:7.5.20, phpunit-polyfills
tools: phpunit-polyfills
- name: Checkout source code
uses: actions/checkout@v2
- name: Install Subversion
run: sudo apt-get update && sudo apt-get install -y subversion
- name: Install WordPress Test Suite
run: |
bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:${{ job.services.mysql.ports['3306'] }}
bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:${{ job.services.mysql.ports['3306'] }} ${{ matrix.wp-version }}
- name: Get Composer Cache Directory
id: composer-cache
run: |
Expand Down
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,14 @@ artifact
# build assets files
assets/js/*.min.js
assets/css/*.min.css

### yarn.lock is the tracked lockfile; npm's lockfile must never be committed
### (npm install also rewrites yarn.lock into a format yarn 1 cannot parse)
package-lock.json

### wp-env / tests
.wp-env.override.json
.phpunit.result.cache
artifacts/
playwright-report/
test-results/
16 changes: 16 additions & 0 deletions .wp-env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"core": null,
"phpVersion": "7.4",
"testsEnvironment": false,
"plugins": [ "." ],
"config": {
"WP_DEBUG": true,
"WP_DEBUG_LOG": true,
"WP_DEBUG_DISPLAY": false,
"SCRIPT_DEBUG": true,
"FS_METHOD": "direct"
},
"lifecycleScripts": {
"afterStart": "bash bin/wp-env-setup.sh"
}
}
64 changes: 54 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,33 @@ WP Maintenance Mode (LightStart) is a WordPress plugin by Themeisle that display
## Commands

```bash
# Install dependencies
# Install dependencies (yarn.lock is the tracked lockfile; package-lock.json is
# ignored, and --ignore-engines is needed because the legacy eslint toolchain
# caps its node engines range below current node versions)
composer install
npm install
yarn install --frozen-lockfile --ignore-engines

# Lint (PHP_CodeSniffer with WordPress coding standards)
composer run lint
# Environment (wp-env, requires Docker)
npm run env:start # reuse a running instance, or pick a free port + start
npm run env:stop
npm run env:cleanup # remove THIS checkout's containers/volumes (run before deleting a worktree)

# Auto-fix coding standards
composer run format
# Lint / format (PHP_CodeSniffer with WordPress coding standards)
composer run lint # on the host
npm run lint:php # same, inside the wp-env container
npm run format:php

# Run PHPUnit tests
./vendor/bin/phpunit
# Static analysis (PHPStan level 6, WordPress stubs)
composer run phpstan
composer run phpstan:generate:baseline # refresh phpstan-baseline.neon after intentional changes

# Run a single test file
./vendor/bin/phpunit tests/generic-test.php
# PHP unit tests (run inside wp-env; no local MySQL/SVN setup needed)
npm run test:unit:php # start env + run the suite
npm run test:unit:php:base # run the suite against an already-running env

# E2E tests (Playwright; needs `npx playwright install chromium` once)
npm run test:e2e
npm run test:e2e:ui # interactive UI mode

# Build assets (minify JS + CSS via Grunt)
npm run build # or: npx grunt
Expand All @@ -30,6 +42,38 @@ npm run build # or: npx grunt
npx grunt watch
```

Configs: PHPUnit `phpunit.xml` (+ `tests/bootstrap.php`), Playwright `tests/e2e/playwright.config.js`, wp-env `.wp-env.json` + gitignored `.wp-env.override.json`, PHPStan `phpstan.neon` + `phpstan-baseline.neon` (stubs for optional integrations and dynamic constants live in `tests/static-analysis-stubs/`, loaded only during analysis).

## wp-env Instance

Single environment (`"testsEnvironment": false`): one `wordpress`/`cli`/`mysql` container set serves dev, PHPUnit, and E2E. Login: `admin`/`password`. Port precedence everywhere: `WP_BASE_URL` > `WP_ENV_PORT` > `.wp-env.override.json` > `8888` — `npm run env:start` (`bin/wp-env-up.js`) probes for a free port and pins it in the override file, which the Playwright config reads too.

- PHPUnit runs in the container with `WORDPRESS_TABLE_PREFIX=wptests_` (baked into `test:unit:php:base`). Never drop that prefix override: the container's tests config otherwise points at the dev site's own `wp_` tables and the suite install WIPES the site.
- `bin/wp-env-setup.sh` (wp-env `afterStart`) sets pretty permalinks, provisions the plugin's default settings, and disables the setup-wizard redirect plus the block-based "new look" (`wpmm_new_look=0`) so the classic settings screens are testable. While `wpmm_settings` is missing, the plugin re-flags the install as fresh on every request — provision settings before touching `wpmm_fresh_install`.
- The environment runs with `SCRIPT_DEBUG=true`, so unminified assets load and no Grunt build is needed for tests; `WPMM_ASSETS_SUFFIX` is empty in this mode.

## E2E Rules (Important)

- `workers: 1`, always. Maintenance mode is a site-wide option; virtually every spec flips global state. Do not raise the worker count or add `fullyParallel`.
- Specs must leave maintenance mode OFF when they finish, or every later spec sees the 503 page.
- Use the helpers in `tests/e2e/utils.js` (`setMaintenanceMode`, `activateSettingsTab`, `saveSettingsForm`, `openAsVisitor`) instead of hand-rolling admin flows. They encode three non-obvious constraints:
- After any settings save (form POST + redirect), headless Chromium stops producing animation frames for the page, so non-`force` Playwright interactions hang on the "element is stable" actionability check. Helpers use `force: true` plus explicit state assertions.
- The settings tabs are hash-driven; navigating to the hash-less settings URL is a same-document navigation, so the previously active tab persists. Always `activateSettingsTab` explicitly.
- The save redirect lands on `?updated=1#<tab>` and WordPress strips the query right after load — wait for the redirect response, not the URL.
- Visitor contexts: `browser.newContext()` inherits the admin `storageState`; `openAsVisitor` clears cookies to get a real logged-out visitor.

## Testing Practices (TDD)

- Red → green: write the failing test first, then only enough code to make it pass. One seam, one test, one minimal implementation per cycle — don't batch-write tests for imagined behavior (vertical slices, not horizontal). Refactoring is a separate review-stage step, not part of the loop.
- Test behavior through public seams, never internals: the admin-ajax endpoints (`wp_ajax_wpmm_*`), public helpers (`includes/functions/helpers.php`), rendered frontend output, and the settings screens. If a test breaks when you refactor but behavior hasn't changed, it's testing the wrong thing.
- Expected values must come from an independent source of truth (a known-good literal, the spec, a worked example) — never recompute them the way the code does.
- Plugin-specific seams and traps (see `tests/ajax-api-test.php`):
- Several AJAX handlers guard with plain `die( $msg )` (not `wp_die`); those guard paths CANNOT be exercised through `_handleAjax` — a plain `die()` kills the PHPUnit process with exit code 0.
- Handlers wrapped in `catch ( Exception )` swallow the suite's die-exception and answer twice; the test class installs a die handler that throws `WPMM_Ajax_Die_Signal extends Error` instead.
- `_handleAjax()` fires `admin_init` without defining `DOING_AJAX`; keep `maybe_redirect` unhooked in tests or a fresh-install flag turns it into a process-killing wizard redirect.
- The WP suite auto-excludes tests annotated `@group ajax` — don't add that annotation.
- wp-env's sender address `wordpress@localhost` fails PHPMailer validation; filter `wp_mail_from` in mail tests.

## Architecture

### Entry Point & Bootstrap
Expand Down
5 changes: 4 additions & 1 deletion assets/css/style.bot.css
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,15 @@ CHAT BOT STYLING

@media screen and (max-width: 700px) {
.bot-avatar {
display: none !important;
width: 50px;
height: 50px;
}

.bot-chat-wrapper,
.bg-image .bot-chat-wrapper {
padding: 20px;
width: 85%;
height: 60%;
}

.bg-image .bot-chat-wrapper {
Expand Down
Loading
Loading