Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
01d98fa5
Commit
01d98fa5
authored
Aug 19, 2009
by
webchick
Browse files
#400292
by effulgentsia: Allow preprocess functions for theme hooks implemented as functions.
parent
40003c83
Changes
2
Hide whitespace changes
Inline
Side-by-side
CHANGELOG.txt
View file @
01d98fa5
...
...
@@ -101,6 +101,12 @@ Drupal 7.0, xxxx-xx-xx (development version)
http://drupal.org/project/chameleon and http://drupal.org/project/pushbutton).
* Added Stark theme to make analyzing Drupal's default HTML and CSS easier.
* Added Seven theme as the default administration interface theme.
* Variable preprocessing of theme hooks prior to template rendering now goes
through two phases: a 'preprocess' phase and a new 'process' phase. See
http://api.drupal.org/api/function/theme/7 for details.
* Theme hooks implemented as functions (rather than as templates) can now
also have preprocess (and process) functions. See
http://api.drupal.org/api/function/theme/7 for details.
- File handling:
* Files are now first class Drupal objects with file_load(), file_save(),
and file_validate() functions and corresponding hooks.
...
...
includes/theme.inc
View file @
01d98fa5
...
...
@@ -313,9 +313,9 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
$result
=
array
();
$function
=
$name
.
'_theme'
;
//
Template
functions work in two distinct phases with the process
//
Processor
functions work in two distinct phases with the process
// functions always being executed after the preprocess functions.
$
template
_phases
=
array
(
$
variable_process
_phases
=
array
(
'preprocess functions'
=>
'preprocess'
,
'process functions'
=>
'process'
,
);
...
...
@@ -365,49 +365,58 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
}
// Check for sub-directories.
$result
[
$hook
][
'theme paths'
][]
=
isset
(
$info
[
'path'
])
?
$info
[
'path'
]
:
$path
;
}
foreach
(
$template_phases
as
$phase_key
=>
$template_phase
)
{
// Check for existing variable processors. Ensure arrayness.
if
(
!
isset
(
$info
[
$phase_key
])
||
!
is_array
(
$info
[
$phase_key
]))
{
$info
[
$phase_key
]
=
array
();
$prefixes
=
array
();
if
(
$type
==
'module'
)
{
// Default variable processor prefix.
$prefixes
[]
=
'template'
;
// Add all modules so they can intervene with their own variable processors. This allows them
// to provide variable processors even if they are not the owner of the current hook.
$prefixes
+=
module_list
();
}
elseif
(
$type
==
'theme_engine'
||
$type
==
'base_theme_engine'
)
{
// Theme engines get an extra set that come before the normally named variable processors.
$prefixes
[]
=
$name
.
'_engine'
;
// The theme engine registers on behalf of the theme using the theme's name.
$prefixes
[]
=
$theme
;
}
else
{
// This applies when the theme manually registers their own variable processors.
$prefixes
[]
=
$name
;
}
foreach
(
$prefixes
as
$prefix
)
{
if
(
function_exists
(
$prefix
.
'_'
.
$template_phase
))
{
$info
[
$phase_key
][]
=
$prefix
.
'_'
.
$template_phase
;
}
if
(
function_exists
(
$prefix
.
'_'
.
$template_phase
.
'_'
.
$hook
))
{
$info
[
$phase_key
][]
=
$prefix
.
'_'
.
$template_phase
.
'_'
.
$hook
;
}
}
// Allow variable processors for all theming hooks, whether the hook is
// implemented as a template or as a function.
foreach
(
$variable_process_phases
as
$phase_key
=>
$phase
)
{
// Check for existing variable processors. Ensure arrayness.
if
(
!
isset
(
$info
[
$phase_key
])
||
!
is_array
(
$info
[
$phase_key
]))
{
$info
[
$phase_key
]
=
array
();
$prefixes
=
array
();
if
(
$type
==
'module'
)
{
// Default variable processor prefix.
$prefixes
[]
=
'template'
;
// Add all modules so they can intervene with their own variable
// processors. This allows them to provide variable processors even
// if they are not the owner of the current hook.
$prefixes
+=
module_list
();
}
elseif
(
$type
==
'theme_engine'
||
$type
==
'base_theme_engine'
)
{
// Theme engines get an extra set that come before the normally
// named variable processors.
$prefixes
[]
=
$name
.
'_engine'
;
// The theme engine registers on behalf of the theme using the
// theme's name.
$prefixes
[]
=
$theme
;
}
// Check for the override flag and prevent the cached variable processors from being used.
// This allows themes or theme engines to remove variable processors set earlier in the registry build.
if
(
!
empty
(
$info
[
'override '
.
$phase_key
]))
{
// Flag not needed inside the registry.
unset
(
$result
[
$hook
][
'override '
.
$phase_key
]);
else
{
// This applies when the theme manually registers their own variable
// processors.
$prefixes
[]
=
$name
;
}
elseif
(
isset
(
$cache
[
$hook
][
$phase_key
])
&&
is_array
(
$cache
[
$hook
][
$phase_key
]))
{
$info
[
$phase_key
]
=
array_merge
(
$cache
[
$hook
][
$phase_key
],
$info
[
$phase_key
]);
foreach
(
$prefixes
as
$prefix
)
{
// Only use non-hook-specific variable processors for theming hooks
// implemented as templates. @see theme().
if
(
isset
(
$info
[
'template'
])
&&
function_exists
(
$prefix
.
'_'
.
$phase
))
{
$info
[
$phase_key
][]
=
$prefix
.
'_'
.
$phase
;
}
if
(
function_exists
(
$prefix
.
'_'
.
$phase
.
'_'
.
$hook
))
{
$info
[
$phase_key
][]
=
$prefix
.
'_'
.
$phase
.
'_'
.
$hook
;
}
}
$result
[
$hook
][
$phase_key
]
=
$info
[
$phase_key
];
}
// Check for the override flag and prevent the cached variable
// processors from being used. This allows themes or theme engines to
// remove variable processors set earlier in the registry build.
if
(
!
empty
(
$info
[
'override '
.
$phase_key
]))
{
// Flag not needed inside the registry.
unset
(
$result
[
$hook
][
'override '
.
$phase_key
]);
}
elseif
(
isset
(
$cache
[
$hook
][
$phase_key
])
&&
is_array
(
$cache
[
$hook
][
$phase_key
]))
{
$info
[
$phase_key
]
=
array_merge
(
$cache
[
$hook
][
$phase_key
],
$info
[
$phase_key
]);
}
$result
[
$hook
][
$phase_key
]
=
$info
[
$phase_key
];
}
}
...
...
@@ -418,17 +427,19 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
// Let themes have variable processors even if they didn't register a template.
if
(
$type
==
'theme'
||
$type
==
'base_theme'
)
{
foreach
(
$cache
as
$hook
=>
$info
)
{
// Check only if
it's a template and
not registered by the theme or engine.
if
(
!
empty
(
$info
[
'template'
])
&&
empty
(
$result
[
$hook
]))
{
foreach
(
$
template
_phases
as
$phase_key
=>
$
template_
phase
)
{
// Check only if not registered by the theme or engine.
if
(
empty
(
$result
[
$hook
]))
{
foreach
(
$
variable_process
_phases
as
$phase_key
=>
$phase
)
{
if
(
!
isset
(
$info
[
$phase_key
]))
{
$cache
[
$hook
][
$phase_key
]
=
array
();
}
if
(
function_exists
(
$name
.
'_'
.
$template_phase
))
{
$cache
[
$hook
][
$phase_key
][]
=
$name
.
'_'
.
$template_phase
;
// Only use non-hook-specific variable processors for theming hooks
// implemented as templates. @see theme().
if
(
isset
(
$info
[
'template'
])
&&
function_exists
(
$name
.
'_'
.
$phase
))
{
$cache
[
$hook
][
$phase_key
][]
=
$name
.
'_'
.
$phase
;
}
if
(
function_exists
(
$name
.
'_'
.
$
template_
phase
.
'_'
.
$hook
))
{
$cache
[
$hook
][
$phase_key
][]
=
$name
.
'_'
.
$
template_
phase
.
'_'
.
$hook
;
if
(
function_exists
(
$name
.
'_'
.
$phase
.
'_'
.
$hook
))
{
$cache
[
$hook
][
$phase_key
][]
=
$name
.
'_'
.
$phase
.
'_'
.
$hook
;
}
// Ensure uniqueness.
$cache
[
$hook
][
$phase_key
]
=
array_unique
(
$cache
[
$hook
][
$phase_key
]);
...
...
@@ -475,8 +486,17 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
// Finally, hooks provided by the theme itself.
_theme_process_registry
(
$cache
,
$theme
->
name
,
'theme'
,
$theme
->
name
,
dirname
(
$theme
->
filename
));
// Let modules alter the registry
// Let modules alter the registry
.
drupal_alter
(
'theme_registry'
,
$cache
);
// Optimize the registry to not have empty arrays for functions.
foreach
(
$cache
as
$hook
=>
$info
)
{
foreach
(
array
(
'preprocess functions'
,
'process functions'
)
as
$phase
)
{
if
(
empty
(
$info
[
$phase
]))
{
unset
(
$cache
[
$hook
][
$phase
]);
}
}
}
return
$cache
;
}
...
...
@@ -568,9 +588,6 @@ function list_themes($refresh = FALSE) {
* registry is checked to determine which implementation to use, which may
* be a function or a template.
*
* If the implementation is a function, it is executed and its return value
* passed along.
*
* If the implementation is a template, the arguments are converted to a
* $variables array. This array is then modified by the module implementing
* the hook, theme engine (if applicable) and the theme. The following
...
...
@@ -665,13 +682,42 @@ function list_themes($refresh = FALSE) {
* The same applies from the previous function, but it is called for a
* specific hook.
*
* There are two special variables that these hooks can set:
* If the implementation is a function, only the hook-specific preprocess
* and process functions (the ones ending in _HOOK) are called from the
* above list. There are two reasons why the non-hook-specific preprocess
* and process functions (the ones not ending in _HOOK) are not called for
* function-implemented theme hooks:
*
* - Function-implemented theme hooks need to be fast, and calling the
* non-hook-specific preprocess and process functions on them would incur
* a noticeable performance penalty.
*
* - Function-implemented theme hooks can only make use of variables
* declared as arguments within the hook_theme() function that registers
* the theme hook, and cannot make use of additional generic variables.
* For the most part, non-hook-specific preprocess and process functions
* add/modify variables other than the theme hook's arguments, variables
* that are potentially useful in template files, but unavailable to
* function implementations.
*
* For template-implemented theme hooks, there are two special variables that
* these preprocess and process functions can set:
* 'template_file' and 'template_files'. These will be merged together
* to form a list of 'suggested' alternate template files to use, in
* reverse order of priority. template_file will always be a higher
* priority than items in template_files. theme() will then look for these
* files, one at a time, and use the first one
* that exists.
* files, one at a time, and use the first one that exists. If none exists,
* theme() will use the original registered file for the theme hook.
*
* For function-implemented theme hooks, there are two special variables that
* these preprocess and process functions can set:
* 'theme_function' and 'theme_functions'. These will be merged together
* to form a list of 'suggested' alternate functions to use, in
* reverse order of priority. theme_function will always be a higher
* priority than items in theme_functions. theme() will then call the
* highest priority function that exists. If none exists, theme() will call
* the original registered function for the theme hook.
*
* @param $hook
* The name of the theme function to call. May be an array, in which
* case the first hook that actually has an implementation registered
...
...
@@ -723,18 +769,80 @@ function theme() {
}
if
(
isset
(
$info
[
'function'
]))
{
// The theme call is a function.
if
(
drupal_function_exists
(
$info
[
'function'
]))
{
// If a theme function that does not expect a renderable array is called
// with a renderable array as the only argument (via drupal_render), then
// we take the arguments from the properties of the renderable array. If
// missing, use hook_theme() defaults.
if
(
isset
(
$args
[
0
])
&&
is_array
(
$args
[
0
])
&&
isset
(
$args
[
0
][
'#theme'
])
&&
count
(
$info
[
'arguments'
])
>
1
)
{
$new_args
=
array
();
foreach
(
$info
[
'arguments'
]
as
$name
=>
$default
)
{
$new_args
[]
=
isset
(
$args
[
0
][
"#
$name
"
])
?
$args
[
0
][
"#
$name
"
]
:
$default
;
// If a theme function that does not expect a renderable array is called
// with a renderable array as the only argument (via drupal_render), then
// we take the arguments from the properties of the renderable array. If
// missing, use hook_theme() defaults.
if
(
isset
(
$args
[
0
])
&&
is_array
(
$args
[
0
])
&&
isset
(
$args
[
0
][
'#theme'
])
&&
count
(
$info
[
'arguments'
])
>
1
)
{
$new_args
=
array
();
foreach
(
$info
[
'arguments'
]
as
$name
=>
$default
)
{
$new_args
[]
=
isset
(
$args
[
0
][
"#
$name
"
])
?
$args
[
0
][
"#
$name
"
]
:
$default
;
}
$args
=
$new_args
;
}
// Invoke the variable processors, if any.
// We minimize the overhead for theming hooks that have no processors and
// are called many times per page request by caching '_no_processors'. If
// we do have processors, then the overhead of calling them overshadows the
// overhead of calling empty().
if
(
!
isset
(
$info
[
'_no_processors'
]))
{
if
(
!
empty
(
$info
[
'preprocess functions'
])
||
!
empty
(
$info
[
'process functions'
]))
{
$variables
=
array
(
'theme_functions'
=>
array
(),
);
if
(
!
empty
(
$info
[
'arguments'
]))
{
$count
=
0
;
foreach
(
$info
[
'arguments'
]
as
$name
=>
$default
)
{
$variables
[
$name
]
=
isset
(
$args
[
$count
])
?
$args
[
$count
]
:
$default
;
$count
++
;
}
}
// We don't want a poorly behaved process function changing $hook.
$hook_clone
=
$hook
;
foreach
(
array
(
'preprocess functions'
,
'process functions'
)
as
$phase
)
{
if
(
!
empty
(
$info
[
$phase
]))
{
foreach
(
$info
[
$phase
]
as
$processor_function
)
{
if
(
drupal_function_exists
(
$processor_function
))
{
$processor_function
(
$variables
,
$hook_clone
);
}
}
}
}
$args
=
$new_args
;
if
(
!
empty
(
$info
[
'arguments'
]))
{
$count
=
0
;
foreach
(
$info
[
'arguments'
]
as
$name
=>
$default
)
{
$args
[
$count
]
=
$variables
[
$name
];
$count
++
;
}
}
// Get suggestions for alternate functions out of the variables that
// were set. This lets us dynamically choose a function from a list.
// The order is FILO, so this array is ordered from least appropriate
// functions to most appropriate last.
$suggestions
=
array
();
if
(
isset
(
$variables
[
'theme_functions'
]))
{
$suggestions
=
$variables
[
'theme_functions'
];
}
if
(
isset
(
$variables
[
'theme_function'
]))
{
$suggestions
[]
=
$variables
[
'theme_function'
];
}
foreach
(
array_reverse
(
$suggestions
)
as
$suggestion
)
{
if
(
drupal_function_exists
(
$suggestion
))
{
$info
[
'function'
]
=
$suggestion
;
break
;
}
}
}
else
{
$hooks
[
$hook
][
'_no_processors'
]
=
TRUE
;
}
}
// Call the function.
if
(
drupal_function_exists
(
$info
[
'function'
]))
{
$output
=
call_user_func_array
(
$info
[
'function'
],
$args
);
}
}
...
...
@@ -774,11 +882,12 @@ function theme() {
// This construct ensures that we can keep a reference through
// call_user_func_array.
$args
=
array
(
&
$variables
,
$hook
);
// Template functions in two phases.
foreach
(
array
(
'preprocess functions'
,
'process functions'
)
as
$template_phase
)
{
foreach
(
$info
[
$template_phase
]
as
$template_function
)
{
if
(
drupal_function_exists
(
$template_function
))
{
call_user_func_array
(
$template_function
,
$args
);
foreach
(
array
(
'preprocess functions'
,
'process functions'
)
as
$phase
)
{
if
(
!
empty
(
$info
[
$phase
]))
{
foreach
(
$info
[
$phase
]
as
$processor_function
)
{
if
(
drupal_function_exists
(
$processor_function
))
{
call_user_func_array
(
$processor_function
,
$args
);
}
}
}
}
...
...
@@ -1877,7 +1986,7 @@ function template_process(&$variables, $hook) {
*
* Any changes to variables in this preprocessor should also be changed inside
* template_preprocess_maintenance_page() to keep all of them consistent.
*
*
* @see drupal_render_page
* @see template_process_page
* @see page.tpl.php
...
...
@@ -1979,8 +2088,8 @@ function template_preprocess_page(&$variables) {
/**
* Process variables for page.tpl.php
*
* Perform final addition and modification of variables before passing into
* the template. To customize these variables, call drupal_render() on elements
* Perform final addition and modification of variables before passing into
* the template. To customize these variables, call drupal_render() on elements
* in $variables['page'] during THEME_preprocess_page().
*
* @see template_preprocess_page()
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment