$npx -y skills add Lonsdale201/wp-agent-skills --skill wp-docker-compose-stackBuild a custom docker-compose development stack for WordPress when wp-env's abstraction runs out — Redis object cache, Mailpit SMTP capture, custom PHP extensions (phpredis, Xdebug), php.ini overrides. Covers the official wordpress image's runtime-env config model (wp-config.php
| 1 | # A custom docker-compose stack for WordPress |
| 2 | |
| 3 | Hand-write a compose stack when you need services the official tooling doesn't model: Redis object cache, SMTP capture, custom PHP extensions, production-like topology. **Default to `wp-env` first** (see `wp-env-local-dev`) — it covers plain plugin/block development with less to maintain. This skill is the escape hatch, grounded against a fully booted and verified stack (WordPress + MariaDB + Redis + Mailpit + wp-cli, drop-in connected, mail captured). The complete tested files are bundled under `examples/`. |
| 4 | |
| 5 | ## When to use this skill |
| 6 | |
| 7 | - Writing or reviewing a `docker-compose.yml` for WordPress development. |
| 8 | - Adding **Redis** (object cache), **Mailpit** (mail capture), **Xdebug**, or php.ini overrides to a WP container setup. |
| 9 | - Debugging "my `WORDPRESS_CONFIG_EXTRA` / `WP_REDIS_HOST` is ignored" or "wp-cli sees different config than the site". |
| 10 | - `wp_mail` silently fails inside a container. |
| 11 | - A team needs a production-like local topology that `wp-env` can't express. |
| 12 | |
| 13 | ## The config model: env is read at request time |
| 14 | |
| 15 | This is the load-bearing fact of the official `wordpress` image, and the source of most broken stacks. The generated `wp-config.php` does **not** bake values in — it calls `getenv_docker()` on every request, and `WORDPRESS_CONFIG_EXTRA` is `eval`'d from the environment at runtime. |
| 16 | |
| 17 | Consequence (verified by hitting it): a **wp-cli container sharing the same volume gets none of that config unless it has the same environment variables**. Our `wp redis enable` failed with `Connection refused [tcp://127.0.0.1:6379]` because only the `wordpress` service had `WORDPRESS_CONFIG_EXTRA` with `WP_REDIS_HOST` — the wp-cli service silently fell back to defaults. Share the block with a YAML anchor: |
| 18 | |
| 19 | ```yaml |
| 20 | x-wp-environment: &wp-environment |
| 21 | WORDPRESS_DB_HOST: db |
| 22 | WORDPRESS_DB_USER: wordpress |
| 23 | WORDPRESS_DB_PASSWORD: wordpress |
| 24 | WORDPRESS_DB_NAME: wordpress |
| 25 | WORDPRESS_CONFIG_EXTRA: | |
| 26 | define( 'WP_REDIS_HOST', 'redis' ); |
| 27 | if ( ! defined( 'WP_DEBUG' ) ) { define( 'WP_DEBUG', true ); } |
| 28 | define( 'WP_DEBUG_LOG', true ); |
| 29 | |
| 30 | services: |
| 31 | wordpress: |
| 32 | environment: *wp-environment |
| 33 | wpcli: |
| 34 | environment: *wp-environment |
| 35 | ``` |
| 36 | |
| 37 | Two refinements, both verified: |
| 38 | |
| 39 | - **Guard `WP_DEBUG` with `if ( ! defined(...) )`** — wp-cli defines it first and an unguarded define in `CONFIG_EXTRA` throws "Constant WP_DEBUG already defined" warnings on every cli call. (Alternative: the image's own `WORDPRESS_DEBUG: 1` env var toggles `WP_DEBUG` without touching `CONFIG_EXTRA`.) |
| 40 | - Other image env vars: `WORDPRESS_TABLE_PREFIX`, the `WORDPRESS_AUTH_KEY`…`WORDPRESS_NONCE_SALT` salts (auto-generated if omitted), and a `_FILE` suffix convention on all of them for Docker secrets. |
| 41 | |
| 42 | ## Baseline stack |
| 43 | |
| 44 | Abbreviated (full tested file: `examples/docker-compose.yml`): |
| 45 | |
| 46 | ```yaml |
| 47 | services: |
| 48 | db: |
| 49 | image: mariadb:lts |
| 50 | environment: |
| 51 | MARIADB_DATABASE: wordpress |
| 52 | MARIADB_USER: wordpress |
| 53 | MARIADB_PASSWORD: wordpress |
| 54 | MARIADB_ROOT_PASSWORD: root |
| 55 | volumes: [ db_data:/var/lib/mysql ] |
| 56 | healthcheck: |
| 57 | test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] |
| 58 | interval: 5s |
| 59 | timeout: 5s |
| 60 | retries: 12 |
| 61 | |
| 62 | wordpress: |
| 63 | image: wordpress:latest # pin in real projects — see below |
| 64 | depends_on: |
| 65 | db: |
| 66 | condition: service_healthy |
| 67 | ports: [ "8080:80" ] |
| 68 | environment: *wp-environment |
| 69 | volumes: |
| 70 | - wp_data:/var/www/html |
| 71 | - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini |
| 72 | ``` |
| 73 | |
| 74 | - **The he |