When creating plugins or themes, you often need build assets and/or deploy it to somewhere else, e.g. to the WordPress.org plugin repository. Since the code is often hosted on GitHub, the so called GitHub Actions can be used to do this.

GitHub Actions

So what are GitHub Actions exactly? It’s a service you can use on GitHub to run certain actions after publishing code, adding a tag or various other Git related triggers. You can define what the action should do and it will be done whenever you want it to. There is also a marketplace with actions someone built, which you can then use without needing to reinvent the wheel. So for most usual actions, there’s already a solution.

How does it work?

The configuration of GitHub Actions is placed within your repository under the .github/workflows directory. It is YAML file (or multiple YAML files) and contains strict instructions on how to do something and when to do it.

Deploy to WordPress.org

When a plugin should be deployed to the WordPress.org plugin repository, there is an action for that by 10up, which can be used. In the following example, it will always deploy the code to WordPress.org if a tag is created:

name: Deploy to WordPress.org
on:
  push:
    tags:
    - "*"
    - "!*-*"
jobs:
  tag:
    name: New tag
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: WordPress Plugin Deploy
      id: deploy
      uses: 10up/action-wordpress-plugin-deploy@stable
      env:
        SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
        SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
Code language: YAML (yaml)

Here, we use two actions. One is the actions/checkout@v4 to retrieve the actual code from the repository, and 10up/action-wordpress-plugin-deploy@stable to deploy it to WordPress.org.

But let’s break it down line per line:
First, the name of the action is set. Then, we determine that the action should be started whenever a tag is pushed, that doesn’t contain a - (which allows to ignore tags like v1.0.0-dev1).
Then, we create the jobs, which is one job called tag with the name “New tag”, that runs on the latest version of Ubuntu with two steps: one is the above mentioned checkout step to get the code and the other is the deploy action from 10up. As you might have already seen, this needs a username and a password to connect to the SVN on WordPress.org. To set it, go to Settings > Secrets and variables > Actions in your repository at GitHub and create the two variables SVN_USERNAME and SVN_PASSWORD with your username and password of your WordPress.org account.

Compile and minify assets

Often you need to compile code, such as SCSS/Sass to CSS or minify JavaScript. You can also use or create an action to do that. Since I usually use @wordpress/scripts to compile and minify my code, I need to run npm before deploying something. To do that, I use the action bahmutov/npm-install@v1 with the following steps:

    - uses: bahmutov/npm-install@v1
    - name: npm build
      run: npm run build
Code language: YAML (yaml)

Using the job from above, the complete code looks like this:

name: Deploy to WordPress.org
on:
  push:
    tags:
    - "*"
    - "!*-*"
jobs:
  tag:
    name: New tag
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: bahmutov/npm-install@v1
    - name: npm build
      run: npm run build
    - name: WordPress Plugin Deploy
      id: deploy
      uses: 10up/action-wordpress-plugin-deploy@stable
      env:
        SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
        SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
Code language: PHP (php)

It installs all npm dependencies and then runs the command npm run build, which is used in @wordpress/scripts to build the assets. This is done before deploying it to WordPress.org.

Deploy to remote server via SSH

It may also necessary to deploy the code to a remote server, in this example via rsync on a SSH connection. I use that to keep a plugin updated automatically after deploying a new version on my server without the need to search for updates, first. I use the actions shimataro/ssh-key-action and Burnett01/rsync-deployments for that, but it’s also possible to run a rsync command directly in GitHub Actions (as any other shell command as well):

      - name: Install SSH key
        uses: shimataro/ssh-key-action@v2
        with:
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          known_hosts: ${{ secrets.KNOWN_HOSTS }}
      - name: Deploy plugin
        uses: Burnett01/rsync-deployments@7.0.1
        with:
          switches: -ahv --exclude=".git"
          path: .
          remote_path: /home/wp-content/plugins/plugin-name
          remote_host: ${{ secrets.REMOTE_HOST }}
          remote_user: ${{ secrets.REMOTE_USER }}
          remote_key: ${{ secrets.SSH_PRIVATE_KEY }}
Code language: YAML (yaml)

The action shimataro/ssh-key-action makes sure that the GitHub Action knows the host key of my remote server and thus allow connecting to it. The second one actually deploys the code as is to the plugins directory of a WordPress instance on my server.

To use it, you need to create certain secrets again as mentioned above:

  • KNOWN_HOSTS: The host key(s) of your remote host. For the server example.com, you can retrieve them via ssh-keyscan example.com.
  • SSH_PRIVATE_KEY: A SSH private key that matches an allowed SSH public key on your remote server.
  • REMOTE_HOST: The hostname of your remote server.
  • REMOTE_USER: The username on your remote server.

Create release

You can also create a GitHub release and attach the plugin/theme as ZIP file to it to always allow access to a released version of your plugin/theme. This requires you to create the ZIP file yourself and then add it to a release via a GitHub action:

      - run: mkdir ${{ github.event.repository.name }}-build && rsync -a . ${{ github.event.repository.name }}-build
      - run: cd ${{ github.event.repository.name }}-build && zip -r ../${{ github.event.repository.name }}.zip * -x "${{ github.event.repository.name }}-build/*" && cd ..
      - run: rm -rf ${{ github.event.repository.name }}-build
      - name: Create Release
        id: create_release
        uses: softprops/action-gh-release@v2
        with:
          files: ${{ github.event.repository.name }}.zip
          name: Release ${{ github.ref_name }}
Code language: YAML (yaml)

I use a temporary directory to copy all data into it I want to have included in the ZIP file. Via rsync, I could add certain excludes, which won’t be copied to this directory and thus were not present inside the ZIP file later on.

To create the release, I then use the GitHub Action softprops/action-gh-release and attach the created ZIP file to this release. The ZIP file is named after the repository while the release is named after the tag I gave it.

Conclusion

Nobody wants to do something manually that can be automated. GitHub Actions are perfectly usable to deploy your WordPress plugin/theme fully automatically and without even think about it once the actions have been defined.

Leave a Reply

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