diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php index 5c135a181e5..f6db2c3eb58 100644 --- a/core/.phpstan-baseline.php +++ b/core/.phpstan-baseline.php @@ -451,12 +451,6 @@ $ignoreErrors[] = [ 'count' => 1, 'path' => __DIR__ . '/includes/theme.inc', ]; -$ignoreErrors[] = [ - // identifier: missingType.return - 'message' => '#^Function drupal_common_theme\\(\\) has no return type specified\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/includes/theme.inc', -]; $ignoreErrors[] = [ // identifier: missingType.return 'message' => '#^Function drupal_find_theme_templates\\(\\) has no return type specified\\.$#', diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 5858525ab41..2924ae25ee6 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1801,156 +1801,3 @@ function _field_multiple_value_form_sort_helper($a, $b) { $b_weight = (is_array($b) && isset($b['_weight']['#value']) ? $b['_weight']['#value'] : 0); return $a_weight - $b_weight; } - -/** - * Provides theme registration for themes across .inc files. - */ -function drupal_common_theme() { - return [ - // From theme.inc. - 'html' => [ - 'render element' => 'html', - ], - 'page' => [ - 'render element' => 'page', - ], - 'page_title' => [ - 'variables' => ['title' => NULL], - ], - 'region' => [ - 'render element' => 'elements', - ], - 'time' => [ - 'variables' => ['timestamp' => NULL, 'text' => NULL, 'attributes' => []], - ], - 'datetime_form' => [ - 'render element' => 'element', - ], - 'datetime_wrapper' => [ - 'render element' => 'element', - ], - 'status_messages' => [ - 'variables' => ['status_headings' => [], 'message_list' => NULL], - ], - 'links' => [ - 'variables' => ['links' => [], 'attributes' => ['class' => ['links']], 'heading' => [], 'set_active_class' => FALSE], - ], - 'dropbutton_wrapper' => [ - 'variables' => ['children' => NULL], - ], - 'image' => [ - // HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft - // allows the alt attribute to be omitted in some cases. Therefore, - // default the alt attribute to an empty string, but allow code providing - // variables to image.html.twig templates to pass explicit NULL for it to - // be omitted. Usually, neither omission nor an empty string satisfies - // accessibility requirements, so it is strongly encouraged for code - // building variables for image.html.twig templates to pass a meaningful - // value for the alt variable. - // - https://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8 - // - https://www.w3.org/TR/xhtml1/dtds.html - // - http://dev.w3.org/html5/spec/Overview.html#alt - // The title attribute is optional in all cases, so it is omitted by - // default. - 'variables' => ['uri' => NULL, 'width' => NULL, 'height' => NULL, 'alt' => '', 'title' => NULL, 'attributes' => [], 'sizes' => NULL, 'srcset' => [], 'style_name' => NULL], - ], - 'breadcrumb' => [ - 'variables' => ['links' => []], - ], - 'table' => [ - 'variables' => ['header' => NULL, 'rows' => NULL, 'footer' => NULL, 'attributes' => [], 'caption' => NULL, 'colgroups' => [], 'sticky' => FALSE, 'responsive' => TRUE, 'empty' => ''], - ], - 'tablesort_indicator' => [ - 'variables' => ['style' => NULL], - ], - 'mark' => [ - 'variables' => ['status' => MARK_NEW], - ], - 'item_list' => [ - 'variables' => ['items' => [], 'title' => '', 'list_type' => 'ul', 'wrapper_attributes' => [], 'attributes' => [], 'empty' => NULL, 'context' => []], - ], - 'feed_icon' => [ - 'variables' => ['url' => NULL, 'title' => NULL, 'attributes' => []], - ], - 'progress_bar' => [ - 'variables' => ['label' => NULL, 'percent' => NULL, 'message' => NULL], - ], - 'indentation' => [ - 'variables' => ['size' => 1], - ], - // From theme.maintenance.inc. - 'maintenance_page' => [ - 'render element' => 'page', - ], - 'install_page' => [ - 'render element' => 'page', - ], - 'maintenance_task_list' => [ - 'variables' => ['items' => NULL, 'active' => NULL, 'variant' => NULL], - ], - 'authorize_report' => [ - 'variables' => ['messages' => [], 'attributes' => []], - 'includes' => ['core/includes/theme.maintenance.inc'], - 'template' => 'authorize-report', - ], - 'pager' => [ - 'render element' => 'pager', - ], - 'menu' => [ - 'variables' => ['menu_name' => NULL, 'items' => [], 'attributes' => []], - ], - 'menu_local_task' => [ - 'render element' => 'element', - ], - 'menu_local_action' => [ - 'render element' => 'element', - ], - 'menu_local_tasks' => [ - 'variables' => ['primary' => [], 'secondary' => []], - ], - // From form.inc. - 'input' => [ - 'render element' => 'element', - ], - 'select' => [ - 'render element' => 'element', - ], - 'fieldset' => [ - 'render element' => 'element', - ], - 'details' => [ - 'render element' => 'element', - ], - 'radios' => [ - 'render element' => 'element', - ], - 'checkboxes' => [ - 'render element' => 'element', - ], - 'form' => [ - 'render element' => 'element', - ], - 'textarea' => [ - 'render element' => 'element', - ], - 'form_element' => [ - 'render element' => 'element', - ], - 'form_element_label' => [ - 'render element' => 'element', - ], - 'vertical_tabs' => [ - 'render element' => 'element', - ], - 'container' => [ - 'render element' => 'element', - ], - // From field system. - 'field' => [ - 'render element' => 'element', - ], - 'field_multiple_value_form' => [ - 'render element' => 'element', - ], - ]; -} diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index e85a72ffe8f..66f4225c945 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -391,9 +391,16 @@ class Registry implements DestructableInterface { $cache = $cached->data; } else { - $this->moduleHandler->invokeAllWith('theme', function (callable $callback, string $module) use (&$cache) { - $this->processExtension($cache, $module, 'module', $module, $this->moduleList->getPath($module)); - }); + if (defined('MAINTENANCE_MODE') && constant('MAINTENANCE_MODE') === 'install') { + // System is still set here so preprocess can be updated in install. + $this->processExtension($cache, 'system', 'install', 'system', $this->moduleList->getPath('system')); + } + else { + $this->moduleHandler->invokeAllWith('theme', function (callable $callback, string $module) use (&$cache) { + $this->processExtension($cache, $module, 'module', $module, $this->moduleList->getPath($module)); + }); + } + // Only cache this registry if all modules are loaded. if ($this->moduleHandler->isLoaded()) { $this->cache->set("theme_registry:build:modules", $cache); @@ -464,12 +471,12 @@ class Registry implements DestructableInterface { * The name of the module, theme engine, base theme engine, theme or base * theme implementing hook_theme(). * @param string $type - * One of 'module', 'theme_engine', 'base_theme_engine', 'theme', or - * 'base_theme'. Unlike regular hooks that can only be implemented by - * modules, each of these can implement hook_theme(). This function is - * called in aforementioned order and new entries override older ones. For - * example, if a theme hook is both defined by a module and a theme, then - * the definition in the theme will be used. + * One of 'module', 'theme_engine', 'base_theme_engine', 'theme', + * 'base_theme', or 'install'. Unlike regular hooks that can only be + * implemented by modules, each of these can implement hook_theme(). This + * function is called in aforementioned order and new entries override + * older ones. For example, if a theme hook is both defined by a module and + * a theme, then the definition in the theme will be used. * @param string $theme * The actual name of theme, module, etc. that is being processed. * @param string $path @@ -502,6 +509,12 @@ class Registry implements DestructableInterface { if ($type === 'module') { $result = $this->moduleHandler->invoke($name, 'theme', $args); } + elseif ($type === 'install') { + $result = ThemeCommonElements::commonElements(); + // Reset to module so that preprocess hooks are handled in install. + $type = 'module'; + $args = [$cache, $type, $theme, $path]; + } else { $function = $name . '_theme'; if (function_exists($function)) { diff --git a/core/lib/Drupal/Core/Theme/ThemeCommonElements.php b/core/lib/Drupal/Core/Theme/ThemeCommonElements.php new file mode 100644 index 00000000000..a9ebe744004 --- /dev/null +++ b/core/lib/Drupal/Core/Theme/ThemeCommonElements.php @@ -0,0 +1,252 @@ + [ + 'render element' => 'html', + ], + 'page' => [ + 'render element' => 'page', + ], + 'page_title' => [ + 'variables' => [ + 'title' => NULL, + ], + ], + 'region' => [ + 'render element' => 'elements', + ], + 'time' => [ + 'variables' => [ + 'timestamp' => NULL, + 'text' => NULL, + 'attributes' => [], + ], + ], + 'datetime_form' => [ + 'render element' => 'element', + ], + 'datetime_wrapper' => [ + 'render element' => 'element', + ], + 'status_messages' => [ + 'variables' => [ + 'status_headings' => [], + 'message_list' => NULL, + ], + ], + 'links' => [ + 'variables' => [ + 'links' => [], + 'attributes' => [ + 'class' => ['links'], + ], + 'heading' => [], + 'set_active_class' => FALSE, + ], + ], + 'dropbutton_wrapper' => [ + 'variables' => [ + 'children' => NULL, + ], + ], + 'image' => [ + // HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft + // allows the alt attribute to be omitted in some cases. Therefore, + // default the alt attribute to an empty string, but allow code providing + // variables to image.html.twig templates to pass explicit NULL for it to + // be omitted. Usually, neither omission nor an empty string satisfies + // accessibility requirements, so it is strongly encouraged for code + // building variables for image.html.twig templates to pass a meaningful + // value for the alt variable. + // - https://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8 + // - https://www.w3.org/TR/xhtml1/dtds.html + // - http://dev.w3.org/html5/spec/Overview.html#alt + // The title attribute is optional in all cases, so it is omitted by + // default. + 'variables' => [ + 'uri' => NULL, + 'width' => NULL, + 'height' => NULL, + 'alt' => '', + 'title' => NULL, + 'attributes' => [], + 'sizes' => NULL, + 'srcset' => [], + 'style_name' => NULL, + ], + ], + 'breadcrumb' => [ + 'variables' => [ + 'links' => [], + ], + ], + 'table' => [ + 'variables' => [ + 'header' => NULL, + 'rows' => NULL, + 'footer' => NULL, + 'attributes' => [], + 'caption' => NULL, + 'colgroups' => [], + 'sticky' => FALSE, + 'responsive' => TRUE, + 'empty' => '', + ], + ], + 'tablesort_indicator' => [ + 'variables' => [ + 'style' => NULL, + ], + ], + 'mark' => [ + 'variables' => [ + 'status' => MARK_NEW, + ], + ], + 'item_list' => [ + 'variables' => [ + 'items' => [], + 'title' => '', + 'list_type' => 'ul', + 'wrapper_attributes' => [], + 'attributes' => [], + 'empty' => NULL, + 'context' => [], + ], + ], + 'feed_icon' => [ + 'variables' => [ + 'url' => NULL, + 'title' => NULL, + 'attributes' => [], + ], + ], + 'progress_bar' => [ + 'variables' => [ + 'label' => NULL, + 'percent' => NULL, + 'message' => NULL, + ], + ], + 'indentation' => [ + 'variables' => ['size' => 1], + ], + // From theme.maintenance.inc. + 'maintenance_page' => [ + 'render element' => 'page', + ], + 'install_page' => [ + 'render element' => 'page', + ], + 'maintenance_task_list' => [ + 'variables' => [ + 'items' => NULL, + 'active' => NULL, + 'variant' => NULL, + ], + ], + 'authorize_report' => [ + 'variables' => [ + 'messages' => [], + 'attributes' => [], + ], + 'includes' => ['core/includes/theme.maintenance.inc'], + 'template' => 'authorize-report', + ], + 'pager' => [ + 'render element' => 'pager', + ], + 'menu' => [ + 'variables' => [ + 'menu_name' => NULL, + 'items' => [], + 'attributes' => [], + ], + ], + 'menu_local_task' => [ + 'render element' => 'element', + ], + 'menu_local_action' => [ + 'render element' => 'element', + ], + 'menu_local_tasks' => [ + 'variables' => [ + 'primary' => [], + 'secondary' => [], + ], + ], + // From form.inc. + 'input' => [ + 'render element' => 'element', + ], + 'select' => [ + 'render element' => 'element', + ], + 'fieldset' => [ + 'render element' => 'element', + ], + 'details' => [ + 'render element' => 'element', + ], + 'radios' => [ + 'render element' => 'element', + ], + 'checkboxes' => [ + 'render element' => 'element', + ], + 'form' => [ + 'render element' => 'element', + ], + 'textarea' => [ + 'render element' => 'element', + ], + 'form_element' => [ + 'render element' => 'element', + ], + 'form_element_label' => [ + 'render element' => 'element', + ], + 'vertical_tabs' => [ + 'render element' => 'element', + ], + 'container' => [ + 'render element' => 'element', + ], + // From field system. + 'field' => [ + 'render element' => 'element', + ], + 'field_multiple_value_form' => [ + 'render element' => 'element', + ], + 'off_canvas_page_wrapper' => [ + 'variables' => [ + 'children' => NULL, + ], + ], + 'status_report_grouped' => [ + 'variables' => [ + 'grouped_requirements' => NULL, + 'requirements' => NULL, + ], + ], + ]; + } + +} diff --git a/core/modules/system/src/Hook/ThemeHook.php b/core/modules/system/src/Hook/ThemeHook.php new file mode 100644 index 00000000000..efb5167113c --- /dev/null +++ b/core/modules/system/src/Hook/ThemeHook.php @@ -0,0 +1,138 @@ + [ + 'render element' => 'elements', + 'base hook' => 'block', + ], + 'block__system_messages_block' => [ + 'base hook' => 'block', + ], + 'block__system_menu_block' => [ + 'render element' => 'elements', + 'base hook' => 'block', + ], + 'system_themes_page' => [ + 'variables' => [ + 'theme_groups' => [], + 'theme_group_titles' => [], + ], + 'file' => 'system.admin.inc', + ], + 'system_config_form' => [ + 'render element' => 'form', + ], + 'confirm_form' => [ + 'render element' => 'form', + ], + 'system_modules_details' => [ + 'render element' => 'form', + 'file' => 'system.admin.inc', + ], + 'system_modules_uninstall' => [ + 'render element' => 'form', + 'file' => 'system.admin.inc', + ], + 'status_report_page' => [ + 'variables' => [ + 'counters' => [], + 'general_info' => [], + 'requirements' => NULL, + ], + ], + 'status_report' => [ + 'variables' => [ + 'grouped_requirements' => NULL, + 'requirements' => NULL, + ], + ], + 'status_report_counter' => [ + 'variables' => [ + 'amount' => NULL, + 'text' => NULL, + 'severity' => NULL, + ], + ], + 'status_report_general_info' => [ + 'variables' => [ + 'drupal' => [], + 'cron' => [], + 'database_system' => [], + 'database_system_version' => [], + 'php' => [], + 'php_memory_limit' => [], + 'webserver' => [], + ], + ], + 'admin_page' => [ + 'variables' => [ + 'blocks' => NULL, + ], + 'file' => 'system.admin.inc', + ], + 'admin_block' => [ + 'variables' => [ + 'block' => NULL, + 'attributes' => [], + ], + 'file' => 'system.admin.inc', + ], + 'admin_block_content' => [ + 'variables' => [ + 'content' => NULL, + ], + 'file' => 'system.admin.inc', + ], + 'system_admin_index' => [ + 'variables' => [ + 'menu_items' => NULL, + ], + 'file' => 'system.admin.inc', + ], + 'entity_add_list' => [ + 'variables' => [ + 'bundles' => [], + 'add_bundle_message' => NULL, + ], + 'template' => 'entity-add-list', + ], + 'system_security_advisories_fetch_error_message' => [ + 'file' => 'system.theme.inc', + 'variables' => [ + 'error_message' => [], + ], + ], + 'entity_page_title' => [ + 'variables' => [ + 'attributes' => [], + 'title' => NULL, + 'entity' => NULL, + 'view_mode' => NULL, + ], + ], + ]; + + return array_merge($themeCommonElements, $systemTheme); + } + +} diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 5ed2f283264..cdc25a2cc04 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -40,120 +40,6 @@ const REGIONS_VISIBLE = 'visible'; */ const REGIONS_ALL = 'all'; -/** - * Implements hook_theme(). - */ -function system_theme(): array { - return array_merge(drupal_common_theme(), [ - // Normally theme suggestion templates are only picked up when they are in - // themes. We explicitly define theme suggestions here so that the block - // templates in core/modules/system/templates are picked up. - 'block__system_branding_block' => [ - 'render element' => 'elements', - 'base hook' => 'block', - ], - 'block__system_messages_block' => [ - 'base hook' => 'block', - ], - 'block__system_menu_block' => [ - 'render element' => 'elements', - 'base hook' => 'block', - ], - 'system_themes_page' => [ - 'variables' => [ - 'theme_groups' => [], - 'theme_group_titles' => [], - ], - 'file' => 'system.admin.inc', - ], - 'system_config_form' => [ - 'render element' => 'form', - ], - 'confirm_form' => [ - 'render element' => 'form', - ], - 'system_modules_details' => [ - 'render element' => 'form', - 'file' => 'system.admin.inc', - ], - 'system_modules_uninstall' => [ - 'render element' => 'form', - 'file' => 'system.admin.inc', - ], - 'status_report_page' => [ - 'variables' => [ - 'counters' => [], - 'general_info' => [], - 'requirements' => NULL, - ], - ], - 'status_report' => [ - 'variables' => [ - 'grouped_requirements' => NULL, - 'requirements' => NULL, - ], - ], - 'status_report_grouped' => [ - 'variables' => [ - 'grouped_requirements' => NULL, - 'requirements' => NULL, - ], - ], - 'status_report_counter' => [ - 'variables' => ['amount' => NULL, 'text' => NULL, 'severity' => NULL], - ], - 'status_report_general_info' => [ - 'variables' => [ - 'drupal' => [], - 'cron' => [], - 'database_system' => [], - 'database_system_version' => [], - 'php' => [], - 'php_memory_limit' => [], - 'webserver' => [], - ], - ], - 'admin_page' => [ - 'variables' => ['blocks' => NULL], - 'file' => 'system.admin.inc', - ], - 'admin_block' => [ - 'variables' => ['block' => NULL, 'attributes' => []], - 'file' => 'system.admin.inc', - ], - 'admin_block_content' => [ - 'variables' => ['content' => NULL], - 'file' => 'system.admin.inc', - ], - 'system_admin_index' => [ - 'variables' => ['menu_items' => NULL], - 'file' => 'system.admin.inc', - ], - 'entity_add_list' => [ - 'variables' => [ - 'bundles' => [], - 'add_bundle_message' => NULL, - ], - 'template' => 'entity-add-list', - ], - 'off_canvas_page_wrapper' => [ - 'variables' => ['children' => NULL], - ], - 'system_security_advisories_fetch_error_message' => [ - 'file' => 'system.theme.inc', - 'variables' => ['error_message' => []], - ], - 'entity_page_title' => [ - 'variables' => [ - 'attributes' => [], - 'title' => NULL, - 'entity' => NULL, - 'view_mode' => NULL, - ], - ], - ]); -} - /** * Implements hook_hook_info(). */ diff --git a/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php b/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php index 76e9b232ec6..9b5a78f091b 100644 --- a/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php +++ b/core/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php @@ -21,7 +21,7 @@ class ContentNegotiationRoutingTest extends KernelTestBase { /** * {@inheritdoc} */ - protected static $modules = ['content_negotiation_test', 'path_alias']; + protected static $modules = ['content_negotiation_test', 'path_alias', 'system']; /** * {@inheritdoc}