From 4fdb52de0c078933df0beecccfbe3801ff1639e7 Mon Sep 17 00:00:00 2001 From: O K Date: Fri, 26 Sep 2025 13:07:27 +0300 Subject: [PATCH] upgraded controllers and admin link builder --- controllers/front/category.php | 37 +---- controllers/front/generate.php | 94 ----------- controllers/front/product.php | 171 ++++++++++---------- productlinkchecker.php | 33 +++- views/templates/admin/configure.tpl | 236 +++++++++++++++++++++++++--- 5 files changed, 342 insertions(+), 229 deletions(-) delete mode 100644 controllers/front/generate.php diff --git a/controllers/front/category.php b/controllers/front/category.php index c2773ef..e9e336d 100644 --- a/controllers/front/category.php +++ b/controllers/front/category.php @@ -15,13 +15,10 @@ class ProductLinkCheckerCategoryModuleFrontController extends ModuleFrontControl { parent::init(); - // Security check: Validate the token, same as the other controller - $token = Tools::getValue('token'); - $storedToken = Configuration::get('PLC_SECURITY_TOKEN'); - - if (!$token || $token !== $storedToken) { - header('HTTP/1.1 403 Forbidden'); - exit('Invalid security token.'); + if (!Tools::getValue('token') || Tools::getValue('token') !== Configuration::get('PLC_SECURITY_TOKEN')) { + $response = new JsonResponse(['error' => 'Not Authorized'], 403); + $response->send(); + exit; } } @@ -29,31 +26,11 @@ class ProductLinkCheckerCategoryModuleFrontController extends ModuleFrontControl { parent::initContent(); - header('Content-Type: application/json'); - $categoriesData = []; $collection = new PrestaShopCollection('Category'); - $id_shop_filter = (int)Tools::getValue('plc_id_shop'); - $id_lang_filter = (int)Tools::getValue('plc_id_lang'); - - // Determine which shops to scan - if ($id_shop_filter) { - $shop_ids = [$id_shop_filter]; - } else { - $shop_ids = Shop::getShops(true, null, true); - } - - // Determine which languages to scan - if ($id_lang_filter) { - $lang_ids = [$id_lang_filter]; - } else { - $lang_ids = Language::getLanguages(true, false, true); - } - - - foreach ($shop_ids as $id_shop) { - foreach ($lang_ids as $id_lang) { + foreach ((array)Tools::getValue('plc_id_shop', Shop::getShops(true, null, true)) as $id_shop) { + foreach ((array)Tools::getValue('plc_id_lang', Language::getLanguages(false, false, true)) as $id_lang) { foreach ($collection as $cat) { @@ -62,6 +39,8 @@ class ProductLinkCheckerCategoryModuleFrontController extends ModuleFrontControl continue; } $data = [ + 'id_lang' => $id_lang, + 'id_shop' => $id_shop, 'id_category' => $category->id, 'id_parent' => $category->id_parent, 'active' => $category->active, diff --git a/controllers/front/generate.php b/controllers/front/generate.php deleted file mode 100644 index 8da293e..0000000 --- a/controllers/front/generate.php +++ /dev/null @@ -1,94 +0,0 @@ -context->link->getProductLink($product, null, null, null, $id_lang, $id_shop); - $all_links[] = $base_link; - - // Get links for combinations if they exist - if ($product->hasAttributes()) { - $combinations = $product->getAttributesResume($id_lang); - if ($combinations) { - foreach ($combinations as $combination) { - $combo_link = $this->context->link->getProductLink( - $product, - null, - null, - null, - $id_lang, - $id_shop, - $combination['id_product_attribute'], - false, - false, - true // Add attribute anchor - ); - $all_links[] = $combo_link; - } - } - } - } - } - } - - // Remove duplicates that might occur in complex shop setups and output JSON - echo json_encode(array_values(array_unique($all_links)), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - exit; - } -} diff --git a/controllers/front/product.php b/controllers/front/product.php index e463be9..7435203 100644 --- a/controllers/front/product.php +++ b/controllers/front/product.php @@ -7,121 +7,128 @@ * with detailed information for external services. */ +use Symfony\Component\HttpFoundation\JsonResponse; + class ProductLinkCheckerProductModuleFrontController extends ModuleFrontController { + /** + * @see FrontController::init() + */ public function init() { parent::init(); // Security check: Validate the token, same as the other controller - $token = Tools::getValue('token'); - $storedToken = Configuration::get('PLC_SECURITY_TOKEN'); - - if (!$token || $token !== $storedToken) { - header('HTTP/1.1 403 Forbidden'); - exit('Invalid security token.'); + if (!Tools::getValue('token') || Tools::getValue('token') !== Configuration::get('PLC_SECURITY_TOKEN')) { + $response = new JsonResponse(['error' => 'Not Authorized'], 403); + $response->send(); + exit; } } + /** + * @see FrontController::initContent() + */ public function initContent() { parent::initContent(); - header('Content-Type: application/json'); + $productsData = []; + $collection = new PrestaShopCollection('Product'); - $id_shop_filter = (int)Tools::getValue('plc_id_shop'); - $id_lang_filter = (int)Tools::getValue('plc_id_lang'); + foreach ((array)Tools::getValue('plc_id_shop', Shop::getShops(true, null, true)) as $id_shop) { + foreach ((array)Tools::getValue('plc_id_lang', Language::getLanguages(false, false, true)) as $id_lang) { - // Determine which shops to scan - if ($id_shop_filter) { - $shop_ids = [$id_shop_filter]; - } else { - $shop_ids = Shop::getShops(true, null, true); - } + foreach ($collection as $p) { + $product = new Product((int)$p->id, false, $id_lang, $id_shop); - // Determine which languages to scan - if ($id_lang_filter) { - $lang_ids = [$id_lang_filter]; - } else { - $lang_ids = Language::getLanguages(true, false, true); - } - - $all_product_data = []; - - foreach ($shop_ids as $id_shop) { - foreach ($lang_ids as $id_lang) { - // Get all active products for the current shop and language - $products = Product::getProducts($id_lang, 0, 0, 'id_product', 'ASC', false, true); - - foreach ($products as $product_data) { - $product = new Product($product_data['id_product'], false, $id_lang, $id_shop); - - // Skip invalid or unloaded products if (!Validate::isLoadedObject($product)) { continue; } + if (Tools::getValue('plc_only_active') && !$product->active) { + continue; + } - - - // 2. Add data for all attribute combinations + // Handle products with attribute combinations if ($product->hasAttributes()) { - // getAttributeCombinations provides detailed data for each combination $combinations = $product->getAttributeCombinations($id_lang); - if ($combinations) { - foreach ($combinations as $combination) { - if (!isset($all_product_data[$product->id . '_' . $combination['id_product_attribute']])) { - $all_product_data[$product->id . '_' . $combination['id_product_attribute']] = [ - 'id_product' => (int)$product->id, - 'id_product_attribute' => (int)$combination['id_product_attribute'], - 'meta_title' => $product->meta_title, // Meta is usually product-level - 'meta_description' => $product->meta_description, - // Title and descriptions are also from the main product - 'title' => $product->name, - 'description' => Tools::getValue('plc_no_description') ? null : $product->description, - 'description_short' => Tools::getValue('plc_no_description_short') ? null : $product->description_short, - // These fields are specific to the combination - 'mpn' => $combination['mpn'] ?? null, - 'reference' => $combination['reference'] ?? null, - 'ean13' => $combination['ean13'] ?? null, - 'upc' => $combination['upc'] ?? null, - 'id_language' => (int)$id_lang, - 'id_shop' => (int)$id_shop, - 'link' => $this->context->link->getProductLink($product, null, null, null, (int)$id_lang, (int)$id_shop, (int)$combination['id_product_attribute']), - 'link_rewrite' => $product->link_rewrite, - ]; - } - $all_product_data[$product->id . '_' . $combination['id_product_attribute']]['attributes'][] = [ - 'group_name' => $combination['group_name'] ?? null, - 'attribute_name' => $combination['attribute_name'] ?? null, + foreach ($combinations as $combination) { + $index = $product->id . '_' . $combination['id_product_attribute']; + if (!isset($productsData[$index])) { + $productsData[$index] = [ + 'id_lang' => (int)$id_lang, + 'id_shop' => (int)$id_shop, + 'id_product' => (int)$product->id, + 'id_product_attribute' => (int)$combination['id_product_attribute'], + 'active' => (bool)$product->active, + 'link' => $this->context->link->getProductLink( + $product, + null, + null, + null, + (int)$id_lang, + (int)$id_shop, + (int)$combination['id_product_attribute'], + false + ), ]; + + // Conditionally add data based on URL flags + Tools::getValue('plc_name') ? $productsData[$index]['name'] = $product->name : null; + Tools::getValue('plc_link_rewrite') ? $productsData[$index]['link_rewrite'] = $product->link_rewrite : null; + Tools::getValue('plc_description') ? $productsData[$index]['description'] = $product->description : null; + Tools::getValue('plc_description_short') ? $productsData[$index]['description_short'] = $product->description_short : null; + Tools::getValue('plc_meta_title') ? $productsData[$index]['meta_title'] = $product->meta_title : null; + Tools::getValue('plc_meta_description') ? $productsData[$index]['meta_description'] = $product->meta_description : null; + Tools::getValue('plc_reference') ? $productsData[$index]['reference'] = $combination['reference'] : null; + Tools::getValue('plc_ean13') ? $productsData[$index]['ean13'] = $combination['ean13'] : null; + Tools::getValue('plc_upc') ? $productsData[$index]['upc'] = $combination['upc'] : null; + Tools::getValue('plc_mpn') ? $productsData[$index]['mpn'] = $combination['mpn'] : null; } + + $productsData[$index]['attributes'][] = [ + 'group_name' => $combination['group_name'] ?? null, + 'attribute_name' => $combination['attribute_name'] ?? null, + ]; } - } else { // 1. Add the main product data (as a product without a specific combination) - $all_product_data[] = [ - 'id_product' => (int)$product->id, - 'id_product_attribute' => 0, // 0 for the main product - 'meta_title' => $product->meta_title, - // Grouping meta fields for clarity - 'meta_description' => $product->meta_description, - 'title' => $product->name, - 'description' => Tools::getValue('plc_no_description') ? null : $product->description, - 'description_short' => Tools::getValue('plc_no_description_short') ? null : $product->description_short, - 'mpn' => $product->mpn ?? null, - 'reference' => $product->reference ?? null, - 'ean13' => $product->ean13 ?? null, - 'upc' => $product->upc ?? null, - 'id_language' => (int)$id_lang, + } else { // Handle simple products (without combinations) + $index = $product->id . '_' . 0; + $productsData[$index] = [ + 'id_lang' => (int)$id_lang, 'id_shop' => (int)$id_shop, - 'link' => $this->context->link->getProductLink($product), - 'link_rewrite' => $product->link_rewrite, + 'id_product' => (int)$product->id, + 'id_product_attribute' => 0, + 'active' => (bool)$product->active, + 'link' => $this->context->link->getProductLink( + $product, + null, + null, + null, + (int)$id_lang, + (int)$id_shop, + 0, + false + ), ]; + + // Conditionally add data based on URL flags + Tools::getValue('plc_name') ? $productsData[$index]['name'] = $product->name : null; + Tools::getValue('plc_link_rewrite') ? $productsData[$index]['link_rewrite'] = $product->link_rewrite : null; + Tools::getValue('plc_description') ? $productsData[$index]['description'] = $product->description : null; + Tools::getValue('plc_description_short') ? $productsData[$index]['description_short'] = $product->description_short : null; + Tools::getValue('plc_meta_title') ? $productsData[$index]['meta_title'] = $product->meta_title : null; + Tools::getValue('plc_meta_description') ? $productsData[$index]['meta_description'] = $product->meta_description : null; + Tools::getValue('plc_reference') ? $productsData[$index]['reference'] = $product->reference : null; + Tools::getValue('plc_ean13') ? $productsData[$index]['ean13'] = $product->ean13 : null; + Tools::getValue('plc_upc') ? $productsData[$index]['upc'] = $product->upc : null; + Tools::getValue('plc_mpn') ? $productsData[$index]['mpn'] = $product->mpn : null; } } } } - // Output the final array as a JSON object - echo json_encode($all_product_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + $response = new JsonResponse($productsData); + $response->send(); exit; } } diff --git a/productlinkchecker.php b/productlinkchecker.php index 31faf97..6ae0591 100644 --- a/productlinkchecker.php +++ b/productlinkchecker.php @@ -1,4 +1,5 @@ name = 'productlinkchecker'; $this->tab = 'seo'; - $this->version = '1.0.0'; + $this->version = '2.0.0'; $this->author = 'Panariga'; $this->need_instance = 0; $this->ps_versions_compliancy = ['min' => '1.7.0', 'max' => _PS_VERSION_]; @@ -62,13 +63,39 @@ class ProductLinkChecker extends Module */ public function getContent() { + // Define the available data fields for each controller based on your code + $product_fields = [ + 'plc_name' => $this->l('Name'), + 'plc_link_rewrite' => $this->l('Link Rewrite'), + 'plc_description' => $this->l('Description'), + 'plc_description_short' => $this->l('Short Description'), + 'plc_meta_title' => $this->l('Meta Title'), + 'plc_meta_description' => $this->l('Meta Description'), + 'plc_reference' => $this->l('Reference'), + 'plc_ean13' => $this->l('EAN13'), + 'plc_upc' => $this->l('UPC'), + 'plc_mpn' => $this->l('MPN'), + ]; + + $category_fields = [ + 'plc_name' => $this->l('Name'), + 'plc_link_rewrite' => $this->l('Link Rewrite'), + 'plc_description' => $this->l('Description'), + 'plc_additional_description' => $this->l('Additional Description'), + 'plc_meta_title' => $this->l('Meta Title'), + 'plc_meta_description' => $this->l('Meta Description'), + ]; + $this->context->smarty->assign([ 'security_token' => Configuration::get('PLC_SECURITY_TOKEN'), 'shops' => Shop::getShops(true, null, true), 'languages' => Language::getLanguages(true), - 'base_controller_url' => $this->context->link->getModuleLink($this->name, 'generate', [], true), + 'product_controller_url' => $this->context->link->getModuleLink($this->name, 'product', [], true), + 'category_controller_url' => $this->context->link->getModuleLink($this->name, 'category', [], true), + 'product_fields' => $product_fields, + 'category_fields' => $category_fields, ]); return $this->display(__FILE__, 'views/templates/admin/configure.tpl'); } -} \ No newline at end of file +} diff --git a/views/templates/admin/configure.tpl b/views/templates/admin/configure.tpl index a4a60d8..a9752e9 100644 --- a/views/templates/admin/configure.tpl +++ b/views/templates/admin/configure.tpl @@ -4,34 +4,228 @@ {l s='Product Link Checker Configuration' mod='productlinkchecker'} -
+

{l s='Your Security Token' mod='productlinkchecker'}

-

{l s='Use this token to access the link generator. Keep it secret!' mod='productlinkchecker'}

+

{l s='Use this token to access the link generators below. Keep it secret!' mod='productlinkchecker'}

{$security_token|escape:'html':'UTF-8'}

- {l s='Available URLs' mod='productlinkchecker'} + {l s='URL Generator' mod='productlinkchecker'}
-
- - {l s='All Shops & All Languages' mod='productlinkchecker'}
- {$base_controller_url}?token={$security_token|escape:'html':'UTF-8'} -
- {foreach from=$shops item=shop} - - {l s='Shop:' mod='productlinkchecker'} {$shop.name|escape:'html':'UTF-8'} ({l s='All Languages' mod='productlinkchecker'})
- {$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}&plc_id_shop={$shop.id_shop|intval} -
- {foreach from=$languages item=lang} - - {l s='Shop:' mod='productlinkchecker'} {$shop.name|escape:'html':'UTF-8'} | {l s='Language:' mod='productlinkchecker'} {$lang.name|escape:'html':'UTF-8'}
- {$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}&plc_id_shop={$shop.id_shop|intval}&plc_id_lang={$lang.id_lang|intval} -
- {/foreach} - {/foreach} + + + + +
+ {* --- PRODUCT URL BUILDER --- *} +
+
+

{l s='1. Select Filters' mod='productlinkchecker'}

+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + + + + + + +
+
+ +
+

{l s='2. Select Data Fields to Include' mod='productlinkchecker'}

+
+
+ {foreach from=$product_fields key=key item=label} +
+ +
+ {/foreach} +
+
+ +
+

{l s='3. Generated URL' mod='productlinkchecker'}

+
+
+
+ + + + + {l s='Open' mod='productlinkchecker'} + + +
+
+
+
+
+ + {* --- CATEGORY URL BUILDER --- *} +
+
+

{l s='1. Select Filters' mod='productlinkchecker'}

+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + + + + + + +
+
+ +
+

{l s='2. Select Data Fields to Include' mod='productlinkchecker'}

+
+
+ {foreach from=$category_fields key=key item=label} +
+ +
+ {/foreach} +
+
+ +
+

{l s='3. Generated URL' mod='productlinkchecker'}

+
+
+
+ + + + + {l s='Open' mod='productlinkchecker'} + + +
+
+
+
+
-
\ No newline at end of file +
+ + \ No newline at end of file