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']);
}

Performance-Optimized Extensions

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

Performance Considerations

  • 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

  1. Navigate to PureClarity configuration
  2. Enable Debug Logging
  3. Run feed processing
  4. 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.