Ankit Agarwal
+1
Jun 2, 2026
visibility 308
star star star star star
(0 votes)

Creating Read-Only Calculated Fields in Optimizely Commerce 14

Introduction

In many Optimizely Commerce projects, product information comes from external systems such as ERPs, PIMs, inventory management systems, or custom business services. While editors need visibility into this information, they should not always be allowed to modify it.

Examples include:

  • ERP Product ID

  • Total Inventory Across Warehouses

  • Last Inventory Sync Date

  • Product Popularity Score

  • Margin Percentage

  • Number of Active Variants

A common requirement is to display these values within the Commerce editor interface while preventing accidental edits.

In this blog post, we'll explore how to create a read-only Commerce property in Optimizely Commerce 14 that displays calculated or external data to editors.


The Problem

Consider a product that exists in an ERP system.

Editors manage product content within Optimizely, but the ERP SKU is controlled by the ERP and should never be modified manually.

A typical implementation might look like this:

public virtual string ErpProductId { get; set; }

Unfortunately, this renders an editable textbox in the CMS editor.

This creates several issues:

  • Editors may accidentally overwrite values.

  • Data can become inconsistent with external systems.

  • Additional validation becomes necessary.

A better approach is to display the value as read-only.


Creating a Read-Only Property

First, add the property to your product content type.

[Display(
    Name = "ERP Product ID",
    GroupName = SystemTabNames.Content,
    Order = 100)]
[Editable(false)]
public virtual string ErpProductId { get; set; }

The Editable(false) attribute indicates that the property should not be editable within the editor interface.

However, depending on the editor component being used, additional customization may be required.


Creating a Custom Editor Descriptor

To ensure a consistent read-only experience, create a custom Editor Descriptor.

using EPiServer.Shell.ObjectEditing;
using EPiServer.Shell.ObjectEditing.EditorDescriptors;

[EditorDescriptorRegistration(
    TargetType = typeof(string),
    UIHint = "ReadOnlyText")]
public class ReadOnlyTextEditorDescriptor : EditorDescriptor
{
    public override void ModifyMetadata(
        ExtendedMetadata metadata,
        IEnumerable<Attribute> attributes)
    {
        base.ModifyMetadata(metadata, attributes);

        metadata.IsReadOnly = true;
    }
}

This descriptor forces the editor field into read-only mode.


Applying the UI Hint

Now update the product property.

[Display(
    Name = "ERP Product ID",
    Order = 100)]
[UIHint("ReadOnlyText")]
public virtual string ErpProductId { get; set; }

When editors open the product, they can see the value but cannot change it.


Populating the Value Dynamically

In many scenarios, the value should be calculated rather than stored.

For example, displaying total inventory across all warehouses.

Create a service:

public interface IInventorySummaryService
{
    int GetTotalInventory(string sku);
}

Implementation:

public class InventorySummaryService :
    IInventorySummaryService
{
    private readonly IInventoryService _inventoryService;

    public InventorySummaryService(
        IInventoryService inventoryService)
    {
        _inventoryService = inventoryService;
    }

    public int GetTotalInventory(string sku)
    {
        var records =
            _inventoryService.QueryByEntry(
                new CatalogKey(sku));

        return records.Sum(x => x.PurchaseAvailableQuantity);
    }
}

Displaying Calculated Information

A useful pattern is to expose calculated information through a backing property.

[Display(
    Name = "Total Inventory",
    Order = 200)]
[UIHint("ReadOnlyText")]
public virtual string TotalInventoryDisplay
{
    get
    {
        return CalculateInventory().ToString();
    }
}

This allows editors to view business-critical information directly from the product editor.


Additional Use Cases

1. Number of Variants

Display how many variants belong to a product.

public virtual string VariantCount
{
    get
    {
        return GetVariantCount().ToString();
    }
}

2. Last ERP Synchronization

public virtual DateTime LastErpSyncDate
{
    get; set;
}

Displayed as read-only so editors know when data was last refreshed.


3. Product Popularity Score

public virtual decimal PopularityScore
{
    get; set;
}

Generated from analytics and displayed for editorial insight.


4. Margin Percentage

public virtual decimal MarginPercentage
{
    get; set;
}

Calculated from pricing and cost information.


Improving the Editor Experience

For even better usability, consider placing these properties into a dedicated tab.

[Display(
    Name = "ERP Product ID",
    GroupName = "System Information",
    Order = 10)]

Example editor layout:

System Information

  • ERP Product ID

  • Last ERP Sync Date

  • Total Inventory

  • Active Variants

  • Popularity Score

This creates a clean separation between editable content and system-generated information.


Benefits

Implementing read-only properties provides several advantages:

  • Prevents accidental data modification

  • Improves editor confidence

  • Exposes useful business information

  • Reduces validation requirements

  • Keeps external systems as the source of truth

  • Creates a cleaner editing experience


Conclusion

Not every piece of information in Optimizely Commerce should be editable. In many enterprise Commerce implementations, valuable product data originates from external systems and should only be displayed to editors.

By combining content properties, custom editor descriptors, and calculated values, you can create a richer editing experience while ensuring data integrity.

This small customization is easy to implement but can significantly improve the usability and reliability of your Commerce solution.

Jun 02, 2026

Comments

error Please login to comment.
Latest blogs
Optimizely Commerce 14 Now Supports .NET 10

In my previous post, Optimizely CMS 12 Now Fully Supports .NET 10 , I noted one remaining limitation: Commerce 14 (Commerce Connect) did not yet...

Bien Nguyen | Aug 7, 2026

The Top 10 Things I'm Actually Using AI For

A while back I wrote about ReviewPR, an Azure Function that uses AI to review Azure DevOps pull requests. That was one specific use case, but over...

KennyG | Aug 5, 2026

Drag-and-Drop Reordering for Commerce Media Collection in Optimizely Commerce Connect

Optimizely Commerce Connect ships a polished asset editor for the CommerceMediaCollection  property on catalog entries. It lets editors add, remove...

Linh Doan Cuu | Aug 5, 2026

Order tabs with drag and drop V2

I earlier did a very simple Blazor version to be able to sort tabs with drag and drop. I wanted to update it a bit and also display how the tabs ar...

Per Nergård (MVP) | Aug 4, 2026