Hi All,

I have successfully disabled caching for logged in users of my form with a hook:

function fest_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
      	//disable form cache
      	$form['#cache'] = ['max-age' => 0];
}

This is working perfectly for all logged in users: Every time the page is refreshed, the form is created newly.
However, this does not work for the Anonymous user, s/he always gets the same cached form no matter what.

What would be the hook method for disabling the cache for the anonymous user?

Thank you,
magahugu

Comments

dwillcox’s picture

There's a good chance that you know more about this than I, since I'm pretty new to D8. But just putting this out there....

Have you tried clearing all caches once?

The problem is, if the form was already cached, your hook_form_alter() won't be called to alter the cached form. So you won't be able to add the '#cache' item.

Maybe, if you clear the cache, your hook will work for subsequent uses.

dwillcox’s picture

So yes, I'm trying to do something kind of similar to you. I want to hook into the user register form to insert an extra challenge that's easy for humans but probably hard for spam bots. Trouble is, the form is cached, so if the inserted challenge needed to change, the hook wouldn't get a chance to update it.

So I tried your trick to disable caching of the form. That seems to work, but I'm guessing that the page containing the form is also cached, because:

  • When the user register page is first displayed, the hook_form_alter() doesn't fire.
  • When the form is submitted, the hook does fire. (Without your cache snippet, the hook wouldn't fire then, either.)

And this tells me that:

  • Yes, the form cache was disabled. Otherwise the hook would have fired the first time.
  • But this means that the validation handler validates a version of the form other than what was on the actual page seen by the user.

This seems like a bug.

dwillcox’s picture

This is a solution that was provided to me by an (obviously) well-experienced Drupler who's helping me port a module to D8. This is totally obscure, and apparently undocumented, but works for me. It might not quite work for you, but might point you an an interesting direction.

My module has a settings form, and implements hook_form_user_register_alter() to add on to the user registration form. The form would need to be rebuilt any time the module settings are changed, but caching is fine if the settings don't change.

The solution he provided was this:

function mymodule_form_user_register_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $myconfig = \Drupal::config('mymodule.settings');  // The module's settings form.
   // Set cache tags so the form is updated when settings are updated.
   $form['#cache']['tags'] =  Cache::mergeTags($form['#cache']['tags'], $myconfig->getCacheTags());
   ...

With this element added, the user registration page and form are rebuilt any time my module settings change.

I'm not entirely sure how, but it works. There's obviously some behind-the-scenes communication between the cache and \Drupal.config to signal when the cached item needs to be purged. The value returned by getCacheTags() in my case is "config:mymodule.settings", which probably doesn't tell you anything useful.

Problem solved. Almost. You still need to clear all caches once so your hook is invoked the first time.

dwillcox’s picture

By the way, you can call drupal_flush_all_caches() to clear all caches, but that's a very big hammer that should be used sparingly. Like once when your module is installed.

You'd think that you'd put that in your mymodule_install() function, but I learned from experience that that creates chaos.

I got around that by adding a settings variable that's initialized to true. When settings are edited, if that variable is still true I clear caches and reset the variable to false.

nitin.k’s picture

You can check this thread.

magahugu2’s picture

Hi dwillcox Nitin,
thank you for your inputs. What worked for me in the end was to use

function fest_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
     if ($form_id == "node_something_form") {
           	//disable the form cache for anonymous users and all others too
	\Drupal::service('page_cache_kill_switch')->trigger();
	}
}
     
Andrew211’s picture

Nice solution, IMO this should be integrated in the captcha or webform module by default.

sahil_girhotra’s picture

I am using this code "\Drupal::service('page_cache_kill_switch')->trigger();" in Google tag module to disable cache. Will this line disable cache for particular module OR for whole website?   
Andrew211’s picture

Hey,

Whole site if that code is executed, however only for the given request.

Cheers

petercook’s picture

Code similar to this worked for me too. Drupal 8.7.5

function fest_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
     if ($form_id == "node_something_form") {
           	//disable the form cache for anonymous users and all others too
	\Drupal::service('page_cache_kill_switch')->trigger();
	}
}