Overriding function declared in another module
Hi, I'm trying to modify the delegate_menu_admin module in such a way that the node/add/page form will show the Menu Settings for users with "administer some menus" permissions. In it's current form the module will allow users with this permission to add pages via node/add/page and subsequently link them to menu items via admin/build/menu without having full "administer menu" access. However, this two step approach is not very convenient. The problem I face is the fact that menu_alter_form() declared in menu.module (Drupal 6.2) unconditionally overwrites $form['menu']['#access'] with "user_access('administer menu')" where I want it to also honour user_access('administer some menus'). I also want to limit the presented menus in "Parent item" to the ones that the user has access to but that's just a matter of filtering out the forbidden menus. I would like to avoid having to hack the menu module itself, so I am looking for a way to unhook and redefine menu_form_alter() in delegate_menu_admin. I don't want the module to have to rely on things like PECL modules (override_function() from APD is way too intrusive). Depending on other Drupal modules is an option but I'd rather avoid that too. So the question is, how do I override menu_form_alter() from another module? Regards, Leonard. -- mount -t life -o ro /dev/dna /genetic/research
Create your own module with hook_form_alter and just reset the $form['menu']['#access'] to whatever you want. The trick is to set the weight of your module higher than the weight of the menu module so that the hook runs after menu's hook_form_alter. You do this in the system table by altering the weight column. Jamie Holly http://www.intoxination.net http://www.hollyit.net On 1/18/2011 7:22 AM, Leonard den Ottolander.nl wrote:
Hi,
I'm trying to modify the delegate_menu_admin module in such a way that the node/add/page form will show the Menu Settings for users with "administer some menus" permissions. In it's current form the module will allow users with this permission to add pages via node/add/page and subsequently link them to menu items via admin/build/menu without having full "administer menu" access. However, this two step approach is not very convenient.
The problem I face is the fact that menu_alter_form() declared in menu.module (Drupal 6.2) unconditionally overwrites $form['menu']['#access'] with "user_access('administer menu')" where I want it to also honour user_access('administer some menus'). I also want to limit the presented menus in "Parent item" to the ones that the user has access to but that's just a matter of filtering out the forbidden menus.
I would like to avoid having to hack the menu module itself, so I am looking for a way to unhook and redefine menu_form_alter() in delegate_menu_admin. I don't want the module to have to rely on things like PECL modules (override_function() from APD is way too intrusive). Depending on other Drupal modules is an option but I'd rather avoid that too.
So the question is, how do I override menu_form_alter() from another module?
Regards, Leonard.
Hello Jamie, On Tue, 2011-01-18 at 07:29 -0500, Jamie Holly wrote:
The trick is to set the weight of your module higher than the weight of the menu module so that the hook runs after menu's hook_form_alter.
Right. That did the trick. Thanks! The fact that I saw no explicit hooking confused me. I assume every module hooks to the forms using <module name>_form_alter implicitly? Regards, Leonard. -- mount -t life -o ro /dev/dna /genetic/research
Or <module name>_form_<form_id>_alter(). ----- Original Message ----- From: "Leonard den Ottolander.nl" <drupal@den.ottolander.nl> To: <development@drupal.org> Sent: Tuesday, January 18, 2011 2:16 PM Subject: Re: [development] Overriding function declared in another module Hello Jamie, On Tue, 2011-01-18 at 07:29 -0500, Jamie Holly wrote:
The trick is to set the weight of your module higher than the weight of the menu module so that the hook runs after menu's hook_form_alter.
Right. That did the trick. Thanks! The fact that I saw no explicit hooking confused me. I assume every module hooks to the forms using <module name>_form_alter implicitly? Regards, Leonard. -- mount -t life -o ro /dev/dna /genetic/research
On Tue, Jan 18, 2011 at 6:16 AM, Leonard den Ottolander.nl <drupal@den.ottolander.nl> wrote:
Hello Jamie,
On Tue, 2011-01-18 at 07:29 -0500, Jamie Holly wrote:
The trick is to set the weight of your module higher than the weight of the menu module so that the hook runs after menu's hook_form_alter.
Right. That did the trick. Thanks!
The fact that I saw no explicit hooking confused me. I assume every module hooks to the forms using <module name>_form_alter implicitly?
Exactly. Knowing how to use the hook_form_alter hooks properly makes customizing Drupal much easier. Each time a form is built, it gets sent through every hook_form_alter implementation in every active Drupal Module. And, as FGM pointed it, it also goes through a specific hook: hook_form_FORM_ID_alter. Have a look at both of these and play around with them. I personally prefer to use the second one, because it's more specific and obvious what it does, and you don't get one of those huge if/switch statements in the hook... but sometimes you need to use hook_form_alter because your changes apply across a couple of related forms, especially the node forms. -- John Fiala www.jcfiala.net
While it makes sense to prefer the for hook_form_FORM_ID_alter(), it is called before the more general hook_form_alter() so if you want to run after all other alterations you need to use hook_form_alter() . Also since CCK uses hook_form_alter(), if you want to run after it you need to use hook_form_alter(). Nevets On 1/18/2011 8:21 AM, John Fiala wrote:
On Tue, Jan 18, 2011 at 6:16 AM, Leonard den Ottolander.nl <drupal@den.ottolander.nl> wrote:
Hello Jamie,
On Tue, 2011-01-18 at 07:29 -0500, Jamie Holly wrote:
The trick is to set the weight of your module higher than the weight of the menu module so that the hook runs after menu's hook_form_alter.
Right. That did the trick. Thanks!
The fact that I saw no explicit hooking confused me. I assume every module hooks to the forms using<module name>_form_alter implicitly? Exactly. Knowing how to use the hook_form_alter hooks properly makes customizing Drupal much easier.
Each time a form is built, it gets sent through every hook_form_alter implementation in every active Drupal Module. And, as FGM pointed it, it also goes through a specific hook: hook_form_FORM_ID_alter. Have a look at both of these and play around with them. I personally prefer to use the second one, because it's more specific and obvious what it does, and you don't get one of those huge if/switch statements in the hook... but sometimes you need to use hook_form_alter because your changes apply across a couple of related forms, especially the node forms.
-- John Fiala www.jcfiala.net
On Tue, Jan 18, 2011 at 8:28 AM, Steve Ringwood <nevets@tds.net> wrote:
While it makes sense to prefer the for hook_form_FORM_ID_alter(), it is called before the more general hook_form_alter() so if you want to run after all other alterations you need to use hook_form_alter() .
Not according to http://api.drupal.org/api/drupal/modules--system--system.api.php/function/ho.... Exactly the opposite actually. Justin
Justin Not sure what you are referring to in the docs for hook_form_alter but here is the relavent code from form.inc, function drupal_prepare_form(). $data = &$form; $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form_'. $form_id, $data); << Form ID specific call // __drupal_alter_by_ref is unset in the drupal_alter() function, we need // to repopulate it to ensure both calls get the data. $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form', $data, $form_id); << General call (hook_form_alter) Nevets
Code speaks truth, you're correct. However, there's some contradicting documentation.
From http://api.drupal.org/api/drupal/modules--system--system.api.php/function/ho...: "For each module (in system weight order) the general form alter hook implementation is invoked first, then the form ID specific alter implementation is called."
From http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_fo...: "Note that this hook fires before hook_form_alter(). Therefore all implementations of hook_form_FORM_ID_alter() will run before all implementations of hook_form_alter(), regardless of the module order."
Unfortunately, Google returns the former link first, which must've been what I learned from. Sorry for any confusion, Justin On Tue, Jan 18, 2011 at 9:26 AM, Steve Ringwood <nevets@tds.net> wrote:
Justin
Not sure what you are referring to in the docs for hook_form_alter but here is the relavent code from form.inc, function drupal_prepare_form().
$data = &$form; $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form_'. $form_id, $data); << Form ID specific call
// __drupal_alter_by_ref is unset in the drupal_alter() function, we need // to repopulate it to ensure both calls get the data. $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form', $data, $form_id); << General call (hook_form_alter)
Nevets
I just filed an issue: http://drupal.org/node/1031458 The doc is only incorrect in D6. In D7 the order has changed. --Jennifer On 1/18/2011 7:37 AM, Justin Ellison wrote:
Code speaks truth, you're correct. However, there's some contradicting documentation.
From http://api.drupal.org/api/drupal/modules--system--system.api.php/function/ho...: "For each module (in system weight order) the general form alter hook implementation is invoked first, then the form ID specific alter implementation is called."
From http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_fo...: "Note that this hook fires before hook_form_alter(). Therefore all implementations of hook_form_FORM_ID_alter() will run before all implementations of hook_form_alter(), regardless of the module order."
Unfortunately, Google returns the former link first, which must've been what I learned from.
Sorry for any confusion,
Justin
On Tue, Jan 18, 2011 at 9:26 AM, Steve Ringwood<nevets@tds.net> wrote:
Justin
Not sure what you are referring to in the docs for hook_form_alter but here is the relavent code from form.inc, function drupal_prepare_form().
$data =&$form; $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form_'. $form_id, $data);<< Form ID specific call
// __drupal_alter_by_ref is unset in the drupal_alter() function, we need // to repopulate it to ensure both calls get the data. $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form', $data, $form_id);<< General call (hook_form_alter)
Nevets
-- Jennifer Hodgdon * Poplar ProductivityWare www.poplarware.com Drupal web sites and custom Drupal modules
The problem here is really important, regardless of the documentation. In Drupal 7, the problem has been resolved (and the doc may well be wrong). In D7, hook_form_alter() and hook_form_FORMID_alter() no longer compete in the inappropriate way they did in D6 - they fire in order by weight. So a given module weight will execute the form_alter and the formid_alter at about the same time. In Drupal 6, you *very* often can't achieve what you want to with hook_form_FORMID_alter() because *all* of the hook_form_alters run after all of the hook_form_FORMID_alters. That means that you *can't* alter a prepared node form successfully with hook_form_FORMID_alter() because all of the things that have built up the form (using hook_form_alter()) haven't run yet. So the form doesn't even look right yet. hook_form_alter() is often the only way around this. As a general statement, hook_form_FORM_ID_alter() in Drupal 6 is often not useful because of this and you *always* have to be aware of this problem. And in general, this problem is fixed very nicely in Drupal 7. Thanks effulgentsia and sun! -Randy On Tue, Jan 18, 2011 at 5:37 PM, Jennifer Hodgdon <yahgrp@poplarware.com>wrote:
I just filed an issue: http://drupal.org/node/1031458
The doc is only incorrect in D6. In D7 the order has changed.
--Jennifer
On 1/18/2011 7:37 AM, Justin Ellison wrote:
Code speaks truth, you're correct. However, there's some contradicting documentation.
From
http://api.drupal.org/api/drupal/modules--system--system.api.php/function/ho... :
"For each module (in system weight order) the general form alter hook implementation is invoked first, then the form ID specific alter implementation is called."
From
http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_fo... :
"Note that this hook fires before hook_form_alter(). Therefore all implementations of hook_form_FORM_ID_alter() will run before all implementations of hook_form_alter(), regardless of the module order."
Unfortunately, Google returns the former link first, which must've been what I learned from.
Sorry for any confusion,
Justin
On Tue, Jan 18, 2011 at 9:26 AM, Steve Ringwood<nevets@tds.net> wrote:
Justin
Not sure what you are referring to in the docs for hook_form_alter but here is the relavent code from form.inc, function drupal_prepare_form().
$data =&$form; $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form_'. $form_id, $data);<< Form ID specific call
// __drupal_alter_by_ref is unset in the drupal_alter() function, we need // to repopulate it to ensure both calls get the data. $data['__drupal_alter_by_ref'] = array(&$form_state); drupal_alter('form', $data, $form_id);<< General call (hook_form_alter)
Nevets
-- Jennifer Hodgdon * Poplar ProductivityWare www.poplarware.com Drupal web sites and custom Drupal modules
-- Randy Fay Drupal Module and Site Development randy@randyfay.com +1 970.462.7450
participants (8)
-
FGM -
Jamie Holly -
Jennifer Hodgdon -
John Fiala -
Justin Ellison -
Leonard den Ottolander.nl -
Randy Fay -
Steve Ringwood