├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Ipunkt │ └── LaravelAnalytics │ │ ├── AnalyticsFacade.php │ │ ├── AnalyticsServiceProvider.php │ │ ├── Contracts │ │ ├── AnalyticsProviderInterface.php │ │ └── TrackingBagInterface.php │ │ ├── Data │ │ ├── Campaign.php │ │ ├── Event.php │ │ └── Renderer │ │ │ ├── CampaignRenderer.php │ │ │ └── Renderer.php │ │ ├── Providers │ │ ├── GoogleAnalytics.php │ │ └── NoAnalytics.php │ │ └── TrackingBag.php └── config │ └── analytics.php └── tests └── .gitkeep /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | .idea -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.2 5 | - 7.3 6 | - 7.4 7 | 8 | before_script: 9 | - composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts --no-suggest 10 | 11 | script: phpunit 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Robert Kummer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Analytics tracking package for Laravel 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/ipunkt/laravel-analytics/v/stable.svg)](https://packagist.org/packages/ipunkt/laravel-analytics) [![Latest Unstable Version](https://poser.pugx.org/ipunkt/laravel-analytics/v/unstable.svg)](https://packagist.org/packages/ipunkt/laravel-analytics) [![License](https://poser.pugx.org/ipunkt/laravel-analytics/license.svg)](https://packagist.org/packages/ipunkt/laravel-analytics) [![Total Downloads](https://poser.pugx.org/ipunkt/laravel-analytics/downloads.svg)](https://packagist.org/packages/ipunkt/laravel-analytics) [![Building](https://api.travis-ci.org/ipunkt/laravel-analytics.svg?branch=master)](https://travis-ci.org/ipunkt/laravel-analytics) 4 | 5 | ## Quickstart 6 | 7 | ``` 8 | composer require ipunkt/laravel-analytics 9 | ``` 10 | 11 | You can use the facade `Analytics`. 12 | 13 | To your `.env` add these variables and set them to your liking: 14 | 15 | ``` 16 | ANALYTICS_PROVIDER=GoogleAnalytics 17 | ANALYTICS_TRACKING_ID=your-tracking-id 18 | ``` 19 | We support the whole configuration as environment variables. Please see Configuration section. 20 | 21 | Finally, just above your `` closing tag place, this code: 22 | 23 | ``` 24 | {!! Analytics::render() !!} 25 | ``` 26 | 27 | **You now have Google Analytics working. Enjoy!** 28 | 29 | 30 | ## Installation 31 | 32 | Add to your composer.json following lines 33 | 34 | "require": { 35 | "ipunkt/laravel-analytics": "~3.0" 36 | } 37 | 38 | Add `Ipunkt\LaravelAnalytics\AnalyticsServiceProvider::class,` to `providers` in `app/config/app.php`. 39 | 40 | Optional: Add `'Analytics' => Ipunkt\LaravelAnalytics\AnalyticsFacade::class,` to `aliases` in `app/config/app.php`. 41 | 42 | Run `php artisan vendor:publish --provider="Ipunkt\LaravelAnalytics\AnalyticsServiceProvider"` 43 | 44 | Then edit `analytics.php` in `config` to your needs. We do config merge in the service provider, so your local settings 45 | will stay the same. 46 | 47 | For laravel 7.x please use the 3.x release. 48 | 49 | "require": { 50 | "ipunkt/laravel-analytics": "~3.0" 51 | } 52 | 53 | For laravel 6.x please use the 2.x release. 54 | 55 | "require": { 56 | "ipunkt/laravel-analytics": "~2.0" 57 | } 58 | 59 | For php < 7.2 or laravel < 6.0 please use the 1.x release. 60 | 61 | "require": { 62 | "ipunkt/laravel-analytics": "~1.0" 63 | } 64 | 65 | ## Configuration 66 | 67 |
68 |
provider
Provider to use, possible Providers are: GoogleAnalytics, NoAnalytics
69 |
70 | 71 | ### Google Analytics 72 | 73 |
74 |
tracking_id
Tracking ID, Your tracking id for Google Analytics
75 |
tracking_domain
Tracking domain, unset or set to "auto" for automatic fallback
76 |
tracker_name
Tracker name
77 |
display_features
enabling the display features plugin, possible values: (true|false)
78 |
anonymize_ip
anonymize users ip, possible values: (true|false)
79 |
auto_track
auto tracking current pageview, possible values: (true|false)
80 |
debug
enabling the debug mode, possible values: (true|false)
81 |
optimize_id
enabling the optimze feature of [Google Analytics](https://support.google.com/optimize/answer/6262084)
82 |
83 | 84 | ### Environment-based Configuration 85 | 86 | You can configure the whole settings by changing/setting environment variables in your .env file. (Or .env.dusk file if you use Laravel Dusk). 87 | 88 | Here is the mapping of configuration value and the environment-based names: 89 |
90 |
tracking_id
ANALYTICS_TRACKING_ID
91 |
tracking_domain
ANALYTICS_TRACKING_DOMAIN (auto)
92 |
tracker_name
ANALYTICS_TRACKER_NAME (t0)
93 |
display_features
ANALYTICS_DISPLAY_FEATURES (false)
94 |
anonymize_ip
ANALYTICS_ANONYMIZE_IP (true)
95 |
auto_track
ANALYTICS_AUTO_TRACK (true)
96 |
debug
ANALYTICS_DEBUG (true on local environment)
97 |
optimize_id
ANALYTICS_OPTIMIZE_ID
98 |
99 | 100 | This behaviour was integrated with version 1.3.2. 101 | 102 | ### Other 103 | 104 |
105 |
disable_script_block
You can disable script block generation by configuration value, possible values: (true|false), false by default.
106 |
107 | 108 | ## Usage 109 | 110 | In controller action (or anywhere else) use following statement to track an event or page view: 111 | 112 | // tracking the current page view 113 | Analytics::trackPage(); // only necessary if `auto_track` is false or Analytics::disableAutoTracking() was called before 114 | 115 | // tracking an event 116 | Analytics::trackEvent('category', 'action'); 117 | 118 | // tracking a custom line 119 | Analytics::trackCustom("ga('send', ......"); // this line will be added within the tracking script 120 | 121 | You can set an optional campaign for the tracking: 122 | 123 | // creating a campaign 124 | $campaign = new \Ipunkt\LaravelAnalytics\Data\Campaign('Sales2016'); 125 | $campaign->setMedium('web')->setSource('IT Magazine')->setKeyword('Hot stuff'); 126 | Analytics::setCampaign($campaign); 127 | 128 | You can set an user id for the tracking: 129 | 130 | // creating a campaign 131 | Analytics::setUserId($userIdentificationHash); 132 | 133 | In your view or layout template (e.g. a blade template) use the following statement: 134 | 135 | {!! Analytics::render() !!} 136 | 137 | For Google Analytics you should place the statement right below the `body` tag 138 | 139 | {!! Analytics::render() !!} 140 | 141 | ### Dependency Injection 142 | 143 | You can inject the analytics provider by referencing the interface: 144 | 145 | class PageController extends Controller 146 | { 147 | public function show(\Ipunkt\LaravelAnalytics\Contracts\AnalyticsProviderInterface $analytics) 148 | { 149 | $analytics->setUserId(md5(\Auth::user()->id)); // identical to Analytics::setUserId(md5(\Auth::user()->id)); 150 | return view('welcome'); 151 | } 152 | } 153 | 154 | ## How to use 155 | 156 | The `GoogleAnalytics` Provider automatically controls the [local environment](https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced#localhost) behaviour for testing purposes. 157 | 158 | There is a builtin provider called `NoAnalytics`. This is for testing environments and tracks nothing. So you do 159 | not have to rewrite your code, simple select this `provider` in `analytics` configuration for your special environment 160 | configurations. 161 | 162 | ### Track a measurement without having javascript 163 | 164 | 1. Log in to Google Analytics and create custom definition. There you create a custom metrics. 165 | For example: Email opens, Integer type, min: 0 and max: 1 166 | This will be available as `metric1`. 167 | 168 | 2. Within your mail template (or page template) you have to create a tracking image 169 | 170 | `` 171 | 172 | 3. That's it 173 | 174 | ## Content Security Policy 175 | 176 | Since version 1.3 is a support for Content Security Policy integrated. 177 | 178 | Please call the `withCSP()` on the provider interface instance. 179 | 180 | Then use an additional package (or implement on your own) `martijnc/php-csp` and use the following code in your middleware or your javascript sending controller: 181 | ```php 182 | use Phpcsp\Security\ContentSecurityPolicyHeaderBuilder; 183 | 184 | $policy = new ContentSecurityPolicyHeaderBuilder(); 185 | 186 | // Set the default-src directive to 'none' 187 | $policy->addSourceExpression(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_DEFAULT_SRC, 'none'); 188 | 189 | // Add the nonce to the script-src directive 190 | $policy->addNonce(ContentSecurityPolicyHeaderBuilder::DIRECTIVE_SCRIPT_SRC, $analytics->withCSP()->cspNonce()); 191 | 192 | foreach ($policy->getHeaders(true) as $header) { 193 | header(sprintf('%s: %s', $header['name'], $header['value'])); 194 | } 195 | ``` 196 | 197 | The result looks like this: 198 | ```php 199 | array (size=1) 200 | 0 => 201 | array (size=2) 202 | 'name' => string 'Content-Security-Policy' (length=23) 203 | 'value' => string 'default-src 'none'; script-src 'nonce-RandomNonceStringFromAnalyticsProvider';' (length=58) 204 | ``` 205 | 206 | On rendering your analytics script the `nonce` attribute will be automatically added on your script tag. 207 | 208 | ## API Documentation 209 | 210 | For the correct usage methods look at the `Ipunkt\LaravelAnalytics\Contracts\AnalyticsProviderInterface.php` 211 | 212 | ### Analytics::render() 213 | 214 | Context: Blade Templates, View 215 | 216 | For rendering the correct javascript code. It is necessary to have it in all layout files to track your actions and page calls. 217 | 218 | /** 219 | * returns the javascript code for embedding the analytics stuff 220 | * 221 | * @return string 222 | */ 223 | public function render(); 224 | 225 | 226 | ### Analytics::trackPage() 227 | 228 | Context: Controller, Action code 229 | 230 | For tracking a page view. 231 | 232 | /** 233 | * track an page view 234 | * 235 | * @param null|string $page 236 | * @param null|string $title 237 | * @param null|string $hittype 238 | * @return void 239 | */ 240 | public function trackPage($page, $title, $hittype); 241 | 242 | 243 | ### Analytics::trackEvent() 244 | 245 | Context: Controller, Action code 246 | 247 | For tracking an event 248 | 249 | /** 250 | * track an event 251 | * 252 | * @param string $category 253 | * @param string $action 254 | * @param null|string $label 255 | * @param null|int $value 256 | * @return void 257 | */ 258 | public function trackEvent($category, $action, $label, $value); 259 | 260 | 261 | ### Analytics::trackCustom() 262 | 263 | Context: Controller, Action code 264 | 265 | For tracking a custom script line within the embedded analytics code. 266 | 267 | /** 268 | * track any custom code 269 | * 270 | * @param string $customCode 271 | * @return void 272 | */ 273 | public function trackCustom($customCode); 274 | 275 | 276 | ### Analytics::enableDisplayFeatures() 277 | 278 | Context: Controller, Action code 279 | 280 | Enabling display features, overriding the configuration setting `display_features`. 281 | 282 | /** 283 | * enable display features 284 | * 285 | * @return GoogleAnalytics 286 | */ 287 | public function enableDisplayFeatures(); 288 | 289 | 290 | ### Analytics::disableDisplayFeatures() 291 | 292 | Context: Controller, Action code 293 | 294 | Disabling display features, overriding the configuration setting `display_features`. 295 | 296 | /** 297 | * disable display features 298 | * 299 | * @return GoogleAnalytics 300 | */ 301 | public function disableDisplayFeatures(); 302 | 303 | ### Analytics::enableAutoTracking() 304 | 305 | Context: Controller, Action code 306 | 307 | Enabling the auto tracking, overriding the configuration setting `auto_track`. 308 | 309 | /** 310 | * enable auto tracking 311 | * 312 | * @return GoogleAnalytics 313 | */ 314 | public function enableAutoTracking(); 315 | 316 | 317 | ### Analytics::disableAutoTracking() 318 | 319 | Context: Controller, Action code 320 | 321 | Disabling the auto tracking, overriding the configuration setting `auto_track`. 322 | 323 | /** 324 | * disable auto tracking 325 | * 326 | * @return GoogleAnalytics 327 | */ 328 | public function disableAutoTracking(); 329 | 330 | ### Analytics::trackMeasurementUrl() 331 | 332 | Context: Blade Template, View 333 | 334 | Sometimes you have to track measurements, e.g. opening an email newsletter. There you have no javascript at all. 335 | 336 | /** 337 | * assembles an url for tracking measurement without javascript 338 | * 339 | * e.g. for tracking email open events within a newsletter 340 | * 341 | * @param string $metricName 342 | * @param mixed $metricValue 343 | * @param \Ipunkt\LaravelAnalytics\Data\Event $event 344 | * @param \Ipunkt\LaravelAnalytics\Data\Campaign $campaign 345 | * @param string|null $clientId 346 | * @param array $params 347 | * @return string 348 | */ 349 | public function trackMeasurementUrl($metricName, $metricValue, Event $event, Campaign $campaign, $clientId = null, array $params = array()); 350 | 351 | ### Analytics::setUserId($userId) 352 | 353 | Context: Controller, Action code 354 | 355 | Adding an user id to analytics tracking. This user id is a user-dependent unique id. But be careful, you should have no 356 | direct relation to the special user itself - it should be unique per user for analyzing. 357 | 358 | This user tracking is implemented at [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id). 359 | 360 | /** 361 | * sets an user id for user tracking 362 | * 363 | * @param string $userId 364 | * @return AnalyticsProviderInterface 365 | */ 366 | public function setUserId($userId); 367 | 368 | ### Analytics::unsetUserId() 369 | 370 | Context: Controller, Action code 371 | 372 | Removing of an user id is also possible. 373 | 374 | /** 375 | * unset an user id 376 | * 377 | * @return AnalyticsProviderInterface 378 | */ 379 | public function unsetUserId(); 380 | 381 | ### Analytics::setCampaign($campaign) 382 | 383 | Context: Controller, Action code 384 | 385 | Adding a campaign to the current tracking. 386 | 387 | This campaign tracking is documented for [Google Analytics](https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#campaignName). 388 | 389 | /** 390 | * sets a campaign 391 | * 392 | * @param Campaign $campaign 393 | * @return AnalyticsProviderInterface 394 | */ 395 | public function setCampaign(Campaign $campaign); 396 | 397 | ### Analytics::unsetCampaign() 398 | 399 | Context: Controller, Action code 400 | 401 | Removing of a campaign is also possible. 402 | 403 | /** 404 | * unset a possible given campaign 405 | * 406 | * @return AnalyticsProviderInterface 407 | */ 408 | public function unsetCampaign(); 409 | 410 | ### Analytics::enableScriptBlock() 411 | 412 | Context: Controller, Action code 413 | 414 | Enabling the rendering of the `` block tags. Is enabled by default, so you do not have to call this. 415 | 416 | /** 417 | * render script block 418 | * 419 | * @return GoogleAnalytics 420 | */ 421 | public function enableScriptBlock(); 422 | 423 | ### Analytics::disableScriptBlock() 424 | 425 | Context: Controller, Action code 426 | 427 | Disabling the rendering of the `` block tags. 428 | 429 | /** 430 | * do not render script block 431 | * 432 | * @return GoogleAnalytics 433 | */ 434 | public function disableScriptBlock(); 435 | 436 | ### Analytics::enableEcommerceTracking() 437 | 438 | Context: Controller, Action code 439 | 440 | Enabling ecommerce tracking. 441 | 442 | /** 443 | * enable ecommerce tracking 444 | * 445 | * @return AnalyticsProviderInterface 446 | */ 447 | public function enableEcommerceTracking(); 448 | 449 | ### Analytics::disableEcommerceTracking() 450 | 451 | Context: Controller, Action code 452 | 453 | Disabling ecommerce tracking. 454 | 455 | /** 456 | * disable ecommerce tracking 457 | * 458 | * @return AnalyticsProviderInterface 459 | */ 460 | public function disableEcommerceTracking(); 461 | 462 | ### Analytics::ecommerceAddTransaction() 463 | 464 | Context: Controller, Action code 465 | 466 | Add ecommerce transaction to tracking code. 467 | 468 | /** 469 | * ecommerce tracking - add transaction 470 | * 471 | * @param string $id 472 | * @param null|string $affiliation 473 | * @param null|float $revenue 474 | * @param null|float $shipping 475 | * @param null|float $tax 476 | * @param null|string $currency 477 | * 478 | * @return AnalyticsProviderInterface 479 | */ 480 | public function ecommerceAddTransaction($id, $affiliation = null, $revenue = null, $shipping = null, $tax = null, $currency = null); 481 | 482 | The [multi currency](https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce#multicurrency) tracking is supported with currency values defined [here](https://support.google.com/analytics/answer/6205902#supported-currencies). 483 | 484 | ### Analytics::ecommerceAddItem() 485 | 486 | Context: Controller, Action code 487 | 488 | Add ecommerce item to tracking code. 489 | 490 | /** 491 | * ecommerce tracking - add item 492 | * 493 | * @param string $id 494 | * @param string $name 495 | * @param null|string $sku 496 | * @param null|string $category 497 | * @param null|float $price 498 | * @param null|int $quantity 499 | * @param null|string $currency 500 | * 501 | * @return AnalyticsProviderInterface 502 | */ 503 | public function ecommerceAddItem($id, $name, $sku = null, $category = null, $price = null, $quantity = null, $currency = null); 504 | 505 | The [multi currency](https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce#multicurrency) tracking is supported with currency values defined [here](https://support.google.com/analytics/answer/6205902#supported-currencies). 506 | 507 | ### Analytics::setCustom() 508 | 509 | Context: Controller, Action code 510 | 511 | Adds custom settings. 512 | 513 | /** 514 | * sets custom dimensions 515 | * 516 | * @param string|array $dimension 517 | * @param null|string $value 518 | * @return AnalyticsProviderInterface 519 | */ 520 | public function setCustom($dimension, $value = null) 521 | 522 | ### Analytics::withCSP() 523 | 524 | Context: Controller, Action code 525 | 526 | Enabling the Content Security Policy feature. 527 | 528 | /** 529 | * enables Content Security Polity and sets nonce 530 | * 531 | * @return AnalyticsProviderInterface 532 | */ 533 | public function withCSP(); 534 | 535 | ### Analytics::withoutCSP() 536 | 537 | Context: Controller, Action code 538 | 539 | Disabling the Content Security Policy feature. 540 | 541 | /** 542 | * disables Content Security Polity 543 | * 544 | * @return AnalyticsProviderInterface 545 | */ 546 | public function withoutCSP(); 547 | 548 | ### Analytics::cspNonce() 549 | 550 | Context: Controller, Action code 551 | 552 | Returns the nonce generated for the Content Security Policy Header. 553 | 554 | /** 555 | * returns the current Content Security Policy nonce 556 | * 557 | * @return string|null 558 | */ 559 | public function cspNonce(); 560 | 561 | ### Analytics::setOptimizeId() 562 | 563 | /** 564 | * set a custom optimize ID (the GTM-XXXXXX code) 565 | * 566 | * @param string $optimizeId 567 | * 568 | * @return AnalyticsProviderInterface 569 | */ 570 | public function setOptimizeId($optimizeId); 571 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ipunkt/laravel-analytics", 3 | "type": "library", 4 | "description": "Analytics tracking for Laravel", 5 | "keywords": ["analytics", "google analytics", "laravel", "statistics", "javascript", "php"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Robert Kummer", 10 | "email": "r.kummer@ipunkt.biz" 11 | } 12 | ], 13 | "require": { 14 | "php": "^7.2 || ^8.0", 15 | "illuminate/config": "~5.0 || ^6.20 || ^7.24 || ^8.40", 16 | "illuminate/session": "~5.0 || ^6.20 || ^7.24 || ^8.40", 17 | "illuminate/support": "~5.0 || ^6.20 || ^7.24 || ^8.40" 18 | }, 19 | "require-dev": { 20 | "laravel/framework": "~5.0 || ^6.20 || ^7.24 || ^8.40" 21 | }, 22 | "autoload": { 23 | "psr-0": { 24 | "Ipunkt\\LaravelAnalytics\\": "src/" 25 | } 26 | }, 27 | "minimum-stability": "stable", 28 | "suggest": { 29 | "martijnc/php-csp": "For handling Content Security Policy matters" 30 | }, 31 | "support": { 32 | "issues": "https://github.com/ipunkt/laravel-analytics/issues", 33 | "source": "https://github.com/ipunkt/laravel-analytics/archive/master.zip" 34 | }, 35 | "extra": { 36 | "laravel": { 37 | "providers": [ 38 | "Ipunkt\\LaravelAnalytics\\AnalyticsServiceProvider" 39 | ], 40 | "aliases": { 41 | "Analytics": "Ipunkt\\LaravelAnalytics\\AnalyticsFacade" 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/AnalyticsFacade.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom($config, 'analytics'); 27 | 28 | $this->publishes([ 29 | $config => config_path('analytics.php'), 30 | ]); 31 | } 32 | 33 | /** 34 | * Register the service provider. 35 | * 36 | * @return void 37 | */ 38 | public function register() 39 | { 40 | $this->app->singleton('Ipunkt\LaravelAnalytics\Contracts\AnalyticsProviderInterface', 41 | function () { 42 | // get analytics provider name 43 | $provider = Config::get('analytics.provider'); 44 | 45 | // make it a class 46 | $providerClass = 'Ipunkt\LaravelAnalytics\Providers\\' . $provider; 47 | 48 | // getting the config 49 | $providerConfig = []; 50 | if (Config::has('analytics.configurations.' . $provider)) { 51 | $providerConfig = Config::get('analytics.configurations.' . $provider); 52 | } 53 | 54 | // make provider instance 55 | $instance = new $providerClass($providerConfig); 56 | 57 | // check if we want to prematurely disable the script block 58 | if (Config::get('analytics.disable_script_block', false)) { 59 | $instance->disableScriptBlock(); 60 | } 61 | 62 | return $instance; 63 | }); 64 | } 65 | 66 | /** 67 | * Get the services provided by the provider. 68 | * 69 | * @return array 70 | */ 71 | public function provides() 72 | { 73 | return []; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/Contracts/AnalyticsProviderInterface.php: -------------------------------------------------------------------------------- 1 | nonInteraction(true)->render(); 123 | * getting: if ($this->nonInteraction()) echo 'non-interaction set'; 124 | * 125 | * @param boolean|null $value 126 | * 127 | * @return bool|AnalyticsProviderInterface 128 | */ 129 | public function nonInteraction($value = null); 130 | 131 | /** 132 | * sets an user id for user tracking 133 | * 134 | * @param string $userId 135 | * 136 | * @return AnalyticsProviderInterface 137 | * 138 | * @see https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id 139 | */ 140 | public function setUserId($userId); 141 | 142 | /** 143 | * unsets a possible given user id 144 | * 145 | * @return AnalyticsProviderInterface 146 | */ 147 | public function unsetUserId(); 148 | 149 | /** 150 | * sets a campaign 151 | * 152 | * @param Campaign $campaign 153 | * 154 | * @return AnalyticsProviderInterface 155 | */ 156 | public function setCampaign(Campaign $campaign); 157 | 158 | /** 159 | * unsets a possible given campaign 160 | * 161 | * @return AnalyticsProviderInterface 162 | */ 163 | public function unsetCampaign(); 164 | 165 | /** 166 | * enable ecommerce tracking 167 | * 168 | * @return AnalyticsProviderInterface 169 | */ 170 | public function enableEcommerceTracking(); 171 | 172 | /** 173 | * disable ecommerce tracking 174 | * 175 | * @return AnalyticsProviderInterface 176 | */ 177 | public function disableEcommerceTracking(); 178 | 179 | /** 180 | * ecommerce tracking - add transaction 181 | * 182 | * @param string $id 183 | * @param null|string $affiliation 184 | * @param null|float $revenue 185 | * @param null|float $shipping 186 | * @param null|float $tax 187 | * @param null|string $currency 188 | * 189 | * @return AnalyticsProviderInterface 190 | */ 191 | public function ecommerceAddTransaction( 192 | $id, 193 | $affiliation = null, 194 | $revenue = null, 195 | $shipping = null, 196 | $tax = null, 197 | $currency = null 198 | ); 199 | 200 | /** 201 | * ecommerce tracking - add item 202 | * 203 | * @param string $id 204 | * @param string $name 205 | * @param null|string $sku 206 | * @param null|string $category 207 | * @param null|float $price 208 | * @param null|int $quantity 209 | * @param null|string $currency 210 | * 211 | * @return AnalyticsProviderInterface 212 | */ 213 | public function ecommerceAddItem( 214 | $id, 215 | $name, 216 | $sku = null, 217 | $category = null, 218 | $price = null, 219 | $quantity = null, 220 | $currency = null 221 | ); 222 | 223 | /** 224 | * sets custom dimensions 225 | * 226 | * @param string|array $dimension 227 | * @param null|string $value 228 | * @return AnalyticsProviderInterface 229 | */ 230 | public function setCustom($dimension, $value = null); 231 | 232 | /** 233 | * set a custom tracking ID (the UA-XXXXXXXX-1 code) 234 | * 235 | * @param string $trackingId 236 | * 237 | * @return AnalyticsProviderInterface 238 | */ 239 | public function setTrackingId($trackingId); 240 | 241 | /** 242 | * set a custom optimize ID (the GTM-XXXXXX code) 243 | * 244 | * @param string $optimizeId 245 | * 246 | * @return AnalyticsProviderInterface 247 | */ 248 | public function setOptimizeId($optimizeId); 249 | 250 | /** 251 | * enables Content Security Polity and sets nonce 252 | * 253 | * @return AnalyticsProviderInterface 254 | */ 255 | public function withCSP(); 256 | 257 | /** 258 | * disables Content Security Polity 259 | * 260 | * @return AnalyticsProviderInterface 261 | */ 262 | public function withoutCSP(); 263 | 264 | /** 265 | * returns the current Content Security Policy nonce 266 | * 267 | * @return string|null 268 | */ 269 | public function cspNonce(); 270 | } 271 | -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/Contracts/TrackingBagInterface.php: -------------------------------------------------------------------------------- 1 | name = $name; 60 | } 61 | 62 | /** 63 | * set medium 64 | * 65 | * @param string $medium 66 | * 67 | * @return Campaign 68 | */ 69 | public function setMedium($medium) 70 | { 71 | $this->medium = $medium; 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * @return string 78 | */ 79 | public function getMedium() 80 | { 81 | return $this->medium; 82 | } 83 | 84 | /** 85 | * set name 86 | * 87 | * @param string $name 88 | * 89 | * @return Campaign 90 | */ 91 | public function setName($name) 92 | { 93 | $this->name = $name; 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * @return string 100 | */ 101 | public function getName() 102 | { 103 | return $this->name; 104 | } 105 | 106 | /** 107 | * set source 108 | * 109 | * @param string $source 110 | * 111 | * @return Campaign 112 | */ 113 | public function setSource($source) 114 | { 115 | $this->source = $source; 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * @return string 122 | */ 123 | public function getSource() 124 | { 125 | return $this->source; 126 | } 127 | 128 | /** 129 | * returns Keyword 130 | * 131 | * @return string 132 | */ 133 | public function getKeyword() 134 | { 135 | return $this->keyword; 136 | } 137 | 138 | /** 139 | * sets keyword 140 | * 141 | * @param string $keyword 142 | * 143 | * @return \Ipunkt\LaravelAnalytics\Data\Campaign 144 | */ 145 | public function setKeyword($keyword) 146 | { 147 | $this->keyword = $keyword; 148 | return $this; 149 | } 150 | 151 | /** 152 | * returns Content 153 | * 154 | * @return string 155 | */ 156 | public function getContent() 157 | { 158 | return $this->content; 159 | } 160 | 161 | /** 162 | * sets content 163 | * 164 | * @param string $content 165 | * 166 | * @return \Ipunkt\LaravelAnalytics\Data\Campaign 167 | */ 168 | public function setContent($content) 169 | { 170 | $this->content = $content; 171 | return $this; 172 | } 173 | 174 | /** 175 | * returns Id 176 | * 177 | * @return string 178 | */ 179 | public function getId() 180 | { 181 | return $this->id; 182 | } 183 | 184 | /** 185 | * sets id 186 | * 187 | * @param string $id 188 | * 189 | * @return \Ipunkt\LaravelAnalytics\Data\Campaign 190 | */ 191 | public function setId($id) 192 | { 193 | $this->id = $id; 194 | return $this; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/Data/Event.php: -------------------------------------------------------------------------------- 1 | action = $action; 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * returns action 56 | * 57 | * @return string 58 | */ 59 | public function getAction() 60 | { 61 | return $this->action; 62 | } 63 | 64 | /** 65 | * set category 66 | * 67 | * @param string $category 68 | * 69 | * @return Event 70 | */ 71 | public function setCategory($category) 72 | { 73 | $this->category = $category; 74 | 75 | return $this; 76 | } 77 | 78 | /** 79 | * returns category 80 | * 81 | * @return string 82 | */ 83 | public function getCategory() 84 | { 85 | return $this->category; 86 | } 87 | 88 | /** 89 | * sets hit type 90 | * 91 | * @param string $hitType 92 | * 93 | * @return Event 94 | */ 95 | public function setHitType($hitType) 96 | { 97 | $this->hitType = $hitType; 98 | 99 | return $this; 100 | } 101 | 102 | /** 103 | * returns hit type 104 | * 105 | * @return string 106 | */ 107 | public function getHitType() 108 | { 109 | return $this->hitType; 110 | } 111 | 112 | /** 113 | * sets label 114 | * 115 | * @param string $label 116 | * 117 | * @return Event 118 | */ 119 | public function setLabel($label) 120 | { 121 | $this->label = $label; 122 | 123 | return $this; 124 | } 125 | 126 | /** 127 | * returns label 128 | * 129 | * @return string 130 | */ 131 | public function getLabel() 132 | { 133 | return $this->label; 134 | } 135 | } -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/Data/Renderer/CampaignRenderer.php: -------------------------------------------------------------------------------- 1 | campaign = $campaign; 23 | } 24 | 25 | /** 26 | * Renders data 27 | * 28 | * @return string 29 | */ 30 | public function render() 31 | { 32 | return $this->renderName() 33 | . $this->renderSource() 34 | . $this->renderMedium() 35 | . $this->renderKeyword() 36 | . $this->renderContent() 37 | . $this->renderId(); 38 | } 39 | 40 | /** 41 | * returns the rendered name 42 | * 43 | * @return string 44 | */ 45 | private function renderName() 46 | { 47 | $name = $this->campaign->getName(); 48 | 49 | return empty($name) ? '' : "ga('set', 'campaignName', '{$name}');"; 50 | } 51 | 52 | /** 53 | * returns the rendered source 54 | * 55 | * @return string 56 | */ 57 | private function renderSource() 58 | { 59 | $source = $this->campaign->getSource(); 60 | 61 | return empty($source) ? '' : "ga('set', 'campaignSource', '{$source}');"; 62 | } 63 | 64 | /** 65 | * returns the rendered medium 66 | * 67 | * @return string 68 | */ 69 | private function renderMedium() 70 | { 71 | $medium = $this->campaign->getMedium(); 72 | 73 | return empty($medium) ? '' : "ga('set', 'campaignMedium', '{$medium}');"; 74 | } 75 | 76 | /** 77 | * returns the rendered keyword 78 | * 79 | * @return string 80 | */ 81 | private function renderKeyword() 82 | { 83 | $keyword = $this->campaign->getKeyword(); 84 | 85 | return empty($keyword) ? '' : "ga('set', 'campaignKeyword', '{$keyword}');"; 86 | } 87 | 88 | /** 89 | * returns the rendered content 90 | * 91 | * @return string 92 | */ 93 | private function renderContent() 94 | { 95 | $content = $this->campaign->getContent(); 96 | 97 | return empty($content) ? '' : "ga('set', 'campaignContent', '{$content}');"; 98 | } 99 | 100 | /** 101 | * returns the rendered id 102 | * 103 | * @return string 104 | */ 105 | private function renderId() 106 | { 107 | $id = $this->campaign->getId(); 108 | 109 | return empty($id) ? '' : "ga('set', 'campaignId', '{$id}');"; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/Data/Renderer/Renderer.php: -------------------------------------------------------------------------------- 1 | trackingId = Arr::get($options, 'tracking_id'); 142 | $this->optimizeId = Arr::get($options, 'optimize_id'); 143 | $this->trackingDomain = Arr::get($options, 'tracking_domain', 'auto'); 144 | $this->trackerName = Arr::get($options, 'tracker_name', 't0'); 145 | $this->displayFeatures = Arr::get($options, 'display_features', false); 146 | $this->anonymizeIp = Arr::get($options, 'anonymize_ip', false); 147 | $this->autoTrack = Arr::get($options, 'auto_track', false); 148 | $this->debug = Arr::get($options, 'debug', false); 149 | 150 | if ($this->trackingId === null) { 151 | throw new InvalidArgumentException('Argument tracking_id can not be null'); 152 | } 153 | 154 | $this->trackingBag = new TrackingBag; 155 | } 156 | 157 | /** 158 | * track an page view 159 | * 160 | * @param null|string $page 161 | * @param null|string $title 162 | * @param null|string $hittype 163 | * 164 | * @return void 165 | */ 166 | public function trackPage($page = null, $title = null, $hittype = null) 167 | { 168 | $allowedHitTypes = ['pageview', 'appview', 'event', 'transaction', 'item', 'social', 'exception', 'timing']; 169 | if ($hittype === null) { 170 | $hittype = $allowedHitTypes[0]; 171 | } 172 | 173 | if (!in_array($hittype, $allowedHitTypes)) { 174 | return; 175 | } 176 | 177 | $trackingCode = "ga('send', 'pageview');"; 178 | 179 | if ($page !== null || $title !== null || $hittype !== null) { 180 | $page = ($page === null) ? "window.location.protocol + '//' + window.location.hostname + window.location.pathname + window.location.search" : "'{$page}'"; 181 | $title = ($title === null) ? "document.title" : "'{$title}'"; 182 | 183 | $trackingCode = "ga('send', {'hitType': '{$hittype}', 'page': {$page}, 'title': {$title}});"; 184 | } 185 | 186 | $this->trackingBag->add($trackingCode); 187 | } 188 | 189 | /** 190 | * track an event 191 | * 192 | * @param string $category 193 | * @param string $action 194 | * @param null|string $label 195 | * @param null|int $value 196 | */ 197 | public function trackEvent($category, $action, $label = null, $value = null) 198 | { 199 | $command = ''; 200 | if ($label !== null) { 201 | $command .= ", '{$label}'"; 202 | if ($value !== null && is_numeric($value)) { 203 | $command .= ", {$value}"; 204 | } 205 | } 206 | 207 | $trackingCode = "ga('send', 'event', '{$category}', '{$action}'$command);"; 208 | 209 | $this->trackingBag->add($trackingCode); 210 | } 211 | 212 | /** 213 | * ecommerce tracking - add transaction 214 | * 215 | * @param string $id 216 | * @param null|string $affiliation 217 | * @param null|float $revenue 218 | * @param null|float $shipping 219 | * @param null|float $tax 220 | * @param null|string $currency 221 | * 222 | * @return AnalyticsProviderInterface 223 | */ 224 | public function ecommerceAddTransaction( 225 | $id, 226 | $affiliation = null, 227 | $revenue = null, 228 | $shipping = null, 229 | $tax = null, 230 | $currency = null 231 | ) { 232 | // Call to enable ecommerce tracking automatically 233 | $this->enableEcommerceTracking(); 234 | 235 | $parameters = ['id' => $id]; 236 | 237 | if (!is_null($affiliation)) { 238 | $parameters['affiliation'] = $affiliation; 239 | } 240 | 241 | if (!is_null($revenue)) { 242 | $parameters['revenue'] = $revenue; 243 | } 244 | 245 | if (!is_null($shipping)) { 246 | $parameters['shipping'] = $shipping; 247 | } 248 | 249 | if (!is_null($tax)) { 250 | $parameters['tax'] = $tax; 251 | } 252 | 253 | if (!is_null($currency)) { 254 | $parameters['currency'] = $currency; 255 | } 256 | 257 | $jsonParameters = json_encode($parameters); 258 | $trackingCode = "ga('ecommerce:addTransaction', {$jsonParameters});"; 259 | 260 | $this->trackingBag->add($trackingCode); 261 | 262 | return $this; 263 | } 264 | 265 | /** 266 | * ecommerce tracking - add item 267 | * 268 | * @param string $id 269 | * @param string $name 270 | * @param null|string $sku 271 | * @param null|string $category 272 | * @param null|float $price 273 | * @param null|int $quantity 274 | * @param null|string $currency 275 | * 276 | * @return AnalyticsProviderInterface 277 | */ 278 | public function ecommerceAddItem( 279 | $id, 280 | $name, 281 | $sku = null, 282 | $category = null, 283 | $price = null, 284 | $quantity = null, 285 | $currency = null 286 | ) { 287 | // Call to enable ecommerce tracking automatically 288 | $this->enableEcommerceTracking(); 289 | 290 | $parameters = [ 291 | 'id' => $id, 292 | 'name' => $name, 293 | ]; 294 | 295 | if (!is_null($sku)) { 296 | $parameters['sku'] = $sku; 297 | } 298 | 299 | if (!is_null($category)) { 300 | $parameters['category'] = $category; 301 | } 302 | 303 | if (!is_null($price)) { 304 | $parameters['price'] = $price; 305 | } 306 | 307 | if (!is_null($quantity)) { 308 | $parameters['quantity'] = $quantity; 309 | } 310 | 311 | if (!is_null($currency)) { 312 | $parameters['currency'] = $currency; 313 | } 314 | 315 | $jsonParameters = json_encode($parameters); 316 | $trackingCode = "ga('ecommerce:addItem', {$jsonParameters});"; 317 | 318 | $this->trackingBag->add($trackingCode); 319 | 320 | return $this; 321 | } 322 | 323 | /** 324 | * track any custom code 325 | * 326 | * @param string $customCode 327 | * 328 | * @return void 329 | */ 330 | public function trackCustom($customCode) 331 | { 332 | $this->trackingBag->add($customCode); 333 | } 334 | 335 | /** 336 | * enable display features 337 | * 338 | * @return GoogleAnalytics 339 | */ 340 | public function enableDisplayFeatures() 341 | { 342 | $this->displayFeatures = true; 343 | 344 | return $this; 345 | } 346 | 347 | /** 348 | * disable display features 349 | * 350 | * @return GoogleAnalytics 351 | */ 352 | public function disableDisplayFeatures() 353 | { 354 | $this->displayFeatures = false; 355 | 356 | return $this; 357 | } 358 | 359 | /** 360 | * enable ecommerce tracking 361 | * 362 | * @return GoogleAnalytics 363 | */ 364 | public function enableEcommerceTracking() 365 | { 366 | $this->ecommerceTracking = true; 367 | 368 | return $this; 369 | } 370 | 371 | /** 372 | * disable ecommerce tracking 373 | * 374 | * @return GoogleAnalytics 375 | */ 376 | public function disableEcommerceTracking() 377 | { 378 | $this->ecommerceTracking = false; 379 | 380 | return $this; 381 | } 382 | 383 | /** 384 | * enable auto tracking 385 | * 386 | * @return GoogleAnalytics 387 | */ 388 | public function enableAutoTracking() 389 | { 390 | $this->autoTrack = true; 391 | 392 | return $this; 393 | } 394 | 395 | /** 396 | * disable auto tracking 397 | * 398 | * @return GoogleAnalytics 399 | */ 400 | public function disableAutoTracking() 401 | { 402 | $this->autoTrack = false; 403 | 404 | return $this; 405 | } 406 | 407 | /** 408 | * render script block 409 | * 410 | * @return \Ipunkt\LaravelAnalytics\Providers\GoogleAnalytics 411 | */ 412 | public function enableScriptBlock() 413 | { 414 | $this->renderScriptBlock = true; 415 | 416 | return $this; 417 | } 418 | 419 | /** 420 | * do not render script block 421 | * 422 | * @return \Ipunkt\LaravelAnalytics\Providers\GoogleAnalytics 423 | */ 424 | public function disableScriptBlock() 425 | { 426 | $this->renderScriptBlock = false; 427 | 428 | return $this; 429 | } 430 | 431 | /** 432 | * returns the javascript embedding code 433 | * 434 | * @return string 435 | */ 436 | public function render() 437 | { 438 | $script[] = $this->_getJavascriptTemplateBlockBegin(); 439 | 440 | $trackingUserId = (null === $this->userId) 441 | ? '' 442 | : sprintf(", {'userId': '%s'}", $this->userId); 443 | 444 | if ($this->debug) { 445 | $script[] = "ga('create', '{$this->trackingId}', { 'cookieDomain': 'none' }, '{$this->trackerName}'{$trackingUserId});"; 446 | } else { 447 | $script[] = "ga('create', '{$this->trackingId}', '{$this->trackingDomain}', '{$this->trackerName}'{$trackingUserId});"; 448 | } 449 | 450 | if ($this->ecommerceTracking) { 451 | $script[] = "ga('require', 'ecommerce');"; 452 | } 453 | 454 | if ($this->displayFeatures) { 455 | $script[] = "ga('require', 'displayfeatures');"; 456 | } 457 | 458 | if ($this->optimizeId) { 459 | $script[] = "ga('require', '{$this->optimizeId}');"; 460 | } 461 | 462 | if ($this->anonymizeIp) { 463 | $script[] = "ga('set', 'anonymizeIp', true);"; 464 | } 465 | 466 | if ($this->nonInteraction) { 467 | $script[] = "ga('set', 'nonInteraction', true);"; 468 | } 469 | 470 | if ($this->campaign instanceof Campaign) { 471 | $script[] = (new CampaignRenderer($this->campaign))->render(); 472 | } 473 | 474 | $trackingStack = $this->trackingBag->get(); 475 | if (count($trackingStack)) { 476 | $script[] = implode("\n", $trackingStack); 477 | } 478 | 479 | if ($this->autoTrack) { 480 | $script[] = "ga('send', 'pageview');"; 481 | } 482 | 483 | if ($this->ecommerceTracking) { 484 | $script[] = "ga('ecommerce:send');"; 485 | } 486 | 487 | $script[] = $this->_getJavascriptTemplateBlockEnd(); 488 | 489 | return implode('', $script); 490 | } 491 | 492 | /** 493 | * sets or gets nonInteraction 494 | * 495 | * setting: $this->nonInteraction(true)->render(); 496 | * getting: if ($this->nonInteraction()) echo 'non-interaction set'; 497 | * 498 | * @param boolean|null $value 499 | * 500 | * @return bool|$this 501 | */ 502 | public function nonInteraction($value = null) 503 | { 504 | if (null === $value) { 505 | return $this->nonInteraction; 506 | } 507 | 508 | $this->nonInteraction = ($value === true); 509 | 510 | return $this; 511 | } 512 | 513 | /** 514 | * make the tracking measurement url insecure 515 | * 516 | * @return \Ipunkt\LaravelAnalytics\Providers\GoogleAnalytics 517 | */ 518 | public function unsecureMeasurementUrl() 519 | { 520 | $this->secureTrackingUrl = false; 521 | 522 | return $this; 523 | } 524 | 525 | /** 526 | * use the secured version of the tracking measurement url 527 | * 528 | * @return \Ipunkt\LaravelAnalytics\Providers\GoogleAnalytics 529 | */ 530 | public function secureMeasurementUrl() 531 | { 532 | $this->secureTrackingUrl = false; 533 | 534 | return $this; 535 | } 536 | 537 | /** 538 | * assembles an url for tracking measurement without javascript 539 | * 540 | * e.g. for tracking email open events within a newsletter 541 | * 542 | * @param string $metricName 543 | * @param mixed $metricValue 544 | * @param \Ipunkt\LaravelAnalytics\Data\Event $event 545 | * @param \Ipunkt\LaravelAnalytics\Data\Campaign $campaign 546 | * @param string|null $clientId 547 | * @param array $params 548 | * 549 | * @return string 550 | */ 551 | public function trackMeasurementUrl( 552 | $metricName, 553 | $metricValue, 554 | Event $event, 555 | Campaign $campaign, 556 | $clientId = null, 557 | array $params = [] 558 | ) { 559 | $uniqueId = ($clientId !== null) ? $clientId : uniqid('track_'); 560 | 561 | if ($event->getLabel() === '') { 562 | $event->setLabel($uniqueId); 563 | } 564 | 565 | if ($campaign->getName() === '') { 566 | $campaign->setName('Campaign ' . date('Y-m-d')); 567 | } 568 | 569 | $protocol = $this->secureTrackingUrl ? 'https' : 'http'; 570 | 571 | $defaults = [ 572 | 'url' => $protocol . '://www.google-analytics.com/collect?', 573 | 'params' => [ 574 | 'v' => 1, // protocol version 575 | 'tid' => $this->trackingId, // tracking id 576 | 'cid' => $uniqueId, // client id 577 | 't' => $event->getHitType(), 578 | 'ec' => $event->getCategory(), 579 | 'ea' => $event->getAction(), 580 | 'el' => $event->getLabel(), 581 | 'cs' => $campaign->getSource(), 582 | 'cm' => $campaign->getMedium(), 583 | 'cn' => $campaign->getName(), 584 | $metricName => $metricValue, // metric data 585 | ], 586 | ]; 587 | 588 | $url = isset($params['url']) ? $params['url'] : $defaults['url']; 589 | $url = rtrim($url, '?') . '?'; 590 | 591 | if (isset($params['url'])) { 592 | unset($params['url']); 593 | } 594 | 595 | $params = array_merge($defaults['params'], $params); 596 | $queryParams = []; 597 | foreach ($params as $key => $value) { 598 | if (!empty($value)) { 599 | $queryParams[] = sprintf('%s=%s', $key, $value); 600 | } 601 | } 602 | 603 | return $url . implode('&', $queryParams); 604 | } 605 | 606 | /** 607 | * sets an user id for user tracking 608 | * 609 | * @param string $userId 610 | * 611 | * @return AnalyticsProviderInterface 612 | * 613 | * @see https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id 614 | */ 615 | public function setUserId($userId) 616 | { 617 | $this->userId = $userId; 618 | 619 | return $this; 620 | } 621 | 622 | /** 623 | * unset a possible given user id 624 | * 625 | * @return AnalyticsProviderInterface 626 | */ 627 | public function unsetUserId() 628 | { 629 | return $this->setUserId(null); 630 | } 631 | 632 | /** 633 | * sets custom dimensions 634 | * 635 | * @param string|array $dimension 636 | * @param null|string $value 637 | * @return AnalyticsProviderInterface 638 | */ 639 | public function setCustom($dimension, $value = null) 640 | { 641 | if ($value === null && is_array($dimension)) { 642 | $params = json_encode($dimension); 643 | $trackingCode = "ga('set', $params);"; 644 | } else { 645 | $trackingCode = "ga('set', '$dimension', '$value');"; 646 | } 647 | 648 | $this->trackCustom($trackingCode); 649 | 650 | return $this; 651 | } 652 | 653 | /** 654 | * sets a campaign 655 | * 656 | * @param Campaign $campaign 657 | * @return AnalyticsProviderInterface 658 | */ 659 | public function setCampaign(Campaign $campaign) 660 | { 661 | $this->campaign = $campaign; 662 | 663 | return $this; 664 | } 665 | 666 | /** 667 | * unset a possible given campaign 668 | * 669 | * @return AnalyticsProviderInterface 670 | */ 671 | public function unsetCampaign() 672 | { 673 | $this->campaign = null; 674 | 675 | return $this; 676 | } 677 | 678 | /** 679 | * enables Content Security Polity and sets nonce 680 | * 681 | * @return AnalyticsProviderInterface 682 | * @throws \Exception 683 | */ 684 | public function withCSP() 685 | { 686 | if ($this->cspNonce === null) { 687 | $this->cspNonce = 'nonce-' . random_int(0, PHP_INT_MAX); 688 | } 689 | 690 | return $this; 691 | } 692 | 693 | /** 694 | * disables Content Security Polity 695 | * 696 | * @return AnalyticsProviderInterface 697 | */ 698 | public function withoutCSP() 699 | { 700 | $this->cspNonce = null; 701 | 702 | return $this; 703 | } 704 | 705 | /** 706 | * returns the current Content Security Policy nonce 707 | * 708 | * @return string|null 709 | */ 710 | public function cspNonce() 711 | { 712 | return $this->cspNonce; 713 | } 714 | 715 | /** 716 | * returns start block 717 | * 718 | * @return string 719 | */ 720 | protected function _getJavascriptTemplateBlockBegin() 721 | { 722 | $appendix = $this->debug ? '_debug' : ''; 723 | 724 | $scriptTag = ($this->cspNonce === null) 725 | ? '' 742 | : ''; 743 | } 744 | 745 | /** 746 | * set a custom tracking ID (the UA-XXXXXXXX-1 code) 747 | * 748 | * @param string $trackingId 749 | * 750 | * @return AnalyticsProviderInterface 751 | */ 752 | public function setTrackingId($trackingId) 753 | { 754 | $this->trackingId = $trackingId; 755 | 756 | return $this; 757 | } 758 | 759 | /** 760 | * set a custom optimize ID (the GTM-XXXXXX code) 761 | * 762 | * @param string $optimizeId 763 | * 764 | * @return AnalyticsProviderInterface 765 | */ 766 | public function setOptimizeId($optimizeId) 767 | { 768 | $this->optimizeId = $optimizeId; 769 | 770 | return $this; 771 | } 772 | } 773 | -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/Providers/NoAnalytics.php: -------------------------------------------------------------------------------- 1 | nonInteraction(true)->render(); 153 | * getting: if ($this->nonInteraction()) echo 'non-interaction set'; 154 | * 155 | * @param boolean|null $value 156 | * 157 | * @return bool|AnalyticsProviderInterface 158 | */ 159 | public function nonInteraction($value = null) 160 | { 161 | if (null === $value) { 162 | return false; 163 | } 164 | 165 | return $this; 166 | } 167 | 168 | /** 169 | * sets an user id for user tracking 170 | * 171 | * @param string $userId 172 | * 173 | * @return AnalyticsProviderInterface 174 | * 175 | * @see https://developers.google.com/analytics/devguides/collection/analyticsjs/cookies-user-id 176 | */ 177 | public function setUserId($userId) 178 | { 179 | return $this; 180 | } 181 | 182 | /** 183 | * unsets a possible given user id 184 | * 185 | * @return AnalyticsProviderInterface 186 | */ 187 | public function unsetUserId() 188 | { 189 | return $this; 190 | } 191 | 192 | /** 193 | * sets custom dimensions 194 | * 195 | * @param string|array $dimension 196 | * @param null|string $value 197 | * @return AnalyticsProviderInterface 198 | */ 199 | public function setCustom($dimension, $value = null) 200 | { 201 | return $this; 202 | } 203 | 204 | /** 205 | * sets a campaign 206 | * 207 | * @param Campaign $campaign 208 | * @return AnalyticsProviderInterface 209 | */ 210 | public function setCampaign(Campaign $campaign) 211 | { 212 | return $this; 213 | } 214 | 215 | /** 216 | * unsets a possible given campaign 217 | * 218 | * @return AnalyticsProviderInterface 219 | */ 220 | public function unsetCampaign() 221 | { 222 | return $this; 223 | } 224 | 225 | /** 226 | * enable ecommerce tracking 227 | * 228 | * @return AnalyticsProviderInterface 229 | */ 230 | public function enableEcommerceTracking() 231 | { 232 | return $this; 233 | } 234 | 235 | /** 236 | * disable ecommerce tracking 237 | * 238 | * @return AnalyticsProviderInterface 239 | */ 240 | public function disableEcommerceTracking() 241 | { 242 | return $this; 243 | } 244 | 245 | /** 246 | * ecommerce tracking - add transaction 247 | * 248 | * @param string $id 249 | * @param null|string $affiliation 250 | * @param null|float $revenue 251 | * @param null|float $shipping 252 | * @param null|float $tax 253 | * @param null|string $currency 254 | * 255 | * @return AnalyticsProviderInterface 256 | */ 257 | public function ecommerceAddTransaction( 258 | $id, 259 | $affiliation = null, 260 | $revenue = null, 261 | $shipping = null, 262 | $tax = null, 263 | $currency = null 264 | ) { 265 | return $this; 266 | } 267 | 268 | /** 269 | * ecommerce tracking - add item 270 | * 271 | * @param string $id 272 | * @param string $name 273 | * @param null|string $sku 274 | * @param null|string $category 275 | * @param null|float $price 276 | * @param null|int $quantity 277 | * @param null|string $currency 278 | * 279 | * @return AnalyticsProviderInterface 280 | */ 281 | public function ecommerceAddItem( 282 | $id, 283 | $name, 284 | $sku = null, 285 | $category = null, 286 | $price = null, 287 | $quantity = null, 288 | $currency = null 289 | ) { 290 | return $this; 291 | } 292 | 293 | /** 294 | * enables Content Security Polity and sets nonce 295 | * 296 | * @return AnalyticsProviderInterface 297 | */ 298 | public function withCSP() 299 | { 300 | return $this; 301 | } 302 | 303 | /** 304 | * disables Content Security Polity 305 | * 306 | * @return AnalyticsProviderInterface 307 | */ 308 | public function withoutCSP() 309 | { 310 | return $this; 311 | } 312 | 313 | /** 314 | * returns the current Content Security Policy nonce 315 | * 316 | * @return string|null 317 | */ 318 | public function cspNonce() 319 | { 320 | return null; 321 | } 322 | 323 | /** 324 | * set a custom tracking ID (the UA-XXXXXXXX-1 code) 325 | * 326 | * @param string $trackingId 327 | * 328 | * @return AnalyticsProviderInterface 329 | */ 330 | public function setTrackingId($trackingId) 331 | { 332 | return $this; 333 | } 334 | 335 | /** 336 | * set a custom optimize ID (the GTM-XXXXXX code) 337 | * 338 | * @param string $optimizeId 339 | * 340 | * @return AnalyticsProviderInterface 341 | */ 342 | public function setOptimizeId($optimizeId) 343 | { 344 | return $this; 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /src/Ipunkt/LaravelAnalytics/TrackingBag.php: -------------------------------------------------------------------------------- 1 | sessionIdentifier)) { 31 | $sessionTracks = Session::get($this->sessionIdentifier); 32 | } 33 | 34 | // prevent duplicates in session 35 | $trackingKey = md5($tracking); 36 | $sessionTracks[$trackingKey] = $tracking; 37 | 38 | Session::flash($this->sessionIdentifier, $sessionTracks); 39 | } 40 | 41 | /** 42 | * returns all trackings with forgetting it 43 | * 44 | * @return array 45 | */ 46 | public function get() 47 | { 48 | $trackings = []; 49 | if (Session::has($this->sessionIdentifier)) { 50 | $trackings = Session::get($this->sessionIdentifier); 51 | Session::forget($this->sessionIdentifier); 52 | } 53 | 54 | return $trackings; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/config/analytics.php: -------------------------------------------------------------------------------- 1 | env('ANALYTICS_PROVIDER', 'GoogleAnalytics'), 9 | 10 | /** 11 | * configurations for all possible providers 12 | */ 13 | 'configurations' => [ 14 | 15 | /** 16 | * The Google Analytics provider supports the following properties: 17 | * - tracking_id (string) 18 | * - optimize_id (string) 19 | * - tracking_domain (string:auto) - default will be 'auto' if config property not exists 20 | * - tracker_name (string:t0) - default will be 't0' if config property not exists 21 | * - display_features (bool) - default will be false if no config property exists 22 | * - anonymize_ip (bool) - default will be false if no config property exists 23 | * - auto_track (bool) - default will be false if no config property exists 24 | * - debug (bool) - default will be false if no config property exists 25 | */ 26 | 'GoogleAnalytics' => [ 27 | 28 | /** 29 | * Tracking ID: You have to set this 30 | * Format example: UA-XXXXXXXX-1 31 | */ 32 | 'tracking_id' => env('ANALYTICS_TRACKING_ID', 'UA-XXXXXXXX-1'), 33 | 34 | /** 35 | * Optimize ID 36 | * Format example: GTM-XXXXXX 37 | */ 38 | 'optimize_id' => env('ANALYTICS_OPTIMIZE_ID', ''), 39 | 40 | /** 41 | * Tracking Domain 42 | */ 43 | 'tracking_domain' => env('ANALYTICS_TRACKING_DOMAIN', 'auto'), 44 | 45 | /** 46 | * Tracker Name 47 | */ 48 | 'tracker_name' => env('ANALYTICS_TRACKER_NAME', 't0'), 49 | 50 | /** 51 | * enabling the display feature plugin 52 | */ 53 | 'display_features' => env('ANALYTICS_DISPLAY_FEATURES', false), 54 | 55 | /** 56 | * Use ip anonymized 57 | */ 58 | 'anonymize_ip' => env('ANALYTICS_ANONYMIZE_IP', true), 59 | 60 | /** 61 | * Auto tracking pageview: ga('send', 'pageview'); 62 | * If false, you have to do it manually for each request 63 | * Or you can use Analytics::disableAutoTracking(), Analytics::enableAutoTracking() 64 | */ 65 | 'auto_track' => env('ANALYTICS_AUTO_TRACK', true), 66 | 67 | /** 68 | * Enable the debugging version of Google Analytics 69 | */ 70 | 'debug' => env('ANALYTICS_DEBUG', env('APP_ENV') === 'local'), 71 | ], 72 | 73 | ], 74 | 75 | /** 76 | * disable Analytics