PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.14
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.14
2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 All 139 releases
metasync / wp-mcp-server / tools / class-mcp-tool-bulk-operations.php

class-mcp-tool-bulk-operations.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.14, at wp-mcp-server/tools/class-mcp-tool-bulk-operations.php

503 lines 15.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MCP Tools for Bulk Operations
4 *
5 * Provides MCP tools for performing bulk operations on multiple posts.
6 *
7 * @package MetaSync
8 * @subpackage MCP_Server/Tools
9 */
10
11 if (!defined('ABSPATH')) {
12 exit;
13 }
14
15 require_once plugin_dir_path(dirname(__FILE__)) . 'class-mcp-tool-base.php';
16
17 /**
18 * Bulk Update Meta Tool
19 *
20 * Updates meta for multiple posts
21 */
22 class MCP_Tool_Bulk_Update_Meta extends MCP_Tool_Base {
23
24 public function get_name() {
25 return 'wordpress_bulk_update_meta';
26 }
27
28 public function get_description() {
29 return 'Update post meta for multiple posts at once (max 100 posts)';
30 }
31
32 public function get_input_schema() {
33 return [
34 'type' => 'object',
35 'properties' => [
36 'post_ids' => [
37 'type' => 'array',
38 'description' => 'Array of post IDs to update (max 100)',
39 'items' => ['type' => 'integer'],
40 'maxItems' => 100,
41 ],
42 'meta_key' => [
43 'type' => 'string',
44 'description' => 'Meta key to update',
45 ],
46 'meta_value' => [
47 'type' => 'string',
48 'description' => 'Meta value to set',
49 ],
50 ],
51 'required' => ['post_ids', 'meta_key', 'meta_value'],
52 ];
53 }
54
55 public function execute($params) {
56 $this->validate_params($params);
57 $this->require_capability('edit_posts');
58
59 if (!is_array($params['post_ids'])) {
60 throw new Exception('post_ids must be an array');
61 }
62
63 $post_ids = array_map('intval', $params['post_ids']);
64
65 if (empty($post_ids)) {
66 throw new Exception('No post IDs provided');
67 }
68
69 if (count($post_ids) > 100) {
70 throw new Exception('Maximum 100 posts can be updated at once');
71 }
72
73 $meta_key = sanitize_text_field($params['meta_key']);
74 $meta_value = $params['meta_value']; // Don't sanitize yet, depends on key
75
76 $results = [
77 'success' => [],
78 'failed' => [],
79 ];
80
81 foreach ($post_ids as $post_id) {
82 try {
83 // Verify post exists
84 $post = get_post($post_id);
85 if (!$post) {
86 $results['failed'][] = [
87 'post_id' => $post_id,
88 'error' => 'Post not found',
89 ];
90 continue;
91 }
92
93 // Check permissions
94 try {
95 $this->check_post_permission($post_id);
96 } catch (Exception $e) {
97 $results['failed'][] = [
98 'post_id' => $post_id,
99 'error' => $e->getMessage(),
100 ];
101 continue;
102 }
103
104 // Update meta
105 update_post_meta($post_id, $meta_key, $meta_value);
106
107 $results['success'][] = [
108 'post_id' => $post_id,
109 'post_title' => $post->post_title,
110 ];
111
112 } catch (Exception $e) {
113 $results['failed'][] = [
114 'post_id' => $post_id,
115 'error' => $e->getMessage(),
116 ];
117 }
118 }
119
120 return $this->success([
121 'total_requested' => count($post_ids),
122 'success_count' => count($results['success']),
123 'failed_count' => count($results['failed']),
124 'results' => $results,
125 'meta_key' => $meta_key,
126 'message' => count($results['success']) . ' post(s) updated successfully',
127 ]);
128 }
129 }
130
131 /**
132 * Bulk Set Categories Tool
133 *
134 * Sets categories for multiple posts
135 */
136 class MCP_Tool_Bulk_Set_Categories extends MCP_Tool_Base {
137
138 public function get_name() {
139 return 'wordpress_bulk_set_categories';
140 }
141
142 public function get_description() {
143 return 'Set categories for multiple posts at once (max 100 posts)';
144 }
145
146 public function get_input_schema() {
147 return [
148 'type' => 'object',
149 'properties' => [
150 'post_ids' => [
151 'type' => 'array',
152 'description' => 'Array of post IDs to update (max 100)',
153 'items' => ['type' => 'integer'],
154 'maxItems' => 100,
155 ],
156 'category_ids' => [
157 'type' => 'array',
158 'description' => 'Array of category IDs to assign',
159 'items' => ['type' => 'integer'],
160 ],
161 ],
162 'required' => ['post_ids', 'category_ids'],
163 ];
164 }
165
166 public function execute($params) {
167 $this->validate_params($params);
168 $this->require_capability('edit_posts');
169
170 if (!is_array($params['post_ids'])) {
171 throw new Exception('post_ids must be an array');
172 }
173
174 if (!is_array($params['category_ids'])) {
175 throw new Exception('category_ids must be an array');
176 }
177
178 $post_ids = array_map('intval', $params['post_ids']);
179 $category_ids = array_map('intval', $params['category_ids']);
180
181 if (empty($post_ids)) {
182 throw new Exception('No post IDs provided');
183 }
184
185 if (count($post_ids) > 100) {
186 throw new Exception('Maximum 100 posts can be updated at once');
187 }
188
189 // Validate categories exist (per-item failure: report in failed[] instead of throwing)
190 $invalid_category_ids = [];
191 foreach ($category_ids as $category_id) {
192 $category = get_term($category_id, 'category');
193 if (is_wp_error($category) || !$category) {
194 $invalid_category_ids[] = $category_id;
195 }
196 }
197
198 $results = [
199 'success' => [],
200 'failed' => [],
201 ];
202
203 $category_error = !empty($invalid_category_ids)
204 ? 'Category not found with ID(s): ' . implode(', ', array_map('absint', $invalid_category_ids))
205 : '';
206
207 foreach ($post_ids as $post_id) {
208 try {
209 if ($category_error !== '') {
210 $results['failed'][] = [
211 'post_id' => $post_id,
212 'error' => $category_error,
213 ];
214 continue;
215 }
216
217 // Verify post exists
218 $post = get_post($post_id);
219 if (!$post) {
220 $results['failed'][] = [
221 'post_id' => $post_id,
222 'error' => 'Post not found',
223 ];
224 continue;
225 }
226
227 // Check permissions
228 try {
229 $this->check_post_permission($post_id);
230 } catch (Exception $e) {
231 $results['failed'][] = [
232 'post_id' => $post_id,
233 'error' => $e->getMessage(),
234 ];
235 continue;
236 }
237
238 // Set categories
239 wp_set_post_categories($post_id, $category_ids);
240
241 $results['success'][] = [
242 'post_id' => $post_id,
243 'post_title' => $post->post_title,
244 ];
245
246 } catch (Exception $e) {
247 $results['failed'][] = [
248 'post_id' => $post_id,
249 'error' => $e->getMessage(),
250 ];
251 }
252 }
253
254 return $this->success([
255 'total_requested' => count($post_ids),
256 'success_count' => count($results['success']),
257 'failed_count' => count($results['failed']),
258 'results' => $results,
259 'category_ids' => $category_ids,
260 'message' => count($results['success']) . ' post(s) updated successfully',
261 ]);
262 }
263 }
264
265 /**
266 * Bulk Change Status Tool
267 *
268 * Changes status for multiple posts
269 */
270 class MCP_Tool_Bulk_Change_Status extends MCP_Tool_Base {
271
272 public function get_name() {
273 return 'wordpress_bulk_change_status';
274 }
275
276 public function get_description() {
277 return 'Change status for multiple posts at once (max 100 posts)';
278 }
279
280 public function get_input_schema() {
281 return [
282 'type' => 'object',
283 'properties' => [
284 'post_ids' => [
285 'type' => 'array',
286 'description' => 'Array of post IDs to update (max 100)',
287 'items' => ['type' => 'integer'],
288 'maxItems' => 100,
289 ],
290 'status' => [
291 'type' => 'string',
292 'enum' => ['publish', 'draft', 'pending', 'private'],
293 'description' => 'New status for the posts',
294 ],
295 ],
296 'required' => ['post_ids', 'status'],
297 ];
298 }
299
300 public function execute($params) {
301 $this->validate_params($params);
302 $this->require_capability('edit_posts');
303
304 if (!is_array($params['post_ids'])) {
305 throw new Exception('post_ids must be an array');
306 }
307
308 $post_ids = array_map('intval', $params['post_ids']);
309 $status = sanitize_text_field($params['status']);
310
311 if (empty($post_ids)) {
312 throw new Exception('No post IDs provided');
313 }
314
315 if (count($post_ids) > 100) {
316 throw new Exception('Maximum 100 posts can be updated at once');
317 }
318
319 $results = [
320 'success' => [],
321 'failed' => [],
322 ];
323
324 foreach ($post_ids as $post_id) {
325 try {
326 // Verify post exists
327 $post = get_post($post_id);
328 if (!$post) {
329 $results['failed'][] = [
330 'post_id' => $post_id,
331 'error' => 'Post not found',
332 ];
333 continue;
334 }
335
336 // Check permissions
337 try {
338 $this->check_post_permission($post_id);
339 } catch (Exception $e) {
340 $results['failed'][] = [
341 'post_id' => $post_id,
342 'error' => $e->getMessage(),
343 ];
344 continue;
345 }
346
347 // Update status
348 $result = wp_update_post([
349 'ID' => $post_id,
350 'post_status' => $status,
351 ], true);
352
353 if (is_wp_error($result)) {
354 $results['failed'][] = [
355 'post_id' => $post_id,
356 'error' => $result->get_error_message(),
357 ];
358 continue;
359 }
360
361 $results['success'][] = [
362 'post_id' => $post_id,
363 'post_title' => $post->post_title,
364 'old_status' => $post->post_status,
365 'new_status' => $status,
366 ];
367
368 } catch (Exception $e) {
369 $results['failed'][] = [
370 'post_id' => $post_id,
371 'error' => $e->getMessage(),
372 ];
373 }
374 }
375
376 return $this->success([
377 'total_requested' => count($post_ids),
378 'success_count' => count($results['success']),
379 'failed_count' => count($results['failed']),
380 'results' => $results,
381 'new_status' => $status,
382 'message' => count($results['success']) . ' post(s) status changed successfully',
383 ]);
384 }
385 }
386
387 /**
388 * Bulk Delete Posts Tool
389 *
390 * Deletes multiple posts
391 */
392 class MCP_Tool_Bulk_Delete_Posts extends MCP_Tool_Base {
393
394 public function get_name() {
395 return 'wordpress_bulk_delete_posts';
396 }
397
398 public function get_description() {
399 return 'Delete multiple posts at once (max 100 posts)';
400 }
401
402 public function get_input_schema() {
403 return [
404 'type' => 'object',
405 'properties' => [
406 'post_ids' => [
407 'type' => 'array',
408 'description' => 'Array of post IDs to delete (max 100)',
409 'items' => ['type' => 'integer'],
410 'maxItems' => 100,
411 ],
412 'force_delete' => [
413 'type' => 'boolean',
414 'description' => 'If true, permanently delete (default: false, moves to trash)',
415 ],
416 ],
417 'required' => ['post_ids'],
418 ];
419 }
420
421 public function execute($params) {
422 $this->validate_params($params);
423 $this->require_capability('delete_posts');
424
425 if (!is_array($params['post_ids'])) {
426 throw new Exception('post_ids must be an array');
427 }
428
429 $post_ids = array_map('intval', $params['post_ids']);
430 $force_delete = isset($params['force_delete']) ? (bool)$params['force_delete'] : false;
431
432 if (empty($post_ids)) {
433 throw new Exception('No post IDs provided');
434 }
435
436 if (count($post_ids) > 100) {
437 throw new Exception('Maximum 100 posts can be deleted at once');
438 }
439
440 $results = [
441 'success' => [],
442 'failed' => [],
443 ];
444
445 foreach ($post_ids as $post_id) {
446 try {
447 // Verify post exists
448 $post = get_post($post_id);
449 if (!$post) {
450 $results['failed'][] = [
451 'post_id' => $post_id,
452 'error' => 'Post not found',
453 ];
454 continue;
455 }
456
457 // Check permissions
458 if (!current_user_can('delete_post', $post_id)) {
459 $results['failed'][] = [
460 'post_id' => $post_id,
461 'error' => 'Permission denied',
462 ];
463 continue;
464 }
465
466 $title = $post->post_title;
467
468 // Delete post
469 $result = wp_delete_post($post_id, $force_delete);
470
471 if (!$result) {
472 $results['failed'][] = [
473 'post_id' => $post_id,
474 'error' => 'Failed to delete post',
475 ];
476 continue;
477 }
478
479 $results['success'][] = [
480 'post_id' => $post_id,
481 'post_title' => $title,
482 'permanently_deleted' => $force_delete,
483 ];
484
485 } catch (Exception $e) {
486 $results['failed'][] = [
487 'post_id' => $post_id,
488 'error' => $e->getMessage(),
489 ];
490 }
491 }
492
493 return $this->success([
494 'total_requested' => count($post_ids),
495 'success_count' => count($results['success']),
496 'failed_count' => count($results['failed']),
497 'results' => $results,
498 'permanently_deleted' => $force_delete,
499 'message' => count($results['success']) . ' post(s) ' . ($force_delete ? 'permanently deleted' : 'moved to trash'),
500 ]);
501 }
502 }
503