n8n-nodes-blog-post 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -0
- package/dist/credentials/BlogApi.credentials.d.ts +7 -0
- package/dist/credentials/BlogApi.credentials.js +32 -0
- package/dist/nodes/BlogPost/BlogPost.node.d.ts +5 -0
- package/dist/nodes/BlogPost/BlogPost.node.js +185 -0
- package/dist/nodes/BlogPost/blog.svg +8 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# n8n Blog Post Node
|
|
2
|
+
|
|
3
|
+
A custom n8n node for posting blog content to the kepha14.dev API.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Post blog content with all required fields
|
|
8
|
+
- Support for optional fields (excerpt, cover image, tags, category, SEO metadata)
|
|
9
|
+
- Bearer token authentication
|
|
10
|
+
- Error handling with continue on fail option
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
1. Install dependencies:
|
|
15
|
+
```bash
|
|
16
|
+
npm install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Build the node:
|
|
20
|
+
```bash
|
|
21
|
+
npm run build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
3. Link the package to n8n:
|
|
25
|
+
```bash
|
|
26
|
+
npm link
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
4. In your n8n installation directory, link the package:
|
|
30
|
+
```bash
|
|
31
|
+
npm link n8n-nodes-blog-post
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
5. Restart n8n to load the custom node.
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Setting Up Credentials
|
|
39
|
+
|
|
40
|
+
Before using the Blog Post node, you need to create credentials:
|
|
41
|
+
|
|
42
|
+
1. In n8n, go to **Credentials** → **Add Credential**
|
|
43
|
+
2. Search for **Blog API** and select it
|
|
44
|
+
3. Fill in the following fields:
|
|
45
|
+
- **API URL**: The endpoint URL
|
|
46
|
+
- **Secret**: Your Bearer token for API authentication
|
|
47
|
+
4. Save the credentials
|
|
48
|
+
|
|
49
|
+
### Using the Node
|
|
50
|
+
|
|
51
|
+
The Blog Post node allows you to:
|
|
52
|
+
- Set blog post title and slug (required)
|
|
53
|
+
- Add full content (required)
|
|
54
|
+
- Optionally add excerpt, cover image, tags, category
|
|
55
|
+
- Set SEO metadata (meta title, meta description)
|
|
56
|
+
- Specify author email
|
|
57
|
+
- Configure published status
|
|
58
|
+
|
|
59
|
+
## Node Parameters
|
|
60
|
+
|
|
61
|
+
### Required Fields
|
|
62
|
+
- **Title**: The title of the blog post
|
|
63
|
+
- **Slug**: URL-friendly slug for the blog post
|
|
64
|
+
- **Content**: Full blog post content
|
|
65
|
+
- **Credentials**: Blog API credentials (configured separately)
|
|
66
|
+
|
|
67
|
+
### Optional Fields
|
|
68
|
+
- **Excerpt**: Short excerpt or summary
|
|
69
|
+
- **Cover Image URL**: URL of the cover image
|
|
70
|
+
- **Published**: Whether the blog post should be published (default: true)
|
|
71
|
+
- **Tags**: Array of tags for the blog post
|
|
72
|
+
- **Category**: Category of the blog post
|
|
73
|
+
- **Meta Title**: SEO meta title
|
|
74
|
+
- **Meta Description**: SEO meta description
|
|
75
|
+
- **Author Email**: Email of the author
|
|
76
|
+
|
|
77
|
+
## Credentials
|
|
78
|
+
|
|
79
|
+
The node requires **Blog API** credentials with:
|
|
80
|
+
- **API URL**: The API endpoint URL (e.g., `)
|
|
81
|
+
- **Secret**: Bearer token for authentication
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Watch mode for development
|
|
87
|
+
npm run dev
|
|
88
|
+
|
|
89
|
+
# Build for production
|
|
90
|
+
npm run build
|
|
91
|
+
|
|
92
|
+
# Lint code
|
|
93
|
+
npm run lint
|
|
94
|
+
|
|
95
|
+
# Format code
|
|
96
|
+
npm run format
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
|
102
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BlogApi = void 0;
|
|
4
|
+
class BlogApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'blogApi';
|
|
7
|
+
this.displayName = 'Blog API';
|
|
8
|
+
this.documentationUrl = '';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'API URL',
|
|
12
|
+
name: 'url',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: '',
|
|
15
|
+
required: true,
|
|
16
|
+
description: 'The API endpoint URL for blog posts',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
displayName: 'Secret',
|
|
20
|
+
name: 'secret',
|
|
21
|
+
type: 'string',
|
|
22
|
+
typeOptions: {
|
|
23
|
+
password: true,
|
|
24
|
+
},
|
|
25
|
+
default: '',
|
|
26
|
+
required: true,
|
|
27
|
+
description: 'Bearer token for API authentication',
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.BlogApi = BlogApi;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BlogPost = void 0;
|
|
4
|
+
class BlogPost {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.description = {
|
|
7
|
+
displayName: 'Blog Post',
|
|
8
|
+
name: 'blogPost',
|
|
9
|
+
icon: 'file:blog.svg',
|
|
10
|
+
group: ['transform'],
|
|
11
|
+
version: 1,
|
|
12
|
+
description: 'Post blog content to kepha14.dev API',
|
|
13
|
+
defaults: {
|
|
14
|
+
name: 'Blog Post',
|
|
15
|
+
},
|
|
16
|
+
inputs: ['main'],
|
|
17
|
+
outputs: ['main'],
|
|
18
|
+
credentials: [
|
|
19
|
+
{
|
|
20
|
+
name: 'blogApi',
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
properties: [
|
|
25
|
+
{
|
|
26
|
+
displayName: 'Title',
|
|
27
|
+
name: 'title',
|
|
28
|
+
type: 'string',
|
|
29
|
+
default: '',
|
|
30
|
+
required: true,
|
|
31
|
+
description: 'The title of the blog post',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
displayName: 'Slug',
|
|
35
|
+
name: 'slug',
|
|
36
|
+
type: 'string',
|
|
37
|
+
default: '',
|
|
38
|
+
required: true,
|
|
39
|
+
description: 'URL-friendly slug for the blog post',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
displayName: 'Content',
|
|
43
|
+
name: 'content',
|
|
44
|
+
type: 'string',
|
|
45
|
+
typeOptions: {
|
|
46
|
+
rows: 5,
|
|
47
|
+
},
|
|
48
|
+
default: '',
|
|
49
|
+
required: true,
|
|
50
|
+
description: 'Full blog post content',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
displayName: 'Excerpt',
|
|
54
|
+
name: 'excerpt',
|
|
55
|
+
type: 'string',
|
|
56
|
+
typeOptions: {
|
|
57
|
+
rows: 3,
|
|
58
|
+
},
|
|
59
|
+
default: '',
|
|
60
|
+
description: 'Short excerpt or summary of the blog post',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
displayName: 'Cover Image URL',
|
|
64
|
+
name: 'coverImage',
|
|
65
|
+
type: 'string',
|
|
66
|
+
default: '',
|
|
67
|
+
description: 'URL of the cover image',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
displayName: 'Published',
|
|
71
|
+
name: 'published',
|
|
72
|
+
type: 'boolean',
|
|
73
|
+
default: true,
|
|
74
|
+
description: 'Whether the blog post should be published',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
displayName: 'Tags',
|
|
78
|
+
name: 'tags',
|
|
79
|
+
type: 'string',
|
|
80
|
+
typeOptions: {
|
|
81
|
+
multipleValues: true,
|
|
82
|
+
},
|
|
83
|
+
default: [],
|
|
84
|
+
description: 'Tags for the blog post',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
displayName: 'Category',
|
|
88
|
+
name: 'category',
|
|
89
|
+
type: 'string',
|
|
90
|
+
default: '',
|
|
91
|
+
description: 'Category of the blog post',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
displayName: 'Meta Title',
|
|
95
|
+
name: 'metaTitle',
|
|
96
|
+
type: 'string',
|
|
97
|
+
default: '',
|
|
98
|
+
description: 'SEO meta title',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
displayName: 'Meta Description',
|
|
102
|
+
name: 'metaDescription',
|
|
103
|
+
type: 'string',
|
|
104
|
+
typeOptions: {
|
|
105
|
+
rows: 3,
|
|
106
|
+
},
|
|
107
|
+
default: '',
|
|
108
|
+
description: 'SEO meta description',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
displayName: 'Author Email',
|
|
112
|
+
name: 'authorEmail',
|
|
113
|
+
type: 'string',
|
|
114
|
+
default: '',
|
|
115
|
+
description: 'Email of the author',
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async execute() {
|
|
121
|
+
const items = this.getInputData();
|
|
122
|
+
const returnData = [];
|
|
123
|
+
const credentials = await this.getCredentials('blogApi');
|
|
124
|
+
for (let i = 0; i < items.length; i++) {
|
|
125
|
+
try {
|
|
126
|
+
const title = this.getNodeParameter('title', i);
|
|
127
|
+
const slug = this.getNodeParameter('slug', i);
|
|
128
|
+
const content = this.getNodeParameter('content', i);
|
|
129
|
+
const excerpt = this.getNodeParameter('excerpt', i);
|
|
130
|
+
const coverImage = this.getNodeParameter('coverImage', i);
|
|
131
|
+
const published = this.getNodeParameter('published', i);
|
|
132
|
+
const tags = this.getNodeParameter('tags', i);
|
|
133
|
+
const category = this.getNodeParameter('category', i);
|
|
134
|
+
const metaTitle = this.getNodeParameter('metaTitle', i);
|
|
135
|
+
const metaDescription = this.getNodeParameter('metaDescription', i);
|
|
136
|
+
const authorEmail = this.getNodeParameter('authorEmail', i);
|
|
137
|
+
const body = {
|
|
138
|
+
title,
|
|
139
|
+
slug,
|
|
140
|
+
content,
|
|
141
|
+
excerpt: excerpt || undefined,
|
|
142
|
+
coverImage: coverImage || undefined,
|
|
143
|
+
published,
|
|
144
|
+
tags: tags || [],
|
|
145
|
+
category: category || undefined,
|
|
146
|
+
metaTitle: metaTitle || undefined,
|
|
147
|
+
metaDescription: metaDescription || undefined,
|
|
148
|
+
authorEmail: authorEmail || undefined,
|
|
149
|
+
};
|
|
150
|
+
const response = await this.helpers.httpRequest({
|
|
151
|
+
method: 'POST',
|
|
152
|
+
url: credentials.url,
|
|
153
|
+
headers: {
|
|
154
|
+
'Authorization': `Bearer ${credentials.secret}`,
|
|
155
|
+
'Content-Type': 'application/json',
|
|
156
|
+
},
|
|
157
|
+
body,
|
|
158
|
+
json: true,
|
|
159
|
+
});
|
|
160
|
+
returnData.push({
|
|
161
|
+
json: response,
|
|
162
|
+
pairedItem: {
|
|
163
|
+
item: i,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (this.continueOnFail()) {
|
|
169
|
+
returnData.push({
|
|
170
|
+
json: {
|
|
171
|
+
error: error instanceof Error ? error.message : String(error),
|
|
172
|
+
},
|
|
173
|
+
pairedItem: {
|
|
174
|
+
item: i,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return [returnData];
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
exports.BlogPost = BlogPost;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
|
|
3
|
+
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
|
|
4
|
+
<line x1="8" y1="7" x2="16" y2="7"></line>
|
|
5
|
+
<line x1="8" y1="11" x2="16" y2="11"></line>
|
|
6
|
+
<line x1="8" y1="15" x2="12" y2="15"></line>
|
|
7
|
+
</svg>
|
|
8
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-blog-post",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Custom n8n node for posting blogs to API endpoints with Bearer token authentication",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n-nodes-base"
|
|
8
|
+
],
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"homepage": "",
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "",
|
|
13
|
+
"email": ""
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": ""
|
|
18
|
+
},
|
|
19
|
+
"main": "index.js",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc && gulp build:icons",
|
|
22
|
+
"dev": "tsc --watch",
|
|
23
|
+
"format": "prettier nodes credentials --write",
|
|
24
|
+
"lint": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\"",
|
|
25
|
+
"lintfix": "eslint \"nodes/**/*.ts\" \"credentials/**/*.ts\" --fix",
|
|
26
|
+
"prepublishOnly": "npm run build && npm run lint -s"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"n8n": {
|
|
33
|
+
"n8nNodesApiVersion": 1,
|
|
34
|
+
"nodes": [
|
|
35
|
+
"dist/nodes/BlogPost/BlogPost.node.js"
|
|
36
|
+
],
|
|
37
|
+
"credentials": [
|
|
38
|
+
"dist/credentials/BlogApi.credentials.js"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@typescript-eslint/parser": "^5.45.0",
|
|
43
|
+
"eslint-plugin-n8n-nodes-base": "~1.11.0",
|
|
44
|
+
"gulp": "^4.0.2",
|
|
45
|
+
"n8n-workflow": "*",
|
|
46
|
+
"prettier": "^2.7.1",
|
|
47
|
+
"typescript": "~5.3.3"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"n8n-workflow": "*"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|