'POST', 'callback' => [ $this, 'handle_request' ], 'permission_callback' => function() { // Autenticar via WordPress Application Passwords no n8n: // Header: Authorization: Basic base64(user:app-password) return current_user_can( 'edit_posts' ); }, ]); } public function handle_request( WP_REST_Request $request ) { $params = $request->get_json_params(); $action = sanitize_text_field( $params['action'] ?? '' ); if ( ! function_exists( 'jet_engine' ) || ! class_exists( 'Jet_Engine' ) ) { return new WP_Error( 'no_jet_engine', 'JetEngine não está activo.', [ 'status' => 500 ] ); } switch ( $action ) { case 'create_cct_item': case 'update_cct_item': return $this->handle_cct_write( $params ); case 'get_cct_item': return $this->handle_cct_get( $params ); case 'delete_cct_item': return $this->handle_cct_delete( $params ); case 'manage_relation': return $this->handle_relation( $params ); default: return new WP_Error( 'invalid_action', 'Acção inválida. Disponíveis: create_cct_item, update_cct_item, get_cct_item, delete_cct_item, manage_relation', [ 'status' => 400 ] ); } } /** * Criar ou actualizar item CCT * * Payload: { * "action": "create_cct_item", * "cct_slug": "faturas", * "item_data": { * "titulo": "Fatura #1024", * "valor": 500, * "estado": "pendente" * } * } * Para update, incluir "_ID": 42 em item_data. */ private function handle_cct_write( array $params ) { $cct_slug = sanitize_key( $params['cct_slug'] ?? '' ); $item_data = $params['item_data'] ?? []; if ( empty( $cct_slug ) ) { return new WP_Error( 'missing_slug', 'cct_slug é obrigatório.', [ 'status' => 400 ] ); } if ( empty( $item_data ) ) { return new WP_Error( 'missing_data', 'item_data é obrigatório.', [ 'status' => 400 ] ); } $handler = $this->get_cct_handler( $cct_slug ); if ( is_wp_error( $handler ) ) return $handler; $result_id = $handler->update_item( $item_data ); if ( ! $result_id ) { return new WP_Error( 'db_error', 'Falha ao guardar item na base de dados.', [ 'status' => 500 ] ); } return rest_ensure_response( [ 'success' => true, 'item_id' => $result_id, 'action' => isset( $item_data['_ID'] ) ? 'updated' : 'created', ] ); } /** * Ler item CCT por ID * * Payload: { "action": "get_cct_item", "cct_slug": "faturas", "item_id": 42 } */ private function handle_cct_get( array $params ) { $cct_slug = sanitize_key( $params['cct_slug'] ?? '' ); $item_id = absint( $params['item_id'] ?? 0 ); if ( empty( $cct_slug ) || ! $item_id ) { return new WP_Error( 'missing_data', 'cct_slug e item_id são obrigatórios.', [ 'status' => 400 ] ); } $handler = $this->get_cct_handler( $cct_slug ); if ( is_wp_error( $handler ) ) return $handler; $item = $handler->get_item( $item_id ); if ( ! $item ) { return new WP_Error( 'not_found', "Item {$item_id} não encontrado no CCT '{$cct_slug}'.", [ 'status' => 404 ] ); } return rest_ensure_response( [ 'success' => true, 'item' => $item, ] ); } /** * Eliminar item CCT * * Payload: { "action": "delete_cct_item", "cct_slug": "faturas", "item_id": 42 } */ private function handle_cct_delete( array $params ) { $cct_slug = sanitize_key( $params['cct_slug'] ?? '' ); $item_id = absint( $params['item_id'] ?? 0 ); if ( empty( $cct_slug ) || ! $item_id ) { return new WP_Error( 'missing_data', 'cct_slug e item_id são obrigatórios.', [ 'status' => 400 ] ); } $handler = $this->get_cct_handler( $cct_slug ); if ( is_wp_error( $handler ) ) return $handler; $result = $handler->delete_item( $item_id ); return rest_ensure_response( [ 'success' => (bool) $result, 'item_id' => $item_id, 'deleted' => (bool) $result, ] ); } /** * Criar ou remover relação entre dois items * * Payload: { * "action": "manage_relation", * "rel_key": "clientes-projetos", * "parent_id": 10, * "child_id": 20, * "connect": true * } */ private function handle_relation( array $params ) { $rel_key = sanitize_text_field( $params['rel_key'] ?? '' ); $parent_id = absint( $params['parent_id'] ?? 0 ); $child_id = absint( $params['child_id'] ?? 0 ); $connect = (bool) ( $params['connect'] ?? true ); if ( empty( $rel_key ) || ! $parent_id || ! $child_id ) { return new WP_Error( 'missing_data', 'rel_key, parent_id e child_id são obrigatórios.', [ 'status' => 400 ] ); } if ( ! class_exists( '\Jet_Engine\Relations\Manager' ) ) { return new WP_Error( 'no_relations', 'Módulo de Relações JetEngine não disponível.', [ 'status' => 500 ] ); } \Jet_Engine\Relations\Manager::get_instance()->process_relation( $rel_key, $parent_id, $child_id, $connect ); return rest_ensure_response( [ 'success' => true, 'action' => $connect ? 'connected' : 'disconnected', 'rel_key' => $rel_key, 'parent' => $parent_id, 'child' => $child_id, ] ); } /** * Obter CCT handler com verificação de erro */ private function get_cct_handler( string $cct_slug ) { $cct_module = jet_engine()->modules->get_module( 'custom-content-types' ); if ( ! $cct_module ) { return new WP_Error( 'no_cct_module', 'Módulo CCT não está activo no JetEngine.', [ 'status' => 500 ] ); } $manager = $cct_module->instance->manager; $type = $manager->get_content_type_instance( $cct_slug ); if ( ! $type ) { return new WP_Error( 'invalid_cct', "CCT '{$cct_slug}' não encontrado.", [ 'status' => 404 ] ); } return $type->get_handler_instance(); } } new Descomplicar_Jet_Bridge();