From f200a37dd2121723dc0e52b1837230de54028db2 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Thu, 24 Feb 2022 10:45:53 +0000
Subject: [PATCH] Issue #3265362 by quietone, dww, murilohp: Do not display
 obsolete themes at admin/appearance

(cherry picked from commit d7a82b5b1a7dd6159a9b668d92d5c418fb5a0efc)
---
 core/lib/Drupal/Core/Extension/Extension.php        | 13 +++++++++++++
 .../system/src/Controller/SystemController.php      |  7 ++++++-
 .../tests/src/Functional/System/ThemeTest.php       |  4 ++++
 .../obsolete_theme_test.info.yml                    |  7 +++++++
 4 files changed, 30 insertions(+), 1 deletion(-)
 create mode 100644 core/modules/system/tests/themes/obsolete_theme_test/obsolete_theme_test.info.yml

diff --git a/core/lib/Drupal/Core/Extension/Extension.php b/core/lib/Drupal/Core/Extension/Extension.php
index 17ca3fe7dc3d..62977ba7ce5c 100644
--- a/core/lib/Drupal/Core/Extension/Extension.php
+++ b/core/lib/Drupal/Core/Extension/Extension.php
@@ -209,4 +209,17 @@ public function isExperimental(): bool {
         && $this->info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER] === ExtensionLifecycle::EXPERIMENTAL);
   }
 
+  /**
+   * Checks if an extension is marked as obsolete.
+   *
+   * @return bool
+   *   TRUE if an extension is marked as obsolete, FALSE otherwise.
+   */
+  public function isObsolete(): bool {
+    // This function checks for 'lifecycle: obsolete' to determine if an
+    // extension is marked as obsolete.
+    return (isset($this->info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER])
+        && $this->info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER] === ExtensionLifecycle::OBSOLETE);
+  }
+
 }
diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php
index 4d30102d06bb..39c67dac7979 100644
--- a/core/modules/system/src/Controller/SystemController.php
+++ b/core/modules/system/src/Controller/SystemController.php
@@ -195,7 +195,7 @@ public function systemAdminMenuBlockPage() {
   }
 
   /**
-   * Returns a theme listing.
+   * Returns a theme listing which excludes obsolete themes.
    *
    * @return string
    *   An HTML string of the theme listing page.
@@ -206,6 +206,11 @@ public function themesPage() {
     $config = $this->config('system.theme');
     // Get all available themes.
     $themes = $this->themeHandler->rebuildThemeData();
+
+    // Remove obsolete themes.
+    $themes = array_filter($themes, function ($theme) {
+      return !$theme->isObsolete();
+    });
     uasort($themes, [ThemeExtensionList::class, 'sortByName']);
 
     $theme_default = $config->get('default');
diff --git a/core/modules/system/tests/src/Functional/System/ThemeTest.php b/core/modules/system/tests/src/Functional/System/ThemeTest.php
index 7765a2b93e60..e74bf68b23ce 100644
--- a/core/modules/system/tests/src/Functional/System/ThemeTest.php
+++ b/core/modules/system/tests/src/Functional/System/ThemeTest.php
@@ -320,6 +320,10 @@ public function testAdministrationTheme() {
     $this->drupalGet('admin/appearance');
     $this->submitForm($edit, 'Save configuration');
 
+    // Check that obsolete themes are not displayed.
+    $this->drupalGet('admin/appearance');
+    $this->assertSession()->pageTextNotContains('Obsolete test theme');
+
     // Check that the administration theme is used on an administration page.
     $this->drupalGet('admin/config');
     $this->assertSession()->responseContains('core/themes/seven');
diff --git a/core/modules/system/tests/themes/obsolete_theme_test/obsolete_theme_test.info.yml b/core/modules/system/tests/themes/obsolete_theme_test/obsolete_theme_test.info.yml
new file mode 100644
index 000000000000..46f10e3b05ce
--- /dev/null
+++ b/core/modules/system/tests/themes/obsolete_theme_test/obsolete_theme_test.info.yml
@@ -0,0 +1,7 @@
+name: 'Obsolete theme test'
+type: theme
+description: 'Obsolete test theme.'
+version: VERSION
+lifecycle: obsolete
+lifecycle_link: 'https://example.com/obsolete'
+base theme: false
-- 
GitLab