Bulk-Assigning Media Items

Setting the scenario:

You've got a new client who has a major product catalog (~1500 products) and they've sent it to you in CSV, looking something like this.

prodid;prodname;proddesc;prodnumber
01;Giant Hat;This hat only fits dwarfs;GH001V023;
02;Red Hat;This hat only fits redheads;GH002V458;

The product catalog data in CSV format

The data itself we import with CMS Import, no problems there.

Along with all this data we've also received a truckload of images, all named like this: gh001v023.png, gh002v458.png etc. You can see the filename matches the productnumber.

The problem

So usually we would have a Media Picker on the Product node to select the image for it, but that's not an option with 1500 products in the catalog... 

So instead of selecting images on all 1500 products, we just need to match up the productnumber with the urlName of the media.

When bulk uploading images to the media section they all get a @urlName according to the filename, without the extension. Pretty darn useful. But the full path to the image will contain a number that we cannot predict or lookup, e.g.: /media/1234/gh002v458.png. What to do?

We need a little magic

Fortunately, uComponents has an XSLT extension called GetMediaByUrlName() - so this exactly the kind of magic we need.

The Media XML for an image looks like this:

<Image id="4736" level="2" nodeName="GH001V023" urlName="gh001v023" nodeTypeAlias="Image">
	<umbracoFile>/media/1234/gh001v023.png</umbracoFile>
	<umbracoWidth>1200</umbracoWidth>
	<umbracoHeight>1200</umbracoHeight>
	<umbracoBytes>1643882</umbracoBytes>
	<umbracoExtension>png</umbracoExtension>
</Image>

The Media XML - note that @urlName matches the filename

And here we have the relevant XSLT:

<xsl:template match="Product">
	<!-- Lets check if productNumber contains any data,
		otherwise we give at a default value.
		Remember to have an image called 'default' -->
	<xsl:variable name="mediaUrlName">
		<xsl:choose>
			<xsl:when test="productNumber[normalize-space()]">
				<xsl:value-of select="translate(productNumber, $uppercase, $lowercase)" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="'default'" />
			</xsl:otherwise>
		</xsl:choose>
	</xsl:variable>

	<!-- Here we use the GetMediaByUrlName from uComponents
		to get the Image selected in the productNumber property.
		And in case it returns multiple items,
		we just select the first [1] -->
	<xsl:variable name="media"
		select="umedia:GetMediaByUrlName($mediaUrlName)[1]" />

	<li>
		<xsl:apply-templates select="productTitle[normalize-space()]" />

	<!-- If the media variable has any content, we apply a template to it,
		and we pass a crop mode to the CropUp extension -->
		<xsl:apply-templates select="$media[normalize-space()]" mode="media">
			<xsl:with-param name="crop" select="'150x170M'" />
		</xsl:apply-templates>
	</li>
</xsl:template>

Example of getting a product's image from its product number

I was very happy to not have to instruct someone to pick every single product's image, but yet still be able to use the Media section instead of a flat folder of images. 

You can download the complete XSLT here

Merry Christmas everyone!

Sebastian Dammark

Sebastian is on Twitter as