summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAngie Byron2010-03-21 04:05:24 (GMT)
committerAngie Byron2010-03-21 04:05:24 (GMT)
commit426f82ac6dc41caa09d98168a40c96b677223831 (patch)
tree4757b41b8ab36091bd3df6602cf0150316fe9bbe
parente6bdfc8a2e83ed0c289bab4b589e20c06fad26e8 (diff)
#241570 by effulgentsia and merlinofchaos: Fixed Theme preprocess functions do not get retained when using patterns.
-rw-r--r--includes/theme.inc93
-rw-r--r--modules/simpletest/tests/theme.test17
-rw-r--r--modules/simpletest/tests/theme_test.info8
-rw-r--r--modules/simpletest/tests/theme_test.module40
-rw-r--r--themes/tests/test_theme/template.php11
-rw-r--r--themes/tests/test_theme/test_theme.info6
6 files changed, 137 insertions, 38 deletions
diff --git a/includes/theme.inc b/includes/theme.inc
index 6f436df..f581299 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 d3ba6f9..631d69d 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 0000000..2a35cad
--- /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 0000000..5235977
--- /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 0000000..944c236
--- /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 0000000..853a501
--- /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