: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
'block_template_folders' => $this->get_block_template_folders(),
'block_theme' => $this->is_block_theme(),
'headers' => $this->headers,
'errors' => $this->errors,
'stylesheet' => $this->stylesheet,
'template' => $this->template,
// Set the parent. Pass the current instance so we can do the checks above and assess errors.
$this->parent = new WP_Theme( $this->template, isset( $theme_root_template ) ? $theme_root_template : $this->theme_root, $this );
if ( wp_paused_themes()->get( $this->stylesheet ) && ( ! is_wp_error( $this->errors ) || ! isset( $this->errors->errors['theme_paused'] ) ) ) {
$this->errors = new WP_Error( 'theme_paused', __( 'This theme failed to load properly and was paused within the admin backend.' ) );
// We're good. If we didn't retrieve from cache, set it.
if ( ! is_array( $cache ) ) {
'block_theme' => $this->is_block_theme(),
'block_template_folders' => $this->get_block_template_folders(),
'headers' => $this->headers,
'errors' => $this->errors,
'stylesheet' => $this->stylesheet,
'template' => $this->template,
// If the parent theme is in another root, we'll want to cache this. Avoids an entire branch of filesystem calls above.
if ( isset( $theme_root_template ) ) {
$cache['theme_root_template'] = $theme_root_template;
$this->cache_add( 'theme', $cache );
* When converting the object to a string, the theme name is returned.
* @return string Theme name, ready for display (translated)
public function __toString() {
return (string) $this->display( 'Name' );
* __isset() magic method for properties formerly returned by current_theme_info()
* @param string $offset Property to check if set.
* @return bool Whether the given property is set.
public function __isset( $offset ) {
static $properties = array(
return in_array( $offset, $properties, true );
* __get() magic method for properties formerly returned by current_theme_info()
* @param string $offset Property to get.
* @return mixed Property value.
public function __get( $offset ) {
return $this->get( 'Name' );
return $this->get( 'Version' );
return $this->parent() ? $this->parent()->get( 'Name' ) : '';
return $this->get_template_directory();
return $this->get_stylesheet_directory();
return $this->get_template();
return $this->get_stylesheet();
return $this->get_screenshot( 'relative' );
// 'author' and 'description' did not previously return translated data.
return $this->display( 'Description' );
return $this->display( 'Author' );
return $this->get( 'Tags' );
return $this->get_theme_root();
return $this->get_theme_root_uri();
// For cases where the array was converted to an object.
return $this->offsetGet( $offset );
* Method to implement ArrayAccess for keys formerly returned by get_themes()
public function offsetSet( $offset, $value ) {}
* Method to implement ArrayAccess for keys formerly returned by get_themes()
public function offsetUnset( $offset ) {}
* Method to implement ArrayAccess for keys formerly returned by get_themes()
public function offsetExists( $offset ) {
return in_array( $offset, $keys, true );
* Method to implement ArrayAccess for keys formerly returned by get_themes().
* Author, Author Name, Author URI, and Description did not previously return
* translated data. We are doing so now as it is safe to do. However, as
* Name and Title could have been used as the key for get_themes(), both remain
* untranslated for back compatibility. This means that ['Name'] is not ideal,
* and care should be taken to use `$theme::display( 'Name' )` to get a properly
public function offsetGet( $offset ) {
* See note above about using translated data. get() is not ideal.
* It is only for backward compatibility. Use display().
return $this->get( 'Name' );
return $this->display( 'Author' );
return $this->display( 'Author', false );
return $this->display( 'AuthorURI' );
return $this->display( 'Description' );
return $this->get( $offset );
return $this->get_template();
return $this->get_stylesheet();
return $this->get_files( 'php', 1, true );
return $this->get_files( 'css', 0, false );
return $this->get_template_directory();
return $this->get_stylesheet_directory();
return $this->get_screenshot( 'relative' );
return $this->get( 'Tags' );
return $this->get_theme_root();
return $this->get_theme_root_uri();
return $this->parent() ? $this->parent()->get( 'Name' ) : '';
* Returns errors property.
* @return WP_Error|false WP_Error if there are errors, or false.
public function errors() {
return is_wp_error( $this->errors ) ? $this->errors : false;
* Determines whether the theme exists.
* A theme with errors exists. A theme with the error of 'theme_not_found',
* meaning that the theme's directory was not found, does not exist.
* @return bool Whether the theme exists.
public function exists() {
return ! ( $this->errors() && in_array( 'theme_not_found', $this->errors()->get_error_codes(), true ) );
* Returns reference to the parent theme.
* @return WP_Theme|false Parent theme, or false if the active theme is not a child theme.
public function parent() {
return isset( $this->parent ) ? $this->parent : false;
* Perform reinitialization tasks.
* Prevents a callback from being injected during unserialization of an object.
public function __wakeup() {
if ( $this->parent && ! $this->parent instanceof self ) {
throw new UnexpectedValueException();
if ( $this->headers && ! is_array( $this->headers ) ) {
throw new UnexpectedValueException();
foreach ( $this->headers as $value ) {
if ( ! is_string( $value ) ) {
throw new UnexpectedValueException();
$this->headers_sanitized = array();
* Adds theme data to cache.
* Cache entries keyed by the theme and the type of data.
* @param string $key Type of data to store (theme, screenshot, headers, post_templates)
* @param array|string $data Data to store
* @return bool Return value from wp_cache_add()
private function cache_add( $key, $data ) {
return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'themes', self::$cache_expiration );
* Gets theme data from cache.
* Cache entries are keyed by the theme and the type of data.
* @param string $key Type of data to retrieve (theme, screenshot, headers, post_templates)
* @return mixed Retrieved data
private function cache_get( $key ) {
return wp_cache_get( $key . '-' . $this->cache_hash, 'themes' );
* Clears the cache for the theme.
public function cache_delete() {
foreach ( array( 'theme', 'screenshot', 'headers', 'post_templates' ) as $key ) {
wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' );
$this->textdomain_loaded = null;
$this->theme_root_uri = null;
$this->headers_sanitized = null;
$this->name_translated = null;
$this->block_theme = null;
$this->block_template_folders = null;
$this->headers = array();
$this->__construct( $this->stylesheet, $this->theme_root );
$this->delete_pattern_cache();
* Gets a raw, unformatted theme header.
* The header is sanitized, but is not translated, and is not marked up for display.
* To get a theme header for display, use the display() method.
* Use the get_template() method, not the 'Template' header, for finding the template.
* The 'Template' header is only good for what was written in the style.css, while
* get_template() takes into account where WordPress actually located the theme and
* whether it is actually valid.
* @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
* @return string|array|false String or array (for Tags header) on success, false on failure.
public function get( $header ) {
if ( ! isset( $this->headers[ $header ] ) ) {
if ( ! isset( $this->headers_sanitized ) ) {
$this->headers_sanitized = $this->cache_get( 'headers' );
if ( ! is_array( $this->headers_sanitized ) ) {
$this->headers_sanitized = array();
if ( isset( $this->headers_sanitized[ $header ] ) ) {
return $this->headers_sanitized[ $header ];
// If themes are a persistent group, sanitize everything and cache it. One cache add is better than many cache sets.
if ( self::$persistently_cache ) {
foreach ( array_keys( $this->headers ) as $_header ) {
$this->headers_sanitized[ $_header ] = $this->sanitize_header( $_header, $this->headers[ $_header ] );
$this->cache_add( 'headers', $this->headers_sanitized );
$this->headers_sanitized[ $header ] = $this->sanitize_header( $header, $this->headers[ $header ] );
return $this->headers_sanitized[ $header ];
* Gets a theme header, formatted and translated for display.
* @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
* @param bool $markup Optional. Whether to mark up the header. Defaults to true.
* @param bool $translate Optional. Whether to translate the header. Defaults to true.
* @return string|array|false Processed header. An array for Tags if `$markup` is false, string otherwise.
public function display( $header, $markup = true, $translate = true ) {
$value = $this->get( $header );
if ( false === $value ) {
if ( $translate && ( empty( $value ) || ! $this->load_textdomain() ) ) {
$value = $this->translate_header( $header, $value );
$value = $this->markup_header( $header, $value, $translate );
* Sanitizes a theme header.
* @since 5.4.0 Added support for `Requires at least` and `Requires PHP` headers.
* @since 6.1.0 Added support for `Update URI` header.
* @param string $header Theme header. Accepts 'Name', 'Description', 'Author', 'Version',
* 'ThemeURI', 'AuthorURI', 'Status', 'Tags', 'RequiresWP', 'RequiresPHP',
* @param string $value Value to sanitize.
* @return string|array An array for Tags header, string otherwise.
private function sanitize_header( $header, $value ) {
// Fall through otherwise.
static $header_tags = array(
'abbr' => array( 'title' => true ),
'acronym' => array( 'title' => true ),
$value = wp_kses( $value, $header_tags );
// There shouldn't be anchor tags in Author, but some themes like to be challenging.
static $header_tags_with_a = array(
'abbr' => array( 'title' => true ),
'acronym' => array( 'title' => true ),
$value = wp_kses( $value, $header_tags_with_a );
$value = sanitize_url( $value );
$value = array_filter( array_map( 'trim', explode( ',', strip_tags( $value ) ) ) );
$value = strip_tags( $value );
* Marks up a theme header.