Command Line WordPress, Node.js, Unit Testing

Dockunit: Containerized Unit Testing Across Any Platform and Programming Language

Problem:

I want my application to work on all the environments I claim to support but I have no way of easily testing updates in each environment.

Bad Solution:

Continuously push to your remote to force Travis CI to test changes in multiple environments.

Good Solution:

Containerized unit testing with Dockunit.

Dockunit is a simple node command that lets you run your test framework of choice across a number of predefined containers. Each container can have it’s own test command and Docker image. It was born out of the need to ensure my PHP applications (WordPress specifically) were compatible with a spectrum of environments. Travis CI dropping support for PHP 5.2 was the final straw so I created this command for myself and decided to make it public.

Install/Usage Instructions for Dockunit

1. Ensure dependencies are met. See requirements on Github.

2. Install Dockunit

npm install -g dockunit

3. Setup project(s) with predefined containers.

To do this create a file called Dockunit.json in the root of any project you want to run Dockunit on. Github contains specific guidelines for how to write Dockunit.json files. Here is an example file for testing a WordPress plugin in PHP 5.2 FPM in WordPress 4.1, PHP 5.5 FPM in WordPress 4.0, and PHP 5.5 for Apache in WordPress 3.9:

{
  "containers": [
    {
      "prettyName": "PHP 5.2 FPM WordPress 4.1",
      "image": "tlovett1/php-5.2-phpunit-3.5",
      "beforeScripts": [
        "service mysql start",
        "bash bin/install-wp-tests.sh wordpress_test root '' localhost 4.1"
      ],
      "testCommand": "phpunit"
    },
    {
      "prettyName": "PHP 5.5 FPM WordPress 4.0",
      "image": "tlovett1/php-fpm-phpunit-wp",
      "beforeScripts": [
        "service mysql start",
        "bash bin/install-wp-tests.sh wordpress_test2 root '' localhost 4.0"
      ],
      "testCommand": "phpunit"
    },
    {
      "prettyName": "PHP 5.5 for Apache WordPress 3.9",
      "image": "tlovett1/php-apache-phpunit-wp",
      "beforeScripts": [
        "service mysql start",
        "bash bin/install-wp-tests.sh wordpress_test3 root '' localhost 3.9"
      ],
      "testCommand": "phpunit"
    }
  ]
}

3. Run Dockunit command.

dockunit

Note: This assumes you have changed directories to your project root. You may need to sudo.

Detailed command usage instructions can be found on Github. Contributions and bug reports are encouraged :).

Command Line WordPress, Unit Testing, WP API

Using the WordPress JSON REST API in Testing Suites with Travis CI

Problem:

We are writing custom endpoints and routes that extend WP API in a theme or plugin. We want to write tests for this code and run tests in Travis CI. Right now, WP API is not in WordPress core and must be included as a plugin. Therefore, we have a WordPress plugin/theme that depends on another plugin. We want to make sure all our dependencies are installed/included when we bootstrap our testing suite. WP API is not a registered Composer package.

Bad Solution #1:

Complain about WP API not being a registered Composer package. Just joking. The reason behind this is that WP API must remain backwards compatible after being included in WordPress core.

Bad Solution #2:

Include WP API in your theme/plugin as a Git submodule. Not only are Git submodules annoying but this doesn’t even make sense. Git submodules point to a specific commit. We want to just install the latest stable version which isn’t possible using submodules unless we want to manually update our submodule commit hash every time WP API is updated.

Final Solution

We need to manually include WP API in our plugin/theme but we want it up-to-date. We want to pretend WP API is a Composer package. If it’s not already there, create a folder vendor/ in the root of your project. This is the same folder that Composer will store your packages. Add vendor/ to your .gitignore since we don’t need this code in production (assuming you don’t have other packages in vendor that are needed in production).

We can execute bash scripts whenever Composer install/update is called. Let’s write a simple Bash script to clone/update WP API into vendor/. Place this code in bin/install-wp-api.sh:

cloneOutput=$(git clone https://github.com/WP-API/WP-API.git ./vendor/wp-api 2>&1)

if [[ $cloneOutput =~ "destination path './vendor/wp-api' already exists" ]]; then
  cd vendor/wp-api
  git reset --hard &>/dev/null
  git checkout master &>/dev/null
  git reset --hard &>/dev/null
  git pull origin master &>/dev/null
fi

This script will clone WP API, if it doesn’t exist. Otherwise it will checkout the master branch and pull the latest from Github.

Now we need to execute this script. We will use Composer scripts. Here is an example composer.json file:

{
    "name": "tlovett1/package-name",
    "description": "Description of my package.",
    "license": "MIT",
    "authors": [
        {
            "name": "Taylor Lovett",
            "email": "email@email.com"
        }
    ],
    "minimum-stability": "stable",
    "require": {},
    "scripts": {
        "pre-install-cmd": [
            "./bin/install-wp-api.sh"
        ],
        "pre-update-cmd": [
            "./bin/install-wp-api.sh"
        ]
    }
}

composer.json defines your package as a Composer package, registers it’s dependancies, and more. As I mentioned before, we can call scripts as well. We use the pre-install-cmd hook to execute our script every time composer install is called. We use the pre-update-cmd hook to execute our script every time composer update is called. On both of these hooks we are executing our script at ./bin/install-wp-api.sh.

Now we simply add the following to our .travis.yml file:

before_script:
   - composer install

In your test suite bootstrap file, you can insert the following PHP to manually use WP API assuming you are using the WordPress standard unit testing suite:

function _manually_load_plugin() {
	require( dirname( __FILE__ ) . '/../vendor/wp-api/plugin.php' );
}
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );

EDIT: Another solution which is easier than this one is using a composer inline package.

Command Line WordPress, Node.js, WordPress for Enterprise

Run WordPress Cron on Real Unix Cron with Node.js

WordPress cron is a confusing beast. Most people don’t understand it or intentionally use it. It is not the same technology as Unix cron. Scheduled post functionality actually depends on WordPress cron. By default on every page load, WordPress checks to see if any cron events are due to fire. If an event is due, it sends a request to wp-cron.php asynchronously to execute the event(s).

So what?

This system works great for small websites running simple theme and plugin setups. Often when building WordPress applications for enterprise, enough resource intensive events get setup on cron that HTTP requests timeout before completion. We can circumvent this problem by executing WordPress cron using actual cron.

wp-cron-node is a simple node command that runs WordPress cron events via PHP CLI and Unix cron. It will execute WordPress cron events that are due for execution. The command requires WP-CLI.

Let’s run our scheduled events using actual Unix cron and Node:

  1. Make sure npm and WP-CLI are installed.
  2. Run the following command:
    npm install -g wp-cron-node
  3. Disable WordPress cron. This will prevent HTTP requests from triggering cron events. Put this code in wp-config.php:
    define( 'DISABLE_WP_CRON', true );
  4. Finally, setup your crontab file to your liking. Edit your crontab with the following command:
    crontab -e

    Here is an example crontab entry that will check for scheduled events every 10 minutes.

    */10 * * * * wp-cron-node /path/to/wp

    Note: Running this every 10 minutes means cron events could fire up to 10 minutes late. Ten is a conservative number for performance reasons. Change this to whatever makes you comfortable.

Command Line WordPress, WordCamps, WordPress Plugins

WordCamp Ottawa

This weekend I was lucky enough to present at the 2nd annual WordCamp Ottawa. My talk was titled “Saving Time with WP-CLI”. WP-CLI is a plugin that lets you interact with your WordPress installations via the command line. My talk runs through some cool built-in WP-CLI commands as well as creating custom commands. My slides for the talk are here: