The new hook_custom theme that went into core by http://drupal.org/node/553944#comment-2415492 does not work as expected.
Due to the fact that the reopened issue #553944: Define hook_menu_get_item_alter() as a reliable hook that runs before the page is doomed now discusses a different issue I decided to open a new issue.
drupal_theme_initialize() calls menu_get_custom_theme() without parameters. This causes menu_get_custom_theme() to not fire hook_custom_theme().
Later in the bootstrap menu_set_custom_theme() calls menu_set_custom_theme(TRUE) which fires hook_custom_theme(). But now it's too late because the default theme has already been initialized.
The attached patch gets any module implementing hook_custom_theme() to work but I'm convinced that this breaks something else.
| Comment | File | Size | Author |
|---|---|---|---|
| #16 | drupal-hook_custom_theme_issues-943616-16.patch | 2.08 KB | jojonaloha |
| #16 | drupal-backtrace-943616-16.txt | 6.57 KB | jojonaloha |
| hook_custom_theme_fix.patch | 672 bytes | mkalkbrenner |
Comments
Comment #1
chx commentedSo what's the intent here? If drupal_theme_initialize is called, why does it call menu_get_custom_theme with $initialize FALSE? So the patch seems correct I set it to CNR so that the bot can judge it -- but if it goes through (should) then the call in full bootstrap needs to be removed.
Comment #2
hass commented+
Comment #4
David_Rothstein commentedWe have tests in core that verify that hook_custom_theme() works. As far as I know, those tests pass. Do you have an example of an implementation of this hook that proves it doesn't work?
Also, http://api.drupal.org/api/function/_drupal_bootstrap_full/7 calls menu_set_custom_theme() before it calls drupal_theme_initialize(), so there is no problem there. Is there somewhere else in the bootstrap where drupal_theme_initialize() is called earlier?
Comment #5
chx commentedI felt this was not critical, sorry for not checking for those tests.
Comment #6
mkalkbrennerI tried it with a small test module that simply implements hook_custom_theme():
To my surprise it now worked like expected on a fresh drupal 7 installation. As I had a deeper look at the previous setup I found a different module that created a message containing a link created by l() before hook_custom_theme() of our module got called. This already initialized the theme engine using the default theme.
Unfortunately my debugging around the two calls of menu_set_custom_theme() lead my to the wrong solution I posted as a patch. Please excuse the confusion ...
Comment #7
David_Rothstein commentedHm, that is a bit unfortunate that merely calling l() results in the theme system being initialized, but yeah, there isn't much we can do about that :( At least the list of hooks that can run before hook_custom_theme() is pretty limited.
Comment #8
hass commentedWas in one of t'ified strings in the l() functions a % theme placeholder? This would explain the theme init as I know.
Comment #9
David_Rothstein commentedNo, it's actually l() itself: http://api.drupal.org/api/function/l/7
In Drupal 7, % placeholders no longer trigger the theme system.
Comment #10
alan d. commentedActually %wildcard may trigger the theme system, and this does cause issues. This would be mainly be limited to the entity system loads triggering themed output.
It is a complete chicken and egg thing going on here, with the menu potentially defining the theme but the theme may need to be invoked before defining the active menu item.
This strongly suggests that entity_load() should never invoke the theme layer, and this makes more sense as the entity load is cached independently of the theme anyway.
So some of the limitations / wtf with hook_custom_theme(), all by design.
Comment #11
David_Rothstein commentedIt sounds like you're talking about the use of % in menu wildcards. Above we were talking about t() % placeholders, which don't trigger the theme system.
If you're choosing the theme based on the menu item, it's probably best not to use hook_custom_theme() at all, but rather to use the 'theme callback' property in hook_menu().... However, I'm guessing this problem would occur with that too.
I think you're right that a module which intentionally triggers the theme system during entity_load() is probably doing something wrong, but with l() doing it by default I guess there are ways it can happen by accident too...
For Drupal 8 and beyond, I would think something like #981654: Use several themes during the same page request is the way to handle these kinds of issues once and for all.
Comment #12
agentrickardThis has to be fixable, as it poses several nasty problems for context modules (og, context, domain access).
Looking into this for a site now. Perhaps it's not fixable, but if so I need a suitable workaround. If I find a patch that works, I'll post here.
Comment #13
agentrickardThere is an l() in system_token_info() -- $date['custom'] -- that can get called very early in the load process and may cause part of this issue, however, removing that still throws a problem when certain filters run and implement tokens.
In my case, the culprit may be media_filter and media_token_to_markup().
Comment #14
agentrickardBut even if I eliminate that, the l() in system_token_info() still causes the problem. Both need to be fixed.
Comment #15
agentrickardThis solution "fixes" the problem in a custom module. Nothing else I did could solve the race condition.
What has been happening is that on cache clear, the theme gets initialized twice, but one of the passes doesn't invoke hook_custom_theme(). I think that's related to the l() function in system_token_info(), but there were also calls coming from contrib that made the problem unpredictable.
I'm going to mark this "won't fix", which is more accurate than "works as designed."
Comment #16
jojonaloha commentedI am coming to this issue from #2147409: Interaction with Context OG. I think agentrickard is right about
l()causing part of the problem with somehook_custom_theme()implementations.From what I can tell the problem is that any implementation that calls a function that might end up calling
drupal_theme_initialize()will cause the default theme to be displayed instead of the custom theme. Sincedrupal_theme_initialize()callsmenu_get_custom_theme()without the$initializeparameter (and for good reason because otherwise we would end up in an infinite loop), the theme that gets initialized will always be NULL because ourhook_custom_theme()has not returned yet.Attached is a backtrace for one case where this was an issue for me. My
hook_custom_theme()implementation is very much like the one inog_theme_custom_theme(), callingog_context()which after a cache-clear (like when saving a View, Node, etc), the theme is not properly set on the next page load.I'm also attaching a patch that so far resolves this for me, but I think there might be other places where
drupal_theme_initialize()might be called at an inappropriate time.Comment #17
pragna commentedWe can also change theme of existing path of core module using below code :
function custom_menu_alter(&$items) {
$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/add']['theme callback'] = 'norden_core_default_term_theme';
$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/add']['theme arguments'] = array(3);
}
function custom_default_term_theme($v_name) {
return variable_get('theme_default', '0');
}
Comment #18
cilefen commentedIt seems this is a duplicate of #2086335: Bootstrap issue with theme initialization causes hook_custom_theme() never to be invoked.
Comment #19
alan d. commentedThat is just one of many possible trigger for these symptoms. Short solution, never call a theming function before the menu system has initialised :(
Comment #20
hermes_costell commentedTo add to what pragna said above in comment #17:
Let's say you want your theme to kick in for users who are editing a certain type of node, but want the normal (admin) theme to display otherwise.
Comment #21
chasingmaxwell commentedFor anyone who is considering using agentrickard's workaround in #15, you may also need to call
drupal_static_reset('theme_get_registry');so the theme registry can be rebuilt. Without that, I was running into an issue on certain pages where some of the content would get rendered with the default theme while other content would use the custom theme.So the workaround I implemented looked something like this:
Comment #22
jojonaloha commentedI was running into this again recently but the previous patch alone wasn't working, nor did the one in #2086335: Bootstrap issue with theme initialization causes hook_custom_theme() never to be invoked. I found I also needed the patch in #1814516: Subpathauto causing admin pages to appear in default theme and had to update my implementation of hook_custom_theme() to not use menu_get_object(); otherwise the callstack looked something like node_load() => text_field_load() => check_markup() => media_wysiwyg_filter() => media_wysiwyg_token_to_markup() => drupal_theme_initialize()
Comment #23
hanskuiters commentedThis issue about DA and AMP is related: #2909926: Domain access and amp doesn't work!
Comment #24
mrweiner commentedI had a similar issue as #22. Instead of using node_load, I queried the database directly to check my condition: