← back to Glassbeadedwallpaper
fetch-glass-bead-products.js
325 lines
require('dotenv').config();
const axios = require('axios');
const fs = require('fs');
const SHOPIFY_STORE = process.env.SHOPIFY_STORE_NAME;
const ACCESS_TOKEN = process.env.SHOPIFY_ACCESS_TOKEN;
const API_VERSION = process.env.SHOPIFY_API_VERSION || '2024-10';
// Shopify Admin API GraphQL endpoint
const GRAPHQL_ENDPOINT = `https://${SHOPIFY_STORE}.myshopify.com/admin/api/${API_VERSION}/graphql.json`;
async function fetchAllProducts() {
console.log('🔍 Fetching glass bead, sequin, and glitter products from Shopify...');
const allProducts = [];
let hasNextPage = true;
let cursor = null;
// Search for products with "glass bead", "sequin", or "glitter" in title/tags
const searchQueries = [
'glass bead',
'glass beaded',
'sequin',
'glitter'
];
for (const searchTerm of searchQueries) {
console.log(`\n🔎 Searching for: "${searchTerm}"`);
hasNextPage = true;
cursor = null;
while (hasNextPage) {
const query = `
query ($cursor: String) {
products(first: 250, after: $cursor, query: "${searchTerm} status:active") {
edges {
cursor
node {
id
title
handle
description
descriptionHtml
productType
vendor
tags
createdAt
updatedAt
status
variants(first: 10) {
edges {
node {
id
title
sku
price
inventoryQuantity
}
}
}
featuredImage {
url
altText
}
images(first: 5) {
edges {
node {
url
altText
}
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`;
try {
const response = await axios.post(
GRAPHQL_ENDPOINT,
{
query: query,
variables: { cursor: cursor }
},
{
headers: {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': ACCESS_TOKEN
}
}
);
if (response.data.errors) {
console.error('GraphQL Errors:', response.data.errors);
break;
}
const products = response.data.data.products.edges;
// Add products, avoiding duplicates
products.forEach(product => {
const exists = allProducts.find(p => p.node.id === product.node.id);
if (!exists) {
allProducts.push(product);
}
});
hasNextPage = response.data.data.products.pageInfo.hasNextPage;
cursor = response.data.data.products.pageInfo.endCursor;
console.log(` Found ${products.length} products (Total unique: ${allProducts.length})`);
// Rate limiting: wait 500ms between requests
await new Promise(resolve => setTimeout(resolve, 500));
} catch (error) {
console.error('❌ Error fetching products:', error.message);
if (error.response) {
console.error('Response data:', error.response.data);
}
break;
}
}
}
console.log(`\n✅ Total unique products fetched: ${allProducts.length}`);
return allProducts;
}
function filterGlassBeadProducts(products) {
console.log('\n🔍 Processing glass bead, sequin, and glitter products...');
const glassBeadProducts = [];
// Color families for sorting
const colorFamilies = {
'Gold': ['gold', 'golden', 'champagne', 'bronze'],
'Silver': ['silver', 'metallic', 'chrome', 'platinum'],
'White': ['white', 'ivory', 'cream', 'ecru', 'pearl', 'chalk'],
'Black': ['black', 'onyx', 'charcoal', 'ebony', 'midnight'],
'Pink': ['pink', 'blush', 'fuchsia', 'magenta', 'rose'],
'Red': ['red', 'crimson', 'burgundy', 'wine', 'claret'],
'Purple': ['purple', 'plum', 'aubergine', 'amethyst', 'violet', 'lavender'],
'Blue': ['blue', 'navy', 'cobalt', 'azure', 'indigo', 'sapphire', 'aqua', 'teal', 'turquoise'],
'Green': ['green', 'emerald', 'jade', 'olive', 'viridian'],
'Yellow': ['yellow', 'amber', 'citrine'],
'Orange': ['orange', 'coral', 'apricot', 'peach', 'copper'],
'Brown': ['brown', 'chocolate', 'mocha', 'tan', 'camel'],
'Gray': ['gray', 'grey', 'gunmetal', 'slate'],
'Multi': ['multi', 'rainbow', 'iridescent', 'holographic']
};
products.forEach(product => {
const node = product.node;
// Only include ACTIVE products
if (node.status !== 'ACTIVE') {
return;
}
const titleLower = node.title.toLowerCase();
const tagsLower = node.tags.map(t => t.toLowerCase());
const descLower = (node.description || '').toLowerCase();
// Check if product matches our criteria
const matchesGlassBead = titleLower.includes('glass bead') ||
titleLower.includes('glass beaded') ||
tagsLower.some(t => t.includes('glass bead'));
const matchesSequin = titleLower.includes('sequin') ||
tagsLower.some(t => t.includes('sequin'));
const matchesGlitter = titleLower.includes('glitter') ||
tagsLower.some(t => t.includes('glitter'));
// Only include if it matches one of our criteria
if (!matchesGlassBead && !matchesSequin && !matchesGlitter) {
return;
}
// Extract SKU from variants
const variants = node.variants.edges;
const skus = variants.map(v => v.node.sku).filter(sku => sku);
// Determine primary color family
let primaryColor = 'Other';
const tagString = node.tags.join(' ').toLowerCase();
const searchString = `${titleLower} ${tagString}`;
for (const [family, keywords] of Object.entries(colorFamilies)) {
if (keywords.some(keyword => searchString.includes(keyword))) {
primaryColor = family;
break;
}
}
// Determine product category
let category = 'Glass Beaded';
if (matchesSequin) category = 'Sequin';
if (matchesGlitter) category = 'Glitter';
if (matchesGlassBead && matchesSequin) category = 'Glass Beaded & Sequin';
glassBeadProducts.push({
id: node.id,
title: node.title,
handle: node.handle,
description: node.description,
vendor: node.vendor,
productType: node.productType,
tags: node.tags,
primaryColor: primaryColor,
category: category,
skus: skus,
primarySku: skus[0] || 'N/A',
price: variants[0]?.node.price || '0.00',
image: node.featuredImage?.url || node.images.edges[0]?.node.url,
imageAlt: node.featuredImage?.altText || node.images.edges[0]?.node.altText,
productUrl: `https://designerwallcoverings.com/products/${node.handle}`,
status: node.status,
createdAt: node.createdAt,
fireRated: true // All products are Class A Fire Rated
});
console.log(` ✅ ${node.title} (SKU: ${skus.join(', ')}) - ${category}`);
});
console.log(`\n✅ Found ${glassBeadProducts.length} active glass bead/sequin/glitter products`);
return glassBeadProducts;
}
function sortByColor(products) {
console.log('\n🎨 Sorting products by color...');
// Define color order
const colorOrder = [
'Gold', 'Silver', 'White', 'Black', 'Pink', 'Red',
'Purple', 'Blue', 'Green', 'Yellow', 'Orange',
'Brown', 'Gray', 'Multi', 'Other'
];
// Sort products by color family
const sorted = products.sort((a, b) => {
const indexA = colorOrder.indexOf(a.primaryColor);
const indexB = colorOrder.indexOf(b.primaryColor);
if (indexA !== indexB) {
return indexA - indexB;
}
// Within same color, sort by title
return a.title.localeCompare(b.title);
});
// Count products per color
const colorCounts = {};
const categoryCounts = {};
sorted.forEach(p => {
colorCounts[p.primaryColor] = (colorCounts[p.primaryColor] || 0) + 1;
categoryCounts[p.category] = (categoryCounts[p.category] || 0) + 1;
});
console.log('\n📊 Products per color:');
colorOrder.forEach(color => {
if (colorCounts[color]) {
console.log(` ${color}: ${colorCounts[color]} products`);
}
});
console.log('\n📊 Products per category:');
Object.entries(categoryCounts).forEach(([category, count]) => {
console.log(` ${category}: ${count} products`);
});
return sorted;
}
async function main() {
try {
console.log('🚀 Starting Glass Bead Product Fetch Process\n');
console.log(`Store: ${SHOPIFY_STORE}`);
console.log(`API Version: ${API_VERSION}\n`);
// Fetch all products
const allProducts = await fetchAllProducts();
// Filter glass bead products
const glassBeadProducts = filterGlassBeadProducts(allProducts);
// Sort by color
const sortedProducts = sortByColor(glassBeadProducts);
// Save to JSON file
const outputPath = './glass-bead-products.json';
fs.writeFileSync(outputPath, JSON.stringify(sortedProducts, null, 2));
console.log(`\n💾 Saved ${sortedProducts.length} products to ${outputPath}`);
// Generate a summary
console.log('\n📊 SUMMARY:');
console.log(` Total Products Searched: ${allProducts.length}`);
console.log(` Glass Bead/Sequin/Glitter Products: ${glassBeadProducts.length}`);
console.log(` All products are Class "A" Fire Rated`);
// Show first 5 products
console.log('\n📦 Sample Products:');
glassBeadProducts.slice(0, 5).forEach((product, index) => {
console.log(` ${index + 1}. ${product.title}`);
console.log(` SKU: ${product.primarySku}`);
console.log(` Category: ${product.category}`);
console.log(` URL: ${product.productUrl}`);
});
} catch (error) {
console.error('\n❌ Fatal Error:', error.message);
process.exit(1);
}
}
main();