{ "kind": "open-flow-workflow", "version": 1, "name": "Publish Recent WordPress Posts to Medium", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_efb50c7bcfa1fef9": { "name": "Run manually", "kind": "start", "inputDefs": [] }, "n_e35266fe81f29abf": { "inputs": { "perPage": { "kind": "value", "value": 5 }, "page": { "kind": "value", "value": 1 }, "order": { "kind": "value", "value": "desc" }, "orderby": { "kind": "value", "value": "date" }, "status": { "kind": "value", "value": [ "publish" ] } }, "name": "Read recent published posts", "kind": "task", "task": { "inputs": [ { "description": "Limit results to resources matching this search string.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Limit results to resources matching this search string." }, "nullable": true, "handle": "search", "value": null }, { "description": "The page number of WordPress results to return.", "jsonSchema": { "type": "integer", "exclusiveMinimum": 0, "description": "The page number of WordPress results to return." }, "nullable": true, "handle": "page", "value": null }, { "description": "The maximum number of WordPress results to return.", "jsonSchema": { "type": "integer", "minimum": 1, "maximum": 100, "description": "The maximum number of WordPress results to return." }, "nullable": true, "handle": "perPage", "value": null }, { "description": "The sort direction for WordPress list results.", "jsonSchema": { "type": "string", "enum": [ "asc", "desc" ], "description": "The sort direction for WordPress list results." }, "nullable": true, "handle": "order", "value": null }, { "description": "WordPress statuses to include.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "A WordPress post status to include, including trash or any." }, "minItems": 1, "description": "WordPress statuses to include." }, "nullable": true, "handle": "status", "value": null }, { "description": "Category IDs used to filter WordPress posts.", "jsonSchema": { "type": "array", "items": { "type": "integer", "exclusiveMinimum": 0, "description": "One numeric WordPress resource ID." }, "minItems": 1, "description": "Category IDs used to filter WordPress posts." }, "nullable": true, "handle": "categories", "value": null }, { "description": "Tag IDs used to filter WordPress posts.", "jsonSchema": { "type": "array", "items": { "type": "integer", "exclusiveMinimum": 0, "description": "One numeric WordPress resource ID." }, "minItems": 1, "description": "Tag IDs used to filter WordPress posts." }, "nullable": true, "handle": "tags", "value": null }, { "description": "Post IDs to include in the response.", "jsonSchema": { "type": "array", "items": { "type": "integer", "exclusiveMinimum": 0, "description": "One numeric WordPress resource ID." }, "minItems": 1, "description": "Post IDs to include in the response." }, "nullable": true, "handle": "include", "value": null }, { "description": "Post IDs to exclude from the response.", "jsonSchema": { "type": "array", "items": { "type": "integer", "exclusiveMinimum": 0, "description": "One numeric WordPress resource ID." }, "minItems": 1, "description": "Post IDs to exclude from the response." }, "nullable": true, "handle": "exclude", "value": null }, { "description": "Author user IDs used to filter WordPress posts.", "jsonSchema": { "type": "array", "items": { "type": "integer", "exclusiveMinimum": 0, "description": "One numeric WordPress resource ID." }, "minItems": 1, "description": "Author user IDs used to filter WordPress posts." }, "nullable": true, "handle": "author", "value": null }, { "description": "Post slugs used to filter WordPress posts.", "jsonSchema": { "type": "array", "items": { "type": "string", "pattern": "\\S", "minLength": 1, "description": "The WordPress URL slug." }, "minItems": 1, "description": "Post slugs used to filter WordPress posts." }, "nullable": true, "handle": "slug", "value": null }, { "description": "The field used to sort WordPress posts or pages.", "jsonSchema": { "type": "string", "enum": [ "author", "date", "id", "include", "modified", "parent", "relevance", "slug", "include_slugs", "title" ], "description": "The field used to sort WordPress posts or pages." }, "nullable": true, "handle": "orderby", "value": null } ], "outputs": [ { "description": "The WordPress posts returned by the list request.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer", "exclusiveMinimum": 0, "description": "The numeric WordPress post ID." }, "slug": { "type": "string", "description": "The WordPress post slug." }, "status": { "type": "string", "description": "The WordPress post status." }, "title": { "type": "object", "properties": { "rendered": { "type": "string", "description": "The rendered HTML value returned by WordPress." } }, "additionalProperties": true, "description": "A WordPress rendered object." } }, "required": [ "id", "slug", "status", "title" ], "additionalProperties": true, "description": "A WordPress post object." }, "description": "The WordPress posts returned by the list request." }, "nullable": false, "handle": "posts" }, { "description": "Pagination metadata returned in WordPress response headers.", "jsonSchema": { "type": "object", "properties": { "total": { "type": [ "integer", "null" ], "description": "The total number of matching WordPress resources." }, "totalPages": { "type": [ "integer", "null" ], "description": "The total number of WordPress result pages." } }, "required": [ "total", "totalPages" ], "additionalProperties": false, "description": "Pagination metadata returned in WordPress response headers." }, "nullable": false, "handle": "pagination" } ], "name": "Read recent published posts", "executor": { "kind": "connector", "action": "wordpress.list_posts" } } }, "n_c338dbb31328fad1": { "inputs": { "url": { "kind": "value", "value": "https://api.medium.com/v1/me" }, "auth.token": { "kind": "unset" } }, "name": "Read Medium author", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Read Medium author", "executor": { "method": "GET", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "bearer" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_a616e66694072dc3": { "inputs": { "posts": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_e35266fe81f29abf", "output": "posts" } ] }, "author": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c338dbb31328fad1", "output": "body" } ] }, "previous": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_a616e66694072dc3", "output": "state" } ] } }, "name": "Prepare the next post", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer", "exclusiveMinimum": 0, "description": "The numeric WordPress post ID." }, "slug": { "type": "string", "description": "The WordPress post slug." }, "status": { "type": "string", "description": "The WordPress post status." }, "title": { "type": "object", "properties": { "rendered": { "type": "string", "description": "The rendered HTML value returned by WordPress." } }, "additionalProperties": true, "description": "A WordPress rendered object." } }, "required": [ "id", "slug", "status", "title" ], "additionalProperties": true, "description": "A WordPress post object." }, "description": "The WordPress posts returned by the list request." }, "nullable": false, "handle": "posts" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previous" }, { "jsonSchema": {}, "nullable": true, "handle": "author" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "body" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "summary" } ], "name": "Prepare the next post", "moduleId": "n_74966ed698a777dc", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_0c81c6111382a97b": { "inputs": {}, "name": "More posts?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_a616e66694072dc3", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_4ae9f3e6a21ba5e9": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_a616e66694072dc3", "output": "url" } ] }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_a616e66694072dc3", "output": "body" } ] }, "auth.token": { "kind": "unset" } }, "name": "Publish to Medium", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Publish to Medium", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "authentication": { "type": "bearer" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_b3129d01e949d287": { "inputs": { "response": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4ae9f3e6a21ba5e9", "output": "body" } ] } }, "name": "Confirm publication", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "response" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "ok" } ], "name": "Confirm publication", "moduleId": "n_36bd6d4a538f6d9f", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_59c7b9d036322fe0": { "name": "Publication count", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "summary" } ], "outputMappings": { "summary": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_a616e66694072dc3", "output": "summary" } ] } } } }, "edges": [ { "source": "n_efb50c7bcfa1fef9", "target": "n_e35266fe81f29abf" }, { "source": "n_e35266fe81f29abf", "target": "n_c338dbb31328fad1" }, { "source": "n_c338dbb31328fad1", "target": "n_a616e66694072dc3" }, { "source": "n_a616e66694072dc3", "target": "n_0c81c6111382a97b" }, { "source": "n_0c81c6111382a97b", "target": "n_4ae9f3e6a21ba5e9", "sourceHandle": "yes" }, { "source": "n_4ae9f3e6a21ba5e9", "target": "n_b3129d01e949d287" }, { "source": "n_b3129d01e949d287", "target": "n_a616e66694072dc3" }, { "source": "n_0c81c6111382a97b", "target": "n_59c7b9d036322fe0", "sourceHandle": "otherwise" } ] } }, "modules": { "n_74966ed698a777dc": { "name": "Prepare the next post", "imports": [], "source": "export default function next({posts,previous,author}){const s=previous??{index:0};if(!Array.isArray(posts)||posts.length>5)throw Error('Invalid WordPress results');if(s.index>=posts.length)return{state:s,more:false,url:'https://api.medium.com/',body:{},summary:{published:s.index}};if(typeof author?.data?.id!=='string'||!author.data.id)throw Error('Medium author was not confirmed');const p=posts[s.index],title=p?.title?.rendered,content=p?.content?.rendered;if(typeof title!=='string'||typeof content!=='string'||!title.trim()||!content.trim())throw Error('A post has no rendered title or content');const text=title.replace(/<[^>]*>/g,'').replace(/&#(x[0-9a-f]+|\\d+);/gi,(_,v)=>String.fromCodePoint(v[0].toLowerCase()==='x'?parseInt(v.slice(1),16):parseInt(v,10))).replace(/&(amp|lt|gt|quot|apos|nbsp);/gi,(_,v)=>({amp:'&',lt:'<',gt:'>',quot:'\"',apos:\"'\",nbsp:' '})[v.toLowerCase()]);if(/&[a-z][a-z0-9]+;/i.test(text))throw Error('Unsupported HTML entity in title; review before publishing');return{state:{index:s.index+1},more:true,url:'https://api.medium.com/v1/users/'+encodeURIComponent(author.data.id)+'/posts',body:{title:text,contentFormat:'html',content,tags:['Email Hosting','Email','Email Marketing'],publishStatus:'public',notifyFollowers:false},summary:{published:s.index}}}\n" }, "n_36bd6d4a538f6d9f": { "name": "Confirm publication", "imports": [], "source": "export default function confirm({response}){if(!response?.data?.id||!response?.data?.url)throw Error('Medium publication not confirmed; inspect before retrying');return{ok:true}}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }