Serious WordPress Development – Part 1 – Local Development Setup

This article is Part 1 of my Serious WordPress Development series. All code can be found here. For more context please read the introduction.

Regardless what application is being developed, it all starts with setting up your local machine in a simple and automated fashion, so that a new team member can get on-boarded quickly. If each developer has the very same environment, then the “works on my machine” effect is avoided. Hence, we reduce the risk of wasting time on single and localised errors caused by environmental differences.

Setting up a new local environment must be done with the following goals in mind:

  • Standard – the setup should use well-known and well-supported packages and infrastructure setup primitives.
  • Speed – the process should take a few minutes, and not hours.
  • Simple – the initial setup should be automated, done with a minimal set of simple commands (ideally one), without requiring the developer to know about its intricacies.
  • Self-contained – once setup, the need for “external” dependencies – i.e. remote applications, servers, databases, cloud services – should be limited to package repositories (e.g. yum, docker, NPM, maven repos etc…)

My team initially decided to use the free MAMP local WordPress server environment. MAMP is downloadable as an OS native package, and can also be installed with Homebrew on MacOSX. MAMP comes installed with PHP, Apache, and MySQL, and provides a user interface that lets you manage your local WordPress sites.

I had several issues with MAMP. The initial installation is a multi-step process requiring installing MAMP and configuring it (e.g. what ports the site should run on). It is largely a manual process done through the MAMP graphical user interface. More importantly we were relying on a third party software for doing something pretty standard. So this setup definitely failed the Standard, Speed, and Simple test.

 

I therefore replaced MAMP with a Docker setup using Docker Compose.  I often use Docker Compose for orchestrating multiple containers locally. I find it very easy to get started with, as it requires only one deployment descriptor (docker-compose.yml) and a set of simple commands (up, down, stop, start). It is also relatively well documented, with an active community of users.

Below is an example I re-created for this article that is very similar to what we had:

version: '3.1'

services:

  wordpress:
    image: wordpress:5.3.2-php7.3-apache
    container_name: wordpress
    restart: always
    ports:
      - 80:80
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_USER: wp_db_user
      WORDPRESS_DB_PASSWORD: wp_db_password
      WORDPRESS_DB_NAME: wp_db
    volumes:
      - ./wordpress:/var/www/html

  mysql:
    image: mariadb:10.3.22
    restart: always
    container_name: mysql
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wp_db
      MYSQL_USER: wp_db_user
      MYSQL_PASSWORD: wp_db_password
    volumes:
      - ./mysql/data:/var/lib/mysql

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: phpmyadmin
    depends_on:
      - mysql
    restart: always
    ports:
      - 8989:80
    environment:
      PMA_HOST: mysql

This setup enables a few things that are really important to me:

1. The whole stack is orchestrated as one fleet of resources, composed of three integrated containers:

    • the wordpress app
    • the mysqldatabase
    • the phpmyadmin app

Note: WORDPRESS_DB_HOST: mysql and PMA_HOST: mysql allow the WordPress and MyPhpAdmin apps to connect to the database using the mysql service name on the Docker Compose virtual network.

2. All WordPress files are mounted to our host folder ./wordpress. It means that, while the container runs, any change to a PHP file will be automatically picked up.

3. All MySQL database files are mounted to our host folder ./mysql/data. It makes it easier to tear down if necessary and re-create the site from scratch (we will use that in a later part of my series about dB changes management).

 

If you want to try this stack you can do the following:

git clone https://github.com/jdamore/wordpress-blog.git
git checkout 9662a4a5379840
docker-compose up -d 

The initial creation of the three containers on my machine with a pruned docker system (i.e. cleaned of any image, volume, or network) takes under a minute. Once finished you should have something like that:

 ➜  wordpress-blog git:(master)docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                    NAMES
cb2aec9b914e        phpmyadmin/phpmyadmin           "/docker-entrypoint.…"   30 minutes ago      Up 30 minutes       0.0.0.0:8989->80/tcp     phpmyadmin
e1e95cfb1a95        wordpress:5.3.2-php7.3-apache   "docker-entrypoint.s…"   30 minutes ago      Up 30 minutes       0.0.0.0:80->80/tcp       wordpress
0a963bda3776        mariadb:10.3.22                 "docker-entrypoint.s…"   30 minutes ago      Up 30 minutes       0.0.0.0:3306->3306/tcp   mysql

Then all you have left to do is:

  • Setup your WordPress site, username, and password by visiting http://localhost, and after a few clicks you should be able to access the WordPress admin at http://localhost/wp-admin.
  • Visit the MyPhpAdmin at http://localhost:8989 using the root/root or wp_db_user/wp_db_password credentials, where you will see that the wp_db schema has been created.

 

In this article I explored how you can initially setup your WordPress project with one single Docker Compose descriptor file. In my next article I will talk about how to manage environment-specific WordPress configurations, which is necessary as soon as you want to have a Continuous Delivery process in place.

I hope this article can be useful to you.

 

 

 

Serious WordPress Development – Introduction

In my next series of articles, I would like to talk about practices that should help any “serious developer” to use the WordPress platform. By “serious developer” I mean anyone who wants to apply adequate software development practices with WordPress, as opposed to writing a blog and/or making some small PHP code changes in the WordPress admin.

Some context. This year I have led my team into building a web application on top of WordPress. We went for a (ReactJS + headless WordPress) approach i.e. we decided not to use WordPress as a website publishing front-end. Instead, we set it up as a headless Content Management System (CMS), only responsible for content authoring, accessible via secure REST APIs. Our intent was to write zero-to-little logic in the WordPress/PHP codebase, and as much logic as possible in the React/TypeScript codebase.

Note that WordPress/PHP is not a technology I would have chosen by default for a scalable and robust web application. But in this case it made sense for a few reasons. First, we had very limited time and budget, and I was not keen on building a set of back-end APIs from the ground up. Second, our customer needed a few administrative functions (e.g. list of registered users), which are provided by default through the WordPress admin UI. Finally we had one seasoned developer familiar with WordPress, who could help us bootstrap the project.

Nevertheless, I was keen on making sure we followed our usual development workflow i.e. develop and test locally, integrate safely, and automatically deploy to test and prod. Finally, many security aspects of the WordPress back-end required some attention, as WordPress is known to have many vulnerabilities.

The parts of our process I would like to describe more in details in this series are:

  • Part 1 – Local development setup
  • Part 2 – Environment specific configuration
  • Part 3 – Deployment of the application code
  • Part 4 – Management and deployment of database changes
  • Part 5 – Securing the WordPress site

There are other aspects of building applications with WordPress I will not cover in this series (e.g. unit testing), as I want to focus on what was really important to us.

I hope you will enjoy this series and feel free to comment if you need more details.