Coder Social home page Coder Social logo

spatie / laravel-googletagmanager Goto Github PK

View Code? Open in Web Editor NEW
392.0 23.0 56.0 104 KB

Easily setup and send data to Google Tag Manager in Laravel apps

Home Page: https://murze.be/2015/06/easily-setup-and-send-data-to-google-tag-manager-in-laravel-apps/

License: MIT License

PHP 87.07% Blade 12.93%

laravel-googletagmanager's Introduction

Google Tag Manager integration for Laravel

Latest Version on Packagist Software License Quality Score Total Downloads

An easy Google Tag Manager implementation for your Laravel 5 application.

Laravel 4 version: spatie/laravel4-googletagmanager

Spatie is a webdesign agency in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Google Tag Manager

Google Tag Manager allows you manage tracking and marketing optimization with AdWords, Google Analytics, et al. without editing your site code. One way of using Google Tag Manager is by sending data through a dataLayer variable in javascript after the page load and on custom events. This package makes managing the data layer easy.

For concrete examples of what you want to send through the data layer, check out Google Tag Manager's Developer Guide.

You'll also need a Google Tag Manager ID, which you can retrieve by signing up and creating an account for your website.

Install

You can install the package via Composer:

composer require spatie/laravel-googletagmanager

In Laravel 5.5 and up, the package will automatically register the service provider and facade

In L5.4 or below start by registering the package's the service provider and facade:

// config/app.php

'providers' => [
    ...
    Spatie\GoogleTagManager\GoogleTagManagerServiceProvider::class,
],

'aliases' => [
    ...
    'GoogleTagManager' => Spatie\GoogleTagManager\GoogleTagManagerFacade::class,
],

The facade is optional, but the rest of this guide assumes you're using the facade.

Next, publish the config files:

php artisan vendor:publish --provider="Spatie\GoogleTagManager\GoogleTagManagerServiceProvider" --tag="config"

Optionally publish the view files. It's not recommended to do this unless necessary so your views stay up-to-date in future package releases.

php artisan vendor:publish --provider="Spatie\GoogleTagManager\GoogleTagManagerServiceProvider" --tag="views"

If you plan on using the flash-functionality you must install the GoogleTagManagerMiddleware, after the StartSession middleware:

// app/Http/Kernel.php

protected $middleware = [
    ...
    \Illuminate\Session\Middleware\StartSession::class,
    \Spatie\GoogleTagManager\GoogleTagManagerMiddleware::class,
    ...
];

Configuration

The configuration file is fairly simple.

return [

    /*
     * The Google Tag Manager id, should be a code that looks something like "gtm-xxxx".
     */
    'id' => '',
    
    /*
     * Enable or disable script rendering. Useful for local development.
     */
    'enabled' => true,

    /*
     * If you want to use some macro's you 'll probably store them
     * in a dedicated file. You can optionally define the path
     * to that file here, and we will load it for you.
     */
    'macroPath' => '',
    
     /*
     * The key under which data is saved to the session with flash.
     */
    'sessionKey' => '_googleTagManager',

     /*
     * Configures the Google Tag Manager script domain.
     * Modify this value only if you're using "Google Tag Manage: Web Container" client
     * to serve gtm.js for your web container. Else, keep the default value.
     */
    'domain' => 'www.googletagmanager.com',
];

During development, you don't want to be sending data to your production's tag manager account, which is where enabled comes in.

Example setup:

return [
    'id' => 'GTM-XXXXXX',
    'enabled' => env('APP_ENV') === 'production',
    'macroPath' => app_path('Services/GoogleTagManager/Macros.php'),
    'sessionKey' => '_googleTagManager',
    // Base domain used in your GTM server container
    'domain' => 'gtm.yourdomain.com',
];

Usage

Basic Example

First you'll need to include Google Tag Manager's script. Google's docs recommend doing this right after the body tag.

{{-- layout.blade.php --}}
<html>
  <head>
    @include('googletagmanager::head')
    {{-- ... --}}
  </head>
  <body>
    @include('googletagmanager::body')
    {{-- ... --}}
  </body>
</html>

Your base dataLayer will also be rendered here. To add data, use the set() function.

// HomeController.php

public function index()
{
    GoogleTagManager::set('pageType', 'productDetail');

    return view('home');
}

This renders:

<html>
  <head>
    <script>dataLayer = [{"pageType":"productDetail"}];</script>
    <script>/* Google Tag Manager's script */</script>
    <!-- ... -->
  </head>
  <!-- ... -->
</html>

Flashing data for the next request

The package can also set data to render on the next request. This is useful for setting data after an internal redirect.

// ContactController.php

public function getContact()
{
    GoogleTagManager::set('pageType', 'contact');

    return view('contact');
}

public function postContact()
{
    // Do contact form stuff...

    GoogleTagManager::flash('formResponse', 'success');

    return redirect()->action('ContactController@getContact');
}

After a form submit, the following dataLayer will be parsed on the contact page:

<html>
  <head>
    <script>dataLayer = [{"pageType":"contact","formResponse":"success"}];</script>
    <script>/* Google Tag Manager's script */</script>
    <!-- ... -->
  </head>
  <!-- ... -->
</html>

Other Simple Methods

// Retrieve your Google Tag Manager id
$id = GoogleTagManager::id(); // GTM-XXXXXX

// Check whether script rendering is enabled
$enabled = GoogleTagManager::isEnabled(); // true|false

// Enable and disable script rendering
GoogleTagManager::enable();
GoogleTagManager::disable();

// Add data to the data layer (automatically renders right before the tag manager script). Setting new values merges them with the previous ones. Set also supports dot notation.
GoogleTagManager::set(['foo' => 'bar']);
GoogleTagManager::set('baz', ['ho' => 'dor']);
GoogleTagManager::set('baz.ho', 'doorrrrr');

// [
//   'foo' => 'bar',
//   'baz' => ['ho' => 'doorrrrr']
// ]

Dump

GoogleTagManager also has a dump() function to convert arrays to json objects on the fly. This is useful for sending data to the view that you want to use at a later time.

<a data-gtm-product='{!! GoogleTagManager::dump($product->toArray()) !!}' data-gtm-click>Product</a>
$('[data-gtm-click]').on('click', function(event) {
    event.preventDefault();
    var self = this;
    dataLayer.push({
        'event': 'productClick',
        'ecommerce': {
            'click': {
                'products': $(self).data('gtm-product')
            }
        },
        'eventCallback': function() {
            document.location = $(self).attr('href');
        }
    });
});

DataLayer

Internally GoogleTagManager uses the DataLayer class to hold and render data. This class is perfectly usable without the rest of the package for some custom implementations. DataLayer is a glorified array that has dot notation support and easily renders to json.

$dataLayer = new Spatie\GoogleTagManager\DataLayer();
$dataLayer->set('ecommerce.click.products', $products->toJson());
echo $dataLayer->toJson(); // {"ecommerce":{"click":{"products":"..."}}}

If you want full access to the GoogleTagManager instances' data layer, call the getDataLayer() function.

$dataLayer = GoogleTagManager::getDataLayer();

Macroable

Adding tags to pages can become a repetitive process. Since this package isn't supposed to be opinionated on what your tags should look like, the GoogleTagManager is macroable.

GoogleTagManager::macro('impression', function ($product) {
    GoogleTagManager::set('ecommerce', [
        'currencyCode' => 'EUR',
        'detail' => [
            'products' => [ $product->getGoogleTagManagerData() ]
        ]
    ]);
});

GoogleTagManager::impression($product);

In the configuration you can optionally set the path to the file that contains your macros.

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Postcardware

You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium.

We publish all received postcards on our company website.

Credits

License

The MIT License (MIT). Please see License File for more information.

laravel-googletagmanager's People

Contributors

1e4 avatar adrianmrn avatar akoepcke avatar bilfeldt avatar davidrushton avatar fransjooste1 avatar freekmurze avatar frittenkeez avatar igor-kamil avatar llaski avatar m1guelpf avatar mattdfloyd avatar mickaelperrin avatar mithredate avatar mkwsra avatar nbz4live avatar pdbreen avatar rdok avatar sebastiandedeyne avatar tonning avatar viktorasbuivydas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-googletagmanager's Issues

GTM id is empty

I need your help cant seem to pin point whats causing the problem I followed the steps in the documentation, seems like the id set in config was not passed or something.

<script async="" src="//www.google-analytics.com/analytics_debug.js"></script>
<script async="" src="https://www.google-analytics.com/analytics.js" style=""></script>
<script async="" src="//www.googletagmanager.com/gtm.js?id="></script>
<script>window.dataLayer = window.dataLayer || []; dataLayer = [{"foo":"bar"}];</script>
<noscript>&lt;iframe src="//www.googletagmanager.com/ns.html?id=" height="0" width="0" style="display:none;visibility:hidden"&gt;&lt;/iframe&gt;</noscript>

<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= '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer',''); </script>

-GET http://www.googletagmanager.com/gtm.js?id=

Error in Setup

Argument 1 passed to Illuminate\Session\Store::flash() must be of the type string, null given, called in F:\xampp\htdocs\ECD\ecd\vendor\spatie\laravel-googletagmanager\src\GoogleTagManagerMiddleware.php on line 54

DataLayer escapes unicode characters

For non-english websites data layer escapes unicode characters and causes bad product names in Analytics. Like this:

"impressions":[{"id":73,"name":"\u0643\u0648\u0633\u0646 \u06af\u0648\u0646\u06cc \u067e\u0648\u0634"]}

It happens in Spatie\GoogleTagManager\DataLayer class which:

return json_encode($this->data);

should be replaced with:

return json_encode($this->data, JSON_UNESCAPED_UNICODE);

Small error in readme

In the readme it states that the "enabled" configuration can be set like this:
'enabled' => app()->environment() === 'production',

This causes the following error, probably because the environment is not yet set at this point:

Fatal error: Uncaught ReflectionException: Class env does not exist in /home/vagrant/Code/barryvanveen/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 734
ReflectionException: Class env does not exist in /home/vagrant/Code/barryvanveen/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 734

I believe a better way to use this would be:
'enabled' => env('APP_ENV') === 'production',

Could this be fixed in the readme to help new users?

Cheers,

Barry

macro example

Hi, can you provide a file as an example of macro?.
i have this file in App\Helpers\Browse.php

<?php

use GoogleTagManager;

GoogleTagManager::macro('browse', function($order, array $products) {
    GoogleTagManager::set('event','list_view_item');

    foreach($products` as $product) {

        GoogleTagManager::set('ecommerce.' . $order . '.products', [
            [
                'id' => $product->hashed_id,
                'name' => $product->name,
                'price' => 1.0,
                'brand' => $product['user']->name,
                'geo' => $product['location']->name
            ]
        ]);
    }
});

and in config i added
'macroPath' => 'app/Helpers/Browse.php',

but I got Method browse does not exist.
and how do i declare multiple method in a single file?

Problem W3C with HTML Optimization - remove line breaks

Hi,

I have a problem when I activate HTML optimization (removing line breaks)

No space between attributes (error W3C)
...id=GTM-xxxxx"height="0" widt...

in file : laravel-googletagmanager/resources/views/body.blade.php

<noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ $id }}"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>

new code to correct the problem :

<noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ $id }}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>

Thanks

confirming property for google seach console broken since 2.6.7

during the improvement from #50 the code was enhanced with a new script tag in front of the <noscript> tag. This changes the code produced in the final page.

Current code output:

    <body>

    <script>
        function gtmPush() {
            window.dataLayer.push({...}});
        }
        addEventListener("load", gtmPush);
    </script>
    <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=XXX-XXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>

Beforehand it was:

    <body>

    <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=XXX-XXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>

On confirming a property for google seach console via tag manager, the generated tag manager code is not recognized properly, since the <noscript>tag is not following the <body> tag immediately.

See: https://support.google.com/webmasters/answer/9008080#google_tag_manager_verification&zippy=%2Ccontainer-snippet-in-google-tag-manager

I think the <script> tag should be placed after the <noscript> tag.

Non-static method should not be called statically

Good evening!

I just tried to install this package and immediately ran into this error. It seems like the methods on the facade are not static, but according to the readme they should be called statically.

My controller contains a call to the set-method like

use Spatie\GoogleTagManager\GoogleTagManager;

class Controller extends BaseController
{

    public function __construct()
    {
        GoogleTagManager::set('pageType', 'productDetail');

Which results in the following error: Non-static method Spatie\GoogleTagManager\GoogleTagManager::set() should not be called statically

It feels like I'm missing something obvious because the readme is so clear about how to call the facade. Could someone please have a look?

-- Barry

DataLayer is being overriden by head template

If you set dataLayer before the head template partial is included, the variable will be reset.
Some new cookie information handling requires specific dataLayer entries to be set before GTM is loaded, so it goes dataLayer --> cookie information script --> GTM script

multiple domains

I want to set tag manager id trough a function. Can you make that?

GTM Multiple environment snippet support

Hello,

I've recently had to overwrite the googletagmanager body & head templates to add in additional parameters gtm_auth and gtm_preview in order to support multiple GTM environments. Just wondering if this is something you'd be interested in adding?

I can potentially submit a PR if required?

Is it possible to push events after gtm?

Is it possible to use this package to push events after the gtm code has been fired off. For example.

0: {event: "impressionsExample", gtm.uniqueEventId: 0}
1: {gtm.start: "123456789", event: "gtm.js"m gtm.uniqueEventId: 1}
2: {event: "gtm.dom", gtm.uniqueEventId: 2}
3: {event: "gtm.load", gtm.uniqueEventId: 3}
4: {event: "loginExample", gtm.uniqueEventId: 4}

Would it be possible to use this package for the loginExample event?

Flashing data with octane

When using octane and googletagmanager->flash method to flash data to the next request, the flashed data persist in the datalayer object on all the other requests

Empty dataLayer yields array with empty array

The head script wraps the json_encode call in an array which results in an array of an empty array (I haven't added any variables yet).

dataLayer = [[]];

Should the hard-coded [] be removed?

dataLayer = {!! $dataLayer->toJson() !!};

instead of

dataLayer = [{!! $dataLayer->toJson() !!}];

Or perhaps there should be a check for an empty initial data layer?

dataLayer = @if($dataLayer) [{!! $dataLayer->toJson() !!}] @else [] @endif;

Will the dataLayer normally consist of an array containing a single object followed by push calls to add more values? Please forgive me as I'm still new to GTM.

How to use different Environments

Google now offers to use different Environments for the GTM code (GTM-ID ID is the same for all environments -> gtm_auth and gtm_preview are specific to the environments)
It seems that the customizing options only allow to set ID and enable/disable.

Has anyone implemented it using these options yet? How?

The objective is to also use GTM on Stage and Testing Environments but separate the data from Production (obviously).

GA4 Clear the previous ecommerce object.

For GA4 ecommerce this feature will be great:

Clear the ecommerce object
It's recommended that you use the following command to clear the ecommerce object prior to pushing an ecommerce event to the data layer. Clearing the object will prevent multiple ecommerce events on a page from affecting each other.

dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object.

<noscript> does not support dataLayer variables

DataLayer variables should be added to iframe URL as query parameters.

Docs: https://developers.google.com/tag-manager/devguide#adding-data-layer-variables-for-devices-without-javascript-support

Example snippet from docs:

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-XXXX&pageCategory=sports&visitorType=returning" height="0"
              width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

Error after Upgrade

See this error after Upgrade:

Argument 1 passed to Spatie\GoogleTagManager\ScriptViewCreator::__construct() must be an instance of Spatie\GoogleTagManager\GoogleTagManager, instance of Closure given (View: /root/emailfirst-web/resources/views/layouts/guest.blade.php)

GTM Code in Controller not firing

Hey, i'm not sure if this is just my setup, but i'm working on an application that needs to firing some purchase information off once the user has proceed through the checkout. I have created a macro and called that in the controller method that is being fired.

I can see from my debugging that this is actually being called but when I look at the tag manager debug and tag assistant I cannot see the data layer being sent across.

On the other hand if I make this call in the view, it fires successfully. For reasons, I need to be able to make these calls via the controller. I have the tags set up in tag manager to fire on an event rather than a page view so in theory it should work.

I'm not sure what info, snippets you might need so i'll just post the code for the macro and macro call. If there is anything else required, let me know. I'm honestly quite stumped with this.

GoogleTagManager::macro('purchase', function($order, array $products) {
    GoogleTagManager::set('event','transaction');

    GoogleTagManager::set('ecommerce.purchase.actionField',
        [
            'id' => $order->id,
            'affiliation' => '',
            'revenue'=> number_format($order->order_total, 2),
        ]);

    foreach($products as $product) {
        $product = (object) $product;

        GoogleTagManager::set('ecommerce.purchase.products', [
            [
                'name' => $product->name . ' - ' . number_format($product->unit_price, 2),
                'id' => $product->model_id,
                'price' => number_format($product->unit_price, 2),
                'brand' => '',
                'category' => $product->isVoucher ? 'Voucher' : 'Product',
                'quantity' => $product->quantity
            ]
        ]);
    }
});

And the call in the controller

GoogleTagManager::purchase($order, $basket->getLines()->toArray());

Thanks in advance.

Flash multiple eventes

Because of a redirect I have to use flash and wanted to push multiple events. It seems that everytime i do the flash method, the one i did before was overwritten. Is there another function or is that feature not possible at the moment?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.