Score:1

What is the new methodology for Form Pre-Render in order to utilize TrustedCallbackInterface

cn flag

We are upgrading our sites one at a time from Drupal 8 to Drupal 9 and there is one line of code in our custom theme that is the last of our problems.

We get the following error on View that uses an exposed filter:

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 MYSITE_form_alter_views_exposed_form_MYVIEW_pre_render. See https://www.drupal.org/node/2966725 in Drupal\Core\Render\Renderer->doTrustedCallback() (line 96 of core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php).

In the OURTHEME.theme file, we have this function:

/**
 * Custom form alter for events.
 */
function OURTHEME_form_alter_views_exposed_form_events_pre_render($form) {
  $fields = [
    'field_start_date_value',
    'field_end_date_value',
    'field_address_locality',
  ];
  foreach ($fields as $field) {
    $form[$field]['#title_display'] = 'after';
  }
  $form['field_date_range_end_value']['#prefix'] = '<div class="event-exposed-form">';
  $form['field_event_address_locality']['#suffix'] = '</div>';
  return $form;
}

And the function is called here (just a snippet of the code in this function):

/**
 * These are the alterations to forms variables before they are rendered.
 */
function OURTHEME_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-events-') === 0) {
    $form['#pre_render'][] = 'OURTHEME_form_alter_views_exposed_form_events_pre_render';
  }
  return $form;
}

From what I could divine from the research I've done so far, it seems that normally whatever class these kinds of functions are utilized in have implemented Drupal's TrustedCallbackInterface. Unfortunately, the only information I have found has been throughout the various patches being applied to projects throughout Drupal.org, so I'm trying to cobble together a methodology from random applications of it.

Of course, there's the Drupal API page, but that's not especially helpful when it comes to actually putting the pieces together into a useful methodology without knowing the rest of the API like the back of your hand.

Does anyone know if there's any documentation on how to apply the TrustedCallbackInterface to a function that previously used $form['#pre_render'][], especially in THEME.theme which is not set up the same as any old custom class in a Module?

Kevin avatar
in flag
The error is right there - you are adding a function to pre_render that is not approved to be called. https://www.drupal.org/node/2966725
Loopy avatar
cn flag
So, the answer is just "Don't try altering the form pre-render. Do what you need to do another way." ?
Kevin avatar
in flag
Look at the linked change record
Loopy avatar
cn flag
The .theme file isn't a class. So I should create an src folder in my theme and move the code from my .theme file to a new class declaration?
4uk4 avatar
cn flag
Yes, see for example https://drupal.stackexchange.com/a/300204/47547. For a different callback type, but it shows a class implementing RenderCallbackInterface in a theme.
Loopy avatar
cn flag
Thanks for the more realistic example. In the end, I had such a difficult time figuring out the proper way to pass the values around for a form and its elements that I did give up and scrapped this methodology entirely in favor of just altering the twig template instead.
Score:3
cn flag

You can do something like this:

in your new module my_prerenders in my_prerenders/src/ add a new class:

namespace Drupal\my_prerenders;

use Drupal\Core\Security\TrustedCallbackInterface;


class MyPreRenders implements TrustedCallbackInterface {

  /**
   * @inheritDoc
   */
  public static function trustedCallbacks() {
    return ['formAlterViewsExposedFormEventsPreRender'];
  }

  public function formAlterViewsExposedFormEventsPreRender($form) {
    $fields = [
    'field_start_date_value',
    'field_end_date_value',
    'field_address_locality',
    ];
    foreach ($fields as $field) {
      $form[$field]['#title_display'] = 'after';
    }
    $form['field_date_range_end_value']['#prefix'] = '<div class="event-exposed-form">';
    $form['field_event_address_locality']['#suffix'] = '</div>';
    return $form;
  }

}

In OURTHEME.theme you just have to use:

use Drupal\my_prerenders\MyPreRenders;

...
...

$form['#pre_render'][] = [MyPreRenders::class, 'formAlterViewsExposedFormEventsPreRender'];

instead of

$form['#pre_render'][] = 'OURTHEME_form_alter_views_exposed_form_events_pre_render';
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.