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": "article_relationsをアップサート",
"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 Maps、SendGrid、AIを使用してB2Bリード獲得とメールマーケティングを自動化
If
Set
Code
+
If
Set
Code
141 ノードEzema Kingsley Chibuzo
リード獲得
FacebookおよびInstagramのトークン更新
Meta トークンの自動更新を Graph API およびデータストアで実行
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
コンテンツ作成