4

I've created a custom module which does some additional form handling and styling required for my project - this is all working fine.

Due to the size of the form - 50 odd fields - I'm setting up a Twig file in my module for the confirmation screen as it is far easier to manage it in my IDE than using the GUI. My confirmation page lists all the values styled in a specific way and laid out in a specific way. I've technically got it working by using hook_theme_suggestions_webform_confirmation_alter and hook_theme to point to my Twig template.

However, I've just recently discovered that, due to Drupal 8 internal page caching being so aggressive for anonymous users, the confirmation page is getting cached for everyone regardless of the actual submission values. So the first user gets it fine but the second submission from then on gets the cached version from the first.

I've read in other places to make use of hook_preprocess_webform_confirmation and set $variables['message']['#cache']['max-age'] = 0;. However, this is never called which I suspect is due to how I went about using my Twig template mentioned above.

Can someone help point me in the right direction here. Am I supposed to setup some kind of overwriting route in order to change the theme file or is it just a matter of tweaking what I've already done?

Functions in my .module file

function application_theme($existing, $type, $theme, $path) {
  $info = [
    'gib_application' => [
      'render element' => 'form',
      'template' => 'application-form'
    ],
    'application_form_confirmation' => [
      'template' => 'application-form-confirmation'
    ]
  ];
  return $info;
}

And

function application_theme_suggestions_webform_confirmation_alter(array &$suggestions, array $variables) {
  if (empty($variables['header'])) {
    $suggestions[] = 'application_form_confirmation';
  }
}

UPDATE

I've tweaked my hook_theme function to the below and also disabled hook_theme_suggestions_webform_confirmation_alter assuming it isn't relevant so long as hook_theme is defining the correct name.

function application_theme($existing, $type, $theme, $path) {
  $info = [
    'gib_application' => [
      'render element' => 'form',
      'template' => 'application-form'
    ],
    'webform_confirmation__application_form' => [
      'template' => 'application-form-confirmation',
      'base hook' => 'webform_confirmation'
    ],
  ];
  return $info;
}

Here are the Twig suggestions:

<!-- FILE NAME SUGGESTIONS:
   * webform-confirmation--application-form.html.twig
   x webform-confirmation.html.twig
-->

Unfortunately now my Twig template isn't being loaded at all now (due to dropping hook_theme_suggestions_webform_confirmation_alter.

13
  • Seems like $variables['message'] is wrong. Please retry it with $variables['#cache']['max-age'] = 0;.
    – leymannx
    Oct 31, 2018 at 8:46
  • 1
    To clarify, the hook to allow me to use $variables is never called. If I stop using the theme suggestion hook then I can alter the cache but this means I can't have a custom twig template
    – SaRiD
    Oct 31, 2018 at 18:12
  • 1
    Yes, this is correct, to move the template to the module folder you have to implement hook_theme(), but the naming rules still apply, that the template needs to start with the base hook, in your case webform_confirmation__ and instead of defining your own variables reference the base hook. Then the preprocess hook you are trying to invoke should work. See drupal.stackexchange.com/questions/267263/…
    – 4uk4
    Nov 5, 2018 at 21:15
  • 1
    The template in theme_hook() is not necessary, but you need the suggestion. The linked example is different because there the suggestion for the content type already exists.
    – 4uk4
    Nov 5, 2018 at 22:10
  • 1
    It's working! After removing the template, and then renaming my Twig filename accordingly, it is now loading the Twig template from my module while also allowing me to use hook_preprocess_webform_confirmation so that I can disable cache.Unfortunately the preprocess hook isn't called everytime for anonymous users which means I can't use it to disable cache! That is a different question though which I'll look into.
    – SaRiD
    Nov 6, 2018 at 0:41

3 Answers 3

4
+50

Seems like there are two different issues here:

(a) Loading a twig template from an arbitrary folder.

Could you try setting the path theme property and see if that allows your twig template to be loaded? For example:

'webform_confirmation__application_form' => [
  'template' => 'application-form-confirmation',
  'base hook' => 'webform_confirmation'
  'path' => \Drupal::moduleHandler()->getModule('application')->getPath() . '/templates',
],

(b) Modifying the cache settings for a part of your render variables.

You should check that the cache tags bubble all the way up from the message array. Apparently:

You have to render the content variable to ensure that its cache tags bubble up and end up in the page cache.

as mentioned here => (https://www.previousnext.com.au/blog/ensuring-drupal-8-block-cache-tags-bubble-up-page)

So, one place to start would be trying to render the whole content variable in your twig template, provided you got past (a)

Update: You could also try calling \Drupal::service(''page_cache_kill_switch'')->trigger(); in order to avoid Internal Page Cache to interfere with the request and page loading.

A simple way to do this inside a twig template would be using an approach similar to this module => https://github.com/stefanospetrakis/twig_killswitch_trigger

Good luck!

P.S.: Sample code is also available here => https://www.drupal.org/sandbox/stefanospetrakis/3011610, I may promote this to a full project if there is any potential interest.

4
  • I have the twig template loading now thanks to comments under my question. Caching is still an issue though. I've checked the header tags and I can see cache tags there that appear to be unique to the form submission - this would tell me it should be unique? That said I only see this on my dev box and not on production which is where the issue is. Configuration is all the same except for a normal setup for a production install.
    – SaRiD
    Nov 6, 2018 at 1:02
  • 1
    @SaRiD : Threw some code that you could use over here => github.com/stefanospetrakis/twig_killswitch_trigger . If you don't want to use that module, you can still try to call \Drupal::service(''page_cache_kill_switch'')->trigger(); from your own implementation. Updated my answer as well. Nov 6, 2018 at 1:23
  • Yep page_cache_kill_switch does the trick thanks! I was able to simply add it in to hook_preprocess_webform_confirmation - nice job quickly creating a reusable module though.
    – SaRiD
    Nov 6, 2018 at 2:08
  • Perfect! Happy it worked out, great summarised answer below! Nov 6, 2018 at 10:02
3

Summary of the final answer to my original questions.

hook_theme was still required in the module to state that it can be used for suggested Twig templates.

function application_theme($existing, $type, $theme, $path) {
  $info = [
    'webform_confirmation__application_form' => [
      'base hook' => 'webform_confirmation'
    ]
  ];
  return $info;
}

hook_theme_suggestions_webform_confirmation_alter was not required in the end once hook_theme was setup correctly.

hook_theme needed to have the suggested name as proposed by the Twig debugger. Twig suggested these files:

<!-- FILE NAME SUGGESTIONS:
   * webform-confirmation--application-form.html.twig
   x webform-confirmation.html.twig
-->

The dashes get converted to underscores i.e. webform-confirmation--application-form is translated to webform_confirmation__application_form.

The only variable associated with that part of the array was base hook. This states to use the initial hook functionality rather than setting it all up again in my module - read more here.

base hook: Used for theme suggestions only: the base theme hook name. Instead of this suggestion's implementation being used directly, the base hook will be invoked with this implementation as its first suggestion. The base hook's files will be included and the base hook's preprocess functions will be called in addition to any suggestion's preprocess functions. If an implementation of hook_theme_suggestions_HOOK() (where HOOK is the base hook) changes the suggestion order, a different suggestion may be used in place of this suggestion. If after hook_theme_suggestions_HOOK() this suggestion remains the first suggestion, then this suggestion's function or template will be used to generate the rendered output.

template was not required so long as the filename of my Twig file matched the one Twig was suggesting. For my site it was webform-confirmation--application-form.html.twig.

With the above tweaks my Twig file was loading correctly while also still using all of the original hooks from the webform module.

The other issue was the confirmation page being cached for anonymous users. I was able to resolve this by using \Drupal::service('page_cache_kill_switch')->trigger(); inside hook_preprocess_webform_confirmation. After clearing Drupal's cache the confirmation page would then never get cached again.

function application_preprocess_webform_confirmation(array &$variables) {
  \Drupal::service('page_cache_kill_switch')->trigger();
}

This same logic will apply for updating Twig templates in other modules as well - this is not a webform module only solution.

Thanks to 4k4 and Stefanos for the guidance.

0

You can add the following statement to your Twig template to turn off caching.

{{ {'#cache': {'max-age': 0}} }}

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.