1

We want to block external traffic in Google Tag Manager and I am trying to do something like shown here.

I created this:

/**
 * Implements hook_init().
 */
function myfunction_init() {

  $internal_ips = [
    'x.x.x.x',
    'x.x.x.x',
  ];

  $internal_traffic = 'no';
  if (in_array(ip_address(), $internal_ips)) {
    $internal_traffic = 'yes';
  }

  $data_layer = [
    '#type' => 'markup',
    '#tag' => 'script',
    '#markup' => "<script>
                    var dataLayer = [];
                    dataLayer.push({ 'internalTraffic': '$internal_traffic'});
                  </script>",
    '#weight' => 100 ,
  ];

  drupal_add_html_head($data_layer, 'data-layer');
}

It would work but the problem is I have cached pages so this will not be correct. I did try hook_boot but that did not work because drupal_add_html_head() is not a valid function (I'm assuming it wasn't initialized yet).

1

To request the uncached client IP I recommend providing a JSON endpoint that has drupal_page_is_cacheable(FALSE) set. Then get the IP from there with an Ajax request and do whatever you need to do now with JavaScript.

First, provide a route.

/**
 * Implements hook_menu().
 */
function MYMODULE_menu() {

  $items['myip'] = [
    'page callback'   => '_MYMODULE_myip_callback',
    'access callback' => TRUE,
  ];

  return $items;
}

Second, provide the endpoint that returns the result of the IP comparison. (Bonus points for getting the internal IPs from an admin settings form. More bonus points for checking the user role as well.)

/**
 * Callback to provide an uncached JSON response.
 */
function _MYMODULE_myip_callback() {

  $internal_ips = [
    'x.x.x.x',
    'x.x.x.x',
  ];

  $data = [
    'internal_ip' => in_array(ip_address(), $internal_ips) ? TRUE : FALSE,
  ];

  // Mark this page as being uncacheable.
  drupal_page_is_cacheable(FALSE);

  drupal_json_output($data);
}

Third, add the JS.

/**
 * Implements hook_page_build().
 */
function MYMODULE_page_build(&$page) {

  drupal_add_js(drupal_get_path('module', 'MYMODULE') . '/js/scripts.js', ['scope' => 'footer']);
}

Fourth, the Ajax request and DOM manipulation in the JS file.

(function ($, Drupal) {
  'use strict';
  Drupal.behaviors.myBehavior = {
    attach: function (context, settings) {

      $.getJSON('/myip', function (result) {

        if (result.internal_ip) {
          function_to_call_if_internal_ip();
        }
      });

      var function_to_call_if_internal_ip = function () {

        // Do whatever you need to do.
        // ...

      };

    }
  };
})(jQuery, Drupal);

Note

One thing to mention. I adjusted the sample to follow your sample flow "do something if internal IP". In the original snippet I do the opposite "only add Google Tag Manager if external IP" to never have the tag manager script added at all if the request comes from an internal IP and it works just fine.

$.getJSON('/myip', function (result) {

  if (result.add_scripts_by_client_ip && result.add_scripts_by_user && result.add_scripts_by_host) {
    _add_google_tag_manager('GTM-XXXXX');
  }
});

var _add_google_tag_manager = function (gtmid) {

  if (!!gtmid && gtmid !== null && gtmid !== '') {

    $('html').once('myBehavior').each(function () {
      $('body').prepend('<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=' + gtmid + '" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>');
      $('head').append("<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer', '" + gtmid + "');</script>");
    });
  }
};

If you use Varnish, Memchached or some other server-side caching strategy, don't forget to exclude /myip from them.

  • 1
    Thanks. I ended up creating the endpoint and just setting dataLayer.push({ 'internalTraffic': '$internal_traffic'}); based on the result via ajax. Was hoping that there was a way to do it without ajax but because of Drupal caching, I don't see any other way. – albertski Jul 17 at 15:30

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.