The Hitchhiker’s Guide to the WordPress Coding Standards


A talk by @thorstenfrommen

Who’s That Guy?

Thorsten Frommen

Thorsten Frommen

  • Certified PHP engineer, web development professional, and tester.
  • Senior WordPress Engineer at Human Made.
  • Co-organizer of the local WordPress meetup in Aachen, Germany.

Coding Standards

What Are Coding Standards?

  • Rules and guidelines for writing code.
  • Adopted by a large group of people.

Terminology

  • Coding Standards
  • Coding Conventions
  • Code Style
  • Best Practices
  • Naming Conventions
  • Comment Conventions
  • ...

Who Defines Coding Standards?

  • Inventors of a programming language.
  • Company (e.g., Zend Framework Coding Standards).
  • Community (e.g., WordPress Coding Standards).
  • Any large enough group of people, actually.

Why Use Coding Standards?

  • Better readability.
  • Consistent code.
  • Easier maintenance.
  • Secure code.
  • Contributes to code quality.

“Rules are meant to be broken.”

WordPress
Coding Standards

WordPress Coding Standards

  • PHP Coding Standards
  • JavaScript Coding Standards
  • HTML Coding Standards
  • CSS Coding Standards
  • Accessibility Coding Standards

PHP Coding Standards

  • Use real tabs, and not spaces.
  • Use elseif, not else if.
  • Constants should be in all upper-case with underscores separating words:
    
    							define( 'DOING_AJAX', true );
    						

JavaScript Coding Standards

  • No whitespace at the end of line or on blank lines.
  • Use single-quotes for string literals.
  • Always include extra spaces around elements and arguments:
    
    							foo( options, object[ property ] );
    						

HTML Coding Standards

  • All tags and attributes must be written in lowercase.
  • Always quote attributes.
  • Self-closing tags should have exactly one space before the forward slash:
    
    							<br />
    						

CSS Coding Standards

  • Attribute selectors should use double quotes around values.
  • Properties should be followed by a colon and a space.
  • Rule sets for media queries should be indented one level in:
    
    							@media all and (min-width: 1024px) {
    
    								/* Your selectors */
    							}
    						

Accessibility Coding Standards

  • Use wp.a11y.speak() for all simple AJAX responses.
  • For <img> elements, the accessible name should be in the alt attribute.
  • Links surrounded by other text (in a line or block of text) need to be always underlined.

How to Start

EditorConfig
EditorConfig

.editorconfig

  • Single dot file.
  • Define and maintain consistent coding styles.
  • Usable with different editors and IDEs.

EditorConfig Properties

  • indent_style
  • indent_size
  • tab_width
  • end_of_line
  • charset
  • trim_trailing_whitespace
  • insert_final_newline
  • (max_line_length)

Example .editorconfig File


					root = true

					[*]
					charset = utf-8
					end_of_line = lf
					insert_final_newline = true
					trim_trailing_whitespace = true
					indent_style = tab

					[*.yml]
					indent_style = space
					indent_size = 2

					[*.md]
					trim_trailing_whitespace = false

					[{*.txt,wp-config-sample.php}]
					end_of_line = crlf
				

Git
Git

.gitattributes

  • Single dot file.
  • Define attributes per pathnames.

Example .gitattributes File


					* text eol=lf
					*.jpg binary
					*.png binary

					/.gitattributes export-ignore
					# Other attribute defitions...
				

PHP_CodeSniffer

PHP_CodeSniffer

  • Detects violations of PHP coding standards.
  • Actually, JavaScript and CSS too.
  • The main tool for coding standards.

PHP_CodeSniffer Standards

  • Collection of pre-configured rules.
  • Built-in standards:
    • PEAR
    • PSR2
    • Zend
    • ...

PHP_CodeSniffer WordPress Standards

  • WordPress
  • WordPress-Core
  • WordPress-VIP
  • ...

Other PHP_CodeSniffer Standards

PHP_CodeSniffer Ruleset File


					<?xml version="1.0"?>
					<ruleset name="MyStandard">

						<file>./src</file>
						<file>./index.php</file>
						<file>./uninstall.php</file>

						<exclude-pattern>*/node_modules/*</exclude-pattern>

						<arg name="extensions" value="php"/>

						<arg value="ps"/>

						<config name="testVersion" value="7.0-"/>
						<rule ref="PHPCompatibility"/>

						<rule ref="WordPress"/>

					</ruleset>
				

Including/Excluding Individual Sniffs


					<?xml version="1.0"?>
					<ruleset name="MyStandard">

						<!-- Other configuration... -->

						<rule ref="Generic.PHP.Syntax"/>

						<rule ref="WordPress">
							<exclude name="WordPress.VIP"/>
						</rule>

						<rule ref="WordPress.NamingConventions.ValidHookName">
							<properties>
								<property name="additionalWordDelimiters" value="."/>
							</properties>
						</rule>

					</ruleset>
				

Generating Reports


					<?xml version="1.0"?>
					<ruleset name="MyStandardWithReports">

						<arg name="report-full" value="report-full.txt"/>
						<arg name="report-source" value="report-source.txt"/>
						<arg name="report-summary" value="report-summary.txt"/>

						<arg name="cache"/>

						<rule ref="./phpcs.xml.dist"/>

					</ruleset>
				

Using PHP_CodeSniffer

  • Reporting:
    $ phpcs
  • Autofixing (!):
    $ phpcbf

Example: Malformatted Code


					function wp_set_post_lock($postId )
					{
						if ( ! $post = get_post( $postId ) ) return false;

						if ( 0 == ( $user_id = get_current_user_id() ) )
							return false;

						$now = time();
						$lock = "$now:$user_id";

						update_post_meta ( $post->ID, "_edit_lock", $lock);
						return array( $now, $user_id )

					}
				

Example: Automatically Fixed Code


					function wp_set_post_lock( $postId ) {
						if ( ! $post = get_post( $postId ) ) {
							return false;
						}

						if ( 0 == ( $user_id = get_current_user_id() ) ) {
							return false;
						}

						$now  = time();
						$lock = "$now:$user_id";

						update_post_meta( $post->ID, '_edit_lock', $lock );

						return array( $now, $user_id );
					}
				

Example: Manually Fixed Code


					function wp_set_post_lock( $post_id ) {
						$post = get_post( $post_id );
						if ( ! $post ) {
							return false;
						}

						$user_id = get_current_user_id();
						if ( 0 == $user_id ) {
							return false;
						}

						$now  = time();
						$lock = "$now:$user_id";

						update_post_meta( $post->ID, '_edit_lock', $lock );

						return array( $now, $user_id );
					}
				

Selectively Disabling PHP_CodeSniffer

  • Directive comments:
    • // phpcs:ignore
    • // phpcs:disable
    • // phpcs:enable
    • // phpcs:ignoreFile
  • Optional list of standards/sniffs:
    • // phpcs:ignore WordPress
    • // phpcs:disable WordPress.CSRF

ESLint
ESLint

ESLint

  • Pluggable linting utility for JavaScript and JSX.
  • Highly configurable.
  • Optional autofix capabilities.

ESLint Rule Categories

  • Possible errors.
  • Best practices.
  • Variables.
  • Node.js and CommonJS.
  • Stylistic issues.
  • ES6.

ESLint Configuration


					{
						"parserOptions": {
							"ecmaVersion": 6,
							"sourceType": "module",
							"ecmaFeatures": {
								"jsx": true
							}
						},
						"plugins": [
							"import"
						],
						"rules": {
							"eqeqeq": 2,
							"import/named": 2
						}
					}
				

Using ESLint

  • Linting:
    $ eslint
  • Autofixing:
    $ eslint --fix

Selectively Disabling ESLint Rules

  • Directive comments:
    • // eslint-disable
    • // eslint-enable
    • // eslint-disable-line
    • // eslint-disable-next-line
  • Optional list of rules:
    • // eslint-disable eqeqeq
    • // eslint-disable-line curly, eqeqeq

eslint-config-wordpress


					{
						"extends": "wordpress",
						"plugins": [
							"import"
						],
						"rules": {
							"import/named": 2
						}
					}
				

Prettier
Prettier

Prettier

  • Opinionated code formatter.
  • Works with JavaScript and CSS, and more.
  • PHP is a work-in-progress.

Not Being Used . . . Yet!?

Reach out on Twitter:

Tide
Tide

Lessons Learned

  • Coding standards make a whole lot of sense.
  • Use them!
  • It’s not all or nothing.
  • WordPress Core contains tons of CS violations. Yet!?

So Long, and Thanks for All the Fish!












slides.tfrommen.de/HGWPCS