verifySecurity()) { wp_send_json_error([ 'message' => 'Security check failed' ], 403); return; } // 2. Sanitizar input $componentName = sanitize_key($_POST['component_name'] ?? ''); $data = $_POST['data'] ?? []; if (empty($componentName)) { wp_send_json_error([ 'message' => 'Component name is required' ], 400); return; } // 3. Crear Request DTO $request = new SaveComponentRequest($componentName, $data); // 4. Ejecutar Use Case $useCase = new SaveComponentUseCase( $this->container->getComponentRepository(), $this->container->getValidationService(), $this->container->getCacheService() ); $response = $useCase->execute($request); // 5. Respuesta HTTP if ($response->isSuccess()) { wp_send_json_success($response->getData()); } else { wp_send_json_error([ 'message' => 'Validation failed', 'errors' => $response->getErrors() ], 422); } } /** * Endpoint: Obtener componente * * GET /wp-admin/admin-ajax.php?action=roi_theme_get_component&component_name=xxx */ public function getComponent(): void { if (!$this->verifySecurity()) { wp_send_json_error(['message' => 'Security check failed'], 403); return; } $componentName = sanitize_key($_GET['component_name'] ?? ''); if (empty($componentName)) { wp_send_json_error(['message' => 'Component name is required'], 400); return; } $request = new GetComponentRequest($componentName); $useCase = new GetComponentUseCase( $this->container->getComponentRepository(), $this->container->getCacheService() ); $response = $useCase->execute($request); if ($response->isSuccess()) { wp_send_json_success($response->getData()); } else { wp_send_json_error(['message' => $response->getError()], 404); } } /** * Endpoint: Eliminar componente * * POST /wp-admin/admin-ajax.php?action=roi_theme_delete_component * Body: { nonce, component_name } */ public function deleteComponent(): void { if (!$this->verifySecurity()) { wp_send_json_error(['message' => 'Security check failed'], 403); return; } $componentName = sanitize_key($_POST['component_name'] ?? ''); if (empty($componentName)) { wp_send_json_error(['message' => 'Component name is required'], 400); return; } $request = new DeleteComponentRequest($componentName); $useCase = new DeleteComponentUseCase( $this->container->getComponentRepository(), $this->container->getCacheService() ); $response = $useCase->execute($request); if ($response->isSuccess()) { wp_send_json_success(['message' => $response->getMessage()]); } else { wp_send_json_error(['message' => $response->getError()], 404); } } /** * Endpoint: Sincronizar schemas * * POST /wp-admin/admin-ajax.php?action=roi_theme_sync_schema */ public function syncSchema(): void { if (!$this->verifySecurity()) { wp_send_json_error(['message' => 'Security check failed'], 403); return; } $syncService = $this->container->getSchemaSyncService(); $result = $syncService->syncAll(); if ($result['success']) { wp_send_json_success($result['data']); } else { wp_send_json_error(['message' => $result['error']], 500); } } /** * Verificar seguridad (nonce + capabilities) * * @return bool */ private function verifySecurity(): bool { // Verificar nonce $nonce = $_REQUEST['nonce'] ?? ''; if (!wp_verify_nonce($nonce, self::NONCE_ACTION)) { return false; } // Verificar permisos (solo administradores) if (!current_user_can('manage_options')) { return false; } return true; } }