├── registration.php ├── etc ├── module.xml ├── frontend │ └── routes.xml ├── config.xml └── adminhtml │ └── system.xml ├── view └── frontend │ ├── templates │ ├── noscript.phtml │ └── gtm.phtml │ └── layout │ └── default.xml ├── composer.json ├── Controller └── Index │ └── Index.php ├── Helper └── Data.php ├── README.md └── Block └── Gtm.php /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /view/frontend/templates/noscript.phtml: -------------------------------------------------------------------------------- 1 | getContainerId(); 3 | if ($block->getIsEnable()): // if module is enabled 4 | ?> 5 | 6 | 7 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chapagain/googletagmanager2", 3 | "description": "Google Tag Manager module for Magento 2", 4 | "type": "magento2-module", 5 | "version": "1.0.1", 6 | "license": [ 7 | "OSL-3.0", 8 | "AFL-3.0" 9 | ], 10 | "require": { 11 | "php": "~5.5.0|~5.6.0|~7.0.0" 12 | }, 13 | "autoload": { 14 | "files": [ 15 | "registration.php" 16 | ], 17 | "psr-4": { 18 | "Chapagain\\GoogleTagManager\\": "" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /view/frontend/templates/gtm.phtml: -------------------------------------------------------------------------------- 1 | getContainerId(); 3 | 4 | if ($block->getIsEnable()): // if module is enabled 5 | ?> 6 | 7 | 8 | 9 | getIsEnableDataLayer()): 11 | echo $block->getDataLayerProduct(); // Product Detail Page 12 | echo $block->getDataLayerOrder(); // Order Success Page 13 | endif; 14 | ?> 15 | 16 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /view/frontend/layout/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Controller/Index/Index.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 21 | parent::__construct($context); 22 | } 23 | /** 24 | * Default customer account page 25 | * 26 | * @return void 27 | */ 28 | public function execute() 29 | { 30 | return $this->resultPageFactory->create(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Helper/Data.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 20 | } 21 | 22 | /** 23 | * Check if the module is enabled 24 | * 25 | * @return boolean 0 or 1 26 | */ 27 | public function getIsEnable() 28 | { 29 | $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; 30 | return $this->scopeConfig->getValue(self::XML_PATH_GTM_ENABLED, $storeScope); 31 | } 32 | 33 | /** 34 | * Check if data layered is enabled or not 35 | * 36 | * @return boolean 0 or 1 37 | */ 38 | public function getIsEnableDataLayer() 39 | { 40 | $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; 41 | return $this->scopeConfig->getValue(self::XML_PATH_GTM_ENABLED_DATA_LAYER, $storeScope); 42 | } 43 | 44 | /** 45 | * Get container id 46 | * 47 | * @return string 48 | */ 49 | public function getContainerId() 50 | { 51 | $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; 52 | $containerId = $this->scopeConfig->getValue(self::XML_PATH_GTM_CONTAINER_ID, $storeScope); 53 | return trim($containerId); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | chapagain_tab 11 | Chapagain_GoogleTagManager::config 12 | 13 | 14 | 15 | 16 | Magento\Config\Model\Config\Source\Yesno 17 | 18 | 19 | 20 | Magento\Config\Model\Config\Source\Yesno 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Google Tag Manager - Extension for Magento 2.x 2 | 3 | This extension allows you to integrate Google Tag Manager on your Magento site so that you can track 4 | and gather valuable visitor data from your website and make important decisions to grow your 5 | business. This extension also provides e-commerce transaction tracking feature. You just need to enter 6 | your Tag Manager container id in the extension's configuration settings. 7 | 8 | [Google Tag Manager](https://support.google.com/tagmanager/answer/6102821?hl=en) allows you to quickly and easily update tags and code snippets on your website or 9 | mobile app, such as those intended for traffic analysis and marketing optimization. You can add and 10 | update AdWords, Google Analytics, Floodlight, and 3rd party or custom tags from the Google Tag 11 | Manager user interface instead of editing site code. This reduces errors, frees you from having to 12 | involve a web developer, and allows you to quickly deploy new features or content onto your site. 13 | 14 | Google Tag Manager are FREE of charge services offered by Google. You need to create a separate 15 | Google Tag Manager account from [here](https://tagmanager.google.com/?hl=en#/admin/accounts/create) and link the account with your Magento store by adding the 16 | "Container ID" of your Google Tag Manager account to the current extension's configuration setting. 17 | 18 | ## Features 19 | 20 | - Tracks views of the product 21 | - Tracks categories and price of the product 22 | - Tracks transaction of the product by SKU, name, category, price and quantity 23 | - Tracks the transaction purchase revenue, tax and shipping cost 24 | - Tracks the coupon code 25 | 26 | ## Installation 27 | 28 | 1. The module's files should be placed in folder: `app/code/Chapagain/GoogleTagManager` 29 | 2. Open terminal/command-prompt 30 | 3. Go to your Magento website’s root directory with the following command: 31 | - `cd /path/to/your/magento/root/directory` 32 | 4. Enable the module and clear static content with the following command: 33 | - `php bin/magento module:enable Chapagain_GoogleTagManager –clear-static-content` 34 | 5. Do setup upgrade with the following command: 35 | - `php bin/magento setup:upgrade` 36 | 6. Flush cache with the following command: 37 | - `php bin/magento cache:flush` 38 | 7. That's all. The extension is installed now. 39 | 40 | ## Configuration Settings 41 | 42 | 1. Login to your Magento site's admin 43 | 2. Go to `STORES → Settings → Configuration` page 44 | 3. On left sidebar, click on `CHAPAGAIN EXTENSIONS → Google Tag Manager` menu 45 | 4. Here, you will see the following settings from where you can: 46 | - Enable/Disable module 47 | - Enable/Disable data layer 48 | - Add container ID of your site from Google Tag Manager 49 | 50 | ## Links 51 | 52 | - This extension is also available on Magento Marketplace: [Google Tag Manager on Magento Marketplace](https://marketplace.magento.com/chapagain-googletagmanager2.html) 53 | - BLOG: [http://blog.chapagain.com.np/google-tag-manager-magento-2-extension-free/](http://blog.chapagain.com.np/google-tag-manager-magento-2-extension-free/) 54 | -------------------------------------------------------------------------------- /Block/Gtm.php: -------------------------------------------------------------------------------- 1 | _helper = $helper; 94 | $this->_logo = $logo; 95 | $this->_request = $request; 96 | $this->_registry = $registry; 97 | $this->_order = $order; 98 | $this->_checkoutSession = $checkoutSession; 99 | $this->_categoryRepository = $categoryRepository; 100 | $this->_currency = $currency; 101 | $this->_locale = $locale; 102 | $this->_tax = $tax; 103 | 104 | parent::__construct($context, $data); 105 | } 106 | 107 | // HELPER FUNCTIONS 108 | 109 | /** 110 | * Check if the module is enabled 111 | * 112 | * @return boolean 0 or 1 113 | */ 114 | public function getIsEnable() 115 | { 116 | return $this->_helper->getIsEnable(); 117 | } 118 | 119 | /** 120 | * Check if data layered is enabled or not 121 | * 122 | * @return boolean 0 or 1 123 | */ 124 | public function getIsEnableDataLayer() 125 | { 126 | return $this->_helper->getIsEnableDataLayer(); 127 | } 128 | 129 | /** 130 | * Get container id 131 | * 132 | * @return string 133 | */ 134 | public function getContainerId() 135 | { 136 | return $this->_helper->getContainerId(); 137 | } 138 | 139 | // END HELPER FUNCTIONS 140 | 141 | 142 | /** 143 | * Check if current page is homepage 144 | * 145 | * @return boolean true or false 146 | */ 147 | public function getIsHomePage() 148 | { 149 | return $this->_logo->isHomePage(); 150 | } 151 | 152 | /** 153 | * Check if current page is order success page 154 | * 155 | * @return boolean true or false 156 | */ 157 | public function getIsOrderSuccessPage() 158 | { 159 | if (strpos($this->_request->getPathInfo(), '/checkout/onepage/success') !== false) { 160 | return true; 161 | } 162 | return false; 163 | } 164 | 165 | /** 166 | * Check if current page is shopping cart page 167 | * 168 | * @return boolean true or false 169 | */ 170 | public function getIsCartPage() 171 | { 172 | if (strpos($this->_request->getPathInfo(), '/checkout/cart') !== false) { 173 | return true; 174 | } 175 | return false; 176 | } 177 | 178 | /** 179 | * Check if current page is checkout page 180 | * 181 | * @return boolean true or false 182 | */ 183 | public function getIsCheckoutPage() 184 | { 185 | if (strpos($this->_request->getPathInfo(), '/checkout/onepage') !== false) { 186 | return true; 187 | } 188 | return false; 189 | } 190 | 191 | /** 192 | * Get current product 193 | * 194 | * @return \Magento\Catalog\Model\Product\Interceptor 195 | */ 196 | public function getCurrentProduct() 197 | { 198 | return $this->_registry->registry('current_product'); 199 | } 200 | 201 | /** 202 | * Get current category 203 | * 204 | * @return \Magento\Catalog\Model\Category\Interceptor 205 | */ 206 | public function getCurrentCategory() 207 | { 208 | return $this->_registry->registry('current_category'); 209 | } 210 | 211 | /** 212 | * Get order 213 | * 214 | * @return mixed \Magento\Sales\Model\Order or false 215 | */ 216 | public function getOrder() 217 | { 218 | if ($this->getIsOrderSuccessPage()) { 219 | $orderId = $this->_checkoutSession->getLastOrderId(); 220 | $order = $this->_order->load($orderId); 221 | if (!$order) { 222 | return false; 223 | } 224 | return $order; 225 | } 226 | return false; 227 | } 228 | 229 | public function getDataLayerProduct() 230 | { 231 | if ($product = $this->getCurrentProduct()) { 232 | 233 | $categoryCollection = $product->getCategoryCollection(); 234 | 235 | $categories = array(); 236 | foreach ($categoryCollection as $category) { 237 | $categories[] = $this->_categoryRepository->get($category->getEntityId())->getName(); 238 | } 239 | 240 | $objProduct = new stdClass(); 241 | $objProduct->name = $product->getName(); 242 | $objProduct->id = $product->getSku(); 243 | 244 | //$objProduct->price = $this->_currency->formatTxt($product->getFinalPrice(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 245 | /** 246 | * Fix for price for different locale 247 | * 248 | * For example: 249 | * Price display of Dutch locale is the opposite of English locale 250 | * English locale price = 1,230.55 251 | * Dutch locale price = 1.230,55 252 | */ 253 | $objProduct->price = (string) $this->_locale->getNumber($product->getFinalPrice(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 254 | 255 | $objProduct->category = implode('|', $categories); 256 | 257 | $objEcommerce = new stdClass(); 258 | $objEcommerce->ecommerce = new stdClass(); 259 | $objEcommerce->ecommerce->detail = new stdClass(); 260 | $objEcommerce->ecommerce->detail->actionField = new stdClass(); 261 | $objEcommerce->ecommerce->detail->actionField->list = 'Catalog'; 262 | $objEcommerce->ecommerce->detail->products = $objProduct; 263 | 264 | /*$objAddToCart = new stdClass(); 265 | $objAddToCart->event = 'addToCart'; 266 | $objAddToCart->ecommerce = new stdClass(); 267 | $objAddToCart->ecommerce->add = new stdClass(); 268 | $objAddToCart->ecommerce->add->products = $objProduct;*/ 269 | 270 | $pageCategory = json_encode(array('pageCategory' => 'product-detail'), JSON_PRETTY_PRINT); 271 | 272 | $dataScript = PHP_EOL; 273 | 274 | $dataScript .= ''; 275 | 276 | $dataScript .= PHP_EOL.PHP_EOL; 277 | 278 | $dataScript .= ''; 279 | 280 | //$dataScript .= PHP_EOL.PHP_EOL; 281 | 282 | //$dataScript .= ''; 283 | 284 | return $dataScript; 285 | } 286 | } 287 | 288 | public function getDataLayerOrder() 289 | { 290 | if ($order = $this->getOrder()) { 291 | 292 | $aItems = array(); 293 | $productItems = array(); 294 | foreach ($order->getAllVisibleItems() as $item) { 295 | 296 | $categoryCollection = $item->getProduct()->getCategoryCollection(); 297 | $categories = array(); 298 | foreach ($categoryCollection as $category) { 299 | $categories[] = $this->_categoryRepository->get($category->getEntityId())->getName(); 300 | } 301 | 302 | $productItem = array(); 303 | $productItem['name'] = $item->getName(); 304 | $productItem['id'] = $item->getSku(); 305 | 306 | //$productItem['price'] = $this->_currency->formatTxt($item->getBasePrice(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 307 | /** 308 | * Fix for price for different locale 309 | * 310 | * For example: 311 | * Price display of Dutch locale is the opposite of English locale 312 | * English locale price = 1,230.55 313 | * Dutch locale price = 1.230,55 314 | */ 315 | $productItem['price'] = (string) $this->_locale->getNumber($item->getBasePrice(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 316 | 317 | $productItem['category'] = implode('|', $categories); 318 | $productItem['quantity'] = intval($item->getQtyOrdered()); // converting qty from decimal to integer 319 | $productItem['coupon'] = ''; 320 | $productItems[] = (object) $productItem; 321 | 322 | $objItem = array(); 323 | $objItem['sku'] = $item->getSku(); 324 | $objItem['name'] = $item->getName(); 325 | $objItem['category'] = implode('|', $categories); 326 | 327 | //$objItem['price'] = $this->_currency->formatTxt($item->getBasePrice(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 328 | /** 329 | * Fix for price for different locale 330 | * 331 | * For example: 332 | * Price display of Dutch locale is the opposite of English locale 333 | * English locale price = 1,230.55 334 | * Dutch locale price = 1.230,55 335 | */ 336 | $objItem['price'] = (string) $this->_locale->getNumber($item->getBasePrice(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 337 | 338 | $objItem['quantity'] = intval($item->getQtyOrdered()); // converting qty from decimal to integer 339 | $aItems[] = (object) $objItem; 340 | } 341 | 342 | $objOrder = new stdClass(); 343 | 344 | $objOrder->transactionId = $order->getIncrementId(); 345 | $objOrder->transactionAffiliation = $this->_storeManager->getStore()->getFrontendName(); 346 | 347 | //$objOrder->transactionTotal = $this->_currency->formatTxt($order->getBaseGrandTotal(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 348 | //$objOrder->transactionTax = $this->_currency->formatTxt($order->getBaseTaxAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 349 | //$objOrder->transactionShipping = $this->_currency->formatTxt($order->getBaseShippingAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 350 | /** 351 | * Fix for price for different locale 352 | */ 353 | $objOrder->transactionTotal = (string) $this->_locale->getNumber($order->getBaseGrandTotal(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 354 | $objOrder->transactionTax = (string) $this->_locale->getNumber($order->getBaseTaxAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 355 | $objOrder->transactionShipping = (string) $this->_locale->getNumber($order->getBaseShippingAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 356 | 357 | $objOrder->transactionProducts = $aItems; 358 | 359 | $objOrder->ecommerce = new stdClass(); 360 | $objOrder->ecommerce->purchase = new stdClass(); 361 | $objOrder->ecommerce->purchase->actionField = new stdClass(); 362 | $objOrder->ecommerce->purchase->actionField->id = $order->getIncrementId(); 363 | $objOrder->ecommerce->purchase->actionField->affiliation = $this->_storeManager->getStore()->getFrontendName(); 364 | 365 | //$objOrder->ecommerce->purchase->actionField->revenue = $this->_currency->formatTxt($order->getBaseGrandTotal(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 366 | //$objOrder->ecommerce->purchase->actionField->tax = $this->_currency->formatTxt($order->getBaseTaxAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 367 | //$objOrder->ecommerce->purchase->actionField->shipping = $this->_currency->formatTxt($order->getBaseShippingAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 368 | /** 369 | * Fix for price for different locale 370 | */ 371 | $objOrder->ecommerce->purchase->actionField->revenue = (string) $this->_locale->getNumber($order->getBaseGrandTotal(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 372 | $objOrder->ecommerce->purchase->actionField->tax = (string) $this->_locale->getNumber($order->getBaseTaxAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 373 | $objOrder->ecommerce->purchase->actionField->shipping = (string) $this->_locale->getNumber($order->getBaseShippingAmount(), array('display' => \Magento\Framework\Currency::NO_SYMBOL)); 374 | 375 | $coupon = $order->getCouponCode(); 376 | $objOrder->ecommerce->purchase->actionField->coupon = $coupon == null ? '' : $coupon; 377 | 378 | $objOrder->ecommerce->products = $productItems; 379 | 380 | $pageCategory = json_encode(array('pageCategory' => 'order-success'), JSON_PRETTY_PRINT); 381 | 382 | $dataScript = PHP_EOL; 383 | 384 | $dataScript .= ''; 385 | 386 | $dataScript .= PHP_EOL.PHP_EOL; 387 | 388 | $dataScript .= ''; 389 | 390 | return $dataScript; 391 | } 392 | } 393 | } 394 | --------------------------------------------------------------------------------