Allow customers to change their field values

This feature is deprecated. It is no longer actively maintained and we only provide support for existing implementations created before November 2021. If you need to create forms with support for customer Metafields, we highly recommend using Helium's Customer Fields app. Follow the link for a 20% partnership discount

This article contains information about:

  • Enabling customers to edit the information stored about them in custom fields

  • Creating a customer account with or without custom fields

  • How to set up HTML elements for different ACF field types, including file upload

  • How to handle repeatable fields

  • How to use the ACF proxy for form submission

This is an advanced tutorial requiring some knowledge of both HTML and Javascript. The examples also make basic use of jQuery for connecting the form and the proxy script

Enabling customers to edit the information stored about them in custom fields

To create a form for editing an existing customer's custom fields, you must include a hidden field with the name "customer[id]" and set its value to that of the logged-in customer via {{ customer.id }}

<form id="metafields_form">  

  <input type="hidden" name="customer[id]" value="{{ customer.id }}" /> 

</form>

Each form element linked to a custom field must be named "metafield[ namespace.fieldname]". The namespace must be included even if you just use the default "accentuate".

<form id="metafields_form">  

  <input type="hidden" name="customer[id]" value="{{ customer.id }}" /> 
  <input type="text" name="metafield[accentuate.nick_name]" value="{{ customer.metafields.accentuate.nick_name }}" placeholder="Nickname" /> 
  <input type="text" name="metafield[accentuate.birthday]" value="{{ customer.metafields.accentuate.birthday }}" placeholder="Your birthday" /> 

</form>

In addition to custom fields, you can provide these fields as well to have them updated in Shopify:

  • customer[email]

  • customer[first_name]

  • customer[last_name]

  • customer[email_marketing_consent] (defaults to false*)

  • customer[sms_marketing_consent] (defaults to false*)

  • customer[phone]

  • customer[tags]

  • customer[address.property] (where property is one of the valid address properties listed in the Shopify docs). When referencing an [address.property] you must always include the address id via [address.id] (for example {{ customer.default_address.id }})

  • customer[password] and customer[password_confirmation] (both must come together and have matching values)

<form id="metafields_form">  

  <input type="hidden" name="customer[id]" value="{{ customer.id }}" /> 
  <input type="text" name="metafield[accentuate.nick_name]" value="{{ customer.metafields.accentuate.nick_name }}" placeholder="Nickname" /> 
  <input type="text" name="metafield[accentuate.birthday]" value="{{ customer.metafields.accentuate.birthday }}" placeholder="Your birthday" /> 

  <!-- Fields belonging to the customer object in Shopify --> 
  <input type="text" name="customer[first_name]" value="{{ customer.first_name }}" placeholder="First name" /> 
  <input type="text" name="customer[last_name]" value="{{ customer.last_name }}" placeholder="Last name" /> 
  <input type="checkbox" name="customer[email_marketing_consent]" {% if customer.email_marketing_consent %} checked {% endif %}/> Can't wait, send me stuff!  
  <input type="checkbox" name="customer[sms_marketing_consent]" {% if customer.sms_marketing_consent %} checked {% endif %}/> Send me a text as well!
</form>

Custom fields referenced via the form elements' "name" attribute must be configured in advance for the customer scope in ACF before they can be updated

Enabling customers to edit the information stored in their orders' custom fields

The procedure here is exactly the same as above for customer custom fields, except that you must use a hidden field with the name "order[id]" and set its value to that of the relevant order via {{ order.id }}. Having an "order[id]" field present in the form switches the scope of any provided custom fields to orders.

<form id="metafields_form">  

  <input type="hidden" name="order[id]" value="{{ order.id }}" />  
  <input type="text" name="metafield[accentuate.nick_name]" value="{{ order.metafields.accentuate.po_reference }}" placeholder="Purchase order reference" /> 

</form>

Custom fields referenced via the form elements' "name" attribute must be configured in advance for the order scope in ACF before they can be updated

Creating a customer account with or without custom fields

ACF can create new customer accounts on form submission AND update any provided custom fields after the fact. To do this, set the value of "customer[id]" to an empty string and include at least one of these fields as well:

  1. customer[email]

  2. customer[first_name] and/or customer[last_name]

<form id="metafields_form">  

  <input type="hidden" name="customer[id]" value="" /> 
  <input type="text" name="customer[email]" value="{{ customer.email }}" placeholder="Email" /> 
  <input type="text" name="customer[first_name]" value="{{ customer.first_name }}" placeholder="First name" /> 
  <input type="text" name="customer[last_name]" value="{{ customer.last_name }}" placeholder="Last name" /> 

  <input type="checkbox" name="metafield[accentuate.check]" {% if customer.metafields.accentuate.check %} checked {% endif %}/> Yes, send me a free gift on my birthday  

</form>

Optional fields for customer creation include:

  • customer[verified_email] (default to false*)

  • customer[send_email_invite] (defaults to false*)

  • customer[password] and customer[password_confirmation] (both must come together and have matching values)

  • customer[send_email_welcome] (defaults to false*)

  • customer[email_marketing_consent] (defaults to false*)

  • customer[sms_marketing_consent] (defaults to false*)

  • customer[phone]

  • customer[tags]

* ACF converts a field value of "true", "yes" or "1" to a boolean "true" and all other values to "false". A checkbox as shown in the example will work just fine

Field types examples

This form example highlights some different ways to provide values for custom fields Please note:

  • For fields where you need to send multiple values, define them as form "arrays", i.e. "metafield[ namespace.fieldname][ ]" (note the closing [ ]'s)

  • If you use checkboxes to have your customer select one or more values for a Selection or Tags type field, be sure to include each field's value as a "data-option-value" attribute.

...
  <!-- Text examples --> 
  <input type="text" name="metafield[accentuate.nick_name]" value="{{ customer.metafields.accentuate.nick_name }}" placeholder="Nickname" /> 

  <!-- Checkbox to select on or off for a Checkbox field --> 
  <input type="checkbox" name="metafield[accentuate.check]" {% if customer.metafields.accentuate.check %} checked {% endif %}/> Yes, send me a free gift on my birthday  

  <!-- Checkboxes to select multiple predefined values for a Selection list or Tags field --> 
  <input type="checkbox" name="metafield[accentuate.multiselect][]" data-option-value="value-1" /> Select this to choose value 1 
  <input type="checkbox" name="metafield[accentuate.multiselect][]" data-option-value="value-2" /> Select this to choose value 2  

  <!-- Radio buttons to select a single value for a field (Text field or Selection list) --> 
  <input type="radio" name="metafield[accentuate.color]" value="Red" {% if customer.metafields.accentuate.color == "Red" %} checked {% endif %}/> Red
  <input type="radio" name="metafield[accentuate.color]" value="Blue" {% if customer.metafields.accentuate.color == "Blue" %} checked {% endif %}/> Blue
  <input type="radio" name="metafield[accentuate.color]" value="Green" {% if customer.metafields.accentuate.color == "Green" %} checked {% endif %}/> Green

   <!-- Single value selection list -->
  <select name="metafield[accentuate.preferred_color]">
    <option value="Magenta">Magenta color</option>
    <option value="Plum">Plum color</option>
    <option value="Beige">Beige color</option>
  </select>

   <!-- Multiple value selection list -->
  <select multiple name="metafield[accentuate.preferred_color][]">
    <option value="Magenta">Magenta color</option>
    <option value="Plum">Plum color</option>
    <option value="Beige">Beige color</option>
  </select>

  <!-- File upload example --> 
  <input type="file" name="metafield[accentuate.avatar]" accept="image/png, image/jpeg" />  <input type="submit"/> 

</form>

How to get the defined values from a Selection type field

Now, you may be wondering how you are going to keep your form's selection lists in sync with the allowed values defined for the field. Getting to those values is possible using special ACF Metafields. Please see the related article on Liquid access to field definitions. Armed with this information, you can loop over the defined "preferred_color" values in Liquid like this:

...
  {% assign field = shop.metafields.acf_settings.product | where: "name", "preferred_color" | first %}
  {% assign values = field.value | split: '|' %}
  <select name="metafield[accentuate.preferred_color]">
  {% for value in values %}
    <option value="{{ value }}">{{ value }}</option>
  {% endfor %}
  </select>
...

Repeatable fields handling

If you need your form input to add values to a repeatable field (e.g. register a newly bought product to an existing list of bought products) rather than overwriting the value, add this option to your form:

... 
  <input type="hidden" name="options.append" value="true" />
...

Similarly, if you need your form input to remove values from a repeatable field (e.g. remove an element from a list) rather than overwriting the value, add this option to your form:

...
  <input type="hidden" name="options.remove" value="true" />
...

There is also an option to have ACF split text values to multiple values based on a split character defined by you. Say you want your customer to input a comma-separated list of values but you'd like this to be stored as individual elements of a repeatable field in ACF, you can add the below option to your form. If this is present, ACF will automatically split any non-array form values targeted for repeatable fields by the provided split character:

...
  <input type="hidden" name="options.split" value="," />
...

These options apply to all repeatable fields in your form. If you need to add or remove values for some fields, but not for others, consider creating two different forms

You can remove a set of repeatable field values that "belong" together (like "pet_name" and "pet_date_of_birth" for a customer's list of registered pets) by defining them inside the same repeatable section in ACF, like this:

Then, in your form, provide a special field options.remove.id that points out the Metafield that contains the value to be removed:

...
  <input type="hidden" name="options.remove" value="true" />
  <input type="hidden" name="options.remove.id" value="accentuate.pet_name" />
...
  <input type="text" name="metafield[accentuate.pet_name]" value="Fido" />
...

ACF will automatically determine the index of the provided value ("Fido") within the existing value of "accentuate.pet_name" and remove any other values at that index for the section's other fields (in this example "pet_date_of_birth" as well).

Preferably the options.remove.id points to something reasonably unique - ACF will determine the index from the first occurrence of the field's value matching the provided value. Consider providing an id in a separate field to store a unique id, e.g. a GUID

Submitting the form

In your theme.liquid file, near the closing </body> tag, be sure to include the ACF proxy script and one line of code to bind your form to the proxy.

  ...
  {% if template contains 'customers/account' or template contains 'customers/order' %}  
  <script src="https://app.accentuate.io/dist/proxy.js"></script>; 
  <script> Accentuate(jQuery("#metafields_form")); </script> 
  {% endif %}  
</body>

The Accentuate proxy script depends on jQuery to work, so make sure jQuery is loaded separately before the proxy script is invoked The proxy script sets up a handler for the form submission but does not actually submit the form. This is up to you, either by using a standard submit button or by calling the form's .submit() method via Javascript

Adjust the above selector of the form - jQuery("#metafields_form") - to match your actual code. Accentuate will automatically handle the form submission and determine the endpoint target for the form submission - therefore you don't need to define METHOD or ACTION attributes on the form itself (and they will be ignored, if present). The "Accentuate()" function takes two optional parameters: The first optional parameter is a callback function where you can take action after updates have been submitted to ACF. This callback is served with a "data" object containing the below properties, which you can use for inspecting whether the update succeeded or not, and which:

data.status

will contain either "OK" or "ERROR"

data.message

will contain a related message with details

data.errors

in case of status = "ERROR", this will contain an object structure highlighting which parts of the request failed, e.g. { email: ["is already taken"], phone: ["is invalid"] } Here is a simple example, where the results are just logged to the browser's console:

<script> 
  Accentuate(jQuery("#metafields_form"), function(data) { console.log(data.status, data.message); }); 
</script>

If your form contains file uploads (input type="file"), the file uploads are handled separately from the rest of the form's fields. This is handled automatically by the proxy script but you will experience that the callback function (if defined) is called twice, once for any files and once for all other fields The second optional parameter is a callback function where you can validate your form prior to submitting it to ACF's handling. If you return false from the validation callback, the form will not be submitted. Any other value than false will allow for form submission. Example of a validation function that checks for a non-zero length of a field with an id of "myfield":

<script>
  Accentuate(jQuery("#metafields_form"), null, function() { if ($("#myfield").val().length == 0) return false });
</script>

Last updated