Shopify FAQ page template with automatic questions and answers using jQuery

<div class="page-title clearfix">
  <div class="page-title-inner">
    <div class="page-title-title">
      <h1 class="sweetsansmedium"><span>{{ page.title }}</span></h1>
    </div>
  </div>            
</div>
<div class="page-wrapper clearfix faq">
  <div class="page-container">
    <div class="rte page-container-content">
      {{ page.content }}
    </div>
  </div>
  <div class="page-follow">
    {% include 'help-menu' %}
  </div>
</div>

<script>
 jQuery(function($) {
   
   $('.page-container-content').children(':not(h1):not(h2)').hide();
   $('.page-container-content h2').click(function() {
        $(this).toggleClass('open');
        $(this).nextUntil('h2').toggle();
     	
    });

   }); 
</script>

Conditional click events on a Youtube Video (check state if playing or stopped)

I wanted to create on click events:

  • When the video playing send user to another page
  • When the video is stopped, re-start the video

Requried javascript API:

<script src="https://www.youtube.com/iframe_api"></script>

HTML mark-up

<div class="herovideo"> <!-- this is the wrapper //-->
  <div class="herovideo-clicker"></div> <!-- this is the clicker //-->
  <div class="video-wrapper"> <!-- this is a responsive wrapper //-->
    <div id="video-placeholder"></div> <!-- this gets replaced with iframe //-->
  </div>
</div>

CSS:

<style>
	.video-wrapper {   }
	.herovideo { position:relative;  }
	.herovideo-clicker { z-index:99; position:absolute; width: 100%; height: 100%; cursor:pointer;}
	.herovideo .video-wrapper { position:relative; z-index:9; }
</style>

Javascript that will:

  • Initialise the player and define it’s appearance
  • Do the responsive resizing
  • On stae change, set the click event
<script>

var player;
function onYouTubeIframeAPIReady() {
	player = new YT.Player('video-placeholder', {
		width: 1280,
		height: 720,
		videoId: 'Write your Youtube Video ID here',
		playerVars: {
			modestbranding: 1,
			autoplay: 1,
			controls: 0,
			enablejsapi: 1,
			fs: 0,
			rel: 0,
			showinfo: 0,
			color: 'white'
		},
		events: {
			onReady: initialize,
			onStateChange: onytplayerStateChange
		}
	});
}

function initialize(){

	var $allVideos = $("iframe[src*='//player.vimeo.com'], iframe[src*='//www.youtube.com'], object, embed"),
		$fluidEl = $(".video-wrapper");

	$allVideos.each(function() {
	  $(this)
	  .attr('data-aspectRatio', this.height / this.width)
	  .removeAttr('height')
	  .removeAttr('width');
	});

	var newWidth = $fluidEl.width();
	  $allVideos.each(function() {
		var $el = $(this);
		$el
		.width(newWidth)
		.height(newWidth * $el.attr('data-aspectRatio'));
	  });

}
  
function onytplayerStateChange(newState) {

  if(newState.data == 1) {
	 // take the user to a new page while the video is playing
	 $( ".herovideo-clicker").unbind( "click" );
	 $('.herovideo-clicker').on('click', function(){
		window.location.href = 'write your URL here'; 
		return false;
	 });
  } else  {
	// restart the video if it is not playing
	$( ".herovideo-clicker").unbind( "click" );
	$('.herovideo-clicker').on('click', function(){
		player.playVideo();
		return false;
	});
  }
}

</script>

References:

  • https://github.com/chriscoyier/Fluid-Width-Video
  • https://developers.google.com/youtube/iframe_api_reference

Search suggestions for Shopify

Add a search form to your theme:

<form action="/search" method="get" role="search" id="header-search">
<input type="hidden" name="type" value="product">
<label for="q">{{ 'general.search.placeholder' | t }}</label>
<input type="search" id="q" name="q" value="{{ search.terms | escape }}" class="input-group-field" />
<input type="submit" value="{{ 'general.search.submit' | t }}" class="input-group-field" />
</form>

Create a template called search.json.liquid

{% layout none %}
{% capture results %}
  {% for item in search.results %}
    {% assign product = item %}
    { 
      "vendor"    : {{ product.vendor | json }},
      "title"    : {{ product.title | json }},
      "url"      : {{ product.url | within: product.collections.last | json }},
      "thumbnail": {{ product.featured_image.src | product_img_url: 'thumb' | json }}
    }
    {% unless forloop.last %},{% endunless %}
  {% endfor %}
{% endcapture %}
{
  "results_count": {{ search.results_count }},
  "results": [{{ results }}]
}

Create this snippet and add to theme layout.

<script>
$(function() {
  // Current Ajax request.
  var currentAjaxRequest = null;
  // Grabbing all search forms on the page, and adding a .search-results list to each.
  var searchForms = $('form[action="/search"]').css('position','relative').each(function() {
    // Grabbing text input.
    var input = $(this).find('input[name="q"]');
    // Adding a list for showing search results.
    var offSet = input.position().top + input.innerHeight();
    $('<ul class="search-results"></ul>').appendTo($(this)).hide();    
    // Listening to keyup and change on the text field within these search forms.
    input.attr('autocomplete', 'off').bind('keyup change input propertychange', function() {
      // What's the search term?
      var term = $(this).val();
      // What's the search form?
      var form = $(this).closest('form');
      // What's the search URL?
      var searchURL = '/search?type=product&q=' + term;
      // What's the search results list?
      var resultsList = form.find('.search-results');
      // If that's a new term and it contains at least 3 characters.
      if (term.length > 3 && term != $(this).attr('data-old-term')) {
        // Saving old query.
        $(this).attr('data-old-term', term);
        // Killing any Ajax request that's currently being processed.
        if (currentAjaxRequest != null) currentAjaxRequest.abort();
        // Pulling results.
        currentAjaxRequest = $.getJSON(searchURL + '&view=json', function(data) {
          // Reset results.
          resultsList.empty();
          // If we have no results.
          if(data.results_count == 0) {
            // resultsList.html('<li><span class="title">No results.</span></li>');
            // resultsList.fadeIn(200);
            resultsList.hide();
          } else {
            // If we have results.
            $.each(data.results, function(index, item) {
              var link = $('<a></a>').attr('href', item.url);
              link.append('<span class="thumbnail"><img src="' + item.thumbnail + '" /></span>');
              link.append('<span class="title"><strong>' + item.vendor + '</strong><br >' + item.title + '</span>');
              link.wrap('<li></li>');
              resultsList.append(link.parent());
            });
            // The Ajax request will return at the most 10 results.
            // If there are more than 10, let's link to the search results page.
            if(data.results_count > 10) {
              resultsList.append('<li><span class="title"><a href="' + searchURL + '">See all results (' + data.results_count + ')</a></span></li>');
            }
            resultsList.fadeIn(200);
          }        
        });
      }
    });
  });
  // Clicking outside makes the results disappear.
  $('body').bind('click', function(){
    $('.search-results').hide();
  });
});
</script>

Reference: https://help.shopify.com/themes/customization/store/enable-autocomplete-for-search-boxes

Custom Addthis Social Media Sharing Buttons for Shopify (for free)

The process is:

  1. Create a Google Analtyics account and get your site ID
  2. Sign-up to Addthis and get your profile ID
  3. Sign-up to Bitly for URL shortening on Tweets (and get your API username and key)
  4. Add the Shopify Theme settings to your settings_schema.js
  5. Add the javascript to your Shopify theme layout file
  6. Add HTML for sharing buttons to your Shopify pages
  7. Add custom icon font and CSS to style your buttons
  8. Configure the Addthis Custom HTML Email Template
  9. Create a Facebook App and add the id to the settings

Addthis theme settings

Add this code to your Shopify settings_schema.json then click on “customise theme” to enter the right values.

  {
    "name": "Addthis Sharing Settings",
    "settings": [
      {
        "type": "checkbox",
        "id": "addthis_use",
        "label": "Use Addthis?"
      },
      {
        "type": "text",
        "id": "addthis_id",
        "label": "AddThis ID"
      },
      {
        "type": "text",
        "id": "google_analytics_id",
        "label": "Google Analytics ID"
      },
      {
        "type": "text",
        "id": "addthis_twitter_id",
        "label": "Twitter name"
      },
      {
        "type": "text",
        "id": "addthis_twitter_string",
        "label": "Twitter string",
        "default": "*title* Coming Soon. #signup #exclusiveaccess"
      },
      {
        "type": "checkbox",
        "id": "addthis_bitly_use",
        "label": "Use Bitly?"
      },
      {
        "type": "checkbox",
        "id": "addthis_email_template_use",
        "label": "Use custom email template?"
      },
      {
        "type": "text",
        "id": "addthis_email_template_name",
        "label": "Add this email template name",
        "default": "product_template"
      },
      {
        "type": "text",
        "id": "addthis_facebook_app_id",
        "label": "Facebook App ID"
      },
      {
        "type": "text",
        "id": "addthis_facebook_redirect_url",
        "label": "Facebook Redirect URL"
      }
    ]
  }

Addthis Javascript

Create a new snippet called “addthis.liquid” and add it to the end of your theme (before end of body tags) using {% include ‘addthis’ %}

{% if settings.addthis_use %}
<script>
  jQuery(function($) {
    initAddThis();
    jQuery('.sharenulify').on('click', function (e) {
      return false;
    });
  });
  function initAddThis() 
  {
    if ( typeof( window[ 'addthis' ] ) != "undefined" ) {
      addthis.init()
    } 
  }
</script> 

{% capture addthis_title %}{% endcapture %}
{% capture addthis_description %}{% endcapture %}
{% capture addthis_image %}{% endcapture %}
{% if template contains 'product' %}
  {% capture addthis_title %}{{ product.title | strip_html | escape }}{% endcapture %}
  {% capture addthis_description %}{{ product.description | strip_html | strip_newlines | truncatewords: 30, '' | escape }}{% endcapture %}
  {% capture addthis_image %}https:{{ product.featured_image | img_url: 'large' }}{% endcapture %}
{% elsif template contains 'article' %}
  {% capture addthis_title %}{{ article.title | strip_html | escape }}{% endcapture %}
  {% capture addthis_description %}{{ article.excerpt_or_content | strip_html | strip_newlines | truncatewords: 30, '' | escape }}{% endcapture %}
  {% if article.image %}
    {% capture addthis_image %}https:{{ article.image.src | img_url: 'large' }}{% endcapture %}
  {% endif %}
{% elsif template contains 'page' %}
  {% capture addthis_title %}{{ page.title | strip_html | escape }}{% endcapture %}
  {% capture addthis_description %}{{ page.content | strip_html | strip_newlines | truncatewords: 30, '' | escape }}{% endcapture %}
  {% assign img_tag = '<' | append: 'img' %}
  {% if page.content contains img_tag %}
    {% assign src = page.content | split: 'src="' %}
    {% assign src = src[1] | split: '"' | first | remove: 'https:' | remove: 'http:' | replace: '_small.', '_large.' %}
    {% capture addthis_image %}https:{{ src }}{% endcapture %}
  {% endif %}
{% else %}
  {% capture addthis_title %}{{ page_title | escape }}{% endcapture %}
  {% if page_description %}{% capture addthis_description %}{{ page_description | escape }}{% endcapture %}{% endif %}
{% endif %}

{% capture addthis_twitter_string_calculated %}{{ settings.addthis_twitter_string | replace: '*title*', addthis_title }}{% endcapture %}  
<script type="text/javascript">
  var addthis_config = {
    {% if settings.google_analytics_id.size > 0 %}
    data_ga_property: '{{ settings.google_analytics_id }}',
    data_ga_social : true,
    {% endif %}
    "data_track_addressbar":false,
    ui_use_css : true,
    image_include: "at_include",
    image_exclude: "at_exclude"
  };
  addthis_share = {
    {% if settings.addthis_bitly_use %}
    url_transforms : {
      shorten: {
        twitter: 'bitly',
        facebook: 'bitly'
      }
    }, 
    shorteners : {
      bitly : {} 
    },
    {% endif %}
    url: "{{ canonical_url }}",
    title: "{{ addthis_title }}",
    description: "{{ addthis_description }}",
    passthrough : {
      twitter: {
        {% if settings.addthis_twitter_id.size > 0 %}via: "{{ settings.addthis_twitter_id }}",{% endif %}
        text: "{{ addthis_twitter_string_calculated }}"
      }{% if settings.addthis_facebook_app_id.size > 0 %},
      facebook: {
        app_id: '{{ settings.addthis_facebook_app_id }}',
        redirect_uri: '{{ settings.addthis_facebook_redirect_url }}',
      }{% endif %}
    }
    {% if settings.addthis_email_template_use and addthis_image.size > 0 %},
    email_template: "{{ settings.addthis_email_template_name }}",
    email_vars: { 
      thisTitle: "{{ addthis_title }}" ,
      thisDescription: "{{ addthis_description }}", 
      thisImage: "{{ addthis_image }}" ,
    }
    {% endif %}
  }
</script>        
<script type="text/javascript" src="https://s7.addthis.com/js/300/addthis_widget.js#pubid={{ settings.addthis_id }}" async="async"></script>
{% endif %}

HTML for share buttons

Create a new snippet called “addthis-share-buttons.liquid” and add it on any page you like using {% include ‘addthis-share-buttons’ %}

<div class="product-share">
  <a class="product-share-button" href="#">Share</a>
  <div class="share">
    <ul>
      <li><a class="tooltip sharebutton addthis_button_facebook" id="share_facebook" title="Share {{ mysharetitle }} on Facebook"><i class="fa fa-facebook"></i></a></li>
      <li><a class="tooltip sharebutton addthis_button_twitter" id="share_twitter" title="Share {{ mysharetitle }} on Twitter"><i class="fa fa-twitter"></i></a></li>
      <li><a class="tooltip sharebutton addthis_button_tumblr" id="share_tumblr" title="Share {{ mysharetitle }} on Tumblr"><i class="fa fa-tumblr"></i></a></li>
      <li><a class="tooltip sharebutton sharenulify addthis_button_pinterest_share" id="share_pinterest" title="Share {{ mysharetitle }} on Pinterest"><i class="fa fa-pinterest"></i></a></li>
      <li><a class="tooltip sharebutton addthis_button_email" id="share_email" title="Send  {{ mysharetitle }} to a friend by Email"><i class="fa fa-envelope-o"></i></a></li>
      <li><a class="tooltip sharebutton addthis_button_compact" id="share_other" title="More share options"><i class="fa fa-bookmark"></i></a></li>
    </ul>
  </div>
</div>

Use CSS to style your buttons

For Fontawesome icons, remember to add the font css to your theme file.

.product-share-button, .share { display:inline-block; }
.share ul { display:inline-block; list-style:none; margin:0; padding:0; }
.share li {  margin:0; padding:0; display:inline-block; }
.share li a { display:inline-block; margin:0; padding:10px; font-size:18px; line-height: 38px;}

Validate Magento form fields as you type with jQuery


jQuery('.input-text').on('blur', function(){
		Validation.validate(this);
	});
	

Set cookie with form values before submit

Use jquery cookie plugin.


<script>
  $('#formid').submit(function(e) {
    var field = $('#fieldid').val();
    $.cookie('field', field, { expires: 1, path: '/' });  
  });
</script>

Reposition element to the bottom right of another element


// resize grid gaps onload and onresize
function reposition_popup(e, t)
{
var windowwidth = $( window ).width();
var windowheight = $( window ).height();
if (windowwidth < 480) { // small } else { // other } var offset = t.offset(); var height = t.height(); var width = t.width(); farright = offset.left + width - 40; // change this constant farbottom = offset.top + height - 40; // change this constant var popupheight = e.height(); var popupwidth = e.width(); newtop = farbottom - popupheight; newleft = farright - popupwidth; $( e ).css({ "position": "fixed", "top": newtop+'px', "left": newleft+'px' }); }