Skip to content

Commit c683839

Browse files
first commit
1 parent dc7f678 commit c683839

33 files changed

+2365
-0
lines changed

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# --- Windows and Mac files
2+
[Tt]humbs.db
3+
.DS_Store
4+
5+
# --- Root
6+
/*
7+
!.github
8+
!.gitignore
9+
!composer.json
10+
!composer.lock
11+
!README.md
12+
!LICENSE
13+
14+
# -- Rules
15+
!Travelopia-WordPress

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# WordPress Docker Images
2+
3+
![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)
4+
5+
Official Travelopia WordPress PHP coding standards.
6+
7+
<table width="100%">
8+
<tr>
9+
<td align="left" width="70%">
10+
<p>Built by the super talented team at <strong><a href="https://www.travelopia.com/work-with-us/">Travelopia</a></strong>.</p>
11+
</td>
12+
<td align="center" width="30%">
13+
<img src="https://www.travelopia.com/wp-content/themes/travelopia/assets/svg/logo-travelopia-circle.svg" width="50" />
14+
</td>
15+
</tr>
16+
</table>
17+
18+
## Installation
19+
Install the library via Composer:
20+
21+
```
22+
$ composer require --dev travelopia/wordpress-coding-standards
23+
```
24+
25+
That's it!
26+
27+
## Usage
28+
Lint your PHP files with the following command:
29+
30+
```
31+
$ ./vendor/bin/phpcs .
32+
```
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/**
3+
* Sniff: WPQueryParamsSniff.
4+
*
5+
* @package travelopia-coding-standards
6+
*/
7+
8+
namespace Travelopia\Sniffs\Classes;
9+
10+
use PHP_CodeSniffer\Sniffs\Sniff;
11+
use PHP_CodeSniffer\Files\File;
12+
13+
/**
14+
* Sniffs related to WP_Query params.
15+
*/
16+
class WPQueryParamsSniff implements Sniff {
17+
18+
/**
19+
* Register the sniff.
20+
*
21+
* @return mixed[]
22+
*/
23+
public function register(): array {
24+
return [ T_CONSTANT_ENCAPSED_STRING ];
25+
}
26+
27+
/**
28+
* Process the sniff.
29+
*
30+
* @param File $phpcsFile The file being processed.
31+
* @param int $stackPtr Stack pointer.
32+
*
33+
* @return void
34+
*/
35+
public function process( File $phpcsFile, $stackPtr ): void {
36+
// Get tokens.
37+
$tokens = $phpcsFile->getTokens();
38+
39+
if ( 'post__not_in' === trim( $tokens[ $stackPtr ]['content'], '\'' ) ) {
40+
$phpcsFile->addWarning( 'Using `post__not_in` should be done with caution.', $stackPtr, 'post__not_in' );
41+
}
42+
}
43+
44+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<?php
2+
/**
3+
* Sniff: WPQuerySniff.
4+
*
5+
* @package travelopia-coding-standards
6+
*/
7+
8+
namespace Travelopia\Sniffs\Classes;
9+
10+
use PHP_CodeSniffer\Sniffs\Sniff;
11+
use PHP_CodeSniffer\Files\File;
12+
13+
/**
14+
* Sniffs related to WP_Query.
15+
*/
16+
class WPQuerySniff implements Sniff {
17+
18+
/**
19+
* Register the sniff.
20+
*
21+
* @return mixed[]
22+
*/
23+
public function register(): array {
24+
return [ T_NEW ];
25+
}
26+
27+
/**
28+
* Process the sniff.
29+
*
30+
* @param File $phpcsFile The file being processed.
31+
* @param int $stackPtr Stack pointer.
32+
*
33+
* @return void
34+
*/
35+
public function process( File $phpcsFile, $stackPtr ): void {
36+
// Get tokens.
37+
$tokens = $phpcsFile->getTokens();
38+
39+
// Get the next string.
40+
$next_string = $phpcsFile->findNext( [ T_STRING ], $stackPtr );
41+
42+
// Check if WP_Query is the string after `new`.
43+
if ( false === $next_string || 'WP_Query' !== $tokens[ $next_string ]['content'] ) {
44+
return;
45+
}
46+
47+
// Get open parenthesis.
48+
$open_parenthesis = $phpcsFile->findNext( [ T_OPEN_PARENTHESIS ], $stackPtr );
49+
if ( false === $open_parenthesis ) {
50+
return;
51+
}
52+
53+
// Get close parenthesis.
54+
$close_parenthesis = $phpcsFile->findNext( [ T_CLOSE_PARENTHESIS ], $open_parenthesis );
55+
if ( false === $close_parenthesis ) {
56+
return;
57+
}
58+
59+
// Keep track of args.
60+
$required_args = [
61+
"'post_type'" => [
62+
'exists' => false,
63+
'error' => "Missing 'post_type' argument.",
64+
'error_code' => 'MissingPostType',
65+
],
66+
"'no_found_rows'" => [
67+
'exists' => false,
68+
'error' => "Missing 'no_found_rows' argument.",
69+
'error_code' => 'MissingNoFoundRows',
70+
],
71+
"'update_post_meta_cache'" => [
72+
'exists' => false,
73+
'error' => "Missing 'update_post_meta_cache' argument.",
74+
'error_code' => 'MissingPostMetaCache',
75+
],
76+
"'update_post_term_cache'" => [
77+
'exists' => false,
78+
'error' => "Missing 'update_post_term_cache' argument.",
79+
'error_code' => 'MissingPostTermCache',
80+
],
81+
"'fields'" => [
82+
'exists' => false,
83+
'error' => "Missing 'fields' argument.",
84+
'error_code' => 'MissingFields',
85+
],
86+
"'posts_per_page'" => [
87+
'exists' => false,
88+
'error' => "Missing 'posts_per_page' argument.",
89+
'error_code' => 'MissingPostsPerPage',
90+
],
91+
"'ignore_sticky_posts'" => [
92+
'exists' => false,
93+
'error' => "Missing 'ignore_sticky_posts' argument.",
94+
'error_code' => 'MissingIgnoreStickyPosts',
95+
],
96+
];
97+
98+
// Tax query stuff.
99+
$tax_query = 0;
100+
$taxonomies = 0;
101+
$include_children = 0;
102+
103+
// Traverse all tokens before close parenthesis.
104+
for ( $i = $open_parenthesis; $i <= $close_parenthesis; $i ++ ) {
105+
if ( 'T_VARIABLE' === $tokens[ $i ]['type'] ) {
106+
// Bail if a variable is found within parenthesis.
107+
return;
108+
}
109+
110+
if ( 'T_CONSTANT_ENCAPSED_STRING' !== $tokens[ $i ]['type'] ) {
111+
continue;
112+
}
113+
114+
if ( array_key_exists( $tokens[ $i ]['content'], $required_args ) ) {
115+
$required_args[ $tokens[ $i ]['content'] ]['exists'] = true;
116+
}
117+
118+
if ( "'tax_query'" === $tokens[ $i ]['content'] ) {
119+
$tax_query ++;
120+
} elseif ( "'taxonomy'" === $tokens[ $i ]['content'] ) {
121+
$taxonomies ++;
122+
} elseif ( "'include_children'" === $tokens[ $i ]['content'] ) {
123+
$include_children ++;
124+
}
125+
}
126+
127+
// Add warnings for missing args.
128+
foreach ( $required_args as $required_arg ) {
129+
if ( false === $required_arg['exists'] ) {
130+
$phpcsFile->addWarningOnLine(
131+
$required_arg['error'],
132+
$tokens[ $stackPtr ]['line'],
133+
$required_arg['error_code']
134+
);
135+
}
136+
}
137+
138+
// Tax query warnings.
139+
if ( 1 === $tax_query && $taxonomies !== $include_children ) {
140+
$phpcsFile->addWarningOnLine(
141+
"'include_children' is required for each taxonomy query.",
142+
$tokens[ $stackPtr ]['line'],
143+
'MissingIncludeChildren'
144+
);
145+
}
146+
}
147+
148+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
/**
3+
* Sniff: AcfFieldGroupSniff.
4+
*
5+
* @package travelopia-coding-standards
6+
*/
7+
8+
namespace Travelopia\Sniffs\Functions;
9+
10+
use PHP_CodeSniffer\Sniffs\Sniff;
11+
use PHP_CodeSniffer\Files\File;
12+
13+
/**
14+
* Sniffs to check for ACF Field Groups.
15+
*/
16+
class AcfFieldGroupSniff implements Sniff {
17+
18+
/**
19+
* Register the sniff.
20+
*
21+
* @return mixed[]
22+
*/
23+
public function register(): array {
24+
return [ T_STRING ];
25+
}
26+
27+
/**
28+
* Process the sniff.
29+
*
30+
* @param File $phpcsFile The file being processed.
31+
* @param int $stackPtr Stack pointer.
32+
*
33+
* @return void
34+
*/
35+
public function process( File $phpcsFile, $stackPtr ): void {
36+
// Get tokens.
37+
$tokens = $phpcsFile->getTokens();
38+
39+
// Check for ACF group function.
40+
if ( 'acf_add_local_field_group' !== $tokens[ $stackPtr ]['content'] ) {
41+
return;
42+
}
43+
44+
// Get open parenthesis.
45+
$open_parenthesis = $phpcsFile->findNext( [ T_OPEN_PARENTHESIS ], $stackPtr );
46+
if ( false === $open_parenthesis ) {
47+
return;
48+
}
49+
50+
// Get close parenthesis.
51+
$close_parenthesis = $phpcsFile->findNext( [ T_CLOSE_PARENTHESIS ], $open_parenthesis );
52+
if ( false === $close_parenthesis ) {
53+
return;
54+
}
55+
56+
// Prepare tokens.
57+
$style_token = [];
58+
$seamless_token = [];
59+
60+
// Traverse all tokens before close parenthesis.
61+
for ( $i = $open_parenthesis; $i <= $close_parenthesis; $i ++ ) {
62+
// Look for encapsed strings.
63+
if ( T_CONSTANT_ENCAPSED_STRING !== $tokens[ $i ]['code'] ) {
64+
continue;
65+
}
66+
67+
// Look for seamless style.
68+
if ( "'seamless'" === $tokens[ $i ]['content'] ) {
69+
if ( ! empty( $style_token ) && $style_token['line'] === $tokens[ $i ]['line'] ) {
70+
$seamless_token = $tokens[ $i ];
71+
break;
72+
}
73+
} elseif ( "'style'" === $tokens[ $i ]['content'] ) {
74+
$style_token = $tokens[ $i ];
75+
}
76+
}
77+
78+
// Show an error if no seamless style found.
79+
if ( empty( $seamless_token ) ) {
80+
$phpcsFile->addWarningOnLine(
81+
'ACF field groups must have "seamless" style.',
82+
$tokens[ $stackPtr ]['line'],
83+
'MissingSeamless'
84+
);
85+
}
86+
}
87+
88+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
/**
3+
* Sniff: CommentOnFirstLineOfFunctionsSniff.
4+
*
5+
* @package travelopia-coding-standards
6+
*/
7+
8+
namespace Travelopia\Sniffs\Functions;
9+
10+
use PHP_CodeSniffer\Sniffs\Sniff;
11+
use PHP_CodeSniffer\Files\File;
12+
13+
/**
14+
* Sniff to check if the first line of a function contains a comment.
15+
*/
16+
class CommentOnFirstLineOfFunctionsSniff implements Sniff {
17+
18+
/**
19+
* Register the sniff.
20+
*
21+
* @return mixed[]
22+
*/
23+
public function register(): array {
24+
return [ T_FUNCTION ];
25+
}
26+
27+
/**
28+
* Process the sniff.
29+
*
30+
* @param File $phpcsFile The file being processed.
31+
* @param int $stackPtr Stack pointer.
32+
*
33+
* @return void
34+
*/
35+
public function process( File $phpcsFile, $stackPtr ): void {
36+
// Get tokens.
37+
$tokens = $phpcsFile->getTokens();
38+
39+
// Ignore abstract functions.
40+
$abstract_token = $phpcsFile->findPrevious( [ T_ABSTRACT ], $stackPtr );
41+
if ( is_int( $abstract_token ) && $tokens[ $abstract_token ]['line'] === $tokens[ $stackPtr ]['line'] ) {
42+
return;
43+
}
44+
45+
// Get next comment.
46+
$next_comment = $phpcsFile->findNext( [ T_COMMENT, T_DOC_COMMENT_OPEN_TAG ], $stackPtr );
47+
if ( ! is_int( $next_comment ) || $tokens[ $next_comment ]['line'] !== $tokens[ $stackPtr ]['line'] + 1 ) {
48+
$phpcsFile->addWarningOnLine(
49+
'The first line of a function must contain a comment.',
50+
$tokens[ $stackPtr ]['line'] + 1,
51+
'Missing'
52+
);
53+
}
54+
}
55+
56+
}

0 commit comments

Comments
 (0)