Aryan Jasala

A local WordPress dev setup: LocalWP, MailHog, PHPCS

A laptop running a local WordPress stack with three services beside it

A WordPress local setup that catches mistakes before review does: LocalWP for the site, MailHog so test mail never reaches a real inbox, PHPCS and PHPCBF for the coding standards, and the handful of editor extensions that actually earn their place. This is the toolchain, the install commands, and the standards worth memorising.

Where a violation gets caught
Editorphpcs inline, as you type
phpcbfrepairs what it can
phpcswhat is left needs a human
CI on pushphpcs runs on every push
Human reviewstandards already enforced

Run phpcbf first, then phpcs; what remains is the short human list.

Standards are enforced four times before a human sees the code, so review is not the first check.

The site and the editor

LocalWP spins up a WordPress site in a few clicks, which is the whole reason to use it.

The editor extensions that matter for PHP work:

  • PHP Intelephense -> completion and go-to-definition
  • phpcs -> standards violations inline, as you type
  • phpcbf -> fixes them
  • PHP DocBlocker -> generates the docblock skeleton
  • PHP Debug -> step debugging

Deliberately not the WordPress-specific extensions on day one. Core PHP first, then the framework on top of it. ๐Ÿงฑ

MailHog, so nothing escapes

MailHog starts two servers, an SMTP listener and a web panel. It accepts mail and shows it in the panel instead of delivering it.

SMTP : 1025
HTTP : 8025

For mail sent through PHP’s own mail() rather than SMTP, install mhsendmail and point php.ini at it:

sendmail_path = "/path/to/go/bin/mhsendmail"

Now a plugin that fires 400 password resets during a migration test fires them at you. ๐Ÿ™ƒ

PHPCS

PHPCS reports violations of a defined coding standard. On WordPress VIP it ships with the repo already configured. Everywhere else, install it globally through Composer:

composer global require "squizlabs/php_codesniffer=*"

One file:

phpcs <filename>

Everything under the current directory:

phpcs .

PHPCBF

PHP Code Beautifier and Fixer, the other half of the same tool. It repairs every violation it knows how to repair:

phpcbf <filename>
phpcbf .

Run phpcbf first, then phpcs, and what is left is the list of things that need a human. That is usually a much shorter list than the first run suggests. ๐Ÿงน

Where test mail stops
Site sends mailSMTP, or PHP mail()
MailHog SMTPlistener on port 1025
Held, not deliveredno real inbox reached
Web panelread it on port 8025

Mail sent through PHP's mail() needs mhsendmail set as sendmail_path in php.ini.

MailHog accepts mail on one port and shows it on another, so it never reaches a real inbox.

The standards worth memorising

The rules that come up in review over and over:

  • opening and closing PHP tags go on lines of their own
  • no short tags, so no <? ?>
  • single quotes unless the string is interpolating something
  • lowercase for variables, functions, actions and filters. No camelCase
  • class files are named class-{class_name}.php
  • braces always, even where the language does not need them. No inline control structures
  • long array syntax, array()
  • spaces inside parentheses, because it makes the logic readable:
function( $param1, $param2 );

if ( ! empty( $string ) ) {

}
  • validate and sanitise everything. Never trust input

That last one is not a formatting rule sitting in a formatting list by accident. It is the only one where getting it wrong is a security bug rather than a review comment. ๐Ÿ”’

Git, and the merge conflict

The commands that cover most days:

  • git init -> start a repository
  • git config -> set user.name and user.email
  • git branch <name> -> create a branch
  • git checkout <branch> -> switch to it
  • git clone -> copy a remote repository
  • git add . -> stage everything
  • git commit -m "message" -> commit the staged changes
  • git diff -> what is not staged yet
  • git status -> what is going to be committed
  • git log -> history of the current branch
  • git push <remote> <branch> -> send it up
  • git pull -> fetch and merge

A merge conflict happens when two branches change the same line, or when one deletes a file the other edited. Git will not guess which side wins, so it stops and asks:

git log --merge

That prints a log limited to the commits involved in the conflict, which is a faster way in than reading the file and hoping. ๐Ÿ”€

The fork and pull request flow

  • fork the official repository, which gives you a server-side copy
  • clone your copy locally
  • add a remote pointing at the official repository
  • branch, change, commit
  • push the branch to your own copy
  • open a pull request from that branch against the official repository
  • it gets reviewed, approved and merged

GitHub Actions

Workflows are event driven, defined in .yml under the repository:

name: GitHub Actions Demo
on: [push]
jobs:
  Explore-GitHub-Actions:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository code
        uses: actions/checkout@v3
      - run: ls ${{ github.workspace }}
  • on -> the event that triggers the run
  • name -> what the workflow is called
  • jobs -> the units of work
  • runs-on -> the runner platform
  • steps -> executed in order

The obvious first workflow is the one that runs phpcs on every push, so the standards above stop being something anyone has to remember. wp scaffold plugin-tests will even write you a CI config to start from. ๐Ÿค–

What this does not cover

Xdebug configuration, wp-env and Docker-based setups, and the WordPress-specific PHPCS ruleset, which is a separate install from the standard above and is the one you actually want on a WordPress project. ๐Ÿšง