Setting Up Your Local Development Environment for WordPress

By: Cameron Pavey

As a software developer, you’re likely familiar with local development environments. They allow you to run your code, applications, and sites on your workstation, similarly to how they run on a production server. This gives you a safe environment to make changes, break and fix things, and watch your changes take place in real time, all without disrupting your users. In the case of WordPress, local development environments are often used to assist in building new sites, testing changes to existing sites, and developing or trialing new plugins and themes.

In this article, you’ll learn about the different types of local development environments commonly used with WordPress and how to set up your own development environment with Docker. Then you’ll make some changes to see it all in action.

Running WordPress Locally

Before diving in and setting up a local development environment for WordPress, please note that there are multiple ways to do so, each with varying benefits and limitations.

Several components are at play in a normal user-facing WordPress site, such as the web server (often Apache or Nginx), the PHP-FPM runtime, and the database. These can be hosted in any number of ways but will usually be locked down with restricted access for security purposes. Precisely mirroring this setup for local development would be unnecessarily cumbersome, and the limitations imposed for security would likely be detrimental to the developer experience.

Consider, for example, database access. In a production environment, you would likely want to lock down database access so that only connections from particular hosts are permitted. Imposing this same level of restriction in a development environment would be unnecessary and actively disruptive to your development efforts if you wanted to simply check some records in the database. Some of the solutions for local development environments tend to prioritize convenience and ease of use over security and production-readiness to circumvent these issues. This priority shift is fine as long as you keep this limitation in mind and don’t try to use a local development environment tool for your user-facing production site. Mostly, these tools are suitable for development, local testing, validation, and trialing or experimenting with plugins and themes. For production workloads, you should typically consider one of the many WordPress hosting services available.

There are several popular methods for running local development environments for WordPress, some of which are covered by the official developer handbook.

XAMPP / WAMP / MAMP

Although these are technically three separate software bundles, XAMPPWAMP, and MAMP are grouped here for brevity, as they are conceptually very similar. The names of these packages are acronyms that represent the characteristics of each bundle. For WAMP and MAMP, the first letter (W/M) represents either Windows or macOS as the platforms these bundles are intended to run on (though confusingly, MAMP also runs on Windows). The remaining letters denote Apache, MySQL, and PHP, respectively. You will note that these pieces of software map directly to the core components required to run WordPress—the web server, the database, and the PHP runtime.

XAMPP is similar, with its acronym representing multiplatform, Apache, MariaDB, PHP, and Perl. While there are some slight variations in terms of what each server offers, particularly with XAMPP, all these local servers are suitable for WordPress development and are similar in usage, with beginner-friendly, turnkey solutions, as they each only need to be installed and are otherwise ready for development out of the box.

Vagrant

Vagrant is a virtual machine (VM)–centric solution for running local development environments. One of Vagrant’s best features is the ability to have configurations that you can apply for different use cases. One such configuration is Varying Vagrant Vagrants (VVV), a configuration designed specifically for WordPress development. This configuration provides you with a virtual machine preloaded with tools and utilities to help you develop WordPress sites, such as the following:

VVV is a fantastic choice if you’re already at ease with Vagrant or VM-based workflows. It provides a turnkey solution for local WordPress development while keeping all necessary dependencies confined to a VM. This isolation helps keep your development environments decoupled from individual device configurations and ensures that development environments remain consistent and repeatable, something that becomes especially valuable when you’re working on multiple similar projects or a team with multiple developers.

InstantWP

InstantWP is a stand-alone, portable local development environment for Windows and macOS. It’s easy to get started with, essentially just needing to be downloaded and unzipped. As with the other options mentioned so far, it’s fantastic for beginners and experienced developers alike, particularly if you don’t have a preferred alternative (like Vagrant or Docker) and want to get a WordPress environment up and running quickly.

So far, the solutions mentioned have been relatively turnkey, meaning that there isn’t much required in the way of configuration and setup. All you need to do is download and install them and, in some cases, also download the WordPress source code and set up your database. Each solution has reasonably detailed documentation and guides on their sites to help you through the setup process if needed.

Docker

Docker is a containerization platform that allows you to create containers where you can run applications inside. These containers run on top of your operating system but are somewhat decoupled from it, making the applications portable and allowing you to run things like WordPress without having to install all the dependencies on your host machine, such as the PHP runtime and a compatible database.

Using Docker for your local development environment is a slightly more involved process. It’s not designed specifically for WordPress or PHP development and, thus, has more things that need to be configured. Despite this, it’s still a very compelling option if you’re familiar with container-based development workflows. Because the other options on this list are relatively straightforward to configure and container-based workflows are becoming increasingly ubiquitous in the development world, this is the approach that this tutorial will use.

Getting Started with Docker for Your Local WordPress Development Environment

If you want to follow along with this tutorial, you’ll need the following:

Once you have these prerequisites installed, you can create the Docker Compose config that you will use to orchestrate your containers. Typically, when using Docker, you can issue commands to create individual containers, but if you want a portable config that links multiple containers together, you need more. This is what Docker Compose is for. It lets you define a config with multiple containers that can reference each other. In this case, you’ll have a wordpress container that handles the HTTP and PHP side of things, a db container that handles your database, and a phpmyadmin container that will provide you with a simple database client.

Create a new directory for this project, navigate to it, and create a file called docker-compose.yml. In that file, add the following content:

version: "3.6"
services:
 wordpress:
   image: wordpress:latest
   container_name: wordpress
   volumes:
     - ./wordpress:/var/www/html
   environment:
     - WORDPRESS_DB_NAME=wordpress
     - WORDPRESS_TABLE_PREFIX=wp_
     - WORDPRESS_DB_HOST=db
     - WORDPRESS_DB_USER=root
     - WORDPRESS_DB_PASSWORD=password
   depends_on:
     - db
     - phpmyadmin
   restart: always
   ports:
     - 8080:80

 db:
   image: mariadb:latest
   container_name: db
   volumes:
     - db_data:/var/lib/mysql
   environment:
     - MYSQL_ROOT_PASSWORD=password
     - MYSQL_USER=root
     - MYSQL_PASSWORD=password
     - MYSQL_DATABASE=wordpress
   restart: always

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

volumes:
 db_data:

This configuration defines the three containers mentioned earlier and binds the wordpress container’s /var/www/html/ directory to a wordpress/ directory that Docker will create alongside your docker-compose.yml file. Save this file, and then run the following command in your terminal from the project directory you created:

docker-compose up

This command will instruct docker-compose to create the three containers by downloading the base images from the Docker Hub before setting everything up and exposing your WordPress site on localhost:8080 and phpMyAdmin on localhost:8180.

Once your terminal output settles, there’s one more change you need to make. Open a new terminal window, navigate to your project directory, and run the following command:

# make sure to substitute the placeholders with your actual username
sudo chown -R {your-username}:{your-username} wordpress

This command is necessary due to how Docker handles file permissions and how the wordpress Docker image is constructed. Without this change, you can’t easily edit the files of your WordPress site from outside the Docker container.

When finished, navigate to localhost:8080 in your browser, and WordPress should greet you with its installation screen:

Proceed through the installation, selecting a language and any other required information, such as site title, username, password, and email. Once you’ve provided these details, WordPress will take you to the login screen, where you can use those details to access the admin dashboard:

Your Development Environment

With your development environment set up, you can start building WordPress sites, themes, and plugins. However, if you’re new to WordPress or Docker and want to see what sort of things you can do, follow along, and you can create your first WordPress plugin using your new local development environment.

For demonstrative purposes, you’ll create a simple, contrived plugin that registers a shortcode that will resolve to the name of the latest post published. This will give you some light exposure to pluginshooks, and transients.

Creating the Plugin

The first step in creating your plugin is creating the files to house the actual plugin. In your code editor, open the project directory, and you should see your wordpress/ directory. Using either your editor or your terminal, navigate to wordpress/wp-content/plugins and create a new directory called latest-post. This directory will contain the files for your plugin. Within this directory, create a file named index.php and add the following content to that file:

<?php
/**
* Plugin Name: Latest Post
* Plugin URI: https://www.your-plugins-site.com/
* Description: Show the latest published post.
* Version: 0.1
* Author: your-name
* Author URI: https://www.your-site.com/
**/

This comment sets the metadata WordPress shows in the interface when dealing with your plugin. If you go back to your browser and navigate to localhost:8080/wp-admin/plugins.php, you’ll see that your plugin has been added to the list (albeit inactive and with no functionality).

Next, add the following code to your index.php file:

// register the shortcode
add_shortcode('latest_post', 'latest_post_shortcode');

// define the shortcode function
function latest_post_shortcode() {

    // check if the transient is set, and if not, get the latest post, and set the transient
    if ( false === ( $latest_post = get_transient( 'latest_post' ) ) ) {
        $latest_post = get_posts()[0];
        set_transient( 'latest_post', $latest_post, WEEK_IN_SECONDS );
    }

    // return the title of the latest post
    return $latest_post->post_title;
}

This code handles the core functionality of your plugin. It fetches the latest post and returns its title. To avoid making extra database calls, it leverages the WordPress transient mechanism to cache the query result for up to a week. If you publish a new post, you need to invalidate the cache and allow the query to run again. To do this, you can add the following code:

// add action hook to remove transient on post save
add_action('save_post', 'latest_post_transient');

// define the function to remove transient
function latest_post_transient() {
    delete_transient('latest_post');
}

This code registers an action hook that will remove the transient’s current value when a post is saved.

Save any changes to this file, and go back to your browser. Refresh the page, and click the Activate button on your plugin’s entry:

With that, your shortcode is now ready for use. In the navigation menu, hover over Appearance and then select Editor in the flyout menu. This will take you to the block editor. From here, click the Plus button near the top left-hand corner, and search for “shortcode” in the menu that appears:

Drag the shortcode block onto your page, and in the field that appears, type the name of your new shortcode, surrounded by square brackets (ie [latest_post]):

Save your changes, and then navigate to your site’s home page (localhost:8080), and you should see that your shortcode has resolved to the name of the site’s default post, “Hello world!” To test that things are working as intended, hover over the New menu in the admin navigation at the top of the screen, and select Post. Give your new post a title from this page and publish it:

Now, navigate back to the home page, and you’ll see that the shortcode now resolves to the latest post’s title, as intended:

Wrapping up

In this article, you were introduced to several different solutions that you can use to run a local development environment for WordPress. You learned how to configure a container-based environment using Docker and Docker Compose and, subsequently, how to use that environment to develop a simple, contrived WordPress plugin to test that everything is working as intended.

Using what you’ve learned in this tutorial, you can go on to build and test WordPress sites, plugins, and themes of your own. Be sure to refer to the developer handbook as you go, as it will likely contain answers to most of your questions when it comes to WordPress development.