Blog Automation TEMPLATE
Automate your blog content creation and publishing with the Blog Automation TEMPLATE, a powerful n8n workflow designed to streamline your content pipeline. This workflow intelligently fetches blog post ideas and configurations from Google Sheets using the Schedule and fetchConfig nodes, then leverages OpenAI's AgentLLM to generate compelling content. Once content is generated, it's saved back to your Google Sheet with the SaveBackToSheet node, ensuring a centralized record. The workflow then uses the Basic LLM Chain to refine the content before the CreatePost httpRequest node publishes it directly to your blog, with status updates logged in Google Sheets via LogStatus and LogPublished. This template is perfect for content marketers, small business owners, and bloggers looking to scale their content output without manual intervention, saving significant time and effort in content generation, scheduling, and publishing.
Workflow JSON
{"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": "", "name": "[Your googleSheetsOAuth2Api]"}}, "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();\nlet params = {};\na.forEach(p => params[p.json.Key] = p.json.Value);\n\nreturn params;\n"}, "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": "", "name": "[Your googleSheetsOAuth2Api]"}}, "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": "", "name": "[Your openAiApi]"}}, "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) {\n function checkProp(prop, lookup) {\n // console.log('checkProp:' + prop);\n if (!lookup.hasOwnProperty(prop)) return false;\n let value = lookup[prop];\n if (typeof(value) == 'string') {\n value = value.trim();\n if (value == '') return false;\n }\n // console.log('checkProp found:', value)\n return value;\n }\n function replaceMatch(fullMatch, prop) { \n prop = prop.trim();\n // Return the corresponding value\n return checkProp(prop, row)\n || checkProp(prop, config)\n || checkProp(prop + checkProp('Context', row), config)\n || `[could not find \"${ prop }]\"`;\n }\n\n if (typeof(text) != 'string') return '';\n\n // Regex to capture {{ ... }}\n const pattern = /\\{\\{\\s*([^}]+)\\s*\\}\\}/g\n const result = text.replace(pattern, replaceMatch);\n return result.trim();\n}\n\nconst row = $json;\nconst settings = $(\"Settings\").first().json;\nconst config = $(\"Config\").first().json;\nconst prompt_key = 'prompt_' + row.Action;\nconst prompt = replacePlaceholders(config[prompt_key], row, config);\nconst model_key = prompt_key + '_model';\nconst model = replacePlaceholders(config[model_key], row, config);\nconst outputFormat = config[prompt_key + '_outputFormat'];\nconst takeAction = row.Action != row.Status;\nconst action = row.Action\n\n// console.log('prompt', prompt);\n\n// console.log(prompt);\nreturn { 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": "/**\n * Attempts to parse the \"text\" property in a JSON object\n * that may contain malformed or incorrectly escaped JSON.\n *\n * @param {Object} raw - A string to parse.\n * @returns {Object|null} The parsed JSON object if successful, or null if all attempts fail.\n */\nfunction parseTextAsJson(raw) {\n // 1) First, try a direct parse.\n try {\n return JSON.parse(raw);\n } catch (e) {\n // Continue to next strategy\n }\n\n // Common \"fix-up\" strategies:\n // Strategy A: Attempt to remove over-escaped quotes like `\\\\\"` -> `\"`\n try {\n const fixedA = raw.replace(/\\\\\"/g, '\"');\n return JSON.parse(fixedA);\n } catch (e) {\n // Continue\n }\n\n // Strategy B: Remove escaped newlines, tabs, carriage returns if they\u2019re suspected\n try {\n const fixedB = raw\n .replace(/\\\\n/g, ' ')\n .replace(/\\\\r/g, ' ')\n .replace(/\\\\t/g, ' ');\n return JSON.parse(fixedB);\n } catch (e) {\n // Continue\n }\n\n // Strategy C: Replace single quotes with double quotes (useful if the JSON was incorrectly quoted).\n // NOTE: This is a very rough fix. If your data legitimately includes single quotes you may need\n // a more nuanced approach.\n try {\n const fixedC = raw.replace(/'/g, '\"');\n return JSON.parse(fixedC);\n } catch (e) {\n // Continue\n }\n\n // Strategy D: Combine strategies or chain them if needed:\n // For example, single-quote fix plus removing new lines, etc.\n try {\n let fixedD = raw.replace(/\\\\\"/g, '\"');\n fixedD = fixedD.replace(/\\\\n|\\\\r|\\\\t/g, ' ');\n fixedD = fixedD.replace(/'/g, '\"');\n return JSON.parse(fixedD);\n } catch (e) {\n // If all attempts fail, log or handle the error as needed\n console.error('Could not parse \"text\" property as JSON.', e);\n return { 'Fulltext': raw };\n }\n}\n\nfunction isolateCurlySubstring(str) {\n // This pattern greedily matches everything from the first '{' to the last '}'.\n const match = str.match(/\\{[\\s\\S]*\\}/);\n \n // If a match is found, return it; otherwise return the entire string.\n return match ? match[0] : str;\n}\n\nfunction fixJsonSyntax(str) {\n str = str.replace('\\\"', '\"');\n str = str\n .split(/(\"[^\"]*\"|'[^']*')/)\n .map((part, i) => i % 2 ? part : part.replace(/\\n/g, \" \"))\n .join(\"\");\n return str;\n}\n\nfunction normalizeLLMOutput(param, iteration = 3) {\n // If it's not an object or it's null or an array, just return it as is.\n // (In some workflows, you might decide to throw an error or handle differently.)\n if (!iteration || typeof param !== 'object' || param === null || Array.isArray(param)) {\n return param;\n }\n\n // Get the object's own property keys\n const keys = Object.keys(param);\n\n // If there's more than one property, we assume it's already the complex object we want.\n if (keys.length > 1) {\n // console.log('keys > 1 \u2192 return param', param);\n return param;\n }\n\n // If there are no properties, just return it (though this is likely an empty object).\n if (keys.length === 0) {\n return param;\n }\n\n // If there's exactly one property, it might be a JSON-string that we need to parse.\n const singleKey = keys[0];\n const value = param[singleKey];\n // If that single property is a string, fix it and try to parse it as JSON.\n if (typeof value === 'string') {\n try {\n return parseTextAsJson(isolateCurlySubstring(value));\n } catch (e) {\n console.log('value is string \u2192 parse failed with error:', e.toString(), '\u2192 return param:', param, 'value:', value);\n // Parsing failed; perhaps it's just a plain string or invalid JSON, so return as is.\n return param;\n }\n }\n\n // Otherwise, repeat this process itratively.\n return normalizeLLMOutput(value, iteration-1);\n}\n\nconst preparedData = $(\"PreparedData\").itemMatching($itemIndex).json;\nconst row = preparedData.row;\nlet gen = normalizeLLMOutput($json);\nlet fulltext = gen.hasOwnProperty('Fulltext') ? gen.Fulltext : gen;\n\n// Append any fulltext field returned to the field\n// in our data row corresponding to the current action. \ngen[row.Action] = fulltext;\n\n// Concatenate any generated fields with those already exisiting\n// in our data row (using seperator if necessary),\n// so we don't loose any pre-entered data.\nconst combined = {};\nObject.keys(gen).forEach(key => {\n const a = String(row[key] ?? \"\");\n const b = String(gen[key]);\n combined[key] = (a && b) ? (a + \"\\n---\\n\" + b) : (a || b);\n});\n\n// Add the row number and set the new status to the action just performed.\ncombined.row_number = row.row_number;\ncombined.Status = row.Action;\ncombined.model = preparedData.model;\n\nreturn 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": "", "name": "[Your googleSheetsOAuth2Api]"}}, "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": "", "name": "[Your googleSheetsOAuth2Api]"}}, "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;\nconst password = $('Settings').item.json.wordpressApplicationPassword;\nconst blogId = 0;\nconst published = 1; // 0 = draft, 1 = published\nconst title = $json.row.Title;\nconst text = $json.row.final;\n\n// Helper function to escape XML special characters\nfunction escapeXml(unsafe) {\n return unsafe.replace(/[<>&'\"]/g, (c) => {\n switch (c) {\n case '<': return '<';\n case '>': return '>';\n case '&': return '&';\n case '\\'': return ''';\n case '\"': return '"';\n default: return c;\n }\n });\n}\n\n// Your actual post text, which may contain characters needing escaping\nconst titleEscaped = escapeXml(title);\nconst textEscaped = escapeXml(text);\n\n// Build the XML payload\nconst xmlData = `<?xml version=\"1.0\"?>\n<methodCall>\n <methodName>wp.newPost</methodName>\n <params>\n <param>\n <value><string>${blogId}</string></value>\n </param>\n <param>\n <value><string>${username}</string></value>\n </param>\n <param>\n <value><string>${password}</string></value>\n </param>\n <param>\n <value>\n <struct>\n <member>\n <name>post_title</name>\n <value><string>${titleEscaped}</string></value>\n </member>\n <member>\n <name>post_content</name>\n <value><string>${textEscaped}</string></value>\n </member>\n </struct>\n </value>\n </param>\n <param>\n <value><boolean>${published}</boolean></value>\n </param>\n </params>\n</methodCall>`;\n\n\n// Add a new field called 'myNewField' to the JSON of the item\n$input.item.json.xmlRequestBody = xmlData;\n\nreturn $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\nconst xmlResponse = $json.data;\n\n// Helper function to extract a value by matching a regex pattern\nfunction extractValue(pattern, xml) {\n const match = xml.match(pattern);\n return match ? match[1] : null;\n}\n\n// Check if the XML contains a fault\nif (xmlResponse.indexOf(\"<fault>\") !== -1) {\n // Extract the faultCode and faultString using regex\n // This regex matches the value inside <int> or <string> for faultCode\n const faultCode = extractValue(/<name>faultCode<\\/name>\\s*<value><(?:int|string)>(.*?)<\\/(?:int|string)>/s, xmlResponse);\n // This regex extracts the faultString from within <string>\n const faultString = extractValue(/<name>faultString<\\/name>\\s*<value><string>(.*?)<\\/string>/s, xmlResponse);\n return { 'errorCode': faultCode, 'error': faultString };\n} else {\n // Otherwise, assume a successful response.\n // The post ID is contained inside a <string> tag within <params>\n const postId = extractValue(/<params>[\\s\\S]*?<string>(.*?)<\\/string>/, xmlResponse);\n return { postId };\n}"}, "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": "", "name": "[Your googleSheetsOAuth2Api]"}}, "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": "", "name": "[Your googleSheetsOAuth2Api]"}}, "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\nUsing 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\n{{ 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\nUse 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\nNormalize 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\nExtract 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\n## 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\n## 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}]]}}}How to Import This Workflow
- 1Copy the workflow JSON above using the Copy Workflow JSON button.
- 2Open your n8n instance and go to Workflows.
- 3Click Import from JSON and paste the copied workflow.
Don't have an n8n instance? Start your free trial at n8nautomation.cloud
Related Templates
Auto-create TikTok videos with VEED.io AI avatars, ElevenLabs & GPT-4
Automate the creation and distribution of trending TikTok videos using AI avatars. This workflow connects Telegram, Perplexity, OpenAI, ElevenLabs, VEED.io, and BLOTATO to generate scripts, synthesize voice, create video, and publish across multiple social platforms. Content creators and marketers can rapidly produce engaging short-form video content without manual editing.
Automate LinkedIn Posts with AI
Automate your LinkedIn content creation and publishing by leveraging AI with this powerful workflow. This n8n automation connects LinkedIn, OpenAI, and Notion to streamline your social media presence. A Schedule Trigger initiates the process daily, querying your Notion database for today's scheduled posts. For each post, the workflow fetches all content from its Notion page, including text blocks and an image URL, then uses OpenAI to reformat the post text for optimal engagement. The workflow then combines the rephrased text and fetched image, publishing the complete post directly to LinkedIn. Finally, it updates the post's status in Notion to "Done," ensuring your content calendar remains accurate. This workflow is ideal for content creators, marketers, and businesses looking to maintain a consistent and engaging LinkedIn presence without manual effort, saving significant time on content preparation and publishing while ensuring high-quality, AI-enhanced posts.
Customer Support Channel and Ticketing System with Slack and Linear
Automate your customer support channel and ticketing system by efficiently managing incoming requests from Slack and creating structured tickets in Linear. This workflow connects Slack to capture customer inquiries, then leverages OpenAI's AI capabilities to understand and categorize these requests. It regularly polls Slack for new messages in a designated support channel using a Schedule Trigger, extracts key information, and checks Linear to see if similar issues already exist. If a new, unique issue is identified, the workflow uses OpenAI's language model to generate a comprehensive ticket description and then creates a new ticket in Linear, ensuring all relevant details are captured. This automation is ideal for customer support teams, product managers, and operations personnel who need to streamline their issue tracking, reduce manual data entry, and ensure no customer request falls through the cracks. It significantly reduces the time spent on triaging and creating support tickets, allowing teams to focus more on resolving customer issues rather than administrative tasks, ultimately improving response times and customer satisfaction.