0

I have a code base I am working in that has plenty of custom modules. It also has an analytics scheme already in place that have been trying to make work with certain customer requirements.

One of these is to report a 'page_type' value, that if set on certain landing pages is reported correctly in another module called my_analytics. The landing pages are custom module also, named my_landing_page.

I added the page_type property successfully to the module and have developed code to add analytics information from other modules. The set up I have works- actually, but it only works on the first page load, due to caching. I know why I am having the issue but am looking for solutions to get around it. I am an experienced programmer, but not an experienced Drupal-person.

Here is how I had it set up. The only place I could find to grab the field info from the my_landing_page module is in the preprocess hook, as follows:

function my_landing_page_preprocess(&$variables) {
  if (isset($variables['entity'])) {
    $node = $variables['entity'];

      my_analytics_get_landing_page_analytics($node);
  }
}

This calls a series of functions in the other module my_analytics which eventually merges these global additions into an array that becomes drupalSettings. There some analytics populated in my_analytics_page_bottom as well. This allows the javascript to use these values to send the analytics call with the info on the client side. The use of globals is unfortunate, but do you have a better idea?

function my_analytics_get_landing_page_analytics($node) {
  if ($node instanceof Node && $node->getEntityTypeId() == 'node' && $node->getType() == 'landing_page') {

    if ($node->hasField('field_page_type') && count($node->get('field_page_type')->getValue()) > 0) {
      my_analytics_add_tags_global([
        'TagID_channel' => $node->get('field_page_type')->getValue()[0]['value'],
      ]);
    }

  }
}

function my_analytics_add_tags_global(array $tags) {
  if (isset($GLOBALS['my_dtm_global_tags']) && is_array($GLOBALS['my_dtm_global_tags'])) {
    $GLOBALS['my_dtm_global_tags'] = array_merge($GLOBALS['my_dtm_global_tags'], $tags);
  }
  else {
    $GLOBALS['my_dtm_global_tags'] = $tags;
  }
}

function my_analytics_add_set_tags(array &$build, array $tags) {
  if (!empty($build['#attached']['drupalSettings']['my_analytics']['setTags'])) {
    $build['#attached']['drupalSettings']['my_analytics'['setTags'] = [];
  }

  // Search for global tags added from other modules.
  if (isset($GLOBALS['my_dtm_global_tags']) && is_array($GLOBALS['my_dtm_global_tags'])) {
    $tags = array_merge($tags, $GLOBALS['my_dtm_global_tags']);
  }

  foreach ($tags as $tag_id => $tag_value) {
    $build['#attached']['drupalSettings']['my_analytics']['setTags'][] = [
      'id' => $tag_id,
      'value' => $tag_value,
    ];
  }
}

So as I mentioned, this works on the first page load. I have done enough of my own investigating to know this is because the preprocess hook in my_landing_page does not fire after the page is cached and that this is intended behavior.

Keep in mind I do not have complete control over how the rest of the set up was written. I have inherited it.

So here are the options I have considered, but in most cases don't know how to accomplish.

1) Find something better than preprocess, a way to get the info (page_type) from my_landing_page each page load so that it populates my_analytics properly each time the page loads.

2) Somehow cache the drupalSettings with the page (or something similar) be it by using the Cache API or addCacheableDependency or something I am unaware of so that the original cached version is used for subsequent page loads.

3) ???

Does anyone know how to accomplish what I am trying here? Basically, grabbing info from one module and sharing it with another in a way that happens every page load? I want to get the page_type value from my_landing_page and into the drupalSettings object we populate in my_analytics and that to happen every visit to the page.

Thanks.

1 Answer 1

0

In general when you add attachments to a build array, then add the cache metadata in the same place:

$build = [];

// attach libraries and their drupal settings
$build['#attached'] = [...];

// add the cache dependencies for this data
$build['#cache'] = [
  'contexts' => ['url'],
  'tags' => ['dtm_global'],
  'max-age' => 60,
];

If you want to add cacheable dependencies of objects to the build array, you can use addCacheableDependency(), see https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays

Now sharing this with other modules is no problem anymore, Drupal builds a page with hundreds of render arrays like this, all from different modules.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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