Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 483
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Posts
0.00% covered (danger)
0.00%
0 / 483
0.00% covered (danger)
0.00%
0 / 4
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 register_post_abilities
0.00% covered (danger)
0.00%
0 / 204
0.00% covered (danger)
0.00%
0 / 1
20
 register_category_abilities
0.00% covered (danger)
0.00%
0 / 138
0.00% covered (danger)
0.00%
0 / 1
2
 register_tag_abilities
0.00% covered (danger)
0.00%
0 / 138
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types=1 );
3
4namespace BLU\Abilities;
5
6/**
7 * Posts abilities for WordPress posts, categories, and tags.
8 */
9class Posts {
10
11    /**
12     * Constructor - registers all post-related abilities.
13     */
14    public function __construct() {
15        $this->register_post_abilities();
16        $this->register_category_abilities();
17        $this->register_tag_abilities();
18    }
19
20    /**
21     * Register post abilities.
22     */
23    private function register_post_abilities(): void {
24        // Search/list posts
25        blu_register_ability(
26            'blu/posts-search',
27            array(
28                'label'               => 'Search Posts',
29                'description'         => 'Search and filter WordPress posts with pagination',
30                'category'            => 'blu-mcp',
31                'input_schema'        => array(
32                    'type'       => 'object',
33                    'properties' => array(
34                        'search'   => array(
35                            'type'        => 'string',
36                            'description' => 'Search term',
37                        ),
38                        'status'   => array(
39                            'type'        => 'string',
40                            'description' => 'Post status(es): publish, draft, pending, future, private. Comma-separated for multiple. Omit to search all statuses.',
41                        ),
42                        'page'     => array(
43                            'type'        => 'integer',
44                            'description' => 'Page number',
45                        ),
46                        'per_page' => array(
47                            'type'        => 'integer',
48                            'description' => 'Posts per page',
49                        ),
50                    ),
51                ),
52                'execute_callback'    => function ( $input = null ) {
53                    $request = new \WP_REST_Request( 'GET', '/wp/v2/posts' );
54                    $all_statuses = 'publish,future,draft,pending,private';
55                    if ( $input ) {
56                        // Default to all statuses when not specified or empty (WP defaults to publish only).
57                        if ( ! isset( $input['status'] ) || '' === $input['status'] ) {
58                            $input['status'] = $all_statuses;
59                        }
60                        $request->set_query_params( $input );
61                    } else {
62                        $request->set_param( 'status', $all_statuses );
63                    }
64                    $response = rest_do_request( $request );
65                    return blu_standardize_rest_response( $response );
66                },
67                'permission_callback' => fn() => current_user_can( 'edit_posts' ),
68                'meta'                => array(
69                    'annotations' => array(
70                        'readonly'    => true,
71                        'destructive' => false,
72                        'idempotent'  => true,
73                    ),
74                ),
75            )
76        );
77
78        // Get single post
79        blu_register_ability(
80            'blu/get-post',
81            array(
82                'label'               => 'Get Post',
83                'description'         => 'Get a WordPress post by ID',
84                'category'            => 'blu-mcp',
85                'input_schema'        => array(
86                    'type'       => 'object',
87                    'properties' => array(
88                        'id' => array(
89                            'type'        => 'integer',
90                            'description' => 'Post ID',
91                        ),
92                    ),
93                    'required'   => array( 'id' ),
94                ),
95                'execute_callback'    => function ( $input ) {
96                    $request = new \WP_REST_Request( 'GET', '/wp/v2/posts/' . $input['id'] );
97                    $response = rest_do_request( $request );
98                    return blu_standardize_rest_response( $response );
99                },
100                'permission_callback' => fn() => current_user_can( 'edit_posts' ),
101                'meta'                => array(
102                    'annotations' => array(
103                        'readonly'    => true,
104                        'destructive' => false,
105                        'idempotent'  => true,
106                    ),
107                ),
108            )
109        );
110
111        // Add post
112        blu_register_ability(
113            'blu/add-post',
114            array(
115                'label'               => 'Add Post',
116                'description'         => 'Add a new WordPress post',
117                'category'            => 'blu-mcp',
118                'input_schema'        => array(
119                    'type'       => 'object',
120                    'properties' => array(
121                        'title'   => array(
122                            'type'        => 'string',
123                            'description' => 'Post title',
124                        ),
125                        'content' => array(
126                            'type'        => 'string',
127                            'description' => 'Post content in Gutenberg block format',
128                        ),
129                        'excerpt' => array(
130                            'type'        => 'string',
131                            'description' => 'Post excerpt',
132                        ),
133                        'status'  => array(
134                            'type'        => 'string',
135                            'description' => 'Post status (publish, draft, etc.)',
136                        ),
137                    ),
138                    'required'   => array( 'title', 'content' ),
139                ),
140                'execute_callback'    => function ( $input ) {
141                    $request = new \WP_REST_Request( 'POST', '/wp/v2/posts' );
142                    $request->set_body_params( $input );
143                    $response = rest_do_request( $request );
144                    return blu_standardize_rest_response( $response );
145                },
146                'permission_callback' => fn() => current_user_can( 'edit_posts' ),
147                'meta'                => array(
148                    'annotations' => array(
149                        'readonly'    => false,
150                        'destructive' => false,
151                        'idempotent'  => false,
152                    ),
153                ),
154            )
155        );
156
157        // Update post
158        blu_register_ability(
159            'blu/update-post',
160            array(
161                'label'               => 'Update Post',
162                'description'         => 'Update a WordPress post by ID',
163                'category'            => 'blu-mcp',
164                'input_schema'        => array(
165                    'type'       => 'object',
166                    'properties' => array(
167                        'id'      => array(
168                            'type'        => 'integer',
169                            'description' => 'Post ID',
170                        ),
171                        'title'   => array(
172                            'type'        => 'string',
173                            'description' => 'Post title',
174                        ),
175                        'content' => array(
176                            'type'        => 'string',
177                            'description' => 'Post content',
178                        ),
179                        'excerpt' => array(
180                            'type'        => 'string',
181                            'description' => 'Post excerpt',
182                        ),
183                        'status'  => array(
184                            'type'        => 'string',
185                            'description' => 'Post status',
186                        ),
187                    ),
188                    'required'   => array( 'id' ),
189                ),
190                'execute_callback'    => function ( $input ) {
191                    $id = $input['id'];
192                    unset( $input['id'] );
193                    $request = new \WP_REST_Request( 'PUT', '/wp/v2/posts/' . $id );
194                    $request->set_body_params( $input );
195                    $response = rest_do_request( $request );
196                    return blu_standardize_rest_response( $response );
197                },
198                'permission_callback' => fn() => current_user_can( 'edit_posts' ),
199                'meta'                => array(
200                    'annotations' => array(
201                        'readonly'    => false,
202                        'destructive' => false,
203                        'idempotent'  => true,
204                    ),
205                ),
206            )
207        );
208
209        // Delete post
210        blu_register_ability(
211            'blu/delete-post',
212            array(
213                'label'               => 'Delete Post',
214                'description'         => 'Delete a WordPress post by ID',
215                'category'            => 'blu-mcp',
216                'input_schema'        => array(
217                    'type'       => 'object',
218                    'properties' => array(
219                        'id' => array(
220                            'type'        => 'integer',
221                            'description' => 'Post ID',
222                        ),
223                    ),
224                    'required'   => array( 'id' ),
225                ),
226                'execute_callback'    => function ( $input ) {
227                    $request = new \WP_REST_Request( 'DELETE', '/wp/v2/posts/' . $input['id'] );
228                    $response = rest_do_request( $request );
229                    return blu_standardize_rest_response( $response );
230                },
231                'permission_callback' => fn() => current_user_can( 'delete_posts' ),
232                'meta'                => array(
233                    'annotations' => array(
234                        'readonly'    => false,
235                        'destructive' => true,
236                        'idempotent'  => true,
237                    ),
238                ),
239            )
240        );
241    }
242
243    /**
244     * Register category abilities.
245     */
246    private function register_category_abilities(): void {
247        // List categories
248        blu_register_ability(
249            'blu/list-categories',
250            array(
251                'label'               => 'List Categories',
252                'description'         => 'List all WordPress post categories',
253                'category'            => 'blu-mcp',
254                'input_schema'        => array(
255                    'type' => 'object',
256                ),
257                'execute_callback'    => function () {
258                    $request = new \WP_REST_Request( 'GET', '/wp/v2/categories' );
259                    $response = rest_do_request( $request );
260                    return blu_standardize_rest_response( $response );
261                },
262                'permission_callback' => fn() => current_user_can( 'edit_posts' ),
263                'meta'                => array(
264                    'annotations' => array(
265                        'readonly'    => true,
266                        'destructive' => false,
267                        'idempotent'  => true,
268                    ),
269                ),
270            )
271        );
272
273        // Add category
274        blu_register_ability(
275            'blu/add-category',
276            array(
277                'label'               => 'Add Category',
278                'description'         => 'Add a new WordPress post category',
279                'category'            => 'blu-mcp',
280                'input_schema'        => array(
281                    'type'       => 'object',
282                    'properties' => array(
283                        'name'        => array(
284                            'type'        => 'string',
285                            'description' => 'Category name',
286                        ),
287                        'description' => array(
288                            'type'        => 'string',
289                            'description' => 'Category description',
290                        ),
291                        'slug'        => array(
292                            'type'        => 'string',
293                            'description' => 'Category slug',
294                        ),
295                    ),
296                    'required'   => array( 'name' ),
297                ),
298                'execute_callback'    => function ( $input ) {
299                    $request = new \WP_REST_Request( 'POST', '/wp/v2/categories' );
300                    $request->set_body_params( $input );
301                    $response = rest_do_request( $request );
302                    return blu_standardize_rest_response( $response );
303                },
304                'permission_callback' => fn() => current_user_can( 'manage_categories' ),
305                'meta'                => array(
306                    'annotations' => array(
307                        'readonly'    => false,
308                        'destructive' => false,
309                        'idempotent'  => false,
310                    ),
311                ),
312            )
313        );
314
315        // Update category
316        blu_register_ability(
317            'blu/update-category',
318            array(
319                'label'               => 'Update Category',
320                'description'         => 'Update a WordPress post category',
321                'category'            => 'blu-mcp',
322                'input_schema'        => array(
323                    'type'       => 'object',
324                    'properties' => array(
325                        'id'          => array(
326                            'type'        => 'integer',
327                            'description' => 'Category ID',
328                        ),
329                        'name'        => array(
330                            'type'        => 'string',
331                            'description' => 'Category name',
332                        ),
333                        'description' => array(
334                            'type'        => 'string',
335                            'description' => 'Category description',
336                        ),
337                    ),
338                    'required'   => array( 'id' ),
339                ),
340                'execute_callback'    => function ( $input ) {
341                    $id = $input['id'];
342                    unset( $input['id'] );
343                    $request = new \WP_REST_Request( 'PUT', '/wp/v2/categories/' . $id );
344                    $request->set_body_params( $input );
345                    $response = rest_do_request( $request );
346                    return blu_standardize_rest_response( $response );
347                },
348                'permission_callback' => fn() => current_user_can( 'manage_categories' ),
349                'meta'                => array(
350                    'annotations' => array(
351                        'readonly'    => false,
352                        'destructive' => false,
353                        'idempotent'  => true,
354                    ),
355                ),
356            )
357        );
358
359        // Delete category
360        blu_register_ability(
361            'blu/delete-category',
362            array(
363                'label'               => 'Delete Category',
364                'description'         => 'Delete a WordPress post category',
365                'category'            => 'blu-mcp',
366                'input_schema'        => array(
367                    'type'       => 'object',
368                    'properties' => array(
369                        'id' => array(
370                            'type'        => 'integer',
371                            'description' => 'Category ID',
372                        ),
373                    ),
374                    'required'   => array( 'id' ),
375                ),
376                'execute_callback'    => function ( $input ) {
377                    $request = new \WP_REST_Request( 'DELETE', '/wp/v2/categories/' . $input['id'] );
378                    $request->set_query_params( array( 'force' => true ) );
379                    $response = rest_do_request( $request );
380                    return blu_standardize_rest_response( $response );
381                },
382                'permission_callback' => fn() => current_user_can( 'manage_categories' ),
383                'meta'                => array(
384                    'annotations' => array(
385                        'readonly'    => false,
386                        'destructive' => true,
387                        'idempotent'  => true,
388                    ),
389                ),
390            )
391        );
392    }
393
394    /**
395     * Register tag abilities.
396     */
397    private function register_tag_abilities(): void {
398        // List tags
399        blu_register_ability(
400            'blu/list-tags',
401            array(
402                'label'               => 'List Tags',
403                'description'         => 'List all WordPress post tags',
404                'category'            => 'blu-mcp',
405                'input_schema'        => array(
406                    'type' => 'object',
407                ),
408                'execute_callback'    => function () {
409                    $request = new \WP_REST_Request( 'GET', '/wp/v2/tags' );
410                    $response = rest_do_request( $request );
411                    return blu_standardize_rest_response( $response );
412                },
413                'permission_callback' => fn() => current_user_can( 'edit_posts' ),
414                'meta'                => array(
415                    'annotations' => array(
416                        'readonly'    => true,
417                        'destructive' => false,
418                        'idempotent'  => true,
419                    ),
420                ),
421            )
422        );
423
424        // Add tag
425        blu_register_ability(
426            'blu/add-tag',
427            array(
428                'label'               => 'Add Tag',
429                'description'         => 'Add a new WordPress post tag',
430                'category'            => 'blu-mcp',
431                'input_schema'        => array(
432                    'type'       => 'object',
433                    'properties' => array(
434                        'name'        => array(
435                            'type'        => 'string',
436                            'description' => 'Tag name',
437                        ),
438                        'description' => array(
439                            'type'        => 'string',
440                            'description' => 'Tag description',
441                        ),
442                        'slug'        => array(
443                            'type'        => 'string',
444                            'description' => 'Tag slug',
445                        ),
446                    ),
447                    'required'   => array( 'name' ),
448                ),
449                'execute_callback'    => function ( $input ) {
450                    $request = new \WP_REST_Request( 'POST', '/wp/v2/tags' );
451                    $request->set_body_params( $input );
452                    $response = rest_do_request( $request );
453                    return blu_standardize_rest_response( $response );
454                },
455                'permission_callback' => fn() => current_user_can( 'manage_categories' ),
456                'meta'                => array(
457                    'annotations' => array(
458                        'readonly'    => false,
459                        'destructive' => false,
460                        'idempotent'  => false,
461                    ),
462                ),
463            )
464        );
465
466        // Update tag
467        blu_register_ability(
468            'blu/update-tag',
469            array(
470                'label'               => 'Update Tag',
471                'description'         => 'Update a WordPress post tag',
472                'category'            => 'blu-mcp',
473                'input_schema'        => array(
474                    'type'       => 'object',
475                    'properties' => array(
476                        'id'          => array(
477                            'type'        => 'integer',
478                            'description' => 'Tag ID',
479                        ),
480                        'name'        => array(
481                            'type'        => 'string',
482                            'description' => 'Tag name',
483                        ),
484                        'description' => array(
485                            'type'        => 'string',
486                            'description' => 'Tag description',
487                        ),
488                    ),
489                    'required'   => array( 'id' ),
490                ),
491                'execute_callback'    => function ( $input ) {
492                    $id = $input['id'];
493                    unset( $input['id'] );
494                    $request = new \WP_REST_Request( 'PUT', '/wp/v2/tags/' . $id );
495                    $request->set_body_params( $input );
496                    $response = rest_do_request( $request );
497                    return blu_standardize_rest_response( $response );
498                },
499                'permission_callback' => fn() => current_user_can( 'manage_categories' ),
500                'meta'                => array(
501                    'annotations' => array(
502                        'readonly'    => false,
503                        'destructive' => false,
504                        'idempotent'  => true,
505                    ),
506                ),
507            )
508        );
509
510        // Delete tag
511        blu_register_ability(
512            'blu/delete-tag',
513            array(
514                'label'               => 'Delete Tag',
515                'description'         => 'Delete a WordPress post tag',
516                'category'            => 'blu-mcp',
517                'input_schema'        => array(
518                    'type'       => 'object',
519                    'properties' => array(
520                        'id' => array(
521                            'type'        => 'integer',
522                            'description' => 'Tag ID',
523                        ),
524                    ),
525                    'required'   => array( 'id' ),
526                ),
527                'execute_callback'    => function ( $input ) {
528                    $request = new \WP_REST_Request( 'DELETE', '/wp/v2/tags/' . $input['id'] );
529                    $request->set_query_params( array( 'force' => true ) );
530                    $response = rest_do_request( $request );
531                    return blu_standardize_rest_response( $response );
532                },
533                'permission_callback' => fn() => current_user_can( 'manage_categories' ),
534                'meta'                => array(
535                    'annotations' => array(
536                        'readonly'    => false,
537                        'destructive' => true,
538                        'idempotent'  => true,
539                    ),
540                ),
541            )
542        );
543    }
544}