deconf / Analytics-Insights

GNU General Public License v2.0
5 stars 7 forks source link

Add filters for customization of gtag() output, allowing custom parameters and events to be inserted #7

Closed jerclarke closed 1 year ago

jerclarke commented 1 year ago

Thank you for this plugin, it does so much of what I need, but our project also requires some elements that are probably beyond the scope of your plugin, which is fine!

I am willing to create the JS for my customizations to the gtag() output from my own PHP plugin, and all I need are some small actions and filters in your code so I can hook into the correct place. I think these could be valuable to a lot of developers, and that your plugin is the perfect one for developers like me to build upon, as long as there are some hooks so we can create customized extensions.

This PR has two separate commits, sorry about that, I'm not that good at PRs.

The first one adds a filter during the setup of the gtag('config') command, so that I can insert custom parameters (dimensions) based on my own needs. This one is kind of weird because the code that's being filtered probably wasn't designed to have other people using it, but it works, as you can see in the demo code below.

The second one adds two actions in the actual output of the gtag code, one before and one after the main gtag('config') command for the tracker. I think having both present is important because some things may only work before or after (such as the gtag('set') command only working before the gtag('config') command). So far I am using these hooks to insert a second tracker, and to insert custom events based on jQuery, but there are many other uses I might make of them, as long as I have a spot to insert code. In the example below I insert a custom click event in the *_after action.

In both cases, these are just the simplest, most minimal ways of achieving what I need. I'm sure you could make them more elegant and fitting with your coding style if you wanted, so of course feel free to change them any way you need to. As long as I can insert custom parameters into the config command, and insert arbitrary JS before/after the config command, I will be extremely happy!

Here is my demo plugin that demonstrates both changes:

<?php
/**
 * Plugin Name: AIWP Jer's Filter Demo
 * Plugin URI: https://jerclarke.org
 * Description: Simple demo of the filters Jer is proposing to add to AIWP
 * Author: Jer Clarke
 * Version: 0.1
 * Author URI: https://jerclarke.org
 * Text Domain: jer-demo
 * Domain Path: /languages
 */

// Insert a custom parameter into the gtag('config') command
function jer_demo_insert_global_parameters($command_array, AIWP_Tracking_GlobalSiteTag $aiwp_tracker) {

    $command_array['fieldsobject']['demo_parameter'] = 'demo_value';

    return $command_array;
}
add_filter('aiwp_gtag_command', 'jer_demo_insert_global_parameters', 10, 2 );

// Add a custom click event with gtag('event') right after the tracker is registered
function demo_insert_ga_events_after_gtag() {

    $output = "
    jQuery(document).ready(function($) {
        $('body').on('click', '.entry-title', function() {
            gtag('event', 'select_content', {
               'content_type': 'entry_title'
            });
        });
    });
    ";

    echo $output;
}
add_action('aiwp_output_globalsitetag_trackingcode_after', 'demo_insert_ga_events_after_gtag');

Thank you so much for your consideration, and once again for all the work you do on this plugin!

deconf commented 1 year ago

Hi and thanks for the PR.

Can you send the original output of tracking code and the one you need to be outputed so I can check if that or part of that is achievable using the existing hooks?

Thank you

jerclarke commented 1 year ago

Sure, thanks!

Here's the before and after that the aiwp_gtag_command enables:

before

    gtag('config', 'G-YS89ZY2NZ3', {
        'allow_display_features': false
    });

after

    gtag('config', 'G-YS89ZY2NZ3', {
        'allow_display_features': false,
        'gv_screen_type': 'home',
        'gv_lingua_site': 'globalvoices_es',
        'gv_ab_homepage_intro_location': 'homepage_intro_top'
    });

Here's an example of stuff I insert before and after the tag with aiwp_output_globalsitetag_trackingcode_before and aiwp_output_globalsitetag_trackingcode_after actions:

before

    <!-- BEGIN AIWP v5.8.1 Global Site Tag - https://deconf.com/analytics-insights-for-wordpress/ -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-YS89ZY2NZ3"></script>
    <script>
    window.dataLayer = window.dataLayer || [];
    function gtag() {
        dataLayer.push(arguments);
    }
    gtag('js', new Date());

    gtag('config', 'G-YS89ZY2NZ3', {
        'allow_display_features': false
    });

    if (window.performance) {
        var timeSincePageLoad = Math.round(performance.now());
        gtag('event', 'timing_complete', {
            'name': 'load',
            'value': timeSincePageLoad,
            'event_category': 'JS Dependencies'
        });
    }
    </script>
    <!-- END AIWP Global Site Tag -->

after

    <!-- BEGIN AIWP v5.8.1 Global Site Tag - https://deconf.com/analytics-insights-for-wordpress/ -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-YS89ZY2NZ3"></script>
    <script>
    window.dataLayer = window.dataLayer || [];
    function gtag() {
        dataLayer.push(arguments);
    }
    gtag('js', new Date());

    // GV_GA_Manager->aiwp_output_globalsitetag_trackingcode_before()
    gtag('config', 'G-8KG160R08Q', {
        "gv_screen_type": "home",
        "gv_lingua_site": "globalvoices_es",
        "gv_ab_homepage_intro_location": "homepage_intro_top"
    });

    // Main AIWP output 
    gtag('config', 'G-YS89ZY2NZ3', {
        'allow_display_features': false
    });

    // GV_GA_Manager->aiwp_output_globalsitetag_trackingcode_after()
    jQuery(document).ready(function($) {
        $('body').on('click', '#cycled-features a', function() {
            gtag('event', 'select_content', {
                "content_type": "featured_post"
            });
        });
    });

    // Final AIWP output
    if (window.performance) {
        var timeSincePageLoad = Math.round(performance.now());
        gtag('event', 'timing_complete', {
            'name': 'load',
            'value': timeSincePageLoad,
            'event_category': 'JS Dependencies'
        });
    }
    </script>
    <!-- END AIWP Global Site Tag -->
deconf commented 1 year ago

Hi,

I think that this hook would be a very good choice for manipulating the analytics commands: https://github.com/deconf/Analytics-Insights/blob/5694cae6045226574d04c641b3f3e48d77d4563b/front/tracking-analytics.php#L450 If you have trouble using the above hook let me know and I will try to create an example of use. The commands can be manipulated using the get() and set() methods https://github.com/deconf/Analytics-Insights/blob/5694cae6045226574d04c641b3f3e48d77d4563b/front/tracking-analytics.php#L181

As for the jQuery script you need to add, wouldn't be better to add it in a separate tag using the standard WordPress hooks? For example AIWP outputs the tracking code with these hooks: https://github.com/deconf/Analytics-Insights/blob/5694cae6045226574d04c641b3f3e48d77d4563b/front/tracking-analytics.php#L221. You could simply hook right after it with the same effect.

jerclarke commented 1 year ago

Ok! Thank you so much! Very helpful.

For the insertion of parameters, yes you are right! I had looked at the existing aiwp_gtag_commands action, but because ->commands was protected, I thought it was a dead end. Of course you're right that ->set() and ->get() are the answer.

I've converted my work to use aiwp_gtag_commands and it's stable. Thanks!

For the outputting of JS alonside the AIWP stuff, I would much rather have a hook within AIWP to do so, for a few reasons:

Do those reasons make sense? Like you say I can probably live without this, but it strikes me as a pretty safe thing to add, and would make it a lot easier to insert things with confidence going forward. I used to use a similar plugin called "Google Analyticator", and it had a hook like this that was supremely useful.

deconf commented 1 year ago

Makes sense, I will drive some tests on it and merge it on next version.

Thanks again for your helpful feedback!

jerclarke commented 1 year ago

Bless you! Thanks so much! Looking forward to it :)

deconf commented 1 year ago

FYI

The actions were renamed as: aiwp_gtag_output_before and aiwp_gtag_output_after