first commit
This commit is contained in:
93
controllers/front/generate.php
Normal file
93
controllers/front/generate.php
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Product Link Checker Generate Controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ProductLinkCheckerGenerateModuleFrontController extends ModuleFrontController
|
||||||
|
{
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
parent::init();
|
||||||
|
|
||||||
|
// Security check: Validate the token
|
||||||
|
$token = Tools::getValue('token');
|
||||||
|
$storedToken = Configuration::get('PLC_SECURITY_TOKEN');
|
||||||
|
|
||||||
|
if (!$token || $token !== $storedToken) {
|
||||||
|
header('HTTP/1.1 403 Forbidden');
|
||||||
|
exit('Invalid security token.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initContent()
|
||||||
|
{
|
||||||
|
parent::initContent();
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$id_shop_filter = (int)Tools::getValue('id_shop');
|
||||||
|
$id_lang_filter = (int)Tools::getValue('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);
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_links = [];
|
||||||
|
|
||||||
|
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 products
|
||||||
|
if (!Validate::isLoadedObject($product)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get base product link
|
||||||
|
$base_link = $this->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
74
productlinkchecker.php
Normal file
74
productlinkchecker.php
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Product Link Checker
|
||||||
|
*
|
||||||
|
* @author Panariga
|
||||||
|
* @copyright 2025 Panariga
|
||||||
|
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('_PS_VERSION_')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProductLinkChecker extends Module
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->name = 'productlinkchecker';
|
||||||
|
$this->tab = 'seo';
|
||||||
|
$this->version = '1.0.0';
|
||||||
|
$this->author = 'Panariga';
|
||||||
|
$this->need_instance = 0;
|
||||||
|
$this->ps_versions_compliancy = ['min' => '1.7.6', 'max' => _PS_VERSION_];
|
||||||
|
$this->bootstrap = true;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->displayName = $this->l('Product Link Checker');
|
||||||
|
$this->description = $this->l('Generates a JSON list of all product links for testing purposes.');
|
||||||
|
|
||||||
|
$this->confirmUninstall = $this->l('Are you sure you want to uninstall this module?');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installation of the module.
|
||||||
|
*/
|
||||||
|
public function install()
|
||||||
|
{
|
||||||
|
if (!parent::install()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate and save a unique security token
|
||||||
|
$token = Tools::passwdGen(32);
|
||||||
|
Configuration::updateValue('PLC_SECURITY_TOKEN', $token);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uninstallation of the module.
|
||||||
|
*/
|
||||||
|
public function uninstall()
|
||||||
|
{
|
||||||
|
Configuration::deleteByName('PLC_SECURITY_TOKEN');
|
||||||
|
|
||||||
|
return parent::uninstall();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module configuration page.
|
||||||
|
*/
|
||||||
|
public function getContent()
|
||||||
|
{
|
||||||
|
$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),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->display(__FILE__, 'views/templates/admin/configure.tpl');
|
||||||
|
}
|
||||||
|
}
|
||||||
37
views/templates/admin/configure.tpl
Normal file
37
views/templates/admin/configure.tpl
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{* views/templates/admin/configure.tpl *}
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="icon-link"></i> {l s='Product Link Checker Configuration' mod='productlinkchecker'}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<h4><i class="icon-key"></i> {l s='Your Security Token' mod='productlinkchecker'}</h4>
|
||||||
|
<p>{l s='Use this token to access the link generator. Keep it secret!' mod='productlinkchecker'}</p>
|
||||||
|
<p><strong>{$security_token|escape:'html':'UTF-8'}</strong></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="icon-list"></i> {l s='Available URLs' mod='productlinkchecker'}
|
||||||
|
</div>
|
||||||
|
<div class="list-group">
|
||||||
|
<a href="{$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}" target="_blank" class="list-group-item">
|
||||||
|
<strong>{l s='All Shops & All Languages' mod='productlinkchecker'}</strong><br>
|
||||||
|
<code>{$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}</code>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{foreach from=$shops item=shop}
|
||||||
|
<a href="{$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}&id_shop={$shop.id_shop|intval}" target="_blank" class="list-group-item">
|
||||||
|
<strong>{l s='Shop:' mod='productlinkchecker'} {$shop.name|escape:'html':'UTF-8'} ({l s='All Languages' mod='productlinkchecker'})</strong><br>
|
||||||
|
<code>{$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}&id_shop={$shop.id_shop|intval}</code>
|
||||||
|
</a>
|
||||||
|
{foreach from=$languages item=lang}
|
||||||
|
<a href="{$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}&id_shop={$shop.id_shop|intval}&id_lang={$lang.id_lang|intval}" target="_blank" class="list-group-item">
|
||||||
|
<strong>{l s='Shop:' mod='productlinkchecker'} {$shop.name|escape:'html':'UTF-8'} | {l s='Language:' mod='productlinkchecker'} {$lang.name|escape:'html':'UTF-8'}</strong><br>
|
||||||
|
<code>{$base_controller_url}?token={$security_token|escape:'html':'UTF-8'}&id_shop={$shop.id_shop|intval}&id_lang={$lang.id_lang|intval}</code>
|
||||||
|
</a>
|
||||||
|
{/foreach}
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user