I have created a custom module called SpecialsSubCategory. The folder sits in app > code > Gelmar > SpecialsSubCategory. The file structures are as follows
SpecialsSubCategory > Controller > Adminhtml > Specials > Run.php
SpecialsSubCategory > etc > adminhtml > acl.xml
SpecialsSubCategory > etc > adminhtml > routes.xml
SpecialsSubCategory > etc > adminhtml > system.xml
SpecialsSubCategory > etc > module.xml
SpecialsSubCategory > registration.php
I am trying to get all products that are in the specials category (ID = 206) and then get their specific category eg Bathroom and then add the corresponding category specials ID.The specific category IDs and their corelating category specials IDs are as follows:
(Electrical ID = 249)
(Handles ID = 5)
(Kitchen ID = 21)
(Bedroom ID = 19)
(Castors ID = 24)
(Adhesives ID = 28)
(Locks ID = 53)
(Electrical Specials ID = 259)
(Handles Specials ID = 260)
(Kitchen Specials ID = 261)
(Bedroom Specials ID = 262)
(Castors Specials ID = 263)
(Adhesives Specials ID = 264)
(Locks Specials ID = 265)
So for example if the product has the ID 249 then it must add the ID 259 to the product. I have double checked the IDs and they are all correct but the module does not work. The files are below, please advise and help.
Module.xml file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Gelmar_SpecialsSubCategory" setup_version="1.0.0" />
</config>
routes.xml file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="adminhtml">
<route id="specials_subcategory" frontName="specials_subcategory">
<module name="Gelmar_SpecialsSubCategory" before="Magento_Backend"/>
</route>
</router>
</config>
registration.php file
<?php
MagentoFrameworkComponentComponentRegistrar::register(
MagentoFrameworkComponentComponentRegistrar::MODULE,
'Gelmar_SpecialsSubCategory',
__DIR__
);
system.xml file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="specials_subcategory" translate="label" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<class>separator-top</class>
<label>Category Specials</label>
<tab>ThreeYearOrders</tab>
<resource>Gelmar_SpecialsSubCategory::config</resource>
<group id="general" translate="label" type="text" sortOrder="110" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Settings</label>
<field id="run_specials_logic" translate="label" type="button" sortOrder="2" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Update Category Specials</label>
<button class="action specials" type="button">
<span>Update</span>
</button>
<action>
<url path="gelmar/specials/run" />
</action>
</field>
</group>
</section>
</system>
</config>
Run.php file
<?php
namespace GelmarSpecialsSubCategoryControllerAdminhtmlSpecials;
use MagentoBackendAppAction;
use MagentoCatalogModelResourceModelProductCollectionFactory as ProductCollectionFactory;
use MagentoCatalogApiCategoryLinkManagementInterface;
use MagentoFrameworkControllerResultFactory;
use PsrLogLoggerInterface;
class Run extends Action
{
protected $productCollectionFactory;
protected $categoryLinkManagement;
protected $logger;
public function __construct(
ActionContext $context,
ProductCollectionFactory $productCollectionFactory,
CategoryLinkManagementInterface $categoryLinkManagement,
LoggerInterface $logger
) {
parent::__construct($context);
$this->productCollectionFactory = $productCollectionFactory;
$this->categoryLinkManagement = $categoryLinkManagement;
$this->logger = $logger;
}
public function execute()
{
// Start logging
$this->logger->info('Starting the "Category Specials" update process.');
// Category IDs
$specialsCategoryId = 206;
$mapping = [
249 => 259,
5 => 260,
21 => 261,
19 => 262,
24 => 263,
28 => 264,
53 => 265
];
// Get all products in the Specials category (206)
$this->logger->info('Fetching products from category ID: ' . $specialsCategoryId);
$productCollection = $this->productCollectionFactory->create()
->addCategoriesFilter(['in' => $specialsCategoryId]);
// Log the count of products found
$this->logger->info('Number of products found in category ' . $specialsCategoryId . ': ' . $productCollection->getSize());
// Loop through the products
foreach ($productCollection as $product) {
$productSku = $product->getSku();
$categoryIds = $product->getCategoryIds();
// Log the product SKU and its existing categories
$this->logger->info('Processing product SKU: ' . $productSku);
$this->logger->info('Current categories for product ' . $productSku . ': ' . implode(', ', $categoryIds));
// Use array_intersect() to find matching categories
$categoriesToAdd = array_intersect(array_keys($mapping), $categoryIds);
if (!empty($categoriesToAdd)) {
$newCategoryIds = array_merge($categoryIds, array_map(function($id) use ($mapping) {
return $mapping[$id];
}, $categoriesToAdd));
// Ensure no duplicates
$newCategoryIds = array_unique($newCategoryIds);
// Log new categories to be added
$this->logger->info('New categories to assign for product ' . $productSku . ': ' . implode(', ', $newCategoryIds));
// Only update if categories have changed
if ($newCategoryIds !== $categoryIds) {
try {
$this->categoryLinkManagement->assignProductToCategories($productSku, $newCategoryIds);
$this->logger->info('Categories updated successfully for product ' . $productSku);
} catch (Exception $e) {
// Log the error
$this->logger->error('Error assigning categories to product ' . $productSku . ': ' . $e->getMessage());
$this->messageManager->addErrorMessage(__('Error assigning categories to product %1: %2', $productSku, $e->getMessage()));
}
} else {
$this->logger->info('No category changes needed for product ' . $productSku);
}
} else {
$this->logger->info('No relevant categories to add for product ' . $productSku);
}
}
// Display success message in the admin
$this->messageManager->addSuccessMessage(__('Specials category update completed successfully.'));
$this->logger->info('Category specials update completed successfully.');
// Test code: This is to check if the button is calling the controller
$result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
$result->setContents("Controller executed successfully!"); // Temporary message for testing
return $result;
// Redirect back to the config page (after testing, comment out the above test block and use this return)
// $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
// $resultRedirect->setPath('adminhtml/system_config/edit/section/specials_subcategory');
// return $resultRedirect;
}
}
acl.xml file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3g.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework/Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Gelmar_SpecialsSubCategory::specials" title="Specials SubCategory" sortOrder="10" />
</resource>
</resources>
</acl>
</config>
The file names at the top of each code is not there in my program I just put them there to help understand which file was which. I can not seem to get any messages to display on the admin side and I have go through the system.log file and debug.log file and they both have no messages in them either, which makes me think that the module is not executing at all. Please help with solutions and/or suggestions