Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.191 diff -u -p -r1.191 module.inc --- includes/module.inc 28 Apr 2010 12:36:26 -0000 1.191 +++ includes/module.inc 28 Apr 2010 22:57:19 -0000 @@ -852,10 +852,22 @@ function drupal_alter($type, &$data, &$c } // If any modules implement one of the extra hooks that do not implement // the primary hook, we need to add them to the $modules array in their - // appropriate order. + // appropriate order. module_implements() can only return ordered + // implementations of a single hook. To get the ordered implementations + // of multiple hooks, we mimic the module_implements() logic of first + // ordering by module_list(), and then calling + // drupal_alter('module_implements'). if (array_diff($extra_modules, $modules)) { - // Order the modules by the order returned by module_list(). + // Merge the arrays and order by module_list(). $modules = array_intersect(module_list(), array_merge($modules, $extra_modules)); + // 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); + // Let modules adjust the order solely based on the primary hook. This + // ensures the same module order regardless of whether this if block + // runs. + drupal_alter('module_implements', $implementations, $hook); + $modules = array_keys($implementations); } foreach ($modules as $module) { // Since $modules is a merged array, for any given module, we do not Index: modules/simpletest/tests/common.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v retrieving revision 1.110 diff -u -p -r1.110 common.test --- modules/simpletest/tests/common.test 22 Apr 2010 21:41:09 -0000 1.110 +++ modules/simpletest/tests/common.test 28 Apr 2010 22:57:20 -0000 @@ -57,6 +57,14 @@ class DrupalAlterTestCase extends Drupal $this->assertEqual($array_copy, $array_expected, t('First argument to drupal_alter() was altered.')); $this->assertEqual($entity_copy, $entity_expected, t('Second argument to drupal_alter() was altered.')); $this->assertEqual($array2_copy, $array2_expected, t('Third argument to drupal_alter() was altered.')); + + // Verify alteration order when passing an array of types to drupal_alter(). + // common_test_module_implements_alter() places 'block' implementation after + // other modules. + $array_copy = $array; + $array_expected = array('foo' => 'Drupal block theme'); + drupal_alter(array('drupal_alter', 'drupal_alter_foo'), $array_copy); + $this->assertEqual($array_copy, $array_expected, t('hook_TYPE_alter() implementations ran in correct order.')); } } Index: modules/simpletest/tests/common_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common_test.module,v retrieving revision 1.10 diff -u -p -r1.10 common_test.module --- modules/simpletest/tests/common_test.module 2 Mar 2010 08:47:41 -0000 1.10 +++ modules/simpletest/tests/common_test.module 28 Apr 2010 22:57:20 -0000 @@ -141,6 +141,34 @@ function garland_drupal_alter_alter(&$da } /** + * Implements hook_TYPE_alter() on behalf of block module. + * + * This is for verifying that drupal_alter(array(TYPE1, TYPE2), ...) allows + * hook_module_implements_alter() to affect the order in which module + * implementations are executed. + */ +function block_drupal_alter_foo_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) { + $data['foo'] .= ' block'; +} + +/** + * Implements hook_module_implements_alter(). + * + * @see block_drupal_alter_foo_alter() + */ +function common_test_module_implements_alter(&$implementations, $hook) { + // For drupal_alter(array('drupal_alter', 'drupal_alter_foo'), ...), make the + // block module implementations run after all the other modules. Note that + // when drupal_alter() is called with an array of types, the first type is + // considered primary and controls the module order. + if ($hook == 'drupal_alter_alter' && isset($implementations['block'])) { + $group = $implementations['block']; + unset($implementations['block']); + $implementations['block'] = $group; + } +} + +/** * Implements hook_theme(). */ function common_test_theme() {