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!

8
  • 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. Commented Jan 17, 2018 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? Commented Jan 17, 2018 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. Commented Jan 17, 2018 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 Commented Jan 17, 2018 at 10:08
  • 1
    Edge Side Includes - basically placeholders that get resolved by a reverse proxy (eg Varnish). Commented Jan 17, 2018 at 11:25

1 Answer 1

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.

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.