The MailPoet plugin monorepo.
If you have any questions or need help or support, please see the Support document.
The development environment is built on @wordpress/env (wp-env) plus Mailpit for email capture. Continue with the steps below to set it up. If you'd like to use the plugin code directly without wp-env, see the plugin's readme.
- Run
pnpm bootstrapto install dependencies, download WooCommerce test plugins, generate the wp-env override, and compile assets. - Add secrets to
.envfiles inmailpoetandmailpoet-premiumdirectories. Go to the Secret Store and look for "MailPoet: plugin .env". - Run
pnpm env:startto start wp-env and the Mailpit SMTP catcher. - Open the services:
- WordPress — http://localhost:8888 (admin user:
admin/password) - phpMyAdmin — http://localhost:8081
- Mailpit — http://localhost:8082 (captures all outgoing mail)
- WordPress — http://localhost:8888 (admin user:
✉️ Mail routing is configured automatically. Every
pnpm env:startruns.wp-env/scripts/configure-mailpoet-dev-smtp.phpvialifecycleScripts.afterStart, which points MailPoet's mailer at Mailpit (host.docker.internal:1026), seeds a default sender, and skips the MailPoet welcome wizard so it can't overwrite the config. Newsletters land in Mailpit without any wp-admin setup. See doc/mailpit-setup.md for details.
- Docker Desktop (wp-env and
tests_env/both use Docker). - PHP as per
composer.jsonrequirements (used for host-side QA and the prefixer). - Node.js as specified by
.nvmrc. For automatic management use nvm, FNM, or Volta. - pnpm as specified in
package.json. For automatic setup enable Corepack usingcorepack enable. - GitHub CLI (
gh) for downloading private WooCommerce test plugins. Rungh auth loginto authenticate — no personal access token needed. External contributors without access can skip the download step; the bootstrap script treats those failures as non-fatal.
@wordpress/env is pinned to ≥ 11.4 in package.json. Earlier 10.x versions are missing wp-env destroy --force and the testsEnvironment flag that this project relies on, so do not downgrade.
All commands below run from the repository root. The same scripts are also exposed inside mailpoet/ and mailpoet-premium/ so pnpm <task> works from either plugin directory too. pnpm -w <task> runs the root-level script from anywhere in the workspace.
pnpm env:start # Start wp-env + Mailpit (boots the dev environment)
pnpm env:stop # Stop wp-env + Mailpit (state preserved)
pnpm env:destroy # Stop and delete all wp-env data + Mailpit
pnpm env:restart # Destroy + start (fresh WordPress install)
pnpm env:debug # Start with Xdebug enabled on port 9003
pnpm env:logs # Tail logs from all wp-env containers
pnpm shell # Bash into the wp-env cli container
pnpm shell:test # Bash into the tests_env wordpress container
pnpm wp <args> # Run wp-cli inside the wp-env containerpnpm compile # Compile JS + CSS on host
pnpm compile:js # Compile JS only
pnpm compile:css # Compile SCSS only
pnpm watch:js # Rebuild JS on change
pnpm watch:css # Rebuild SCSS on changepnpm qa # All QA checks (PHP + JS + CSS + Prettier)
pnpm qa:js # ESLint + TypeScript type-check
pnpm qa:css # Stylelint
pnpm qa:php # PHP CodeSniffer
pnpm qa:phpstan # PHPStan static analysis
pnpm qa:prettier # Prettier (check only)
pnpm qa:fix # Prettier (write) — auto-format all filespnpm test:unit # Unit tests (tests_env)
pnpm test:integration # Integration tests (tests_env)
pnpm test:acceptance # Acceptance tests with Selenium (tests_env)
pnpm test:javascript # Mocha JS tests
pnpm test:unit:premium # Premium unit tests
pnpm test:integration:premium # Premium integration tests
pnpm test:acceptance:premium # Premium acceptance tests
pnpm test:install-deps # Re-install composer deps before testing
# (default test:* scripts pass --skip-deps)Pass test-runner flags directly — the pnpm scripts forward them to the underlying test command:
pnpm test:integration --file=tests/integration/WP/EmojiTest.php
pnpm test:acceptance --file=tests/acceptance/Misc/MailpoetMenuCest.phppnpm shell:test
cd /wp-core/wp-content/plugins/mailpoet-premium
./do test:unit --file=tests/unit/Config/EnvTest.phpThese need a running WordPress runtime, so they go through the wp-env cli container automatically:
pnpm migrations:new <db|app> # Create a new database migration
pnpm migrations:status # Show migration status
pnpm templates # Generate email template classes
pnpm changelog:add --type=<type> --description="..."Xdebug is off by default (performance). Start the dev environment with Xdebug enabled:
pnpm env:debugThis runs wp-env start --update --xdebug=develop,debug. Xdebug listens on port 9003 inside the container.
- Settings → PHP → Servers, click + to add:
- Name:
wp-env - Host:
localhost - Port:
8888 - Debugger:
Xdebug - Check Use path mappings
- Name:
- Add the mappings:
<repo root>/mailpoet → /var/www/html/wp-content/plugins/mailpoet <repo root>/mailpoet-premium → /var/www/html/wp-content/plugins/mailpoet-premium - Click the phone icon to Start Listening for PHP Debug Connections.
- Trigger Xdebug with the JetBrains browser extension or append
?XDEBUG_TRIGGER=1to the URL.
For debugging cron jobs, pass &XDEBUG_TRIGGER=yes in the cron request URL.
Install the PHP Debug extension and add to .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/wp-content/plugins/mailpoet": "${workspaceFolder}/mailpoet",
"/var/www/html/wp-content/plugins/mailpoet-premium": "${workspaceFolder}/mailpoet-premium"
}
}
]
}Integration tests run in tests_env/ (not wp-env), so they use a separate server config:
-
Settings → PHP → Servers, add a new server
MailPoetTest, hostlocalhost, port80, with mappings:wordpress → /wp-core mailpoet → /wp-core/wp-content/plugins/mailpoet mailpoet-premium → /wp-core/wp-content/plugins/mailpoet-premium mailpoet/vendor/bin/codecept → /project/vendor/bin/codecept mailpoet/vendor/bin/wp → /usr/local/bin/wp -
Add
XDEBUG_TRIGGER: 1to thecodeception_*service intests_env/docker/docker-compose.ymlto trigger Xdebug during tests. -
Click the phone icon in PhpStorm to listen for connections.
We use Husky to run automated checks in pre-commit hooks.
If you use NVM for Node version management you may need to create or update ~/.huskyrc:
# Loads nvm.sh and sets the correct PATH before running the hooks:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"Without it, some Git clients fail on hook execution.
We use Prettier for consistent formatting:
pnpm qa:fix # Auto-format all files (Prettier write)
pnpm qa:prettier # Check formatting (read-only)