Installing Google Tag Manager on WordPress | Blue Frog Docs

Installing Google Tag Manager on WordPress

Complete guide to implementing GTM on WordPress using plugins, manual installation, and child themes

Installing Google Tag Manager on WordPress

Google Tag Manager (GTM) provides centralized control over all tracking tags without editing WordPress theme files. This guide covers WordPress-specific GTM implementation methods.

Why Use GTM with WordPress?

Benefits for WordPress Sites

  • No theme edits needed to add/modify tags
  • Marketing autonomy - update tracking without developer help
  • Version control - track changes and rollback if needed
  • Conflict prevention - avoid plugin conflicts from multiple analytics tools
  • Performance - lazy load tags, fire only when needed
  • Testing - preview mode validates tags before publishing

Use Cases

  • Multiple tracking tools (GA4, Meta Pixel, LinkedIn Insight, etc.)
  • Marketing teams need to deploy tags frequently
  • A/B testing platforms (Google Optimize, VWO, Optimizely)
  • Event tracking for forms, buttons, downloads
  • E-commerce with complex WooCommerce tracking

Prerequisites

  1. Create GTM Account

    • Go to tagmanager.google.com
    • Click Create Account
    • Enter account details
    • Create container (select Web)
    • Copy your Container ID (format: GTM-XXXXXX)
  2. Copy Installation Code

    • GTM provides two code snippets:
      • Head snippet - goes in <head>
      • Body snippet - goes after opening <body> tag

Installation Methods

Method 1: GTM Plugin (Easiest)

Best for: Non-technical users, quick setup, minimal configuration

1. GTM4WP (Google Tag Manager for WordPress)

Most comprehensive GTM plugin with 200,000+ active installations.

Installation:

  1. Navigate to Plugins → Add New
  2. Search for "GTM4WP" or "DuracellTomi's Google Tag Manager"
  3. Click Install NowActivate

Configuration:

Settings → Google Tag Manager

Basic Settings:
Google Tag Manager ID: GTM-XXXXXX

✓ Include GTM noscript in body
✓ Placement of the GTM code: Default (in header)
□ Track logged in admins (disable for clean data)

Events:
✓ Track outbound links
✓ Track downloads
✓ Track form submissions
✓ Track internal search

Advanced:
✓ Fire tags on DOM Ready (for Elementor/Divi compatibility)

WooCommerce Integration:

Integration → WooCommerce

✓ Enable tracking of ecommerce data
✓ Track classic ecommerce
✓ Track enhanced ecommerce

Product Data:
✓ Include tax in prices
✓ Include shipping in prices
✓ Use SKU instead of product ID

Events to track:
✓ Product impressions on listings
✓ Product detail views
✓ Add to cart
✓ Remove from cart
✓ Checkout steps
✓ Purchases

Verify Installation:

// Check if GTM4WP is active and configured
if (function_exists('gtm4wp_get_the_gtm_tag')) {
    echo 'GTM4WP is active';
}
2. Simple GTM

Lightweight alternative without e-commerce features.

Installation:

1. Install "Simple GTM" plugin
2. Go to Settings → Simple GTM
3. Enter Container ID: GTM-XXXXXX
4. Choose placement: Header (recommended)
5. Save changes
3. Google Site Kit

If already using Site Kit for GA4, you can add GTM:

Site Kit → Settings → Connect More Services → Tag Manager
Enter Container ID → Complete Setup

Plugin Comparison

Feature GTM4WP Simple GTM Site Kit
Setup Difficulty Easy Easiest Easy
Data Layer Support Full Basic Basic
WooCommerce Integration Automatic Manual Manual
Event Tracking Automatic Manual Manual
Page Weight ~100 KB ~20 KB ~150 KB
Free Yes Yes Yes

Method 2: Manual Theme Integration (Most Control)

Best for: Developers, custom themes, performance optimization

Step 1: Create Child Theme

Always use a child theme to prevent losing changes during theme updates.

/wp-content/themes/your-child-theme/
├── functions.php
├── style.css

style.css:

/*
Theme Name: Your Child Theme
Template: parent-theme-folder
Version: 1.0.0
*/

functions.php:

<?php
// Enqueue parent theme styles
add_action('wp_enqueue_scripts', 'child_theme_enqueue_styles');
function child_theme_enqueue_styles() {
    wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');
}

Step 2: Add GTM Head Code

// Add to functions.php
add_action('wp_head', 'add_gtm_head', 1);
function add_gtm_head() {
    // Don't load for admin users (optional)
    if (current_user_can('manage_options')) {
        return;
    }

    $gtm_id = 'GTM-XXXXXX'; // Replace with your Container ID
    ?>
    <!-- Google Tag Manager -->
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer','<?php echo $gtm_id; ?>');</script>
    <!-- End Google Tag Manager -->
    <?php
}

Step 3: Add GTM Body Code

The body snippet is trickier because wp_body_open hook support varies by theme.

Option A: Using wp_body_open hook (WordPress 5.2+):

add_action('wp_body_open', 'add_gtm_body', 1);
function add_gtm_body() {
    if (current_user_can('manage_options')) {
        return;
    }

    $gtm_id = 'GTM-XXXXXX';
    ?>
    <!-- Google Tag Manager (noscript) -->
    <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=<?php echo $gtm_id; ?>"
    height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <!-- End Google Tag Manager (noscript) -->
    <?php
}

Option B: Direct header.php edit (if wp_body_open not supported):

Create header.php in your child theme:

<?php
// Copy content from parent theme's header.php
// Then add immediately after <body> tag:
?>
<body <?php body_class(); ?>>
<?php
// Add GTM noscript here
$gtm_id = 'GTM-XXXXXX';
?>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=<?php echo $gtm_id; ?>"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
<?php
// Rest of header.php content...
?>

Method 3: Using Code Snippets Plugin

Best for: Users comfortable with code but want plugin management

  1. Install Code Snippets Plugin

    • Plugins → Add New
    • Search "Code Snippets"
    • Install and activate
  2. Add GTM Head Snippet

    Snippets → Add New
    Name: GTM Head Code
    Code:
    
    add_action('wp_head', 'custom_gtm_head', 1);
    function custom_gtm_head() {
        ?>
        <!-- Google Tag Manager -->
        <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
        new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
        j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
        'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
        })(window,document,'script','dataLayer','GTM-XXXXXX');</script>
        <!-- End Google Tag Manager -->
        <?php
    }
    
  3. Add GTM Body Snippet

    Snippets → Add New
    Name: GTM Body Code
    Code:
    
    add_action('wp_body_open', 'custom_gtm_body', 1);
    function custom_gtm_body() {
        ?>
        <!-- Google Tag Manager (noscript) -->
        <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
        height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
        <!-- End Google Tag Manager (noscript) -->
        <?php
    }
    

WordPress-Specific Considerations

Caching Plugins

GTM generally works with caching, but verify:

WP Rocket:

// Usually no exclusions needed, but if issues occur:
add_filter('rocket_exclude_js', 'exclude_gtm_from_optimization');
function exclude_gtm_from_optimization($excluded) {
    $excluded[] = 'googletagmanager.com/gtm.js';
    return $excluded;
}

W3 Total Cache:

Performance → Minify → Never minify the following JS files:
googletagmanager.com/gtm.js

LiteSpeed Cache:

LiteSpeed Cache → Page Optimization → JS Excludes:
googletagmanager.com

Multisite Networks

For WordPress Multisite with different containers per site:

add_action('wp_head', 'multisite_gtm_head', 1);
function multisite_gtm_head() {
    $blog_id = get_current_blog_id();

    // Map blog IDs to GTM container IDs
    $gtm_ids = array(
        1 => 'GTM-MAIN',      // Main site
        2 => 'GTM-BLOG2',     // Blog 2
        3 => 'GTM-BLOG3'      // Blog 3
    );

    $gtm_id = isset($gtm_ids[$blog_id]) ? $gtm_ids[$blog_id] : 'GTM-DEFAULT';
    ?>
    <!-- Google Tag Manager -->
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer','<?php echo $gtm_id; ?>');</script>
    <!-- End Google Tag Manager -->
    <?php
}

Page Builders (Elementor, Divi, Beaver Builder)

GTM works with all major page builders:

  • Elementor: Ensure "DOM Ready" triggers in GTM
  • Divi: Use "Window Loaded" triggers for module interactions
  • Beaver Builder: Standard triggers work fine

Page Builder Compatibility Check:

// Adjust GTM firing for page builders
add_filter('wp_footer', 'pagebuilder_gtm_compatibility', 99);
function pagebuilder_gtm_compatibility() {
    if (did_action('elementor/loaded')) {
        ?>
        <script>
            // Ensure dataLayer is ready for Elementor
            window.dataLayer = window.dataLayer || [];
        </script>
        <?php
    }
}

AJAX and Single Page Applications (SPAs)

For WordPress sites using AJAX navigation (like Barba.js):

// Re-fire GTM on AJAX page transitions
document.addEventListener('ajaxPageLoad', function() {
    dataLayer.push({
        'event': 'virtualPageview',
        'pageUrl': window.location.pathname,
        'pageTitle': document.title
    });
});

Advanced Configuration

Environment-Based Containers

Use different GTM containers for staging vs. production:

add_action('wp_head', 'environment_based_gtm', 1);
function environment_based_gtm() {
    // Detect environment
    $environment = defined('WP_ENVIRONMENT_TYPE') ? WP_ENVIRONMENT_TYPE : 'production';

    // Set container ID based on environment
    $gtm_containers = array(
        'production' => 'GTM-PROD123',
        'staging' => 'GTM-STAGE456',
        'development' => 'GTM-DEV789'
    );

    $gtm_id = isset($gtm_containers[$environment]) ? $gtm_containers[$environment] : $gtm_containers['production'];
    ?>
    <!-- Google Tag Manager -->
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer','<?php echo $gtm_id; ?>');</script>
    <!-- End Google Tag Manager -->
    <?php
}

Delay GTM loading until user consents:

add_action('wp_head', 'gtm_with_consent', 1);
function gtm_with_consent() {
    ?>
    <script>
        // Initialize dataLayer before GTM
        window.dataLayer = window.dataLayer || [];

        // Wait for consent before loading GTM
        document.addEventListener('cookieConsentAccepted', function() {
            (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
            'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
            })(window,document,'script','dataLayer','GTM-XXXXXX');
        });
    </script>
    <?php
}

Performance Optimization

Preconnect to GTM domain for faster loading:

add_action('wp_head', 'gtm_preconnect', 1);
function gtm_preconnect() {
    echo '<link rel="preconnect" href="https://www.googletagmanager.com">';
    echo '<link rel="dns-prefetch" href="//www.googletagmanager.com">';
}

Validation and Testing

1. Install GTM Preview Extension

  • Install Tag Assistant
  • Navigate to tagmanager.google.com
  • Click Preview in your container
  • Enter your WordPress site URL
  • Verify container loads

2. Check Installation in Browser

// Open browser console and check:
console.log(window.google_tag_manager);
console.log(window.dataLayer);

// Should see GTM container object and dataLayer array

3. Verify Data Layer

// Check if dataLayer exists and has data
console.log(window.dataLayer);

// Example output:
// [
//   {gtm.start: 1234567890, event: "gtm.js"},
//   {event: "gtm.dom"},
//   {event: "gtm.load"}
// ]

4. GTM Debug Mode

In GTM interface:

  1. Click Preview
  2. Enter your WordPress URL
  3. Browse your site
  4. Check Tag Assistant panel for:
    • Tags Fired
    • Tags Not Fired
    • Data Layer
    • Variables

Common Installation Issues

GTM not loading:

  • Check browser console for errors
  • Verify Container ID is correct (format: GTM-XXXXXX)
  • Check if ad blockers are interfering
  • Ensure caching plugins aren't preventing script load

Data layer not populating:

Tags not firing:

  • Check triggers in GTM Preview mode
  • Verify DOM element selectors are correct
  • Ensure page builder content is loaded when tag fires

See Tracking Troubleshooting for detailed debugging.

Migrating from Direct GA4 to GTM

If you already have GA4 installed directly and want to migrate to GTM:

  1. Create GA4 Configuration Tag in GTM

    • New Tag → Google Analytics: GA4 Configuration
    • Enter Measurement ID
    • Trigger: All Pages
  2. Remove Direct GA4 Code from WordPress

    • Disable GA4 plugin, or
    • Remove manual GA4 code from theme
  3. Test in Preview Mode

    • Verify GA4 tag fires on all pages
    • Check Real-Time reports in GA4
  4. Publish GTM Container

  5. Monitor for 48 Hours

    • Compare traffic levels before/after migration
    • Verify all custom events still fire

Next Steps

// SYS.FOOTER