Commit 6cbb5d9e authored by catch's avatar catch

Issue #2350949 by Wim Leers: Add hook_page_attachments(_alter)() and deprecate...

Issue #2350949 by Wim Leers: Add hook_page_attachments(_alter)() and deprecate hook_page_build/alter().
parent e83d8970
...@@ -706,14 +706,14 @@ function drupal_http_header_attributes(array $attributes = array()) { ...@@ -706,14 +706,14 @@ function drupal_http_header_attributes(array $attributes = array()) {
* For authenticated users, the "active" class will be calculated on the * For authenticated users, the "active" class will be calculated on the
* client (through JavaScript), only data- attributes are added to links to * client (through JavaScript), only data- attributes are added to links to
* prevent breaking the render cache. The JavaScript is added in * prevent breaking the render cache. The JavaScript is added in
* system_page_build(). * system_page_attachments().
* - Additional $options elements used by the url() function. * - Additional $options elements used by the url() function.
* *
* @return string * @return string
* An HTML string containing a link to the given path. * An HTML string containing a link to the given path.
* *
* @see _url() * @see _url()
* @see system_page_build() * @see system_page_attachments()
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0. * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0.
* Use \Drupal::l($text, $url) where $url is an instance of * Use \Drupal::l($text, $url) where $url is an instance of
* \Drupal\Core\Url. To build a \Drupal\Core\Url object for internal paths * \Drupal\Core\Url. To build a \Drupal\Core\Url object for internal paths
...@@ -917,8 +917,7 @@ function _drupal_add_html_head_link($attributes, $header = FALSE) { ...@@ -917,8 +917,7 @@ function _drupal_add_html_head_link($attributes, $header = FALSE) {
* $options['preprocess'] should be only set to TRUE when a file is required for * $options['preprocess'] should be only set to TRUE when a file is required for
* all typical visitors and most pages of a site. It is critical that all * all typical visitors and most pages of a site. It is critical that all
* preprocessed files are added unconditionally on every page, even if the * preprocessed files are added unconditionally on every page, even if the
* files do not happen to be needed on a page. This is normally done by calling * files do not happen to be needed on a page.
* _drupal_add_css() in a hook_page_build() implementation.
* *
* Non-preprocessed files should only be added to the page when they are * Non-preprocessed files should only be added to the page when they are
* actually needed. * actually needed.
...@@ -966,8 +965,8 @@ function _drupal_add_html_head_link($attributes, $header = FALSE) { ...@@ -966,8 +965,8 @@ function _drupal_add_html_head_link($attributes, $header = FALSE) {
* page of the website for users for whom it is present at all. This * page of the website for users for whom it is present at all. This
* defaults to FALSE. It is set to TRUE for stylesheets added via module and * defaults to FALSE. It is set to TRUE for stylesheets added via module and
* theme .info.yml files. Modules that add stylesheets within * theme .info.yml files. Modules that add stylesheets within
* hook_page_build() implementations, or from other code that ensures that * hook_page_attachments() implementations, or from other code that ensures
* the stylesheet is added to all website pages, should also set this flag * that the stylesheet is added to all website pages, should also set this flag
* to TRUE. All stylesheets within the same group that have the 'every_page' * to TRUE. All stylesheets within the same group that have the 'every_page'
* flag set to TRUE and do not have 'preprocess' set to FALSE are aggregated * flag set to TRUE and do not have 'preprocess' set to FALSE are aggregated
* together into a single aggregate file, and that aggregate file can be * together into a single aggregate file, and that aggregate file can be
...@@ -1367,8 +1366,7 @@ function drupal_clean_id_identifier($id) { ...@@ -1367,8 +1366,7 @@ function drupal_clean_id_identifier($id) {
* $options['preprocess'] should be only set to TRUE when a file is required for * $options['preprocess'] should be only set to TRUE when a file is required for
* all typical visitors and most pages of a site. It is critical that all * all typical visitors and most pages of a site. It is critical that all
* preprocessed files are added unconditionally on every page, even if the * preprocessed files are added unconditionally on every page, even if the
* files are not needed on a page. This is normally done by calling * files are not needed on a page.
* _drupal_add_js() in a hook_page_build() implementation.
* *
* Non-preprocessed files should only be added to the page when they are * Non-preprocessed files should only be added to the page when they are
* actually needed. * actually needed.
...@@ -1411,9 +1409,9 @@ function drupal_clean_id_identifier($id) { ...@@ -1411,9 +1409,9 @@ function drupal_clean_id_identifier($id) {
* page of the website for users for whom it is present at all. This * page of the website for users for whom it is present at all. This
* defaults to FALSE. It is set to TRUE for JavaScript files that are added * defaults to FALSE. It is set to TRUE for JavaScript files that are added
* via module and theme .info.yml files. Modules that add JavaScript within * via module and theme .info.yml files. Modules that add JavaScript within
* hook_page_build() implementations, or from other code that ensures that * hook_page_attachments() implementations, or from other code that ensures
* the JavaScript is added to all website pages, should also set this flag * that the JavaScript is added to all website pages, should also set this
* to TRUE. All JavaScript files within the same group and that have the * flag to TRUE. All JavaScript files within the same group and that have the
* 'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE * 'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE
* are aggregated together into a single aggregate file, and that aggregate * are aggregated together into a single aggregate file, and that aggregate
* file can be reused across a user's entire site visit, leading to faster * file can be reused across a user's entire site visit, leading to faster
...@@ -1712,13 +1710,13 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS ...@@ -1712,13 +1710,13 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
* *
* Example: * Example:
* @code * @code
* function module1_page_build(&$page) { * function module1_page_attachments(&$page) {
* $page['#attached']['js'][] = array( * $page['#attached']['js'][] = array(
* 'type' => 'setting', * 'type' => 'setting',
* 'data' => array('foo' => array('a', 'b', 'c')), * 'data' => array('foo' => array('a', 'b', 'c')),
* ); * );
* } * }
* function module2_page_build(&$page) { * function module2_page_attachments(&$page) {
* $page['#attached']['js'][] = array( * $page['#attached']['js'][] = array(
* 'type' => 'setting', * 'type' => 'setting',
* 'data' => array('foo' => array('d')), * 'data' => array('foo' => array('d')),
...@@ -2443,7 +2441,10 @@ function drupal_pre_render_links($element) { ...@@ -2443,7 +2441,10 @@ function drupal_pre_render_links($element) {
* @return array * @return array
* The processed render array for the page. * The processed render array for the page.
* *
* @see hook_page_alter() * @see hook_page_attachments()
* @see hook_page_attachments_alter()
* @see hook_page_top()
* @see hook_page_bottom()
* @see element_info() * @see element_info()
*/ */
function drupal_prepare_page($page) { function drupal_prepare_page($page) {
...@@ -2462,15 +2463,59 @@ function drupal_prepare_page($page) { ...@@ -2462,15 +2463,59 @@ function drupal_prepare_page($page) {
$page = element_info('page'); $page = element_info('page');
} }
// Modules can add elements to $page as needed in hook_page_build(). // Modules can add attachments.
foreach (\Drupal::moduleHandler()->getImplementations('page_build') as $module) { $attachments = [];
$function = $module . '_page_build'; foreach (\Drupal::moduleHandler()->getImplementations('page_attachments') as $module) {
$function($page); $function = $module . '_page_attachments';
$function($attachments);
}
if (array_diff(array_keys($attachments), ['#attached', '#post_render_cache']) !== []) {
throw new \LogicException('Only #attached and #post_render_cache may be set in hook_page_attachments().');
}
// Modules and themes can alter page attachments.
\Drupal::moduleHandler()->alter('page_attachments', $attachments);
\Drupal::theme()->alter('page_attachments', $attachments);
if (array_diff(array_keys($attachments), ['#attached', '#post_render_cache']) !== []) {
throw new \LogicException('Only #attached and #post_render_cache may be set in hook_page_attachments_alter().');
}
if (isset($attachments['#attached'])) {
$page['#attached'] = $attachments['#attached'];
}
if (isset($attachments['#post_render_cache'])) {
$page['#post_render_cache'] = $attachments['#post_render_cache'];
}
// Modules can add renderable arrays to the top and bottom of the page.
$pseudo_page_top = [];
$pseudo_page_bottom = [];
foreach (\Drupal::moduleHandler()->getImplementations('page_top') as $module) {
$function = $module . '_page_top';
$function($pseudo_page_top);
}
foreach (\Drupal::moduleHandler()->getImplementations('page_bottom') as $module) {
$function = $module . '_page_bottom';
$function($pseudo_page_bottom);
}
if (!empty($pseudo_page_top)) {
$page['page_top'] = $pseudo_page_top;
}
if (!empty($pseudo_page_bottom)) {
$page['page_bottom'] = $pseudo_page_bottom;
}
// @todo Clean this up as part of https://www.drupal.org/node/2352155.
if (\Drupal::moduleHandler()->moduleExists('block')) {
_block_page_build($page);
// Find all non-empty page regions, and add a theme wrapper function that
// allows them to be consistently themed.
$regions = system_region_list(\Drupal::theme()->getActiveTheme()->getName());
foreach (array_keys($regions) as $region) {
if (!empty($page[$region])) {
$page[$region]['#theme_wrappers'][] = 'region';
$page[$region]['#region'] = $region;
}
}
} }
// Modules alter the $page as needed. Blocks are populated into regions like
// 'sidebar_first', 'footer', etc.
\Drupal::moduleHandler()->alter('page', $page);
\Drupal::theme()->alter('page', $page);
// If no module has taken care of the main content, add it to the page now. // If no module has taken care of the main content, add it to the page now.
// This allows the site to still be usable even if no modules that // This allows the site to still be usable even if no modules that
......
...@@ -925,7 +925,7 @@ function template_preprocess_status_messages(&$variables) { ...@@ -925,7 +925,7 @@ function template_preprocess_status_messages(&$variables) {
* For authenticated users, the "active" class will be calculated on the * For authenticated users, the "active" class will be calculated on the
* client (through JavaScript), only data- attributes are added to list * client (through JavaScript), only data- attributes are added to list
* items and contained links, to prevent breaking the render cache. The * items and contained links, to prevent breaking the render cache. The
* JavaScript is added in system_page_build(). * JavaScript is added in system_page_attachments().
* - heading: (optional) A heading to precede the links. May be an * - heading: (optional) A heading to precede the links. May be an
* associative array or a string. If it's an array, it can have the * associative array or a string. If it's an array, it can have the
* following elements: * following elements:
...@@ -953,7 +953,7 @@ function template_preprocess_status_messages(&$variables) { ...@@ -953,7 +953,7 @@ function template_preprocess_status_messages(&$variables) {
* *
* @see \Drupal\Core\Utility\LinkGenerator * @see \Drupal\Core\Utility\LinkGenerator
* @see \Drupal\Core\Utility\LinkGenerator::generate() * @see \Drupal\Core\Utility\LinkGenerator::generate()
* @see system_page_build() * @see system_page_attachments()
*/ */
function template_preprocess_links(&$variables) { function template_preprocess_links(&$variables) {
$links = $variables['links']; $links = $variables['links'];
...@@ -1920,7 +1920,7 @@ function theme_get_suggestions($args, $base, $delimiter = '__') { ...@@ -1920,7 +1920,7 @@ function theme_get_suggestions($args, $base, $delimiter = '__') {
* An associative array containing: * An associative array containing:
* - content - An array of page content. * - content - An array of page content.
* *
* @see system_page_build() * @see system_page_attachments()
*/ */
function template_preprocess_maintenance_page(&$variables) { function template_preprocess_maintenance_page(&$variables) {
// @todo Rename the templates to page--maintenance + page--install. // @todo Rename the templates to page--maintenance + page--install.
...@@ -1935,7 +1935,7 @@ function template_preprocess_maintenance_page(&$variables) { ...@@ -1935,7 +1935,7 @@ function template_preprocess_maintenance_page(&$variables) {
} }
$attributes['class'] = $classes; $attributes['class'] = $classes;
// @see system_page_build() // @see system_page_attachments()
$variables['#attached']['library'][] = 'core/normalize'; $variables['#attached']['library'][] = 'core/normalize';
$variables['#attached']['library'][] = 'system/maintenance'; $variables['#attached']['library'][] = 'system/maintenance';
} }
......
...@@ -72,8 +72,12 @@ public function render(HtmlFragmentInterface $fragment, $status_code = 200) { ...@@ -72,8 +72,12 @@ public function render(HtmlFragmentInterface $fragment, $status_code = 200) {
// Persist cache tags associated with this page. Also associate the // Persist cache tags associated with this page. Also associate the
// "rendered" cache tag. This allows us to invalidate the entire render // "rendered" cache tag. This allows us to invalidate the entire render
// cache, regardless of the cache bin. // cache, regardless of the cache bin.
$cache_tags = $page_array['#cache']['tags']; $cache_tags = Cache::mergeTags(
$cache_tags[] = 'rendered'; isset($page_array['page_top']) ? $page_array['page_top']['#cache']['tags'] : [],
$page_array['#cache']['tags'],
isset($page_array['page_bottom']) ? $page_array['page_bottom']['#cache']['tags'] : [],
['rendered']
);
// Only keep unique cache tags. We need to prevent duplicates here already // Only keep unique cache tags. We need to prevent duplicates here already
// rather than only in the cache layer, because they are also used by // rather than only in the cache layer, because they are also used by
// reverse proxies (like Varnish), not only by Drupal's page cache. // reverse proxies (like Varnish), not only by Drupal's page cache.
......
...@@ -64,9 +64,9 @@ public function generateFromLink(Link $link) { ...@@ -64,9 +64,9 @@ public function generateFromLink(Link $link) {
* For authenticated users, the "active" class will be calculated on the * For authenticated users, the "active" class will be calculated on the
* client (through JavaScript), only data- attributes are added to links to * client (through JavaScript), only data- attributes are added to links to
* prevent breaking the render cache. The JavaScript is added in * prevent breaking the render cache. The JavaScript is added in
* system_page_build(). * system_page_attachments().
* *
* @see system_page_build() * @see system_page_attachments()
*/ */
public function generate($text, Url $url) { public function generate($text, Url $url) {
// Performance: avoid Url::toString() needing to retrieve the URL generator // Performance: avoid Url::toString() needing to retrieve the URL generator
......
<?php
/**
* @file
* Install, update and uninstall functions for the block module.
*/
use Drupal\Core\Language\Language;
/**
* Implements hook_install().
*/
function block_install() {
// Block should go first so that other modules can alter its output
// during hook_page_alter(). Almost everything on the page is a block,
// so before block module runs, there will not be much to alter.
module_set_weight('block', -5);
}
...@@ -62,11 +62,11 @@ function block_theme() { ...@@ -62,11 +62,11 @@ function block_theme() {
} }
/** /**
* Implements hook_page_build().
*
* Renders blocks into their regions. * Renders blocks into their regions.
*
* @todo Clean this up as part of https://www.drupal.org/node/2352155.
*/ */
function block_page_build(&$page) { function _block_page_build(&$page) {
$theme = \Drupal::theme()->getActiveTheme()->getName(); $theme = \Drupal::theme()->getActiveTheme()->getName();
// Fetch a list of regions for the current theme. // Fetch a list of regions for the current theme.
......
...@@ -722,9 +722,9 @@ function content_translation_preprocess_language_content_settings_table(&$variab ...@@ -722,9 +722,9 @@ function content_translation_preprocess_language_content_settings_table(&$variab
} }
/** /**
* Implements hook_page_alter(). * Implements hook_page_attachments().
*/ */
function content_translation_page_alter(&$page) { function content_translation_page_attachments(&$page) {
$route_match = \Drupal::routeMatch(); $route_match = \Drupal::routeMatch();
// If the current route has no parameters, return. // If the current route has no parameters, return.
......
...@@ -44,15 +44,14 @@ function contextual_toolbar() { ...@@ -44,15 +44,14 @@ function contextual_toolbar() {
} }
/** /**
* Implements hook_page_build(). * Implements hook_page_attachments().
* *
* Adds the drupal.contextual-links library to the page for any user who has the * Adds the drupal.contextual-links library to the page for any user who has the
* 'access contextual links' permission. * 'access contextual links' permission.
* *
* @see contextual_preprocess() * @see contextual_preprocess()
*/ */
function contextual_page_build(&$page) { function contextual_page_attachments(array &$page) {
if (!\Drupal::currentUser()->hasPermission('access contextual links')) { if (!\Drupal::currentUser()->hasPermission('access contextual links')) {
return; return;
} }
...@@ -89,7 +88,7 @@ function contextual_help($route_name, RouteMatchInterface $route_match) { ...@@ -89,7 +88,7 @@ function contextual_help($route_name, RouteMatchInterface $route_match) {
* Implements hook_preprocess(). * Implements hook_preprocess().
* *
* @see contextual_pre_render_placeholder() * @see contextual_pre_render_placeholder()
* @see contextual_page_build() * @see contextual_page_attachments()
* @see \Drupal\contextual\ContextualController::render() * @see \Drupal\contextual\ContextualController::render()
*/ */
function contextual_preprocess(&$variables, $hook, $info) { function contextual_preprocess(&$variables, $hook, $info) {
...@@ -111,9 +110,9 @@ function contextual_preprocess(&$variables, $hook, $info) { ...@@ -111,9 +110,9 @@ function contextual_preprocess(&$variables, $hook, $info) {
// Renders a contextual links placeholder unconditionally, thus not breaking // Renders a contextual links placeholder unconditionally, thus not breaking
// the render cache. Although the empty placeholder is rendered for all // the render cache. Although the empty placeholder is rendered for all
// users, contextual_page_build() only adds the drupal.contextual-links // users, contextual_page_attachments() only adds the asset library for
// library for users with the 'access contextual links' permission, thus // users with the 'access contextual links' permission, thus preventing
// preventing unnecessary HTTP requests for users without that permission. // unnecessary HTTP requests for users without that permission.
$variables['title_suffix']['contextual_links'] = array( $variables['title_suffix']['contextual_links'] = array(
'#type' => 'contextual_links_placeholder', '#type' => 'contextual_links_placeholder',
'#id' => _contextual_links_to_id($element['#contextual_links']), '#id' => _contextual_links_to_id($element['#contextual_links']),
......
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI; use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI;
/** /**
* Implements hook_page_build(). * Implements hook_page_top().
*/ */
function language_test_page_build() { function language_test_page_top() {
if (\Drupal::moduleHandler()->moduleExists('language')) { if (\Drupal::moduleHandler()->moduleExists('language')) {
language_test_store_language_negotiation(); language_test_store_language_negotiation();
drupal_set_message(t('Language negotiation method: @name', array('@name' => \Drupal::languageManager()->getNegotiatedLanguageMethod()))); drupal_set_message(t('Language negotiation method: @name', array('@name' => \Drupal::languageManager()->getNegotiatedLanguageMethod())));
......
...@@ -885,9 +885,9 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $langcode = NULL) { ...@@ -885,9 +885,9 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $langcode = NULL) {
} }
/** /**
* Implements hook_page_build(). * Implements hook_page_top().
*/ */
function node_page_build(&$page) { function node_page_top(array &$page) {
// Add 'Back to content editing' link on preview page. // Add 'Back to content editing' link on preview page.
$route_match = \Drupal::routeMatch(); $route_match = \Drupal::routeMatch();
if ($route_match->getRouteName() == 'entity.node.preview') { if ($route_match->getRouteName() == 'entity.node.preview') {
......
...@@ -36,12 +36,12 @@ function quickedit_help($route_name, RouteMatchInterface $route_match) { ...@@ -36,12 +36,12 @@ function quickedit_help($route_name, RouteMatchInterface $route_match) {
} }
/** /**
* Implements hook_page_build(). * Implements hook_page_attachments().
* *
* Adds the quickedit library to the page for any user who has the 'access * Adds the quickedit library to the page for any user who has the 'access
* in-place editing' permission. * in-place editing' permission.
*/ */
function quickedit_page_build(&$page) { function quickedit_page_attachments(array &$page) {
if (!\Drupal::currentUser()->hasPermission('access in-place editing')) { if (!\Drupal::currentUser()->hasPermission('access in-place editing')) {
return; return;
} }
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\Common\PageRenderTest.
*/
namespace Drupal\system\Tests\Common;
use Drupal\simpletest\KernelTestBase;
/**
* Test page rendering hooks.
*
* @group system
*/
class PageRenderTest extends KernelTestBase {
/**
* Tests hook_page_attachments() exceptions.
*/
function testHookPageAttachmentsExceptions() {
$this->enableModules(['common_test']);
$this->assertPageRenderHookExceptions('common_test', 'hook_page_attachments');
}
/**
* Tests hook_page_attachments_alter() exceptions.
*/
function testHookPageAlter() {
$this->enableModules(['common_test']);
$this->assertPageRenderHookExceptions('common_test', 'hook_page_attachments_alter');
}
/**
* Tests hook_page_build() exceptions, a deprecated hook kept around for BC.
*/
function testHookPageBuildExceptions() {
// Also enable the system module, because that module invokes the BC hooks.
$this->enableModules(['bc_test', 'system']);
$this->assertPageRenderHookExceptions('bc_test', 'hook_page_build');
}
/**
* Tests hook_page_alter(), a deprecated hook kept around for BC.
*/
function testHookPageAttachmentsAlter() {
// Also enable the system module, because that module invokes the BC hooks.
$this->enableModules(['bc_test', 'system']);
$this->assertPageRenderHookExceptions('bc_test', 'hook_page_alter');
}
/**
* Asserts whether expected exceptions are thrown for invalid hook implementations.
*
* @param string $module
* The module whose invalid logic in its hooks to enable.
* @param string $hook
* The page render hook to assert expected exceptions for.
*/
function assertPageRenderHookExceptions($module, $hook) {
// Assert a valid hook implementation doesn't trigger an exception.
$page = [];
drupal_prepare_page($page);
// Assert an invalid hook implementation doesn't trigger an exception.
\Drupal::state()->set($module . '.' . $hook . '.descendant_attached', TRUE);
$assertion = $hook . '() implementation that sets #attached on a descendant triggers an exception';
$page = [];
try {
drupal_prepare_page($page);
$this->error($assertion);
}
catch (\LogicException $e) {
$this->pass($assertion);
$this->assertEqual($e->getMessage(), 'Only #attached and #post_render_cache may be set in ' . $hook . '().');
}
\Drupal::state()->set('bc_test.' . $hook . '.descendant_attached', FALSE);
// Assert an invalid hook implementation doesn't trigger an exception.
\Drupal::state()->set('bc_test.' . $hook . '.render_array', TRUE);
$assertion = $hook . '() implementation that sets a child render array triggers an exception';
$page = [];
try {
drupal_prepare_page($page);
$this->error($assertion);
}
catch (\LogicException $e) {
$this->pass($assertion);
$this->assertEqual($e->getMessage(), 'Only #attached and #post_render_cache may be set in ' . $hook . '().');
}
\Drupal::state()->set($module . '.' . $hook . '.render_array', FALSE);
}
}
...@@ -61,19 +61,13 @@ function testMainContentFallback() { ...@@ -61,19 +61,13 @@ function testMainContentFallback() {
// Fallback should not trigger when another module is handling content. // Fallback should not trigger when another module is handling content.
$this->drupalGet('system-test/main-content-handling'); $this->drupalGet('system-test/main-content-handling');
$this->assertRaw('id="system-test-content"', 'Content handled by another module'); $this->assertRaw('id="system-test-content"', 'Content handled by another module');
$this->assertText(t('Content to test main content fallback'), 'Main content still displayed.'); $this->assertNoText(t('Content to test main content fallback'), 'Main content not displayed.');
// Fallback should trigger when another module // Fallback should trigger when another module
// indicates that it is not handling the content. // indicates that it is not handling the content.
$this->drupalGet('system-test/main-content-fallback'); $this->drupalGet('system-test/main-content-fallback');
$this->assertText(t('Content to test main content fallback'), 'Main content fallback properly triggers.'); $this->assertText(t('Content to test main content fallback'), 'Main content fallback properly triggers.');
// Fallback should not trigger when another module is handling content.
// Note that this test ensures that no duplicate
// content gets created by the fallback.
$this->drupalGet('system-test/main-content-duplication');
$this->assertNoText(t('Content to test main content fallback'), 'Main content not duplicated.');
// Request a user* page and see if it is displayed. // Request a user* page and see if it is displayed.
$this->drupalLogin($this->web_user); $this->drupalLogin($this->web_user);
$this->drupalGet('user/' . $this->web_user->id() . '/edit'); $this->drupalGet('user/' . $this->web_user->id() . '/edit');
......
...@@ -288,26 +288,18 @@ function hook_ajax_render_alter(array &$data) { ...@@ -288,26 +288,18 @@ function hook_ajax_render_alter(array &$data) {
} }
/** /**
* Add elements to a page before it is rendered. * Add attachments (typically assets) to a page before it is rendered.
* *
* Use this hook when you want to add elements at the page level. For your * Kept around for backwards compatibility, but now allows only attachments to
* additions to be printed, they have to be placed below a top level array key * be added, adding renderable arrays is no longer allowed.
* of the $page array that has the name of a region of the active theme.
* *
* By default, valid region keys are 'page_top', 'header', 'sidebar_first', * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. Successor:
* 'content', 'sidebar_second' and 'page_bottom'. To get a list of all regions * hook_page_attachments(). Is now effectively an alias of that hook.
* of the active theme, use system_region_list($theme). Note that $theme is a
* global variable.
*
* If you want to alter the elements added by other modules or if your module
* depends on the elements of other modules, use hook_page_alter() instead which
* runs after this hook.
* *
* @param $page * @param $page
*