assets
3 weeks ago
abilities.php
3 weeks ago
manager.php
3 weeks ago
rest-proxy.php
3 weeks ago
server.php
3 weeks ago
service.php
3 weeks ago
rest-proxy.php
147 lines
| 1 | <?php |
| 2 | namespace ElementsKit_Lite\Mcp; |
| 3 | |
| 4 | defined( 'ABSPATH' ) || exit; |
| 5 | |
| 6 | /** |
| 7 | * REST proxy for the Angie editor tools. |
| 8 | * |
| 9 | * Exposes a single endpoint — POST /wp-json/elementskit/v1/mcp-proxy — that the |
| 10 | * editor-side Angie tools call. It validates the requested tool and input, |
| 11 | * enforces permissions and delegates to the shared {@see Service}. No insertion |
| 12 | * or template logic lives here; this is purely a dispatcher. |
| 13 | * |
| 14 | * Request body: |
| 15 | * { "tool": "insert-widget", "input": { ... } } |
| 16 | * |
| 17 | * @since 3.10.x |
| 18 | */ |
| 19 | class Rest_Proxy { |
| 20 | |
| 21 | const NAMESPACE = 'elementskit/v1'; |
| 22 | const ROUTE = '/mcp-proxy'; |
| 23 | |
| 24 | /** |
| 25 | * Map of proxy tool names to the Service method that handles them, together |
| 26 | * with whether the tool mutates a document (which raises the capability bar). |
| 27 | * |
| 28 | * @return array<string, array{method:string, mutating:bool}> |
| 29 | */ |
| 30 | private function tool_map() { |
| 31 | return [ |
| 32 | 'list-widgets' => [ 'method' => 'list_widgets', 'mutating' => false ], |
| 33 | 'insert-widget' => [ 'method' => 'insert_widget', 'mutating' => true ], |
| 34 | 'list-templates' => [ 'method' => 'list_templates', 'mutating' => false ], |
| 35 | 'insert-template' => [ 'method' => 'insert_template', 'mutating' => true ], |
| 36 | 'create-page' => [ 'method' => 'create_page', 'mutating' => true ], |
| 37 | 'create-template' => [ 'method' => 'create_template', 'mutating' => true ], |
| 38 | 'create-header-footer' => [ 'method' => 'create_header_footer', 'mutating' => true ], |
| 39 | 'list-custom-widgets' => [ 'method' => 'list_custom_widgets', 'mutating' => false ], |
| 40 | 'create-custom-widget' => [ 'method' => 'create_custom_widget', 'mutating' => true ], |
| 41 | 'list-mega-menus' => [ 'method' => 'list_mega_menus', 'mutating' => false ], |
| 42 | 'enable-mega-menu' => [ 'method' => 'enable_mega_menu', 'mutating' => true ], |
| 43 | 'update-mega-menu-item' => [ 'method' => 'update_mega_menu_item', 'mutating' => true ], |
| 44 | 'create-mega-menu' => [ 'method' => 'create_mega_menu', 'mutating' => true ], |
| 45 | 'list-library-templates' => [ 'method' => 'list_library_templates', 'mutating' => false ], |
| 46 | 'import-library-template' => [ 'method' => 'import_library_template', 'mutating' => true ], |
| 47 | ]; |
| 48 | } |
| 49 | |
| 50 | public function hooks() { |
| 51 | add_action( 'rest_api_init', [ $this, 'register_routes' ] ); |
| 52 | } |
| 53 | |
| 54 | public function register_routes() { |
| 55 | register_rest_route( |
| 56 | self::NAMESPACE, |
| 57 | self::ROUTE, |
| 58 | [ |
| 59 | 'methods' => \WP_REST_Server::CREATABLE, |
| 60 | 'callback' => [ $this, 'handle' ], |
| 61 | 'permission_callback' => [ $this, 'permission' ], |
| 62 | 'args' => [ |
| 63 | 'tool' => [ |
| 64 | 'type' => 'string', |
| 65 | 'required' => true, |
| 66 | ], |
| 67 | 'input' => [ |
| 68 | 'type' => 'object', |
| 69 | 'required' => false, |
| 70 | 'default' => [], |
| 71 | ], |
| 72 | ], |
| 73 | ] |
| 74 | ); |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * Base gate: the user must at least be able to edit posts. Per-document |
| 79 | * capability checks happen inside the Service for mutating tools. |
| 80 | * |
| 81 | * @return bool |
| 82 | */ |
| 83 | public function permission() { |
| 84 | return current_user_can( 'edit_posts' ); |
| 85 | } |
| 86 | |
| 87 | /** |
| 88 | * @param \WP_REST_Request $request |
| 89 | * @return \WP_REST_Response |
| 90 | */ |
| 91 | public function handle( \WP_REST_Request $request ) { |
| 92 | $tool = (string) $request->get_param( 'tool' ); |
| 93 | $input = $request->get_param( 'input' ); |
| 94 | $input = is_array( $input ) ? $input : []; |
| 95 | |
| 96 | $map = $this->tool_map(); |
| 97 | |
| 98 | if ( ! isset( $map[ $tool ] ) ) { |
| 99 | return $this->error_response( |
| 100 | 'ekit_mcp_unknown_tool', |
| 101 | /* translators: %s: tool name */ |
| 102 | sprintf( __( 'Unknown proxy tool: %s', 'elementskit-lite' ), $tool ), |
| 103 | 404 |
| 104 | ); |
| 105 | } |
| 106 | |
| 107 | $method = $map[ $tool ]['method']; |
| 108 | $result = ( new Service() )->$method( $input ); |
| 109 | |
| 110 | if ( is_wp_error( $result ) ) { |
| 111 | return $this->error_from_wp_error( $result ); |
| 112 | } |
| 113 | |
| 114 | return new \WP_REST_Response( $result, 200 ); |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * @param \WP_Error $error |
| 119 | * @return \WP_REST_Response |
| 120 | */ |
| 121 | private function error_from_wp_error( \WP_Error $error ) { |
| 122 | $data = $error->get_error_data(); |
| 123 | $status = is_array( $data ) && isset( $data['status'] ) ? (int) $data['status'] : 400; |
| 124 | |
| 125 | return $this->error_response( $error->get_error_code(), $error->get_error_message(), $status ); |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * @param string $code |
| 130 | * @param string $message |
| 131 | * @param int $status |
| 132 | * @return \WP_REST_Response |
| 133 | */ |
| 134 | private function error_response( $code, $message, $status ) { |
| 135 | return new \WP_REST_Response( |
| 136 | [ |
| 137 | 'success' => false, |
| 138 | 'error' => [ |
| 139 | 'code' => $code, |
| 140 | 'message' => $message, |
| 141 | ], |
| 142 | ], |
| 143 | $status |
| 144 | ); |
| 145 | } |
| 146 | } |
| 147 |