diff --git a/config.xml b/config.xml index 691faa5..5490ef7 100644 --- a/config.xml +++ b/config.xml @@ -2,7 +2,7 @@ gsitemap - + diff --git a/controllers/front/cron.php b/controllers/front/cron.php new file mode 100644 index 0000000..975fbf4 --- /dev/null +++ b/controllers/front/cron.php @@ -0,0 +1,49 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +class GsitemapCronModuleFrontController extends ModuleFrontController +{ + public function postProcess() + { + // Check correct token when not in CLI context + if (!Tools::isPHPCLI() && Tools::substr(Tools::hash('gsitemap/cron'), 0, 10) != Tools::getValue('token')) { + exit('Bad token'); + } + + // Check if the requested shop exists + $shops = Db::getInstance()->ExecuteS('SELECT id_shop FROM `' . _DB_PREFIX_ . 'shop`'); + $list_id_shop = []; + foreach ($shops as $shop) { + $list_id_shop[] = (int) $shop['id_shop']; + } + + $id_shop = (Tools::getIsset('id_shop') && in_array(Tools::getValue('id_shop'), $list_id_shop)) ? (int) Tools::getValue('id_shop') : (int) Configuration::get('PS_SHOP_DEFAULT'); + + // Mark a flag that we are in cron context + $this->module->cron = true; + + // If this is the first request to generate, we delete all previous sitemaps + if (!Tools::getIsset('continue')) { + $this->module->emptySitemap((int) $id_shop); + } + + // Run generation + $this->module->createSitemap((int) $id_shop); + } +} diff --git a/controllers/front/index.php b/controllers/front/index.php new file mode 100644 index 0000000..45df26c --- /dev/null +++ b/controllers/front/index.php @@ -0,0 +1,34 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ +header('Expires: Mon, 26 Jul 1997 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; diff --git a/controllers/index.php b/controllers/index.php new file mode 100644 index 0000000..45df26c --- /dev/null +++ b/controllers/index.php @@ -0,0 +1,34 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ +header('Expires: Mon, 26 Jul 1997 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; diff --git a/gsitemap-cron.php b/gsitemap-cron.php index 2185b55..93aab72 100644 --- a/gsitemap-cron.php +++ b/gsitemap-cron.php @@ -25,8 +25,11 @@ */ /* - * This file can be called using a cron to generate Google sitemap files automatically + * This file can be called using a cron to generate Google sitemap files automatically. + * This file should no longer be used and will be removed in 5.0.0 version of this module. + * Please update your cron tasks to use the new URL available in module settings. */ +trigger_error('This file should no longer be used and will be removed in 5.0.0 version of this module. Please update your cron tasks to use the new URL available in module settings.', E_USER_NOTICE); include dirname(__FILE__) . '/../../config/config.inc.php'; diff --git a/gsitemap.php b/gsitemap.php index 929929d..84fa70b 100755 --- a/gsitemap.php +++ b/gsitemap.php @@ -60,7 +60,7 @@ public function __construct() { $this->name = 'gsitemap'; $this->tab = 'checkout'; - $this->version = '4.3.1'; + $this->version = '4.4.0'; $this->author = 'PrestaShop'; $this->need_instance = 0; $this->bootstrap = true; @@ -77,6 +77,7 @@ public function __construct() 'meta', 'product', 'category', + 'manufacturer', 'cms', 'module', ]; @@ -106,9 +107,11 @@ public function install() 'GSITEMAP_PRIORITY_HOME' => 1.0, 'GSITEMAP_PRIORITY_PRODUCT' => 0.9, 'GSITEMAP_PRIORITY_CATEGORY' => 0.8, + 'GSITEMAP_PRIORITY_MANUFACTURER' => 0.7, 'GSITEMAP_PRIORITY_CMS' => 0.7, 'GSITEMAP_FREQUENCY' => 'weekly', 'GSITEMAP_LAST_EXPORT' => false, + 'GSITEMAP_DISABLE_LINKS' => '', ] as $key => $val) { if (!Configuration::updateValue($key, $val)) { return false; @@ -152,14 +155,16 @@ protected function installHook() public function uninstall() { foreach ([ - 'GSITEMAP_PRIORITY_HOME' => '', - 'GSITEMAP_PRIORITY_PRODUCT' => '', - 'GSITEMAP_PRIORITY_CATEGORY' => '', - 'GSITEMAP_PRIORITY_CMS' => '', - 'GSITEMAP_FREQUENCY' => '', - 'GSITEMAP_LAST_EXPORT' => '', - ] as $key => $val) { - if (!Configuration::deleteByName($key)) { + 'GSITEMAP_PRIORITY_HOME', + 'GSITEMAP_PRIORITY_PRODUCT', + 'GSITEMAP_PRIORITY_CATEGORY', + 'GSITEMAP_PRIORITY_MANUFACTURER', + 'GSITEMAP_PRIORITY_CMS', + 'GSITEMAP_FREQUENCY', + 'GSITEMAP_LAST_EXPORT', + 'GSITEMAP_DISABLE_LINKS', + ] as $configurationKey) { + if (!Configuration::deleteByName($configurationKey)) { return false; } } @@ -194,7 +199,6 @@ public function getContent() /* Store the posted parameters and generate a new Google sitemap files for the current Shop */ if (Tools::isSubmit('SubmitGsitemap')) { Configuration::updateValue('GSITEMAP_FREQUENCY', pSQL(Tools::getValue('gsitemap_frequency'))); - Configuration::updateValue('GSITEMAP_INDEX_CHECK', ''); $meta = ''; if (Tools::getValue('gsitemap_meta')) { $meta .= implode(', ', Tools::getValue('gsitemap_meta')); @@ -224,7 +228,14 @@ function ($meta) { $store_url = $this->context->link->getBaseLink(); $this->context->smarty->assign([ 'gsitemap_form' => './index.php?controller=AdminModules&configure=gsitemap&token=' . Tools::getAdminTokenLite('AdminModules') . '&tab_module=' . $this->tab . '&module_name=gsitemap', - 'gsitemap_cron' => $store_url . 'modules/gsitemap/gsitemap-cron.php?token=' . Tools::substr(Tools::hash('gsitemap/cron'), 0, 10) . '&id_shop=' . $this->context->shop->id, + 'gsitemap_cron' => $this->context->link->getModuleLink( + 'gsitemap', + 'cron', + [ + 'token' => Tools::substr(Tools::hash('gsitemap/cron'), 0, 10), + 'id_shop' => $this->context->shop->id, + ] + ), 'gsitemap_feed_exists' => file_exists($this->normalizeDirectory(_PS_ROOT_DIR_) . 'index_sitemap.xml'), 'gsitemap_last_export' => Configuration::get('GSITEMAP_LAST_EXPORT'), 'gsitemap_frequency' => Configuration::get('GSITEMAP_FREQUENCY'), @@ -310,7 +321,19 @@ public function addLinkToSitemap(&$link_sitemap, $new_link, $lang, &$index, &$i, exit(); } else { if ($this->cron) { - Tools::redirect($this->context->link->getBaseLink() . 'modules/gsitemap/gsitemap-cron.php?continue=1&token=' . Tools::substr(Tools::hash('gsitemap/cron'), 0, 10) . '&type=' . $new_link['type'] . '&lang=' . $lang . '&index=' . $index . '&id=' . (int) $id_obj . '&id_shop=' . $this->context->shop->id); + Tools::redirect($this->context->link->getModuleLink( + 'gsitemap', + 'cron', + [ + 'continue' => '1', + 'token' => Tools::substr(Tools::hash('gsitemap/cron'), 0, 10), + 'type' => $new_link['type'], + 'lang' => $lang, + 'index' => $index, + 'id' => (int) $id_obj, + 'id_shop' => $this->context->shop->id, + ] + )); } else { Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true, [], [ 'tab_module' => $this->tab, @@ -441,7 +464,7 @@ protected function getProductLink(&$link_sitemap, $lang, &$index, &$i, $id_produ $images_product = []; foreach ($product->getImages((int) $lang['id_lang']) as $id_image) { if (isset($id_image['id_image'])) { - $image_link = $this->context->link->getImageLink($product->link_rewrite, $product->id . '-' . (int) $id_image['id_image'], ImageType::getFormattedName('large')); + $image_link = $this->context->link->getImageLink($product->link_rewrite, (string) $id_image['id_image'], ImageType::getFormattedName('large')); $image_link = (!in_array(rtrim(Context::getContext()->shop->virtual_uri, '/'), explode('/', $image_link))) ? str_replace([ 'https', Context::getContext()->shop->domain . Context::getContext()->shop->physical_uri, @@ -546,6 +569,70 @@ protected function getCategoryLink(&$link_sitemap, $lang, &$index, &$i, $id_cate return true; } + /** + * return the link elements for the manufacturer object + * + * @param array $link_sitemap contain all the links for the Google Sitemap file to be generated + * @param array $lang language of link to add + * @param int $index index of the current Google Sitemap file + * @param int $i count of elements added to sitemap main array + * @param int $id_manufacturer manufacturer object identifier + * + * @return bool + */ + protected function getManufacturerLink(&$link_sitemap, $lang, &$index, &$i, $id_manufacturer = 0) + { + $link = new Link(); + if (method_exists('ShopUrl', 'resetMainDomainCache')) { + ShopUrl::resetMainDomainCache(); + } + + // Get manufacturers IDs + $manufacturers_id = Db::getInstance()->ExecuteS('SELECT m.`id_manufacturer` FROM `' . _DB_PREFIX_ . 'manufacturer` m + INNER JOIN `' . _DB_PREFIX_ . 'manufacturer_lang` ml on m.`id_manufacturer` = ml.`id_manufacturer`' . + ' INNER JOIN `' . _DB_PREFIX_ . 'manufacturer_shop` ms ON m.`id_manufacturer` = ms.`id_manufacturer`' . + ' WHERE m.`active` = 1 AND m.`id_manufacturer` >= ' . (int) $id_manufacturer . + ' AND ms.`id_shop` = ' . (int) $this->context->shop->id . + ' AND ml.`id_lang` = ' . (int) $lang['id_lang'] . + ' ORDER BY m.`id_manufacturer` ASC' + ); + + // Process each manufacturer and add it to list of links that will be further "converted" to XML and added to the sitemap + foreach ($manufacturers_id as $manufacturer_id) { + $manufacturer = new Manufacturer((int) $manufacturer_id['id_manufacturer'], $lang['id_lang']); + $url = $link->getManufacturerLink($manufacturer, urlencode($manufacturer->link_rewrite), $lang['id_lang']); + + $image_link = $this->context->link->getManufacturerImageLink((int) $manufacturer->id, ImageType::getFormattedName('medium')); + $image_link = (!in_array(rtrim(Context::getContext()->shop->virtual_uri, '/'), explode('/', $image_link))) ? str_replace([ + 'https', + Context::getContext()->shop->domain . Context::getContext()->shop->physical_uri, + ], [ + 'http', + Context::getContext()->shop->domain . Context::getContext()->shop->physical_uri . Context::getContext()->shop->virtual_uri, + ], $image_link) : $image_link; + + $manufacturer_image = [ + 'title_img' => htmlspecialchars(strip_tags($manufacturer->name)), + 'caption' => htmlspecialchars(strip_tags($manufacturer->short_description)), + 'link' => $image_link, + ]; + + if (!$this->addLinkToSitemap($link_sitemap, [ + 'type' => 'manufacturer', + 'page' => 'manufacturer', + 'lastmod' => $manufacturer->date_upd, + 'link' => $url, + 'image' => $manufacturer_image, + ], $lang['iso_code'], $index, $i, $manufacturer_id['id_manufacturer'])) { + return false; + } + + unset($image_link); + } + + return true; + } + /** * return the link elements for the CMS object * @@ -563,8 +650,8 @@ protected function getCmsLink(&$link_sitemap, $lang, &$index, &$i, $id_cms = 0) if (method_exists('ShopUrl', 'resetMainDomainCache')) { ShopUrl::resetMainDomainCache(); } - $cmss_id = Db::getInstance()->ExecuteS('SELECT c.`id_cms` FROM `' . _DB_PREFIX_ . 'cms` c INNER JOIN `' . _DB_PREFIX_ . 'cms_lang` cl ON c.`id_cms` = cl.`id_cms` ' . ($this->tableColumnExists(_DB_PREFIX_ . 'supplier_shop') ? 'INNER JOIN `' . _DB_PREFIX_ . 'cms_shop` cs ON c.`id_cms` = cs.`id_cms` ' : '') . 'INNER JOIN `' . _DB_PREFIX_ . 'cms_category` cc ON c.id_cms_category = cc.id_cms_category AND cc.active = 1 - WHERE c.`active` =1 AND c.`indexation` =1 AND c.`id_cms` >= ' . (int) $id_cms . ($this->tableColumnExists(_DB_PREFIX_ . 'supplier_shop') ? ' AND cs.id_shop = ' . (int) $this->context->shop->id : '') . ' AND cl.`id_lang` = ' . (int) $lang['id_lang'] . ' GROUP BY c.`id_cms` ORDER BY c.`id_cms` ASC'); + $cmss_id = Db::getInstance()->ExecuteS('SELECT c.`id_cms` FROM `' . _DB_PREFIX_ . 'cms` c INNER JOIN `' . _DB_PREFIX_ . 'cms_lang` cl ON c.`id_cms` = cl.`id_cms` ' . 'INNER JOIN `' . _DB_PREFIX_ . 'cms_shop` cs ON c.`id_cms` = cs.`id_cms` ' . 'INNER JOIN `' . _DB_PREFIX_ . 'cms_category` cc ON c.id_cms_category = cc.id_cms_category AND cc.active = 1 + WHERE c.`active` =1 AND c.`indexation` =1 AND c.`id_cms` >= ' . (int) $id_cms . ' AND cs.id_shop = ' . (int) $this->context->shop->id . ' AND cl.`id_lang` = ' . (int) $lang['id_lang'] . ' GROUP BY c.`id_cms` ORDER BY c.`id_cms` ASC'); if (is_array($cmss_id)) { foreach ($cmss_id as $cms_id) { @@ -673,7 +760,6 @@ public function createSitemap($id_shop = 0) } } $this->recursiveSitemapCreator($link_sitemap, $lang['iso_code'], $index); - $page = ''; $index = 0; } @@ -721,7 +807,7 @@ protected function recursiveSitemapCreator($link_sitemap, $lang, &$index) $write_fd = fopen($this->normalizeDirectory(_PS_ROOT_DIR_) . $sitemap_link, 'wb'); fwrite($write_fd, '' . PHP_EOL . '' . PHP_EOL); - foreach ($link_sitemap as $key => $file) { + foreach ($link_sitemap as $file) { fwrite($write_fd, '' . PHP_EOL); $lastmod = (isset($file['lastmod']) && !empty($file['lastmod'])) ? date('c', strtotime($file['lastmod'])) : null; $this->addSitemapNode($write_fd, htmlspecialchars(strip_tags($file['link'])), $this->getPriorityPage($file['page']), Configuration::get('GSITEMAP_FREQUENCY'), $lastmod); @@ -755,7 +841,8 @@ protected function recursiveSitemapCreator($link_sitemap, $lang, &$index) } /** - * return the priority value set in the configuration parameters + * Returns the priority value set in the configuration parameters. + * Falls back to 0.1 for things that don't have priority. * * @param string $page * @@ -813,32 +900,6 @@ protected function createIndexSitemap() return true; } - protected function tableColumnExists($table_name, $column = null) - { - if (array_key_exists($table_name, $this->sql_checks)) { - if (!empty($column) && array_key_exists($column, $this->sql_checks[$table_name])) { - return $this->sql_checks[$table_name][$column]; - } else { - return $this->sql_checks[$table_name]; - } - } - - $table = Db::getInstance()->ExecuteS('SHOW TABLES LIKE \'' . $table_name . '\''); - if (empty($column)) { - if (count($table) < 1) { - return $this->sql_checks[$table_name] = false; - } else { - $this->sql_checks[$table_name] = true; - } - } else { - $table = Db::getInstance()->ExecuteS('SELECT * FROM `' . $table_name . '` LIMIT 1'); - - return $this->sql_checks[$table_name][$column] = array_key_exists($column, current($table)); - } - - return true; - } - protected function normalizeDirectory($directory) { $last = $directory[Tools::strlen($directory) - 1]; diff --git a/tests/phpstan/phpstan-1.7.1.2.neon b/tests/phpstan/phpstan-1.7.1.2.neon index f938e40..69f1c11 100644 --- a/tests/phpstan/phpstan-1.7.1.2.neon +++ b/tests/phpstan/phpstan-1.7.1.2.neon @@ -7,3 +7,4 @@ parameters: - '#Parameter \#1 \$idCategory of class Category constructor expects null, int given.#' - '#Parameter \#2 \$idLang of class Category constructor expects null, int given.#' - '#Parameter \#3 \$type of method LinkCore\:\:getCatImageLink\(\) expects null, string given.#' + - '#Parameter \#2 \$type of method LinkCore\:\:getManufacturerImageLink\(\) expects null, string given.#' diff --git a/tests/phpstan/phpstan-1.7.2.5.neon b/tests/phpstan/phpstan-1.7.2.5.neon index f938e40..69f1c11 100644 --- a/tests/phpstan/phpstan-1.7.2.5.neon +++ b/tests/phpstan/phpstan-1.7.2.5.neon @@ -7,3 +7,4 @@ parameters: - '#Parameter \#1 \$idCategory of class Category constructor expects null, int given.#' - '#Parameter \#2 \$idLang of class Category constructor expects null, int given.#' - '#Parameter \#3 \$type of method LinkCore\:\:getCatImageLink\(\) expects null, string given.#' + - '#Parameter \#2 \$type of method LinkCore\:\:getManufacturerImageLink\(\) expects null, string given.#' diff --git a/tests/phpstan/phpstan-1.7.3.4.neon b/tests/phpstan/phpstan-1.7.3.4.neon index f938e40..69f1c11 100644 --- a/tests/phpstan/phpstan-1.7.3.4.neon +++ b/tests/phpstan/phpstan-1.7.3.4.neon @@ -7,3 +7,4 @@ parameters: - '#Parameter \#1 \$idCategory of class Category constructor expects null, int given.#' - '#Parameter \#2 \$idLang of class Category constructor expects null, int given.#' - '#Parameter \#3 \$type of method LinkCore\:\:getCatImageLink\(\) expects null, string given.#' + - '#Parameter \#2 \$type of method LinkCore\:\:getManufacturerImageLink\(\) expects null, string given.#' diff --git a/tests/phpstan/phpstan-1.7.4.4.neon b/tests/phpstan/phpstan-1.7.4.4.neon index f938e40..69f1c11 100644 --- a/tests/phpstan/phpstan-1.7.4.4.neon +++ b/tests/phpstan/phpstan-1.7.4.4.neon @@ -7,3 +7,4 @@ parameters: - '#Parameter \#1 \$idCategory of class Category constructor expects null, int given.#' - '#Parameter \#2 \$idLang of class Category constructor expects null, int given.#' - '#Parameter \#3 \$type of method LinkCore\:\:getCatImageLink\(\) expects null, string given.#' + - '#Parameter \#2 \$type of method LinkCore\:\:getManufacturerImageLink\(\) expects null, string given.#' diff --git a/tests/phpstan/phpstan-1.7.5.1.neon b/tests/phpstan/phpstan-1.7.5.1.neon index f938e40..69f1c11 100644 --- a/tests/phpstan/phpstan-1.7.5.1.neon +++ b/tests/phpstan/phpstan-1.7.5.1.neon @@ -7,3 +7,4 @@ parameters: - '#Parameter \#1 \$idCategory of class Category constructor expects null, int given.#' - '#Parameter \#2 \$idLang of class Category constructor expects null, int given.#' - '#Parameter \#3 \$type of method LinkCore\:\:getCatImageLink\(\) expects null, string given.#' + - '#Parameter \#2 \$type of method LinkCore\:\:getManufacturerImageLink\(\) expects null, string given.#' diff --git a/tests/phpstan/phpstan-1.7.6.neon b/tests/phpstan/phpstan-1.7.6.neon index f938e40..69f1c11 100644 --- a/tests/phpstan/phpstan-1.7.6.neon +++ b/tests/phpstan/phpstan-1.7.6.neon @@ -7,3 +7,4 @@ parameters: - '#Parameter \#1 \$idCategory of class Category constructor expects null, int given.#' - '#Parameter \#2 \$idLang of class Category constructor expects null, int given.#' - '#Parameter \#3 \$type of method LinkCore\:\:getCatImageLink\(\) expects null, string given.#' + - '#Parameter \#2 \$type of method LinkCore\:\:getManufacturerImageLink\(\) expects null, string given.#' diff --git a/tests/phpstan/phpstan-1.7.7.neon b/tests/phpstan/phpstan-1.7.7.neon index 25e8982..fb8d10d 100644 --- a/tests/phpstan/phpstan-1.7.7.neon +++ b/tests/phpstan/phpstan-1.7.7.neon @@ -5,3 +5,4 @@ parameters: ignoreErrors: - '#Access to an undefined property Cookie\:\:\$id_lang.#' - '#Parameter \#3 \$type of method LinkCore\:\:getCatImageLink\(\) expects null, string given.#' + - '#Parameter \#2 \$type of method LinkCore\:\:getManufacturerImageLink\(\) expects null, string given.#' diff --git a/tests/phpstan/phpstan-1.7.8.neon b/tests/phpstan/phpstan-1.7.8.neon index d108bda..006c0ef 100644 --- a/tests/phpstan/phpstan-1.7.8.neon +++ b/tests/phpstan/phpstan-1.7.8.neon @@ -4,3 +4,4 @@ includes: parameters: ignoreErrors: - '#Access to an undefined property Cookie\:\:\$id_lang.#' + - '#Parameter \#1 \$str of function strip_tags expects string, array given.#' diff --git a/upgrade/upgrade-4.4.0.php b/upgrade/upgrade-4.4.0.php new file mode 100644 index 0000000..dc3b9c3 --- /dev/null +++ b/upgrade/upgrade-4.4.0.php @@ -0,0 +1,35 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ +if (!defined('_PS_VERSION_')) { + exit; +} + +function upgrade_module_4_4_0($object) +{ + Configuration::updateValue('GSITEMAP_PRIORITY_MANUFACTURER', 0.7); + + return true; +}