You can create 2 plugins for after load
method for collection and product.
Plugin declaration
app/code/Acme/StackExchange/etc/di.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Model\Product">
<plugin name="Acme_StackExchange_Plugin_Catalog_Model_ProductPlugin"
type="Acme\StackExchange\Plugin\Catalog\Model\ProductPlugin" sortOrder="10"/>
</type>
<type name="Magento\Catalog\Model\ResourceModel\Product\Collection">
<plugin name="Acme_StackExchange_Plugin_Catalog_Model_ResourceModel_Product_CollectionPlugin"
type="Acme\StackExchange\Plugin\Catalog\Model\ResourceModel\Product\CollectionPlugin" sortOrder="10"/>
</type>
</config>
Product Model Plugin
app/code/Acme/StackExchange/Plugin/Catalog/Model/ProductPlugin.php
<?php
declare(strict_types=1);
namespace Acme\StackExchange\Plugin\Catalog\Model;
use Magento\Catalog\Model\Product;
class ProductPlugin
{
public function afterLoad(Product $product)
{
// load your custom data and assign to $product instance
return $product;
}
}
Product Collection Plugin
app/code/Acme/StackExchange/Plugin/Catalog/Model/ResourceModel/Product/CollectionPlugin.php
<?php
declare(strict_types=1);
namespace Acme\StackExchange\Plugin\Catalog\Model\ResourceModel\Product;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
class CollectionPlugin
{
protected bool $isLoaded = false;
public function beforeLoad(Collection $subject, $printQuery = false, $logQuery = false): array
{
$this->isLoaded = $subject->isLoaded();
return [$printQuery, $logQuery];
}
public function afterLoad(Collection $subject, Collection $result): Collection
{
if (!$this->isLoaded) {
$this->isLoaded = true;
// collect loaded product ids
$productIds = [];
/** @var Product $product */
foreach ($subject->getItems() as $product) {
$productIds[] = $product->getId();
}
// load your data for $productIds
foreach ($subject->getItems() as $product) {
// check is data loaded for $product
// assign loaded data to $product instance
}
}
return $result;
}
}