Problem/Motivation

#2228093: Modernize theme initialization removed the ability for themes to implement system-wide alter hooks and instead limits to a certain "whitelist" due to the nature of the caching system in 8.x. This "whitelist" does not contain hook_element_info_alter().

This is a critical hook that should allow themes to alter element information before the callbacks in #process and #pre_render are invoked.

This blocks the port of Bootstrap which uses this hook to replace core (as well as other contrib) and injecting it's own additional #process and #pre_render callbacks. Bootstrap currently has > 50k installs in 7.x.

Proposed resolution

Add this alter hook back.

Remaining tasks

Create patch.
Create tests.

User interface changes

None.

API changes

Allows themes to implement hook_element_info_alter() again.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

markhalliwell’s picture

dawehner’s picture

Status: Active » Needs review
FileSize
3.08 KB

First one.

Fabianx’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Render/ElementInfoManager.php
@@ -67,7 +78,7 @@ public function getInfo($type) {
     // Get cached definitions.
-    if ($cache = $this->cacheBackend->get('element_info_build')) {
+    if ($cache = $this->cacheBackend->get('element_info_build' . $this->themeManager->getActiveTheme()->getName())) {

Missing ':', I would appreciate a $this->getCacheId() function ...

The last submitted patch, 2: 2448843-2.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
FileSize
7.34 KB
5.82 KB

No comment to the PHP error ;)

, I would appreciate a $this->getCacheId() function ...

Sure.

There we go.

tim.plunkett’s picture

+++ b/core/lib/Drupal/Core/Render/ElementInfoManager.php
@@ -119,5 +132,14 @@ public function clearCachedDefinitions() {
+    return 'element_info_build:' . $this->themeManager->getActiveTheme()
+      ->getName();

Put this on one-line please.

The issue summary should mention the caching changes too (which are essential!)

Does this still need non-unit tests?

Status: Needs review » Needs work

The last submitted patch, 5: 2448843-5.patch, failed testing.

webchick’s picture

Hm. Can you explain how this meets the definition of critical? https://www.drupal.org/node/45111

Critical bugs include those that:

Render a system unusable and have no workaround.
Cause loss of data.
Expose security vulnerabilities.
Cause tests to fail in HEAD on the automated testing platform, since this blocks all other work.

Note especially this part:

Regressions in functionality are not automatically considered critical. Even if the bug existed before, it should be prioritized according to its impact.

I find it a bit difficult to believe that it's impossible to theme at all without this being fixed, but it sounds solidly major since it falls under "Issues that have significant repercussions but do not render the whole system unusable (or have a known workaround) are marked major."

markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Issue summary: View changes
catch’s picture

I discussed this with markcarver in irc a bit.

As I understand it, these two hooks block a port of the bootstrap theme, which has > 50,000 users (which puts it in top four themes on d.o, AdaptiveTheme, Omega and Zen are above, I don't know if they also implement these hooks).

We discussed between branch maintainers last week that 1. regressions definitely aren't always critical (has been documented for a while now) 2. contributed project blockers aren't necessarily critical (is not really documented anywhere either way).

However I don't think we've sorted out what the criteria are for contributed blockers that are critical.

It's probably going to come down to a combination of how much of a blocker the blocker is, usage, and whether other projects depend on the project (so that they'd also not be able to port). So I suggested open as critical for now. I'm personally borderline on this, although if lots of themes rely on these two hooks that'd put me strongly towards keeping it a release blocker.

Wim Leers’s picture

@markcarver: could you provide (or point to) a concrete example, to clarify what exactly this enables? That makes it much easier to understand what this is about for everybody :)

tim.plunkett’s picture

Fabianx’s picture

Issue tags: +Needs backport to D7

#13: That is however only true for contrib behaving badly, but not a core limitation.

Hence this is a regression from core, but yes the fix here (add to the cache key) could and should be backported to D7.

markhalliwell’s picture

http://cgit.drupalcode.org/bootstrap/tree/includes/alter.inc#n64
http://cgit.drupalcode.org/bootstrap/tree/includes/registry.inc#n100
http://cgit.drupalcode.org/bootstrap/tree/includes/pre-render.inc
http://cgit.drupalcode.org/bootstrap/tree/includes/process.inc

These are 7.x examples because it's stable code. I know in 8.x some of this does change, especially in regards to some of the theme hook suggestion stuff in hook_theme_register_alter(), but the majority of this is still needed and doesn't work and makes the theme completely unusable.

The main reason this is important is because it allows blanket wide implementation instead of having to add, say, a .form-control class on every single input individually via hook_preprocess_HOOK()or to alter the #theme_wrappers for "fieldsets" to the custom "bootstrap_panel" theme hook. It's not perfect, but the theme system isn't to begin with. Obviously there is a lot of stuff that could be done differently, but my time is limited and having to come up with a different solution just to port to 8.x is going to be a huge PITA instead of a (more or less) direct port for all this code.

Bootstrap is an external framework that only works with markup it recognizes, core doesn't always give is needed. By replacing #process and #pre_render callbacks from core, this allows Bootstrap to not "double process" so to speak unnecessary code from core when it's not needed and/or prevent Bootstrap to affect the render array before core does and thus doesn't have a real chance to process it properly.

Re #13 and #14:
This is an entirely separate issue.

This hook does work in themes. There's like a 1% change of this happening in where something might get rendered before the theme initializes properly (because someone made the bright idea to render in hook_boot() for instance) and calls element_info() too early.

This causes the element info to become statically cached. However, this has a huge off chance of this actually happening each and every single page request as is more of a random workflow issue. As I posted in that issue, the "fix" for a theme is relatively simple: clear the static cache in template.php (when it gets initialized) and let it rebuild properly. The "real" fix would likely be to to check and see if there's an active/initialized theme in element_info() or whatever first before saving it to static cache, but again, that's an entirely different issue.

markhalliwell’s picture

Issue tags: -Needs backport to D7

There's nothing to backport from this issue, this is a 8.x issue only.

Fabianx’s picture

Issue tags: +Needs backport to D7

#16: Yes, there is, the solution in this patch is back-portable and should be back ported.

That is what I said in #14, hook_element_info_alter() worked properly for themes in D7 - except when contrib modules misbehave.

markhalliwell’s picture

I fail to see how this is back-portable. 8.x caches it in the DB, 7.x does not. The "solution" for 7.x will be entirely different and should really be addressed in #2351731: hook_element_info_alter() does not always get invoked in themes.

catch’s picture

The 7.x static cache could still key by theme name.

markhalliwell’s picture

Fabianx’s picture

We should also key the internal static cache by the active theme probably.

dawehner’s picture

FileSize
960 bytes

I tried to key by theme name, but this did not fixed the failure.

dawehner’s picture

Status: Needs work » Needs review
FileSize
6.94 KB
9.43 KB

This could be it.

Fabianx’s picture

Status: Needs review » Reviewed & tested by the community

Nice work! **RTBC** from me - if tests pass.

dawehner’s picture

Thank you for your RTBC, but I think we want to have a proper integration test first, let me work on that.

dawehner’s picture

Issue tags: -Needs tests
FileSize
10.18 KB
759 bytes

There we go.

Fabianx’s picture

Status: Reviewed & tested by the community » Needs work

Yes, that is good, but should we not check if the alter is actually called?

dawehner’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
11.83 KB
1.66 KB

Forgot the test file.

Fabianx’s picture

Back to RTBC indeed :).

catch’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed/pushed to 8.0.x, thanks!

Moving back to 7.x for the static cache fix.

  • catch committed d64047e on 8.0.x
    Issue #2448843 by dawehner: [regression] Themes unable to implement...
xjm’s picture

kumkum29’s picture

Hello,

This bug is fixed for D8.
Is there a solution for D7 ? If not, until the problem is committed to D7, should I use this patch :
https://www.drupal.org/node/2351731#comment-9701387

Thanks for your replies.

cilefen’s picture

@kumkum29 It is necessary for someone to post a patch on this issue. This is the patch by @markcarver

cilefen’s picture

I pinged @markcarver on IRC and #34 isn't a backport of what was committed to D8, so we should start from #28.

milos.kroulik’s picture

The patch mentioned in #34 didn't work for me. I tried to create node editing form using Panels. The stacktrace looks like this:

Fatal error:  Call to undefined function _bootstrap_process_element() in /var/www/myproject/includes/form.inc on line 1850, referer: http://localhost/najemce/1772/edit
Stack trace:, referer: http://localhost/najemce/1772/edit
 1. {main}() /var/www/myproject/index.php:0, referer: http://localhost/najemce/1772/edit
 2. drupal_bootstrap() /var/www/myproject/index.php:20, referer: http://localhost/najemce/1772/edit
 3. _drupal_bootstrap_full() /var/www/myproject/includes/bootstrap.inc:2262, referer: http://localhost/najemce/1772/edit
 4. menu_set_custom_theme() /var/www/myproject/includes/common.inc:5243, referer: http://localhost/najemce/1772/edit
 5. menu_get_custom_theme() /var/www/myproject/includes/menu.inc:1772, referer: http://localhost/najemce/1772/edit
 6. menu_get_item() /var/www/myproject/includes/menu.inc:1757, referer: http://localhost/najemce/1772/edit
 7. _menu_translate() /var/www/myproject/includes/menu.inc:474, referer: http://localhost/najemce/1772/edit
 8. _menu_load_objects() /var/www/myproject/includes/menu.inc:763, referer: http://localhost/najemce/1772/edit
 9. call_user_func_array() /var/www/myproject/includes/menu.inc:592, referer: http://localhost/najemce/1772/edit
10. pm_arg_load() /var/www/myproject/includes/menu.inc:592, referer: http://localhost/najemce/1772/edit
11. _pm_arg_load() /var/www/myproject/profiles/cartaro/modules/contrib/ctools/page_manager/page_manager.module:1004, referer: http://localhost/najemce/1772/edit
12. ctools_context_get_context_from_argument() /var/www/myproject/profiles/cartaro/modules/contrib/ctools/page_manager/plugins/tasks/page.inc:548, referer: http://localhost/najemce/1772/edit
13. ctools_node_edit_context() /var/www/myproject/profiles/cartaro/modules/contrib/ctools/includes/context.inc:803, referer: http://localhost/najemce/1772/edit
14. ctools_context_create() /var/www/myproject/profiles/cartaro/modules/contrib/ctools/plugins/arguments/node_edit.inc:49, referer: http://localhost/najemce/1772/edit
15. ctools_context_create_node_edit_form() /var/www/myproject/profiles/cartaro/modules/contrib/ctools/includes/context.inc:607, referer: http://localhost/najemce/1772/edit
16. drupal_build_form() /var/www/myproject/profiles/cartaro/modules/contrib/ctools/plugins/contexts/node_edit_form.inc:70, referer: http://localhost/najemce/1772/edit
17. drupal_process_form() /var/www/myproject/includes/form.inc:385, referer: http://localhost/najemce/1772/edit
18. form_builder() /var/www/myproject/includes/form.inc:885, referer: http://localhost/najemce/1772/edit
cilefen’s picture

Did you see what I wrote in #35? The patch in #34 is invalid. We must proceed with backporting #28.

cilefen’s picture

Also re #36, did you implement hook_element_info_alter()?

markhalliwell’s picture

@cilefen, #36 is part of #2156371: Fatal error: Call to undefined function _bootstrap_process_element() (where I'm redirecting people to this issue... which should have fixed it). Regardless, it could be that #36 is still our issue after all (sigh).

Also, FWIW, yes... Bootstrap most definitely uses hook_element_info_alter() (which is why i created this issue): http://cgit.drupalcode.org/bootstrap/tree/includes/alter.inc#n75

  • catch committed d64047e on 8.1.x
    Issue #2448843 by dawehner: [regression] Themes unable to implement...
_San_’s picture

Is there a D7 patch for this?

cilefen’s picture

See #33.

ClimbingUpTheWalls’s picture

Ok so #33 redirect at the end to this issue and has the same patch as #34. So there's no fix for this issue ?
Cause I applied the patch and same problem.
I am using a custom layout with DisplaySuite on user and node displays and now I'm having the Call to undefined function _bootstrap_process_element... on my node displays but not on the user ones everytime I try to place a field on a region of the display. Any help on this ?

Thank you

terribeausejour’s picture

I have just encountered this issue, it occurs when I submit a form inside a block. I am using bootstrap theme. I followed other threads and per recommendation, set my admin theme to match my main bootstrap derived custom theme. This error goes away for a while, then recurs after I clear caches, browser history, etc. But even when the error does not occur, it seems that ajax/javascript fails silently and my form submit callback never gets called.

I am on Drupal 8.0.5. The whole patch history here is pretty confusing, it is unclear to me at this point if this is or is not fixed in Drupal 8.0.X. Any help would be enormously appreciated, this is the only item that is blocking the launch of my site.

My call stack is below:

Warning: call_user_func_array() expects parameter 1 to be a valid callback, function 'bootstrap_form_process' not found or invalid function name in Drupal\Core\Form\FormBuilder->doBuildForm() (line 984 of core/lib/Drupal/Core/Form/FormBuilder.php).

Drupal\Core\Form\FormBuilder->doBuildForm('donate_form_vehicle', Array, Object) (Line: 560)
Drupal\Core\Form\FormBuilder->processForm('donate_form_vehicle', Array, Object) (Line: 319)
Drupal\Core\Form\FormBuilder->buildForm('Drupal\donate\Form\DonateFormVehicle', Object) (Line: 217)
Drupal\Core\Form\FormBuilder->getForm('Drupal\donate\Form\DonateFormVehicle') (Line: 34)
Drupal\donate\Plugin\Block\DonateBlock->build() (Line: 116)
Drupal\panels\Plugin\DisplayBuilder\StandardDisplayBuilder->buildRegions(Array, Array) (Line: 133)
Drupal\panels\Plugin\DisplayBuilder\StandardDisplayBuilder->build(Object) (Line: 281)
Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant->build() (Line: 34)
Drupal\page_manager\Entity\PageVariantViewBuilder->view(Object, 'full') (Line: 101)
Drupal\Core\Entity\Controller\EntityViewController->view(Object, 'full')
call_user_func_array(Array, Array) (Line: 128)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 577)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 129)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 102)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array) (Line: 139)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 62)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 62)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 103)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 55)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 637)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Thanks to all for tackling this painful ongoing issue!

terribeausejour’s picture

Version: 7.x-dev » 8.0.5

I was able to resolve this by updating to the latest Drupal Bootstrap theme. This was a painful choice however, the theme update has caused a lot of layout problems. But I did want to report that the issue is resolved for me in 8.0.5 by updating to the latest Bootstrap module in case it helps someone else.

catch’s picture

Version: 8.0.5 » 7.x-dev

This was fixed in 8.0.x, moving back to 7.x

terribeausejour’s picture

@catch -- my apologies -- I thought the version would only pertain to my comment. Thank you for fixing it.

However, I do have an issue I need help with. I am on Drupal 8.0.5 but my site was built on a prior version of the Bootstrap module that has the bug. I attempted to update my bootstrap theme, but that was a disaster, the navbar collapse broke and all my template overrides would have to be redone. So I had to revert to my originally installed Bootstrap module/theme.

The less invasive solution for this site would be for me to patch my Bootstrap theme with the specific fix for this issue. Is there an existing patch for Bootstrap 8.x-3.0-alpha1 to fix this issue? Or if not, could one be provided?

This is causing my multi-part form to be completely unusable and I am unable to launch my site as a result. A fix would be greatly appreciated. Thank you.

terribeausejour’s picture

@catch, @markcarver I just read through this history again carefully to see if I could possibly decipher how to apply a patch or series of patches to resolve this issue without having to update Bootstrap on my existing site, but given the comments in #36, #39 and #43, I don't see a clear path. I have updated core, so I only need the part that would apply to bootstrap. Please advise, and thank you for your efforts on this.

David_Rothstein’s picture

Version: 7.x-dev » 8.0.x-dev
Status: Patch (to be ported) » Fixed
Issue tags: -Needs backport to D7

I don't think it makes sense to keep this open for Drupal 7 - first because it's not the same bug (this was a critical problem in Drupal 8 but is only triggered in edge cases in Drupal 7), plus there is debate about the best fix for Drupal 7 - with the latest patch here literally not even being a backport at all (and none of the possible other solutions really looking like an actual backport either).

I will reopen #2351731: hook_element_info_alter() does not always get invoked in themes instead, with a pointer to this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.