Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exporter: wordpress export action #639

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"flatfilers/*",
"plugins/*",
"support/*",
"utils/*"
"utils/*",
"validators/*"
],
"scripts": {
"clean": "find ./ '(' -name 'node_modules' -o -name 'dist' -o -name '.turbo' -o -name '.parcel-cache' ')' -type d -exec rm -rf {} +",
Expand Down
59 changes: 59 additions & 0 deletions validators/WordpressCMSExporter/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Flatfile to WordPress Exporter

This plugin integrates Flatfile with WordPress, allowing for seamless export of records from Flatfile to WordPress posts. It uses the Flatfile Listener and Record Hook plugin to process records and map them to WordPress post fields.

## Features

- Automatic field mapping from Flatfile to WordPress post fields
- Support for custom fields
- Handling of categories and tags as arrays
- Ability to update existing posts or create new ones
- Error handling and reporting

## Installation

To install this plugin, run the following command:

```bash
npm install @flatfile/listener @flatfile/plugin-record-hook @flatfile/api axios
```

## Example Usage

```javascript
import { FlatfileListener } from '@flatfile/listener';
import { recordHook } from '@flatfile/plugin-record-hook';
import api from '@flatfile/api';
import axios from 'axios';

const listener = FlatfileListener.create((listener) => {
listener.use(
recordHook('contacts', async (record, event) => {
// ... (code implementation as provided in the original snippet)
})
);
});

export default listener;
```

## Configuration

To use this plugin, you need to set up the following in your Flatfile space metadata:

- `wpApiUrl`: The URL of your WordPress API
- `wpApiKey`: Your WordPress API authentication key

These credentials are used to authenticate requests to the WordPress API.

## Behavior

1. The plugin processes each record in the 'contacts' sheet.
2. It maps Flatfile fields to WordPress post fields according to a predefined mapping.
3. Special handling is applied for categories, tags, and custom fields.
4. The plugin checks if a post with the same title already exists in WordPress.
5. If an existing post is found, it updates the post; otherwise, it creates a new post.
6. The WordPress post ID is stored back in the Flatfile record.
7. Any errors during the export process are logged and added to the record.

Note: This plugin assumes that the 'title' field is used as a unique identifier for posts. Adjust this logic if a different field should be used for identifying existing posts.
105 changes: 105 additions & 0 deletions validators/WordpressCMSExporter/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
{
"timestamp": "2024-09-25T06-27-21-653Z",
"task": "Create a Wordpress CMS Export Flatfile Listener plugin:\n - Implement a custom action to export data to Wordpress\n - Allow users to select the target CMS platform and provide necessary API credentials\n - Map Flatfile fields to corresponding CMS fields (e.g., title, content, author, categories, tags)\n - Support exporting rich text content, including formatting and embedded media\n - Implement options for post status (draft, published) and scheduling\n - Handle batch processing for efficient export of multiple posts\n - Provide error handling and reporting for failed exports\n - Allow configuration of default post settings (e.g., featured image, excerpt)\n - Implement a preview function to review post formatting before export\n - Support updating existing posts by matching on a unique identifier\n - Include options for handling custom fields specific to each CMS platform",
"summary": "This code implements a Flatfile Listener that uses the Record Hook plugin to process records and export them to WordPress. It includes functionality for field mapping, handling custom fields, and updating existing posts.",
"steps": [
[
"Retrieve general knowledge about Flatfile Listeners and the Record Hook plugin to understand the structure and capabilities we can utilize.\n",
"#E1",
"PineconeAssistant",
"Provide information on Flatfile Listeners and the Record Hook plugin, including their structure and capabilities",
"Plan: Retrieve general knowledge about Flatfile Listeners and the Record Hook plugin to understand the structure and capabilities we can utilize.\n#E1 = PineconeAssistant[Provide information on Flatfile Listeners and the Record Hook plugin, including their structure and capabilities]"
],
[
"Implement the custom action for exporting data to Wordpress, including user selection for the target CMS platform and API credential input.\n",
"#E3",
"LLM",
"Extend the code from #E2 to include a custom action for exporting data to Wordpress, allowing users to select the target CMS platform and provide API credentials",
"Plan: Implement the custom action for exporting data to Wordpress, including user selection for the target CMS platform and API credential input.\n#E3 = LLM[Extend the code from #E2 to include a custom action for exporting data to Wordpress, allowing users to select the target CMS platform and provide API credentials]"
],
[
"Implement field mapping functionality to map Flatfile fields to corresponding CMS fields.\n",
"#E4",
"LLM",
"Add field mapping functionality to the code from #E3, mapping Flatfile fields to CMS fields such as title, content, author, categories, and tags",
"Plan: Implement field mapping functionality to map Flatfile fields to corresponding CMS fields.\n#E4 = LLM[Add field mapping functionality to the code from #E3, mapping Flatfile fields to CMS fields such as title, content, author, categories, and tags]"
],
[
"Add support for exporting rich text content, including formatting and embedded media.\n",
"#E5",
"LLM",
"Extend the code from #E4 to support exporting rich text content, including formatting and embedded media",
"Plan: Add support for exporting rich text content, including formatting and embedded media.\n#E5 = LLM[Extend the code from #E4 to support exporting rich text content, including formatting and embedded media]"
],
[
"Implement options for post status (draft, published) and scheduling.\n",
"#E6",
"LLM",
"Add functionality to the code from #E5 for setting post status (draft, published) and scheduling",
"Plan: Implement options for post status (draft, published) and scheduling.\n#E6 = LLM[Add functionality to the code from #E5 for setting post status (draft, published) and scheduling]"
],
[
"Implement batch processing for efficient export of multiple posts.\n",
"#E7",
"LLM",
"Extend the code from #E6 to include batch processing functionality for efficient export of multiple posts",
"Plan: Implement batch processing for efficient export of multiple posts.\n#E7 = LLM[Extend the code from #E6 to include batch processing functionality for efficient export of multiple posts]"
],
[
"Add error handling and reporting for failed exports.\n",
"#E8",
"LLM",
"Implement error handling and reporting for failed exports in the code from #E7",
"Plan: Add error handling and reporting for failed exports.\n#E8 = LLM[Implement error handling and reporting for failed exports in the code from #E7]"
],
[
"Implement configuration options for default post settings.\n",
"#E9",
"LLM",
"Add configuration options for default post settings (e.g., featured image, excerpt) to the code from #E8",
"Plan: Implement configuration options for default post settings.\n#E9 = LLM[Add configuration options for default post settings (e.g., featured image, excerpt) to the code from #E8]"
],
[
"Implement a preview function to review post formatting before export.\n",
"#E10",
"LLM",
"Add a preview function to the code from #E9 to allow users to review post formatting before export",
"Plan: Implement a preview function to review post formatting before export.\n#E10 = LLM[Add a preview function to the code from #E9 to allow users to review post formatting before export]"
],
[
"Implement functionality to update existing posts by matching on a unique identifier.\n",
"#E11",
"LLM",
"Extend the code from #E10 to support updating existing posts by matching on a unique identifier",
"Plan: Implement functionality to update existing posts by matching on a unique identifier.\n#E11 = LLM[Extend the code from #E10 to support updating existing posts by matching on a unique identifier]"
],
[
"Add support for handling custom fields specific to each CMS platform.\n",
"#E12",
"LLM",
"Implement support for handling custom fields specific to each CMS platform in the code from #E11",
"Plan: Add support for handling custom fields specific to each CMS platform.\n#E12 = LLM[Implement support for handling custom fields specific to each CMS platform in the code from #E11]"
],
[
"Verify that the implemented Listener subscribes to valid Event Topics.\n",
"#E13",
"PineconeAssistant",
"Verify that the Event Topics used in the Listener implementation are valid according to the event.topics.fact file",
"Plan: Verify that the implemented Listener subscribes to valid Event Topics.\n#E13 = PineconeAssistant[Verify that the Event Topics used in the Listener implementation are valid according to the event.topics.fact file]"
],
[
"Review the final code, remove any unused imports, and validate the parameters for any plugins used.\n",
"#E14",
"LLM",
"Review the complete code from #E12, remove any unused imports, and validate the parameters for any plugins used. Ensure that the code is valid and follows best practices for Flatfile Listeners",
"Plan: Review the final code, remove any unused imports, and validate the parameters for any plugins used.\n#E14 = LLM[Review the complete code from #E12, remove any unused imports, and validate the parameters for any plugins used. Ensure that the code is valid and follows best practices for Flatfile Listeners]"
]
],
"metrics": {
"tokens": {
"plan": 5552,
"state": 7901,
"total": 13453
}
}
}
69 changes: 69 additions & 0 deletions validators/WordpressCMSExporter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"name": "@flatfile/plugin-wordpress-exporter",
"version": "1.0.0",
"description": "A Flatfile plugin for exporting records to WordPress",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"browser": {
"./dist/index.js": "./dist/index.browser.js",
"./dist/index.mjs": "./dist/index.browser.mjs"
},
"exports": {
"types": "./dist/index.d.ts",
"node": {
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"browser": {
"require": "./dist/index.browser.js",
"import": "./dist/index.browser.mjs"
},
"default": "./dist/index.mjs"
},
"source": "./src/index.ts",
"files": [
"dist/**"
],
"scripts": {
"build": "rollup -c",
"build:watch": "rollup -c --watch",
"build:prod": "NODE_ENV=production rollup -c",
"check": "tsc ./**/*.ts --noEmit --esModuleInterop",
"test": "jest ./**/*.spec.ts --config=../../jest.config.js --runInBand"
},
"keywords": [
"flatfile",
"plugin",
"wordpress",
"exporter",
"flatfile-plugins",
"category-transform"
],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"@flatfile/listener": "^1.0.5",
"@flatfile/plugin-record-hook": "^1.7.0",
"@flatfile/api": "^1.9.15",
"axios": "^1.7.7"
},
"devDependencies": {
"@flatfile/hooks": "^1.5.0",
"@flatfile/rollup-config": "^0.1.1",
"typescript": "^5.6.2",
"@types/node": "^22.7.0",
"rollup": "^4.22.4",
"jest": "^29.7.0",
"@types/jest": "^29.5.13"
},
"repository": {
"type": "git",
"url": "https://github.com/YourUsername/flatfile-plugin-wordpress-exporter.git"
},
"browserslist": [
"> 0.5%",
"last 2 versions",
"not dead"
]
}
47 changes: 47 additions & 0 deletions validators/WordpressCMSExporter/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { buildConfig } from '@flatfile/rollup-config';
import typescript from '@rollup/plugin-typescript';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';

const umdExternals = [
'@flatfile/api',
'@flatfile/hooks',
'@flatfile/listener',
'@flatfile/util-common',
'@flatfile/plugin-record-hook',
'axios'
];

const config = buildConfig({
input: 'src/index.ts', // Assuming your main file is src/index.ts
includeUmd: true,
umdConfig: {
name: 'FlatfileWordPressExport',
external: umdExternals
},
plugins: [
typescript({
tsconfig: './tsconfig.json',
declaration: true,
declarationDir: 'dist/types'
}),
resolve({
browser: true
}),
commonjs(),
json()
]
});

// Add custom configuration for TypeScript handling
config.forEach(conf => {
if (conf.plugins) {
conf.plugins.unshift(typescript({
tsconfig: './tsconfig.json',
declaration: false
}));
}
});

export default config;
93 changes: 93 additions & 0 deletions validators/WordpressCMSExporter/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { FlatfileListener } from '@flatfile/listener'
import { recordHook } from '@flatfile/plugin-record-hook'
import api from '@flatfile/api'
import axios from 'axios'

const listener = FlatfileListener.create((listener) => {
listener.use(
recordHook('contacts', async (record, event) => {
const { jobId, environmentId, spaceId, sheetId } = event.context

// Field mapping
const fieldMapping = {
title: 'name',
content: 'description',
author: 'email',
categories: 'category',
tags: 'tags',
status: 'status',
custom_fields: 'custom_fields',
}

// Prepare post data
const postData = {}
for (const [wpField, ffField] of Object.entries(fieldMapping)) {
if (record.get(ffField)) {
if (wpField === 'categories' || wpField === 'tags') {
postData[wpField] = record
.get(ffField)
.split(',')
.map((item) => item.trim())
} else if (wpField === 'custom_fields') {
postData[wpField] = JSON.parse(record.get(ffField) || '{}')
} else {
postData[wpField] = record.get(ffField)
}
}
}

try {
// Get WordPress API credentials from Flatfile space metadata
const { data: space } = await api.spaces.get(spaceId)
const wpApiUrl = space.metadata.wpApiUrl
const wpApiKey = space.metadata.wpApiKey

if (!wpApiUrl || !wpApiKey) {
throw new Error(
'WordPress API credentials not found in space metadata'
)
}

const headers = {
Authorization: `Bearer ${wpApiKey}`,
'Content-Type': 'application/json',
}

// Check if post already exists (assuming 'name' is unique identifier)
const existingPosts = await axios.get(
`${wpApiUrl}/wp-json/wp/v2/posts?search=${postData.title}`,
{ headers }
)
flatfile-nullify[bot] marked this conversation as resolved.
Show resolved Hide resolved

let response
if (existingPosts.data.length > 0) {
// Update existing post
const postId = existingPosts.data[0].id
response = await axios.put(
`${wpApiUrl}/wp-json/wp/v2/posts/${postId}`,
postData,
{ headers }
)
flatfile-nullify[bot] marked this conversation as resolved.
Show resolved Hide resolved
} else {
// Create new post
response = await axios.post(
`${wpApiUrl}/wp-json/wp/v2/posts`,
postData,
{ headers }
)
flatfile-nullify[bot] marked this conversation as resolved.
Show resolved Hide resolved
}

// Update record with WordPress post ID
record.set('wp_post_id', response.data.id)

return record
} catch (error) {
console.error('Error exporting to WordPress:', error.message)
record.addError('wordpress_export', 'Failed to export to WordPress')
return record
}
})
)
})

export default listener
Loading