Recent security releases have shown that the render system needs to be stricter about what it allow to be called by a callback. See:
- https://www.drupal.org/sa-core-2018-002
- https://www.drupal.org/sa-core-2018-004
- #2860607: Code execution via Twig templates (including inline)
If you have code that adds a render callback - #access_callback, #lazy_builder, #pre_render or #post_render it might need to be updated. This will initially result in deprecation errors, but will eventually result in code throwing an exception.
Procedural function callbacks
If the callback is to a procedural function, for example, color_block_view_pre_render() you will need to move it to an object that implements \Drupal\Core\Security\TrustedCallbackInterface. For example:
class ColorBlock implements TrustedCallbackInterface {
/**
* {@inheritdoc}
*/
public static function trustedCallbacks() {
return ['preRender'];
}
/**
* #pre_render callback: Sets color preset logo.
*/
public static function preRender($build) {
// Do what the color_block_view_pre_render() function did. For the minimal change you can call the procedural function.
}
}
In core:
drupal_pre_render_links()replaced with\Drupal\Core\Render\Element\Link::preRenderLinks()color_block_view_pre_render()replaced with\Drupal\color\ColorBlock::preRender()filter_form_access_denied()replaced with\Drupal\filter\Element\TextFormat::accessDeniedCallback()history_attach_timestamp()replaced with\Drupal\history\HistoryRenderCallback::lazyBuilder()_toolbar_do_get_rendered_subtrees()replaced with\Drupal\toolbar\Controller\ToolbarController::preRenderGetRenderedSubtrees()toolbar_prerender_toolbar_administration_tray()replaced with\Drupal\toolbar\Controller\ToolbarController::preRenderAdministrationTray()views_pre_render_views_form_views_form()replaced with\Drupal\views\Form\ViewsFormMainForm::preRenderViewsForm()
Object method callbacks
If the callback is a RenderCallbackInterface object no update is necessary. Otherwise the object needs to implement \Drupal\Core\Security\TrustedCallbackInterface. For example, \Drupal\node\Plugin\Search\NodeSearch has #pre_render callback to ::removeSubmittedInfo(). You need to add TrustedCallbackInterface to NodeSearch and implement TrustedCallbackInterface::trustedCallbacks() like so:
/**
* {@inheritdoc}
*/
public static function trustedCallbacks() {
return ['removeSubmittedInfo'];
}
Anonymous function callbacks
These are not recommended because they cannot be serialized. But they do not require updating as they are trusted.
Comments
Example of what could happen with an anonymous function
Here's an example of what could happen with an anonymous function as a #pre_render callback:
RenderElementInterface or RenderCallbackInterface?
I cannot seem to find any mentions or implementations of RenderElementInterface. Was RenderCallbackInterface by chance the one that was meant instead?
Good catch, Alexandre!
Good catch, Alexandre! I've updated the change record to use the correct interface.
- John (JohnAlbin)
Help with custom.module
I'm trying to alter the commerce cart block with a custom module. I found an example here but this doesn't work with D9: https://www.drupal.org/project/commerce/issues/2880926.
I get this error:
Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function.
Here is my code:
I'm not sure how to fix this, can someone please help me?
Hi tinamrak
Step 1:- Create a folder "src" under your custom module and add a file like "OllaBlockViewBuilder.php"
Step 2:- In the "OllaBlockViewBuilder.php", Please add the below code:-
Step 3:- In your "olla_common.module" file. Please add
use Drupal\olla_common\OllaBlockViewBuilder;AND
For step 2, you can implement TrustedCallbackInterface
Here's an example using
TrustedCallbackInterfacefor step 2 below.I am following this but
I am following this but throwing this error
I think issue is already created see https://www.drupal.org/project/drupal/issues/3224723
Well, it looks strange to me
Well, it looks strange to me its working now after updating new controller namespace with the suffix as "Controller" like
I have a custom module that
I have a custom module that adds an extra field to breadcrumbs on taxonomy terms from one vocabulary. It was working in D9.1 but since upgrading to D9.2 it is throwing a similar exception to tinamrak:
Error: Call to a member function loadAllParents() on null in Drupal\breadcrumb_extra_field\Service\BreadcrumbExtraFieldBreadcrumbBuilder->build() (line 34 of modules\custom\breadcrumb_extra_field\src\Service\BreadcrumbExtraFieldBreadcrumbBuilder.php)...
...Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function.
But it is a more complex case. Below is my src\Service\BreadcrumbExtraFieldBreadcrumbBuilder.php file. Line 34 is:
$parents = $this->termStorage->loadAllParents($term->id());Can anyone please advise how I can fix this? Even a hint would be much appreciated.
(I only just got this module working in D9.1. The forum thread about it is here.)
Similar error and the cause of it
Maybe my experience can give anyone some input.
I relized the problem in 9.2.4, but after reinstalling older backups I can see the problem was there already in 9.1.x.
The error came when trying to reach the settings in the module background_image, and the error was:
Drupal\Core\Security\UntrustedCallbackException : Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was Drupal\background_image\Form\BackgroundImageForm::preRenderStates. See https://www.drupal.org/node/2966725 dans Drupal\Core\Render\Renderer->doTrustedCallback() (ligne 96 de /home/domaine.com/public_html/project/web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php).
The culprit was a Core patch used for the Core module Forums. here is the origin of that issue: https://www.drupal.org/project/drupal/issues/2010132
Same Error?
Version 9.3.14 PHP 8.0 I got the the Error:
The website encountered an unexpected error. Please try again later.
TypeError: strpos(): Argument #1 ($haystack) must be of type string, array given in strpos() (line 151 of core/lib/Drupal/Core/Utility/LinkGenerator.php).
strpos(Array, '<') (Line: 151)
Drupal\Core\Utility\LinkGenerator->generate('en', Object) (Line: 95)
Drupal\Core\Render\Element\Link::preRenderLink(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 772)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 363)