Skip to content

Instantly share code, notes, and snippets.

@steveosoule
Last active May 11, 2020 23:53
Show Gist options
  • Save steveosoule/665741fbcd02c9e53cdc to your computer and use it in GitHub Desktop.
Save steveosoule/665741fbcd02c9e53cdc to your computer and use it in GitHub Desktop.
Miva - Category Page Multi-Add Example

Miva - Multi-Add Category Page Example

Note: Attribute Machine currently does not work with Multi-Add


The only thing that is required for the Multi-Add is the input name changes within the Example Category Product List and Example Product Attribute files. Everything else is just to show a completed category page.


Setup Example:

Create a new Multi-Add category page within Miva.

Create a copy of your CTGY page. You could call it, "CTGY_MULTI". Assign all of items that CTGY has to CTGY_MULTI, and transfer all of the page template code from CTGY to CTGY_MULTI as well.

Here are some example items, templates, and settings I ended up migrating:

Items

Code Module
affiliatelink CSSUI Affiliate Sign-in Link
breadcrumbs CSSUI Smart Breadcrumbs
buttons CSSUI Buttons
category Standard Category Fields
category_listing CSSUI Product List
category_listing_imagemachine Image Machine
category_title CSSUI Category Title
category_tree CSSUI Category Tree
cssui_links CSSUI Links
customerlink CSSUI Customer Sign-in Link
ga_jsencode Google Analytics
ga_tracking Google Analytics
global_minibasket Mini-Basket
hdft CSSUI Headers & Footers
head CSSUI HEAD Tag Content/CSS
html_profile CSSUI HTML Profile
navbar CSSUI Navigation Bar
prodctgy_meta Product/Category META-Tag Settings
product Standard Product Fields
product_attributes CSSUI Product Attributes
prod_ctgy_hdft CSSUI Product/Category Header & Footer
readytheme ReadyTheme
store Standard Store Fields
tokenlist Token List

Category Image Machine

Category Image Machine Settings

Notes

ADPM Products Structure

Products[]:code                          Required
Products[]:quantity                      Required if you want to add the product
Products[]:attributes[]:code             Required if the product has attributes
Products[]:attributes[]:template_code    Required if the attribute is from an attribute-template
Products[]:attributes[]:value            Required if the attribute is required
Products[]:subterm_id                    Required if the product can only be purchased with subscriptions

Example HTML Form

<input type="hidden" name="Products[1]:code"                        value="prod-abc">
<input type="hidden" name="Products[1]:quantity"                    value="1">
<input type="hidden" name="Products[1]:attributes[1]:code"          value="size">
<input type="hidden" name="Products[1]:attributes[1]:template_code" value="size-template">
<input type="hidden" name="Products[1]:attributes[1]:value"         value="small">
<input type="hidden" name="Products[1]:attributes[2]:code"          value="color">
<input type="hidden" name="Products[1]:attributes[2]:template_code" value="color-template">
<input type="hidden" name="Products[1]:attributes[2]:value"         value="red">
<input type="hidden" name="Products[1]:subterm_id"                  value="123">

Example Template Code

<form action="&mvte:urls:BASK:auto;">
	<input type="hidden" name="Action" value="ADPM">
	<mvt:foreach iterator="product" array="category_listing:products">
		<input type="hidden" name="Products[<mvt:eval expr="l.pos1"/>]:code" value="&mvte:product:code;">
		<input type="number" name="Products[<mvt:eval expr="l.pos1"/>]:quantity" value="1">

		<mvt:comment><!-- Attributes --></mvt:comment>
		<mvt:foreach iterator="attribute" array="product:attributes">
			<div>
				<input type="hidden" name="Products[<mvt:eval expr="l.pos1"/>]:attributes[<mvt:eval expr="l.pos2"/>]:code" value="&mvte:attribute:code;" />
				<mvt:if expr="l.settings:attribute:template_code NE 0">
					<input type="hidden" name="Products[<mvt:eval expr="l.pos1"/>]:attributes[<mvt:eval expr="l.pos2"/>]:template_code" value="&mvte:attribute:template_code;" />
				</mvt:if>
				&mvt:attribute:prompt;
				<mvt:if expr="l.settings:attribute:type EQ 'text'">
					<input type="text" name="Products[<mvt:eval expr="l.pos1"/>]:attributes[<mvt:eval expr="l.pos2"/>]:value" value="&mvte:attribute:value;" class="textfield" />
				<mvt:elseif expr="l.settings:attribute:type EQ 'memo'">
					<textarea name="Products[<mvt:eval expr="l.pos1"/>]:attributes[<mvt:eval expr="l.pos2"/>]:value">&mvte:attribute:value;</textarea>
				<mvt:elseif expr="l.settings:attribute:type EQ 'radio'">
					<mvt:foreach iterator="option" array="attribute:options">
						<label>
							<input type="radio" name="Products[<mvt:eval expr="l.pos1"/>]:attributes[<mvt:eval expr="l.pos2"/>]:value" value="&mvte:option:code;" />
							&mvte:option:prompt;
						</label>
					</mvt:foreach>
				<mvt:elseif expr="( l.settings:attribute:type EQ 'select' ) OR ( l.settings:attribute:type EQ 'swatch-select' )">
					<select name="Products[<mvt:eval expr="l.pos1"/>]:attributes[<mvt:eval expr="l.pos2"/>]:value">
						<mvt:foreach iterator="option" array="attribute:options">
							<option value="&mvte:option:code;">&mvte:option:prompt;</option>
						</mvt:foreach>
					</select>
				<mvt:elseif expr="l.settings:attribute:type EQ 'checkbox'">
					<label>
						<input type="checkbox" name="Products[<mvt:eval expr="l.pos1"/>]:attributes[<mvt:eval expr="l.pos2"/>]:value" />
						&mvt:attribute:prompt;
					</label>
				</mvt:if>
			</div>
		</mvt:foreach>

		<mvt:comment><!-- Subscriptions --></mvt:comment>
		<mvt:if expr="l.settings:subscription:enabled AND l.settings:subscription:term_count">
			<label>Select Subscription</label>
			<select name="Products[<mvt:eval expr="l.pos1"/>]:subterm_id">
				<option value="0">One Time Purchase</option>
				<mvt:foreach iterator="term" array="subscription:terms">
					<option value="&mvte:term:id;">&mvte:term:descrip;</option>
				</mvt:foreach>
			</select>
		</mvt:if>
	</mvt:foreach>
	<button>Add to Basket</button>
</form>
<div class="expanded"><div id="filter-items-container"><mvt:if expr="l.settings:category_listing:products_on_page_count GT 1">
<div class="sorting">
<form method="get" action="&mvte:global:sessionurl;">
<input type="hidden" name="Screen" value="&mvte:global:Screen;" />
<input type="hidden" name="Store_Code" value="&mvte:global:Store_Code;" />
<input type="hidden" name="Category_Code" value="&mvte:global:Category_Code;" />
<input type="hidden" name="Product_Code" value="&mvte:global:Product_Code;" />
<input type="hidden" name="Search" value="&mvte:global:Search;" />
<input type="hidden" name="Per_Page" value="&mvte:global:Per_Page;" />
<label for="Sort_By">Sort By:</label>
<select name="Sort_By" id="Sort_By" onchange="this.form.submit();">
<mvt:if expr="ISNULL g.Sort_By">
<option value="disp_order" selected="selected">Default</option>
<mvt:else>
<option value="disp_order">Default</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'name_asc'">
<option value="name_asc" selected="selected">Name Ascending</option>
<mvt:else>
<option value="name_asc">Name Ascending</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'name_desc'">
<option value="name_desc" selected="selected">Name Descending</option>
<mvt:else>
<option value="name_desc">Name Descending</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'code_asc'">
<option value="code_asc" selected="selected">Code Ascending</option>
<mvt:else>
<option value="code_asc">Code Ascending</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'code_desc'">
<option value="code_desc" selected="selected">Code Descending</option>
<mvt:else>
<option value="code_desc">Code Descending</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'bestsellers'">
<option value="bestsellers" selected="selected">Best Selling</option>
<mvt:else>
<option value="bestsellers">Best Selling</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'price_asc'">
<option value="price_asc" selected="selected">Lowest Price</option>
<mvt:else>
<option value="price_asc">Lowest Price</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'price_desc'">
<option value="price_desc" selected="selected">Highest Price</option>
<mvt:else>
<option value="price_desc">Highest Price</option>
</mvt:if>
<mvt:if expr="g.Sort_By EQ 'newest'">
<option value="newest" selected="selected">Newest Items</option>
<mvt:else>
<option value="newest">Newest Items</option>
</mvt:if>
</select>
<noscript><input type="submit" value="go"></noscript>
</form>
</div></mvt:if><mvt:if expr="l.settings:category_listing:products_on_page_count GT 1">
<div class="per-page">
<form method="get" action="&mvte:global:sessionurl;">
<input type="hidden" name="Screen" value="&mvte:global:Screen;" />
<input type="hidden" name="Store_Code" value="&mvte:global:Store_Code;" />
<input type="hidden" name="Category_Code" value="&mvte:global:Category_Code;" />
<input type="hidden" name="Product_Code" value="&mvte:global:Product_Code;" />
<input type="hidden" name="Search" value="&mvte:global:Search;" />
<input type="hidden" name="Sort_By" value="&mvte:global:Sort_By;" />
<label for="Per_Page">View:</label>
<select name="Per_Page" id="Per_Page" onchange="this.form.submit();">
<mvt:if expr="g.Per_Page EQ 10">
<option value="10" selected="selected">10</option>
<mvt:else>
<option value="10">10</option>
</mvt:if>
<mvt:if expr="g.Per_Page EQ 20">
<option value="20" selected="selected">20</option>
<mvt:else>
<option value="20">20</option>
</mvt:if>
<mvt:if expr="g.Per_Page EQ 40">
<option value="40" selected="selected">40</option>
<mvt:else>
<option value="40">40</option>
</mvt:if>
<mvt:if expr="g.Per_Page EQ -1">
<option value="-1" selected="selected">All</option>
<mvt:else>
<option value="-1">All</option>
</mvt:if>
</select>
<noscript><input type="submit" value="go"></noscript>
</form>
</div></mvt:if>
<mvt:if expr="l.settings:category_listing:page_links:last_page GT 1">
<div class="page-links">
<span class="page-links-title">Page(s):</span>
<span class="page-links-container">
<mvt:if expr="l.settings:category_listing:page_links:current_page NE 1">
<a href="&mvte:category_listing:page_links:prev_link;" class="page-links-previous">&lt;</a>
<mvt:else>
<span class="page-links-previous page-links-deactivated">&lt;</span>
</mvt:if>
<mvt:if expr="l.settings:category_listing:page_links:current_page NE l.settings:category_listing:page_links:last_page">
<a href="&mvte:category_listing:page_links:next_link;" class="page-links-next">&gt;</a>
<mvt:else>
<span class="page-links-next page-links-deactivated">&gt;</span>
</mvt:if>
<span class="page-disp">
<mvt:if expr="NOT l.settings:category_listing:page_links:contains_first">
<a href="&mvte:category_listing:page_links:first_link;" class="page-links-inactive">1</a>...
</mvt:if>
<mvt:foreach iterator="pages" array="category_listing:page_links:pages">
<mvt:if expr="l.settings:category_listing:page_links:current_page EQ l.settings:pages:page_num">
<span class="page-links-active">&mvte:pages:page_num;</span>
<mvt:else>
<a href="&mvte:pages:link;" class="page-links-inactive">&mvte:pages:page_num;</a>
</mvt:if>
</mvt:foreach>
<mvt:if expr="NOT l.settings:category_listing:page_links:contains_last">
...<a href="&mvte:category_listing:page_links:last_link;" class="page-links-inactive">&mvte:category_listing:page_links:last_page;</a>
</mvt:if>
</span>
</span>
</div>
</mvt:if>
</div>
<div class="clear"></div>
<form method="post" action="&mvte:global:sessionurl;Screen=BASK">
<input type="hidden" name="Action" value="ADPM">
<input type="hidden" name="Attributes" value="Yes">
<input type="hidden" name="Store_Code" value="&mvte:store:code;">
<mvt:item name="buttons" param="AddToBasketE" />
<hr>
<div class="clear"></div>
<mvt:foreach iterator="product" array="category_listing:products">
<div class="product-item" style="width:50%">
<div class="padding">
<div class="product-details">
<div class="product-image">
<mvt:if expr="NOT ISNULL l.settings:product:imagetypes:main">
<a href="&mvte:product:link;">
<img src="&mvte:product:imagetypes:main;" alt="&mvte:product:name;" id="main_image_&mvte:product:id;" />
</a>
<mvt:else>
<a class="image-not-available" href="&mvte:product:link;" title="&mvte:product:name;">
<img id="main_image_&mvte:product:id;" src="graphics/en-US/cssui/blank.gif" alt="&mvte:product:name;" />
</a>
</mvt:if>
</div>
<ul id="thumbnails_&mvte:product:id;" class="thumbnails"></ul>
<div id="closeup_div_&mvte:product:id;" class="closeup">
<img id="closeup_image_&mvte:product:id;" src="graphics/en-US/cssui/blank.gif" alt="&mvte:product:name;">
<div>
<a id="closeup_close_&mvte:product:id;">close</a>
</div>
</div>
<div class="product-name"><a href="&mvte:product:link;">&mvt:product:name;</a></div>
<div class="product-code">Code: <span class="bold">&mvt:product:code;</span></div>
<div class="product-code">SKU: <span class="bold">&mvt:product:sku;</span></div>
<div class="product-price">
Price:
<span style="text-decoration: line-through" id="price-value-additional_&mvte:product:id;">
<mvt:if expr="l.settings:product:base_price GT l.settings:product:price">
&mvt:product:formatted_base_price;
</mvt:if>
</span>
<span class="bold" id="price-value_&mvte:product:id;">&mvt:product:formatted_price;</span>
<div id="product-discounts_&mvte:product:id;">
<mvt:foreach iterator="discount" array="product:discounts">
<div class="product-discount">&mvt:discount:descrip;: &mvt:discount:formatted_discount;</div>
</mvt:foreach>
</div>
</div>
<mvt:if expr="l.settings:product:weight NE 0">
<div class="product-weight">Weight: <span class="bold">&mvt:product:weight;</span></div>
</mvt:if>
<div id="inventory-message_&mvte:product:id;"><mvt:if expr="l.settings:product:inv_active">&mvt:product:inv_long;<br></mvt:if></div>
<div class="product-quantity">
Quantity in Basket:
<mvt:if expr="l.settings:product:quantity EQ 0">
<span class="italic">none</span>
<mvt:else>
<span class="italic">&mvt:product:quantity;</span>
</mvt:if>
</div>
</div>
<mvt:if expr="l.settings:product:inv_level NE 'out'">
<div class="purchase-buttons">
<ul id="swatches_&mvte:product:id;" class="swatches"></ul>
<input type="hidden" name="Products[ &mvt:product:id; ]:code" value="&mvte:product:code;" />
<mvt:item name="product_attributes" param="product:id" />
</div>
<b>Quantity:</b> <input type="text" name="Products[ &mvt:product:id; ]:quantity" value="1" size="2" />
</mvt:if>
<mvt:item name="category_listing_imagemachine" param="body:product:id" />
</div>
</div>
</mvt:foreach>
<div class="clear"></div>
<hr>
<mvt:item name="buttons" param="AddToBasketE" />
</form>
<mvt:if expr="NOT l.settings:category_listing:page_disp_count GT 0">
<mvt:if expr="g.CatListingOffset OR g.CatListingNextOffset">
<div class="next-previous">
<mvt:if expr="g.CatListingOffset GT 0">
<div class="previous-button">
<form method="post" action="&mvte:global:sessionurl;">
<input type="hidden" name="Screen" value="&mvte:global:Screen;" />
<input type="hidden" name="Store_Code" value="&mvte:global:Store_Code;" />
<input type="hidden" name="Category_Code" value="&mvte:global:Category_Code;" />
<input type="hidden" name="Product_Code" value="&mvte:global:Product_Code;" />
<input type="hidden" name="Search" value="&mvte:global:Search;" />
<input type="hidden" name="Per_Page" value="&mvte:global:Per_Page;" />
<input type="hidden" name="Sort_By" value="&mvte:global:Sort_By;" />
<input type="hidden" name="Offset" value = "&mvte:global:CatListingPrevOffset;" />
<input type="hidden" name="AllOffset" value = "&mvte:global:AllOffset;" />
<input type="hidden" name="CatListingOffset" value = "&mvte:global:CatListingPrevOffset;" />
<input type="hidden" name="RelatedOffset" value = "&mvte:global:RelatedOffset;" />
<input type="hidden" name="SearchOffset" value = "&mvte:global:SearchOffset;" />
<mvt:item name="buttons" param="Previous" />
</form>
</div>
</mvt:if>
<mvt:if expr="g.CatListingNextOffset GT 0">
<div class="next-button">
<form method="post" action="&mvte:global:sessionurl;">
<input type="hidden" name="Screen" value="&mvte:global:Screen;" />
<input type="hidden" name="Store_Code" value="&mvte:global:Store_Code;" />
<input type="hidden" name="Category_Code" value="&mvte:global:Category_Code;" />
<input type="hidden" name="Product_Code" value="&mvte:global:Product_Code;" />
<input type="hidden" name="Search" value="&mvte:global:Search;" />
<input type="hidden" name="Per_Page" value="&mvte:global:Per_Page;" />
<input type="hidden" name="Sort_By" value="&mvte:global:Sort_By;" />
<input type="hidden" name="Offset" value = "&mvte:global:CatListingNextOffset;" />
<input type="hidden" name="AllOffset" value = "&mvte:global:AllOffset;" />
<input type="hidden" name="CatListingOffset" value = "&mvte:global:CatListingNextOffset;" />
<input type="hidden" name="RelatedOffset" value = "&mvte:global:RelatedOffset;" />
<input type="hidden" name="SearchOffset" value = "&mvte:global:SearchOffset;" />
<mvt:item name="buttons" param="Next" />
</form>
</div>
</mvt:if>
</div>
</mvt:if>
</mvt:if>
</div>
<mvt:item name="html_profile" />
<head>
<title>&mvt:store:name;: &mvt:category:name;</title>
<base href="&mvt:global:basehref;" />
<mvt:item name="prodctgy_meta" param="ctgy" />
<mvt:item name="head" param="css_list" />
<mvt:item name="head" param="head_tag" />
<mvt:item name="category_listing_imagemachine" param="head" />
</head>
<body class="CTGY">
<div id="site-container">
<div id="global-header"><mvt:item name="hdft" param="global_header" /></div>
<div id="navigation-bar"><mvt:item name="navbar" /></div>
<table id="content-container">
<tr>
<td id="left-navigation"><mvt:item name="category_tree" /></td>
<td id="main-content">
<div id="page-header"><mvt:item name="hdft" param="header" /></div>
<div id="breadcrumbs"><mvt:item name="breadcrumbs" /></div>
<div id="category-header"><mvt:item name="prod_ctgy_hdft" param="ctgy_header" /></div>
<mvt:if expr="NOT ISNULL l.settings:category_title:image">
<img src="&mvte:category_title:image;" alt="&mvte:category:name;" />
<mvt:else>
<h1>&mvte:category:name;</h1>
</mvt:if>
<div id="category-listing"><mvt:item name="category_listing" /></div>
<div id="category-footer"><mvt:item name="prod_ctgy_hdft" param="ctgy_footer" /></div>
<div id="page-footer"><mvt:item name="hdft" param="footer" /></div>
</td>
</tr>
</table>
<div id="bottom-wrap"></div>
<div id="global-footer"><mvt:item name="hdft" param="global_footer" /></div>
</div>
</body>
</html>
<table>
<mvt:foreach iterator="attribute" array="attributes">
<tr>
<td class="prompt">
<input type="hidden" name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:code" value="&mvte:attribute:code;" />
<mvt:if expr="l.settings:attribute:template_code NE 0">
<input type="hidden" name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:template_code" value="&mvte:attribute:template_code;" />
</mvt:if>
<mvt:if expr="l.settings:attribute:type NE 'checkbox'">
<mvt:if expr="l.settings:attribute:image">
<img src="&mvte:attribute:image;" alt="&mvte:attribute:raw_prompt;" />
<mvt:else>
<mvt:if expr="l.settings:attribute:required">
<span class="required">
<mvt:else>
<span>
</mvt:if>
&mvt:attribute:prompt;
</span>
</mvt:if>
<mvt:else>
&nbsp;
</mvt:if>
</td>
<td class="field">
<mvt:if expr="l.settings:attribute:type EQ 'text'">
<input type="text" name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:value" value="&mvte:attribute:value;" class="textfield" />
<mvt:elseif expr="l.settings:attribute:type EQ 'memo'">
<textarea name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:value">&mvte:attribute:value;</textarea>
<mvt:elseif expr="l.settings:attribute:type EQ 'radio'">
<mvt:foreach iterator="option" array="attribute:options">
<div>
<mvt:if expr="( ( g.Products[l.settings:product:id]:attributes[l.settings:attribute:index]:value EQ 0 ) AND
( l.settings:option:id EQ l.settings:attribute:default_id ) ) OR
( g.Products[l.settings:product:id]:attributes[l.settings:attribute:index]:value EQ l.settings:option:code )">
<input type="radio" name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:value" value="&mvte:option:code;" checked />
<mvt:else>
<input type="radio" name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:value" value="&mvte:option:code;" />
</mvt:if>
<mvt:if expr="l.settings:option:image">
<img src="&mvte:option:image;" alt="&mvte:option:prompt;" />
<mvt:else>
&mvte:option:prompt;
</mvt:if>
</div>
</mvt:foreach>
<mvt:elseif expr="( l.settings:attribute:type EQ 'select' ) OR ( l.settings:attribute:type EQ 'swatch-select' )">
<select name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:value">
<mvt:foreach iterator="option" array="attribute:options">
<mvt:if expr="( ( g.Products[l.settings:product:id]:attributes[l.settings:attribute:index]:value EQ 0 ) AND ( l.settings:option:id EQ l.settings:attribute:default_id ) ) OR
( g.Products[l.settings:product:id]:attributes[l.settings:attribute:index]:value EQ l.settings:option:code )">
<option value="&mvte:option:code;" selected>&mvte:option:prompt;</option>
<mvt:else>
<option value="&mvte:option:code;">&mvte:option:prompt;</option>
</mvt:if>
</mvt:foreach>
</select>
<mvt:elseif expr="l.settings:attribute:type EQ 'checkbox'">
<mvt:if expr="g.Products[l.settings:product:id]:attributes[l.settings:attribute:index]:value">
<input type="checkbox" name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:value" value="Yes" checked />
<mvt:else>
<input type="checkbox" name="Products[ &mvt:product:id; ]:attributes[ &mvt:attribute:index; ]:value" />
</mvt:if>
<mvt:if expr="l.settings:attribute:image">
<img src="&mvte:attribute:image;" alt="&mvte:attribute:raw_prompt;" />
<mvt:else>
<mvt:if expr="l.settings:attribute:required">
<span class="required">
<mvt:else>
<span>
</mvt:if>
&mvt:attribute:prompt;
</span>
</mvt:if>
</mvt:if>
</td>
</tr>
</mvt:foreach>
</table>
<mvt:if expr="l.settings:subscription:enabled AND l.settings:subscription:term_count">
<label>Select Subscription</label>
<select name="Products[<mvt:eval expr="l.pos1"/>]:subterm_id">
<option value="0">One Time Purchase</option>
<mvt:foreach iterator="term" array="subscription:terms">
<option value="&mvte:term:id;">&mvte:term:descrip;</option>
</mvt:foreach>
</select>
</mvt:if>
<div class="clear"></div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment