Show/hide entire product select template for product variations

I want to show a select dropdown for product variations, but only if there are any in the first place. So I’ve looked at this part of the docs under “Showing product variations”, but in my case I want to hide the entire div containing the select input if there is only one product:

[[!commerce.get_products? 
   &products=`[[+tv.products]]`
   &tpl=`product_select`
]]

// product_select chunk:

[[+total_products:eq=`1`:then=`
    <input type="hidden" name="product" value="[[+id]]">
`:else=`
    <div class="product-variation select-wrapper">
        <label for="choose-variation">Option:</label>
        <select id="choose-variation" name="product">
            <option value="[[+id]]">[[+name]]</option>
        </select>
    </div>
`]]

Of course as of right now this doesn’t work as it gives me a individual dropdown for each option, but I don’t know how I can access every product on its own for the option part.

Thanks for any help!

May I be so bold to request some direct help here, @mhamstra? I just don’t know how to tackle this issue. If my question needs any more clarification let me know.

Of course, sorry for not replying sooner. I can’t think of a clean way to do that either with the current templating. You’d need to do something with comparing the [[+idx]] to the [[+total_products]] and 0 and conditionally add the additional markup that way. Might work, but that code would get real messy real fast.

The better solution would be a new &wrapperTpl property that would hold the logic based on [[+total_products]] on wether to add a <select> or not. I’ve added that property to 1.1. That release is tentatively planned for mid-end July.

(An alternative option I have planned is supporting twig templates in snippets that currently only use chunks; but that’s not currently roadmapped to any particular version yet.)

1 Like

Has this been added yet?

I seem to have forgotten to update the documentation for get_products, but yes, &wrapperTpl was added in v1.1.0-rc1 released 2019-08-15. Simply provide it the name of a chunk that has the conditional for [[+total_products]] to render [[+output]]:

[[+total_products:gt=`0`:then=`[[+output]]`:else=`no products`]]
1 Like

That explains, why I couldn’t find it! :wink: Thank you, having that feature now is awesome!

I tried implementing this today, but I’m having some issues. It works in regards that it shows the dropdown for resources with multiple products and no dropdown at all for single product resources. :+1:

The issue is that in the dropdown, it currently only shows one product (should be 4).

I list my products through pdoPage and within that chunk the products get called like this:

[[!commerce.get_products? 
    &products=`[[+tv.products]]`
    &wrapperTpl=`product_wrapper`
]]

Then I use the “new” feature and define the wrapper chunks through product_wrapper:

[[+total_products:gt=`1`:then=`[[$multiple_product_tpl]]`:else=`[[$product_tpl]]`]]

multiple_product_tpl chunk:

<div>
    <select id="choose-variation" name="product">
        [[!commerce.get_products? 
            &products=`[[+tv.products]]`
            &tpl=`product_select`
        ]]
    </select>
</div>

Did I get the general usage of &wrapperTpl right? I’m guessing I have something wrong with the tags, therefore it’s only showing one product in the dropdown instead of the four?

I think you’ll probably want to change your wrapper call. This is how I’ve implemented what you’ve pretty much described that you’re trying to do.

Here’s my snippet call:

[[!commerce.get_products?
  &products=`[[*products]]`
  &tpl=`tplProductSimpleOption`
  &wrapperTpl=`tplProductSimpleSelectWrapper` 
]]

Here’s my wrapper (tplProductSimpleSelectWrapper):

[[+total_products:eq=`1`:then=`
  [[+output]]
`:else=`
    <select name="product" class="product-simple__select">[[+output]]</select>
`]]

…and the chunk (tplProductSimpleOption)

[[+total_products:eq=`1`:then=`
<input type="hidden" name="product" value="[[+id]]">
`:else=`
<option value="[[+id]]" [[+idx:eq=`0`:then=`selected`:else=``]]
  data-sku="[[+sku]]"
  data-stock="[[+stock]]"
  data-image="[[+image]]"
  data-price="[[+price]]"
  data-price-formatted="[[+price_rendered:htmlent]]"
>[[+name]] ([[+price_formatted]])</option>
`]]

@wallacio First, sorry for my late reply, I was a week off and then it took me way to long to wrap my head around this, but I think I figured it out mostly and your example was of great use! Thank you very much! :slight_smile:

One last thing I’m trying right now is to get the “Product Details (#details)” link working. Basically I want a link to the page of the product which was selected.

Here’s my updated (and shortened) wrapperTpl:

[[+total_products:eq=`1`:then=`
  [[+output]]
  
  <!-- This works fine for single products obviously: -->
  <a id="details" href="[[~[[+id]]]]">Product Details</a>
  
`:else=`
  <div class="product-variation">
      <label for="choose-variation">Option:</label>
      <select id="choose-variation" name="product">[[+output]]</select>
  </div>
    
  <!-- This doesn't work: -->
  <a id="details" href="[[~[[commerce.get_product? &product=`[[+tv.products]]` &field=`id`]]]]">Product Details</a>
`]]

I know that getting a link to the initial selected item and getting the link to the new selected item is a different thing. First I’m trying to get the initial product link and I guess the rest has to be done with JS anyway? Any ideas on this?

Can anybody give some hints on this?

I’m not completely sure what you’re trying to do here. The [[+output]] tag will contain the contents of the repeated template for each product (so in my example above, tplProductSimpleOption is repeated here).

I don’t believe you have any access to anything other than total_products and output placeholders in your wrapper tag but surely, the product you’re trying to link to in that Product Details link will already appear in the select list above it?

If this is really what you want to do, I would have thought that the place to do this was outside of the snippet call which uses this wrapper, in the template from which you’re calling get_products to begin with.

Thank you for your help! Here’s an image of my frontend to clarify. I basically need the ID of the selected product to link to the resource of the product through the “Product Details” link at the bottom.

products

Now if I would just use

<a href="[[~[[+id]]]]">Product Details</a>

that would obviously link me only to the “Multi Product” resource, so my question is how do I populate the link with the right ID of the selected product (also after a different one is selected).

You might be right, that this has to happen outside the snippet, I’m just not sure how to retrieve the selected products ID and generate a working link out of it (also with FURL in mind).

I think you touched on this before - the selected product is most likely the first product in the list on initial page display but subsequent presentation will be using Javascript.

I would create your Product Details link outside of the get_products snippet that you’re using to display the <select> with a simple call to get_product in the parent template, and update your link with an onchange event.

Here’s my implementation of something very similar which is an adaptation of the product_matrix from the Red theme:

The page template contains the following snippet which retrieves the first product from the TV and sets it to a placeholder:

[[commerce.get_product? &toPlaceholders=`product`
    &product=`[[*products]]`
    &limit=`1`
]]

Then I have the get_products snippet call in the template to display the select:

[[!commerce.get_products?
    &products=`[[*products]]`
    &tpl=`tplProductSimpleOption`
    &wrapperTpl=`tplProductSimpleSelectWrapper` 
]]

And finally, you could add your Product Details link using the placeholder you first set:

<a href="[[~[[+product.id]]]]">Product Details</a>

That last link wouldn’t make any sense in my implementation, but it may work for you.

That doesn’t work for me for some reason, I can’t seem to get any output for my link at all.

Does get_product even support the &limit property? It’s not in the docs atleast, so I’m wondering if that would even work the intended way (or if it just gets the first item in your case).

Right now I’m simply trying to get a working link to the initial selected product, but I don’t know what I’m doing wrong, it just won’t work.

Next to your example I’ve tried:

[[!commerce.get_products?
  &product=`[[+tv.products]]`
  &limit=`1`
  &tpl=`product_detail_link`
]]

// product_detail_link
<a href="[[~[[+id]]]]">Product Details</a>

and

<a href="[[~[[!commerce.get_product? &product=`[[*products]]` &field=`id`]]]]">Product Details</a>

What am I doing wrong?

You can’t link to a product id - only to a resource id.

This makes a lot more sense of course… but does this mean that what I want to achieve is not possible, as my products don’t have a single resource but just a shared one?

In my use case each product has it’s own description (although being a variation), so it would be helpful to show those, depending on which product is selected…

Apologies for the [[~[[+product.id]]]] suggestion - obviously untested on my part and a bit of a guess at what I thought you were trying to do.

You may wish to re-think how you structure your products and why you’re doing it the way you are. To me, this use case is for a product with a single variation, so the product being a chair, which is available in red, blue or green. The description of a chair is common to all variations so my description of the product belongs to the resource which holds the variations in the products TV, not the actual product.

You could of course bring in a description from each product if they are all different, and there are a couple of ways to achieve this but the most obvious one is using the same method you’d use to change the product price, image etc using Javascript with an onchange event of your <select> element.

1 Like

No worries @wallacio, really appreciate all your thinking and I see now how it’s a more structural issue. I’ll have to check whether or not this is working for my usecase. As my initial problem is fixed, I will consider this case closed for now, though. Thanks again (also to you @mhamstra as always) :slight_smile: