Bundling in Fathom Analytics


If you haven’t seen Fathom Analytics yet, then please do. It’s a breath of fresh air in the web analytics space, and I argue that it’s a pretty good fit for WordPress sites. They offer free and paid plans however most of what I’ll be talking about relates to their free self-managed code.

Fathom now supports multiple websites

Earlier this year I setup a self-hosted instance of Fathom. It’s been working great for my own site, however it initially only supported one site per instance. Well no more. With Fathom v1.1 it now supports many sites per Fathom instance.

Switching from Jetpack stats to Fathom Analytics

Stats are pretty important as I use them to determine which hosting plan my customers require. Currently I rely on the free stats WordPress.com provides via Jetpack Stats which I use in via their API. Requiring Jetpack for stats is not a great solution, and also while their stats are accessible it’s not like you can just spin up a self-hosted version of their stats collection service. Moving to a full open source solution is the best for the long term. I’m planning to capture a year of stats with Fathom before I fully replace it with Jetpack Stats.

Deploying Fathom via a generated must-use plugin

I decided to roll out Fathom to my customers via a must-use plugin. It’s less likely to be deactivated and can be reapplied if it was removed due to a site migration or something else. I’ve begun this deployment process¬†manually from the command line. I may eventually automate this by adding some GUI to CaptainCore. The command is simple:¬†captaincore stats-deploy <sitename> <fathom-site-id>, which generates the following must-use plugin based on my custom configurations:

/wp-content/mu-plugins/anchorhost-stats.php

<?php

/**
 * Plugin Name: Anchor Hosting Stats
 * Description: Fathom Analytics tracking snippet for Anchor Hosting's bundled Fathom instance.
 * Version: 1.0
 * Author: Anchor Hosting
 * Author URI: https://anchor.host
 * Text Domain: anchorhost-stats
 */

function anchorhost_fathom_print_js_snippet() { ?>
<!-- Fathom - simple website analytics - https://github.com/usefathom/fathom -->
<script>
(function(f, a, t, h, o, m){
        a[h]=a[h]||function(){
                (a[h].q=a[h].q||[]).push(arguments)
        };
        o=f.createElement('script'),
        m=f.getElementsByTagName('script')[0];
        o.async=1; o.src=t; o.id='fathom-script';
        m.parentNode.insertBefore(o,m)
})(document, window, '//stats.anchor.host/tracker.js', 'fathom');
fathom('set', 'siteId', 'XXXXX');
fathom('trackPageview');
</script>
<!-- / Fathom -->
<?php

}

add_action( 'wp_head', 'anchorhost_fathom_print_js_snippet', 50 );

For WordPress multisite networks with domain mapping, I came up with the following approach which stores all of the domains and Fathom site IDs in a single PHP array. That outputs on the corresponding sub-site if a match is found.

<?php

/**
 * Plugin Name: Anchor Hosting Stats
 * Description: Fathom Analytics tracking snippet for Anchor Hosting's bundled Fathom instance.
 * Version: 1.0
 * Author: Anchor Hosting
 * Author URI: https://anchor.host
 * Text Domain: anchorhost-stats
 */

function anchorhost_fathom_print_js_snippet() {

        $current_site = get_blog_details();

        $fathom_site_ids = array(
                "domain-name1.com" => "ABCDE",
                "domain-name2.com" => "FGHIJ",
	            "domain-name3.com" => "KLMNO",
        );

        if ( array_key_exists( $current_site->domain, $fathom_site_ids ) ) {

                $fathom_site_id = $fathom_site_ids[$current_site->domain];
?>
<!-- Fathom - simple website analytics - https://github.com/usefathom/fathom <?php echo $current_site->domain; ?> -->
<script>
(function(f, a, t, h, o, m){
        a[h]=a[h]||function(){
                (a[h].q=a[h].q||[]).push(arguments)
        };
        o=f.createElement('script'),
        m=f.getElementsByTagName('script')[0];
        o.async=1; o.src=t; o.id='fathom-script';
        m.parentNode.insertBefore(o,m)
})(document, window, '//stats.anchor.host/tracker.js', 'fathom');
fathom('set', 'siteId', '<?php echo $fathom_site_id; ?>');
fathom('trackPageview');
</script>
<!-- / Fathom -->
<?php
        }

}

add_action( 'wp_head', 'anchorhost_fathom_print_js_snippet', 50 );

Generating the plugin using bash script

The above must-use plugin(s) are the output of the following bash script deploy-fathom.sh which is deployed via SSH. The bash script allows the plugins to be generated with greater control and flexibility.

#!/usr/bin/env bash

#
#   Deploy Fathom
#
#   `deploy-fathom.sh --tracker=<tracker-domain> --id=<site-id> --branding_author=<captaincore_branding_author> --branding_author_uri=<captaincore_branding_author_uri> --branding_slug=<captaincore_branding_slug>`
#

# Loop through arguments and separate regular arguments from flags
for arg in "$@"; do

  # Add to arguments array. (Does not starts with "--")
  if [[ $arg != --* ]]; then
    count=1+${#arguments[*]}
    arguments[$count]=$arg
    continue
  fi

  # Remove leading "--"
  flag_name=$( echo $arg | cut -c 3- )

  # Add to flags array
  count=1+${#flags[*]}
  flags[$count]=$arg

  # Process flags without data (Assign to variable)
  if [[ $arg != *"="* ]]; then
    flag_name=${flag_name//-/_}
    declare "$flag_name"=true
  fi

  # Process flags with data (Assign to variable)
  if [[ $arg == *"="* ]]; then
    flag_value=$( echo $flag_name | perl -n -e '/.+?=(.+)/&& print $1' ) # extract value
    flag_name=$( echo $flag_name | perl -n -e '/(.+?)=.+/&& print $1' ) # extract name
    flag_name=${flag_name/-/_}

    # Remove first and last quote if found
    flag_value="${flag_value%\"}"
    flag_value="${flag_value#\"}"

    declare "$flag_name"="$flag_value"
    continue
  fi

done

# Generate must-use plugin
read -r -d '' build_mu_plugin << heredoc
<?php

/**
 * Plugin Name: $branding_author Stats
 * Description: Fathom Analytics tracking snippet for ${branding_author}'s bundled Fathom instance.
 * Version: 1.0
 * Author: $branding_author
 * Author URI: $branding_author_uri
 * Text Domain: ${branding_slug}-stats
 */

function ${branding_slug}_fathom_print_js_snippet() { ?>
<!-- Fathom - simple website analytics - https://github.com/usefathom/fathom -->
<script>
(function(f, a, t, h, o, m){
	a[h]=a[h]||function(){
		(a[h].q=a[h].q||[]).push(arguments)
	};
	o=f.createElement('script'),
	m=f.getElementsByTagName('script')[0];
	o.async=1; o.src=t; o.id='fathom-script';
	m.parentNode.insertBefore(o,m)
})(document, window, '//$tracker/tracker.js', 'fathom');
fathom('set', 'siteId', '$id');
fathom('trackPageview');
</script>
<!-- / Fathom -->
<?php

}

add_action( 'wp_head', '${branding_slug}_fathom_print_js_snippet', 50 );
heredoc

echo "Generating 'wp-content/mu-plugins/${branding_slug}-stats.php'"
echo "$build_mu_plugin" > wp-content/mu-plugins/${branding_slug}-stats.php