php代码粘贴到functions.php
<?php
/**
* Plugin Name: Polylang REST API Extension - Enhanced (Fixed)
* Description: Custom REST API endpoints for Polylang with proper translation linking
* Version: 2.1.0
* Author: Your Name
*/
if (!defined('ABSPATH')) {
exit;
}
class Polylang_REST_API_Extension {
private $namespace = 'polylang-api/v1';
public function __construct() {
add_action('rest_api_init', array($this, 'register_routes'));
}
/**
* Register all REST API routes
*/
public function register_routes() {
// Get all translatable post types
register_rest_route($this->namespace, '/post-types', array(
'methods' => 'GET',
'callback' => array($this, 'get_post_types'),
'permission_callback' => array($this, 'check_permission'),
));
// Get untranslated posts
register_rest_route($this->namespace, '/untranslated-posts', array(
'methods' => 'GET',
'callback' => array($this, 'get_untranslated_posts'),
'permission_callback' => array($this, 'check_permission'),
'args' => array(
'post_type' => array(
'default' => 'post',
'sanitize_callback' => 'sanitize_text_field',
),
'source_lang' => array(
'default' => 'en',
'sanitize_callback' => 'sanitize_text_field',
),
'target_lang' => array(
'required' => true,
'sanitize_callback' => 'sanitize_text_field',
),
),
));
// Get post content for translation
register_rest_route($this->namespace, '/post/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_post_content'),
'permission_callback' => array($this, 'check_permission'),
'args' => array(
'id' => array(
'validate_callback' => function($param) {
return is_numeric($param);
}
),
),
));
// Create translated post
register_rest_route($this->namespace, '/translate-post', array(
'methods' => 'POST',
'callback' => array($this, 'create_translated_post'),
'permission_callback' => array($this, 'check_permission'),
));
// Get languages
register_rest_route($this->namespace, '/languages', array(
'methods' => 'GET',
'callback' => array($this, 'get_languages'),
'permission_callback' => array($this, 'check_permission'),
));
// Get translation status
register_rest_route($this->namespace, '/translation-status/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_translation_status'),
'permission_callback' => array($this, 'check_permission'),
));
}
/**
* Permission callback
*/
public function check_permission() {
return current_user_can('edit_posts');
}
/**
* Get all public post types that support translation
*/
public function get_post_types() {
if (!function_exists('pll_languages_list')) {
return new WP_Error('polylang_not_active', 'Polylang is not active', array('status' => 500));
}
$post_types = get_post_types(array(
'public' => true,
), 'objects');
unset($post_types['attachment'], $post_types['video'], $post_types['page']);
$translatable_types = array();
foreach ($post_types as $post_type) {
if (function_exists('pll_is_translated_post_type') && pll_is_translated_post_type($post_type->name)) {
$translatable_types[] = array(
'name' => $post_type->name,
'label' => $post_type->label,
'singular_name' => $post_type->labels->singular_name,
);
}
}
return rest_ensure_response(array(
'success' => true,
'post_types' => array_column($translatable_types, 'name'),
'post_types_details' => $translatable_types,
));
}
/**
* Get all untranslated posts for a specific language
*/
public function get_untranslated_posts($request) {
if (!function_exists('pll_languages_list')) {
return new WP_Error('polylang_not_active', 'Polylang is not active', array('status' => 500));
}
$post_type = $request->get_param('post_type');
$source_lang = $request->get_param('source_lang');
$target_lang = $request->get_param('target_lang');
$args = array(
'post_type' => $post_type,
'posts_per_page' => -1,
'lang' => $source_lang,
'post_status' => 'publish',
);
$posts = get_posts($args);
$untranslated = array();
foreach ($posts as $post) {
$translation_id = pll_get_post($post->ID, $target_lang);
if (!$translation_id) {
$untranslated[] = array(
'id' => $post->ID,
'title' => $post->post_title,
'slug' => $post->post_name,
'status' => $post->post_status,
'date' => $post->post_date,
'modified' => $post->post_modified,
'post_type' => $post->post_type,
'language' => $source_lang,
);
}
}
return rest_ensure_response(array(
'success' => true,
'count' => count($untranslated),
'posts' => $untranslated,
));
}
/**
* Get full post content including all meta fields
*/
public function get_post_content($request) {
$post_id = $request->get_param('id');
$post = get_post($post_id);
if (!$post) {
return new WP_Error('post_not_found', 'Post not found', array('status' => 404));
}
$post_meta = get_post_meta($post_id);
$clean_meta = array();
foreach ($post_meta as $key => $value) {
if (substr($key, 0, 1) === '_') continue;
$meta_value = is_array($value) ? $value[0] : $value;
if (!is_string($meta_value) || $this->is_serialized($meta_value)) continue;
$clean_meta[$key] = $meta_value;
}
$categories = wp_get_post_categories($post_id, array('fields' => 'all'));
$tags = wp_get_post_tags($post_id, array('fields' => 'all'));
$custom_taxonomies = array();
$taxonomies = get_object_taxonomies($post->post_type, 'objects');
foreach ($taxonomies as $taxonomy) {
if (!in_array($taxonomy->name, array('category', 'post_tag', 'language', 'post_translations'))) {
$terms = wp_get_post_terms($post_id, $taxonomy->name);
if (!is_wp_error($terms) && !empty($terms)) {
$custom_taxonomies[$taxonomy->name] = $terms;
}
}
}
$thumbnail_id = get_post_thumbnail_id($post_id);
$thumbnail_url = $thumbnail_id ? wp_get_attachment_url($thumbnail_id) : null;
$acf_fields = array();
if (function_exists('get_fields')) {
$acf_fields = get_fields($post_id) ?: array();
}
$current_lang = pll_get_post_language($post_id);
return rest_ensure_response(array(
'success' => true,
'post' => array(
'id' => $post->ID,
'title' => $post->post_title,
'content' => $post->post_content,
'excerpt' => $post->post_excerpt,
'slug' => $post->post_name,
'status' => $post->post_status,
'type' => $post->post_type,
'language' => $current_lang,
'featured_image' => $thumbnail_url,
'thumbnail_id' => $thumbnail_id,
'categories' => $categories,
'tags' => $tags,
'custom_taxonomies' => $custom_taxonomies,
'meta' => $clean_meta,
'acf_fields' => $acf_fields,
),
));
}
/**
* Create or update translated post - FIXED VERSION
* Now properly preserves all translation relationships
*/
public function create_translated_post($request) {
$params = $request->get_json_params();
if (!isset($params['source_post_id']) || !isset($params['target_lang'])) {
return new WP_Error('missing_params', 'Missing required parameters', array('status' => 400));
}
$source_post_id = intval($params['source_post_id']);
$target_lang = sanitize_text_field($params['target_lang']);
$translated_title = sanitize_text_field($params['title']);
$translated_content = wp_kses_post($params['content']);
$translated_excerpt = isset($params['excerpt']) ? sanitize_textarea_field($params['excerpt']) : '';
$source_post = get_post($source_post_id);
if (!$source_post) {
return new WP_Error('post_not_found', 'Source post not found', array('status' => 404));
}
// Check if translation exists
$existing_translation = pll_get_post($source_post_id, $target_lang);
if ($existing_translation) {
// Update existing translation
$updated_post = array(
'ID' => $existing_translation,
'post_title' => $translated_title,
'post_content' => $translated_content,
'post_excerpt' => $translated_excerpt,
);
$result = wp_update_post($updated_post, true);
if (is_wp_error($result)) {
return $result;
}
$translated_post_id = $existing_translation;
$action = 'updated';
} else {
// Create new translation
$new_post = array(
'post_title' => $translated_title,
'post_content' => $translated_content,
'post_excerpt' => $translated_excerpt,
'post_status' => $source_post->post_status,
'post_type' => $source_post->post_type,
'post_author' => $source_post->post_author,
);
$translated_post_id = wp_insert_post($new_post, true);
if (is_wp_error($translated_post_id)) {
return $translated_post_id;
}
// Set language for new post
pll_set_post_language($translated_post_id, $target_lang);
// ⭐ CRITICAL FIX: Get ALL existing translations first
$existing_translations = pll_get_post_translations($source_post_id);
// Add the new translation to the existing group
$existing_translations[$target_lang] = $translated_post_id;
// Save the complete translation group
pll_save_post_translations($existing_translations);
$action = 'created';
}
// Copy or set featured image
if (isset($params['thumbnail_id']) && $params['thumbnail_id']) {
set_post_thumbnail($translated_post_id, intval($params['thumbnail_id']));
} else {
$thumbnail_id = get_post_thumbnail_id($source_post_id);
if ($thumbnail_id) {
set_post_thumbnail($translated_post_id, $thumbnail_id);
}
}
// Handle categories
if (isset($params['categories']) && is_array($params['categories'])) {
$translated_category_ids = array();
foreach ($params['categories'] as $category_data) {
$cat_id = $this->translate_term($category_data, 'category', $target_lang);
if ($cat_id) {
$translated_category_ids[] = $cat_id;
}
}
wp_set_post_categories($translated_post_id, $translated_category_ids);
}
// Handle tags
if (isset($params['tags']) && is_array($params['tags'])) {
$translated_tag_ids = array();
foreach ($params['tags'] as $tag_data) {
$tag_id = $this->translate_term($tag_data, 'post_tag', $target_lang);
if ($tag_id) {
$translated_tag_ids[] = $tag_id;
}
}
wp_set_post_tags($translated_post_id, $translated_tag_ids);
}
// Handle ACF fields
if (isset($params['acf_fields']) && function_exists('update_field')) {
foreach ($params['acf_fields'] as $field_key => $field_value) {
update_field($field_key, $field_value, $translated_post_id);
}
}
// Handle custom meta fields
if (isset($params['meta_fields']) && is_array($params['meta_fields'])) {
foreach ($params['meta_fields'] as $meta_key => $meta_value) {
if (substr($meta_key, 0, 1) === '_') continue;
update_post_meta($translated_post_id, $meta_key, sanitize_text_field($meta_value));
}
}
// Get final translation status for verification
$final_translations = pll_get_post_translations($source_post_id);
return rest_ensure_response(array(
'success' => true,
'action' => $action,
'translated_post_id' => $translated_post_id,
'source_post_id' => $source_post_id,
'post_type' => $source_post->post_type,
'target_language' => $target_lang,
'url' => get_permalink($translated_post_id),
'all_translations' => $final_translations, // Shows all connected translations
));
}
/**
* Helper to translate taxonomy terms
*/
private function translate_term($term_data, $taxonomy, $target_lang) {
$source_term_id = isset($term_data['term_id']) ? intval($term_data['term_id']) : 0;
$translated_name = isset($term_data['translated_name']) ? sanitize_text_field($term_data['translated_name']) : '';
if ($source_term_id && function_exists('pll_get_term')) {
$existing_translation = pll_get_term($source_term_id, $target_lang);
if ($existing_translation) {
return $existing_translation;
}
}
if ($translated_name) {
$new_term = wp_insert_term($translated_name, $taxonomy);
if (!is_wp_error($new_term)) {
$new_term_id = $new_term['term_id'];
if (function_exists('pll_set_term_language')) {
pll_set_term_language($new_term_id, $target_lang);
if ($source_term_id) {
// ⭐ SAME FIX for terms: preserve existing translations
$existing_term_translations = pll_get_term_translations($source_term_id);
$existing_term_translations[$target_lang] = $new_term_id;
pll_save_term_translations($existing_term_translations);
}
}
return $new_term_id;
}
}
return null;
}
/**
* Get all configured languages
*/
public function get_languages() {
if (!function_exists('pll_languages_list')) {
return new WP_Error('polylang_not_active', 'Polylang is not active', array('status' => 500));
}
$languages = pll_languages_list(array('fields' => 'all'));
$lang_data = array();
foreach ($languages as $lang) {
$lang_data[] = array(
'slug' => $lang->slug,
'name' => $lang->name,
'locale' => $lang->locale,
'is_rtl' => $lang->is_rtl,
'flag' => $lang->flag,
);
}
return rest_ensure_response(array(
'success' => true,
'languages' => $lang_data,
));
}
/**
* Get translation status for a specific post
*/
public function get_translation_status($request) {
$post_id = $request->get_param('id');
if (!function_exists('pll_get_post_translations')) {
return new WP_Error('polylang_not_active', 'Polylang is not active', array('status' => 500));
}
$translations = pll_get_post_translations($post_id);
$languages = pll_languages_list();
$status = array();
foreach ($languages as $lang) {
$status[$lang] = isset($translations[$lang]) ? array(
'exists' => true,
'post_id' => $translations[$lang],
'url' => get_permalink($translations[$lang]),
) : array(
'exists' => false,
'post_id' => null,
'url' => null,
);
}
return rest_ensure_response(array(
'success' => true,
'post_id' => $post_id,
'translations' => $status,
));
}
/**
* Check if a string is serialized
*/
private function is_serialized($data) {
if (!is_string($data)) {
return false;
}
$data = trim($data);
if ($data === 'N;') {
return true;
}
if (strlen($data) < 4 || $data[1] !== ':') {
return false;
}
return @unserialize($data) !== false;
}
}
// Initialize the plugin
new Polylang_REST_API_Extension();
JSON代码导入到n8n
{
"name": "wp-auto-translate-all-post-types",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
-1568,
16
],
"id": "866ab43f-a481-40f3-9db2-a313c5d29d21"
},
{
"parameters": {
"url": "=https://banwork.cn/wp-json/polylang-api/v1/post-types",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"options": {}
},
"name": "Get All Post Types",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-1376,
16
],
"id": "f4ef3bef-f814-4d55-bbfc-6a757e00c6a9",
"credentials": {
"httpBasicAuth": {
"id": "nRdVHRimMjQuSFHB",
"name": "Unnamed credential"
}
}
},
{
"parameters": {
"fields": {
"values": [
{
"name": "target_languages",
"stringValue": "zh"
},
{
"name": "source_lang",
"stringValue": "en"
}
]
},
"options": {}
},
"name": "Set Language Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
-1168,
16
],
"id": "e7ced265-d70d-460c-ab49-96ac8462e4ff"
},
{
"parameters": {
"fieldToSplitOut": "post_types",
"include": "selectedOtherFields",
"fieldsToInclude": "target_languages",
"options": {}
},
"name": "Split Post Types",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
-976,
16
],
"id": "d115ab2c-e40e-4e7a-9a24-238afdb977ea"
},
{
"parameters": {
"fieldToSplitOut": "target_languages",
"options": {}
},
"name": "Split Target Languages",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
-768,
16
],
"id": "30482dd5-90b4-4220-91b6-cba4bb4803ad"
},
{
"parameters": {
"url": "=https://banwork.cn/wp-json/polylang-api/v1/untranslated-posts",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "post_type",
"value": "={{ $('Split Post Types').item.json.post_types }}"
},
{
"name": "source_lang",
"value": "={{ $('Set Language Config').item.json.source_lang }}"
},
{
"name": "target_lang",
"value": "={{ $json.target_languages }}"
}
]
},
"options": {}
},
"name": "Get Untranslated Posts",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-560,
16
],
"id": "63ab9178-11e4-4b42-b2e6-100606587a1f",
"credentials": {
"httpBasicAuth": {
"id": "nRdVHRimMjQuSFHB",
"name": "Unnamed credential"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "has-posts",
"leftValue": "={{ $json.count }}",
"rightValue": 0,
"operator": {
"type": "number",
"operation": "gt"
}
}
],
"combinator": "and"
},
"options": {}
},
"name": "Has Untranslated Posts?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-352,
16
],
"id": "4e7cc773-54c9-40a1-aa3d-1f0202dad896"
},
{
"parameters": {
"fieldToSplitOut": "posts",
"options": {}
},
"name": "Split Posts",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
-144,
-96
],
"id": "6969d7f5-5d8d-4209-aeda-f7a01d83ab8e"
},
{
"parameters": {
"url": "=https://banwork.cn/wp-json/polylang-api/v1/post/{{ $json.id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"options": {}
},
"name": "Get Post Content",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
64,
-96
],
"id": "3661b4f7-7727-4632-b039-90d00420fe77",
"credentials": {
"httpBasicAuth": {
"id": "nRdVHRimMjQuSFHB",
"name": "Unnamed credential"
}
}
},
{
"parameters": {
"jsCode": "function stripHtml(html) {\n if (!html) return '';\n \n let text = html\n .replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '')\n .replace(/<style\\b[^<]*(?:(?!<\\/style>)<[^<]*)*<\\/style>/gi, '');\n \n text = text.replace(/<[^>]+>/g, ' ');\n text = text.replace(/\\s+/g, ' ').trim();\n \n return text;\n}\n\n// Process translatable meta fields\nfunction extractTranslatableMeta(metaFields, postType) {\n const translatable = {};\n \n if (!metaFields || typeof metaFields !== 'object') return translatable;\n \n // Extract text-based meta fields (skip internal WordPress fields)\n for (const [key, value] of Object.entries(metaFields)) {\n // Skip internal WP fields and serialized data\n if (key.startsWith('_') || !value) continue;\n \n // Handle arrays (take first value)\n const metaValue = Array.isArray(value) ? value[0] : value;\n \n // Only include string values\n if (typeof metaValue === 'string' && metaValue.length > 0) {\n translatable[key] = stripHtml(metaValue);\n }\n }\n \n return translatable;\n}\n\nconst items = $input.all();\n\nreturn items.map((item, index) => {\n const postData = item.json.post || item.json;\n \n return {\n json: {\n id: item.json.id || postData.id,\n post: {\n id: postData.id,\n post_type: postData.type,\n title: stripHtml(postData.title),\n content: stripHtml(postData.content),\n excerpt: stripHtml(postData.excerpt || ''),\n categories: postData.categories || [],\n tags: postData.tags || [],\n acf_fields: postData.acf_fields || {},\n meta_fields: extractTranslatableMeta(postData.meta, postData.type),\n thumbnail_id: postData.thumbnail_id || null\n }\n },\n pairedItem: index\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
272,
-96
],
"id": "23fca5fa-d3df-4050-b874-180875215767",
"name": "Process Post Data"
},
{
"parameters": {
"jsCode": "const items = $input.all();\nconst sourceLang = $('Set Language Config').item.json.source_lang;\nconst targetLang = $('Split Target Languages').item.json.target_languages;\n\nreturn items.map((item, index) => {\n const postData = item.json.post;\n \n // Build content for translation including meta fields\n let translationContent = `Title: ${postData.title}\\n\\nContent: ${postData.content}`;\n \n if (postData.excerpt) {\n translationContent += `\\n\\nExcerpt: ${postData.excerpt}`;\n }\n \n // Add meta fields to translation\n const metaFieldsArray = [];\n if (postData.meta_fields && Object.keys(postData.meta_fields).length > 0) {\n translationContent += '\\n\\nMeta Fields:';\n for (const [key, value] of Object.entries(postData.meta_fields)) {\n translationContent += `\\n${key}: ${value}`;\n metaFieldsArray.push({ key, value });\n }\n }\n \n // Build expected JSON structure\n let expectedStructure = '\"title\": \"translated title\", \"content\": \"translated content\"';\n if (postData.excerpt) {\n expectedStructure += ', \"excerpt\": \"translated excerpt\"';\n }\n if (metaFieldsArray.length > 0) {\n expectedStructure += ', \"meta_fields\": {\"field_key\": \"translated value\"}';\n }\n \n const requestBody = {\n model: \"deepseek-chat\",\n messages: [\n {\n role: \"system\",\n content: `You are a professional translator. Translate the following WordPress ${postData.post_type} content from ${sourceLang} to ${targetLang}. Return ONLY a valid JSON object with these exact keys: {${expectedStructure}}. For meta_fields, use the same keys but translate the values.`\n },\n {\n role: \"user\",\n content: translationContent\n }\n ],\n temperature: 0.3,\n response_format: { type: \"json_object\" }\n };\n \n return {\n json: {\n requestBody: requestBody,\n post: postData,\n metaFieldsKeys: metaFieldsArray.map(m => m.key)\n },\n pairedItem: index\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
-96
],
"id": "",
"name": "Build DeepSeek Request"
},
{
"parameters": {
"method": "POST",
"url": "https://api.deepseek.com/v1/chat/completions",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ $json.requestBody }}",
"options": {}
},
"name": "DeepSeek Translate",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
688,
-96
],
"id": "",
"credentials": {
"httpHeaderAuth": {
"id": "5X9OcogB9LTTIp0J",
"name": "Header Auth account"
}
}
},
{
"parameters": {
"jsCode": "const items = $input.all();\nconst postContentItems = $('Get Post Content').all();\nconst targetLang = $('Split Target Languages').item.json.target_languages;\n\nreturn items.map((item, index) => {\n const response = item.json;\n const translatedData = JSON.parse(response.choices[0].message.content);\n \n const originalPostItem = postContentItems[index].json;\n const originalPost = originalPostItem.post || originalPostItem;\n \n const categories = (originalPost.categories || []).map(cat => ({\n term_id: cat.term_id,\n translated_name: cat.name\n }));\n \n const tags = (originalPost.tags || []).map(tag => ({\n term_id: tag.term_id,\n translated_name: tag.name\n }));\n \n let acfFields = {};\n if (originalPost.acf_fields && typeof originalPost.acf_fields === 'object') {\n acfFields = originalPost.acf_fields;\n }\n \n // Extract translated meta fields\n let translatedMeta = {};\n if (translatedData.meta_fields && typeof translatedData.meta_fields === 'object') {\n translatedMeta = translatedData.meta_fields;\n }\n \n return {\n json: {\n source_post_id: originalPost.id,\n post_type: originalPost.type,\n target_lang: targetLang,\n title: translatedData.title,\n content: translatedData.content,\n excerpt: translatedData.excerpt || '',\n categories: categories,\n tags: tags,\n acf_fields: acfFields,\n meta_fields: translatedMeta,\n thumbnail_id: originalPost.thumbnail_id\n },\n pairedItem: index\n };\n});"
},
"name": "Format Translation Data",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
896,
-96
],
"id": "d7593a9c-37c4-4618-8c2f-773644978361"
},
{
"parameters": {
"method": "POST",
"url": "=https://banwork.cn/wp-json/polylang-api/v1/translate-post",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"source_post_id\": {{ $json.source_post_id }},\n \"target_lang\": \"{{ $json.target_lang }}\",\n \"title\": {{ JSON.stringify($json.title) }},\n \"content\": {{ JSON.stringify($json.content) }},\n \"excerpt\": {{ JSON.stringify($json.excerpt) }},\n \"categories\": {{ JSON.stringify($json.categories) }},\n \"tags\": {{ JSON.stringify($json.tags) }},\n \"acf_fields\": {{ JSON.stringify($json.acf_fields) }},\n \"meta_fields\": {{ JSON.stringify($json.meta_fields) }},\n \"thumbnail_id\": {{ $json.thumbnail_id }}\n}",
"options": {}
},
"name": "Create Translation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
1104,
-96
],
"id": "765c02b2-5ffc-4575-b30c-3ca224c5fe0c",
"credentials": {
"httpBasicAuth": {
"id": "nRdVHRimMjQuSFHB",
"name": "Unnamed credential"
}
}
},
{
"parameters": {
"amount": 2
},
"name": "Rate Limit Delay",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1312,
-96
],
"id": "13ba9a90-d155-4d25-9ec2-f69bfee9b0fb",
"webhookId": "rate-limit-delay"
},
{
"parameters": {
"options": {}
},
"name": "Log Success",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
1504,
-96
],
"id": "4794f7d4-b410-453c-bee6-af3b1cd6481c"
},
{
"parameters": {
"options": {}
},
"name": "Workflow Complete",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
1712,
16
],
"id": "5e1a1b81-857f-4fae-b49b-b90e2b833119"
}
],
"pinData": {},
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Get All Post Types",
"type": "main",
"index": 0
}
]
]
},
"Get All Post Types": {
"main": [
[
{
"node": "Set Language Config",
"type": "main",
"index": 0
}
]
]
},
"Set Language Config": {
"main": [
[
{
"node": "Split Post Types",
"type": "main",
"index": 0
}
]
]
},
"Split Post Types": {
"main": [
[
{
"node": "Split Target Languages",
"type": "main",
"index": 0
}
]
]
},
"Split Target Languages": {
"main": [
[
{
"node": "Get Untranslated Posts",
"type": "main",
"index": 0
}
]
]
},
"Get Untranslated Posts": {
"main": [
[
{
"node": "Has Untranslated Posts?",
"type": "main",
"index": 0
}
]
]
},
"Has Untranslated Posts?": {
"main": [
[
{
"node": "Split Posts",
"type": "main",
"index": 0
}
],
[
{
"node": "Workflow Complete",
"type": "main",
"index": 0
}
]
]
},
"Split Posts": {
"main": [
[
{
"node": "Get Post Content",
"type": "main",
"index": 0
}
]
]
},
"Get Post Content": {
"main": [
[
{
"node": "Process Post Data",
"type": "main",
"index": 0
}
]
]
},
"Process Post Data": {
"main": [
[
{
"node": "Build DeepSeek Request",
"type": "main",
"index": 0
}
]
]
},
"Build DeepSeek Request": {
"main": [
[
{
"node": "DeepSeek Translate",
"type": "main",
"index": 0
}
]
]
},
"DeepSeek Translate": {
"main": [
[
{
"node": "Format Translation Data",
"type": "main",
"index": 0
}
]
]
},
"Format Translation Data": {
"main": [
[
{
"node": "Create Translation",
"type": "main",
"index": 0
}
]
]
},
"Create Translation": {
"main": [
[
{
"node": "Rate Limit Delay",
"type": "main",
"index": 0
}
]
]
},
"Rate Limit Delay": {
"main": [
[
{
"node": "Log Success",
"type": "main",
"index": 0
}
]
]
},
"Log Success": {
"main": [
[
{
"node": "Workflow Complete",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"availableInMCP": false
},
"versionId": "4379907a-2214-4e78-94ca-670f802ac693",
"meta": {
"instanceId": "e116f0cdc2af85ea765f95e160256c7af2464258f43bb537f78b1a25e7dab4f3"
},
"id": "aGlXEQLoxR9kRL97kU8c-",
"tags": []
}