Theme Check - Version 20200922.1

Version Description

Download this release

Release Info

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

Code changes from version 20200731.1 to 20200922.1

Files changed (8) hide show
  1. changelog.txt +6 -0
  2. checkbase.php +132 -105
  3. checks/badthings.php +4 -1
  4. checks/postthumb.php +2 -2
  5. checks/style_tags.php +104 -14
  6. main.php +175 -91
  7. readme.txt +2 -1
  8. theme-check.php +23 -23
changelog.txt CHANGED
@@ -1,3 +1,9 @@
 
 
 
 
 
 
1
  = 20200731.1 =
2
  * Added add_menu_page & add_submenu_page to the allowed functions list
3
  * Added loco.xml to the allowed files list and extend the allowlist check functionality to support an array of (possible) filenames.
1
+ = 20200922.1 =
2
+ * Reformatting of main.php and checkbase.php
3
+ * Additions to malware checks in badthings.php
4
+ * Spacing fix in postthumb.php
5
+ * Improved check for tags in styletags.php
6
+
7
  = 20200731.1 =
8
  * Added add_menu_page & add_submenu_page to the allowed functions list
9
  * Added loco.xml to the allowed files list and extend the allowlist check functionality to support an array of (possible) filenames.
checkbase.php CHANGED
@@ -7,30 +7,30 @@ $themechecks = array();
7
  global $checkcount;
8
  $checkcount = 0;
9
 
10
- // interface that all checks should implement
11
- interface themecheck
12
- {
13
- // should return true for good/okay/acceptable, false for bad/not-okay/unacceptable
14
  public function check( $php_files, $css_files, $other_files );
15
 
16
- // should return an array of strings explaining any problems found
17
  public function getError();
18
  }
19
 
20
- // load all the checks in the checks directory
21
  $dir = 'checks';
22
- foreach (glob(dirname(__FILE__). "/{$dir}/*.php") as $file) {
23
  include $file;
24
  }
25
 
26
- do_action('themecheck_checks_loaded');
27
 
28
- function run_themechecks($php, $css, $other) {
29
  global $themechecks;
30
  $pass = true;
31
- foreach($themechecks as $check) {
32
- if ($check instanceof themecheck) {
33
- $pass = $pass & $check->check($php, $css, $other);
34
  }
35
  }
36
  return $pass;
@@ -40,32 +40,36 @@ function display_themechecks() {
40
  $results = '';
41
  global $themechecks;
42
  $errors = array();
43
- foreach ($themechecks as $check) {
44
- if ($check instanceof themecheck) {
45
  $error = $check->getError();
46
  $error = (array) $error;
47
- if (!empty($error)) {
48
  $errors = array_unique( array_merge( $error, $errors ) );
49
  }
50
  }
51
  }
52
- if (!empty($errors)) {
53
- rsort($errors);
54
- foreach ($errors as $e) {
55
-
56
- if ( defined( 'TC_TRAC' ) ) {
57
- $results .= ( isset( $_POST['s_info'] ) && preg_match( '/INFO/', $e ) ) ? '' : '* ' . tc_trac( $e ) . "\r\n";
58
- } else {
59
- $results .= ( isset( $_POST['s_info'] ) && preg_match( '/INFO/', $e ) ) ? '' : '<li>' . tc_trac( $e ) . '</li>';
60
  }
61
  }
62
  }
63
 
64
  if ( defined( 'TC_TRAC' ) ) {
65
 
66
- if ( defined( 'TC_PRE' ) ) $results = TC_PRE . $results;
67
- $results = '<textarea cols=140 rows=20>' . strip_tags( $results );
68
- if ( defined( 'TC_POST' ) ) $results = $results . TC_POST;
 
 
 
 
69
  $results .= '</textarea>';
70
  }
71
  return $results;
@@ -76,22 +80,23 @@ function checkcount() {
76
  $checkcount++;
77
  }
78
 
79
- // some functions theme checks use
80
  function tc_grep( $error, $file ) {
81
  if ( ! file_exists( $file ) ) {
82
  return '';
83
  }
84
- $lines = file( $file, FILE_IGNORE_NEW_LINES ); // Read the theme file into an array
85
  $line_index = 0;
86
- $bad_lines = '';
87
- foreach( $lines as $this_line ) {
88
- if ( stristr ( $this_line, $error ) ) {
89
- $error = str_replace( '"', "'", $error );
90
- $this_line = str_replace( '"', "'", $this_line );
91
- $error = ltrim( $error );
92
- $pre = ( FALSE !== ( $pos = strpos( $this_line, $error ) ) ? substr( $this_line, 0, $pos ) : FALSE );
93
- $pre = ltrim( htmlspecialchars( $pre ) );
94
- $bad_lines .= "<pre class='tc-grep'>". __("Line ", "theme-check") . ( $line_index+1 ) . ": " . $pre . htmlspecialchars( substr( stristr( $this_line, $error ), 0, 75 ) ) . "</pre>";
 
95
  }
96
  $line_index++;
97
  }
@@ -102,21 +107,22 @@ function tc_preg( $preg, $file ) {
102
  if ( ! file_exists( $file ) ) {
103
  return '';
104
  }
105
- $lines = file( $file, FILE_IGNORE_NEW_LINES ); // Read the theme file into an array
106
  $line_index = 0;
107
- $bad_lines = '';
108
- $error = '';
109
- foreach( $lines as $this_line ) {
110
  if ( preg_match( $preg, $this_line, $matches ) ) {
111
- $error = $matches[0];
112
  $this_line = str_replace( '"', "'", $this_line );
113
- $error = ltrim( $error );
114
- $pre = '';
115
- if ( !empty( $error ) ) {
116
- $pre = ( FALSE !== ( $pos = strpos( $this_line, $error ) ) ? substr( $this_line, 0, $pos ) : FALSE );
 
117
  }
118
- $pre = ltrim( htmlspecialchars( $pre ) );
119
- $bad_lines .= "<pre class='tc-grep'>" . __("Line ", "theme-check") . ( $line_index+1 ) . ": " . $pre . htmlspecialchars( substr( stristr( $this_line, $error ), 0, 75 ) ) . "</pre>";
120
  }
121
  $line_index++;
122
 
@@ -130,10 +136,10 @@ function tc_filename( $file ) {
130
  }
131
 
132
  function tc_trac( $e ) {
133
- $trac_left = array( '<strong>', '</strong>' );
134
- $trac_right= array( "'''", "'''" );
135
- $html_link = '/<a\s?href\s?=\s?[\'|"]([^"|\']*)[\'|"]>([^<]*)<\/a>/i';
136
- $html_new = '[$1 $2]';
137
  if ( defined( 'TC_TRAC' ) ) {
138
  $e = preg_replace( $html_link, $html_new, $e );
139
  $e = str_replace( $trac_left, $trac_right, $e );
@@ -144,61 +150,67 @@ function tc_trac( $e ) {
144
  }
145
 
146
  function listdir( $dir ) {
147
- $files = array();
148
  $dir_iterator = new RecursiveDirectoryIterator( $dir );
149
- $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
150
 
151
- foreach ($iterator as $file) {
152
- array_push( $files, $file->getPathname() );
153
  }
154
  return $files;
155
  }
156
 
157
  function get_theme_data_from_contents( $theme_data ) {
158
  $themes_allowed_tags = array(
159
- 'a' => array(
160
- 'href' => array(),'title' => array()
161
- ),
162
- 'abbr' => array(
163
- 'title' => array()
164
- ),
 
165
  'acronym' => array(
166
- 'title' => array()
167
- ),
168
- 'code' => array(),
169
- 'em' => array(),
170
- 'strong' => array()
171
  );
172
 
173
- $theme_data = str_replace ( '\r', '\n', $theme_data );
174
  preg_match( '|^[ \t\/*#@]*Theme Name:(.*)$|mi', $theme_data, $theme_name );
175
  preg_match( '|^[ \t\/*#@]*Theme URI:(.*)$|mi', $theme_data, $theme_uri );
176
  preg_match( '|^[ \t\/*#@]*Description:(.*)$|mi', $theme_data, $description );
177
 
178
- if ( preg_match( '|^[ \t\/*#@]*Author URI:(.*)$|mi', $theme_data, $author_uri ) )
179
- $author_uri = esc_url( trim( $author_uri[1]) );
180
- else
181
  $author_uri = '';
 
182
 
183
- if ( preg_match( '|^[ \t\/*#@]*Template:(.*)$|mi', $theme_data, $template ) )
184
  $template = wp_kses( trim( $template[1] ), $themes_allowed_tags );
185
- else
186
  $template = '';
 
187
 
188
- if ( preg_match( '|^[ \t\/*#@]*Version:(.*)|mi', $theme_data, $version ) )
189
  $version = wp_kses( trim( $version[1] ), $themes_allowed_tags );
190
- else
191
  $version = '';
 
192
 
193
- if ( preg_match('|^[ \t\/*#@]*Status:(.*)|mi', $theme_data, $status) )
194
  $status = wp_kses( trim( $status[1] ), $themes_allowed_tags );
195
- else
196
  $status = 'publish';
 
197
 
198
- if ( preg_match('|^[ \t\/*#@]*Tags:(.*)|mi', $theme_data, $tags) )
199
  $tags = array_map( 'trim', explode( ',', wp_kses( trim( $tags[1] ), array() ) ) );
200
- else
201
  $tags = array();
 
202
 
203
  $theme = ( isset( $theme_name[1] ) ) ? wp_kses( trim( $theme_name[1] ), $themes_allowed_tags ) : '';
204
 
@@ -210,13 +222,24 @@ function get_theme_data_from_contents( $theme_data ) {
210
  if ( empty( $author_uri ) ) {
211
  $author = wp_kses( trim( $author_name[1] ), $themes_allowed_tags );
212
  } else {
213
- $author = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $author_uri, __( 'Visit author homepage' ), wp_kses( trim( $author_name[1] ), $themes_allowed_tags ) );
214
  }
215
  } else {
216
- $author = __('Anonymous');
217
  }
218
 
219
- return array( 'Name' => $theme, 'Title' => $theme, 'URI' => $theme_uri, 'Description' => $description, 'Author' => $author, 'Author_URI' => $author_uri, 'Version' => $version, 'Template' => $template, 'Status' => $status, 'Tags' => $tags );
 
 
 
 
 
 
 
 
 
 
 
220
  }
221
 
222
  /*
@@ -225,22 +248,25 @@ function get_theme_data_from_contents( $theme_data ) {
225
  */
226
  function tc_get_themes() {
227
 
228
- if ( ! class_exists( 'WP_Theme' ) )
229
- return get_themes();
 
230
 
231
  global $wp_themes;
232
- if ( isset( $wp_themes ) )
233
  return $wp_themes;
 
234
 
235
- $themes = wp_get_themes();
236
  $wp_themes = array();
237
 
238
  foreach ( $themes as $theme ) {
239
- $name = $theme->get('Name');
240
- if ( isset( $wp_themes[ $name ] ) )
241
  $wp_themes[ $name . '/' . $theme->get_stylesheet() ] = $theme;
242
- else
243
  $wp_themes[ $name ] = $theme;
 
244
  }
245
 
246
  return $wp_themes;
@@ -248,26 +274,27 @@ function tc_get_themes() {
248
 
249
  function tc_get_theme_data( $theme_file ) {
250
 
251
- if ( ! class_exists( 'WP_Theme' ) )
252
- return get_theme_data( $theme_file );
 
253
 
254
  $theme = new WP_Theme( basename( dirname( $theme_file ) ), dirname( dirname( $theme_file ) ) );
255
 
256
  $theme_data = array(
257
- 'Name' => $theme->get('Name'),
258
- 'URI' => $theme->display('ThemeURI', true, false),
259
- 'Description' => $theme->display('Description', true, false),
260
- 'Author' => $theme->display('Author', true, false),
261
- 'AuthorURI' => $theme->display('AuthorURI', true, false),
262
- 'Version' => $theme->get('Version'),
263
- 'Template' => $theme->get('Template'),
264
- 'Status' => $theme->get('Status'),
265
- 'Tags' => $theme->get('Tags'),
266
- 'Title' => $theme->get('Name'),
267
- 'AuthorName' => $theme->display('Author', false, false),
268
- 'License' => $theme->display( 'License', false, false),
269
- 'License URI' => $theme->display( 'License URI', false, false),
270
- 'Template Version' => $theme->display( 'Template Version', false, false)
271
  );
272
  return $theme_data;
273
  }
7
  global $checkcount;
8
  $checkcount = 0;
9
 
10
+ // interface that all checks should implement.
11
+ interface themecheck {
12
+
13
+ // should return true for good/okay/acceptable, false for bad/not-okay/unacceptable.
14
  public function check( $php_files, $css_files, $other_files );
15
 
16
+ // should return an array of strings explaining any problems found.
17
  public function getError();
18
  }
19
 
20
+ // load all the checks in the checks directory.
21
  $dir = 'checks';
22
+ foreach ( glob( dirname( __FILE__ ) . "/{$dir}/*.php" ) as $file ) {
23
  include $file;
24
  }
25
 
26
+ do_action( 'themecheck_checks_loaded' );
27
 
28
+ function run_themechecks( $php, $css, $other ) {
29
  global $themechecks;
30
  $pass = true;
31
+ foreach ( $themechecks as $check ) {
32
+ if ( $check instanceof themecheck ) {
33
+ $pass = $pass & $check->check( $php, $css, $other );
34
  }
35
  }
36
  return $pass;
40
  $results = '';
41
  global $themechecks;
42
  $errors = array();
43
+ foreach ( $themechecks as $check ) {
44
+ if ( $check instanceof themecheck ) {
45
  $error = $check->getError();
46
  $error = (array) $error;
47
+ if ( ! empty( $error ) ) {
48
  $errors = array_unique( array_merge( $error, $errors ) );
49
  }
50
  }
51
  }
52
+ if ( ! empty( $errors ) ) {
53
+ rsort( $errors );
54
+ foreach ( $errors as $e ) {
55
+
56
+ if ( defined( 'TC_TRAC' ) ) {
57
+ $results .= ( isset( $_POST['s_info'] ) && preg_match( '/INFO/', $e ) ) ? '' : '* ' . tc_trac( $e ) . "\r\n";
58
+ } else {
59
+ $results .= ( isset( $_POST['s_info'] ) && preg_match( '/INFO/', $e ) ) ? '' : '<li>' . tc_trac( $e ) . '</li>';
60
  }
61
  }
62
  }
63
 
64
  if ( defined( 'TC_TRAC' ) ) {
65
 
66
+ if ( defined( 'TC_PRE' ) ) {
67
+ $results = TC_PRE . $results;
68
+ }
69
+ $results = '<textarea cols=140 rows=20>' . wp_strip_all_tags( $results );
70
+ if ( defined( 'TC_POST' ) ) {
71
+ $results = $results . TC_POST;
72
+ }
73
  $results .= '</textarea>';
74
  }
75
  return $results;
80
  $checkcount++;
81
  }
82
 
83
+ // some functions theme checks use.
84
  function tc_grep( $error, $file ) {
85
  if ( ! file_exists( $file ) ) {
86
  return '';
87
  }
88
+ $lines = file( $file, FILE_IGNORE_NEW_LINES ); // Read the theme file into an array.
89
  $line_index = 0;
90
+ $bad_lines = '';
91
+ foreach ( $lines as $this_line ) {
92
+ if ( stristr( $this_line, $error ) ) {
93
+ $error = str_replace( '"', "'", $error );
94
+ $this_line = str_replace( '"', "'", $this_line );
95
+ $error = ltrim( $error );
96
+ $pos = strpos( $this_line, $error );
97
+ $pre = ( false !== $pos ? substr( $this_line, 0, $pos ) : false );
98
+ $pre = ltrim( htmlspecialchars( $pre ) );
99
+ $bad_lines .= "<pre class='tc-grep'>" . __( 'Line ', 'theme-check' ) . ( $line_index + 1 ) . ': ' . $pre . htmlspecialchars( substr( stristr( $this_line, $error ), 0, 75 ) ) . '</pre>';
100
  }
101
  $line_index++;
102
  }
107
  if ( ! file_exists( $file ) ) {
108
  return '';
109
  }
110
+ $lines = file( $file, FILE_IGNORE_NEW_LINES ); // Read the theme file into an array.
111
  $line_index = 0;
112
+ $bad_lines = '';
113
+ $error = '';
114
+ foreach ( $lines as $this_line ) {
115
  if ( preg_match( $preg, $this_line, $matches ) ) {
116
+ $error = $matches[0];
117
  $this_line = str_replace( '"', "'", $this_line );
118
+ $error = ltrim( $error );
119
+ $pre = '';
120
+ if ( ! empty( $error ) ) {
121
+ $pos = strpos( $this_line, $error );
122
+ $pre = ( false !== $pos ? substr( $this_line, 0, $pos ) : false );
123
  }
124
+ $pre = ltrim( htmlspecialchars( $pre ) );
125
+ $bad_lines .= "<pre class='tc-grep'>" . __( 'Line ', 'theme-check' ) . ( $line_index + 1 ) . ': ' . $pre . htmlspecialchars( substr( stristr( $this_line, $error ), 0, 75 ) ) . '</pre>';
126
  }
127
  $line_index++;
128
 
136
  }
137
 
138
  function tc_trac( $e ) {
139
+ $trac_left = array( '<strong>', '</strong>' );
140
+ $trac_right = array( "'''", "'''" );
141
+ $html_link = '/<a\s?href\s?=\s?[\'|"]([^"|\']*)[\'|"]>([^<]*)<\/a>/i';
142
+ $html_new = '[$1 $2]';
143
  if ( defined( 'TC_TRAC' ) ) {
144
  $e = preg_replace( $html_link, $html_new, $e );
145
  $e = str_replace( $trac_left, $trac_right, $e );
150
  }
151
 
152
  function listdir( $dir ) {
153
+ $files = array();
154
  $dir_iterator = new RecursiveDirectoryIterator( $dir );
155
+ $iterator = new RecursiveIteratorIterator( $dir_iterator, RecursiveIteratorIterator::SELF_FIRST );
156
 
157
+ foreach ( $iterator as $file ) {
158
+ array_push( $files, $file->getPathname() );
159
  }
160
  return $files;
161
  }
162
 
163
  function get_theme_data_from_contents( $theme_data ) {
164
  $themes_allowed_tags = array(
165
+ 'a' => array(
166
+ 'href' => array(),
167
+ 'title' => array(),
168
+ ),
169
+ 'abbr' => array(
170
+ 'title' => array(),
171
+ ),
172
  'acronym' => array(
173
+ 'title' => array(),
174
+ ),
175
+ 'code' => array(),
176
+ 'em' => array(),
177
+ 'strong' => array(),
178
  );
179
 
180
+ $theme_data = str_replace( '\r', '\n', $theme_data );
181
  preg_match( '|^[ \t\/*#@]*Theme Name:(.*)$|mi', $theme_data, $theme_name );
182
  preg_match( '|^[ \t\/*#@]*Theme URI:(.*)$|mi', $theme_data, $theme_uri );
183
  preg_match( '|^[ \t\/*#@]*Description:(.*)$|mi', $theme_data, $description );
184
 
185
+ if ( preg_match( '|^[ \t\/*#@]*Author URI:(.*)$|mi', $theme_data, $author_uri ) ) {
186
+ $author_uri = esc_url( trim( $author_uri[1] ) );
187
+ } else {
188
  $author_uri = '';
189
+ }
190
 
191
+ if ( preg_match( '|^[ \t\/*#@]*Template:(.*)$|mi', $theme_data, $template ) ) {
192
  $template = wp_kses( trim( $template[1] ), $themes_allowed_tags );
193
+ } else {
194
  $template = '';
195
+ }
196
 
197
+ if ( preg_match( '|^[ \t\/*#@]*Version:(.*)|mi', $theme_data, $version ) ) {
198
  $version = wp_kses( trim( $version[1] ), $themes_allowed_tags );
199
+ } else {
200
  $version = '';
201
+ }
202
 
203
+ if ( preg_match( '|^[ \t\/*#@]*Status:(.*)|mi', $theme_data, $status ) ) {
204
  $status = wp_kses( trim( $status[1] ), $themes_allowed_tags );
205
+ } else {
206
  $status = 'publish';
207
+ }
208
 
209
+ if ( preg_match( '|^[ \t\/*#@]*Tags:(.*)|mi', $theme_data, $tags ) ) {
210
  $tags = array_map( 'trim', explode( ',', wp_kses( trim( $tags[1] ), array() ) ) );
211
+ } else {
212
  $tags = array();
213
+ }
214
 
215
  $theme = ( isset( $theme_name[1] ) ) ? wp_kses( trim( $theme_name[1] ), $themes_allowed_tags ) : '';
216
 
222
  if ( empty( $author_uri ) ) {
223
  $author = wp_kses( trim( $author_name[1] ), $themes_allowed_tags );
224
  } else {
225
+ $author = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $author_uri, __( 'Visit author homepage', 'theme-check' ), wp_kses( trim( $author_name[1] ), $themes_allowed_tags ) );
226
  }
227
  } else {
228
+ $author = __( 'Anonymous', 'theme-check' );
229
  }
230
 
231
+ return array(
232
+ 'Name' => $theme,
233
+ 'Title' => $theme,
234
+ 'URI' => $theme_uri,
235
+ 'Description' => $description,
236
+ 'Author' => $author,
237
+ 'Author_URI' => $author_uri,
238
+ 'Version' => $version,
239
+ 'Template' => $template,
240
+ 'Status' => $status,
241
+ 'Tags' => $tags,
242
+ );
243
  }
244
 
245
  /*
248
  */
249
  function tc_get_themes() {
250
 
251
+ if ( ! class_exists( 'WP_Theme' ) ) {
252
+ return wp_get_theme();
253
+ }
254
 
255
  global $wp_themes;
256
+ if ( isset( $wp_themes ) ) {
257
  return $wp_themes;
258
+ }
259
 
260
+ $themes = wp_get_themes();
261
  $wp_themes = array();
262
 
263
  foreach ( $themes as $theme ) {
264
+ $name = $theme->get( 'Name' );
265
+ if ( isset( $wp_themes[ $name ] ) ) {
266
  $wp_themes[ $name . '/' . $theme->get_stylesheet() ] = $theme;
267
+ } else {
268
  $wp_themes[ $name ] = $theme;
269
+ }
270
  }
271
 
272
  return $wp_themes;
274
 
275
  function tc_get_theme_data( $theme_file ) {
276
 
277
+ if ( ! class_exists( 'WP_Theme' ) ) {
278
+ return wp_get_theme( $theme_file );
279
+ }
280
 
281
  $theme = new WP_Theme( basename( dirname( $theme_file ) ), dirname( dirname( $theme_file ) ) );
282
 
283
  $theme_data = array(
284
+ 'Name' => $theme->get( 'Name' ),
285
+ 'URI' => $theme->display( 'ThemeURI', true, false ),
286
+ 'Description' => $theme->display( 'Description', true, false ),
287
+ 'Author' => $theme->display( 'Author', true, false ),
288
+ 'AuthorURI' => $theme->display( 'AuthorURI', true, false ),
289
+ 'Version' => $theme->get( 'Version' ),
290
+ 'Template' => $theme->get( 'Template' ),
291
+ 'Status' => $theme->get( 'Status' ),
292
+ 'Tags' => $theme->get( 'Tags' ),
293
+ 'Title' => $theme->get( 'Name' ),
294
+ 'AuthorName' => $theme->display( 'Author', false, false ),
295
+ 'License' => $theme->display( 'License', false, false ),
296
+ 'License URI' => $theme->display( 'License URI', false, false ),
297
+ 'Template Version' => $theme->display( 'Template Version', false, false ),
298
  );
299
  return $theme_data;
300
  }
checks/badthings.php CHANGED
@@ -14,7 +14,10 @@ class Bad_Checks implements themecheck {
14
  '/uudecode/ims' => __( 'uudecode() is not allowed', 'theme-check' ),
15
  '/str_rot13/ims' => __( 'str_rot13() is not allowed', 'theme-check' ),
16
  '/cx=[0-9]{21}:[a-z0-9]{10}/' => __( 'Google search code detected', 'theme-check' ),
17
- '/pub-[0-9]{16}/i' => __( 'Google advertising code detected', 'theme-check' )
 
 
 
18
  );
19
 
20
  $grep = '';
14
  '/uudecode/ims' => __( 'uudecode() is not allowed', 'theme-check' ),
15
  '/str_rot13/ims' => __( 'str_rot13() is not allowed', 'theme-check' ),
16
  '/cx=[0-9]{21}:[a-z0-9]{10}/' => __( 'Google search code detected', 'theme-check' ),
17
+ '/pub-[0-9]{16}/i' => __( 'Google advertising code detected', 'theme-check' ),
18
+ '/sharesale/i' => __( 'Sharesale affiliate link detected', 'theme-check' ),
19
+ '/affiliate_id/i' => __( 'Potential affiliate link detected', 'theme-check' ),
20
+ '/(elementor_partner_id)|(wpbeaverbuilder.*?fla)/i' => __( 'Potential affiliate link detected', 'theme-check' ),
21
  );
22
 
23
  $grep = '';
checks/postthumb.php CHANGED
@@ -16,7 +16,7 @@ class PostThumbnailCheck implements themecheck {
16
  }
17
 
18
  if ( strpos( $php, 'post-thumbnails' ) === false ) {
19
- $this->error[] = '<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('No reference to post-thumbnails was found in the theme. If the theme has a thumbnail like functionality, it should be implemented with <strong>add_theme_support( "post-thumbnails" )</strong>in the functions.php file.', 'theme-check' );
20
  }
21
 
22
  return $ret;
@@ -24,4 +24,4 @@ class PostThumbnailCheck implements themecheck {
24
 
25
  function getError() { return $this->error; }
26
  }
27
- $themechecks[] = new PostThumbnailCheck;
16
  }
17
 
18
  if ( strpos( $php, 'post-thumbnails' ) === false ) {
19
+ $this->error[] = '<span class="tc-lead tc-recommended">'.__('RECOMMENDED','theme-check').'</span>: '.__('No reference to post-thumbnails was found in the theme. If the theme has a thumbnail like functionality, it should be implemented with <strong>add_theme_support( "post-thumbnails" )</strong> in the functions.php file.', 'theme-check' );
20
  }
21
 
22
  return $ret;
24
 
25
  function getError() { return $this->error; }
26
  }
27
+ $themechecks[] = new PostThumbnailCheck;
checks/style_tags.php CHANGED
@@ -5,25 +5,24 @@ class Style_Tags implements themecheck {
5
  function check( $php_files, $css_files, $other_files ) {
6
 
7
  checkcount();
8
- $ret = true;
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' );
@@ -47,14 +46,14 @@ class Style_Tags implements themecheck {
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
  }
@@ -64,5 +63,96 @@ class Style_Tags implements themecheck {
64
  }
65
 
66
  function getError() { return $this->error; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
- $themechecks[] = new Style_Tags;
5
  function check( $php_files, $css_files, $other_files ) {
6
 
7
  checkcount();
8
+ $ret = true;
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
+ } else {
19
+ $deprecated_tags = $this->get_deprecated_tags();
20
+ $allowed_tags = $this->get_allowed_tags();
21
+ $subject_tags = $this->get_subject_tags();
 
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' );
46
  if ( in_array( strtolower( $tag ), $allowed_tags ) ) {
47
  if ( count( array_keys ($data[ 'Tags' ], $tag ) ) > 1) {
48
  $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>' );
49
+ $ret = false;
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
  }
63
  }
64
 
65
  function getError() { return $this->error; }
66
+
67
+ /**
68
+ * Get full list of allowed tags - including subject tags.
69
+ *
70
+ * @return array
71
+ */
72
+ private function get_allowed_tags() {
73
+ $allowed_tags = array(
74
+ 'grid-layout',
75
+ 'one-column',
76
+ 'two-columns',
77
+ 'three-columns',
78
+ 'four-columns',
79
+ 'left-sidebar',
80
+ 'right-sidebar',
81
+ 'wide-blocks',
82
+ 'flexible-header',
83
+ 'footer-widgets',
84
+ 'accessibility-ready',
85
+ 'block-patterns',
86
+ 'block-styles',
87
+ 'buddypress',
88
+ 'custom-background',
89
+ 'custom-colors',
90
+ 'custom-header',
91
+ 'custom-logo',
92
+ 'custom-menu',
93
+ 'editor-style',
94
+ 'featured-image-header',
95
+ 'featured-images',
96
+ 'front-page-post-form',
97
+ 'full-width-template',
98
+ 'full-site-editing',
99
+ 'microformats',
100
+ 'post-formats',
101
+ 'rtl-language-support',
102
+ 'sticky-post',
103
+ 'theme-options',
104
+ 'threaded-comments',
105
+ 'translation-ready',
106
+ );
107
+ return array_merge( $allowed_tags, self::get_subject_tags() );
108
+ }
109
+
110
+ /**
111
+ * Get the list of subject tags.
112
+ *
113
+ * @return array
114
+ */
115
+ private function get_subject_tags() {
116
+ return array(
117
+ 'blog',
118
+ 'e-commerce',
119
+ 'education',
120
+ 'entertainment',
121
+ 'food-and-drink',
122
+ 'holiday',
123
+ 'news',
124
+ 'photography',
125
+ 'portfolio',
126
+ );
127
+ }
128
+
129
+ private function get_deprecated_tags() {
130
+ return array(
131
+ 'flexible-width',
132
+ 'fixed-width',
133
+ 'black',
134
+ 'blue',
135
+ 'brown',
136
+ 'gray',
137
+ 'green',
138
+ 'orange',
139
+ 'pink',
140
+ 'purple',
141
+ 'red',
142
+ 'silver',
143
+ 'tan',
144
+ 'white',
145
+ 'yellow',
146
+ 'dark',
147
+ 'light',
148
+ 'fixed-layout',
149
+ 'fluid-layout',
150
+ 'responsive-layout',
151
+ 'blavatar',
152
+ 'holiday',
153
+ 'photoblogging',
154
+ 'seasonal',
155
+ );
156
+ }
157
  }
158
+ $themechecks[] = new Style_Tags();
main.php CHANGED
@@ -2,153 +2,209 @@
2
  function check_main( $theme ) {
3
  global $themechecks, $data, $themename;
4
  $themename = $theme;
5
- $theme = get_theme_root( $theme ) . "/$theme";
6
- $files = listdir( $theme );
7
- $data = tc_get_theme_data( $theme . '/style.css' );
8
- if ( $data[ 'Template' ] ) {
9
  // This is a child theme, so we need to pull files from the parent, which HAS to be installed.
10
- $parent = get_theme_root( $data[ 'Template' ] ) . '/' . $data['Template'];
11
  if ( ! tc_get_theme_data( $parent . '/style.css' ) ) { // This should never happen but we will check while were here!
12
- echo '<h2>' . sprintf(__('Parent theme %1$s not found! You have to have parent AND child-theme installed!', 'theme-check'), '<strong>' . $data[ 'Template' ] . '</strong>' ) . '</h2>';
 
 
 
 
 
 
13
  return;
14
  }
15
  $parent_data = tc_get_theme_data( $parent . '/style.css' );
16
- $themename = basename( $parent );
17
- $files = array_merge( listdir( $parent ), $files );
18
  }
19
 
20
  if ( $files ) {
21
- foreach( $files as $key => $filename ) {
22
- if ( substr( $filename, -4 ) == '.php' && ! is_dir( $filename ) ) {
23
- $php[$filename] = file_get_contents( $filename );
24
- $php[$filename] = tc_strip_comments( $php[$filename] );
25
- }
26
- else if ( substr( $filename, -4 ) == '.css' && ! is_dir( $filename ) ) {
27
- $css[$filename] = file_get_contents( $filename );
28
- }
29
- else {
30
- $other[$filename] = ( ! is_dir($filename) ) ? file_get_contents( $filename ) : '';
 
 
 
 
 
31
  }
32
  }
33
 
34
- // run the checks
35
- $success = run_themechecks($php, $css, $other);
36
 
37
  global $checkcount;
38
 
39
- // second loop, to display the errors
40
- echo '<h2>' . __( 'Theme Info', 'theme-check' ) . ': </h2>';
41
  echo '<div class="theme-info">';
42
- if (file_exists( trailingslashit( WP_CONTENT_DIR . '/themes' ) . trailingslashit( basename( $theme ) ) . 'screenshot.png' ) ) {
43
  $image = getimagesize( $theme . '/screenshot.png' );
44
  echo '<div style="float:right" class="theme-info"><img style="max-height:180px;" src="' . trailingslashit( WP_CONTENT_URL . '/themes' ) . trailingslashit( basename( $theme ) ) . 'screenshot.png" />';
45
- echo '<br /><div style="text-align:center">' . $image[0] . 'x' . $image[1] . ' ' . round( filesize( $theme . '/screenshot.png' )/1024 ) . 'k</div></div>';
46
  }
47
 
48
- echo ( !empty( $data[ 'Title' ] ) ) ? '<p><label>' . __( 'Title', 'theme-check' ) . '</label><span class="info">' . $data[ 'Title' ] . '</span></p>' : '';
49
- echo ( !empty( $data[ 'Version' ] ) ) ? '<p><label>' . __( 'Version', 'theme-check' ) . '</label><span class="info">' . $data[ 'Version' ] . '</span></p>' : '';
50
- echo ( !empty( $data[ 'AuthorName' ] ) ) ? '<p><label>' . __( 'Author', 'theme-check' ) . '</label><span class="info">' . $data[ 'AuthorName' ] . '</span></p>' : '';
51
- echo ( !empty( $data[ 'AuthorURI' ] ) ) ? '<p><label>' . __( 'Author URI', 'theme-check' ) . '</label><span class="info"><a href="' . $data[ 'AuthorURI' ] . '">' . $data[ 'AuthorURI' ] . '</a>' . '</span></p>' : '';
52
- echo ( !empty( $data[ 'URI' ] ) ) ? '<p><label>' . __( 'Theme URI', 'theme-check' ) . '</label><span class="info"><a href="' . $data[ 'URI' ] . '">' . $data[ 'URI' ] . '</a>' . '</span></p>' : '';
53
- echo ( !empty( $data[ 'License' ] ) ) ? '<p><label>' . __( 'License', 'theme-check' ) . '</label><span class="info">' . $data[ 'License' ] . '</span></p>' : '';
54
- echo ( !empty( $data[ 'License URI' ] ) ) ? '<p><label>' . __( 'License URI', 'theme-check' ) . '</label><span class="info">' . $data[ 'License URI' ] . '</span></p>' : '';
55
- echo ( !empty( $data[ 'Tags' ] ) ) ? '<p><label>' . __( 'Tags', 'theme-check' ) . '</label><span class="info">' . implode( ', ', $data[ 'Tags' ] ) . '</span></p>' : '';
56
- echo ( !empty( $data[ 'Description' ] ) ) ? '<p><label>' . __( 'Description', 'theme-check' ) . '</label><span class="info">' . $data[ 'Description' ] . '</span></p>' : '';
57
 
58
- if ( $data[ 'Template' ] ) {
59
- if ( $data['Template Version'] > $parent_data['Version'] ) {
60
- echo '<p>' . sprintf(
61
- __('This child theme requires at least version %1$s of theme %2$s to be installed. You only have %3$s please update the parent theme.', 'theme-check'),
62
- '<strong>' . $data['Template Version'] . '</strong>',
63
- '<strong>' . $parent_data['Title'] . '</strong>',
64
- '<strong>' . $parent_data['Version'] . '</strong>'
65
- ) . '</p>';
66
- }
67
  echo '<p>' . sprintf(
68
- __( 'This is a child theme. The parent theme is: %s. These files have been included automatically!', 'theme-check'),
69
- '<strong>' . $data[ 'Template' ] . '</strong>'
 
70
  ) . '</p>';
71
  if ( empty( $data['Template Version'] ) ) {
72
- echo '<p>' . __('Child theme does not have the <strong>Template Version</strong> tag in style.css.', 'theme-check') . '</p>';
73
  } else {
74
- echo ( $data['Template Version'] < $parent_data['Version'] ) ? '<p>' . sprintf(__('Child theme is only tested up to version %1$s of %2$s breakage may occur! %3$s installed version is %4$s', 'theme-check'), $data['Template Version'], $parent_data['Title'], $parent_data['Title'], $parent_data['Version'] ) . '</p>' : '';
75
  }
76
- }
77
  echo '</div><!-- .theme-info-->';
78
 
79
  $plugins = get_plugins( '/theme-check' );
80
  $version = explode( '.', $plugins['theme-check.php']['Version'] );
81
  echo '<p>' . sprintf(
82
- __(' Running %1$s tests against %2$s using Guidelines Version: %3$s Plugin revision: %4$s', 'theme-check'),
83
- '<strong>' . $checkcount . '</strong>',
84
- '<strong>' . $data[ 'Title' ] . '</strong>',
85
- '<strong>' . $version[0] . '</strong>',
86
- '<strong>' . $version[1] . '</strong>'
87
  ) . '</p>';
88
  $results = display_themechecks();
89
- if ( !$success ) {
90
- echo '<h2>' . sprintf(__('One or more errors were found for %1$s.', 'theme-check'), $data[ 'Title' ] ) . '</h2>';
91
  } else {
92
- echo '<h2>' . sprintf(__('%1$s passed the tests', 'theme-check'), $data[ 'Title' ] ) . '</h2>';
93
  tc_success();
94
  }
95
- if ( !defined( 'WP_DEBUG' ) || WP_DEBUG == false ) echo '<div class="updated"><span class="tc-fail">' . __('WARNING','theme-check') . '</span> ' . __( '<strong>WP_DEBUG is not enabled!</strong> Please test your theme with <a href="https://wordpress.org/support/article/editing-wp-config-php/">debug enabled</a> before you upload!', 'theme-check' ) . '</div>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  echo '<div class="tc-box">';
97
  echo '<ul class="tc-result">';
98
- echo $results;
 
 
 
 
 
 
 
 
 
99
  echo '</ul></div>';
100
  }
101
  }
102
 
103
- // strip comments from a PHP file in a way that will not change the underlying structure of the file
104
  function tc_strip_comments( $code ) {
105
- $strip = array( T_COMMENT => true, T_DOC_COMMENT => true);
106
- $newlines = array( "\n" => true, "\r" => true );
107
- $tokens = token_get_all($code);
108
- reset($tokens);
 
 
 
 
 
 
109
  $return = '';
110
- $token = current($tokens);
111
- while( $token ) {
112
- if( !is_array($token) ) {
113
- $return.= $token;
114
- } elseif( !isset( $strip[ $token[0] ] ) ) {
115
- $return.= $token[1];
116
  } else {
117
- for( $i = 0, $token_length = strlen($token[1]); $i < $token_length; ++$i )
118
- if( isset($newlines[ $token[1][$i] ]) )
119
- $return.= $token[1][$i];
 
 
120
  }
121
- $token = next($tokens);
122
  }
123
  return $return;
124
  }
125
 
126
 
127
  function tc_intro() {
128
- ?>
129
- <h2><?php _e( 'About', 'theme-check' ); ?></h2>
130
- <p><?php _e( "The Theme Check plugin is an easy way to test your theme and make sure it's up to date with the latest theme review standards. With it, you can run all the same automated testing tools on your theme that WordPress.org uses for theme submissions.", 'theme-check' ); ?></p>
131
- <h2><?php _e( 'Contact', 'theme-check' ); ?></h2>
132
- <p><?php printf( __( 'Theme Check is maintained by %1$s and %2$s.', 'theme-check' ),
 
 
 
133
  '<a href="https://profiles.wordpress.org/otto42/">Otto42</a>',
134
  '<a href="https://profiles.wordpress.org/pross/">Pross</a>'
135
  ); ?></p>
136
- <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 theme review 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>
137
- <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>
138
- <h3><?php _e( 'Testers', 'theme-check' ); ?></h3>
139
- <p><a href="https://make.wordpress.org/themes/"><?php _e( 'The WordPress Theme Review Team', 'theme-check' ); ?></a></p>
140
  <?php
141
  }
142
 
143
  function tc_success() {
144
  ?>
145
- <div class="tc-success"><p><?php _e( 'Now that your theme has passed the basic tests you need to check it properly using the test data before you upload it to the WordPress Themes Directory.', 'theme-check' ); ?></p>
146
- <p><?php _e( 'Make sure to review the guidelines at <a href="https://make.wordpress.org/themes/handbook/review/required/">Theme Review</a> before uploading a Theme.', 'theme-check' ); ?></p>
147
- <h3><?php _e( 'Useful Links', 'theme-check' ); ?></h3>
 
 
 
 
 
 
 
 
 
148
  <ul>
149
- <li><a href="https://developer.wordpress.org/themes/"><?php _e( 'Theme Handbook', 'theme-check' ); ?></a></li>
150
- <li><a href="https://wordpress.org/support/forum/wp-advanced/"><?php _e( 'Developing with WordPress Forum', 'theme-check' ); ?></a></li>
151
- <li><a href="https://github.com/WPTRT/theme-unit-test"><?php _e( 'Theme Unit Tests', 'theme-check' ); ?></a></li>
152
  </ul></div>
153
  <?php
154
  }
@@ -157,7 +213,7 @@ function tc_form() {
157
  $themes = tc_get_themes();
158
  echo '<form action="themes.php?page=themecheck" method="post">';
159
  echo '<select name="themename">';
160
- foreach( $themes as $name => $location ) {
161
  echo '<option ';
162
  if ( isset( $_POST['themename'] ) ) {
163
  echo ( $location['Stylesheet'] === $_POST['themename'] ) ? 'selected="selected" ' : '';
@@ -167,9 +223,37 @@ function tc_form() {
167
  echo ( basename( STYLESHEETPATH ) === $location['Stylesheet'] ) ? 'value="' . $location['Stylesheet'] . '" style="font-weight:bold;">' . $name . '</option>' : 'value="' . $location['Stylesheet'] . '">' . $name . '</option>';
168
  }
169
  echo '</select>';
170
- echo '<input class="button" type="submit" value="' . __( 'Check it!', 'theme-check' ) . '" />';
171
- if ( defined( 'TC_PRE' ) || defined( 'TC_POST' ) ) echo ' <input name="trac" type="checkbox" /> ' . __( 'Output in Trac format.', 'theme-check' );
172
- echo '<input name="s_info" type="checkbox" /> ' . __( 'Suppress INFO.', 'theme-check' );
 
 
173
  wp_nonce_field( 'themecheck-nonce' );
174
  echo '</form>';
175
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  function check_main( $theme ) {
3
  global $themechecks, $data, $themename;
4
  $themename = $theme;
5
+ $theme = get_theme_root( $theme ) . "/$theme";
6
+ $files = listdir( $theme );
7
+ $data = tc_get_theme_data( $theme . '/style.css' );
8
+ if ( $data['Template'] ) {
9
  // This is a child theme, so we need to pull files from the parent, which HAS to be installed.
10
+ $parent = get_theme_root( $data['Template'] ) . '/' . $data['Template'];
11
  if ( ! tc_get_theme_data( $parent . '/style.css' ) ) { // This should never happen but we will check while were here!
12
+ echo '<h2>';
13
+ printf(
14
+ /* translators: The parent theme name. */
15
+ esc_html__( 'Parent theme %1$s not found! You have to have parent AND child-theme installed!', 'theme-check' ),
16
+ '<strong>' . esc_html( $data['Template'] ) . '</strong>'
17
+ );
18
+ echo '</h2>';
19
  return;
20
  }
21
  $parent_data = tc_get_theme_data( $parent . '/style.css' );
22
+ $themename = basename( $parent );
23
+ $files = array_merge( listdir( $parent ), $files );
24
  }
25
 
26
  if ( $files ) {
27
+ foreach ( $files as $key => $filename ) {
28
+ if ( substr( $filename, -4 ) === '.php' && ! is_dir( $filename ) ) {
29
+ $php[ $filename ] = file_get_contents( $filename );
30
+ $php[ $filename ] = tc_strip_comments( $php[ $filename ] );
31
+ } elseif ( substr( $filename, -4 ) === '.css' && ! is_dir( $filename ) ) {
32
+ $css[ $filename ] = file_get_contents( $filename );
33
+ } else {
34
+ // In local development it might be useful to skip other files
35
+ // (non .php or .css files) in dev directories.
36
+ if ( apply_filters( 'tc_skip_development_directories', false ) ) {
37
+ if ( tc_is_other_file_in_dev_directory( $filename ) ) {
38
+ continue;
39
+ }
40
+ }
41
+ $other[ $filename ] = ( ! is_dir( $filename ) ) ? file_get_contents( $filename ) : '';
42
  }
43
  }
44
 
45
+ // Run the checks.
46
+ $success = run_themechecks( $php, $css, $other );
47
 
48
  global $checkcount;
49
 
50
+ // Second loop, to display the errors.
51
+ echo '<h2>' . esc_html__( 'Theme Info', 'theme-check' ) . ': </h2>';
52
  echo '<div class="theme-info">';
53
+ if ( file_exists( trailingslashit( WP_CONTENT_DIR . '/themes' ) . trailingslashit( basename( $theme ) ) . 'screenshot.png' ) ) {
54
  $image = getimagesize( $theme . '/screenshot.png' );
55
  echo '<div style="float:right" class="theme-info"><img style="max-height:180px;" src="' . trailingslashit( WP_CONTENT_URL . '/themes' ) . trailingslashit( basename( $theme ) ) . 'screenshot.png" />';
56
+ echo '<br /><div style="text-align:center">' . $image[0] . 'x' . $image[1] . ' ' . round( filesize( $theme . '/screenshot.png' ) / 1024 ) . 'k</div></div>';
57
  }
58
 
59
+ echo ( ! empty( $data['Title'] ) ) ? '<p><label>' . esc_html__( 'Title', 'theme-check' ) . '</label><span class="info">' . esc_html( $data['Title'] ) . '</span></p>' : '';
60
+ echo ( ! empty( $data['Version'] ) ) ? '<p><label>' . esc_html__( 'Version', 'theme-check' ) . '</label><span class="info">' . esc_html( $data['Version'] ) . '</span></p>' : '';
61
+ echo ( ! empty( $data['AuthorName'] ) ) ? '<p><label>' . esc_html__( 'Author', 'theme-check' ) . '</label><span class="info">' . esc_html( $data['AuthorName'] ) . '</span></p>' : '';
62
+ echo ( ! empty( $data['AuthorURI'] ) ) ? '<p><label>' . esc_html__( 'Author URI', 'theme-check' ) . '</label><span class="info"><a href="' . esc_attr( $data['AuthorURI'] ) . '">' . $data['AuthorURI'] . '</a></span></p>' : '';
63
+ echo ( ! empty( $data['URI'] ) ) ? '<p><label>' . esc_html__( 'Theme URI', 'theme-check' ) . '</label><span class="info"><a href="' . esc_attr( $data['URI'] ) . '">' . $data['URI'] . '</a></span></p>' : '';
64
+ echo ( ! empty( $data['License'] ) ) ? '<p><label>' . esc_html__( 'License', 'theme-check' ) . '</label><span class="info">' . esc_html( $data['License'] ) . '</span></p>' : '';
65
+ echo ( ! empty( $data['License URI'] ) ) ? '<p><label>' . esc_html__( 'License URI', 'theme-check' ) . '</label><span class="info">' . $data['License URI'] . '</span></p>' : '';
66
+ echo ( ! empty( $data['Tags'] ) ) ? '<p><label>' . esc_html__( 'Tags', 'theme-check' ) . '</label><span class="info">' . implode( ', ', $data['Tags'] ) . '</span></p>' : '';
67
+ echo ( ! empty( $data['Description'] ) ) ? '<p><label>' . esc_html__( 'Description', 'theme-check' ) . '</label><span class="info">' . $data['Description'] . '</span></p>' : '';
68
 
69
+ if ( $data['Template'] ) {
70
+ if ( $data['Template Version'] > $parent_data['Version'] ) {
71
+ echo '<p>' . sprintf(
72
+ esc_html__( 'This child theme requires at least version %1$s of theme %2$s to be installed. You only have %3$s please update the parent theme.', 'theme-check' ),
73
+ '<strong>' . esc_html( $data['Template Version'] ) . '</strong>',
74
+ '<strong>' . esc_html( $parent_data['Title'] ) . '</strong>',
75
+ '<strong>' . esc_html( $parent_data['Version'] ) . '</strong>'
76
+ ) . '</p>';
77
+ }
78
  echo '<p>' . sprintf(
79
+ /* translators: %s: Name of the parent theme. */
80
+ esc_html__( 'This is a child theme. The parent theme is: %s. These files have been included automatically!', 'theme-check' ),
81
+ '<strong>' . esc_html( $data['Template'] ) . '</strong>'
82
  ) . '</p>';
83
  if ( empty( $data['Template Version'] ) ) {
84
+ echo '<p>' . esc_html__( 'Child theme does not have the <strong>Template Version</strong> tag in style.css.', 'theme-check' ) . '</p>';
85
  } else {
86
+ echo ( $data['Template Version'] < $parent_data['Version'] ) ? '<p>' . sprintf( esc_html__( 'Child theme is only tested up to version %1$s of %2$s breakage may occur! %3$s installed version is %4$s', 'theme-check' ), esc_html( $data['Template Version'] ), esc_html( $parent_data['Title'] ), esc_html( $parent_data['Title'] ), esc_html( $parent_data['Version'] ) ) . '</p>' : '';
87
  }
88
+ }
89
  echo '</div><!-- .theme-info-->';
90
 
91
  $plugins = get_plugins( '/theme-check' );
92
  $version = explode( '.', $plugins['theme-check.php']['Version'] );
93
  echo '<p>' . sprintf(
94
+ esc_html__( ' Running %1$s tests against %2$s using Guidelines Version: %3$s Plugin revision: %4$s', 'theme-check' ),
95
+ '<strong>' . esc_html( $checkcount ) . '</strong>',
96
+ '<strong>' . esc_html( $data['Title'] ) . '</strong>',
97
+ '<strong>' . esc_html( $version[0] ) . '</strong>',
98
+ '<strong>' . esc_html( $version[1] ) . '</strong>'
99
  ) . '</p>';
100
  $results = display_themechecks();
101
+ if ( ! $success ) {
102
+ echo '<h2>' . sprintf( esc_html__( 'One or more errors were found for %1$s.', 'theme-check' ), esc_html( $data['Title'] ) ) . '</h2>';
103
  } else {
104
+ echo '<h2>' . sprintf( __( '%1$s passed the tests', 'theme-check' ), esc_html( $data['Title'] ) ) . '</h2>';
105
  tc_success();
106
  }
107
+ if ( ! defined( 'WP_DEBUG' ) || WP_DEBUG === false ) {
108
+ echo '<div class="updated">';
109
+ echo '<span class="tc-fail">';
110
+ echo esc_html__( 'WARNING', 'theme-check' );
111
+ echo '</span> ';
112
+ echo '<strong>';
113
+ echo esc_html__( 'WP_DEBUG is not enabled!', 'theme-check' );
114
+ echo '</strong>';
115
+ printf(
116
+ /* translators: %1$s is an opening anchor tag. %2$s is the closing part of the tag. */
117
+ esc_html__( 'Please test your theme with %1$sdebug enabled%2$s before you upload!', 'theme-check' ),
118
+ '<a href="https://wordpress.org/support/article/editing-wp-config-php/">',
119
+ '</a>'
120
+ );
121
+ echo '</div>';
122
+ }
123
  echo '<div class="tc-box">';
124
  echo '<ul class="tc-result">';
125
+ echo wp_kses(
126
+ $results,
127
+ array(
128
+ 'li' => array(),
129
+ 'span' => array(
130
+ 'class' => array(),
131
+ ),
132
+ 'strong' => array(),
133
+ )
134
+ );
135
  echo '</ul></div>';
136
  }
137
  }
138
 
139
+ // Strip comments from a PHP file in a way that will not change the underlying structure of the file.
140
  function tc_strip_comments( $code ) {
141
+ $strip = array(
142
+ T_COMMENT => true,
143
+ T_DOC_COMMENT => true,
144
+ );
145
+ $newlines = array(
146
+ "\n" => true,
147
+ "\r" => true,
148
+ );
149
+ $tokens = token_get_all( $code );
150
+ reset( $tokens );
151
  $return = '';
152
+ $token = current( $tokens );
153
+ while ( $token ) {
154
+ if ( ! is_array( $token ) ) {
155
+ $return .= $token;
156
+ } elseif ( ! isset( $strip[ $token[0] ] ) ) {
157
+ $return .= $token[1];
158
  } else {
159
+ for ( $i = 0, $token_length = strlen( $token[1] ); $i < $token_length; ++$i ) {
160
+ if ( isset( $newlines[ $token[1][ $i ] ] ) ) {
161
+ $return .= $token[1][ $i ];
162
+ }
163
+ }
164
  }
165
+ $token = next( $tokens );
166
  }
167
  return $return;
168
  }
169
 
170
 
171
  function tc_intro() {
172
+ ?>
173
+ <h2><?php esc_html_e( 'About', 'theme-check' ); ?></h2>
174
+ <p><?php esc_html_e( "The Theme Check plugin is an easy way to test your theme and make sure it's up to date with the latest theme review standards. With it, you can run all the same automated testing tools on your theme that WordPress.org uses for theme submissions.", 'theme-check' ); ?></p>
175
+ <h2><?php esc_html_e( 'Contact', 'theme-check' ); ?></h2>
176
+ <p>
177
+ <?php
178
+ printf(
179
+ esc_html__( 'Theme Check is maintained by %1$s and %2$s.', 'theme-check' ),
180
  '<a href="https://profiles.wordpress.org/otto42/">Otto42</a>',
181
  '<a href="https://profiles.wordpress.org/pross/">Pross</a>'
182
  ); ?></p>
183
+ <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>
184
+ <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>
185
+ <h3><?php esc_html_e( 'Testers', 'theme-check' ); ?></h3>
186
+ <p><a href="https://make.wordpress.org/themes/"><?php esc_html_e( 'The WordPress Themes Team', 'theme-check' ); ?></a></p>
187
  <?php
188
  }
189
 
190
  function tc_success() {
191
  ?>
192
+ <div class="tc-success"><p><?php esc_html_e( 'Now that your theme has passed the basic tests you need to check it properly using the test data before you upload it to the WordPress Themes Directory.', 'theme-check' ); ?></p>
193
+ <p>
194
+ <?php
195
+ printf(
196
+ /* translators: %1$s is an opening anchor tag. %2$s is the closing part of the tag. */
197
+ esc_html__( 'Make sure to review the guidelines at %1$sTheme Review%2$s before uploading a Theme.', 'theme-check' ),
198
+ '<a href="https://make.wordpress.org/themes/handbook/review/required/">',
199
+ '</a>'
200
+ );
201
+ ?>
202
+ </p>
203
+ <h3><?php esc_html_e( 'Useful Links', 'theme-check' ); ?></h3>
204
  <ul>
205
+ <li><a href="https://developer.wordpress.org/themes/"><?php esc_html_e( 'Theme Handbook', 'theme-check' ); ?></a></li>
206
+ <li><a href="https://wordpress.org/support/forum/wp-advanced/"><?php esc_html_e( 'Developing with WordPress Forum', 'theme-check' ); ?></a></li>
207
+ <li><a href="https://github.com/WPTRT/theme-unit-test"><?php esc_html_e( 'Theme Unit Tests', 'theme-check' ); ?></a></li>
208
  </ul></div>
209
  <?php
210
  }
213
  $themes = tc_get_themes();
214
  echo '<form action="themes.php?page=themecheck" method="post">';
215
  echo '<select name="themename">';
216
+ foreach ( $themes as $name => $location ) {
217
  echo '<option ';
218
  if ( isset( $_POST['themename'] ) ) {
219
  echo ( $location['Stylesheet'] === $_POST['themename'] ) ? 'selected="selected" ' : '';
223
  echo ( basename( STYLESHEETPATH ) === $location['Stylesheet'] ) ? 'value="' . $location['Stylesheet'] . '" style="font-weight:bold;">' . $name . '</option>' : 'value="' . $location['Stylesheet'] . '">' . $name . '</option>';
224
  }
225
  echo '</select>';
226
+ echo '<input class="button" type="submit" value="' . esc_attr__( 'Check it!', 'theme-check' ) . '" />';
227
+ if ( defined( 'TC_PRE' ) || defined( 'TC_POST' ) ) {
228
+ echo ' <input name="trac" type="checkbox" /> ' . esc_html__( 'Output in Trac format.', 'theme-check' );
229
+ }
230
+ echo '<input name="s_info" type="checkbox" /> ' . esc_html__( 'Suppress INFO.', 'theme-check' );
231
  wp_nonce_field( 'themecheck-nonce' );
232
  echo '</form>';
233
  }
234
+
235
+ /**
236
+ * Used to allow some directories to be skipped during development.
237
+ *
238
+ * @param string $filename a filename/path
239
+ * @return boolean
240
+ */
241
+ function tc_is_other_file_in_dev_directory( $filename ) {
242
+ $skip = false;
243
+ // Filterable List of dirs that you may want to skip other files in during
244
+ // development.
245
+ $dev_dirs = apply_filters(
246
+ 'tc_common_dev_directories',
247
+ array(
248
+ 'node_modules',
249
+ 'vendor',
250
+ )
251
+ );
252
+ foreach ( $dev_dirs as $dev_dir ) {
253
+ if ( strpos( $filename, $dev_dir ) ) {
254
+ $skip = true;
255
+ break;
256
+ }
257
+ }
258
+ return $skip;
259
+ }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: Otto42, pross, poena, dingo-d, acosmin, joyously
3
  Requires at Least: 3.7
4
  Tested Up To: 5.4
5
  Tags: template, theme, check, checker, tool, wordpress.org, upload, uploader, test, guideline, review
6
- Stable tag: 20200731.1
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
 
@@ -52,5 +52,6 @@ comments, or feedback:[[br]]
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
  = 20200504.1 =
56
  * Changes can be found in the changelog.txt file.
3
  Requires at Least: 3.7
4
  Tested Up To: 5.4
5
  Tags: template, theme, check, checker, tool, wordpress.org, upload, uploader, test, guideline, review
6
+ Stable tag: 20200922.1
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
 
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.
theme-check.php CHANGED
@@ -1,14 +1,14 @@
1
  <?php
2
- /*
3
- Plugin Name: Theme Check
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: The WordPress Theme Review Team
7
- Version: 20200731.1
8
- Text Domain: theme-check
9
- License: GPLv2
10
- License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
- */
12
 
13
  class ThemeCheckMain {
14
  function __construct() {
@@ -17,16 +17,16 @@ class ThemeCheckMain {
17
  }
18
 
19
  function tc_i18n() {
20
- load_plugin_textdomain( 'theme-check', false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' );
21
  }
22
 
23
  function load_styles() {
24
- wp_enqueue_style('style', plugins_url( 'assets/style.css', __FILE__ ), null, null, 'screen');
25
  }
26
 
27
  function themecheck_add_page() {
28
  $page = add_theme_page( 'Theme Check', 'Theme Check', 'manage_options', 'themecheck', array( $this, 'themecheck_do_page' ) );
29
- add_action('admin_print_styles-' . $page, array( $this, 'load_styles' ) );
30
  }
31
 
32
  function tc_add_headers( $extra_headers ) {
@@ -35,8 +35,8 @@ class ThemeCheckMain {
35
  }
36
 
37
  function themecheck_do_page() {
38
- if ( !current_user_can( 'manage_options' ) ) {
39
- wp_die( __( 'You do not have sufficient permissions to access this page.', 'theme-check' ) );
40
  }
41
 
42
  add_filter( 'extra_theme_headers', array( $this, 'tc_add_headers' ) );
@@ -46,22 +46,22 @@ class ThemeCheckMain {
46
 
47
  ?>
48
  <div id="theme-check" class="wrap">
49
- <h1><?php _ex( 'Theme Check', 'title of the main page', 'theme-check' ); ?></h1>
50
  <div class="theme-check">
51
  <?php
52
  tc_form();
53
- if ( !isset( $_POST[ 'themename' ] ) ) {
54
  tc_intro();
55
 
56
  }
57
 
58
- if ( isset( $_POST[ 'themename' ] ) ) {
59
  check_admin_referer( 'themecheck-nonce' );
60
- if ( isset( $_POST[ 'trac' ] ) ) define( 'TC_TRAC', true );
61
- if ( defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
62
- @ini_set( 'memory_limit', WP_MAX_MEMORY_LIMIT );
63
  }
64
- check_main( $_POST[ 'themename' ] );
 
65
  }
66
  ?>
67
  </div> <!-- .theme-check-->
@@ -69,4 +69,4 @@ class ThemeCheckMain {
69
  <?php
70
  }
71
  }
72
- new ThemeCheckMain;
1
  <?php
2
+ /**
3
+ * Plugin Name: Theme Check
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: 20200922.1
8
+ * Text Domain: theme-check
9
+ * License: GPLv2
10
+ * License URI: https://www.gnu.org/licenses/gpl-2.0.html
11
+ */
12
 
13
  class ThemeCheckMain {
14
  function __construct() {
17
  }
18
 
19
  function tc_i18n() {
20
+ load_plugin_textdomain( 'theme-check', false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' );
21
  }
22
 
23
  function load_styles() {
24
+ wp_enqueue_style( 'style', plugins_url( 'assets/style.css', __FILE__ ), null, null, 'screen' );
25
  }
26
 
27
  function themecheck_add_page() {
28
  $page = add_theme_page( 'Theme Check', 'Theme Check', 'manage_options', 'themecheck', array( $this, 'themecheck_do_page' ) );
29
+ add_action( 'admin_print_styles-' . $page, array( $this, 'load_styles' ) );
30
  }
31
 
32
  function tc_add_headers( $extra_headers ) {
35
  }
36
 
37
  function themecheck_do_page() {
38
+ if ( ! current_user_can( 'manage_options' ) ) {
39
+ wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'theme-check' ) );
40
  }
41
 
42
  add_filter( 'extra_theme_headers', array( $this, 'tc_add_headers' ) );
46
 
47
  ?>
48
  <div id="theme-check" class="wrap">
49
+ <h1><?php echo esc_html_x( 'Theme Check', 'title of the main page', 'theme-check' ); ?></h1>
50
  <div class="theme-check">
51
  <?php
52
  tc_form();
53
+ if ( ! isset( $_POST['themename'] ) ) {
54
  tc_intro();
55
 
56
  }
57
 
58
+ if ( isset( $_POST['themename'] ) ) {
59
  check_admin_referer( 'themecheck-nonce' );
60
+ if ( isset( $_POST['trac'] ) ) {
61
+ define( 'TC_TRAC', true );
 
62
  }
63
+ wp_raise_memory_limit();
64
+ check_main( $_POST['themename'] );
65
  }
66
  ?>
67
  </div> <!-- .theme-check-->
69
  <?php
70
  }
71
  }
72
+ new ThemeCheckMain();