* @copyright 2022 ECSoft * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registered Trademark & Property of ECSoft */ include_once dirname(__FILE__) . '/classes/EcsGtmProInstaller.php'; include_once dirname(__FILE__) . '/classes/config/EcsGtmProGtmConfig.php'; include_once dirname(__FILE__) . '/classes/config/EcsGtmProGcrConfig.php'; include_once dirname(__FILE__) . '/classes/EcsGtmProOrder.php'; include_once dirname(__FILE__) . '/classes/EcsGtmProTools.php'; include_once dirname(__FILE__) . '/classes/gtm/EcsGtmProDataLayerManager.php'; if (!defined('JSON_UNESCAPED_SLASHES')) { define('JSON_UNESCAPED_SLASHES', 64); } if (!defined('JSON_PRETTY_PRINT')) { define('JSON_PRETTY_PRINT', 128); } define('_ECSGTMPRO_PRICE_DECIMAL_', 2); define('_ECSGTMPRO_ORDER_RESEND_POOL_', 'ECSGTMPRO_ORDER_RESEND_POOL'); define('_ECSGTMPRO_ORDER_REFUND_POOL_', 'ECSGTMPRO_ORDER_REFUND_POOL'); /** * @property $gtmConfig EcsGtmProGtmConfig * @property $gcrConfig EcsGtmProGcrConfig * @property $preDataLayer EcsGtmProDataLayer * @property $dataLayer EcsGtmProDataLayer */ class EcsGtmPro extends Module { const ADDONS_ID = 88980; const CHECK_HOOKS_PARAM = 'ecsgtmpro_check_hooks'; public $html; public $orderIdField = "id"; public $gtmConfig; public $gcrConfig; public $preDataLayer; public $dlManager; public $eventDatalayerReady = "datalayer_ready"; public $orderValidationDetails; protected $displayOrderConfirmation; protected $displayOrderConfirmationOrderObj; protected $debugStack = []; public function __construct() { $this->name = 'ecsgtmpro'; $this->tab = 'analytics_stats'; $this->version = '1.1.3'; $this->controllers = array('async', 'callback'); $this->author = 'ECSoft'; $this->need_instance = 0; $this->bootstrap = true; if ($this->is17() || $this->is8x()) { $this->ps_versions_compliancy = array( 'min' => '1.7', 'max' => _PS_VERSION_ ); } $this->module_key = 'dbcf21303d0231d76b102b06bf397abd'; parent::__construct(); $this->displayName = $this->l('Google Tag Manager for eCommerce PRO (UA + GA4) '); $this->description = $this->l('GTM integration (GA4 + UA) + Enhanced E-commerce + Google Customer Reviews in one module'); $this->confirmUninstall = $this->l('Are you sure you want to delete all data?'); $this->gtmConfig = new EcsGtmProGtmConfig($this); $this->gcrConfig = new EcsGtmProGcrConfig($this); $this->gtmConfig->loadAllFromConfig(); $this->gcrConfig->loadFromConfig(); $this->dlManager = new EcsGtmProDataLayerManager($this, $this->gtmConfig->generalConfig->format); } public function addDebug($message) { if (is_array($message) || is_object($message)) { $this->debugStack[] = json_encode($message, JSON_PRETTY_PRINT); } else { $this->debugStack[] = $message; } } public function renderDebug() { return $this->render('debug.tpl', array( 'isAjax' => EcsGtmProTools::isAjax(), 'debugStack' => $this->debugStack )); } public function getInstaller() { return new EcsGtmProInstaller($this); } public function install() { return parent::install() && $this->getInstaller()->install() && $this->createMissingGtmOrderLogs(); } public function uninstall() { return parent::uninstall() && $this->getInstaller()->uninstall(); } public function getForms() { return array( $this->gtmConfig->generalConfig, $this->gtmConfig->dataConfig, $this->gtmConfig->userIdConfig, $this->gtmConfig->remarketingConfig, $this->gcrConfig ); } public function getContent() { if ($this->isSubmit()) { if ($this->postValidate()) { $this->postProcess(); } } $this->html .= $this->renderForm(); return $this->html; } public function isSubmit() { foreach ($this->getAllowedSubmits() as $submit) { if (Tools::isSubmit($submit)) { return true; } } } public function getAllowedSubmits() { $submits = array(); foreach ($this->getForms() as $model) { $submits[] = get_class($model); } return $submits; } public function clearCache() { } public function postProcess() { foreach ($this->getForms() as $model) { if (Tools::isSubmit(get_class($model))) { $model->populate(); if ($model->saveToConfig()) { $this->html .= $this->displayConfirmation($this->l('Settings updated')); } else { $this->postValidate(); } } } $this->clearCache(); } public function postValidate() { foreach ($this->getForms() as $model) { if (Tools::isSubmit(get_class($model))) { $model->loadFromConfig(); $model->populate(); if (!$model->validate()) { foreach ($model->getErrors() as $errors) { foreach ($errors as $error) { $this->html .= $this->displayError($error); } } return false; } return true; } } } public function isMobile() { return Context::getContext()->getMobileDetect()->isMobile() || Context::getContext()->getMobileDetect()->isTablet(); } public function render($file, $params = array()) { $this->smarty->assign($params); return $this->display(__FILE__, $file); } public function renderForm() { return $this->renderNewConfig(); } public function renderNewConfig() { $this->context->controller->addCSS($this->_path.'views/css/main.a75059e8.css'); $lang = new Language((int)Configuration::get('PS_LANG_DEFAULT')); $defaultLang = array( 'id' => $lang->id, 'label' => $lang->name, 'short' => $lang->iso_code ); $langs = array(); foreach($this->context->controller->getLanguages() as $l) { $langs[$l['iso_code']] = array( 'id' => $l['id_lang'], 'label' => $l['name'], 'short' => $l['iso_code'] ); } $this->smarty->assign(array( 'langs' => EcsGtmProTools::jsonEncode($langs, JSON_NUMERIC_CHECK), 'defaultLang' => EcsGtmProTools::jsonEncode($defaultLang, JSON_NUMERIC_CHECK), 'ajaxURL' => $this->getAjaxUrl('AdminEcsGtmProHooks') . '&ajax=true', 'ajaxURLHooks' => Context::getContext()->link->getPageLink('index', null, null, null, false, null, true), 'author' => $this->author, 'name' => $this->displayName, 'description' => $this->description, 'version' => $this->version, 'logoURL' => $this->getPath() . 'views/img/logo-big.png', 'brandLogoURL' => $this->getPath() . 'views/img/brand-logo.png', 'ratingURL' => 'https://addons.prestashop.com/en/ratings.php', 'supportURL' => 'https://addons.prestashop.com/en/contact-us?id_product=' . self::ADDONS_ID, 'ajaxURLHooksInstall' => $this->getAjaxUrl('AdminEcsGtmProHooks'), 'path' => $this->getPath() )); return $this->display(__FILE__, 'views/templates/admin/config-react.tpl'); } public function isAllowed() { if ($this->gtmConfig->generalConfig->enable && $this->gtmConfig->generalConfig->gtm_id) { $ips = explode(PHP_EOL, $this->gtmConfig->generalConfig->allowed_ips); if (($this->gtmConfig->generalConfig->sandbox && in_array(Tools::getRemoteAddr(), $ips)) || !$this->gtmConfig->generalConfig->sandbox) { return true; } } return false; } public function isController($controller) { return Tools::getValue('controller') == $controller; } public function isModule($module) { return Tools::getValue('module') == $module; } public function isHomePage() { return $this->isController('index'); } public function isProductPage() { return $this->isController('product'); } public function isCartPage() { return $this->isController('cart'); } public function isOrderPage() { return $this->isController('order'); } public function isPaymentPage() { return $this->isController('payment'); } public function isCategoryPage() { return $this->isController('category'); } public function isSearchPage() { return $this->isController('search'); } public function isOPC() { if ($this->isController('orderopc') || $this->isController('supercheckout')) { return true; } elseif ($this->isModule('onepagecheckoutps')) { return true; } elseif ($this->isModule('klarnaofficial') && $this->isController('checkoutklarna')) { return true; } elseif ($this->isModule('klarnaofficial') && $this->isController('checkoutklarnakco')) { return true; } elseif ($this->isModule('collectorcheckout') && $this->isController('confirmation')) { return true; } elseif ($this->isModule('collectorcheckout') && $this->isController('checkout')) { return true; } elseif ($this->isModule('steasycheckout') && $this->isController('default')) { return true; } return false; } public function saveDataLayerInLog($dataLayerjs) { if (is_array($this->orderValidationDetails) && count($this->orderValidationDetails)) { foreach ($this->orderValidationDetails as $order) { $order_log = EcsGtmProOrder::getByOrderId($order['id_order'], Context::getContext()->shop->id); if (Validate::isLoadedObject($order_log)) { $order_log->datalayer = $dataLayerjs; $order_log->save(); } } } } public function isOrderValidationPage() { $ovp = false; if ($this->displayOrderConfirmation) { $ovp = true; } elseif ($this->isController('orderconfirmation')) { $ovp = true; } elseif ($this->isModule('paypal') && $this->isController('submit')) { $ovp = true; } elseif ($this->isModule('paypalplus') && $this->isController('confirmation')) { $ovp = true; } elseif ($this->isModule('stripejs') && $this->isController('confirmation')) { $ovp = true; } elseif ($this->isModule('firstdatapayment') && $this->isController('success')) { $ovp = true; } elseif ($this->isModule('przelewy24') && $this->isController('paymentSuccessful')) { $ovp = true; $this->displayOrderConfirmationOrderObj['id_cart'] = (int) Tools::getValue('ga_cart_id'); } elseif ($this->isModule('mollie') && $this->isController('return')) { $ovp = true; $this->displayOrderConfirmationOrderObj['id_cart'] = (int) Tools::getValue('cart_id'); } elseif ($this->isModule('klarnaofficial') && $this->isController('thankyou')) { $ovp = true; } elseif ($this->isModule('collectorcheckout') && $this->isController('confirmation')) { $ovp = true; } elseif ($this->isModule('sveacheckout') && $this->isController('confirmation')) { $ovp = true; } elseif ($this->isModule('paysoncheckout2') && $this->isController('confirmation')) { $ovp = true; } elseif ($this->isModule('g2apay') && $$this->isController('success')) { $ovp = true; } elseif ($this->isModule('iyzicocheckoutform') && $this->isController('result')) { $ovp = true; $this->displayOrderConfirmationOrderObj['id_cart'] = (int) $this->context->cart->id; } elseif ($this->isModule('payu') && $this->isController('success')) { $ovp = true; } elseif ($this->isModule('ecm_checkout') && $this->isController('checkout_end')) { $ovp = true; } elseif ($this->isModule('dotpay') && $this->isController('back')) { $ovp = true; } if ($ovp && !is_array($this->orderValidationDetails)) { $this->orderValidationDetails = array(); } return $ovp; } public function createMissingGtmOrderLogs() { $sql = 'SELECT o.id_order, o.id_shop FROM `' . _DB_PREFIX_ . EcsGtmProOrder::TABLE_NAME . '` t RIGHT JOIN `' . _DB_PREFIX_ . 'orders` o ON (o.id_order = t.id_order) WHERE t.id IS NULL'; $missingOrdersLogs = Db::getInstance()->executeS($sql); $createdCount = 0; if (!empty($missingOrdersLogs)) { foreach ($missingOrdersLogs as $missingOrder) { $createdCount += self::createGtmOrder($missingOrder['id_order'], $missingOrder['id_shop']); } } return $createdCount; } public static function createGtmOrder($id_order, $id_shop) { if (EcsGtmProOrder::countByOrderId($id_order, $id_shop) == 0) { $order_log = new EcsGtmProOrder(); $order_log->id_order = $id_order; $order_log->id_shop = $id_shop; $order_log->sent = 0; $order_log->resent = 0; $order_log->save(); return 1; } return 0; } /** HOOKS **/ public function hookActionOrderGridDefinitionModifier($params) { } public function hookActionOrderGridQueryBuilderModifier($params) { } public function hookDisplayHeader() { if ($this->isAllowed()) { $isAjaxCart = Configuration::get('PS_BLOCK_CART_AJAX', 0); if ($this->isDebugMode()) { $this->addDebug('PS version: ' . _PS_VERSION_ . ' | Module version: ' . $this->version); $this->addDebug('Controller: ' . Tools::getValue('controller') . ' | Module: ' . Tools::getValue('module')); } $this->context->smarty->assign(array( 'ajaxcartEnabled' => $isAjaxCart, 'ajaxGetProductUrl' => Context::getContext()->link->getModuleLink('ecsgtmpro', 'async', array(), null, null, null, true), )); if ($isAjaxCart) { $this->context->controller->addJS($this->_path.'views/js/dl.js'); if ($this->is16()) { $this->context->controller->addJS($this->_path.'views/js/dl16.js'); } elseif ($this->is17() || $this->is8x()) { $this->context->controller->addJS($this->_path.'views/js/dl17.js'); } } } } public function hookDisplayAfterTitleTag() { if (Tools::isSubmit(self::CHECK_HOOKS_PARAM)) { return $this->render('check_hook.tpl', array( 'hookName' => 'displayAfterTitleTag' )); } if ($this->isAllowed()) { $this->dlManager->generateDataLayer(); if ($this->gtmConfig->remarketingConfig->enable) { $this->dlManager->generateRemarketingParams(); } $this->dlManager->generateGtmTag(); return $this->render('gtm.tpl', array( 'debug' => $this->isDebugMode(), 'async' => $this->gtmConfig->userIdConfig->async, 'generalConfig' => $this->gtmConfig->generalConfig, 'userIdConfig' => $this->gtmConfig->userIdConfig )); } } public function hookDisplayAfterBodyOpeningTag() { if (Tools::isSubmit(self::CHECK_HOOKS_PARAM)) { return $this->render('check_hook.tpl', array( 'hookName' => 'displayAfterBodyOpeningTag' )); } $content = ''; if ($this->isAllowed()) { $content .= $this->render('gtm_noscript.tpl', array( 'generalConfig' => $this->gtmConfig->generalConfig )); } return $content; } public function hookDisplayBeforeBodyClosingTag() { if (Tools::isSubmit(self::CHECK_HOOKS_PARAM)) { return $this->render('check_hook.tpl', array( 'hookName' => 'displayBeforeBodyClosingTag' )); } $content = ''; if ($this->isAllowed()) { if ($this->isOPC()) { if ($this->dlManager->generateDataLayer()) { $this->dlManager->generateGtmTag(); } $content .= $this->render('opc.tpl', array( 'debug' => $this->isDebugMode(), 'async' => $this->gtmConfig->userIdConfig->async, )); } } if ($this->gcrConfig->enable) { if ($this->gcrConfig->confirmation && $this->isOrderValidationPage()) { $this->dlManager->generateOrderConfirmationCode(); $content .= $this->render('gcr_order_confirmation_code.tpl'); } else { if ($this->gcrConfig->add_badge) { $content .= $this->render('gcr_badge_tag.tpl', array( 'gcrConfig' => $this->gcrConfig, 'langCode' => strtolower(Context::getContext()->language->iso_code) )); } } } if ($this->isDebugMode()) { $this->addDebug('POST:'); $this->addDebug($_POST); $this->addDebug('GET:'); $this->addDebug($_GET); $content .= $this->renderDebug(); } return $content; } public function isDebugMode() { return $this->gtmConfig->generalConfig->debug || Tools::getValue('ecsgtmpro_debug') || isset($_COOKIE['XDEBUG_SESSION']); } public function hookActionObjectOrderDetailUpdateAfter($params) { $orderDetail = $params['object']; // if no quantity refunded, no action if (empty($orderDetail->product_quantity_refunded)) { return; } $order_id = $orderDetail->id_order; $gtmOrderLog = EcsGtmProOrder::getByOrderId($order_id); if (Validate::isLoadedObject($gtmOrderLog)) { if (EcsGtmProOrder::isRefundable($order_id, $gtmOrderLog->id_shop)) { $this->addRefund($order_id, $gtmOrderLog->id_shop, $orderDetail->product_id, $orderDetail->product_attribute_id, $orderDetail->product_quantity_refunded); } } } public function hookUpdateOrderStatus($params) { $order_id = $params['id_order']; $newOrderStatus = $params['newOrderStatus']->id; $refund_state_id = array( Configuration::get('PS_OS_CANCELED'), Configuration::get('PS_OS_REFUND'), Configuration::get('PS_OS_ERROR') ); $gtmOrderLog = EcsGtmProOrder::getByOrderId($order_id); if (Validate::isLoadedObject($gtmOrderLog)) { if (in_array($newOrderStatus, $refund_state_id)) { if (EcsGtmProOrder::isRefundable($order_id, $gtmOrderLog->id_shop)) { $this->addRefund($order_id, $gtmOrderLog->id_shop); } } } } /** ToDo **/ public function hookDisplayBackOfficeHeader() { $content = ''; if ($this->isAllowed()) { $this->gtmConfig->userIdConfig->async = 0; if ($this->gtmConfig->generalConfig->resend_orders) { $this->resendOrders(); } // if ($this->recreateOrderConfirmationFromBO() || $this->dataLayerRefund() || $this->generateEnhancedEcommerceOrderResend()) { $this->eventDatalayerReady = "bo_" . $this->eventDatalayerReady; // $this->dlManager->generateGtmTag(); $content = $this->render('gtm_script.tpl', array( 'debug' => $this->isDebugMode(), 'async' => $this->gtmConfig->userIdConfig->async, 'generalConfig' => $this->gtmConfig->generalConfig, 'userIdConfig' => $this->gtmConfig->userIdConfig )); if ($this->dataLayerRefund()) { $this->dlManager->generateGtmTag(); $content .= $this->render('gtm_push_script.tpl'); } // } } return $content; } public function hookDisplayOrderConfirmation(array $params) { $this->displayOrderConfirmation = true; try { if (!empty($params['objOrder'])) { $this->displayOrderConfirmationOrderObj = json_decode(json_encode($params['objOrder']), true); } } catch (Exception $e) { // nothing } } public function hookActionCustomerAccountAdd($params) { try { $preDataLayer = new EcsGtmProDataLayerManager($this, $this->gtmConfig->generalConfig->format); $preDataLayer->event = 'sign_up'; Context::getContext()->cookie->preDataLayerJs = $preDataLayer->toJson(); } catch (Exception $e) { // nothing } } public function hookActionAuthentication($params) { try { $preDataLayer = new EcsGtmProDataLayerManager($this, $this->gtmConfig->generalConfig->format); $preDataLayer->event = 'login'; Context::getContext()->cookie->preDataLayerJs = $preDataLayer->toJson(); } catch (Exception $e) { // nothing } } public function hookDisplayProductPriceBlock($params) { if (!empty($params['type']) && $params['type'] == 'price' && isset($params['product']) && is_array($params['product'])) { $id_product = !empty($params['product']['id_product']) ? $params['product']['id_product'] : 0; $id_product_attribute = !empty($params['product']['id_product_attribute']) ? $params['product']['id_product_attribute'] : 0; return ''; } } /** HOOKS END **/ public function addRefund($id_order, $id_shop, $product_id = null, $product_attribute_id = 0, $qty = null) { $gtmOrder = EcsGtmProOrder::getByOrderId($id_order, $id_shop); $refundsPool = $this->getRefundPool($id_shop); if (is_null($product_id)) { $gtmOrder->refund = "all"; $refundsPool[$id_order] = "all"; } else { $productsRefunded = array(); if ($gtmOrder->refund && $gtmOrder->refund != "all") { $productsRefunded = explode(',', $gtmOrder->refund); } $product_id_with_attribute = $product_id.'-'.$product_attribute_id; $productsRefunded[] = $product_id_with_attribute; $gtmOrder->refund = implode(',', $productsRefunded); if (!isset($refundsPool[$id_order])) { $refundsPool[$id_order] = array(); } if ($refundsPool[$id_order] != "all") { $refundsPool[$id_order][$product_id_with_attribute] = $qty; } } $this->updateRefundPool($refundsPool, $id_shop); $gtmOrder->save(); } protected function recreateOrderConfirmationFromBO() { if (Tools::getIsset('ecsGtmPro_createDlBo')) { $orderLog = new EcsGtmProOrder(Tools::getValue('id')); if (Validate::isLoadedObject($orderLog) && empty($orderLog->datalayer)) { $order = new Order(Tools::getValue('order_id')); if (Validate::isLoadedObject($order)) { $this->dlManager->orderConfirmation($order->id_cart); $orderLog->datalayer = $this->dlManager->toJson(); $orderLog->save(); return true; } } } return false; } protected function dataLayerRefund() { $pool = $this->getRefundPool(Context::getContext()->shop->id); if (!empty($pool)) { if (is_array($pool) && count($pool)) { $products = reset($pool); $order_id = key($pool); $this->dlManager->generateRefund($order_id, $products); return true; } } return false; } protected function generateEnhancedEcommerceOrderResend() { $pool = $this->getResendPool(Context::getContext()->shop->id); if (!empty($pool)) { if (is_array($pool) && count($pool)) { reset($pool); $id_cart = key($pool); $this->dlManager->orderConfirmation($id_cart, true); $this->dlManager->getDataLayer()->event = "order_resend"; return true; } } return false; } public function addOrderToResendPool($order_id, $id_shop) { $order = new Order($order_id); if (Validate::isLoadedObject($order)) { $id_cart = $order->id_cart; if (!$id_cart) { return false; } $pool = $this->getResendPool($id_shop); if (!isset($pool[$id_cart]) || !is_array($pool[$id_cart])) { $pool[$id_cart] = array(); } if (!in_array($order_id, $pool[$id_cart])) { $pool[$id_cart][] = $order_id; } $this->updateResendPool($pool, $id_shop); } } public function getQueuePool($poolName, $id_shop) { $data = Configuration::get($poolName, null, null, $id_shop); if (empty($data)) { $data = array(); } else { $data = EcsGtmProTools::jsonDecode($data, true); } return $data; } public function getResendPool($id_shop) { return $this->getQueuePool(_ECSGTMPRO_ORDER_RESEND_POOL_, $id_shop); } public function getRefundPool($id_shop) { return $this->getQueuePool(_ECSGTMPRO_ORDER_REFUND_POOL_, $id_shop); } public function updateResendPool($data, $id_shop) { Configuration::updateValue(_ECSGTMPRO_ORDER_RESEND_POOL_, EcsGtmProTools::jsonEncode($data), false, null, $id_shop); } public function updateRefundPool($data, $id_shop) { Configuration::updateValue(_ECSGTMPRO_ORDER_REFUND_POOL_, EcsGtmProTools::jsonEncode($data), false, null, $id_shop); } public function resendOrders() { $maxDelay = (int)$this->gtmConfig->generalConfig->max_resend; if ($maxDelay < 1) { $maxDelay = 1; } $orders = EcsGtmProOrder::getNotSent(null, $maxDelay, 10); foreach ($orders as $order) { $this->addOrderToResendPool($order['id_order'], $order['id_shop']); } } public function getAjaxUrl($controller) { return Context::getContext()->link->getAdminLink($controller); } public function getActiveTab() { foreach ($this->getForms() as $model) { if (Tools::isSubmit(get_class($model))) { return $model->getActiveTab(); } } return null; } public function getActiveSubTab() { foreach ($this->getForms() as $model) { if (Tools::isSubmit(get_class($model))) { if ($model->getActiveTab() == 'EcsGtmProGtmConfig') { return get_class($model); } return null; } } return null; } public function getFormConfigs() { $configs = array(); foreach ($this->getForms() as $form) { $configs[] = $this->getForm($form); } return $configs; } public function getForm($model) { $model->populate(); $model->validate(false); $config = $model->getFormHelperConfig(); return array( 'form' => array( 'name' => get_class($model), 'legend' => array( 'title' => $model->getFormTitle(), 'icon' => $model->getFormIcon() ), 'input' => $config, 'submit' => array( 'name' => get_class($model), 'class' => $this->is15() ? 'button' : null, 'title' => $this->l('Save'), ) ) ); } public function getConfigFieldsValues() { $values = array(); foreach ($this->getForms() as $model) { $model->loadFromConfig(); $model->populate(); foreach ($model->getAttributes() as $attr => $value) { $values[$model->getConfigAttribueName($attr)] = $value; } } return $values; } public function is15() { if ((version_compare(_PS_VERSION_, '1.5.0', '>=') === true) && (version_compare(_PS_VERSION_, '1.6.0', '<') === true)) { return true; } return false; } public function is16() { if ((version_compare(_PS_VERSION_, '1.6.0', '>=') === true) && (version_compare(_PS_VERSION_, '1.7.0', '<') === true)) { return true; } return false; } public function is17() { if ((version_compare(_PS_VERSION_, '1.7.0', '>=') === true) && (version_compare(_PS_VERSION_, '1.8.0', '<') === true)) { return true; } return false; } public function is8x() { if ((version_compare(_PS_VERSION_, '8.0.0', '>=') === true) && (version_compare(_PS_VERSION_, '9.0.0', '<') === true)) { return true; } return false; } public function getPath($abs = false) { if ($abs) { return _PS_MODULE_DIR_ . $this->name . '/'; } return $this->_path; } public function getModuleBaseUrl() { return Tools::getShopDomainSsl(true, true).__PS_BASE_URI__ . 'modules/' . $this->name . '/'; } public function clearGlobalCache() { Tools::clearSmartyCache(); Tools::clearXMLCache(); Media::clearCache(); if (method_exists('Tools', 'generateIndex')) { Tools::generateIndex(); } return true; } }