diff --git a/core/modules/views/config/schema/views.display.schema.yml b/core/modules/views/config/schema/views.display.schema.yml index 725b0d072ea..a685e33a990 100644 --- a/core/modules/views/config/schema/views.display.schema.yml +++ b/core/modules/views/config/schema/views.display.schema.yml @@ -68,6 +68,10 @@ views.display.page: menu_name: type: string label: 'Menu name' + use_admin_theme: + type: boolean + nullable: true + label: 'Use the administration theme when rendering the view page' views.display.block: type: views_display diff --git a/core/modules/views/src/Plugin/views/display/Page.php b/core/modules/views/src/Plugin/views/display/Page.php index a578c355a99..c378885b7a2 100644 --- a/core/modules/views/src/Plugin/views/display/Page.php +++ b/core/modules/views/src/Plugin/views/display/Page.php @@ -105,6 +105,10 @@ class Page extends PathPluginBase { // Explicitly set HTML as the format for Page displays. $route->setRequirement('_format', 'html'); + if ($this->getOption('use_admin_theme')) { + $route->setOption('_admin_route', TRUE); + } + return $route; } @@ -244,6 +248,26 @@ class Page extends PathPluginBase { $options['menu']['setting'] = $this->t('Parent menu link'); $options['menu']['links']['tab_options'] = $this->t('Change settings for the parent menu'); } + + // If the display path starts with 'admin/' the page will be rendered with + // the Administration theme regardless of the 'use_admin_theme' option + // therefore, we need to set the summary message to reflect this. + if (str_starts_with($this->getOption('path') ?? '', 'admin/')) { + $admin_theme_text = $this->t('Yes (admin path)'); + } + elseif ($this->getOption('use_admin_theme')) { + $admin_theme_text = $this->t('Yes'); + } + else { + $admin_theme_text = $this->t('No'); + } + + $options['use_admin_theme'] = [ + 'category' => 'page', + 'title' => $this->t('Administration theme'), + 'value' => $admin_theme_text, + 'desc' => $this->t('Use the administration theme when rendering this display.'), + ]; } /** @@ -445,6 +469,20 @@ class Page extends PathPluginBase { ], ]; break; + + case 'use_admin_theme': + $form['#title'] .= $this->t('Administration theme'); + $form['use_admin_theme'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Use the administration theme'), + '#default_value' => $this->getOption('use_admin_theme'), + ]; + if (str_starts_with($this->getOption('path') ?? '', 'admin/')) { + $form['use_admin_theme']['#description'] = $this->t('Paths starting with "@admin" always use the administration theme.', ['@admin' => 'admin/']); + $form['use_admin_theme']['#default_value'] = TRUE; + $form['use_admin_theme']['#attributes'] = ['disabled' => 'disabled']; + } + break; } } @@ -495,6 +533,16 @@ class Page extends PathPluginBase { case 'tab_options': $this->setOption('tab_options', $form_state->getValue('tab_options')); break; + + case 'use_admin_theme': + if ($form_state->getValue('use_admin_theme')) { + $this->setOption('use_admin_theme', $form_state->getValue('use_admin_theme')); + } + else { + unset($this->options['use_admin_theme']); + unset($this->display['display_options']['use_admin_theme']); + } + break; } } diff --git a/core/modules/views/tests/src/Functional/Plugin/DisplayPageWebTest.php b/core/modules/views/tests/src/Functional/Plugin/DisplayPageWebTest.php index e6b97da7c2d..1cc6c9f0cd9 100644 --- a/core/modules/views/tests/src/Functional/Plugin/DisplayPageWebTest.php +++ b/core/modules/views/tests/src/Functional/Plugin/DisplayPageWebTest.php @@ -147,6 +147,37 @@ class DisplayPageWebTest extends ViewTestBase { $this->assertPagePath('☺'); } + /** + * Tests the 'use_admin_theme' page display option. + */ + public function testAdminTheme(): void { + $account = $this->drupalCreateUser(['view the administration theme']); + $this->drupalLogin($account); + // Use distinct default and administrative themes for this test. + /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */ + $theme_handler = $this->container->get('theme_handler'); + /** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */ + $theme_installer = $this->container->get('theme_installer'); + $theme_installer->install(['claro']); + $this->container->get('config.factory') + ->getEditable('system.theme') + ->set('admin', 'claro') + ->set('default', 'stable') + ->save(); + $theme_handler->refreshInfo(); + // Check that the page has been served with the default theme. + $this->drupalGet('test_page_display_200'); + $this->assertSession()->responseNotContains('core/themes/claro/css/base/elements.css'); + + $view = $this->config('views.view.test_page_display'); + $view->set('display.page_3.display_options.use_admin_theme', TRUE)->save(); + $this->container->get('router.builder')->rebuild(); + + // Check that the page was served with the administrative theme. + $this->drupalGet('test_page_display_200'); + $this->assertSession()->responseContains('core/themes/claro/css/base/elements.css'); + } + /** * Tests that we can successfully change a view page display path. * diff --git a/core/modules/views_ui/tests/src/Functional/DisplayPathTest.php b/core/modules/views_ui/tests/src/Functional/DisplayPathTest.php index 36991c2f547..9f5c103ab08 100644 --- a/core/modules/views_ui/tests/src/Functional/DisplayPathTest.php +++ b/core/modules/views_ui/tests/src/Functional/DisplayPathTest.php @@ -4,6 +4,7 @@ namespace Drupal\Tests\views_ui\Functional; use Drupal\Core\Menu\MenuTreeParameters; use Drupal\menu_link_content\Entity\MenuLinkContent; +use Drupal\Tests\SchemaCheckTestTrait; use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait; /** @@ -15,6 +16,7 @@ use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait; class DisplayPathTest extends UITestBase { use AssertPageCacheContextsAndTagsTrait; + use SchemaCheckTestTrait; /** * {@inheritdoc} @@ -286,4 +288,56 @@ class DisplayPathTest extends UITestBase { $this->assertSession()->statusCodeEquals(200); } + /** + * Tests the "Use the administration theme" configuration. + * + * @see \Drupal\Tests\views\Functional\Plugin\DisplayPageWebTest::testAdminTheme + */ + public function testUseAdminTheme(): void { + $this->drupalGet('admin/structure/views/view/test_view'); + + // Add a new page display. + $this->submitForm([], 'Add Page'); + $this->assertSession()->pageTextContains('No path is set'); + $this->assertSession()->pageTextContains('Administration theme: No'); + + // Test with a path starting with "/admin". + $admin_path = 'admin/test_admin_path'; + $this->drupalGet('admin/structure/views/nojs/display/test_view/page_1/path'); + $this->submitForm(['path' => $admin_path], 'Apply'); + $this->assertSession()->pageTextContains('/' . $admin_path); + $this->assertSession()->pageTextContains('Administration theme: Yes (admin path)'); + $this->submitForm([], 'Save'); + + $this->assertConfigSchemaByName('views.view.test_view'); + $display_options = $this->config('views.view.test_view')->get('display.page_1.display_options'); + $this->assertArrayNotHasKey('use_admin_theme', $display_options); + + $this->drupalGet('admin/structure/views/nojs/display/test_view/page_1/use_admin_theme'); + $this->assertSession()->elementExists('css', 'input[name="use_admin_theme"][disabled="disabled"][checked="checked"]'); + + // Test with a non-administration path. + $non_admin_path = 'kittens'; + $this->drupalGet('admin/structure/views/nojs/display/test_view/page_1/path'); + $this->submitForm(['path' => $non_admin_path], 'Apply'); + $this->assertSession()->pageTextContains('/' . $non_admin_path); + $this->assertSession()->pageTextContains('Administration theme: No'); + $this->submitForm([], 'Save'); + + $this->assertConfigSchemaByName('views.view.test_view'); + $display_options = $this->config('views.view.test_view')->get('display.page_1.display_options'); + $this->assertArrayNotHasKey('use_admin_theme', $display_options); + + // Enable administration theme. + $this->drupalGet('admin/structure/views/nojs/display/test_view/page_1/use_admin_theme'); + $this->submitForm(['use_admin_theme' => TRUE], 'Apply'); + $this->assertSession()->pageTextContains('Administration theme: Yes'); + $this->submitForm([], 'Save'); + + $this->assertConfigSchemaByName('views.view.test_view'); + $display_options = $this->config('views.view.test_view')->get('display.page_1.display_options'); + $this->assertArrayHasKey('use_admin_theme', $display_options); + $this->assertTrue($display_options['use_admin_theme']); + } + }