Custom WordPress and WooCommerce Development

Use WP-Cli in your GitHub actions for translating plugin releases

Anybody who follows me on Twitter knows that I am always, and I mean, always fighting the build tools. Things that are supposed help us automate tasks and make life easier, frequently are hard to set up, break, and generally cause me a lot of stress.

So when I figured out how to have Grunt handle most of my plugin building routine (compile SASS into CSS, minimize JS, make a .pot file for translation support, package it up into a .zip file), let’s just say… I have not touched that process that much.

But now Blocks are a whole thing, which I also lament about on the Twitters… and my Grunt translation tasks do not include/cover the strings in the jsx/block script. Le sigh.

The WP CLI tools includes a translation tool for making a .pot file. Great! A lot of teams rely on doing this locally, whereas I now use GitHub actions to build all the things and generate a zip file for my plugin release.

Fortunately, it is possible to combine the powers of several build tool processes to get the WP CLI translation tool to run in a GitHub action. This overview assumes you have some familiarity with the dreaded build tools, especially composer, npm, and Github Actions.

Step 1 – require wp-cli

Require wp-cli as a dev dependency in your composer.json

    "name": "kathyisawesome/my-awesome-plugin",
    "require-dev": {
        "wp-cli/i18n-command": "*"
    "scripts": {
        "makepot-audit": [
			"wp --allow-root i18n make-pot . languages/free_gift_coupons.pot --slug=wc_free_gift_coupons --exclude=\".github,.wordpress-org,node_modules,vendor,build,deploy\" --headers=\"Report-Msgid-Bugs-To:\n\""
        "makepot": [
			"@makepot-audit --skip-audit"
}Code language: JSON / JSON with Comments (json)

Or you can also run composer require --dev wp-cli/i18n-command from your command line in your plugin’s root directory.

Step 2 – define npm script for calling wp-cli

Define an npm script in your package.json that calls your new composer script.

"makepot": "composer run-script makepot",

This is optional as it largely depends on Step 3, how you set up your GitHub action. I personally have mine do 1 big build task, but you could customize your Action to also call the composer script directly.

  "name": "my-awesome-plugin",
  "scripts": {
    "start": "wp-scripts start",
    "build:js": "wp-scripts build",
    "build": "npm run build:js && grunt build",
    "makepot": "composer run-script makepot",
    "prerelease": "npm run makepot && npm run build:js && grunt prerelease",
    "release": "npm run makepot && npm run build:js && grunt release"
}Code language: JSON / JSON with Comments (json)

npm run release is what I have my GitHub action run to build all the things and you can see that it calls npm run makepot which runs our composer script… which calls WP CLI to make the .pot file.

Some of that is probably over-abstracted. It could be moved to the GitHub action itself, but I like that I still have the option to run the tools locally if I ever need to.

Step 3 – Setup your GitHub action

If you are using a GitHub action to build your whole plugin (I do it whenever a new tag is pushed) then you need to add a few steps in your release workflow.

1. setup PHP with composer
installs composer, 2. installs npm, and then can finally run your release script.
2 setup npm
3. run your npm run release or whatever you’ve named your release script to be in your package.json

For reference, here’s my full GitHub Action. Currently the npm run release does still call some scripts from my tried and true Gruntfile.js but I might get away from that over time… then again, if it ain’t broke!

# Add build zip to GitHub releases.
# Version: 1.1.0
# yaml-language-server: $schema=

name: Release

      # Semver ( release pattern.
      - '[0-9]+.[0-9]+.[0-9]+*'

  # Build distribution release.
  # Performs the following steps:
  # - Checks out the repository.
  # - Sets up PHP with Composer.
  # - Logs debug information.
  # - Get Composer Cache Directory.
  # - Sets up Composer Caching..
  # - Logs debug information.
  # - Install Composer dependencies with development dependencies.
  # - Setup NodeJS.
  # - Get NPM cache directory.
  # - Sets up NPM Caching.
  # - Install NPM dependencies.
  # - Get release version.
  # - Check for Alpha release.
  # - Check for Beta release.
  # - Check for Release Candidate release.
  # - Logs debug information.
  # - Build release:
  #    - Pre-release.
  #    - Stable.
  # - Add package to GitHub releases.

    name: "Build distribution release."
    runs-on: ubuntu-latest
      release: stable

      - name: "Checks out the repository."
        uses: "actions/checkout@v2"

      - name: "Sets up PHP with Composer."
        uses: shivammathur/setup-php@v2
          php-version: '7.4'
          tools: composer
          COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: "Get Composer Cache Directory."
        id: composer-cache
        run: |
          echo "::set-output name=dir::$(composer config cache-files-dir)"

      - name: "Sets up Composer Caching."
        uses: "actions/cache@v2"
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-php-composer-build-${{ hashFiles('**/composer.lock') }}
          restore-keys: |
            ${{ runner.os }}-php-composer-build-

      - name: "Logs debug information."
        run: |
          php --version
          composer --version

      - name: "Install Composer dependencies with development dependencies."
        run: |
          composer install --no-interaction --prefer-dist --no-scripts

      - name: "Setup NodeJS."
        uses: actions/setup-node@v2
          node-version: '14'

      - name: "Get NPM cache directory."
        id: npm-cache-dir
        run: |
          echo "::set-output name=dir::$(npm config get cache)"

      - name: "Sets up NPM Caching."
        uses: actions/cache@v2
          path: ${{ steps.npm-cache-dir.outputs.dir }}
          key: ${{ runner.os }}-node-npm-build-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-npm-build-

      - name: "Install NPM dependencies."
        run: npm install

      - name: "Get release version."
        run: |
          echo "release_tag=$(node -p -e "require('./package.json').version")" >> $GITHUB_ENV

      - name: "Get release file base name."
        run: |
          echo "release_name=$(node -p -e "require('./package.json').name")" >> $GITHUB_ENV

      - name: "Check for Alpha release."
        if: ${{ contains(env.release_tag, '-alpha') }}
        run: |
          echo "release_status=pre-release" >> $GITHUB_ENV

      - name: "Check for Beta release."
        if: ${{ contains(env.release_tag, '-beta') }}
        run: |
          echo "release_status=pre-release" >> $GITHUB_ENV

      - name: "Check for Release Candidate release."
        if: ${{ contains(env.release_tag, '-rc') }}
        run: |
          echo "release_status=pre-release" >> $GITHUB_ENV

      - name: "Logs debug information."
        run: |
          node --version
          npm --version
          echo ${{ env.release_tag }}
          echo ${{ env.release_status }}

      - name: "Build release: Pre-release"
        if: ${{ env.release_status == 'pre-release' }}
        run: |
          npm run prerelease

      - name: "Build release: Stable"
        if: ${{ env.release_status != 'pre-release' }}
        run: |
          npm run release

      - name: "Add package to GitHub releases."
        uses: softprops/action-gh-release@v1
          files: ./deploy/${{ env.release_tag }}/${{ env.release_name }}.zip
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Code language: PHP (php)

My GitHub action was originally built by Michael Bragg, who I definitely recommend if you want some help getting started with GitHub actions.

You can see all the nuts and bolts by reviewing the source for my Nav Menu Roles plugin at GitHub.