post_type) || !in_array($screen->post_type, ['post', 'page'], true)) {
return;
}
$post_id = absint(AIWEST_Security::get_text('post'));
wp_enqueue_style('aiwest-editor-panel', AIWEST_URL . 'assets/admin.css', [], AIWEST_VERSION);
wp_enqueue_script(
'aiwest-editor-panel',
AIWEST_URL . 'assets/editor-panel.js',
['wp-plugins', 'wp-edit-post', 'wp-element', 'wp-components', 'wp-data', 'wp-blocks', 'wp-block-editor'],
AIWEST_VERSION,
true
);
wp_localize_script('aiwest-editor-panel', 'AIWEST_EDITOR_PANEL', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'adminPostUrl' => admin_url('admin-post.php'),
'postId' => $post_id,
'nonce' => $post_id ? wp_create_nonce('aiwest_editor_action_' . $post_id) : '',
'title' => 'AI Web',
'description' => __('AI Web tools for this page or post.', 'ai-webmaster-studio'),
'saveFirst' => __('Save the draft or publish the post/page first, then run the AI Web action.', 'ai-webmaster-studio'),
'buttonLabel' => __('Run AI Web action', 'ai-webmaster-studio'),
'promptLabel' => __('Additional prompt / instruction', 'ai-webmaster-studio'),
'promptPlaceholder' => __('Example: Improve the layout with cards and sections while preserving all text, headings and links...', 'ai-webmaster-studio'),
'actionLabel' => __('Action', 'ai-webmaster-studio'),
'workingMessage' => __('AI Web is working on this content. This can take from several seconds to a few minutes. Do not close this tab.', 'ai-webmaster-studio'),
'unknownError' => __('Unknown AI Web error.', 'ai-webmaster-studio'),
'successSuffix' => __('The saved changes have been refreshed in the block editor. Review the result before making any further edits.', 'ai-webmaster-studio'),
'connectionErrorPrefix' => __('AI Web connection error:', 'ai-webmaster-studio'),
'fallbackDone' => __('AI Web completed the action.', 'ai-webmaster-studio'),
'workingButton' => __('AI Web is working...', 'ai-webmaster-studio'),
'finalHint' => __('Save any pending edits before running AI Web. When the task finishes, the saved result will appear as WordPress blocks.', 'ai-webmaster-studio'),
'savePendingFirst' => __('Save or publish your pending editor changes before running AI Web. This prevents unsaved work from being overwritten.', 'ai-webmaster-studio'),
'rewriteConfirm' => __('Rewrite content mode may replace the existing text. Are you sure you want to continue?', 'ai-webmaster-studio'),
'visualHint' => __('Improve visual layout only. Existing text, headings and links will be preserved.', 'ai-webmaster-studio'),
'actions' => self::actions_for_js(),
]);
}
private static function actions_for_js() {
return [
['value' => 'visual', 'label' => __('Preserve content and improve layout', 'ai-webmaster-studio')],
['value' => 'improve', 'label' => __('Expand content', 'ai-webmaster-studio')],
['value' => 'seo', 'label' => __('Add SEO', 'ai-webmaster-studio')],
['value' => 'faq', 'label' => __('Add FAQ', 'ai-webmaster-studio')],
['value' => 'cta', 'label' => __('Add CTA', 'ai-webmaster-studio')],
['value' => 'image', 'label' => __('Add featured image', 'ai-webmaster-studio')],
['value' => 'custom', 'label' => __('Custom instruction', 'ai-webmaster-studio')],
['value' => 'rewrite', 'label' => __('Rewrite content', 'ai-webmaster-studio')],
];
}
public static function render($post) {
if (!$post || !current_user_can('edit_post', $post->ID)) return;
$url = admin_url('admin-post.php');
$heading_report = class_exists('AIWEST_Page_Title_Heading_Normalizer')
? get_post_meta($post->ID, AIWEST_Page_Title_Heading_Normalizer::META_REPORT, true)
: [];
echo '
';
echo '
AI AI Web ' . esc_html(__('can improve this content without leaving the editor.', 'ai-webmaster-studio')) . '
';
if (is_array($heading_report) && !empty($heading_report['message'])) {
echo '
' . esc_html(__('Heading check:', 'ai-webmaster-studio')) . ' ' . esc_html((string)$heading_report['message']) . '
';
}
echo '
';
}
private static function normalize_summary($summary, $mode = '') {
$summary = sanitize_textarea_field((string)$summary);
if ($summary === '') {
return __('AI Web completed the action.', 'ai-webmaster-studio');
}
if ((!class_exists('AIWEST_Product') || AIWEST_Product::is_en())) {
$legacy = [
'Przebudowano stronę kontaktową jako wizualną stronę docelową: dodano sekcje hero, karty kontaktu, przewodnik krok po kroku, FAQ, CTA, polecane zasoby i czytelne bloki. Zwiększono przejrzystość i atrakcyjność wizualną.' => 'The contact page was rebuilt as a visual landing page with a hero section, contact cards, step-by-step guidance, FAQ, CTA, featured resources and readable content blocks. Clarity and visual appeal were improved.',
'Treść została zaktualizowana.' => 'The content has been updated.',
'AI Web wykonał akcję.' => 'AI Web completed the action.',
'Grafika wyróżniająca została wygenerowana i przypisana do tej treści.' => 'The featured image has been generated and assigned to this content.',
];
foreach ($legacy as $pl => $en) {
if (stripos($summary, $pl) !== false) {
return $en;
}
}
if (preg_match('/\b(została|został|dodano|przebudowano|ulepszono|rozbudowano|treść|stronę|sekcję|sekcje|zmiany)\b/iu', $summary)) {
return self::fallback_summary_for_mode($mode);
}
}
return $summary;
}
private static function fallback_summary_for_mode($mode) {
$mode = sanitize_key($mode);
$map = [
'visual' => __('The layout has been improved while preserving existing content.', 'ai-webmaster-studio'),
'improve' => __('The content has been expanded.', 'ai-webmaster-studio'),
'seo' => __('The content has been improved for SEO.', 'ai-webmaster-studio'),
'faq' => __('The FAQ section has been added or improved.', 'ai-webmaster-studio'),
'cta' => __('The CTA section has been added or improved.', 'ai-webmaster-studio'),
'image' => __('The featured image has been generated and assigned to this content.', 'ai-webmaster-studio'),
'custom' => __('The custom AI Web instruction has been completed.', 'ai-webmaster-studio'),
'rewrite' => __('The content has been rewritten at the administrator’s explicit request.', 'ai-webmaster-studio'),
];
return $map[$mode] ?? __('AI Web completed the action.', 'ai-webmaster-studio');
}
private static function run_ai_action($post_id, $mode, $extra) {
$mode = sanitize_key($mode ?: 'improve');
$extra = sanitize_textarea_field($extra ?: '');
if ($mode === 'image') {
if (!class_exists('AIWEST_Image_Generator')) {
return new WP_Error('aiwest_missing_image_generator', __('The AI image module is missing.', 'ai-webmaster-studio'));
}
$image_result = AIWEST_Image_Generator::generate_for_post($post_id);
if (is_wp_error($image_result)) return $image_result;
return [
'post_id' => $post_id,
'summary' => self::fallback_summary_for_mode('image'),
'image' => true,
];
}
if (!class_exists('AIWEST_Content_Upgrader')) {
return new WP_Error('aiwest_missing_content_upgrader', __('The content development module is missing.', 'ai-webmaster-studio'));
}
return AIWEST_Content_Upgrader::improve_post($post_id, $mode, $extra);
}
private static function response_payload($post_id, $result) {
$post = get_post($post_id);
if (!$post) {
return new WP_Error('aiwest_missing_post_after_update', __('Could not read the content after the AI action.', 'ai-webmaster-studio'));
}
$edit_link = get_edit_post_link($post_id, 'raw');
$preview_link = get_preview_post_link($post);
$view_link = get_permalink($post_id);
$mode = is_array($result) && !empty($result['mode']) ? sanitize_key($result['mode']) : '';
$summary = is_array($result) && !empty($result['summary']) ? self::normalize_summary($result['summary'], $mode) : self::fallback_summary_for_mode($mode);
return [
'post_id' => intval($post_id),
'title' => get_the_title($post_id),
'excerpt' => $post->post_excerpt,
'content' => $post->post_content,
'summary' => $summary,
'message' => $summary,
'links' => [
'edit' => $edit_link,
'preview' => $preview_link,
'view' => $view_link,
],
];
}
public static function handle_ajax_action() {
$post_id = AIWEST_Security::post_int('post_id');
if (!$post_id || !current_user_can('edit_post', $post_id)) {
wp_send_json_error(['message' => __('Missing permission or content ID.', 'ai-webmaster-studio')], 403);
}
if (!check_ajax_referer('aiwest_editor_action_'.$post_id, '_wpnonce', false)) {
wp_send_json_error(['message' => __('Invalid security token. Refresh the editor and try again.', 'ai-webmaster-studio')], 403);
}
$mode = AIWEST_Security::post_key('mode', 'improve');
$extra = AIWEST_Security::post_textarea('extra_prompt');
try {
$result = self::run_ai_action($post_id, $mode, $extra);
if (is_wp_error($result)) {
if (class_exists('AIWEST_Logger')) AIWEST_Logger::warning('AI Web editor AJAX action failed.', ['post_id'=>$post_id,'mode'=>$mode,'error'=>$result->get_error_message()]);
wp_send_json_error(['message' => $result->get_error_message()], 200);
}
if (is_array($result)) $result['mode'] = $mode;
$payload = self::response_payload($post_id, $result);
if (is_wp_error($payload)) {
wp_send_json_error(['message' => $payload->get_error_message()], 200);
}
wp_send_json_success($payload);
} catch (Throwable $e) {
if (class_exists('AIWEST_Logger')) AIWEST_Logger::error('AI Web editor AJAX critical error.', ['post_id'=>$post_id,'mode'=>$mode,'error'=>$e->getMessage()]);
wp_send_json_error(['message' => __('AI Web error:', 'ai-webmaster-studio') . ' ' . $e->getMessage()], 200);
}
}
public static function handle_action() {
$post_id = AIWEST_Security::post_int('post_id');
if (!$post_id || !current_user_can('edit_post', $post_id)) wp_die(esc_html(__('Missing permission.', 'ai-webmaster-studio')));
check_admin_referer('aiwest_editor_action_'.$post_id);
$mode = AIWEST_Security::post_key('mode', 'improve');
$extra = AIWEST_Security::post_textarea('extra_prompt');
try {
$result = self::run_ai_action($post_id, $mode, $extra);
if (is_wp_error($result)) {
if (class_exists('AIWEST_Logger')) AIWEST_Logger::warning('AI Web editor action failed.', ['post_id'=>$post_id,'mode'=>$mode,'error'=>$result->get_error_message()]);
$args = ['aiwest_editor_error'=>rawurlencode($result->get_error_message())];
} else {
$summary = is_array($result) && !empty($result['summary']) ? self::normalize_summary($result['summary'], $mode) : self::fallback_summary_for_mode($mode);
$args = ['aiwest_editor_success'=>rawurlencode($summary)];
}
} catch (Throwable $e) {
if (class_exists('AIWEST_Logger')) AIWEST_Logger::error('AI Web editor critical action error.', ['post_id'=>$post_id,'mode'=>$mode,'error'=>$e->getMessage()]);
$args = ['aiwest_editor_error'=>rawurlencode($e->getMessage())];
}
wp_safe_redirect(add_query_arg($args, get_edit_post_link($post_id, '')));
exit;
}
public static function notice() {
$success = AIWEST_Security::get_text('aiwest_editor_success');
$error = AIWEST_Security::get_text('aiwest_editor_error');
if ($success !== '') {
echo 'AI Web: '.esc_html(rawurldecode($success)).' ' . esc_html(__('The content has been saved. Refresh the editor if you do not see the changes.', 'ai-webmaster-studio')) . '
';
}
if ($error !== '') {
echo '' . esc_html(__('AI Web — error:', 'ai-webmaster-studio')) . ' '.esc_html(rawurldecode($error)).'
';
}
}
}
AIWEST_Editor_Panel::init();