diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 6f05be0..e206764 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1299,7 +1299,6 @@ function template_preprocess_page(&$variables) { $site_config = \Drupal::config('system.site'); // 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])) { 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..f4deff0 --- /dev/null +++ b/core/lib/Drupal/Core/Block/TitleBlockPluginInterface.php @@ -0,0 +1,27 @@ + 'Page top', 'page_bottom' => 'Page bottom', 'breadcrumb' => 'Breadcrumb', + 'page_title' => 'Page title', ), 'description' => '', 'features' => $this->defaultFeatures, diff --git a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php index 5cfa312..c9ae172 100644 --- a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php +++ b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php @@ -192,11 +192,19 @@ 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) { + $this_title = isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject()); + return isset($this_title['#markup']) ? $this->renderer->renderPlain($this_title) : $this_title; + }; + // 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 +236,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 +245,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 +269,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..0f0fd64 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,8 +45,17 @@ public function setMainContent(array $main_content) { /** * {@inheritdoc} */ + public function setTitle($title) { + $this->title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ public function build() { $build = [ + 'title' => ['#markup' => '

' . $this->title . '

'], 'content' => [ 'main_content' => $this->mainContent, 'messages' => [ diff --git a/core/modules/block/src/Plugin/DisplayVariant/BlockPageVariant.php b/core/modules/block/src/Plugin/DisplayVariant/BlockPageVariant.php index 650cf78..5785f8d 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; } @@ -165,6 +187,13 @@ public function build() { ]; } + // Analogously for the page title. + if (!$title_block_displayed) { + $build['title'] = [ + '#markup' => $this->title, + ]; + } + // 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/page_cache/src/Tests/PageCacheTagsIntegrationTest.php b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php index f19ac70..b4178d6 100644 --- a/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php +++ b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php @@ -105,6 +105,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(), @@ -141,6 +142,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..49caca8 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -311,7 +311,7 @@ function shortcut_preprocess_page(&$variables) { $query = array( 'link' => $link, - 'name' => $variables['title'], + 'name' => \Drupal::service('title_resolver')->getTitle(\Drupal::request(), $route_match->getRouteObject()), ); $shortcut_set = shortcut_current_displayed_set(); 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..e0bd82c --- /dev/null +++ b/core/modules/system/src/Plugin/Block/SystemPageTitleBlock.php @@ -0,0 +1,77 @@ +title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return ['label_display' => FALSE]; + } + + /** + * {@inheritdoc} + */ + public function build() { + return [ + 'title' => $this->title, + ]; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + + // The 'Page title' block is never cacheable, because it may be dynamic. + $form['cache']['#disabled'] = TRUE; + $form['cache']['#description'] = t('This block is never cacheable, it is not configurable.'); + $form['cache']['max_age']['#value'] = 0; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function isCacheable() { + // The 'Page title' block is never cacheable, because it may be dynamic. + return FALSE; + } + +} diff --git a/core/modules/system/system.module b/core/modules/system/system.module index c12a2d4..50ebd3c 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -163,6 +163,10 @@ function system_theme() { 'render element' => 'elements', 'base hook' => 'block', ), + 'block__system_page_title_block' => array( + 'base hook' => 'block', + 'template' => 'block--system-page-title-block', + ), 'block__system_messages_block' => array( 'base hook' => 'block', ), @@ -809,6 +813,15 @@ function system_preprocess_block(&$variables) { case 'system_powered_by_block': $variables['attributes']['role'] = 'complementary'; break; + + case 'system_page_title_block': + $variables['title'] = ''; + if(property_exists($variables['content']['title'], 'markup') && $variables['content']['title']['#markup']) { + $variables['title'] = $variables['content']['title']['#markup']; + } else if ($variables['content']['title']) { + $variables['title'] = $variables['content']['title']; + } + break; } } diff --git a/core/modules/system/templates/block--system-page-title-block.html.twig b/core/modules/system/templates/block--system-page-title-block.html.twig new file mode 100644 index 0000000..aca427c --- /dev/null +++ b/core/modules/system/templates/block--system-page-title-block.html.twig @@ -0,0 +1,23 @@ +{% extends "@block/block.html.twig" %} +{# +/** + * @file + * Default 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 + */ +#} +{% block content %} + {{ title_prefix }} + {% if title %} +

{{ title }}

+ {% endif %} + {{ title_suffix }} +{% endblock %} diff --git a/core/modules/system/templates/page.html.twig b/core/modules/system/templates/page.html.twig index b80310e..a8d7483 100644 --- a/core/modules/system/templates/page.html.twig +++ b/core/modules/system/templates/page.html.twig @@ -28,7 +28,6 @@ * 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. @@ -48,6 +47,7 @@ * - page.sidebar_second: Items for the second sidebar. * - page.footer: Items for the footer region. * - page.breadcrumb: Items for the breadcrumb region. + * - page.title: Items for the page title region. * * @see template_preprocess_page() * @see html.html.twig @@ -68,7 +68,7 @@
{# Use h1 when the content title is empty #} - {% if title %} + {% if page.title %} {{ site_name }} @@ -102,9 +102,7 @@
{{ title_prefix }} - {% if title %} -

{{ title }}

- {% endif %} + {{ page.title }} {{ title_suffix }} {{ page.content }}
{# /.layout-content #} 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..8263474 --- /dev/null +++ b/core/profiles/minimal/config/install/block.block.stark_page_title.yml @@ -0,0 +1,17 @@ +id: stark_page_title +theme: stark +weight: 10 +status: true +langcode: en +region: title +plugin: system_page_title_block +settings: + id: system_page_title_block + label: 'Page title' + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - stark 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..ff73d59 --- /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: 10 +status: true +langcode: en +region: title +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..ae1cb30 --- /dev/null +++ b/core/profiles/standard/config/install/block.block.seven_page_title.yml @@ -0,0 +1,18 @@ +id: page_title +theme: seven +weight: 0 +status: true +langcode: en +region: title +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.info.yml b/core/themes/bartik/bartik.info.yml index 8b52f48..4bebcd5 100644 --- a/core/themes/bartik/bartik.info.yml +++ b/core/themes/bartik/bartik.info.yml @@ -22,6 +22,7 @@ regions: highlighted: Highlighted featured_top: 'Featured top' breadcrumb: Breadcrumb + title: Title content: Content sidebar_first: 'Sidebar first' sidebar_second: 'Sidebar second' diff --git a/core/themes/bartik/bartik.theme b/core/themes/bartik/bartik.theme index 1b82230..ba98b80 100644 --- a/core/themes/bartik/bartik.theme +++ b/core/themes/bartik/bartik.theme @@ -45,7 +45,7 @@ function bartik_preprocess_page(&$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']) { + if (!empty($variables['title_suffix']['add_or_remove_shortcut']) && $variables['page.title']) { // Add a wrapper div using the title_prefix and title_suffix render // elements. $variables['title_prefix']['shortcut_wrapper'] = array( diff --git a/core/themes/bartik/templates/block--system-page-title-block.html.twig b/core/themes/bartik/templates/block--system-page-title-block.html.twig new file mode 100644 index 0000000..9a36994 --- /dev/null +++ b/core/themes/bartik/templates/block--system-page-title-block.html.twig @@ -0,0 +1,25 @@ +{% extends "@block/block.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 + */ +#} +{% block content %} + {{ title_prefix }} + {% if title %} +

+ {{ title }} +

+ {% endif %} + {{ title_suffix }} +{% endblock %} diff --git a/core/themes/bartik/templates/page.html.twig b/core/themes/bartik/templates/page.html.twig index 4c27d8f..09a90f3 100644 --- a/core/themes/bartik/templates/page.html.twig +++ b/core/themes/bartik/templates/page.html.twig @@ -33,11 +33,6 @@ * added to make the site slogan visually hidden, but still accessible. * * 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 @@ -61,6 +56,7 @@ * - page.footer_fourth: Items for the fourth footer column. * - page.footer_fifth: Items for the fifth footer column. * - page.breadcrumb: Items for the breadcrumb region. + * - page.title: Items for the page title region. * * @see template_preprocess_page() * @see bartik_preprocess_page() @@ -124,13 +120,7 @@
- {{ title_prefix }} - {% if title %} -

- {{ title }} -

- {% endif %} - {{ title_suffix }} + {{ page.title }} {{ page.content }}
diff --git a/core/themes/classy/templates/layout/page.html.twig b/core/themes/classy/templates/layout/page.html.twig index 8c81950..29dc472 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 @@ -48,6 +43,7 @@ * - page.sidebar_second: Items for the second sidebar. * - page.footer: Items for the footer region. * - page.breadcrumb: Items for the breadcrumb region. + * - page.title: Items for the page title region. * * @see template_preprocess_page() * @see html.html.twig @@ -99,12 +95,7 @@
{{ page.highlighted }} - - {{ title_prefix }} - {% if title %} -

{{ title }}

- {% endif %} - {{ title_suffix }} + {{ page.title }} {{ page.content }}
{# /.layout-content #} diff --git a/core/themes/seven/seven.info.yml b/core/themes/seven/seven.info.yml index 1427896..bcb9d7c 100644 --- a/core/themes/seven/seven.info.yml +++ b/core/themes/seven/seven.info.yml @@ -23,5 +23,6 @@ regions: page_top: 'Page top' page_bottom: 'Page bottom' sidebar_first: 'First sidebar' + title: Title regions_hidden: - sidebar_first diff --git a/core/themes/seven/templates/block--system-page-title-block.html.twig b/core/themes/seven/templates/block--system-page-title-block.html.twig new file mode 100644 index 0000000..8314b3b --- /dev/null +++ b/core/themes/seven/templates/block--system-page-title-block.html.twig @@ -0,0 +1,25 @@ +{% extends "@block/block.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 + */ +#} +{% block content %} + {{ title_prefix }} + {% if title %} +

+ {{ title }} +

+ {% endif %} + {{ title_suffix }} +{% endblock %} diff --git a/core/themes/seven/templates/page.html.twig b/core/themes/seven/templates/page.html.twig index ac26a51..92caec2 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 @@ -44,6 +39,7 @@ * - page.highlighted: Items for the highlighted region. * - page.help: Dynamic help text, mostly for admin pages. * - page.content: The main content of the current page. + * - page.title: Items for the page title region. * * @see template_preprocess_page() * @see seven_preprocess_page() @@ -52,11 +48,9 @@ #}
- {{ title_prefix }} - {% if title %} -

{{ title }}

+ {% if page.title %} + {{ page.title }} {% endif %} - {{ title_suffix }} {{ page.header }}