commit af907b25a71cd5a6f735742adde628bf53e7acc0 Author: O K Date: Sat Feb 22 10:59:30 2025 +0200 Initial diff --git a/config_uk.xml b/config_uk.xml new file mode 100644 index 0000000..03abeba --- /dev/null +++ b/config_uk.xml @@ -0,0 +1,11 @@ + + + urlredirection + + + + + + 1 + 0 + \ No newline at end of file diff --git a/override/classes/URLRedirect.php b/override/classes/URLRedirect.php new file mode 100644 index 0000000..4fd91f9 --- /dev/null +++ b/override/classes/URLRedirect.php @@ -0,0 +1,155 @@ + 'url_redirection', + 'primary' => 'id_url_redirection', + 'multilang' => false, + 'fields' => [ + 'url' => ['type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true, 'size' => 255], + 'object_name' => ['type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true, 'size' => 64], + 'object_id' => ['type' => self::TYPE_INT, 'validate' => 'isInt', 'required' => true], + 'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => false], + 'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate', 'required' => false], + ], + ]; + + /** + * @param string $url + * @param string $object_name + * @param int $object_id + * @param bool $updateExisting + * + * @return bool + */ + public static function saveUrl(string $url, string $object_name, int $object_id, bool $updateExisting = false): bool + { + // $url = trim($url, '/'); // Remove leading/trailing slashes + $url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $url), '/'); + + if (empty($url) || empty($object_name) || $object_id <= 0) { + return false; + } + + $existingRedirection = new URLRedirect(); + if ($existingRedirection->getByUrl($url)) { + if (!$updateExisting) { + return false; // Do not update if we shouldn't. + } + // Update existing entry + $existingRedirection->object_name = $object_name; + $existingRedirection->object_id = $object_id; + $existingRedirection->date_upd = date('Y-m-d H:i:s'); + return $existingRedirection->update(); + } + + + $redirection = new self(); + $redirection->url = $url; + $redirection->object_name = $object_name; + $redirection->object_id = $object_id; + $redirection->date_add = date('Y-m-d H:i:s'); + + return $redirection->add(); + } + + /** + * Get redirection by URL. + * + * @param string $url + * @return bool|ObjectModel + */ + public function getByUrl(string $url) + { + $url = trim($url, '/'); + $sql = new DbQuery(); + $sql->select('*'); + $sql->from(self::$definition['table']); + $sql->where('url = "' . pSQL($url) . '"'); + + if ($result = Db::getInstance()->getRow($sql)) { + $this->id = (int) $result['id_url_redirection']; + $this->url = $result['url']; + $this->object_name = $result['object_name']; + $this->object_id = (int) $result['object_id']; + $this->date_add = $result['date_add']; + $this->date_upd = $result['date_upd']; + return $this; + } + + return false; + } + public static function extractPath($requestUri) + { + // Remove query string if present + $uri = parse_url($requestUri, PHP_URL_PATH); + $segments = explode('/', trim($uri, '/')); + + // If the first segment is 2 letters, ignore it + if (isset($segments[0]) && preg_match('/^[a-zA-Z]{2}$/', $segments[0])) { + array_shift($segments); + } + + return strtolower(implode('/', $segments)); + } + /** + * This method hooks into the dispatcher to check if the current URL + * is a 404 and if there's a redirection available for it. + * This hook needs to be called `hookActionDispatcherBefore` in a module. + * + * @param array $params + * @return void + */ + public static function hookActionDispatcher(array $params): void + { + if (!defined('_PS_ADMIN_DIR_') && $params['controller_class'] === 'PageNotFoundController') { + $url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $_SERVER['REQUEST_URI']), '/'); + + if (!empty($url)) { + $redirection = new URLRedirect(); + + if ($redirection->getByUrl($url)) { + $targetUrl = ''; + + switch ($redirection->object_name) { + case 'category': + $targetUrl = Context::getContext()->link->getCategoryLink($redirection->object_id); + break; + case 'product': + $targetUrl = Context::getContext()->link->getProductLink($redirection->object_id); + break; + case 'cms': + $targetUrl = Context::getContext()->link->getCMSLink($redirection->object_id); + break; + // Add more cases for other object types (cms_category, supplier, manufacturer etc.) + default: + // Log the invalid object_name or maybe remove the redirection. + PrestaShopLogger::addLog( + 'Invalid object_name in URLRedirect table: ' . $redirection->object_name . ' URL: ' . $url, + 3, // Severity: WARNING + 0, // Error Code + 'URLRedirect', // Object Class + $redirection->id, // Object ID + true + ); + return; // Don't redirect if the object name is invalid. + } + + if (!empty($targetUrl)) { + Tools::redirect($targetUrl); + } + } + } + } + } +} diff --git a/urlredirection.php b/urlredirection.php new file mode 100644 index 0000000..6ab5b85 --- /dev/null +++ b/urlredirection.php @@ -0,0 +1,178 @@ +name = 'urlredirection'; + $this->tab = 'front_office_features'; + $this->version = '1.0.0'; + $this->author = 'panariga'; + $this->need_instance = 0; + + + + parent::__construct(); + + $this->displayName = $this->l('urlredirection'); + $this->description = $this->l('urlredirection'); + + $this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_); + } + + + public function install() + { + if ( + !parent::install() || + !$this->registerHook('actionDispatcher') || + !$this->registerHook('ActionObjectCategoryUpdateAfter') || + !$this->registerHook('ActionObjectProductUpdateAfter') + ) { + return false; + } + // Create table (you might want to handle this in a separate function with more sophisticated error checking) + $sql = "CREATE TABLE IF NOT EXISTS `" . _DB_PREFIX_ . "url_redirection` ( + `id_url_redirection` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `url` VARCHAR(255) NOT NULL, + `object_name` VARCHAR(64) NOT NULL, + `object_id` INT(10) UNSIGNED NOT NULL, + `date_add` DATETIME DEFAULT NULL, + `date_upd` DATETIME DEFAULT NULL, + PRIMARY KEY (`id_url_redirection`), + UNIQUE KEY `url_unique` (`url`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"; + if (!Db::getInstance()->execute($sql)) { + return false; + } + return true; + } + + + public function uninstall() + { + if (!parent::uninstall()) { + return false; + } + +/* // Drop table + $sql = "DROP TABLE IF EXISTS `" . _DB_PREFIX_ . "url_redirection`"; + if (!Db::getInstance()->execute($sql)) { + return false; + } */ + + return true; + } + + public function hookactionDispatcher($params) + { + URLRedirect::hookActionDispatcher($params); + } + public function hookActionObjectCategoryUpdateAfter($params) + { + $category = $params['object']; + $idCategory = (int) $category->id; + $languages = Language::getLanguages(false, Context::getContext()->shop->id); // Get all languages for this shop + + foreach ($languages as $lang) { + $link = Context::getContext()->link; + $url = $link->getCategoryLink($idCategory, null, $lang['id_lang'],Context::getContext()->shop->id); // Generate new URL + + URLRedirect::saveUrl($url, 'category', $idCategory, true); // true for update if exists + } + } + public function hookActionObjectProductUpdateAfter($params) + { + $product = $params['object']; + $id_product = (int)$product->id; + $languages = Language::getLanguages(false, Context::getContext()->shop->id); // get all languages for this shop + + foreach ($languages as $lang) { + $link = Context::getContext()->link; + $url = $link->getProductLink($id_product, null, null, null, $lang['id_lang']); // generate new URL + + // $new_url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $url), '/'); // Get the URL part after base URL + URLRedirect::saveUrl($url, 'product', $id_product, true); // true for update if exists + } + } + + public function generateAndSaveAllUrls() + { + $savedUrls = [ + 'category' => 0, + 'product' => 0, + 'cms' => 0, + ]; + + $link = Context::getContext()->link; + + // Categories + $categories = Category::getCategories(null, true, false); // all categories + foreach ($categories as $category) { + $categoryId = (int)$category['id_category']; + $languages = Language::getLanguages(true); // Get all available languages + foreach ($languages as $language) { + $categoryLink = $link->getCategoryLink($categoryId, null, $language['id_lang']); + // $url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $categoryLink), '/'); + if (URLRedirect::saveUrl($categoryLink, 'category', $categoryId, true)) { // update existing + $savedUrls['category']++; + } + } + } + + // Products + $products = Product::getProducts(Context::getContext()->language->id, 0, 0, 'id_product', 'ASC'); //Get all products + foreach ($products as $product) { + $productId = (int)$product['id_product']; + $languages = Language::getLanguages(true); + foreach ($languages as $language) { + $productLink = $link->getProductLink($productId, null, null, null, $language['id_lang']); + // $url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $productLink), '/'); + if (URLRedirect::saveUrl($productLink, 'product', $productId, true)) { // update existing + $savedUrls['product']++; + } + } + } + + // CMS Pages + $cmsPages = CMS::getCMSPages(null, true, Context::getContext()->language->id, Context::getContext()->shop->id); + foreach ($cmsPages as $cmsPage) { + $cmsId = (int)$cmsPage['id_cms']; + $languages = Language::getLanguages(true); + foreach ($languages as $language) { + $cmsLink = $link->getCMSLink($cmsId, null, null, $language['id_lang']); + // $url = trim(str_replace(Context::getContext()->shop->getBaseURL(true, false), '', $cmsLink), '/'); + if (URLRedirect::saveUrl($cmsLink, 'cms', $cmsId, true)) { // update existing + $savedUrls['cms']++; + } + } + } + + return $savedUrls; + } + + public function getContent() + { + $output = ''; + if (Tools::isSubmit('generate_urls')) { + $savedUrls = $this->generateAndSaveAllUrls(); + $output .= $this->displayConfirmation( + $this->l('URLs generated successfully.') . ' ' . + $this->l('Categories:') . ' ' . $savedUrls['category'] . ', ' . + $this->l('Products:') . ' ' . $savedUrls['product'] . ', ' . + $this->l('CMS:') . ' ' . $savedUrls['cms'] + ); + } + + $output .= ' +
+ +
+ '; + + return $output; + } +}