Setup CD pipeline for WP themes & plugins

Ivan Radunovic
Setup CD pipeline for WP themes & plugins

Manually deleting theme folder and re-uploading is not the most elegant way of doing things.

GitHub Actions are elegant, so I’ll use them.

In this tutorial I’ll:

  • use GitHub action to build theme
  • upload compiled code from action to live server
  • use secrets to store credentials of server

GitHub Environments

Usually you’ll have at least staging & production environments. Here I’ll configure only 1, you can repeat steps for other ones.

Go into GitHub repository visit Settings -> Environments.

Environments page of a GitHub repository

Click on New environment button and choose a name.

New env created

At the bottom you see Add Secret button, clicking on it will open modal where you can add a secret.

You add them one by one.

New secret modal

Conventions for naming secrets

In short:

  • caps lock ON
  • start with a letter
  • separate words with _
  • never use GITHUB_ as a prefix

Basically use alphabet letters in caps lock and separate words with _.


In my case I have 5 secrets and they are:

  • IP – server IP where WP is hosted
  • PORT – SSH port, usually 22
  • THEME_PATH – absolute path to theme folder on live server
  • USERNAME – SSH username
  • DEPLOY_KEY – SSH secret key
Secrets of my env

I also allowed only master branch to deploy to this environment. Otherwise it would deploy on every push on any branch.

Get server details

You can checkout this Provision web server and install WordPress – least effort way and learn how you can install server and WP. It’s very simple tutorial.

In my case I am using domain and I’ll visit SSH tab inside WPJack.

SSH tab of my WP server

For DEPLOY_KEY secret I need SSH private key and this is where I can get it.

I’ll choose User who is associated with my site.

Creating new SSH key

After clicking Create system will show new private key.

Private key

Private key will be visible only here, so save it. You need to copy/paste this variable into DEPLOY_KEY secret on Github.

After closing private key page, you’ll new key under SSH Keys table:

All ssh keys of my server

From here I see that user is acmer, I’ll copy/paste it into USERNAME secret inside GitHub env.

IP secret is ip address of my server it’s visible under server name, in my case it is

THEME_PATH variable is absolute path of theme on live server. In WPJack case path is calculate like this:


In brackets:

  • user: acmer
  • site:
  • your-theme-folder: whatever name you want to use here

When I replace variable I get:


And I’ll copy/paste this into THEME_PATH.

If you’re using some other system instead of WPJack you need to findout full path to your site and append wp_content part to it.

Action code

Action code is hosted in repository unde .github/workflows/main.yml.

# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the workflow will run
  # Triggers the workflow on push or pull request events but only for the "master" branch
    branches: [ "master" ]
    branches: [ "master" ]

  # Allows you to run this workflow manually from the Actions tab

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
  # This workflow contains a single job called "build"
    # The type of runner that the job will run on
    runs-on: ubuntu-latest
    environment: staging
    # Steps represent a sequence of tasks that will be executed as part of the job
      - uses: actions/checkout@v2

      - uses: actions/setup-node@v2
          node-version: 12.x

      - name: Install dependencies
        run: npm install

      - name: Build
        run: npm run production

      - name: Sync
          dest: '${{secrets.USERNAME}}@${{secrets.IP}}:${{secrets.THEME_PATH}}'
        run: |
          echo "${{secrets.DEPLOY_KEY}}" > deploy_key
          chmod 600 ./deploy_key
          rsync -chav --delete \
            -e 'ssh -p ${{secrets.PORT}} -i ./deploy_key -o StrictHostKeyChecking=no' \
            --exclude /deploy_key \
            --exclude /.git/ \
            --exclude /.github/ \
            --exclude /node_modules/ \
            ./ ${{env.dest}}

My repository is using certain frontend framework so commands are tied to it. In your case you could use different commands but logic is the same.

Steps inside action:

  • Triggers defined
  • Use ubuntu-latest
  • Environment staging to be used
  • Define GH action version
  • Use certain Node
  • npm install
  • npm run production
  • Define dest variable
  • Upload files with rsync but skip .git, .github and node_modules folders.

You can skip any other number of files that are not needed, like readme, license etc.

Test action

Now try to push something to master branch and see will it deploy successfully.

Oopen Actions tab of your repository and monitor events there.

You’ll see error log if anything goes wrong.

Install WordPress on any Cloud. In under 5 minutes.
Supports Linode, Digital Ocean, Hetzner and Vultr.
Free Tier includes 1 server and 2 sites.
Sign up today