get_row($wpdb->prepare('SELECT * FROM %i WHERE id = %d', $t['chat_history'], intval($chat_id))); if (!$row) { return new WP_Error('aiwest_no_chat', __('The selected conversation was not found.', 'ai-webmaster-studio')); } if (!isset($row->mode) || $row->mode !== 'command') { return [ 'applied' => false, 'note' => __('This conversation mode produces guidance or a reusable prompt. It does not make website changes.', 'ai-webmaster-studio'), ]; } if (!current_user_can('manage_options')) return new WP_Error('aiwest_chat_permission',__('Missing permission.','ai-webmaster-studio')); if (!AIWEST_History::chat_can_be_approved($row)) return new WP_Error('aiwest_chat_decision',__('This command is not waiting for approval or has already been applied.','ai-webmaster-studio')); $lock='aiwest_chat_execution_'.absint($chat_id); if (!add_option($lock,time(),'','no')) return new WP_Error('aiwest_chat_busy',__('This command is already being applied.','ai-webmaster-studio')); try { // Re-read after acquiring the lock: another request may have completed while we waited. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $row=$wpdb->get_row($wpdb->prepare('SELECT * FROM %i WHERE id = %d',$t['chat_history'],intval($chat_id))); if (!AIWEST_History::chat_can_be_approved($row)) return new WP_Error('aiwest_chat_decision',__('This command is not waiting for approval or has already been applied.','ai-webmaster-studio')); AIWEST_History::record_chat_decision($chat_id,'executing',__('Applying the approved command.','ai-webmaster-studio')); if (!empty($row->target_post_id)) return self::apply_page_command($row); $text = trim(wp_strip_all_tags($row->user_message)); if (self::looks_like_menu_command($text)) { return self::apply_menu_command($row); } if (self::looks_like_page_command($text)) { return self::apply_page_command($row); } return [ 'applied' => false, 'note' => __('The administrator decision was recorded, but no supported technical target was detected. No website content was changed.', 'ai-webmaster-studio'), ]; } finally { delete_option($lock); } } public static function looks_like_menu_command($text) { $text = strtolower(remove_accents((string) $text)); $menu_terms = ['menu','submenu','navigation','nawigacj','navigationsmen','menue','meny']; $action_terms = ['add','create','complete','dodaj','utworz','stworz','uzupelnij','ajoute','ajouter','creer','erstellen','fuge','hinzufugen','anadir','agregar','crear','aggiungi','crea','adicionar','criar']; $has_menu_term = count(array_filter($menu_terms, static fn($term) => $term !== '' && strpos($text, $term) !== false)) > 0; $has_action_term = count(array_filter($action_terms, static fn($term) => $term !== '' && strpos($text, $term) !== false)) > 0; return $has_menu_term && $has_action_term; } public static function apply_menu_command($row) { if (!class_exists('AIWEST_OpenAI')) { return new WP_Error('aiwest_no_openai', __('The OpenAI module is unavailable.', 'ai-webmaster-studio')); } $prompt = sprintf( /* translators: 1: Administrator's menu command. 2: AI response associated with that command. */ __("Convert the administrator's WordPress menu request into a safe JSON structure. Do not remove the existing menu. Create missing pages as drafts and add menu items.\n\nAdministrator command and AI response:\n%1\$s\n\n%2\$s\n\nReturn JSON only, without Markdown:\n{\"menu_name\":\"AI Webmaster Studio — main menu\",\"items\":[{\"title\":\"Menu item\",\"slug\":\"menu-item\",\"children\":[{\"title\":\"Child item\",\"slug\":\"child-item\"}]}],\"note\":\"...\"}", 'ai-webmaster-studio'), $row->user_message, $row->ai_response ); $result = AIWEST_OpenAI::chat([ ['role' => 'system', 'content' => AIWEST_OpenAI::system_prompt()], ['role' => 'user', 'content' => $prompt], ], 0.2); if (is_wp_error($result)) { return $result; } $data = self::decode_json($result); if (!is_array($data) || empty($data['items'])) { return new WP_Error('aiwest_bad_menu_json', __('AI did not return valid menu JSON.', 'ai-webmaster-studio')); } return self::create_menu_from_items($data); } public static function looks_like_page_command($text) { return self::resolve_local_post_id($text) > 0; } public static function apply_page_command($row) { if (!class_exists('AIWEST_Content_Upgrader')) { return new WP_Error('aiwest_no_content_upgrader', __('The Content Development engine is unavailable.', 'ai-webmaster-studio')); } $instruction = sanitize_textarea_field((string)$row->user_message); $post_id = !empty($row->target_post_id)?absint($row->target_post_id):self::resolve_local_post_id($instruction); if (!$post_id) { return new WP_Error('aiwest_chat_page_not_found', __('The local WordPress page or post in this command could not be found.', 'ai-webmaster-studio')); } if (!current_user_can('edit_post', $post_id)) { return new WP_Error('aiwest_chat_page_permission', __('You do not have permission to edit the selected content.', 'ai-webmaster-studio')); } $normalized = strtolower(remove_accents($instruction)); $visual_requested = preg_match('/\b(visual|layout|appearance|design|style|look|wyglad|uklad|wizualn|styl)\b/i', $normalized) === 1; $rewrite_requested = preg_match('/\b(rewrite|replace|from scratch|przepisz|zastap|napisz od nowa)\b/i', $normalized) === 1; $faq_requested = preg_match('/\b(faq|frequently asked|pytania|odpowiedzi)\b/i', $normalized) === 1; $seo_requested = preg_match('/\b(seo|search engine|pozycjon|wyszukiw)\b/i', $normalized) === 1; $content_requested = preg_match('/\b(improve|update|expand|content|heading|section|popraw|rozbud|tresc|naglow|sekcj)\b/i', $normalized) === 1; $selected=sanitize_key($row->command_action??'auto'); if (in_array($selected,['improve','rewrite','seo','faq','cta','visual'],true)) { $result=AIWEST_Content_Upgrader::improve_post($post_id,$selected,$instruction); if (is_wp_error($result)) return $result; return ['applied'=>true,'post_id'=>$post_id,'note'=>$result['summary']??__('Command approved and applied.','ai-webmaster-studio'),'edit_link'=>get_edit_post_link($post_id,'raw'),'view_link'=>get_permalink($post_id)]; } $results = []; if ($rewrite_requested) { $results[] = AIWEST_Content_Upgrader::improve_post($post_id, 'rewrite', $instruction); } elseif ($content_requested || $seo_requested || $faq_requested || !$visual_requested) { $mode = ($seo_requested && !$faq_requested && !$content_requested) ? 'seo' : (($faq_requested && !$seo_requested && !$content_requested) ? 'faq' : 'improve'); $results[] = AIWEST_Content_Upgrader::improve_post($post_id, $mode, $instruction); } if ($visual_requested) { $results[] = AIWEST_Content_Upgrader::improve_post( $post_id, 'visual', __('Apply the current AI Webmaster Studio Design System without changing text, headings, links or their order.', 'ai-webmaster-studio') ); } $summaries = []; foreach ($results as $result) { if (is_wp_error($result)) return $result; if (is_array($result) && !empty($result['summary'])) { $summaries[] = sanitize_textarea_field($result['summary']); } } if (!$results) { return [ 'applied' => false, 'note' => __('No supported page action was detected. No website content was changed.', 'ai-webmaster-studio'), ]; } return [ 'applied' => true, 'note' => implode(' ', array_filter($summaries)) ?: __('The approved page command was applied.', 'ai-webmaster-studio'), 'post_id' => $post_id, 'edit_link' => get_edit_post_link($post_id, 'raw'), 'view_link' => get_permalink($post_id), ]; } protected static function resolve_local_post_id($text) { if (!preg_match_all('~https?://[^\s<>"\']+~i', (string)$text, $matches)) return 0; $site_host = strtolower((string)wp_parse_url(home_url('/'), PHP_URL_HOST)); foreach ($matches[0] as $url) { $url = rtrim($url, ".,;:!?)]}"); $host = strtolower((string)wp_parse_url($url, PHP_URL_HOST)); if ($host === '' || $host !== $site_host) continue; $post_id = url_to_postid($url); if ($post_id && in_array(get_post_type($post_id), ['page', 'post'], true)) { return absint($post_id); } } return 0; } public static function create_menu_from_items($data) { $menu_name = sanitize_text_field($data['menu_name'] ?? __('AI Webmaster Studio — main menu', 'ai-webmaster-studio')); $menu = wp_get_nav_menu_object($menu_name); $menu_id = $menu ? intval($menu->term_id) : wp_create_nav_menu($menu_name); if (is_wp_error($menu_id)) return $menu_id; $created_pages = []; $created_items = []; foreach ((array) $data['items'] as $item) { $parent_id = self::add_menu_item($menu_id, $item, 0, $created_pages, $created_items); foreach ((array) ($item['children'] ?? []) as $child) { self::add_menu_item($menu_id, $child, $parent_id, $created_pages, $created_items); } } self::assign_menu($menu_id); return [ 'applied' => true, 'note' => sanitize_textarea_field($data['note'] ?? __('The menu was updated.', 'ai-webmaster-studio')), 'menu_id' => $menu_id, 'created_pages' => $created_pages, 'created_items' => $created_items, 'menu_link' => admin_url('nav-menus.php?action=edit&menu=' . intval($menu_id)), ]; } public static function add_menu_item($menu_id, $item, $parent, &$created_pages, &$created_items) { $title = sanitize_text_field($item['title'] ?? __('Menu item', 'ai-webmaster-studio')); $slug = sanitize_title($item['slug'] ?? $title); $page = get_page_by_path($slug, OBJECT, 'page'); if ($slug === 'ai-directory-map' && class_exists('AIWEST_Directory_Map')) { $map_page = AIWEST_Directory_Map::resolve_map_page(); if (!$map_page) { $map_page_id = AIWEST_Directory_Map::ensure_map_page(false); if (!is_wp_error($map_page_id)) $map_page = get_post((int) $map_page_id); } if ($map_page instanceof WP_Post) $page = $map_page; } if (!$page) { $placeholder = '
' . esc_html(__('Page created by AI Webmaster Studio as a menu item. Its content requires administrator review and completion.', 'ai-webmaster-studio')) . '
'; $pid = wp_insert_post([ 'post_title' => $title, 'post_name' => $slug, 'post_status' => 'draft', 'post_type' => 'page', 'post_content' => $placeholder, 'post_author' => class_exists('AIWEST_Technical_Operator') ? AIWEST_Technical_Operator::post_author_id(get_current_user_id()) : (get_current_user_id() ?: 1), ], true); if (is_wp_error($pid)) return 0; update_post_meta($pid, '_aiwest_generated', 'yes'); if (class_exists('AIWEST_Technical_Operator')) { AIWEST_Technical_Operator::annotate_post($pid, 'create_menu_page', AIWEST_Technical_Operator::explain_decision('create_page', 'content_page_create', ['post_type'=>'page','post_status'=>'draft'])); } $created_pages[] = intval($pid); } else $pid = intval($page->ID); $item_id = wp_update_nav_menu_item($menu_id, 0, ['menu-item-title'=>$title,'menu-item-object'=>'page','menu-item-object-id'=>$pid,'menu-item-type'=>'post_type','menu-item-status'=>'publish','menu-item-parent-id'=>intval($parent)]); if (!is_wp_error($item_id)) $created_items[] = intval($item_id); return is_wp_error($item_id) ? 0 : intval($item_id); } public static function assign_menu($menu_id) { $locations = get_theme_mod('nav_menu_locations', []); $registered = get_registered_nav_menus(); $preferred=''; foreach (['primary','menu-1','main','primary-menu','header-menu'] as $key) if(isset($registered[$key])) { $preferred=$key; break; } if (!$preferred && $registered) { $keys=array_keys($registered); $preferred=$keys[0]; } if ($preferred) { $locations[$preferred]=intval($menu_id); set_theme_mod('nav_menu_locations',$locations); } update_option('aiwest_site_menu_id', intval($menu_id)); update_option('aiwest_site_menu_location', sanitize_key($preferred)); } public static function decode_json($result) { $clean = trim((string)$result); $clean = preg_replace('/^```json\s*/i','',$clean); $clean=preg_replace('/^```\s*/','',$clean); $clean=preg_replace('/\s*```$/','',$clean); $data=json_decode($clean,true); if(!is_array($data)){ $first=strpos($clean,'{'); $last=strrpos($clean,'}'); if($first!==false&&$last!==false&&$last>$first) $data=json_decode(substr($clean,$first,$last-$first+1),true); } return $data; } }