Theme Check - Version 20210921

Version Description

Download this release

Release Info

Developer githubsync
Plugin Icon 128x128 Theme Check
Version 20210921
Comparing to
See all releases

Code changes from version 20210617 to 20210921

CONTRIBUTING.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # Contributing code
3
+
4
+ To submit pull requests, please first [fork the repository](https://help.github.com/articles/fork-a-repo/).
5
+
6
+ On your fork, create a new branch and add your changes to that branch.
7
+
8
+ Submit a [pull request](https://help.github.com/articles/creating-a-pull-request/) from your updated branch to the Theme Check repository.
9
+
10
+ In your pull request's description, please explain your update and reference the associated issue you're fixing.
11
+ Include testing instructions.
12
+
13
+ After you send your proposed changes, one of the maintainers will test and review the pull request. After it's reviewed and the changes are accepted by at least one of the maintainers, someone will merge the pull request.
14
+
15
+ ## Testing your code
16
+
17
+ You can use Composer to install PHP CodeSniffer and test your code against the WordPress coding standards.
18
+
19
+ https://getcomposer.org/
20
+
21
+ ### Commands
22
+
23
+ Install the dependencies:
24
+ `composer install`
25
+
26
+ Check the code:
27
+ `composer standards:check`
28
+
29
+ Automated fixes:
30
+ `composer standards:fix`
31
+
32
+ # Contributing to issues
33
+
34
+ GitHub issues are how we track changes to the plugin that need to be discussed and completed.
35
+ Ideally, all changes are broken down into issues that can be addressed by discussion or a pull request.
36
+
37
+ Before creating an issue, please search the existing issues to see if it has been discussed before. If not, create an issue and the maintainers will add labels as appropriate.
38
+
39
+ Issues should be descriptive but not too long. Use text, screenshots, and screen recordings to communicate the issue.
40
+
41
+ # Reviewing pull requests
42
+
43
+ All code changes happen through a pull request made by contributors, ideally associated with an issue.
44
+
45
+ If you're not already using Git, you may benefit from installing the [GitHub desktop application.](https://desktop.github.com)
46
+
47
+ This will allow you to download the repository in one click, keep it in sync, and easily switch between different pull requests.
48
+
49
+ Once a pull request is selected in the application, create a zip file of the whole repository, and upload it to your site to test.
50
+
51
+ Otherwise, you can test a pull request by pulling down the associated branch, creating a zip file of the contents, and uploading to your WordPress site via the admin. This repository includes all files, so it will install just like any other uploaded plugin.
52
+
53
+ Once you've tested and reviewed, please report your findings by adding a review or comment to the pull request on GitHub.
changelog.txt CHANGED
@@ -1,3 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 20200922.1 =
2
  * Reformatting of main.php and checkbase.php
3
  * Additions to malware checks in badthings.php
1
+ = 20210921 =
2
+ * Fix: `tc_filename()` to always return theme-relative paths when possible.
3
+ * Fix: Correct the block theme adaptation check to work in WordPress.org Theme Uploader
4
+ * Fix: Update the texts of the script tag check and the WP_Filesystem check.
5
+ * Fix: Allow pre, link and code tags when presenting the result.
6
+ * Fix: Allow phpcs.xml and development tool configuration files (postcss, stylelint etc).
7
+ * Fix: Correct the theme information display on the plugin page.
8
+ * Fix: Add template-editing to the list of allowed tags.
9
+ * Fix: Solve PHP notice in the i18n check.
10
+ * Reduce the severity level of the following checks:
11
+ Favicon, wp_title, title tag
12
+ * Added checks:
13
+ Requires PHP versioning, Tested up to versioning, add_role, copyright notice
14
+ * Removed checks:
15
+ content_width, Theme URI and Author URI must not be the same, emoji scripts
16
+
17
+ = 20210617 =
18
+ * Introduced a generic function, run_themechecks_against_theme(), that allows it to be run against a WP_Theme instance, rather than relying upon global state
19
+ * Adapted checks for block themes. Create a list of the checks that are skipped for block themes (full site editing themes)
20
+ * Fix: Avoid false positives in title checks
21
+ * Fix invalid regular expression in the customizer check
22
+ * Fix: Avoid false positives when .svn/.git/.hg/.bzr exists within the path to a theme
23
+ * Fix: Allow .map files
24
+ * Fix Non GPL sites check: Adjust the unsplash text, add vecteezy and update a link for undraw that was not correct
25
+ * Fixed a bug where all the theme information was not showing on the plugins admin page
26
+ * Added a check for files required by block themes
27
+ * Added checks for block patterns and block styles
28
+ * Added checks for custom logo, html5, responsive embeds, align-wide, wp-block-styles
29
+ * Split the Style_Needed check into two: Screen_Reader_Text_Check and Style_CSS_Header_Check
30
+ * Split the Title_Checks into two: Title_Check and Theme_Support_Title_Tag_Check
31
+ * Removed warnings about file_get_contents() and encourages it's usage over WP_Filesystem for general IO operations
32
+ * New error message for HTTP methods, to use the WordPress HTTP library instead
33
+ * Removed dep_recommended.php and moved items into class-deprecated-check.php
34
+ * Removed unused code from the file names check
35
+ * Codestyle improvements, including new file names for checks
36
+ * Reduce the severity level of the following checks:
37
+ Admin menu, comments, comment reply, content width, gravatar, pagination, post formats,
38
+ script tag, search form, suggested styles, tags
39
+
40
  = 20200922.1 =
41
  * Reformatting of main.php and checkbase.php
42
  * Additions to malware checks in badthings.php
checkbase.php CHANGED
@@ -16,6 +16,10 @@ $themechecks = array();
16
  global $checkcount;
17
  $checkcount = 0;
18
 
 
 
 
 
19
  // interface that all checks should implement.
20
  interface themecheck {
21
 
@@ -46,7 +50,11 @@ function run_themechecks_against_theme( $theme, $theme_slug ) {
46
  -1 /* infinite recursion */,
47
  true /* include parent theme files */
48
  );
 
49
 
 
 
 
50
  foreach ( $files as $filename ) {
51
  if ( substr( $filename, -4 ) === '.php' ) {
52
  $php[ $filename ] = file_get_contents( $filename );
@@ -88,7 +96,10 @@ function run_themechecks_against_theme( $theme, $theme_slug ) {
88
  * @return bool
89
  */
90
  function run_themechecks( $php, $css, $other, $context = array() ) {
91
- global $themechecks;
 
 
 
92
 
93
  $pass = true;
94
 
@@ -104,6 +115,8 @@ function run_themechecks( $php, $css, $other, $context = array() ) {
104
  }
105
  }
106
 
 
 
107
  return $pass;
108
  }
109
 
@@ -202,8 +215,50 @@ function tc_preg( $preg, $file ) {
202
  }
203
 
204
  function tc_filename( $file ) {
205
- $filename = ( preg_match( '/themes\/[a-z0-9-]*\/(.*)/', $file, $out ) ) ? $out[1] : basename( $file );
206
- return $filename;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  }
208
 
209
  function tc_trac( $e ) {
16
  global $checkcount;
17
  $checkcount = 0;
18
 
19
+ // current WP_Theme being tested. Internal use only.
20
+ global $theme_check_current_theme;
21
+ $theme_check_current_theme = false;
22
+
23
  // interface that all checks should implement.
24
  interface themecheck {
25
 
50
  -1 /* infinite recursion */,
51
  true /* include parent theme files */
52
  );
53
+ unset( $files[0] ); // Work around https://core.trac.wordpress.org/ticket/53599
54
 
55
+ $php = array();
56
+ $css = array();
57
+ $other = array();
58
  foreach ( $files as $filename ) {
59
  if ( substr( $filename, -4 ) === '.php' ) {
60
  $php[ $filename ] = file_get_contents( $filename );
96
  * @return bool
97
  */
98
  function run_themechecks( $php, $css, $other, $context = array() ) {
99
+ global $themechecks, $theme_check_current_theme;
100
+
101
+ // Provide context to some functions that need to know the current theme, but aren't passed the object.
102
+ $theme_check_current_theme = isset( $context['theme'] ) ? $context['theme'] : false;
103
 
104
  $pass = true;
105
 
115
  }
116
  }
117
 
118
+ $theme_check_current_theme = false;
119
+
120
  return $pass;
121
  }
122
 
215
  }
216
 
217
  function tc_filename( $file ) {
218
+ // If we know the WP_Theme object, we can get the exact path.
219
+ $filename = _get_filename_from_current_theme( $file );
220
+ if ( $filename ) {
221
+ return $filename;
222
+ }
223
+
224
+ // If the $file exists within a theme-like folder, use that.
225
+ // Does not support themes nested in directories such as wp-content/themes/pub/wporg-themes/index.php
226
+ if ( preg_match( '!/themes/[^/]+/(.*)$!i', $file, $m ) ) {
227
+ return $m[1];
228
+ }
229
+
230
+ // If still nothing, use the basename.
231
+ return basename( $file );
232
+ }
233
+
234
+ /**
235
+ * Get a filename relative to the current theme.
236
+ *
237
+ * @param string $file the file to get a relative filename for.
238
+ * @return false|string The filename, or false on failure.
239
+ * @access private
240
+ */
241
+ function _get_filename_from_current_theme( $file ) {
242
+ global $theme_check_current_theme;
243
+ static $theme_files = array();
244
+ static $theme_path = '';
245
+
246
+ if ( empty( $theme_check_current_theme ) ) {
247
+ return false;
248
+ }
249
+
250
+ // Fetch the files for the theme, once per theme.
251
+ if ( $theme_path != $theme_check_current_theme->get_stylesheet_directory() ) {
252
+ $theme_path = $theme_check_current_theme->get_stylesheet_directory();
253
+
254
+ $theme_files = $theme_check_current_theme->get_files(
255
+ null /* all file types */,
256
+ -1 /* infinite recursion */,
257
+ true /* include parent theme files */
258
+ );
259
+ }
260
+
261
+ return array_search( $file, $theme_files, true );
262
  }
263
 
264
  function tc_trac( $e ) {
checks/class-copyright-notice-check.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Checks if the theme has a copyright notice.
4
+ *
5
+ * @package Theme Check
6
+ */
7
+
8
+ /**
9
+ * Checks if the theme has a copyright notice.
10
+ */
11
+ class Copyright_Notice_Check implements themecheck {
12
+ /**
13
+ * Error messages, warnings and info notices.
14
+ *
15
+ * @var array $error
16
+ */
17
+ protected $error = array();
18
+
19
+ function set_context( $data ) {
20
+ if ( isset( $data['slug'] ) ) {
21
+ $this->slug = $data['slug'];
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Check that return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
27
+ *
28
+ * @param array $php_files File paths and content for PHP files.
29
+ * @param array $css_files File paths and content for CSS files.
30
+ * @param array $other_files Folder names, file paths and content for other files.
31
+ */
32
+ public function check( $php_files, $css_files, $other_files ) {
33
+
34
+ // Get a list of file names and check for the readme, license.txt and style.css.
35
+ $combined_files = $css_files + $other_files;
36
+ $content = '';
37
+
38
+ // Get the contents of themeslug/filename:
39
+ foreach ( $combined_files as $path => $contents ) {
40
+ if ( stripos( $path, $this->slug . '/readme.txt' ) ||
41
+ stripos( $path, $this->slug . '/readme.md' ) ||
42
+ stripos( $path, $this->slug . '/style.css' ) ||
43
+ stripos( $path, $this->slug . '/licence.txt' ) !== false ) {
44
+ $content .= $contents;
45
+ }
46
+ }
47
+
48
+ checkcount();
49
+
50
+ // Check for Copyright and (C) in the combined content of the selected files.
51
+ if ( ! preg_match( '/[ \t\/*#]*Copyright/i', $content, $matches ) && ! preg_match( '/[ \t\/*#]*\(C\)/i', $content, $matches ) ) {
52
+ $this->error[] = sprintf(
53
+ '<span class="tc-lead tc-warning">%s</span>: %s %s',
54
+ __( 'WARNING', 'theme-check' ),
55
+ __( 'Could not find a copyright notice for the theme. A copyright notice is needed if your theme is licenced as GPL.', 'theme-check' ),
56
+ '<a href="' . esc_url( 'https://www.gnu.org/licenses/gpl-howto.html' ) . '" target="_blank">' . __( 'Learn how to add a copyright notice (opens in a new window).', 'theme-check' ) . '</a>'
57
+ );
58
+ }
59
+
60
+ return true;
61
+ }
62
+
63
+ /**
64
+ * Get error messages from the checks.
65
+ *
66
+ * @return array Error message.
67
+ */
68
+ public function getError() {
69
+ return $this->error;
70
+ }
71
+ }
72
+
73
+ $themechecks[] = new Copyright_Notice_Check();
checks/class-deprecated-check.php CHANGED
@@ -26,7 +26,6 @@ class Deprecated_Check implements themecheck {
26
  public function check( $php_files, $css_files, $other_files ) {
27
 
28
  $grep = '';
29
- $ret = true;
30
 
31
  $checks = array(
32
  // Start wp-includes deprecated.
@@ -1176,16 +1175,14 @@ class Deprecated_Check implements themecheck {
1176
 
1177
  // Add the finalized error message.
1178
  $this->error[] = sprintf(
1179
- '<span class="tc-lead tc-required">%s</span>: %s',
1180
- __( 'REQUIRED', 'theme-check' ),
1181
  $error_msg
1182
  );
1183
-
1184
- $ret = false;
1185
  }
1186
  }
1187
  }
1188
- return $ret;
1189
  }
1190
 
1191
  /**
26
  public function check( $php_files, $css_files, $other_files ) {
27
 
28
  $grep = '';
 
29
 
30
  $checks = array(
31
  // Start wp-includes deprecated.
1175
 
1176
  // Add the finalized error message.
1177
  $this->error[] = sprintf(
1178
+ '<span class="tc-lead tc-warning">%s</span>: %s',
1179
+ __( 'WARNING', 'theme-check' ),
1180
  $error_msg
1181
  );
 
 
1182
  }
1183
  }
1184
  }
1185
+ return true;
1186
  }
1187
 
1188
  /**
checks/class-deprecated-param-check.php CHANGED
@@ -25,8 +25,6 @@ class Deprecated_Param_Check implements themecheck {
25
  */
26
  public function check( $php_files, $css_files, $other_files ) {
27
 
28
- $ret = true;
29
-
30
  $checks = array(
31
  'get_bloginfo' => array(
32
  'home' => 'home_url()',
@@ -66,8 +64,8 @@ class Deprecated_Param_Check implements themecheck {
66
  $error = ltrim( rtrim( $matches[0], '(' ) );
67
  $grep = tc_grep( $error, $php_key );
68
  $this->error[] = sprintf(
69
- '<span class="tc-lead tc-required">%s</span>: %s %s',
70
- __( 'REQUIRED', 'theme-check' ),
71
  sprintf(
72
  __( '%1$s was found in the file %2$s. Use %3$s instead.', 'theme-check' ),
73
  '<strong>' . $error . '</strong>',
@@ -76,13 +74,12 @@ class Deprecated_Param_Check implements themecheck {
76
  ),
77
  $grep
78
  );
79
- $ret = false;
80
  }
81
  }
82
  }
83
  }
84
 
85
- return $ret;
86
  }
87
 
88
  /**
25
  */
26
  public function check( $php_files, $css_files, $other_files ) {
27
 
 
 
28
  $checks = array(
29
  'get_bloginfo' => array(
30
  'home' => 'home_url()',
64
  $error = ltrim( rtrim( $matches[0], '(' ) );
65
  $grep = tc_grep( $error, $php_key );
66
  $this->error[] = sprintf(
67
+ '<span class="tc-lead tc-warning">%s</span>: %s %s',
68
+ __( 'WARNING', 'theme-check' ),
69
  sprintf(
70
  __( '%1$s was found in the file %2$s. Use %3$s instead.', 'theme-check' ),
71
  '<strong>' . $error . '</strong>',
74
  ),
75
  $grep
76
  );
 
77
  }
78
  }
79
  }
80
  }
81
 
82
+ return true;
83
  }
84
 
85
  /**
checks/class-favicon-check.php CHANGED
@@ -27,8 +27,6 @@ class Favicon_Check implements themecheck {
27
  */
28
  public function check( $php_files, $css_files, $other_files ) {
29
 
30
- $ret = true;
31
-
32
  checkcount();
33
 
34
  foreach ( $php_files as $file_path => $file_content ) {
@@ -40,17 +38,16 @@ class Favicon_Check implements themecheck {
40
  preg_match( '/(<meta name=[\'"]msapplication-TileImage[\'"])/i', $file_content )
41
  ) {
42
  $this->error[] = sprintf(
43
- '<span class="tc-lead tc-required">%s</span>: %s',
44
- __( 'REQUIRED', 'theme-check' ),
45
  sprintf(
46
  __( 'Possible Favicon found in %1$s. Favicons are handled by the Site Icon setting in the customizer since version 4.3.', 'theme-check' ),
47
  '<strong>' . $filename . '</strong>'
48
  )
49
  );
50
- $ret = false;
51
  }
52
  }
53
- return $ret;
54
  }
55
 
56
  /**
27
  */
28
  public function check( $php_files, $css_files, $other_files ) {
29
 
 
 
30
  checkcount();
31
 
32
  foreach ( $php_files as $file_path => $file_content ) {
38
  preg_match( '/(<meta name=[\'"]msapplication-TileImage[\'"])/i', $file_content )
39
  ) {
40
  $this->error[] = sprintf(
41
+ '<span class="tc-lead tc-info">%s</span>: %s',
42
+ __( 'INFO', 'theme-check' ),
43
  sprintf(
44
  __( 'Possible Favicon found in %1$s. Favicons are handled by the Site Icon setting in the customizer since version 4.3.', 'theme-check' ),
45
  '<strong>' . $filename . '</strong>'
46
  )
47
  );
 
48
  }
49
  }
50
+ return true;
51
  }
52
 
53
  /**
checks/class-file-check.php CHANGED
@@ -42,6 +42,7 @@ class File_Check implements themecheck {
42
  $allowlist = array(
43
  'wpml-config.xml',
44
  'loco.xml',
 
45
  );
46
 
47
  $blocklist = array(
@@ -60,14 +61,8 @@ class File_Check implements themecheck {
60
  '\.lubith' => __( 'Lubith theme generator file', 'theme-check' ),
61
  '\.wie' => __( 'Widget import file', 'theme-check' ),
62
  '\.dat' => __( 'Customizer import file', 'theme-check' ),
63
- 'phpcs\.xml\.dist' => __( 'PHPCS file', 'theme-check' ),
64
- 'phpcs\.xml' => __( 'PHPCS file', 'theme-check' ),
65
  '\.xml' => __( 'XML file', 'theme-check' ),
66
  '\.sh' => __( 'Shell script file', 'theme-check' ),
67
- 'postcss\.config\.js' => __( 'PostCSS config file', 'theme-check' ),
68
- '\.editorconfig.' => __( 'Editor config file', 'theme-check' ),
69
- '\.stylelintrc\.json' => __( 'Stylelint config file', 'theme-check' ),
70
- '\.eslintrc' => __( 'ES lint config file', 'theme-check' ),
71
  'favicon\.ico' => __( 'Favicon', 'theme-check' ),
72
  );
73
 
@@ -91,7 +86,7 @@ class File_Check implements themecheck {
91
  '<span class="tc-lead tc-required">%s</span>: %s',
92
  __( 'REQUIRED', 'theme-check' ),
93
  sprintf(
94
- __( '%1$s %2$s found. This file must not be in a theme.', 'theme-check' ),
95
  '<strong>' . $error . '</strong>',
96
  $reason
97
  )
42
  $allowlist = array(
43
  'wpml-config.xml',
44
  'loco.xml',
45
+ 'phpcs.xml',
46
  );
47
 
48
  $blocklist = array(
61
  '\.lubith' => __( 'Lubith theme generator file', 'theme-check' ),
62
  '\.wie' => __( 'Widget import file', 'theme-check' ),
63
  '\.dat' => __( 'Customizer import file', 'theme-check' ),
 
 
64
  '\.xml' => __( 'XML file', 'theme-check' ),
65
  '\.sh' => __( 'Shell script file', 'theme-check' ),
 
 
 
 
66
  'favicon\.ico' => __( 'Favicon', 'theme-check' ),
67
  );
68
 
86
  '<span class="tc-lead tc-required">%s</span>: %s',
87
  __( 'REQUIRED', 'theme-check' ),
88
  sprintf(
89
+ __( '%1$s %2$s found. This file must not be in the production version of the theme.', 'theme-check' ),
90
  '<strong>' . $error . '</strong>',
91
  $reason
92
  )
checks/class-filesystem-http-check.php CHANGED
@@ -24,16 +24,11 @@ class Filesystem_HTTP_Check implements themecheck {
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
 
29
  $checks = array(
30
  // Filesystem operations are not advised. file_get_contents() is allowed.
31
  '/[^a-z0-9](?<!_)(readfile|fopen)\s?\(/i' => __( 'File read operations should use file_get_contents() but are discouraged unless required', 'theme-check' ),
32
  '/[^a-z0-9](?<!_)(fopen|fclose|fread|fwrite|file_put_contents)\s?\(/i' => __( 'File write operations should are avoided unless necessary', 'theme-check' ),
33
-
34
- // WP_Filesystem should only be used for theme upgrade operations. It should not be used to avoid the fopen()/file_put_contents()/etc warnings.
35
- '/[^a-z0-9](?<!_)(WP_Filesystem)\s?\(/i' => __( 'WP_Filesystem should only be used for theme upgrade operations, not for all file operations. Consider using file_get_contents(), scandir(), or glob()', 'theme-check' ),
36
-
37
  // HTTP Requests should use WP_HTTP.
38
  '/[^a-z0-9](?<!_)(curl_exec|curl_init|fsockopen|pfsockopen|stream_context_create)\s?\(/' => __( 'HTTP requests should be made using the WordPress HTTP wrappers, such as wp_safe_remote_get() and wp_safe_remote_post()', 'theme-check' ),
39
  );
@@ -54,7 +49,7 @@ class Filesystem_HTTP_Check implements themecheck {
54
  '<span class="tc-lead tc-warning">%s</span>: %s %s',
55
  __( 'WARNING', 'theme-check' ),
56
  sprintf(
57
- __( '%1$s was found in the file %2$s %3$s', 'theme-check' ),
58
  '<strong>' . $error . '</strong>',
59
  '<strong>' . $filename . '</strong>',
60
  $check
@@ -65,7 +60,43 @@ class Filesystem_HTTP_Check implements themecheck {
65
  }
66
  }
67
  }
68
- return $ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  }
70
 
71
  /**
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
  $checks = array(
29
  // Filesystem operations are not advised. file_get_contents() is allowed.
30
  '/[^a-z0-9](?<!_)(readfile|fopen)\s?\(/i' => __( 'File read operations should use file_get_contents() but are discouraged unless required', 'theme-check' ),
31
  '/[^a-z0-9](?<!_)(fopen|fclose|fread|fwrite|file_put_contents)\s?\(/i' => __( 'File write operations should are avoided unless necessary', 'theme-check' ),
 
 
 
 
32
  // HTTP Requests should use WP_HTTP.
33
  '/[^a-z0-9](?<!_)(curl_exec|curl_init|fsockopen|pfsockopen|stream_context_create)\s?\(/' => __( 'HTTP requests should be made using the WordPress HTTP wrappers, such as wp_safe_remote_get() and wp_safe_remote_post()', 'theme-check' ),
34
  );
49
  '<span class="tc-lead tc-warning">%s</span>: %s %s',
50
  __( 'WARNING', 'theme-check' ),
51
  sprintf(
52
+ __( '%1$s was found in the file %2$s. %3$s.', 'theme-check' ),
53
  '<strong>' . $error . '</strong>',
54
  '<strong>' . $filename . '</strong>',
55
  $check
60
  }
61
  }
62
  }
63
+
64
+ foreach ( $php_files as $php_key => $phpfile ) {
65
+
66
+ $checks = array(
67
+ // WP_Filesystem should only be used for theme upgrade operations. It should not be used to avoid the fopen()/file_put_contents()/etc warnings.
68
+ '/[^a-z0-9](?<!_)(WP_Filesystem)\s?\(/i' => __( 'Theme Check is not able to determine if WP_Filesystem is used correctly. WP_Filesystem should only be used for theme upgrade operations, not for all file operations. Before continuing, you must manually review the code. Consider using file_get_contents(), scandir(), or glob(). It is not recommended to make changes to third-party frameworks that use WP_Filesystem, for example, TGMPA', 'theme-check' ),
69
+ );
70
+
71
+ foreach ( $checks as $key => $check ) {
72
+ checkcount();
73
+
74
+ if ( preg_match_all( $key, $phpfile, $matches ) ) {
75
+ $filename = tc_filename( $php_key );
76
+
77
+ foreach ( $matches[1] as $match ) {
78
+ $error = ltrim( $match, '(' );
79
+ $error = rtrim( $error, '(' );
80
+
81
+ $grep = tc_grep( $error, $php_key );
82
+ $this->error[] = sprintf(
83
+ '<span class="tc-lead tc-info">%s</span>: %s <br><code>%s</code>',
84
+ __( 'INFO', 'theme-check' ),
85
+ sprintf(
86
+ __( '%1$s was found in the file %2$s. %3$s.', 'theme-check' ),
87
+ '<strong>' . $error . '</strong>',
88
+ '<strong>' . $filename . '</strong>',
89
+ $check
90
+ ),
91
+ $grep
92
+ );
93
+ }
94
+ }
95
+ }
96
+ }
97
+
98
+ return true;
99
+
100
  }
101
 
102
  /**
checks/class-generated-check.php CHANGED
@@ -30,7 +30,6 @@ class Generated_Check implements themecheck {
30
 
31
  checkcount();
32
 
33
- $ret = true;
34
  if (
35
  // Artisteer.
36
  strpos( $php, 'art_normalize_widget_style_tokens' ) !== false
@@ -51,14 +50,13 @@ class Generated_Check implements themecheck {
51
  || strpos( $php, 'wptg_' ) !== false
52
  ) {
53
  $this->error[] = sprintf(
54
- '<span class="tc-lead tc-required">%s</span>: %s',
55
- __( 'REQUIRED', 'theme-check' ),
56
- __( 'This theme appears to have been auto-generated. Generated themes are not allowed in the themes directory.', 'theme-check' )
57
  );
58
- $ret = false;
59
  }
60
 
61
- return $ret;
62
  }
63
 
64
  /**
30
 
31
  checkcount();
32
 
 
33
  if (
34
  // Artisteer.
35
  strpos( $php, 'art_normalize_widget_style_tokens' ) !== false
50
  || strpos( $php, 'wptg_' ) !== false
51
  ) {
52
  $this->error[] = sprintf(
53
+ '<span class="tc-lead tc-warning">%s</span>: %s',
54
+ __( 'WARNING', 'theme-check' ),
55
+ __( 'This theme appears to have been auto-generated.', 'theme-check' )
56
  );
 
57
  }
58
 
59
+ return true;
60
  }
61
 
62
  /**
checks/class-i18n-check.php CHANGED
@@ -1,12 +1,12 @@
1
  <?php
2
  /**
3
- * Check for various I18N errors
4
  *
5
  * @package Theme Check
6
  */
7
 
8
  /**
9
- * Check for various I18N errors.
10
  */
11
  class I18N_Check implements themecheck {
12
  /**
@@ -24,8 +24,7 @@ class I18N_Check implements themecheck {
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
- $error = '';
29
  checkcount();
30
 
31
  // Make sure the tokenizer is available.
@@ -34,16 +33,16 @@ class I18N_Check implements themecheck {
34
  }
35
 
36
  foreach ( $php_files as $php_key => $phpfile ) {
37
- $error = '';
38
-
39
  $stmts = array();
40
  foreach ( array( '_e(', '__(', '_e (', '__ (' ) as $finder ) {
41
  $search = $phpfile;
42
- while ( ( $pos = strpos( $search, $finder ) ) !== false ) {
 
 
43
  $search = substr( $search, $pos );
44
  $open = 1;
45
  $i = strpos( $search, '(' ) + 1;
46
- while ( $open > 0 ) {
47
  switch ( $search[ $i ] ) {
48
  case '(':
49
  $open++;
@@ -61,24 +60,21 @@ class I18N_Check implements themecheck {
61
 
62
  foreach ( $stmts as $match ) {
63
  $tokens = token_get_all( '<?php ' . $match . ';' );
 
64
  if ( ! empty( $tokens ) ) {
65
  foreach ( $tokens as $token ) {
66
  if ( is_array( $token ) && in_array( $token[0], array( T_VARIABLE ) ) ) {
67
- $filename = tc_filename( $php_key );
68
- $grep = tc_grep( ltrim( $match ), $php_key );
69
- preg_match( '/[^\s]*\s[0-9]+/', $grep, $line );
70
- $error = '';
71
- if ( isset( $line[0] ) ) {
72
- $error = ( ! strpos( $error, $line[0] ) ) ? $grep : '';
73
- }
74
  $this->error[] = sprintf(
75
  '<span class="tc-lead tc-recommended">%s</span>: %s',
76
  __( 'RECOMMENDED', 'theme-check' ),
77
  sprintf(
78
- __( 'Possible variable %1$s found in translation function in %2$s. Translation function calls must NOT contain PHP variables. %3$s', 'theme-check' ),
79
  '<strong>' . $token[1] . '</strong>',
80
  '<strong>' . $filename . '</strong>',
81
- $error
 
82
  )
83
  );
84
  break; // Stop looking at the tokens on this line once a variable is found.
@@ -87,7 +83,8 @@ class I18N_Check implements themecheck {
87
  }
88
  }
89
  }
90
- return $ret;
 
91
  }
92
 
93
  /**
1
  <?php
2
  /**
3
+ * Check if there are PHP variables in translation strings.
4
  *
5
  * @package Theme Check
6
  */
7
 
8
  /**
9
+ * Check if there are PHP variables in translation strings.
10
  */
11
  class I18N_Check implements themecheck {
12
  /**
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
  checkcount();
29
 
30
  // Make sure the tokenizer is available.
33
  }
34
 
35
  foreach ( $php_files as $php_key => $phpfile ) {
 
 
36
  $stmts = array();
37
  foreach ( array( '_e(', '__(', '_e (', '__ (' ) as $finder ) {
38
  $search = $phpfile;
39
+ while ( ( $pos = strpos( $search, $finder ) ) !== false &&
40
+ strpos( $search, 'pll__' ) === false &&
41
+ strpos( $search, 'pll_e' ) === false ) {
42
  $search = substr( $search, $pos );
43
  $open = 1;
44
  $i = strpos( $search, '(' ) + 1;
45
+ while ( $open > 0 && isset( $search[ $i ] ) ) {
46
  switch ( $search[ $i ] ) {
47
  case '(':
48
  $open++;
60
 
61
  foreach ( $stmts as $match ) {
62
  $tokens = token_get_all( '<?php ' . $match . ';' );
63
+
64
  if ( ! empty( $tokens ) ) {
65
  foreach ( $tokens as $token ) {
66
  if ( is_array( $token ) && in_array( $token[0], array( T_VARIABLE ) ) ) {
67
+ $filename = tc_filename( $php_key );
68
+ $grep = tc_grep( ltrim( $token[1] ), $php_key );
 
 
 
 
 
69
  $this->error[] = sprintf(
70
  '<span class="tc-lead tc-recommended">%s</span>: %s',
71
  __( 'RECOMMENDED', 'theme-check' ),
72
  sprintf(
73
+ __( 'Possible variable %1$s found in translation function in %2$s. Translation function calls must not contain PHP variables, use placeholders instead. See <a href="%3$s" target="_blank">Internationalization Guidelines (Opens in a new window)</a>. %4$s', 'theme-check' ),
74
  '<strong>' . $token[1] . '</strong>',
75
  '<strong>' . $filename . '</strong>',
76
+ 'https://developer.wordpress.org/apis/handbook/internationalization/internationalization-guidelines/#variables',
77
+ $grep
78
  )
79
  );
80
  break; // Stop looking at the tokens on this line once a variable is found.
83
  }
84
  }
85
  }
86
+
87
+ return true;
88
  }
89
 
90
  /**
checks/class-image-size-check.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Check if the image sizes are larger than necessary
4
+ *
5
+ * @package Theme Check
6
+ */
7
+
8
+ /**
9
+ * Check if the image sizes are larger than necessary
10
+ */
11
+ class Image_Size_Check 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
+ checkcount();
29
+
30
+ foreach ( $other_files as $other_key => $otherfile ) {
31
+
32
+ $file = wp_check_filetype_and_ext( $other_key, basename( $other_key ) );
33
+ if ( 'image/' !== substr( $file['type'], 0, 6 ) ) {
34
+ continue;
35
+ }
36
+
37
+ // Check if the file is larger than 500 KB.
38
+ $image_size = filesize( $other_key );
39
+ if ( $image_size < 500 * KB_IN_BYTES ) {
40
+ continue;
41
+ }
42
+
43
+ $this->error[] = sprintf(
44
+ '<span class="tc-lead tc-warning">%s</span>: %s',
45
+ __( 'WARNING', 'theme-check' ),
46
+ sprintf(
47
+ /* translators: %1$s file name. %2$s file size. */
48
+ __( '%1$s is %2$s in size. Large file sizes have a negative impact on website performance and loading time. Compress images before using them.', 'theme-check' ),
49
+ '<strong>' . tc_filename( $other_key ) . '</strong>',
50
+ size_format( $image_size, 1 )
51
+ )
52
+ );
53
+ }
54
+
55
+ return true;
56
+ }
57
+
58
+ /**
59
+ * Get error messages from the checks.
60
+ *
61
+ * @return array Error message.
62
+ */
63
+ public function getError() {
64
+ return $this->error;
65
+ }
66
+ }
67
+
68
+ $themechecks[] = new Image_Size_Check();
checks/class-plugin-territory-check.php CHANGED
@@ -27,45 +27,16 @@ class Plugin_Territory_Check implements themecheck {
27
  */
28
  public function check( $php_files, $css_files, $other_files ) {
29
  $ret = true;
30
- $php = implode( ' ', $php_files );
31
 
32
  // Functions that are required to be removed from the theme.
33
  $forbidden_functions = array(
34
  'register_post_type',
35
  'register_taxonomy',
36
- 'wp_add_dashboard_widget',
37
  'register_block_type',
 
 
38
  );
39
 
40
- foreach ( $forbidden_functions as $function ) {
41
- checkcount();
42
- if ( preg_match( '/[\s?]' . $function . '\s?\(/', $php ) ) {
43
- $this->error[] = sprintf(
44
- '<span class="tc-lead tc-required">%s</span> %s',
45
- __( 'REQUIRED', 'theme-check' ),
46
- sprintf(
47
- __( 'The theme uses the %s function, which is plugin-territory functionality.', 'theme-check' ),
48
- '<strong>' . esc_html( $function ) . '()</strong>'
49
- )
50
- );
51
- $ret = false;
52
- }
53
- }
54
-
55
- // Shortcodes can't be used in the post content, so warn about them.
56
- if ( false !== strpos( $php, 'add_shortcode(' ) ) {
57
- checkcount();
58
- $this->error[] = sprintf(
59
- '<span class="tc-lead tc-required">%s</span> %s',
60
- __( 'REQUIRED', 'theme-check' ),
61
- sprintf(
62
- __( 'The theme uses the %s function. Custom post-content shortcodes are plugin-territory functionality.', 'theme-check' ),
63
- '<strong>add_shortcode()</strong>'
64
- )
65
- );
66
- $ret = false;
67
- }
68
-
69
  // Hooks (actions & filters) that are required to be removed from the theme.
70
  $forbidden_hooks = array(
71
  'filter' => array(
@@ -73,39 +44,16 @@ class Plugin_Territory_Check implements themecheck {
73
  'upload_mimes',
74
  'user_contactmethods',
75
  ),
76
- 'action' => array(
77
- 'wp_dashboard_setup',
78
- ),
79
  );
80
 
81
- foreach ( $forbidden_hooks as $type => $hooks ) {
82
- foreach ( $hooks as $hook ) {
83
- checkcount();
84
- if ( preg_match( '/[\s?]add_' . $type . '\s*\(\s*([\'"])' . $hook . '([\'"])\s*,/', $php ) ) {
85
- $this->error[] = sprintf(
86
- '<span class="tc-lead tc-required">%s</span>: %s',
87
- __( 'REQUIRED', 'theme-check' ),
88
- sprintf(
89
- __( 'The theme uses the %1$s %2$s, which is plugin-territory functionality.', 'theme-check' ),
90
- '<strong>' . esc_html( $hook ) . '</strong>',
91
- esc_html( $type )
92
- )
93
- );
94
- $ret = false;
95
- }
96
- }
97
- }
98
-
99
  /**
100
  * Check for removal of non presentational hooks.
101
- * Removing emojis is also not allowed.
102
  */
103
  $blocklist = array(
104
- 'wp_head' => array(
105
  'wp_generator', // @link https://developer.wordpress.org/reference/functions/wp_generator/
106
  'feed_links', // @link https://developer.wordpress.org/reference/functions/feed_links/
107
  'feed_links_extra', // @link https://developer.wordpress.org/reference/functions/feed_links_extra/
108
- 'print_emoji_detection_script', // @link https://developer.wordpress.org/reference/functions/print_emoji_detection_script/
109
  'wp_resource_hints', // @link https://developer.wordpress.org/reference/functions/wp_resource_hints/
110
  'adjacent_posts_rel_link_wp_head', // @link https://developer.wordpress.org/reference/functions/adjacent_posts_rel_link_wp_head/
111
  'wp_shortlink_wp_head', // @link https://developer.wordpress.org/reference/functions/wp_shortlink_wp_head/
@@ -116,38 +64,77 @@ class Plugin_Territory_Check implements themecheck {
116
  'wp_oembed_add_host_js', // @link https://developer.wordpress.org/reference/functions/wp_oembed_add_host_js/
117
  'rel_canonical', // @link https://developer.wordpress.org/reference/functions/rel_canonical/
118
  ),
119
- 'wp_print_styles' => array(
120
- 'print_emoji_styles', // @link https://developer.wordpress.org/reference/functions/print_emoji_styles/
121
- ),
122
- 'admin_print_scripts' => array(
123
- 'print_emoji_detection_script', // @link https://developer.wordpress.org/reference/functions/print_emoji_detection_script/
124
- ),
125
- 'admin_print_styles' => array(
126
- 'print_emoji_styles', // @link https://developer.wordpress.org/reference/functions/print_emoji_styles/
127
- ),
128
- 'template_redirect' => array(
129
  'rest_output_link_header', // @link https://developer.wordpress.org/reference/functions/rest_output_link_header/
130
  'wp_shortlink_header', // @link https://developer.wordpress.org/reference/functions/wp_shortlink_header/
131
  'redirect_canonical', // @link https://developer.wordpress.org/reference/functions/redirect_canonical/
132
  ),
133
  );
134
 
135
- foreach ( $blocklist as $hook => $functions ) {
136
- foreach ( $functions as $function ) {
 
137
  checkcount();
138
- if ( preg_match( '/[\s?]remove_action\s*\(\s*([\'"])' . $hook . '([\'"])\s*,\s*([\'"])' . $function . '([\'"])/', $php ) ) {
 
 
139
  $this->error[] = sprintf(
140
- '<span class="tc-lead tc-required">%s</span> %s',
141
  __( 'REQUIRED', 'theme-check' ),
142
  sprintf(
143
- __( 'The theme uses <strong>remove_action %1$s %2$s</strong>, which is plugin-territory functionality.', 'theme-check' ),
144
- esc_html( $hook ),
145
- esc_html( $function )
 
146
  )
147
  );
148
  $ret = false;
149
  }
150
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
152
 
153
  return $ret;
27
  */
28
  public function check( $php_files, $css_files, $other_files ) {
29
  $ret = true;
 
30
 
31
  // Functions that are required to be removed from the theme.
32
  $forbidden_functions = array(
33
  'register_post_type',
34
  'register_taxonomy',
 
35
  'register_block_type',
36
+ 'add_role',
37
+ 'add_shortcode',
38
  );
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  // Hooks (actions & filters) that are required to be removed from the theme.
41
  $forbidden_hooks = array(
42
  'filter' => array(
44
  'upload_mimes',
45
  'user_contactmethods',
46
  ),
 
 
 
47
  );
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  /**
50
  * Check for removal of non presentational hooks.
 
51
  */
52
  $blocklist = array(
53
+ 'wp_head' => array(
54
  'wp_generator', // @link https://developer.wordpress.org/reference/functions/wp_generator/
55
  'feed_links', // @link https://developer.wordpress.org/reference/functions/feed_links/
56
  'feed_links_extra', // @link https://developer.wordpress.org/reference/functions/feed_links_extra/
 
57
  'wp_resource_hints', // @link https://developer.wordpress.org/reference/functions/wp_resource_hints/
58
  'adjacent_posts_rel_link_wp_head', // @link https://developer.wordpress.org/reference/functions/adjacent_posts_rel_link_wp_head/
59
  'wp_shortlink_wp_head', // @link https://developer.wordpress.org/reference/functions/wp_shortlink_wp_head/
64
  'wp_oembed_add_host_js', // @link https://developer.wordpress.org/reference/functions/wp_oembed_add_host_js/
65
  'rel_canonical', // @link https://developer.wordpress.org/reference/functions/rel_canonical/
66
  ),
67
+ 'template_redirect' => array(
 
 
 
 
 
 
 
 
 
68
  'rest_output_link_header', // @link https://developer.wordpress.org/reference/functions/rest_output_link_header/
69
  'wp_shortlink_header', // @link https://developer.wordpress.org/reference/functions/wp_shortlink_header/
70
  'redirect_canonical', // @link https://developer.wordpress.org/reference/functions/redirect_canonical/
71
  ),
72
  );
73
 
74
+ foreach ( $php_files as $php_key => $phpfile ) {
75
+
76
+ foreach ( $forbidden_functions as $function ) {
77
  checkcount();
78
+ if ( preg_match( '/[\s?]' . $function . '\s?\(/', $phpfile ) ) {
79
+ $filename = tc_filename( $php_key );
80
+ $grep = tc_grep( $function, $php_key );
81
  $this->error[] = sprintf(
82
+ '<span class="tc-lead tc-required">%s</span>: %s',
83
  __( 'REQUIRED', 'theme-check' ),
84
  sprintf(
85
+ __( 'The theme uses the %1$s function in the file %2$s. %1$s is plugin-territory functionality and must not be used in themes. Use a plugin instead. %3$s', 'theme-check' ),
86
+ '<strong>' . esc_html( $function ) . '()</strong>',
87
+ esc_html( $filename ),
88
+ $grep
89
  )
90
  );
91
  $ret = false;
92
  }
93
  }
94
+
95
+ foreach ( $forbidden_hooks as $type => $hooks ) {
96
+ foreach ( $hooks as $hook ) {
97
+ checkcount();
98
+ if ( preg_match( '/[\s?]add_' . $type . '\s*\(\s*([\'"])' . $hook . '([\'"])\s*,/', $phpfile ) ) {
99
+ $filename = tc_filename( $php_key );
100
+ $grep = tc_grep( $hook, $php_key );
101
+ $this->error[] = sprintf(
102
+ '<span class="tc-lead tc-required">%s</span>: %s',
103
+ __( 'REQUIRED', 'theme-check' ),
104
+ sprintf(
105
+ __( 'The theme uses the %1$s %2$s in the file %3$s. This is plugin-territory functionality and must not be used in themes. Use a plugin instead. %4$s', 'theme-check' ),
106
+ '<strong>' . esc_html( $hook ) . '</strong>',
107
+ esc_html( $type ),
108
+ $filename,
109
+ $grep
110
+ )
111
+ );
112
+ $ret = false;
113
+ }
114
+ }
115
+ }
116
+
117
+ foreach ( $blocklist as $hook => $functions ) {
118
+ foreach ( $functions as $function ) {
119
+ checkcount();
120
+ if ( preg_match( '/[\s?]remove_action\s*\(\s*([\'"])' . $hook . '([\'"])\s*,\s*([\'"])' . $function . '([\'"])/', $phpfile ) ) {
121
+ $filename = tc_filename( $php_key );
122
+ $grep = tc_preg( '/' . $hook . '([\'"])\s*,\s*([\'"])' . $function . '([\'"])/', $php_key );
123
+ $this->error[] = sprintf(
124
+ '<span class="tc-lead tc-required">%s</span>: %s',
125
+ __( 'REQUIRED', 'theme-check' ),
126
+ sprintf(
127
+ __( 'The theme uses <strong>remove_action %1$s %2$s</strong> in the file %3$s. This is plugin-territory functionality and must not be used in themes. Use a plugin instead. %4$s', 'theme-check' ),
128
+ esc_html( $hook ),
129
+ esc_html( $function ),
130
+ $filename,
131
+ $grep
132
+ )
133
+ );
134
+ $ret = false;
135
+ }
136
+ }
137
+ }
138
  }
139
 
140
  return $ret;
checks/class-screen-reader-text-check.php CHANGED
@@ -26,7 +26,6 @@ class Screen_Reader_Text_Check implements themecheck {
26
  public function check( $php_files, $css_files, $other_files ) {
27
 
28
  $css = implode( ' ', $css_files );
29
- $ret = true;
30
 
31
  $checks = array(
32
  '\.screen-reader-text' => __( '<strong>.screen-reader-text</strong> CSS class is generated by WordPress and needs to be styled with your theme CSS. See <a href="http://codex.wordpress.org/CSS#WordPress_Generated_Classes">the Codex</a> for an example implementation.', 'theme-check' ),
@@ -36,15 +35,14 @@ class Screen_Reader_Text_Check implements themecheck {
36
  checkcount();
37
  if ( ! preg_match( '/' . $key . '/i', $css, $matches ) ) {
38
  $this->error[] = sprintf(
39
- '<span class="tc-lead tc-required">%s</span> %s',
40
- __( 'REQUIRED', 'theme-check' ),
41
  $check
42
  );
43
- $ret = false;
44
  }
45
  }
46
 
47
- return $ret;
48
  }
49
 
50
  /**
26
  public function check( $php_files, $css_files, $other_files ) {
27
 
28
  $css = implode( ' ', $css_files );
 
29
 
30
  $checks = array(
31
  '\.screen-reader-text' => __( '<strong>.screen-reader-text</strong> CSS class is generated by WordPress and needs to be styled with your theme CSS. See <a href="http://codex.wordpress.org/CSS#WordPress_Generated_Classes">the Codex</a> for an example implementation.', 'theme-check' ),
35
  checkcount();
36
  if ( ! preg_match( '/' . $key . '/i', $css, $matches ) ) {
37
  $this->error[] = sprintf(
38
+ '<span class="tc-lead tc-info">%s</span> %s',
39
+ __( 'INFO', 'theme-check' ),
40
  $check
41
  );
 
42
  }
43
  }
44
 
45
+ return true;
46
  }
47
 
48
  /**
checks/class-script-tag-check.php CHANGED
@@ -37,10 +37,10 @@ class Script_Tag_Check implements themecheck {
37
  if ( false !== stripos( $file_content, '<script' ) ) {
38
  $grep = tc_preg( '/<script/i', $file_path );
39
  $this->error[] = sprintf(
40
- '<span class="tc-lead tc-required">%s</span>: %s %s',
41
- __( 'REQUIRED', 'theme-check' ),
42
  sprintf(
43
- __( 'Found a script tag in %s. Scripts and styles needs to be enqueued or added via a hook, not hard coded.', 'theme-check' ),
44
  '<strong>' . $filename . '</strong>'
45
  ),
46
  $grep
37
  if ( false !== stripos( $file_content, '<script' ) ) {
38
  $grep = tc_preg( '/<script/i', $file_path );
39
  $this->error[] = sprintf(
40
+ '<span class="tc-lead tc-recommended">%s</span>: %s %s',
41
+ __( 'RECOMMENDED', 'theme-check' ),
42
  sprintf(
43
+ __( 'Found a script tag in %s. Scripts and styles need to be enqueued or added via a hook, otherwise it is more difficult to remove or replace them with plugins or child themes.', 'theme-check' ),
44
  '<strong>' . $filename . '</strong>'
45
  ),
46
  $grep
checks/class-style-tags-check.php CHANGED
@@ -38,12 +38,11 @@ class Style_Tags_Check implements themecheck {
38
  */
39
  public function check( $php_files, $css_files, $other_files ) {
40
  checkcount();
41
- $ret = true;
42
 
43
  if ( ! $this->tags ) {
44
  $this->error[] = sprintf(
45
- '<span class="tc-lead tc-recommended">%s</span> %s',
46
- __( 'RECOMMENDED', 'theme-check' ),
47
  __( '<strong>Tags:</strong> is either empty or missing in style.css header.', 'theme-check' )
48
  );
49
  } else {
@@ -66,24 +65,22 @@ class Style_Tags_Check implements themecheck {
66
  if ( ! in_array( strtolower( $tag ), $allowed_tags ) ) {
67
  if ( in_array( strtolower( $tag ), $deprecated_tags ) ) {
68
  $this->error[] = sprintf(
69
- '<span class="tc-lead tc-required">%s</span> %s',
70
- __( 'REQUIRED', 'theme-check' ),
71
  sprintf(
72
  __( 'The tag %s has been deprecated, please remove it from your style.css header.', 'theme-check' ),
73
  '<strong>' . $tag . '</strong>'
74
  )
75
  );
76
- $ret = false;
77
  } else {
78
  $this->error[] = sprintf(
79
- '<span class="tc-lead tc-required">%s</span> %s',
80
- __( 'REQUIRED', 'theme-check' ),
81
  sprintf(
82
  __( 'Found wrong tag, remove %s from your style.css header.', 'theme-check' ),
83
  '<strong>' . $tag . '</strong>'
84
  )
85
  );
86
- $ret = false;
87
  }
88
  }
89
 
@@ -95,22 +92,21 @@ class Style_Tags_Check implements themecheck {
95
  if ( in_array( strtolower( $tag ), $allowed_tags ) ) {
96
  if ( count( array_keys( $this->tags, $tag ) ) > 1 ) {
97
  $this->error[] = sprintf(
98
- '<span class="tc-lead tc-required">%s</span> %s',
99
- __( 'REQUIRED', 'theme-check' ),
100
  sprintf(
101
  __( 'The tag %s is being used more than once, please remove it from your style.css header.', 'theme-check' ),
102
  '<strong>' . $tag . '</strong>'
103
  )
104
  );
105
- $ret = false;
106
  }
107
  }
108
  }
109
 
110
  if ( $subject_tags_count > 3 ) {
111
  $this->error[] = sprintf(
112
- '<span class="tc-lead tc-required">%s</span>: %s %s',
113
- __( 'REQUIRED', 'theme-check' ),
114
  sprintf(
115
  __( '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' ),
116
  $subject_tags_count,
@@ -122,11 +118,10 @@ class Style_Tags_Check implements themecheck {
122
  __( 'See Theme Tags', 'theme-check' )
123
  )
124
  );
125
- $ret = false;
126
  }
127
  }
128
 
129
- return $ret;
130
  }
131
 
132
  /**
@@ -174,6 +169,7 @@ class Style_Tags_Check implements themecheck {
174
  'post-formats',
175
  'rtl-language-support',
176
  'sticky-post',
 
177
  'theme-options',
178
  'threaded-comments',
179
  'translation-ready',
38
  */
39
  public function check( $php_files, $css_files, $other_files ) {
40
  checkcount();
 
41
 
42
  if ( ! $this->tags ) {
43
  $this->error[] = sprintf(
44
+ '<span class="tc-lead tc-info">%s</span> %s',
45
+ __( 'INFO', 'theme-check' ),
46
  __( '<strong>Tags:</strong> is either empty or missing in style.css header.', 'theme-check' )
47
  );
48
  } else {
65
  if ( ! in_array( strtolower( $tag ), $allowed_tags ) ) {
66
  if ( in_array( strtolower( $tag ), $deprecated_tags ) ) {
67
  $this->error[] = sprintf(
68
+ '<span class="tc-lead tc-info">%s</span> %s',
69
+ __( 'INFO', 'theme-check' ),
70
  sprintf(
71
  __( 'The tag %s has been deprecated, please remove it from your style.css header.', 'theme-check' ),
72
  '<strong>' . $tag . '</strong>'
73
  )
74
  );
 
75
  } else {
76
  $this->error[] = sprintf(
77
+ '<span class="tc-lead tc-info">%s</span> %s',
78
+ __( 'INFO', 'theme-check' ),
79
  sprintf(
80
  __( 'Found wrong tag, remove %s from your style.css header.', 'theme-check' ),
81
  '<strong>' . $tag . '</strong>'
82
  )
83
  );
 
84
  }
85
  }
86
 
92
  if ( in_array( strtolower( $tag ), $allowed_tags ) ) {
93
  if ( count( array_keys( $this->tags, $tag ) ) > 1 ) {
94
  $this->error[] = sprintf(
95
+ '<span class="tc-lead tc-info">%s</span> %s',
96
+ __( 'INFO', 'theme-check' ),
97
  sprintf(
98
  __( 'The tag %s is being used more than once, please remove it from your style.css header.', 'theme-check' ),
99
  '<strong>' . $tag . '</strong>'
100
  )
101
  );
 
102
  }
103
  }
104
  }
105
 
106
  if ( $subject_tags_count > 3 ) {
107
  $this->error[] = sprintf(
108
+ '<span class="tc-lead tc-info">%s</span>: %s %s',
109
+ __( 'INFO', 'theme-check' ),
110
  sprintf(
111
  __( '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' ),
112
  $subject_tags_count,
118
  __( 'See Theme Tags', 'theme-check' )
119
  )
120
  );
 
121
  }
122
  }
123
 
124
+ return true;
125
  }
126
 
127
  /**
169
  'post-formats',
170
  'rtl-language-support',
171
  'sticky-post',
172
+ 'template-editing',
173
  'theme-options',
174
  'threaded-comments',
175
  'translation-ready',
checks/{textdomain.php → class-textdomain-check.php} RENAMED
@@ -1,8 +1,38 @@
1
  <?php
2
- class TextDomainCheck implements themecheck {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  protected $error = array();
4
 
5
- // rules come from WordPress core tool makepot.php, modified to have domain info.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  var $rules = array(
7
  '__' => array( 'string', 'domain' ),
8
  '_e' => array( 'string', 'domain' ),
@@ -27,13 +57,9 @@ class TextDomainCheck implements themecheck {
27
  'comments_number_link' => array( 'string', 'singular', 'plural', 'domain' ),
28
  );
29
 
30
- // core names their themes differently
31
  var $exceptions = array( 'twentyten', 'twentyeleven', 'twentytwelve', 'twentythirteen', 'twentyfourteen', 'twentyfifteen', 'twentysixteen', 'twentyseventeen', 'twentyeighteen', 'twentynineteen', 'twentytwenty', 'twentytwentyone' );
32
 
33
- protected $name = '';
34
- protected $slug = '';
35
- protected $is_wporg = false;
36
-
37
  function set_context( $data ) {
38
  if ( isset( $data['theme']['Name'] ) ) {
39
  $this->name = $data['theme']['Name'];
@@ -45,26 +71,30 @@ class TextDomainCheck implements themecheck {
45
  $this->is_wporg = ! empty( $data['is_wporg'] );
46
  }
47
 
 
 
 
 
 
 
 
48
  function check( $php_files, $css_files, $other_files ) {
49
  $ret = true;
50
  $error = '';
51
  checkcount();
52
 
53
- // make sure the tokenizer is available
54
  if ( ! function_exists( 'token_get_all' ) ) {
55
  return true;
56
  }
57
 
58
- $funcs = array_keys( $this->rules );
59
-
60
  $domains = array();
61
 
62
  foreach ( $php_files as $php_key => $phpfile ) {
63
  $error = '';
64
-
65
- // tokenize the file
66
- $tokens = token_get_all( $phpfile );
67
-
68
  $in_func = false;
69
  $args_started = false;
70
  $parens_balance = 0;
@@ -72,9 +102,8 @@ class TextDomainCheck implements themecheck {
72
 
73
  foreach ( $tokens as $token ) {
74
  $string_success = false;
75
-
76
  if ( is_array( $token ) ) {
77
- list($id, $text) = $token;
78
  if ( T_STRING == $id && in_array( $text, $funcs ) ) {
79
  $in_func = true;
80
  $func = $text;
@@ -84,20 +113,33 @@ class TextDomainCheck implements themecheck {
84
  } elseif ( T_CONSTANT_ENCAPSED_STRING == $id ) {
85
  if ( $in_func && $args_started ) {
86
  if ( ! isset( $this->rules[ $func ][ $args_count ] ) ) {
87
- // avoid a warning when too many arguments are in a function, cause a fail case
88
- $new_args = $args;
89
- $new_args[] = $text;
 
 
 
 
 
 
 
 
 
 
 
90
  $this->error[] = sprintf(
91
  '<span class="tc-lead tc-warning">%s</span>: %s',
92
  __( 'WARNING', 'theme-check' ),
93
  sprintf(
94
- __( 'Found a translation function that has an incorrect number of arguments. Function %1$s, with the arguments %2$s', 'theme-check' ),
 
95
  '<strong>' . $func . '</strong>',
96
- '<strong>' . implode( ', ', $new_args ) . '</strong>'
 
97
  )
98
  );
99
  } elseif ( $this->rules[ $func ][ $args_count ] == 'domain' ) {
100
- // strip quotes from the domain, avoids 'domain' and "domain" not being recognized as the same
101
  $text = str_replace( array( '"', "'" ), '', $text );
102
  $domains[] = $text;
103
  $found_domain = true;
@@ -119,17 +161,31 @@ class TextDomainCheck implements themecheck {
119
  } elseif ( ')' == $token ) {
120
  --$parens_balance;
121
  if ( $in_func && 0 == $parens_balance ) {
122
- if ( ! $found_domain ) {
 
 
 
 
 
 
 
 
 
 
 
123
  $this->error[] = sprintf(
124
  '<span class="tc-lead tc-warning">%s</span>: %s',
125
  __( 'WARNING', 'theme-check' ),
126
  sprintf(
127
- __( 'Found a translation function that is missing a text-domain. Function %1$s, with the arguments %2$s', 'theme-check' ),
 
128
  '<strong>' . $func . '</strong>',
129
- '<strong>' . implode( ', ', $args ) . '</strong>'
 
130
  )
131
  );
132
  }
 
133
  $in_func = false;
134
  $func = '';
135
  $args_started = false;
@@ -148,7 +204,7 @@ class TextDomainCheck implements themecheck {
148
  $correct_domain = sanitize_title_with_dashes( $this->name );
149
  if ( $this->slug != $correct_domain ) {
150
  $this->error[] = sprintf(
151
- '<span class="tc-lead tc-warning">%s</span> %s %s',
152
  __( 'WARNING', 'theme-check' ),
153
  sprintf(
154
  __( "Your theme appears to be in the wrong directory for the theme name. The directory name must match the slug of the theme. This theme's correct slug and text-domain is %s.", 'theme-check' ),
@@ -158,7 +214,7 @@ class TextDomainCheck implements themecheck {
158
  );
159
  } elseif ( ! in_array( $correct_domain, $domains ) ) {
160
  $this->error[] = sprintf(
161
- '<span class="tc-lead tc-required">%s</span> %s %s',
162
  __( 'REQUIRED', 'theme-check' ),
163
  sprintf(
164
  __( "This theme text domain does not match the theme's slug. The text domain used: %s", 'theme-check' ),
@@ -175,21 +231,21 @@ class TextDomainCheck implements themecheck {
175
 
176
  if ( $domainscount > 1 ) {
177
  $this->error[] = sprintf(
178
- '<span class="tc-lead tc-warning">%s</span> %s %s',
179
  __( 'WARNING', 'theme-check' ),
180
  __( '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' ),
181
  sprintf(
182
- __( 'The domains found are %s', 'theme-check' ),
183
  '<strong>' . $domainlist . '</strong>'
184
  )
185
  );
186
  } else {
187
  $this->error[] = sprintf(
188
- '<span class="tc-lead tc-info">%s</span> %s %s',
189
  __( 'INFO', 'theme-check' ),
190
  __( "Only one text-domain is being used in this theme. Make sure it matches the theme's slug correctly so that the theme will be compatible with WordPress.org language packs.", 'theme-check' ),
191
  sprintf(
192
- __( 'The domain found is %s', 'theme-check' ),
193
  '<strong>' . $domainlist . '</strong>'
194
  )
195
  );
@@ -207,4 +263,4 @@ class TextDomainCheck implements themecheck {
207
  return $this->error;
208
  }
209
  }
210
- $themechecks[] = new TextDomainCheck();
1
  <?php
2
+ /**
3
+ * Check if translation functions have a text domain.
4
+ *
5
+ * @package Theme Check
6
+ */
7
+
8
+ /**
9
+ * Check if translation functions have a text domain.
10
+ */
11
+ class TextDomain_Check implements themecheck {
12
+ /**
13
+ * Error messages, warnings and info notices.
14
+ *
15
+ * @var array $error
16
+ */
17
  protected $error = array();
18
 
19
+ /**
20
+ * Theme name
21
+ *
22
+ * @var string $name
23
+ */
24
+ protected $name = '';
25
+
26
+ /**
27
+ * Theme slug
28
+ *
29
+ * @var string $slug
30
+ */
31
+ protected $slug = '';
32
+
33
+ protected $is_wporg = false;
34
+
35
+ // Rules come from WordPress core tool makepot.php, modified to have domain info.
36
  var $rules = array(
37
  '__' => array( 'string', 'domain' ),
38
  '_e' => array( 'string', 'domain' ),
57
  'comments_number_link' => array( 'string', 'singular', 'plural', 'domain' ),
58
  );
59
 
60
+ // Core names their themes differently.
61
  var $exceptions = array( 'twentyten', 'twentyeleven', 'twentytwelve', 'twentythirteen', 'twentyfourteen', 'twentyfifteen', 'twentysixteen', 'twentyseventeen', 'twentyeighteen', 'twentynineteen', 'twentytwenty', 'twentytwentyone' );
62
 
 
 
 
 
63
  function set_context( $data ) {
64
  if ( isset( $data['theme']['Name'] ) ) {
65
  $this->name = $data['theme']['Name'];
71
  $this->is_wporg = ! empty( $data['is_wporg'] );
72
  }
73
 
74
+ /**
75
+ * Check that return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
76
+ *
77
+ * @param array $php_files File paths and content for PHP files.
78
+ * @param array $css_files File paths and content for CSS files.
79
+ * @param array $other_files Folder names, file paths and content for other files.
80
+ */
81
  function check( $php_files, $css_files, $other_files ) {
82
  $ret = true;
83
  $error = '';
84
  checkcount();
85
 
86
+ // Make sure the tokenizer is available.
87
  if ( ! function_exists( 'token_get_all' ) ) {
88
  return true;
89
  }
90
 
91
+ $funcs = array_keys( $this->rules );
 
92
  $domains = array();
93
 
94
  foreach ( $php_files as $php_key => $phpfile ) {
95
  $error = '';
96
+ // Tokenize the file.
97
+ $tokens = token_get_all( $phpfile );
 
 
98
  $in_func = false;
99
  $args_started = false;
100
  $parens_balance = 0;
102
 
103
  foreach ( $tokens as $token ) {
104
  $string_success = false;
 
105
  if ( is_array( $token ) ) {
106
+ list( $id, $text ) = $token;
107
  if ( T_STRING == $id && in_array( $text, $funcs ) ) {
108
  $in_func = true;
109
  $func = $text;
113
  } elseif ( T_CONSTANT_ENCAPSED_STRING == $id ) {
114
  if ( $in_func && $args_started ) {
115
  if ( ! isset( $this->rules[ $func ][ $args_count ] ) ) {
116
+ $filename = tc_filename( $php_key );
117
+ // Avoid a warning when too many arguments are in a function, cause a fail case.
118
+ $new_args = $args;
119
+ $new_args[] = $text;
120
+ $error = $new_args['0'];
121
+ $grep = tc_grep( $error, $php_key );
122
+ $lines = explode( 'Line', $grep );
123
+
124
+ foreach ( $lines as $line ) {
125
+ if ( strpos( $line, $func ) !== false && strpos( $line, $error ) !== false ) {
126
+ $grep = "<pre class='tc-grep'>" . __( 'Line ', 'theme-check' ) . $line . '</pre>';
127
+ }
128
+ }
129
+
130
  $this->error[] = sprintf(
131
  '<span class="tc-lead tc-warning">%s</span>: %s',
132
  __( 'WARNING', 'theme-check' ),
133
  sprintf(
134
+ __( 'Found a translation function that has an incorrect number of arguments in the file %1$s. Function %2$s, with the arguments %3$s. %4$s', 'theme-check' ),
135
+ $filename,
136
  '<strong>' . $func . '</strong>',
137
+ '<strong>' . implode( ', ', $new_args ) . '</strong>',
138
+ $grep
139
  )
140
  );
141
  } elseif ( $this->rules[ $func ][ $args_count ] == 'domain' ) {
142
+ // Strip quotes from the domain, avoids 'domain' and "domain" not being recognized as the same
143
  $text = str_replace( array( '"', "'" ), '', $text );
144
  $domains[] = $text;
145
  $found_domain = true;
161
  } elseif ( ')' == $token ) {
162
  --$parens_balance;
163
  if ( $in_func && 0 == $parens_balance ) {
164
+ $error = implode( ', ', $args );
165
+
166
+ if ( ! $found_domain && ! empty( $error ) ) {
167
+ $filename = tc_filename( $php_key );
168
+ $grep = tc_grep( $error, $php_key );
169
+ $lines = explode( 'Line', $grep );
170
+ foreach ( $lines as $line ) {
171
+ if ( strpos( $line, $func ) !== false && strpos( $line, $error ) !== false ) {
172
+ $grep = "<pre class='tc-grep'>" . __( 'Line ', 'theme-check' ) . $line . '</pre>';
173
+ }
174
+ }
175
+
176
  $this->error[] = sprintf(
177
  '<span class="tc-lead tc-warning">%s</span>: %s',
178
  __( 'WARNING', 'theme-check' ),
179
  sprintf(
180
+ __( 'Found a translation function that is missing a text-domain in the file %1$s. Function %2$s, with the arguments %3$s. %4$s', 'theme-check' ),
181
+ $filename,
182
  '<strong>' . $func . '</strong>',
183
+ '<strong>' . $error . '</strong>',
184
+ $grep
185
  )
186
  );
187
  }
188
+
189
  $in_func = false;
190
  $func = '';
191
  $args_started = false;
204
  $correct_domain = sanitize_title_with_dashes( $this->name );
205
  if ( $this->slug != $correct_domain ) {
206
  $this->error[] = sprintf(
207
+ '<span class="tc-lead tc-warning">%s</span>: %s %s',
208
  __( 'WARNING', 'theme-check' ),
209
  sprintf(
210
  __( "Your theme appears to be in the wrong directory for the theme name. The directory name must match the slug of the theme. This theme's correct slug and text-domain is %s.", 'theme-check' ),
214
  );
215
  } elseif ( ! in_array( $correct_domain, $domains ) ) {
216
  $this->error[] = sprintf(
217
+ '<span class="tc-lead tc-required">%s</span>: %s %s',
218
  __( 'REQUIRED', 'theme-check' ),
219
  sprintf(
220
  __( "This theme text domain does not match the theme's slug. The text domain used: %s", 'theme-check' ),
231
 
232
  if ( $domainscount > 1 ) {
233
  $this->error[] = sprintf(
234
+ '<span class="tc-lead tc-warning">%s</span>: %s %s',
235
  __( 'WARNING', 'theme-check' ),
236
  __( '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' ),
237
  sprintf(
238
+ __( 'The domains found are %s.', 'theme-check' ),
239
  '<strong>' . $domainlist . '</strong>'
240
  )
241
  );
242
  } else {
243
  $this->error[] = sprintf(
244
+ '<span class="tc-lead tc-info">%s</span>: %s %s',
245
  __( 'INFO', 'theme-check' ),
246
  __( "Only one text-domain is being used in this theme. Make sure it matches the theme's slug correctly so that the theme will be compatible with WordPress.org language packs.", 'theme-check' ),
247
  sprintf(
248
+ __( 'The domain found is %s.', 'theme-check' ),
249
  '<strong>' . $domainlist . '</strong>'
250
  )
251
  );
263
  return $this->error;
264
  }
265
  }
266
+ $themechecks[] = new TextDomain_Check();
checks/class-title-check.php CHANGED
@@ -28,22 +28,24 @@ class Title_Check implements themecheck {
28
  * @param array $other_files Folder names, file paths and content for other files.
29
  */
30
  public function check( $php_files, $css_files, $other_files ) {
31
- $ret = true;
32
  $php = implode( ' ', $php_files );
33
 
34
  foreach ( $php_files as $file_path => $file_content ) {
35
 
36
  // Check whether there is a call to wp_title().
37
  checkcount();
38
- if ( false !== strpos( $file_content, 'wp_title(' ) ) {
39
- $ret = false;
 
40
  $this->error[] = sprintf(
41
- '<span class="tc-lead tc-required">%s</span>: %s',
42
- __( 'REQUIRED', 'theme-check' ),
43
  sprintf(
44
- __( 'The theme must not use <strong>wp_title()</strong>. Found wp_title() in %1$s.', 'theme-check' ),
45
  '<strong>' . tc_filename( $file_path ) . '</strong>'
46
- )
 
47
  );
48
  }
49
 
@@ -53,21 +55,23 @@ class Title_Check implements themecheck {
53
  // Look for <title> and </title> tags.
54
  checkcount();
55
  if ( ( false !== strpos( $file_content, '<title>' ) ) || ( false !== strpos( $file_content, '</title>' ) ) ) {
56
- $ret = false;
 
57
  $this->error[] = sprintf(
58
- '<span class="tc-lead tc-required">%s</span>: %s',
59
- __( 'REQUIRED', 'theme-check' ),
60
  sprintf(
61
- __( 'The theme must not use <strong>&lt;title&gt;</strong> tags. Found the tag in %1$s.', 'theme-check' ),
62
  '<strong>' . tc_filename( $file_path ) . '</strong>'
63
- )
 
64
  );
65
  }
66
  }
67
 
68
- return $ret;
69
- }
70
 
 
71
 
72
  /**
73
  * Get error messages from the checks.
28
  * @param array $other_files Folder names, file paths and content for other files.
29
  */
30
  public function check( $php_files, $css_files, $other_files ) {
31
+
32
  $php = implode( ' ', $php_files );
33
 
34
  foreach ( $php_files as $file_path => $file_content ) {
35
 
36
  // Check whether there is a call to wp_title().
37
  checkcount();
38
+ if ( preg_match( '/\bwp_title\b/', $file_content ) ) {
39
+ $filename = tc_filename( $file_path );
40
+ $grep = tc_grep( 'wp_title(', $file_path ); // tc_grep does not use preg_match, so there is a known risk for false positives here.
41
  $this->error[] = sprintf(
42
+ '<span class="tc-lead tc-recommended">%s</span>: %s. %s',
43
+ __( 'RECOMMENDED', 'theme-check' ),
44
  sprintf(
45
+ __( '<strong>wp_title()</strong> was found in the file %1$s. wp_title was historically used for the document &lt;title&gt; tag and was never intended for other purposes. Use <strong>add_theme_support( "title-tag" )</strong> instead', 'theme-check' ),
46
  '<strong>' . tc_filename( $file_path ) . '</strong>'
47
+ ),
48
+ $grep
49
  );
50
  }
51
 
55
  // Look for <title> and </title> tags.
56
  checkcount();
57
  if ( ( false !== strpos( $file_content, '<title>' ) ) || ( false !== strpos( $file_content, '</title>' ) ) ) {
58
+ $filename = tc_filename( $file_path );
59
+ $grep = tc_grep( '<title>', $file_path );
60
  $this->error[] = sprintf(
61
+ '<span class="tc-lead tc-recommended">%s</span>: %s. %s',
62
+ __( 'RECOMMENDED', 'theme-check' ),
63
  sprintf(
64
+ __( '<strong>&lt;title&gt;</strong> tag was found in the file %1$s. Document titles must not be hard coded, use <strong>add_theme_support( "title-tag" )</strong> instead', 'theme-check' ),
65
  '<strong>' . tc_filename( $file_path ) . '</strong>'
66
+ ),
67
+ $grep
68
  );
69
  }
70
  }
71
 
72
+ return true;
 
73
 
74
+ }
75
 
76
  /**
77
  * Get error messages from the checks.
checks/class-uri-check.php CHANGED
@@ -1,12 +1,12 @@
1
  <?php
2
  /**
3
- * Check if theme and author URI are the same and that wordpress.org is not used for theme URI
4
  *
5
  * @package Theme Check
6
  */
7
 
8
  /**
9
- * Check if theme and author URI are the same and that wordpress.org is not used for theme URI.
10
  */
11
  class URI_Check implements themecheck {
12
  /**
@@ -40,16 +40,7 @@ class URI_Check implements themecheck {
40
  checkcount();
41
  $ret = true;
42
 
43
- if ( ! empty( $this->theme->get( 'AuthorURI' ) ) && ! empty( $this->theme->get( 'ThemeURI' ) ) ) {
44
-
45
- if ( strtolower( preg_replace( '/https?:\/\/|www./i', '', trim( $this->theme->get( 'ThemeURI' ), '/' ) ) ) == strtolower( preg_replace( '/https?:\/\/|www./i', '', trim( $this->theme->get( 'AuthorURI' ), '/' ) ) ) ) {
46
- $this->error[] = sprintf(
47
- '<span class="tc-lead tc-required">%s</span>: %s',
48
- __( 'REQUIRED', 'theme-check' ),
49
- __( 'Your Theme URI and Author URI must not be the same.', 'theme-check' )
50
- );
51
- $ret = false;
52
- }
53
 
54
  // We allow .org user profiles as Author URI, so only check the Theme URI. We also allow WordPress.com links.
55
  if (
1
  <?php
2
  /**
3
+ * Check that wordpress.org is not used for theme URI
4
  *
5
  * @package Theme Check
6
  */
7
 
8
  /**
9
+ * Check that wordpress.org is not used for theme URI.
10
  */
11
  class URI_Check implements themecheck {
12
  /**
40
  checkcount();
41
  $ret = true;
42
 
43
+ if ( ! empty( $this->theme->get( 'ThemeURI' ) ) ) {
 
 
 
 
 
 
 
 
 
44
 
45
  // We allow .org user profiles as Author URI, so only check the Theme URI. We also allow WordPress.com links.
46
  if (
checks/class-version-php-check.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Check for Requires PHP versioning
4
+ *
5
+ * @package Theme Check
6
+ */
7
+
8
+ /**
9
+ * Check for PHP versioning.
10
+ * Does "Requires PHP" include patch versions (e.g. 7.4.1)?
11
+ * If so, recommend including major and minor verisions only (e.g. 7.4)
12
+ *
13
+ * See: https://developer.wordpress.org/themes/basics/main-stylesheet-style-css/#explanations
14
+ */
15
+ class Version_Requires_PHP_Check implements themecheck {
16
+ /**
17
+ * Error messages, warnings and info notices.
18
+ *
19
+ * @var array $error
20
+ */
21
+ protected $error = array();
22
+
23
+ /**
24
+ * Theme information. Requires PHP,
25
+ *
26
+ * @var object $theme
27
+ */
28
+ protected $theme;
29
+
30
+ function set_context( $data ) {
31
+ if ( isset( $data['theme'] ) ) {
32
+ $this->theme = $data['theme'];
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Check that return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
38
+ *
39
+ * @param array $php_files File paths and content for PHP files.
40
+ * @param array $css_files File paths and content for CSS files.
41
+ * @param array $other_files Folder names, file paths and content for other files.
42
+ */
43
+ public function check( $php_files, $css_files, $other_files ) {
44
+
45
+ checkcount();
46
+
47
+ if ( ! empty( $this->theme->get( 'RequiresPHP' ) ) ) {
48
+
49
+ $req_php_decimal_count = substr_count( $this->theme->get( 'RequiresPHP' ), '.' );
50
+
51
+ if ( $req_php_decimal_count > 1 ) {
52
+ $this->error[] = sprintf(
53
+ '<span class="tc-lead tc-recommended">%s</span>: %s',
54
+ __( 'RECOMMENDED', 'theme-check' ),
55
+ __( '<strong>Requires PHP</strong> is recommended to have major and minor versions only (e.g. 7.4). Patch version is not needed (e.g. 7.4.1).', 'theme-check' )
56
+ );
57
+ }
58
+ }
59
+ return true;
60
+ }
61
+
62
+ /**
63
+ * Get error messages from the checks.
64
+ *
65
+ * @return array Error message.
66
+ */
67
+ public function getError() {
68
+ return $this->error;
69
+ }
70
+ }
71
+
72
+ $themechecks[] = new Version_Requires_PHP_Check();
checks/class-version-tested-check.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Check for "Tested up to" versioning
4
+ *
5
+ * @package Theme Check
6
+ */
7
+
8
+ /**
9
+ * Check for "Tested up to" versioning.
10
+ * Does "Tested up to" include patch versions (e.g. 5.8.1)?
11
+ * If so, recommend including major versions only (e.g. 5.8)
12
+ *
13
+ * See: https://developer.wordpress.org/themes/basics/main-stylesheet-style-css/#explanations
14
+ */
15
+ class Version_Tested_Upto_Check implements themecheck {
16
+ /**
17
+ * Error messages, warnings and info notices.
18
+ *
19
+ * @var array $error
20
+ */
21
+ protected $error = array();
22
+
23
+ /**
24
+ * Theme information. Requires PHP,
25
+ *
26
+ * @var object $theme
27
+ */
28
+ protected $theme;
29
+
30
+ function set_context( $data ) {
31
+ if ( isset( $data['theme'] ) ) {
32
+ $this->theme = $data['theme'];
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Check that return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
38
+ *
39
+ * @param array $php_files File paths and content for PHP files.
40
+ * @param array $css_files File paths and content for CSS files.
41
+ * @param array $other_files Folder names, file paths and content for other files.
42
+ */
43
+ public function check( $php_files, $css_files, $other_files ) {
44
+
45
+ $filepath = $this->theme->get_stylesheet_directory() . '/style.css';
46
+ $theme_data = get_file_data(
47
+ $filepath,
48
+ array(
49
+ 'TestedUpto' => 'Tested up to',
50
+ )
51
+ );
52
+
53
+ if ( ! empty( $theme_data['TestedUpto'] ) ) {
54
+ $req_tested_decimal_count = substr_count( $theme_data['TestedUpto'], '.' );
55
+ if ( $req_tested_decimal_count > 1 ) {
56
+ $this->error[] = sprintf(
57
+ '<span class="tc-lead tc-recommended">%s</span>: %s',
58
+ __( 'RECOMMENDED', 'theme-check' ),
59
+ __( '<strong>Tested up to</strong> is recommended to have major versions only (e.g. 5.8). Patch version is not needed (e.g. 5.8.1).', 'theme-check' )
60
+ );
61
+ }
62
+ }
63
+ return true;
64
+ }
65
+
66
+ /**
67
+ * Get error messages from the checks.
68
+ *
69
+ * @return array Error message.
70
+ */
71
+ public function getError() {
72
+ return $this->error;
73
+ }
74
+ }
75
+
76
+ $themechecks[] = new Version_Tested_Upto_Check();
checks/content-width.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
-
3
- class ContentWidthCheck implements themecheck {
4
- protected $error = array();
5
-
6
- function check( $php_files, $css_files, $other_files ) {
7
-
8
- // combine all the php files into one string to make it easier to search
9
- $php = implode( ' ', $php_files );
10
- checkcount();
11
- if (
12
- strpos( $php, '$content_width' ) === false &&
13
- strpos( $php, '$GLOBALS' . "['content_width']" ) === false &&
14
- ! preg_match( '/add_filter\(\s?("|\')embed_defaults/', $php ) &&
15
- ! preg_match( '/add_filter\(\s?("|\')content_width/', $php )
16
- ) {
17
- $this->error[] = sprintf(
18
- '<span class="tc-lead tc-recommended">%s</span>: %s',
19
- __( 'RECOMMENDED', 'theme-check' ),
20
- __( 'No content width has been defined. Example: <pre>if ( ! isset( $content_width ) ) $content_width = 900;</pre>', 'theme-check' )
21
- );
22
- }
23
-
24
- return true;
25
- }
26
-
27
- function getError() {
28
- return $this->error;
29
- }
30
- }
31
- $themechecks[] = new ContentWidthCheck();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
main.php CHANGED
@@ -88,15 +88,10 @@ function check_main( $theme_slug ) {
88
  }
89
  }
90
  echo '</div><!-- .theme-info-->';
91
-
92
- $plugins = get_plugins( '/theme-check' );
93
- $version = explode( '.', $plugins['theme-check.php']['Version'] );
94
  echo '<p>' . sprintf(
95
- esc_html__( 'Running %1$s tests against %2$s using Guidelines Version: %3$s Plugin revision: %4$s', 'theme-check' ),
96
  '<strong>' . esc_html( $checkcount ) . '</strong>',
97
- '<strong>' . esc_html( $theme['Title'] ) . '</strong>',
98
- '<strong>' . esc_html( $version[0] ) . '</strong>',
99
- '<strong>' . esc_html( $version[1] ) . '</strong>'
100
  ) . '</p>';
101
 
102
  $results = display_themechecks();
@@ -135,6 +130,11 @@ function check_main( $theme_slug ) {
135
  'class' => array(),
136
  ),
137
  'strong' => array(),
 
 
 
 
 
138
  )
139
  );
140
  echo '</ul></div>';
@@ -151,16 +151,28 @@ function tc_intro() {
151
  <p>
152
  <?php
153
  printf(
154
- esc_html__( 'Theme Check is maintained by %1$s and %2$s.', 'theme-check' ),
155
- '<a href="https://profiles.wordpress.org/otto42/">Otto42</a>',
156
- '<a href="https://profiles.wordpress.org/pross/">Pross</a>'
157
  );
158
  ?>
159
- </p>
160
- <p><?php printf( __( 'If you have found a bug or would like to make a suggestion or contribution, please leave a post on the <a href="%1$s">WordPress forums</a>, or talk about it with the Themes Team on <a href="%2$s">Make WordPress Themes</a> site.', 'theme-check' ), 'https://wordpress.org/tags/theme-check?forum_id=10', 'https://make.wordpress.org/themes/' ); ?></p>
161
- <p><?php printf( __( 'The code for Theme Check can be contributed to on <a href="%s">GitHub</a>.', 'theme-check' ), 'https://github.com/WordPress/theme-check' ); ?></p>
162
- <h3><?php esc_html_e( 'Testers', 'theme-check' ); ?></h3>
163
- <p><a href="https://make.wordpress.org/themes/"><?php esc_html_e( 'The WordPress Themes Team', 'theme-check' ); ?></a></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  <?php
165
  }
166
 
88
  }
89
  }
90
  echo '</div><!-- .theme-info-->';
 
 
 
91
  echo '<p>' . sprintf(
92
+ esc_html__( 'Running %1$s tests against %2$s.', 'theme-check' ),
93
  '<strong>' . esc_html( $checkcount ) . '</strong>',
94
+ '<strong>' . esc_html( $theme['Title'] ) . '</strong>'
 
 
95
  ) . '</p>';
96
 
97
  $results = display_themechecks();
130
  'class' => array(),
131
  ),
132
  'strong' => array(),
133
+ 'code' => array(),
134
+ 'pre' => array(),
135
+ 'a' => array(
136
+ 'href' => array(),
137
+ ),
138
  )
139
  );
140
  echo '</ul></div>';
151
  <p>
152
  <?php
153
  printf(
154
+ esc_html__( 'Theme Check is maintained by %s.', 'theme-check' ),
155
+ '<a href="https://make.wordpress.org/themes/">' . esc_html__( 'The WordPress Themes Team', 'theme-check' ) . '</a>'
 
156
  );
157
  ?>
158
+ </p>
159
+ <p>
160
+ <?php
161
+ printf(
162
+ __( 'If you have found a bug or would like to make a suggestion or contribution, please leave a post on the <a href="%1$s">WordPress forums</a>, or talk about it with the Themes Team on <a href="%2$s">Make WordPress Themes</a> site.', 'theme-check' ),
163
+ 'https://wordpress.org/support/plugin/theme-check/',
164
+ 'https://make.wordpress.org/themes/'
165
+ );
166
+ ?>
167
+ </p>
168
+ <p>
169
+ <?php
170
+ printf(
171
+ __( 'The code for Theme Check can be contributed to on <a href="%s">GitHub</a>.', 'theme-check' ),
172
+ 'https://github.com/WordPress/theme-check'
173
+ );
174
+ ?>
175
+ </p>
176
  <?php
177
  }
178
 
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: Otto42, pross, poena, dingo-d, acosmin, joyously
3
  Requires at Least: 3.7
4
  Tested Up To: 5.8
5
- Tags: template, theme, check, checker, tool, wordpress.org, upload, uploader, test, guideline, review
6
- Stable tag: 20210617
7
 
8
  A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool!
9
 
@@ -34,9 +34,9 @@ This plugin does not decide the guidelines used. Any issues with particular them
34
  = How to enable trac formatting =
35
 
36
  The Theme Review team use this plugin while reviewing themes and copy/paste the output into trac tickets, the trac system has its own markup language.
37
- To enable trac formatting in Theme-Check you need to define a couple of variables in wp-config.php:
38
- *TC_PRE* and *TC_POST* are used as a ticket header and footer.
39
- Examples:
40
  `define( 'TC_PRE', 'Theme Review:[[br]]
41
  - Themes should be reviewed using "define(\'WP_DEBUG\', true);" in wp-config.php[[br]]
42
  - Themes should be reviewed using the test data from the Theme Checklists (TC)
@@ -49,9 +49,9 @@ comments, or feedback:[[br]]
49
  * Leave a comment on this ticket[[br]]
50
  * Send an email to the Theme Review email list[[br]]
51
  * Use the #wordpress-themes IRC channel on Freenode.' );`
 
52
  If **either** of these two vars are defined a new trac tickbox will appear next to the *Check it!* button.
53
 
54
  == Changelog ==
55
 
56
- = 20200504.1 =
57
- * Changes can be found in the changelog.txt file.
2
  Contributors: Otto42, pross, poena, dingo-d, acosmin, joyously
3
  Requires at Least: 3.7
4
  Tested Up To: 5.8
5
+ Tags: themes, guidelines, wordpress.org
6
+ Stable tag: 20210921
7
 
8
  A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool!
9
 
34
  = How to enable trac formatting =
35
 
36
  The Theme Review team use this plugin while reviewing themes and copy/paste the output into trac tickets, the trac system has its own markup language.
37
+ To enable trac formatting in Theme-Check you need to define a couple of variables in wp-config.php: *TC_PRE* and *TC_POST* are used as a ticket header and footer.
38
+ For example:
39
+
40
  `define( 'TC_PRE', 'Theme Review:[[br]]
41
  - Themes should be reviewed using "define(\'WP_DEBUG\', true);" in wp-config.php[[br]]
42
  - Themes should be reviewed using the test data from the Theme Checklists (TC)
49
  * Leave a comment on this ticket[[br]]
50
  * Send an email to the Theme Review email list[[br]]
51
  * Use the #wordpress-themes IRC channel on Freenode.' );`
52
+
53
  If **either** of these two vars are defined a new trac tickbox will appear next to the *Check it!* button.
54
 
55
  == Changelog ==
56
 
57
+ Changes can be found in [the changelog.txt file](https://github.com/WordPress/theme-check/blob/master/changelog.txt).
 
theme-check.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin URI: https://github.com/WordPress/theme-check/
5
  * Description: A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool!
6
  * Author: Theme Review Team
7
- * Version: 20210617
8
  * Text Domain: theme-check
9
  * License: GPLv2
10
  * License URI: https://www.gnu.org/licenses/gpl-2.0.html
4
  * Plugin URI: https://github.com/WordPress/theme-check/
5
  * Description: A simple and easy way to test your theme for all the latest WordPress standards and practices. A great theme development tool!
6
  * Author: Theme Review Team
7
+ * Version: 20210921
8
  * Text Domain: theme-check
9
  * License: GPLv2
10
  * License URI: https://www.gnu.org/licenses/gpl-2.0.html