8
n8n 한국어amn8n.com

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(/&nbsp;/g, ' ')\n    .replace(/&amp;/g, '&')\n    .replace(/&lt;/g, '<')\n    .replace(/&gt;/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)는 사용자 직접 비용을 지불해야 할 수 있습니다.

워크플로우 정보
난이도
고급
노드 수26
카테고리2
노드 유형9
난이도 설명

고급 사용자를 위한 16+개 노드의 복잡한 워크플로우

저자
Geoffroy

Geoffroy

@jojoq42

Just a simple guy discovering the power of AI

외부 링크
n8n.io에서 보기

이 워크플로우 공유

카테고리

카테고리: 34