This developer guide explains how to extend PureClarity’s feed process in Magento 2.x to add custom data or modify existing feed content. Use these techniques to integrate custom fields, modify data processing, or enhance feed functionality.
Overview of Feed Extension
When to Extend Feeds
Common extension scenarios:
- Custom product attributes not included in standard feeds
- Modified pricing logic for specific business rules
- Additional product data from external systems
- Custom category information beyond standard attributes
- Brand data enhancement with custom fields
- User data integration from CRM systems
Extension Approach
Recommended method: Use Magento plugins for clean, maintainable extensions
- Non-invasive - Doesn’t modify core PureClarity code
- Upgrade-safe - Survives extension updates
- Maintainable - Clear separation of custom logic
- Testable - Isolated functionality for testing
Always use plugins rather than class rewrites or core modifications to ensure compatibility with future updates.
Feed Architecture
Extension Points
Each feed type provides two main extension points:
Feed Data Handler
- Purpose: Gathers data from Magento using collections
- Extension use: Modify data collection logic, add joins, filter data
- Method: Plugin the collection building methods
Row Data Handler
- Purpose: Transforms Magento data into PureClarity feed format
- Extension use: Add custom fields, modify data format, apply business rules
- Method: Plugin the data transformation methods
Feed Types and Classes
Product Feed
Feed Data Handler: Pureclarity\Core\Model\Feed\Type\Product\FeedData
- Key method:
buildCollection()
- Returns product collection
Row Data Handler: Pureclarity\Core\Model\Feed\Type\Product\RowData
- Key method:
getRowData()
- Returns formatted product data array
Specialized row handlers:
- Located in
Pureclarity\Core\Model\Feed\Type\Product\RowDataHandlers\*
- Individual handlers for specific data aspects (pricing, images, attributes)
Category Feed
Feed Data Handler: Pureclarity\Core\Model\Feed\Type\Category\FeedData
- Key method:
buildCategoryCollection()
- Returns category collection
Row Data Handler: Pureclarity\Core\Model\Feed\Type\Category\RowData
- Key method:
getRowData()
- Returns formatted category data array
Brand Feed
Feed Data Handler: Pureclarity\Core\Model\Feed\Type\Brand\FeedData
- Key method:
buildBrandCollection()
- Returns brand collection
Row Data Handler: Pureclarity\Core\Model\Feed\Type\Brand\RowData
- Key method:
getRowData()
- Returns formatted brand data array
User Feed
Feed Data Handler: Pureclarity\Core\Model\Feed\Type\User\FeedData
- Key method:
buildCustomerCollection()
- Returns customer collection
Row Data Handler: Pureclarity\Core\Model\Feed\Type\User\RowData
- Key method:
getRowData()
- Returns formatted user data array
Order History Feed
Feed Data Handler: Pureclarity\Core\Model\Feed\Type\Order\FeedData
- Key method:
buildOrderCollection()
- Returns order collection
Row Data Handler: Pureclarity\Core\Model\Feed\Type\Order\RowData
- Key method:
getRowData()
- Returns formatted order data array
Implementation Examples
Basic Product Data Extension
Scenario: Add a custom product field to the feed
1. Create di.xml configuration:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Pureclarity\Core\Model\Feed\Type\Product\RowData">
<plugin name="custom_product_feed_extension"
type="MyCompany\MyModule\Plugin\ProductFeedPlugin"
sortOrder="10"
disabled="false" />
</type>
</config>
2. Create the plugin class:
<?php
namespace MyCompany\MyModule\Plugin;
use Pureclarity\Core\Model\Feed\Type\Product\RowData;
class ProductFeedPlugin
{
/**
* Add custom field to product feed data
*
* @param RowData $subject
* @param array $result
* @return array
*/
public function afterGetRowData(RowData $subject, array $result)
{
// Add custom field to the product data
$result['custom_field'] = $this->getCustomFieldValue($subject);
return $result;
}
/**
* Get custom field value for current product
*
* @param RowData $subject
* @return string
*/
private function getCustomFieldValue(RowData $subject)
{
// Your custom logic here
return 'Custom Value';
}
}
Advanced Product Collection Modification
Scenario: Add custom data joins to product collection
1. Plugin the collection builder:
<type name="Pureclarity\Core\Model\Feed\Type\Product\FeedData">
<plugin name="custom_product_collection_extension"
type="MyCompany\MyModule\Plugin\ProductCollectionPlugin"
sortOrder="10"
disabled="false" />
</type>
2. Implement collection modification:
<?php
namespace MyCompany\MyModule\Plugin;
use Pureclarity\Core\Model\Feed\Type\Product\FeedData;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
class ProductCollectionPlugin
{
/**
* Add custom joins and attributes to product collection
*
* @param FeedData $subject
* @param Collection $result
* @return Collection
*/
public function afterBuildCollection(FeedData $subject, Collection $result)
{
// Add custom table join
$result->getSelect()->joinLeft(
['custom_table' => $result->getTable('custom_product_data')],
'e.entity_id = custom_table.product_id',
['custom_data' => 'custom_table.data_field']
);
// Add custom attributes
$result->addAttributeToSelect('custom_attribute');
return $result;
}
}
Category Data Enhancement
Scenario: Add external system data to category feed
<?php
namespace MyCompany\MyModule\Plugin;
use Pureclarity\Core\Model\Feed\Type\Category\RowData;
class CategoryFeedPlugin
{
private $externalDataService;
public function __construct(
\MyCompany\MyModule\Service\ExternalDataService $externalDataService
) {
$this->externalDataService = $externalDataService;
}
/**
* Enhance category data with external information
*
* @param RowData $subject
* @param array $result
* @return array
*/
public function afterGetRowData(RowData $subject, array $result)
{
$categoryId = $result['id'] ?? null;
if ($categoryId) {
// Get external data for this category
$externalData = $this->externalDataService->getCategoryData($categoryId);
// Add external data to feed
$result['external_description'] = $externalData['description'] ?? '';
$result['external_metadata'] = $externalData['metadata'] ?? [];
}
return $result;
}
}
User Feed Customization
Scenario: Add CRM data to user feed
<?php
namespace MyCompany\MyModule\Plugin;
use Pureclarity\Core\Model\Feed\Type\User\RowData;
class UserFeedPlugin
{
private $crmService;
public function __construct(
\MyCompany\MyModule\Service\CrmService $crmService
) {
$this->crmService = $crmService;
}
/**
* Add CRM data to user feed
*
* @param RowData $subject
* @param array $result
* @return array
*/
public function afterGetRowData(RowData $subject, array $result)
{
$customerId = $result['id'] ?? null;
if ($customerId) {
// Get CRM data for customer
$crmData = $this->crmService->getCustomerData($customerId);
// Add CRM information
$result['customer_tier'] = $crmData['tier'] ?? 'standard';
$result['lifetime_value'] = $crmData['ltv'] ?? 0;
$result['acquisition_channel'] = $crmData['channel'] ?? 'unknown';
}
return $result;
}
}
Advanced Extension Patterns
Conditional Data Addition
public function afterGetRowData(RowData $subject, array $result)
{
// Only add custom data for specific conditions
if ($this->shouldAddCustomData($result)) {
$result['custom_field'] = $this->getCustomData($result);
}
return $result;
}
private function shouldAddCustomData(array $productData): bool
{
// Custom logic to determine when to add data
return isset($productData['category_ids']) &&
in_array('premium_category_id', $productData['category_ids']);
}
public function afterGetRowData(RowData $subject, array $result)
{
// Batch process custom data to avoid N+1 queries
static $customDataCache = [];
$productId = $result['id'];
if (!isset($customDataCache[$productId])) {
// Load custom data in batches
$customDataCache = $this->loadCustomDataBatch($productId);
}
$result['custom_field'] = $customDataCache[$productId] ?? 'default_value';
return $result;
}
Data Validation and Sanitization
public function afterGetRowData(RowData $subject, array $result)
{
// Validate and sanitize custom data
$customValue = $this->getCustomValue($result);
// Validate data format
if ($this->isValidCustomValue($customValue)) {
$result['custom_field'] = $this->sanitizeCustomValue($customValue);
}
return $result;
}
private function isValidCustomValue($value): bool
{
// Custom validation logic
return is_string($value) && strlen($value) <= 255;
}
private function sanitizeCustomValue(string $value): string
{
// Sanitize for PureClarity feed format
return htmlspecialchars(trim($value), ENT_QUOTES, 'UTF-8');
}
Testing Feed Extensions
Unit Testing Plugin Methods
<?php
namespace MyCompany\MyModule\Test\Unit\Plugin;
use PHPUnit\Framework\TestCase;
use MyCompany\MyModule\Plugin\ProductFeedPlugin;
class ProductFeedPluginTest extends TestCase
{
private $plugin;
protected function setUp(): void
{
$this->plugin = new ProductFeedPlugin();
}
public function testAfterGetRowDataAddsCustomField()
{
$mockRowData = $this->createMock(\Pureclarity\Core\Model\Feed\Type\Product\RowData::class);
$inputData = ['id' => 123, 'name' => 'Test Product'];
$result = $this->plugin->afterGetRowData($mockRowData, $inputData);
$this->assertArrayHasKey('custom_field', $result);
$this->assertEquals('Custom Value', $result['custom_field']);
}
}
Integration Testing
public function testCustomFieldAppearsInFeed()
{
// Create test product with custom data
$product = $this->createTestProduct();
// Generate feed data
$feedData = $this->feedProcessor->generateProductFeed();
// Verify custom field is included
$productData = $this->findProductInFeed($feedData, $product->getId());
$this->assertArrayHasKey('custom_field', $productData);
}
Best Practices
- Minimize database queries - Use collection modifications over individual lookups
- Cache external API calls - Avoid repeated API requests during feed generation
- Batch operations - Process multiple items together when possible
- Monitor feed performance - Track impact of customizations on feed speed
Data Quality
- Validate data formats - Ensure custom data meets PureClarity requirements
- Handle missing data - Provide defaults for missing custom fields
- Sanitize input - Clean data to prevent feed corruption
- Test edge cases - Verify behavior with unusual data scenarios
Maintainability
- Document customizations - Explain business logic and data sources
- Use clear naming - Make custom fields easily identifiable
- Version control - Track changes to feed extensions
- Monitor for updates - Verify compatibility with PureClarity updates
Error Handling
- Graceful degradation - Feed should work even if custom data fails
- Logging - Log custom data processing for debugging
- Exception handling - Catch and handle external service failures
- Fallback values - Provide defaults when custom processing fails
Debugging Feed Extensions
Enable Debug Logging
- Navigate to PureClarity configuration
- Enable Debug Logging
- Run feed processing
- Review logs for custom data processing
Log Custom Processing
public function afterGetRowData(RowData $subject, array $result)
{
try {
$customData = $this->getCustomData($result);
$result['custom_field'] = $customData;
// Log successful processing
$this->logger->info('Custom data added', [
'product_id' => $result['id'],
'custom_data' => $customData
]);
} catch (\Exception $e) {
// Log errors but don't break feed
$this->logger->error('Custom data processing failed', [
'product_id' => $result['id'],
'error' => $e->getMessage()
]);
}
return $result;
}
Development References
PureClarity Integration
Testing and Debugging
Summary
Feed extension in PureClarity provides powerful customization options:
- Plugin-based approach for clean, maintainable extensions
- Multiple extension points for different types of customizations
- Performance considerations for large-scale implementations
- Testing strategies to ensure reliable custom functionality
- Best practices for maintainable, upgrade-safe customizations
Use these techniques to enhance PureClarity feeds with your specific business requirements while maintaining system performance and reliability.