> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pureclarity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Server-Side Mode Implementation

> Advanced guide to implementing and customizing server-side mode in Magento 2.x for complex pricing and custom data requirements

Server-side mode routes recommendation requests through Magento to ensure personalized pricing, complex business rules, and custom data processing. This advanced implementation guide covers template customization and data extension.

## Server-Side Mode Overview

### How Server-Side Mode Works

1. **PureClarity provides SKUs** - Recommendation algorithm returns product identifiers
2. **Magento processes SKUs** - Server loads current product data with customer context
3. **Custom logic applied** - Pricing rules, inventory, and business logic processed
4. **Template renders output** - Knockout.js template displays final recommendations
5. **HTML delivered to page** - Complete recommendation content served

### Differences from Client-Side Mode

**Template Management:**

* **Server-side:** Templates managed in Magento theme files
* **Client-side:** Templates managed in PureClarity admin

**Data Processing:**

* **Server-side:** Real-time Magento data with customer context
* **Client-side:** Static data from pre-generated feeds

**Customization:**

* **Server-side:** Full access to Magento functionality
* **Client-side:** Limited to feed data and PureClarity template editor

<Note>
  Changes made in PureClarity Admin's Template Editor or Recommender Designer will not affect server-side mode displays. All template customization must be done in Magento.
</Note>

## Template Customization

### Default Template Location

The product recommender template is located at:

```
vendor/pureclarity/pureclarity-magento-2/view/frontend/web/template/product-recommender.html
```

### Override Template in Your Theme

To customize the template, copy it to your theme:

**Target location:**

```
app/design/frontend/[Vendor]/[theme]/Pureclarity_Core/web/template/product-recommender.html
```

**Example file structure:**

```
app/design/frontend/
└── MyCompany/
    └── mytheme/
        └── Pureclarity_Core/
            └── web/
                └── template/
                    └── product-recommender.html
```

<Warning>
  Never modify the original template in the vendor directory as it will be overwritten during extension updates.
</Warning>

### Basic Template Structure

The template uses Knockout.js data binding:

```html theme={null}
<!-- ko foreach: products -->
<div class="product-item" data-bind="attr: {id: 'product-' + id}">
    <div class="product-image">
        <img data-bind="attr: {src: image, alt: name}" />
    </div>
    
    <div class="product-info">
        <h3 class="product-name" data-bind="text: name"></h3>
        <div class="product-price" data-bind="text: price"></div>
        
        <!-- Custom fields can be added here -->
        <div class="custom-data" data-bind="text: my_custom_field"></div>
    </div>
    
    <div class="product-actions">
        <button class="btn-cart" data-bind="attr: {href: url}">
            Add to Cart
        </button>
    </div>
</div>
<!-- /ko -->
```

### Available Data Fields

**Standard product data available in templates:**

* `id` - Product ID
* `name` - Product name
* `price` - Formatted price string
* `url` - Product page URL
* `image` - Product image URL
* `description` - Product description
* `sku` - Product SKU

**Additional fields through customization:**

* Custom attributes
* Calculated pricing
* Inventory information
* Customer-specific data

## Custom Data Extension

### Extension Point

Extend product data using plugins on the `ProductData` class:

**Class:** `\Pureclarity\Core\Model\Serverside\Response\ProductData`\
**Method:** `populateProductData()` - Adds data to the array sent to Knockout

### Implementation Example

**1. Create di.xml configuration:**

```xml theme={null}
<?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\Serverside\Response\ProductData">
        <plugin name="custom_serverside_data" 
                type="MyCompany\MyModule\Plugin\ServersideDataPlugin" 
                sortOrder="10" 
                disabled="false" />
    </type>
</config>
```

**2. Create the plugin class:**

```php theme={null}
<?php
namespace MyCompany\MyModule\Plugin;

use Pureclarity\Core\Model\Serverside\Response\ProductData;

class ServersideDataPlugin
{
    private $customerSession;
    private $pricingHelper;
    
    public function __construct(
        \Magento\Customer\Model\Session $customerSession,
        \MyCompany\MyModule\Helper\Pricing $pricingHelper
    ) {
        $this->customerSession = $customerSession;
        $this->pricingHelper = $pricingHelper;
    }
    
    /**
     * Add custom data to product recommendations
     *
     * @param ProductData $subject
     * @param array $data
     * @return array
     */
    public function afterPopulateProductData(ProductData $subject, array $data)
    {
        // Add custom pricing logic
        $data['price'] = $this->calculateCustomPrice($data);
        
        // Add custom fields
        $data['my_custom_field'] = $this->getCustomFieldValue($data);
        $data['customer_tier'] = $this->getCustomerTier();
        $data['stock_status'] = $this->getStockStatus($data['id']);
        
        return $data;
    }
    
    /**
     * Calculate customer-specific pricing
     */
    private function calculateCustomPrice(array $productData)
    {
        $customer = $this->customerSession->getCustomer();
        return $this->pricingHelper->getCustomerPrice($productData['id'], $customer);
    }
    
    /**
     * Get custom field value
     */
    private function getCustomFieldValue(array $productData)
    {
        // Your custom logic here
        return 'Custom Value for Product ' . $productData['id'];
    }
    
    /**
     * Get customer tier information
     */
    private function getCustomerTier()
    {
        $customer = $this->customerSession->getCustomer();
        return $customer->getCustomAttribute('customer_tier') ?? 'standard';
    }
    
    /**
     * Get current stock status
     */
    private function getStockStatus($productId)
    {
        // Implement stock checking logic
        return 'in_stock';
    }
}
```

### Advanced Custom Pricing Example

```php theme={null}
private function calculateCustomPrice(array $productData)
{
    $customer = $this->customerSession->getCustomer();
    $productId = $productData['id'];
    
    // Get base price
    $basePrice = $productData['price_raw'] ?? 0;
    
    // Apply customer-specific discount
    $customerDiscount = $this->getCustomerDiscount($customer);
    $discountedPrice = $basePrice * (1 - $customerDiscount);
    
    // Apply volume pricing
    $volumePrice = $this->applyVolumePricing($productId, $customer, $discountedPrice);
    
    // Apply contract pricing if applicable
    $finalPrice = $this->applyContractPricing($productId, $customer, $volumePrice);
    
    // Format for display
    return $this->formatPrice($finalPrice);
}
```

## Advanced Template Customization

### Responsive Design Template

```html theme={null}
<!-- ko foreach: products -->
<div class="product-item col-xs-12 col-sm-6 col-md-4 col-lg-3">
    <div class="product-card">
        <div class="product-image-container">
            <img data-bind="attr: {src: image, alt: name}" 
                 class="product-image img-responsive" />
            
            <!-- Custom badge for special pricing -->
            <!-- ko if: customer_tier === 'premium' -->
            <span class="premium-badge">Premium Price</span>
            <!-- /ko -->
        </div>
        
        <div class="product-details">
            <h4 class="product-name" data-bind="text: name"></h4>
            
            <!-- Custom pricing display -->
            <div class="price-container">
                <!-- ko if: has_special_price -->
                <span class="regular-price" data-bind="text: regular_price"></span>
                <span class="special-price" data-bind="text: price"></span>
                <!-- /ko -->
                
                <!-- ko ifnot: has_special_price -->
                <span class="price" data-bind="text: price"></span>
                <!-- /ko -->
            </div>
            
            <!-- Custom stock indicator -->
            <div class="stock-indicator" data-bind="css: stock_status">
                <span data-bind="text: stock_message"></span>
            </div>
            
            <!-- Custom attributes -->
            <!-- ko if: custom_attribute -->
            <div class="custom-info" data-bind="text: custom_attribute"></div>
            <!-- /ko -->
        </div>
        
        <div class="product-actions">
            <!-- ko if: stock_status === 'in_stock' -->
            <button class="btn btn-primary btn-cart" 
                    data-bind="click: $parent.addToCart">
                Add to Cart
            </button>
            <!-- /ko -->
            
            <!-- ko if: stock_status === 'out_of_stock' -->
            <button class="btn btn-secondary" disabled>
                Out of Stock
            </button>
            <!-- /ko -->
            
            <a class="btn btn-link view-details" 
               data-bind="attr: {href: url}">
                View Details
            </a>
        </div>
    </div>
</div>
<!-- /ko -->
```

### Template with Custom Styling

```html theme={null}
<style>
.pureclarity-recommendations {
    margin: 20px 0;
}

.product-card {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 15px;
    margin-bottom: 20px;
    transition: box-shadow 0.3s;
}

.product-card:hover {
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}

.premium-badge {
    position: absolute;
    top: 10px;
    right: 10px;
    background: gold;
    color: #333;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
}

.price-container .regular-price {
    text-decoration: line-through;
    color: #999;
    margin-right: 10px;
}

.price-container .special-price {
    color: #e74c3c;
    font-weight: bold;
}

.stock-indicator.in_stock {
    color: #27ae60;
}

.stock-indicator.out_of_stock {
    color: #e74c3c;
}
</style>

<div class="pureclarity-recommendations">
    <!-- ko foreach: products -->
    <!-- Template content here -->
    <!-- /ko -->
</div>
```

## Performance Optimization

### Caching Strategies

```php theme={null}
public function afterPopulateProductData(ProductData $subject, array $data)
{
    // Use static cache for expensive operations
    static $priceCache = [];
    static $customerTierCache = null;
    
    $productId = $data['id'];
    
    // Cache customer tier for session
    if ($customerTierCache === null) {
        $customerTierCache = $this->getCustomerTier();
    }
    
    // Cache pricing calculations
    if (!isset($priceCache[$productId])) {
        $priceCache[$productId] = $this->calculateCustomPrice($data);
    }
    
    $data['price'] = $priceCache[$productId];
    $data['customer_tier'] = $customerTierCache;
    
    return $data;
}
```

### Batch Processing

```php theme={null}
public function afterPopulateProductData(ProductData $subject, array $data)
{
    // Collect product IDs for batch processing
    static $productIds = [];
    static $batchData = [];
    
    $productIds[] = $data['id'];
    
    // Process in batches of 10
    if (count($productIds) >= 10) {
        $batchData = array_merge($batchData, $this->processBatch($productIds));
        $productIds = [];
    }
    
    // Apply batch data if available
    if (isset($batchData[$data['id']])) {
        $data = array_merge($data, $batchData[$data['id']]);
    }
    
    return $data;
}
```

## Error Handling and Fallbacks

### Graceful Degradation

```php theme={null}
public function afterPopulateProductData(ProductData $subject, array $data)
{
    try {
        // Attempt custom pricing calculation
        $customPrice = $this->calculateCustomPrice($data);
        $data['price'] = $customPrice;
        
    } catch (\Exception $e) {
        // Log error but don't break recommendations
        $this->logger->error('Custom pricing failed', [
            'product_id' => $data['id'],
            'error' => $e->getMessage()
        ]);
        
        // Use fallback pricing
        $data['price'] = $this->formatPrice($data['price_raw'] ?? 0);
    }
    
    return $data;
}
```

### API Integration with Timeouts

```php theme={null}
private function getExternalData($productId)
{
    try {
        // Set timeout for external API
        $this->httpClient->setTimeout(2); // 2 second timeout
        
        $response = $this->httpClient->get("/api/product/{$productId}");
        return $response->getData();
        
    } catch (\Exception $e) {
        // Return empty array on failure
        $this->logger->warning('External API failed', [
            'product_id' => $productId,
            'error' => $e->getMessage()
        ]);
        
        return [];
    }
}
```

## Testing Server-Side Implementation

### Unit Testing Custom Data

```php theme={null}
public function testCustomDataIsAddedToProduct()
{
    // Mock dependencies
    $mockCustomerSession = $this->createMock(\Magento\Customer\Model\Session::class);
    $mockPricingHelper = $this->createMock(\MyCompany\MyModule\Helper\Pricing::class);
    
    // Create plugin instance
    $plugin = new ServersideDataPlugin($mockCustomerSession, $mockPricingHelper);
    
    // Test data
    $inputData = ['id' => 123, 'name' => 'Test Product', 'price_raw' => 29.99];
    
    // Mock the subject
    $mockSubject = $this->createMock(ProductData::class);
    
    // Execute plugin
    $result = $plugin->afterPopulateProductData($mockSubject, $inputData);
    
    // Assert custom fields are added
    $this->assertArrayHasKey('my_custom_field', $result);
    $this->assertArrayHasKey('customer_tier', $result);
}
```

### Integration Testing

```php theme={null}
public function testServersideRecommendationsDisplay()
{
    // Set up test customer with special pricing
    $customer = $this->createTestCustomer(['tier' => 'premium']);
    $this->customerSession->loginById($customer->getId());
    
    // Create test products
    $products = $this->createTestProducts(5);
    
    // Request server-side recommendations
    $response = $this->serversideProcessor->processRecommendation([
        'zone' => 'test-zone',
        'products' => array_column($products, 'id')
    ]);
    
    // Verify custom data is included
    $this->assertNotEmpty($response['products']);
    $this->assertArrayHasKey('customer_tier', $response['products'][0]);
}
```

## Related Resources

### Configuration and Setup

* [Configuration Mode](/integrations/magento/magento-2/configuration-mode) - Enabling server-side mode
* [Customer Specific Prices](/integrations/magento/magento-2/customer-specific-prices) - Pricing use cases
* [Adding Zones Using HTML](/integrations/magento/magento-2/adding-zones-html) - Server-side zone syntax

### Development Resources

* [Extending Feeds](/integrations/magento/magento-2/extending-feed) - Related data customization
* [Magento Logs](/integrations/magento/magento-2/logs) - Debugging server-side processing

### Troubleshooting

* [Zones Not Showing](/integrations/magento/magento-2/zones-not-showing) - Server-side zone issues
* [Products Not Updating](/integrations/magento/magento-2/products-not-updating) - Data synchronization problems

## Summary

Server-side mode implementation enables:

* **Custom pricing logic** with real-time calculations
* **Template customization** through Magento theme system
* **Data extension** via plugin system
* **Performance optimization** through caching and batch processing
* **Error handling** with graceful degradation

Use server-side mode when your requirements exceed the capabilities of client-side recommendations and feed-based data delivery.
