Tuesday, March 17, 2015

More Miva Merchant for Geeks: Pulling in an admin controlled template to custom MivaScript code

I've got to say, I'm thoroughly enjoying my snippet approach to Miva, whereby I can embed MivaScript code in arbitrary Miva Merchant templates. To recap, I can put code similar to the following in a Miva template:

    <mvt:item name="ads-extfile"
              param="function|/mm5/snippets/seo/title.mvc"/> 

and the MivaScript code in /mm5/snippets/seo/title.mv gets executed and the output included on the page. I can trivially maintain these snippet files using emacs, and track them in subversion.

Recently I found myself wanting to push this setup further. Specifically, I'd like to allow my customers to customize parts of the snippet content. This will make far more sense with an example.

Suppose I've got the attribute packaging type, and I want to allow shoppers to choose between Stress Free and Stress Inducing. Miva Merchant allows me to create such an attribute, but doesn't provide an easy way to include instructions for the attribute. I've got a snippet that generates the HTML for the attribute in question. What's the best way to get customized text inserted before the radio buttons associated with the attribute?

The easiest solution is to ask my client for the text and hard code it in the snippet. But this is asking for trouble, as no doubt this text will need to get tweaked over time. Furthermore, if I had a general purpose method of pulling in customized text, I'd be able to find all sorts of uses for this capability.

Not quite sure which approach take, I created a new page in Miva with the code Packaging-Type-Info. For the page's content I put some place holder text ("Sending a gift to your Mom? Choose stress free. Sending a gift to a frenemy? Select Stress Inducing!").

I confirmed that I could pick up that text by visiting:

  http://mysite.com/mm5/merchant.mvc?Screen=Packaging-Type-Info

One option then, is to embed an invocation of MvCALL in my snippet with the above URL. That's terribly inefficient though, as it means every call to my snippet will result in an additional HTTP request. I kept digging around. I finally caught a break when I realized that the template was being written out to the following .mvc file:

  /mm5/5.00/templates/s01/packaging-type-info.mvc

Now all I needed to do was to read in that .mvc file and hopefully include the contents of the template in my snippet.

My first attempt was to add the following to my snippet:

  <MvDO FILE="/mm5/5.00/templates/s01/packaging-preference-info.mvc" />

While that didn't generate an error, it also didn't include the text within the template. I looked all over the MivaScript documentation for a function that would pull in my template contents. I could find none. Luckily, I stumbled onto the docs for miva_template_compile, which actually cleared the whole situation up. Specifically, the docs contain this tidbit:

Compiled templates contain a single function Template_Render(). Execute the template by calling that function, not by executing the compile template .mvc file directly

In other words, there's no function to pull in a template because templates are self executing. Including my template file is as simple as saying:

  
 <MvASSIGN NAME="l.path" VALUE="/mm5/5.00/templates/s01/packaging-preference-info.mvc"/>
 <MvEVAL EXPR="{ [ l.path ].Template_Render(l.page, l.settings) }"/>

l.page is unset, and l.settings is passed through from the settings variable provided to the snippet.

The above is awfully close to what I want, but it still hard codes the path to the particular template. Furthermore, the snippet I'm working on is used to render all option based templates, not just the packaging one that has instructions. My final code, therefore, looks like so:

  <MvASSIGN NAME="l.info_template" VALUE="{ g.store_template_path $ tolower(l.attr:code) $ '-info.mvc' }"/>
  <MvIF EXPR="{ sexists(l.info_template) EQ 1 }">
    <div class='att-info leading'>
      <MvEVAL EXPR="{ [ l.info_template ].Template_Render(l.page, l.settings) }"/>
    </div>
  </MvIF>

g.store_template_path is that ugly path to where templates are stored on disk, and sexists() allows me to check for the existence of the template before I attempt to load it. This allows for some attributes to have info blocks and some to skip this feature.

I've now got the best of all worlds: a snippet to cleanly maintain the code of the site, and the ability to efficiently pull in arbitrary content maintained in the UI.

Now if I could just get rid of the silly dependency on the admin UI for maintaining site templates, and perhaps come up with a far terser way to write MivaScript I'd be all set. Stay tuned...

No comments:

Post a Comment