Simplified WordPress Development with Docker Compose

15 January 2024

While not a WordPress developer, I nonetheless find myself occasionally putting together one-off themes and plugins. As a result, it’s rarely necessary for me to maintain a full WordPress development environment, but I also want to avoid starting from scratch whenever such a project crosses my desk.

In this post, we’ll look at using Docker Compose to create a quick way to start building on WordPress plugins and themes that’s both developer- and source control–friendly. Read on to find out more!

Getting Started

Before starting, you’ll need Docker installed locally. Once installed, the official MySQL and WordPress Docker images provide an excellent foundation for what we need. We’ll start with a standard Docker Compose configuration; the only points of note are that we’re using a volume for the WordPress database (so we don’t lose any data if we need to recreate the containers), and that we establish a dependency for the WordPress image on the MySQL one (via the depends_on property).

NOTE: Please be aware this is absolutely not a production-safe configuration: Its purpose is solely for local development.

version: '3.9'

image: wordpress:latest
- db
restart: always
# NOTE: WordPress will be accessible via port 8000, as defined here.
- '8000:80'

image: mysql:5.7
restart: always
- '3306:3306'
- dbdata:/var/lib/mysql
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_USER: wordpress


Once we have the Compose configuration in place, we can get WordPress started:

$ docker compose pull
$ docker compose up

It will take a moment for the images to be pulled and spin up, but once that’s done, visit http://localhost:8000 (port 8000 was configured in our Compose configuration file) and go through the WordPress setup. Once that’s complete, we now have a full WordPress instance up and running!

Adding Our Code

Now that we have a running WordPress instance, let’s modify our Compose config to link up our own code. I won’t prescribe a specific folder structure, but this approach has worked well for me: Everything’s grouped in a src folder, within which each theme and plugin has its own folder:

- /project
- /src
- /example-plugin
- index.php
- docker-compose.yml

We’ll use Compose’s volumes collection to do the mapping. Note that we’re not mapping the entire plugins folder: Since most WordPress instances use at least some other plugins, it behooves us to map only the plugins we’re working on. This also helps keep the source code clean and focused to just our own code.

version: '3.9'

# Other fields removed for brevity
- ./src/example-plugin:/var/www/html/wp-content/plugins/example

Creating a WordPress plugin is beyond the scope of this post, but let’s use the following trivial plugin for testing: The plugin’s only “function” is to render a message on each page…just enough for us to verify everything’s working.


* Plugin Name: Example Plugin

add_action('wp_footer', 'add_footer');
function add_footer() {
echo '<p>Hello, world!</p>';

Compose won’t be aware of our new volume mapping until the service is stopped and restarted (a normal restart command isn’t sufficient):

$ docker compose stop
$ docker compose up

Once the containers are running again, take a peek at your instance’s plugins page at http://localhost:8000/wp-admin/plugins.php. If all went well, you should see our new plugin in the list! Just click “Activate” and verify everything works by visiting any page of your WordPress instance and scrolling to the bottom.

Next Steps

Though we’ve just demonstrated plugin development in this post, the same procedure applies for themes, as well: Just map your theme to /var/www/html/wp-content/themes/<theme>. Don’t forget to activate it!

If you’d like a jumping-off point, the code for this post is available on GitHub. Happy coding with WordPress!