In this tutorial, we will look into how to set up PhpStorm to use Xdebug in a dockerized PHP project. For a non-trivial PHP project example, we choose the development of a WordPress theme.

Table of Contents


Prerequisites

PhpStorm is a popular PHP IDE with many useful features including Docker and Xdebug support. In this tutorial, we are using version 2019.3.2.

You will need the Xdebug helper for Chrome or an equivalent helper for other browsers.

This tutorial is written for Windows 10 and Docker Desktop running Linux containers. Make sure the Docker Daemon is exposed on port 2375. To check if it is, go to Settings > Generaland tick the respective checkbox:

The version of WordPress we are going to work with is 5.4.1. It should work also with newer versions: download the most recent WordPress and update the reference to the newer WordPress Docker image in the Dockerfile that is mentioned below.

The WordPress theme that is the subject of this development project can be a scratch-built custom one or a modification of an existing theme. For simplicity’s sake, we will be debugging an existing theme BeOnePage Lite by BeTheme.

The companion repository for this tutorial can be found on GitHub: wordpress_xdebug

Project Setup

The project will use a container built from an official WordPress image. The tag used in this project is 5.4.1-php-7.2-apache.

In an empty project folder, we create a docker-compose configuration file, docker-compose-local.yml. In this file, we define two services. The first one is for the database server:

  db:
    image: mysql:8.0
    container_name: db_blog_xdb
    restart: unless-stopped
    env_file: .env
    environment:
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      MYSQL_USER: $MYSQL_USER
      MYSQL_PASSWORD: $MYSQL_PASSWORD
      MYSQL_DATABASE: $DB_NAME
    ports:
      - 42333:3306
    volumes:
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

file docker-compose-local.yml, line 4

This is a simple database service configuration that uses an official MySQL image. It reads environment variable values from the .env file and maps to the host port 42333 to allow MySQL clients that run on the host machine to connect to the database.

The second service runs the WordPress code:

wp:
    depends_on:
      - db
    build:
      context: ./
      dockerfile: Dockerfile_local
    container_name: wp_blog_xdb
    restart: unless-stopped
    env_file: .env
    ports:
      - "80:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: $MYSQL_USER
      WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
      WORDPRESS_DB_NAME: $DB_NAME
      XDEBUG_CONFIG: remote_host=host.docker.internal
    volumes:
      - ./src/wordpress:/var/www/html
      - ./src/themes/beonepage:/var/www/html/wp-content/themes/beonepage
    networks:
      - app-network

file docker-compose-local.yml, line 22

The build instructions for this image will be available in a separate Dockerfile. Note that we bind two project directories as volumes: ./src/wordpress/ for the core WordPress files and ./src/themes/beonepage that hosts the files for the custom theme.

We place the core WordPress files into a separate directory so that we could exclude it from the repository using .gitignore. We do not need the core files to be deployed live from the repository, because they will be provided by a WordPress official image that will be the basis for the live version of the container. But in the development environment, we still need the core files in the project to step into them when debugging.

The .env file is used by both services contains variables and is required for the MySQL operation. This file’s content is simple:

MYSQL_ROOT_PASSWORD=password
MYSQL_USER=db_admin
MYSQL_PASSWORD=password
DB_NAME=my_blog_db

file .env

The full content of the docker-compose-local.yml file is this:

version: "3"

services:
  db:
    image: mysql:8.0
    container_name: db_blog_xdb
    restart: unless-stopped
    env_file: .env
    environment:
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      MYSQL_USER: $MYSQL_USER
      MYSQL_PASSWORD: $MYSQL_PASSWORD
      MYSQL_DATABASE: $DB_NAME
    ports:
      - 42333:3306
    volumes:
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wp:
    depends_on:
      - db
    build:
      context: ./
      dockerfile: Dockerfile_local
    container_name: wp_blog_xdb
    restart: unless-stopped
    env_file: .env
    ports:
      - "80:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: $MYSQL_USER
      WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
      WORDPRESS_DB_NAME: $DB_NAME
      XDEBUG_CONFIG: remote_host=host.docker.internal
    volumes:
      - ./src/wordpress:/var/www/html
      - ./src/themes/beonepage:/var/www/html/wp-content/themes/beonepage
    networks:
      - app-network

volumes:
  dbdata:

networks:
  app-network:
    driver: bridge

file docker-compose-local.yml

Xdebug Installation

For the service wp, we need a custom image based on WordPress docker image tagged 5.4.1-php7.2-apache. We name the Dockerfile Dockerfile_local and add instructions there that install and enable the Xdebug extension:

FROM wordpress:5.4.1-php7.2-apache
RUN pecl install xdebug-2.6.0
RUN docker-php-ext-enable xdebug
RUN echo "xdebug.remote_enable=1" >> /usr/local/etc/php/php.ini

file Dockerfile_local

WordPress Source Code

As mentioned above, we will need the source code for WordPress in our project to step into code when debugging. In the project directory, create a path src/wordpress. Download WordPress version 5.4.1 and place the extracted files there, so that the main index.php and directories wp-admin, wp-includes are available directly under src/wordpress.

Next, in the src/ directory add a subfolder themes and place there the extracted BeOnePage theme so that the theme’s files are available under src/themes/beonepage

Finally, exclude all directories that we are not going to need in the project repository by adding the .gitignore file into the project root:

.idea/
.env
src/wordpress/

The final project structure will look like this:

├── src
│ ├── themes
│ │ ├── beonepage
│ ├── wordpress
│ │ ├── wp-admin
│ │ ├── wp-content
│ │ ├── wp-includes
│ │ ├── index.php
│ │ ├── ...
├── .env
├── .gitignore
├── docker-compose-local.yml
├── Dockerfile_local

Launching the Docker Project

We are now ready to launch the prepared WordPress project using PhpStorm Docker tools.

First, we need to create a Run Configuration. To do that, in the project view right-click the file docker-compose-local.yml and select “Create docker-compose-local…”:

This will open the “Create Run Configuration” dialog that looks like this:

For our project, there is nothing required to change in this dialog. However, you might want to check “–build, force build images” if your project has some changes that can affect the composition of the services’ images.

Possible Problems

If the “Server” setting does not show “Docker”, it means that PhpStorm can’t connect to the Docker daemon. The error message can read, for example:

“Cannot connect: Cannot connect to the Docker daemon at tcp://localhost:2375. Is the docker daemon running?”

To fix this, open Docker Desktop and check if there is any problem with the docker daemon. Also, make sure that the daemon is exposed at port 2375 as described in the “Prerequisites” section earlier in this post.

Another problem can happen when PhpStorm fails to start the service containers with an error message like this:

Failed ... com.intellij.execution.process.ProcessNotCreatedException: Cannot run program docker-compose CreateProcess error=193, %1 is not a valid Win32 application

This problem happens on Windows machines and the reason is that the tool settings for the Docker executables lack “.exe” extensions in file paths. Simply adding the missing extensions should solve it:

Starting the Service Containers

Once the Run Configuration is created, we can build the images and start the containers by clicking the run button in the IDE toolbar. The deploy log in the IDE will show this:

Deploying 'Compose: docker-compose-local.yml'...
"C:\Program Files\Docker\Docker\resources\bin\docker-compose.exe" -f C:\__projects\docker\wordpress_xdebug\docker-compose-local.yml up -d
Creating network "wordpress_xdebug_app-network" with driver "bridge"
Creating volume "wordpress_xdebug_dbdata" with default driver
Creating db_blog_xdb ... 
Creating wp_blog_xdb ... 
'Compose: docker-compose-local.yml' has been deployed successfully.

Alternatively, this could be done from PowerShell running in the privileged mode:

cd <project directory>
docker-compose -f ./docker-compose-local.yml up -d --build

Wait a minute before testing the project in the browser. The db service takes some time to launch the MySQL service and start accepting connections. You can follow this process using the logs command:

docker-compose -f ./docker-compose-local.yml logs -f

Wait until the log shows this line:

[System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.20'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

Now, go ahead and open the http://localhost. You will be greeted with the familiar WordPress installation wizard. Finish it and log into the admin area. There, activate the BeOnePage theme. Now your blog will look like this:

Debugging

We are now ready to start the first debugging session. Open the core WordPress index file located at src/wordpress/index.php and place a breakpoint in the last line

require __DIR__ . '/wp-blog-header.php';

Now, in the IDE toolbar, click the “Start listening for PHP Debug connections” button:

In your browser, activate the Xdebug Helper:

Reload the index page and make sure the execution stops at the breakpoint. If yes, try stepping in and go a few levels deeper. Test breakpoints in other locations in the core files directory.

Possible Problems

It can happen that the breakpoint is missed, or there are Xdebug connection errors like this appear:

<em>Cannot accept external Xdebug connection: Cannot evaluate expression 'isset($_SERVER['PHP_IDE_CONFIG'])'</em>

In this case, open the project settings and under “Languages and Frameworks” > “PHP” > “Servers” delete all server configurations. They will be automatically fixed and recreated the next time you start debugging:

Debugging the Custom Theme

Now that the core files debugging works, we need to try debugging the custom theme files located at /src/themes/beonepage. To enable this debugging simply add a mapping to the theme directory:

Now, the breakpoints in the theme files should work as well.

Next Steps

In this tutorial, we showed how to enable debugging of PHP files in a dockerized WordPress project with PhpStorm.

Once the project is ready for deployment, you will have to work out a way to bring the theme modifications to the production environment. The volume mapping we used in the docker-compose service configuration will not be necessary for a live container so you may need to create a Docker file for the production version. You can find more information on deployment Deploy Containerized WordPress Websites with GitLab and Nginx-Proxy


0 Comments

Leave a Reply

Avatar placeholder

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