Blog Automation TEMPLATE
工作流概述
这是一个包含35个节点的复杂工作流,主要用于自动化处理各种任务。
工作流源代码
{
"id": "b0KRVIuuUxE5afHo",
"meta": {
"instanceId": "98bf0d6aef1dd8b7a752798121440fb171bf7686b95727fd617f43452393daa3",
"templateCredsSetupCompleted": true
},
"name": "Blog Automation TEMPLATE",
"tags": [
{
"id": "uumvgGHY5e6zEL7V",
"name": "Published Template",
"createdAt": "2025-02-10T11:18:10.923Z",
"updatedAt": "2025-02-10T11:18:10.923Z"
}
],
"nodes": [
{
"id": "20e00146-6bda-4a8a-9544-bf7e5fd4e12e",
"name": "Settings",
"type": "n8n-nodes-base.set",
"position": [
-420,
-160
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "528b371f-0fba-4be1-9801-0502652da23e",
"name": "urlSpreadsheet",
"type": "string",
"value": "https://docs.google.com/spreadsheets/d/1Kg1-U6mJF4bahH1jCw8kT48MiKz1UMC5n-9q77BHM3Q/edit?gid=0#gid=0"
},
{
"id": "1be018c7-51fe-4ea2-967d-ce47a2e8795c",
"name": "urlWordpress",
"type": "string",
"value": "SUBDOMAIN.wordpress.com"
},
{
"id": "95377f4f-184b-46a7-94c7-b2313c314cb2",
"name": "wordpressUsername",
"type": "string",
"value": "YourUserName"
},
{
"id": "fdc99dc6-d9b0-4d2f-b770-1d8b6b360cad",
"name": "wordpressApplicationPassword",
"type": "string",
"value": "y0ur app1 p4ss w0rd"
},
{
"id": "517cb9ff-24fc-41d6-8bcc-253078f56356",
"name": "sheetSchedule",
"type": "string",
"value": "=Schedule"
},
{
"id": "584e11da-546b-4472-8674-33ca7e8f4f30",
"name": "sheetConfig",
"type": "string",
"value": "Config"
},
{
"id": "ba38cb1e-fd97-4aed-9147-1946c318ddab",
"name": "actionPublish",
"type": "string",
"value": "publish"
},
{
"id": "678394b5-20af-4718-9249-4ff6a3c77018",
"name": "actionUpdate",
"type": "string",
"value": ""
},
{
"id": "f375b2fa-8772-4313-9d6b-a104edd918b3",
"name": "sheetLog",
"type": "string",
"value": "Log"
},
{
"id": "3d7f9677-c753-4126-b33a-d78ef701771f",
"name": "",
"type": "string",
"value": ""
}
]
}
},
"typeVersion": 3.4
},
{
"id": "35731842-9215-43df-9009-9b130d663237",
"name": "ScheduleTrigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-620,
-280
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "4c284d44-ac46-4cdf-9dcb-727b464269a0",
"name": "ManualTrigger",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-620,
-100
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b63e7345-67d0-4761-8c1a-49275f34e88d",
"name": "Schedule",
"type": "n8n-nodes-base.googleSheets",
"position": [
-220,
-80
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $('Settings').item.json.sheetSchedule }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.urlSpreadsheet }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "XeXufn5uZvHp3lcX",
"name": "Google Sheets account 2"
}
},
"notesInFlow": true,
"typeVersion": 4.5
},
{
"id": "5fed06a3-3188-4aed-8040-04e245b74e20",
"name": "Config",
"type": "n8n-nodes-base.code",
"position": [
40,
-220
],
"parameters": {
"jsCode": "let a = $(\"fetchConfig\").all();
let params = {};
a.forEach(p => params[p.json.Key] = p.json.Value);
return params;
"
},
"typeVersion": 2
},
{
"id": "685490c8-6b45-40c2-b4db-e97a81c4be8e",
"name": "fetchConfig",
"type": "n8n-nodes-base.googleSheets",
"position": [
-220,
-220
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $('Settings').item.json.sheetConfig }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.urlSpreadsheet }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "XeXufn5uZvHp3lcX",
"name": "Google Sheets account 2"
}
},
"notesInFlow": true,
"typeVersion": 4.5
},
{
"id": "52a39db8-f9cc-44bb-9c3e-a9abf5821a04",
"name": "AgentLLM",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-400,
440
],
"parameters": {
"model": "={{ $json.model }}",
"options": {}
},
"credentials": {
"openAiApi": {
"id": "66JEQJ5kJel1P9t3",
"name": "OpenRouter"
}
},
"typeVersion": 1.1
},
{
"id": "6a311ac4-032b-42da-b06e-c916209d2843",
"name": "IfScheduledNow",
"type": "n8n-nodes-base.if",
"position": [
-620,
780
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "bb707069-b372-4bbd-8ba5-b7f6b492ab9d",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ DateTime.now().ts }}",
"rightValue": "={{ DateTime.fromFormat($json.row.Scheduled, \"yyyy-MM-dd HH:mm:ss\").ts }}"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "845e419b-15ad-4548-86c5-44bda0433b71",
"name": "PreparedData",
"type": "n8n-nodes-base.code",
"position": [
40,
-80
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "function replacePlaceholders(text, row, config) {
function checkProp(prop, lookup) {
// console.log('checkProp:' + prop);
if (!lookup.hasOwnProperty(prop)) return false;
let value = lookup[prop];
if (typeof(value) == 'string') {
value = value.trim();
if (value == '') return false;
}
// console.log('checkProp found:', value)
return value;
}
function replaceMatch(fullMatch, prop) {
prop = prop.trim();
// Return the corresponding value
return checkProp(prop, row)
|| checkProp(prop, config)
|| checkProp(prop + checkProp('Context', row), config)
|| `[could not find \"${ prop }]\"`;
}
if (typeof(text) != 'string') return '';
// Regex to capture {{ ... }}
const pattern = /\{\{\s*([^}]+)\s*\}\}/g
const result = text.replace(pattern, replaceMatch);
return result.trim();
}
const row = $json;
const settings = $(\"Settings\").first().json;
const config = $(\"Config\").first().json;
const prompt_key = 'prompt_' + row.Action;
const prompt = replacePlaceholders(config[prompt_key], row, config);
const model_key = prompt_key + '_model';
const model = replacePlaceholders(config[model_key], row, config);
const outputFormat = config[prompt_key + '_outputFormat'];
const takeAction = row.Action != row.Status;
const action = row.Action
// console.log('prompt', prompt);
// console.log(prompt);
return { takeAction, action, model_key, model, prompt_key, prompt, outputFormat, row, config, settings }"
},
"typeVersion": 2
},
{
"id": "db294805-df67-4266-919f-94fb0f32c593",
"name": "RecombinedDataRow",
"type": "n8n-nodes-base.code",
"position": [
40,
280
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "/**
* Attempts to parse the \"text\" property in a JSON object
* that may contain malformed or incorrectly escaped JSON.
*
* @param {Object} raw - A string to parse.
* @returns {Object|null} The parsed JSON object if successful, or null if all attempts fail.
*/
function parseTextAsJson(raw) {
// 1) First, try a direct parse.
try {
return JSON.parse(raw);
} catch (e) {
// Continue to next strategy
}
// Common \"fix-up\" strategies:
// Strategy A: Attempt to remove over-escaped quotes like `\\\"` -> `\"`
try {
const fixedA = raw.replace(/\\\"/g, '\"');
return JSON.parse(fixedA);
} catch (e) {
// Continue
}
// Strategy B: Remove escaped newlines, tabs, carriage returns if they’re suspected
try {
const fixedB = raw
.replace(/\\n/g, ' ')
.replace(/\\r/g, ' ')
.replace(/\\t/g, ' ');
return JSON.parse(fixedB);
} catch (e) {
// Continue
}
// Strategy C: Replace single quotes with double quotes (useful if the JSON was incorrectly quoted).
// NOTE: This is a very rough fix. If your data legitimately includes single quotes you may need
// a more nuanced approach.
try {
const fixedC = raw.replace(/'/g, '\"');
return JSON.parse(fixedC);
} catch (e) {
// Continue
}
// Strategy D: Combine strategies or chain them if needed:
// For example, single-quote fix plus removing new lines, etc.
try {
let fixedD = raw.replace(/\\\"/g, '\"');
fixedD = fixedD.replace(/\\n|\\r|\\t/g, ' ');
fixedD = fixedD.replace(/'/g, '\"');
return JSON.parse(fixedD);
} catch (e) {
// If all attempts fail, log or handle the error as needed
console.error('Could not parse \"text\" property as JSON.', e);
return { 'Fulltext': raw };
}
}
function isolateCurlySubstring(str) {
// This pattern greedily matches everything from the first '{' to the last '}'.
const match = str.match(/\{[\s\S]*\}/);
// If a match is found, return it; otherwise return the entire string.
return match ? match[0] : str;
}
function fixJsonSyntax(str) {
str = str.replace('\\"', '\"');
str = str
.split(/(\"[^\"]*\"|'[^']*')/)
.map((part, i) => i % 2 ? part : part.replace(/\n/g, \" \"))
.join(\"\");
return str;
}
function normalizeLLMOutput(param, iteration = 3) {
// If it's not an object or it's null or an array, just return it as is.
// (In some workflows, you might decide to throw an error or handle differently.)
if (!iteration || typeof param !== 'object' || param === null || Array.isArray(param)) {
return param;
}
// Get the object's own property keys
const keys = Object.keys(param);
// If there's more than one property, we assume it's already the complex object we want.
if (keys.length > 1) {
// console.log('keys > 1 → return param', param);
return param;
}
// If there are no properties, just return it (though this is likely an empty object).
if (keys.length === 0) {
return param;
}
// If there's exactly one property, it might be a JSON-string that we need to parse.
const singleKey = keys[0];
const value = param[singleKey];
// If that single property is a string, fix it and try to parse it as JSON.
if (typeof value === 'string') {
try {
return parseTextAsJson(isolateCurlySubstring(value));
} catch (e) {
console.log('value is string → parse failed with error:', e.toString(), '→ return param:', param, 'value:', value);
// Parsing failed; perhaps it's just a plain string or invalid JSON, so return as is.
return param;
}
}
// Otherwise, repeat this process itratively.
return normalizeLLMOutput(value, iteration-1);
}
const preparedData = $(\"PreparedData\").itemMatching($itemIndex).json;
const row = preparedData.row;
let gen = normalizeLLMOutput($json);
let fulltext = gen.hasOwnProperty('Fulltext') ? gen.Fulltext : gen;
// Append any fulltext field returned to the field
// in our data row corresponding to the current action.
gen[row.Action] = fulltext;
// Concatenate any generated fields with those already exisiting
// in our data row (using seperator if necessary),
// so we don't loose any pre-entered data.
const combined = {};
Object.keys(gen).forEach(key => {
const a = String(row[key] ?? \"\");
const b = String(gen[key]);
combined[key] = (a && b) ? (a + \"\n---\n\" + b) : (a || b);
});
// Add the row number and set the new status to the action just performed.
combined.row_number = row.row_number;
combined.Status = row.Action;
combined.model = preparedData.model;
return combined;"
},
"typeVersion": 2
},
{
"id": "e0c993c1-678f-4236-8976-735cccb49fee",
"name": "SaveBackToSheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
480,
280
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Topic",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Topic",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Scheduled",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Scheduled",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Action",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Action",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Context",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Context",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Idea",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Idea",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Content",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Content",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Length",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Length",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Media",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Media",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LinksInternal",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "LinksInternal",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LinksExternal",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "LinksExternal",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Title",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Sections",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Sections",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "MainPoints",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "MainPoints",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "GuidingPrinciple",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "GuidingPrinciple",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Metaphor",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Metaphor",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Draft",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Draft",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Final",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Final",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "internal notes",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "internal notes",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [
"row_number"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"handlingExtraData": "ignoreIt"
},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $('Settings').item.json.sheetSchedule }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.urlSpreadsheet }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "XeXufn5uZvHp3lcX",
"name": "Google Sheets account 2"
}
},
"typeVersion": 4.5
},
{
"id": "e0b982d9-d24e-4fd0-bc03-8642cd4c988b",
"name": "IfActionPublish",
"type": "n8n-nodes-base.if",
"position": [
500,
-80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c3735d0d-da54-44e7-afe6-fdfacb6117f2",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.row.Action }}",
"rightValue": "={{ $('Settings').item.json.actionPublish }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1d5c2731-61a1-434c-bdf1-294217e4ac1c",
"name": "IfTakeAction",
"type": "n8n-nodes-base.if",
"position": [
260,
-80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "85536861-b213-4567-9c9a-f844a28b5405",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.takeAction }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "aae766a4-d29e-4357-a344-74ee36a382e1",
"name": "IfPromptExists",
"type": "n8n-nodes-base.if",
"position": [
-600,
280
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "73333657-16ed-4b0d-a81f-34add6c22a1b",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.prompt }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "5b4c4bdf-8997-4c19-8e95-8c84b725404c",
"name": "Basic LLM Chain",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
-360,
280
],
"parameters": {
"text": "={{ $json.prompt }}",
"promptType": "define"
},
"typeVersion": 1.5
},
{
"id": "8dc422a3-6b86-4f57-8c4c-df6422f72f57",
"name": "CreatePost",
"type": "n8n-nodes-base.httpRequest",
"position": [
-220,
780
],
"parameters": {
"url": "=https://{{ $('Settings').item.json.urlWordpress }}/xmlrpc.php",
"body": "={{ $json.xmlRequestBody }}",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "raw",
"sendHeaders": true,
"rawContentType": "text/xml",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "text/xml"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "6ad42453-d56b-4bae-aaf3-eb689df998cc",
"name": "SetToPublish",
"type": "n8n-nodes-base.googleSheets",
"position": [
700,
780
],
"parameters": {
"columns": {
"value": {
"Status": "={{ $('Settings').item.json.actionPublish }}",
"row_number": "={{ $('PreparedData').item.json.row.row_number }}"
},
"schema": [
{
"id": "ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Topic",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Topic",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Scheduled",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Scheduled",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Action",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Action",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Context",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Context",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Ideas",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Ideas",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Content",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Content",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Length",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Length",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Media",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Media",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LinksInternal",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "LinksInternal",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LinksExternal",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "LinksExternal",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Sections",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Sections",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "MainPoints",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "MainPoints",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "GuidingPrinciple",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "GuidingPrinciple",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Metaphor",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Metaphor",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Title",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "draft",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "draft",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "words",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "words",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "final",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "final",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "words",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "words",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TeaserTitle",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "TeaserTitle",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TeaserText",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "TeaserText",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "internal notes",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "internal notes",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"row_number"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $('Settings').item.json.sheetSchedule }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.urlSpreadsheet }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "XeXufn5uZvHp3lcX",
"name": "Google Sheets account 2"
}
},
"typeVersion": 4.5
},
{
"id": "a1af0f00-de59-48d4-93d2-9cc20e7f1c1c",
"name": "PrepareXmlPost",
"type": "n8n-nodes-base.code",
"position": [
-380,
780
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const username = $('Settings').item.json.wordpressUsername;
const password = $('Settings').item.json.wordpressApplicationPassword;
const blogId = 0;
const published = 1; // 0 = draft, 1 = published
const title = $json.row.Title;
const text = $json.row.final;
// Helper function to escape XML special characters
function escapeXml(unsafe) {
return unsafe.replace(/[<>&'\"]/g, (c) => {
switch (c) {
case '<': return '<';
case '>': return '>';
case '&': return '&';
case '\'': return ''';
case '\"': return '"';
default: return c;
}
});
}
// Your actual post text, which may contain characters needing escaping
const titleEscaped = escapeXml(title);
const textEscaped = escapeXml(text);
// Build the XML payload
const xmlData = `<?xml version=\"1.0\"?>
<methodCall>
<methodName>wp.newPost</methodName>
<params>
<param>
<value><string>${blogId}</string></value>
</param>
<param>
<value><string>${username}</string></value>
</param>
<param>
<value><string>${password}</string></value>
</param>
<param>
<value>
<struct>
<member>
<name>post_title</name>
<value><string>${titleEscaped}</string></value>
</member>
<member>
<name>post_content</name>
<value><string>${textEscaped}</string></value>
</member>
</struct>
</value>
</param>
<param>
<value><boolean>${published}</boolean></value>
</param>
</params>
</methodCall>`;
// Add a new field called 'myNewField' to the JSON of the item
$input.item.json.xmlRequestBody = xmlData;
return $input.item;"
},
"typeVersion": 2
},
{
"id": "00e6d2ab-6dc4-42ba-8a92-04a35d104908",
"name": "HandleXMLRPCResponse",
"type": "n8n-nodes-base.code",
"position": [
40,
780
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Get the XML response from the incoming JSON
const xmlResponse = $json.data;
// Helper function to extract a value by matching a regex pattern
function extractValue(pattern, xml) {
const match = xml.match(pattern);
return match ? match[1] : null;
}
// Check if the XML contains a fault
if (xmlResponse.indexOf(\"<fault>\") !== -1) {
// Extract the faultCode and faultString using regex
// This regex matches the value inside <int> or <string> for faultCode
const faultCode = extractValue(/<name>faultCode<\/name>\s*<value><(?:int|string)>(.*?)<\/(?:int|string)>/s, xmlResponse);
// This regex extracts the faultString from within <string>
const faultString = extractValue(/<name>faultString<\/name>\s*<value><string>(.*?)<\/string>/s, xmlResponse);
return { 'errorCode': faultCode, 'error': faultString };
} else {
// Otherwise, assume a successful response.
// The post ID is contained inside a <string> tag within <params>
const postId = extractValue(/<params>[\s\S]*?<string>(.*?)<\/string>/, xmlResponse);
return { postId };
}"
},
"typeVersion": 2
},
{
"id": "23212e92-4ad1-4a8c-8e0a-04d8d2a4511d",
"name": "PostingSuccessful",
"type": "n8n-nodes-base.if",
"position": [
480,
780
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "815d85a1-8f91-4338-977f-503f02c53ea2",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $('HandleXMLRPCResponse').item.json.postId }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "45c786f0-d795-4ed4-b6d2-f005b43e797f",
"name": "LogStatus",
"type": "n8n-nodes-base.googleSheets",
"position": [
260,
280
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $now }}",
"Type": "=info",
"Message": "=Status {{ $json.Status }} for row {{ $('PreparedData').item.json.row.row_number }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Type",
"type": "string",
"display": true,
"required": false,
"displayName": "Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Message",
"type": "string",
"display": true,
"required": false,
"displayName": "Message",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $('Settings').item.json.sheetLog }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.urlSpreadsheet }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "XeXufn5uZvHp3lcX",
"name": "Google Sheets account 2"
}
},
"typeVersion": 4.5
},
{
"id": "f58306f5-a5e9-4e44-9c5d-3810e18e6605",
"name": "LogPublished",
"type": "n8n-nodes-base.googleSheets",
"position": [
260,
780
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $now }}",
"Type": "={{ $json.errorCode ? 'error' : 'info' }}",
"Message": "=Publishing row {{ $('PreparedData').item.json.row.row_number }}: {{ $json.postId }}{{ $json.errorCode }}{{ $json.error }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Type",
"type": "string",
"display": true,
"required": false,
"displayName": "Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Message",
"type": "string",
"display": true,
"required": false,
"displayName": "Message",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $('Settings').item.json.sheetLog }}"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Settings').item.json.urlSpreadsheet }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "XeXufn5uZvHp3lcX",
"name": "Google Sheets account 2"
}
},
"typeVersion": 4.5
},
{
"id": "c227b790-e1ee-4370-9f24-a734443d1e97",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-460,
-300
],
"parameters": {
"width": 180,
"height": 360,
"content": "## Settings"
},
"typeVersion": 1
},
{
"id": "904da209-68fd-4139-885f-bd3f25034aeb",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-440,
180
],
"parameters": {
"color": 3,
"width": 380,
"height": 380,
"content": "## Author Blog-Post
Using OpenRouter to make model fully configurable for each authoring stage"
},
"typeVersion": 1
},
{
"id": "29f35bf0-6dd3-4c3c-b688-73eb46781c87",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
-300
],
"parameters": {
"color": 5,
"height": 360,
"content": "## Post-process Data
{{ Placehoder }} replacement"
},
"typeVersion": 1
},
{
"id": "296c3257-836d-488c-b048-72261180e286",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
180
],
"parameters": {
"color": 4,
"width": 180,
"height": 380,
"content": "## Log to Sheet"
},
"typeVersion": 1
},
{
"id": "42a06803-087f-4dc4-9dd5-1f0281942a30",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
420,
180
],
"parameters": {
"color": 6,
"width": 420,
"height": 380,
"content": "## Save Result To Sheet"
},
"typeVersion": 1
},
{
"id": "7a6393e9-ae81-4b9b-856b-7be18f783cf4",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-440,
620
],
"parameters": {
"color": 3,
"width": 380,
"height": 380,
"content": "## Publish Blog-Post
Use a generic XMLHttpRequest with subsequent response handling, since the Wordpress node did not work at all."
},
"typeVersion": 1
},
{
"id": "2d154bd4-c3bc-4137-90ce-7885bac77c71",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
180
],
"parameters": {
"color": 5,
"height": 380,
"content": "## Post-process Data
Normalize and re-merge output data structure. "
},
"typeVersion": 1
},
{
"id": "83834b00-a647-403f-b88a-4c38d9750eb0",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
620
],
"parameters": {
"color": 5,
"height": 380,
"content": "## Post-process Data
Extract post id or error message from response."
},
"typeVersion": 1
},
{
"id": "e7494d0b-b796-437e-b977-a5350b1a8dc5",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
620
],
"parameters": {
"color": 4,
"width": 180,
"height": 380,
"content": "## Log to Sheet"
},
"typeVersion": 1
},
{
"id": "1d036f6a-c6e4-428d-b0ce-1e710eb7d90c",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
420,
620
],
"parameters": {
"color": 6,
"width": 420,
"height": 380,
"content": "## Save Status To Sheet"
},
"typeVersion": 1
},
{
"id": "105e0743-b4e8-47d7-a4bf-3939df43a43c",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
-640,
160
],
"parameters": {
"color": 7,
"width": 1500,
"height": 420,
"content": "## Authoring
## Stage"
},
"typeVersion": 1
},
{
"id": "80fefb90-35b2-4f0b-b4d5-1cca8519361d",
"name": "Sticky Note11",
"type": "n8n-nodes-base.stickyNote",
"position": [
-640,
600
],
"parameters": {
"color": 7,
"width": 1500,
"height": 420,
"content": "## Publishing
## Stage"
},
"typeVersion": 1
},
{
"id": "99b0a7b7-6513-47b0-af16-ee66d37dd821",
"name": "Sticky Note12",
"type": "n8n-nodes-base.stickyNote",
"position": [
-260,
-300
],
"parameters": {
"width": 200,
"height": 360,
"content": "## Config & Data"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "7005e556-a7ae-484c-af71-57c75abd3e17",
"connections": {
"Config": {
"main": [
[]
]
},
"AgentLLM": {
"ai_languageModel": [
[
{
"node": "Basic LLM Chain",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Schedule": {
"main": [
[
{
"node": "PreparedData",
"type": "main",
"index": 0
}
]
]
},
"Settings": {
"main": [
[
{
"node": "fetchConfig",
"type": "main",
"index": 0
},
{
"node": "Schedule",
"type": "main",
"index": 0
}
]
]
},
"LogStatus": {
"main": [
[
{
"node": "SaveBackToSheet",
"type": "main",
"index": 0
}
]
]
},
"CreatePost": {
"main": [
[
{
"node": "HandleXMLRPCResponse",
"type": "main",
"index": 0
}
]
]
},
"fetchConfig": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"IfTakeAction": {
"main": [
[
{
"node": "IfActionPublish",
"type": "main",
"index": 0
}
]
]
},
"LogPublished": {
"main": [
[
{
"node": "PostingSuccessful",
"type": "main",
"index": 0
}
]
]
},
"PreparedData": {
"main": [
[
{
"node": "IfTakeAction",
"type": "main",
"index": 0
}
]
]
},
"SetToPublish": {
"main": [
[]
]
},
"ManualTrigger": {
"main": [
[
{
"node": "Settings",
"type": "main",
"index": 0
}
]
]
},
"IfPromptExists": {
"main": [
[
{
"node": "Basic LLM Chain",
"type": "main",
"index": 0
}
]
]
},
"IfScheduledNow": {
"main": [
[
{
"node": "PrepareXmlPost",
"type": "main",
"index": 0
}
]
]
},
"PrepareXmlPost": {
"main": [
[
{
"node": "CreatePost",
"type": "main",
"index": 0
}
]
]
},
"Basic LLM Chain": {
"main": [
[
{
"node": "RecombinedDataRow",
"type": "main",
"index": 0
}
]
]
},
"IfActionPublish": {
"main": [
[
{
"node": "IfScheduledNow",
"type": "main",
"index": 0
}
],
[
{
"node": "IfPromptExists",
"type": "main",
"index": 0
}
]
]
},
"SaveBackToSheet": {
"main": [
[]
]
},
"ScheduleTrigger": {
"main": [
[
{
"node": "Settings",
"type": "main",
"index": 0
}
]
]
},
"PostingSuccessful": {
"main": [
[
{
"node": "SetToPublish",
"type": "main",
"index": 0
}
]
]
},
"RecombinedDataRow": {
"main": [
[
{
"node": "LogStatus",
"type": "main",
"index": 0
}
]
]
},
"HandleXMLRPCResponse": {
"main": [
[
{
"node": "LogPublished",
"type": "main",
"index": 0
}
]
]
}
}
}
功能特点
- 自动检测新邮件
- AI智能内容分析
- 自定义分类规则
- 批量处理能力
- 详细的处理日志
技术分析
节点类型及作用
- Set
- Scheduletrigger
- Manualtrigger
- Googlesheets
- Code
复杂度评估
配置难度:
维护难度:
扩展性:
实施指南
前置条件
- 有效的Gmail账户
- n8n平台访问权限
- Google API凭证
- AI分类服务订阅
配置步骤
- 在n8n中导入工作流JSON文件
- 配置Gmail节点的认证信息
- 设置AI分类器的API密钥
- 自定义分类规则和标签映射
- 测试工作流执行
- 配置定时触发器(可选)
关键参数
| 参数名称 | 默认值 | 说明 |
|---|---|---|
| maxEmails | 50 | 单次处理的最大邮件数量 |
| confidenceThreshold | 0.8 | 分类置信度阈值 |
| autoLabel | true | 是否自动添加标签 |
最佳实践
优化建议
- 定期更新AI分类模型以提高准确性
- 根据邮件量调整处理批次大小
- 设置合理的分类置信度阈值
- 定期清理过期的分类规则
安全注意事项
- 妥善保管API密钥和认证信息
- 限制工作流的访问权限
- 定期审查处理日志
- 启用双因素认证保护Gmail账户
性能优化
- 使用增量处理减少重复工作
- 缓存频繁访问的数据
- 并行处理多个邮件分类任务
- 监控系统资源使用情况
故障排除
常见问题
邮件未被正确分类
检查AI分类器的置信度阈值设置,适当降低阈值或更新训练数据。
Gmail认证失败
确认Google API凭证有效且具有正确的权限范围,重新进行OAuth授权。
调试技巧
- 启用详细日志记录查看每个步骤的执行情况
- 使用测试邮件验证分类逻辑
- 检查网络连接和API服务状态
- 逐步执行工作流定位问题节点
错误处理
工作流包含以下错误处理机制:
- 网络超时自动重试(最多3次)
- API错误记录和告警
- 处理失败邮件的隔离机制
- 异常情况下的回滚操作