Ask customer for additional information

From Shopify Wiki

Jump to: navigation, search

When you update the content of a cart or click the checkout button on a standard Shopify cart.liquid page, Shopify looks for two special parameters called note and attributes to include with the order.

Contents

Cart Note

Imagine that you’re running a gift shop and you want to ask your customers for a note to be included in the package.

To get that functionality, add the following html/liquid code cart.liquid between the opening <form> and closing </form> tags in cart.liquid:

<p>
  <label for="note">Gift note:</label><br/>
  <textarea name="note" id="note" rows="3" cols="60">{{ cart.note }}</textarea>
</p>

File:/upload/4/46/Gift-note.png

After placed and paid, this order will display the note in the Shopify admin.

File:/upload/e/ef/Gift-order.png

If you want to show your cart note in your email notifications, you will need to edit your email templates by going to Preferences in your admin, then by going to Email & Notifications.

To show the cart note, use this code:

Gift note: {{ note }}

You can only have one cart note in the cart form.

Cart Attributes

Cart Attributes let you attach arbitrary values to an order, making them useful for creating more complex forms with checkboxes, drop-downs or even hidden fields.

You can submit an unlimited number of cart attributes with the cart form. They're all gonna get through to the other side!

Create them by setting the name attribute to attributes[something] on input (or other type of form) elements. The “something” part is your key. Example:

<input type="text" name="attributes[your-pet-name]" value="{{ cart.attributes.your-pet-name }}" />

Note that cart attributes may not be nested, so attributes[wrapping][fabric] or attributes[wrapping][style] will not work as expected. The cart attributes are flattened to a single level.

As an example, let’s ask the customer if they want their gift wrapped:

<p>
  <input type="hidden" name="attributes[wrapping]" value="" />
  <input id="wrapping" type="checkbox" name="attributes[wrapping]" value="yes" {% if cart.attributes.wrapping %} checked="checked"{% endif %} />
  <label for="wrapping">Please wrap the products in this order</label>
</p>

File:/upload/c/c5/Gift-wrapping-note.png

This order, after it’s placed and paid, will display the following note in the Shopify admin:

File:/upload/f/f3/Gift-wrapping-order.png

You can add as many attributes as you like, but each attributes[name] must be unique.

If you want to show your cart attributes in your email notifications, you will need to edit your email templates by going to Preferences in your admin, then by going to Email & Notifications.

To show a cart attribute, you can access it directly by key like so in the email template:

{% if attributes.wrapping %}Your items will be gift-wrapped.{% endif %}

No need to use cart in the email templates, like you do in cart.liquid.

To show all the cart attributes you have, you can loop through them like so:

<ul>
{% for attribute in attributes %}
<li>{{ attribute | first | replace: '-', ' ' | replace: '_', ' ' | capitalize }} : {{ attribute | last }}</li>
{% endfor %}
</ul>

Collecting data for each Line Item in the cart

You can collect data for each Line item in the cart. Your cart.liquid template typically iterates through all line items in the cart. You'll add your code to the for loop like so:

{% for item in cart.items %}
...
<p>
  {% capture attribute %}engraving-{{ item.title | handle }}{% endcapture %}
  <label for="{{ attribute }}">Engraving text:</label><br />
  <input id="{{ attribute }}" type="text" name="attributes[{{ attribute }}]" value="{{ cart.attributes[attribute] }}" />
</p>
...
{% endfor %}

The 'engraving' part of the attribute name tells us that we're collecting engraving information. We could be collecting information about something else, so feel free to edit this to whatever you want. As for the {{ item.title | handle }} part, it tells us which line item the attribute describes. Note: cart attributes are attributes of the cart. Shopify does not provide line items attributes. This is why we must name each attribute after the line item it describes. If we don't do that, how else will we know which line item the attribute describes?

By default, your Order Confirmation template contains the following:

{% for line in line_items %}{{ line.quantity }}x {{line.title }} for {{ line.price | money }} each
{% endfor %}

To include the cart attributes in the confirmation email, you'll modify the above code to this:

{% for line in line_items %}{{ line.quantity }}x {{line.title }} for {{ line.price | money }} each
{% capture attribute %}engraving-{{ line.title | handle }}{% endcapture %}{% if attributes[attribute] != '' %}Engraving for {{ line.title }}: {{ attributes[attribute] }}{% endif %}
{% endfor %}

The result:

File:/upload/6/6a/Engraving email.png

And the attributes shown on the Order details page:

File:/upload/1/1c/Engraving order.png

Collecting data for each single item in the cart

You can collect data for each item in the cart. Your cart.liquid template typically iterates through all line items in the cart. You'll add your code in that for loop like so:

{% for item in cart.items %}
...
  {% for i in (1..item.quantity) %}
  <p>  
    {% capture attribute %}engraving-{{ item.title | handle }}-{{ i }}{% endcapture %}
    <label for="{{ attribute }}">Engraving text for item {{ i }}:</label><br />
    <input id="{{ attribute }}" type="text" name="attributes[{{ attribute }}]" value="{{ cart.attributes[attribute] }}" />
  </p>
  {% endfor %}
...
{% endfor %}

The 'engraving' part of the attribute name tells us that we're collecting engraving information. We could be collecting information about something else, so feel free to edit this to whatever you want. As for the {{ item.title | handle }}-{{ i }} part, it tells us which item in the cart the attribute describes.

File:/upload/1/16/Engraving per item.png

By default, your Order Confirmation template contains the following:

{% for line in line_items %}{{ line.quantity }}x {{line.title }} for {{ line.price | money }} each
{% endfor %}

To include the cart attributes in the confirmation email, you'll change the above code so that it becomes:

{% for line in line_items %}{{ line.quantity }}x {{line.title }} for {{ line.price | money }} each
{% for i in (1..line.quantity) %}{% capture attribute %}engraving-{{ line.title | handle }}-{{ i }}{% endcapture %}{% if attributes[attribute] != '' %}Engraving for {{ line.title }} no {{ i }}: {{ attributes[attribute] }}{% endif %}
{% endfor %}
{% endfor %}

The result in the email will be for example:

File:/upload/e/e8/Mailplane.png

And the attributes shown on the Order details page:

File:/upload/1/1e/Google Chrome 3.png

Our example shows that only 1 Line item was purchased, but using these code snippets, one can purchase any number of items from any number of Line items.

Common questions

I added a second note to my cart but only 1 note is submitted. Why?


There can only be one cart note in the cart form. As soon as you need to collect more information — as soon as you need to add another text box — you need to look into using cart attributes.

You can submit an unlimited number of cart attributes with the order, but only one cart note.

Can I use a select element? What would be the code for that?

{% assign attribute = 'favorite-meal' %}
<label for="{{ attribute }}">My favorite meal of the day is...</label>
<select id="{{ attribute }}" name="attributes[{{ attribute }}]">
  <!-- Below, set the upper-bound number to the number of options -->
  {% for i in (1..3) %}
  <!-- List your options here, captain... -->
    {% capture option %}{% cycle 'Breakfast', 'Lunch', 'Dinner' %}{% endcapture %}
    <option value="{{ option }}"{% if cart.attributes[attribute] == option %} selected="selected"{% endif %}>{{ option }}</option>
  {% endfor %}
</select>

Can I use radio buttons? What would be the code for those?

<p>My favorite meal of the day is...</p>
{% assign attribute = 'favorite-meal' %}
<!-- Below, set the upper-bound number to the number of radios -->
{% for i in (1..3) %}
  <!-- List your options here, captain... -->
  {% capture option %}{% cycle 'Breakfast', 'Lunch', 'Dinner' %}{% endcapture %}
  <input type="radio" id="{{ option }}-{{ i }}" name="attributes[{{ attribute }}]" value="{{ option }}"{% if cart.attributes[attribute] == option %} checked="checked"{% endif %} />
  <label for="{{ option }}-{{ i }}">{{ option }}</label>
{% endfor %}

My clients fill up the cart attributes, but they are not saved. When they leave the cart page and come back, the boxes previously filled-up are empty. How can I fix this?

One has to click on the Update button to save the attributes. It works the same as quantity edits: if you edit a value and do not click on Update nor Checkout and browse to another page, your edit is lost.

If you do click on Update and the attributes are not saved — boxes are empty after the “update” — then your code is incorrect. It needs to be fixed!

What if you want to avoid the “click on Update” step, though? What if you want any edit to be auto-saved? Add the following at the bottom of your cart.liquid template:

<script type="text/javascript" charset="utf-8">
//<![CDATA[
jQuery(function() {
  jQuery(window).unload(function() {
    var params = {
      type: 'POST',
      url: '/cart/update.js',
      data: jQuery('form[action="/cart"]').serialize(),
      dataType: 'json',
      async: false
    };
    jQuery.ajax(params);
  });        
});  
//]]>
</script>

The above code added to your cart.liquid template will autosave the cart when user leaves the cart page without updating the cart. This is particularly useful when using cart attributes. The code requires jQuery. jQuery('form[action="/cart"]') will grab any cart form.

I want to make my field(s) required

Use the HTML5 'required' attribute or use the class 'required' on your form field. It makes no difference which of the 2 you use. Go with what you prefer. Example:

<input type="text" name="attributes[some-info]" value="{{ cart.attributes.some-info }}" placeholder="Some info..." class="required" data-error="Please tell us your info." />

Use a data-error attribute to specify which message should be shown to the shopper if he does not fill out the field and tries to checkout.

Then, add the content of this file to your theme.liquid file. Paste the content before the closing </body> tag, that's near the bottom of theme.liquid.