From b6e1bcaeac53d710894f8ebf155e475c876a1bbc Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Mon, 13 Jul 2015 22:48:46 +0200 Subject: [PATCH] Setup/Tracking * added tracking code for Google Analytics - enabling is optional - add account in config to enable tracking * removed usage tracking - the results were just seriously depressing.. --- includes/utilities.php | 2 +- setup/db_structure.sql | 2 +- setup/setup.php | 6 - setup/updates/1445293761_01.sql | 2 + static/js/filters.js | 9 ++ static/js/global.js | 207 ++++++++++++++++++++++++++++++++ static/js/home.js | 2 + template/bricks/head.tpl.php | 51 +++++--- template/bricks/lvTabs.tpl.php | 2 +- 9 files changed, 256 insertions(+), 27 deletions(-) create mode 100644 setup/updates/1445293761_01.sql diff --git a/includes/utilities.php b/includes/utilities.php index 2e46a10d..1a4ff2ae 100644 --- a/includes/utilities.php +++ b/includes/utilities.php @@ -695,7 +695,7 @@ class Util ); public static $configCats = array( - 'Site', 'Caching', 'Account', 'Session', 'Site Reputation', 'Other' + 'Site', 'Caching', 'Account', 'Session', 'Site Reputation', 'Other', 'Google Analytics' ); public static $tcEncoding = '0zMcmVokRsaqbdrfwihuGINALpTjnyxtgevElBCDFHJKOPQSUWXYZ123456789'; diff --git a/setup/db_structure.sql b/setup/db_structure.sql index 80ef19c8..472d2d49 100644 --- a/setup/db_structure.sql +++ b/setup/db_structure.sql @@ -2432,7 +2432,7 @@ UNLOCK TABLES; LOCK TABLES `aowow_config` WRITE; /*!40000 ALTER TABLE `aowow_config` DISABLE KEYS */; -INSERT INTO `aowow_config` VALUES ('sql_limit_search','500',0,129,'default: 500 - max results for search'),('sql_limit_default','300',0,129,'default: 300 - max results for listviews'),('sql_limit_quicksearch','10',0,129,'default: 10 - max results for suggestions'),('sql_limit_none','0',0,129,'default: 0 - unlimited results (i wouldn\'t change that mate)'),('ttl_rss','60',0,129,'default: 60 - time to live for RSS (in seconds)'),('name','Aowow Database Viewer (ADV)',0,136,' - website title'),('name_short','Aowow',0,136,' - feed title'),('board_url','http://www.wowhead.com/forums?board=',0,136,' - another halfbaked javascript thing..'),('contact_email','feedback@aowow.org',0,136,' - displayed sender for auth-mails, ect'),('battlegroup','Pure Pwnage',0,136,' - pretend, we belong to a battlegroup to satisfy profiler-related Jscripts'),('debug','0',0,132,'default: 0 - disable cache, enable sql-errors, enable error_reporting'),('maintenance','1',0,132,'default: 0 - display brb gnomes and block access for non-staff'),('user_max_votes','50',0,129,'default: 50 - vote limit per day'),('force_ssl','0',0,132,'default: 0 - enforce SSL, if the server is behind a load balancer'),('locales','333',0,161,'default: 0x14D - allowed locales - 0:English, 2:French, 3:German, 6:Spanish, 8:Russian'),('screenshot_min_size','200',0,129,'default: 200 - minimum dimensions of uploaded screenshots in px (yes, it\'s square)'),('site_host','',0,136,' - points js to executable files'),('static_host','',0,136,' - points js to images & scripts'),('cache_decay','25200',1,129,'default: 60 * 60 * 7 - time to keep cache in seconds'),('cache_mode','1',1,161,'default: 1 - set cache method - 0:filecache, 1:memcached'),('cache_dir','',1,136,'default: cache/template - generated pages are saved here (requires CACHE_MODE: filecache)'),('acc_failed_auth_block','900',2,129,'default: 15 * 60 - how long an account is closed after exceeding FAILED_AUTH_COUNT (in seconds)'),('acc_failed_auth_count','5',2,129,'default: 5 - how often invalid passwords are tolerated'),('acc_allow_register','1',2,132,'default: 1 - allow/disallow account creation (requires AUTH_MODE: aowow)'),('acc_auth_mode','0',2,145,'default: 0 - source to auth against - 0:aowow, 1:TC auth-table, 2:external script'),('acc_create_save_decay','604800',2,129,'default: 604800 - time in wich an unconfirmed account cannot be overwritten by new registrations'),('acc_recovery_decay','300',2,129,'default: 300 - time to recover your account and new recovery requests are blocked'),('session_timeout_delay','3600',3,129,'default: 60 * 60 - non-permanent session times out in time() + X'),('session.gc_maxlifetime','604800',3,200,'default: 7*24*60*60 - lifetime of session data'),('session.gc_probability','1',3,200,'default: 0 - probability to remove session data on garbage collection'),('session.gc_divisor', 100, 3, 200, 'default: 100 - probability to remove session data on garbage collection'),('session_cache_dir','',3,136,'default: - php sessions are saved here. Leave empty to use php default directory.'),('rep_req_upvote','125',4,129,'default: 125 - required reputation to upvote comments'),('rep_req_downvote','250',4,129,'default: 250 - required reputation to downvote comments'),('rep_req_comment','75',4,129,'default: 75 - required reputation to write a comment / reply'),('rep_req_supervote','2500',4,129,'default: 2500 - required reputation for double vote effect'),('rep_req_votemore_base','2000',4,129,'default: 2000 - gains more votes past this threshold'),('rep_reward_register','100',4,129,'default: 100 - activated an account'),('rep_reward_upvoted','5',4,129,'default: 5 - comment received upvote'),('rep_reward_downvoted','0',4,129,'default: 0 - comment received downvote'),('rep_reward_good_report','10',4,129,'default: 10 - filed an accepted report'),('rep_reward_bad_report','0',4,129,'default: 0 - filed a rejected report'),('rep_reward_dailyvisit','5',4,129,'default: 5 - daily visit'),('rep_reward_user_warned','-50',4,129,'default: -50 - moderator imposed a warning'),('rep_reward_comment','1',4,129,'default: 1 - created a comment (not a reply) '),('rep_req_premium','25000',4,129,'default: 25000 - required reputation for premium status through reputation'),('rep_reward_upload','10',4,129,'default: 10 - suggested / uploaded video / screenshot was approved'),('rep_reward_article','100',4,129,'default: 100 - submitted an approved article/guide'),('rep_reward_user_suspended','-200',4,129,'default: -200 - moderator revoked rights'),('rep_req_votemore_add','250',4,129,'default: 250 - required reputation per additional vote past threshold'),('serialize_precision','4',5,65,' - some derelict code, probably unused'),('memory_limit','2048M',5,200,'default: 2048M - parsing spell.dbc is quite intense'),('default_charset','UTF-8',5,72,'default: UTF-8'); +INSERT INTO `aowow_config` VALUES ('sql_limit_search','500',0,129,'default: 500 - max results for search'),('sql_limit_default','300',0,129,'default: 300 - max results for listviews'),('sql_limit_quicksearch','10',0,129,'default: 10 - max results for suggestions'),('sql_limit_none','0',0,129,'default: 0 - unlimited results (i wouldn\'t change that mate)'),('ttl_rss','60',0,129,'default: 60 - time to live for RSS (in seconds)'),('name','Aowow Database Viewer (ADV)',0,136,' - website title'),('name_short','Aowow',0,136,' - feed title'),('board_url','http://www.wowhead.com/forums?board=',0,136,' - another halfbaked javascript thing..'),('contact_email','feedback@aowow.org',0,136,' - displayed sender for auth-mails, ect'),('battlegroup','Pure Pwnage',0,136,' - pretend, we belong to a battlegroup to satisfy profiler-related Jscripts'),('debug','0',0,132,'default: 0 - disable cache, enable sql-errors, enable error_reporting'),('maintenance','1',0,132,'default: 0 - display brb gnomes and block access for non-staff'),('user_max_votes','50',0,129,'default: 50 - vote limit per day'),('force_ssl','0',0,132,'default: 0 - enforce SSL, if the server is behind a load balancer'),('locales','333',0,161,'default: 0x14D - allowed locales - 0:English, 2:French, 3:German, 6:Spanish, 8:Russian'),('screenshot_min_size','200',0,129,'default: 200 - minimum dimensions of uploaded screenshots in px (yes, it\'s square)'),('site_host','',0,136,' - points js to executable files'),('static_host','',0,136,' - points js to images & scripts'),('cache_decay','25200',1,129,'default: 60 * 60 * 7 - time to keep cache in seconds'),('cache_mode','1',1,161,'default: 1 - set cache method - 0:filecache, 1:memcached'),('cache_dir','',1,136,'default: cache/template - generated pages are saved here (requires CACHE_MODE: filecache)'),('acc_failed_auth_block','900',2,129,'default: 15 * 60 - how long an account is closed after exceeding FAILED_AUTH_COUNT (in seconds)'),('acc_failed_auth_count','5',2,129,'default: 5 - how often invalid passwords are tolerated'),('acc_allow_register','1',2,132,'default: 1 - allow/disallow account creation (requires AUTH_MODE: aowow)'),('acc_auth_mode','0',2,145,'default: 0 - source to auth against - 0:aowow, 1:TC auth-table, 2:external script'),('acc_create_save_decay','604800',2,129,'default: 604800 - time in wich an unconfirmed account cannot be overwritten by new registrations'),('acc_recovery_decay','300',2,129,'default: 300 - time to recover your account and new recovery requests are blocked'),('session_timeout_delay','3600',3,129,'default: 60 * 60 - non-permanent session times out in time() + X'),('session.gc_maxlifetime','604800',3,200,'default: 7*24*60*60 - lifetime of session data'),('session.gc_probability','1',3,200,'default: 0 - probability to remove session data on garbage collection'),('session.gc_divisor', 100, 3, 200, 'default: 100 - probability to remove session data on garbage collection'),('session_cache_dir','',3,136,'default: - php sessions are saved here. Leave empty to use php default directory.'),('rep_req_upvote','125',4,129,'default: 125 - required reputation to upvote comments'),('rep_req_downvote','250',4,129,'default: 250 - required reputation to downvote comments'),('rep_req_comment','75',4,129,'default: 75 - required reputation to write a comment / reply'),('rep_req_supervote','2500',4,129,'default: 2500 - required reputation for double vote effect'),('rep_req_votemore_base','2000',4,129,'default: 2000 - gains more votes past this threshold'),('rep_reward_register','100',4,129,'default: 100 - activated an account'),('rep_reward_upvoted','5',4,129,'default: 5 - comment received upvote'),('rep_reward_downvoted','0',4,129,'default: 0 - comment received downvote'),('rep_reward_good_report','10',4,129,'default: 10 - filed an accepted report'),('rep_reward_bad_report','0',4,129,'default: 0 - filed a rejected report'),('rep_reward_dailyvisit','5',4,129,'default: 5 - daily visit'),('rep_reward_user_warned','-50',4,129,'default: -50 - moderator imposed a warning'),('rep_reward_comment','1',4,129,'default: 1 - created a comment (not a reply) '),('rep_req_premium','25000',4,129,'default: 25000 - required reputation for premium status through reputation'),('rep_reward_upload','10',4,129,'default: 10 - suggested / uploaded video / screenshot was approved'),('rep_reward_article','100',4,129,'default: 100 - submitted an approved article/guide'),('rep_reward_user_suspended','-200',4,129,'default: -200 - moderator revoked rights'),('rep_req_votemore_add','250',4,129,'default: 250 - required reputation per additional vote past threshold'),('serialize_precision','4',5,65,' - some derelict code, probably unused'),('memory_limit','2048M',5,200,'default: 2048M - parsing spell.dbc is quite intense'),('default_charset','UTF-8',5,72,'default: UTF-8'),('analytics_user','',6,136,'default: - enter your GA-user here to track site stats'); /*!40000 ALTER TABLE `aowow_config` ENABLE KEYS */; UNLOCK TABLES; diff --git a/setup/setup.php b/setup/setup.php index eb72fc75..21c65597 100644 --- a/setup/setup.php +++ b/setup/setup.php @@ -25,12 +25,6 @@ function finish() if (!getopt('d', ['delete'])) // generated with TEMPORARY keyword. Manual deletion is not needed CLISetup::log('generated dbc_* - tables kept available', CLISetup::LOG_INFO); - // send "i'm in use @" - ping - $u = !empty($_SERVER['USER']) ? $_SERVER['USER'] : 'NULL'; - $s = !empty($_SERVER['SSH_CONNECTION']) ? explode(' ', $_SERVER['SSH_CONNECTION'])[2] : 'NULL'; - if ($h = @fopen('http://aowow.meedns.com/ref?u='.$u.'&s='.$s, 'r')) - fclose($h); - die("\n"); } diff --git a/setup/updates/1445293761_01.sql b/setup/updates/1445293761_01.sql new file mode 100644 index 00000000..f58e5267 --- /dev/null +++ b/setup/updates/1445293761_01.sql @@ -0,0 +1,2 @@ +DELETE FROM `aowow_config` WHERE `cat` = 6; +INSERT INTO `aowow_config` VALUES ('analytics_user', '', 6, 0x88, 'default: - enter your GA-user here to track site stats'); diff --git a/static/js/filters.js b/static/js/filters.js index b4f2cafe..63e84edc 100644 --- a/static/js/filters.js +++ b/static/js/filters.js @@ -982,6 +982,11 @@ function fi_setCriteria(cr, crs, crv) { for (i = 0; i < _.length; ++i) { if (_[i].value == cr[0]) { _[i].selected = true; + + if (fi_Lookup(cr[0])) { + g_trackEvent('Filters', fi_type, fi_Lookup(cr[0]).name); + } + break; } } @@ -990,6 +995,10 @@ function fi_setCriteria(cr, crs, crv) { var a = $WH.ge('fi_addcriteria'); for (i = 1; i < cr.length && i < 5; ++i) { fi_criterionChange(fi_addCriterion(a, cr[i]), crs[i], crv[i]); + + if (fi_Lookup(cr[i])) { + g_trackEvent('Filters', fi_type, fi_Lookup(cr[i]).name); + } } } diff --git a/static/js/global.js b/static/js/global.js index 2a1e88b0..0fbc490c 100644 --- a/static/js/global.js +++ b/static/js/global.js @@ -184,6 +184,21 @@ function g_setInnerHtml(n, text, nodeType) { } } +function g_getFirstTextContent(node) { + for (var i = 0; i < node.childNodes.length; ++i) { + if (node.childNodes[i].nodeName == '#text') { + return node.childNodes[i].nodeValue; + } + + var ret = g_getFirstTextContent(node.childNodes[i]); + if (ret) { + return ret; + } + } + + return false; +} + function g_getTextContent(el) { var txt = ''; for (var i = 0; i < el.childNodes.length; ++i) { @@ -2383,6 +2398,8 @@ var ScreenshotViewer = new function() { imgDiv.innerHTML = html; if (!resizing) { + g_trackEvent('Screenshots', 'Show', screenshot.id + ( (screenshot.caption && screenshot.caption.length) ? ' (' + screenshot.caption + ')' : '')); + if (screenshot.url) { aOriginal.href = url; } @@ -2970,6 +2987,8 @@ var VideoViewer = new function() { computeDimensions(); if (!resizing) { + g_trackEvent('Videos', 'Show', video.id + (video.caption.length ? ' (' + video.caption + ')' : '')); + if (video.videoType == 1) { imgDiv.innerHTML = Markup.toHtml('[youtube=' + video.videoId + ' width=' + imgWidth + ' height=' + imgHeight + ' autoplay=true]', {mode:Markup.MODE_ARTICLE}); } @@ -4260,6 +4279,8 @@ function Tabs(opt) { if (this.onHide) { this.onHide = this.onHide.bind(this); } + + this.trackClick = Tabs.trackClick.bind(this); } Tabs.prototype = { @@ -4560,6 +4581,10 @@ Tabs.onShow = function(newTab, oldTab) { $WH.ge('tab-' + oldTab.id).style.display = 'none'; } + if (this.poundedTab != null || oldTab) { + this.trackClick(newTab); + } + _ = $WH.ge('tab-' + newTab.id); _.style.display = ''; @@ -4578,6 +4603,145 @@ Tabs.onShow = function(newTab, oldTab) { } }; +Tabs.trackClick = function(tab) +{ + if (!this.trackable || tab.tracked) { + return; + } + + g_trackEvent('Tabs', 'Show', this.trackable + ': ' + tab.id); + tab.tracked = 1; +} + +/* +TODO: Create "Tracking" class +*/ + +function g_trackPageview(tag) +{ + function track() + { + if (typeof ga == 'function') + ga('send', 'pageview', tag); + }; + + $(document).ready(track); +} + +function g_trackEvent(category, action, label, value) +{ + function track() + { + if (typeof ga == 'function') + ga('send', 'event', category, action, label, value); + }; + + $(document).ready(track); +} + +function g_attachTracking(node, category, action, label, value) +{ + var $node = $(node); + + $node.click(function() { g_trackEvent(category, action, label, value); }); +} + +function g_addAnalytics() +{ + var objs = { + 'home-logo': { + 'category': 'Homepage Logo', + 'actions': { + 'Click image': function(node) { return true; } + } + }, + 'home-featuredbox': { + 'category': 'Featured Box', + 'actions': { + 'Follow link': function(node) { return (node.parentNode.className != 'home-featuredbox-links'); }, + 'Click image': function(node) { return (node.parentNode.className == 'home-featuredbox-links'); } + } + }, + 'home-oneliner': { + 'category': 'Oneliner', + 'actions': { + 'Follow link': function(node) { return true; } + } + }, + 'sidebar-container': { + 'category': 'Page sidebar', + 'actions': { + 'Click image': function(node) { return true; } + } + }, + 'toptabs-promo': { + 'category': 'Page header', + 'actions': { + 'Click image': function(node) { return true; } + } + } + }; + + for (var i in objs) + { + var e = $WH.ge(i); + if (e) + g_addAnalyticsToNode(e, objs[i]); + } +} + +function g_getNodeTextId(node) +{ + var + id = null, + text = g_getFirstTextContent(node); + + if (text) + id = g_urlize(text); + else if (node.title) + id = g_urlize(node.title); + else if (node.id) + id = g_urlize(node.id); + + return id; +} + +function g_addAnalyticsToNode(node, opts, labelPrefix) +{ + if (!opts || !opts.actions || !opts.category) + { + if ($WH.isset('g_dev') && g_dev) + { + console.log('Tried to add analytics event without appropriate parameters.'); + console.log(node); + console.log(opts); + } + + return; + } + + var category = opts.category; + var tags = $WH.gE(node, 'a'); + for (var i = 0; i < tags.length; ++i) + { + var node = tags[i]; + var action = 'Follow link'; + for (var a in opts.actions) + { + if (opts.actions[a] && opts.actions[a](node)) + { + action = a; + break; + } + } + var label = (labelPrefix ? labelPrefix + '-' : '') + g_getNodeTextId(node); + + g_attachTracking(node, category, action, label); + } +} + +$(document).ready(g_addAnalytics); + var g_listviews = {}; function Listview(opt) { @@ -4997,6 +5161,8 @@ function Listview(opt) { id: this.id, onLoad: this.initialize.bind(this) }); + + this.tabClick = Tabs.trackClick.bind(this.tabs, this.tabs.tabs[this.tabIndex]); } else { this.initialize(); @@ -19521,6 +19687,39 @@ var ModelViewer = new function() { setTimeout(render, 1); } + var trackCode = ''; + if (opt.fromTag) + { + trackCode += 'Custom '; + switch (opt.type) + { + case 1: // npc + trackCode += 'NPC ' + opt.displayId + (opt.humanoid ? ' humanoid' : ''); break; + case 2: // object + trackCode += 'Object ' + opt.displayId; break; + case 3: // item + trackCode += 'Item ' + opt.displayId + ' Slot ' + (opt.slot | 0); break; + case 4: // item set + trackCode += 'Item set ' + equipList.join('.'); break; + } + } + else + { + switch (opt.type) + { + case 1: // npc + trackCode += 'NPC ' + (opt.typeId ? opt.typeId : ' DisplayID ' + opt.displayId); break; + case 2: // object + trackCode += 'Object ' + opt.typeId; break; + case 3: // item + trackCode += 'Item ' + opt.typeId; break; + case 4: // item set + trackCode += 'Item set ' + equipList.join('.'); break; + } + } + + g_trackEvent('Model Viewer', 'Show', g_urlize(trackCode)); + oldHash = location.hash; } @@ -20505,6 +20704,7 @@ Announcement.prototype = { // todo: iron out the quirks this.parentDiv.style.opacity = '100'; this.parentDiv.style.height = (this.parentDiv.offsetHeight + 10) + 'px'; // + margin-bottom of child + g_trackEvent('Announcements', 'Show', '' + this.name); }, hide: function() { @@ -20525,6 +20725,7 @@ Announcement.prototype = { }, markRead: function() { + g_trackEvent('Announcements', 'Close', '' + this.name); g_setWowheadCookie('announcement-' + this.id, 'closed'); // $WH.sc('announcement-' + this.id, 20, 'closed', "/", location.hostname); this.hide(); @@ -20538,6 +20739,12 @@ Announcement.prototype = { setText: function(text) { this.text = text; Markup.printHtml(this.text, this.parent + '-markup'); + g_addAnalyticsToNode($WH.ge(this.parent + '-markup'), { + 'category': 'Announcements', + 'actions': { + 'Follow link': function(node) { return true; } + } + }, this.id); } }; diff --git a/static/js/home.js b/static/js/home.js index 3ffc3654..05017e14 100644 --- a/static/js/home.js +++ b/static/js/home.js @@ -16,5 +16,7 @@ $(document).ready(function () { $('.home-featuredbox-links a').hover( function () { $(this).next('var').addClass('active') }, function () { $(this).next('var').removeClass('active') } + ).click(function () { g_trackEvent('Featured Box', 'Click', this.title) } + ).each( function () { g_trackEvent('Featured Box', 'Impression', this.title) } ) }); diff --git a/template/bricks/head.tpl.php b/template/bricks/head.tpl.php index b8efd5bf..f88e657a 100644 --- a/template/bricks/head.tpl.php +++ b/template/bricks/head.tpl.php @@ -1,12 +1,12 @@ - <?php echo htmlentities(implode(' - ', $this->title)); ?> + <?=htmlentities(implode(' - ', $this->title)); ?> - - - - - - + + + + + + \n"; @@ -23,22 +23,22 @@ foreach ($this->css as $css): endforeach; ?> - - - - - - - + + + + + + + \n"; @@ -51,5 +51,20 @@ foreach ($this->js as $js): endforeach; ?> + + + diff --git a/template/bricks/lvTabs.tpl.php b/template/bricks/lvTabs.tpl.php index a3775116..d53dfe57 100644 --- a/template/bricks/lvTabs.tpl.php +++ b/template/bricks/lvTabs.tpl.php @@ -24,7 +24,7 @@ if (!empty($this->gemScores)): // inherited from it endif; if ($isTabbed): - echo " var ".$tabVar." = new Tabs({parent: \$WH.ge('tabs-generic')});\n"; + echo " var ".$tabVar." = new Tabs({parent: \$WH.ge('tabs-generic')".(isset($this->type) ? ", trackable: '".ucfirst(Util::$typeStrings[$this->type]."'") : null)."});\n"; endif; foreach ($this->lvTabs as $lv):