Theme Check - Version 20200612.1

Version Description

Download this release

Release Info

Developer Otto42
Plugin Icon 128x128 Theme Check
Version 20200612.1
Comparing to
See all releases

Code changes from version 20190801.1 to 20200612.1

assets/style.css CHANGED
@@ -1,77 +1,83 @@
1
- .tc-box {
2
- padding:20px 0;
3
- border-top:1px solid #dfdfdf;
4
- }
5
- .tc-warning, .tc-required, .tc-fail {
6
- color:red;
7
- }
8
- .tc-recommended, .tc-pass {
9
- color: green;
10
- }
11
- .tc-info {
12
- color: blue;
13
- }
14
- .tc-grep span {
15
- background: yellow;
16
- }
17
- pre {
18
- white-space: pre-wrap;
19
- }
20
- .tc-success {
21
- margin:0 20px 20px 20px;
22
- background:#e6ffe2;
23
- border:1px solid #d1eecc;
24
- }
25
- form {
26
- margin:20px auto;
27
- }
28
- .theme-check {
29
- margin:20px auto;
30
- border:1px solid #dfdfdf;
31
- -moz-border-radius:5px;
32
- -khtml-border-radius:5px;
33
- -webkit-border-radius:5px;
34
- border-radius:5px;
35
- }
36
- .theme-check h2 {
37
- margin:0 0 20px 0;
38
- padding:0 20px;
39
- background:#dfdfdf url("gray-grad.png") repeat-x left top;
40
- font-size:20px;
41
- border-bottom:1px solid #ccc;
42
- }
43
- .theme-check p {
44
- padding:5px 20px;
45
- }
46
- .theme-check form {
47
- margin-left:20px;
48
- }
49
- .theme-check ul {
50
- margin-left:20px;
51
- }
52
- .theme-check h3 {
53
- margin:0 0 10px 20px;
54
- padding:0;
55
- }
56
- .theme-check ul {
57
- margin-bottom:10px;
58
- }
59
- .theme-info {
60
- padding:10px;
61
- border:1px solid #dfdfdf;
62
- margin:10px 20px 0 20px;
63
- }
64
- .theme-info p {
65
- padding:0;
66
- margin-bottom:10px;
67
- }
68
- .theme-info label {
69
- float:left;
70
- width:100px;
71
- font-weight:bold;
72
- display:block;
73
- }
74
- .theme-info span.info {
75
- margin-left:100px;
76
- display:block;
77
- }
 
 
 
 
 
 
1
+ .tc-box {
2
+ padding:20px 0;
3
+ border-top:1px solid #dfdfdf;
4
+ }
5
+ .tc-required, .tc-fail {
6
+ color:red;
7
+ }
8
+ .tc-warning {
9
+ color: orange;
10
+ }
11
+ .tc-recommended, .tc-pass {
12
+ color: green;
13
+ }
14
+ .tc-info {
15
+ color: blue;
16
+ }
17
+ .tc-grep span {
18
+ background: yellow;
19
+ }
20
+ pre {
21
+ white-space: pre-wrap;
22
+ }
23
+ .tc-success {
24
+ margin:0 20px 20px 20px;
25
+ background:#e6ffe2;
26
+ border:1px solid #d1eecc;
27
+ }
28
+ form {
29
+ margin: 1.5em auto;
30
+ }
31
+ .theme-check {
32
+ margin: 1em auto;
33
+ border:1px solid #dfdfdf;
34
+ -moz-border-radius:5px;
35
+ -khtml-border-radius:5px;
36
+ -webkit-border-radius:5px;
37
+ border-radius:5px;
38
+ }
39
+ .theme-check h2 {
40
+ margin: 0 0 1em 0;
41
+ padding: 1em;
42
+ background:#dfdfdf url("gray-grad.png") repeat-x left top;
43
+ font-size:20px;
44
+ border-bottom:1px solid #ccc;
45
+ }
46
+ .theme-check p {
47
+ padding:5px 20px;
48
+ }
49
+ .theme-check form {
50
+ margin-left: 1.5em;
51
+ }
52
+ .theme-check ul {
53
+ margin-left:20px;
54
+ }
55
+ .theme-check h3 {
56
+ margin:0 0 10px 20px;
57
+ padding:0;
58
+ }
59
+ .theme-check ul {
60
+ margin-bottom:10px;
61
+ }
62
+ .theme-info {
63
+ padding: 1em;
64
+ border:1px solid #dfdfdf;
65
+ margin: 1em 1em 0 1em;
66
+ }
67
+ .theme-info p {
68
+ padding:0;
69
+ margin-bottom:10px;
70
+ }
71
+ .theme-info label {
72
+ float:left;
73
+ width:100px;
74
+ font-weight:bold;
75
+ display:block;
76
+ }
77
+ .theme-info span.info {
78
+ margin-left:100px;
79
+ display:block;
80
+ }
81
+ .theme-check input[name="s_info"] {
82
+ margin-left: 0.5em;
83
+ }
changelog.txt CHANGED
@@ -1,3 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 20140929.1 =
2
  * Added new checks and updates from Frank Klein at Automattic. Thanks Frank!
3
  * Updated deprecated function listings
@@ -48,11 +90,11 @@
48
  * Add check for wp_link_pages() + fix eval() check
49
 
50
  = 20110219.2 =
51
- * Merged new UI props Gua Bob [1](http://guabob.com/)
52
  * Last tested theme is always pre-selected in the themes list.
53
  * Fixed php error in admin_menu.php
54
 
55
- = 20110219.1 =
56
  * See [commit log](https://github.com/Pross/theme-check/commits/) for changes.
57
 
58
  = 20110201.2 =
1
+ = 20200612.1 =
2
+ * Release to WordPress.org plugins directory
3
+
4
+ = 20200611.1 =
5
+ * Added escaping checks
6
+ * Added tested up to and Requires PHP checks for the style.css
7
+ * Added register_block_type to plugin territory check
8
+ * Check for remove_action wp_head
9
+ * Changed some checks from errors to warnings
10
+ * Updated error messages
11
+ * Updated regex for non printable characters
12
+ * Fixed parse errors
13
+ * Removed unused functions
14
+
15
+ = 20200504.1 =
16
+ * Contributor and URI adjustments
17
+ * site_url checks
18
+ * smarter nav menu and favicon checks
19
+ * additional filename blacklist checks
20
+ * developer files added to github (phpcs, composer, attributes, gitignore, etc)
21
+ * improvements to existing checks, move some warnings to required to reflect updated guidelines
22
+ * check for themes being copies of underscores
23
+ * check for non-gpl-compatible sites used for images
24
+ * Add warnings for demo content
25
+ * Update links in messages to point to new development and documentation locations
26
+ * disallow dashboard widgets in themes
27
+
28
+ = 20190801.1 =
29
+ * Fix missing nonce and nonce check on admin page. props Steven Stern for reporting the issue to the plugins team. Though this is technically a CSRF, there is no vulnerability arising from it, as the only thing that could be done with the form is to scan a theme.
30
+
31
+ = 20190208.1 =
32
+ * Add new styles for the block editor. See https://meta.trac.wordpress.org/ticket/3921
33
+
34
+ = 20160523.1 =
35
+ * Fix for theme-names with dashes in them
36
+ * Comments stripping changes
37
+ * Many changes by the theme review team and others. See Github for full change list.
38
+
39
+ = 20151211.1 =
40
+ * Full sync with Github and all the changes that have happened there.
41
+ * Release for 4.4 deprecated functions.
42
+
43
  = 20140929.1 =
44
  * Added new checks and updates from Frank Klein at Automattic. Thanks Frank!
45
  * Updated deprecated function listings
90
  * Add check for wp_link_pages() + fix eval() check
91
 
92
  = 20110219.2 =
93
+ * Merged new UI props Gua Bob [1](http://guabob.com/)
94
  * Last tested theme is always pre-selected in the themes list.
95
  * Fixed php error in admin_menu.php
96
 
97
+ = 20110219.1 =
98
  * See [commit log](https://github.com/Pross/theme-check/commits/) for changes.
99
 
100
  = 20110201.2 =
checkbase.php CHANGED
@@ -124,22 +124,6 @@ function tc_preg( $preg, $file ) {
124
  return str_replace( $error, '<span class="tc-grep">' . $error . '</span>', $bad_lines );
125
  }
126
 
127
- function tc_strxchr($haystack, $needle, $l_inclusive = 0, $r_inclusive = 0){
128
- if(strrpos($haystack, $needle)){
129
- //Everything before last $needle in $haystack.
130
- $left = substr($haystack, 0, strrpos($haystack, $needle) + $l_inclusive);
131
- //Switch value of $r_inclusive from 0 to 1 and viceversa.
132
- $r_inclusive = ($r_inclusive == 0) ? 1 : 0;
133
- //Everything after last $needle in $haystack.
134
- $right = substr(strrchr($haystack, $needle), $r_inclusive);
135
- //Return $left and $right into an array.
136
- return array($left, $right);
137
- } else {
138
- if(strrchr($haystack, $needle)) return array('', substr(strrchr($haystack, $needle), $r_inclusive));
139
- else return false;
140
- }
141
- }
142
-
143
  function tc_filename( $file ) {
144
  $filename = ( preg_match( '/themes\/[a-z0-9-]*\/(.*)/', $file, $out ) ) ? $out[1] : basename( $file );
145
  return $filename;
@@ -170,37 +154,6 @@ function listdir( $dir ) {
170
  return $files;
171
  }
172
 
173
- function old_listdir( $start_dir='.' ) {
174
- $files = array();
175
- if ( is_dir( $start_dir ) ) {
176
- $fh = opendir( $start_dir );
177
- while ( ( $file = readdir( $fh ) ) !== false ) {
178
- # loop through the files, skipping . and .., and recursing if necessary
179
- if ( strcmp( $file, '.' )==0 || strcmp( $file, '..' )==0 ) continue;
180
- $filepath = $start_dir . '/' . $file;
181
- if ( is_dir( $filepath ) )
182
- $files = array_merge( $files, listdir( $filepath ) );
183
- else
184
- array_push( $files, $filepath );
185
- }
186
- closedir( $fh );
187
-
188
- } else {
189
-
190
- # false if the function was called with an invalid non-directory argument
191
- $files = false;
192
- }
193
- return $files;
194
- }
195
-
196
- function tc_print_r( $data ) {
197
- $out = "\n<pre class='html-print-r'";
198
- $out .= " style='border: 1px solid #ccc; padding: 7px;'>\n";
199
- $out .= esc_html( print_r( $data, TRUE ) );
200
- $out .= "\n</pre>\n";
201
- echo $out;
202
- }
203
-
204
  function get_theme_data_from_contents( $theme_data ) {
205
  $themes_allowed_tags = array(
206
  'a' => array(
124
  return str_replace( $error, '<span class="tc-grep">' . $error . '</span>', $bad_lines );
125
  }
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  function tc_filename( $file ) {
128
  $filename = ( preg_match( '/themes\/[a-z0-9-]*\/(.*)/', $file, $out ) ) ? $out[1] : basename( $file );
129
  return $filename;
154
  return $files;
155
  }
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  function get_theme_data_from_contents( $theme_data ) {
158
  $themes_allowed_tags = array(
159
  'a' => array(
checks/admin_menu.php CHANGED
@@ -10,8 +10,8 @@ class AdminMenu implements themecheck {
10
  //check for levels deprecated in 2.0 in creating menus.
11
 
12
  $checks = array(
13
- '/([^_](add_(admin|submenu|menu|dashboard|posts|media|links|pages|comments|theme|plugins|users|management|options)_page)\s?\([^,]*,[^,]*,\s[\'|"]?(level_[0-9]|[0-9])[^;|\r|\r\n]*)/' => __( 'User levels were deprecated in <strong>2.0</strong>. Please see <a href="https://codex.wordpress.org/Roles_and_Capabilities">Roles_and_Capabilities</a>', 'theme-check' ),
14
- '/[^a-z0-9](current_user_can\s?\(\s?[\'\"]level_[0-9][\'\"]\s?\))[^\r|\r\n]*/' => __( 'User levels were deprecated in <strong>2.0</strong>. Please see <a href="https://codex.wordpress.org/Roles_and_Capabilities">Roles_and_Capabilities</a>', 'theme-check' )
15
  );
16
 
17
  foreach ( $php_files as $php_key => $phpfile ) {
10
  //check for levels deprecated in 2.0 in creating menus.
11
 
12
  $checks = array(
13
+ '/([^_](add_(admin|submenu|menu|dashboard|posts|media|links|pages|comments|theme|plugins|users|management|options)_page)\s?\([^,]*,[^,]*,\s[\'|"]?(level_[0-9]|[0-9])[^;|\r|\r\n]*)/' => __( 'User levels were deprecated in <strong>2.0</strong>. Please see <a href="https://wordpress.org/support/article/roles-and-capabilities/">Roles_and_Capabilities</a>', 'theme-check' ),
14
+ '/[^a-z0-9](current_user_can\s?\(\s?[\'\"]level_[0-9][\'\"]\s?\))[^\r|\r\n]*/' => __( 'User levels were deprecated in <strong>2.0</strong>. Please see <a href="https://wordpress.org/support/article/roles-and-capabilities/">Roles_and_Capabilities</a>', 'theme-check' )
15
  );
16
 
17
  foreach ( $php_files as $php_key => $phpfile ) {
checks/adminbar.php CHANGED
@@ -1,41 +1,55 @@
1
  <?php
2
  /**
3
- * This checks, if the admin bar gets hidden by the theme
4
  **/
5
  class NoHiddenAdminBar implements themecheck {
6
  protected $error = array();
7
 
8
- function check( $php_files, $css_files, $other_files ) {
9
- $ret = true;
10
- checkcount();
11
- $php_regex = "/(add_filter(\s*)\((\s*)(\"|')show_admin_bar(\"|')(\s*)(.*))|(([^\S])show_admin_bar(\s*)\((.*))/";
12
- $css_regex = "/(#wpadminbar)/";
13
 
14
- //Check php files for filter show_admin_bar and show_admin_bar()
15
- foreach ( $php_files as $file_path => $file_content ) {
16
 
17
- $filename = tc_filename( $file_path );
 
 
18
 
19
- if ( preg_match( $php_regex, $file_content, $matches ) ) {
20
- $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check').'</span>: ' . __( 'You are not allowed to hide the admin bar.', 'theme-check' ),
21
- '<strong>' . $filename . '</strong>');
22
- $ret = false;
23
- }
24
- }
25
 
26
- //Check CSS Files for #wpadminbar
27
- foreach ( $css_files as $file_path => $file_content ) {
28
 
29
- $filename = tc_filename( $file_path );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- if ( preg_match( $css_regex, $file_content, $matches ) ) {
32
- $this->error[] = sprintf( '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check').'</span>: ' . __( 'The theme is using `#wpadminbar`. Hiding the admin bar is not allowed.', 'theme-check' ),
33
- '<strong>' . $filename . '</strong>');
34
- }
35
  }
 
 
36
  return $ret;
37
  }
38
 
39
  function getError() { return $this->error; }
40
  }
41
- $themechecks[] = new NoHiddenAdminBar;
 
1
  <?php
2
  /**
3
+ * This checks if the admin bar gets hidden by the theme.
4
  **/
5
  class NoHiddenAdminBar implements themecheck {
6
  protected $error = array();
7
 
8
+ function check( $php_files, $css_files, $other_files ) {
9
+ $ret = true;
 
 
 
10
 
11
+ $php_regex = "/(add_filter(\s*)\((\s*)(\"|')show_admin_bar(\"|')(\s*)(.*))|(([^\S])show_admin_bar(\s*)\((.*))/";
12
+ $css_regex = "/(#wpadminbar)/";
13
 
14
+ checkcount();
15
+ // Check php files for filter show_admin_bar, show_admin_bar_front, and show_admin_bar().
16
+ foreach ( $php_files as $file_path => $file_content ) {
17
 
18
+ $filename = tc_filename( $file_path );
19
+
20
+ if ( preg_match( $php_regex, $file_content, $matches ) ) {
 
 
 
21
 
22
+ $error = '/show_admin_bar/';
23
+ $grep = tc_preg( $error, $file_path );
24
 
25
+ $this->error[] = sprintf( '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check' ) . '</span>: ' . __( '%1$s Themes are not allowed to hide the admin bar. This warning must be manually checked.', 'theme-check' ),
26
+ '<strong>' . $filename . '</strong>' ) . $grep;
27
+ }
28
+ }
29
+
30
+ checkcount();
31
+ // Check CSS Files for #wpadminbar.
32
+ foreach ( $css_files as $file_path => $file_content ) {
33
+
34
+ $filename = tc_filename( $file_path );
35
+ $error = '/#wpadminbar/';
36
+ // Don't print minified files.
37
+ if ( strpos( $filename, '.min.' ) === false ) {
38
+ $grep = tc_preg( $error, $file_path );
39
+ } else {
40
+ $grep = '';
41
+ }
42
 
43
+ if ( preg_match( $css_regex, $file_content, $matches ) ) {
44
+ $this->error[] = sprintf( '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check' ) . '</span>: ' . __( 'The theme is using `#wpadminbar` in %1$s. Hiding the admin bar is not allowed. This warning must be manually checked.', 'theme-check' ),
45
+ '<strong>' . $filename . '</strong>' ) . $grep;
 
46
  }
47
+ }
48
+
49
  return $ret;
50
  }
51
 
52
  function getError() { return $this->error; }
53
  }
54
+
55
+ $themechecks[] = new NoHiddenAdminBar();
checks/badthings.php CHANGED
@@ -26,7 +26,7 @@ class Bad_Checks implements themecheck {
26
  $filename = tc_filename( $php_key );
27
  $error = ltrim( trim( $matches[0], '(' ) );
28
  $grep = tc_grep( $error, $php_key );
29
- $this->error[] = sprintf('<span class="tc-lead tc-warning">'. __( 'WARNING', 'theme-check' ) . '</span>: ' . __( 'Found %1$s in the file %2$s. %3$s. %4$s', 'theme-check' ), '<strong>' . $error . '</strong>', '<strong>' . $filename . '</strong>', $check, $grep );
30
  $ret = false;
31
  }
32
  }
@@ -45,7 +45,7 @@ class Bad_Checks implements themecheck {
45
  $filename = tc_filename( $php_key );
46
  $error = ltrim( rtrim( $matches[0],'(' ) );
47
  $grep = tc_grep( $error, $php_key );
48
- $this->error[] = sprintf(__('<span class="tc-lead tc-warning">WARNING</span>: Found <strong>%1$s</strong> in the file <strong>%2$s</strong>. %3$s.%4$s', 'theme-check'), $error, $filename, $check, $grep);
49
  $ret = false;
50
  }
51
  }
26
  $filename = tc_filename( $php_key );
27
  $error = ltrim( trim( $matches[0], '(' ) );
28
  $grep = tc_grep( $error, $php_key );
29
+ $this->error[] = sprintf('<span class="tc-lead tc-required">'. __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( 'Found %1$s in the file %2$s. %3$s. %4$s', 'theme-check' ), '<strong>' . $error . '</strong>', '<strong>' . $filename . '</strong>', $check, $grep );
30
  $ret = false;
31
  }
32
  }
45
  $filename = tc_filename( $php_key );
46
  $error = ltrim( rtrim( $matches[0],'(' ) );
47
  $grep = tc_grep( $error, $php_key );
48
+ $this->error[] = sprintf(__('<span class="tc-lead tc-required">REQUIRED</span>: Found <strong>%1$s</strong> in the file <strong>%2$s</strong>. %3$s.%4$s', 'theme-check'), $error, $filename, $check, $grep);
49
  $ret = false;
50
  }
51
  }
checks/basic.php CHANGED
@@ -12,17 +12,18 @@ class Basic_Checks implements themecheck {
12
 
13
  $checks = array(
14
  'DOCTYPE' => __( 'See: <a href="https://codex.wordpress.org/HTML_to_XHTML">https://codex.wordpress.org/HTML_to_XHTML</a><pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"<br />"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"?&gt;</pre>', 'theme-check' ),
15
- 'wp_footer\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Function_Reference/wp_footer">wp_footer</a><pre> &lt;?php wp_footer(); ?&gt;</pre>', 'theme-check' ),
16
- 'wp_head\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Function_Reference/wp_head">wp_head</a><pre> &lt;?php wp_head(); ?&gt;</pre>', 'theme-check' ),
17
- 'language_attributes' => __( 'See: <a href="https://codex.wordpress.org/Function_Reference/language_attributes">language_attributes</a><pre>&lt;html &lt;?php language_attributes(); ?&gt;</pre>', 'theme-check' ),
 
18
  'charset' => __( 'There must be a charset defined in the Content-Type or the meta charset tag in the head.', 'theme-check' ),
19
- 'add_theme_support\s*\(\s?("|\')automatic-feed-links("|\')\s?\)' => __( 'See: <a href="https://codex.wordpress.org/Function_Reference/add_theme_support">add_theme_support</a><pre> &lt;?php add_theme_support( $feature ); ?&gt;</pre>', 'theme-check' ),
20
- 'comments_template\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Template_Tags/comments_template">comments_template</a><pre> &lt;?php comments_template( $file, $separate_comments ); ?&gt;</pre>', 'theme-check' ),
21
- 'wp_list_comments\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Template_Tags/wp_list_comments">wp_list_comments</a><pre> &lt;?php wp_list_comments( $args ); ?&gt;</pre>', 'theme-check' ),
22
- 'comment_form\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Template_Tags/comment_form">comment_form</a><pre> &lt;?php comment_form(); ?&gt;</pre>', 'theme-check' ),
23
- 'body_class\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Template_Tags/body_class">body_class</a><pre> &lt;?php body_class( $class ); ?&gt;</pre>', 'theme-check' ),
24
- 'wp_link_pages\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Function_Reference/wp_link_pages">wp_link_pages</a><pre> &lt;?php wp_link_pages( $args ); ?&gt;</pre>', 'theme-check' ),
25
- 'post_class\s*\(' => __( 'See: <a href="https://codex.wordpress.org/Template_Tags/post_class">post_class</a><pre> &lt;div id="post-&lt;?php the_ID(); ?&gt;" &lt;?php post_class(); ?&gt;&gt;</pre>', 'theme-check' )
26
  );
27
 
28
  foreach ($checks as $key => $check) {
@@ -30,6 +31,7 @@ class Basic_Checks implements themecheck {
30
  if ( !preg_match( '/' . $key . '/i', $php ) ) {
31
  if ( $key === 'add_theme_support\s*\(\s?("|\')automatic-feed-links("|\')\s?\)' ) $key = __( 'add_theme_support( \'automatic-feed-links\' )', 'theme-check');
32
  if ( $key === 'body_class\s*\(' ) $key = __( 'body_class call in body tag', 'theme-check');
 
33
  $key = str_replace( '\s*\(', '', $key );
34
  $this->error[] = sprintf( '<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Could not find %1$s. %2$s', 'theme-check' ), '<strong>' . $key . '</strong>', $check );
35
  $ret = false;
12
 
13
  $checks = array(
14
  'DOCTYPE' => __( 'See: <a href="https://codex.wordpress.org/HTML_to_XHTML">https://codex.wordpress.org/HTML_to_XHTML</a><pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"<br />"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"?&gt;</pre>', 'theme-check' ),
15
+ '(wp_body_open\s*\()|(do_action\s*\(\s*["\']wp_body_open)' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/wp_body_open/">wp_body_open</a><pre> &lt;?php wp_body_open(); ?&gt;</pre>', 'theme-check' ),
16
+ 'wp_footer\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/wp_footer/">wp_footer</a><pre> &lt;?php wp_footer(); ?&gt;</pre>', 'theme-check' ),
17
+ 'wp_head\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/wp_head/">wp_head</a><pre> &lt;?php wp_head(); ?&gt;</pre>', 'theme-check' ),
18
+ 'language_attributes' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/language_attributes/">language_attributes</a><pre>&lt;html &lt;?php language_attributes(); ?&gt;</pre>', 'theme-check' ),
19
  'charset' => __( 'There must be a charset defined in the Content-Type or the meta charset tag in the head.', 'theme-check' ),
20
+ 'add_theme_support\s*\(\s?("|\')automatic-feed-links("|\')\s?\)' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/add_theme_support/">add_theme_support</a><pre> &lt;?php add_theme_support( $feature ); ?&gt;</pre>', 'theme-check' ),
21
+ 'comments_template\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/comments_template/">comments_template</a><pre> &lt;?php comments_template( $file, $separate_comments ); ?&gt;</pre>', 'theme-check' ),
22
+ 'wp_list_comments\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/wp_list_comments/">wp_list_comments</a><pre> &lt;?php wp_list_comments( $args ); ?&gt;</pre>', 'theme-check' ),
23
+ 'comment_form\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/comment_form/">comment_form</a><pre> &lt;?php comment_form(); ?&gt;</pre>', 'theme-check' ),
24
+ 'body_class\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/body_class/">body_class</a><pre> &lt;?php body_class( $class ); ?&gt;</pre>', 'theme-check' ),
25
+ 'wp_link_pages\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/wp_link_pages/">wp_link_pages</a><pre> &lt;?php wp_link_pages( $args ); ?&gt;</pre>', 'theme-check' ),
26
+ 'post_class\s*\(' => __( 'See: <a href="https://developer.wordpress.org/reference/functions/post_class/">post_class</a><pre> &lt;div id="post-&lt;?php the_ID(); ?&gt;" &lt;?php post_class(); ?&gt;&gt;</pre>', 'theme-check' )
27
  );
28
 
29
  foreach ($checks as $key => $check) {
31
  if ( !preg_match( '/' . $key . '/i', $php ) ) {
32
  if ( $key === 'add_theme_support\s*\(\s?("|\')automatic-feed-links("|\')\s?\)' ) $key = __( 'add_theme_support( \'automatic-feed-links\' )', 'theme-check');
33
  if ( $key === 'body_class\s*\(' ) $key = __( 'body_class call in body tag', 'theme-check');
34
+ if ( $key === '(wp_body_open\s*\()|(do_action\s*\(\s*["\']wp_body_open)' ) $key = __( 'wp_body_open action or function call at the very top of the body just after the opening body tag', 'theme-check');
35
  $key = str_replace( '\s*\(', '', $key );
36
  $this->error[] = sprintf( '<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Could not find %1$s. %2$s', 'theme-check' ), '<strong>' . $key . '</strong>', $check );
37
  $ret = false;
checks/cdn.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * Checks for resources being loaded from CDNs.
5
  */
@@ -17,22 +16,24 @@ class CDNCheck implements themecheck {
17
  checkcount();
18
 
19
  $cdn_list = array(
20
- 'bootstrap-maxcdn' => 'maxcdn.bootstrapcdn.com/bootstrap',
21
- 'bootstrap-netdna' => 'netdna.bootstrapcdn.com/bootstrap',
22
- 'bootswatch-maxcdn' => 'maxcdn.bootstrapcdn.com/bootswatch',
23
- 'bootswatch-netdna' => 'netdna.bootstrapcdn.com/bootswatch',
24
- 'font-awesome-maxcdn' => 'maxcdn.bootstrapcdn.com/font-awesome',
25
- 'font-awesome-netdna' => 'netdna.bootstrapcdn.com/font-awesome',
26
- 'html5shiv-google' => 'html5shiv.googlecode.com/svn/trunk/html5.js',
27
- 'html5shiv-maxcdn' => 'oss.maxcdn.com/libs/html5shiv',
28
  'jquery' => 'code.jquery.com/jquery-',
29
- 'respond-js' => 'oss.maxcdn.com/libs/respond.js',
 
 
 
 
30
  );
31
 
32
  foreach( $cdn_list as $cdn_slug => $cdn_url ) {
33
  if ( false !== strpos( $all_code, $cdn_url ) ) {
34
- $this->error[] = '<span class="tc-lead tc-recommended">' . __('RECOMMENDED','theme-check') . '</span>: ' . sprintf( __( 'Found the URL of a CDN in the code: %s. You should not load CSS or Javascript resources from a CDN, please bundle them with the theme.', 'theme-check' ), '<code>' . esc_html( $cdn_url ) . '</code>' );
35
- //$ret = false;
36
  }
37
  }
38
 
1
  <?php
 
2
  /**
3
  * Checks for resources being loaded from CDNs.
4
  */
16
  checkcount();
17
 
18
  $cdn_list = array(
19
+ 'bootstrap-maxcdn' => 'maxcdn.bootstrapcdn.com',
20
+ 'bootstrap-netdna' => 'netdna.bootstrapcdn.com',
21
+ 'bootstrap-stackpath' => 'stackpath.bootstrapcdn.com',
22
+ 'fontawesome' => 'kit.fontawesome.com',
23
+ 'googlecode' => 'googlecode.com/svn/',
24
+ 'oss.maxcdn' => 'oss.maxcdn.com',
 
 
25
  'jquery' => 'code.jquery.com/jquery-',
26
+ 'aspnetcdn' => 'aspnetcdn.com',
27
+ 'cloudflare' => 'cloudflare.com',
28
+ 'keycdn' => 'keycdn.com',
29
+ 'pxgcdn' => 'pxgcdn.com',
30
+ 'vimeocdn' => 'vimeocdn.com', //usually in JS files
31
  );
32
 
33
  foreach( $cdn_list as $cdn_slug => $cdn_url ) {
34
  if ( false !== strpos( $all_code, $cdn_url ) ) {
35
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED','theme-check' ) . '</span>: ' . sprintf( __( 'Found the URL of a CDN in the code: %s. You should not load CSS or Javascript resources from a CDN, please bundle them with the theme.', 'theme-check' ), '<code>' . esc_html( $cdn_url ) . '</code>' );
36
+ $ret = false;
37
  }
38
  }
39
 
checks/comment_reply.php CHANGED
@@ -1,27 +1,27 @@
1
- <?php
2
- class Comment_Reply implements themecheck {
3
- protected $error = array();
4
-
5
- function check( $php_files, $css_files, $other_files) {
6
-
7
- $php = implode( ' ', $php_files );
8
- $ret = true;
9
-
10
- checkcount();
11
-
12
- if ( ! preg_match( '/wp_enqueue_script\(\s?("|\')comment-reply("|\')/i', $php ) ) {
13
- if ( ! preg_match( '/comment-reply/', $php ) ) {
14
- $check = __( 'See: <a href="https://codex.wordpress.org/Migrating_Plugins_and_Themes_to_2.7/Enhanced_Comment_Display">Migrating Plugins and Themes to 2.7/Enhanced Comment Display</a><pre> &lt;?php if ( is_singular() ) wp_enqueue_script( "comment-reply" ); ?&gt;</pre>', 'theme-check' );
15
- $this->error[] = sprintf('<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Could not find the <strong>comment-reply</strong> script enqueued. %1$s', 'theme-check'), $check);
16
- $ret = false;
17
- } else {
18
- $this->error[] = '<span class="tc-lead tc-info">'.__('INFO','theme-check').'</span>: '.__('Could not find the <strong>comment-reply</strong> script enqueued, however a reference to \'comment-reply\' was found. Make sure that the comment-reply script is being enqueued properly on singular pages.', 'theme-check');
19
- }
20
- }
21
- return $ret;
22
- }
23
-
24
- function getError() { return $this->error; }
25
- }
26
-
27
- $themechecks[] = new Comment_Reply;
1
+ <?php
2
+ class Comment_Reply implements themecheck {
3
+ protected $error = array();
4
+
5
+ function check( $php_files, $css_files, $other_files) {
6
+
7
+ $php = implode( ' ', $php_files );
8
+ $ret = true;
9
+
10
+ checkcount();
11
+
12
+ if ( ! preg_match( '/wp_enqueue_script\(\s?("|\')comment-reply("|\')/i', $php ) ) {
13
+ if ( ! preg_match( '/comment-reply/', $php ) ) {
14
+ $check = __( 'See: <a href="https://codex.wordpress.org/Migrating_Plugins_and_Themes_to_2.7/Enhanced_Comment_Display">Migrating Plugins and Themes to 2.7/Enhanced Comment Display</a><pre> &lt;?php if ( is_singular() ) wp_enqueue_script( "comment-reply" ); ?&gt;</pre>', 'theme-check' );
15
+ $this->error[] = sprintf('<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Could not find the <strong>comment-reply</strong> script enqueued. %1$s', 'theme-check'), $check);
16
+ $ret = false;
17
+ } else {
18
+ $this->error[] = '<span class="tc-lead tc-info">'.__('INFO','theme-check').'</span>: '.__('Could not find the <strong>comment-reply</strong> script enqueued, however a reference to \'comment-reply\' was found. Make sure that the comment-reply script is being enqueued properly on singular pages.', 'theme-check');
19
+ }
20
+ }
21
+ return $ret;
22
+ }
23
+
24
+ function getError() { return $this->error; }
25
+ }
26
+
27
+ $themechecks[] = new Comment_Reply;
checks/customizer.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * Checks for the Customizer.
5
  */
@@ -7,7 +6,7 @@
7
  class CustomizerCheck implements themecheck {
8
  protected $error = array();
9
 
10
- function check( $php_files, $css_files, $other_files) {
11
 
12
  $ret = true;
13
 
@@ -17,18 +16,33 @@ class CustomizerCheck implements themecheck {
17
  * Check whether every Customizer setting has a sanitization callback set.
18
  */
19
  foreach ( $php_files as $file_path => $file_content ) {
20
- // Get the arguments passed to the add_setting method
21
  if ( preg_match_all( '/\$wp_customize->add_setting\(([^;]+)/', $file_content, $matches ) ) {
22
- // The full match is in [0], the match group in [1]
23
  foreach ( $matches[1] as $match ) {
24
- // Check if we have sanitize_callback or sanitize_js_callback
25
  if ( false === strpos( $match, 'sanitize_callback' ) && false === strpos( $match, 'sanitize_js_callback' ) ) {
26
- $this->error[] = '<span class="tc-lead tc-required">' . __('REQUIRED','theme-check') . '</span>: ' . __( 'Found a Customizer setting that did not have a sanitization callback function. Every call to the <strong>add_setting()</strong> method needs to have a sanitization callback function passed.', 'theme-check' );
 
 
 
 
 
 
 
 
27
  $ret = false;
28
  } else {
29
  // There's a callback, check that no empty parameter is passed.
30
  if ( preg_match( '/[\'"](?:sanitize_callback|sanitize_js_callback)[\'"]\s*=>\s*[\'"]\s*[\'"]/', $match ) ) {
31
- $this->error[] = '<span class="tc-lead tc-required">' . __('REQUIRED','theme-check') . '</span>: ' . __( 'Found a Customizer setting that had an empty value passed as sanitization callback. You need to pass a function name as sanitization callback.', 'theme-check' );
 
 
 
 
 
 
 
32
  $ret = false;
33
  }
34
  }
@@ -41,4 +55,5 @@ class CustomizerCheck implements themecheck {
41
 
42
  function getError() { return $this->error; }
43
  }
44
- $themechecks[] = new CustomizerCheck;
 
1
  <?php
 
2
  /**
3
  * Checks for the Customizer.
4
  */
6
  class CustomizerCheck implements themecheck {
7
  protected $error = array();
8
 
9
+ function check( $php_files, $css_files, $other_files ) {
10
 
11
  $ret = true;
12
 
16
  * Check whether every Customizer setting has a sanitization callback set.
17
  */
18
  foreach ( $php_files as $file_path => $file_content ) {
19
+ // Get the arguments passed to the add_setting method.
20
  if ( preg_match_all( '/\$wp_customize->add_setting\(([^;]+)/', $file_content, $matches ) ) {
21
+ // The full match is in [0], the match group in [1].
22
  foreach ( $matches[1] as $match ) {
23
+ // Check if we have sanitize_callback or sanitize_js_callback.
24
  if ( false === strpos( $match, 'sanitize_callback' ) && false === strpos( $match, 'sanitize_js_callback' ) ) {
25
+ /* Clean up our match to be able to present the results better. */
26
+ $match = preg_split( '/,/', $match );
27
+ $filename = tc_filename( $file_path );
28
+ $grep = tc_preg( $match[0], $file_path );
29
+ $grep = preg_split( '/,/', $grep );
30
+ $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( 'Found a Customizer setting called %1$s in %2$s that did not have a sanitization callback function. ', 'theme-check' ) . __( 'Every call to the <strong>add_setting()</strong> method needs to have a sanitization callback function passed.', 'theme-check' ),
31
+ '<strong>' . $match[0] . '</strong>',
32
+ '<strong>' . $filename . '</strong>'
33
+ ) . $grep[0];
34
  $ret = false;
35
  } else {
36
  // There's a callback, check that no empty parameter is passed.
37
  if ( preg_match( '/[\'"](?:sanitize_callback|sanitize_js_callback)[\'"]\s*=>\s*[\'"]\s*[\'"]/', $match ) ) {
38
+ $match = preg_split( '/,/', $match );
39
+ $filename = tc_filename( $file_path );
40
+ $grep = tc_preg( '/[\'"](?:sanitize_callback|sanitize_js_callback)[\'"]\s*=>\s*[\'"]\s*[\'"]/', $file_path );
41
+ $grep = preg_split( '/,/', $grep );
42
+ $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( 'Found a Customizer setting called %1$s in %2$s that had an empty value passed as sanitization callback. You need to pass a function name as sanitization callback.', 'theme-check' ),
43
+ '<strong>' . $match[0] . '</strong>',
44
+ '<strong>' . $filename . '</strong>'
45
+ ) . $grep[0];
46
  $ret = false;
47
  }
48
  }
55
 
56
  function getError() { return $this->error; }
57
  }
58
+
59
+ $themechecks[] = new CustomizerCheck();
checks/deprecated.php CHANGED
@@ -254,7 +254,13 @@ class Deprecated implements themecheck {
254
  array( 'prepreview_added_widget_instance' => 'customize_dynamic_setting_args', '4.2' ),
255
  array( 'remove_prepreview_filters' => 'customize_dynamic_setting_args', '4.2' ),
256
 
 
 
 
 
257
  array( 'wp_get_http' => 'WP_Http', '4.4' ),
 
 
258
 
259
  array( 'is_comments_popup' => '', '4.5' ),
260
  array( 'add_object_page' => 'add_menu_page', '4.5' ),
@@ -264,6 +270,38 @@ class Deprecated implements themecheck {
264
  array( 'popuplinks' => '', '4.5' ),
265
  array( 'get_currentuserinfo' => 'wp_get_current_user', '4.5' ),
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  );
268
  foreach ( $php_files as $php_key => $phpfile ) {
269
  foreach ( $checks as $alt => $check ) {
254
  array( 'prepreview_added_widget_instance' => 'customize_dynamic_setting_args', '4.2' ),
255
  array( 'remove_prepreview_filters' => 'customize_dynamic_setting_args', '4.2' ),
256
 
257
+ array( 'wp_htmledit_pre' => 'format_for_editor', '4.3' ),
258
+ array( 'wp_richedit_pre' => 'format_for_editor', '4.3' ),
259
+ array( 'preview_theme' => '', '4.3' ),
260
+
261
  array( 'wp_get_http' => 'WP_Http', '4.4' ),
262
+ array( 'post_permalink' => 'get_permalink', '4.4' ),
263
+ array( 'force_ssl_login' => 'force_ssl_admin', '4.4' ),
264
 
265
  array( 'is_comments_popup' => '', '4.5' ),
266
  array( 'add_object_page' => 'add_menu_page', '4.5' ),
270
  array( 'popuplinks' => '', '4.5' ),
271
  array( 'get_currentuserinfo' => 'wp_get_current_user', '4.5' ),
272
 
273
+ array( 'wp_embed_handler_googlevideo' => '', '4.6' ),
274
+ array( 'wp_get_sites' => 'get_sites', '4.6' ),
275
+ array( 'post_form_autocomplete_off' => '', '4.6' ),
276
+
277
+ array( 'wp_die_handler' => '', '4.7' ),
278
+ array( 'wp_redirect_status' => '', '4.7' ),
279
+ array( 'customize_preview_override_404_status' => '', '4.7' ),
280
+ array( 'customize_preview_base' => '', '4.7' ),
281
+ array( 'customize_preview_html5' => '', '4.7' ),
282
+ array( 'customize_preview_signature' => '', '4.7' ),
283
+ array( 'remove_preview_signature' => '', '4.7' ),
284
+ array( '_cmp_priority' => 'wp_list_sort', '4.7' ),
285
+ array( 'reinit' => 'WP_Roles::for_site()', '4.7' ),
286
+ array( 'get_paged_template' => '', '4.7' ),
287
+ array( 'wp_kses_js_entities' => '', '4.7' ),
288
+ array( 'wp_get_network' => 'get_network()', '4.7' ),
289
+ array( '_sort_menus_by_orderby' => 'wp_list_sort', '4.7' ),
290
+
291
+ array( 'wp_dashboard_plugins_output' => '', '4.8' ),
292
+
293
+ array( '_init' => 'WP_Roles::for_site()', '4.9' ),
294
+ array( '_init_caps' => 'WP_User::for_site()', '4.9' ),
295
+ array( 'for_blog' => 'WP_User::for_site()', '4.9' ),
296
+ array( 'get_shortcut_link' => '', '4.9' ),
297
+ array( 'wp_ajax_press_this_save_post' => '', '4.9' ),
298
+ array( 'wp_ajax_press_this_add_category' => '', '4.9' ),
299
+ array( 'is_user_option_local' => '', '4.9' ),
300
+ array( 'maybe_log_events_response' => '', '4.9' ),
301
+
302
+ array( 'insert_blog' => 'wp_insert_site()', '5.1' ),
303
+ array( 'install_blog' => '', '5.1' ),
304
+
305
  );
306
  foreach ( $php_files as $php_key => $phpfile ) {
307
  foreach ( $checks as $alt => $check ) {
checks/deregister.php CHANGED
@@ -17,8 +17,7 @@ class DeregisterCheck implements themecheck {
17
  $grep = tc_preg( $error, $file_path );
18
 
19
  $this->error[] = sprintf( '<span class="tc-lead tc-warning">' . __('WARNING','theme-check') . '</span>: ' . __( 'Found wp_deregister_script in %1$s. Themes must not deregister core scripts.', 'theme-check' ),
20
- '<strong>' . $filename . '</strong>') . $grep;
21
- $ret = false;
22
  }
23
  }
24
  return $ret;
@@ -27,4 +26,4 @@ class DeregisterCheck implements themecheck {
27
 
28
  function getError() { return $this->error; }
29
  }
30
- $themechecks[] = new DeregisterCheck;
17
  $grep = tc_preg( $error, $file_path );
18
 
19
  $this->error[] = sprintf( '<span class="tc-lead tc-warning">' . __('WARNING','theme-check') . '</span>: ' . __( 'Found wp_deregister_script in %1$s. Themes must not deregister core scripts.', 'theme-check' ),
20
+ '<strong>' . $filename . '</strong>') . $grep;
 
21
  }
22
  }
23
  return $ret;
26
 
27
  function getError() { return $this->error; }
28
  }
29
+ $themechecks[] = new DeregisterCheck;
checks/escaping.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php // phpcs:ignore WordPress.Files.FileName
2
+ /**
3
+ * Checks for common escaping issues.
4
+ *
5
+ * @link https://make.wordpress.org/themes/handbook/review/required/#code
6
+ */
7
+
8
+ /**
9
+ * Checks for common escaping issues.
10
+ */
11
+ class EscapingCheck implements themecheck {
12
+ /**
13
+ * Error messages, warnings and info notices.
14
+ *
15
+ * @var array $error
16
+ */
17
+ protected $error = array();
18
+
19
+ /**
20
+ * Check that return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
21
+ *
22
+ * @param array $php_files File paths and content for PHP files.
23
+ * @param array $css_files File paths and content for CSS files.
24
+ * @param array $other_files Folder names, file paths and content for other files.
25
+ */
26
+ public function check( $php_files, $css_files, $other_files ) {
27
+
28
+ $ret = true;
29
+
30
+ $warnings = array(
31
+ '/="<\?php esc_html_e/' => __( 'Use esc_attr_e() inside HTML attributes, and esc_url() for link attributes', 'theme-check' ),
32
+ '/="<\?php echo esc_html__/' => __( 'Use esc_attr__() inside HTML attributes, and esc_url() for link attributes', 'theme-check' ),
33
+ '/="<\?php esc_html\(/' => __( 'Use esc_attr() inside HTML attributes, and esc_url() for link attributes', 'theme-check' ),
34
+ '/><\?php echo esc_attr\(/' => __( 'Only use esc_attr() inside HTML attributes. Use esc_html() between HTML tags', 'theme-check' ),
35
+ '/><\?php echo esc_attr__/' => __( 'Only use esc_attr__() inside HTML attributes. Use esc_html__() between HTML tags', 'theme-check' ),
36
+ '/><\?php esc_attr_e/' => __( 'Only use esc_attr_e() inside HTML attributes. Use esc_html_e() between HTML tags', 'theme-check' ),
37
+ );
38
+
39
+ $required = array (
40
+ '/echo home_url/' => __( 'home_url() must be escaped. Use esc_url() for link attributes', 'theme-check' ),
41
+ '/echo get_template_directory_uri/' => __( 'get_template_directory_uri() must be escaped when output as part of a link or image source. Use esc_url() for link attributes', 'theme-check' ),
42
+ );
43
+
44
+ foreach ( $php_files as $php_key => $phpfile ) {
45
+
46
+ checkcount();
47
+ if ( false !== strpos( $phpfile, 'echo get_theme_mod' ) ) {
48
+ $filename = tc_filename( $php_key );
49
+ $error = 'echo get_theme_mod';
50
+ $grep = tc_grep( $error, $php_key );
51
+ $this->error[] = sprintf(
52
+ '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check' ) . '</span>: ' . __( 'Found %1$s in %2$s. <a href="%3$s" target="_blank">Theme options must be escaped (Opens in a new window).</a>. ', 'theme-check' ),
53
+ '<code>' . esc_html( $error ) . '</code>',
54
+ '<strong>' . $filename . '</strong>',
55
+ 'https://developer.wordpress.org/themes/theme-security/data-sanitization-escaping/#escaping-securing-output'
56
+ ) . $grep;
57
+
58
+ }
59
+
60
+ foreach ( $warnings as $key => $check ) {
61
+ checkcount();
62
+ if ( preg_match( $key, $phpfile, $matches ) ) {
63
+ $filename = tc_filename( $php_key );
64
+ $error = $matches[0];
65
+ $grep = tc_grep( $error, $php_key );
66
+ $this->error[] = sprintf(
67
+ '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check' ) . '</span>: ' . __( 'Found %1$s in %2$s. %3$s. A manual review is needed.', 'theme-check' ),
68
+ '<code>' . esc_html( $error ) . '</code>',
69
+ '<strong>' . $filename . '</strong>',
70
+ $check
71
+ ) . $grep;
72
+ }
73
+ }
74
+
75
+ foreach ( $required as $key => $check ) {
76
+ checkcount();
77
+ if ( preg_match( $key, $phpfile, $matches ) ) {
78
+ $filename = tc_filename( $php_key );
79
+ $error = $matches[0];
80
+ $grep = tc_grep( $error, $php_key );
81
+ $this->error[] = sprintf(
82
+ '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( 'Found %1$s in %2$s. %3$s. A manual review is needed.', 'theme-check' ),
83
+ '<code>' . esc_html( $error ) . '</code>',
84
+ '<strong>' . $filename . '</strong>',
85
+ $check
86
+ ) . $grep;
87
+
88
+ $ret = false;
89
+ }
90
+ }
91
+ }
92
+ return $ret;
93
+ }
94
+
95
+ /**
96
+ * Get error messages from the checks.
97
+ *
98
+ * @return array Error message.
99
+ */
100
+ public function getError() {
101
+ return $this->error;
102
+ }
103
+ }
104
+
105
+ $themechecks[] = new EscapingCheck();
checks/favicon.php CHANGED
@@ -1,4 +1,8 @@
1
  <?php
 
 
 
 
2
 
3
  class FaviconCheck implements themecheck {
4
  protected $error = array();
@@ -6,16 +10,18 @@ class FaviconCheck implements themecheck {
6
  function check( $php_files, $css_files, $other_files ) {
7
 
8
  $ret = true;
9
-
10
  checkcount();
11
 
12
  foreach ( $php_files as $file_path => $file_content ) {
13
 
14
  $filename = tc_filename( $file_path );
15
 
16
- if ( preg_match( '/(<link rel=[\'"]icon[\'"])|(<link rel=[\'"]apple-touch-icon-precomposed[\'"])|(<meta name=[\'"]msapplication-TileImage[\'"])/', $file_content, $matches ) ) {
17
- $this->error[] = sprintf( '<span class="tc-lead tc-info">' . __('INFO','theme-check') . '</span>: ' . __( 'Possible Favicon found in %1$s. Favicons are handled by the Site Icon setting in the customizer since version 4.3.', 'theme-check' ),
18
- '<strong>' . $filename . '</strong>');
 
 
19
  }
20
  }
21
  return $ret;
@@ -23,4 +29,5 @@ class FaviconCheck implements themecheck {
23
 
24
  function getError() { return $this->error; }
25
  }
26
- $themechecks[] = new FaviconCheck;
 
1
  <?php
2
+ /**
3
+ * Checks for favicons.
4
+ * Note that the check for the icon file is in filenames.php.
5
+ */
6
 
7
  class FaviconCheck implements themecheck {
8
  protected $error = array();
10
  function check( $php_files, $css_files, $other_files ) {
11
 
12
  $ret = true;
13
+
14
  checkcount();
15
 
16
  foreach ( $php_files as $file_path => $file_content ) {
17
 
18
  $filename = tc_filename( $file_path );
19
 
20
+ if ( preg_match( '/(<link rel=[\'"]icon[\'"])|(<link rel=[\'"]shortcut icon[\'"])|(<link rel=[\'"]apple-touch-icon.*[\'"])|(<meta name=[\'"]msapplication-TileImage[\'"])/i', $file_content, $matches ) ) {
21
+ $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( 'Possible Favicon found in %1$s. Favicons are handled by the Site Icon setting in the customizer since version 4.3.', 'theme-check' ),
22
+ '<strong>' . $filename . '</strong>'
23
+ );
24
+ $ret = false;
25
  }
26
  }
27
  return $ret;
29
 
30
  function getError() { return $this->error; }
31
  }
32
+
33
+ $themechecks[] = new FaviconCheck();
checks/filenames.php CHANGED
@@ -17,45 +17,63 @@ class File_Checks implements themecheck {
17
  foreach ( $css_files as $php_key => $phpfile ) {
18
  array_push( $filenames, strtolower( basename( $php_key ) ) );
19
  }
 
 
 
20
  $blacklist = array(
21
- 'thumbs.db' => __( 'Windows thumbnail store', 'theme-check' ),
22
- 'desktop.ini' => __( 'windows system file', 'theme-check' ),
23
- 'project.properties' => __( 'NetBeans Project File', 'theme-check' ),
24
- 'project.xml' => __( 'NetBeans Project File', 'theme-check' ),
25
- '\.kpf' => __( 'Komodo Project File', 'theme-check' ),
26
- '^\.+[a-zA-Z0-9]' => __( 'Hidden Files or Folders', 'theme-check' ),
27
- 'php.ini' => __( 'PHP server settings file', 'theme-check' ),
28
- 'dwsync.xml' => __( 'Dreamweaver project file', 'theme-check' ),
29
- 'error_log' => __( 'PHP error log', 'theme-check' ),
30
- 'web.config' => __( 'Server settings file', 'theme-check' ),
31
- '\.sql' => __( 'SQL dump file', 'theme-check' ),
32
- '__MACOSX' => __( 'OSX system file', 'theme-check' ),
33
- '\.lubith' => __( 'Lubith theme generator file', 'theme-check' ),
34
- );
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
- $musthave = array( 'index.php', 'style.css' );
37
- $rechave = array( 'readme.txt' => __( 'Please see <a href="https://codex.wordpress.org/Theme_Review#Theme_Documentation">Theme_Documentation</a> for more information.', 'theme-check' ) );
38
 
39
  checkcount();
40
 
41
- foreach( $blacklist as $file => $reason ) {
42
- if ( $filename = preg_grep( '/' . $file . '/', $filenames ) ) {
43
- $error = implode( array_unique( $filename ), ' ' );
44
- $this->error[] = sprintf('<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('%1$s %2$s found.', 'theme-check'), '<strong>' . $error . '</strong>', $reason) ;
45
- $ret = false;
 
 
 
46
  }
47
  }
48
 
49
- foreach( $musthave as $file ) {
50
- if ( !in_array( $file, $filenames ) ) {
51
- $this->error[] = sprintf('<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('Could not find the file %s in the theme.', 'theme-check'), '<strong>' . $file . '</strong>' );
52
- $ret = false;
53
  }
54
  }
55
 
56
- foreach( $rechave as $file => $reason ) {
57
- if ( !in_array( $file, $filenames ) ) {
58
- $this->error[] = sprintf('<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('Could not find the file %1$s in the theme. %2$s', 'theme-check'), '<strong>' . $file . '</strong>', $reason );
59
  }
60
  }
61
 
@@ -64,4 +82,5 @@ class File_Checks implements themecheck {
64
 
65
  function getError() { return $this->error; }
66
  }
67
- $themechecks[] = new File_Checks;
 
17
  foreach ( $css_files as $php_key => $phpfile ) {
18
  array_push( $filenames, strtolower( basename( $php_key ) ) );
19
  }
20
+
21
+ $whitelist = 'wpml-config.xml';
22
+
23
  $blacklist = array(
24
+ 'thumbs\.db' => __( 'Windows thumbnail store', 'theme-check' ),
25
+ 'desktop\.ini' => __( 'windows system file', 'theme-check' ),
26
+ 'project\.properties' => __( 'NetBeans Project File', 'theme-check' ),
27
+ 'project\.xml' => __( 'NetBeans Project File', 'theme-check' ),
28
+ '\.kpf' => __( 'Komodo Project File', 'theme-check' ),
29
+ '^\.+[a-zA-Z0-9]' => __( 'Hidden Files or Folders', 'theme-check' ),
30
+ 'php\.ini' => __( 'PHP server settings file', 'theme-check' ),
31
+ 'dwsync\.xml' => __( 'Dreamweaver project file', 'theme-check' ),
32
+ 'error_log' => __( 'PHP error log', 'theme-check' ),
33
+ 'web\.config' => __( 'Server settings file', 'theme-check' ),
34
+ '\.sql' => __( 'SQL dump file', 'theme-check' ),
35
+ '__MACOSX' => __( 'OSX system file', 'theme-check' ),
36
+ '\.lubith' => __( 'Lubith theme generator file', 'theme-check' ),
37
+ '\.wie' => __( 'Widget import file', 'theme-check' ),
38
+ '\.dat' => __( 'Customizer import file', 'theme-check' ),
39
+ 'phpcs\.xml\.dist' => __( 'PHPCS file', 'theme-check' ),
40
+ 'phpcs\.xml' => __( 'PHPCS file', 'theme-check' ),
41
+ '\.xml' => __( 'XML file', 'theme-check' ),
42
+ '\.sh' => __( 'Shell script file', 'theme-check' ),
43
+ 'postcss\.config\.js' => __( 'PostCSS config file', 'theme-check' ),
44
+ '\.editorconfig.' => __( 'Editor config file', 'theme-check' ),
45
+ '\.stylelintrc\.json' => __( 'Stylelint config file', 'theme-check' ),
46
+ '\.map' => __( 'Map file', 'theme-check' ),
47
+ '\.eslintrc' => __( 'ES lint config file', 'theme-check' ),
48
+ 'favicon\.ico' => __( 'Favicon', 'theme-check' ),
49
+ );
50
 
51
+ $musthave = array( 'index.php', 'style.css', 'readme.txt' );
52
+ $rechave = array();
53
 
54
  checkcount();
55
 
56
+ foreach ( $blacklist as $file => $reason ) {
57
+ if ( $filename = preg_grep( '/' . $file . '/', $filenames ) ) {
58
+ $error = implode( ' ', array_unique( $filename ) );
59
+ if ( $error === $whitelist ) {
60
+ continue;
61
+ }
62
+ $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( '%1$s %2$s found. This file must not be in a theme.', 'theme-check' ), '<strong>' . $error . '</strong>', $reason );
63
+ $ret = false;
64
  }
65
  }
66
 
67
+ foreach ( $musthave as $file ) {
68
+ if ( ! in_array( $file, $filenames ) ) {
69
+ $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( 'Could not find the file %s in the theme.', 'theme-check' ), '<strong>' . $file . '</strong>' );
70
+ $ret = false;
71
  }
72
  }
73
 
74
+ foreach ( $rechave as $file => $reason ) {
75
+ if ( ! in_array( $file, $filenames ) ) {
76
+ $this->error[] = sprintf( '<span class="tc-lead tc-recommended">' . __( 'RECOMMENDED', 'theme-check' ) . '</span>: ' . __( 'Could not find the file %1$s in the theme. %2$s', 'theme-check' ), '<strong>' . $file . '</strong>', $reason );
77
  }
78
  }
79
 
82
 
83
  function getError() { return $this->error; }
84
  }
85
+
86
+ $themechecks[] = new File_Checks();
checks/generated.php CHANGED
@@ -30,7 +30,7 @@ class GeneratedCheck implements themecheck {
30
  //wpthemegenerator
31
  || strpos ( $php, "wptg_") !== false
32
  ) {
33
- $this->error[] = "<span class='tc-lead tc-warning'>" . __('WARNING', 'theme-check' ). "</span>: " . __( 'This theme appears to have been auto-generated. Generated themes are not allowed in the themes directory.', 'theme-check' );
34
  $ret = false;
35
  }
36
 
@@ -39,4 +39,4 @@ class GeneratedCheck implements themecheck {
39
 
40
  function getError() { return $this->error; }
41
  }
42
- $themechecks[] = new GeneratedCheck;
30
  //wpthemegenerator
31
  || strpos ( $php, "wptg_") !== false
32
  ) {
33
+ $this->error[] = "<span class='tc-lead tc-required'>" . __('REQUIRED', 'theme-check' ). "</span>: " . __( 'This theme appears to have been auto-generated. Generated themes are not allowed in the themes directory.', 'theme-check' );
34
  $ret = false;
35
  }
36
 
39
 
40
  function getError() { return $this->error; }
41
  }
42
+ $themechecks[] = new GeneratedCheck;
checks/i18n.php CHANGED
@@ -1,70 +1,71 @@
1
- <?php
2
-
3
- // check for various I18N errors
4
-
5
- class I18NCheck implements themecheck {
6
- protected $error = array();
7
-
8
- function check( $php_files, $css_files, $other_files ) {
9
- $ret = true;
10
- $error = '';
11
- checkcount();
12
-
13
- // make sure the tokenizer is available
14
- if ( !function_exists( 'token_get_all' ) ) return true;
15
-
16
- foreach ( $php_files as $php_key => $phpfile ) {
17
- $error='';
18
-
19
- $stmts = array();
20
- foreach ( array('_e(', '__(', '_e (', '__ (') as $finder) {
21
- $search = $phpfile;
22
- while ( ( $pos = strpos($search, $finder) ) !== false ) {
23
- $search = substr($search,$pos);
24
- $open=1;
25
- $i=strpos($search,'(')+1;
26
- while( $open>0 ) {
27
- switch($search[$i]) {
28
- case '(':
29
- $open++; break;
30
- case ')':
31
- $open--; break;
32
- }
33
- $i++;
34
- }
35
- $stmts[] = substr($search,0,$i);
36
- $search = substr($search,$i);
37
- }
38
- }
39
-
40
- foreach ( $stmts as $match ) {
41
- $tokens = @token_get_all('<?php '.$match.';');
42
- if (!empty($tokens)) {
43
- foreach ($tokens as $token) {
44
- if (is_array($token) && in_array( $token[0], array( T_VARIABLE ) ) ) {
45
- $filename = tc_filename( $php_key );
46
- $grep = tc_grep( ltrim( $match ), $php_key );
47
- preg_match( '/[^\s]*\s[0-9]+/', $grep, $line);
48
- $error = '';
49
- if ( isset( $line[0] ) ) {
50
- $error = ( !strpos( $error, $line[0] ) ) ? $grep : '';
51
- }
52
- $this->error[] = sprintf('<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('Possible variable %1$s found in translation function in %2$s. Translation function calls must NOT contain PHP variables. %3$s','theme-check'),
53
- '<strong>' . $token[1] . '</strong>',
54
- '<strong>' . $filename . '</strong>',
55
- $error
56
- );
57
- break; // stop looking at the tokens on this line once a variable is found
58
- }
59
- }
60
- }
61
- }
62
-
63
-
64
- }
65
- return $ret;
66
- }
67
-
68
- function getError() { return $this->error; }
69
- }
 
70
  $themechecks[] = new I18NCheck;
1
+ <?php
2
+
3
+ // check for various I18N errors
4
+
5
+ class I18NCheck implements themecheck {
6
+ protected $error = array();
7
+
8
+ function check( $php_files, $css_files, $other_files ) {
9
+
10
+ $ret = true;
11
+ $error = '';
12
+ checkcount();
13
+
14
+ // make sure the tokenizer is available
15
+ if ( !function_exists( 'token_get_all' ) ) return true;
16
+
17
+ foreach ( $php_files as $php_key => $phpfile ) {
18
+ $error='';
19
+
20
+ $stmts = array();
21
+ foreach ( array('_e(', '__(', '_e (', '__ (') as $finder) {
22
+ $search = $phpfile;
23
+ while ( ( $pos = strpos($search, $finder) ) !== false ) {
24
+ $search = substr($search,$pos);
25
+ $open=1;
26
+ $i=strpos($search,'(')+1;
27
+ while( $open>0 ) {
28
+ switch($search[$i]) {
29
+ case '(':
30
+ $open++; break;
31
+ case ')':
32
+ $open--; break;
33
+ }
34
+ $i++;
35
+ }
36
+ $stmts[] = substr($search,0,$i);
37
+ $search = substr($search,$i);
38
+ }
39
+ }
40
+
41
+ foreach ( $stmts as $match ) {
42
+ $tokens = @token_get_all('<?php '.$match.';');
43
+ if (!empty($tokens)) {
44
+ foreach ($tokens as $token) {
45
+ if (is_array($token) && in_array( $token[0], array( T_VARIABLE ) ) ) {
46
+ $filename = tc_filename( $php_key );
47
+ $grep = tc_grep( ltrim( $match ), $php_key );
48
+ preg_match( '/[^\s]*\s[0-9]+/', $grep, $line);
49
+ $error = '';
50
+ if ( isset( $line[0] ) ) {
51
+ $error = ( !strpos( $error, $line[0] ) ) ? $grep : '';
52
+ }
53
+ $this->error[] = sprintf('<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('Possible variable %1$s found in translation function in %2$s. Translation function calls must NOT contain PHP variables. %3$s','theme-check'),
54
+ '<strong>' . $token[1] . '</strong>',
55
+ '<strong>' . $filename . '</strong>',
56
+ $error
57
+ );
58
+ break; // stop looking at the tokens on this line once a variable is found
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+
65
+ }
66
+ return $ret;
67
+ }
68
+
69
+ function getError() { return $this->error; }
70
+ }
71
  $themechecks[] = new I18NCheck;
checks/included-plugins.php CHANGED
@@ -19,7 +19,7 @@ class IncludedPlugins implements themecheck {
19
 
20
  foreach ( $blacklist as $file => $reason ) {
21
  if ( $filename = preg_grep( '/' . $file . '/', $filenames ) ) {
22
- $error = implode( array_unique( $filename ), ' ' );
23
  $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED','theme-check' ) . '</span>: ' . __( '<strong>Zip file found.</strong> Plugins are not allowed in themes. The zip file found was <em>%s</em>.', 'theme-check' ), $error );
24
  $ret = false;
25
  }
19
 
20
  foreach ( $blacklist as $file => $reason ) {
21
  if ( $filename = preg_grep( '/' . $file . '/', $filenames ) ) {
22
+ $error = implode( ' ', array_unique( $filename ) );
23
  $this->error[] = sprintf( '<span class="tc-lead tc-required">' . __( 'REQUIRED','theme-check' ) . '</span>: ' . __( '<strong>Zip file found.</strong> Plugins are not allowed in themes. The zip file found was <em>%s</em>.', 'theme-check' ), $error );
24
  $ret = false;
25
  }
checks/lineendings.php CHANGED
@@ -8,7 +8,7 @@ class LineEndingsCheck implements themecheck {
8
  if (preg_match("/\r\n/",$phpfile)) {
9
  if (preg_match("/[^\r]\n/",$phpfile)) {
10
  $filename = tc_filename( $php_key );
11
- $this->error[] = sprintf('<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('Both DOS and UNIX style line endings were found in the file %1$s. This causes a problem with SVN repositories and must be corrected before the theme can be accepted. Please change the file to use only one style of line endings.', 'theme-check'), '<strong>' . $filename . '</strong>' );
12
  $ret = false;
13
  }
14
  }
@@ -17,7 +17,7 @@ class LineEndingsCheck implements themecheck {
17
  if (preg_match("/\r\n/",$cssfile)) {
18
  if (preg_match("/[^\r]\n/",$cssfile)) {
19
  $filename = tc_filename( $css_key );
20
- $this->error[] = sprintf('<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('Both DOS and UNIX style line endings were found in the file %1$s. This causes a problem with SVN repositories and must be corrected before the theme can be accepted. Please change the file to use only one style of line endings.', 'theme-check'), '<strong>' . $filename . '</strong>' );
21
  $ret = false;
22
  }
23
  }
@@ -28,7 +28,7 @@ class LineEndingsCheck implements themecheck {
28
  if (preg_match("/\r\n/",$othfile)) {
29
  if (preg_match("/[^\r]\n/",$othfile)) {
30
  $filename = tc_filename( $oth_key );
31
- $this->error[] = sprintf('<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('Both DOS and UNIX style line endings were found in the file %1$s. This causes a problem with SVN repositories and must be corrected before the theme can be accepted. Please change the file to use only one style of line endings.', 'theme-check'), '<strong>' . $filename . '</strong>' );
32
  $ret = false;
33
  }
34
  }
8
  if (preg_match("/\r\n/",$phpfile)) {
9
  if (preg_match("/[^\r]\n/",$phpfile)) {
10
  $filename = tc_filename( $php_key );
11
+ $this->error[] = sprintf('<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Both DOS and UNIX style line endings were found in the file %1$s. This causes a problem with SVN repositories and must be corrected before the theme can be accepted. Please change the file to use only one style of line endings.', 'theme-check'), '<strong>' . $filename . '</strong>' );
12
  $ret = false;
13
  }
14
  }
17
  if (preg_match("/\r\n/",$cssfile)) {
18
  if (preg_match("/[^\r]\n/",$cssfile)) {
19
  $filename = tc_filename( $css_key );
20
+ $this->error[] = sprintf('<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Both DOS and UNIX style line endings were found in the file %1$s. This causes a problem with SVN repositories and must be corrected before the theme can be accepted. Please change the file to use only one style of line endings.', 'theme-check'), '<strong>' . $filename . '</strong>' );
21
  $ret = false;
22
  }
23
  }
28
  if (preg_match("/\r\n/",$othfile)) {
29
  if (preg_match("/[^\r]\n/",$othfile)) {
30
  $filename = tc_filename( $oth_key );
31
+ $this->error[] = sprintf('<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Both DOS and UNIX style line endings were found in the file %1$s. This causes a problem with SVN repositories and must be corrected before the theme can be accepted. Please change the file to use only one style of line endings.', 'theme-check'), '<strong>' . $filename . '</strong>' );
32
  $ret = false;
33
  }
34
  }
checks/navmenu.php CHANGED
@@ -5,21 +5,63 @@ class NavMenuCheck implements themecheck {
5
 
6
  function check( $php_files, $css_files, $other_files ) {
7
 
8
- $ret = true;
 
 
 
9
 
10
- // combine all the php files into one string to make it easier to search
11
- $php = implode( ' ', $php_files );
12
  checkcount();
13
  if ( strpos( $php, 'nav_menu' ) === false ) {
14
- $this->error[] = '<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__("No reference to nav_menu's was found in the theme. Note that if your theme has a menu bar, it is required to use the WordPress nav_menu functionality for it.", 'theme-check' );
15
  }
16
 
17
  // Look for add_theme_support( 'menus' ).
18
  checkcount();
19
  if ( preg_match( '/add_theme_support\s*\(\s?("|\')menus("|\')\s?\)/', $php ) ) {
20
  /* translators: 1: function found, 2: function to be used */
21
- $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check') . '</span>: ' . sprintf( __( 'Reference to %1$s was found in the theme. This should be removed and %2$s used instead.', 'theme-check' ), '<strong>add_theme_support( "menus" )</strong>', '<a href="https://developer.wordpress.org/reference/functions/register_nav_menus/">register_nav_menus()</a>' );
22
- $ret = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
  return $ret;
@@ -28,4 +70,4 @@ class NavMenuCheck implements themecheck {
28
  function getError() { return $this->error; }
29
  }
30
 
31
- $themechecks[] = new NavMenuCheck;
5
 
6
  function check( $php_files, $css_files, $other_files ) {
7
 
8
+ $ret = true;
9
+ $name_check = false;
10
+
11
+ $php = implode( ' ', $php_files );
12
 
 
 
13
  checkcount();
14
  if ( strpos( $php, 'nav_menu' ) === false ) {
15
+ $this->error[] = '<span class="tc-lead tc-recommended">' . __( 'RECOMMENDED', 'theme-check' ) . '</span>: ' . __( "No reference to nav_menu's was found in the theme. Note that if your theme has a menu bar, it is required to use the WordPress nav_menu functionality for it.", 'theme-check' );
16
  }
17
 
18
  // Look for add_theme_support( 'menus' ).
19
  checkcount();
20
  if ( preg_match( '/add_theme_support\s*\(\s?("|\')menus("|\')\s?\)/', $php ) ) {
21
  /* translators: 1: function found, 2: function to be used */
22
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'Reference to %1$s was found in the theme. This should be removed and %2$s used instead.', 'theme-check' ), '<strong>add_theme_support( "menus" )</strong>', '<a href="https://developer.wordpress.org/reference/functions/register_nav_menus/">register_nav_menus()</a>' );
23
+ $ret = false;
24
+ }
25
+
26
+ foreach ( $php_files as $file_path => $file_content ) {
27
+ $filename = tc_filename( $file_path );
28
+
29
+ // We are checking for wp_nav_menu( specifically, to allow wp_nav_menu and wp_nav_menu_item in filters etc.
30
+ if ( strpos( $file_content, 'wp_nav_menu(' ) !== false ) {
31
+ $menu_part = explode( 'wp_nav_menu(', $file_content );
32
+ $menu_part = explode( ';', $menu_part[1] );
33
+
34
+ // If there is a menu, check for a theme location, which is required.
35
+ // Check if the arguments are placed outside wp_nav_menu.
36
+ checkcount();
37
+ if ( strpos( $menu_part[0], '$' ) !== false && strpos( $menu_part[0], 'theme_location' ) === false ) {
38
+ $menu_args = explode( '$', $menu_part[0], 1 );
39
+ $name = explode( ')', $menu_args[0] );
40
+ $this->error[] = '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check' ) . '</span>: ' . sprintf( __( 'A menu without a theme_location was found in %1$s. %2$s is used inside wp_nav_menu(). You must manually check if the theme_location is included.', 'theme-check' ),
41
+ '<strong>' . $filename . '</strong>',
42
+ '<code>' . $name[0] . '</code>'
43
+ );
44
+ $name_check = true;
45
+ } else {
46
+ checkcount();
47
+ if ( strpos( $menu_part[0], 'theme_location' ) === false ) {
48
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'A menu without a theme_location was found in %1$s.', 'theme-check' ),
49
+ '<strong>' . $filename . '</strong>'
50
+ );
51
+ $ret = false;
52
+ $name_check = true;
53
+ }
54
+ }
55
+
56
+ // We only need to warn for the menu name if theme location is not set.
57
+ checkcount();
58
+ if ( $name_check === true && preg_match( '/("|\')menu("|\').*?=>/', $menu_part[0] ) ) {
59
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'A menu name is being used for a menu in %1$s. By using menu name, the menu would be required to have the exact same name in the WordPress admin area. Use a theme_location instead.', 'theme-check' ),
60
+ '<strong>' . $filename . '</strong>'
61
+ );
62
+ $ret = false;
63
+ }
64
+ }
65
  }
66
 
67
  return $ret;
70
  function getError() { return $this->error; }
71
  }
72
 
73
+ $themechecks[] = new NavMenuCheck();
checks/nongplsites.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Checks if the theme includes resoruces from websites that does not use a GPL compatible license.
4
+ */
5
+ class NonGPLCheck implements themecheck {
6
+ protected $error = array();
7
+
8
+ function check( $php_files, $css_files, $other_files ) {
9
+
10
+ $ret = true;
11
+ $code = implode( ' ', $other_files ); // The references are usually in the readme.
12
+
13
+ checkcount();
14
+
15
+ $link_list = array(
16
+ 'unsplash' => 'https://unsplash.com/license',
17
+ 'pixabay' => 'https://pixabay.com/service/license/',
18
+ 'freeimages' => 'https://www.freeimages.com/license',
19
+ 'photopin' => 'http://photopin.com/faq',
20
+ 'splitshire' => 'https://www.splitshire.com/licence/',
21
+ 'freepik' => 'https://www.freepikcompany.com/legal',
22
+ 'flaticon' => 'https://www.freepikcompany.com/legal',
23
+ 'pikwizard' => 'https://pikwizard.com/standard-license',
24
+ 'stock.adobe' => 'https://stock.adobe.com/license-terms',
25
+ 'elements.envato' => 'https://elements.envato.com/license-terms',
26
+ 'undraw.co' => 'https://undraw.co/licenses',
27
+ );
28
+
29
+ foreach ( $link_list as $link_slug => $link_url ) {
30
+ if ( false !== stripos( $code, $link_slug ) ) {
31
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' .
32
+ sprintf(
33
+ __( 'Found a reference to %s. Images from this website does not use a license that is compatible with GPL.', 'theme-check' ),
34
+ '<code>' . esc_html( $link_slug ) . '</code>'
35
+ )
36
+ . ' <a href="' . esc_url( $link_url ) . '" target="_blank">' . __( 'View license (opens in a new window).', 'theme-check' ) . '</a>';
37
+ }
38
+ }
39
+
40
+ return $ret;
41
+ }
42
+
43
+ function getError() { return $this->error; }
44
+ }
45
+
46
+ $themechecks[] = new NonGPLCheck;
checks/nonprintable.php CHANGED
@@ -10,10 +10,10 @@ class NonPrintableCheck implements themecheck {
10
  // 09 = tab
11
  // 0A = line feed
12
  // 0D = new line
13
- if ( preg_match('/[\x00-\x08\x0B-\x0C\x0E-\x1F\x80-\xFF]/', $content, $matches ) ) {
14
  $filename = tc_filename( $name );
15
- $non_print = tc_preg( '/[\x00-\x08\x0B-\x0C\x0E-\x1F\x80-\xFF]/', $name );
16
- $this->error[] = sprintf('<span class="tc-lead tc-info">'.__('INFO','theme-check').'</span>: '.__('Non-printable characters were found in the %1$s file. You may want to check this file for errors.%2$s', 'theme-check'), '<strong>' . $filename . '</strong>', $non_print);
17
  }
18
  }
19
 
@@ -24,4 +24,4 @@ class NonPrintableCheck implements themecheck {
24
  function getError() { return $this->error; }
25
  }
26
 
27
- $themechecks[] = new NonPrintableCheck;
10
  // 09 = tab
11
  // 0A = line feed
12
  // 0D = new line
13
+ if ( preg_match('/[\x00-\x08\x0B-\x0C\x0E-\x1F]/', $content, $matches ) ) {
14
  $filename = tc_filename( $name );
15
+ $non_print = tc_preg( '/[\x00-\x08\x0B-\x0C\x0E-\x1F]/', $name );
16
+ $this->error[] = sprintf('<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check' ) . '</span>: ' . __( 'Non-printable characters were found in the %1$s file. You may want to check this file for errors.%2$s', 'theme-check' ), '<strong>' . $filename . '</strong>', $non_print);
17
  }
18
  }
19
 
24
  function getError() { return $this->error; }
25
  }
26
 
27
+ $themechecks[] = new NonPrintableCheck;
checks/phpshort.php CHANGED
@@ -12,7 +12,6 @@ class PHPShortTagsCheck implements themecheck {
12
  $filename = tc_filename( $php_key );
13
  $grep = tc_preg( '/<\?(\=?)(?!php|xml)/', $php_key );
14
  $this->error[] = sprintf('<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('Found PHP short tags in file %1$s.%2$s', 'theme-check'), '<strong>' . $filename . '</strong>', $grep);
15
- $ret = false;
16
  }
17
  }
18
 
@@ -22,4 +21,4 @@ class PHPShortTagsCheck implements themecheck {
22
  function getError() { return $this->error; }
23
  }
24
 
25
- $themechecks[] = new PHPShortTagsCheck;
12
  $filename = tc_filename( $php_key );
13
  $grep = tc_preg( '/<\?(\=?)(?!php|xml)/', $php_key );
14
  $this->error[] = sprintf('<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('Found PHP short tags in file %1$s.%2$s', 'theme-check'), '<strong>' . $filename . '</strong>', $grep);
 
15
  }
16
  }
17
 
21
  function getError() { return $this->error; }
22
  }
23
 
24
+ $themechecks[] = new PHPShortTagsCheck;
checks/plugin-territory.php CHANGED
@@ -1,14 +1,29 @@
1
- <?php
2
  /**
3
  * Checks for Plugin Territory Guidelines.
4
  *
5
- * See http://make.wordpress.org/themes/guidelines/guidelines-plugin-territory/
6
  */
7
 
 
 
 
8
  class Plugin_Territory implements themecheck {
 
 
 
 
 
9
  protected $error = array();
10
 
11
- function check( $php_files, $css_files, $other_files ) {
 
 
 
 
 
 
 
12
  $ret = true;
13
  $php = implode( ' ', $php_files );
14
 
@@ -16,26 +31,107 @@ class Plugin_Territory implements themecheck {
16
  $forbidden_functions = array(
17
  'register_post_type',
18
  'register_taxonomy',
 
 
19
  );
20
 
21
  foreach ( $forbidden_functions as $function ) {
22
  checkcount();
23
  if ( preg_match( '/[\s?]' . $function . '\s?\(/', $php ) ) {
24
- $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check').'</span>: ' . sprintf( __( 'The theme uses the %s function, which is plugin-territory functionality.', 'theme-check' ), '<strong>' . esc_html( $function ) . '()</strong>' ) ;
25
- $ret = false;
26
  }
27
  }
28
 
29
  // Shortcodes can't be used in the post content, so warn about them.
30
- if ( false !== strpos( $php, 'add_shortcode' ) ) {
31
  checkcount();
32
- $this->error[] = '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check').'</span>: ' . sprintf( __( 'The theme uses the %s function. Custom post-content shortcodes are plugin-territory functionality.', 'theme-check' ), '<strong>add_shortcode()</strong>' ) ;
33
- $ret = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
 
36
  return $ret;
37
  }
38
 
39
- function getError() { return $this->error; }
 
 
 
 
 
 
 
40
  }
41
- $themechecks[] = new Plugin_Territory;
 
1
+ <?php // phpcs:ignore WordPress.Files.FileName
2
  /**
3
  * Checks for Plugin Territory Guidelines.
4
  *
5
+ * @link https://make.wordpress.org/themes/handbook/review/required/#presentation-vs-functionality
6
  */
7
 
8
+ /**
9
+ * Checks for Plugin Territory
10
+ */
11
  class Plugin_Territory implements themecheck {
12
+ /**
13
+ * Error messages, warnings and info notices.
14
+ *
15
+ * @var array $error
16
+ */
17
  protected $error = array();
18
 
19
+ /**
20
+ * Check that return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
21
+ *
22
+ * @param array $php_files File paths and content for PHP files.
23
+ * @param array $css_files File paths and content for CSS files.
24
+ * @param array $other_files Folder names, file paths and content for other files.
25
+ */
26
+ public function check( $php_files, $css_files, $other_files ) {
27
  $ret = true;
28
  $php = implode( ' ', $php_files );
29
 
31
  $forbidden_functions = array(
32
  'register_post_type',
33
  'register_taxonomy',
34
+ 'wp_add_dashboard_widget',
35
+ 'register_block_type',
36
  );
37
 
38
  foreach ( $forbidden_functions as $function ) {
39
  checkcount();
40
  if ( preg_match( '/[\s?]' . $function . '\s?\(/', $php ) ) {
41
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'The theme uses the %s function, which is plugin-territory functionality.', 'theme-check' ), '<strong>' . esc_html( $function ) . '()</strong>' );
42
+ $ret = false;
43
  }
44
  }
45
 
46
  // Shortcodes can't be used in the post content, so warn about them.
47
+ if ( false !== strpos( $php, 'add_shortcode(' ) ) {
48
  checkcount();
49
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'The theme uses the %s function. Custom post-content shortcodes are plugin-territory functionality.', 'theme-check' ), '<strong>add_shortcode()</strong>' );
50
+ $ret = false;
51
+ }
52
+
53
+ // Hooks (actions & filters) that are required to be removed from the theme.
54
+ $forbidden_hooks = array(
55
+ 'filter' => array(
56
+ 'mime_types',
57
+ 'upload_mimes',
58
+ 'user_contactmethods',
59
+ ),
60
+ 'action' => array(
61
+ 'wp_dashboard_setup',
62
+ ),
63
+ );
64
+
65
+ foreach ( $forbidden_hooks as $type => $hooks ) {
66
+ foreach ( $hooks as $hook ) {
67
+ checkcount();
68
+ if ( preg_match( '/[\s?]add_' . $type . '\s*\(\s*([\'"])' . $hook . '([\'"])\s*,/', $php ) ) {
69
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'The theme uses the %1$s %2$s, which is plugin-territory functionality.', 'theme-check' ), '<strong>' . esc_html( $hook ) . '</strong>', esc_html( $type ) );
70
+ $ret = false;
71
+ }
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Check for removal of non presentational hooks.
77
+ * Removing emojis is also not allowed.
78
+ */
79
+ $blacklist = array(
80
+ 'wp_head' => array(
81
+ 'wp_generator', // @link https://developer.wordpress.org/reference/functions/wp_generator/
82
+ 'feed_links', // @link https://developer.wordpress.org/reference/functions/feed_links/
83
+ 'feed_links_extra', // @link https://developer.wordpress.org/reference/functions/feed_links_extra/
84
+ 'print_emoji_detection_script', // @link https://developer.wordpress.org/reference/functions/print_emoji_detection_script/
85
+ 'wp_resource_hints', // @link https://developer.wordpress.org/reference/functions/wp_resource_hints/
86
+ 'adjacent_posts_rel_link_wp_head', // @link https://developer.wordpress.org/reference/functions/adjacent_posts_rel_link_wp_head/
87
+ 'wp_shortlink_wp_head', // @link https://developer.wordpress.org/reference/functions/wp_shortlink_wp_head/
88
+ '_admin_bar_bump_cb', // @link https://developer.wordpress.org/reference/functions/_admin_bar_bump_cb/
89
+ 'rsd_link', // @link https://developer.wordpress.org/reference/functions/rsd_link/
90
+ 'rest_output_link_wp_head', // @link https://developer.wordpress.org/reference/functions/rest_output_link_wp_head/
91
+ 'wp_oembed_add_discovery_links', // @link https://developer.wordpress.org/reference/functions/wp_oembed_add_discovery_links/
92
+ 'wp_oembed_add_host_js', // @link https://developer.wordpress.org/reference/functions/wp_oembed_add_host_js/
93
+ 'rel_canonical', // @link https://developer.wordpress.org/reference/functions/rel_canonical/
94
+ ),
95
+ 'wp_print_styles' => array(
96
+ 'print_emoji_styles', // @link https://developer.wordpress.org/reference/functions/print_emoji_styles/
97
+ ),
98
+ 'admin_print_scripts' => array(
99
+ 'print_emoji_detection_script', //@link https://developer.wordpress.org/reference/functions/print_emoji_detection_script/
100
+ ),
101
+ 'admin_print_styles' => array(
102
+ 'print_emoji_styles', // @link https://developer.wordpress.org/reference/functions/print_emoji_styles/
103
+ ),
104
+ 'template_redirect' => array(
105
+ 'rest_output_link_header', // @link https://developer.wordpress.org/reference/functions/rest_output_link_header/
106
+ 'wp_shortlink_header', // @link https://developer.wordpress.org/reference/functions/wp_shortlink_header/
107
+ 'redirect_canonical', // @link https://developer.wordpress.org/reference/functions/redirect_canonical/
108
+ ),
109
+ );
110
+
111
+ foreach ( $blacklist as $hook => $functions ) {
112
+ foreach ( $functions as $function ) {
113
+ checkcount();
114
+ if ( preg_match( '/[\s?]remove_action\s*\(\s*([\'"])' . $hook . '([\'"])\s*,\s*([\'"])' . $function . '([\'"])/', $php ) ) {
115
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'The theme uses <strong>remove_action %1$s %2$s</strong>, which is plugin-territory functionality.', 'theme-check' ),
116
+ esc_html( $hook ),
117
+ esc_html( $function )
118
+ );
119
+ $ret = false;
120
+ }
121
+ }
122
  }
123
 
124
  return $ret;
125
  }
126
 
127
+ /**
128
+ * Get error messages from the checks.
129
+ *
130
+ * @return array Error message.
131
+ */
132
+ public function getError() {
133
+ return $this->error;
134
+ }
135
  }
136
+
137
+ $themechecks[] = new Plugin_Territory();
checks/screenshot.php CHANGED
@@ -18,13 +18,15 @@ class Screenshot_Checks implements themecheck {
18
  foreach ( $other_files as $other_key => $otherfile ) {
19
 
20
  if ( ( basename( $other_key ) === 'screenshot.png' || basename( $other_key ) === 'screenshot.jpg' ) && preg_match( '/.*themes\/[^\/]*\/screenshot\.(png|jpg)/', $other_key ) ) {
21
- // we have or screenshot!
22
  $image = getimagesize( $other_key );
23
  if ( $image[0] > 1200 || $image[1] > 900 ) {
24
- $this->error[] = sprintf('<span class="tc-lead tc-recommended">'. __( 'RECOMMENDED','theme-check' ) . '</span>: ' . __( 'Screenshot is wrong size! Detected: %1$sx%2$spx. Maximum allowed size is 1200x900px.', 'theme-check' ), '<strong>' . $image[0], $image[1] . '</strong>' );
 
25
  }
26
  if ( $image[1] / $image[0] != 0.75 ) {
27
- $this->error[] = '<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('Screenshot dimensions are wrong! Ratio of width to height should be 4:3.', 'theme-check');
 
28
  }
29
  if ( $image[0] != 1200 || $image[1] != 900 ) {
30
  $this->error[] = '<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('Screenshot size should be 1200x900, to account for HiDPI displays. Any 4:3 image size is acceptable, but 1200x900 is preferred.', 'theme-check');
@@ -32,7 +34,7 @@ class Screenshot_Checks implements themecheck {
32
  }
33
  }
34
  } else {
35
- $this->error[] = '<span class="tc-lead tc-warning">'.__('WARNING','theme-check').'</span>: '.__('No screenshot detected! Please include a screenshot.png or screenshot.jpg.', 'theme-check' );
36
  $ret = false;
37
  }
38
  return $ret;
18
  foreach ( $other_files as $other_key => $otherfile ) {
19
 
20
  if ( ( basename( $other_key ) === 'screenshot.png' || basename( $other_key ) === 'screenshot.jpg' ) && preg_match( '/.*themes\/[^\/]*\/screenshot\.(png|jpg)/', $other_key ) ) {
21
+ // we have our screenshot!
22
  $image = getimagesize( $other_key );
23
  if ( $image[0] > 1200 || $image[1] > 900 ) {
24
+ $this->error[] = sprintf('<span class="tc-lead tc-required">'. __( 'REQUIRED','theme-check' ) . '</span>: ' . __( 'Screenshot is wrong size! Detected: %1$sx%2$spx. Maximum allowed size is 1200x900px.', 'theme-check' ), '<strong>' . $image[0], $image[1] . '</strong>' );
25
+ $ret = false;
26
  }
27
  if ( $image[1] / $image[0] != 0.75 ) {
28
+ $this->error[] = '<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('Screenshot dimensions are wrong! Ratio of width to height should be 4:3.', 'theme-check');
29
+ $ret = false;
30
  }
31
  if ( $image[0] != 1200 || $image[1] != 900 ) {
32
  $this->error[] = '<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('Screenshot size should be 1200x900, to account for HiDPI displays. Any 4:3 image size is acceptable, but 1200x900 is preferred.', 'theme-check');
34
  }
35
  }
36
  } else {
37
+ $this->error[] = '<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('No screenshot detected! Please include a screenshot.png or screenshot.jpg.', 'theme-check' );
38
  $ret = false;
39
  }
40
  return $ret;
checks/siteurl.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php // phpcs:ignore WordPress.Files.FileName
2
+ /**
3
+ * Checks if site_url is used, and adds an info.
4
+ *
5
+ * @link https://developer.wordpress.org/reference/functions/site_url/
6
+ */
7
+
8
+ /**
9
+ * Check for site_url
10
+ */
11
+ class SiteUrlCheck implements themecheck {
12
+ /**
13
+ * Error messages, warnings and info notices.
14
+ *
15
+ * @var array $error
16
+ */
17
+ protected $error = array();
18
+
19
+ /**
20
+ * Check that return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
21
+ *
22
+ * @param array $php_files File paths and content for PHP files.
23
+ * @param array $css_files File paths and content for CSS files.
24
+ * @param array $other_files Folder names, file paths and content for other files.
25
+ */
26
+ public function check( $php_files, $css_files, $other_files ) {
27
+
28
+ $ret = true;
29
+
30
+ checkcount();
31
+ foreach ( $php_files as $file_path => $file_content ) {
32
+ $filename = tc_filename( $file_path );
33
+
34
+ if ( strpos( $file_content, 'site_url' ) !== false ) {
35
+ $this->error[] = sprintf(
36
+ '<span class="tc-lead tc-info">' . __( 'INFO', 'theme-check' ) . '</span>: ' . __( 'site_url() or get_site_url() was found in %1$s. site_url() references the URL where the WordPress files are located. Use home_url() if the intention is to point to the site address (home page), and in the search form.', 'theme-check' ),
37
+ '<strong>' . $filename . '</strong>'
38
+ );
39
+ }
40
+ }
41
+ return $ret;
42
+ }
43
+
44
+ /**
45
+ * Get error messages from the checks.
46
+ *
47
+ * @return array Error message.
48
+ */
49
+ public function getError() {
50
+ return $this->error;
51
+ }
52
+ }
53
+
54
+ $themechecks[] = new SiteUrlCheck();
checks/style_needed.php CHANGED
@@ -15,6 +15,8 @@ class Style_Needed implements themecheck {
15
  '[ \t\/*#]*License:' => __( '<strong>License:</strong> is missing from your style.css header.', 'theme-check' ),
16
  '[ \t\/*#]*License URI:' => __( '<strong>License URI:</strong> is missing from your style.css header.', 'theme-check' ),
17
  '[ \t\/*#]*Text Domain:' => __( '<strong>Text Domain:</strong> is missing from your style.css header.', 'theme-check' ),
 
 
18
  '\.sticky' => __( '<strong>.sticky</strong> css class is needed in your theme css.', 'theme-check' ),
19
  '\.bypostauthor' => __( '<strong>.bypostauthor</strong> css class is needed in your theme css.', 'theme-check' ),
20
  '\.alignleft' => __( '<strong>.alignleft</strong> css class is needed in your theme css.', 'theme-check' ),
15
  '[ \t\/*#]*License:' => __( '<strong>License:</strong> is missing from your style.css header.', 'theme-check' ),
16
  '[ \t\/*#]*License URI:' => __( '<strong>License URI:</strong> is missing from your style.css header.', 'theme-check' ),
17
  '[ \t\/*#]*Text Domain:' => __( '<strong>Text Domain:</strong> is missing from your style.css header.', 'theme-check' ),
18
+ '[ \t\/*#]*Tested up to:' => __( '<strong>Tested up to:</strong> is missing from your style.css header. Also, this should be numbers only, so <em>5.0</em> and not <em>WP 5.0</em>', 'theme-check' ),
19
+ '[ \t\/*#]*Requires PHP:' => __( '<strong>Requires PHP:</strong> is missing from your style.css header.', 'theme-check' ),
20
  '\.sticky' => __( '<strong>.sticky</strong> css class is needed in your theme css.', 'theme-check' ),
21
  '\.bypostauthor' => __( '<strong>.bypostauthor</strong> css class is needed in your theme css.', 'theme-check' ),
22
  '\.alignleft' => __( '<strong>.alignleft</strong> css class is needed in your theme css.', 'theme-check' ),
checks/style_tags.php CHANGED
@@ -9,51 +9,55 @@ class Style_Tags implements themecheck {
9
  $filenames = array();
10
 
11
  foreach( $css_files as $cssfile => $content ) {
12
- if ( basename( $cssfile ) === 'style.css' ) $data = get_theme_data_from_contents( $content );
13
- }
14
 
15
- if ( !$data[ 'Tags' ] ) {
16
- $this->error[] = '<span class="tc-lead tc-recommended">' . __('RECOMMENDED','theme-check') . '</span>: ' . __( '<strong>Tags:</strong> is either empty or missing in style.css header.', 'theme-check' );
17
- return $ret;
18
- }
19
- $deprecated_tags = array("flexible-width","fixed-width","black","blue","brown","gray","green","orange","pink","purple","red","silver","tan","white","yellow","dark","light","fixed-layout","fluid-layout","responsive-layout","blavatar","holiday","photoblogging","seasonal");
20
- $allowed_tags = array('grid-layout',"one-column","two-columns","three-columns","four-columns","left-sidebar","right-sidebar","wide-blocks","flexible-header",'footer-widgets',"accessibility-ready","block-styles","buddypress","custom-background","custom-colors","custom-header","custom-menu","custom-logo","editor-style","featured-image-header","featured-images","front-page-post-form","full-width-template","microformats","post-formats","rtl-language-support","sticky-post","theme-options","threaded-comments","translation-ready",'blog','e-commerce','education','entertainment','food-and-drink','holiday','news','photography','portfolio');
21
- $subject_tags = array('blog','e-commerce','education','entertainment','food-and-drink','holiday','news','photography','portfolio');
22
- $subject_tags_count = 0;
23
- $subject_tags_name = "";
 
24
 
25
- foreach( $data[ 'Tags' ] as $tag ) {
26
 
27
- if ( strpos( strtolower( $tag ), "accessibility-ready") !== false ) {
28
- $this->error[] = '<span class="tc-lead tc-info">'. __('INFO','theme-check'). '</span>: ' . __( 'Themes that use the tag accessibility-ready will need to undergo an accessibility review.','theme-check' ) . ' ' . __('See <a href="https://make.wordpress.org/themes/handbook/review/accessibility/">https://make.wordpress.org/themes/handbook/review/accessibility/</a>', 'theme-check' );
29
- }
30
 
31
- if ( ! in_array( strtolower( $tag ), $allowed_tags ) ) {
32
- if ( in_array( strtolower( $tag ), $deprecated_tags ) ) {
33
- $this->error[] = '<span class="tc-lead tc-warning">'. __('WARNING','theme-check'). '</span>: ' . sprintf( __('The tag %s has been deprecated, please remove it from your style.css header.', 'theme-check'), '<strong>' . $tag . '</strong>' );
34
- } else {
35
- $this->error[] = '<span class="tc-lead tc-warning">'. __('WARNING','theme-check'). '</span>: ' . sprintf( __('Found wrong tag, remove %s from your style.css header.', 'theme-check'), '<strong>' . $tag . '</strong>' );
36
- $ret = false;
37
- }
38
- }
 
39
 
40
- if ( in_array( strtolower( $tag ), $subject_tags ) ) {
41
- $subject_tags_name .= strtolower( $tag ) . ', ';
42
- $subject_tags_count++;
43
- }
 
 
 
 
 
 
 
 
44
 
45
- if ( in_array( strtolower( $tag ), $allowed_tags ) ) {
46
- if ( count( array_keys ($data[ 'Tags' ], $tag ) ) > 1) {
47
- $this->error[] = '<span class="tc-lead tc-required">'. __('REQUIRED','theme-check'). '</span>: ' . sprintf( __('The tag %s is being used more than once, please remove it from your style.css header.', 'theme-check'), '<strong>' . $tag . '</strong>' );
48
- $ret = false;
49
  }
50
  }
51
-
52
- }
53
-
54
- if ( $subject_tags_count > 3 ) {
55
- $this->error[] = '<span class="tc-lead tc-required">'. __('REQUIRED','theme-check'). '</span>: ' . sprintf( __('A maximum of 3 subject tags are allowed. The theme has %1$u subjects tags ( %2$s ). Please remove the subject tags, which do not directly apply to the theme.', 'theme-check'), $subject_tags_count, '<strong>' . rtrim( $subject_tags_name, ', ' ) . '</strong>' ) . ' ' . '<a target="_blank" href="https://make.wordpress.org/themes/handbook/review/required/theme-tags/">' . __( 'See Theme Tags', 'theme-check' ) . '</a>';
56
- $ret = false;
57
  }
58
 
59
  return $ret;
9
  $filenames = array();
10
 
11
  foreach( $css_files as $cssfile => $content ) {
12
+ if ( basename( $cssfile ) === 'style.css' ) {
13
+ $data = get_theme_data_from_contents( $content );
14
 
15
+ if ( !$data[ 'Tags' ] ) {
16
+ $this->error[] = '<span class="tc-lead tc-recommended">' . __('RECOMMENDED','theme-check') . '</span>: ' . __( '<strong>Tags:</strong> is either empty or missing in style.css header.', 'theme-check' )
17
+ . ' ('. basename( dirname( $cssfile)) . ')';
18
+ }
19
+ else {
20
+ $deprecated_tags = array("flexible-width","fixed-width","black","blue","brown","gray","green","orange","pink","purple","red","silver","tan","white","yellow","dark","light","fixed-layout","fluid-layout","responsive-layout","blavatar","holiday","photoblogging","seasonal");
21
+ $allowed_tags = array('grid-layout',"one-column","two-columns","three-columns","four-columns","left-sidebar","right-sidebar","wide-blocks","flexible-header",'footer-widgets',"accessibility-ready","block-styles","buddypress","custom-background","custom-colors","custom-header","custom-menu","custom-logo","editor-style","featured-image-header","featured-images","front-page-post-form","full-width-template","microformats","post-formats","rtl-language-support","sticky-post","theme-options","threaded-comments","translation-ready",'blog','e-commerce','education','entertainment','food-and-drink','holiday','news','photography','portfolio');
22
+ $subject_tags = array('blog','e-commerce','education','entertainment','food-and-drink','holiday','news','photography','portfolio');
23
+ $subject_tags_count = 0;
24
+ $subject_tags_name = "";
25
 
26
+ foreach( $data[ 'Tags' ] as $tag ) {
27
 
28
+ if ( strpos( strtolower( $tag ), "accessibility-ready") !== false ) {
29
+ $this->error[] = '<span class="tc-lead tc-info">'. __('INFO','theme-check'). '</span>: ' . __( 'Themes that use the tag accessibility-ready will need to undergo an accessibility review.','theme-check' ) . ' ' . __('See <a href="https://make.wordpress.org/themes/handbook/review/accessibility/">https://make.wordpress.org/themes/handbook/review/accessibility/</a>', 'theme-check' );
30
+ }
31
 
32
+ if ( ! in_array( strtolower( $tag ), $allowed_tags ) ) {
33
+ if ( in_array( strtolower( $tag ), $deprecated_tags ) ) {
34
+ $this->error[] = '<span class="tc-lead tc-required">'. __('REQUIRED','theme-check'). '</span>: ' . sprintf( __('The tag %s has been deprecated, please remove it from your style.css header.', 'theme-check'), '<strong>' . $tag . '</strong>' );
35
+ $ret = false;
36
+ } else {
37
+ $this->error[] = '<span class="tc-lead tc-required">'. __('REQUIRED','theme-check'). '</span>: ' . sprintf( __('Found wrong tag, remove %s from your style.css header.', 'theme-check'), '<strong>' . $tag . '</strong>' );
38
+ $ret = false;
39
+ }
40
+ }
41
 
42
+ if ( in_array( strtolower( $tag ), $subject_tags ) ) {
43
+ $subject_tags_name .= strtolower( $tag ) . ', ';
44
+ $subject_tags_count++;
45
+ }
46
+
47
+ if ( in_array( strtolower( $tag ), $allowed_tags ) ) {
48
+ if ( count( array_keys ($data[ 'Tags' ], $tag ) ) > 1) {
49
+ $this->error[] = '<span class="tc-lead tc-required">'. __('REQUIRED','theme-check'). '</span>: ' . sprintf( __('The tag %s is being used more than once, please remove it from your style.css header.', 'theme-check'), '<strong>' . $tag . '</strong>' );
50
+ $ret = false;
51
+ }
52
+ }
53
+ }
54
 
55
+ if ( $subject_tags_count > 3 ) {
56
+ $this->error[] = '<span class="tc-lead tc-required">'. __('REQUIRED','theme-check'). '</span>: ' . sprintf( __('A maximum of 3 subject tags are allowed. The theme has %1$u subjects tags ( %2$s ). Please remove the subject tags, which do not directly apply to the theme.', 'theme-check'), $subject_tags_count, '<strong>' . rtrim( $subject_tags_name, ', ' ) . '</strong>' ) . ' ' . '<a target="_blank" href="https://make.wordpress.org/themes/handbook/review/required/theme-tags/">' . __( 'See Theme Tags', 'theme-check' ) . '</a>';
57
+ $ret = false;
58
+ }
59
  }
60
  }
 
 
 
 
 
 
61
  }
62
 
63
  return $ret;
checks/textdomain.php CHANGED
@@ -140,7 +140,7 @@ class TextDomainCheck implements themecheck {
140
  }
141
 
142
  if ( $domainscount > 1 ) {
143
- $this->error[] = '<span class="tc-lead tc-warning">' . __( 'Warning', 'theme-check' ) . '</span>: '
144
  . __( 'More than one text-domain is being used in this theme. This means the theme will not be compatible with WordPress.org language packs.', 'theme-check' )
145
  . '<br>'
146
  . sprintf( __( 'The domains found are %s', 'theme-check'), '<strong>' . $domainlist . '</strong>' );
140
  }
141
 
142
  if ( $domainscount > 1 ) {
143
+ $this->error[] = '<span class="tc-lead tc-warning">' . __( 'WARNING', 'theme-check' ) . '</span>: '
144
  . __( 'More than one text-domain is being used in this theme. This means the theme will not be compatible with WordPress.org language packs.', 'theme-check' )
145
  . '<br>'
146
  . sprintf( __( 'The domains found are %s', 'theme-check'), '<strong>' . $domainlist . '</strong>' );
checks/title.php CHANGED
@@ -5,49 +5,59 @@
5
  * Is there a call to wp_title()?
6
  * There can't be any hardcoded text in the <title> tag.
7
  *
8
- * See: http://make.wordpress.org/themes/guidelines/guidelines-theme-check/
9
  */
10
  class Title_Checks implements themecheck {
11
- protected $error = array();
12
 
13
  function check( $php_files, $css_files, $other_files ) {
14
  $ret = true;
15
  $php = implode( ' ', $php_files );
16
 
17
- // Look for add_theme_support( 'title-tag' ) first
18
  $titletag = true;
19
  if ( ! preg_match( '#add_theme_support\s?\(\s?[\'|"]title-tag#', $php ) ) {
20
- $this->error[] = '<span class="tc-lead tc-required">'.__('REQUIRED','theme-check').'</span>: '.__('No reference to <strong>add_theme_support( "title-tag" )</strong> was found in the theme.', 'theme-check' );
21
- $titletag = false;
22
- $ret = false;
23
  }
24
 
25
- // Look for <title> and </title> tags.
26
- checkcount();
27
- if ( ( 0 <= strpos( $php, '<title>' ) || 0 <= strpos( $php, '</title>' ) ) && !$titletag ) {
28
- $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check').'</span>: ' . __( 'The theme must not used the <strong>&lt;title&gt;</strong> tags.', 'theme-check' );
29
- $ret = false;
30
- }
31
 
32
- // Check whether there is a call to wp_title()
33
- checkcount();
34
- if ( 0 <= strpos( $php, 'wp_title(' ) && !$titletag ) {
35
- $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check').'</span>: ' . __( 'The theme must not call to <strong>wp_title()</strong>.', 'theme-check' );
36
- $ret = false;
37
- }
38
 
39
- //Check whether the the <title> tag contains something besides a call to wp_title()
40
- checkcount();
 
 
 
 
 
 
41
 
42
- foreach ( $php_files as $file_path => $file_content ) {
43
- // Look for anything that looks like <svg>...</svg> and exclude it (inline svg's have titles too)
44
- $file_content = preg_replace('/<svg.*>.*<\/svg>/s', '', $file_content);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
- // First looks ahead to see of there's <title>...</title>
47
- // Then performs a negative look ahead for <title> wp_title(...); </title>
48
  if ( preg_match( '/(?=<title>(.*)<\/title>)(?!<title>\s*<\?php\s*wp_title\([^\)]*\);?\s*\?>\s*<\/title>)/s', $file_content ) ) {
49
- $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check').'</span>: ' . __( 'The <strong>&lt;title&gt;</strong> tags can only contain a call to <strong>wp_title()</strong>. Use the <strong>wp_title filter</strong> to modify the output', 'theme-check' );
50
- $ret = false;
 
 
51
  }
52
  }
53
 
@@ -57,4 +67,4 @@ class Title_Checks implements themecheck {
57
  function getError() { return $this->error; }
58
  }
59
 
60
- $themechecks[] = new Title_Checks;
5
  * Is there a call to wp_title()?
6
  * There can't be any hardcoded text in the <title> tag.
7
  *
8
+ * See: https://make.wordpress.org/themes/handbook/review/required/theme-check-plugin/
9
  */
10
  class Title_Checks implements themecheck {
11
+ protected $error = array();
12
 
13
  function check( $php_files, $css_files, $other_files ) {
14
  $ret = true;
15
  $php = implode( ' ', $php_files );
16
 
17
+ // Look for add_theme_support( 'title-tag' ) first.
18
  $titletag = true;
19
  if ( ! preg_match( '#add_theme_support\s?\(\s?[\'|"]title-tag#', $php ) ) {
20
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . __( 'No reference to <strong>add_theme_support( "title-tag" )</strong> was found in the theme.', 'theme-check' );
21
+ $titletag = false;
22
+ $ret = false;
23
  }
24
 
25
+ foreach ( $php_files as $file_path => $file_content ) {
 
 
 
 
 
26
 
27
+ $filename = tc_filename( $file_path );
 
 
 
 
 
28
 
29
+ // Look for <title> and </title> tags.
30
+ checkcount();
31
+ if ( ( 0 <= strpos( $php, '<title>' ) || 0 <= strpos( $php, '</title>' ) ) && ! $titletag ) {
32
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'The theme must not use the <strong>&lt;title&gt;</strong> tags. Found the tag in %1$s.', 'theme-check' ),
33
+ '<strong>' . $filename . '</strong>'
34
+ );
35
+ $ret = false;
36
+ }
37
 
38
+ // Check whether there is a call to wp_title().
39
+ checkcount();
40
+ if ( 0 <= strpos( $php, 'wp_title(' ) && ! $titletag ) {
41
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check' ) . '</span>: ' . sprintf( __( 'The theme must not call to <strong>wp_title()</strong>. Found wp_title() in %1$s.', 'theme-check' ),
42
+ '<strong>' . $filename . '</strong>'
43
+ );
44
+ $ret = false;
45
+ }
46
+
47
+ // Check whether the the <title> tag contains something besides a call to wp_title().
48
+ checkcount();
49
+ // Look for anything that looks like <svg>...</svg> and exclude it (inline svg's have titles too).
50
+ $file_content = preg_replace( '/<svg.*>.*<\/svg>/s', '', $file_content );
51
+ // First looks ahead to see of there's <title>...</title>.
52
+ // Then performs a negative look ahead for <title> wp_title(...); </title>.
53
+ $error = '/<title>/';
54
+ $grep = tc_preg( $error, $file_path );
55
 
 
 
56
  if ( preg_match( '/(?=<title>(.*)<\/title>)(?!<title>\s*<\?php\s*wp_title\([^\)]*\);?\s*\?>\s*<\/title>)/s', $file_content ) ) {
57
+ $this->error[] = '<span class="tc-lead tc-required">' . __( 'REQUIRED', 'theme-check').'</span>: ' . sprintf( __( '%1$s: The <strong>&lt;title&gt;</strong> tags can only contain a call to <strong>wp_title()</strong>. Use the <strong>wp_title filter</strong> to modify the output.', 'theme-check' ),
58
+ '<strong>' . $filename . '</strong>'
59
+ ) . $grep;
60
+ $ret = false;
61
  }
62
  }
63
 
67
  function getError() { return $this->error; }
68
  }
69
 
70
+ $themechecks[] = new Title_Checks();
checks/underscores.php ADDED
@@ -0,0 +1,57 @@