Configure PHP_CodeSniffer and Visual Studio Code to manage coding standards for WordPress Development

In this article I’ll try to show you how to setup a development environment for a WordPress plugin that follows the WordPress coding standards.

I’ll be using Composer for installing all the packages and configuring namespaces for autoloading. So be sure to have it installed globally first.

Be noted that there are some standards that will not be followed like the file naming, since I want to be able to use composer packages with autoloading without too much hassle.

If you want an introduction on PHPCodeSniffer and PHPCodeBeautifier, take a look at this excellent presentation given by Sal Ferrarello (@salcode).

TOC

Start the project

The first step is easy.. just create a folder in you plugins directory and start composer.

cd /path/to/wordpress/wp-content/plugins/
mkdir my-plugin && cd my-plugin/
composer init

Answer the questions that composer issues like the name of the package and the author.

In my case, I didn’t defined dependencies just yet so my composer.json file looks like this:

// composer.json
{
  "name": "marioy47/wordpress-phpcs",
  "description": "Test for phpcs in wordpress",
  "type": "project",
  "authors": [
    {
      "name": "Mario Yepes",
      "email": "[email protected]"
    }
  ],
  "require": {}
}

Install PHPCS Composer Installer

This is a composer package that makes installing PHP_CodeSniffer files easier and per project (as opposed of globally).

So in a terminal, just issue the following command:

composer require --dev 'dealerdirect/phpcodesniffer-composer-installer:*'

This might take a little while if this is the first time that you execute a composer require ... command in you environment since it has to verify all versions and create local copies of files.

After the command finishes, add the following lines to composer.json

// composer.json
{
  // ...
  "scripts": {
    "install-codestandards": [
      "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run"
    ],
    "post-install-cmd": ["@install-codestandards"]
  }
}

This creates a new section called scripts where we instruct composer to execute the command to install any coding standard after installing any composer package.

This might seem like an overkill since it executes the install-codestandards script every time we issue a composer require ... command, but we’re supposed to do that just a couple of times throughout the project configuration.

Install PHPCS Validators

Now that we have composer configured to install and configure any new coding standard, we can start installing them.

We’ll be installing the following sniffs:

So just open up a terminal in the plugin directory and execute the following command:

composer require --dev 'phpcompatibility/php-compatibility:*' \
  'phpcompatibility/phpcompatibility-wp:*'  \
  'sirbrillig/phpcs-variable-analysis:*' \
  'wp-coding-standards/wpcs:*'

And add the following in the scripts section on the composer.json file:

// composer.json
{
  // ...
  "scripts": {
    // Add this three commands.
    "phpcs": "phpcs",
    "phpcsi": "phpcs -i",
    "phpcbf": "phpcbf"
  }
}

To validate that you have installed all the required standards you should execute phpcs -i but since we have phpcs installed only locally we created the composer phpcs-i command. That will list the locally installed standards.

$ composer phpcsi
> phpcs -i
The installed coding standards are PEAR, Zend, PSR2, MySource, Squiz, PSR1, PSR12, PHPCompatibility, PHPCompatibilityParagonieRandomCompat, PHPCompatibilityParagonieSodiumCompat, PHPCompatibilityWP, VariableAnalysis, WordPress, WordPress-Extra, WordPress-Docs and WordPress-Core

Our first test

Lets do a simple test by creating a REALLY BAD php file called phpcs-test.php:

// phpcs-test.php

function my_FunctionOne()
{ $a = null;
$b;
    // This is a test
return ""}

And in the terminal run composer phpcs to verify that its working. You should get something like:

$ composer phpcs phpcs-test.php
> phpcs 'phpcs-test.php'

FILE: /Users/Mario/Projects/blog-posts/wordpress-phpcs/phpcs-test.php
----------------------------------------------------------------------
FOUND 8 ERRORS AFFECTING 5 LINES
----------------------------------------------------------------------
 2 | ERROR | [ ] Missing file doc comment
 3 | ERROR | [ ] Function name "my_FunctionOne" is prefixed with a
   |       |     package name but does not begin with a capital
   |       |     letter
 3 | ERROR | [ ] Function name "my_FunctionOne" is invalid; consider
   |       |     "My_functionOne" instead
 3 | ERROR | [ ] Missing doc comment for function my_FunctionOne()
 4 | ERROR | [x] Opening brace must be the last content on the line
 5 | ERROR | [x] Line indented incorrectly; expected at least 4
   |       |     spaces, found 0
 7 | ERROR | [x] Line indented incorrectly; expected at least 4
   |       |     spaces, found 0
 7 | ERROR | [x] Closing brace must be on a line by itself
----------------------------------------------------------------------
PHPCBF CAN FIX THE 4 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 45ms; Memory: 4MB

Script phpcs handling the phpcs event returned with error code 2

This confirms that PHP_CodeSniffer is working and detecting error on php files. But if you are familiar with Wordpress Standards, you can see that the WordPress Coding Standards are NOT being checked even though we have them installed.

That’s because we still have to tell PHP_CodeSniffer to check against WordPress standards.

Checking and fixing files with bad WordPress standards

To have composer phpcs use the WordPress standards, add the following 2 commands to the scripts section in the composer.json file.

// composer.json
{
  // ...
  "scripts": {
    // ...
    "phpcs-wp": [
      "phpcs --standard=WordPress,WordPress-Extra,WordPress-Docs,WordPress-Core"
    ],
    "phpcbf-wp": [
      "phpcbf --standard=WordPress,WordPress-Extra,WordPress-Docs,WordPress-Core"
    ]
  }
}

And execute composer phpcs-wp phpcs-test.php to make the check but using WordPress standards

$ composer phpcs-wp phpcs-test.php
> phpcs --standard=WordPress,WordPress-Extra,WordPress-Docs,WordPress-Core 'phpcs-test.php'

FILE: /Users/Mario/Projects/blog-posts/wordpress-phpcs/phpcs-test.php
----------------------------------------------------------------------
FOUND 12 ERRORS AFFECTING 6 LINES
----------------------------------------------------------------------
 1 | ERROR | [ ] Missing file doc comment
 3 | ERROR | [x] Expected exactly one space between closing
   |       |     parenthesis and opening control structure; "
   |       |     " found.
 3 | ERROR | [ ] Function name "my_FunctionOne" is not in snake case
   |       |     format, try "my_function_one"
 3 | ERROR | [ ] Missing doc comment for function my_FunctionOne()
 4 | ERROR | [x] Opening brace should be on the same line as the
   |       |     declaration
 4 | ERROR | [x] Opening brace must be the last content on the line
 5 | ERROR | [x] Line indented incorrectly; expected at least 1 tabs,
   |       |     found 0
 6 | ERROR | [x] Tabs must be used to indent lines; spaces are not
   |       |     allowed
 6 | ERROR | [ ] Inline comments must end in full-stops, exclamation
   |       |     marks, or question marks
 7 | ERROR | [x] Line indented incorrectly; expected at least 1 tabs,
   |       |     found 0
 7 | ERROR | [ ] PHP syntax error: syntax error, unexpected '}',
   |       |     expecting ';'
 7 | ERROR | [x] String "" does not require double quotes; use single
   |       |     quotes instead
----------------------------------------------------------------------
PHPCBF CAN FIX THE 7 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 207ms; Memory: 8MB

Script phpcs --standard=WordPress,WordPress-Extra,WordPress-Docs,WordPress-Core handling the phpcs-wp event returned with error code 2

NOW we are applying WordPress standards!.

But there are some elements that we’re still not validating, like language namespace and the warning of unused variables.

We could add more parameters to the command phpcs-wp on the scripts section in composer.json file. But that would make it very complex and with way too many parameters, that’s why we’ll be using a configuration file to tell PHP_CodeSniffer ALL the checks and ignores.

PHPCS configuration using xml file

PHP_CodeSniffer can be configured by creating a phpcs.xml.dist file in the root of our project.

Among other things, this file tells phpcs which checks to perform, which files to check, what languages to check, how fast the checks should be performed, which directories to ignore, etc.

To be sincere, this file is kind of complex and deserves its own blog article to explain. So for now I’ll just say that the following phpcs.xml.dist file will check to following:

So take the following code and save it in a file called phpcs.xml.dist

<!-- phpcs.xml.dist -->
<?xml version="1.0"?>
<ruleset name="Wordpress Plugin">
  <config name="minimum_supported_wp_version" value="5.1" />
  <config name="testVersion" value="7.0-"/>

  <rule ref="PHPCompatibilityWP"/>
  <rule ref="WordPress-Core">
    <!-- a couple of excldes since I dont want any issues with composer packages -->
    <exclude name="WordPress.Files.FileName.NotHyphenatedLowercase" />
    <exclude name="WordPress.Files.FileName.InvalidClassFileName" />
  </rule>
  <rule ref="WordPress-Docs" />
  <rule ref="WordPress-Extra" />
  <rule ref="VariableAnalysis" />
  <rule ref="WordPress.WP.I18n">
    <properties>
      <!-- CONFIGURE HERE YOUR text-domain -->
      <property name="text_domain" type="array" value="text-domain" />
    </properties>
	</rule>
  <rule ref="Squiz.PHP.CommentedOutCode.Found">
    <severity>0</severity>
  </rule>

  <!-- CONFIGURE HERE THE PATHS YOU WANT TO CHECK -->
  <file>plugin-start-file.php</file>
  <file>app/</file>

  <!-- Show sniff codes in all reports -->
  <arg value="sp"/> <!-- Show sniff and progress -->
  <arg name="parallel" value="8"/> <!-- Enables parallel processing when available for faster results. -->
  <arg name="colors"/>
  <arg name="extensions" value="php"/>

  <!-- Configure here the paths you want to IGNORE -->
  <exclude-pattern>/docker/*</exclude-pattern>
  <exclude-pattern>/node_modules/*</exclude-pattern>
  <exclude-pattern>/tests/*</exclude-pattern>
  <exclude-pattern>/vendor/*</exclude-pattern>
</ruleset>

Now you can execute composer phpcs without any arguments and it will validate against Wordpress and any additional rule you’ve configured

Don’t forget to change the paths and the text-domain first… Otherwise you’ll get errors.

Visual Studio Code

Up until now, all works on the terminal. But is very probable that you are using Visual Studio Code to create you new amazing plugin.

So lets configure Visual Studio Code so the code validation is done automatically for us. For that we’ll be installing a couple of extensions and creating a workspace configuration file.

There are a couple of extensions that work with phpcs but at the time of this writing the most updated one was wongjn.php-sniffer which can be installed with the following command:

code --install-extension wongjn.php-sniffer

And since you are using a locally installed phpcs you should make the following configuration in Visual Studio Code by editing the file .vscode/settings.json and adding the following:

// .vscode/settings.json
{
  "[php]": {
    "editor.defaultFormatter": "wongjn.php-sniffer"
  },
  "phpSniffer.executablesFolder": "vendor/bin/"
}

Now, you can use the Format Document command ( ⇧⌥F in Mac) to instantly format any php file.

Starter Project

Since this are too many files to take care of, and many commands just to start a project, I’ve created a Wordpress Plugin Starter project in GitHub that you can grab to start you own project with PHP_CodeSniffer enabled.