diff options
author | Angie Byron <webchick@24967.no-reply.drupal.org> | 2010-03-21 04:05:24 +0000 |
---|---|---|
committer | Angie Byron <webchick@24967.no-reply.drupal.org> | 2010-03-21 04:05:24 +0000 |
commit | 426f82ac6dc41caa09d98168a40c96b677223831 (patch) | |
tree | 4757b41b8ab36091bd3df6602cf0150316fe9bbe | |
parent | e6bdfc8a2e83ed0c289bab4b589e20c06fad26e8 (diff) | |
download | brdo-426f82ac6dc41caa09d98168a40c96b677223831.tar.gz brdo-426f82ac6dc41caa09d98168a40c96b677223831.tar.bz2 |
#241570 by effulgentsia and merlinofchaos: Fixed Theme preprocess functions do not get retained when using patterns.
-rw-r--r-- | includes/theme.inc | 93 | ||||
-rw-r--r-- | modules/simpletest/tests/theme.test | 17 | ||||
-rw-r--r-- | modules/simpletest/tests/theme_test.info | 8 | ||||
-rw-r--r-- | modules/simpletest/tests/theme_test.module | 40 | ||||
-rw-r--r-- | themes/tests/test_theme/template.php | 11 | ||||
-rw-r--r-- | themes/tests/test_theme/test_theme.info | 6 |
6 files changed, 137 insertions, 38 deletions
diff --git a/includes/theme.inc b/includes/theme.inc index 6f436df02..f5812999f 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -382,15 +382,14 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) { $result[$hook]['includes'][] = $include_file; } - // If 'variables' have been defined previously, carry them forward. - // This should happen if a theme overrides a Drupal defined theme - // function, for example. - if (!isset($info['variables']) && isset($cache[$hook]['variables'])) { - $result[$hook]['variables'] = $cache[$hook]['variables']; - } - // Same for 'render element'. - if (!isset($info['render element']) && isset($cache[$hook]['render element'])) { - $result[$hook]['render element'] = $cache[$hook]['render element']; + // If these keys are left unspecified within overridden entries returned + // by hook_theme(), carry them forward from the prior entry. This is so + // that themes don't need to specify this information, since the module + // that registered the theme hook already has. + foreach (array('variables', 'render element', 'pattern', 'base hook') as $key) { + if (!array_key_exists($key, $info) && isset($cache[$hook][$key])) { + $result[$hook][$key] = $cache[$hook][$key]; + } } // The following apply only to theming hooks implemented as templates. @@ -837,7 +836,19 @@ function theme($hook, $variables = array()) { } // Invoke the variable processors, if any. The processors may specify - // alternate suggestions for which hook's template/function to use. + // alternate suggestions for which hook's template/function to use. If the + // hook is a suggestion of a base hook, invoke the variable processors of + // the base hook, but retain the suggestion as a high priority suggestion to + // be used unless overridden by a variable processor function. + if (isset($info['base hook'])) { + $base_hook = $info['base hook']; + $base_hook_info = $hooks[$base_hook]; + if (isset($base_hook_info['preprocess functions']) || isset($base_hook_info['process functions'])) { + $variables['theme_hook_suggestion'] = $hook; + $hook = $base_hook; + $info = $base_hook_info; + } + } if (isset($info['preprocess functions']) || isset($info['process functions'])) { $variables['theme_hook_suggestions'] = array(); foreach (array('preprocess functions', 'process functions') as $phase) { @@ -960,44 +971,53 @@ function path_to_theme() { * @param $prefixes * An array of prefixes to test, in reverse order of importance. * - * @return $templates + * @return $implementations * The functions found, suitable for returning from hook_theme; */ function drupal_find_theme_functions($cache, $prefixes) { - $templates = array(); + $implementations = array(); $functions = get_defined_functions(); foreach ($cache as $hook => $info) { foreach ($prefixes as $prefix) { + // Find theme functions that implement possible "suggestion" variants of + // registered theme hooks and add those as new registered theme hooks. + // The 'pattern' key defines a common prefix that all suggestions must + // start with. The default is the name of the hook followed by '__'. An + // 'base hook' key is added to each entry made for a found suggestion, + // so that common functionality can be implemented for all suggestions of + // the same base hook. To keep things simple, deep heirarchy of + // suggestions is not supported: each suggestion's 'base hook' key + // refers to a base hook, not to another suggestion, and all suggestions + // are found using the base hook's pattern, not a pattern from an + // intermediary suggestion. $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__'); - if (!empty($pattern)) { + if (!isset($info['base hook']) && !empty($pattern)) { $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $functions['user']); if ($matches) { foreach ($matches as $match) { $new_hook = str_replace($prefix . '_', '', $match); $arg_name = isset($info['variables']) ? 'variables' : 'render element'; - $templates[$new_hook] = array( + $implementations[$new_hook] = array( 'function' => $match, $arg_name => $info[$arg_name], + 'base hook' => $hook, ); } } } + // Find theme functions that implement registered theme hooks and include + // that in what is returned so that the registry knows that the theme has + // this implementation. if (function_exists($prefix . '_' . $hook)) { - $templates[$hook] = array( + $implementations[$hook] = array( 'function' => $prefix . '_' . $hook, ); - // Ensure that the pattern is maintained from base themes to its sub-themes. - // Each sub-theme will have their functions scanned so the pattern must be - // held for subsequent runs. - if (isset($info['pattern'])) { - $templates[$hook]['pattern'] = $info['pattern']; - } } } } - return $templates; + return $implementations; } /** @@ -1011,7 +1031,7 @@ function drupal_find_theme_functions($cache, $prefixes) { * The path to search. */ function drupal_find_theme_templates($cache, $extension, $path) { - $templates = array(); + $implementations = array(); // Collect paths to all sub-themes grouped by base themes. These will be // used for filtering. This allows base themes to have sub-themes in its @@ -1034,9 +1054,12 @@ function drupal_find_theme_templates($cache, $extension, $path) { // Escape the periods in the extension. $regex = '/' . str_replace('.', '\.', $extension) . '$/'; - // Because drupal_system_listing works the way it does, we check for real - // templates separately from checking for patterns. + // Get a listing of all template files in the path to search. $files = drupal_system_listing($regex, $path, 'name', 0); + + // Find templates that implement registered theme hooks and include that in + // what is returned so that the registry knows that the theme has this + // implementation. foreach ($files as $template => $file) { // Ignore sub-theme templates for the current theme. if (strpos($file->uri, str_replace($subtheme_paths, '', $file->uri)) !== 0) { @@ -1052,24 +1075,21 @@ function drupal_find_theme_templates($cache, $extension, $path) { // for the purposes of searching. $hook = strtr($template, '-', '_'); if (isset($cache[$hook])) { - $templates[$hook] = array( + $implementations[$hook] = array( 'template' => $template, 'path' => dirname($file->uri), ); } - // Ensure that the pattern is maintained from base themes to its sub-themes. - // Each sub-theme will have their templates scanned so the pattern must be - // held for subsequent runs. - if (isset($cache[$hook]['pattern'])) { - $templates[$hook]['pattern'] = $cache[$hook]['pattern']; - } } + // Find templates that implement possible "suggestion" variants of registered + // theme hooks and add those as new registered theme hooks. @see + // drupal_find_theme_functions() for more information about suggestions and + // the use of 'pattern' and 'base hook'. $patterns = array_keys($files); - foreach ($cache as $hook => $info) { $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__'); - if (!empty($pattern)) { + if (!isset($info['base hook']) && !empty($pattern)) { // Transform _ in pattern to - to match file naming scheme // for the purposes of searching. $pattern = strtr($pattern, '_', '-'); @@ -1080,16 +1100,17 @@ function drupal_find_theme_templates($cache, $extension, $path) { $file = substr($match, 0, strpos($match, '.')); // Put the underscores back in for the hook name and register this pattern. $arg_name = isset($info['variables']) ? 'variables' : 'render element'; - $templates[strtr($file, '-', '_')] = array( + $implementations[strtr($file, '-', '_')] = array( 'template' => $file, 'path' => dirname($files[$match]->uri), $arg_name => $info[$arg_name], + 'base hook' => $hook, ); } } } } - return $templates; + return $implementations; } /** diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test index d3ba6f9bb..631d69d5b 100644 --- a/modules/simpletest/tests/theme.test +++ b/modules/simpletest/tests/theme.test @@ -9,15 +9,20 @@ /** * Unit tests for the Theme API. */ -class TemplateUnitTest extends DrupalWebTestCase { +class ThemeUnitTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Theme API', - 'description' => 'Test low-level theme template functions.', + 'description' => 'Test low-level theme functions.', 'group' => 'Theme', ); } + function setUp() { + parent::setUp('theme_test'); + theme_enable(array('test_theme')); + } + /** * Test function theme_get_suggestions() for SA-CORE-2009-003. */ @@ -39,6 +44,14 @@ class TemplateUnitTest extends DrupalWebTestCase { $suggestions = theme_get_suggestions($args, 'page'); $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), t('Removed invalid \\0 from suggestions')); } + + /** + * Preprocess functions for the base hook should run even for suggestion implementations. + */ + function testPreprocessForSuggestions() { + $this->drupalGet('theme-test/suggestion'); + $this->assertText('test_theme_breadcrumb__suggestion: 1', t('Theme hook suggestion ran with data available from a preprocess function for the base hook.')); + } /** * Ensure page-front template suggestion is added when on front page. diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info new file mode 100644 index 000000000..2a35cad76 --- /dev/null +++ b/modules/simpletest/tests/theme_test.info @@ -0,0 +1,8 @@ +; $Id$ +name = "Theme test" +description = "Support module for theme system testing." +package = Testing +version = VERSION +core = 7.x +files[] = theme_test.module +hidden = TRUE diff --git a/modules/simpletest/tests/theme_test.module b/modules/simpletest/tests/theme_test.module new file mode 100644 index 000000000..52359778f --- /dev/null +++ b/modules/simpletest/tests/theme_test.module @@ -0,0 +1,40 @@ +<?php +// $Id$ + +/** + * Implements hook_menu(). + */ +function theme_test_menu() { + $items['theme-test/suggestion'] = array( + 'title' => 'Suggestion', + 'page callback' => '_theme_test_suggestion', + 'access arguments' => array('access content'), + 'theme callback' => '_theme_custom_theme', + 'type' => MENU_CALLBACK, + ); + + return $items; +} + +/** + * Custom theme callback. + */ +function _theme_custom_theme() { + return 'test_theme'; +} + +/** + * Page callback, calls a theme hook suggestion. + */ +function _theme_test_suggestion() { + return theme(array('breadcrumb__suggestion', 'breadcrumb'), array()); +} + +/** + * Implements hook_preprocess_breadcrumb(). + * + * Set a variable that can later be tested to see if this function ran. + */ +function theme_test_preprocess_breadcrumb(&$variables) { + $variables['theme_test_preprocess_breadcrumb'] = 1; +} diff --git a/themes/tests/test_theme/template.php b/themes/tests/test_theme/template.php new file mode 100644 index 000000000..944c23690 --- /dev/null +++ b/themes/tests/test_theme/template.php @@ -0,0 +1,11 @@ +<?php +// $Id$ + +/** + * Tests a theme overriding a suggestion of a base theme hook. + */ +function test_theme_breadcrumb__suggestion($variables) { + // Tests that preprocess functions for the base theme hook get called even + // when the suggestion has an implementation. + return 'test_theme_breadcrumb__suggestion: ' . $variables['theme_test_preprocess_breadcrumb']; +} diff --git a/themes/tests/test_theme/test_theme.info b/themes/tests/test_theme/test_theme.info new file mode 100644 index 000000000..853a501b5 --- /dev/null +++ b/themes/tests/test_theme/test_theme.info @@ -0,0 +1,6 @@ +; $Id$ +name = Test theme +description = Theme for testing the theme system +core = 7.x +engine = phptemplate +hidden = TRUE
\ No newline at end of file |