diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 4ce12c5..61bc83f 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1342,9 +1342,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(); @@ -1465,6 +1462,10 @@ function template_preprocess_maintenance_page(&$variables) { $variables['logo'] = theme_get_setting('logo.url'); $variables['site_name'] = $site_config->get('name'); $variables['site_slogan'] = $site_config->get('slogan'); + + // Maintenance page and install page need page title in variable because there + // are no blocks. + $variables['title'] = $variables['page']['#title']; } /** @@ -1707,6 +1708,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/Plugin/Block/PageTitleBlock.php b/core/lib/Drupal/Core/Block/Plugin/Block/PageTitleBlock.php new file mode 100644 index 0000000..d134d00 --- /dev/null +++ b/core/lib/Drupal/Core/Block/Plugin/Block/PageTitleBlock.php @@ -0,0 +1,55 @@ +title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return ['label_display' => FALSE]; + } + + /** + * {@inheritdoc} + */ + public function build() { + return [ + '#type' => 'page_title', + '#title' => $this->title, + ]; + } + +} diff --git a/core/lib/Drupal/Core/Block/TitleBlockPluginInterface.php b/core/lib/Drupal/Core/Block/TitleBlockPluginInterface.php new file mode 100644 index 0000000..19ab275 --- /dev/null +++ b/core/lib/Drupal/Core/Block/TitleBlockPluginInterface.php @@ -0,0 +1,30 @@ + 'page_title', + // The page title: either a string for plain titles or a render array for + // formatted titles. + '#title' => NULL, + ]; + } + +} diff --git a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php index 96b909f..4a4ab59 100644 --- a/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php +++ b/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php @@ -193,11 +193,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. @@ -229,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) { @@ -236,6 +245,7 @@ protected function prepare(array $main_content, Request $request, RouteMatchInte } $page_display ->setMainContent($main_content) + ->setTitle($title) ->addCacheableDependency($event) ->setConfiguration($event->getPluginConfiguration()); // Some display variants need to be passed an array of contexts with @@ -268,10 +278,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..f281c82 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: a string (plain title) or a render array (formatted title). + * + * @var string|array + */ + protected $title = ''; + + /** * {@inheritdoc} */ public function setMainContent(array $main_content) { @@ -38,14 +45,27 @@ public function setMainContent(array $main_content) { /** * {@inheritdoc} */ + public function setTitle($title) { + $this->title = $title; + return $this; + } + + /** + * {@inheritdoc} + */ public function build() { $build = [ 'content' => [ - 'main_content' => $this->mainContent, 'messages' => [ '#type' => 'status_messages', '#weight' => -1000, ], + 'page_title' => [ + '#type' => 'page_title', + '#title' => $this->title, + '#weight' => -900, + ], + 'main_content' => ['#weight' => -800] + $this->mainContent, ], ]; return $build; diff --git a/core/modules/aggregator/src/Tests/AddFeedTest.php b/core/modules/aggregator/src/Tests/AddFeedTest.php index ef70cd1..cf95815 100644 --- a/core/modules/aggregator/src/Tests/AddFeedTest.php +++ b/core/modules/aggregator/src/Tests/AddFeedTest.php @@ -14,6 +14,13 @@ * @group aggregator */ class AddFeedTest extends AggregatorTestBase { + + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Creates and ensures that a feed is unique, checks source, and deletes feed. */ diff --git a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php index 351f48c..63a7e97 100644 --- a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php +++ b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php @@ -23,6 +23,12 @@ class AggregatorRenderingTest extends AggregatorTestBase { */ public static $modules = array('block', 'test_page_test'); + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Adds a feed block to the page and checks its links. */ diff --git a/core/modules/block/src/BlockViewBuilder.php b/core/modules/block/src/BlockViewBuilder.php index 7972bbc..f23979d 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; @@ -100,12 +101,13 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la 'tags' => $cache_tags, 'max-age' => $plugin->getCacheMaxAge(), ], + '#weight' => $entity->getWeight(), ); // 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..b7b2647 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: a string (plain title) or a render array (formatted title). + * + * @var string|array + */ + protected $title = ''; + + /** * Constructs a new BlockPageVariant. * * @param array $configuration @@ -111,6 +119,14 @@ 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. $main_content_block_displayed = FALSE; @@ -131,6 +147,9 @@ public function build() { $block_plugin->setMainContent($this->mainContent); $main_content_block_displayed = TRUE; } + elseif ($block_plugin instanceof TitleBlockPluginInterface) { + $block_plugin->setTitle($this->title); + } elseif ($block_plugin instanceof MessagesBlockPluginInterface) { $messages_block_displayed = TRUE; } @@ -138,8 +157,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 +185,12 @@ public function build() { ]; } + // If any render arrays are manually placed, render arrays and blocks must + // be sorted. + if (!$main_content_block_displayed || !$messages_block_displayed) { + unset($build['content']['#sorted']); + } + // 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/BlockTest.php b/core/modules/block/src/Tests/BlockTest.php index bd360f6..c98b042 100644 --- a/core/modules/block/src/Tests/BlockTest.php +++ b/core/modules/block/src/Tests/BlockTest.php @@ -135,6 +135,9 @@ function testBlockVisibilityListedEmpty() { * Test configuring and moving a module-define block to specific regions. */ function testBlock() { + // Place page title block to test error messages. + $this->drupalPlaceBlock('page_title_block'); + // Select the 'Powered by Drupal' block to be configured and moved. $block = array(); $block['id'] = 'system_powered_by_block'; 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..5652533 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. + 'block6' => 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' => [], + 'block6' => [], '#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' => [], + 'block6' => [], '#sorted' => TRUE, ], 'bottom' => [ @@ -157,6 +163,7 @@ public function providerBuild() { ], ]; unset($blocks_config['block4']); + unset($blocks_config['block6']); $test_cases[] = [$blocks_config, 3, [ '#cache' => [ @@ -205,6 +212,7 @@ public function testBuild(array $blocks_config, $visible_block_count, array $exp $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 +220,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)) diff --git a/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php b/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php index 964f0f9..91ccfda 100644 --- a/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php +++ b/core/modules/block_content/src/Tests/BlockContentTranslationUITest.php @@ -50,6 +50,8 @@ protected function setUp() { $this->bundle = 'basic'; $this->testLanguageSelector = FALSE; parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/block_content/src/Tests/BlockContentTypeTest.php b/core/modules/block_content/src/Tests/BlockContentTypeTest.php index cf37f51..2e29d10 100644 --- a/core/modules/block_content/src/Tests/BlockContentTypeTest.php +++ b/core/modules/block_content/src/Tests/BlockContentTypeTest.php @@ -42,6 +42,12 @@ class BlockContentTypeTest extends BlockContentTestBase { */ protected $autoCreateBasicBlockType = FALSE; + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Tests creating a block type programmatically and via a form. */ diff --git a/core/modules/block_content/src/Tests/PageEditTest.php b/core/modules/block_content/src/Tests/PageEditTest.php index e2ce38f..b5b6697 100644 --- a/core/modules/block_content/src/Tests/PageEditTest.php +++ b/core/modules/block_content/src/Tests/PageEditTest.php @@ -17,6 +17,12 @@ */ class PageEditTest extends BlockContentTestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Checks block edit functionality. */ diff --git a/core/modules/book/src/Tests/BookTest.php b/core/modules/book/src/Tests/BookTest.php index b530265..86c23be 100644 --- a/core/modules/book/src/Tests/BookTest.php +++ b/core/modules/book/src/Tests/BookTest.php @@ -68,6 +68,7 @@ class BookTest extends WebTestBase { protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_breadcrumb_block'); + $this->drupalPlaceBlock('page_title_block'); // node_access_test requires a node_access_rebuild(). node_access_rebuild(); diff --git a/core/modules/comment/src/Tests/CommentAdminTest.php b/core/modules/comment/src/Tests/CommentAdminTest.php index ee03405..ee434f7 100644 --- a/core/modules/comment/src/Tests/CommentAdminTest.php +++ b/core/modules/comment/src/Tests/CommentAdminTest.php @@ -15,6 +15,13 @@ * @group comment */ class CommentAdminTest extends CommentTestBase { + + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Test comment approval functionality through admin/content/comment. */ diff --git a/core/modules/comment/src/Tests/CommentNonNodeTest.php b/core/modules/comment/src/Tests/CommentNonNodeTest.php index 8d8e38b..98099fb 100644 --- a/core/modules/comment/src/Tests/CommentNonNodeTest.php +++ b/core/modules/comment/src/Tests/CommentNonNodeTest.php @@ -50,6 +50,7 @@ class CommentNonNodeTest extends WebTestBase { protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_breadcrumb_block'); + $this->drupalPlaceBlock('page_title_block'); // Create a bundle for entity_test. entity_test_create_bundle('entity_test', 'Entity Test', 'entity_test'); diff --git a/core/modules/comment/src/Tests/CommentTestBase.php b/core/modules/comment/src/Tests/CommentTestBase.php index b487fd5..62e43f6 100644 --- a/core/modules/comment/src/Tests/CommentTestBase.php +++ b/core/modules/comment/src/Tests/CommentTestBase.php @@ -191,14 +191,22 @@ public function postComment($entity, $comment, $subject = '', $contact = NULL, $ */ function commentExists(CommentInterface $comment = NULL, $reply = FALSE) { if ($comment) { - $regex = '!' . ($reply ? '
(.*?)' : ''); - $regex .= 'getSubject() . '(.*?)'; - $regex .= $comment->comment_body->value . '(.*?)'; - $regex .= ($reply ? '\s
(.*?)' : ''); - $regex .= '!s'; - - return (boolean) preg_match($regex, $this->getRawContent()); + $comment_element = $this->cssSelect('.comment-wrapper ' . ($reply ? '.indented ' : '') . '#comment-' . $comment->id() . ' ~ article'); + if (empty($comment_element)) { + return FALSE; + } + + $comment_title = $comment_element[0]->xpath('div/h3/a'); + if (empty($comment_title) || ((string)$comment_title[0]) !== $comment->getSubject()) { + return FALSE; + } + + $comment_body = $comment_element[0]->xpath('div/div/p'); + if (empty($comment_body) || ((string)$comment_body[0]) !== $comment->comment_body->value) { + return FALSE; + } + + return TRUE; } else { return FALSE; diff --git a/core/modules/comment/src/Tests/CommentTypeTest.php b/core/modules/comment/src/Tests/CommentTypeTest.php index 6efc6b6..a2c4c6c 100644 --- a/core/modules/comment/src/Tests/CommentTypeTest.php +++ b/core/modules/comment/src/Tests/CommentTypeTest.php @@ -43,6 +43,9 @@ class CommentTypeTest extends CommentTestBase { */ protected function setUp() { parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + $this->adminUser = $this->drupalCreateUser($this->permissions); } diff --git a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php b/core/modules/config/src/Tests/ConfigSingleImportExportTest.php index 0a382e2..7b3336d 100644 --- a/core/modules/config/src/Tests/ConfigSingleImportExportTest.php +++ b/core/modules/config/src/Tests/ConfigSingleImportExportTest.php @@ -28,6 +28,12 @@ class ConfigSingleImportExportTest extends WebTestBase { 'config_test' ]; + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Tests importing a single configuration file. */ diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php index 3048e01..13b56d5 100644 --- a/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php +++ b/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php @@ -69,6 +69,7 @@ protected function setUp() { } $this->localeStorage = $this->container->get('locale.storage'); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php index 13890c0..a359c9f 100644 --- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php +++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php @@ -119,6 +119,7 @@ protected function setUp() { } $this->localeStorage = $this->container->get('locale.storage'); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/contact/src/Tests/ContactSitewideTest.php b/core/modules/contact/src/Tests/ContactSitewideTest.php index 651c283..39cd34a 100644 --- a/core/modules/contact/src/Tests/ContactSitewideTest.php +++ b/core/modules/contact/src/Tests/ContactSitewideTest.php @@ -40,6 +40,7 @@ protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_breadcrumb_block'); $this->drupalPlaceBlock('local_actions_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/dblog/src/Tests/DbLogTest.php b/core/modules/dblog/src/Tests/DbLogTest.php index 2f5499f..bffdb2e 100644 --- a/core/modules/dblog/src/Tests/DbLogTest.php +++ b/core/modules/dblog/src/Tests/DbLogTest.php @@ -49,6 +49,7 @@ class DbLogTest extends WebTestBase { protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_breadcrumb_block'); + $this->drupalPlaceBlock('page_title_block'); // Create users with specific permissions. $this->adminUser = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports', 'administer users')); diff --git a/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php b/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php index 1a6007c..2847d07 100644 --- a/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php +++ b/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php @@ -30,6 +30,7 @@ protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('local_actions_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/field_ui/src/Tests/FieldUIDeleteTest.php b/core/modules/field_ui/src/Tests/FieldUIDeleteTest.php index 6fe6649..e6e2f59 100644 --- a/core/modules/field_ui/src/Tests/FieldUIDeleteTest.php +++ b/core/modules/field_ui/src/Tests/FieldUIDeleteTest.php @@ -43,6 +43,7 @@ protected function setUp() { $this->drupalPlaceBlock('system_breadcrumb_block'); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); // Create a test user. $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'administer node display', 'administer users', 'administer account settings', 'administer user display', 'bypass node access')); diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php index f1db4d4..e4e9981 100644 --- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php @@ -70,6 +70,7 @@ protected function setUp() { $this->drupalPlaceBlock('system_breadcrumb_block'); $this->drupalPlaceBlock('local_actions_block'); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); // Create a test user. $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'administer node display', 'administer taxonomy', 'administer taxonomy_term fields', 'administer taxonomy_term display', 'administer users', 'administer account settings', 'administer user display', 'bypass node access')); diff --git a/core/modules/filter/src/Tests/FilterFormatAccessTest.php b/core/modules/filter/src/Tests/FilterFormatAccessTest.php index 441be0d..590a337 100644 --- a/core/modules/filter/src/Tests/FilterFormatAccessTest.php +++ b/core/modules/filter/src/Tests/FilterFormatAccessTest.php @@ -71,6 +71,8 @@ class FilterFormatAccessTest extends WebTestBase { protected function setUp() { parent::setUp(); + $this->drupalPlaceBlock('page_title_block'); + $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); // Create a user who can administer text formats, but does not have diff --git a/core/modules/forum/src/Tests/ForumTest.php b/core/modules/forum/src/Tests/ForumTest.php index 767e3e3..974e400 100644 --- a/core/modules/forum/src/Tests/ForumTest.php +++ b/core/modules/forum/src/Tests/ForumTest.php @@ -83,6 +83,7 @@ class ForumTest extends WebTestBase { protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_breadcrumb_block'); + $this->drupalPlaceBlock('page_title_block'); // Create users. $this->adminUser = $this->drupalCreateUser(array( diff --git a/core/modules/menu_ui/src/Tests/MenuNodeTest.php b/core/modules/menu_ui/src/Tests/MenuNodeTest.php index 22b10f3..b3397cc 100644 --- a/core/modules/menu_ui/src/Tests/MenuNodeTest.php +++ b/core/modules/menu_ui/src/Tests/MenuNodeTest.php @@ -35,6 +35,7 @@ protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_menu_block:main'); + $this->drupalPlaceBlock('page_title_block'); $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php index e87cd86..ef79989 100644 --- a/core/modules/menu_ui/src/Tests/MenuTest.php +++ b/core/modules/menu_ui/src/Tests/MenuTest.php @@ -70,6 +70,8 @@ class MenuTest extends MenuWebTestBase { protected function setUp() { parent::setUp(); + $this->drupalPlaceBlock('page_title_block'); + $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article')); // Create users. diff --git a/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php index e188b48..ed7b0f3 100644 --- a/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php +++ b/core/modules/page_cache/src/Tests/PageCacheTagsIntegrationTest.php @@ -100,6 +100,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:0', @@ -138,6 +139,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/search/src/Tests/SearchConfigSettingsFormTest.php b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php index 2c17ed6..5c2a1c2 100644 --- a/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php +++ b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php @@ -59,6 +59,7 @@ protected function setUp() { // Enable the search block. $this->drupalPlaceBlock('search_form_block'); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/search/src/Tests/SearchPageTextTest.php b/core/modules/search/src/Tests/SearchPageTextTest.php index 8a95fe6..d47325c 100644 --- a/core/modules/search/src/Tests/SearchPageTextTest.php +++ b/core/modules/search/src/Tests/SearchPageTextTest.php @@ -39,6 +39,7 @@ protected function setUp() { // Create user. $this->searchingUser = $this->drupalCreateUser(array('search content', 'access user profiles', 'use advanced search')); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index a5d0c87..f6667e0 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,12 @@ 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. + $name = render($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..e52b9b6 100644 --- a/core/modules/shortcut/src/Tests/ShortcutLinksTest.php +++ b/core/modules/shortcut/src/Tests/ShortcutLinksTest.php @@ -27,6 +27,15 @@ class ShortcutLinksTest extends ShortcutTestBase { public static $modules = array('router_test', 'views', 'block'); /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + + /** * Tests that creating a shortcut works properly. */ public function testShortcutLinkAdd() { diff --git a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php index 5aeef20..5e8e5fa 100644 --- a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php +++ b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php @@ -47,7 +47,7 @@ protected function setUp() { */ function testEntityViewController() { $get_label_markup = function($label) { - return '

+ return '

' . $label . '

'; }; diff --git a/core/modules/system/src/Tests/Installer/InstallerTest.php b/core/modules/system/src/Tests/Installer/InstallerTest.php index b17e3e7..debb891 100644 --- a/core/modules/system/src/Tests/Installer/InstallerTest.php +++ b/core/modules/system/src/Tests/Installer/InstallerTest.php @@ -40,6 +40,41 @@ protected function setUpLanguage() { // metatags as expected to the first page of the installer. $this->assertRaw('core/themes/seven/css/components/buttons.css'); $this->assertRaw(''); + + // Assert that the expected title is present. + $this->assertEqual('Choose language', $this->cssSelect('main h1')[0]); + parent::setUpLanguage(); } + + /** + * {@inheritdoc} + */ + protected function setUpProfile() { + // Assert that the expected title is present. + $this->assertEqual('Select an installation profile', $this->cssSelect('main h1')[0]); + + parent::setUpProfile(); + } + + /** + * {@inheritdoc} + */ + protected function setUpSettings() { + // Assert that the expected title is present. + $this->assertEqual('Database configuration', $this->cssSelect('main h1')[0]); + + parent::setUpSettings(); + } + + /** + * {@inheritdoc} + */ + protected function setUpSite() { + // Assert that the expected title is present. + $this->assertEqual('Configure site', $this->cssSelect('main h1')[0]); + + parent::setUpSite(); + } + } diff --git a/core/modules/system/src/Tests/Menu/MenuRouterTest.php b/core/modules/system/src/Tests/Menu/MenuRouterTest.php index 21052a4..42332e0 100644 --- a/core/modules/system/src/Tests/Menu/MenuRouterTest.php +++ b/core/modules/system/src/Tests/Menu/MenuRouterTest.php @@ -44,6 +44,7 @@ protected function setUp() { $this->drupalPlaceBlock('system_menu_block:tools'); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/system/src/Tests/System/AccessDeniedTest.php b/core/modules/system/src/Tests/System/AccessDeniedTest.php index 0f37320..b068802 100644 --- a/core/modules/system/src/Tests/System/AccessDeniedTest.php +++ b/core/modules/system/src/Tests/System/AccessDeniedTest.php @@ -30,6 +30,8 @@ class AccessDeniedTest extends WebTestBase { protected function setUp() { parent::setUp(); + $this->drupalPlaceBlock('page_title_block'); + // Create an administrative user. $this->adminUser = $this->drupalCreateUser(['access administration pages', 'administer site configuration', 'link to any page', 'administer blocks']); diff --git a/core/modules/system/src/Tests/System/PageTitleTest.php b/core/modules/system/src/Tests/System/PageTitleTest.php index 73ef4bd..8dab86f 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('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('//h1[@class="page-title"]'); $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('//h1[@class="page-title"]'); $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('//h1[@class="page-title"]'); $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('//h1[@class="page-title"]'); $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/SiteMaintenanceTest.php b/core/modules/system/src/Tests/System/SiteMaintenanceTest.php index 6794120..b89dc81 100644 --- a/core/modules/system/src/Tests/System/SiteMaintenanceTest.php +++ b/core/modules/system/src/Tests/System/SiteMaintenanceTest.php @@ -67,10 +67,13 @@ protected function testSiteMaintenance() { // Logout and verify that offline message is displayed. $this->drupalLogout(); $this->drupalGet(''); + $this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]); $this->assertText($offline_message); $this->drupalGet('node'); + $this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]); $this->assertText($offline_message); $this->drupalGet('user/register'); + $this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]); $this->assertText($offline_message); // Verify that user is able to log in. @@ -103,6 +106,7 @@ protected function testSiteMaintenance() { // Logout and verify that custom site offline message is displayed. $this->drupalLogout(); $this->drupalGet(''); + $this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]); $this->assertRaw($offline_message, 'Found the site offline message.'); // Verify that custom site offline message is not displayed on user/password. @@ -121,5 +125,14 @@ protected function testSiteMaintenance() { // Log in with temporary login link. $this->drupalPostForm($path, array(), t('Log in')); $this->assertText($user_message); + + // Regression test to check if title displays in Bartik on maintenance page. + \Drupal::service('theme_handler')->install(array('bartik')); + \Drupal::service('theme_handler')->setDefault('bartik'); + + // Logout and verify that offline message is displayed in Bartik. + $this->drupalLogout(); + $this->drupalGet(''); + $this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]); } } diff --git a/core/modules/system/src/Tests/Update/PageTitleConvertedIntoBlockUpdateTest.php b/core/modules/system/src/Tests/Update/PageTitleConvertedIntoBlockUpdateTest.php new file mode 100644 index 0000000..1602a52 --- /dev/null +++ b/core/modules/system/src/Tests/Update/PageTitleConvertedIntoBlockUpdateTest.php @@ -0,0 +1,82 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz', + __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.page-title-into-block-2476947.php', + ]; + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + // @todo Remove in https://www.drupal.org/node/2568069. + /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */ + $theme_handler = \Drupal::service('theme_handler'); + $theme_handler->refreshInfo(); + } + + /** + * Tests that page title is being converted into a block. + */ + public function testUpdateHookN() { + $this->runUpdates(); + + /** @var \Drupal\block\BlockInterface $block_storage */ + $block_storage = \Drupal::entityManager()->getStorage('block'); + + $this->assertRaw('Because your site has custom theme(s) installed, we have placed the page title block in the content region. Please manually review the block configuration and remove the page title variables from your page templates.'); + + // Disable maintenance mode. + // @todo Can be removed once maintenance mode is automatically turned off + // after updates in https://www.drupal.org/node/2435135. + \Drupal::state()->set('system.maintenance_mode', FALSE); + + // We finished updating so we can login the user now. + $this->drupalLogin($this->rootUser); + + $page = Node::create([ + 'type' => 'page', + 'title' => 'Page node', + ]); + $page->save(); + + // Page title is visible on the home page. + $this->drupalGet('/node'); + $this->assertRaw('page-title'); + + // Page title is visible on a node page. + $this->drupalGet('node/' . $page->id()); + $this->assertRaw('page-title'); + + $this->drupalGet('admin/structure/block/list/bartik'); + + /** @var \Drupal\Core\Config\StorageInterface $config_storage */ + $config_storage = \Drupal::service('config.storage'); + $this->assertTrue($config_storage->exists('block.block.test_theme_page_title'), 'Page title block has been created for the custom theme.'); + } + +} diff --git a/core/modules/system/system.install b/core/modules/system/system.install index f391829..d227bf4 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -1470,16 +1470,16 @@ function system_update_8005() { default: $custom_themes_installed = TRUE; - $name = sprintf('block.block.%s_local_actions', $theme_name); + $name = 'block.block.' . $theme_name . '_local_actions'; $values = [ - 'id' => sprintf('%s_local_actions', $theme_name), + 'id' => $theme_name . '_local_actions', 'weight' => -10, ] + $local_actions_default_settings; _system_update_create_block($name, $theme_name, $values); $name = sprintf('block.block.%s_local_tasks', $theme_name); $values = [ - 'id' => sprintf('%s_local_tasks', $theme_name), + 'id' => $theme_name . '_local_tasks', 'weight' => -20, ] + $tabs_default_settings; _system_update_create_block($name, $theme_name, $values); @@ -1663,5 +1663,88 @@ function system_update_8008() { } /** + * Place page title blocks in every theme. + */ +function system_update_8009() { + // When block module is not installed, there is nothing that could be done + // except showing a warning. + if (!\Drupal::moduleHandler()->moduleExists('block')) { + return t('Block module is not enabled. The page title has been converted to a block, but default page title markup will still display at the top of the main content area.'); + } + + /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */ + $theme_handler = \Drupal::service('theme_handler'); + $custom_themes_installed = FALSE; + $message = NULL; + $langcode = \Drupal::service('language_manager')->getCurrentLanguage()->getId(); + + $page_title_default_settings = [ + 'plugin' => 'page_title_block', + 'region' => 'content', + 'settings.label' => 'Page title', + 'settings.label_display' => 0, + 'visibility' => [], + 'weight' => -50, + 'langcode' => $langcode, + ]; + foreach ($theme_handler->listInfo() as $theme) { + $theme_name = $theme->getName(); + switch ($theme_name) { + case 'bartik': + $name = 'block.block.bartik_page_title'; + $values = [ + 'id' => 'bartik_page_title', + ] + $page_title_default_settings; + _system_update_create_block($name, $theme_name, $values); + break; + + case 'stark': + $name = 'block.block.stark_page_title'; + $values = [ + 'id' => 'stark_page_title', + 'region' => 'content', + ] + $page_title_default_settings; + _system_update_create_block($name, $theme_name, $values); + break; + + case 'seven': + $name = 'block.block.seven_page_title'; + $values = [ + 'id' => 'seven_page_title', + 'region' => 'header', + ] + $page_title_default_settings; + _system_update_create_block($name, $theme_name, $values); + break; + + case 'classy': + $name = 'block.block.classy_page_title'; + $values = [ + 'id' => 'classy_page_title', + 'region' => 'content', + ] + $page_title_default_settings; + _system_update_create_block($name, $theme_name, $values); + break; + + default: + $custom_themes_installed = TRUE; + $name = sprintf('block.block.%s_page_title', $theme_name); + $values = [ + 'id' => sprintf('%s_page_title', $theme_name), + 'region' => 'content', + 'weight' => '-50', + ] + $page_title_default_settings; + _system_update_create_block($name, $theme_name, $values); + break; + } + } + + if ($custom_themes_installed) { + $message = t('Because your site has custom theme(s) installed, we have placed the page title block in the content region. Please manually review the block configuration and remove the page title variables from your page templates.'); + } + + return $message; +} + +/** * @} End of "addtogroup updates-8.0.0-beta". */ 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..2b994bc --- /dev/null +++ b/core/modules/system/templates/page-title.html.twig @@ -0,0 +1,23 @@ +{# +/** + * @file + * Default theme implementation for page titles. + * + * Available variables: + * - title_attributes: HTML attributes for the page title element. + * - 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/fixtures/update/block.block.testfor2476947.yml b/core/modules/system/tests/fixtures/update/block.block.testfor2476947.yml new file mode 100644 index 0000000..21cfb2f --- /dev/null +++ b/core/modules/system/tests/fixtures/update/block.block.testfor2476947.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + theme: + - bartik +id: bartik_page_title +theme: bartik +region: content +weight: -50 +provider: null +plugin: page_title_block +settings: + id: page_title_block + label: 'Page title' + provider: core + label_display: '0' +visibility: { } diff --git a/core/modules/system/tests/fixtures/update/drupal-8.page-title-into-block-2476947.php b/core/modules/system/tests/fixtures/update/drupal-8.page-title-into-block-2476947.php new file mode 100644 index 0000000..ae3e777 --- /dev/null +++ b/core/modules/system/tests/fixtures/update/drupal-8.page-title-into-block-2476947.php @@ -0,0 +1,60 @@ +insert('config') + ->fields([ + 'collection', + 'name', + 'data', + ]) + ->values([ + 'collection' => '', + 'name' => 'block.block.' . $block_config['id'], + 'data' => serialize($block_config), + ]) + ->execute(); +} + +// Update the config entity query "index". +$existing_blocks = $connection->select('key_value') + ->fields('key_value', ['value']) + ->condition('collection', 'config.entity.key_store.block') + ->condition('name', 'theme:bartik') + ->execute() + ->fetchField(); +$existing_blocks = unserialize($existing_blocks); + +$connection->update('key_value') + ->fields([ + 'value' => serialize(array_merge($existing_blocks, ['block.block.bartik_page_title'])) + ]) + ->condition('collection', 'config.entity.key_store.block') + ->condition('name', 'theme:bartik') + ->execute(); + +// Enable test theme. +$extensions = $connection->select('config') + ->fields('config', ['data']) + ->condition('name', 'core.extension') + ->execute() + ->fetchField(); +$extensions = unserialize($extensions); +$connection->update('config') + ->fields([ + 'data' => serialize(array_merge_recursive($extensions, ['theme' => ['test_theme' => 0]])) + ]) + ->condition('name', 'core.extension') + ->execute(); 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 0bee2a9..1fa9047 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 @@ -30,6 +30,13 @@ class TestDisplayVariant extends VariantBase implements PageVariantInterface, Co protected $mainContent = []; /** + * The page title: a string (plain title) or a render array (formatted title). + * + * @var string|array + */ + protected $title = ''; + + /** * An array of collected contexts. * * This is only used on runtime, and is not stored. @@ -72,6 +79,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/taxonomy/src/Tests/TermTest.php b/core/modules/taxonomy/src/Tests/TermTest.php index 9d06719..4bf221f 100644 --- a/core/modules/taxonomy/src/Tests/TermTest.php +++ b/core/modules/taxonomy/src/Tests/TermTest.php @@ -50,6 +50,7 @@ protected function setUp() { $this->drupalPlaceBlock('local_actions_block'); $this->drupalPlaceBlock('local_tasks_block'); + $this->drupalPlaceBlock('page_title_block'); $this->drupalLogin($this->drupalCreateUser(['administer taxonomy', 'bypass node access'])); $this->vocabulary = $this->createVocabulary(); diff --git a/core/modules/taxonomy/src/Tests/VocabularyPermissionsTest.php b/core/modules/taxonomy/src/Tests/VocabularyPermissionsTest.php index 00df789..6294e60 100644 --- a/core/modules/taxonomy/src/Tests/VocabularyPermissionsTest.php +++ b/core/modules/taxonomy/src/Tests/VocabularyPermissionsTest.php @@ -14,6 +14,12 @@ */ class VocabularyPermissionsTest extends TaxonomyTestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Create, edit and delete a taxonomy term via the user interface. */ diff --git a/core/modules/taxonomy/src/Tests/VocabularyUiTest.php b/core/modules/taxonomy/src/Tests/VocabularyUiTest.php index 029e99d..6787c7c 100644 --- a/core/modules/taxonomy/src/Tests/VocabularyUiTest.php +++ b/core/modules/taxonomy/src/Tests/VocabularyUiTest.php @@ -30,6 +30,7 @@ protected function setUp() { $this->drupalLogin($this->drupalCreateUser(['administer taxonomy'])); $this->vocabulary = $this->createVocabulary(); $this->drupalPlaceBlock('local_actions_block'); + $this->drupalPlaceBlock('page_title_block'); } /** diff --git a/core/modules/views/js/views-contextual.js b/core/modules/views/js/views-contextual.js deleted file mode 100644 index e6586eb..0000000 --- a/core/modules/views/js/views-contextual.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file - * Javascript related to contextual links. - */ - -(function ($) { - - "use strict"; - - /** - * Attaches contextual region classes to views elements. - * - * @type {Drupal~behavior} - * - * @prop {Drupal~behaviorAttach} attach - * Adds class `contextual-region` to views elements. - */ - Drupal.behaviors.viewsContextualLinks = { - attach: function (context) { - var id = $('body').attr('data-views-page-contextual-id'); - - $('[data-contextual-id="' + id + '"]') - .closest(':has(.view)') - .addClass('contextual-region'); - } - }; - -})(jQuery); diff --git a/core/modules/views/src/Routing/ViewPageController.php b/core/modules/views/src/Routing/ViewPageController.php index cf3ae53..592b7d1 100644 --- a/core/modules/views/src/Routing/ViewPageController.php +++ b/core/modules/views/src/Routing/ViewPageController.php @@ -60,6 +60,8 @@ public function handle($view_id, $display_id, RouteMatchInterface $route_match) $build = $class::buildBasicRenderable($view_id, $display_id, $args, $route); Page::setPageRenderArray($build); + views_add_contextual_links($build, 'page', $display_id, $build); + return $build; } } diff --git a/core/modules/views/src/Tests/DefaultViewsTest.php b/core/modules/views/src/Tests/DefaultViewsTest.php index 3df4082..1a268cf 100644 --- a/core/modules/views/src/Tests/DefaultViewsTest.php +++ b/core/modules/views/src/Tests/DefaultViewsTest.php @@ -47,6 +47,8 @@ class DefaultViewsTest extends ViewTestBase { protected function setUp() { parent::setUp(); + $this->drupalPlaceBlock('page_title_block'); + // Create Basic page node type. $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); diff --git a/core/modules/views/src/Tests/Plugin/DisabledDisplayTest.php b/core/modules/views/src/Tests/Plugin/DisabledDisplayTest.php index e9052b4..2268a47 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('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('//h1[@class="page-title"]'); $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('//h1[@class="page-title"]'); $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/Wizard/BasicTest.php b/core/modules/views/src/Tests/Wizard/BasicTest.php index d84722b..8a64df8 100644 --- a/core/modules/views/src/Tests/Wizard/BasicTest.php +++ b/core/modules/views/src/Tests/Wizard/BasicTest.php @@ -19,6 +19,12 @@ */ class BasicTest extends WizardTestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + function testViewsWizardAndListing() { $this->drupalCreateContentType(array('type' => 'article')); $this->drupalCreateContentType(array('type' => 'page')); diff --git a/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php b/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php index 132df58..9e3a80e 100644 --- a/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php +++ b/core/modules/views/src/Tests/Wizard/ItemsPerPageTest.php @@ -15,6 +15,12 @@ */ class ItemsPerPageTest extends WizardTestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Tests the number of items per page. */ diff --git a/core/modules/views/src/Tests/Wizard/SortingTest.php b/core/modules/views/src/Tests/Wizard/SortingTest.php index 41a0040..9fccdcd 100644 --- a/core/modules/views/src/Tests/Wizard/SortingTest.php +++ b/core/modules/views/src/Tests/Wizard/SortingTest.php @@ -14,6 +14,12 @@ */ class SortingTest extends WizardTestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Tests the sorting functionality. */ diff --git a/core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php b/core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php index 0c0443e..7c9d068 100644 --- a/core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php +++ b/core/modules/views/tests/src/Unit/Plugin/Block/ViewsBlockTest.php @@ -206,7 +206,8 @@ public function testBuildFailed() { } namespace { - // @todo replace views_add_contextual_links() + // @todo https://www.drupal.org/node/2571679 replace + // views_add_contextual_links(). if (!function_exists('views_add_contextual_links')) { function views_add_contextual_links() { } diff --git a/core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php b/core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php index 4604406..45d0636 100644 --- a/core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php +++ b/core/modules/views/tests/src/Unit/Routing/ViewPageControllerTest.php @@ -5,7 +5,7 @@ * Contains \Drupal\Tests\views\Unit\Routing\ViewPageControllerTest. */ -namespace Drupal\Tests\views\Unit\Routing; +namespace Drupal\Tests\views\Unit\Routing { use Drupal\Core\Routing\RouteMatch; use Drupal\Tests\UnitTestCase; @@ -181,3 +181,14 @@ public function testHandleWithArgumentsOnOverriddenRouteWithUpcasting() { } } + +} + +namespace { + // @todo https://www.drupal.org/node/2571679 replace + // views_add_contextual_links() + if (!function_exists('views_add_contextual_links')) { + function views_add_contextual_links() { + } + } +} diff --git a/core/modules/views/views.libraries.yml b/core/modules/views/views.libraries.yml index 03efb2c..640492d 100644 --- a/core/modules/views/views.libraries.yml +++ b/core/modules/views/views.libraries.yml @@ -16,12 +16,3 @@ views.ajax: - core/jquery.once - core/jquery.form - core/drupal.ajax - -views.contextual-links: - version: VERSION - js: - # Ensure to run before contextual/drupal.contextual-links. - js/views-contextual.js: { weight: -10 } - dependencies: - - core/jquery - - core/drupal diff --git a/core/modules/views/views.module b/core/modules/views/views.module index b9ff347..743626b 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -302,39 +302,6 @@ function views_theme_suggestions_container_alter(array &$suggestions, array $var } /** - * Implements MODULE_preprocess_HOOK(). - */ -function views_preprocess_html(&$variables) { - if (!\Drupal::moduleHandler()->moduleExists('contextual')) { - return; - } - - // If the main content of this page contains a view, attach its contextual - // links to the overall page array. This allows them to be rendered directly - // next to the page title. - if ($render_array = Page::getPageRenderArray()) { - views_add_contextual_links($variables['page'], 'page', $render_array['#display_id'], $render_array); - } - - // If the page contains a view as its main content, contextual links may have - // been attached to the page as a whole; for example, by - // views_page_display_pre_render(). - // This allows them to be associated with the page and rendered by default - // next to the page title (which we want). However, it also causes the - // Contextual Links module to treat the wrapper for the entire page (i.e., - // the tag) as the HTML element that these contextual links are - // associated with. This we don't want; for better visual highlighting, we - // prefer a smaller region to be chosen. The region we prefer differs from - // theme to theme and depends on the details of the theme's markup in - // page.html.twig, so we can only find it using JavaScript. We therefore - // remove the "contextual-region" class from the tag here and add - // JavaScript that will insert it back in the correct place. - if (!empty($variables['page']['#views_contextual_links'])) { - $variables['attributes']['data-views-page-contextual-id'] = _contextual_links_to_id($variables['page']['#contextual_links']); - } -} - -/** * Adds contextual links associated with a view display to a renderable array. * * This function should be called when a view is being rendered in a particular @@ -470,9 +437,6 @@ function views_add_contextual_links(&$render_element, $location, $display_id, ar // user that may use contextual links, attach Views' contextual links // JavaScript. $render_element['#cache']['contexts'][] = 'user.permissions'; - if ($location === 'page' && $render_element['#type'] === 'page' && \Drupal::currentUser()->hasPermission('access contextual links')) { - $render_element['#attached']['library'][] = 'views/views.contextual-links'; - } } } } diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc index f34d076..0ad38b0 100644 --- a/core/modules/views/views.theme.inc +++ b/core/modules/views/views.theme.inc @@ -38,6 +38,18 @@ function template_preprocess_views_view(&$variables) { $variables['attributes']['class'][] = $variables['css_class']; } + // contextual_preproces() only works on render elements, and since this theme + // hook is not for a render element, contextual_preprocess() falls back to the + // first argument and checks if that is a render element. The first element is + // view_array. However, view_array does not get set anywhere, but since we do + // have access to the View object, we can also access the View object's + // element, which is a render element that does have #contextual_links set if + // the display supports it. Doing this allows contextual_preprocess() to + // access this theme hook's render element, and therefore allows this template + // to have contextual links. + // @see views_theme() + $variables['view_array'] = $variables['view']->element; + // Attachments are always updated with the outer view, never by themselves, // so they do not have dom ids. if (empty($view->is_attachment)) { diff --git a/core/modules/views_ui/src/Tests/DefaultViewsTest.php b/core/modules/views_ui/src/Tests/DefaultViewsTest.php index 416f276..84496ee 100644 --- a/core/modules/views_ui/src/Tests/DefaultViewsTest.php +++ b/core/modules/views_ui/src/Tests/DefaultViewsTest.php @@ -25,6 +25,13 @@ class DefaultViewsTest extends UITestBase { */ public static $testViews = array('test_view_status', 'test_page_display_menu', 'test_page_display_arguments'); + + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Tests default views. */ diff --git a/core/modules/views_ui/src/Tests/DisplayPathTest.php b/core/modules/views_ui/src/Tests/DisplayPathTest.php index 275dce7..5e8f595 100644 --- a/core/modules/views_ui/src/Tests/DisplayPathTest.php +++ b/core/modules/views_ui/src/Tests/DisplayPathTest.php @@ -17,6 +17,12 @@ */ class DisplayPathTest extends UITestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * {@inheritdoc} */ diff --git a/core/modules/views_ui/src/Tests/DisplayTest.php b/core/modules/views_ui/src/Tests/DisplayTest.php index 89096d0..ff7ca81 100644 --- a/core/modules/views_ui/src/Tests/DisplayTest.php +++ b/core/modules/views_ui/src/Tests/DisplayTest.php @@ -180,6 +180,8 @@ public function testPageContextualLinks() { $view->enable()->save(); $this->container->get('router.builder')->rebuildIfNeeded(); + // When no "main content" block is placed, we find a contextual link + // placeholder for editing just the view. $this->drupalGet('test-display'); $id = 'entity.view.edit_form:view=test_display:location=page&name=test_display&display_id=page_1&langcode=en'; // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder() @@ -192,6 +194,15 @@ public function testPageContextualLinks() { $this->assertResponse(200); $json = Json::decode($response); $this->assertIdentical($json[$id], ''); + + // When a "main content" is placed, we still find a contextual link + // placeholder for editing just the view (not the main content block). + // @see system_block_view_system_main_block_alter() + $this->drupalPlaceBlock('system_main_block', ['id' => 'main_content']); + $this->drupalGet('test-display'); + $id = 'entity.view.edit_form:view=test_display:location=page&name=test_display&display_id=page_1&langcode=en'; + // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder() + $this->assertRaw(' $id)) . '>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $id))); } /** diff --git a/core/modules/views_ui/src/Tests/DuplicateTest.php b/core/modules/views_ui/src/Tests/DuplicateTest.php index e8f55b3..3f4a5a4 100644 --- a/core/modules/views_ui/src/Tests/DuplicateTest.php +++ b/core/modules/views_ui/src/Tests/DuplicateTest.php @@ -14,6 +14,12 @@ */ class DuplicateTest extends UITestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Checks if duplicated view exists and has correct label. */ diff --git a/core/modules/views_ui/src/Tests/HandlerTest.php b/core/modules/views_ui/src/Tests/HandlerTest.php index 6f1ed39..313e14c 100644 --- a/core/modules/views_ui/src/Tests/HandlerTest.php +++ b/core/modules/views_ui/src/Tests/HandlerTest.php @@ -28,6 +28,15 @@ class HandlerTest extends UITestBase { public static $testViews = array('test_view_empty', 'test_view_broken', 'node'); /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + + /** * Overrides \Drupal\views\Tests\ViewTestBase::schemaDefinition(). * * Adds a uid column to test the relationships. @@ -191,7 +200,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('//h1[@class="page-title"]'); $this->assertTrue(strpos((string) $result[0], $text) !== FALSE, 'Ensure the broken handler text was found.'); $original_configuration = [ diff --git a/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php b/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php index 2a693f7..25efc32 100644 --- a/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php +++ b/core/modules/views_ui/src/Tests/OverrideDisplaysTest.php @@ -14,6 +14,12 @@ */ class OverrideDisplaysTest extends UITestBase { + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('page_title_block'); + } + /** * Tests that displays can be overridden via the UI. */ 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..d5fe87c --- /dev/null +++ b/core/profiles/minimal/config/install/block.block.stark_page_title.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + theme: + - stark +id: stark_page_title +theme: stark +region: content +weight: -30 +provider: null +plugin: page_title_block +settings: + id: page_title_block + label: 'Page title' + provider: core + label_display: '0' +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..21cfb2f --- /dev/null +++ b/core/profiles/standard/config/install/block.block.bartik_page_title.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + theme: + - bartik +id: bartik_page_title +theme: bartik +region: content +weight: -50 +provider: null +plugin: page_title_block +settings: + id: page_title_block + label: 'Page title' + provider: core + label_display: '0' +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.classy_page_title.yml b/core/profiles/standard/config/install/block.block.classy_page_title.yml new file mode 100644 index 0000000..4236224 --- /dev/null +++ b/core/profiles/standard/config/install/block.block.classy_page_title.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + theme: + - classy +id: classy_page_title +theme: classy +region: content +weight: -50 +provider: null +plugin: page_title_block +settings: + id: page_title_block + label: 'Page title' + provider: core + label_display: '0' +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..56df293 --- /dev/null +++ b/core/profiles/standard/config/install/block.block.seven_page_title.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + theme: + - seven +id: seven_page_title +theme: seven +region: header +weight: -30 +provider: null +plugin: page_title_block +settings: + id: page_title_block + label: 'Page title' + provider: core + label_display: '0' +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/page-title.html.twig b/core/themes/bartik/templates/page-title.html.twig new file mode 100644 index 0000000..e061cd2 --- /dev/null +++ b/core/themes/bartik/templates/page-title.html.twig @@ -0,0 +1,16 @@ +{% extends "@classy/content/page-title.html.twig" %} +{# +/** + * @file + * Bartik's theme implementation for a page title. + * + * Available variables: + * - title_attributes: HTML attributes for the page title element. + * - 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. + */ +#} +{% set title_attributes = title_attributes.addClass('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/content/page-title.html.twig b/core/themes/classy/templates/content/page-title.html.twig new file mode 100644 index 0000000..adec853 --- /dev/null +++ b/core/themes/classy/templates/content/page-title.html.twig @@ -0,0 +1,21 @@ +{# +/** + * @file + * Theme override for page titles. + * + * Available variables: + * - title_attributes: HTML attributes for the page title element. + * - 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() + */ +#} +{{ title_prefix }} +{% if title %} + {{ title }} +{% endif %} +{{ title_suffix }} diff --git a/core/themes/classy/templates/layout/page.html.twig b/core/themes/classy/templates/layout/page.html.twig index 0ac734b..f998a33 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 @@ -72,12 +67,6 @@ {# link is in html.html.twig #}
- - {{ title_prefix }} - {% if title %} -

{{ title }}

- {% endif %} - {{ title_suffix }} {{ page.content }}
{# /.layout-content #} 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 }}