Subida del módulo y tema de PrestaShop

This commit is contained in:
Kaloyan
2026-04-09 18:31:51 +02:00
parent 12c253296f
commit 16b3ff9424
39262 changed files with 7418797 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use PrestaShop\Module\Ps_Googleanalytics\Repository\CarrierRepository;
use Ps_Googleanalytics;
class HookActionCarrierProcess implements HookInterface
{
private $module;
private $context;
private $params;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return void
*/
public function run()
{
if (isset($this->params['cart']->id_carrier)) {
$carrierRepository = new CarrierRepository();
// Load carrier name
$carrierName = (string) $carrierRepository->findByCarrierId((int) $this->params['cart']->id_carrier);
// Check if we actually have some name
if (empty($carrierName)) {
return;
}
// Prepare and render the event
$eventData = [
'currency' => $this->context->currency->iso_code,
'value' => (float) $this->context->cart->getSummaryDetails()['total_price'],
'shipping_tier' => $carrierName,
];
$jsCode = $this->module->getTools()->renderEvent(
'add_shipping_info',
$eventData
);
// Store it into our repository so we can flush it on next page load
$this->module->getDataHandler()->persistData($jsCode);
}
}
/**
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\ProductWrapper;
use Product;
use Ps_Googleanalytics;
class HookActionCartUpdateQuantityBefore implements HookInterface
{
private $module;
/**
* @var Context
*/
private $context;
private $params;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return void
*/
public function run()
{
/*
* The hook passes a legacy Product object to add, but no attribute information.
* But thankfully, we can use id_product_attribute for this.
*
* Other info is fairly standard:
*
* Add to cart from product page + up from cart page
* $this->params['operator'] == up
* $this->params['quantity'] to determine quantity
*
* Down from cart page
* $this->params['operator'] == down
* $this->params['quantity'] to determine quantity
*/
// Format product and standardize ID
$product = (array) $this->params['product'];
$product['id_product'] = $product['id'];
// Add information about attribute
if (!empty($this->params['id_product_attribute'])) {
$product['id_product_attribute'] = (int) $this->params['id_product_attribute'];
}
// Get some basic information
$product = Product::getProductProperties($this->context->language->id, $product);
// Add information about quantity difference
$product['quantity'] = (int) $this->params['quantity'];
// Prepare it and format it for our purpose
$productWrapper = new ProductWrapper($this->context);
$item = $productWrapper->prepareItemFromProduct($product, true);
// Prepare and render event
$eventData = [
'currency' => $this->context->currency->iso_code,
'value' => $item['price'] * $item['quantity'],
'items' => [$item],
];
$jsCode = $this->module->getTools()->renderEvent(
$this->params['operator'] == 'up' ? 'add_to_cart' : 'remove_from_cart',
$eventData
);
// Store this event
$this->module->getDataHandler()->persistData($jsCode);
}
/**
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\ProductWrapper;
use Product;
use Ps_Googleanalytics;
use Validate;
class HookActionObjectProductInCartDeleteBefore implements HookInterface
{
private $module;
/**
* @var Context
*/
private $context;
private $params;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return void
*/
public function run()
{
// Format product and standardize ID
$product = new Product((int) $this->params['id_product'], false, (int) $this->context->language->id);
if (!Validate::isLoadedObject($product)) {
return;
}
$product = (array) $product;
$product['id_product'] = $product['id'];
// Get some basic information
$product = Product::getProductProperties($this->context->language->id, $product);
// Add information about attribute
if (!empty($this->params['id_product_attribute'])) {
$product['id_product_attribute'] = (int) $this->params['id_product_attribute'];
}
// Prepare it and format it for our purpose
$productWrapper = new ProductWrapper($this->context);
$item = $productWrapper->prepareItemFromProduct($product, false);
// Prepare and render event
$eventData = [
'currency' => $this->context->currency->iso_code,
'value' => $item['price'] * $item['quantity'],
'items' => [$item],
];
$jsCode = $this->module->getTools()->renderEvent(
'remove_from_cart',
$eventData
);
// Store this event
$this->module->getDataHandler()->persistData($jsCode);
}
/**
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
}

View File

@@ -0,0 +1,112 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Configuration;
use Context;
use Db;
use Ps_Googleanalytics;
class HookActionOrderStatusPostUpdate implements HookInterface
{
/**
* @var Ps_Googleanalytics
*/
private $module;
/**
* @var Context
*/
private $context;
/**
* @var array
*/
private $params;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return void
*/
public function run()
{
// If we do not have an order or a new order status, we return
if (empty($this->params['id_order']) || empty($this->params['newOrderStatus']->id)) {
return;
}
// We get all states in which the merchant want to have refund sent and check if the new state being set belongs there
$gaCancelledStates = json_decode(Configuration::get('GA_CANCELLED_STATES'), true);
if (empty($gaCancelledStates) || !in_array($this->params['newOrderStatus']->id, $gaCancelledStates)) {
return;
}
// We check if the refund was already sent to Google Analytics
$gaRefundSent = Db::getInstance()->getValue(
'SELECT id_order FROM `' . _DB_PREFIX_ . 'ganalytics` WHERE id_order = ' . (int) $this->params['id_order'] . ' AND refund_sent = 1'
);
// If it was not already refunded
if ($gaRefundSent === false) {
// We refund it and set the "sent" flag to true
$jsCode = $this->getGoogleAnalytics4($this->params['id_order']);
$this->context->cookie->ga_admin_refund = $jsCode;
$this->context->cookie->write();
// We save this information to database
Db::getInstance()->execute(
'UPDATE `' . _DB_PREFIX_ . 'ganalytics` SET refund_sent = 1 WHERE id_order = ' . (int) $this->params['id_order']
);
}
}
/**
* setParams
*
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
/**
* @param int $idOrder
*/
protected function getGoogleAnalytics4($idOrder)
{
$eventData = [
'transaction_id' => (int) $idOrder,
];
return $this->module->getTools()->renderEvent(
'refund',
$eventData
);
}
}

View File

@@ -0,0 +1,112 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use OrderDetail;
use Ps_Googleanalytics;
use Validate;
class HookActionProductCancel implements HookInterface
{
/**
* @var Ps_Googleanalytics
*/
private $module;
/**
* @var Context
*/
private $context;
private $params;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return void
*/
public function run()
{
if (!isset($this->params['id_order_detail']) || !isset($this->params['cancel_quantity'])) {
return;
}
// Display GA refund product
$orderDetail = new OrderDetail($this->params['id_order_detail']);
// Check if the hook provided us with a valid existing ID of order detail.
// An example are automatic tests, which do not provide it unfortunately.
if (!Validate::isLoadedObject($orderDetail)) {
return;
}
$idProduct = empty($orderDetail->product_attribute_id) ? $orderDetail->product_id : $orderDetail->product_id . '-' . $orderDetail->product_attribute_id;
$jsCode = $this->getGoogleAnalytics4(
(int) $this->params['order']->id,
$idProduct,
(float) $this->params['cancel_quantity'],
$orderDetail->product_name
);
$this->context->cookie->ga_admin_refund = $jsCode;
$this->context->cookie->write();
}
/**
* setParams
*
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
/**
* @param int $idOrder
* @param string $idProduct
* @param float $quantity
* @param string $nameProduct
*/
protected function getGoogleAnalytics4($idOrder, $idProduct, $quantity, $nameProduct)
{
$eventData = [
'transaction_id' => (int) $idOrder,
'items' => [
[
'item_id' => (int) $idProduct,
'item_name' => $nameProduct,
'quantity' => (int) $quantity,
],
],
];
return $this->module->getTools()->renderEvent(
'refund',
$eventData
);
}
}

View File

@@ -0,0 +1,89 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use Ps_Googleanalytics;
class HookActionValidateOrder implements HookInterface
{
/**
* @var Ps_Googleanalytics
*/
private $module;
/**
* @var Context
*/
private $context;
/**
* @var array
*/
private $params;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return void
*/
public function run()
{
// Check if we are creating backoffice order, we are only launching this hook when creating backoffice order
// For FO purposes, we use displayOrderConfirmation.
if (empty($this->context->controller->controller_name)
|| !in_array($this->context->controller->controller_name, ['AdminOrders', 'Admin'])) {
return;
}
// Mark this ID to immediately display it on next page load
$order = $this->params['order'];
// We are checking this, because in case of multishipping, there could be multiple orders
if (!empty($this->context->cookie->ga_admin_order)) {
$ga_admin_order = sprintf(
'%1$s,%2$s',
$this->context->cookie->ga_admin_order,
$order->id
);
} else {
$ga_admin_order = $order->id;
}
$this->context->cookie->ga_admin_order = $ga_admin_order;
$this->context->cookie->write();
}
/**
* setParams
*
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
}

View File

@@ -0,0 +1,184 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Cart;
use Configuration;
use Context;
use Db;
use Order;
use PrestaShop\Module\Ps_Googleanalytics\Handler\GanalyticsJsHandler;
use PrestaShop\Module\Ps_Googleanalytics\Repository\GanalyticsRepository;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\OrderWrapper;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\ProductWrapper;
use Ps_Googleanalytics;
use Tools;
use Validate;
class HookDisplayBackOfficeHeader implements HookInterface
{
private $module;
private $context;
private $gaScripts = '';
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return string
*/
public function run()
{
// Add assets if we are on configuration page
if (strcmp(Tools::getValue('configure'), $this->module->name) === 0) {
$this->context->controller->addCSS($this->module->getPathUri() . 'views/css/ganalytics.css');
}
// Render base tag using displayHeader hook with backoffice parameter
$this->gaScripts .= $this->module->hookDisplayHeader(null, true);
// Process manual orders instantly, we have their IDs in cookie
$this->processManualOrders();
// Backload old orders that failed to load normally
$this->processFailedOrders();
return $this->gaScripts;
}
/**
* Checks if there are any orders that failed to be sent normally through front office and processes them
*/
protected function processFailedOrders()
{
if (empty(Configuration::get('GA_BACKLOAD_ENABLED'))) {
return;
}
// Check for value on how long back we will get them
$backloadDays = (int) Configuration::get('GA_BACKLOAD_DAYS');
if ($backloadDays < 1) {
return;
}
// Get all failed orders (either not present in our table or not sent)
// We go GA_BACKLOAD_DAYS into the past and at least 30 minutes old
$failedOrders = Db::getInstance()->ExecuteS(
'SELECT DISTINCT o.id_order, g.sent FROM `' . _DB_PREFIX_ . 'orders` o
LEFT JOIN `' . _DB_PREFIX_ . GanalyticsRepository::TABLE_NAME . '` g ON o.id_order = g.id_order
WHERE (g.sent IS NULL OR g.sent = 0) AND o.date_add BETWEEN NOW() - INTERVAL ' . $backloadDays . ' DAY AND NOW() - INTERVAL 30 MINUTE'
);
// Process each failed order
foreach ($failedOrders as $row) {
$this->processOrder((int) $row['id_order']);
}
}
/**
* Checks if there are any manual orders in cookie and processes them
*/
protected function processManualOrders()
{
$adminOrders = $this->context->cookie->ga_admin_order;
if (empty($adminOrders)) {
return;
}
// Separate them by IDs and process one by one
$adminOrders = explode(',', $adminOrders);
foreach ($adminOrders as $idOrder) {
$this->processOrder((int) $idOrder);
}
// Clean up the cookie
unset($this->context->cookie->ga_admin_order);
$this->context->cookie->write();
}
/**
* Renders tracking code for given order
*
* @param int $idOrder
*/
public function processOrder($idOrder)
{
$order = new Order((int) $idOrder);
if (!Validate::isLoadedObject($order) || $order->getCurrentState() == (int) Configuration::get('PS_OS_ERROR')) {
return;
}
// Load up our handlers and repositories
$ganalyticsRepository = new GanalyticsRepository();
$gaTagHandler = new GanalyticsJsHandler($this->module, $this->context);
$productWrapper = new ProductWrapper($this->context);
$orderWrapper = new OrderWrapper($this->context);
// If it's a completely new order, add order to repository, so we can later mark it as sent
if (empty($ganalyticsRepository->findGaOrderByOrderId((int) $order->id))) {
$ganalyticsRepository->addOrder((int) $order->id, (int) $order->id_shop);
}
// If the order was already sent for some reason, don't do anything
if ($ganalyticsRepository->hasOrderBeenAlreadySent((int) $order->id)) {
return;
}
// Prepare transaction data
$orderData = $orderWrapper->wrapOrder($order);
// Empty script for the current order
$gaScripts = '';
// Prepare order products, if the cart still exists
$orderProducts = [];
$cart = new Cart($order->id_cart);
if (Validate::isLoadedObject($cart)) {
$orderProducts = $productWrapper->prepareItemListFromProductList($cart->getProducts(), true);
}
// Add payment event
$gaScripts .= $this->module->getTools()->renderEvent(
'add_payment_info',
[
'currency' => $orderData['currency'],
'value' => (float) $orderData['value'],
'payment_type' => $orderData['payment_type'],
'items' => $orderProducts,
]
);
// Render transaction code
$gaScripts .= $this->module->getTools()->renderPurchaseEvent(
$orderProducts,
$orderData,
$this->context->link->getAdminLink('AdminGanalyticsAjax')
);
$this->gaScripts .= $gaTagHandler->generate($gaScripts);
}
}

View File

@@ -0,0 +1,279 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use PrestaShop\Module\Ps_Googleanalytics\Handler\GanalyticsJsHandler;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\ProductWrapper;
use Ps_Googleanalytics;
class HookDisplayBeforeBodyClosingTag implements HookInterface
{
private $module;
private $context;
private $gaScripts = '';
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return string
*/
public function run()
{
// Prepare our tag handler
$gaTagHandler = new GanalyticsJsHandler($this->module, $this->context);
// Log information about product listing
$this->saveInformationAboutListing();
// Flush events stored in data storage from previous pages
$this->outputStoredEvents();
// Add events
$this->renderProductListing();
$this->renderSearch();
$this->renderCartPage();
$this->renderBeginCheckout();
$this->renderLogin();
$this->renderRegistration();
// Output everything
return $gaTagHandler->generate($this->gaScripts);
}
/**
* This method renders tracking code for product listings, like category pages.
*/
private function renderProductListing()
{
// Try to get product list variable
$listing = $this->context->smarty->getTemplateVars('listing');
if (empty($listing['products'])) {
return;
}
// Prepare items to our format
$productWrapper = new ProductWrapper($this->context);
$items = $productWrapper->prepareItemListFromProductList($listing['products']);
// Prepare info about the list
$item_list_id = $this->context->controller->php_self;
$item_list_name = $listing['label'];
// Render the event
$eventData = [
'item_list_id' => $item_list_id,
'item_list_name' => $item_list_name,
'items' => $items,
];
$this->gaScripts .= $this->module->getTools()->renderEvent(
'view_item_list',
$eventData
);
// Render quickview events
foreach ($items as $item) {
$eventData = [
'item_list_id' => $item_list_id,
'item_list_name' => $item_list_name,
'items' => [$item],
];
// Keep only product ID if id_product_attribute was appended
$productId = explode('-', $item['item_id']);
$productId = $productId[0];
// Render the event wrapped in onclick
$this->gaScripts .= '
$(\'article[data-id-product="' . $productId . '"] a.quick-view\').on(
"click",
function() {' . $this->module->getTools()->renderEvent('select_item', $eventData) . '}
);
';
}
}
/**
* This method renders tracking code when user searches on the shop.
*/
private function renderSearch()
{
// Check if we are on search page and we have a search string
if ($this->context->controller->php_self != 'search' || empty($_GET['s'])) {
return;
}
// Render the event
$eventData = [
'search_term' => (string) $_GET['s'],
];
$this->gaScripts .= $this->module->getTools()->renderEvent(
'search',
$eventData
);
}
/**
* This method renders tracking code for product listings, like category pages.
*/
private function renderCartpage()
{
// Check if we are on cart page
if ($this->context->controller->php_self != 'cart') {
return;
}
// Try to get product list variable and check if it's not empty
$cart = $this->context->smarty->getTemplateVars('cart');
if (empty($cart['products'])) {
return;
}
// Prepare items to our format
$productWrapper = new ProductWrapper($this->context);
$items = $productWrapper->prepareItemListFromProductList($cart['products'], true);
// Render the event
$eventData = [
'currency' => $this->context->currency->iso_code,
'value' => $cart['totals']['total']['amount'],
'items' => $items,
];
$this->gaScripts .= $this->module->getTools()->renderEvent(
'view_cart',
$eventData
);
}
/**
* This method renders tracking code for product listings, like category pages.
*/
private function renderBeginCheckout()
{
// Check if we are on some supported order controller
$allowed_controllers = ['order', 'orderopc', 'checkout'];
if (!in_array($this->context->controller->php_self, $allowed_controllers)) {
return;
}
// If the user reliably came from previous page, we won't render this event
// We want to do it just for first visiting checkout
if (!empty($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], $_SERVER['REQUEST_URI']) !== false) {
return;
}
// Try to get product list variable and check if it's not empty
$cart = $this->context->smarty->getTemplateVars('cart');
if (empty($cart['products'])) {
return;
}
// Prepare items to our format
$productWrapper = new ProductWrapper($this->context);
$items = $productWrapper->prepareItemListFromProductList($cart['products'], true);
// Render the event
$eventData = [
'currency' => $this->context->currency->iso_code,
'value' => $cart['totals']['total']['amount'],
'items' => $items,
];
$this->gaScripts .= $this->module->getTools()->renderEvent(
'begin_checkout',
$eventData
);
}
/**
* This method renders tracking code after user logs in.
*/
private function renderLogin()
{
// Render it only on login page AND if we are not creating a new account in older PS versions
// For newer versions, registrations are handled with standalone registration controller.
if ($this->context->controller->php_self != 'authentication' || isset($_GET['create_account'])) {
return;
}
// Render the event
$this->gaScripts .= $this->module->getTools()->renderEvent('login', []);
}
/**
* This method renders tracking code after user registers.
*/
private function renderRegistration()
{
if ($this->context->controller->php_self != 'registration' &&
($this->context->controller->php_self != 'authentication' || !isset($_GET['create_account']))
) {
return;
}
// Render the event
$this->gaScripts .= $this->module->getTools()->renderEvent('sign_up', []);
}
/**
* Saves information about last visited product listing, so we can later use it for select_item event.
*/
private function saveInformationAboutListing()
{
// Try to get product list variable
$listing = $this->context->smarty->getTemplateVars('listing');
if (empty($listing['products']) || empty($listing['label'])) {
return;
}
// Save this information to a cookie
$this->context->cookie->ga_last_listing = json_encode([
'item_list_url' => $_SERVER['REQUEST_URI'],
'item_list_id' => $this->context->controller->php_self,
'item_list_name' => $listing['label'],
]);
}
/**
* Outputs all events we stored into data repository during previous AJAX requests
* on previous page.
*/
private function outputStoredEvents()
{
// Get all stored events
$storedEvents = $this->module->getDataHandler()->readData();
if (empty($storedEvents)) {
return;
}
foreach ($storedEvents as $event) {
$this->gaScripts .= $event;
}
// Delete the repository because everything has been flushed
$this->module->getDataHandler()->deleteData();
}
}

View File

@@ -0,0 +1,145 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use PrestaShop\Module\Ps_Googleanalytics\Handler\GanalyticsJsHandler;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\ProductWrapper;
use Ps_Googleanalytics;
class HookDisplayFooterProduct implements HookInterface
{
private $module;
private $context;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return string|void
*/
public function run()
{
// Check we are really on product page
if ($this->context->controller->php_self !== 'product') {
return;
}
// Get lazy array from context
$product = $this->context->smarty->getTemplateVars('product');
if (empty($product)) {
return;
}
// Initialize tag handler
$gaTagHandler = new GanalyticsJsHandler($this->module, $this->context);
// Prepare it and format it for our purpose
$productWrapper = new ProductWrapper($this->context);
$item = $productWrapper->prepareItemFromProduct($product);
$jsCode = '';
// Prepare and render event
$eventData = [
'currency' => $this->context->currency->iso_code,
'value' => $item['price'],
'items' => [$item],
];
$jsCode .= $this->module->getTools()->renderEvent(
'view_item',
$eventData
);
// If the user got to the product page from previous page on our shop,
// we will also send select_item event.
if ($this->wasPreviousPageOurShop()) {
$eventData = [
'items' => [$item],
];
// We will also try to get the information about the last visited listing.
// We save this information into a cookie. If it's the page that got the user here,
// we will use it.
$previousListingData = $this->getLastVisitedListing();
if (!empty($previousListingData)) {
$eventData = array_merge($previousListingData, $eventData);
}
// Render the event
$jsCode .= $this->module->getTools()->renderEvent(
'select_item',
$eventData
);
}
return $gaTagHandler->generate($jsCode);
}
/**
* Checks HTTP_REFERER to see if the previous page that got user to this product
* was our shop.
*
* @return bool
*/
private function wasPreviousPageOurShop()
{
if (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST']) !== false) {
return true;
}
return false;
}
/**
* Tries to get details of previous listing from the cookie.
*
* @return bool|array
*/
private function getLastVisitedListing()
{
// Fetch it from the cookie
$last_listing = $this->context->cookie->ga_last_listing;
if (empty($last_listing)) {
return false;
}
// Decode the data and check if it contains something sensible
$last_listing = json_decode($last_listing, true);
if (empty($last_listing['item_list_id'])) {
return false;
}
// Check if the last listing is the page the user came from
if (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], $last_listing['item_list_url']) !== false) {
unset($last_listing['item_list_url']);
return $last_listing;
}
return false;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Configuration;
use Context;
use Customer;
use Ps_Googleanalytics;
use Tools;
class HookDisplayHeader implements HookInterface
{
/**
* @var Ps_Googleanalytics
*/
private $module;
/**
* @var Context
*/
private $context;
/**
* @var bool
*/
private $backOffice;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* @return false|string
*/
public function run()
{
if (!Configuration::get('GA_ACCOUNT_ID')) {
return '';
}
// Resolve if we should add user ID into the code
$userId = null;
if (Configuration::get('GA_USERID_ENABLED')
&& $this->context->customer instanceof Customer
&& $this->context->customer->isLogged()
) {
$userId = (int) $this->context->customer->id;
}
$this->context->smarty->assign(
[
'backOffice' => $this->backOffice,
'trackBackOffice' => Configuration::get('GA_TRACK_BACKOFFICE_ENABLED'),
'userId' => $userId,
'gaAccountId' => Tools::safeOutput(Configuration::get('GA_ACCOUNT_ID')),
'gaAnonymizeEnabled' => Configuration::get('GA_ANONYMIZE_ENABLED'),
]
);
return $this->module->display(
$this->module->getLocalPath() . $this->module->name,
'ps_googleanalytics.tpl'
);
}
/**
* @param bool $backOffice
*/
public function setBackOffice($backOffice)
{
$this->backOffice = $backOffice;
}
}

View File

@@ -0,0 +1,115 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Cart;
use Configuration;
use Context;
use PrestaShop\Module\Ps_Googleanalytics\Handler\GanalyticsJsHandler;
use PrestaShop\Module\Ps_Googleanalytics\Repository\GanalyticsRepository;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\OrderWrapper;
use PrestaShop\Module\Ps_Googleanalytics\Wrapper\ProductWrapper;
use Ps_Googleanalytics;
use Validate;
class HookDisplayOrderConfirmation implements HookInterface
{
private $module;
private $context;
private $params;
public function __construct(Ps_Googleanalytics $module, Context $context)
{
$this->module = $module;
$this->context = $context;
}
/**
* run
*
* @return string
*/
public function run()
{
$gaScripts = '';
$order = $this->params['order'];
if (!Validate::isLoadedObject($order) || $order->getCurrentState() == (int) Configuration::get('PS_OS_ERROR')) {
return $gaScripts;
}
// Load up our handlers and repositories
$ganalyticsRepository = new GanalyticsRepository();
$gaTagHandler = new GanalyticsJsHandler($this->module, $this->context);
$productWrapper = new ProductWrapper($this->context);
$orderWrapper = new OrderWrapper($this->context);
// If it's a completely new order, add order to repository, so we can later mark it as sent
if (empty($ganalyticsRepository->findGaOrderByOrderId((int) $order->id))) {
$ganalyticsRepository->addOrder((int) $order->id, (int) $order->id_shop);
}
// If the customer is revisiting confirmation screen and the order was already sent, we don't do anything
if ($ganalyticsRepository->hasOrderBeenAlreadySent((int) $order->id)) {
return $gaScripts;
}
// Prepare transaction data
$orderData = $orderWrapper->wrapOrder($order);
// Prepare order products, if the cart still exists
$orderProducts = [];
$cart = new Cart($order->id_cart);
if (Validate::isLoadedObject($cart)) {
$orderProducts = $productWrapper->prepareItemListFromProductList($cart->getProducts(), true);
}
// Add payment event
$gaScripts .= $this->module->getTools()->renderEvent(
'add_payment_info',
[
'currency' => $orderData['currency'],
'value' => (float) $orderData['value'],
'payment_type' => $orderData['payment_type'],
'items' => $orderProducts,
]
);
// Render transaction code
$gaScripts .= $this->module->getTools()->renderPurchaseEvent(
$orderProducts,
$orderData,
$this->context->link->getModuleLink('ps_googleanalytics', 'ajax', [], true)
);
return $gaTagHandler->generate($gaScripts);
}
/**
* setParams
*
* @param array $params
*/
public function setParams($params)
{
$this->params = $params;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\Ps_Googleanalytics\Hooks;
use Context;
use Ps_Googleanalytics;
interface HookInterface
{
/**
* @param Ps_Googleanalytics $module
* @param Context $context
*/
public function __construct(Ps_Googleanalytics $module, Context $context);
public function run();
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
header('Expires: Mon, 26 Jul 1998 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;