Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.1145 diff -u -p -r1.1145 common.inc --- includes/common.inc 7 Apr 2010 17:30:43 -0000 1.1145 +++ includes/common.inc 8 Apr 2010 18:35:04 -0000 @@ -4634,8 +4634,13 @@ function drupal_system_listing($mask, $d * (optional) An additional variable that is passed by reference. If more * context needs to be provided to implementations, then this should be an * keyed array as described above. + * @param $ids + * (optional) An array of ids for executing specific implementations in + * addition to generic ones. For example, to execute both hook_form_alter() + * and hook_form_FORM_ID_alter() functions, pass 'form' as $type and + * array(FORM_ID) as $ids. */ -function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) { +function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, $ids = array()) { // Use the advanced drupal_static() pattern, since this is called very often. static $drupal_static_fast; if (!isset($drupal_static_fast)) { @@ -4646,11 +4651,50 @@ function drupal_alter($type, &$data, &$c // Some alter hooks are invoked many times per page request, so statically // cache the list of functions to call, and on subsequent calls, iterate // through them quickly. - if (!isset($functions[$type])) { - $functions[$type] = array(); + $cid = empty($ids) ? $type : ($type . ':' . implode(',', $ids)); + if (!isset($functions[$cid])) { + $functions[$cid] = array(); $hook = $type . '_alter'; - foreach (module_implements($hook) as $module) { - $functions[$type][] = $module . '_' . $hook; + $modules = module_implements($hook); + if (empty($ids)) { + foreach ($modules as $module) { + $functions[$cid][] = $module . '_' . $hook; + } + } + else { + $modules_with_id_implementations = array(); + foreach ($ids as $id) { + $modules_with_id_implementations = array_merge($modules_with_id_implementations, module_implements($type . '_' . $id . '_alter')); + } + // If any modules implement an id-specific hook that do not implement the + // generic hook, we need to add them to the $modules array in their + // appropriate order. + if (array_diff($modules_with_id_implementations, $modules)) { + // Order the modules by the order returned by module_list(). + $modules = array_intersect(module_list(), array_merge($modules, $modules_with_id_implementations)); + // @todo Uncomment the remaining code lines when + // http://drupal.org/node/692950 lands. + // Since the order of $modules has been reset from what was earlier + // returned by module_implements($hook), we need to re-invoke + // hook_module_implements_alter() to get the desired order. Since + // module_implements() already took care of loading the necessary + // include files, we can safely pass FALSE for the array values. + //$implementations = array_fill_keys($modules, FALSE); + //drupal_alter('module_implements', $implementations, $hook, $ids); + //$modules = array_keys($implementations); + } + foreach ($modules as $module) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + $functions[$cid][] = $function; + } + foreach ($ids as $id) { + $function = $module . '_' . $type . '_' . $id . '_alter'; + if (function_exists($function)) { + $functions[$cid][] = $function; + } + } + } } // Allow the theme to alter variables after the theme system has been // initialized. @@ -4664,12 +4708,18 @@ function drupal_alter($type, &$data, &$c foreach ($theme_keys as $theme_key) { $function = $theme_key . '_' . $hook; if (function_exists($function)) { - $functions[$type][] = $function; + $functions[$cid][] = $function; + } + foreach ($ids as $id) { + $function = $theme_key . '_' . $type . '_' . $id . '_alter'; + if (function_exists($function)) { + $functions[$cid][] = $function; + } } } } } - foreach ($functions[$type] as $function) { + foreach ($functions[$cid] as $function) { $function($data, $context1, $context2); } } Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.449 diff -u -p -r1.449 form.inc --- includes/form.inc 7 Apr 2010 04:39:59 -0000 1.449 +++ includes/form.inc 8 Apr 2010 18:35:05 -0000 @@ -761,11 +761,8 @@ function drupal_prepare_form($form_id, & } } - // Invoke hook_form_FORM_ID_alter() implementations. - drupal_alter('form_' . $form_id, $form, $form_state); - - // Invoke hook_form_alter() implementations. - drupal_alter('form', $form, $form_state, $form_id); + // Invoke hook_form_alter() and hook_form_FORM_ID_alter() implementations. + drupal_alter('form', $form, $form_state, $form_id, array($form_id)); } Index: includes/database/select.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/database/select.inc,v retrieving revision 1.34 diff -u -p -r1.34 select.inc --- includes/database/select.inc 17 Feb 2010 05:24:53 -0000 1.34 +++ includes/database/select.inc 8 Apr 2010 18:35:06 -0000 @@ -1069,10 +1069,8 @@ class SelectQuery extends Query implemen // Modules may alter all queries or only those having a particular tag. if (isset($this->alterTags)) { - drupal_alter('query', $query); - foreach ($this->alterTags as $tag => $value) { - drupal_alter("query_$tag", $query); - } + $null = NULL; + drupal_alter('query', $query, $null, $null, array_keys($this->alterTags)); } return $this->prepared = TRUE; } Index: modules/block/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.module,v retrieving revision 1.415 diff -u -p -r1.415 block.module --- modules/block/block.module 28 Mar 2010 11:16:29 -0000 1.415 +++ modules/block/block.module 8 Apr 2010 18:35:06 -0000 @@ -740,8 +740,8 @@ function _block_render_blocks($region_bl // Allow modules to modify the block before it is viewed, via either // hook_block_view_MODULE_DELTA_alter() or hook_block_view_alter(). - drupal_alter("block_view_{$block->module}_{$block->delta}", $array, $block); - drupal_alter('block_view', $array, $block); + $null = NULL; + drupal_alter('block_view', $array, $block, $null, array($block->module . '_' . $block->delta)); if (isset($cid)) { cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);