3

I have a custom field formatter that performs dynamic calculations to determine the output. However, for anonymous user's the previous data is always stored until a cache clear is performed.

in the field formatter viewElements() function I have the $elements #cache max-age set to 0. I thought this would resolve the issue but it does not. Am I missing something?

 public function viewElements(FieldItemListInterface $items, $langcode) {


    $elements = [];

    foreach ($this->getEntitiesToView($items, $langcode) as $delta => $file) {
      // Check if gate cookie is set

      if (isset($_COOKIE['Drupal_visitor_resource_gate'])){

        //$tags = $file->getCacheTags();
        //Cache::invalidateTags($tags);
        $item = $file->_referringItem;

        $elements[$delta] = [
          '#theme' => 'file_link',
          '#file' => $file,
          '#description' => $this->getSetting('use_description_as_link_text') ? $item->description : NULL,
          '#cache' => [
            'max-age' => 0,      
          ],
        ];

        // Pass field item attributes to the theme function.
        if (isset($item->_attributes)) {
          $elements[$delta] += ['#attributes' => []];
          $elements[$delta]['#attributes'] += $item->_attributes;
          // Unset field item attributes since they have been included in the
          // formatter output and should not be rendered in the field template.
          unset($item->_attributes);
        }
        $elements['#cache']['max-age'] = 0;
        return $elements;
      }else{
...
}

3 Answers 3

2

Can you try adding:
\Drupal::service('page_cache_kill_switch')->trigger();
At the beginning of the viewElements function before the foreach loop?
Another thing to try is to set the following also:

$elements['#cache']['max-age'] = 0;
$elements['#cache']['contexts'] = [];
$elements['#cache']['tags'] = [];`
1
  • Thank you! Adding: \Drupal::service('page_cache_kill_switch')->trigger(); seems to have resolved my issue. Mar 1, 2019 at 20:13
2

For anonymous traffic in general there are probably better solutions client-side. If you want to build this server-side in Drupal then better use a session, this will pass the built in page cache for anonymous traffic.

If you want to handle your own cookies you have to uninstall the Internal Page Cache and cache the pages only in the Internal Dynamic Page Cache. Then for better caching performance set a cache context for the cookie instead of max-age:

  $elements['#cache']['contexts'][] = 'cookies:Drupal_visitor_resource_gate';
0

The caching is done per entity not per field.

Depending on your use case you might want to consider excluding specific content types from caching or specific nodes

function MODULENAME_node_view(array &$build, NodeInterface $node, $display, $view_mode) {
  // for specific Content types
  if ($node->getType() == 'CONTENTTYPE' && $view_mode == 'full') {
    $build['#cache']['max-age'] = 0;
  }

  // for specific nodes
  if ($node->id() == xxx ) {
    $build['#cache']['max-age'] = 0;
  } 
}

or can even try the cache exclude module

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.