17/11/2024, 13:31
wordpress docker git

WordPress starter template

If you always wondered how to configure a hassle-free WordPress development environment for developing plugins or themes, this might be a solution for you.

GitHub

Introduction

Recently, I started getting interested in WordPress development. After reading the documentation, and trying the recommended path to set up a development environment with wp-env I came to the conclusion that wp-env is not very flexible and is hiding too many details behind the scene. So I decided to build my own Docker container stack. Let me show you my solution incrementally step by step.

Variables

First create a .env file with all values as variables which might be useful being able to change while developing. The .env will be automatically used by docker compose to populate variables inside the compose.yaml.

DB_PASSWORD=password
DB_NAME=wordpress
DB_PREFIX=wp_
WP_USER=admin
WP_PASSWORD=admin
WP_PORT=3000

Database

At the beginning, you need a database for WordPress and the password variable from the .env file to set up the database. And instead of adding a container like PhpMyAdmin for editing the database, I thought it was a more flexible solution to just expose the database port. For example, like this, you can use the database tools baked into PhpStorm.

services:
  db:
    image: mariadb
    ports:
      - '3306:3306'
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}

CLI

In the next step, you need to add the WordPress CLI tool, which will be later used to download WordPress and generate some mock data. To make everything work properly, you need to add a health check to the database. This will make sure that the CLI tool will not run before the database server is fully initialized. You also have to add a volume where to store the WordPress installation, which will be downloaded by the CLI.

+ volumes:
+   data:
+     external: false

  services:
    db:
      image: mariadb
+     container_name: wordpress_db
      ports:
        - '3306:3306'
      environment:
        - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
+     healthcheck:
+       test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
+       start_period: 10s
+       interval: 10s
+       timeout: 5s
+       retries: 3

+   cli:
+     image: wordpress:cli
+     container_name: wordpress_cli
+     volumes:
+       - data:/var/www/html
+     depends_on:
+       db:
+         condition: service_healthy

Initializing

The next step on the list is creating a init.sh script, which contains all the CLI commands. This example script will download WordPress, create the database, create an admin user and generate some mock posts. This script can be modified depending on the needs of the project. The critical point is the --dbhost which has to be the container name of the database container because Docker is using the container names to make the containers inside the docker network reachable by this name.

#!/usr/bin/env bash

wp core download
wp config create \
  --dbprefix="$DB_PREFIX" \
  --dbname="$DB_NAME" \
  --dbuser="root" \
  --dbpass="$DB_PASSWORD" \
  --dbhost=wordpress_db
wp db create
wp core install \
  --url="http://localhost:$WP_PORT" \
  --title="Example" \
  --admin_user="$WP_USER" \
  --admin_password="$WP_PASSWORD" \
  --admin_email="email@example.com"
wp post generate --count=50

Now you need to hand over the variables from the .env file as environment variables. If you wonder how this works: DB_PASSWORD is a shorthand for: DB_PASSWORD=${DB_PASSWORD}. Next, you need to mount the script into the container and add the entrypoint to execute the script on container start.

volumes:
    data:
      external: false

  services:
    db:
      image: mariadb
      container_name: wordpress_db
      ports:
        - '3306:3306'
      environment:
        - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
      healthcheck:
        test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
        start_period: 10s
        interval: 10s
        timeout: 5s
        retries: 3

    cli:
      image: wordpress:cli
      container_name: wordpress_cli
      volumes:
+       - ./init.sh:/init.sh
        - data:/var/www/html
+     environment:
+       - DB_PASSWORD
+       - DB_NAME
+       - DB_PREFIX
+       - WP_USER
+       - WP_PASSWORD
+     entrypoint: ["sh", "-c", "/init.sh"]
      depends_on:
        db:
          condition: service_healthy

Web server

Finally, you need to add a server to run WordPress. I decided to use the official WordPress docker image. Like this, you don’t have to worry about any web server setup. You also need to mount the volume which is already prepared by the CLI tool. The second mount point is for mounting the actual source code which you want to develop. You can mount any file or directory to any point into the WordPress folder structure. This makes this setup super flexible. In the end, you only have to add the same health check for the database like the CLI tool is doing. And we have to make sure that the web server is only starting after the CLI tool has finished the initialization. This can be done by a simple service_completed_successfully check.

volumes:
    data:
      external: false

  services:
+   app:
+     image: wordpress
+     container_name: wordpress_app
+     volumes:
+       - data:/var/www/html
+       - ./src:/var/www/html/wp-content
+     depends_on:
+       db:
+         condition: service_healthy
+       cli:
+         condition: service_completed_successfully
+     ports:
+       - "${WP_PORT}:80"

    db:
      image: mariadb
      container_name: wordpress_db
      ports:
        - '3306:3306'
      environment:
        - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
      healthcheck:
        test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
        start_period: 10s
        interval: 10s
        timeout: 5s
        retries: 3

    cli:
      image: wordpress:cli
      container_name: wordpress_cli
      volumes:
        - ./init.sh:/init.sh
        - data:/var/www/html
      environment:
        - DB_PASSWORD
        - DB_NAME
        - DB_PREFIX
        - WP_USER
        - WP_PASSWORD
      entrypoint: ["sh", "-c", "/init.sh"]
      depends_on:
        db:
          condition: service_healthy

Conclusion

That’s it! Now you have a development environment which will always create a clean installation of WordPress and also being able to modify the initialization to the project’s needs just with a single dependency, Docker.

For starting the environment, just run the following command.

docker compose up

And to clean up everything after stopping the services, you need to run this to also clean up the volume. If you skip this step, the initialization with the CLI will fail because the previous initialized data will be used.

docker compose down --volumes

You can find the complete template in my GitHub Repository. You are welcome to use it or open an issue if you find some.