Automatically deploying WordPress plugins and/or themes with GitHub actions
Tags: continuousdeployment, tutorial, githubactions, wordpress
Published: 2023-10-24 21:29:47

There are a lot of ways in which a WordPress GitHub integration can be helpful in **WordPress development** and project collaboration. One of them is in deploy routines with automatic deployments, instead of the _cowboy coding approach_, using FTP, manually grabbing our themes and/or plugin files, and uploading them manually using software like [FileZilla](https://filezilla-project.org/), we can deploy directly from GitHub to our live WordPress site.

That's why I wrote this post and, as always, to record what I did for when I forget it in a few months from now.

We will review **how to set up a WordPress GitHub integration** to manage the deployment of our WordPress themes and WordPress plugins, which can save us a lot of time and is especially important if we are using custom themes and plugins.

We will not cover:

- 
**The WordPress Core:** Well, we should never edit core WordPress files, so it doesn't make sense to include the core files in our repository.

- 
**The database:** Trying to version control the WordPress database **opens up a can of worms** and we will not open that now.

- **WordPress development of plugins and themes:** I am assuming you have this done, ready to deploy.
  
Let's get started with the sample workflows we will gonna use to synchronize our WordPress themes and plugins!

# Deploying a WordPress Theme

The following .yml code is used to synchronize the theme files you coded, with the **/wp-content/themes** folder in your server. For a LAMP server hosted in a company like Digital Ocean, that's a sample workflow:

```
name: Deploy Theme

on:
  push:
    branches: [master]

env:
  SSH_USER: ${{ secrets.SSH_USER }}
  SSH_HOST: ${{ secrets.SSH_HOST }}

jobs:
  deploy:
    name: Deploy WordPress Theme on Digital Ocean
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set SSH Connection
        run: |
          mkdir -p ~/.ssh/
          echo "$SSH_KEY" > ~/.ssh/deploy.key
          chmod 600 ~/.ssh/deploy.key
          cat >>~/.ssh/config <<END
          Host digitalocean
            HostName $SSH_HOST
            User $SSH_USER
            IdentityFile ~/.ssh/deploy.key
            StrictHostKeyChecking no
          END
        env:
          SSH_KEY: ${{ secrets.DEPLOY_KEY }}

      - name: Sync theme files
        run: "rsync --delete -avO
          --exclude /deploy_key \
          --exclude /.git/ \
          --exclude /.github/ \
          ./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}"
        env:
          SSH_HOST: digitalocean
          # That's the most commom path in a WordPress instalation on a LAMP stack,
          # but you can change the destination according to your needs.
          DEST: "/var/www/your-domain/wp-content/themes/theme-folder"
```

### Workflow name

In the first line we have the workflow name `name: Deploy Theme`. 

### Workflow triggers

Later, we have the trigger definition, in this case, whenever I push a commit to the master branch on the repository with my WordPress theme, the workflow will be triggered. You can custom that, for more details, you can refer to GitHub documentation.

```
on:
  push:
    branches: [master]
```
### Secrets

I create variables for the custom secrets. More info [here](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-encrypted-secrets-for-a-repository). 

```
env:
  SSH_USER: ${{ secrets.SSH_USER }}
  SSH_HOST: ${{ secrets.SSH_HOST }}
```
### Jobs

The jobs section in a GitHub Actions workflow file defines one or more jobs to be executed when a workflow is triggered. 

```
jobs:
  deploy:
    name: Deploy WordPress Theme on Digital Ocean
    runs-on: ubuntu-latest
```
In the case above:

- **deploy** is the name of the job, which can be customized to describe the job's purpose.
- **name** is an optional field we use to making it more understandable when viewing the workflow.

- **runs-on** specifies the type of virtual environment or runner on which the job will be executed. In this case, it uses the ubuntu-latest runner, indicating that the job runs on the latest available version of the Ubuntu operating system.


### Steps

The steps section in a GitHub Actions workflow file defines a series of individual tasks that are executed as part of a job.

```
steps:
      - name: Checkout
        uses: actions/checkout@v2
```

In the case above:

- **steps:** contains a list of actions to be executed in the specified order. 
- **name**: is an optional field we use to making it more understandable when viewing the workflow.
- **uses:** Specifies the action to be performed. In this example, the **actions/checkout@v2** action is used to check out the source code repository.


#### Setting SSH Conection

This is the section of your workflow responsible to sets up an SSH connection for secure access to our remote host.

```
name: Set SSH Connection
        run: |
          mkdir -p ~/.ssh/
          echo "$SSH_KEY" > ~/.ssh/deploy.key
          chmod 600 ~/.ssh/deploy.key
          cat >>~/.ssh/config <<END
          Host digitalocean
            HostName $SSH_HOST
            User $SSH_USER
            IdentityFile ~/.ssh/deploy.key
            StrictHostKeyChecking no
          END
        env:
          SSH_KEY: ${{ secrets.DEPLOY_KEY }}
```

**- name:** as in the previous parts, it's a optional field making it more understandable for us, ins this case we will see: Set SSH Connection.

- 
**run** defines the steps or shell commands to execute. In this case:
      - Creates the ~/.ssh/ directory if it doesn't already exist.
      - Writes the SSH key, stored in the SSH_KEY environment variable, to ~/.ssh/deploy.key.
      - Sets the permissions of ~/.ssh/deploy.key to ensure it's only accessible by the user.
      - Appends SSH configuration to ~/.ssh/config, including the hostname, username, and path to the SSH key. 
      - Additionally, it disables strict host key checking for the "digitalocean" host.
- **env** section specifies environment variables used in the workflow, in this case, it defines the SSH_KEY variable and retrieves its value from a GitHub secret (DEPLOY_KEY).

#### Syncing the theme files:

This syncing section is responsible for syncing theme files to the remote server using the **rsync command**. In some hosts, may be necessaire to [install manually rsync](https://serverspace.io/support/help/use-rsync-to-create-a-backup-on-ubuntu/).

```
  - name: Sync theme files
        run: "rsync --delete -avO
          --exclude /deploy_key \
          --exclude /.git/ \
          --exclude /.github/ \
          ./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}"
```

The rsync command performs the following tasks:

- 
--delete: Ensures that files deleted locally are also deleted on the remote server.
    

- 
-avO: Sets rsync options for archive mode, verbose output, and optimization.
   

- 
 --exclude: Specifies which files or directories to exclude from the synchronization. In this example, it excludes the /deploy_key, /.git/, and /.github/ folders, but you can customize according to your project.
    

- 
./: Specifies the source directory to sync from, which is the current directory of the workflow.
   

- 
 `${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}: `Specifies the destination for the synchronization. It uses environment variables for the SSH username, host, and destination path.

#### The var definition
     
In this section there are some other environment variables that are used within the workflow.

```
 env:
          SSH_HOST: digitalocean
          # That's the most commom path in a WordPress instalation on a LAMP stack,
          # but you can change the destination according to your needs.
          DEST: "/var/www/your-domain/wp-content/themes/theme-folder"

```

# Deploying a WordPress Plugin

To deploy a plugin, you can follow the same idea above, just changing the deploy path to `/var/www/your-domain/wp-content/plugins/plugin-folder`

The sample workflow below:

```

name: Deploy Plugin

on:
  push:
    branches: [master]

env:
  SSH_USER: ${{ secrets.SSH_USER }}
  SSH_HOST: ${{ secrets.SSH_HOST }}

jobs:
  deploy:
    name: Deploy WordPress Plugin on Digital Ocean
    runs-on: ubuntu-20.04

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set SSH Connection
        run: |
          mkdir -p ~/.ssh/
          echo "$SSH_KEY" > ~/.ssh/deploy.key
          chmod 600 ~/.ssh/deploy.key
          cat >>~/.ssh/config <<END
          Host digitalocean
            HostName $SSH_HOST
            User $SSH_USER
            IdentityFile ~/.ssh/deploy.key
            StrictHostKeyChecking no
          END
        env:
          SSH_KEY: ${{ secrets.DEPLOY_KEY }}

      - name: Sync plugin files
        run: "rsync --delete -avO
          --exclude /deploy_key \
          --exclude /.git/ \
          --exclude /.github/ \
          ./ ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:${{ env.DEST }}"
        env:
          SSH_HOST: digitalocean
          # That's the most commom path in a WordPress instalation on a LAMP stack,
          # but you can change the destination according to your needs.
          DEST: "/var/www/your-domain/wp-content/plugins/plugin-folder"
```

That's my repository with some [sample workflows customized](https://github.com/sarahcssiqueira/reusable-wp-workflows) for different servers. Be free to **[contribute through pull requests](https://github.com/sarahcssiqueira/reusable-wp-workflows)** adding more workflows or even suggest improvements to the current ones. If that was useful for you, please consider leaving a star in the repository.

References and special thanks to:
- https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository

- 
https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#about-environments

- 
https://blog.hubspot.com/website/wordpress-github-integration

- 
https://css-tricks.com/continuous-deployments-for-wordpress-using-github-actions/

- 
https://engineering.monstar-lab.com/en/post/2023/01/02/How-to-setup-CI-CD-pipeline-for-WordPress-with-GitHub-Actions-and-AWS/

- 
https://felipeelia.dev/ftp-no-more-deploying-wordpress-sites-with-github-actions/