I wanted to make some changes to the excellent Autonomie theme, but because I’m yet a WordPress development tyro I wanted an environment that I could break. At the same time I didn’t want to manually copy changes from local to the real remote env if those changes did turn out to work. There’s probably a better way of doing all this, but here’s what worked for me.

  1. Install Docker
  2. (optional) Edit your hosts file and make local.host point at 127.0.0.1. This is maybe unnecessary, but browsers and various tools often have special treatment for “localhost” or 127.0.0.1, which has caused problems for me in the past.
  3. Locally, create a root dev directory and subdirectories db, wordpress, and whatever themes you want to work on (I used autonomie-dev). You can skip the theme directory if your theme doesn’t require any special build steps. I git-cloned Autonomie.
  4. Create a docker-compose.yaml in the root directory. See below.
  5. Run docker compose up -d. This should get an empty WordPress installation started.
  6. docker compose down to stop it, so we could import the remote installation.
  7. Copy over the remote wordpress directory into the local wordpress/ overwriting any existing files. I used rsync -av --delete remote:/path/to/wordpress/ wordpress/ from root.
  8. If you don’t want to import your remote content, skip this step. Otherwise:
    • docker compose up db to start only MySQL
    • On the remote side run mysqldump and import locally via mysql -ppassword < dump.sql
    • docker compose up phpmyadmin . Log in to http://localhost:8180 with the MySQL username + password. In the “options” table update two records to point to http://localhost:8080/ (or http://local.host:8080/, if you updated the hosts file). The records are siteurl and home under the option_name column. This ensures that your local setup doesn’t redirect to your real remote domain.
  9. docker compose up -d . You should be able to see your site on http://localhost:8080 (or http://local.host:8080 if you changed the hosts file). Now you can change the theme files as needed.

I also wanted to be able to version control the theme with Git and have it publish the local changes on the remote side when I push. For that I followed this tutorial with some tweaks:

  1. Set up a bare git repo outside the web root on your remote host with git init --bare .
    • e.g. if your web root is /var/www/html/wordpress run git init --bare /var/www/html/your_theme
  2. Create an empty theme directory. I used autonomie-dv, so for me the location was /var/www/html/wordpress/wp-content/themes/autonomie-dv. Set this up in the local wordpress install too.
  3. In the bare git repo, under hooks create a file called post-update. Make it executable with chmod ug+x post-update . Contents are below. Now whenever you push into this repository it’ll copy over the theme files into your actual remote installation.
  4. Inside your local theme directory at the root level, git init . and then add the bare repo as a git remote: git remote add origin your-ssh-host:/var/www/html/your_theme .
  5. (optional) Specifically for Autonomie, I removed _build from .gitignore because I didn’t want to run the build step remotely. I wanted to build locally and then have the git hook just copy the files over. I may change my mind about this later. I also tweaked the grunt clean step to not remove the _build directory, because that would break the Docker volume bind and require restarting the containers for every change to remount the recreated directory.
    • I tweaked the watch target in Gruntfile.js to trigger on more file extensions, so I could run grunt build watch and have it automatically rebuild on any local changes.

Now when you git push you should see rsync output that copies the files over.


docker-compose.yaml

services:
  db:
    restart: unless-stopped
    image: mysql:8
    command: '--mysql-native-password=ON --disable-log-bin --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci'
    environment:
      MYSQL_DATABASE: "wordpress"
      MYSQL_ROOT_PASSWORD: "password"
      MYSQL_USER: "wordpress"
      MYSQL_PASSWORD: "password"
    volumes:
      - "./db:/var/lib/mysql"

  phpmyadmin:
    depends_on:
      - db
    image: phpmyadmin/phpmyadmin:latest
    container_name: phpmyadmin
    ports:
      - 8180:80
    environment:
      PMA_HOST: db
      MYSQL_ROOT_PASSWORD: "password"

  wordpress:
    depends_on:
      - db
    restart: unless-stopped
    image: wordpress
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: "password"

      # If you imported your DB and it uses a table prefix uncomment
      # this and update as needed.
      # WORDPRESS_TABLE_PREFIX: "wp_abc"

    volumes:
      - "./wordpress:/var/www/html"

      # Uncomment the next line and update the paths for your theme.
      # My local theme dir is autonomie-dev, but the theme name in
      # WordPress is dv-autonomie. You could totally name them the
      # same. Also note that I'm using _build/ because Autonomie
      # requires a build step (using grunt) and that's where it
      # outputs the results.
      # - "./autonomie-dev/_build:/var/www/html/wp-content/themes/dv-autonomie:ro"
    ports:
      - "127.0.0.1:8080:80"

post-update

#!/bin/sh

# Check out the theme into a temporary directory and then
# copy it over via rsync into the actual WordPress theme location

export target="../wordpress/wp-content/themes/autonomie-dv"
export GIT_WORK_TREE="/tmp/autonomie-dv"
mkdir -p "$GIT_WORK_TREE"
git checkout -f

# This will overwrite the target location. If you're not sure that
# you got it right, add '-n' to do a dry-run. i.e.:
# rsync -avn --delete "${GIT_WORK_TREE}/_build/" "${target}/"
rsync -av --delete "${GIT_WORK_TREE}/_build/" "${target}/"

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.