WP_Theme::__construct( string $theme_dir, string $theme_root, WP_Theme|null $_child = null )

In this article

Constructor for WP_Theme.

Parameters

$theme_dirstringrequired
Directory of the theme within the theme_root.
$theme_rootstringrequired
Theme root.
$_childWP_Theme|nulloptional
If this theme is a parent theme, the child may be passed for validation purposes.

Default:null

Source

public function __construct( $theme_dir, $theme_root, $_child = null ) {
	global $wp_theme_directories;

	// Initialize caching on first run.
	if ( ! isset( self::$persistently_cache ) ) {
		/** This action is documented in wp-includes/theme.php */
		self::$persistently_cache = apply_filters( 'wp_cache_themes_persistently', false, 'WP_Theme' );
		if ( self::$persistently_cache ) {
			wp_cache_add_global_groups( 'themes' );
			if ( is_int( self::$persistently_cache ) ) {
				self::$cache_expiration = self::$persistently_cache;
			}
		} else {
			wp_cache_add_non_persistent_groups( 'themes' );
		}
	}

	// Handle a numeric theme directory as a string.
	$theme_dir = (string) $theme_dir;

	$this->theme_root = $theme_root;
	$this->stylesheet = $theme_dir;

	// Correct a situation where the theme is 'some-directory/some-theme' but 'some-directory' was passed in as part of the theme root instead.
	if ( ! in_array( $theme_root, (array) $wp_theme_directories, true )
		&& in_array( dirname( $theme_root ), (array) $wp_theme_directories, true )
	) {
		$this->stylesheet = basename( $this->theme_root ) . '/' . $this->stylesheet;
		$this->theme_root = dirname( $theme_root );
	}

	$this->cache_hash = md5( $this->theme_root . '/' . $this->stylesheet );
	$theme_file       = $this->stylesheet . '/style.css';

	$cache = $this->cache_get( 'theme' );

	if ( is_array( $cache ) ) {
		foreach ( array( 'block_template_folders', 'block_theme', 'errors', 'headers', 'template' ) as $key ) {
			if ( isset( $cache[ $key ] ) ) {
				$this->$key = $cache[ $key ];
			}
		}
		if ( $this->errors ) {
			return;
		}
		if ( isset( $cache['theme_root_template'] ) ) {
			$theme_root_template = $cache['theme_root_template'];
		}
	} elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) {
		$this->headers['Name'] = $this->stylesheet;
		if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) ) {
			$this->errors = new WP_Error(
				'theme_not_found',
				sprintf(
					/* translators: %s: Theme directory name. */
					__( 'The theme directory "%s" does not exist.' ),
					esc_html( $this->stylesheet )
				)
			);
		} else {
			$this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) );
		}
		$this->template               = $this->stylesheet;
		$this->block_theme            = false;
		$this->block_template_folders = $this->default_template_folders;
		$this->cache_add(
			'theme',
			array(
				'block_template_folders' => $this->block_template_folders,
				'block_theme'            => $this->block_theme,
				'headers'                => $this->headers,
				'errors'                 => $this->errors,
				'stylesheet'             => $this->stylesheet,
				'template'               => $this->template,
			)
		);
		if ( ! file_exists( $this->theme_root ) ) { // Don't cache this one.
			$this->errors->add( 'theme_root_missing', __( '<strong>Error:</strong> The themes directory is either empty or does not exist. Please check your installation.' ) );
		}
		return;
	} elseif ( ! is_readable( $this->theme_root . '/' . $theme_file ) ) {
		$this->headers['Name']        = $this->stylesheet;
		$this->errors                 = new WP_Error( 'theme_stylesheet_not_readable', __( 'Stylesheet is not readable.' ) );
		$this->template               = $this->stylesheet;
		$this->block_theme            = false;
		$this->block_template_folders = $this->default_template_folders;
		$this->cache_add(
			'theme',
			array(
				'block_template_folders' => $this->block_template_folders,
				'block_theme'            => $this->block_theme,
				'headers'                => $this->headers,
				'errors'                 => $this->errors,
				'stylesheet'             => $this->stylesheet,
				'template'               => $this->template,
			)
		);
		return;
	} else {
		$this->headers = get_file_data( $this->theme_root . '/' . $theme_file, self::$file_headers, 'theme' );
		/*
		 * Default themes always trump their pretenders.
		 * Properly identify default themes that are inside a directory within wp-content/themes.
		 */
		$default_theme_slug = array_search( $this->headers['Name'], self::$default_themes, true );
		if ( $default_theme_slug ) {
			if ( basename( $this->stylesheet ) !== $default_theme_slug ) {
				$this->headers['Name'] .= '/' . $this->stylesheet;
			}
		}
	}

	if ( ! $this->template && $this->stylesheet === $this->headers['Template'] ) {
		$this->errors = new WP_Error(
			'theme_child_invalid',
			sprintf(
				/* translators: %s: Template. */
				__( 'The theme defines itself as its parent theme. Please check the %s header.' ),
				'<code>Template</code>'
			)
		);
		$this->cache_add(
			'theme',
			array(
				'block_template_folders' => $this->get_block_template_folders(),
				'block_theme'            => $this->is_block_theme(),
				'headers'                => $this->headers,
				'errors'                 => $this->errors,
				'stylesheet'             => $this->stylesheet,
			)
		);

		return;
	}

	// (If template is set from cache [and there are no errors], we know it's good.)
	if ( ! $this->template ) {
		$this->template = $this->headers['Template'];
	}

	if ( ! $this->template ) {
		$this->template = $this->stylesheet;
		$theme_path     = $this->theme_root . '/' . $this->stylesheet;

		if ( ! $this->is_block_theme() && ! file_exists( $theme_path . '/index.php' ) ) {
			$error_message = sprintf(
				/* translators: 1: templates/index.html, 2: index.php, 3: Documentation URL, 4: Template, 5: style.css */
				__( 'Template is missing. Standalone themes need to have a %1$s or %2$s template file. <a href="%3$s">Child themes</a> need to have a %4$s header in the %5$s stylesheet.' ),
				'<code>templates/index.html</code>',
				'<code>index.php</code>',
				__( 'https://developer.wordpress.org/themes/advanced-topics/child-themes/' ),
				'<code>Template</code>',
				'<code>style.css</code>'
			);
			$this->errors = new WP_Error( 'theme_no_index', $error_message );
			$this->cache_add(
				'theme',
				array(
					'block_template_folders' => $this->get_block_template_folders(),
					'block_theme'            => $this->block_theme,
					'headers'                => $this->headers,
					'errors'                 => $this->errors,
					'stylesheet'             => $this->stylesheet,
					'template'               => $this->template,
				)
			);
			return;
		}
	}

	// If we got our data from cache, we can assume that 'template' is pointing to the right place.
	if ( ! is_array( $cache )
		&& $this->template !== $this->stylesheet
		&& ! file_exists( $this->theme_root . '/' . $this->template . '/index.php' )
	) {
		/*
		 * If we're in a directory of themes inside /themes, look for the parent nearby.
		 * wp-content/themes/directory-of-themes/*
		 */
		$parent_dir  = dirname( $this->stylesheet );
		$directories = search_theme_directories();

		if ( '.' !== $parent_dir
			&& file_exists( $this->theme_root . '/' . $parent_dir . '/' . $this->template . '/index.php' )
		) {
			$this->template = $parent_dir . '/' . $this->template;
		} elseif ( $directories && isset( $directories[ $this->template ] ) ) {
			/*
			 * Look for the template in the search_theme_directories() results, in case it is in another theme root.
			 * We don't look into directories of themes, just the theme root.
			 */
			$theme_root_template = $directories[ $this->template ]['theme_root'];
		} else {
			// Parent theme is missing.
			$this->errors = new WP_Error(
				'theme_no_parent',
				sprintf(
					/* translators: %s: Theme directory name. */
					__( 'The parent theme is missing. Please install the "%s" parent theme.' ),
					esc_html( $this->template )
				)
			);
			$this->cache_add(
				'theme',
				array(
					'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,
				)
			);
			$this->parent = new WP_Theme( $this->template, $this->theme_root, $this );
			return;
		}
	}

	// Set the parent, if we're a child theme.
	if ( $this->template !== $this->stylesheet ) {
		// If we are a parent, then there is a problem. Only two generations allowed! Cancel things out.
		if ( $_child instanceof WP_Theme && $_child->template === $this->stylesheet ) {
			$_child->parent = null;
			$_child->errors = new WP_Error(
				'theme_parent_invalid',
				sprintf(
					/* translators: %s: Theme directory name. */
					__( 'The "%s" theme is not a valid parent theme.' ),
					esc_html( $_child->template )
				)
			);
			$_child->cache_add(
				'theme',
				array(
					'block_template_folders' => $_child->get_block_template_folders(),
					'block_theme'            => $_child->is_block_theme(),
					'headers'                => $_child->headers,
					'errors'                 => $_child->errors,
					'stylesheet'             => $_child->stylesheet,
					'template'               => $_child->template,
				)
			);
			// The two themes actually reference each other with the Template header.
			if ( $_child->stylesheet === $this->template ) {
				$this->errors = new WP_Error(
					'theme_parent_invalid',
					sprintf(
						/* translators: %s: Theme directory name. */
						__( 'The "%s" theme is not a valid parent theme.' ),
						esc_html( $this->template )
					)
				);
				$this->cache_add(
					'theme',
					array(
						'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,
					)
				);
			}
			return;
		}
		// 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 ) ) {
		$cache = array(
			'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 );
	}
}

Hooks

apply_filters( ‘wp_cache_themes_persistently’, bool $cache_expiration, string $context )

Filters whether to get the cache of the registered theme directories.

Changelog

VersionDescription
3.4.0Introduced.

User Contributed Notes

You must log in before being able to contribute a note or feedback.