2

I have a content type 'homepage' containing one node which is used a the homepage. This node has a multivalue image field, and I need to randomly select one of those images to show on the homepage on every site visit. I have written the logic for this in the THEME_preprocess_node function in my THEME.theme file. This is working fine, but the site in question is still in development mode with most caching deactivated. I'm worried that once the site goes live and the caching is activated, it will serve the homepage from cache and therefore always show the same image until the cached version of the page expires.

Is that the case, or are the preprocess functions evaluated on every page visit even when the cache is active? If not, how can I circumvent this to get a random image every time?

This is the code I have written for this:

  $imgages = $node->get('field_frontpage_header_image');
  $random = $imgs->get(rand(0, $imgages->count() - 1))->getValue();
  $img = File::load($random['target_id']);
  $variables['random_header_image'] = ImageStyle::load('frontpage_header')->buildUrl($img->getFileUri());

I then use {{ random_header_image }} in the twig template. Maybe I can change this variable to a render array with a cache setting of max-age => 0? Not sure if this works in preprocess functions though ...

Thanks!

  • Yes, you can set max-age in preprocess, but this only works for logged-in users. For anonymous users I would load the image in an ajax call. – 4k4 Jan 17 '18 at 9:41
  • @4k4 max-age only works for logged in users? I didn't know that, can you link me to some source that explains this concept further? I'm afraid loading in ajax isn't an option for this particular problem. Is there another way? Also could you provide a code example for this? – MoritzLost Jan 17 '18 at 9:44
  • 1
    This is more a general problem, anonymous traffic is cached on all levels and normally you don't want to disable this for performance reasons. Ajax in this case is rather simple, you don't need the ajax implementation of the form api, you can use jquery ajax and a controller to deliver the images. – 4k4 Jan 17 '18 at 9:56
  • @MoritzLost Unless you have a seriously esoteric use case, you should probably consider the ajax approach. It solves your caching problem, and makes no difference to your users (they don't know whether the image was loaded as part of the normal page build or via ajax, and probably wouldn't care even if they did). The only minor concern is if you really need search engines to pick up the image and its alt. Even then, the big boys can execute JS these days so you're probably covered – Clive Jan 17 '18 at 10:08
  • 1
    Edge Side Includes - basically placeholders that get resolved by a reverse proxy (eg Varnish). – Clive Jan 17 '18 at 11:25
2

If it's a limited set of pictures that you have then I would just write a custom formatter that displays for example an image tag with a data attribute that has your list of image paths (maybe with the first image already set as non-JS fallback maybe). then you just need small bit of JS that picks one of those randomly and sets it as the actual src attribute. Your page is fully cacheable then and while it might still be a noticeable delay until the image shows up, that can even happen with static image links on slower connections.

And it will certainly be much faster than an ajax request.

The placeholder approach might also work and Drupal supports that kind of out of the box with dynamic page cache, doesn't need a reverse proxy or so for that. but you would have to disable the internal page cache then on that page. See http://www.qed42.com/blog/lazy-builders-drupal8 for an example on that.

The way that works with Dynamic Page cache is that the whole page with the placeholders is cached, and then calls the defined lazy builders which returns the actual content for the current request. You would want to use a similar approach as with JS, prepare all image urls for example already as arguments and then just pick one from that array and render it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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