Add hook_google_analytics for other modules
hass - March 7, 2008 - 23:14
| Project: | Google Analytics |
| Version: | 6.x-1.x-dev |
| Component: | Code |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | active |
Description
Since ga.js it looks impossible (untested) for other modules to set a custom variable in head. So it becomes impossible to add tracking data like shopping data to the ga tracking. See http://0-code.google.com.millennium.unicatt.it/apis/analytics/docs/gaJSA... for some good examples.
var pageTracker = _gat._getTracker("UA-12345-1");
pageTracker._initData();
pageTracker._trackPageview();
pageTracker._addTrans(
"1234", // order ID - required
"Womens Apparel", // affiliation or store name
"11.99", // total - required
"1.29", // tax
"15.00", // shipping
"San Jose", // city
"California", // state or province
"USA" // country
);
pageTracker._addItem(
"1234", // order ID - required
"DD44", // SKU/code
"T-Shirt", // product name
"Olive Medium", // category or variation
"11.99", // unit price - required
"1" // quantity - required
);
pageTracker._trackTrans();It looks like we need a hook or something else that would allow other modules to set custom variables and urls. We should do some brainstroming what the best way would be.

#1
Marked #231451 as duplicate.
#2
Nobody is interested on this?
I think it is the 'natural' next step for Analytics module. Now we have tracking and segmentation, but Analytics module has to be capable to track: subscriptions, e-commerce, registrations, newsletter or any other 'calls to action' to use all the power features from Google Analytics.
#3
I thought a little bit more about this and i think there are possible workarounds. There is no real need to add this in the hook way. Someone could create a variable in the page head like
var ecommerceTracker =_addTrans(...);ecommerceTracker =_addTrans(...);
and add something like:
if (ecommerceTracker) { pageTracker = ecommerceTracker; }to the "Custom JavaScript code" text area... not perfect, but this should work, too.
#4
The implementation must allow to add code *before* and *after* _trackPageview() call. See #275359: Allow adding custom javascript code before and after _trackPageview()
#5
#6
This is a first try to implement such a hook for all other modules that likes to hook into GA module. It allows to push in every custom tracking method available in the GA API (http://code.google.com/apis/analytics/docs/gaJSApi.html).
I hope one of the google adsense, ubercart or ecommerce module maintainers could take a look if they are comfortable with this code or if they have a better idea. Feedback is very welcome!!! This patch will stay in queue until a maintainer depend on this code and approved it is working well.
Here follows a code example how this could be integrated in other modules:
<?php
function mymodule_googleanalytics(&$hook) {
switch ($hook) {
case 'preprocess':
$value['methods'][]['_setDomainName'] = array('.example.com');
$value['methods'][]['_clearIgnoredOrganic'] = array();
$value['methods'][]['_setSampleRate'] = array('80');
break;
case 'process':
$value['methods'][]['_addTrans'] = array(
"1234", //order ID - required
"My Partner Store", //affiliation or store name
"84.99", //total - required
"7.66", //tax
"15.99", //shipping
"Boston", //city
"MA", //state or province
"USA" //country
);
$value['methods'][]['_addItem'] = array(
'343212',
'DD4444',
'Lava Lamp',
'Decor',
'34.99',
'1',
);
$value['methods'][]['_addItem'] = array(
'46464',
'CC1111',
'Black Lamp',
'Decor',
'2.99',
'5',
);
$value['methods'][]['_trackTrans'] = array();
break;
}
return $value;
}
?>
#7
Strictly speaking, I don't think this is needed. Modules can use hook_preprocess_page to fiddle with the $javascript array. They can inject their own calls wherever needed. They should do so before template_preprocess_page() does the final drupal_get_js().
#8
I'm not sure how they should insert something before the
'pageTracker._initData();';or after'pageTracker._trackPageview('. $url_custom .');';. If they like to do - they need to alter the $script added in footer with regexes or so and I'm not sure if template_preprocess_page() have the ability to alter this at this late stage. I've got some other troubles at this late stage in D6 that made me to move some parts to the hook_init(), but not all.I will try to test template_preprocess_page() for altering the footer code. Aside this is only available in D6.
#9
I've dumped all $variables in
module_preprocess_page()and the only place I can see the footer code is in$variables['closure']. This is completely ready HTML code. No way to alter an array of javascript code. Therefor this will become a funny regex, but could work.Marking need work to make clear this needs some more investigation and testing.
#10
Ok, here the funny regex... the patch above will not be committed by this way. I hope this regex is correct. Maybe someone else could review this. Then we are able to add this to a readme or a handbook page to give other maintainers the ability to reuse this variant.
<?php
function mymodule_preprocess_page(&$variables) {
// Example code. Make sure your module runs all values through drupal_to_js() to be protected against XSS.
$before = 'pageTracker._setDomainName(".example.com");';
$after = 'pageTracker._addTrans("1234", "My Partner Store", "84.99", "7.66", "15.99", "Boston", "MA", "USA");';
$after .= 'pageTracker._addItem("343212", "DD4444", "Lava Lamp", "Decor", "34.99", "1");';
$after .= 'pageTracker._trackTrans();';
$variables['closure'] = preg_replace('/(.*)(<script type="text\/javascript">var pageTracker = _gat._getTracker\("(UA-\d{4,}-\d+)"\);)(.*)(pageTracker._initData\(\);pageTracker._trackPageview\(\);)(.*)(<\/?script>)(.*)/i', "$2$before$5$after$7", $variables['closure']);
}
?>
The only issue we really have with this solution is - it is not working for D5 and all e-commerce packages are only available for D5 today. I also expect that many people are not able or don't like to upgrade to D6 for a good time...
We could also change the
(UA-\d{4,}-\d+)to(.*)validation here to reduce complexity (untested). We don't really need to validation here.#11
#12
There are some bugs... I will update asap.
#13
Ok, new version that fixes to keep custom URL's, segmentation data and custom javascript code settings as is. Custom javascript code take recedence over module provided google api methods.
<?php
function mymodule_preprocess_page(&$variables) {
// Example code. Make sure your module runs all values through drupal_to_js() to be protected against XSS.
$before = 'pageTracker._setDomainName(".example.com");';
$after = 'pageTracker._addTrans("1234", "My Partner Store", "84.99", "7.66", "15.99", "Boston", "MA", "USA");';
$after .= 'pageTracker._addItem("343212", "DD4444", "Lava Lamp", "Decor", "34.99", "1");';
$after .= 'pageTracker._trackTrans();';
$variables['closure'] = preg_replace('/(.*)(<script type="text\/javascript">var pageTracker = _gat._getTracker\("(UA-\d{4,}-\d+)"\);)(.*)(pageTracker._initData\(\);pageTracker._trackPageview\((.*)?\);)(.*)(<\/?script>)(.*)/i', "$2$before$4$5$7$after$8", $variables['closure']);
}
?>
#14
Book page have been added at http://drupal.org/node/284599.
#15
Automatically closed -- issue fixed for two weeks with no activity.
#16
The original idea seems completely reasonable to me. In fact, I think we should extend the hook idea to include the ability to add multiple trackers.
Modifying this information via a preprocess hook feels quite strange and un-Drupal to me. Where else do we recommend that people do this? Does core ever recommend that people modify it via preg_replace in the theme layer?
#17
Yes. One example - see http://drupal.org/node/228511#comment-881969.
#18
That should also be possible with a theme_form_id function and/or a hook_form_alter which give the data in a structured way (much like the initial hook you proposed here...).
#19
Could you provide an example? I asked this label question very long time and found many many people doing string replacements and such crazy things...
I have thought about a template file in 2.x, but not yet sure how this theming function should looks like best. Otherwise I'm not sure how moshe would do it, but he said we don't need this hook...
#20
Marked #356557: Add a hook for modules wanting to add custom JS as duplicate
#21
@moshe: could you please enlighten us why we don't need it? Others don't like the regex stuff I've created very much... what would be the best solution?
#22
I'm don't have enough familiarity with javascript or pagetracker (in the example). my idea was that modules could call pagetracker methods in their javascript that fiddle with variables. then the javascript that finally sends info to google runs last.
another idea is for this module to structure its javascript injection into a few different drupal_add_js() calls. Then modules can remove/add the parts they want during MODULE_process_page(). for an example of this fiddling, see jquery_update_preprocess_age() at http://cvs.drupal.org/viewvc.py/drupal/contributions/modules/jquery_upda...
#23
Marked #324764: support for multiple analytics keys as duplicate.
#24
#25
Another use case is changing $url_custom from modules. The Apache Solr search module, used on Drupal.org, should set a custom URL to enable site search tracking.
#26
For $url_custom, it would be more simple to do something like:
<?phpdrupal_add_js(array('googleAnalyticsPageURL' => ...), 'setting');
?>
And from JS,
pageTracker._trackPageview(Drupal.settings.googleAnalyticsPageURL).#27
Hook may help #392606: Is it possible to add custom _setVar on a single node? and #320679: Set Goals for new comments, nodes and signups .
#28
@drumm: logic wise this sounds difficult as we process the most code in hook_footer and hook_footer does not have the ability to add a JS setting to head... so core is blocking here :-(
#29
The preg_replace code has no
try{}andcatch (err) {}statement, without them the replace doesn't do anything.#30
Yeah, this needs an update.
#31
Damien (DamZ) proposed a much cleaner way of doing it:
<?php// use hook_preprocess_page or hook_init, etc.
function mymodule_block() {
$node = menu_get_object();
$your_ga_code = "pageTracker._trackEvent('Click', ${node->nid)";
$GLOBALS['conf']['googleanalytics_codesnippet_after'] .= $your_ga_code;
}
?>
The trick is that $GLOBALS['conf'] got flushed for every page request. so you can just use .= to append your GA code.
I've tested the code, and it works!! Thanks Damien!
#32
This is the most dirty way I can think of and not a way we go here.