19 public $update = false; |
19 public $update = false; |
20 |
20 |
21 /** |
21 /** |
22 * Headers for style.css files. |
22 * Headers for style.css files. |
23 * |
23 * |
|
24 * @since 3.4.0 |
|
25 * @since 5.4.0 Added `Requires at least` and `Requires PHP` headers. |
24 * @var array |
26 * @var array |
25 */ |
27 */ |
26 private static $file_headers = array( |
28 private static $file_headers = array( |
27 'Name' => 'Theme Name', |
29 'Name' => 'Theme Name', |
28 'ThemeURI' => 'Theme URI', |
30 'ThemeURI' => 'Theme URI', |
33 'Template' => 'Template', |
35 'Template' => 'Template', |
34 'Status' => 'Status', |
36 'Status' => 'Status', |
35 'Tags' => 'Tags', |
37 'Tags' => 'Tags', |
36 'TextDomain' => 'Text Domain', |
38 'TextDomain' => 'Text Domain', |
37 'DomainPath' => 'Domain Path', |
39 'DomainPath' => 'Domain Path', |
|
40 'RequiresWP' => 'Requires at least', |
|
41 'RequiresPHP' => 'Requires PHP', |
38 ); |
42 ); |
39 |
43 |
40 /** |
44 /** |
41 * Default themes. |
45 * Default themes. |
42 * |
46 * |
52 'twentyfourteen' => 'Twenty Fourteen', |
56 'twentyfourteen' => 'Twenty Fourteen', |
53 'twentyfifteen' => 'Twenty Fifteen', |
57 'twentyfifteen' => 'Twenty Fifteen', |
54 'twentysixteen' => 'Twenty Sixteen', |
58 'twentysixteen' => 'Twenty Sixteen', |
55 'twentyseventeen' => 'Twenty Seventeen', |
59 'twentyseventeen' => 'Twenty Seventeen', |
56 'twentynineteen' => 'Twenty Nineteen', |
60 'twentynineteen' => 'Twenty Nineteen', |
|
61 'twentytwenty' => 'Twenty Twenty', |
57 ); |
62 ); |
58 |
63 |
59 /** |
64 /** |
60 * Renamed theme tags. |
65 * Renamed theme tags. |
61 * |
66 * |
170 private static $cache_expiration = 1800; |
175 private static $cache_expiration = 1800; |
171 |
176 |
172 /** |
177 /** |
173 * Constructor for WP_Theme. |
178 * Constructor for WP_Theme. |
174 * |
179 * |
175 * @since 3.4.0 |
180 * @since 3.4.0 |
176 * |
181 * |
177 * @global array $wp_theme_directories |
182 * @global array $wp_theme_directories |
178 * |
183 * |
179 * @param string $theme_dir Directory of the theme within the theme_root. |
184 * @param string $theme_dir Directory of the theme within the theme_root. |
180 * @param string $theme_root Theme root. |
185 * @param string $theme_root Theme root. |
181 * @param WP_Error|void $_child If this theme is a parent theme, the child may be passed for validation purposes. |
186 * @param WP_Theme|null $_child If this theme is a parent theme, the child may be passed for validation purposes. |
182 */ |
187 */ |
183 public function __construct( $theme_dir, $theme_root, $_child = null ) { |
188 public function __construct( $theme_dir, $theme_root, $_child = null ) { |
184 global $wp_theme_directories; |
189 global $wp_theme_directories; |
185 |
190 |
186 // Initialize caching on first run. |
191 // Initialize caching on first run. |
199 |
204 |
200 $this->theme_root = $theme_root; |
205 $this->theme_root = $theme_root; |
201 $this->stylesheet = $theme_dir; |
206 $this->stylesheet = $theme_dir; |
202 |
207 |
203 // Correct a situation where the theme is 'some-directory/some-theme' but 'some-directory' was passed in as part of the theme root instead. |
208 // Correct a situation where the theme is 'some-directory/some-theme' but 'some-directory' was passed in as part of the theme root instead. |
204 if ( ! in_array( $theme_root, (array) $wp_theme_directories ) && in_array( dirname( $theme_root ), (array) $wp_theme_directories ) ) { |
209 if ( ! in_array( $theme_root, (array) $wp_theme_directories, true ) |
|
210 && in_array( dirname( $theme_root ), (array) $wp_theme_directories, true ) |
|
211 ) { |
205 $this->stylesheet = basename( $this->theme_root ) . '/' . $this->stylesheet; |
212 $this->stylesheet = basename( $this->theme_root ) . '/' . $this->stylesheet; |
206 $this->theme_root = dirname( $theme_root ); |
213 $this->theme_root = dirname( $theme_root ); |
207 } |
214 } |
208 |
215 |
209 $this->cache_hash = md5( $this->theme_root . '/' . $this->stylesheet ); |
216 $this->cache_hash = md5( $this->theme_root . '/' . $this->stylesheet ); |
224 $theme_root_template = $cache['theme_root_template']; |
231 $theme_root_template = $cache['theme_root_template']; |
225 } |
232 } |
226 } elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) { |
233 } elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) { |
227 $this->headers['Name'] = $this->stylesheet; |
234 $this->headers['Name'] = $this->stylesheet; |
228 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) ) { |
235 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) ) { |
229 $this->errors = new WP_Error( 'theme_not_found', sprintf( __( 'The theme directory "%s" does not exist.' ), esc_html( $this->stylesheet ) ) ); |
236 $this->errors = new WP_Error( |
|
237 'theme_not_found', |
|
238 sprintf( |
|
239 /* translators: %s: Theme directory name. */ |
|
240 __( 'The theme directory "%s" does not exist.' ), |
|
241 esc_html( $this->stylesheet ) |
|
242 ) |
|
243 ); |
230 } else { |
244 } else { |
231 $this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) ); |
245 $this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) ); |
232 } |
246 } |
233 $this->template = $this->stylesheet; |
247 $this->template = $this->stylesheet; |
234 $this->cache_add( |
248 $this->cache_add( |
239 'stylesheet' => $this->stylesheet, |
253 'stylesheet' => $this->stylesheet, |
240 'template' => $this->template, |
254 'template' => $this->template, |
241 ) |
255 ) |
242 ); |
256 ); |
243 if ( ! file_exists( $this->theme_root ) ) { // Don't cache this one. |
257 if ( ! file_exists( $this->theme_root ) ) { // Don't cache this one. |
244 $this->errors->add( 'theme_root_missing', __( 'ERROR: The themes directory is either empty or doesn’t exist. Please check your installation.' ) ); |
258 $this->errors->add( 'theme_root_missing', __( 'Error: The themes directory is either empty or doesn’t exist. Please check your installation.' ) ); |
245 } |
259 } |
246 return; |
260 return; |
247 } elseif ( ! is_readable( $this->theme_root . '/' . $theme_file ) ) { |
261 } elseif ( ! is_readable( $this->theme_root . '/' . $theme_file ) ) { |
248 $this->headers['Name'] = $this->stylesheet; |
262 $this->headers['Name'] = $this->stylesheet; |
249 $this->errors = new WP_Error( 'theme_stylesheet_not_readable', __( 'Stylesheet is not readable.' ) ); |
263 $this->errors = new WP_Error( 'theme_stylesheet_not_readable', __( 'Stylesheet is not readable.' ) ); |
260 return; |
274 return; |
261 } else { |
275 } else { |
262 $this->headers = get_file_data( $this->theme_root . '/' . $theme_file, self::$file_headers, 'theme' ); |
276 $this->headers = get_file_data( $this->theme_root . '/' . $theme_file, self::$file_headers, 'theme' ); |
263 // Default themes always trump their pretenders. |
277 // Default themes always trump their pretenders. |
264 // Properly identify default themes that are inside a directory within wp-content/themes. |
278 // Properly identify default themes that are inside a directory within wp-content/themes. |
265 if ( $default_theme_slug = array_search( $this->headers['Name'], self::$default_themes ) ) { |
279 $default_theme_slug = array_search( $this->headers['Name'], self::$default_themes, true ); |
|
280 if ( $default_theme_slug ) { |
266 if ( basename( $this->stylesheet ) != $default_theme_slug ) { |
281 if ( basename( $this->stylesheet ) != $default_theme_slug ) { |
267 $this->headers['Name'] .= '/' . $this->stylesheet; |
282 $this->headers['Name'] .= '/' . $this->stylesheet; |
268 } |
283 } |
269 } |
284 } |
270 } |
285 } |
271 |
286 |
272 if ( ! $this->template && $this->stylesheet === $this->headers['Template'] ) { |
287 if ( ! $this->template && $this->stylesheet === $this->headers['Template'] ) { |
273 /* translators: %s: Template */ |
288 $this->errors = new WP_Error( |
274 $this->errors = new WP_Error( 'theme_child_invalid', sprintf( __( 'The theme defines itself as its parent theme. Please check the %s header.' ), '<code>Template</code>' ) ); |
289 'theme_child_invalid', |
|
290 sprintf( |
|
291 /* translators: %s: Template. */ |
|
292 __( 'The theme defines itself as its parent theme. Please check the %s header.' ), |
|
293 '<code>Template</code>' |
|
294 ) |
|
295 ); |
275 $this->cache_add( |
296 $this->cache_add( |
276 'theme', |
297 'theme', |
277 array( |
298 array( |
278 'headers' => $this->headers, |
299 'headers' => $this->headers, |
279 'errors' => $this->errors, |
300 'errors' => $this->errors, |
283 |
304 |
284 return; |
305 return; |
285 } |
306 } |
286 |
307 |
287 // (If template is set from cache [and there are no errors], we know it's good.) |
308 // (If template is set from cache [and there are no errors], we know it's good.) |
288 if ( ! $this->template && ! ( $this->template = $this->headers['Template'] ) ) { |
309 if ( ! $this->template ) { |
|
310 $this->template = $this->headers['Template']; |
|
311 } |
|
312 |
|
313 if ( ! $this->template ) { |
289 $this->template = $this->stylesheet; |
314 $this->template = $this->stylesheet; |
290 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet . '/index.php' ) ) { |
315 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet . '/index.php' ) ) { |
291 $error_message = sprintf( |
316 $error_message = sprintf( |
292 /* translators: 1: index.php, 2: link to documentation, 3: style.css */ |
317 /* translators: 1: index.php, 2: Documentation URL, 3: style.css */ |
293 __( 'Template is missing. Standalone themes need to have a %1$s template file. <a href="%2$s">Child themes</a> need to have a Template header in the %3$s stylesheet.' ), |
318 __( 'Template is missing. Standalone themes need to have a %1$s template file. <a href="%2$s">Child themes</a> need to have a Template header in the %3$s stylesheet.' ), |
294 '<code>index.php</code>', |
319 '<code>index.php</code>', |
295 __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ), |
320 __( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ), |
296 '<code>style.css</code>' |
321 '<code>style.css</code>' |
297 ); |
322 ); |
311 |
336 |
312 // If we got our data from cache, we can assume that 'template' is pointing to the right place. |
337 // If we got our data from cache, we can assume that 'template' is pointing to the right place. |
313 if ( ! is_array( $cache ) && $this->template != $this->stylesheet && ! file_exists( $this->theme_root . '/' . $this->template . '/index.php' ) ) { |
338 if ( ! is_array( $cache ) && $this->template != $this->stylesheet && ! file_exists( $this->theme_root . '/' . $this->template . '/index.php' ) ) { |
314 // If we're in a directory of themes inside /themes, look for the parent nearby. |
339 // If we're in a directory of themes inside /themes, look for the parent nearby. |
315 // wp-content/themes/directory-of-themes/* |
340 // wp-content/themes/directory-of-themes/* |
316 $parent_dir = dirname( $this->stylesheet ); |
341 $parent_dir = dirname( $this->stylesheet ); |
317 if ( '.' != $parent_dir && file_exists( $this->theme_root . '/' . $parent_dir . '/' . $this->template . '/index.php' ) ) { |
342 $directories = search_theme_directories(); |
|
343 |
|
344 if ( '.' !== $parent_dir && file_exists( $this->theme_root . '/' . $parent_dir . '/' . $this->template . '/index.php' ) ) { |
318 $this->template = $parent_dir . '/' . $this->template; |
345 $this->template = $parent_dir . '/' . $this->template; |
319 } elseif ( ( $directories = search_theme_directories() ) && isset( $directories[ $this->template ] ) ) { |
346 } elseif ( $directories && isset( $directories[ $this->template ] ) ) { |
320 // Look for the template in the search_theme_directories() results, in case it is in another theme root. |
347 // Look for the template in the search_theme_directories() results, in case it is in another theme root. |
321 // We don't look into directories of themes, just the theme root. |
348 // We don't look into directories of themes, just the theme root. |
322 $theme_root_template = $directories[ $this->template ]['theme_root']; |
349 $theme_root_template = $directories[ $this->template ]['theme_root']; |
323 } else { |
350 } else { |
324 // Parent theme is missing. |
351 // Parent theme is missing. |
325 $this->errors = new WP_Error( 'theme_no_parent', sprintf( __( 'The parent theme is missing. Please install the "%s" parent theme.' ), esc_html( $this->template ) ) ); |
352 $this->errors = new WP_Error( |
|
353 'theme_no_parent', |
|
354 sprintf( |
|
355 /* translators: %s: Theme directory name. */ |
|
356 __( 'The parent theme is missing. Please install the "%s" parent theme.' ), |
|
357 esc_html( $this->template ) |
|
358 ) |
|
359 ); |
326 $this->cache_add( |
360 $this->cache_add( |
327 'theme', |
361 'theme', |
328 array( |
362 array( |
329 'headers' => $this->headers, |
363 'headers' => $this->headers, |
330 'errors' => $this->errors, |
364 'errors' => $this->errors, |
340 // Set the parent, if we're a child theme. |
374 // Set the parent, if we're a child theme. |
341 if ( $this->template != $this->stylesheet ) { |
375 if ( $this->template != $this->stylesheet ) { |
342 // If we are a parent, then there is a problem. Only two generations allowed! Cancel things out. |
376 // If we are a parent, then there is a problem. Only two generations allowed! Cancel things out. |
343 if ( $_child instanceof WP_Theme && $_child->template == $this->stylesheet ) { |
377 if ( $_child instanceof WP_Theme && $_child->template == $this->stylesheet ) { |
344 $_child->parent = null; |
378 $_child->parent = null; |
345 $_child->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $_child->template ) ) ); |
379 $_child->errors = new WP_Error( |
|
380 'theme_parent_invalid', |
|
381 sprintf( |
|
382 /* translators: %s: Theme directory name. */ |
|
383 __( 'The "%s" theme is not a valid parent theme.' ), |
|
384 esc_html( $_child->template ) |
|
385 ) |
|
386 ); |
346 $_child->cache_add( |
387 $_child->cache_add( |
347 'theme', |
388 'theme', |
348 array( |
389 array( |
349 'headers' => $_child->headers, |
390 'headers' => $_child->headers, |
350 'errors' => $_child->errors, |
391 'errors' => $_child->errors, |
352 'template' => $_child->template, |
393 'template' => $_child->template, |
353 ) |
394 ) |
354 ); |
395 ); |
355 // The two themes actually reference each other with the Template header. |
396 // The two themes actually reference each other with the Template header. |
356 if ( $_child->stylesheet == $this->template ) { |
397 if ( $_child->stylesheet == $this->template ) { |
357 $this->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $this->template ) ) ); |
398 $this->errors = new WP_Error( |
|
399 'theme_parent_invalid', |
|
400 sprintf( |
|
401 /* translators: %s: Theme directory name. */ |
|
402 __( 'The "%s" theme is not a valid parent theme.' ), |
|
403 esc_html( $this->template ) |
|
404 ) |
|
405 ); |
358 $this->cache_add( |
406 $this->cache_add( |
359 'theme', |
407 'theme', |
360 array( |
408 array( |
361 'headers' => $this->headers, |
409 'headers' => $this->headers, |
362 'errors' => $this->errors, |
410 'errors' => $this->errors, |
392 } |
440 } |
393 |
441 |
394 /** |
442 /** |
395 * When converting the object to a string, the theme name is returned. |
443 * When converting the object to a string, the theme name is returned. |
396 * |
444 * |
397 * @since 3.4.0 |
445 * @since 3.4.0 |
398 * |
446 * |
399 * @return string Theme name, ready for display (translated) |
447 * @return string Theme name, ready for display (translated) |
400 */ |
448 */ |
401 public function __toString() { |
449 public function __toString() { |
402 return (string) $this->display( 'Name' ); |
450 return (string) $this->display( 'Name' ); |
403 } |
451 } |
404 |
452 |
405 /** |
453 /** |
406 * __isset() magic method for properties formerly returned by current_theme_info() |
454 * __isset() magic method for properties formerly returned by current_theme_info() |
407 * |
455 * |
408 * @staticvar array $properties |
456 * @since 3.4.0 |
409 * |
|
410 * @since 3.4.0 |
|
411 * |
457 * |
412 * @param string $offset Property to check if set. |
458 * @param string $offset Property to check if set. |
413 * @return bool Whether the given property is set. |
459 * @return bool Whether the given property is set. |
414 */ |
460 */ |
415 public function __isset( $offset ) { |
461 public function __isset( $offset ) { |
428 'tags', |
474 'tags', |
429 'theme_root', |
475 'theme_root', |
430 'theme_root_uri', |
476 'theme_root_uri', |
431 ); |
477 ); |
432 |
478 |
433 return in_array( $offset, $properties ); |
479 return in_array( $offset, $properties, true ); |
434 } |
480 } |
435 |
481 |
436 /** |
482 /** |
437 * __get() magic method for properties formerly returned by current_theme_info() |
483 * __get() magic method for properties formerly returned by current_theme_info() |
438 * |
484 * |
439 * @since 3.4.0 |
485 * @since 3.4.0 |
440 * |
486 * |
441 * @param string $offset Property to get. |
487 * @param string $offset Property to get. |
442 * @return mixed Property value. |
488 * @return mixed Property value. |
443 */ |
489 */ |
444 public function __get( $offset ) { |
490 public function __get( $offset ) { |
478 } |
524 } |
479 |
525 |
480 /** |
526 /** |
481 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
527 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
482 * |
528 * |
483 * @since 3.4.0 |
529 * @since 3.4.0 |
484 * |
530 * |
485 * @param mixed $offset |
531 * @param mixed $offset |
486 * @param mixed $value |
532 * @param mixed $value |
487 */ |
533 */ |
488 public function offsetSet( $offset, $value ) {} |
534 public function offsetSet( $offset, $value ) {} |
489 |
535 |
490 /** |
536 /** |
491 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
537 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
492 * |
538 * |
493 * @since 3.4.0 |
539 * @since 3.4.0 |
494 * |
540 * |
495 * @param mixed $offset |
541 * @param mixed $offset |
496 */ |
542 */ |
497 public function offsetUnset( $offset ) {} |
543 public function offsetUnset( $offset ) {} |
498 |
544 |
499 /** |
545 /** |
500 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
546 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
501 * |
547 * |
502 * @staticvar array $keys |
548 * @since 3.4.0 |
503 * |
|
504 * @since 3.4.0 |
|
505 * |
549 * |
506 * @param mixed $offset |
550 * @param mixed $offset |
507 * @return bool |
551 * @return bool |
508 */ |
552 */ |
509 public function offsetExists( $offset ) { |
553 public function offsetExists( $offset ) { |
540 * Name and Title could have been used as the key for get_themes(), both remain |
584 * Name and Title could have been used as the key for get_themes(), both remain |
541 * untranslated for back compatibility. This means that ['Name'] is not ideal, |
585 * untranslated for back compatibility. This means that ['Name'] is not ideal, |
542 * and care should be taken to use `$theme::display( 'Name' )` to get a properly |
586 * and care should be taken to use `$theme::display( 'Name' )` to get a properly |
543 * translated header. |
587 * translated header. |
544 * |
588 * |
545 * @since 3.4.0 |
589 * @since 3.4.0 |
546 * |
590 * |
547 * @param mixed $offset |
591 * @param mixed $offset |
548 * @return mixed |
592 * @return mixed |
549 */ |
593 */ |
550 public function offsetGet( $offset ) { |
594 public function offsetGet( $offset ) { |
614 * @since 3.4.0 |
658 * @since 3.4.0 |
615 * |
659 * |
616 * @return bool Whether the theme exists. |
660 * @return bool Whether the theme exists. |
617 */ |
661 */ |
618 public function exists() { |
662 public function exists() { |
619 return ! ( $this->errors() && in_array( 'theme_not_found', $this->errors()->get_error_codes() ) ); |
663 return ! ( $this->errors() && in_array( 'theme_not_found', $this->errors()->get_error_codes(), true ) ); |
620 } |
664 } |
621 |
665 |
622 /** |
666 /** |
623 * Returns reference to the parent theme. |
667 * Returns reference to the parent theme. |
624 * |
668 * |
635 * |
679 * |
636 * Cache entries keyed by the theme and the type of data. |
680 * Cache entries keyed by the theme and the type of data. |
637 * |
681 * |
638 * @since 3.4.0 |
682 * @since 3.4.0 |
639 * |
683 * |
640 * @param string $key Type of data to store (theme, screenshot, headers, post_templates) |
684 * @param string $key Type of data to store (theme, screenshot, headers, post_templates) |
641 * @param string $data Data to store |
685 * @param array|string $data Data to store |
642 * @return bool Return value from wp_cache_add() |
686 * @return bool Return value from wp_cache_add() |
643 */ |
687 */ |
644 private function cache_add( $key, $data ) { |
688 private function cache_add( $key, $data ) { |
645 return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'themes', self::$cache_expiration ); |
689 return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'themes', self::$cache_expiration ); |
646 } |
690 } |
666 */ |
710 */ |
667 public function cache_delete() { |
711 public function cache_delete() { |
668 foreach ( array( 'theme', 'screenshot', 'headers', 'post_templates' ) as $key ) { |
712 foreach ( array( 'theme', 'screenshot', 'headers', 'post_templates' ) as $key ) { |
669 wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' ); |
713 wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' ); |
670 } |
714 } |
671 $this->template = $this->textdomain_loaded = $this->theme_root_uri = $this->parent = $this->errors = $this->headers_sanitized = $this->name_translated = null; |
715 $this->template = null; |
672 $this->headers = array(); |
716 $this->textdomain_loaded = null; |
|
717 $this->theme_root_uri = null; |
|
718 $this->parent = null; |
|
719 $this->errors = null; |
|
720 $this->headers_sanitized = null; |
|
721 $this->name_translated = null; |
|
722 $this->headers = array(); |
673 $this->__construct( $this->stylesheet, $this->theme_root ); |
723 $this->__construct( $this->stylesheet, $this->theme_root ); |
674 } |
724 } |
675 |
725 |
676 /** |
726 /** |
677 * Get a raw, unformatted theme header. |
727 * Get a raw, unformatted theme header. |
685 * whether it is actually valid. |
735 * whether it is actually valid. |
686 * |
736 * |
687 * @since 3.4.0 |
737 * @since 3.4.0 |
688 * |
738 * |
689 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
739 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
690 * @return string|false String on success, false on failure. |
740 * @return string|array|false String or array (for Tags header) on success, false on failure. |
691 */ |
741 */ |
692 public function get( $header ) { |
742 public function get( $header ) { |
693 if ( ! isset( $this->headers[ $header ] ) ) { |
743 if ( ! isset( $this->headers[ $header ] ) ) { |
694 return false; |
744 return false; |
695 } |
745 } |
721 /** |
771 /** |
722 * Gets a theme header, formatted and translated for display. |
772 * Gets a theme header, formatted and translated for display. |
723 * |
773 * |
724 * @since 3.4.0 |
774 * @since 3.4.0 |
725 * |
775 * |
726 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
776 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
727 * @param bool $markup Optional. Whether to mark up the header. Defaults to true. |
777 * @param bool $markup Optional. Whether to mark up the header. Defaults to true. |
728 * @param bool $translate Optional. Whether to translate the header. Defaults to true. |
778 * @param bool $translate Optional. Whether to translate the header. Defaults to true. |
729 * @return string|false Processed header, false on failure. |
779 * @return string|array|false Processed header. An array for Tags if `$markup` is false, string otherwise. |
|
780 * False on failure. |
730 */ |
781 */ |
731 public function display( $header, $markup = true, $translate = true ) { |
782 public function display( $header, $markup = true, $translate = true ) { |
732 $value = $this->get( $header ); |
783 $value = $this->get( $header ); |
733 if ( false === $value ) { |
784 if ( false === $value ) { |
734 return false; |
785 return false; |
751 |
802 |
752 /** |
803 /** |
753 * Sanitize a theme header. |
804 * Sanitize a theme header. |
754 * |
805 * |
755 * @since 3.4.0 |
806 * @since 3.4.0 |
756 * |
807 * @since 5.4.0 Added support for `Requires at least` and `Requires PHP` headers. |
757 * @staticvar array $header_tags |
808 * |
758 * @staticvar array $header_tags_with_a |
809 * @param string $header Theme header. Accepts 'Name', 'Description', 'Author', 'Version', |
759 * |
810 * 'ThemeURI', 'AuthorURI', 'Status', 'Tags', 'RequiresWP', 'RequiresPHP'. |
760 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
811 * @param string $value Value to sanitize. |
761 * @param string $value Value to sanitize. |
812 * @return string|array An array for Tags header, string otherwise. |
762 * @return mixed |
|
763 */ |
813 */ |
764 private function sanitize_header( $header, $value ) { |
814 private function sanitize_header( $header, $value ) { |
765 switch ( $header ) { |
815 switch ( $header ) { |
766 case 'Status': |
816 case 'Status': |
767 if ( ! $value ) { |
817 if ( ! $value ) { |
775 'acronym' => array( 'title' => true ), |
825 'acronym' => array( 'title' => true ), |
776 'code' => true, |
826 'code' => true, |
777 'em' => true, |
827 'em' => true, |
778 'strong' => true, |
828 'strong' => true, |
779 ); |
829 ); |
780 $value = wp_kses( $value, $header_tags ); |
830 |
|
831 $value = wp_kses( $value, $header_tags ); |
781 break; |
832 break; |
782 case 'Author': |
833 case 'Author': |
783 // There shouldn't be anchor tags in Author, but some themes like to be challenging. |
834 // There shouldn't be anchor tags in Author, but some themes like to be challenging. |
784 case 'Description': |
835 case 'Description': |
785 static $header_tags_with_a = array( |
836 static $header_tags_with_a = array( |
791 'acronym' => array( 'title' => true ), |
842 'acronym' => array( 'title' => true ), |
792 'code' => true, |
843 'code' => true, |
793 'em' => true, |
844 'em' => true, |
794 'strong' => true, |
845 'strong' => true, |
795 ); |
846 ); |
796 $value = wp_kses( $value, $header_tags_with_a ); |
847 |
|
848 $value = wp_kses( $value, $header_tags_with_a ); |
797 break; |
849 break; |
798 case 'ThemeURI': |
850 case 'ThemeURI': |
799 case 'AuthorURI': |
851 case 'AuthorURI': |
800 $value = esc_url_raw( $value ); |
852 $value = esc_url_raw( $value ); |
801 break; |
853 break; |
802 case 'Tags': |
854 case 'Tags': |
803 $value = array_filter( array_map( 'trim', explode( ',', strip_tags( $value ) ) ) ); |
855 $value = array_filter( array_map( 'trim', explode( ',', strip_tags( $value ) ) ) ); |
804 break; |
856 break; |
805 case 'Version': |
857 case 'Version': |
|
858 case 'RequiresWP': |
|
859 case 'RequiresPHP': |
806 $value = strip_tags( $value ); |
860 $value = strip_tags( $value ); |
807 break; |
861 break; |
808 } |
862 } |
809 |
863 |
810 return $value; |
864 return $value; |
813 /** |
867 /** |
814 * Mark up a theme header. |
868 * Mark up a theme header. |
815 * |
869 * |
816 * @since 3.4.0 |
870 * @since 3.4.0 |
817 * |
871 * |
818 * @staticvar string $comma |
872 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
819 * |
873 * @param string|array $value Value to mark up. An array for Tags header, string otherwise. |
820 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
874 * @param string $translate Whether the header has been translated. |
821 * @param string $value Value to mark up. |
|
822 * @param string $translate Whether the header has been translated. |
|
823 * @return string Value, marked up. |
875 * @return string Value, marked up. |
824 */ |
876 */ |
825 private function markup_header( $header, $value, $translate ) { |
877 private function markup_header( $header, $value, $translate ) { |
826 switch ( $header ) { |
878 switch ( $header ) { |
827 case 'Name': |
879 case 'Name': |
840 } |
892 } |
841 break; |
893 break; |
842 case 'Tags': |
894 case 'Tags': |
843 static $comma = null; |
895 static $comma = null; |
844 if ( ! isset( $comma ) ) { |
896 if ( ! isset( $comma ) ) { |
845 /* translators: used between list items, there is a space after the comma */ |
897 /* translators: Used between list items, there is a space after the comma. */ |
846 $comma = __( ', ' ); |
898 $comma = __( ', ' ); |
847 } |
899 } |
848 $value = implode( $comma, $value ); |
900 $value = implode( $comma, $value ); |
849 break; |
901 break; |
850 case 'ThemeURI': |
902 case 'ThemeURI': |
859 /** |
911 /** |
860 * Translate a theme header. |
912 * Translate a theme header. |
861 * |
913 * |
862 * @since 3.4.0 |
914 * @since 3.4.0 |
863 * |
915 * |
864 * @staticvar array $tags_list |
916 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
865 * |
917 * @param string|array $value Value to translate. An array for Tags header, string otherwise. |
866 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
918 * @return string|array Translated value. An array for Tags header, string otherwise. |
867 * @param string $value Value to translate. |
|
868 * @return string Translated value. |
|
869 */ |
919 */ |
870 private function translate_header( $header, $value ) { |
920 private function translate_header( $header, $value ) { |
871 switch ( $header ) { |
921 switch ( $header ) { |
872 case 'Name': |
922 case 'Name': |
873 // Cached for sorting reasons. |
923 // Cached for sorting reasons. |
874 if ( isset( $this->name_translated ) ) { |
924 if ( isset( $this->name_translated ) ) { |
875 return $this->name_translated; |
925 return $this->name_translated; |
876 } |
926 } |
|
927 |
877 // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain |
928 // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain |
878 $this->name_translated = translate( $value, $this->get( 'TextDomain' ) ); |
929 $this->name_translated = translate( $value, $this->get( 'TextDomain' ) ); |
|
930 |
879 return $this->name_translated; |
931 return $this->name_translated; |
880 case 'Tags': |
932 case 'Tags': |
881 if ( empty( $value ) || ! function_exists( 'get_theme_feature_list' ) ) { |
933 if ( empty( $value ) || ! function_exists( 'get_theme_feature_list' ) ) { |
882 return $value; |
934 return $value; |
883 } |
935 } |
907 'blavatar' => __( 'Blavatar' ), |
959 'blavatar' => __( 'Blavatar' ), |
908 'photoblogging' => __( 'Photoblogging' ), |
960 'photoblogging' => __( 'Photoblogging' ), |
909 'seasonal' => __( 'Seasonal' ), |
961 'seasonal' => __( 'Seasonal' ), |
910 ); |
962 ); |
911 |
963 |
912 $feature_list = get_theme_feature_list( false ); // No API |
964 $feature_list = get_theme_feature_list( false ); // No API. |
|
965 |
913 foreach ( $feature_list as $tags ) { |
966 foreach ( $feature_list as $tags ) { |
914 $tags_list += $tags; |
967 $tags_list += $tags; |
915 } |
968 } |
916 } |
969 } |
917 |
970 |
969 * @since 3.4.0 |
1022 * @since 3.4.0 |
970 * |
1023 * |
971 * @return string Absolute path of the stylesheet directory. |
1024 * @return string Absolute path of the stylesheet directory. |
972 */ |
1025 */ |
973 public function get_stylesheet_directory() { |
1026 public function get_stylesheet_directory() { |
974 if ( $this->errors() && in_array( 'theme_root_missing', $this->errors()->get_error_codes() ) ) { |
1027 if ( $this->errors() && in_array( 'theme_root_missing', $this->errors()->get_error_codes(), true ) ) { |
975 return ''; |
1028 return ''; |
976 } |
1029 } |
977 |
1030 |
978 return $this->theme_root . '/' . $this->stylesheet; |
1031 return $this->theme_root . '/' . $this->stylesheet; |
979 } |
1032 } |
1077 * @return string|false Screenshot file. False if the theme does not have a screenshot. |
1130 * @return string|false Screenshot file. False if the theme does not have a screenshot. |
1078 */ |
1131 */ |
1079 public function get_screenshot( $uri = 'uri' ) { |
1132 public function get_screenshot( $uri = 'uri' ) { |
1080 $screenshot = $this->cache_get( 'screenshot' ); |
1133 $screenshot = $this->cache_get( 'screenshot' ); |
1081 if ( $screenshot ) { |
1134 if ( $screenshot ) { |
1082 if ( 'relative' == $uri ) { |
1135 if ( 'relative' === $uri ) { |
1083 return $screenshot; |
1136 return $screenshot; |
1084 } |
1137 } |
1085 return $this->get_stylesheet_directory_uri() . '/' . $screenshot; |
1138 return $this->get_stylesheet_directory_uri() . '/' . $screenshot; |
1086 } elseif ( 0 === $screenshot ) { |
1139 } elseif ( 0 === $screenshot ) { |
1087 return false; |
1140 return false; |
1088 } |
1141 } |
1089 |
1142 |
1090 foreach ( array( 'png', 'gif', 'jpg', 'jpeg' ) as $ext ) { |
1143 foreach ( array( 'png', 'gif', 'jpg', 'jpeg' ) as $ext ) { |
1091 if ( file_exists( $this->get_stylesheet_directory() . "/screenshot.$ext" ) ) { |
1144 if ( file_exists( $this->get_stylesheet_directory() . "/screenshot.$ext" ) ) { |
1092 $this->cache_add( 'screenshot', 'screenshot.' . $ext ); |
1145 $this->cache_add( 'screenshot', 'screenshot.' . $ext ); |
1093 if ( 'relative' == $uri ) { |
1146 if ( 'relative' === $uri ) { |
1094 return 'screenshot.' . $ext; |
1147 return 'screenshot.' . $ext; |
1095 } |
1148 } |
1096 return $this->get_stylesheet_directory_uri() . '/' . 'screenshot.' . $ext; |
1149 return $this->get_stylesheet_directory_uri() . '/' . 'screenshot.' . $ext; |
1097 } |
1150 } |
1098 } |
1151 } |
1104 /** |
1157 /** |
1105 * Return files in the theme's directory. |
1158 * Return files in the theme's directory. |
1106 * |
1159 * |
1107 * @since 3.4.0 |
1160 * @since 3.4.0 |
1108 * |
1161 * |
1109 * @param mixed $type Optional. Array of extensions to return. Defaults to all files (null). |
1162 * @param string[]|string $type Optional. Array of extensions to find, string of a single extension, |
1110 * @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). -1 depth is infinite. |
1163 * or null for all extensions. Default null. |
1111 * @param bool $search_parent Optional. Whether to return parent files. Defaults to false. |
1164 * @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). |
1112 * @return array Array of files, keyed by the path to the file relative to the theme's directory, with the values |
1165 * -1 depth is infinite. |
1113 * being absolute paths. |
1166 * @param bool $search_parent Optional. Whether to return parent files. Default false. |
|
1167 * @return string[] Array of files, keyed by the path to the file relative to the theme's directory, with the values |
|
1168 * being absolute paths. |
1114 */ |
1169 */ |
1115 public function get_files( $type = null, $depth = 0, $search_parent = false ) { |
1170 public function get_files( $type = null, $depth = 0, $search_parent = false ) { |
1116 $files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth ); |
1171 $files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth ); |
1117 |
1172 |
1118 if ( $search_parent && $this->parent() ) { |
1173 if ( $search_parent && $this->parent() ) { |
1125 /** |
1180 /** |
1126 * Returns the theme's post templates. |
1181 * Returns the theme's post templates. |
1127 * |
1182 * |
1128 * @since 4.7.0 |
1183 * @since 4.7.0 |
1129 * |
1184 * |
1130 * @return array Array of page templates, keyed by filename and post type, |
1185 * @return string[] Array of page templates, keyed by filename and post type, |
1131 * with the value of the translated header name. |
1186 * with the value of the translated header name. |
1132 */ |
1187 */ |
1133 public function get_post_templates() { |
1188 public function get_post_templates() { |
1134 // If you screw up your current theme and we invalidate your parent, most things still work. Let it slide. |
1189 // If you screw up your current theme and we invalidate your parent, most things still work. Let it slide. |
1135 if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) { |
1190 if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) { |
1136 return array(); |
1191 return array(); |
1184 * @since 4.7.0 Added the `$post_type` parameter. |
1239 * @since 4.7.0 Added the `$post_type` parameter. |
1185 * |
1240 * |
1186 * @param WP_Post|null $post Optional. The post being edited, provided for context. |
1241 * @param WP_Post|null $post Optional. The post being edited, provided for context. |
1187 * @param string $post_type Optional. Post type to get the templates for. Default 'page'. |
1242 * @param string $post_type Optional. Post type to get the templates for. Default 'page'. |
1188 * If a post is provided, its post type is used. |
1243 * If a post is provided, its post type is used. |
1189 * @return array Array of page templates, keyed by filename, with the value of the translated header name. |
1244 * @return string[] Array of template header names keyed by the template file name. |
1190 */ |
1245 */ |
1191 public function get_page_templates( $post = null, $post_type = 'page' ) { |
1246 public function get_page_templates( $post = null, $post_type = 'page' ) { |
1192 if ( $post ) { |
1247 if ( $post ) { |
1193 $post_type = get_post_type( $post ); |
1248 $post_type = get_post_type( $post ); |
1194 } |
1249 } |
1199 /** |
1254 /** |
1200 * Filters list of page templates for a theme. |
1255 * Filters list of page templates for a theme. |
1201 * |
1256 * |
1202 * @since 4.9.6 |
1257 * @since 4.9.6 |
1203 * |
1258 * |
1204 * @param string[] $post_templates Array of page templates. Keys are filenames, |
1259 * @param string[] $post_templates Array of template header names keyed by the template file name. |
1205 * values are translated names. |
|
1206 * @param WP_Theme $this The theme object. |
1260 * @param WP_Theme $this The theme object. |
1207 * @param WP_Post|null $post The post being edited, provided for context, or null. |
1261 * @param WP_Post|null $post The post being edited, provided for context, or null. |
1208 * @param string $post_type Post type to get the templates for. |
1262 * @param string $post_type Post type to get the templates for. |
1209 */ |
1263 */ |
1210 $post_templates = (array) apply_filters( 'theme_templates', $post_templates, $this, $post, $post_type ); |
1264 $post_templates = (array) apply_filters( 'theme_templates', $post_templates, $this, $post, $post_type ); |
1216 * |
1270 * |
1217 * @since 3.9.0 |
1271 * @since 3.9.0 |
1218 * @since 4.4.0 Converted to allow complete control over the `$page_templates` array. |
1272 * @since 4.4.0 Converted to allow complete control over the `$page_templates` array. |
1219 * @since 4.7.0 Added the `$post_type` parameter. |
1273 * @since 4.7.0 Added the `$post_type` parameter. |
1220 * |
1274 * |
1221 * @param string[] $post_templates Array of page templates. Keys are filenames, |
1275 * @param string[] $post_templates Array of template header names keyed by the template file name. |
1222 * values are translated names. |
|
1223 * @param WP_Theme $this The theme object. |
1276 * @param WP_Theme $this The theme object. |
1224 * @param WP_Post|null $post The post being edited, provided for context, or null. |
1277 * @param WP_Post|null $post The post being edited, provided for context, or null. |
1225 * @param string $post_type Post type to get the templates for. |
1278 * @param string $post_type Post type to get the templates for. |
1226 */ |
1279 */ |
1227 $post_templates = (array) apply_filters( "theme_{$post_type}_templates", $post_templates, $this, $post, $post_type ); |
1280 $post_templates = (array) apply_filters( "theme_{$post_type}_templates", $post_templates, $this, $post, $post_type ); |
1240 * @param int $depth Optional. How many levels deep to search for files. Accepts 0, 1+, or |
1293 * @param int $depth Optional. How many levels deep to search for files. Accepts 0, 1+, or |
1241 * -1 (infinite depth). Default 0. |
1294 * -1 (infinite depth). Default 0. |
1242 * @param string $relative_path Optional. The basename of the absolute path. Used to control the |
1295 * @param string $relative_path Optional. The basename of the absolute path. Used to control the |
1243 * returned path for the found files, particularly when this function |
1296 * returned path for the found files, particularly when this function |
1244 * recurses to lower depths. Default empty. |
1297 * recurses to lower depths. Default empty. |
1245 * @return array|false Array of files, keyed by the path to the file relative to the `$path` directory prepended |
1298 * @return string[]|false Array of files, keyed by the path to the file relative to the `$path` directory prepended |
1246 * with `$relative_path`, with the values being absolute paths. False otherwise. |
1299 * with `$relative_path`, with the values being absolute paths. False otherwise. |
1247 */ |
1300 */ |
1248 private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) { |
1301 private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) { |
1249 if ( ! is_dir( $path ) ) { |
1302 if ( ! is_dir( $path ) ) { |
1250 return false; |
1303 return false; |
1251 } |
1304 } |
1254 $extensions = (array) $extensions; |
1307 $extensions = (array) $extensions; |
1255 $_extensions = implode( '|', $extensions ); |
1308 $_extensions = implode( '|', $extensions ); |
1256 } |
1309 } |
1257 |
1310 |
1258 $relative_path = trailingslashit( $relative_path ); |
1311 $relative_path = trailingslashit( $relative_path ); |
1259 if ( '/' == $relative_path ) { |
1312 if ( '/' === $relative_path ) { |
1260 $relative_path = ''; |
1313 $relative_path = ''; |
1261 } |
1314 } |
1262 |
1315 |
1263 $results = scandir( $path ); |
1316 $results = scandir( $path ); |
1264 $files = array(); |
1317 $files = array(); |
1271 * @param string[] $exclusions Array of excluded directories and files. |
1324 * @param string[] $exclusions Array of excluded directories and files. |
1272 */ |
1325 */ |
1273 $exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) ); |
1326 $exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) ); |
1274 |
1327 |
1275 foreach ( $results as $result ) { |
1328 foreach ( $results as $result ) { |
1276 if ( '.' == $result[0] || in_array( $result, $exclusions, true ) ) { |
1329 if ( '.' === $result[0] || in_array( $result, $exclusions, true ) ) { |
1277 continue; |
1330 continue; |
1278 } |
1331 } |
1279 if ( is_dir( $path . '/' . $result ) ) { |
1332 if ( is_dir( $path . '/' . $result ) ) { |
1280 if ( ! $depth ) { |
1333 if ( ! $depth ) { |
1281 continue; |
1334 continue; |
1291 } |
1344 } |
1292 |
1345 |
1293 /** |
1346 /** |
1294 * Loads the theme's textdomain. |
1347 * Loads the theme's textdomain. |
1295 * |
1348 * |
1296 * Translation files are not inherited from the parent theme. Todo: if this fails for the |
1349 * Translation files are not inherited from the parent theme. TODO: If this fails for the |
1297 * child theme, it should probably try to load the parent theme's translations. |
1350 * child theme, it should probably try to load the parent theme's translations. |
1298 * |
1351 * |
1299 * @since 3.4.0 |
1352 * @since 3.4.0 |
1300 * |
1353 * |
1301 * @return bool True if the textdomain was successfully loaded or has already been loaded. |
1354 * @return bool True if the textdomain was successfully loaded or has already been loaded. |
1315 if ( is_textdomain_loaded( $textdomain ) ) { |
1368 if ( is_textdomain_loaded( $textdomain ) ) { |
1316 $this->textdomain_loaded = true; |
1369 $this->textdomain_loaded = true; |
1317 return true; |
1370 return true; |
1318 } |
1371 } |
1319 |
1372 |
1320 $path = $this->get_stylesheet_directory(); |
1373 $path = $this->get_stylesheet_directory(); |
1321 if ( $domainpath = $this->get( 'DomainPath' ) ) { |
1374 $domainpath = $this->get( 'DomainPath' ); |
|
1375 if ( $domainpath ) { |
1322 $path .= $domainpath; |
1376 $path .= $domainpath; |
1323 } else { |
1377 } else { |
1324 $path .= '/languages'; |
1378 $path .= '/languages'; |
1325 } |
1379 } |
1326 |
1380 |
1331 /** |
1385 /** |
1332 * Whether the theme is allowed (multisite only). |
1386 * Whether the theme is allowed (multisite only). |
1333 * |
1387 * |
1334 * @since 3.4.0 |
1388 * @since 3.4.0 |
1335 * |
1389 * |
1336 * @param string $check Optional. Whether to check only the 'network'-wide settings, the 'site' |
1390 * @param string $check Optional. Whether to check only the 'network'-wide settings, the 'site' |
1337 * settings, or 'both'. Defaults to 'both'. |
1391 * settings, or 'both'. Defaults to 'both'. |
1338 * @param int $blog_id Optional. Ignored if only network-wide settings are checked. Defaults to current site. |
1392 * @param int $blog_id Optional. Ignored if only network-wide settings are checked. Defaults to current site. |
1339 * @return bool Whether the theme is allowed for the network. Returns true in single-site. |
1393 * @return bool Whether the theme is allowed for the network. Returns true in single-site. |
1340 */ |
1394 */ |
1341 public function is_allowed( $check = 'both', $blog_id = null ) { |
1395 public function is_allowed( $check = 'both', $blog_id = null ) { |
1342 if ( ! is_multisite() ) { |
1396 if ( ! is_multisite() ) { |
1343 return true; |
1397 return true; |
1344 } |
1398 } |
1345 |
1399 |
1346 if ( 'both' == $check || 'network' == $check ) { |
1400 if ( 'both' === $check || 'network' === $check ) { |
1347 $allowed = self::get_allowed_on_network(); |
1401 $allowed = self::get_allowed_on_network(); |
1348 if ( ! empty( $allowed[ $this->get_stylesheet() ] ) ) { |
1402 if ( ! empty( $allowed[ $this->get_stylesheet() ] ) ) { |
1349 return true; |
1403 return true; |
1350 } |
1404 } |
1351 } |
1405 } |
1352 |
1406 |
1353 if ( 'both' == $check || 'site' == $check ) { |
1407 if ( 'both' === $check || 'site' === $check ) { |
1354 $allowed = self::get_allowed_on_site( $blog_id ); |
1408 $allowed = self::get_allowed_on_site( $blog_id ); |
1355 if ( ! empty( $allowed[ $this->get_stylesheet() ] ) ) { |
1409 if ( ! empty( $allowed[ $this->get_stylesheet() ] ) ) { |
1356 return true; |
1410 return true; |
1357 } |
1411 } |
1358 } |
1412 } |
1363 /** |
1417 /** |
1364 * Determines the latest WordPress default theme that is installed. |
1418 * Determines the latest WordPress default theme that is installed. |
1365 * |
1419 * |
1366 * This hits the filesystem. |
1420 * This hits the filesystem. |
1367 * |
1421 * |
1368 * @since 4.4.0 |
1422 * @since 4.4.0 |
1369 * |
1423 * |
1370 * @return WP_Theme|false Object, or false if no theme is installed, which would be bad. |
1424 * @return WP_Theme|false Object, or false if no theme is installed, which would be bad. |
1371 */ |
1425 */ |
1372 public static function get_core_default_theme() { |
1426 public static function get_core_default_theme() { |
1373 foreach ( array_reverse( self::$default_themes ) as $slug => $name ) { |
1427 foreach ( array_reverse( self::$default_themes ) as $slug => $name ) { |
1406 /** |
1460 /** |
1407 * Returns array of stylesheet names of themes allowed on the network. |
1461 * Returns array of stylesheet names of themes allowed on the network. |
1408 * |
1462 * |
1409 * @since 3.4.0 |
1463 * @since 3.4.0 |
1410 * |
1464 * |
1411 * @staticvar array $allowed_themes |
|
1412 * |
|
1413 * @return string[] Array of stylesheet names. |
1465 * @return string[] Array of stylesheet names. |
1414 */ |
1466 */ |
1415 public static function get_allowed_on_network() { |
1467 public static function get_allowed_on_network() { |
1416 static $allowed_themes; |
1468 static $allowed_themes; |
1417 if ( ! isset( $allowed_themes ) ) { |
1469 if ( ! isset( $allowed_themes ) ) { |
1432 |
1484 |
1433 /** |
1485 /** |
1434 * Returns array of stylesheet names of themes allowed on the site. |
1486 * Returns array of stylesheet names of themes allowed on the site. |
1435 * |
1487 * |
1436 * @since 3.4.0 |
1488 * @since 3.4.0 |
1437 * |
|
1438 * @staticvar array $allowed_themes |
|
1439 * |
1489 * |
1440 * @param int $blog_id Optional. ID of the site. Defaults to the current site. |
1490 * @param int $blog_id Optional. ID of the site. Defaults to the current site. |
1441 * @return string[] Array of stylesheet names. |
1491 * @return string[] Array of stylesheet names. |
1442 */ |
1492 */ |
1443 public static function get_allowed_on_site( $blog_id = null ) { |
1493 public static function get_allowed_on_site( $blog_id = null ) { |
1457 * @param int $blog_id ID of the site. Defaults to current site. |
1507 * @param int $blog_id ID of the site. Defaults to current site. |
1458 */ |
1508 */ |
1459 return (array) apply_filters( 'site_allowed_themes', $allowed_themes[ $blog_id ], $blog_id ); |
1509 return (array) apply_filters( 'site_allowed_themes', $allowed_themes[ $blog_id ], $blog_id ); |
1460 } |
1510 } |
1461 |
1511 |
1462 $current = $blog_id == get_current_blog_id(); |
1512 $current = get_current_blog_id() == $blog_id; |
1463 |
1513 |
1464 if ( $current ) { |
1514 if ( $current ) { |
1465 $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' ); |
1515 $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' ); |
1466 } else { |
1516 } else { |
1467 switch_to_blog( $blog_id ); |
1517 switch_to_blog( $blog_id ); |
1584 * Accesses the Name header directly from the class for maximum speed. |
1634 * Accesses the Name header directly from the class for maximum speed. |
1585 * Would choke on HTML but we don't care enough to slow it down with strip_tags(). |
1635 * Would choke on HTML but we don't care enough to slow it down with strip_tags(). |
1586 * |
1636 * |
1587 * @since 3.4.0 |
1637 * @since 3.4.0 |
1588 * |
1638 * |
1589 * @param string $a First name. |
1639 * @param WP_Theme $a First theme. |
1590 * @param string $b Second name. |
1640 * @param WP_Theme $b Second theme. |
1591 * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. |
1641 * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. |
1592 * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). |
1642 * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). |
1593 */ |
1643 */ |
1594 private static function _name_sort( $a, $b ) { |
1644 private static function _name_sort( $a, $b ) { |
1595 return strnatcasecmp( $a->headers['Name'], $b->headers['Name'] ); |
1645 return strnatcasecmp( $a->headers['Name'], $b->headers['Name'] ); |
1598 /** |
1648 /** |
1599 * Callback function for usort() to naturally sort themes by translated name. |
1649 * Callback function for usort() to naturally sort themes by translated name. |
1600 * |
1650 * |
1601 * @since 3.4.0 |
1651 * @since 3.4.0 |
1602 * |
1652 * |
1603 * @param string $a First name. |
1653 * @param WP_Theme $a First theme. |
1604 * @param string $b Second name. |
1654 * @param WP_Theme $b Second theme. |
1605 * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. |
1655 * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. |
1606 * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). |
1656 * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). |
1607 */ |
1657 */ |
1608 private static function _name_sort_i18n( $a, $b ) { |
1658 private static function _name_sort_i18n( $a, $b ) { |
1609 return strnatcasecmp( $a->name_translated, $b->name_translated ); |
1659 return strnatcasecmp( $a->name_translated, $b->name_translated ); |