I wonder how I can add a class to the form tag (of the _search_content_ view's) exposed form using template_preprocess_views_exposed_form() (or even better template_preprocess_views_exposed_form__search_content()). The form is exposed as block.

It works so far using the following code in MY_THEME.theme:

function MY_THEME_preprocess_form(&$variables) {
  if ($variables['element']['#form_id'] == 'views_exposed_form' && $variables['element']['#view_id'] == 'search_content') {
    $variables['attributes']['class'][] = 'row';
  }
}

But I can't get it work for:

function MY_THEME_preprocess_views_exposed_form__search_content(&$variables) {
  // I tried:
  // $variables['attributes']['class'][] = 'does-not-work';

  // and also:
  // $variables['attributes'] = new Attribute($variables['attributes']);
  // $variables['attributes']->addClass('does-not-work');

  // and also manipulating $variables['form'], but this didn't work either.
}

The function gets called, but it's not adding the class to the form tag. Is it possible to get it work with template_preprocess_views_exposed_form()?

Screenshot of kint($variables) output, for each function:

enter image description here

Is it possible to get it work with template_preprocess_views_exposed_form()?

This question has an open bounty worth +50 reputation from LarS ending in 3 days.

This question has not received enough attention.

Although I already have a workaround, as template_preprocess_form() is working, I would like to know why it is not working or how I can get template_preprocess_views_exposed_form() to add the class to the form tag.

  • Did you debug the code to see if the array is being modified and the structure is correct? – Kevin Dec 5 at 3:32
  • Use hook_form_alter, and ksm, kint, dpm from devel module for debugging. – svetlio Dec 5 at 8:45
  • I was using kint(). The array got modified, but the structure of the variables array in MY_THEME_preprocess_form() is different to the one in MY_THEME_preprocess_views_exposed_form__search_content(). – LarS Dec 5 at 14:08
  • I don't see how hook_form_alter may help, as the preprocessing happens later. I also have MY_THEME_form_views_exposed_form_alter() successfully implemented to modify other parts of the form, but was not able to set the class for the form tag either. – I can set a wrapper via #prefix/suffix with the row class, but it's not what I want, as it would wrap around the form tag, I need the class added to the form tag (or as a container inside the form tag, containing all form elements). – LarS Dec 5 at 14:37
  • 1
    Thanks @StefanosPetrakis, I followed your advice and removed the addition. – LarS yesterday

If you want just add Class to form tag to the exposed filter you can do it with hook_form_FORM_ID_alter no need to template_preprocess_views_exposed_form() or template_preprocess_views_exposed_form__search_content() Like the following:

use Drupal\Component\Utility\Html;
/**
 * Implements hook_form_FORM_ID_alter().
 */
function myModuleName_form_views_exposed_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  $form['#attributes']['class'][] = Html::cleanCssIdentifier('your-new-class');
}
  • are you sure about that? I tested it and it got added to an outer div. I am wondering if the case is a bit special: The exposed form is shown as drupal block, the class got added to the block's div. – LarS Dec 8 at 5:01
  • I am not only interested in a solution, I primarily would like to understand the difference between template_preprocess_views_exposed_form() and template_preprocess_views_exposed_form__search_content() … I am going to point that out in the question. – LarS Dec 8 at 5:03

It is because the hook fired for the exposed form is actually 'form' as you can see in the below screenshot:
enter image description here

And this is why it is always a good idea to enable twig debug
Hope that helps!

EDIT
To elaborate more:
The views exposed form preprocess function does not edit the form itself because this is a different hook. The proper way to add a class to the form is to alter the form it self or use https://api.drupal.org/api/drupal/core%21includes%21form.inc/function/template_preprocess_form/8.6.x because this function is the responsible for adding attributes to the form itself. Also check the twig source of https://api.drupal.org/api/drupal/core%21themes%21stable%21templates%21form%21form.html.twig/8.6.x You'll see that the attributes are printed there.

  • Sorry, I did not yet understand your answer, may I ask you to elaborate a bit more? I am not looking for a hook, instead using the template preprocess functions. If I got it right, they follow the template suggestions, as the twig templates do, like the general one views-exposed-form.html.twig or a more specific one views-exposed-form--search_content.html.twig – LarS Dec 8 at 5:10
  • I have twig debugging enabled, but I guess its output is not complete in this situation, as there is no information about FILE NAME SUGGESTIONS, but I know that I can use different templates here, like views-exposed-form.html.twig or the one I am using for the form views-exposed-form--search_content.html.twig. – LarS Dec 8 at 5:17
  • Please take a look at the views exposed form twig template here api.drupal.org/api/drupal/… What I understood from your question is that you want to add a class to the form. According to the template you can't. The prints the form with no alterations – Ismail Cherri Dec 8 at 7:27
  • It works in MY_THEME_preprocess_form(), as stated in the question, but if I got you right it does not matter it's the wrong place, I should not do that? – LarS Dec 8 at 19:46
  • No. preprocess_form is the right place if you want to edit the form tag and it is ok to use it. preprocess_views_exposed_form and preprocess_views_ecposed_form__search_content are used to change attributes of the wrapper element around the exposed form and you should not use them if you want to add classes to the form tag for example – Ismail Cherri 2 days ago

Short version: You cannot use hook_preprocess_views_exposed_form() to modify the <form> tag. The <form> tag is independently rendered by a form theme hook set through the #theme_wrappers render property. Which means that it is completely disassociated from the actual views_exposed_form theme hook that renders the (internal) content of the views exposed form.

Long version:

  1. views_theme() defines the views_exposed_form theme hook as returning a form render element. That means that it will eventually be using (unless somehow overridden) the definition provided by the Form render element. If you take a look at that, you will see that that definition sets the'#theme_wrappers' property to ['form']. No surprises so far. :-)
  2. At some point during the theming of a views page (or block), the theme hook views_view comes into play; this theme hook contains the exposed render variable that is essentially the exposed form you are interested in. This render variable holds the two relevant properties:

    • #theme => views_exposed_form (and other more specific ones like views_exposed_form__search_content): This is the theme hook that will provide the content of the form, i.e. everything inside the <form> tag. This is what you get access to and given the option to modify when calling template_preprocess_views_exposed_form(). This theme hook is not responsible for rendering the <form> tag and does not allow you to change it.
    • #theme_wrappers => ['form'] : This is the #theme_wrappers list of theme hooks that will provide the actual <form> tag. It will essentially enclose the markup generated by the #theme theme hook into a <form> tag. This is what you get access to and can modify stuff when calling template_preprocess_form(). This theme is responsible for rendering the <form> tag and does allow you to change it.

Implementation suggestion

If you would rather let hook_form_alter() implementations handle form-related logic, you could still use another preprocess hook to implement the functionality you want, namely the preprocess_views_view() hook.

function MY_THEME_preprocess_views_view(&$variables) {
  if ($variables['id'] === 'search_content') {
    $variables['exposed']['#attributes']['class'][] = 'row';
  }
}

Good luck, this is a really good question!

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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