By default, the images shown for items on a product list page (PLP) will be whatever is the item’s default. This is fine in most cases, but what if a shopper refines by a color? Shouldn’t a search for, say, red dresses show images of red dresses, rather than just the default? This article will take you through the steps to using the extensibility API to make an extension to make that a reality. The solution for this functionality lies in both the PLPCOMPONENT and the layout component. We can use a method called addToViewContextDefinition(). When we invoke this method, we can easily pass the existing context object, which means anything the view shares with the template will automatically be available to use to manipulate. This includes the image the template is told to render

Create the Entrypoint
In JavaScript, create PLPColorImages.js. In it, put:
define('PLPColorImages'
, [
]
, function
(
)
{
'use strict';
return {
mountToApp: function mountToApp (container)
{
var PLP = container.getComponent('PLP')
, Environment = container.getComponent('Environment')
, Layout = container.getComponent('Layout')
, customColorId = Environment.getConfig('plpColorImages.customColorId') ? Environment.getConfig('plpColorImages.customColorId') : '';
if (customColorId)
{
Layout.addToViewContextDefinition('Facets.ItemCell.View', 'thumbnail', 'string', function thumbnail (context)
{
var model = _.find(PLP.getItemsInfo(), function (item)
{
return item.internalid == context.itemId
})
, thumbnail = context.thumbnail
, images = model.itemimages_detail ? model.itemimages_detail : ''
, filters = _.find(PLP.getFilters(), function (filter)
{
return filter.id == customColorId
});
// Note the `media` property/object is due to how my test account handles image naming -- this may be different on your site
if (images && images.media && filters && filters.value[0] && images.media[filters.value[0]])
{
_.each(filters.value, function (filter)
{
if (images.media[filter] && images.media[filter].urls)
{
thumbnail = images.media[filter].urls[0]
}
});
}
return thumbnail
});
Layout.addToViewContextDefinition('Facets.ItemCell.View', 'url', 'string', function url (context)
{
var model = _.find(PLP.getItemsInfo(), function (item)
{
return item.internalid == context.itemId
})
, filters = _.find(PLP.getFilters(), function (filter)
{
return filter.id == customColorId
})
, existingUrl = context.url
, fields = model.itemoptions_detail ? model.itemoptions_detail.fields : ''
, fieldColors = fields ? _.find(fields, function (option)
{
return option.sourcefrom == customColorId
}) : ''
, fieldColorValues = fieldColors ? fieldColors.values : '';
if (fieldColorValues && filters && filters.value[0])
{
var url = '';
_.each(filters.value, function (filter)
{
if (!url)
{
url = _.find(fieldColorValues, function (value)
{
return value.label == filter
})
}
});
/* If you want to match the behavior of the above images, then you could implement something like this (this way the URL colors match the color of the thumbnails)
_.each(fieldColorValues, function (value)
{
_.each(filters.value, function (filter)
{
if (value.label == filter)
{
url = value
}
})
});
*/
if (url) {return url.url}
}
else {return existingUrl}
});
}
}
}
});
As the name suggests, what this method does it lets us modify the context object of a view without having to rely on traditional customization methods (ie, wrapping the view’s prototype, adding your value and returning it back). While it’s available on visual components, its scope is limited. Specifically, ones on the PDP and PLP, for example, are restricted to its immediate child views; unfortunately for us, this does not include the specific view we want to tangle with: Facets.ItemCell.View. Luckily for us, the layout component allows us to modify any view we like. So we’re just going to use that instead 🤷🏻♂️.
Take a look at how we’re using it in our code .
Layout.addToViewContextDefinition('Facets.ItemCell.View', 'thumbnail', 'string', function thumbnail (context)
{
...
});
We’re passing it four things:
- The view we want to tinker with
- The property we want to add (or overwrite if it exists already)
- The type of value our function (callback) is going to return
- The function or callback itself — note that it is called with the existing context object as an argument (super handy)
Whatever the function returns will be set as the value for the specified property. In our example, we know that the context object already has a thumbnail property, so by using this method we know that we’re going to overwrite it with whatever we return in our function.
Change the URL
You know what would be cool? If we could set the URL so that when a shopper visits the PDP for an item it automatically selects the color options that they filtered by. Well, it just so happens that we expose these URLs to the item models in the itemoptions_detail property on each item’s model. So, having written some code that goes through the model and matches them based on color options, can we do the same thing with this? Sure can!
Add the following code to the file, within the mountToApp method:
Layout.addToViewContextDefinition('Facets.ItemCell.View', 'url', 'string', function url (context)
{
var model = _.find(PLP.getItemsInfo(), function (item)
{
return item.internalid == context.itemId
})
, filters = _.find(PLP.getFilters(), function (filter)
{
return filter.id == customColorId
})
, existingUrl = context.url
, fields = model.itemoptions_detail ? model.itemoptions_detail.fields : ''
, fieldColors = fields ? _.find(fields, function (option)
{
return option.sourcefrom == customColorId
}) : ''
, fieldColorValues = fieldColors ? fieldColors.values : '';
if (fieldColorValues && filters && filters.value[0])
{
var url = '';
_.each(filters.value, function (filter)
{
if (!url)
{
url = _.find(fieldColorValues, function (value)
{
return value.label == filter
})
}
});
if (url)
{
return url.url
}
}
else
{
return existingUrl
}
});
In the above code, it’s perhaps obvious that you probably shouldn’t mix and match these like I have. At the moment, my site will show an orange shirt and then send the shopper to a PDP with blue pre-selected: so pick one and stick with it! For example, if you want to have your URLs link to the last color (ie what we currently have for the image), you can do something simple like this:
_.each(fieldColorValues, function (value)
{
_.each(filters.value, function (filter)
{
if (value.label == filter)
{
url = value
}
})
});