├── README.md └── app ├── code └── community │ └── CVM │ └── GoogleTagManager │ ├── Block │ └── Gtm.php │ ├── Helper │ └── Data.php │ ├── Model │ └── Observer.php │ └── etc │ ├── adminhtml.xml │ ├── config.xml │ └── system.xml ├── design └── frontend │ └── base │ └── default │ ├── layout │ └── googletagmanager.xml │ └── template │ └── googletagmanager │ └── gtm.phtml └── etc └── modules └── CVM_GoogleTagManager.xml /README.md: -------------------------------------------------------------------------------- 1 | # Google Tag Manager 2 | 3 | A standard implementation of [Google Tag Manager][1] for [Magento][2], with data layer support for transaction and visitor data. 4 | 5 | ## Features 6 | 7 | ### Built in data layer support 8 | 9 | Use the data layer to enable Google Analytics e-commerce tracking using Google Tag Manager's native tags. You can also build more flexible macros in GTM using visitor data. 10 | 11 | ### The future 12 | 13 | Additional data layer work is planned for future releases, starting with site search data. 14 | 15 | This extension is made available for free. Any donations toward maintaining it and adding new features as Google Tag Manager evolves are greatly appreciated. 16 | 17 | [![Donate via PayPal](https://www.paypalobjects.com/en_GB/i/btn/btn_donate_LG.gif)][3] 18 | 19 | ## Installation 20 | 21 | The latest version of this extension can be downloaded via [Magento Connect][4] and installed via Magento Connect Manager. 22 | 23 | Alternatively, you can also clone or download this repository and copy the app directory into the root of your Magento installation (not recommended unless you're sure you know what you're doing). 24 | 25 | ## Usage 26 | 27 | Log in to your Magento installation's admin and navigate to `System > Configuration > Sales > Google API`. If installed correctly, you should see a new section below Google Analytics for Google Tag Manager. 28 | 29 | ### Deploying the tag container 30 | 31 | To deploy the tag container on all your pages, switch the `Enable` option to `Yes` and enter your `Container Public ID`. This can be found in the Google Tag Manager interface, and takes the form `GTM-XXXX`. 32 | 33 | ### Enabling the data layer 34 | 35 | The data layer provides Google Tag Manager with additional data that can be used to form macros which can in turn be used for creating rules that dictate when specific tags will fire. It is also populated with transaction data when orders are placed, facilitating Google Analytics e-commerce tracking when using the appropriate tag in Google Tag Manager. 36 | 37 | The data layer is disabled by default and can be enabled independently for both transaction and visitor data. To do this, change the `Data layer: Transactions` or `Data layer: Visitors` options to `Enable`. 38 | 39 | For transactions, there are additional fields for `transactionType` and `transactionAffiliation` that can take custom values, depending on the store view. These can be left blank if desired, or populated to allow Google Tag Manager to fire different tags for different stores. 40 | 41 | ## Support 42 | 43 | Please report bugs and feature requests using the [Github issue tracker][6]. 44 | 45 | [1]:http://www.google.com/tagmanager 46 | [2]:http://www.magentocommerce.com/ 47 | [3]:https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XZMM6SFDTPCAA 48 | [4]:http://www.magentocommerce.com/magento-connect/ 49 | [5]:https://support.google.com/tagmanager/ 50 | [6]:https://github.com/CVM/Magento_GoogleTagManager/issues -------------------------------------------------------------------------------- /app/code/community/CVM/GoogleTagManager/Block/Gtm.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (c) 2013 Chris Martin 9 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License 3.0 (OSL-3.0) 10 | */ 11 | class CVM_GoogleTagManager_Block_Gtm extends Mage_Core_Block_Template 12 | { 13 | /** 14 | * Generate JavaScript for the container snippet. 15 | * 16 | * @return string 17 | */ 18 | protected function _getContainerSnippet() 19 | { 20 | // Get the container ID. 21 | $containerId = Mage::helper('googletagmanager')->getContainerId(); 22 | 23 | // Render the container snippet JavaScript. 24 | return " 26 | \n"; 31 | } 32 | 33 | /** 34 | * Generate JavaScript for the data layer. 35 | * 36 | * @return string|null 37 | */ 38 | protected function _getDataLayer() 39 | { 40 | // Initialise our data source. 41 | $data = array(); 42 | 43 | // Get transaction and visitor data, if desired. 44 | if (Mage::helper('googletagmanager')->isDataLayerTransactionsEnabled()) $data = $data + $this->_getTransactionData(); 45 | if (Mage::helper('googletagmanager')->isDataLayerVisitorsEnabled()) $data = $data + $this->_getVisitorData(); 46 | 47 | // Enable modules to add custom data to the data layer 48 | $data_layer = new Varien_Object(); 49 | $data_layer->setData($data); 50 | Mage::dispatchEvent('cvm_googletagmanager_get_datalayer', 51 | array('data_layer' => $data_layer) 52 | ); 53 | $data = $data_layer->getData(); 54 | 55 | // Generate the data layer JavaScript. 56 | if (!empty($data)) return "\n\n"; 57 | else return ''; 58 | } 59 | 60 | /** 61 | * Get transaction data for use in the data layer. 62 | * 63 | * @link https://developers.google.com/tag-manager/reference 64 | * @return array 65 | */ 66 | protected function _getTransactionData() 67 | { 68 | $data = array(); 69 | 70 | $orderIds = $this->getOrderIds(); 71 | if (empty($orderIds) || !is_array($orderIds)) return array(); 72 | 73 | $collection = Mage::getResourceModel('sales/order_collection')->addFieldToFilter('entity_id', array('in' => $orderIds)); 74 | 75 | $i = 0; 76 | $products = array(); 77 | 78 | foreach ($collection as $order) { 79 | if ($i == 0) { 80 | // Build all fields for first order. 81 | $data = array( 82 | 'event' => 'transaction', 83 | 'transactionId' => $order->getIncrementId(), 84 | 'transactionDate' => date("Y-m-d"), 85 | 'transactionType' => Mage::helper('googletagmanager')->getTransactionType(), 86 | 'transactionAffiliation' => Mage::helper('googletagmanager')->getTransactionAffiliation(), 87 | 'transactionTotal' => round($order->getBaseGrandTotal(),2), 88 | 'transactionShipping' => round($order->getBaseShippingAmount(),2), 89 | 'transactionTax' => round($order->getBaseTaxAmount(),2), 90 | 'transactionPaymentType' => $order->getPayment()->getMethodInstance()->getTitle(), 91 | 'transactionCurrency' => $order->getOrderCurrencyCode(), 92 | 'transactionShippingMethod' => $order->getShippingCarrier()->getCarrierCode(), 93 | 'transactionPromoCode' => $order->getCouponCode(), 94 | 'transactionProducts' => array() 95 | ); 96 | } else { 97 | // For subsequent orders, append to order ID, totals and shipping method. 98 | $data['transactionId'] .= '|'.$order->getIncrementId(); 99 | $data['transactionTotal'] += $order->getBaseGrandTotal(); 100 | $data['transactionShipping'] += $order->getBaseShippingAmount(); 101 | $data['transactionTax'] += $order->getBaseTaxAmount(); 102 | $data['transactionShippingMethod'] .= '|'.$order->getShippingCarrier()->getCarrierCode(); 103 | } 104 | 105 | // Build products array. 106 | foreach ($order->getAllVisibleItems() as $item) { 107 | $product = Mage::getModel('catalog/product')->load($item->getProductId()); 108 | $product_categories = $product->getCategoryIds(); 109 | $categories = array(); 110 | foreach ($product_categories as $category) { 111 | $categories[] = Mage::getModel('catalog/category')->load($category)->getName(); 112 | } 113 | if (empty($products[$item->getSku()])) { 114 | // Build all fields the first time we encounter this item. 115 | $products[$item->getSku()] = array( 116 | 'name' => $this->jsQuoteEscape(Mage::helper('core')->escapeHtml($item->getName())), 117 | 'sku' => $this->jsQuoteEscape(Mage::helper('core')->escapeHtml($item->getSku())), 118 | 'category' => implode('|',$categories), 119 | 'price' => (double)number_format($item->getBasePrice(),2,'.',''), 120 | 'quantity' => (int)$item->getQtyOrdered() 121 | ); 122 | } else { 123 | // If we already have the item, update quantity. 124 | $products[$item->getSku()]['quantity'] += (int)$item->getQtyOrdered(); 125 | } 126 | } 127 | 128 | $i++; 129 | } 130 | 131 | // Push products into main data array. 132 | foreach ($products as $product) { 133 | $data['transactionProducts'][] = $product; 134 | } 135 | 136 | // Trim empty fields from the final output. 137 | foreach ($data as $key => $value) { 138 | if (!is_numeric($value) && empty($value)) unset($data[$key]); 139 | } 140 | 141 | return $data; 142 | } 143 | 144 | /** 145 | * Get visitor data for use in the data layer. 146 | * 147 | * @link https://developers.google.com/tag-manager/reference 148 | * @return array 149 | */ 150 | protected function _getVisitorData() 151 | { 152 | $data = array(); 153 | $customer = Mage::getSingleton('customer/session'); 154 | 155 | // visitorId 156 | if ($customer->getCustomerId()) $data['visitorId'] = (string)$customer->getCustomerId(); 157 | 158 | // visitorLoginState 159 | $data['visitorLoginState'] = ($customer->isLoggedIn()) ? 'Logged in' : 'Logged out'; 160 | 161 | // visitorType 162 | $data['visitorType'] = (string)Mage::getModel('customer/group')->load($customer->getCustomerGroupId())->getCode(); 163 | 164 | // visitorExistingCustomer / visitorLifetimeValue 165 | $orders = Mage::getResourceModel('sales/order_collection')->addFieldToSelect('*')->addFieldToFilter('customer_id',$customer->getId()); 166 | $ordersTotal = 0; 167 | foreach ($orders as $order) { 168 | $ordersTotal += $order->getGrandTotal(); 169 | } 170 | if ($customer->isLoggedIn()) { 171 | $data['visitorLifetimeValue'] = round($ordersTotal,2); 172 | } else { 173 | $orderData = $this->_getTransactionData(); 174 | if (!empty($orderData)) { 175 | $data['visitorLifetimeValue'] = $orderData['transactionTotal']; 176 | } else { 177 | $data['visitorLifetimeValue'] = 0; 178 | } 179 | } 180 | $data['visitorExistingCustomer'] = ($ordersTotal > 0) ? 'Yes' : 'No'; 181 | 182 | return $data; 183 | } 184 | 185 | /** 186 | * Render Google Tag Manager code 187 | * 188 | * @return string 189 | */ 190 | protected function _toHtml() 191 | { 192 | if (!Mage::helper('googletagmanager')->isGoogleTagManagerAvailable()) return ''; 193 | return parent::_toHtml(); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /app/code/community/CVM/GoogleTagManager/Helper/Data.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (c) 2013 Chris Martin 9 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License 3.0 (OSL-3.0) 10 | */ 11 | class CVM_GoogleTagManager_Helper_Data extends Mage_Core_Helper_Abstract 12 | { 13 | const XML_PATH_ACTIVE = 'google/googletagmanager/active'; 14 | const XML_PATH_CONTAINER = 'google/googletagmanager/containerid'; 15 | 16 | const XML_PATH_DATALAYER_TRANSACTIONS = 'google/googletagmanager/datalayertransactions'; 17 | const XML_PATH_DATALAYER_TRANSACTIONTYPE = 'google/googletagmanager/datalayertransactiontype'; 18 | const XML_PATH_DATALAYER_TRANSACTIONAFFILIATION = 'google/googletagmanager/datalayertransactionaffiliation'; 19 | 20 | const XML_PATH_DATALAYER_VISITORS = 'google/googletagmanager/datalayervisitors'; 21 | 22 | /** 23 | * Determine if GTM is ready to use. 24 | * 25 | * @return bool 26 | */ 27 | public function isGoogleTagManagerAvailable() 28 | { 29 | return Mage::getStoreConfig(self::XML_PATH_CONTAINER) && Mage::getStoreConfigFlag(self::XML_PATH_ACTIVE); 30 | } 31 | 32 | /** 33 | * Get the GTM container ID. 34 | * 35 | * @return string 36 | */ 37 | public function getContainerId() { 38 | return Mage::getStoreConfig(self::XML_PATH_CONTAINER); 39 | } 40 | 41 | /** 42 | * Add transaction data to the data layer? 43 | * 44 | * @return bool 45 | */ 46 | public function isDataLayerTransactionsEnabled() 47 | { 48 | return Mage::getStoreConfig(self::XML_PATH_DATALAYER_TRANSACTIONS); 49 | } 50 | 51 | /** 52 | * Get the transaction type. 53 | * 54 | * @return string 55 | */ 56 | public function getTransactionType() { 57 | if (!Mage::getStoreConfig(self::XML_PATH_DATALAYER_TRANSACTIONTYPE)) return ''; 58 | return Mage::getStoreConfig(self::XML_PATH_DATALAYER_TRANSACTIONTYPE); 59 | } 60 | 61 | /** 62 | * Get the transaction affiliation. 63 | * 64 | * @return string 65 | */ 66 | public function getTransactionAffiliation() { 67 | if (!Mage::getStoreConfig(self::XML_PATH_DATALAYER_TRANSACTIONAFFILIATION)) return ''; 68 | return Mage::getStoreConfig(self::XML_PATH_DATALAYER_TRANSACTIONAFFILIATION); 69 | } 70 | 71 | /** 72 | * Add visitor data to the data layer? 73 | * 74 | * @return bool 75 | */ 76 | public function isDataLayerVisitorsEnabled() 77 | { 78 | return Mage::getStoreConfig(self::XML_PATH_DATALAYER_VISITORS); 79 | } 80 | } -------------------------------------------------------------------------------- /app/code/community/CVM/GoogleTagManager/Model/Observer.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (c) 2013 Chris Martin 9 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License 3.0 (OSL-3.0) 10 | */ 11 | class CVM_GoogleTagManager_Model_Observer 12 | { 13 | /** 14 | * Add order data to GTM block (for subsequent rendering in the data layer). 15 | * 16 | * @param Varien_Event_Observer $observer 17 | */ 18 | public function setGoogleTagManagerTransactionData(Varien_Event_Observer $observer) 19 | { 20 | $orderIds = $observer->getEvent()->getOrderIds(); 21 | if (empty($orderIds) || !is_array($orderIds)) return; 22 | $block = Mage::app()->getFrontController()->getAction()->getLayout()->getBlock('google_tag_manager'); 23 | if ($block) $block->setOrderIds($orderIds); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/code/community/CVM/GoogleTagManager/etc/adminhtml.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Google API 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/code/community/CVM/GoogleTagManager/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | 20 | CVM_GoogleTagManager_Block 21 | 22 | 23 | 24 | 25 | CVM_GoogleTagManager_Helper 26 | 27 | 28 | 29 | 30 | CVM_GoogleTagManager_Model 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | CVM_GoogleTagManager.csv 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | googletagmanager/observer 49 | setGoogleTagManagerTransactionData 50 | 51 | 52 | 53 | 54 | 55 | 56 | googletagmanager/observer 57 | setGoogleTagManagerTransactionData 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | googletagmanager.xml 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | CVM_GoogleTagManager.csv 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 0 85 | 0 86 | 0 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /app/code/community/CVM/GoogleTagManager/etc/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | text 18 | 15 19 | 1 20 | 1 21 | 1 22 | 23 | 24 | 25 | select 26 | adminhtml/system_config_source_yesno 27 | 10 28 | 1 29 | 1 30 | 1 31 | 32 | 33 | 34 | text 35 | 20 36 | 1 37 | 1 38 | 1 39 | 1 40 | 41 | 42 | 43 | Populates GTM data layer with transaction data. 44 | select 45 | adminhtml/system_config_source_enabledisable 46 | 30 47 | 1 48 | 1 49 | 1 50 | 1 51 | 52 | 53 | 54 | Optional value for transactionType field. 55 | text 56 | 31 57 | 1 58 | 1 59 | 1 60 | 61 | 1 62 | 1 63 | 64 | 65 | 66 | 67 | Optional value for transactionAffiliation field. 68 | text 69 | 32 70 | 1 71 | 1 72 | 1 73 | 74 | 1 75 | 1 76 | 77 | 78 | 79 | 80 | Populates GTM data layer with visitor data. 81 | select 82 | adminhtml/system_config_source_enabledisable 83 | 40 84 | 1 85 | 1 86 | 1 87 | 1 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/layout/googletagmanager.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/googletagmanager/gtm.phtml: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (c) 2013 Chris Martin 9 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License 3.0 (OSL-3.0) 10 | */ 11 | ?> 12 | 13 | _getDataLayer(); 16 | 17 | // Render the container snippet. 18 | echo $this->_getContainerSnippet(); 19 | ?> 20 | 21 | -------------------------------------------------------------------------------- /app/etc/modules/CVM_GoogleTagManager.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | true 15 | community 16 | 17 | 18 | --------------------------------------------------------------------------------