Thursday, May 21, 2015

Miva Merchant: Accessing custom fields from mivascript snippets

Miva Merchant has core support for custom fields on both products and categories. In their latest documentation, they provide a clean API for accessing these fields. Recently I wanted to do something similar, but I needed to do so via MivaScript and my snippet framework. It took a bit of fiddling, but in the end it wasn't especially difficult.

First, I defined a series of helper functions that call the low level Miva related custom field functions:

<MvComment>
  lib.mv -- Work with custom fields 
</MvComment>

<MvFUNCTION NAME="product_custom_field" PARAMETERS="field_name" STANDARDOUTPUTLEVEL="html, text">
  <MvASSIGN NAME="l.null" VALUE="{ [ cf_mod_path() ].Read_Product_Code(l.module, l.param, g.product_code, l.field_name, l.result) }"/>
  <MvFUNCTIONRETURN VALUE="{ l.result }"/>
</MvFUNCTION>

<MvFUNCTION NAME="category_custom_field" PARAMETERS="field_name" STANDARDOUTPUTLEVEL="">
  <MvASSIGN NAME="l.null" VALUE="{ [ cf_mod_path() ].Read_Category_Code(l.module, l.param, g.category_code, l.field_name, l.result) }"/>
  <MvFUNCTIONRETURN VALUE="{ l.result }"/>
</MvFUNCTION>

<MvFUNCTION NAME="cf_mod_path" STANDARDOUTPUTLEVEL="">
  <MvFUNCTIONRETURN VALUE="/mm5/5.00/modules/util/customfld.mvc"/>
</MvFUNCTION>

Note above that I'm leveraging g.product_code and g.category_code. These allow me to call product_custom_field and category_custom_field and have it assume I want the field from the currently active product or category.

Also note the use of l.null above. That turned out to be an interesting hiccup to overcome: I needed to call functions like Read_Product_Code and access their return value via a parameter. I originally thought MvEVAL was the way go, but ultimately I realized that calling MvASSIGN and discarding the assigned variable was in fact the proper approach. Using MvEVAL generated output to the page I didn't want.

Once I had these functions defined, I could import them and use them from any of my snippets. For example, here's code that checks for a custom field: seonoindex and if it's set, sets the ROBOTS meta tag appropriately:

<MvINCLUDE FILE='lib/lib.mv'>

<MvFUNCTION NAME = "ADS_External_File" PARAMETERS = "module var, item, all_settings var, settings var, ignored" STANDARDOUTPUTLEVEL = "text, html, compresswhitespace">

  <MvASSIGN NAME="l.follow" VALUE="FOLLOW"/>
  <MvASSIGN NAME="l.index"  VALUE="INDEX"/>
  <MvASSIGN NAME="l.cause"  VALUE="default"/>

  <MvIF EXPR="{ product_custom_field('seonoindex') NE '' }">
    <MvASSIGN NAME="l.index"  VALUE="NOINDEX"/>
    <MvASSIGN NAME="l.cause"  VALUE="prod-seonoindex"/>
  </MvIF>

  <MvIF EXPR="{ category_custom_field('seonoindex') NE '' }">
    <MvASSIGN NAME="l.index"  VALUE="NOINDEX"/>
    <MvASSIGN NAME="l.cause"  VALUE="cat-seonoindex"/>
  </MvIF>

  <MvEVAL EXPR="{'<meta ' $ A('name', 'ROBOTS') $ ' ' $ A('content', l.index $ ',' $ l.follow) $ ' ' $ A('cause', l.cause) $ '/>' }"/>
</MvFUNCTION>

The above code is convenient because it operates at both the product and category level. Meaning, you can mark a whole group of products NOINDEX by simply checking off the relevant custom field at the category level.

No comments:

Post a Comment