From 3f5bb7d9fc8bb1be2980db075124d3ce6044fef1 Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org> Date: Wed, 8 Oct 2014 12:49:20 +0100 Subject: [PATCH] Issue #2346369 by Wim Leers: Support special '#attached' variable for attaching assets in preprocess functions. --- core/includes/theme.inc | 20 ++++++----- .../system/src/Tests/Common/RenderTest.php | 25 ++++++++++++++ .../modules/common_test/common_test.module | 24 +++++++++++++ core/modules/system/theme.api.php | 15 ++++++++ core/modules/views/views.module | 3 +- core/themes/bartik/bartik.theme | 13 ++----- core/themes/seven/seven.libraries.yml | 2 +- core/themes/seven/seven.theme | 34 +++---------------- 8 files changed, 85 insertions(+), 51 deletions(-) diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 03dc12192d35..b84302918545 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -372,6 +372,15 @@ function _theme($hook, $variables = array()) { $preprocessor_function($variables, $hook, $info); } } + // Allow theme preprocess functions to set $variables['#attached'] and use + // it like the #attached property on render arrays. In Drupal 8, this is the + // (only) officially supported method of attaching assets from preprocess + // functions. Assets attached here should be associated with the template + // that we're preprocessing variables for. + if (isset($variables['#attached'])) { + $preprocess_attached = ['#attached' => $variables['#attached']]; + drupal_render($preprocess_attached, TRUE); + } } // Generate the output using either a function or a template. @@ -1946,15 +1955,8 @@ function template_preprocess_maintenance_page(&$variables) { $attributes['class'] = $classes; // @see system_page_build() - $attached = array( - '#attached' => array( - 'library' => array( - 'core/normalize', - 'system/maintenance', - ), - ), - ); - drupal_render($attached); + $variables['#attached']['library'][] = 'core/normalize'; + $variables['#attached']['library'][] = 'system/maintenance'; } /** diff --git a/core/modules/system/src/Tests/Common/RenderTest.php b/core/modules/system/src/Tests/Common/RenderTest.php index d07085cf2cfb..6c286cab0163 100644 --- a/core/modules/system/src/Tests/Common/RenderTest.php +++ b/core/modules/system/src/Tests/Common/RenderTest.php @@ -410,6 +410,31 @@ function testDrupalRenderThemeArguments() { $this->assertEqual(drupal_render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works'); } + /** + * Tests theme preprocess functions being able to attach assets. + */ + function testDrupalRenderThemePreprocessAttached() { + \Drupal::state()->set('theme_preprocess_attached_test', TRUE); + + $test_element = [ + '#theme' => 'common_test_render_element', + 'foo' => [ + '#markup' => 'Kittens!', + ], + ]; + drupal_render($test_element); + + $expected_attached = [ + 'library' => [ + 'test/generic_preprocess', + 'test/specific_preprocess', + ] + ]; + $this->assertEqual($expected_attached, $test_element['#attached'], 'All expected assets from theme preprocess hooks attached.'); + + \Drupal::state()->set('theme_preprocess_attached_test', FALSE); + } + /** * Tests caching of an empty render item. */ diff --git a/core/modules/system/tests/modules/common_test/common_test.module b/core/modules/system/tests/modules/common_test/common_test.module index e23a842eedba..e812b617d6df 100644 --- a/core/modules/system/tests/modules/common_test/common_test.module +++ b/core/modules/system/tests/modules/common_test/common_test.module @@ -142,6 +142,30 @@ function theme_common_test_empty($variables) { return ''; } +/** + * Implements MODULE_preprocess(). + * + * @see RenderTest::testDrupalRenderThemePreprocessAttached() + */ +function common_test_preprocess(&$variables, $hook) { + if (!\Drupal::state()->get('theme_preprocess_attached_test', FALSE)) { + return; + } + $variables['#attached']['library'][] = 'test/generic_preprocess'; +} + +/** + * Implements MODULE_preprocess_HOOK(). + * + * @see RenderTest::testDrupalRenderThemePreprocessAttached() + */ +function common_test_preprocess_common_test_render_element(&$variables) { + if (!\Drupal::state()->get('theme_preprocess_attached_test', FALSE)) { + return; + } + $variables['#attached']['library'][] = 'test/specific_preprocess'; +} + /** * Implements hook_library_info_alter(). */ diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php index 1a613b7d6f75..26c998aab64e 100644 --- a/core/modules/system/theme.api.php +++ b/core/modules/system/theme.api.php @@ -159,6 +159,21 @@ * suggestions as input, and can change this array (adding suggestions and * removing them). * + * @section Assets + * + * We can distinguish between two types of assets: + * 1. global assets (loaded on all pages where the theme is in use): these are + * defined in the theme's *.info.yml file. + * 2. template-specific assets (loaded on all pages where a specific template is + * in use): these can be added by in preprocessing functions, using @code + * $variables['#attached'] @endcode, e.g.: + * @code + * function seven_preprocess_menu_local_action(array &$variables) { + * // We require Modernizr's touch test for button styling. + * $variables['#attached']['library'][] = 'core/modernizr'; + * } + * @endcode + * * @see hooks * @see callbacks * @see theme_render diff --git a/core/modules/views/views.module b/core/modules/views/views.module index f3877e03c0ef..a41e73e182b5 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -329,8 +329,7 @@ function views_preprocess_page(&$variables) { unset($class[$key]); $attributes['class'] = $class; $attributes['data-views-page-contextual-id'] = $variables['title_suffix']['contextual_links']['#id']; - $attached['#attached']['library'][] = 'views/views.contextual-links'; - drupal_render($attached); + $variables['#attached']['library'][] = 'views/views.contextual-links'; } } } diff --git a/core/themes/bartik/bartik.theme b/core/themes/bartik/bartik.theme index db027bea9ba3..60f9a34d8c4d 100644 --- a/core/themes/bartik/bartik.theme +++ b/core/themes/bartik/bartik.theme @@ -87,16 +87,9 @@ function bartik_preprocess_maintenance_page(&$variables) { if (!$variables['db_is_active']) { $variables['site_name'] = ''; } - // Normally we could attach libraries via hook_page_alter(), but when the - // database is inactive it's not called so we add them here. - $libraries = array( - '#attached' => array( - 'library' => array( - 'bartik/maintenance_page', - ), - ), - ); - drupal_render($libraries); + + // Bartik has custom styling for the maintenance page. + $variables['#attached']['library'][] = 'bartik/maintenance_page'; // Set the options that apply to both page and maintenance page. _bartik_process_page($variables); diff --git a/core/themes/seven/seven.libraries.yml b/core/themes/seven/seven.libraries.yml index d7a9495d0b79..a79487161cdf 100644 --- a/core/themes/seven/seven.libraries.yml +++ b/core/themes/seven/seven.libraries.yml @@ -16,7 +16,7 @@ install-page: theme: css/theme/install-page.css: {} dependencies: - - system/maintenance + - seven/maintenance-page drupal.nav-tabs: version: VERSION diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme index ccd1c92bc1f4..88c25704bbbf 100644 --- a/core/themes/seven/seven.theme +++ b/core/themes/seven/seven.theme @@ -128,14 +128,7 @@ function seven_preprocess_menu_local_action(array &$variables) { $variables['link']['#options']['attributes']['class'][] = 'button--small'; // We require Modernizr's touch test for button styling. - $libraries = array( - '#attached' => array( - 'library' => array( - 'core/modernizr', - ), - ), - ); - drupal_render($libraries); + $variables['#attached']['library'][] = 'core/modernizr'; } /** @@ -158,17 +151,8 @@ function seven_preprocess_install_page(&$variables) { $classes[] = 'install-background'; $attributes['class'] = $classes; - // Normally we could attach libraries via hook_page_alter(), but when the - // database is inactive it's not called so we add them here. - $libraries = array( - '#attached' => array( - 'library' => array( - 'seven/maintenance-page', - 'seven/install-page', - ), - ), - ); - drupal_render($libraries); + // Seven has custom styling for the install page. + $variables['#attached']['library'][] = 'seven/install-page'; } /** @@ -181,16 +165,8 @@ function seven_preprocess_maintenance_page(&$variables) { $classes[] = 'maintenance-background'; $attributes['class'] = $classes; - // // Normally we could attach libraries via hook_page_alter(), but when the - // // database is inactive it's not called so we add them here. - $libraries = array( - '#attached' => array( - 'library' => array( - 'seven/maintenance-page', - ), - ), - ); - drupal_render($libraries); + // Seven has custom styling for the maintenance page. + $variables['#attached']['library'][] = 'seven/maintenance-page'; } /** -- GitLab