更新版wp+deepseek+n8n自动翻译所有语言支持所有文章类型所有语言

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": []
}
×
更新版wp+deepseek+n8n自动翻译所有语言支持所有文章类型所有语言

更新版wp+deepseek+n8n自动翻译所有语言支持所有文章类型所有语言

php代码粘贴到functions.ph...