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 @@
#}