diff --git a/core/includes/theme.inc b/core/includes/theme.inc index b1a911a..0cf5fa2 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1290,9 +1290,6 @@ function template_preprocess_html(&$variables) { function template_preprocess_page(&$variables) { $language_interface = \Drupal::languageManager()->getCurrentLanguage(); - // Move some variables to the top level for themer convenience and template cleanliness. - $variables['title'] = $variables['page']['#title']; - foreach (\Drupal::theme()->getActiveTheme()->getRegions() as $region) { if (!isset($variables['page'][$region])) { $variables['page'][$region] = array(); @@ -1659,6 +1656,9 @@ function drupal_common_theme() { 'page' => array( 'render element' => 'page', ), + 'page_title' => array( + 'variables' => array('title' => NULL), + ), 'region' => array( 'render element' => 'elements', ), diff --git a/core/lib/Drupal/Core/Block/MainContentBlockPluginInterface.php b/core/lib/Drupal/Core/Block/MainContentBlockPluginInterface.php index 2516348..38da7b3 100644 --- a/core/lib/Drupal/Core/Block/MainContentBlockPluginInterface.php +++ b/core/lib/Drupal/Core/Block/MainContentBlockPluginInterface.php @@ -10,7 +10,7 @@ /** * The interface for "main page content" blocks. * - * A main page content block represents the content returns by the controller. + * A main page content block represents the content returned by the controller. * * @ingroup block_api */ diff --git a/core/lib/Drupal/Core/Block/TitleBlockPluginInterface.php b/core/lib/Drupal/Core/Block/TitleBlockPluginInterface.php new file mode 100644 index 0000000..229300f --- /dev/null +++ b/core/lib/Drupal/Core/Block/TitleBlockPluginInterface.php @@ -0,0 +1,29 @@ + 'page_title', + '#title' => NULL, + '#cache' => [ + 'contexts' => [ + 'route', + ], + ], + ]; + } + +} diff --git a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php index 5cfa312..cd0d482 100644 --- a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php +++ b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php @@ -192,11 +192,18 @@ public function renderResponse(array $main_content, Request $request, RouteMatch * If the selected display variant does not implement PageVariantInterface. */ protected function prepare(array $main_content, Request $request, RouteMatchInterface $route_match) { + // Determine the title: use the title provided by the main content if any, + // otherwise get it from the routing information. + $get_title = function (array $main_content) use ($request, $route_match) { + return isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject()); + }; + // If the _controller result already is #type => page, // we have no work to do: The "main content" already is an entire "page" // (see html.html.twig). if (isset($main_content['#type']) && $main_content['#type'] === 'page') { $page = $main_content; + $title = $get_title($page); } // Otherwise, render it as the main content of a #type => page, by selecting // page display variant to do that and building that page display variant. @@ -228,6 +235,8 @@ protected function prepare(array $main_content, Request $request, RouteMatchInte ]; } + $title = $get_title($main_content); + // Instantiate the page display, and give it the main content. $page_display = $this->displayVariantManager->createInstance($variant_id); if (!$page_display instanceof PageVariantInterface) { @@ -235,6 +244,7 @@ protected function prepare(array $main_content, Request $request, RouteMatchInte } $page_display ->setMainContent($main_content) + ->setTitle($title) ->setConfiguration($event->getPluginConfiguration()); // Generate a #type => page render array using the page display variant, @@ -258,10 +268,6 @@ protected function prepare(array $main_content, Request $request, RouteMatchInte // Allow hooks to add attachments to $page['#attached']. $this->invokePageAttachmentHooks($page); - // Determine the title: use the title provided by the main content if any, - // otherwise get it from the routing information. - $title = isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject()); - return [$page, $title]; } diff --git a/core/lib/Drupal/Core/Render/Plugin/DisplayVariant/SimplePageVariant.php b/core/lib/Drupal/Core/Render/Plugin/DisplayVariant/SimplePageVariant.php index baef325..db9c4e6 100644 --- a/core/lib/Drupal/Core/Render/Plugin/DisplayVariant/SimplePageVariant.php +++ b/core/lib/Drupal/Core/Render/Plugin/DisplayVariant/SimplePageVariant.php @@ -28,6 +28,13 @@ class SimplePageVariant extends VariantBase implements PageVariantInterface { protected $mainContent; /** + * The page title. + * + * @var string + */ + protected $title = ''; + + /** * {@inheritdoc} */ public function setMainContent(array $main_content) { @@ -38,9 +45,22 @@ public function setMainContent(array $main_content) { /** * {@inheritdoc} */ + public function setTitle($title) { + $this->title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ public function build() { $build = [ 'content' => [ + 'page_title' => [ + '#type' => 'page_title', + '#title' => $this->title, + '#weight' => -900, + ], 'main_content' => $this->mainContent, 'messages' => [ '#type' => 'status_messages', diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index 48b3bcd..cbf243c 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -373,11 +373,6 @@ protected function doRender(&$elements, $is_root_call = FALSE) { $elements['#lazy_builder_built'] = TRUE; } - // All render elements support #markup and #plain_text. - if (!empty($elements['#markup']) || !empty($elements['#plain_text'])) { - $elements = $this->ensureMarkupIsSafe($elements); - } - // Make any final changes to the element before it is rendered. This means // that the $element or the children can be altered or corrected before the // element is rendered into the final text. @@ -390,6 +385,11 @@ protected function doRender(&$elements, $is_root_call = FALSE) { } } + // All render elements support #markup and #plain_text. + if (!empty($elements['#markup']) || !empty($elements['#plain_text'])) { + $elements = $this->ensureMarkupIsSafe($elements); + } + // Defaults for bubbleable rendering metadata. $elements['#cache']['tags'] = isset($elements['#cache']['tags']) ? $elements['#cache']['tags'] : array(); $elements['#cache']['max-age'] = isset($elements['#cache']['max-age']) ? $elements['#cache']['max-age'] : Cache::PERMANENT; diff --git a/core/modules/block/src/BlockViewBuilder.php b/core/modules/block/src/BlockViewBuilder.php index 9a582352..80f52c1 100644 --- a/core/modules/block/src/BlockViewBuilder.php +++ b/core/modules/block/src/BlockViewBuilder.php @@ -8,6 +8,7 @@ namespace Drupal\block; use Drupal\Core\Block\MainContentBlockPluginInterface; +use Drupal\Core\Block\TitleBlockPluginInterface; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Entity\EntityManagerInterface; @@ -104,7 +105,7 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la // Allow altering of cacheability metadata or setting #create_placeholder. $this->moduleHandler->alter(['block_build', "block_build_" . $plugin->getBaseId()], $build[$entity_id], $plugin); - if ($plugin instanceof MainContentBlockPluginInterface) { + if ($plugin instanceof MainContentBlockPluginInterface || $plugin instanceof TitleBlockPluginInterface) { // Immediately build a #pre_render-able block, since this block cannot // be built lazily. $build[$entity_id] += static::buildPreRenderableBlock($entity, $this->moduleHandler()); diff --git a/core/modules/block/src/Plugin/DisplayVariant/BlockPageVariant.php b/core/modules/block/src/Plugin/DisplayVariant/BlockPageVariant.php index 650cf78..4c4f87a 100644 --- a/core/modules/block/src/Plugin/DisplayVariant/BlockPageVariant.php +++ b/core/modules/block/src/Plugin/DisplayVariant/BlockPageVariant.php @@ -9,6 +9,7 @@ use Drupal\block\BlockRepositoryInterface; use Drupal\Core\Block\MainContentBlockPluginInterface; +use Drupal\Core\Block\TitleBlockPluginInterface; use Drupal\Core\Block\MessagesBlockPluginInterface; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Display\PageVariantInterface; @@ -64,6 +65,13 @@ class BlockPageVariant extends VariantBase implements PageVariantInterface, Cont protected $mainContent = []; /** + * The page title. + * + * @var string + */ + protected $title = ''; + + /** * Constructs a new BlockPageVariant. * * @param array $configuration @@ -111,9 +119,19 @@ public function setMainContent(array $main_content) { /** * {@inheritdoc} */ + public function setTitle($title) { + $this->title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ public function build() { - // Track whether blocks showing the main content and messages are displayed. + // Track whether blocks showing the main content, title and messages are + // displayed. $main_content_block_displayed = FALSE; + $title_block_displayed = FALSE; $messages_block_displayed = FALSE; $build = [ @@ -131,6 +149,10 @@ public function build() { $block_plugin->setMainContent($this->mainContent); $main_content_block_displayed = TRUE; } + elseif ($block_plugin instanceof TitleBlockPluginInterface) { + $block_plugin->setTitle($this->title); + $title_block_displayed = TRUE; + } elseif ($block_plugin instanceof MessagesBlockPluginInterface) { $messages_block_displayed = TRUE; } @@ -138,8 +160,9 @@ public function build() { // The main content block cannot be cached: it is a placeholder for the // render array returned by the controller. It should be rendered as-is, - // with other placed blocks "decorating" it. - if ($block_plugin instanceof MainContentBlockPluginInterface) { + // with other placed blocks "decorating" it. Analogous reasoning for the + // title block. + if ($block_plugin instanceof MainContentBlockPluginInterface || $block_plugin instanceof TitleBlockPluginInterface) { unset($build[$region][$key]['#cache']['keys']); } } @@ -165,6 +188,15 @@ public function build() { ]; } + // Analogously for the page title. + if (!$title_block_displayed) { + $build['content']['page_title'] = [ + '#type' => 'page_title', + '#title' => $this->title, + '#weight' => -900, + ]; + } + // The access results' cacheability is currently added to the top level of the // render array. This is done to prevent issues with empty regions being // displayed. diff --git a/core/modules/block/src/Tests/Views/DisplayBlockTest.php b/core/modules/block/src/Tests/Views/DisplayBlockTest.php index f7b3ffe..fb1df5d 100644 --- a/core/modules/block/src/Tests/Views/DisplayBlockTest.php +++ b/core/modules/block/src/Tests/Views/DisplayBlockTest.php @@ -292,7 +292,7 @@ public function testBlockEmptyRendering() { // Ensure that the view cachability metadata is propagated even, for an // empty block. $this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block' ,'rendered'])); - $this->assertCacheContexts(['url.query_args:_wrapper_format']); + $this->assertCacheContexts(['route', 'url.query_args:_wrapper_format']); // Add a header displayed on empty result. $display = &$view->getDisplay('block_1'); @@ -310,7 +310,7 @@ public function testBlockEmptyRendering() { $this->drupalGet($url); $this->assertEqual(1, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]'))); $this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block' ,'rendered'])); - $this->assertCacheContexts(['url.query_args:_wrapper_format']); + $this->assertCacheContexts(['route', 'url.query_args:_wrapper_format']); // Hide the header on empty results. $display = &$view->getDisplay('block_1'); @@ -328,7 +328,7 @@ public function testBlockEmptyRendering() { $this->drupalGet($url); $this->assertEqual(0, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]'))); $this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block' ,'rendered'])); - $this->assertCacheContexts(['url.query_args:_wrapper_format']); + $this->assertCacheContexts(['route', 'url.query_args:_wrapper_format']); // Add an empty text. $display = &$view->getDisplay('block_1'); @@ -345,7 +345,7 @@ public function testBlockEmptyRendering() { $this->drupalGet($url); $this->assertEqual(1, count($this->xpath('//div[contains(@class, "block-views-blocktest-view-block-block-1")]'))); $this->assertCacheTags(array_merge($block->getCacheTags(), ['block_view', 'config:block_list', 'config:views.view.test_view_block' ,'rendered'])); - $this->assertCacheContexts(['url.query_args:_wrapper_format']); + $this->assertCacheContexts(['route', 'url.query_args:_wrapper_format']); } /** diff --git a/core/modules/block/tests/src/Unit/Plugin/DisplayVariant/BlockPageVariantTest.php b/core/modules/block/tests/src/Unit/Plugin/DisplayVariant/BlockPageVariantTest.php index 147e64a..22f3a3e 100644 --- a/core/modules/block/tests/src/Unit/Plugin/DisplayVariant/BlockPageVariantTest.php +++ b/core/modules/block/tests/src/Unit/Plugin/DisplayVariant/BlockPageVariantTest.php @@ -74,28 +74,32 @@ public function setUpDisplayVariant($configuration = array(), $definition = arra public function providerBuild() { $blocks_config = array( 'block1' => array( - // region, is main content block, is messages block - 'top', FALSE, FALSE, + // region, is main content block, is messages block, is title block + 'top', FALSE, FALSE, FALSE, ), // Test multiple blocks in the same region. 'block2' => array( - 'bottom', FALSE, FALSE, + 'bottom', FALSE, FALSE, FALSE, ), 'block3' => array( - 'bottom', FALSE, FALSE, + 'bottom', FALSE, FALSE, FALSE, ), // Test a block implementing MainContentBlockPluginInterface. 'block4' => array( - 'center', TRUE, FALSE, + 'center', TRUE, FALSE, FALSE, ), // Test a block implementing MessagesBlockPluginInterface. 'block5' => array( - 'center', FALSE, TRUE, + 'center', FALSE, TRUE, FALSE, + ), + // Test a block implementing TitleBlockPluginInterface. + 'block7' => array( + 'center', FALSE, FALSE, TRUE, ), ); $test_cases = []; - $test_cases[] = [$blocks_config, 5, + $test_cases[] = [$blocks_config, 6, [ '#cache' => [ 'tags' => [ @@ -113,6 +117,7 @@ public function providerBuild() { 'center' => [ 'block4' => [], 'block5' => [], + 'block7' => [], '#sorted' => TRUE, ], 'bottom' => [ @@ -123,7 +128,7 @@ public function providerBuild() { ], ]; unset($blocks_config['block5']); - $test_cases[] = [$blocks_config, 4, + $test_cases[] = [$blocks_config, 5, [ '#cache' => [ 'tags' => [ @@ -139,6 +144,7 @@ public function providerBuild() { ], 'center' => [ 'block4' => [], + 'block7' => [], '#sorted' => TRUE, ], 'bottom' => [ @@ -146,8 +152,8 @@ public function providerBuild() { 'block3' => [], '#sorted' => TRUE, ], - // The messages are rendered via the fallback in case there is no block - // rendering the main content. + // The messages and title are rendered via the fallback in case there is + // no block rendering the main content. 'content' => [ 'messages' => [ '#weight' => -1000, @@ -157,6 +163,7 @@ public function providerBuild() { ], ]; unset($blocks_config['block4']); + unset($blocks_config['block7']); $test_cases[] = [$blocks_config, 3, [ '#cache' => [ @@ -176,7 +183,7 @@ public function providerBuild() { 'block3' => [], '#sorted' => TRUE, ], - // The main content & messages are rendered via the fallback in case + // The main content, messages and title are rendered via the fallback in case // there are no blocks rendering them. 'content' => [ 'system_main' => ['#markup' => 'Hello kittens!'], @@ -184,6 +191,11 @@ public function providerBuild() { '#weight' => -1000, '#type' => 'status_messages', ], + 'page_title' => [ + '#type' => 'page_title', + '#title' => 'Hi cats!', + '#weight' => -900, + ], ], ], ]; @@ -200,11 +212,13 @@ public function providerBuild() { public function testBuild(array $blocks_config, $visible_block_count, array $expected_render_array) { $display_variant = $this->setUpDisplayVariant(); $display_variant->setMainContent(['#markup' => 'Hello kittens!']); + $display_variant->setTitle('Hi cats!'); $blocks = ['top' => [], 'center' => [], 'bottom' => []]; $block_plugin = $this->getMock('Drupal\Core\Block\BlockPluginInterface'); $main_content_block_plugin = $this->getMock('Drupal\Core\Block\MainContentBlockPluginInterface'); $messages_block_plugin = $this->getMock('Drupal\Core\Block\MessagesBlockPluginInterface'); + $title_block_plugin = $this->getMock('Drupal\Core\Block\TitleBlockPluginInterface'); foreach ($blocks_config as $block_id => $block_config) { $block = $this->getMock('Drupal\block\BlockInterface'); $block->expects($this->any()) @@ -212,7 +226,7 @@ public function testBuild(array $blocks_config, $visible_block_count, array $exp ->willReturn([]); $block->expects($this->atLeastOnce()) ->method('getPlugin') - ->willReturn($block_config[1] ? $main_content_block_plugin : ($block_config[2] ? $messages_block_plugin : $block_plugin)); + ->willReturn($block_config[1] ? $main_content_block_plugin : ($block_config[2] ? $messages_block_plugin : ($block_config[3] ? $title_block_plugin : $block_plugin))); $blocks[$block_config[0]][$block_id] = $block; } $this->blockViewBuilder->expects($this->exactly($visible_block_count)) @@ -239,6 +253,7 @@ public function testBuildWithoutMainContent() { $this->blockRepository->expects($this->once()) ->method('getVisibleBlocksPerRegion') ->willReturn([]); + $display_variant->setTitle('Hi llamas!'); $expected = [ '#cache' => [ @@ -254,6 +269,11 @@ public function testBuildWithoutMainContent() { '#weight' => -1000, '#type' => 'status_messages', ], + 'page_title' => [ + '#type' => 'page_title', + '#title' => 'Hi llamas!', + '#weight' => -900, + ], ], ]; $this->assertSame($expected, $display_variant->build()); diff --git a/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php b/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php index 964f0f9..317baf2 100644 --- a/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php +++ b/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php @@ -35,6 +35,7 @@ class BlockContentTranslationUITest extends ContentTranslationUITestBase { */ protected $defaultCacheContexts = [ 'languages:language_interface', + 'route', 'theme', 'url.path', 'url.query_args', diff --git a/core/modules/comment/src/Tests/CommentTranslationUITest.php b/core/modules/comment/src/Tests/CommentTranslationUITest.php index 6397c69..c0791df 100644 --- a/core/modules/comment/src/Tests/CommentTranslationUITest.php +++ b/core/modules/comment/src/Tests/CommentTranslationUITest.php @@ -37,6 +37,7 @@ class CommentTranslationUITest extends ContentTranslationUITestBase { */ protected $defaultCacheContexts = [ 'languages:language_interface', + 'route', 'theme', 'timezone', 'url.query_args:_wrapper_format', diff --git a/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php b/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php index 08b1d4a..aef2512 100644 --- a/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php +++ b/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php @@ -31,6 +31,7 @@ class ContentTestTranslationUITest extends ContentTranslationUITestBase { */ protected $defaultCacheContexts = [ 'languages:language_interface', + 'route', 'theme', 'url.path', 'url.query_args', diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php index a5d6d09..213b081 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php @@ -52,7 +52,7 @@ * * @var string[] */ - protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'url.query_args:_wrapper_format', 'user.permissions']; + protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'url.query_args:_wrapper_format', 'user.permissions', 'route']; /** * Tests the basic translation UI. diff --git a/core/modules/contextual/src/Tests/ContextualDynamicContextTest.php b/core/modules/contextual/src/Tests/ContextualDynamicContextTest.php index 38955ab..6ed297e 100644 --- a/core/modules/contextual/src/Tests/ContextualDynamicContextTest.php +++ b/core/modules/contextual/src/Tests/ContextualDynamicContextTest.php @@ -47,7 +47,7 @@ class ContextualDynamicContextTest extends WebTestBase { * * @var array */ - public static $modules = array('contextual', 'node', 'views', 'views_ui', 'language', 'menu_test'); + public static $modules = array('block', 'contextual', 'node', 'views', 'views_ui', 'language', 'menu_test'); protected function setUp() { parent::setUp(); @@ -55,6 +55,8 @@ protected function setUp() { $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article')); + $this->drupalPlaceBlock('system_page_title_block'); + ConfigurableLanguage::createFromLangcode('it')->save(); $this->rebuildContainer(); diff --git a/core/modules/help/src/Tests/HelpTest.php b/core/modules/help/src/Tests/HelpTest.php index 2a423ba..06b7312 100644 --- a/core/modules/help/src/Tests/HelpTest.php +++ b/core/modules/help/src/Tests/HelpTest.php @@ -24,7 +24,7 @@ class HelpTest extends WebTestBase { * * @var array. */ - public static $modules = array('help_test'); + public static $modules = array('block', 'help_test'); /** * Use the Standard profile to test help implementations of many core modules. @@ -46,6 +46,8 @@ protected function setUp() { $this->getModuleList(); + $this->drupalPlaceBlock('system_page_title_block'); + // Create users. $this->adminUser = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer permissions')); $this->anyUser = $this->drupalCreateUser(array()); @@ -105,7 +107,8 @@ protected function verifyHelp($response = 200) { $this->assertResponse($response); if ($response == 200) { $this->assertTitle($name . ' | Drupal', format_string('%module title was displayed', array('%module' => $module))); - $this->assertRaw('

' . t($name) . '

', format_string('%module heading was displayed', array('%module' => $module))); + $result = $this->xpath('//h1[@class="page-title"]'); + $this->assertEqual(t($name), trim((string)$result[0]), format_string('%module heading was displayed', array('%module' => $module))); $admin_tasks = system_get_module_admin_tasks($module, system_get_info('module', $module)); if (!empty($admin_tasks)) { $this->assertText(t('@module administration pages', array('@module' => $name))); diff --git a/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php index 4645d68..71234d5 100644 --- a/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php +++ b/core/modules/language/src/Tests/LanguageUILanguageNegotiationTest.php @@ -58,6 +58,8 @@ class LanguageUILanguageNegotiationTest extends WebTestBase { protected function setUp() { parent::setUp(); + $this->drupalPlaceBlock('system_page_title_block'); + $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks')); $this->drupalLogin($admin_user); } diff --git a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php index 1404384..f75586e 100644 --- a/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php +++ b/core/modules/menu_link_content/src/Tests/MenuLinkContentTranslationUITest.php @@ -20,7 +20,7 @@ class MenuLinkContentTranslationUITest extends ContentTranslationUITestBase { /** * {inheritdoc} */ - protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'url.path', 'url.query_args', 'user.permissions', 'user.roles:authenticated']; + protected $defaultCacheContexts = ['languages:language_interface', 'route', 'theme', 'url.path', 'url.query_args', 'user.permissions', 'user.roles:authenticated']; /** * Modules to enable. diff --git a/core/modules/node/src/Tests/NodeBlockFunctionalTest.php b/core/modules/node/src/Tests/NodeBlockFunctionalTest.php index b6855ba..ba02a9f 100644 --- a/core/modules/node/src/Tests/NodeBlockFunctionalTest.php +++ b/core/modules/node/src/Tests/NodeBlockFunctionalTest.php @@ -120,7 +120,7 @@ public function testRecentNodeBlock() { $this->assertText($node3->label(), 'Node found in block.'); $this->assertText($node4->label(), 'Node found in block.'); - $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); + $this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); // Enable the "Powered by Drupal" block only on article nodes. $edit = [ diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php index bcb9de9..509a0d1 100644 --- a/core/modules/node/src/Tests/NodeTranslationUITest.php +++ b/core/modules/node/src/Tests/NodeTranslationUITest.php @@ -27,11 +27,7 @@ class NodeTranslationUITest extends ContentTranslationUITestBase { protected $defaultCacheContexts = [ 'languages:language_interface', 'theme', - 'route.name', - 'route.menu_active_trails:account', - 'route.menu_active_trails:footer', - 'route.menu_active_trails:main', - 'route.menu_active_trails:tools', + 'route', 'timezone', 'url', 'user' diff --git a/core/modules/node/src/Tests/Views/FrontPageTest.php b/core/modules/node/src/Tests/Views/FrontPageTest.php index ba8438f..d4d8cb0 100644 --- a/core/modules/node/src/Tests/Views/FrontPageTest.php +++ b/core/modules/node/src/Tests/Views/FrontPageTest.php @@ -244,6 +244,8 @@ protected function doTestFrontPageViewCacheTags($do_assert_views_caches) { // Cache contexts associated with the view. 'user.node_grants:view', 'languages:' . LanguageInterface::TYPE_INTERFACE, + // Page title cache context. + 'route', // Cache contexts associated with the route's access checking. 'user.permissions', // Default cache contexts of the renderer. diff --git a/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php index 58f8fde..4b54ae2 100644 --- a/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php +++ b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php @@ -106,6 +106,7 @@ function testPageCacheTags() { 'config:block.block.bartik_messages', 'config:block.block.bartik_local_actions', 'config:block.block.bartik_local_tasks', + 'config:block.block.bartik_page_title', 'node_view', 'node:' . $node_1->id(), 'user:' . $author_1->id(), @@ -143,6 +144,7 @@ function testPageCacheTags() { 'config:block.block.bartik_messages', 'config:block.block.bartik_local_actions', 'config:block.block.bartik_local_tasks', + 'config:block.block.bartik_page_title', 'node_view', 'node:' . $node_2->id(), 'user:' . $author_2->id(), diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index be83839..deb6750 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -298,9 +298,9 @@ function shortcut_preprocess_block(&$variables) { } /** - * Implements hook_preprocess_HOOK() for page templates. + * Implements hook_preprocess_HOOK() for page title templates. */ -function shortcut_preprocess_page(&$variables) { +function shortcut_preprocess_page_title(&$variables) { // Only display the shortcut link if the user has the ability to edit // shortcuts and if the page's actual content is being shown (for example, // we do not want to display it on "access denied" or "page not found" @@ -309,9 +309,17 @@ function shortcut_preprocess_page(&$variables) { $link = Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath(); $route_match = \Drupal::routeMatch(); + // Replicate template_preprocess_html()'s processing to get the title in + // string form, so we can set the default name for the shortcut. + if (is_array($variables['title'])) { + $name = (string) \Drupal::service('renderer')->render($variables['title']); + } + else { + $name = $variables['title']; + } $query = array( 'link' => $link, - 'name' => $variables['title'], + 'name' => $name, ); $shortcut_set = shortcut_current_displayed_set(); diff --git a/core/modules/shortcut/src/Tests/ShortcutLinksTest.php b/core/modules/shortcut/src/Tests/ShortcutLinksTest.php index 84f315b..0a5f0b4 100644 --- a/core/modules/shortcut/src/Tests/ShortcutLinksTest.php +++ b/core/modules/shortcut/src/Tests/ShortcutLinksTest.php @@ -26,6 +26,16 @@ class ShortcutLinksTest extends ShortcutTestBase { */ public static $modules = array('router_test', 'views', 'block'); + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_title_block'); + } + /** * Tests that creating a shortcut works properly. */ diff --git a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php index e42262f..59da2ca 100644 --- a/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php +++ b/core/modules/shortcut/src/Tests/ShortcutTranslationUITest.php @@ -21,7 +21,7 @@ class ShortcutTranslationUITest extends ContentTranslationUITestBase { /** * {inheritdoc} */ - protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'user', 'url.path', 'url.query_args', 'url.site']; + protected $defaultCacheContexts = ['languages:language_interface', 'route', 'theme', 'user', 'url.path', 'url.query_args', 'url.site']; /** * Modules to enable. diff --git a/core/modules/system/src/Plugin/Block/SystemPageTitleBlock.php b/core/modules/system/src/Plugin/Block/SystemPageTitleBlock.php new file mode 100644 index 0000000..5615701 --- /dev/null +++ b/core/modules/system/src/Plugin/Block/SystemPageTitleBlock.php @@ -0,0 +1,63 @@ +title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return ['label_display' => FALSE]; + } + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#type' => 'page_title', + '#title' => $this->title, + ]; + } + + /** + * {@inheritdoc} + */ + public function getCacheContexts() { + return ['route']; + } + +} diff --git a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php index ee4fcd8..72e6adc 100644 --- a/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php +++ b/core/modules/system/src/Tests/Entity/EntityCacheTagsTestBase.php @@ -338,7 +338,7 @@ public function testReferencedEntity() { // The default cache contexts for rendered entities. $default_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']; $entity_cache_contexts = $default_cache_contexts; - $page_cache_contexts = Cache::mergeContexts($default_cache_contexts, ['url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]); + $page_cache_contexts = Cache::mergeContexts($default_cache_contexts, ['route', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]); // Cache tags present on every rendered page. // 'user.permissions' is a required cache context, and responses that vary diff --git a/core/modules/system/src/Tests/Render/DisplayVariantTest.php b/core/modules/system/src/Tests/Render/DisplayVariantTest.php index 432aacf..3fcc1b0 100644 --- a/core/modules/system/src/Tests/Render/DisplayVariantTest.php +++ b/core/modules/system/src/Tests/Render/DisplayVariantTest.php @@ -21,7 +21,16 @@ class DisplayVariantTest extends WebTestBase { * * @var array */ - public static $modules = array('display_variant_test'); + public static $modules = array('block', 'display_variant_test'); + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_title_block'); + } /** * Tests selecting the variant and passing configuration. diff --git a/core/modules/system/src/Tests/Routing/RouterTest.php b/core/modules/system/src/Tests/Routing/RouterTest.php index 4d532d1..bd80d05 100644 --- a/core/modules/system/src/Tests/Routing/RouterTest.php +++ b/core/modules/system/src/Tests/Routing/RouterTest.php @@ -33,7 +33,7 @@ class RouterTest extends WebTestBase { */ public function testFinishResponseSubscriber() { $renderer_required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']; - $expected_cache_contexts = Cache::mergeContexts($renderer_required_cache_contexts, ['url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]); + $expected_cache_contexts = Cache::mergeContexts($renderer_required_cache_contexts, ['route', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]); // Confirm that the router can get to a controller. $this->drupalGet('router_test/test1'); @@ -64,12 +64,12 @@ public function testFinishResponseSubscriber() { // 1. controller result: render array, globally cacheable route access. $this->drupalGet('router_test/test18'); $headers = $this->drupalGetHeaders(); - $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url']))); + $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['route', 'url']))); $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered'); // 2. controller result: render array, per-role cacheable route access. $this->drupalGet('router_test/test19'); $headers = $this->drupalGetHeaders(); - $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url', 'user.roles']))); + $this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['route', 'url', 'user.roles']))); $this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo rendered'); // 3. controller result: Response object, globally cacheable route access. $this->drupalGet('router_test/test1'); diff --git a/core/modules/system/src/Tests/System/PageTitleTest.php b/core/modules/system/src/Tests/System/PageTitleTest.php index 73ef4bd..6f26c87 100644 --- a/core/modules/system/src/Tests/System/PageTitleTest.php +++ b/core/modules/system/src/Tests/System/PageTitleTest.php @@ -36,6 +36,8 @@ protected function setUp() { $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); + $this->drupalPlaceBlock('system_page_title_block'); + $this->contentUser = $this->drupalCreateUser(array('create page content', 'access content', 'administer themes', 'administer site configuration', 'link to any page')); $this->drupalLogin($this->contentUser); } @@ -105,14 +107,14 @@ public function testRoutingTitle() { $this->drupalGet('test-render-title'); $this->assertTitle('Foo | Drupal'); - $result = $this->xpath('//h1'); + $result = $this->xpath('//main//h1'); $this->assertEqual('Foo', (string) $result[0]); // Test forms $this->drupalGet('form-test/object-builder'); $this->assertTitle('Test dynamic title | Drupal'); - $result = $this->xpath('//h1'); + $result = $this->xpath('//main//h1'); $this->assertEqual('Test dynamic title', (string) $result[0]); // Set some custom translated strings. @@ -125,14 +127,14 @@ public function testRoutingTitle() { $this->drupalGet('test-page-static-title'); $this->assertTitle('Static title translated | Drupal'); - $result = $this->xpath('//h1'); + $result = $this->xpath('//main//h1'); $this->assertEqual('Static title translated', (string) $result[0]); // Test the dynamic '_title_callback' route option. $this->drupalGet('test-page-dynamic-title'); $this->assertTitle('Dynamic title | Drupal'); - $result = $this->xpath('//h1'); + $result = $this->xpath('//main//h1'); $this->assertEqual('Dynamic title', (string) $result[0]); // Ensure that titles are cacheable and are escaped normally if the diff --git a/core/modules/system/src/Tests/System/TokenReplaceWebTest.php b/core/modules/system/src/Tests/System/TokenReplaceWebTest.php index ba94e51..dbc7f04 100644 --- a/core/modules/system/src/Tests/System/TokenReplaceWebTest.php +++ b/core/modules/system/src/Tests/System/TokenReplaceWebTest.php @@ -36,12 +36,12 @@ public function testTokens() { $this->drupalGet('token-test/' . $node->id()); $this->assertText("Tokens: {$node->id()} {$account->id()}"); $this->assertCacheTags(['node:1', 'rendered', 'user:2']); - $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); + $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); $this->drupalGet('token-test-without-bubleable-metadata/' . $node->id()); $this->assertText("Tokens: {$node->id()} {$account->id()}"); $this->assertCacheTags(['node:1', 'rendered', 'user:2']); - $this->assertCacheContexts(['languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); + $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user']); } } diff --git a/core/modules/system/templates/install-page.html.twig b/core/modules/system/templates/install-page.html.twig index 1d0e479..9c1ee12 100644 --- a/core/modules/system/templates/install-page.html.twig +++ b/core/modules/system/templates/install-page.html.twig @@ -27,9 +27,6 @@
- {% if title %} -

{{ title }}

- {% endif %} {{ page.highlighted }} {{ page.content }}
diff --git a/core/modules/system/templates/maintenance-page.html.twig b/core/modules/system/templates/maintenance-page.html.twig index 748ed5a..67967ef 100644 --- a/core/modules/system/templates/maintenance-page.html.twig +++ b/core/modules/system/templates/maintenance-page.html.twig @@ -32,10 +32,6 @@
- {% if title %} -

{{ title }}

- {% endif %} - {{ page.highlighted }} {{ page.content }} diff --git a/core/modules/system/templates/page-title.html.twig b/core/modules/system/templates/page-title.html.twig new file mode 100644 index 0000000..c0ea332 --- /dev/null +++ b/core/modules/system/templates/page-title.html.twig @@ -0,0 +1,22 @@ +{# +/** + * @file + * Default theme implementation for page titles. + * + * Available variables: + * - title_prefix: Additional output populated by modules, intended to be + * displayed in front of the main title tag that appears in the template. + * - title: The page title, for use in the actual content. + * - title_suffix: Additional output populated by modules, intended to be + * displayed after the main title tag that appears in the template. + * + * @see template_preprocess_page_title() + * + * @ingroup themeable + */ +#} +{{ title_prefix }} +{% if title %} + {{ title }} +{% endif %} +{{ title_suffix }} diff --git a/core/modules/system/templates/page.html.twig b/core/modules/system/templates/page.html.twig index d9532bf..897ffef 100644 --- a/core/modules/system/templates/page.html.twig +++ b/core/modules/system/templates/page.html.twig @@ -26,11 +26,6 @@ * slogan has been disabled in theme settings. * * Page content (in order of occurrence in the default page.html.twig): - * - title_prefix: Additional output populated by modules, intended to be - * displayed in front of the main title tag that appears in the template. - * - title: The page title, for use in the actual content. - * - title_suffix: Additional output populated by modules, intended to be - * displayed after the main title tag that appears in the template. * - messages: Status and error messages. Should be displayed prominently. * - node: Fully loaded node, if there is an automatically-loaded node * associated with the page and the node ID is the second argument in the @@ -74,12 +69,6 @@ {# link is in html.html.twig #}
- - {{ title_prefix }} - {% if title %} -

{{ title }}

- {% endif %} - {{ title_suffix }} {{ page.content }}
{# /.layout-content #} diff --git a/core/modules/system/tests/modules/display_variant_test/src/Plugin/DisplayVariant/TestDisplayVariant.php b/core/modules/system/tests/modules/display_variant_test/src/Plugin/DisplayVariant/TestDisplayVariant.php index 2057272..c952052 100644 --- a/core/modules/system/tests/modules/display_variant_test/src/Plugin/DisplayVariant/TestDisplayVariant.php +++ b/core/modules/system/tests/modules/display_variant_test/src/Plugin/DisplayVariant/TestDisplayVariant.php @@ -28,6 +28,13 @@ class TestDisplayVariant extends VariantBase implements PageVariantInterface { protected $mainContent = []; /** + * The page title. + * + * @var string + */ + protected $title = ''; + + /** * {@inheritdoc} */ public function setMainContent(array $main_content) { @@ -38,6 +45,14 @@ public function setMainContent(array $main_content) { /** * {@inheritdoc} */ + public function setTitle($title) { + $this->title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ public function build() { $config = $this->getConfiguration(); if (empty($config['required_configuration'])) { diff --git a/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php b/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php index 759f646..b265740 100644 --- a/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php +++ b/core/modules/toolbar/src/Tests/ToolbarCacheContextsTest.php @@ -109,6 +109,7 @@ protected function assertToolbarCacheContexts(array $cache_contexts, $message = // Default cache contexts that should exist on all test cases. $default_cache_contexts = [ 'languages:language_interface', + 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, ]; diff --git a/core/modules/tracker/src/Tests/TrackerTest.php b/core/modules/tracker/src/Tests/TrackerTest.php index d8da6e8..7450ba9 100644 --- a/core/modules/tracker/src/Tests/TrackerTest.php +++ b/core/modules/tracker/src/Tests/TrackerTest.php @@ -86,7 +86,7 @@ function testTrackerAll() { $this->assertLink(t('My recent content'), 0, 'User tab shows up on the global tracker page.'); // Assert cache contexts, specifically the pager and node access contexts. - $this->assertCacheContexts(['languages:language_interface', 'route.name', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user.node_grants:view', 'user']); + $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user.node_grants:view', 'user']); // Assert cache tags for the action/tabs blocks, visible node, and node list // cache tag. $expected_tags = Cache::mergeTags($published->getCacheTags(), $published->getOwner()->getCacheTags()); @@ -164,7 +164,7 @@ function testTrackerUser() { $this->assertText($other_published_my_comment->label(), "Nodes that the user has commented on appear in the user's tracker listing."); // Assert cache contexts. - $this->assertCacheContexts(['languages:language_interface', 'route.name', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); + $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); // Assert cache tags for the visible nodes (including owners) and node list // cache tag. $expected_tags = Cache::mergeTags($my_published->getCacheTags(), $my_published->getOwner()->getCacheTags()); @@ -184,7 +184,7 @@ function testTrackerUser() { $expected_tags = Cache::mergeTags($expected_tags, $additional_tags); $this->assertCacheTags($expected_tags); - $this->assertCacheContexts(['languages:language_interface', 'route.name', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); + $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); $this->assertLink($my_published->label()); $this->assertNoLink($unpublished->label()); diff --git a/core/modules/user/src/Tests/Views/RolesRidArgumentTest.php b/core/modules/user/src/Tests/Views/RolesRidArgumentTest.php index 642a691..2c05673 100644 --- a/core/modules/user/src/Tests/Views/RolesRidArgumentTest.php +++ b/core/modules/user/src/Tests/Views/RolesRidArgumentTest.php @@ -23,16 +23,32 @@ class RolesRidArgumentTest extends UserTestBase { public static $testViews = array('test_user_roles_rid'); /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('block'); + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_title_block'); + } + + /** * Tests the generated title of a user: roles argument. */ public function testArgumentTitle() { - $role_id = $this->createRole([], 'markup_role_name', 'Role name with markup'); + $role_id = $this->createRole([], 'markup_role_name', 'Role name with markup'); $user = $this->createUser(); $user->addRole($role_id); $user->save(); $this->drupalGet('/user_roles_rid_test/markup_role_name'); - $this->assertEscaped('Role name with markup'); + $this->assertRaw('Role name with markupalert("test")'); } } diff --git a/core/modules/views/src/Tests/Handler/FieldWebTest.php b/core/modules/views/src/Tests/Handler/FieldWebTest.php index 0435809..01af741 100644 --- a/core/modules/views/src/Tests/Handler/FieldWebTest.php +++ b/core/modules/views/src/Tests/Handler/FieldWebTest.php @@ -75,6 +75,7 @@ public function testClickSorting() { // Check that the view returns the click sorting cache contexts. $expected_contexts = [ 'languages:language_interface', + 'route', 'theme', 'url.query_args', ]; diff --git a/core/modules/views/src/Tests/Plugin/DisabledDisplayTest.php b/core/modules/views/src/Tests/Plugin/DisabledDisplayTest.php index e9052b4..b28d31b 100644 --- a/core/modules/views/src/Tests/Plugin/DisabledDisplayTest.php +++ b/core/modules/views/src/Tests/Plugin/DisabledDisplayTest.php @@ -34,6 +34,8 @@ protected function setUp() { $this->enableViewsTestModule(); + $this->drupalPlaceBlock('system_page_title_block'); + $admin_user = $this->drupalCreateUser(array('administer site configuration')); $this->drupalLogin($admin_user); } @@ -58,7 +60,7 @@ public function testDisabledDisplays() { // Enabled page display should return content. $this->drupalGet('test-disabled-display'); - $result = $this->xpath('//h1'); + $result = $this->xpath('//main//h1'); $this->assertEqual($result[0], 'test_disabled_display', 'The enabled page_1 display is accessible.'); // Disabled page view should 404. @@ -77,7 +79,7 @@ public function testDisabledDisplays() { // Check that the originally disabled page_2 display is now enabled. $this->drupalGet('test-disabled-display-2'); - $result = $this->xpath('//h1'); + $result = $this->xpath('//main//h1'); $this->assertEqual($result[0], 'test_disabled_display', 'The enabled page_2 display is accessible.'); // Disable each disabled display and save the view. diff --git a/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php b/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php index 8bc8bc3..1ce4f59 100644 --- a/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php +++ b/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php @@ -57,7 +57,7 @@ public function testArguments() { $this->drupalGet('test_route_with_argument/1'); $this->assertResponse(200); - $this->assertCacheContexts(['languages:language_interface', 'route.name', 'theme', 'url']); + $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url']); $result = $this->xpath('//span[@class="field-content"]'); $this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.'); $this->assertEqual((string) $result[0], 1, 'The passed ID was returned.'); diff --git a/core/modules/views/src/Tests/Plugin/ExposedFormTest.php b/core/modules/views/src/Tests/Plugin/ExposedFormTest.php index 5df5465..5533b09 100644 --- a/core/modules/views/src/Tests/Plugin/ExposedFormTest.php +++ b/core/modules/views/src/Tests/Plugin/ExposedFormTest.php @@ -230,6 +230,7 @@ public function testExposedSortAndItemsPerPage() { $contexts = [ 'languages:language_interface', 'entity_test_view_grants', + 'route', 'theme', 'url.query_args', 'user.roles:authenticated', diff --git a/core/modules/views/src/Tests/Plugin/PagerTest.php b/core/modules/views/src/Tests/Plugin/PagerTest.php index c1c6c97..294f27b 100644 --- a/core/modules/views/src/Tests/Plugin/PagerTest.php +++ b/core/modules/views/src/Tests/Plugin/PagerTest.php @@ -261,7 +261,7 @@ public function testNormalPager() { // Test pager cache contexts. $this->drupalGet('test_pager_full'); - $this->assertCacheContexts(['languages:language_interface', 'theme', 'timezone', 'url.query_args', 'user.node_grants:view']); + $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'timezone', 'url.query_args', 'user.node_grants:view']); } /** diff --git a/core/modules/views_ui/src/Tests/DisplayTest.php b/core/modules/views_ui/src/Tests/DisplayTest.php index 20667de..f8a1f95 100644 --- a/core/modules/views_ui/src/Tests/DisplayTest.php +++ b/core/modules/views_ui/src/Tests/DisplayTest.php @@ -35,6 +35,15 @@ class DisplayTest extends UITestBase { public static $modules = array('contextual'); /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_title_block'); + } + + /** * Tests reordering of displays. */ public function testReorderDisplay() { diff --git a/core/modules/views_ui/src/Tests/HandlerTest.php b/core/modules/views_ui/src/Tests/HandlerTest.php index c53ddd7..2c3cfca 100644 --- a/core/modules/views_ui/src/Tests/HandlerTest.php +++ b/core/modules/views_ui/src/Tests/HandlerTest.php @@ -26,6 +26,16 @@ class HandlerTest extends UITestBase { public static $testViews = array('test_view_empty', 'test_view_broken'); /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_title_block'); + } + + + /** * Overrides \Drupal\views\Tests\ViewTestBase::schemaDefinition(). * * Adds a uid column to test the relationships. @@ -155,7 +165,7 @@ public function testBrokenHandlers() { $this->assertIdentical((string) $result[0], $text, 'Ensure the broken handler text was found.'); $this->drupalGet($href); - $result = $this->xpath('//h1'); + $result = $this->xpath('//main//h1'); $this->assertTrue(strpos((string) $result[0], $text) !== FALSE, 'Ensure the broken handler text was found.'); $original_configuration = [ diff --git a/core/profiles/minimal/config/install/block.block.stark_page_title.yml b/core/profiles/minimal/config/install/block.block.stark_page_title.yml new file mode 100644 index 0000000..aeadfc1 --- /dev/null +++ b/core/profiles/minimal/config/install/block.block.stark_page_title.yml @@ -0,0 +1,18 @@ +id: stark_page_title +theme: stark +weight: -30 +status: true +langcode: en +region: content +plugin: system_page_title_block +settings: + id: system_page_title_block + label: Page title + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - stark +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.bartik_page_title.yml b/core/profiles/standard/config/install/block.block.bartik_page_title.yml new file mode 100644 index 0000000..c78d10d --- /dev/null +++ b/core/profiles/standard/config/install/block.block.bartik_page_title.yml @@ -0,0 +1,18 @@ +id: bartik_page_title +theme: bartik +weight: -50 +status: true +langcode: en +region: content +plugin: system_page_title_block +settings: + id: system_page_title_block + label: Page title + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - bartik +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.seven_page_title.yml b/core/profiles/standard/config/install/block.block.seven_page_title.yml new file mode 100644 index 0000000..30998fa --- /dev/null +++ b/core/profiles/standard/config/install/block.block.seven_page_title.yml @@ -0,0 +1,18 @@ +id: page_title +theme: seven +weight: -30 +status: true +langcode: en +region: header +plugin: system_page_title_block +settings: + id: system_page_title_block + label: Page Title + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - seven +visibility: { } diff --git a/core/themes/bartik/bartik.theme b/core/themes/bartik/bartik.theme index 556342f..03dc8b4 100644 --- a/core/themes/bartik/bartik.theme +++ b/core/themes/bartik/bartik.theme @@ -39,7 +39,7 @@ function bartik_preprocess_html(&$variables) { /** * Implements hook_preprocess_HOOK() for page templates. */ -function bartik_preprocess_page(&$variables) { +function bartik_preprocess_page_title(&$variables) { // Since the title and the shortcut link are both block level elements, // positioning them next to each other is much simpler with a wrapper div. if (!empty($variables['title_suffix']['add_or_remove_shortcut']) && $variables['title']) { diff --git a/core/themes/bartik/templates/maintenance-page.html.twig b/core/themes/bartik/templates/maintenance-page.html.twig index 3cd787b..f071245 100644 --- a/core/themes/bartik/templates/maintenance-page.html.twig +++ b/core/themes/bartik/templates/maintenance-page.html.twig @@ -35,9 +35,6 @@
- {% if title %} -

{{ title }}

- {% endif %} {{ page.content }} {{ page.highlighted }}
diff --git a/core/themes/bartik/templates/page-title.html.twig b/core/themes/bartik/templates/page-title.html.twig new file mode 100644 index 0000000..59d2e64 --- /dev/null +++ b/core/themes/bartik/templates/page-title.html.twig @@ -0,0 +1,17 @@ +{% extends "@system/page-title.html.twig" %} +{# +/** + * @file + * Bartik's theme implementation for a page title. + * + * Available variables: + * - title_prefix: Additional output populated by modules, intended to be + * displayed in front of the main title tag that appears in the template. + * - title: The page title, for use in the actual content. + * - title_suffix: Additional output populated by modules, intended to be + * displayed after the main title tag that appears in the template. + * + * @ingroup themeable + */ +#} +{% set title_attributes = title_attributes.addClass('title', 'page-title') %} diff --git a/core/themes/bartik/templates/page.html.twig b/core/themes/bartik/templates/page.html.twig index 8bcea09..7122143 100644 --- a/core/themes/bartik/templates/page.html.twig +++ b/core/themes/bartik/templates/page.html.twig @@ -27,11 +27,6 @@ * slogan has been disabled in theme settings. * Page content (in order of occurrence in the default page.html.twig): - * - title_prefix: Additional output populated by modules, intended to be - * displayed in front of the main title tag that appears in the template. - * - title: The page title, for use in the actual content. - * - title_suffix: Additional output populated by modules, intended to be - * displayed after the main title tag that appears in the template. * - node: Fully loaded node, if there is an automatically-loaded node * associated with the page and the node ID is the second argument in the * page's path (e.g. node/12345 and node/12345/revisions, but not @@ -90,13 +85,6 @@
- {{ title_prefix }} - {% if title %} -

- {{ title }} -

- {% endif %} - {{ title_suffix }} {{ page.content }}
diff --git a/core/themes/classy/templates/layout/maintenance-page.html.twig b/core/themes/classy/templates/layout/maintenance-page.html.twig index 7463b02..5e3b73c 100644 --- a/core/themes/classy/templates/layout/maintenance-page.html.twig +++ b/core/themes/classy/templates/layout/maintenance-page.html.twig @@ -35,10 +35,6 @@
- {% if title %} -

{{ title }}

- {% endif %} - {{ page.highlighted }} {{ page.content }} diff --git a/core/themes/classy/templates/layout/page.html.twig b/core/themes/classy/templates/layout/page.html.twig index c714bd1..ec0c075 100644 --- a/core/themes/classy/templates/layout/page.html.twig +++ b/core/themes/classy/templates/layout/page.html.twig @@ -26,11 +26,6 @@ * slogan has been disabled in theme settings. * * Page content (in order of occurrence in the default page.html.twig): - * - title_prefix: Additional output populated by modules, intended to be - * displayed in front of the main title tag that appears in the template. - * - title: The page title, for use in the actual content. - * - title_suffix: Additional output populated by modules, intended to be - * displayed after the main title tag that appears in the template. * - node: Fully loaded node, if there is an automatically-loaded node * associated with the page and the node ID is the second argument in the * page's path (e.g. node/12345 and node/12345/revisions, but not @@ -73,12 +68,6 @@
{{ page.highlighted }} - - {{ title_prefix }} - {% if title %} -

{{ title }}

- {% endif %} - {{ title_suffix }} {{ page.content }}
{# /.layout-content #} diff --git a/core/themes/seven/templates/install-page.html.twig b/core/themes/seven/templates/install-page.html.twig index b501fb8..8c2828f 100644 --- a/core/themes/seven/templates/install-page.html.twig +++ b/core/themes/seven/templates/install-page.html.twig @@ -24,9 +24,6 @@ {% endif %}
- {% if title %} -

{{ title }}

- {% endif %} {{ page.highlighted }} {{ page.content }}
diff --git a/core/themes/seven/templates/maintenance-page.html.twig b/core/themes/seven/templates/maintenance-page.html.twig index 2286e88..8966ddc 100644 --- a/core/themes/seven/templates/maintenance-page.html.twig +++ b/core/themes/seven/templates/maintenance-page.html.twig @@ -24,9 +24,6 @@ {% endif %}
- {% if title %} -

{{ title }}

- {% endif %} {{ page.highlighted }} {{ page.content }}
diff --git a/core/themes/seven/templates/page-title.html.twig b/core/themes/seven/templates/page-title.html.twig new file mode 100644 index 0000000..75855b6 --- /dev/null +++ b/core/themes/seven/templates/page-title.html.twig @@ -0,0 +1,17 @@ +{% extends "@system/page-title.html.twig" %} +{# +/** + * @file + * Seven's theme implementation for a page title. + * + * Available variables: + * - title_prefix: Additional output populated by modules, intended to be + * displayed in front of the main title tag that appears in the template. + * - title: The page title, for use in the actual content. + * - title_suffix: Additional output populated by modules, intended to be + * displayed after the main title tag that appears in the template. + * + * @ingroup themeable + */ +#} +{% set title_attributes = title_attributes.addClass('page-title') %} diff --git a/core/themes/seven/templates/page.html.twig b/core/themes/seven/templates/page.html.twig index 5698bfa..25597a1 100644 --- a/core/themes/seven/templates/page.html.twig +++ b/core/themes/seven/templates/page.html.twig @@ -27,11 +27,6 @@ * slogan has been disabled in theme settings. * * Page content (in order of occurrence in the default page.html.twig): - * - title_prefix: Additional output populated by modules, intended to be - * displayed in front of the main title tag that appears in the template. - * - title: The page title, for use in the actual content. - * - title_suffix: Additional output populated by modules, intended to be - * displayed after the main title tag that appears in the template. * - node: Fully loaded node, if there is an automatically-loaded node * associated with the page and the node ID is the second argument in the * page's path (e.g. node/12345 and node/12345/revisions, but not @@ -52,11 +47,6 @@ #}
- {{ title_prefix }} - {% if title %} -

{{ title }}

- {% endif %} - {{ title_suffix }} {{ page.header }}