Common code used during development of WordPress plugins and themes
Shell PHP
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
diff-tools Fix calculation of realpath from phpcs paths Jul 30, 2018
sample-config Introduce our own Travis runs Apr 20, 2018
.coveralls.yml Remove obsolete src_dir config from Coveralls config Mar 14, 2016
.editorconfig JSHint: Treat JSON files the same as JS, apart from whitelisted files Jul 22, 2016
.eslintignore Add .eslintignore as copy of .jshintignore Mar 31, 2016
.eslintrc Raise ESLint Complexity level to 8. Mar 27, 2017
.gitattributes Add .gitattributes Oct 21, 2014
.gitignore Ignore composer packages Apr 18, 2018
.jscsrc Excude jsx files from jscs May 9, 2016
.jshintignore Stop using .jshintignore as symlink; copy and use from linting dir Feb 15, 2016
.jshintrc Sync .jshintrc from core Mar 8, 2017
.travis.yml Check all PHP files (#280) May 25, 2018
LICENSE.txt Switch from GPL to MIT following WP-CLI May 22, 2017 Fix calculation of realpath from phpcs paths Jul 30, 2018
class-wordpress-readme-parser.php Format plugin tags in URLs (#263) Dec 6, 2017
composer.json Add Composer meta file Apr 18, 2018 Develop no more Dec 8, 2014
generate-markdown-readme Use DIFF_BASE_BRANCH env variable Aug 10, 2017 Quote the paths in perl call, and drop backticks altogether Aug 2, 2016 Add a submodule-aware pre-commit installer Jul 30, 2016
mime-types.csv Adding mime type declaration for SVG format Apr 24, 2015
package.json Remove un-used Apr 21, 2018
parse-diff-ranges.php Add parse-diff-ranges May 19, 2015
phpcs.xml Improve example PHPCS ruleset Aug 14, 2018
phpunit-plugin-bootstrap.php Remove erroneous trailing slashes from WP_CONTENT_DIR and WP_PLUGIN_DIR May 2, 2018
phpunit-plugin.xml Exclude build dir from unit test coverage Aug 6, 2016
pre-commit Check if this is a regular file before using the dev-lib fallback Jan 13, 2017 Improve example PHPCS ruleset Aug 14, 2018
svn-push Ignore .eslintrc from svn-push Jul 8, 2016 Fail louder Dec 21, 2017 Allow PHPUNIT_VERSION to be configurable May 30, 2018 Add environment variable for skipping paths-scope printing Mar 26, 2018


Common tools to facilitate the development and testing of WordPress themes and plugins


Install as submodule

To install as Git submodule (recommended):

git submodule add -b master dev-lib

To update the library with the latest changes:

git submodule update --remote dev-lib
git add dev-lib
git commit -m "Update dev-lib"

To install the pre-commit hook, symlink to pre-commit from your project's .git/hooks/pre-commit, you can use the bundled script to do this:


Also symlink (or copy) the .jshintrc, .jshintignore, .jscsrc, phpcs.xml, and phpunit-plugin.xml (note the PHPUnit config will need its paths modified if it is copied instead of symlinked):

ln -s dev-lib/phpunit-plugin.xml phpunit.xml.dist && git add phpunit.xml.dist # (if working with a plugin)
ln -s dev-lib/phpcs.xml . && git add phpcs.xml
ln -s dev-lib/.jshintrc . && git add .jshintrc
ln -s dev-lib/.jscsrc . && git add .jscsrc
ln -s dev-lib/.eslintrc . && git add .eslintrc
ln -s dev-lib/.eslintignore . && git add .eslintignore
ln -s dev-lib/.editorconfig . && git add .editorconfig
cp dev-lib/.jshintignore . && git add .jshintignore # don't use symlink for this

It is a best practice to install the various tools as dependencies in the project itself, pegging them at specific versions as required. This will ensure that the the tools will be repeatably installed across environments. When a tool is installed locally, it will be used instead of any globally-installed version. To install packages locally, for example:

npm init # if you don't have a package.json already
npm install --save-dev eslint jshint jscs grunt-cli
git add package.json
echo 'node_modules' >> .gitignore

composer init # if you don't have a composer.json already
composer require php '>=5.2' # increase this if you need
composer require --dev "wp-coding-standards/wpcs=*"
composer require --dev "phpcompatibility/phpcompatibility-wp=*"
composer require --dev dealerdirect/phpcodesniffer-composer-installer
echo 'vendor' >> .gitignore

git add .gitignore

See below for how to configure your .travis.yml.

Install via symlink (non-submodule)

Often installing as a submodule is not viable, for example when contributing to an existing project, such as WordPress Core itself. If you don't want to install as a submodule you can instead just clone the repo somewhere on your system and then just add the pre-commit hook (see below) to symlink to this location, for example:

git clone ~/Projects/wp-dev-lib
~/Projects/wp-dev-lib/ /path/to/my-plugin

For the Travis CI checks, the sample .travis.yml in the sample-config directory will clone the repo into the dev-lib directory if it doesn't exist (or whatever your DEV_LIB_PATH environment variable is set to).

To install the .jshintrc, .jshintignore, .jscsrc, and (especially optionally) phpcs.xml, copy the files into the repo root (as opposed to creating symlinks, as when installing via submodule).

To install dev-lib for all themes and plugins that don't already have a pre-commit hook installed, and to upgrade the dev-lib for any submodule installations, you can run the bundled script which will look for any repos in the current directory tree and attempt to auto-install. For example:

git clone ~/Shared/dev-lib
cd ~/Shared/dev-lib
./ ~/Projects/wordpress

Install via Composer

Add wp-dev-lib as a Composer developer dependancy to your project:

composer require xwp/wp-dev-lib:dev-master --dev

which will place this library under vendor/xwp/wp-dev-lib.

Travis CI

Copy the sample-config/.travis.yml file into the root of your repo:

cp dev-lib/sample-config/.travis.yml .

Note that the bulk of the logic in this config file is located in,, and, so there is minimal chance for the .travis.yml to diverge from upstream. Additionally, since each project likely may need to have unique environment targets (such as which PHP versions, whether multisite is relevant, etc), it makes sense that .travis.yml gets forked.

Important Note: The format of the .travis.yml changed in January 2016, so make sure that the file is updated to reflect the changes.

Edit the .travis.yml to change the target PHP version(s) and WordPress version(s) you need to test for and also whether you need to test on multisite or not:

    - 5.3
    - 7.0


Having more variations here is good for open source plugins, which are free for Travis CI. However, if you are using Travis CI with a private repo you probably want to limit the jobs necessary to complete a build. So if your production environment is running PHP 5.5, is on the latest stable version of WordPress, and is not multisite, then your .travis.yml could just be:

    - 5.5


This will greatly speed up the time build time, giving you quicker feedback on your pull request status, and prevent your Travis build queue from getting too backlogged.

Limiting Scope of Checks

A barrier of entry for adding automated code quality checks to an existing project is that there may be a lot of issues in your codebase that get reported initially. So to get passing builds you would then have a major effort to clean up your codebase to make it conforming to PHP_CodeSniffer, JSHint, and other tools. This is not ideal and can be problematic in projects with a lot of activity since these changes will add lots of conflicts with others' pull requests.

To get around this issue, there is now an environment variable available for configuration: CHECK_SCOPE. By default its value is patches which means that when a pre-commit runs or Travis runs a build on a pull request or commit, the checks will be restricted in their scope to only report on issues occurring in the changed lines (patches). Checking patches is the most useful, but CHECK_SCOPE=changed-files can be added in the project config so that the checks will be limited to the entirety of any file that has been modified.

Also important to note that when the the pre-commit check runs, it will run the linters (PHPCS, JSHint, JSCS, etc) on the staged changes, not the files as they exist in the working tree. This means that you can use git add -p to interactively select changes to stage (which is a good general best practice in contrast to git commit -a), and any code excluded from being staged will be ignored by the linter. This is very helpful when you have some debug statements which you weren't intending to commit anyway (e.g. print_r() or console.log()).

With CHECK_SCOPE=patches and CHECK_SCOPE=changed-files available, it is much easier to integrate automated checks on existing projects that may have a lot of nonconforming legacy code. You can fix up a codebase incrementally line-by-line or file-by-file in the normal course of fixing bugs and adding new features.

If you want to disable the scope-limiting behavior, you can define CHECK_SCOPE=all.

Environment Variables

You may customize the behavior of the .travis.yml and pre-commit hook by specifying a .dev-lib (formerly Bash script in the root of the repo, for example:

PHPCS_IGNORE='tests/*,includes/vendor/*' # See also PATH_INCLUDES below
PATH_INCLUDES="docroot/wp-content/plugins/acme-* docroot/wp-content/themes/acme-*"

Set DEFAULT_BASE_BRANCH to be whatever your default branch is in GitHub; this is use when doing diff-checks on changes in a branch build on Travis CI. The PATH_INCLUDES is especially useful when the dev-lib is used in the context of an entire site, so you can target just the themes and plugins that you're responsible for. For excludes, you can specify a PHPCS_IGNORE var and override the .jshintignore; there is a PATH_EXCLUDES_PATTERN as well.

Pre-commit tips

As noted above in Limiting Scope of Checks, the default behavior for the linters is to only report errors on lines that lie within actual staged changes being committed. So remember to selectively stage the files (via git add ...) or better the patches (via git add -p ...).

Skipping Checks

If you do need to disable the pre-commit hook for an extenuating circumstance (e.g. to commit a work in progress to share), you can use the --no-verify argument:

git commit --no-verify -m "WIP"

Alternatively, you can also selectively disable certain aspects of the pre-commit hook from being run via the DEV_LIB_SKIP environment variable. For example, when there is a change to a PHP file and there are PHPUnit tests included in a repo, but you've just changed a PHP comment or something that certainly won't cause tests to fail, you can make a commit and run all checks except for PHPUnit via:

DEV_LIB_SKIP=phpunit git commit

You can string along multiple checks to skip via commas:

DEV_LIB_SKIP=composer,phpunit,phpcs,yuicompressor,jscs,jshint,codeception,executebit git commit

Naturally you'd want to create a Git alias for whatever you use most often, for example:

git config --global alias.commit-without-phpunit '!DEV_LIB_SKIP="$DEV_LIB_SKIP,phpunit" git commit'

Which would allow you to then do the following (with Bash tab completion even):

git commit-without-phpunit

Aside, you can skip Travis CI builds by including [ci skip] in the commit message.

Running specific checks

If you would like to run a specific check and ignore all other checks, then you can use DEV_LIB_ONLY environment variable. For example, you may want to only run PHPUnit before a commit:

DEV_LIB_ONLY=phpunit git commit

Manually invoking pre-commit

Sometimes you may want to run the pre-commit checks manually to compare changes (patches) between branches much in the same way that Travis CI runs its checks. To compare the current staged changes against master, do:

DIFF_BASE=master .git/hooks/pre-commit

To compare the committed changes between master and the current branch:

DIFF_BASE=master DIFF_HEAD=HEAD .git/hooks/pre-commit

PHPUnit Code Coverage

The plugin-tailored phpunit.xml has a filter in place to restrict PHPUnit's code coverage reporting to only look at the plugin's own PHP code, omitting the PHP from WordPress Core and other places that shouldn't be included. The filter greatly speeds up PHPUnit's execution. To get the code coverage report written out to a code-coverage-report directory:

phpunit --coverage-html code-coverage-report/

Then you can open up the index.html in that directory to learn about your plugin's code coverage.


Bootstrap Codeception by:

wget -O /tmp/codecept.phar
php /tmp/codecept.phar bootstrap

Then update Acceptance tests configuration to reflect your own environment settings:

vim tests/acceptance.suite.yml

You can generate your first test, saved to tests/acceptance/WelcomeCept.php by:

php /tmp/codecept.phar generate:cept acceptance Welcome


Create an empty .gitter file in the root of your repo and a Gitter chat badge will be added to your project's README.

Join the chat

Plugin Helpers

The library includes a WordPress README parser and converter to Markdown, so you don't have to manually keep your readme.txt on in sync with the you have on GitHub. The converter will also automatically recognize the presence of projects with Travis CI and include the status image in the markdown. Screenshots and banner images for are also automatically incorporated into the

What is also included in this repo is an svn-push to push commits from a GitHub repo to the SVN repo for the plugin. The /assets/ directory in the root of the project will get automatically moved one directory above in the SVN repo (alongside trunk, branches, and tags). To use, include an svn-url file in the root of your repo and let this file contains he full root URL to the repo for plugin (don't include trunk).

The utilities in this project were first developed to facilitate development of XWP's plugins.