Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #345 from niallkennedy/ga-js

track Facebook social actions in Google Analytics
  • Loading branch information...
commit 79719c827fe1c02de80eae6bdd4be7e3f9bde73a 2 parents a9b6334 + 1014575
@niallkennedy niallkennedy authored
View
74 extras/google-analytics.php
@@ -0,0 +1,74 @@
+<?php
+class Facebook_Google_Analytics {
+ /**
+ * Handle used in WordPress script queue
+ *
+ * @since 1.1.9
+ * @var string
+ */
+ const SCRIPT_HANDLE = 'facebook-google-analytics';
+
+ /**
+ * Add the Google Analytics initialization function to the Facebook for WordPress JavaScript queue to be executed after initialization of the Facebook JavaScript SDK
+ *
+ * @since 1.1.9
+ * @return string JavaScript code snippet
+ */
+ public static function add_to_queue() {
+ return 'if(FB_WP.queue && FB_WP.queue.add){FB_WP.queue.add(function(){FB_WP.extras.analytics.google.init()})}';
+ }
+
+ public static function javascript_file_path() {
+ return 'static/js/extras/analytics/google-analytics' . ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ) . '.js';
+ }
+
+ /**
+ * Echo JavaScript inline to match the style of the plugin
+ *
+ * @since 1.1.9
+ */
+ public static function inline() {
+ $js_file = dirname( dirname( __FILE__ ) ) . '/' . self::javascript_file_path();
+ if ( ! file_exists( $js_file ) )
+ return;
+
+ echo "\n" . file_get_contents( $js_file ) . self::add_to_queue() . "\n";
+ }
+
+ /**
+ * Act on queued Google Analytics tracker commands.
+ * Used to customize Google Analytics for WordPress by Yoast. The plugin only supports filters adding tracker object methods. We must echo our own JavaScript block to pass a function to the Google Analytics queue.
+ *
+ * @since 1.1.9
+ * @param array $command_array flat array of strings. each value includes a tracker object method and parameters later wrapped in brackets for conversion to an array
+ * @return array flat array of strings
+ */
+ public static function gaq_filter( $command_array ) {
+ self::enqueue();
+ return $command_array;
+ }
+
+ /**
+ * Enqueue our Google Analytics script
+ *
+ * @since 1.1.9
+ * @uses wp_enqueue_script()
+ */
+ public static function enqueue() {
+ wp_enqueue_script( self::SCRIPT_HANDLE, plugins_url( self::javascript_file_path(), dirname(__FILE__) ), array('facebook-jssdk'), '1.1.9', true );
+ add_action( 'wp_print_footer_scripts', array( 'Facebook_Google_Analytics', 'gaq_push' ), 11, 0 );
+ }
+
+ /**
+ * Add a Facebook queue item to the Google Analytics queue after Facebook Google Analytics code has loaded
+ *
+ * @since 1.1.9
+ */
+ public static function gaq_push() {
+ global $wp_scripts;
+
+ if ( isset( $wp_scripts ) && $wp_scripts->query( self::SCRIPT_HANDLE, 'done' ) )
+ echo '<script type="text/javascript">var _gaq=_gaq||[];_gaq.push(function(){' . self::add_to_queue() . '});</script>';
+ }
+}
+?>
View
67 facebook.php
@@ -123,7 +123,7 @@ public function register_js_sdk() {
wp_register_script( $handle, ( is_ssl() ? 'https' : 'http' ) . '://connect.facebook.net/' . $this->locale . '/' . ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? 'all/debug.js' : 'all.js' ), array(), null, true );
// register the script but take it back with an async load
- add_filter( 'script_loader_src', array( &$this, 'async_script_loader_src' ), 1, 2 );
+ add_filter( 'script_loader_src', array( 'Facebook_Loader', 'async_script_loader_src' ), 1, 2 );
$args = array(
'channelUrl' => plugins_url( 'channel.php', __FILE__ ),
@@ -140,11 +140,32 @@ public function register_js_sdk() {
// allow the publisher to short circuit the init through the filter
if ( ! empty( $args ) && isset( $wp_scripts ) ) {
- $wp_scripts->add_data( $handle, 'data', 'window.fbAsyncInit=function(){FB.init(' . json_encode( $args ) . ');' . apply_filters( 'facebook_jssdk_init_extras', '', isset( $this->credentials['app_id'] ) ? $this->credentials['app_id'] : '' ) . '}' );
+ $wp_scripts->add_data( $handle, 'data', 'var FB_WP=FB_WP||{};FB_WP.queue={_methods:[],flushed:false,add:function(fn){FB_WP.queue.flushed?fn():FB_WP.queue._methods.push(fn)},flush:function(){for(var fn;fn=FB_WP.queue._methods.shift();){fn()}FB_WP.queue.flushed=true}};window.fbAsyncInit=function(){FB.init(' . json_encode( $args ) . ');if(FB_WP && FB_WP.queue && FB_WP.queue.flush){FB_WP.queue.flush()}' . apply_filters( 'facebook_jssdk_init_extras', '', isset( $this->credentials['app_id'] ) ? $this->credentials['app_id'] : '' ) . '}' );
}
}
/**
+ * Proactively resolve Facebook JavaScript SDK domain name asynchronously before later use
+ *
+ * @since 1.1.9
+ * @link http://dev.chromium.org/developers/design-documents/dns-prefetching Chromium prefetch behavior
+ * @link https://developer.mozilla.org/en-US/docs/Controlling_DNS_prefetching Firefox prefetch behavior
+ */
+ public static function dns_prefetch_js_sdk(){
+ echo '<link rel="dns-prefetch" href="//connect.facebook.net" />' . "\n";
+ }
+
+ /**
+ * Enqueue the JavaScript SDK
+ *
+ * @since 1.1
+ * @uses wp_enqueue_script()
+ */
+ public static function enqueue_js_sdk() {
+ wp_enqueue_script( 'facebook-jssdk', false, array(), false, true );
+ }
+
+ /**
* Load Facebook JS SDK async
* Called from script_loader_src filter
*
@@ -153,14 +174,14 @@ public function register_js_sdk() {
* @param string $handle WordPress registered script handle
* @return string empty string if Facebook JavaScript SDK, else give back the src variable
*/
- public function async_script_loader_src( $src, $handle ) {
+ public static function async_script_loader_src( $src, $handle ) {
global $wp_scripts;
if ( $handle !== 'facebook-jssdk' )
return $src;
// @link https://developers.facebook.com/docs/reference/javascript/#loading
- $html = '<div id="fb-root"></div><script type="text/javascript">(function(d){var js,id="facebook-jssdk",ref=d.getElementsByTagName("script")[0];if(d.getElementById(id)){return;}js=d.createElement("script");js.id=id;js.async=true;js.src=' . json_encode( $src ) . ';ref.parentNode.insertBefore(js,ref);}(document));</script>' . "\n";
+ $html = '<div id="fb-root"></div><script type="text/javascript">(function(d){var id="facebook-jssdk";if(!d.getElementById(id)){var js=d.createElement("script"),ref=d.getElementsByTagName("script")[0];js.id=id,js.async=!0,js.src=' . json_encode( $src ) . ',ref.parentNode.insertBefore(js,ref)}})(document)</script>' . "\n";
if ( isset( $wp_scripts ) && $wp_scripts->do_concat )
$wp_scripts->print_html .= $html;
else
@@ -223,7 +244,9 @@ public function public_init() {
require_once( $this->plugin_directory . 'open-graph-protocol.php' );
add_action( 'wp_head', array( 'Facebook_Open_Graph_Protocol', 'add_og_protocol' ) );
- add_action( 'wp_enqueue_scripts', array( 'Facebook_Loader', 'enqueue_jssdk' ) );
+ add_action( 'wp_head', array( 'Facebook_Loader', 'dns_prefetch_js_sdk' ), 1, 0 );
+ add_action( 'wp_enqueue_scripts', array( 'Facebook_Loader', 'enqueue_js_sdk' ) );
+ self::plugin_extras();
// include comment count filters on all pages
if ( get_option( 'facebook_comments_enabled' ) ) {
@@ -292,16 +315,6 @@ public function public_init() {
}
/**
- * Enqueue the JavaScript SDK
- *
- * @since 1.1
- * @uses wp_enqueue_script()
- */
- public static function enqueue_jssdk() {
- wp_enqueue_script( 'facebook-jssdk', false, array(), false, true );
- }
-
- /**
* Initialize the backend, administrative views
*
* @since 1.1
@@ -389,8 +402,32 @@ public function set_locale() {
$this->locale = $locale;
}
}
+
+ /**
+ * Tie-in to popular site features handled by popular WordPress plugins
+ *
+ * @since 1.1.9
+ */
+ public static function plugin_extras() {
+ // add Google Analytics social trackers
+ if ( defined( 'GOOGLE_ANALYTICATOR_VERSION' ) && function_exists( 'add_google_analytics' ) && has_action( 'wp_head', 'add_google_analytics' ) !== false ) {
+ if ( ! class_exists( 'Facebook_Google_Analytics' ) )
+ require_once( dirname(__FILE__) . '/extras/google-analytics.php' );
+ add_action( 'google_analyticator_extra_js_after', array( 'Facebook_Google_Analytics', 'enqueue' ) );
+ }
+ if ( ( defined( 'GAWP_VERSION' ) && class_exists( 'GA_Filter' ) && has_action( 'wp_head', array( 'GA_Filter', 'spool_analytics' ) ) !== false ) ) {
+ if ( ! class_exists( 'Facebook_Google_Analytics' ) )
+ require_once( dirname(__FILE__) . '/extras/google-analytics.php' );
+ add_filter( 'yoast-ga-push-after-pageview', array( 'Facebook_Google_Analytics', 'gaq_filter' ) );
+ }
+ }
}
+/**
+ * Load plugin function during the WordPress init action
+ *
+ * @since 1.1
+ */
function facebook_loader_init() {
global $facebook_loader;
View
66 static/js/extras/analytics/google-analytics.js
@@ -0,0 +1,66 @@
+/*
+ * track Facebook JavaScript SDK events related to social plugins using Google Analytics social tracking feature.
+ *
+ * @version 1.1.9
+ */
+
+// Google Analytics queue
+var _gaq = _gaq || [];
+
+var FB_WP = FB_WP || {};
+FB_WP.extras = FB_WP.extras || {};
+FB_WP.extras.analytics = FB_WP.extras.analytics || {}
+FB_WP.extras.analytics.google = {
+ /**
+ * Tracks social interactions by iterating through each Google Analytics tracker on the page, calling its _trackSocial method
+ *
+ * @link https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiSocialTracking
+ * @param {string} socialAction The type of action
+ * @param {string} the action URL target
+ * @return a function that iterates over each tracker object and calls the _trackSocial method
+ */
+ trackSocialAction: function( socialAction, opt_target ) {
+ return function() {
+ var trackers = _gat._getTrackers();
+ for ( var i = 0, tracker; tracker = trackers[i]; i++ ) {
+ tracker._trackSocial( "facebook", socialAction, opt_target );
+ }
+ }
+ },
+
+ /**
+ * Attaches event handlers to Facebook JavaScript SDK social plugin button events
+ * Tracks creation of a Like, destruction of a Like, and a Send message sent
+ *
+ * @link https://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe/
+ */
+ addEventHandlers: function() {
+ try {
+ FB.Event.subscribe( "edge.create", function( opt_target ) {
+ _gaq.push( FB_WP.extras.analytics.google.trackSocialAction( "like", opt_target ) );
+ } );
+ FB.Event.subscribe( "edge.remove", function( opt_target ) {
+ _gaq.push( FB_WP.extras.analytics.google.trackSocialAction( "unlike", opt_target ) );
+ } );
+ FB.Event.subscribe( "message.send", function( opt_target ) {
+ _gaq.push( FB_WP.extras.analytics.google.trackSocialAction( "send", opt_target ) );
+ } );
+ FB.Event.subscribe( "comment.create", function( comment ) {
+ if ( comment.href ) {
+ _gaq.push( FB_WP.extras.analytics.google.trackSocialAction( "comment", comment.href ) );
+ }
+ } );
+ FB.Event.subscribe( "comment.remove", function( comment ) {
+ if ( comment.href ) {
+ _gaq.push( FB_WP.extras.analytics.google.trackSocialAction( "uncomment", comment.href ) );
+ }
+ } );
+ } catch (e) {}
+ },
+
+ init: function() {
+ if ( FB && FB.Event && FB.Event.subscribe ) {
+ FB_WP.extras.analytics.google.addEventHandlers();
+ }
+ }
+}
View
2  static/js/extras/analytics/google-analytics.min.js
@@ -0,0 +1,2 @@
+var _gaq=_gaq||[],FB_WP=FB_WP||{}
+FB_WP.extras=FB_WP.extras||{},FB_WP.extras.analytics=FB_WP.extras.analytics||{},FB_WP.extras.analytics.google={trackSocialAction:function(socialAction,opt_target){return function(){for(var tracker,trackers=_gat._getTrackers(),i=0;tracker=trackers[i];i++)tracker._trackSocial("facebook",socialAction,opt_target)}},addEventHandlers:function(){try{FB.Event.subscribe("edge.create",function(opt_target){_gaq.push(FB_WP.extras.analytics.google.trackSocialAction("like",opt_target))}),FB.Event.subscribe("edge.remove",function(opt_target){_gaq.push(FB_WP.extras.analytics.google.trackSocialAction("unlike",opt_target))}),FB.Event.subscribe("message.send",function(opt_target){_gaq.push(FB_WP.extras.analytics.google.trackSocialAction("send",opt_target))}),FB.Event.subscribe("comment.create",function(comment){comment.href&&_gaq.push(FB_WP.extras.analytics.google.trackSocialAction("comment",comment.href))}),FB.Event.subscribe("comment.remove",function(comment){comment.href&&_gaq.push(FB_WP.extras.analytics.google.trackSocialAction("uncomment",comment.href))})}catch(e){}},init:function(){FB&&FB.Event&&FB.Event.subscribe&&FB_WP.extras.analytics.google.addEventHandlers()}}
Please sign in to comment.
Something went wrong with that request. Please try again.