2

I have a block, which renders out a form using code that looks like this:

{{ attribute(form.facets, 'filter_' ~ filter.name) }}

I'd like to amend the markup and CSS classes for the various elements that are output, including fieldset, input, label etc. I appreciate that I can override the template files for fieldset for example, by creating a fieldset.html.twig file in my theme, but I don't want to change the markup for every fieldset element. I only want to apply my custom templates to form elements which are rendered out from a specific block.

I know that I can use a 'suggestion' (mytheme_theme_suggestions_alter) to alter the template for any element, but I can't see a way of determining if an 'input' for example, is an input within my block, or some other block on the site. Does anyone know how I'd identify this?

2

1 Answer 1

1

You can use drupal_static() together with the following two hooks in your module or your theme to add template suggestions for input elements based on the block ID where the input element is used in (same would work with fieldsets or any other form/render element):

/**
 * Implements hook_preprocess_HOOK().
 */
function MYTHEME/MYMODULE_preprocess_block(&$variables) {

  $bid = &drupal_static('block_id', TRUE);
  $bid = $variables['elements']['#id'];
}

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 */
function MYTHEME/MYMODULE_theme_suggestions_input_alter(array &$suggestions, array $variables) {

  $bid = &drupal_static('block_id', FALSE);

  if ($bid) {
    $suggestions[] = 'input__block__' . $bid;
    $suggestions[] = $variables['theme_hook_original'] . '__block__' . $bid;
  };
}

For example the search form textfield:

<!-- FILE NAME SUGGESTIONS:
   * input--search.html.twig
   * input--search--block--neato-search.html.twig
   * input--block--neato-search.html.twig
   x input.html.twig
-->

For example the password textfield:

<!-- FILE NAME SUGGESTIONS:
   * input--password.html.twig
   * input--password--block--userlogin.html.twig
   * input--block--userlogin.html.twig
   x input.html.twig
-->
7
  • Not sure about this @laymannx. It does do the trick, but using the global context to transfer information between functions is risky, think of a call to drupal_static_reset(). Additionally, calls to drupal_static, should be 'namespaced' by using the __FUNCTION__ magic constant to use the function's name inside of which drupal_static is called, i.e. drupal_static(__FUNCTION__), in that way making them specific to the function that needs them multiple times in the same request. Sep 26, 2018 at 22:22
  • @StefanosPetrakis - Thanks a lot for your comment. I definitely have to dive deeper into drupal_static I learned of only yesterday. I will look how core or other contrib modules use it. Do you know of any other alternative to pass variables between hooks?
    – leymannx
    Sep 26, 2018 at 22:34
  • This didn't work for me unfortunately. Instead of MYTHEME/MYMODULE_preprocess_block, I was using MYTHEME/MYMODULE_preprocess_form and then trying to catch the bid in say MYTHEME/MYMODULE_theme_suggestions_input_alter. The problem was that the suggestion appears to run before the preprocess. Sep 26, 2018 at 22:35
  • @laymannx - No worries, I think another option would be using session variables, but I would still go the way suggested in my first comment in the OP Sep 26, 2018 at 22:36
  • @JamesThomson – bid means block ID. You probably won't get that in the form.
    – leymannx
    Sep 26, 2018 at 22:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.