Skip to content

Instantly share code, notes, and snippets.

@kagaim
Created May 11, 2021 08:37
Show Gist options
  • Save kagaim/1104849153258d37157b372eb913fd01 to your computer and use it in GitHub Desktop.
Save kagaim/1104849153258d37157b372eb913fd01 to your computer and use it in GitHub Desktop.
Using Shopify Storefront API to fetch recent posts, blog names and implement load more posts functionality
// Recent Posts
const container = document.querySelector('#blog-posts');
const load_more = document.querySelector('#load-more');
const spinner = document.querySelector("#spinner");
const cat_list = document.querySelector('#sidebar-cat-list');
const rp_title = document.querySelector('#sidebar-recent-posts');
function showSpinner() {
spinner.style.display = 'block';
}
function hideSpinner() {
spinner.style.display = 'none';
}
function showLoadMore() {
load_more.style.display = 'inline-block';
}
function hideLoadMore() {
load_more.style.display = 'none';
}
// API Call
function apiCall(query, variables) {
return fetch('https://[shopify store name].myshopify.com/api/2021-04/graphql.json', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
"Access-Control-Origin": "*",
'X-Shopify-Storefront-Access-Token': "[Hashed Password]"
},
"body": JSON.stringify({
query,
variables
})
}).then(response => response.json());
}
// Parse Returned Posts
function appendToDiv(div, new_html) {
// Put the new HTML into a temp div
// This causes browser to parse it as elements.
var temp = document.createElement('div');
temp.innerHTML = new_html;
// Then we can find and work with those elements.
// Use firstElementChild b/c of how DOM treats whitespace.
var class_name = temp.firstElementChild.className;
var items = temp.getElementsByClassName(class_name);
var len = items.length;
for(i=0; i < len; i++) {
div.appendChild(items[0]);
}
}
// Parse Returned List Items
function appendToLI(li, new_html) {
// Put the new HTML into a temp div
// This causes browser to parse it as elements.
var temp = document.createElement('li');
temp.innerHTML = new_html;
// Then we can find and work with those elements.
// Use firstElementChild b/c of how DOM treats whitespace.
var class_name = temp.firstElementChild.className;
var items = temp.getElementsByClassName(class_name);
var len = items.length;
for(i=0; i < len; i++) {
li.appendChild(items[0]);
}
}
hideLoadMore();
showSpinner();
// Recent Posts Query
const recentPostsQuery = `{
articles(first: 4, reverse: true) {
edges {
node {
title
url
publishedAt
image(crop: CENTER, maxHeight: 600, maxWidth: 600) {
src
}
blog {
title
}
}
cursor
}
pageInfo {
hasNextPage
}
}
blogs(first: 20, sortKey: TITLE) {
edges {
node {
title
url
}
}
}
}`;
// Load More Posts Query
const loadMorePostsQuery = `query loadMorePosts($after: String) {
articles(first: 4, reverse: true, after: $after) {
edges {
node {
title
url
publishedAt
image(crop: CENTER, maxHeight: 600, maxWidth: 600) {
src
}
blog {
title
}
}
cursor
}
pageInfo {
hasNextPage
}
}
blogs(first: 20, sortKey: TITLE) {
edges {
node {
title
url
}
}
}
}`;
// Send Query via API
apiCall(recentPostsQuery).then(response => {
// Categories
let categories = response.data.blogs.edges;
categories.forEach(blogCategories);
// Recent Posts
let next_page = response.data.articles;
let has_next_page = next_page.pageInfo.hasNextPage;
if(has_next_page) {
load_more.setAttribute('data-cursor', next_page.edges[3].cursor);
}
let posts = response.data.articles.edges;
posts.forEach(recentPosts);
hideSpinner();
showLoadMore();
});
// Categories Function
function blogCategories(cat) {
let list = `
<li class="sb__cat-item"><a class="sb__cat-link" href="${cat.node.url}">${cat.node.title}</a></li>
`;
appendToLI(cat_list,list);
}
// Recent Posts Function
function recentPosts(article, div, new_html) {
let mydate = new Date(article.node.publishedAt);
let month = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][mydate.getMonth()];
let day = mydate.getDate();
let date = month + ' ' + day + ', ' + mydate.getFullYear();
let post = `
<article class="rp-col">
<a href="${article.node.url}" class="card" aria-label="${article.node.title}">
<img class="lazyloaded" src="${article.node.image.src}" alt="${article.node.title}">
<div class="card-body">
<h3>${article.node.title}</h3>
<p>${date}</p>
<p>${article.node.blog.title}</p>
</div>
</a>
</article>
`;
let title = `
<li class="rp__title-item"><a class="rp__title-link" href="${article.node.url}">${article.node.title}</a></li>
`;
// append results to end of blog posts
appendToDiv(container, post);
// append recent post titles to sidebar
appendToLI(rp_title,title);
}
// Load More Button Click Event
load_more.addEventListener('click', () => {
hideLoadMore();
showSpinner();
let cursor = load_more.getAttribute('data-cursor');
let variables = {
"after": cursor
}
apiCall(loadMorePostsQuery,variables).then(response => {
let next_page = response.data.articles;
let has_next_page = next_page.pageInfo.hasNextPage;
if(has_next_page) {
load_more.setAttribute('data-cursor', next_page.edges[3].cursor);
} else {
load_more.innerHTML = "No more posts"
load_more.disabled = true;
}
let posts = response.data.articles.edges;
posts.forEach(recentPosts);
hideSpinner();
showLoadMore();
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment