Changeset 3482396
- Timestamp:
- 03/14/2026 07:36:07 AM (2 weeks ago)
- Location:
- wpraiz-content-api-tool
- Files:
-
- 56 added
- 2 deleted
- 6 edited
- 1 copied
-
assets/banner-1544x500.png (modified) (previous)
-
assets/banner-772x250.png (added)
-
assets/icon-128x128.png (added)
-
assets/icon-256x256.png (modified) (previous)
-
tags/2.0.0 (copied) (copied from wpraiz-content-api-tool/trunk)
-
tags/2.0.0/assets/css (added)
-
tags/2.0.0/assets/css/admin.css (added)
-
tags/2.0.0/assets/js/admin-scripts.js (deleted)
-
tags/2.0.0/assets/js/admin.js (added)
-
tags/2.0.0/composer.json (added)
-
tags/2.0.0/includes (added)
-
tags/2.0.0/includes/admin (added)
-
tags/2.0.0/includes/admin/class-admin-page.php (added)
-
tags/2.0.0/includes/admin/class-license.php (added)
-
tags/2.0.0/includes/ai (added)
-
tags/2.0.0/includes/ai/class-ai-manager.php (added)
-
tags/2.0.0/includes/ai/class-ai-provider.php (added)
-
tags/2.0.0/includes/ai/class-claude-provider.php (added)
-
tags/2.0.0/includes/ai/class-openai-provider.php (added)
-
tags/2.0.0/includes/class-auth.php (added)
-
tags/2.0.0/includes/class-content-manager.php (added)
-
tags/2.0.0/includes/class-media-handler.php (added)
-
tags/2.0.0/includes/class-search-engine.php (added)
-
tags/2.0.0/includes/class-seo-handler.php (added)
-
tags/2.0.0/includes/class-webhooks.php (added)
-
tags/2.0.0/includes/mcp (added)
-
tags/2.0.0/includes/mcp/class-mcp-cli.php (added)
-
tags/2.0.0/includes/mcp/class-mcp-prompts.php (added)
-
tags/2.0.0/includes/mcp/class-mcp-resources.php (added)
-
tags/2.0.0/includes/mcp/class-mcp-server.php (added)
-
tags/2.0.0/includes/mcp/class-mcp-tools.php (added)
-
tags/2.0.0/languages (added)
-
tags/2.0.0/readme.txt (modified) (2 diffs)
-
tags/2.0.0/uninstall.php (added)
-
tags/2.0.0/wpraiz-content.php (modified) (1 diff)
-
trunk/assets/css (added)
-
trunk/assets/css/admin.css (added)
-
trunk/assets/js/admin-scripts.js (deleted)
-
trunk/assets/js/admin.js (added)
-
trunk/composer.json (added)
-
trunk/includes (added)
-
trunk/includes/admin (added)
-
trunk/includes/admin/class-admin-page.php (added)
-
trunk/includes/admin/class-license.php (added)
-
trunk/includes/ai (added)
-
trunk/includes/ai/class-ai-manager.php (added)
-
trunk/includes/ai/class-ai-provider.php (added)
-
trunk/includes/ai/class-claude-provider.php (added)
-
trunk/includes/ai/class-openai-provider.php (added)
-
trunk/includes/class-auth.php (added)
-
trunk/includes/class-content-manager.php (added)
-
trunk/includes/class-media-handler.php (added)
-
trunk/includes/class-search-engine.php (added)
-
trunk/includes/class-seo-handler.php (added)
-
trunk/includes/class-webhooks.php (added)
-
trunk/includes/mcp (added)
-
trunk/includes/mcp/class-mcp-cli.php (added)
-
trunk/includes/mcp/class-mcp-prompts.php (added)
-
trunk/includes/mcp/class-mcp-resources.php (added)
-
trunk/includes/mcp/class-mcp-server.php (added)
-
trunk/includes/mcp/class-mcp-tools.php (added)
-
trunk/languages (added)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/uninstall.php (added)
-
trunk/wpraiz-content.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
wpraiz-content-api-tool/tags/2.0.0/readme.txt
r3265377 r3482396 1 1 === WPRaiz Content API Tool === 2 Contributors: zeicaro3 Donate link: https://ai.wpraiz.com.br 4 Tags: REST API, Content, Post Creation, SEO, Image Upload, Automation 5 Requires at least: 5.0 6 Tested up to: 6.7.2 7 Stable tag: 1.58 License: GPLv 39 License URI: https://www.gnu.org/licenses/gpl- 3.0.html2 Contributors: wpraiz, joseicaro 3 Tags: rest-api, content-automation, ai-content, mcp, claude 4 Requires at least: 5.8 5 Tested up to: 6.7 6 Requires PHP: 7.4 7 Stable tag: 2.0.0 8 License: GPLv2 or later 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Create WordPress posts via REST API with custom SEO fields, image uploads, primary category assignment, and integration with major SEO plugins (SEOPress, Yoast SEO, Rank Math).11 REST API + MCP Server for WordPress. Create, update, and manage posts programmatically. AI content generation with your own API keys (BYOK). 12 12 13 13 == Description == 14 14 15 The WPRaiz Content API Tool is a powerful plugin that enables the creation of WordPress posts programmatically through a REST API. Ideal for developers and websites that need seamless content integration from external systems, this plugin supports: 15 **WPRaiz Content API Tool** turns your WordPress site into a powerful content API. Create posts, manage categories, generate AI content, and connect AI agents — all via REST API or Model Context Protocol (MCP). 16 16 17 - **Integration with Major SEO Plugins**: Set custom SEO fields for titles and descriptions, compatible with SEOPress, Yoast SEO, and Rank Math. 18 - **Flexible Image Uploads**: Accept images via URL, with automatic attachment as the featured image. 19 - **Automatic Category Management**: Assign an existing category or create a new one based on supplied category names. 20 - **Installation Check Endpoint**: Verify plugin installation, authentication, and detect the installed SEO plugin. 21 - **Post Similarity Search**: Find and return the top 10 most similar published posts by title for better content linking and duplication checks. 22 - **Admin Interface**: Dashboard section with copyable API endpoints for easy testing. 17 = What You Can Do = 18 19 * **Create & Update Posts** — Full control over title, content, status, categories, tags, excerpt, featured images, and custom meta fields via REST API. 20 * **Bulk Creation** — Create up to 50 posts in a single request (Pro). 21 * **AI Content Generation** — Generate full articles from a topic using Claude or OpenAI with your own API keys (Pro). 22 * **AI Rewrite** — Improve SEO, fix grammar, change tone, expand, or summarize existing posts (Pro). 23 * **Auto-SEO** — Automatically generate SEO titles and meta descriptions when not provided. Supports SEOPress, Yoast SEO, and Rank Math. 24 * **MCP Server** — Connect AI agents (Claude Desktop, Cursor, Windsurf) directly to your site via Model Context Protocol. 25 * **Similar Post Search** — Find duplicate or related content using intelligent Levenshtein-based scoring. 26 * **Webhooks** — Get notified when posts are created or bulk operations complete, with HMAC signature verification. 27 * **JWT Authentication** — Secure token-based auth with configurable rate limiting. 28 29 = Free vs Pro = 30 31 **Free** (this plugin): 32 33 * Create and update single posts via REST API 34 * Search similar posts 35 * List and manage categories 36 * JWT and Basic Auth (Application Passwords) 37 * SEO plugin auto-detection and meta writing 38 * Featured image upload from URL 39 * Rate limiting 40 * Legacy v1 endpoint compatibility 41 42 **Pro** ($49/year at [wpraiz.com.br/pro](https://wpraiz.com.br/pro)): 43 44 * Everything in Free, plus: 45 * Bulk post creation (up to 50 per batch) 46 * AI content generation (BYOK — Claude or OpenAI) 47 * AI post rewriting (5 modes) 48 * Auto-SEO via AI 49 * MCP Server (HTTP + STDIO transports) 50 * Webhook notifications with HMAC signing 51 * Priority support 52 53 = MCP Server = 54 55 The Model Context Protocol server lets AI agents interact with your WordPress site natively. Available via HTTP (REST API) or STDIO (WP-CLI). 56 57 **Tools:** create_post, update_post, search_similar, get_categories, generate_content, rewrite_post, bulk_create 58 59 **Resources:** site-info, recent-posts, categories, content-stats, seo-config 60 61 **Prompts:** publish_seo_article, content_series, seo_audit, refresh_old_content, internal_linking 62 63 Add to your `claude_desktop_config.json`: 64 65 ` 66 { 67 "mcpServers": { 68 "wpraiz": { 69 "command": "wp", 70 "args": ["wpraiz-mcp", "serve", "--path=/path/to/wordpress", "--user=1"] 71 } 72 } 73 } 74 ` 75 76 = REST API Endpoints = 77 78 Base URL: `https://yoursite.com/wp-json/wpraiz/v2/` 79 80 | Endpoint | Method | Auth | Tier | 81 |---|---|---|---| 82 | create-post | POST | JWT/Basic | Free | 83 | update-post | POST | JWT/Basic | Free | 84 | create-posts | POST | JWT/Basic | Pro | 85 | generate-content | POST | JWT/Basic | Pro | 86 | rewrite-post | POST | JWT/Basic | Pro | 87 | search-similar | GET | Public | Free | 88 | categories | GET | Public | Free | 89 | check-status | GET | Public | Free | 90 | auth/token | POST | Credentials | Free | 91 92 = Authentication = 93 94 **JWT Token:** 95 1. POST to `auth/token` with `username` and `password` 96 2. Use the returned token as `Authorization: Bearer <token>` 97 98 **Basic Auth:** 99 Use WordPress Application Passwords with standard HTTP Basic authentication. 100 101 = Requirements = 102 103 * WordPress 5.8+ 104 * PHP 7.4+ 105 * For AI features: Claude API key or OpenAI API key 106 * For MCP STDIO: WP-CLI installed 23 107 24 108 == Installation == 25 109 26 1. Download the plugin zip file. 27 2. In your WordPress dashboard, go to **Plugins > Add New**. 28 3. Click on **Upload Plugin** and choose the zip file you downloaded. 29 4. Click **Install Now** and activate the plugin. 30 5. Use the REST API endpoint `/wp-json/api-post-creator/v1/create-post` to start creating posts programmatically. 31 32 == Authentication == 33 34 To authenticate API requests, you must use an application password, which can be generated from your user profile in the WordPress admin dashboard. 35 36 1. **Generate Application Password**: Go to **Users > Profile** in the WordPress dashboard and create an application password. 37 2. **Authorization Header**: Pass the application password in a Base64-encoded `Authorization` header in the format `Basic {base64_encode(username:application_password)}`. 38 39 == REST API Endpoints == 40 41 1. **Create Post Endpoint** 42 - **URL**: `/wp-json/api-post-creator/v1/create-post` 43 - **Method**: POST 44 - **Parameters**: 45 - `title` (required): Title of the post. 46 - `content` (required): Content of the post. 47 - `status` (optional): Post status (default: draft). 48 - `primary_category` (optional): Primary category name. 49 - `seo_title` (optional): SEO title. 50 - `seo_desc` (optional): SEO description. 51 - `image_url` (optional): URL for the featured image. 52 53 2. **Check Installation Endpoint** 54 - **URL**: `/wp-json/api-post-creator/v1/check-status` 55 - **Method**: GET 56 - **Purpose**: Verifies plugin status and active SEO plugin. 57 58 3. **List Categories Endpoint** 59 - **URL**: `/wp-json/api-post-creator/v1/get-categories` 60 - **Method**: GET 61 - **Purpose**: Returns all registered post categories. 62 63 4. **Similar Titles Search Endpoint** 64 - **URL**: `/wp-json/api-post-creator/v1/search-similar-posts?title=Your+Title+Here` 65 - **Method**: GET 66 - **Purpose**: Returns the top 10 most similar published posts by title. 110 1. Upload the plugin files to `/wp-content/plugins/wpraiz-content-api-tool/` or install through the WordPress plugins screen. 111 2. Activate the plugin through the 'Plugins' screen in WordPress. 112 3. Go to **Tools > WPRaiz Content API** to configure settings. 113 4. (Optional) Add your AI API keys for content generation features. 114 5. (Optional) Configure webhook URL for notifications. 67 115 68 116 == Frequently Asked Questions == 69 117 70 = What is the REST API endpoint to create posts? = 71 Use `/wp-json/api-post-creator/v1/create-post` with a POST request and appropriate parameters. 118 = Do I need an AI API key to use the plugin? = 72 119 73 = How do I authenticate requests? = 74 Use application passwords and pass them using the Basic Auth header. 120 No. The free version works without any API keys. AI features (content generation, rewriting, auto-SEO) require a Claude or OpenAI API key and a Pro license. 75 121 76 = What SEO plugins are supported? = 77 SEOPress, Yoast SEO, and Rank Math. The plugin auto-updates the correct meta fields. 122 = Which SEO plugins are supported? = 78 123 79 = Can I search for similar post titles before publishing? = 80 Yes! Use the `/search-similar-posts` endpoint to retrieve related posts for internal linking or avoiding duplicates. 124 SEOPress, Yoast SEO, and Rank Math. The plugin auto-detects which one is active and writes meta data accordingly. It also writes to all three for maximum compatibility. 125 126 = Is the REST API secure? = 127 128 Yes. All write endpoints require JWT or Basic Auth. Rate limiting is configurable. Read-only endpoints (search, categories, status) are public by design. 129 130 = Can I use custom post types? = 131 132 Yes. Both `create-post` and `search-similar` accept a `post_type` parameter. Any registered public post type is supported. 133 134 = What is MCP? = 135 136 Model Context Protocol is an open standard for connecting AI models to external tools. With our MCP server, Claude Desktop, Cursor, and other AI agents can create posts, search content, and generate articles directly on your WordPress site. 137 138 = Are v1 endpoints still supported? = 139 140 Yes. Legacy endpoints under `api-post-creator/v1/` continue to work for backward compatibility. 81 141 82 142 == Screenshots == 83 143 84 1. **Admin Page Interface** – Displays all endpoints with copy buttons. 85 2. **API Example Payload** – Demonstrates JSON structure to create a post. 86 3. **Similarity Response** – JSON listing similar titles by relevance. 144 1. Admin page — Endpoints tab with copy-to-clipboard URLs 145 2. Admin page — Settings with AI provider configuration 146 3. Admin page — MCP Server setup with Claude Desktop config 147 4. Admin page — License activation 87 148 88 149 == Changelog == 89 150 151 = 2.0.0 = 152 * **Major rewrite** — Complete architecture overhaul with PSR-4 namespacing 153 * **New:** AI content generation with Claude and OpenAI (BYOK) 154 * **New:** AI post rewriting (improve SEO, fix grammar, change tone, expand, summarize) 155 * **New:** Auto-SEO — generate title and meta description via AI 156 * **New:** MCP Server with HTTP and STDIO transports 157 * **New:** MCP Tools, Resources, and Prompts for AI agents 158 * **New:** WP-CLI command `wp wpraiz-mcp serve` for Claude Desktop 159 * **New:** Bulk post creation (up to 50 per batch) 160 * **New:** Post update endpoint 161 * **New:** JWT authentication with configurable rate limiting 162 * **New:** Webhook system with HMAC signing and retry logic 163 * **New:** Admin UI with tabs (Endpoints, Settings, MCP, License) 164 * **Improved:** Similar post search using Levenshtein distance scoring 165 * **Improved:** SEO handler supports SEOPress, Yoast SEO, and Rank Math simultaneously 166 * **Improved:** Media handler with content-type validation 167 * **Improved:** Category auto-creation 168 * Backward compatible with v1 endpoints 169 90 170 = 1.5 = 91 * Ad icionada interface mais organizada para endpoints na página do admin.92 * N ovo endpoint `search-similar-posts` para sugerir conteúdos semelhantes com score.93 * Otimizações de compatibilidade comWordPress 6.7.2.94 * SEO fields agora são gravados diretamente em todos os plugins suportados.171 * Added organized endpoints interface on admin page. 172 * New `search-similar-posts` endpoint for content similarity scoring. 173 * Compatibility with WordPress 6.7.2. 174 * SEO fields now written directly to all supported plugins. 95 175 96 176 = 1.4 = 97 177 * Added SEO metadata integration for SEOPress, Yoast SEO, and Rank Math. 98 * Introduced `/check-status` endpoint to verify installation and authentication.178 * Introduced `/check-status` endpoint. 99 179 * Enhanced error handling and response messages. 100 180 101 181 = 1.3 = 102 182 * Improved compatibility with WordPress 6.6. 103 * Proper enqueuing of admin JavaScript and CSS files.104 183 * Added support for automatic category creation. 105 184 * Enhanced image upload functionality. … … 114 193 == Upgrade Notice == 115 194 116 = 1.5 = 117 Recomendado para todos os usuários. Adiciona recursos importantes de verificação de similaridade e melhoria de usabilidade no painel administrativo. 118 119 == License == 120 Este plugin é licenciado sob a GPLv3. Veja [GNU's official site](https://www.gnu.org/licenses/gpl-3.0.html) para detalhes. 195 = 2.0.0 = 196 Major update with AI features, MCP server, and complete rewrite. All v1 endpoints remain compatible. Review the new Settings page after upgrading. 121 197 122 198 == Support == 123 Para dúvidas ou suporte, visite [WPRaiz Support](https://ai.wpraiz.com.br).199 Visit [wpraiz.com.br](https://wpraiz.com.br) or open an issue on [GitHub](https://github.com/wpraiz/wpraiz-content-api-tool). -
wpraiz-content-api-tool/tags/2.0.0/wpraiz-content.php
r3265375 r3482396 1 1 <?php 2 3 /* 2 /** 4 3 * Plugin Name: WPRaiz Content API Tool 5 4 * Plugin URI: https://wpraiz.com.br 6 * D onate link: https://wpraiz.com.br7 * Description: Plugin para criar postagens via API REST com campos personalizados de SEO, upload de imagens e categoria principal.8 * Version: 1.59 * Author : José caro5 * Description: Create WordPress posts via REST API with SEO integration, AI content generation, and MCP server for AI agents. 6 * Version: 2.0.0 7 * Author: José Ícaro – WPRaiz 8 * Author URI: https://wpraiz.com.br 10 9 * License: GPLv3 10 * License URI: https://www.gnu.org/licenses/gpl-3.0.html 11 * Text Domain: wpraiz-content-api 12 * Domain Path: /languages 13 * Requires at least: 5.0 14 * Tested up to: 7.0 15 * Requires PHP: 7.4 11 16 */ 12 17 13 class API_Post_Creator_With_Image { 18 if ( ! defined( 'ABSPATH' ) ) { 19 exit; 20 } 14 21 15 public function __construct() { 16 // Registra o endpoint na API REST 17 add_action('rest_api_init', [$this, 'register_routes']); 18 // Garante que os arquivos necessários para manipulação de mídia estejam disponíveis 19 require_once(ABSPATH . 'wp-admin/includes/file.php'); 20 require_once(ABSPATH . 'wp-admin/includes/media.php'); 21 require_once(ABSPATH . 'wp-admin/includes/image.php'); 22 // Plugin constants 23 define( 'WPRAIZ_VERSION', '2.0.0' ); 24 define( 'WPRAIZ_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 25 define( 'WPRAIZ_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); 26 define( 'WPRAIZ_PLUGIN_FILE', __FILE__ ); 27 define( 'WPRAIZ_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); 28 29 /** 30 * PSR-4-style autoloader for WPRaiz classes. 31 */ 32 spl_autoload_register( function ( $class ) { 33 $prefix = 'WPRaiz\\ContentAPI\\'; 34 $len = strlen( $prefix ); 35 36 if ( strncmp( $prefix, $class, $len ) !== 0 ) { 37 return; 22 38 } 23 39 24 public function register_routes() { 25 register_rest_route('api-post-creator/v1', '/create-post', [ 26 'methods' => 'POST', 27 'callback' => [$this, 'handle_create_post'], 28 'permission_callback' => [$this, 'authenticate_user'], 29 ]); 40 $relative = substr( $class, $len ); 41 $parts = explode( '\\', $relative ); 42 $filename = 'class-' . strtolower( str_replace( '_', '-', array_pop( $parts ) ) ) . '.php'; 30 43 31 // Novo endpoint GET para verificação 32 register_rest_route('api-post-creator/v1', '/check-status', [ 33 'methods' => 'GET', 34 'callback' => [$this, 'check_status'], 35 //'permission_callback' => [$this, 'authenticate_user'], 36 ]); 44 $subdir = ''; 45 if ( ! empty( $parts ) ) { 46 $subdir = strtolower( implode( '/', $parts ) ) . '/'; 37 47 } 38 48 39 // Função para validar autenticação e plugins de SEO ativos 40 public function check_status() { 41 $seo_plugin = $this->detect_seo_plugin(); 42 43 return new WP_REST_Response([ 44 'message' => 'Plugin ativo e autenticado com sucesso.', 45 'seo_plugin' => $seo_plugin ? $seo_plugin : 'Nenhum plugin de SEO detectado', 46 ], 200); 49 $file = WPRAIZ_PLUGIN_DIR . 'includes/' . $subdir . $filename; 50 51 if ( file_exists( $file ) ) { 52 require_once $file; 47 53 } 54 }); 48 55 49 // Função para detectar o plugin de SEO ativo 50 private function detect_seo_plugin() { 51 if (defined('SEOPRESS_VERSION')) { 52 return 'seopress'; 53 } elseif (defined('WPSEO_VERSION')) { 54 return 'yoastseo'; 55 } elseif (defined('RANK_MATH_VERSION')) { 56 return 'rankmath'; 57 } 58 return null; 59 } 56 /** 57 * Initialize the plugin. 58 */ 59 function wpraiz_init() { 60 // Load textdomain 61 load_plugin_textdomain( 'wpraiz-content-api', false, dirname( WPRAIZ_PLUGIN_BASENAME ) . '/languages' ); 60 62 61 public function handle_create_post($request) { 62 $params = $request->get_json_params(); 63 // Core 64 new WPRaiz\ContentAPI\Auth(); 65 new WPRaiz\ContentAPI\Content_Manager(); 66 new WPRaiz\ContentAPI\Search_Engine(); 67 new WPRaiz\ContentAPI\SEO_Handler(); 68 new WPRaiz\ContentAPI\Media_Handler(); 69 new WPRaiz\ContentAPI\Webhooks(); 63 70 64 if (empty($params['title']) || empty($params['content'])) { 65 return new WP_Error('missing_data', 'Título e conteúdo são obrigatórios.', ['status' => 400]); 66 } 67 68 remove_filter('content_save_pre', 'wp_filter_post_kses'); 71 // AI 72 new WPRaiz\ContentAPI\AI\AI_Manager(); 69 73 70 $post_id = wp_insert_post([ 71 'post_title' => sanitize_text_field($params['title']), 72 'post_content' => $params['content'], 73 'post_status' => sanitize_text_field($params['status'] ?? 'draft'), 74 'post_author' => get_current_user_id(), 75 ]); 74 // MCP 75 new WPRaiz\ContentAPI\MCP\MCP_Server(); 76 76 77 add_filter('content_save_pre', 'wp_filter_post_kses'); 78 79 if (is_wp_error($post_id)) { 80 return new WP_Error('post_creation_failed', 'Falha ao criar o post.', ['status' => 500]); 81 } 82 83 // Verifica ou cria a categoria principal 84 if (!empty($params['primary_category'])) { 85 $primary_category_id = $this->get_or_create_category(trim($params['primary_category'])); 86 if (!is_wp_error($primary_category_id)) { 87 wp_set_post_terms($post_id, [$primary_category_id], 'category'); 88 } 89 } 90 91 // Faz o upload da imagem se a URL for fornecida 92 if (!empty($params['image_url'])) { 93 $image_id = $this->upload_image_from_url($params['image_url'], $post_id); 94 if (!is_wp_error($image_id)) { 95 set_post_thumbnail($post_id, $image_id); 96 } 97 } 98 99 // Adiciona os campos de SEO com base no plugin ativo 100 // Adiciona os campos de SEO diretamente 101 if (!empty($params['seo_title'])) { 102 update_post_meta($post_id, '_seopress_titles_title', sanitize_text_field($params['seo_title'])); 103 update_post_meta($post_id, '_yoast_wpseo_title', sanitize_text_field($params['seo_title'])); 104 update_post_meta($post_id, 'rank_math_title', sanitize_text_field($params['seo_title'])); 105 } 106 107 if (!empty($params['seo_desc'])) { 108 update_post_meta($post_id, '_seopress_titles_desc', sanitize_text_field($params['seo_desc'])); 109 update_post_meta($post_id, '_yoast_wpseo_metadesc', sanitize_text_field($params['seo_desc'])); 110 update_post_meta($post_id, 'rank_math_description', sanitize_text_field($params['seo_desc'])); 111 } 112 113 return new WP_REST_Response([ 114 'message' => 'Post criado com sucesso!', 115 'post_id' => $post_id, 116 'post_url' => get_permalink($post_id), 117 ], 201); 118 } 119 120 /** 121 * Função para verificar ou criar uma categoria. 122 */ 123 public function get_or_create_category($category_name) { 124 $term = get_term_by('name', $category_name, 'category'); 125 if ($term) { 126 return $term->term_id; 127 } else { 128 $new_term = wp_insert_term($category_name, 'category'); 129 if (is_wp_error($new_term)) { 130 return $new_term; 131 } 132 return $new_term['term_id']; 133 } 134 } 135 136 public function upload_image_from_url($image_url, $post_id) { 137 // Usa wp_remote_get() para obter o conteúdo da imagem da URL 138 $response = wp_remote_get($image_url); 139 140 if (is_wp_error($response)) { 141 return new WP_Error('image_download_failed', 'Falha ao baixar a imagem.'); 142 } 143 144 $image_data = wp_remote_retrieve_body($response); 145 $http_code = wp_remote_retrieve_response_code($response); 146 147 // Verifica se a resposta foi bem-sucedida 148 if ($http_code !== 200 || !$image_data) { 149 return new WP_Error('image_download_failed', 'Falha ao baixar a imagem.'); 150 } 151 152 // Cria um arquivo temporário 153 $tmp_file = wp_tempnam($image_url); 154 global $wp_filesystem; 155 156 if (!function_exists('WP_Filesystem')) { 157 require_once(ABSPATH . 'wp-admin/includes/file.php'); 158 } 159 160 WP_Filesystem(); 161 $wp_filesystem->put_contents($tmp_file, $image_data); 162 163 // Define as informações do arquivo para o upload 164 $file_array = array(); 165 $file_array['name'] = basename(wp_parse_url($image_url, PHP_URL_PATH)); // Usando wp_parse_url() 166 $file_array['tmp_name'] = $tmp_file; 167 168 // Faz o upload da imagem para o WordPress 169 $image_id = media_handle_sideload($file_array, $post_id); 170 171 if (is_wp_error($image_id)) { 172 wp_delete_file($tmp_file); // Remove o arquivo temporário 173 return $image_id; 174 } 175 176 return $image_id; 177 } 178 179 public function authenticate_user($request) { 180 return current_user_can('edit_posts'); 77 // Admin 78 if ( is_admin() ) { 79 new WPRaiz\ContentAPI\Admin\Admin_Page(); 80 new WPRaiz\ContentAPI\Admin\License(); 181 81 } 182 82 } 83 add_action( 'plugins_loaded', 'wpraiz_init' ); 183 84 184 class API_Post_Creator_With_Menu { 85 /** 86 * Activation hook — create options and flush rewrite rules. 87 */ 88 function wpraiz_activate() { 89 add_option( 'wpraiz_settings', [ 90 'ai_provider' => '', 91 'openai_api_key' => '', 92 'claude_api_key' => '', 93 'auto_seo' => true, 94 'webhook_url' => '', 95 'webhook_events' => [ 'post_created' ], 96 'rate_limit' => 60, 97 ]); 98 flush_rewrite_rules(); 99 } 100 register_activation_hook( __FILE__, 'wpraiz_activate' ); 185 101 186 public function __construct() { 187 // Adiciona o sub-menu na página de Ferramentas 188 add_action('admin_menu', [$this, 'add_plugin_menu']); 189 add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']); 190 } 102 /** 103 * Deactivation hook. 104 */ 105 function wpraiz_deactivate() { 106 flush_rewrite_rules(); 107 } 108 register_deactivation_hook( __FILE__, 'wpraiz_deactivate' ); 191 109 192 public function add_plugin_menu() { 193 add_submenu_page( 194 'tools.php', // O menu principal "Ferramentas" 195 'WPRaiz Content API', // Título da página 196 'WPRaiz Content API', // Texto do menu 197 'manage_options', // Capability (permissão) 198 'wpraiz-content-api', // Slug da página 199 [$this, 'render_admin_page'] // Função que renderiza a página 200 ); 201 } 202 203 public function render_admin_page() { 204 $site_url = get_site_url(); 205 $endpoint_url = $site_url . '/wp-json/api-post-creator/v1/create-post'; 206 $check_url = $site_url . '/wp-json/api-post-creator/v1/check-status'; 207 $categories_url = $site_url . '/wp-json/api-post-creator/v1/get-categories'; 208 $search_url = $site_url . '/wp-json/api-post-creator/v1/search-similar-posts?title=Exemplo'; 209 ?> 210 <div class="wrap"> 211 <h1>WPRaiz Content API</h1> 212 <img src="<?php echo esc_url(plugins_url('assets/images/logo_wpraiz.png', __FILE__)); ?>" width="300" alt="WPRaiz Logo" /> 213 214 <table class="widefat fixed" style="max-width: 900px; margin-top: 20px;"> 215 <thead> 216 <tr> 217 <th>Descrição</th> 218 <th>Endpoint</th> 219 <th>Ação</th> 220 </tr> 221 </thead> 222 <tbody> 223 <tr> 224 <td><strong>Criação de Post</strong><br><small>Envia um post com imagem e SEO.</small></td> 225 <td><input type="text" id="api-endpoint" value="<?php echo esc_url($endpoint_url); ?>" readonly style="width: 100%;" /></td> 226 <td><button onclick="copyToClipboard('api-endpoint')" class="button">Copiar</button></td> 227 </tr> 228 <tr> 229 <td><strong>Status do Plugin</strong><br><small>Verifica se o plugin e o SEO estão ativos.</small></td> 230 <td><input type="text" id="check-endpoint" value="<?php echo esc_url($check_url); ?>" readonly style="width: 100%;" /></td> 231 <td><button onclick="copyToClipboard('check-endpoint')" class="button">Copiar</button></td> 232 </tr> 233 <tr> 234 <td><strong>Listar Categorias</strong><br><small>Retorna categorias existentes no site.</small></td> 235 <td><input type="text" id="categories-endpoint" value="<?php echo esc_url($categories_url); ?>" readonly style="width: 100%;" /></td> 236 <td><button onclick="copyToClipboard('categories-endpoint')" class="button">Copiar</button></td> 237 </tr> 238 <tr> 239 <td><strong>Buscar Títulos Semelhantes</strong><br><small>Retorna posts parecidos com base no título.</small></td> 240 <td><input type="text" id="search-endpoint" value="<?php echo esc_url($search_url); ?>" readonly style="width: 100%;" /></td> 241 <td><button onclick="copyToClipboard('search-endpoint')" class="button">Copiar</button></td> 242 </tr> 243 </tbody> 244 </table> 245 246 <h2 style="margin-top: 30px;">Exemplo de Requisição</h2> 247 <pre>{ 248 "title": "Título do Post", 249 "content": "Este é o conteúdo do post", 250 "status": "publish", 251 "primary_category": "Geral", 252 "seo_title": "Título SEO", 253 "seo_desc": "Descrição SEO", 254 "image_url": "https://seu-site.com/imagem.jpg" 255 }</pre> 256 <p><strong>Importante:</strong> Use a senha de aplicativo do WordPress para autenticação via API.</p> 257 258 <h2>Links Rápidos</h2> 259 <a href="https://wpraiz.com.br" target="_blank" class="button button-primary">Visitar WPRaiz</a> 260 <a href="https://youtube.com/wpraiz" target="_blank" class="button button-primary">Canal no Youtube</a> 261 </div> 262 263 <script type="text/javascript"> 264 function copyToClipboard(id) { 265 const el = document.getElementById(id); 266 el.select(); 267 el.setSelectionRange(0, 99999); 268 document.execCommand("copy"); 269 alert("Endpoint copiado: " + el.value); 270 } 271 </script> 272 <?php 273 } 274 275 public function enqueue_admin_scripts($hook_suffix) { 276 // Certifique-se de que você só adiciona os scripts na página correta 277 if ($hook_suffix === 'tools_page_wpraiz-content-api') { 278 wp_enqueue_script( 279 'wpraiz-admin-script', 280 plugins_url('assets/js/admin-scripts.js', __FILE__), 281 array('jquery'), 282 '1.3', // Definindo a versão do script 283 true 284 ); 285 } 286 } 110 /** 111 * Helper: get plugin settings. 112 */ 113 function wpraiz_get_settings() { 114 return wp_parse_args( get_option( 'wpraiz_settings', [] ), [ 115 'ai_provider' => '', 116 'openai_api_key' => '', 117 'claude_api_key' => '', 118 'auto_seo' => true, 119 'webhook_url' => '', 120 'webhook_events' => [ 'post_created' ], 121 'rate_limit' => 60, 122 ]); 287 123 } 288 124 289 290 function api_post_creator_with_image_and_menu_init() { 291 new API_Post_Creator_With_Image(); 292 new API_Post_Creator_With_Menu(); 293 } 294 add_action('plugins_loaded', 'api_post_creator_with_image_and_menu_init'); 295 class API_Post_Creator_With_Categories { 296 297 public function __construct() { 298 add_action('rest_api_init', [$this, 'register_routes']); 299 } 300 301 public function register_routes() { 302 register_rest_route('api-post-creator/v1', '/get-categories', [ 303 'methods' => 'GET', 304 'callback' => [$this, 'get_categories'], 305 //'permission_callback' => [$this, 'authenticate_user'], 306 ]); 307 register_rest_route('api-post-creator/v1', '/search-similar-posts', [ 308 'methods' => 'GET', 309 'callback' => [$this, 'search_similar_posts'], 310 'permission_callback' => '__return_true', 311 ]); 312 } 313 314 public function get_categories() { 315 $categories = get_categories([ 316 'taxonomy' => 'category', 317 'hide_empty' => false, 318 ]); 319 320 $category_list = []; 321 foreach ($categories as $category) { 322 $category_list[] = [ 323 'id' => $category->term_id, 324 'name' => $category->name, 325 'slug' => $category->slug, 326 'description' => $category->description, 327 'count' => $category->count, 328 ]; 329 } 330 331 return new WP_REST_Response($category_list, 200); 332 } 333 334 public function search_similar_posts($request) { 335 $query_title = sanitize_text_field($request->get_param('title')); 336 337 if (empty($query_title)) { 338 return new WP_REST_Response(['error' => 'Parâmetro "title" é obrigatório.'], 400); 339 } 340 341 $posts = get_posts([ 342 'numberposts' => 100, 343 'post_status' => 'publish', 344 'post_type' => 'post', 345 ]); 346 347 $resultados = []; 348 349 foreach ($posts as $post) { 350 similar_text(strtolower($query_title), strtolower($post->post_title), $percent); 351 $categorias = get_the_category($post->ID); 352 $categoria_principal = $categorias[0]->name ?? ''; 353 $categoria_secundaria = $categorias[1]->name ?? ''; 354 355 $resultados[] = [ 356 'title' => $post->post_title, 357 'score' => round($percent, 2), 358 'primary_category' => $categoria_principal, 359 'secondary_category' => $categoria_secundaria, 360 'url' => get_permalink($post->ID), 361 ]; 362 } 363 364 usort($resultados, function($a, $b) { 365 return $b['score'] <=> $a['score']; 366 }); 367 368 return new WP_REST_Response(array_slice($resultados, 0, 10), 200); 369 } 370 371 372 public function authenticate_user($request) { 373 return current_user_can('edit_posts'); 374 } 375 } 376 377 new API_Post_Creator_With_Categories(); 125 /** 126 * Helper: check if Pro license is active. 127 */ 128 function wpraiz_is_pro(): bool { 129 return \WPRaiz\ContentAPI\Admin\License::is_pro(); 130 } -
wpraiz-content-api-tool/trunk/readme.txt
r3265377 r3482396 1 1 === WPRaiz Content API Tool === 2 Contributors: zeicaro3 Donate link: https://ai.wpraiz.com.br 4 Tags: REST API, Content, Post Creation, SEO, Image Upload, Automation 5 Requires at least: 5.0 6 Tested up to: 6.7.2 7 Stable tag: 1.58 License: GPLv 39 License URI: https://www.gnu.org/licenses/gpl- 3.0.html2 Contributors: wpraiz, joseicaro 3 Tags: rest-api, content-automation, ai-content, mcp, claude 4 Requires at least: 5.8 5 Tested up to: 6.7 6 Requires PHP: 7.4 7 Stable tag: 2.0.0 8 License: GPLv2 or later 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Create WordPress posts via REST API with custom SEO fields, image uploads, primary category assignment, and integration with major SEO plugins (SEOPress, Yoast SEO, Rank Math).11 REST API + MCP Server for WordPress. Create, update, and manage posts programmatically. AI content generation with your own API keys (BYOK). 12 12 13 13 == Description == 14 14 15 The WPRaiz Content API Tool is a powerful plugin that enables the creation of WordPress posts programmatically through a REST API. Ideal for developers and websites that need seamless content integration from external systems, this plugin supports: 15 **WPRaiz Content API Tool** turns your WordPress site into a powerful content API. Create posts, manage categories, generate AI content, and connect AI agents — all via REST API or Model Context Protocol (MCP). 16 16 17 - **Integration with Major SEO Plugins**: Set custom SEO fields for titles and descriptions, compatible with SEOPress, Yoast SEO, and Rank Math. 18 - **Flexible Image Uploads**: Accept images via URL, with automatic attachment as the featured image. 19 - **Automatic Category Management**: Assign an existing category or create a new one based on supplied category names. 20 - **Installation Check Endpoint**: Verify plugin installation, authentication, and detect the installed SEO plugin. 21 - **Post Similarity Search**: Find and return the top 10 most similar published posts by title for better content linking and duplication checks. 22 - **Admin Interface**: Dashboard section with copyable API endpoints for easy testing. 17 = What You Can Do = 18 19 * **Create & Update Posts** — Full control over title, content, status, categories, tags, excerpt, featured images, and custom meta fields via REST API. 20 * **Bulk Creation** — Create up to 50 posts in a single request (Pro). 21 * **AI Content Generation** — Generate full articles from a topic using Claude or OpenAI with your own API keys (Pro). 22 * **AI Rewrite** — Improve SEO, fix grammar, change tone, expand, or summarize existing posts (Pro). 23 * **Auto-SEO** — Automatically generate SEO titles and meta descriptions when not provided. Supports SEOPress, Yoast SEO, and Rank Math. 24 * **MCP Server** — Connect AI agents (Claude Desktop, Cursor, Windsurf) directly to your site via Model Context Protocol. 25 * **Similar Post Search** — Find duplicate or related content using intelligent Levenshtein-based scoring. 26 * **Webhooks** — Get notified when posts are created or bulk operations complete, with HMAC signature verification. 27 * **JWT Authentication** — Secure token-based auth with configurable rate limiting. 28 29 = Free vs Pro = 30 31 **Free** (this plugin): 32 33 * Create and update single posts via REST API 34 * Search similar posts 35 * List and manage categories 36 * JWT and Basic Auth (Application Passwords) 37 * SEO plugin auto-detection and meta writing 38 * Featured image upload from URL 39 * Rate limiting 40 * Legacy v1 endpoint compatibility 41 42 **Pro** ($49/year at [wpraiz.com.br/pro](https://wpraiz.com.br/pro)): 43 44 * Everything in Free, plus: 45 * Bulk post creation (up to 50 per batch) 46 * AI content generation (BYOK — Claude or OpenAI) 47 * AI post rewriting (5 modes) 48 * Auto-SEO via AI 49 * MCP Server (HTTP + STDIO transports) 50 * Webhook notifications with HMAC signing 51 * Priority support 52 53 = MCP Server = 54 55 The Model Context Protocol server lets AI agents interact with your WordPress site natively. Available via HTTP (REST API) or STDIO (WP-CLI). 56 57 **Tools:** create_post, update_post, search_similar, get_categories, generate_content, rewrite_post, bulk_create 58 59 **Resources:** site-info, recent-posts, categories, content-stats, seo-config 60 61 **Prompts:** publish_seo_article, content_series, seo_audit, refresh_old_content, internal_linking 62 63 Add to your `claude_desktop_config.json`: 64 65 ` 66 { 67 "mcpServers": { 68 "wpraiz": { 69 "command": "wp", 70 "args": ["wpraiz-mcp", "serve", "--path=/path/to/wordpress", "--user=1"] 71 } 72 } 73 } 74 ` 75 76 = REST API Endpoints = 77 78 Base URL: `https://yoursite.com/wp-json/wpraiz/v2/` 79 80 | Endpoint | Method | Auth | Tier | 81 |---|---|---|---| 82 | create-post | POST | JWT/Basic | Free | 83 | update-post | POST | JWT/Basic | Free | 84 | create-posts | POST | JWT/Basic | Pro | 85 | generate-content | POST | JWT/Basic | Pro | 86 | rewrite-post | POST | JWT/Basic | Pro | 87 | search-similar | GET | Public | Free | 88 | categories | GET | Public | Free | 89 | check-status | GET | Public | Free | 90 | auth/token | POST | Credentials | Free | 91 92 = Authentication = 93 94 **JWT Token:** 95 1. POST to `auth/token` with `username` and `password` 96 2. Use the returned token as `Authorization: Bearer <token>` 97 98 **Basic Auth:** 99 Use WordPress Application Passwords with standard HTTP Basic authentication. 100 101 = Requirements = 102 103 * WordPress 5.8+ 104 * PHP 7.4+ 105 * For AI features: Claude API key or OpenAI API key 106 * For MCP STDIO: WP-CLI installed 23 107 24 108 == Installation == 25 109 26 1. Download the plugin zip file. 27 2. In your WordPress dashboard, go to **Plugins > Add New**. 28 3. Click on **Upload Plugin** and choose the zip file you downloaded. 29 4. Click **Install Now** and activate the plugin. 30 5. Use the REST API endpoint `/wp-json/api-post-creator/v1/create-post` to start creating posts programmatically. 31 32 == Authentication == 33 34 To authenticate API requests, you must use an application password, which can be generated from your user profile in the WordPress admin dashboard. 35 36 1. **Generate Application Password**: Go to **Users > Profile** in the WordPress dashboard and create an application password. 37 2. **Authorization Header**: Pass the application password in a Base64-encoded `Authorization` header in the format `Basic {base64_encode(username:application_password)}`. 38 39 == REST API Endpoints == 40 41 1. **Create Post Endpoint** 42 - **URL**: `/wp-json/api-post-creator/v1/create-post` 43 - **Method**: POST 44 - **Parameters**: 45 - `title` (required): Title of the post. 46 - `content` (required): Content of the post. 47 - `status` (optional): Post status (default: draft). 48 - `primary_category` (optional): Primary category name. 49 - `seo_title` (optional): SEO title. 50 - `seo_desc` (optional): SEO description. 51 - `image_url` (optional): URL for the featured image. 52 53 2. **Check Installation Endpoint** 54 - **URL**: `/wp-json/api-post-creator/v1/check-status` 55 - **Method**: GET 56 - **Purpose**: Verifies plugin status and active SEO plugin. 57 58 3. **List Categories Endpoint** 59 - **URL**: `/wp-json/api-post-creator/v1/get-categories` 60 - **Method**: GET 61 - **Purpose**: Returns all registered post categories. 62 63 4. **Similar Titles Search Endpoint** 64 - **URL**: `/wp-json/api-post-creator/v1/search-similar-posts?title=Your+Title+Here` 65 - **Method**: GET 66 - **Purpose**: Returns the top 10 most similar published posts by title. 110 1. Upload the plugin files to `/wp-content/plugins/wpraiz-content-api-tool/` or install through the WordPress plugins screen. 111 2. Activate the plugin through the 'Plugins' screen in WordPress. 112 3. Go to **Tools > WPRaiz Content API** to configure settings. 113 4. (Optional) Add your AI API keys for content generation features. 114 5. (Optional) Configure webhook URL for notifications. 67 115 68 116 == Frequently Asked Questions == 69 117 70 = What is the REST API endpoint to create posts? = 71 Use `/wp-json/api-post-creator/v1/create-post` with a POST request and appropriate parameters. 118 = Do I need an AI API key to use the plugin? = 72 119 73 = How do I authenticate requests? = 74 Use application passwords and pass them using the Basic Auth header. 120 No. The free version works without any API keys. AI features (content generation, rewriting, auto-SEO) require a Claude or OpenAI API key and a Pro license. 75 121 76 = What SEO plugins are supported? = 77 SEOPress, Yoast SEO, and Rank Math. The plugin auto-updates the correct meta fields. 122 = Which SEO plugins are supported? = 78 123 79 = Can I search for similar post titles before publishing? = 80 Yes! Use the `/search-similar-posts` endpoint to retrieve related posts for internal linking or avoiding duplicates. 124 SEOPress, Yoast SEO, and Rank Math. The plugin auto-detects which one is active and writes meta data accordingly. It also writes to all three for maximum compatibility. 125 126 = Is the REST API secure? = 127 128 Yes. All write endpoints require JWT or Basic Auth. Rate limiting is configurable. Read-only endpoints (search, categories, status) are public by design. 129 130 = Can I use custom post types? = 131 132 Yes. Both `create-post` and `search-similar` accept a `post_type` parameter. Any registered public post type is supported. 133 134 = What is MCP? = 135 136 Model Context Protocol is an open standard for connecting AI models to external tools. With our MCP server, Claude Desktop, Cursor, and other AI agents can create posts, search content, and generate articles directly on your WordPress site. 137 138 = Are v1 endpoints still supported? = 139 140 Yes. Legacy endpoints under `api-post-creator/v1/` continue to work for backward compatibility. 81 141 82 142 == Screenshots == 83 143 84 1. **Admin Page Interface** – Displays all endpoints with copy buttons. 85 2. **API Example Payload** – Demonstrates JSON structure to create a post. 86 3. **Similarity Response** – JSON listing similar titles by relevance. 144 1. Admin page — Endpoints tab with copy-to-clipboard URLs 145 2. Admin page — Settings with AI provider configuration 146 3. Admin page — MCP Server setup with Claude Desktop config 147 4. Admin page — License activation 87 148 88 149 == Changelog == 89 150 151 = 2.0.0 = 152 * **Major rewrite** — Complete architecture overhaul with PSR-4 namespacing 153 * **New:** AI content generation with Claude and OpenAI (BYOK) 154 * **New:** AI post rewriting (improve SEO, fix grammar, change tone, expand, summarize) 155 * **New:** Auto-SEO — generate title and meta description via AI 156 * **New:** MCP Server with HTTP and STDIO transports 157 * **New:** MCP Tools, Resources, and Prompts for AI agents 158 * **New:** WP-CLI command `wp wpraiz-mcp serve` for Claude Desktop 159 * **New:** Bulk post creation (up to 50 per batch) 160 * **New:** Post update endpoint 161 * **New:** JWT authentication with configurable rate limiting 162 * **New:** Webhook system with HMAC signing and retry logic 163 * **New:** Admin UI with tabs (Endpoints, Settings, MCP, License) 164 * **Improved:** Similar post search using Levenshtein distance scoring 165 * **Improved:** SEO handler supports SEOPress, Yoast SEO, and Rank Math simultaneously 166 * **Improved:** Media handler with content-type validation 167 * **Improved:** Category auto-creation 168 * Backward compatible with v1 endpoints 169 90 170 = 1.5 = 91 * Ad icionada interface mais organizada para endpoints na página do admin.92 * N ovo endpoint `search-similar-posts` para sugerir conteúdos semelhantes com score.93 * Otimizações de compatibilidade comWordPress 6.7.2.94 * SEO fields agora são gravados diretamente em todos os plugins suportados.171 * Added organized endpoints interface on admin page. 172 * New `search-similar-posts` endpoint for content similarity scoring. 173 * Compatibility with WordPress 6.7.2. 174 * SEO fields now written directly to all supported plugins. 95 175 96 176 = 1.4 = 97 177 * Added SEO metadata integration for SEOPress, Yoast SEO, and Rank Math. 98 * Introduced `/check-status` endpoint to verify installation and authentication.178 * Introduced `/check-status` endpoint. 99 179 * Enhanced error handling and response messages. 100 180 101 181 = 1.3 = 102 182 * Improved compatibility with WordPress 6.6. 103 * Proper enqueuing of admin JavaScript and CSS files.104 183 * Added support for automatic category creation. 105 184 * Enhanced image upload functionality. … … 114 193 == Upgrade Notice == 115 194 116 = 1.5 = 117 Recomendado para todos os usuários. Adiciona recursos importantes de verificação de similaridade e melhoria de usabilidade no painel administrativo. 118 119 == License == 120 Este plugin é licenciado sob a GPLv3. Veja [GNU's official site](https://www.gnu.org/licenses/gpl-3.0.html) para detalhes. 195 = 2.0.0 = 196 Major update with AI features, MCP server, and complete rewrite. All v1 endpoints remain compatible. Review the new Settings page after upgrading. 121 197 122 198 == Support == 123 Para dúvidas ou suporte, visite [WPRaiz Support](https://ai.wpraiz.com.br).199 Visit [wpraiz.com.br](https://wpraiz.com.br) or open an issue on [GitHub](https://github.com/wpraiz/wpraiz-content-api-tool). -
wpraiz-content-api-tool/trunk/wpraiz-content.php
r3265375 r3482396 1 1 <?php 2 3 /* 2 /** 4 3 * Plugin Name: WPRaiz Content API Tool 5 4 * Plugin URI: https://wpraiz.com.br 6 * D onate link: https://wpraiz.com.br7 * Description: Plugin para criar postagens via API REST com campos personalizados de SEO, upload de imagens e categoria principal.8 * Version: 1.59 * Author : José caro5 * Description: Create WordPress posts via REST API with SEO integration, AI content generation, and MCP server for AI agents. 6 * Version: 2.0.0 7 * Author: José Ícaro – WPRaiz 8 * Author URI: https://wpraiz.com.br 10 9 * License: GPLv3 10 * License URI: https://www.gnu.org/licenses/gpl-3.0.html 11 * Text Domain: wpraiz-content-api 12 * Domain Path: /languages 13 * Requires at least: 5.0 14 * Tested up to: 7.0 15 * Requires PHP: 7.4 11 16 */ 12 17 13 class API_Post_Creator_With_Image { 18 if ( ! defined( 'ABSPATH' ) ) { 19 exit; 20 } 14 21 15 public function __construct() { 16 // Registra o endpoint na API REST 17 add_action('rest_api_init', [$this, 'register_routes']); 18 // Garante que os arquivos necessários para manipulação de mídia estejam disponíveis 19 require_once(ABSPATH . 'wp-admin/includes/file.php'); 20 require_once(ABSPATH . 'wp-admin/includes/media.php'); 21 require_once(ABSPATH . 'wp-admin/includes/image.php'); 22 // Plugin constants 23 define( 'WPRAIZ_VERSION', '2.0.0' ); 24 define( 'WPRAIZ_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 25 define( 'WPRAIZ_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); 26 define( 'WPRAIZ_PLUGIN_FILE', __FILE__ ); 27 define( 'WPRAIZ_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); 28 29 /** 30 * PSR-4-style autoloader for WPRaiz classes. 31 */ 32 spl_autoload_register( function ( $class ) { 33 $prefix = 'WPRaiz\\ContentAPI\\'; 34 $len = strlen( $prefix ); 35 36 if ( strncmp( $prefix, $class, $len ) !== 0 ) { 37 return; 22 38 } 23 39 24 public function register_routes() { 25 register_rest_route('api-post-creator/v1', '/create-post', [ 26 'methods' => 'POST', 27 'callback' => [$this, 'handle_create_post'], 28 'permission_callback' => [$this, 'authenticate_user'], 29 ]); 40 $relative = substr( $class, $len ); 41 $parts = explode( '\\', $relative ); 42 $filename = 'class-' . strtolower( str_replace( '_', '-', array_pop( $parts ) ) ) . '.php'; 30 43 31 // Novo endpoint GET para verificação 32 register_rest_route('api-post-creator/v1', '/check-status', [ 33 'methods' => 'GET', 34 'callback' => [$this, 'check_status'], 35 //'permission_callback' => [$this, 'authenticate_user'], 36 ]); 44 $subdir = ''; 45 if ( ! empty( $parts ) ) { 46 $subdir = strtolower( implode( '/', $parts ) ) . '/'; 37 47 } 38 48 39 // Função para validar autenticação e plugins de SEO ativos 40 public function check_status() { 41 $seo_plugin = $this->detect_seo_plugin(); 42 43 return new WP_REST_Response([ 44 'message' => 'Plugin ativo e autenticado com sucesso.', 45 'seo_plugin' => $seo_plugin ? $seo_plugin : 'Nenhum plugin de SEO detectado', 46 ], 200); 49 $file = WPRAIZ_PLUGIN_DIR . 'includes/' . $subdir . $filename; 50 51 if ( file_exists( $file ) ) { 52 require_once $file; 47 53 } 54 }); 48 55 49 // Função para detectar o plugin de SEO ativo 50 private function detect_seo_plugin() { 51 if (defined('SEOPRESS_VERSION')) { 52 return 'seopress'; 53 } elseif (defined('WPSEO_VERSION')) { 54 return 'yoastseo'; 55 } elseif (defined('RANK_MATH_VERSION')) { 56 return 'rankmath'; 57 } 58 return null; 59 } 56 /** 57 * Initialize the plugin. 58 */ 59 function wpraiz_init() { 60 // Load textdomain 61 load_plugin_textdomain( 'wpraiz-content-api', false, dirname( WPRAIZ_PLUGIN_BASENAME ) . '/languages' ); 60 62 61 public function handle_create_post($request) { 62 $params = $request->get_json_params(); 63 // Core 64 new WPRaiz\ContentAPI\Auth(); 65 new WPRaiz\ContentAPI\Content_Manager(); 66 new WPRaiz\ContentAPI\Search_Engine(); 67 new WPRaiz\ContentAPI\SEO_Handler(); 68 new WPRaiz\ContentAPI\Media_Handler(); 69 new WPRaiz\ContentAPI\Webhooks(); 63 70 64 if (empty($params['title']) || empty($params['content'])) { 65 return new WP_Error('missing_data', 'Título e conteúdo são obrigatórios.', ['status' => 400]); 66 } 67 68 remove_filter('content_save_pre', 'wp_filter_post_kses'); 71 // AI 72 new WPRaiz\ContentAPI\AI\AI_Manager(); 69 73 70 $post_id = wp_insert_post([ 71 'post_title' => sanitize_text_field($params['title']), 72 'post_content' => $params['content'], 73 'post_status' => sanitize_text_field($params['status'] ?? 'draft'), 74 'post_author' => get_current_user_id(), 75 ]); 74 // MCP 75 new WPRaiz\ContentAPI\MCP\MCP_Server(); 76 76 77 add_filter('content_save_pre', 'wp_filter_post_kses'); 78 79 if (is_wp_error($post_id)) { 80 return new WP_Error('post_creation_failed', 'Falha ao criar o post.', ['status' => 500]); 81 } 82 83 // Verifica ou cria a categoria principal 84 if (!empty($params['primary_category'])) { 85 $primary_category_id = $this->get_or_create_category(trim($params['primary_category'])); 86 if (!is_wp_error($primary_category_id)) { 87 wp_set_post_terms($post_id, [$primary_category_id], 'category'); 88 } 89 } 90 91 // Faz o upload da imagem se a URL for fornecida 92 if (!empty($params['image_url'])) { 93 $image_id = $this->upload_image_from_url($params['image_url'], $post_id); 94 if (!is_wp_error($image_id)) { 95 set_post_thumbnail($post_id, $image_id); 96 } 97 } 98 99 // Adiciona os campos de SEO com base no plugin ativo 100 // Adiciona os campos de SEO diretamente 101 if (!empty($params['seo_title'])) { 102 update_post_meta($post_id, '_seopress_titles_title', sanitize_text_field($params['seo_title'])); 103 update_post_meta($post_id, '_yoast_wpseo_title', sanitize_text_field($params['seo_title'])); 104 update_post_meta($post_id, 'rank_math_title', sanitize_text_field($params['seo_title'])); 105 } 106 107 if (!empty($params['seo_desc'])) { 108 update_post_meta($post_id, '_seopress_titles_desc', sanitize_text_field($params['seo_desc'])); 109 update_post_meta($post_id, '_yoast_wpseo_metadesc', sanitize_text_field($params['seo_desc'])); 110 update_post_meta($post_id, 'rank_math_description', sanitize_text_field($params['seo_desc'])); 111 } 112 113 return new WP_REST_Response([ 114 'message' => 'Post criado com sucesso!', 115 'post_id' => $post_id, 116 'post_url' => get_permalink($post_id), 117 ], 201); 118 } 119 120 /** 121 * Função para verificar ou criar uma categoria. 122 */ 123 public function get_or_create_category($category_name) { 124 $term = get_term_by('name', $category_name, 'category'); 125 if ($term) { 126 return $term->term_id; 127 } else { 128 $new_term = wp_insert_term($category_name, 'category'); 129 if (is_wp_error($new_term)) { 130 return $new_term; 131 } 132 return $new_term['term_id']; 133 } 134 } 135 136 public function upload_image_from_url($image_url, $post_id) { 137 // Usa wp_remote_get() para obter o conteúdo da imagem da URL 138 $response = wp_remote_get($image_url); 139 140 if (is_wp_error($response)) { 141 return new WP_Error('image_download_failed', 'Falha ao baixar a imagem.'); 142 } 143 144 $image_data = wp_remote_retrieve_body($response); 145 $http_code = wp_remote_retrieve_response_code($response); 146 147 // Verifica se a resposta foi bem-sucedida 148 if ($http_code !== 200 || !$image_data) { 149 return new WP_Error('image_download_failed', 'Falha ao baixar a imagem.'); 150 } 151 152 // Cria um arquivo temporário 153 $tmp_file = wp_tempnam($image_url); 154 global $wp_filesystem; 155 156 if (!function_exists('WP_Filesystem')) { 157 require_once(ABSPATH . 'wp-admin/includes/file.php'); 158 } 159 160 WP_Filesystem(); 161 $wp_filesystem->put_contents($tmp_file, $image_data); 162 163 // Define as informações do arquivo para o upload 164 $file_array = array(); 165 $file_array['name'] = basename(wp_parse_url($image_url, PHP_URL_PATH)); // Usando wp_parse_url() 166 $file_array['tmp_name'] = $tmp_file; 167 168 // Faz o upload da imagem para o WordPress 169 $image_id = media_handle_sideload($file_array, $post_id); 170 171 if (is_wp_error($image_id)) { 172 wp_delete_file($tmp_file); // Remove o arquivo temporário 173 return $image_id; 174 } 175 176 return $image_id; 177 } 178 179 public function authenticate_user($request) { 180 return current_user_can('edit_posts'); 77 // Admin 78 if ( is_admin() ) { 79 new WPRaiz\ContentAPI\Admin\Admin_Page(); 80 new WPRaiz\ContentAPI\Admin\License(); 181 81 } 182 82 } 83 add_action( 'plugins_loaded', 'wpraiz_init' ); 183 84 184 class API_Post_Creator_With_Menu { 85 /** 86 * Activation hook — create options and flush rewrite rules. 87 */ 88 function wpraiz_activate() { 89 add_option( 'wpraiz_settings', [ 90 'ai_provider' => '', 91 'openai_api_key' => '', 92 'claude_api_key' => '', 93 'auto_seo' => true, 94 'webhook_url' => '', 95 'webhook_events' => [ 'post_created' ], 96 'rate_limit' => 60, 97 ]); 98 flush_rewrite_rules(); 99 } 100 register_activation_hook( __FILE__, 'wpraiz_activate' ); 185 101 186 public function __construct() { 187 // Adiciona o sub-menu na página de Ferramentas 188 add_action('admin_menu', [$this, 'add_plugin_menu']); 189 add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']); 190 } 102 /** 103 * Deactivation hook. 104 */ 105 function wpraiz_deactivate() { 106 flush_rewrite_rules(); 107 } 108 register_deactivation_hook( __FILE__, 'wpraiz_deactivate' ); 191 109 192 public function add_plugin_menu() { 193 add_submenu_page( 194 'tools.php', // O menu principal "Ferramentas" 195 'WPRaiz Content API', // Título da página 196 'WPRaiz Content API', // Texto do menu 197 'manage_options', // Capability (permissão) 198 'wpraiz-content-api', // Slug da página 199 [$this, 'render_admin_page'] // Função que renderiza a página 200 ); 201 } 202 203 public function render_admin_page() { 204 $site_url = get_site_url(); 205 $endpoint_url = $site_url . '/wp-json/api-post-creator/v1/create-post'; 206 $check_url = $site_url . '/wp-json/api-post-creator/v1/check-status'; 207 $categories_url = $site_url . '/wp-json/api-post-creator/v1/get-categories'; 208 $search_url = $site_url . '/wp-json/api-post-creator/v1/search-similar-posts?title=Exemplo'; 209 ?> 210 <div class="wrap"> 211 <h1>WPRaiz Content API</h1> 212 <img src="<?php echo esc_url(plugins_url('assets/images/logo_wpraiz.png', __FILE__)); ?>" width="300" alt="WPRaiz Logo" /> 213 214 <table class="widefat fixed" style="max-width: 900px; margin-top: 20px;"> 215 <thead> 216 <tr> 217 <th>Descrição</th> 218 <th>Endpoint</th> 219 <th>Ação</th> 220 </tr> 221 </thead> 222 <tbody> 223 <tr> 224 <td><strong>Criação de Post</strong><br><small>Envia um post com imagem e SEO.</small></td> 225 <td><input type="text" id="api-endpoint" value="<?php echo esc_url($endpoint_url); ?>" readonly style="width: 100%;" /></td> 226 <td><button onclick="copyToClipboard('api-endpoint')" class="button">Copiar</button></td> 227 </tr> 228 <tr> 229 <td><strong>Status do Plugin</strong><br><small>Verifica se o plugin e o SEO estão ativos.</small></td> 230 <td><input type="text" id="check-endpoint" value="<?php echo esc_url($check_url); ?>" readonly style="width: 100%;" /></td> 231 <td><button onclick="copyToClipboard('check-endpoint')" class="button">Copiar</button></td> 232 </tr> 233 <tr> 234 <td><strong>Listar Categorias</strong><br><small>Retorna categorias existentes no site.</small></td> 235 <td><input type="text" id="categories-endpoint" value="<?php echo esc_url($categories_url); ?>" readonly style="width: 100%;" /></td> 236 <td><button onclick="copyToClipboard('categories-endpoint')" class="button">Copiar</button></td> 237 </tr> 238 <tr> 239 <td><strong>Buscar Títulos Semelhantes</strong><br><small>Retorna posts parecidos com base no título.</small></td> 240 <td><input type="text" id="search-endpoint" value="<?php echo esc_url($search_url); ?>" readonly style="width: 100%;" /></td> 241 <td><button onclick="copyToClipboard('search-endpoint')" class="button">Copiar</button></td> 242 </tr> 243 </tbody> 244 </table> 245 246 <h2 style="margin-top: 30px;">Exemplo de Requisição</h2> 247 <pre>{ 248 "title": "Título do Post", 249 "content": "Este é o conteúdo do post", 250 "status": "publish", 251 "primary_category": "Geral", 252 "seo_title": "Título SEO", 253 "seo_desc": "Descrição SEO", 254 "image_url": "https://seu-site.com/imagem.jpg" 255 }</pre> 256 <p><strong>Importante:</strong> Use a senha de aplicativo do WordPress para autenticação via API.</p> 257 258 <h2>Links Rápidos</h2> 259 <a href="https://wpraiz.com.br" target="_blank" class="button button-primary">Visitar WPRaiz</a> 260 <a href="https://youtube.com/wpraiz" target="_blank" class="button button-primary">Canal no Youtube</a> 261 </div> 262 263 <script type="text/javascript"> 264 function copyToClipboard(id) { 265 const el = document.getElementById(id); 266 el.select(); 267 el.setSelectionRange(0, 99999); 268 document.execCommand("copy"); 269 alert("Endpoint copiado: " + el.value); 270 } 271 </script> 272 <?php 273 } 274 275 public function enqueue_admin_scripts($hook_suffix) { 276 // Certifique-se de que você só adiciona os scripts na página correta 277 if ($hook_suffix === 'tools_page_wpraiz-content-api') { 278 wp_enqueue_script( 279 'wpraiz-admin-script', 280 plugins_url('assets/js/admin-scripts.js', __FILE__), 281 array('jquery'), 282 '1.3', // Definindo a versão do script 283 true 284 ); 285 } 286 } 110 /** 111 * Helper: get plugin settings. 112 */ 113 function wpraiz_get_settings() { 114 return wp_parse_args( get_option( 'wpraiz_settings', [] ), [ 115 'ai_provider' => '', 116 'openai_api_key' => '', 117 'claude_api_key' => '', 118 'auto_seo' => true, 119 'webhook_url' => '', 120 'webhook_events' => [ 'post_created' ], 121 'rate_limit' => 60, 122 ]); 287 123 } 288 124 289 290 function api_post_creator_with_image_and_menu_init() { 291 new API_Post_Creator_With_Image(); 292 new API_Post_Creator_With_Menu(); 293 } 294 add_action('plugins_loaded', 'api_post_creator_with_image_and_menu_init'); 295 class API_Post_Creator_With_Categories { 296 297 public function __construct() { 298 add_action('rest_api_init', [$this, 'register_routes']); 299 } 300 301 public function register_routes() { 302 register_rest_route('api-post-creator/v1', '/get-categories', [ 303 'methods' => 'GET', 304 'callback' => [$this, 'get_categories'], 305 //'permission_callback' => [$this, 'authenticate_user'], 306 ]); 307 register_rest_route('api-post-creator/v1', '/search-similar-posts', [ 308 'methods' => 'GET', 309 'callback' => [$this, 'search_similar_posts'], 310 'permission_callback' => '__return_true', 311 ]); 312 } 313 314 public function get_categories() { 315 $categories = get_categories([ 316 'taxonomy' => 'category', 317 'hide_empty' => false, 318 ]); 319 320 $category_list = []; 321 foreach ($categories as $category) { 322 $category_list[] = [ 323 'id' => $category->term_id, 324 'name' => $category->name, 325 'slug' => $category->slug, 326 'description' => $category->description, 327 'count' => $category->count, 328 ]; 329 } 330 331 return new WP_REST_Response($category_list, 200); 332 } 333 334 public function search_similar_posts($request) { 335 $query_title = sanitize_text_field($request->get_param('title')); 336 337 if (empty($query_title)) { 338 return new WP_REST_Response(['error' => 'Parâmetro "title" é obrigatório.'], 400); 339 } 340 341 $posts = get_posts([ 342 'numberposts' => 100, 343 'post_status' => 'publish', 344 'post_type' => 'post', 345 ]); 346 347 $resultados = []; 348 349 foreach ($posts as $post) { 350 similar_text(strtolower($query_title), strtolower($post->post_title), $percent); 351 $categorias = get_the_category($post->ID); 352 $categoria_principal = $categorias[0]->name ?? ''; 353 $categoria_secundaria = $categorias[1]->name ?? ''; 354 355 $resultados[] = [ 356 'title' => $post->post_title, 357 'score' => round($percent, 2), 358 'primary_category' => $categoria_principal, 359 'secondary_category' => $categoria_secundaria, 360 'url' => get_permalink($post->ID), 361 ]; 362 } 363 364 usort($resultados, function($a, $b) { 365 return $b['score'] <=> $a['score']; 366 }); 367 368 return new WP_REST_Response(array_slice($resultados, 0, 10), 200); 369 } 370 371 372 public function authenticate_user($request) { 373 return current_user_can('edit_posts'); 374 } 375 } 376 377 new API_Post_Creator_With_Categories(); 125 /** 126 * Helper: check if Pro license is active. 127 */ 128 function wpraiz_is_pro(): bool { 129 return \WPRaiz\ContentAPI\Admin\License::is_pro(); 130 }
Note: See TracChangeset
for help on using the changeset viewer.