Add pickup availabi...
 
Notifications
Clear all

Add pickup availability on Shopify product page (Plak Theme)

1 Posts
1 Users
0 Reactions
1,647 Views
plaktheme
(@plaktheme)
Reputable Member
Joined: 5 years ago
Posts: 0
Topic starter  

For merchants with both online and brick-and-mortar stores, offering delivery methods like buy online, pickup in-store (BOPIS) and curbside pickup help create a cohesive online–to–in-store shopping experience.

For consumers, in-store pickup is attractive because it helps them get orders faster while avoiding shipping fees. For merchants, leveraging their physical stores as fulfillment centers for online orders helps speed up fulfillment times and increase customer satisfaction while lowering shipping costs on local deliveries.

 

In this tutorial, you will be able to add the store availability feature on Plak theme (This feature is included by default in Plak version 2.6), if you would to hire one of developers to include it in your theme, I invite you to use this form

1- Add the pickup availability section

 

  • From your Shopify dashboard, click Online store> Actions > Edit code
  • Under Sections, Click Add a new section
  • Name the section pickup-availability
  • Remove all the content created in this file and replace it with this one
{% comment %}theme-check-disable UndefinedObject{% endcomment %}
{%- assign pick_up_availabilities = product_variant.store_availabilities | where: 'pick_up_enabled', true -%}

{%- if pick_up_availabilities.size > 0 -%}
<pickup-availability-preview class="pickup-availability-preview">
{%- liquid
assign closest_location = pick_up_availabilities.first

if closest_location.available
render 'icon-tick'
endif
-%}

<div class="pickup-availability-info">
{%- if closest_location.available -%}
<p class="caption-large">{{ 'store_availability.general.pick_up_available_at_html' | t: location_name: closest_location.location.name }}</p>
<p class="caption">{{ closest_location.pick_up_time }}</p>
<button id="ShowPickupAvailabilityDrawer" class="pickup-availability-button link link--text underlined-link" aria-haspopup="dialog">
{%- if pick_up_availabilities.size == 1 -%}
{{ 'store_availability.general.view_store_info' | t }}
{%- else -%}
{{ 'store_availability.general.check_other_stores' | t }}
{%- endif -%}
</button>
{%- else -%}
<p class="caption-large">{{ 'store_availability.general.pick_up_unavailable_at_html' | t: location_name: closest_location.location.name }}</p>
{%- if pick_up_availabilities.size > 1 -%}
<button id="ShowPickupAvailabilityDrawer" class="pickup-availability-button link link--text underlined-link" aria-haspopup="dialog">{{ 'products.product.pickup_availability.check_other_stores' | t }}</button>
{%- endif -%}
{%- endif -%}
</div>
</pickup-availability-preview>

<pickup-availability-drawer tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="PickupAvailabilityHeading">
<div class="pickup-availability-header">
<h2 class="h3 pickup-availability-drawer-title" id="PickupAvailabilityHeading">{{ product_variant.product.title | escape }}</h2>
<button class="pickup-availability-drawer-button" type="button" aria-label="{{ 'accessibility.close' | t }}">{%- render 'icon-close' -%}</button>
</div>

{%- unless product_variant.product.has_only_default_variant -%}
<p class="pickup-availability-variant">
{%- for product_option in product_variant.product.options_with_values -%}
{{ product_option.name | escape }}:&nbsp;
{%- for value in product_option.values -%}
{%- if product_option.selected_value == value -%}
<span>{{ value | escape }}</span>
{%- endif -%}
{%- endfor -%}
{%- unless forloop.last -%},&nbsp;{%- endunless forloop.last -%}
{%- endfor -%}
</p>
{%- endunless -%}

<ul class="pickup-availability-list list-unstyled" role="list" data-store-availability-drawer-content>
{%- for availability in pick_up_availabilities -%}
<li class="pickup-availability-list__item">
<h3 class="h4">{{ availability.location.name | escape }}</h3>
<p class="pickup-availability-preview caption-large">
{%- if availability.available -%}
{% render 'icon-tick' %} {{ 'store_availability.general.pick_up_available' | t }}, {{ availability.pick_up_time | downcase }}
{%- endif -%}
</p>

{%- assign address = availability.location.address -%}
<address class="pickup-availability-address">
{{ address | format_address }}

{%- if address.phone.size > 0 -%}
<p>{{ address.phone }}</p>
{%- endif -%}
</address>
</li>
{%- endfor -%}
</ul>
</pickup-availability-drawer>
{%- endif -%}
  • Click Save

 

2- Add the CSS file

 

  • Under Assets, click Add a new asset > Create a blank file
  • Select .css in the dropdown menu
  • Name the file component-pickup-availability

  • Add the below code into this file
pickup-availability {
display: block;
}

pickup-availability[available] {
min-height: 8rem;
}

.pickup-availability-preview {
align-items: flex-start;
display: flex;
gap: 0.2rem;
padding: 0 2rem 0 0;
font-size : .8rem;
}

.pickup-availability-preview .icon {
flex-shrink: 0;
height: 1rem;
}

.pickup-availability-preview .icon-unavailable {
height: 1.6rem;
margin-top: 0.1rem;
}

.pickup-availability-button {
background-color: transparent;
color: rgba(var(--color-text), 0.75);
letter-spacing: 0.06rem;
padding: 0 0 0.2rem;
text-align: left;
text-decoration: underline;
border:none;
}
.pickup-availability-info * {
margin: 0 0 0.6rem;
font-size : .8rem;
}

pickup-availability-drawer {
background-color: var(--color-bg);
border: 1px solid var(--color-border);
height: 100%;
opacity: 0;
overflow-y: auto;
padding: 2rem;
position: fixed;
top: 0;
right: 0;
z-index: 4;
transition: opacity 200ms ease,
transform 200ms ease;
transform: translateX(100%);
width: 100%;
}

pickup-availability-drawer[open] {
transform: translateX(0);
opacity: 1;
z-index : 99999;
}

@media screen and (min-width: 750px) {
pickup-availability-drawer {
transform: translateX(100%);
width: 23rem;
}

pickup-availability-drawer[open] {
opacity: 1;
transform: translateX(0);
animation: animateDrawerOpen 200ms ease;
}
}

.pickup-availability-header {
align-items: flex-start;
display: flex;
justify-content: space-between;
margin-bottom: 1.2rem;
}

.pickup-availability-drawer-title {
margin: 0.5rem 0 0;
}

.pickup-availability-header .icon {
width: 1.2rem;
}

.pickup-availability-drawer-button {
background-color: transparent;
border: none;
color: rgb(var(--color-text));
cursor: pointer;
display: block;
height: 4.4rem;
padding: 1.2rem;
width: 4.4rem;
}

.pickup-availability-drawer-button:hover {
color: rgba(var(--color-text), 0.75);
}

.pickup-availability-variant {
font-size: 0.8rem;
line-height: 0.03rem;
margin: 0 0 1.2rem;
text-transform: capitalize;
}

.pickup-availability-variant > * + strong {
margin-left: 1rem;
}

.pickup-availability-list__item {
border-bottom:.1rem solid rgba(18,18,18,.08);
padding: 2rem 0;
}

.pickup-availability-list__item:first-child {
border-top: .1rem solid rgba(18,18,18,.08);

}

.pickup-availability-list__item > * {
margin: 0;
}

.pickup-availability-list__item > * + * {
margin-top: 1rem;
}

.pickup-availability-address {
font-style: normal;
font-size: .8rem;
line-height: calc(1 + 0.5 / var(--font-size-base));
}

.pickup-availability-address p {
margin: 0;
}

@keyframes animateDrawerOpen {
@media screen and (max-width: 749px) {
0% {
opacity: 0;
transform: translateX(100%);
}

100% {
opacity: 1;
transform: translateX(0);
}
}

@media screen and (min-width: 750px) {
0% {
opacity: 0;
transform: translateX(100%);
}

100% {
opacity: 1;
transform: translateX(0);
}
}
}
  • Click Save

 

3- Add the JS file

 

  • Under Assets, click Add a new asset > Create a blank file
  • Select .js in the dropdown menu
  • Name the file pickup-availability

  • Copy and paste the below code into the new created file
if (!customElements.get('pickup-availability')) {
  customElements.define('pickup-availability', class PickupAvailability extends HTMLElement {
    constructor() {
      super();

      if(!this.hasAttribute('available')) return;

      this.errorHtml = this.querySelector('template').content.firstElementChild.cloneNode(true);
      this.onClickRefreshList = this.onClickRefreshList.bind(this);
      this.fetchAvailability(this.dataset.variantId);
    }

    fetchAvailability(variantId) {
      const variantSectionUrl = `${this.dataset.baseUrl}variants/${variantId}/?section_id=pickup-availability`;

      fetch(variantSectionUrl)
        .then(response => response.text())
        .then(text => {
          const sectionInnerHTML = new DOMParser()
            .parseFromString(text, 'text/html')
            .querySelector('.shopify-section');
          this.renderPreview(sectionInnerHTML);
        })
        .catch(e => {
          const button = this.querySelector('button');
          if (button) button.removeEventListener('click', this.onClickRefreshList);
          this.renderError();
        });
    }

    onClickRefreshList(evt) {
      this.fetchAvailability(this.dataset.variantId);
    }

    renderError() {
      this.innerHTML = '';
      this.appendChild(this.errorHtml);

      this.querySelector('button').addEventListener('click', this.onClickRefreshList);
    }

    renderPreview(sectionInnerHTML) {
      const drawer = document.querySelector('pickup-availability-drawer');
      if (drawer) drawer.remove();
      if (!sectionInnerHTML.querySelector('pickup-availability-preview')) {
        this.innerHTML = "";
        this.removeAttribute('available');
        return;
      }

      this.innerHTML = sectionInnerHTML.querySelector('pickup-availability-preview').outerHTML;
      this.setAttribute('available', '');

      document.body.appendChild(sectionInnerHTML.querySelector('pickup-availability-drawer'));

      this.querySelector('button').addEventListener('click', (evt) => {
        document.querySelector('pickup-availability-drawer').show(evt.target);
      });
    }
  });
}

if (!customElements.get('pickup-availability-drawer')) {
  customElements.define('pickup-availability-drawer', class PickupAvailabilityDrawer extends HTMLElement {
    constructor() {
      super();

      this.onBodyClick = this.handleBodyClick.bind(this);

      this.querySelector('button').addEventListener('click', () => {
        this.hide();
      });

      this.addEventListener('keyup', () => {
        if(event.code.toUpperCase() === 'ESCAPE') this.hide();
      });
    }

    handleBodyClick(evt) {
      const target = evt.target;
      if (target != this && !target.closest('pickup-availability-drawer') && target.id != 'ShowPickupAvailabilityDrawer') {
        this.hide();
      }
    }

    hide() {
      this.removeAttribute('open');
      document.body.removeEventListener('click', this.onBodyClick);
      document.body.classList.remove('overflow-hidden');
      removeTrapFocus(this.focusElement);
    }

    show(focusElement) {
      this.focusElement = focusElement;
      this.setAttribute('open', '');
      document.body.addEventListener('click', this.onBodyClick);
      document.body.classList.add('overflow-hidden');
      trapFocus(this);
    }
  });
};
    jQuery(document).ready(function($){
      function setVariant(){
        let variant_html = '';

        if($('.swatch').length > 0){
          $('.swatch').each(function(i, swatch){
            let swatches_array = [];
            let checked_values = $(swatch).find('input:checked');
            let swatch_header = $(swatch).find('.header').text();
            
            $.each(checked_values, function(j, checked_value){
              swatches_array.push($(checked_value).val());
            });
            
            if(i > 0){
            	variant_html += ", ";
            }
            	variant_html += swatch_header + ": ";
            	variant_html += '<span>' + swatches_array.join(', ') + '</span>';
          });
        }
        
        if($('.selector-wrapper:visible').length > 0){
          $('.selector-wrapper:visible').each(function(i, selector_wrapper){
            if(i > 0){
            	variant_html += ", ";
            }
			 	variant_html += $(selector_wrapper).find('label').text() + ": ";
            	variant_html += '<span>' + $(selector_wrapper).find('select').val() + '</span>';
          });
        }
        
        $('.pickup-availability-variant').html(variant_html);
      }
      $('.swatch input').change(function(){
      	setVariant();
      });
      
      $('.single-option-selector').change(function(){
        console.log('change');
      	setVariant();
      });
    });
  • Click Save

 

4- Add the icons

  • Under Snippets, click Add a new snippet
  • Name the file icon-close
  • Paste this code into it
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" role="presentation" class="icon icon-close" fill="none" viewBox="0 0 18 17">
<path d="M.865 15.978a.5.5 0 00.707.707l7.433-7.431 7.579 7.282a.501.501 0 00.846-.37.5.5 0 00-.153-.351L9.712 8.546l7.417-7.416a.5.5 0 10-.707-.708L8.991 7.853 1.413.573a.5.5 0 10-.693.72l7.563 7.268-7.418 7.417z" fill="currentColor">
</svg>
  • Click Save
  • Create a new snippet and name it icon-tick
  • Paste into it this code
<svg class="icon icon-tick" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
<path fill="#108043" stroke="#fff" d="M16.136 6.979h0l.003-.004a1.499 1.499 0 00-2.275-1.954l-5.945 6.777-1.858-1.859A1.499 1.499 0 103.94 12.06l2.999 3s0 0 0 0c.289.29.675.44 1.1.439h.019a1.5 1.5 0 001.08-.522l6.998-7.998z"/>
</svg>
  • Click Save
  • Create a new snippet and name it icon-unavailable
  • Paste this into this file
<svg xmlns="http://www.w3.org/2000/svg" fill="none" aria-hidden="true" focusable="false" role="presentation" class="icon icon-unavailable" fill="none" viewBox="0 0 20 20">
<path fill="#DE3618" stroke="#fff" d="M13.94 3.94L10 7.878l-3.94-3.94A1.499 1.499 0 103.94 6.06L7.88 10l-3.94 3.94a1.499 1.499 0 102.12 2.12L10 12.12l3.94 3.94a1.497 1.497 0 002.12 0 1.499 1.499 0 000-2.12L12.122 10l3.94-3.94a1.499 1.499 0 10-2.121-2.12z"/>
</svg>
  • Click Save

 

5- Add the code into the product page

 

  • Plak Theme has 3 product page templates, in order to add the pickup availability in all of them, open the files : prod-template1.liquid, prod-template2.liquid, prod-template2.liquid
  • Just under this code
{% endform %}
  • Paste the below code
{{ 'component-pickup-availability.css' | asset_url | stylesheet_tag }}

{%- assign pick_up_availabilities = product.selected_or_first_available_variant.store_availabilities | where: 'pick_up_enabled', true -%}

<pickup-availability class="product__pickup-availabilities "
{% if product.selected_or_first_available_variant.available and pick_up_availabilities.size > 0 %} available{% endif %}
data-base-url="{{ shop.url }}{{ routes.root_url }}"
data-variant-id="{{ product.selected_or_first_available_variant.id }}"
data-has-only-default-variant="{{ product.has_only_default_variant }}"
>
<template>
<pickup-availability-preview class="pickup-availability-preview">
{% render 'icon-unavailable' %}
<div class="pickup-availability-info">
<p class="caption-large">{{ 'products.product.pickup_availability.unavailable' | t }}</p>
<button class="pickup-availability-button link link--text underlined-link">{{ 'products.product.pickup_availability.refresh' | t }}</button>
</div>
</pickup-availability-preview>
</template>
</pickup-availability>
<script src="{{ 'pickup-availability.js' | asset_url }}" defer="defer"></script>
  • Click Save
  • The final code will look like this

 

if you are offering Pickup on your online store by following Shopify requirements, the the pickup availability feature will now show up just under the add to cart/buy now buttons.

If you have any questions regarding this feature, feel free to comment below

Katrine 

Katrine | Technical support at Plak, Scrowp & Vantout
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as a Solved Solution


   
Quote
Share:

Welcome to the Shopify Forum Community provided by Plak ThemeLLC, a place where you can discuss about eCommerce and Shopify, solve technical issues, get help with Shopify Design, Apps integration, Marketing, Facebooks ad, Google ads and more.

Before posting, we invite you to read and follow the forum rules | We also support any questions related to Free Shopify themes :Dawn, Express, Minimal, Brooklyn, Narrative, Supply, Debut, Venture, Boundless and Simple