Digital Downloads accessed thru customer account

MandyRenee56
Excursionist
40 0 5

I currently have the app Digital Downloads for my products, and have required that customers make an account. My next question is how do I make their purchased digital downloads available thru their customer account? So that if they lose the email, I don't have to manually send it to them again, they can login, go to the order and click the files to download. Thanks! 

Replies 20 (20)

Moira
Shopify Staff
2067 225 327

Hey, @MandyRenee56!

This is Moira from the Social Care team at Shopify. It’s great to hear you are utilizing the Digital Downloads app for your products! I understand you are looking for a way to make the download available in the customer account section. I'd be more than happy to help you with a solution today.

Currently, there is no option through the native Shopify Digital Downloads app that provides what you are after so I have done some digging on the Shopify app store and found a workaround. In order for the download link to be accessible through the customer portal, the easiest method would be to look at using an alternative digital downloads app.

Here are two fantastic apps for you to choose from below:

  • Sky Pilot ‑ Digital Downloads | Shopify App Store - At any point, a customer can log in to their account in your store to access files or videos they have purchased. This page shows an organizable list of files and/or a playlist of all streaming videos.

  • SendOwl | Shopify App Store - You can add a SendOwl download link (so the customer can download their files) to three different locations in your Shopify store: the checkout "Thank You" page, the order confirmation email, and the customer login area.

Alternatively, you could store a metafield on the customer object with the custom URL to your download link. When an order is placed, use an app called Mechanic to grab the download URL from the product and store it in a metafield on the customer. Then in a page in liquid (which you create), loop through the customer's metafields and display the download links. This approach needs a little bit of theme editing to add the extra logic. The Shopify community forums can nudge you in the general direction if you want to give it a go. I have found a tutorial that a developer has posted to help out a fellow merchant right here.

If you wanted to head down the metafield path, Shopify has paid experts who will complete custom coding and in-depth customizations for your store for an agreed fee between you both, they are fantastic at helping you achieve what you're after. Click here to find out more about hiring a Shopify Expert.

If none of these suggestions work out, you can let us know and we'll be glad to see if we can find a better fit for you or you can go through the apps at our App Store here.

If you have any questions please feel free to thread those below.

Cheers!

Moira | Social Care @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog

Michal17
Shopify Partner
835 73 176

Hi @Moira @MandyRenee56 

Hope you're having a great day!

Thanks to @Moira 

If you're looking for a Shopify developer, don't hesitate to contact me!
https://mmorek.com/
MandyRenee56
Excursionist
40 0 5

Thank you for that wonderful information! If I were to install another app, would I have to go back thru all my digital listings and re-upload the digital files to that new app, or is there some way to transfer them to the new app? Thank you! 

I'm not very savvy on the metafield stuff, so I will try to stick with the easiest way for now. 

Moira
Shopify Staff
2067 225 327

Hi @MandyRenee56,

Great question! Because the apps I have suggested above are created by separate developers, this means they may operate slightly differently from one another so your files will need to be manually re-uploaded to your new app of choice.

Don't hesitate to reach back out if you have any further questions.

Cheers!

Moira | Social Care @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog

artedemoldes
Visitor
3 0 0

So, for every solution I need to buy or pay for extra apps for Shopify. When you realize we'll be paying $500 or more or comissions that may become in more than 5% each month on every add-on that are included in other ecommerce like woocommerce.

Moira
Shopify Staff
2067 225 327

I understand this may be frustrating, although some apps are available for free / have free plans. Otherwise, a workaround solution was posted below by @ArthurCannon.

Moira | Social Care @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog

ArthurCannon
Shopify Partner
4 0 4

I realize this is a rather old topic, however I had this same question and this was one of the few search results so I will post a some what decent solution here.

 

If you edit customers/order.liquid you can add a link to the order confirmation page on which you can enable download links.

You generate the link with the following liquid:

{{ order.order_status_url }}

 to be used like this:

<p>Visit <a href="{{ order.order_status_url }}">Order Confirmation Page</a> if your order contains downloadable products.</p>

Instructions for enabling the links on the order confirmation can be found here.

 

Credit for this solution goes to this post. 

Moira
Shopify Staff
2067 225 327

Thank you for sharing the above solution @ArthurCannon! This will be very beneficial for others who may come across this thread.

Moira | Social Care @ Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog

mettatype
New Member
4 0 0

Where do I add this code to the Dawn theme? I tried adding it to the main-account.liquid and also to the main-order.liquid sections but it doesn't show up.

ArthurCannon
Shopify Partner
4 0 4

You should find the order.liquid file in the templates folder, if you have downloaded the theme there is a customers folder in the templates folder and that is where the order.liquid file is. if you are editing on the Shopify admin it will show as customers/order.liquid in the templates folder.

 

once you have the file it should look like this.

 

Click to expand...
{{ 'customer.css' | asset_url | stylesheet_tag }}

<div class="customer order">
  <svg style="display:none">
    <symbol id="icon-discount" viewBox="0 0 12 12">
      <path fill-rule="evenodd" clip-rule="evenodd" d="M7 0h3a2 2 0 012 2v3a1 1 0 01-.3.7l-6 6a1 1 0 01-1.4 0l-4-4a1 1 0 010-1.4l6-6A1 1 0 017 0zm2 2a1 1 0 102 0 1 1 0 00-2 0z" fill="currentColor">
    </symbol>
  </svg>
  <div>
    <h1>{{ 'customer.account.title' | t }}</h1>
    <a href="{{ routes.account_url }}">{{ 'customer.account.return' | t }}</a>
  </div>

  <div>
    <div>
      <h2>{{ 'customer.order.title' | t: name: order.name }}</h2>
      {%- assign order_date = order.created_at | time_tag: format: "date_at_time" -%}
      <p>{{ 'customer.order.date_html' | t: date: order_date }}</p>
      {%- if order.cancelled -%}
        {%- assign cancelled_at = order.cancelled_at | time_tag: format: "date_at_time" -%}
        <p>{{ 'customer.order.cancelled_html' | t: date: cancelled_at }}</p>
        <p>{{ 'customer.order.cancelled_reason' | t: reason: order.cancel_reason_label }}</p>
      {%- endif -%}

      <table role="table" class="order-details">
        <caption class="visually-hidden">{{ 'customer.order.title' | t: name: order.name }}</caption>
        <thead role="rowgroup">
          <tr role="row">
            <th id="ColumnProduct" scope="col" role="columnheader">{{ 'customer.order.product' | t }}</th>
            <th id="ColumnSku" scope="col" role="columnheader">{{ 'customer.order.sku' | t }}</th>
            <th id="ColumnPrice" scope="col" role="columnheader">{{ 'customer.order.price' | t }}</th>
            <th id="ColumnQuantity" scope="col" role="columnheader">{{ 'customer.order.quantity' | t }}</th>
            <th id="ColumnTotal" scope="col" role="columnheader">{{ 'customer.order.total' | t }}</th>
          </tr>
        </thead>
        <tbody role="rowgroup">
          {%- for line_item in order.line_items -%}
            <tr role="row">
              <td
                id="Row{{ line_item.key }}"
                headers="ColumnProduct"
                role="rowheader"
                scope="row"
                data-label="{{ 'customer.order.product' | t }}"
              >
                <div>
                  {%- if line_item.url != blank -%}
                    <a href="{{ line_item.url }}">{{ line_item.title }}</a>
                  {%- else -%}
                    <p>{{ line_item.title }}</p>
                  {%- endif -%}
                  {%- assign property_size = line_item.properties | size -%}
                  {%- unless line_item.selling_plan_allocation == nil and property_size == 0 -%}
                    <div class="properties">
                      {%- unless line_item.product.has_only_default_variant -%}
                        <span>
                          {{ line_item.variant.title }}
                        </span>
                      {%- endunless -%}
                      {%- unless line_item.selling_plan_allocation == nil -%}
                        <span>
                          {{ line_item.selling_plan_allocation.selling_plan.name }}
                        </span>
                      {%- endunless -%}
                      {%- if property_size != 0 -%}
                        {%- for property in line_item.properties -%}
                          {% assign property_first_char = property.first | slice: 0 %}
                          {%- if property.last != blank and property_first_char != '_' -%}
                            <span>
                              {{ property.first }}:&nbsp;
                              {%- if property.last contains '/uploads/' -%}
                                <a href="{{ property.last }}">{{ property.last | split: '/' | last }}</a>
                              {%- else -%}
                                {{ property.last }}
                              {%- endif -%}
                            </span>
                          {%- endif -%}
                        {%- endfor -%}
                      {%- endif -%}
                    </div>
                  {%- endunless -%}

                  {%- if line_item.line_level_discount_allocations != blank -%}
                    <ul role="list" aria-label="{{ 'customer.order.discount' | t }}">
                      {%- for discount_allocation in line_item.line_level_discount_allocations -%}
                        <li>
                          <svg aria-hidden="true" focusable="false" viewBox="0 0 12 12">
                            <use href="#icon-discount" />
                          </svg>
                          {{- discount_allocation.discount_application.title }} (-{{ discount_allocation.amount | money -}})
                        </li>
                      {%- endfor -%}
                    </ul>
                  {%- endif -%}

                  {%- if line_item.fulfillment -%}
                    <div class="fulfillment">
                      {%- assign created_at = line_item.fulfillment.created_at | time_tag: format: 'date' -%}
                      <span>{{ 'customer.order.fulfilled_at_html' | t: date: created_at }}</span>

                        {%- if line_item.fulfillment.tracking_url -%}
                          <a href="{{ line_item.fulfillment.tracking_url }}">
                            {{ 'customer.order.track_shipment' | t }}
                          </a>
                        {%- endif -%}
                        <span>
                          {{ line_item.fulfillment.tracking_company }}
                          {%- if line_item.fulfillment.tracking_number -%} #{{ line_item.fulfillment.tracking_number }} {%- endif -%}
                        </span>
                    </div>
                  {%- endif -%}
                </div>
              </td>
              <td
                headers="Row{{ line_item.key }} ColumnSku"
                role="cell"
                data-label="{{ 'customer.order.sku' | t }}"
              >
                {{ line_item.sku }}
              </td>
              <td
                headers="Row{{ line_item.key }} ColumnPrice"
                role="cell"
                data-label="{{ 'customer.order.price' | t }}"
              >
                {%- if line_item.original_price != line_item.final_price or line_item.unit_price_measurement -%}
                  <dl>
                    {%- if line_item.original_price != line_item.final_price -%}
                      <dt>
                        <span class="visually-hidden">{{ 'products.product.price.regular_price' | t }}</span>
                      </dt>
                      <dd class="regular-price">
                        <s>{{ line_item.original_price | money }}</s>
                      </dd>
                      <dt>
                        <span class="visually-hidden">{{ 'products.product.price.sale_price' | t }}</span>
                      </dt>
                      <dd>
                        <span>{{ line_item.final_price | money }}</span>
                      </dd>
                    {%- else -%}
                      <dt>
                        <span class="visually-hidden">{{ 'products.product.price.regular_price' | t }}</span>
                      </dt>
                      <dd>
                        {{ line_item.original_price | money }}
                      </dd>
                    {%- endif -%}
                    {%- if line_item.unit_price_measurement -%}
                      <dt>
                        <span class="visually-hidden">{{ 'products.product.price.unit_price' | t }}</span>
                      </dt>
                      <dd class="unit-price">
                        <span>
                          {%- capture unit_price_separator -%}
                            <span aria-hidden="true">/</span><span class="visually-hidden">{{ 'accessibility.unit_price_separator' | t }}&nbsp;</span>
                          {%- endcapture -%}
                          {%- capture unit_price_base_unit -%}
                            {%- if line_item.unit_price_measurement.reference_value != 1 -%}
                              {{- line_item.unit_price_measurement.reference_value -}}
                            {%- endif -%}
                            {{ line_item.unit_price_measurement.reference_unit }}
                          {%- endcapture -%}
                          <span data-unit-price>{{ line_item.unit_price | money }}</span>{{- unit_price_separator -}}{{- unit_price_base_unit -}}
                        </span>
                      </dd>
                    {%- endif -%}
                  </dl>
                {%- else -%}
                  <span>{{ line_item.final_price | money }}</span>
                {%- endif -%}
              </td>
              <td
                headers="Row{{ line_item.key }} ColumnQuantity"
                role="cell"
                data-label="{{ 'customer.order.quantity' | t }}"
              >
                {{ line_item.quantity }}
              </td>
              <td
                headers="Row{{ line_item.key }} ColumnTotal"
                role="cell"
                data-label="{{ 'customer.order.total' | t }}"
              >
                {%- if line_item.original_line_price != line_item.final_line_price -%}
                  <dl>
                    <dt>
                      <span class="visually-hidden">{{ 'products.product.price.regular_price' | t }}</span>
                    </dt>
                    <dd class="regular-price">
                      <s>{{ line_item.original_line_price | money }}</s>
                    </dd>
                    <dt>
                      <span class="visually-hidden">{{ 'products.product.price.sale_price' | t }}</span>
                    </dt>
                    <dd>
                      <span>{{ line_item.final_line_price | money }}</span>
                    </dd>
                  </dl>
                {%- else -%}
                  {{ line_item.original_line_price | money }}
                {%- endif -%}
              </td>
            </tr>
          {%- endfor -%}
        </tbody>
        <tfoot role="rowgroup">
          <tr role="row">
            <td id="RowSubtotal" role="rowheader" scope="row" colspan="4">
              {{ 'customer.order.subtotal' | t }}
            </td>
            <td headers="RowSubtotal" role="cell" data-label="{{ 'customer.order.subtotal' | t }}">{{ order.line_items_subtotal_price | money }}</td>
          </tr>
          {%- if order.cart_level_discount_applications != blank -%}
            <tr role="row">
              {%- for discount_application in order.cart_level_discount_applications -%}
                <td id="RowDiscount" role="rowheader" scope="row" colspan="4">
                  {{ 'customer.order.discount' | t }}
                  <span class="cart-discount">
                    <svg aria-hidden="true" focusable="false" viewBox="0 0 12 12">
                      <use href="#icon-discount" />
                    </svg>
                    {{- discount_application.title -}}
                  </span>
                </td>
                <td headers="RowDiscount" role="cell" data-label="{{ 'customer.order.discount' | t }}">
                  <div>
                    <span>-{{ discount_application.total_allocated_amount | money }}</span>
                    <span class="cart-discount">
                      <svg aria-hidden="true" focusable="false" viewBox="0 0 12 12">
                        <use href="#icon-discount" />
                      </svg>
                      {{- discount_application.title -}}
                    </span>
                  </div>
                </td>
              {%- endfor -%}
            </tr>
          {%- endif -%}
          {%- for shipping_method in order.shipping_methods -%}
            <tr role="row">
              <td id="RowShipping" role="rowheader" scope="row" colspan="4">{{ 'customer.order.shipping' | t }} ({{ shipping_method.title }})</td>
              <td headers="RowShipping" role="cell" data-label="{{ 'customer.order.shipping' | t }} ({{ shipping_method.title }})">{{ shipping_method.price | money }}</td>
            </tr>
          {%- endfor -%}
          {%- for tax_line in order.tax_lines -%}
            <tr role="row">
              <td id="RowTax" role="rowheader" scope="row" colspan="4">{{ 'customer.order.tax' | t }} ({{ tax_line.title }} {{ tax_line.rate | times: 100 }}%)</td>
              <td headers="RowTax" role="cell" data-label="{{ 'customer.order.tax' | t }} ({{ tax_line.title }} {{ tax_line.rate | times: 100 }}%)">{{ tax_line.price | money }}</td>
            </tr>
          {%- endfor -%}
          <tr role="row">
            <td id="RowTotal" role="rowheader" scope="row" colspan="3">{{ 'customer.order.total' | t }}</td>
            <td headers="RowTotal" role="cell" colspan="2" data-label="{{ 'customer.order.total' | t }}">{{ order.total_price | money_with_currency }}</td>
          </tr>
        </tfoot>
      </table>
    </div>
    <div>
      <div>
        <h2>{{ 'customer.order.billing_address' | t }}</h2>
        <p>
          <strong>{{ 'customer.order.payment_status' | t }}:</strong>
          {{ order.financial_status_label }}
        </p>
        {{ order.billing_address | format_address }}
      </div>
      <div>
        <h2>{{ 'customer.order.shipping_address' | t }}</h2>
        <p>
          <strong>{{ 'customer.order.fulfillment_status' | t }}:</strong>
          {{ order.fulfillment_status_label }}
        </p>
        {{ order.shipping_address | format_address }}
      </div>
    </div>
  </div>
</div>

Depending on the version of dawn you are editing, it might be slightly different.

 

You want to insert the code outside of the loops or conditionals, but otherwise put it wherever you would like, I put it under the order title and date.

 


mettatype
New Member
4 0 0

Thanks for your reply @ArthurCannon. That code is in main-order.liquid and I only have an order.json file in my templates/customers folder (Dawn 9.0.0). But it doesn't show up when I add it (under customer.order.date_html).

ArthurCannon
Shopify Partner
4 0 4

I see that they changed the way that was done, you need to verify what section file to edit by checking what is specified in the order.json file, it should have the file name specified in the type setting, like so:

"type": "main-order",

You can then edit the corresponding file in the sections folder, in the above case the file would be main-order.liquid.

You mentioned customer.order.date_html, and that does not appear to be a liquid file the code relies on liquid so it must go in a liquid file.

I just tested it with Dawn 9.0.0 and it worked for me.

Screenshot from 2023-04-26 12-43-40.png

Shows up on the order page for a logged in customer.

mettatype
New Member
4 0 0

By all rights it should work, but I'm just not seeing it. Have even tried with a brand new Dawn theme. It's almost as if it's not using the liquid file at all. Thanks for the help though.

 

Screenshot 2023-04-27 at 6.35.41 PM.png

mettatype
New Member
4 0 0

Ah! This works on the classic customer accounts page. I was looking at the new customer accounts.

AudreyD
Tourist
5 0 0

Thank you very much for proposing this workaround. It worked for me! I must say that this is very frustrating that Shopify does not provide this feature for digital products... I think your proposal is an easy and quick way to do it if you have a lot of products.

 

I am just having an issue with Translate and Adapt, the text added through code is not showing up in the app. I have 3 active languages and I would like to be able to translate the sentence "Visit Order Confirmation Page if your order contains downloadable products.".

I found this thread but I don't understand how to adapt the tutorial to our case...

https://community.shopify.com/c/shopify-translate-adapt/text-added-manually-to-the-theme-s-code-how-...

 

By any chance, have you find a way to translate this sentence for your website?

Thank you very much for your attention, Audrey

 

ArthurCannon
Shopify Partner
4 0 4

To adapt this for translation you will need to add an entry in the localization file, I would add it to locales/en.default.json under customer and then order.

    "order": {
      "title": "Order {{ name }}",
      "date_html": "Placed on {{ date }}",
      "cancelled_html": "Order Cancelled on {{ date }}",
      "cancelled_reason": "Reason: {{ reason }}",
      "billing_address": "Billing Address",
      "payment_status": "Payment Status",
      "shipping_address": "Shipping Address",
      "fulfillment_status": "Fulfillment Status",
      "discount": "Discount",
      "shipping": "Shipping",
      "tax": "Tax",
      "product": "Product",
      "sku": "SKU",
      "price": "Price",
      "quantity": "Quantity",
      "total": "Total",
      "fulfilled_at_html": "Fulfilled {{ date }}",
      "track_shipment": "Track shipment",
      "tracking_url": "Tracking link",
      "tracking_company": "Carrier",
      "tracking_number": "Tracking number",
      "subtotal": "Subtotal"
    },

At the bottom of this section add:

,
      "confirmation_page": "View Digital Downloads"

so that it looks like this:

      "tracking_number": "Tracking number",
      "subtotal": "Subtotal",
      "confirmation_page": "View Digital Downloads"
    },

and then edit the link on the customers/order.liquid so that it uses this translation key like so:

<p><a href="{{ order.order_status_url }}" target="_blank">{{ 'customer.order.confirmation_page' | t }}</a></p>

The text will then be available in the Translate and Adapt app under Default theme content/Accounts (classic)/Order, labeled as "Order: Confirmation Page".

I don't know if you need to manually add the key to each language file that you are using or if the Translate and Adapt app will handle that for you as I do not use that app.

Note: I have simplified the text of the link so that it does not require multiple translation keys or figuring out if you can have a block translation key that contains liquid code.

AudreyD
Tourist
5 0 0

Thank you very much for your help @ArthurCannon,  I followed your instructions and it worked great!

For information, I did not need to manually add the key to each language.

I used a simplified text as you did (but another version) "My custom text". The Translate and Adapt app automatically translated "My custom text" but with a translation corresponding to "View Digital Downloads". So I guess the sentence you suggested is a default text. I was then able to translate "My custom text" under Default theme content/Accounts (classic)/Order, labeled as "Order: Confirmation Page" as you said 🙂

 

Thanks again,

Audrey

FEARLESSBEATZ
Tourist
6 0 2

There's a very easy way to do this if you have a little experience with code. I just did this on my store and want to share it with everyone. I made a button on my order pages that takes you to the direct download for each product.

 

1. First get the download link from each of your digital files and have them ready

2. Go into your Shopify Dashboard -> Settings -> Custom data -> Products -> Add Definition

Your going to create a new metadata field. Call it url or whatever you would like and set the type as URL

3. Go into each of your products to edit them in Shopify Dashboard and scroll down to the metafields and now you will see the url section you just created. This is where you are going to paste all of the links to the direct downloads for your products.

4. Now we have to edit the code but it should be fairly easy. Go to your Shopify Dashboard -> Online Store -> Theme -> click the three circles button for more options -> Edit Code

Depending on the theme you are using, the name of the page you are looking for might be a little different. For us, our page is called customers/order.liquid under templates. Your should be something similar.

5. Once you found the page, you gotta find the area where you want to place your button. It might be useful to make an account on your website and make an order so that you can see what your order page looks like and how everything is laid out. For each order, you want to find the last element in the row. Mine is "price". So you want to put a button somewhere around here. Look at the picture I attached, this is where my button is at. You can do something similar

Screen Shot 2023-10-12 at 5.31.06 PM.png

 Once you found the spot in your code that you want to put your button, you want to make that button using line_item.product.metafields.custom.{metadata name you chose} as the href. Note: you need to make sure you are inside the forloop that loops for each product in the customers order so that you can use the line_item. You should see other lines of code using line_item if you are in the right spot. I will put a picture of the code I used below so that you can copy that for your website.

Screen Shot 2023-10-12 at 5.20.40 PM.png

Best of luck. I know this can be challenging for people who are not coders, but if you have any questions, feel free to reply and I will do my best to answer

 

Edit: You will want to remove the part in my code "class='appstle_manageSubBtn'", as you probably do not have that class on your website. Should be completely fine without it

CarbonChic
Visitor
2 0 1

Just came here to let you know, you are a genius!! This worked amazingly. I could barely figure out where to put the code but once I figured out the logic of the tables and headings, I realised I had to create a new column in the table header and the table body in order for it to work and now it does, whee! Thank you!

artedemoldes
Visitor
3 0 0

Thanks for your share, but, ultra inefficient way to do it. My store is only digital. I have more than 900 products, and each of them has 5 o 6 downloads. I will spent more time creating links and adding them than other. Unfortunatelly Shopify is really bad for digital products, WooCommerce is a way much better on this.