How to add a file upload on Shopify product pages

You want to give your customers the ability to upload files when they add a product to their shopping cart.

This functionality can be required, for example, if you want to offer personalized products on Shopify or if you need some additional files to fulfill an order.

We are going to show you two variants on how you can add a file upload option to your Shopify product pages.

Variant 1 - Implement it yourself

Shopify does support file upload when adding an item to the cart. To make use of the functionality, we have to extend our theme with some additional code to display a file upload form item and make sure that the file is uploaded when a customer clicks the "add to cart" button. The implementation details depend on the specific theme and how the products are added to the cart.

If your theme has an AJAX cart implementation, it is not guaranteed to work out of the box.  

We are going to show you how you can implement a file upload on the Shopify Debut theme, including AJAX cart support! 

Variant 2 - Using a Shopify App

There are various Shopify apps that allow you to add a file upload form on your product. We've developed a new app that solves a lot of problems like file validations and custom CSS for you. By installing the app, you do not have to make any theme modifications to enable file uploads on your product pages.

You could argue that the whole reason that we wrote this blog post is to tell you about the app! But seriously, you could build it yourself, and we are going to show you how, have a basic file upload that works only with your current theme, or you can use the app, which provides a beautiful widget with a lot of customization options.  

The app has a free plan that allows an unlimited number of uploads. You can find it on the Shopify App Store.   

You can skip ahead to see the app in action.

Implementing file upload on Shopify Debut theme

The following instructions are specific to the Debut theme on Shopify. 

Tough the general setup can also be applied to other themes.

Creating a custom product template

To be able to add a file upload option to specific products on our store, we first create a new product template file and call it "product.upload.liquid". 

If you do not know how to add a new template, you can follow this Shopify help doc Create alternate templates.

Next, we copy the code of the default "templates/product. liquid" into the new custom template. (The theme editor does this automatically)

After the template is saved, we can configure it on a product by selecting it on the product page in the Shopify admin under "Theme templates" in the bottom right corner.

Creating a custom section

Our template file currently includes a section called "product-template." This file is located in the "sections" folder, and it contains the central part of the product page. To implement our new file upload feature, we best create a new section and call it "product-upload-template.liquid".

Next, we again copy the code of the default "sections/product-template.liquid" into the new custom section.

Now we can update our new "product.upload.liquid" template to point to our new section.

{% section 'product-upload-shopify-template' %}

Shopify cart items properties

To store the link of the uploaded file somewhere on the cart, we can use custom cart line item properties. 

When a customer adds a product to cart, a new cart line_item object is added to the cart.items array. The line_item object contains all the necessary information about the chosen product, like product variant and price.

The line_item.properties attribute is an array that can store additional custom information. These properties are saved when an order is created. That makes them a great place to store the link to the uploaded file.  

Creating the file input element

To create a custom line_item.properties attribute when adding a product to cart, we create an additional form field on the product form.

In "sections/product-upload-template.liquid" we add the following HTML after to the product form after the variant selection:


{% form 'product', product, class:form_classes, novalidate: 'novalidate', data-product-form: '' %}
...
{% comment %}
    Custom form field to add a line_item.properties entry with the name "upload", containing the link to the uploaded file.
{% endcomment %}
<div class="product-form__item product-form__item--upload">
   <label for="upload">Upload</label>
   <input required class="required" id="upload" type="file" name="properties[upload]" class="product-form__input">
</div>
...
{% endform %}

The name of the property is set via the name="properties[...]" attribute of the input tag. You can choose a different property name that makes sense for your use case.

After we saved the section file and our theme is updated, we can navigate to the product with the template and see a file upload input form item appear above the add to cart button.

If you don't see the upload item on your product page, check the previous steps and make sure that you've selected the new template on the product configuration page. 

 

Making the cart upload work

When now can select a file and add the product to cart. We can verify that the product was successfully added to the cart, but the "upload" property is missing on the line_item.properties.

The reason it is not working out of the box is that the Debut theme default cart implementation is using AJAX to call the add.js API to add line_items to the cart. Unfortunately, this skips the file upload process entirely.

We have two options to fix this. 

Option 1 - Disable Ajax cart

The Debut theme settings contain a property to enable/disable the ajax cart.

In the Shopify Admin Themes section, click on "Customize" on your current Debut based theme. Navigate to the "Theme settings" tab. Click on the "Add to cart notification" section.

 

Uncheck the checkbox "Show notification when item is added to cart".

Make sure that you save the theme settings.

The setting is reflected as the property "enable_ajax" in the config file "config/settings_data.json".

When we now try again and select a file and add it to cart, we should see an upload property displayed on the cart line_item on the cart page.

The downside of this approach is that now all of our other products can not make use of the cart ajax functionality, especially the cart popup in the top right is not shown anymore. This causes an overall worse user experience. 

Option 2 - Modify theme.js to support AJAX file uploads

If you disabled the "enable_ajax" setting from the first option. Enable it again. We know you want to have that nice cart popup functionality back!

We have to modify some of the theme's javascript code to make the ajax cart support file uploads.  

Open the "assets/theme.js" file and search for the "_addItemToCart" function. Rename the function, add a suffix "_original" to be able to restore to the original function if needed. 


_addItemToCart_original: function(data) {
... 
}

 

Next, add we add our new implementation below the original one:

 // NEW: implementation to allow ajax file uploads & required checks
    _addItemToCart: function($form) {

      // You need to use standard javascript object here
      // create form data with all the fields from the form
      // FormData is >=IE10
      var formData = new FormData($form[0]);

      var params = {
        type: 'POST',
        contentType: false, // NEEDED, DON'T OMIT THIS (requires jQuery 1.6+)
        processData: false, // NEEDED, DON'T OMIT THIS
        url: '/cart/add.js',
        data: formData,
        dataType: 'json',
        success: function(item) {
          this._hideErrorMessage();
          this._setupCartPopup(item);
        }.bind(this),
        error:  function(response) {
          this.$previouslyFocusedElement.focus();
          var errorMessage = response.responseJSON
              ? response.responseJSON.description
              : theme.strings.cartError;
          this._showErrorMessage(errorMessage);
          this._handleButtonLoadingState(false);
        }.bind(this)
      };

      // execute ajax add to cart
      $.ajax(params);
    },

 

Our new function makes use of the FormData Javascript object to parse and send all form fields, including our new upload field. As commented in the code, the FormData only supports IE >= 10. 

We then pass the formData as the data parameter to the jQuery.ajax() method. The success and error handlers are the same as in the original function.

 

If we now try again and select a file and add it to cart, we should see the cart popup with our upload property displayed on the cart line_item in the top right corner.  

 

Making the file upload required

As you may have noticed, we set the "required" attribute on the upload input field. But when we click on "Add to cart" without selecting a file, the product is still added to cart! The reason for this is again the Ajax cart skips the browser native form validation. We have to implement it ourselves in the "_addItemToCart" function. 

We add the following code to check if all the inputs that are marked as required have a value. If not, we show an error on the page and skip adding the product to the cart. 


    _addItemToCart: function($form) {

      var valid = true;

      // required fields validation
      $.each($form.find('input.required'), function (index, element) {
        if(!$(element).val()){
          valid = false;
        }
      });

      if(!valid){
        this._showErrorMessage('missing required fields');
        this._handleButtonLoadingState(false);
        return;
      }
      
      ...
   }

 

If we now try to add a product to the cart without selecting a file first, we see an error message displayed on the page. 

 

Using the Upload-Lift App

If you don't want to implement the upload functionality yourself, or if you want a more customizable and more pleasing upload widget, then using an app like Upload-Lift is the right way to go. You can install it directly from the Shopify App Store.

Creating a file upload field

After you have installed the app, you will see a UI to create a new upload field. On the UI, we can configure the form input settings like required and the name of the properties. We can also set the look and feel of the widget to match with our theme colors.

In the display settings section, we can configure the field to be shown on a specific product. The app also supports complex conditions to display a single upload field on multiple product pages. If we would want to place the widget on a specific place on the page, we could also provide a CSS selector. The default location is at the end of the product form. 

 

Testing the file upload

When we visit our product page, we should see the upload widget shown right above the "Add to cart" button. 

You can check a live example on this product page: personalized-canvas

 

Seeing the uploaded files

One nice additional feature of the app is the ability to see the uploaded files directly in the app. 

You can download the files at any time. If the customer makes an order, the files get linked with the order. 

 

Customizing the product page based on the uploaded file

The widget triggers custom events on the form element that you can subscribe to with javascript. By subscribing to the "upload:added" event, we can, for example, modify the product image and replace it with the uploaded image. 

You can see a live example of the events on this product page: upload-events

If you need help with the implementation details, send us a message on the support function of the app!

Customizing the cart page based on the uploaded file

As described earlier, the uploaded file link is stored in the cart line_item.properties.

This means you can access them in your liquid templates to display the uploaded files on your cart page or any page where you have access to the cart object. 

Again if you need help with the implementation details, send us a message on the support function of the app!

Conclusion

We have shown you two different ways to add a file upload feature to your product pages. Depending on how much coding you want to do yourself, it is entirely possible to implement the feature with the Shopify core platform. However, to support ajax cart functionality, we had to modify the theme-specific javascript code.

By using a third-party Shopify app like Upload-Lift, the setup becomes straightforward and allows us to provide a way better user experience.