diff --git a/composer.json b/composer.json
index 62a605a16..898b5c035 100644
--- a/composer.json
+++ b/composer.json
@@ -61,6 +61,9 @@
"plugin update",
"theme",
"theme activate",
+ "theme cache",
+ "theme cache clear",
+ "theme cache flush",
"theme delete",
"theme disable",
"theme enable",
diff --git a/extension-command.php b/extension-command.php
index 18b87efd0..a80b2167b 100644
--- a/extension-command.php
+++ b/extension-command.php
@@ -22,3 +22,4 @@
WP_CLI::add_command( 'theme', 'Theme_Command' );
WP_CLI::add_command( 'theme auto-updates', 'Theme_AutoUpdates_Command', $wpcli_extension_requires_wp_5_5 );
WP_CLI::add_command( 'theme mod', 'Theme_Mod_Command' );
+WP_CLI::add_command( 'theme cache', 'Theme_Cache_Command' );
diff --git a/features/theme-cache.feature b/features/theme-cache.feature
new file mode 100644
index 000000000..3f4fb4a2a
--- /dev/null
+++ b/features/theme-cache.feature
@@ -0,0 +1,76 @@
+Feature: Manage theme cache
+
+ Background:
+ Given a WP installation
+
+ Scenario: Clear cache for a single theme
+ When I run `wp theme install twentytwenty --force --activate`
+ Then STDOUT should contain:
+ """
+ Success:
+ """
+
+ When I run `wp theme cache clear twentytwenty`
+ Then STDOUT should be:
+ """
+ Success: Cleared cache for 'twentytwenty' theme.
+ """
+
+ Scenario: Clear cache for multiple themes
+ When I run `wp theme install twentytwentythree --force`
+ Then STDOUT should contain:
+ """
+ Success:
+ """
+
+ When I run `wp theme install twentytwenty --force `
+ Then STDOUT should contain:
+ """
+ Success:
+ """
+
+ When I run `wp theme cache clear twentytwentythree twentytwenty`
+ Then STDOUT should be:
+ """
+ Success: Cleared cache for 2 themes.
+ """
+
+ Scenario: Clear cache for all themes
+ When I run `wp theme install twentytwentythree --force`
+ Then STDOUT should contain:
+ """
+ Success:
+ """
+
+ When I run `wp theme cache clear --all`
+ Then STDOUT should contain:
+ """
+ Success: Cleared cache for
+ """
+ And STDOUT should contain:
+ """
+ themes.
+ """
+
+ Scenario: Clear cache for non-existent theme
+ When I try `wp theme cache clear nonexistent`
+ Then STDERR should contain:
+ """
+ Warning: Theme 'nonexistent' not found.
+ """
+ And the return code should be 1
+
+ Scenario: Clear cache with no arguments
+ When I try `wp theme cache clear`
+ Then STDERR should be:
+ """
+ Error: Please specify one or more themes, or use --all.
+ """
+ And the return code should be 1
+
+ Scenario: Flush the entire theme cache group
+ When I run `wp theme cache flush`
+ Then STDOUT should be:
+ """
+ Success: The theme cache was flushed.
+ """
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index d0cb7801d..1d8835833 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -53,7 +53,7 @@
- */src/(Plugin_(AutoUpdates_)?|Theme_(Mod_|AutoUpdates_)?)Command\.php$
+ */src/(Plugin_(AutoUpdates_)?|Theme_(Mod_|AutoUpdates_|Cache_)?)Command\.php$
diff --git a/src/Theme_Cache_Command.php b/src/Theme_Cache_Command.php
new file mode 100644
index 000000000..db6b733b8
--- /dev/null
+++ b/src/Theme_Cache_Command.php
@@ -0,0 +1,131 @@
+...]
+ * : One or more themes to clear the cache for.
+ *
+ * [--all]
+ * : If set, clear cache for all installed themes.
+ *
+ * ## EXAMPLES
+ *
+ * # Clear cache for a single theme
+ * $ wp theme cache clear twentytwentyfour
+ * Success: Cleared cache for 'twentytwentyfour' theme.
+ *
+ * # Clear cache for multiple themes
+ * $ wp theme cache clear twentytwentythree twentytwentyfour
+ * Success: Cleared cache for 2 themes.
+ *
+ * # Clear cache for all themes
+ * $ wp theme cache clear --all
+ * Success: Cleared cache for all themes.
+ *
+ * @param string[] $args Positional arguments.
+ * @param array{all?: bool} $assoc_args Associative arguments.
+ */
+ public function clear( $args, $assoc_args ) {
+ if ( ! \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) && empty( $args ) ) {
+ WP_CLI::error( 'Please specify one or more themes, or use --all.' );
+ }
+
+ $themes = [];
+
+ if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ) ) {
+ $all_themes = wp_get_themes();
+ foreach ( $all_themes as $theme ) {
+ $themes[] = $theme;
+ }
+ } else {
+ foreach ( $args as $theme_slug ) {
+ $theme = wp_get_theme( $theme_slug );
+ if ( ! $theme->exists() ) {
+ WP_CLI::warning( "Theme '{$theme_slug}' not found." );
+ continue;
+ }
+ $themes[] = $theme;
+ }
+ }
+
+ if ( empty( $themes ) ) {
+ WP_CLI::error( 'No valid themes to clear cache for.' );
+ }
+
+ $cleared = 0;
+ foreach ( $themes as $theme ) {
+ $this->clear_theme_cache( $theme );
+ ++$cleared;
+ }
+
+ if ( 1 === $cleared ) {
+ WP_CLI::success( "Cleared cache for '{$themes[0]->get_stylesheet()}' theme." );
+ } else {
+ WP_CLI::success( "Cleared cache for {$cleared} themes." );
+ }
+ }
+
+ /**
+ * Flushes the entire theme cache group.
+ *
+ * ## EXAMPLES
+ *
+ * # Flush the entire theme cache group
+ * $ wp theme cache flush
+ * Success: The theme cache was flushed.
+ *
+ * @param string[] $args Positional arguments. Unused.
+ * @param array $assoc_args Associative arguments. Unused.
+ */
+ public function flush( $args, $assoc_args ) {
+ // Only added in WordPress 6.1.
+ if ( function_exists( 'wp_cache_flush_group' ) ) {
+ wp_cache_flush_group( 'themes' );
+ WP_CLI::success( 'The theme cache was flushed.' );
+ return;
+ }
+
+ // Fallback for WordPress versions prior to 6.1: clear cache for all themes.
+ if ( function_exists( 'wp_get_themes' ) ) {
+ $all_themes = wp_get_themes();
+ foreach ( $all_themes as $theme ) {
+ $this->clear_theme_cache( $theme );
+ }
+ WP_CLI::success( 'The theme cache was flushed.' );
+ } else {
+ WP_CLI::warning( 'Your WordPress version does not support flushing the theme cache group.' );
+ }
+ }
+
+ /**
+ * Clear cache for a specific theme.
+ *
+ * @param \WP_Theme $theme Theme object.
+ */
+ private function clear_theme_cache( $theme ) {
+ $cache_hash = md5( $theme->get_theme_root() . '/' . $theme->get_stylesheet() );
+ $cache_keys = [ 'theme', 'screenshot', 'headers', 'page_templates' ];
+
+ foreach ( $cache_keys as $key ) {
+ wp_cache_delete( $key . '-' . $cache_hash, 'themes' );
+ }
+ }
+}