Shopify 블로그 내부 링크
고급
이것은Content Creation, AI Summarization분야의자동화 워크플로우로, 26개의 노드를 포함합니다.주로 If, Set, Code, DataTable, HttpRequest 등의 노드를 사용하며. OpenAI text-embedding-3-small를 사용하여 Shopify 블로그 관련 게시물 자동 생성
사전 요구사항
- •대상 API의 인증 정보가 필요할 수 있음
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
"id": "01ZGpwv1rdsk5Ng8",
"meta": {
"instanceId": "8e9162e70be518ca153a70a16d8785f5bfc6523821e135712fb7ef93fe97a5dd",
"templateCredsSetupCompleted": true
},
"name": "Internal linking shopify blog",
"tags": [],
"nodes": [
{
"id": "8848b159-986e-4b67-8bde-a38da0a25f36",
"name": "스케줄 트리거",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1808,
496
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtHour": 20
}
]
}
},
"typeVersion": 1.2
},
{
"id": "057f8499-694c-4391-80a1-e2f7ca093d25",
"name": "워크플로우 설정",
"type": "n8n-nodes-base.set",
"position": [
-1584,
496
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "566ed7c6-84cf-4fcf-ae6e-5607fa4c3909",
"name": "shopifyBlogId",
"type": "string",
"value": ""
},
{
"id": "bdcbb25a-eba1-4a26-bc4e-e4dd8eb268db",
"name": "shopifyBlogDomain",
"type": "string",
"value": "<https://example.com/blogs/>"
},
{
"id": "6f1aaf1c-eb2f-42ac-b16e-6e4cd8cabd9f",
"name": "shopifyStoreName",
"type": "string",
"value": "<domain_before_myshopify.com>"
},
{
"id": "d704d6dd-d887-40d3-9f3b-1a61010095d2",
"name": "shopApiVersion",
"type": "string",
"value": "2025-07"
},
{
"id": "027f4123-2194-4f6d-8411-1305e7602692",
"name": "percent_minimum_similarity",
"type": "number",
"value": 70
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ce7cbd23-b0ec-4420-a262-cc16ddd9f5bd",
"name": "Shopify에서 글 가져오기",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1360,
496
],
"parameters": {
"url": "=https://{{ $('Workflow Configuration').first().json.shopifyStoreName }}.myshopify.com/admin/api/{{ $('Workflow Configuration').first().json.shopApiVersion }}/blogs/{{ $('Workflow Configuration').first().json.shopifyBlogId }}/articles.json",
"options": {},
"sendQuery": true,
"authentication": "predefinedCredentialType",
"queryParameters": {
"parameters": [
{
"name": "published_status",
"value": "published"
}
]
},
"nodeCredentialType": "shopifyAccessTokenApi"
},
"credentials": {
"shopifyAccessTokenApi": {
"id": "oDrAi4lTTxnawLSv",
"name": "Shopify Access Token account 2"
}
},
"typeVersion": 4.2
},
{
"id": "3623adca-6827-467c-81f7-6f138377aefd",
"name": "텍스트 정리 및 준비",
"type": "n8n-nodes-base.code",
"position": [
-1136,
496
],
"parameters": {
"jsCode": "// Function to clean HTML and remove the related section\nfunction stripHtml(html) {\n if (!html) return '';\n return html\n .replace(/<style[^>]*>.*?<\\/style>/gi, '')\n .replace(/<script[^>]*>.*?<\\/script>/gi, '')\n .replace(/<div class=\"related-articles\"[^>]*>[\\s\\S]*?<\\/div>/gi, '') // remove related articles \n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s+/g, ' ')\n .replace(/ /g, ' ')\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .trim();\n}\n\n// Detect what we receive from previous node\nlet allItems = $input.all();\nlet articles = [];\n\n// 1: if multiple items\nif (allItems.length > 0) {\n allItems.forEach(item => {\n // Verificar si el item contiene un array \"articles\"\n if (item.json && Array.isArray(item.json.articles)) {\n articles = articles.concat(item.json.articles);\n } \n // if only one item\n else if (item.json && item.json.id && item.json.title) {\n articles.push(item.json);\n }\n });\n}\n\n// Fallback if no articles found\nif (articles.length === 0 && $input.item.json) {\n if (Array.isArray($input.item.json.articles)) {\n articles = $input.item.json.articles;\n } else if ($input.item.json.id && $input.item.json.title) {\n articles = [$input.item.json];\n }\n}\n\n\n// Process each article\nconst processedArticles = articles.map(article => {\n const cleanContent = stripHtml(article.body_html);\n const cleanSummary = stripHtml(article.summary_html);\n \n // Create text for embeddings \n const textForEmbedding = `Título: ${article.title}\n\nResumen: ${cleanSummary}\n\nContenido: ${cleanContent.substring(0, 15000)}`;\n\n return {\n shopify_id: article.id,\n blog_id: article.blog_id,\n shopify_handle: article.handle,\n title: article.title,\n content: cleanContent,\n summary: cleanSummary,\n url: $('Workflow Configuration').first().json.shopifyBlogDomain + article.handle,\n published_at: article.published_at,\n text_for_embedding: textForEmbedding,\n word_count: cleanContent.split(/\\s+/).filter(w => w.length > 0).length\n };\n});\n\nreturn processedArticles.map(article => ({ json: article }));"
},
"typeVersion": 2
},
{
"id": "a91f14ad-f42c-4ad9-9ddd-4a218e8b8514",
"name": "항목 반복",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-912,
496
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "8a1ffb69-65c0-4cf5-a4cb-e9209a9dc0ea",
"name": "OpenAI 임베딩 가져오기",
"type": "n8n-nodes-base.httpRequest",
"position": [
-464,
512
],
"parameters": {
"url": "https://api.openai.com/v1/embeddings",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "model",
"value": "text-embedding-3-small"
},
{
"name": "input",
"value": "={{ $json.embedding }}"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "openAiApi"
},
"credentials": {
"openAiApi": {
"id": "F6XMlOYUADkfTF7M",
"name": "OpenAi key"
}
},
"typeVersion": 4.2
},
{
"id": "7d83e353-0272-4857-ad4e-f3baab2e62b6",
"name": "글 필드 설정",
"type": "n8n-nodes-base.set",
"position": [
-688,
512
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "e443624a-de8d-485f-a3a1-b567c3145c2c",
"name": "shopify_id",
"type": "number",
"value": "={{ $json.shopify_id }}"
},
{
"id": "139eedb1-6aa3-434a-9425-fac9234c5148",
"name": "blog_id",
"type": "number",
"value": "={{ $json.blog_id }}"
},
{
"id": "9950f411-833a-488f-9f6a-b17f338114bf",
"name": "shopify_handle",
"type": "string",
"value": "={{ $json.shopify_handle }}"
},
{
"id": "1d83dc8d-c93d-41bb-ba5e-0a01f055c0fe",
"name": "title",
"type": "string",
"value": "={{ $json.title }}"
},
{
"id": "4a2a7109-b8d1-43f7-9d69-6d1f0cbef95a",
"name": "content",
"type": "string",
"value": "={{ $json.content }}"
},
{
"id": "0db25418-7777-4fc2-b774-4abf85819790",
"name": "summary",
"type": "string",
"value": "={{ $json.summary }}"
},
{
"id": "960a20c6-77ae-434a-9646-7b562da78a2e",
"name": "url",
"type": "string",
"value": "={{ $json.url }}"
},
{
"id": "4080709d-46e3-4d5c-b4b8-4cc599fae16c",
"name": "published_at",
"type": "string",
"value": "={{ $json.published_at }}"
},
{
"id": "83f98c7d-6ce7-4b58-9034-72f7b78a59e8",
"name": "embedding",
"type": "string",
"value": "={{ $json.text_for_embedding }})"
},
{
"id": "9a2a581c-2c3b-4a27-bde8-a3a62590a9df",
"name": "analyzed_at",
"type": "string",
"value": "={{new Date().toISOString()}}"
},
{
"id": "3a53791e-f7c6-4cef-ad55-8a37c9239073",
"name": "word_count",
"type": "number",
"value": "={{ $json.word_count }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "55ce71bc-afc1-4178-87a3-6fda9829bd68",
"name": "유사도 계산",
"type": "n8n-nodes-base.code",
"position": [
-688,
48
],
"parameters": {
"jsCode": "const doneItems = $(\"Loop Over Items\").all();\n\nconsole.log(`📦 Total items recibidos: ${doneItems.length}`);\n\n// Extract and prepare articles\nconst allArticles = doneItems.map(item => {\n const data = item.json;\n \n // Parsing embedding\n const embedding = typeof data.embedding === 'string' \n ? JSON.parse(data.embedding) \n : data.embedding;\n \n return {\n shopify_id: data.shopify_id,\n blog_id: data.blog_id,\n title: data.title,\n url: data.url,\n embedding: embedding\n };\n});\n\nconst uniqueIds = new Set(allArticles.map(a => a.shopify_id));\n\nif (allArticles.length < 2) {\n throw new Error(`❌ Se necesitan al menos 2 artículos. Solo hay ${allArticles.length}`);\n}\n\nif (uniqueIds.size < 2) {\n throw new Error(`❌ Todos los artículos tienen el mismo ID (${Array.from(uniqueIds)[0]})`);\n}\n\n// Function to calculate similarities\nfunction cosineSimilarity(vecA, vecB) {\n if (!vecA || !vecB || vecA.length !== vecB.length) {\n throw new Error('❌ Embeddings inválidos o de diferente longitud');\n }\n \n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n \n for (let i = 0; i < vecA.length; i++) {\n dotProduct += vecA[i] * vecB[i];\n normA += vecA[i] * vecA[i];\n normB += vecB[i] * vecB[i];\n }\n \n const similarity = dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));\n return Math.round(similarity * 100 * 100) / 100;\n}\n\nconst relations = [];\nlet comparacionesRealizadas = 0;\n\nfor (let i = 0; i < allArticles.length; i++) {\n for (let j = 0; j < allArticles.length; j++) {\n \n // ⚠️ Rule to avoid comparing one article to itself\n if (allArticles[i].shopify_id === allArticles[j].shopify_id) {\n continue; // Saltar esta iteración\n }\n \n comparacionesRealizadas++;\n \n try {\n const similarity = cosineSimilarity(\n allArticles[i].embedding,\n allArticles[j].embedding\n );\n \n // Only keep similarity above the setting\n if (similarity >= $('Workflow Configuration').first().json.percent_minimum_similarity) {\n relations.push({\n source_shopify_id: allArticles[i].shopify_id,\n source_blog_id: allArticles[i].blog_id,\n source_title: allArticles[i].title,\n related_shopify_id: allArticles[j].shopify_id,\n related_title: allArticles[j].title,\n related_url: allArticles[j].url,\n relation_type: \"semantic_similarity\",\n similarity_score: similarity\n });\n }\n } catch (error) {\n console.error(`Error comparando ${allArticles[i].shopify_id} con ${allArticles[j].shopify_id}:`, error.message);\n }\n }\n}\n\n// In case, not enough similarity\nif (relations.length === 0) {\n return [{ \n json: { \n mensaje: \"No se encontraron relaciones con similitud >= 60%\",\n articulos_procesados: allArticles.length,\n articulos_unicos: uniqueIds.size,\n comparaciones_realizadas: comparacionesRealizadas,\n sugerencia: \"Intenta bajar el umbral de similitud o verifica que los embeddings sean correctos\",\n muestra_articulos: allArticles.slice(0, 3).map(a => ({\n shopify_id: a.shopify_id,\n title: a.title,\n longitud_embedding: a.embedding.length\n }))\n } \n }];\n}\n\nreturn relations.map(rel => ({ json: rel }));"
},
"typeVersion": 2,
"alwaysOutputData": false
},
{
"id": "762e212e-1907-4610-9bcd-cc7b79258172",
"name": "글 업서트",
"type": "n8n-nodes-base.dataTable",
"position": [
-240,
512
],
"parameters": {
"columns": {
"value": {
"url": "={{ $('Set article fields').item.json.url }}",
"title": "={{ $('Set article fields').item.json.title }}",
"blog_id": "={{ $('Set article fields').item.json.blog_id }}",
"content": "={{ $('Set article fields').item.json.content }}",
"summary": "={{ $('Set article fields').item.json.summary }}",
"embedding": "={{ JSON.stringify($json.data[0].embedding) }}",
"shopify_id": "={{ $('Set article fields').item.json.shopify_id }}",
"word_count": "={{ $('Set article fields').item.json.word_count }}",
"published_at": "={{ $('Set article fields').item.json.published_at }}",
"shopify_handle": "={{ $('Set article fields').item.json.shopify_handle }}",
"last_analyzed_at": "={{ $('Set article fields').item.json.analyzed_at }}"
},
"schema": [
{
"id": "shopify_id",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "shopify_id",
"defaultMatch": false
},
{
"id": "shopify_handle",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "shopify_handle",
"defaultMatch": false
},
{
"id": "title",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "title",
"defaultMatch": false
},
{
"id": "content",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "content",
"defaultMatch": false
},
{
"id": "summary",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "summary",
"defaultMatch": false
},
{
"id": "url",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "url",
"defaultMatch": false
},
{
"id": "published_at",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "published_at",
"defaultMatch": false
},
{
"id": "embedding",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "embedding",
"defaultMatch": false
},
{
"id": "last_analyzed_at",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "last_analyzed_at",
"defaultMatch": false
},
{
"id": "word_count",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "word_count",
"defaultMatch": false
},
{
"id": "blog_id",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "blog_id",
"defaultMatch": false
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"filters": {
"conditions": [
{
"keyName": "shopify_id",
"keyValue": "={{ $('Set article fields').item.json.shopify_id }}"
}
]
},
"options": {},
"matchType": "allConditions",
"operation": "upsert",
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "kjtDGPfteUD1V64N",
"cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/kjtDGPfteUD1V64N",
"cachedResultName": "articles"
}
},
"typeVersion": 1
},
{
"id": "6607766a-147e-49b6-b127-6655d3221c8c",
"name": "글 관계 업서트",
"type": "n8n-nodes-base.dataTable",
"position": [
-464,
48
],
"parameters": {
"columns": {
"value": {
"related_url": "={{ $json.related_url }}",
"source_title": "={{ $json.source_title }}",
"related_title": "={{ $json.related_title }}",
"source_blog_id": "={{ $json.source_blog_id }}",
"similarity_score": "={{ $json.similarity_score }}",
"source_shopify_id": "={{ $json.source_shopify_id }}",
"related_shopify_id": "={{ $json.related_shopify_id }}"
},
"schema": [
{
"id": "source_shopify_id",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "source_shopify_id",
"defaultMatch": false
},
{
"id": "source_blog_id",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "source_blog_id",
"defaultMatch": false
},
{
"id": "source_title",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "source_title",
"defaultMatch": false
},
{
"id": "related_shopify_id",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "related_shopify_id",
"defaultMatch": false
},
{
"id": "related_title",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "related_title",
"defaultMatch": false
},
{
"id": "related_url",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "related_url",
"defaultMatch": false
},
{
"id": "relation_type",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "relation_type",
"defaultMatch": false
},
{
"id": "similarity_score",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "similarity_score",
"defaultMatch": false
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"filters": {
"conditions": [
{
"keyName": "source_shopify_id",
"keyValue": "={{ $json.source_shopify_id }}"
},
{
"keyName": "related_shopify_id",
"keyValue": "={{ $json.related_shopify_id }}"
}
]
},
"options": {},
"matchType": "allConditions",
"operation": "upsert",
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "KXwn5vzq2gEz09tM",
"cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/KXwn5vzq2gEz09tM",
"cachedResultName": "article_relations"
}
},
"typeVersion": 1
},
{
"id": "ff514a42-ee01-448a-8951-4b6d82ecff01",
"name": "상위 3개 관련 글",
"type": "n8n-nodes-base.code",
"position": [
-240,
48
],
"parameters": {
"jsCode": "// ============================================\n// GROUP AND GET TOP 3 RELATED ARTICLES\n// ============================================\n\nconst relations = $(\"Calculate similarities\").all().map(item => item.json);\n\n// Group by source_shopify_id\nconst groupedBySource = relations.reduce((acc, relation) => {\n const sourceId = relation.source_shopify_id;\n \n if (!acc[sourceId]) {\n acc[sourceId] = {\n source_shopify_id: sourceId,\n source_blog_id: relation.source_blog_id,\n source_title: relation.source_title,\n source_url: relation.source_url,\n related_articles: []\n };\n }\n \n // Add related article with its similarity score\n acc[sourceId].related_articles.push({\n related_shopify_id: relation.related_shopify_id,\n related_title: relation.related_title,\n related_url: relation.related_url,\n similarity_score: relation.similarity_score\n });\n \n return acc;\n}, {});\n\n// Convert to array and get top 3 for each source\nconst result = Object.values(groupedBySource).map(group => {\n // Sort by similarity_score (highest first) and take top 3\n const top3Related = group.related_articles\n .sort((a, b) => b.similarity_score - a.similarity_score)\n .slice(0, 3)\n .map(article => article.related_shopify_id);\n \n return {\n source_shopify_id: group.source_shopify_id,\n related_shopify_ids: top3Related\n };\n});\n\n// Return as separate items for next node\nreturn result.map(item => ({ json: item }));"
},
"typeVersion": 2
},
{
"id": "088f6ac5-4c84-4c63-ba89-ab778c3ce547",
"name": "원본 글 반복",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-16,
48
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "28f1bf7c-db78-4f1f-8db3-b00474dd7284",
"name": "이전 관련 글 가져오기",
"type": "n8n-nodes-base.dataTable",
"position": [
208,
64
],
"parameters": {
"filters": {
"conditions": [
{
"keyName": "source_shopify_id",
"keyValue": "={{ $json.source_shopify_id }}"
}
]
},
"operation": "get",
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "7RrUjeEF2Zfcxpsn",
"cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/7RrUjeEF2Zfcxpsn",
"cachedResultName": "article_related_links_snapshot"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "268e6a49-f852-4056-b9cf-8b912f5b19e1",
"name": "글에 관련 글이 이미 있는지 확인",
"type": "n8n-nodes-base.if",
"position": [
432,
64
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "6a466a42-552d-4be0-a443-e2907f660ba4",
"operator": {
"type": "number",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.source_shopify_id }}",
"rightValue": "={{ $('Loop for source articles').item.json.related_shopify_ids }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "b41317b7-4a8c-4043-94e8-89b6add1c772",
"name": "관계 업서트",
"type": "n8n-nodes-base.dataTable",
"position": [
688,
80
],
"parameters": {
"columns": {
"value": {
"source_shopify_id": "={{ $('Loop for source articles').item.json.source_shopify_id }}",
"related_shopify_ids": "={{ $('Loop for source articles').item.json.related_shopify_ids.join() }}"
},
"schema": [
{
"id": "source_shopify_id",
"type": "number",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "source_shopify_id",
"defaultMatch": false
},
{
"id": "related_shopify_ids",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "related_shopify_ids",
"defaultMatch": false
},
{
"id": "related_urls",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "related_urls",
"defaultMatch": false
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"filters": {
"conditions": [
{
"keyName": "source_shopify_id",
"keyValue": "={{ $('Loop for source articles').item.json.source_shopify_id }}"
}
]
},
"options": {},
"operation": "upsert",
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "7RrUjeEF2Zfcxpsn",
"cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/7RrUjeEF2Zfcxpsn",
"cachedResultName": "article_related_links_snapshot"
}
},
"typeVersion": 1
},
{
"id": "2d051e8b-9f67-4ed3-8a2a-85d19281452f",
"name": "관련 글을 위한 HTML 준비",
"type": "n8n-nodes-base.code",
"position": [
1344,
80
],
"parameters": {
"jsCode": "// ============================================\n// PREPARE HTML FOR RELATED ARTICLES\n// ============================================\n\n// Get source article ID from \"Upsert relations\" node\nconst sourceArticle = $('Upsert relations').first().json;\nconst sourceShopifyId = sourceArticle.source_shopify_id;\n\n// Get related articles details from \"Get related article details\" node\nconst relatedArticles = $('Get related article details').all().map(i => i.json);\n\n// Build the HTML for related articles section\nlet relatedHTML = `\n<div class=\"related-articles\" style=\"margin: 40px 0;\">\n <h3>📚 Artículos relacionados que te pueden interesar</h3>\n <ul style=\"list-style: none; padding: 0;\">\n`;\n\n// Add each related article as a link\nrelatedArticles.forEach(article => {\n relatedHTML += `\n <li style=\"margin-bottom: 10px;\">\n <a href=\"${article.url}\">→ ${article.title}</a>\n </li>\n `;\n});\n\nrelatedHTML += `\n </ul>\n</div>\n`;\n\nreturn {\n json: {\n source_shopify_id: sourceShopifyId,\n related_articles_html: relatedHTML,\n related_count: relatedArticles.length\n }\n};"
},
"typeVersion": 2
},
{
"id": "0e6e4ad1-cf86-4e35-a862-bc8219c99838",
"name": "관련 글이 동일한지 확인",
"type": "n8n-nodes-base.if",
"position": [
608,
-288
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "320c269c-572b-4888-b6c0-7ceec4db0e30",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Loop for source articles').item.json.related_shopify_ids.join() }}",
"rightValue": "={{ $('Get previous related_articles').item.json.related_shopify_ids }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "73604394-344d-469e-b845-0f3660abccaf",
"name": "관련 섹션 변경 불필요",
"type": "n8n-nodes-base.noOp",
"position": [
816,
-304
],
"parameters": {},
"typeVersion": 1
},
{
"id": "2bc885ba-cbc4-4623-82ac-e85759170a6d",
"name": "관련 글 세부 정보 가져오기",
"type": "n8n-nodes-base.dataTable",
"position": [
1120,
80
],
"parameters": {
"filters": {
"conditions": [
{
"keyName": "shopify_id",
"keyValue": "={{ $json.related_shopify_id }}"
}
]
},
"operation": "get",
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "kjtDGPfteUD1V64N",
"cachedResultUrl": "/projects/XqoBcIeUrbWmIJt8/datatables/kjtDGPfteUD1V64N",
"cachedResultName": "articles"
}
},
"typeVersion": 1
},
{
"id": "85357d92-5b8b-4e36-acba-a1f3473237ae",
"name": "관련 ID 분할",
"type": "n8n-nodes-base.code",
"position": [
896,
80
],
"parameters": {
"jsCode": "return $input.all().flatMap(item => {\n const ids = item.json.related_shopify_ids.split(',').map(id => id.trim());\n return ids.map(relatedId => ({\n json: {\n source_shopify_id: item.json.source_shopify_id,\n related_shopify_id: relatedId\n }\n }));\n});"
},
"typeVersion": 2
},
{
"id": "36042f8c-f7b5-48bc-949f-44f8521d407e",
"name": "글에 관련 삽입",
"type": "n8n-nodes-base.code",
"position": [
1568,
80
],
"parameters": {
"jsCode": "// ============================================\n// UPDATE SHOPIFY ARTICLE WITH RELATED LINKS\n// ============================================\n\nconst item = $input.item.json;\n\n// Get current article content from Shopify\nconst currentArticle = $('Get articles from shopify').first().json.articles.find(a => a.id === $input.first().json.source_shopify_id);\nlet currentContent = currentArticle.body_html || '';\n\n// Remove old related articles section if exists\ncurrentContent = currentContent.replace(\n /<div class=\"related-articles\"[^>]*>[\\s\\S]*?<\\/div>/gi, \n ''\n);\n\n// Add new related articles at the end\nconst updatedContent = currentContent.trim() + '\\n\\n' + item.related_articles_html;\n\nconst article = {\n id: item.source_shopify_id,\n body_html: updatedContent\n}\n\nreturn [{ json: { article } }];"
},
"typeVersion": 2
},
{
"id": "1524f17c-e0b2-41dc-a948-4e085885b0a2",
"name": "관련 글 포함하여 글 업데이트",
"type": "n8n-nodes-base.httpRequest",
"position": [
1792,
80
],
"parameters": {
"url": "=https://{{ $('Workflow Configuration').first().json.shopifyStoreName }}.myshopify.com/admin/api/{{ $('Workflow Configuration').first().json.shopApiVersion }}/blogs/{{ $('Workflow Configuration').first().json.shopifyBlogId }}/articles/{{ $json.article.id }}.json",
"method": "PUT",
"options": {},
"jsonBody": "={{ JSON.stringify($json) }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "shopifyAccessTokenApi"
},
"credentials": {
"shopifyAccessTokenApi": {
"id": "oDrAi4lTTxnawLSv",
"name": "Shopify Access Token account 2"
}
},
"typeVersion": 4.2
},
{
"id": "e9d3c731-ff01-4bbc-9c8c-a6eed48abb20",
"name": "스티커 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
-976,
304
],
"parameters": {
"width": 896,
"height": 480,
"content": "## Analyze each article with \"text-embedding-3-small\" model and save to Data Table\n* Previously it cleaned the content for each article\n* Within this loop for each article it's generating the embedding that will then be used to analyze similarities\n* It saves each article in the \"articles\" Data Table"
},
"typeVersion": 1
},
{
"id": "d61c23f1-2de2-4b63-9e3b-a38cbb37688d",
"name": "스티커 노트1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-768,
-448
],
"parameters": {
"color": 5,
"width": 2736,
"height": 736,
"content": "## Core process\n* It compares each article to each other to calculate the semantic similarity \n* In that particular example it looks for article that have more than 70% semantic similarity. This can be changed in the \"Workflow Configuration\" node, the variable is called \"percent_minimum_similarity\" \n* For each article, it gets the top 3 related articles ordered by highest semantic similarity. If you want to include more related articles you can change the node \"Top 3 related articles\"\n* It then checks in the \"article_related_links_snapshot\" Data table to check if this article already had related articles. Then it checks if the related are the same or need to be updated in the article\n* The rest of the process is to get the details of each related articles, create the html section, replace it within the article if there is already one and finally update the article through shopify API"
},
"typeVersion": 1
},
{
"id": "4d66e34f-f02c-4b30-8a7e-182b828330fd",
"name": "스티커 노트2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1856,
304
],
"parameters": {
"color": 4,
"width": 864,
"height": 480,
"content": "## Set up\n* **Workflow Configuration node need to be updated with your info**"
},
"typeVersion": 1
},
{
"id": "03a381af-5bf9-4fa1-a633-3e2a154b1ceb",
"name": "스티커 노트4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1856,
-448
],
"parameters": {
"color": 7,
"width": 1072,
"height": 736,
"content": "## IMPORTANT READ BEFORE LAUNCHING THE WORKFLOW\nFor this workflow to work you first need to create three Data Tables. Below is the details of each one. \n**articles**\n** shopify_id (number)\n** shopify_handle (string)\n** title (string)\n** content (string) \n** summary (string)\n** url (string)\n** published_at (datetime)\n** embedding (string)\n** last_analyzed_at (datetime)\n** word_count (number) \n** blog_id (number) \n\n**article_relations**\n** source_shopify_id (number) \n** source_blog_id (number) \n** source_title (string)\n** related_shopify_id (number) \n** related_title (string)\n** related_url (string) \n** similarity_score (number)\n\n**article_related_links_snapshot**\n** source_shopify_id (number)\n** related_shopify_ids (string) \n\n\nThen, the only thing you need to configure is the second node \"Workflow Configuration\". "
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "ib0LqomNsNIqEoi6",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "f2d0a7cc-1be7-4878-bd20-e82dae800398",
"connections": {
"a91f14ad-f42c-4ad9-9ddd-4a218e8b8514": {
"main": [
[
{
"node": "55ce71bc-afc1-4178-87a3-6fda9829bd68",
"type": "main",
"index": 0
}
],
[
{
"node": "7d83e353-0272-4857-ad4e-f3baab2e62b6",
"type": "main",
"index": 0
}
]
]
},
"762e212e-1907-4610-9bcd-cc7b79258172": {
"main": [
[
{
"node": "a91f14ad-f42c-4ad9-9ddd-4a218e8b8514",
"type": "main",
"index": 0
}
]
]
},
"8848b159-986e-4b67-8bde-a38da0a25f36": {
"main": [
[
{
"node": "057f8499-694c-4391-80a1-e2f7ca093d25",
"type": "main",
"index": 0
}
]
]
},
"b41317b7-4a8c-4043-94e8-89b6add1c772": {
"main": [
[
{
"node": "85357d92-5b8b-4e36-acba-a1f3473237ae",
"type": "main",
"index": 0
}
]
]
},
"85357d92-5b8b-4e36-acba-a1f3473237ae": {
"main": [
[
{
"node": "2bc885ba-cbc4-4623-82ac-e85759170a6d",
"type": "main",
"index": 0
}
]
]
},
"7d83e353-0272-4857-ad4e-f3baab2e62b6": {
"main": [
[
{
"node": "8a1ffb69-65c0-4cf5-a4cb-e9209a9dc0ea",
"type": "main",
"index": 0
}
]
]
},
"3623adca-6827-467c-81f7-6f138377aefd": {
"main": [
[
{
"node": "a91f14ad-f42c-4ad9-9ddd-4a218e8b8514",
"type": "main",
"index": 0
}
]
]
},
"8a1ffb69-65c0-4cf5-a4cb-e9209a9dc0ea": {
"main": [
[
{
"node": "762e212e-1907-4610-9bcd-cc7b79258172",
"type": "main",
"index": 0
}
]
]
},
"55ce71bc-afc1-4178-87a3-6fda9829bd68": {
"main": [
[
{
"node": "6607766a-147e-49b6-b127-6655d3221c8c",
"type": "main",
"index": 0
}
]
]
},
"ff514a42-ee01-448a-8951-4b6d82ecff01": {
"main": [
[
{
"node": "088f6ac5-4c84-4c63-ba89-ab778c3ce547",
"type": "main",
"index": 0
}
]
]
},
"057f8499-694c-4391-80a1-e2f7ca093d25": {
"main": [
[
{
"node": "ce7cbd23-b0ec-4420-a262-cc16ddd9f5bd",
"type": "main",
"index": 0
}
]
]
},
"088f6ac5-4c84-4c63-ba89-ab778c3ce547": {
"main": [
[],
[
{
"node": "28f1bf7c-db78-4f1f-8db3-b00474dd7284",
"type": "main",
"index": 0
}
]
]
},
"6607766a-147e-49b6-b127-6655d3221c8c": {
"main": [
[
{
"node": "ff514a42-ee01-448a-8951-4b6d82ecff01",
"type": "main",
"index": 0
}
]
]
},
"ce7cbd23-b0ec-4420-a262-cc16ddd9f5bd": {
"main": [
[
{
"node": "3623adca-6827-467c-81f7-6f138377aefd",
"type": "main",
"index": 0
}
]
]
},
"36042f8c-f7b5-48bc-949f-44f8521d407e": {
"main": [
[
{
"node": "1524f17c-e0b2-41dc-a948-4e085885b0a2",
"type": "main",
"index": 0
}
]
]
},
"2bc885ba-cbc4-4623-82ac-e85759170a6d": {
"main": [
[
{
"node": "2d051e8b-9f67-4ed3-8a2a-85d19281452f",
"type": "main",
"index": 0
}
]
]
},
"1524f17c-e0b2-41dc-a948-4e085885b0a2": {
"main": [
[
{
"node": "088f6ac5-4c84-4c63-ba89-ab778c3ce547",
"type": "main",
"index": 0
}
]
]
},
"28f1bf7c-db78-4f1f-8db3-b00474dd7284": {
"main": [
[
{
"node": "268e6a49-f852-4056-b9cf-8b912f5b19e1",
"type": "main",
"index": 0
}
]
]
},
"2d051e8b-9f67-4ed3-8a2a-85d19281452f": {
"main": [
[
{
"node": "36042f8c-f7b5-48bc-949f-44f8521d407e",
"type": "main",
"index": 0
}
]
]
},
"268e6a49-f852-4056-b9cf-8b912f5b19e1": {
"main": [
[
{
"node": "0e6e4ad1-cf86-4e35-a862-bc8219c99838",
"type": "main",
"index": 0
}
],
[
{
"node": "b41317b7-4a8c-4043-94e8-89b6add1c772",
"type": "main",
"index": 0
}
]
]
},
"73604394-344d-469e-b845-0f3660abccaf": {
"main": [
[
{
"node": "088f6ac5-4c84-4c63-ba89-ab778c3ce547",
"type": "main",
"index": 0
}
]
]
},
"0e6e4ad1-cf86-4e35-a862-bc8219c99838": {
"main": [
[
{
"node": "73604394-344d-469e-b845-0f3660abccaf",
"type": "main",
"index": 0
}
],
[
{
"node": "b41317b7-4a8c-4043-94e8-89b6add1c772",
"type": "main",
"index": 0
}
]
]
}
}
}자주 묻는 질문
이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급 - 콘텐츠 제작, AI 요약
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
Shopify 블로그 자동화: 키워드 목록 기반 SEO/AEO 최적화 문서
사용GPT-4와Google 스프레드시트로 SEO/AEO 최적화된 Shopify 블로그 기사 생성
If
Set
Code
+
If
Set
Code
32 노드Geoffroy
콘텐츠 제작
GPT-4와 Airtable을 사용한 작업 기록 및 백업 워크플로 자동화
GPT-4와 Airtable로 워크플로우 자동 기록 및 백업
If
N8n
Set
+
If
N8n
Set
38 노드Guillaume Duvernay
AI 요약
리드 생성 및 이메일 워크플로
Google 지도, SendGrid 및 AI를 사용한 B2B 잠재 고객 개발 및 이메일 마케팅 자동화
If
Set
Code
+
If
Set
Code
141 노드Ezema Kingsley Chibuzo
리드 생성
Facebook 및 Instagram 갱신 토큰
Graph API 및 데이터 스토리지를 사용한 Meta 토큰 자동 갱신
If
Set
Data Table
+
If
Set
Data Table
13 노드Geoffroy
批量 SEO 콘텐츠 생성 및 AI 이미지 포함 Webflow 드래그 앤 드롭 생성 (템플릿)
GPT, Gemini 이미지, Webflow 드라フト를 사용하여 대량 SEO 콘텐츠 생성
If
Set
Code
+
If
Set
Code
54 노드Dahiana
콘텐츠 제작
AI와 Freepik을 사용하여 Reddit 비즈니스 문제를 바이러스적인 LinkedIn 콘텐츠로 변환
AI와 Freepik을 사용하여 Reddit 비즈니스 문제를 바이러스적인 LinkedIn 콘텐츠로 변환
If
Set
Code
+
If
Set
Code
48 노드Daniel Lianes
콘텐츠 제작