ai_service = $ai_service; } public function name(): string { return 'replace_selected_blocks'; } public function description(): string { return 'Convert HTML or WordPress block markup into WordPress blocks and replace the currently selected blocks in the editor. ' . 'Use this when the user asks to change, update, restyle, or edit the selected section. ' . 'Provide either raw html/block markup or a description and the content will be generated for you. ' . "Set block_type to 'native' when generating dynamic or native WordPress content such as blog posts, navigation, post content, archives, or search forms."; } public function input_schema(): array { return array( 'type' => 'object', 'properties' => array( 'html' => array( 'type' => 'string', 'description' => 'Tailwind CSS HTML or serialized WordPress block markup to convert and use as the replacement.', ), 'description' => array( 'type' => 'string', 'description' => 'Description of the replacement section to generate. Use this if you do not have ready HTML/block markup.', ), 'block_type' => array( 'type' => 'string', 'enum' => array( 'tailwind', 'native' ), 'default' => 'tailwind', 'description' => "Use 'native' for dynamic or native WordPress blocks (blog posts, navigation, post content, archives, search). Use 'tailwind' (default) for static sections, hero areas, cards, buttons, and custom layouts.", ), ), ); } public function execute( array $input, array $context = array() ): array { $content = $this->prepare_content( $input, $context ); if ( is_wp_error( $content ) ) { return array( 'type' => 'error', 'message' => $content->get_error_message(), ); } $blocks = HtmlToBlocks::convert( $content ); if ( empty( $blocks ) ) { return array( 'type' => 'error', 'message' => sprintf( /* translators: %s: received HTML snippet */ __( 'Could not convert HTML to blocks. Received: %s', 'advanced-animation' ), mb_strimwidth( $content, 0, 200, '...' ) ), ); } $stage_result = 'chat' !== ( $context['request_source'] ?? '' ); $selection = $context['selection'] ?? null; if ( is_array( $selection ) && empty( $selection['post_id'] ) ) { $selection['post_id'] = intval( $context['post_id'] ?? 0 ); } $result = Block_Updater::replace_selection( $blocks, $context['page_content'] ?? null, $stage_result, $selection ); if ( is_wp_error( $result ) ) { return array( 'type' => 'error', 'message' => $result->get_error_message(), ); } return array_merge( array( 'type' => 'blocks_updated', 'action' => 'replace', ), $result ); } /** * Resolve the content to insert, either from input or by generating it. * * @return string|WP_Error */ private function prepare_content( array $input, array $context ) { $html = $input['html'] ?? ''; if ( ! empty( $html ) ) { return $this->clean_content( $html ); } $description = $input['description'] ?? ''; if ( empty( $description ) ) { return new WP_Error( 'missing_input', __( 'No html or description provided.', 'advanced-animation' ) ); } $block_type = $input['block_type'] ?? 'tailwind'; $preference = $context['block_type_preference'] ?? 'auto'; if ( in_array( $preference, array( 'tailwind', 'native' ), true ) ) { $block_type = $preference; } $post_id = intval( $context['post_id'] ?? 0 ) ?: null; if ( 'native' === $block_type ) { $generated = $this->ai_service->generate_native_blocks( $description, $context['selection'] ?? null, $post_id ); } else { $generated = $this->ai_service->generate_html( $description, $context['selection'] ?? null, $post_id ); } if ( is_wp_error( $generated ) ) { return $generated; } return $this->clean_content( $generated ); } /** * Strip markdown fences and other wrapping that breaks conversion. */ private function clean_content( string $content ): string { $content = trim( $content ); // Strip markdown fences. if ( preg_match( '/^```[^\r\n]*\R([\s\S]*?)```$/', $content, $matches ) ) { $content = trim( $matches[1] ); } // Extract serialized native block markup from explanatory model text. $native_start = stripos( $content, '' ); if ( false !== $native_end ) { return trim( substr( $content, 0, $native_end + 3 ) ); } } // Extract body contents if a full document is returned. if ( preg_match( '/]*>(.*?)<\/body>/s', $content, $matches ) ) { $content = trim( $matches[1] ); } return $content; } }