PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/zzseotk.php

https://gitlab.com/Blueprint-Marketing/zzSEOtk
PHP | 386 lines | 311 code | 48 blank | 27 comment | 45 complexity | 34b5f38d82ea9108e600f310ffa2ed30 MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * NOTICE OF LICENSE
  5. * This source file is subject to the License terms Academi cFined in the file LICENSE.md
  6. *
  7. * DISCLAIMER
  8. * This code is provided as is without any warranty.
  9. * No promise of being safe or secure
  10. *
  11. * @author ZiZuu.com <info@zizuu.com>
  12. * @link source available at https://github.com/ZiZuu-store/
  13. */
  14. if (!defined('_PS_VERSION_')) {
  15. return;
  16. }
  17. class zzSeoTK extends Module
  18. {
  19. private $_controller;
  20. private $_paginating_controllers = array(
  21. 'best-sales',
  22. 'category',
  23. 'manufacturer',
  24. 'manufacturer-list',
  25. 'new-products',
  26. 'prices-drop',
  27. 'search',
  28. 'supplier',
  29. 'supplier-list',
  30. );
  31. private $_nobots_controllers = array(
  32. '404',
  33. 'address',
  34. 'addresses',
  35. 'attachment',
  36. 'authentication',
  37. 'cart',
  38. 'discount',
  39. 'footer',
  40. 'get-file',
  41. 'guest-tracking',
  42. 'header',
  43. 'history',
  44. 'identity',
  45. 'images.inc',
  46. 'init',
  47. 'my-account',
  48. 'order',
  49. 'order-opc',
  50. 'order-slip',
  51. 'order-detail',
  52. 'order-follow',
  53. 'order-return',
  54. 'order-confirmation',
  55. 'pagination',
  56. 'password',
  57. 'pdf-invoice',
  58. 'pdf-order-return',
  59. 'pdf-order-slip',
  60. 'product-sort',
  61. 'search',
  62. 'statistics',
  63. );
  64. public function __construct()
  65. {
  66. $this->name = 'zzseotk';
  67. $this->author = 'ZiZuu Store';
  68. $this->tab = 'seo';
  69. $this->version = '1.1.5';
  70. $this->need_instance = 0;
  71. $this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
  72. $this->bootstrap = true;
  73. parent::__construct();
  74. $this->displayName = $this->l('ZiZuu SEO ToolKit');
  75. $this->description = $this->l('Handles a few SEO related improvements, such as \'hreflang\', \'canonical\' and \'noindex\'.');
  76. $this->confirmUninstall = $this->l('Are you sure you want to uninstall "ZiZuu SEO ToolKit"?');
  77. }
  78. public function install()
  79. {
  80. if (Shop::isFeatureActive()) {
  81. Shop::setContext(Shop::CONTEXT_ALL);
  82. }
  83. return parent::install()
  84. && $this->registerHook('header')
  85. && Configuration::updateValue('ZZSEOTK_HREFLANG_ENABLED', false)
  86. && Configuration::updateValue('ZZSEOTK_CANONICAL_ENABLED', false)
  87. && Configuration::updateValue('ZZSEOTK_NOBOTS_ENABLED', false)
  88. ;
  89. }
  90. public function uninstall()
  91. {
  92. return parent::uninstall()
  93. && Configuration::deleteByName('ZZSEOTK_HREFLANG_ENABLED')
  94. && Configuration::deleteByName('ZZSEOTK_CANONICAL_ENABLED')
  95. && Configuration::deleteByName('ZZSEOTK_NOBOTS_ENABLED')
  96. ;
  97. }
  98. //FIXME
  99. public function _clearCache($template, $cache_id = null, $compile_id = null)
  100. {
  101. parent::_clearCache('meta-hreflang.tpl', $this->getCacheId($cache_id));
  102. parent::_clearCache('meta-canonical.tpl', $this->getCacheId($cache_id));
  103. }
  104. public function getContent()
  105. {
  106. $_html = '<div id="'.$this->name.'_config_intro" class="alert alert-info">'.
  107. ' <span class="module_name">'.$this->displayName.'</span>'.
  108. ' <div class="module_description">'.$this->description.'</div>'.
  109. '</div>';
  110. if (Tools::isSubmit('submitOptionsconfiguration')) {
  111. if (null!==Tools::getValue('ZZSEOTK_HREFLANG_ENABLED')) {
  112. Configuration::updateValue('ZZSEOTK_HREFLANG_ENABLED', (bool)Tools::getValue('ZZSEOTK_HREFLANG_ENABLED'));
  113. }
  114. if (null!==Tools::getValue('ZZSEOTK_CANONICAL_ENABLED')) {
  115. Configuration::updateValue('ZZSEOTK_CANONICAL_ENABLED', (bool)Tools::getValue('ZZSEOTK_CANONICAL_ENABLED'));
  116. }
  117. if (null!==Tools::getValue('ZZSEOTK_NOBOTS_ENABLED')) {
  118. Configuration::updateValue('ZZSEOTK_NOBOTS_ENABLED', (bool)Tools::getValue('ZZSEOTK_NOBOTS_ENABLED'));
  119. }
  120. }
  121. $_html .= $this->renderForm();
  122. return $_html;
  123. }
  124. public function renderForm()
  125. {
  126. $this->fields_option = array(
  127. 'hreflang' => array(
  128. 'title' => $this->l('Internationalization'),
  129. 'icon' => 'icon-flag',
  130. 'fields' => array(
  131. 'ZZSEOTK_HREFLANG_ENABLED' => array(
  132. 'title' => $this->l('Enable "hreflang" meta tag'),
  133. 'hint' => $this->l('Set "hreflang" meta tag into the html head to handle the same content in different languages.'),
  134. 'validation' => 'isBool',
  135. 'cast' => 'boolval',
  136. 'type' => 'bool',
  137. ),
  138. ),
  139. 'submit' => array(
  140. 'title' => $this->l('Save'),
  141. ),
  142. ),
  143. 'canonical' => array(
  144. 'title' => $this->l('Canonical URL'),
  145. 'icon' => 'icon-link',
  146. 'fields' => array(
  147. 'ZZSEOTK_CANONICAL_ENABLED' => array(
  148. 'title' => $this->l('Enable "canonical" meta tag'),
  149. 'hint' => $this->l('Set "canonical"meta tag into the html head to avoid content duplication issues in SEO.'),
  150. 'validation' => 'isBool',
  151. 'cast' => 'boolval',
  152. 'type' => 'bool',
  153. ),
  154. ),
  155. 'submit' => array(
  156. 'title' => $this->l('Save'),
  157. ),
  158. ),
  159. 'nobots' => array(
  160. 'title' => $this->l('"nobots"'),
  161. 'icon' => 'icon-sitemap',
  162. 'fields' => array(
  163. 'ZZSEOTK_NOBOTS_ENABLED' => array(
  164. 'title' => $this->l('Enable "noindex" meta tag'),
  165. 'hint' => $this->l('Set "noindex" meta tag into the html head to avoid search engine indicization of "private" pages. Public pages are not affected of course.'),
  166. 'validation' => 'isBool',
  167. 'cast' => 'boolval',
  168. 'type' => 'bool',
  169. ),
  170. ),
  171. 'submit' => array(
  172. 'title' => $this->l('Save'),
  173. ),
  174. ),
  175. );
  176. $helper = new HelperOptions($this);
  177. $helper->id = $this->id;
  178. $helper->module = $this;
  179. $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;
  180. $helper->token = Tools::getAdminTokenLite('AdminModules');
  181. $helper->title = $this->displayName;
  182. return $helper->generateOptions($this->fields_option);
  183. }
  184. public function hookHeader()
  185. {
  186. $this->_controller = Dispatcher::getInstance()->getController();
  187. if (!empty($this->context->controller->php_self)) {
  188. $this->_controller = $this->context->controller->php_self;
  189. }
  190. if ($this->_handleNobots()) {
  191. // no need to add anything else as robots should ignore this page
  192. return;
  193. }
  194. $out = "\n"
  195. .$this->_displayHreflang()
  196. .$this->_displayCanonical()
  197. ;
  198. return $out;
  199. }
  200. private function _handleNobots()
  201. {
  202. if (Configuration::get('ZZSEOTK_NOBOTS_ENABLED')) {
  203. if (in_array($this->_controller, $this->_nobots_controllers)) {
  204. $this->context->smarty->assign('nobots', true);
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210. private function _displayHreflang()
  211. {
  212. if (!Configuration::get('ZZSEOTK_HREFLANG_ENABLED')) {
  213. return;
  214. }
  215. $shop = $this->context->shop;
  216. if (version_compare(_PS_VERSION_, '1.6.1.0', '>=')) {
  217. $requested_URL = $shop->getBaseURL(true /* $auto_secure_mode */, false /* $add_base_uri */) . $_SERVER['REQUEST_URI'];
  218. } else {
  219. $proto = (Configuration::get('PS_SSL_ENABLED') && Configuration::get('PS_SSL_ENABLED_EVERYWHERE')) ? 'https://' : 'http://';
  220. $domain = (Configuration::get('PS_SSL_ENABLED') && Configuration::get('PS_SSL_ENABLED_EVERYWHERE')) ? $shop->domain_ssl : $shop->domain;
  221. $requested_URL = $proto . $domain . $_SERVER['REQUEST_URI'];
  222. }
  223. if (Configuration::get('ZZSEOTK_CANONICAL_ENABLED')
  224. && strtok($requested_URL, '?') != $this->_getCanonicalLink(null, null, false /* $has_qs */)
  225. ) {
  226. // skip if actual page is not the canonical page
  227. return;
  228. }
  229. foreach (Shop::getShops(true /* $active */, null /* $id_shop_group */, true /* $get_as_list_id */) as $shop_id) {
  230. foreach (Language::getLanguages(true /* $active */, $shop_id) as $language) {
  231. $url = $this->_getCanonicalLink($language['id_lang'], $shop_id, true /* $has_qs */);
  232. $shops_data[$shop_id][] = array(
  233. 'url' => $url,
  234. 'language' => array(
  235. 'id' => $language['id_lang'],
  236. 'code' => $language['language_code'],
  237. ),
  238. );
  239. }
  240. }
  241. $this->context->smarty->assign(array(
  242. 'shops_data' => $shops_data,
  243. 'default_lang_id' => (int)Configuration::get('PS_LANG_DEFAULT'),
  244. 'default_shop_id' => (int)Configuration::get('PS_SHOP_DEFAULT'),
  245. ));
  246. return $this->display(__FILE__, 'meta-hreflang.tpl');
  247. }
  248. private function _displayCanonical()
  249. {
  250. if (!Configuration::get('ZZSEOTK_CANONICAL_ENABLED')) {
  251. return;
  252. }
  253. $canonical = $this->_getCanonicalLink();
  254. if (!$this->isCached('meta-canonical.tpl', $this->getCacheId($canonical))) {
  255. $this->context->smarty->assign(array(
  256. 'canonical_url' => $canonical,
  257. ));
  258. }
  259. return $this->display(__FILE__, 'meta-canonical.tpl', $this->getCacheId($canonical));
  260. }
  261. private function _getCanonicalLink($id_lang = null, $id_shop = null, $add_qs = true)
  262. {
  263. $link = $this->context->link;
  264. $controller = $this->_controller;
  265. $module = Tools::getValue('module');
  266. $id = (int)Tools::getValue('id_'.$controller);
  267. $getLinkFunc = 'get'.ucfirst($controller).'Link';
  268. $params = array();
  269. if (!$link || !$controller) {
  270. return;
  271. }
  272. switch ($controller.$module) {
  273. case 'product':
  274. // getProductLink($product, $alias = null, $category = null, $ean13 = null, $id_lang = null, $id_shop = null, $ipa = 0, $force_routes = false, $relative_protocol = false)
  275. $canonical = $link->getProductLink($id, null, null, null, $id_lang, $id_shop);
  276. break;
  277. case 'category':
  278. // getCategoryLink($category, $alias = null, $id_lang = null, $selected_filters = null, $id_shop = null, $relative_protocol = false)
  279. $canonical = $link->getCategoryLink($id, null, $id_lang, Tools::getValue('selected_filters', null), $id_shop);
  280. break;
  281. case 'cms':
  282. // getCMSLink($cms, $alias = null, $ssl = null, $id_lang = null, $id_shop = null, $relative_protocol = false)
  283. $canonical = $link->getCmsLink($id, null, null, $id_lang, $id_shop);
  284. break;
  285. case 'cms-category':
  286. // getCMSCategoryLink ($cms_category, $alias = null, $id_lang = null, $id_shop = null, $relative_protocol = false)
  287. case 'supplier':
  288. // getSupplierLink ($supplier, $alias = null, $id_lang = null, $id_shop = null, $relative_protocol = false)
  289. case 'manufacturer':
  290. // getManufacturerLink($manufacturer, $alias = null, $id_lang = null, $id_shop = null, $relative_protocol = false)
  291. $canonical = $id
  292. ? $link->{$getLinkFunc}($id, null, $id_lang, $id_shop)
  293. : $link->getPageLink($controller, null, $id_lang, null, false, $id_shop);
  294. break;
  295. case 'search':
  296. if ($tag = Tools::getValue('tag')) {
  297. $params['tag'] = $tag;
  298. }
  299. if ($sq = Tools::getValue('search_query')) {
  300. $params['search_query'] = $sq;
  301. }
  302. case 'products-comparison':
  303. if ($ids_str = Tools::getValue('compare_product_list')) {
  304. // use an ordered products' list as canonical param
  305. $ids = explode('|', $ids_str);
  306. sort($ids, SORT_NUMERIC);
  307. $params['compare_product_list'] = implode('|', $ids);
  308. }
  309. default:
  310. if (Validate::isModuleName($module)) {
  311. $_params = $_GET;
  312. unset($_params['fc']);
  313. // getModuleLink($module, $controller = 'default', array $params = array(), $ssl = null, $id_lang = null, $id_shop = null, $relative_protocol = false)
  314. $canonical = $link->getModuleLink($module, $controller, $_params, null, $id_lang, $id_shop);
  315. } else {
  316. // getPageLink($controller, $ssl = null, $id_lang = null, $request = null, $request_url_encode = false, $id_shop = null, $relative_protocol = false)
  317. $canonical = $link->getPageLink($controller, null, $id_lang, null, false, $id_shop);
  318. }
  319. break;
  320. }
  321. if ('index' == $controller && '/' == strtok($_SERVER['REQUEST_URI'], '?')) {
  322. $canonical = rtrim($canonical, '/');
  323. }
  324. // retain pagination for controllers supporting it, remove p=1
  325. if (($p = Tools::getValue('p')) && $p>1
  326. && (in_array($controller, $this->_paginating_controllers) || $module)
  327. ) {
  328. $params['p'] = $p;
  329. }
  330. // remove "dirty" QS
  331. $canonical = strtok($canonical, '?');
  332. // add "canonical" QS if enabled
  333. if ($add_qs && count($params)>0) {
  334. $canonical .= '?'.http_build_query($params, '', '&');
  335. }
  336. return $canonical;
  337. }
  338. }