array('title' => 'Welcome to AI Content Plan Bridge', 'description' => 'Generate WordPress API credentials'), 1 => array('title' => 'Link to AI Content Plan', 'description' => 'Enter your linking code'), 2 => array('title' => 'Choose Capabilities', 'description' => 'Select features to enable'), 3 => array('title' => 'Publishing Defaults', 'description' => 'Configure publishing settings'), 4 => array('title' => 'Content Sharing', 'description' => 'Configure content sharing'), 5 => array('title' => 'Setup Complete!', 'description' => 'Your AI Content Plan Bridge is ready') ); public function __construct(AICP_API $api, AICP_Settings $settings) { $this->api = $api; $this->settings = $settings; // AJAX actions (match names used in wizard step PHP views) add_action('wp_ajax_aicp_generate_credentials', array($this, 'ajax_generate_credentials')); add_action('wp_ajax_aicp_register_with_blogai', array($this, 'ajax_register_with_blogai')); add_action('wp_ajax_aicp_configure_output_channel', array($this, 'ajax_configure_output_channel')); add_action('wp_ajax_aicp_configure_input_channel', array($this, 'ajax_configure_input_channel')); add_action('wp_ajax_aicp_test_connection', array($this, 'ajax_test_connection')); add_action('wp_ajax_aicp_save_capabilities', array($this, 'ajax_save_capabilities')); } public function get_current_step() { if (!$this->settings->has_consumer_credentials()) return 0; if (!$this->settings->is_connected()) return 1; if (!get_option('aicp_capabilities_chosen', false)) return 2; $capabilities = get_option('aicp_chosen_capabilities', array('output' => false, 'input' => false)); if ($capabilities['output'] && !get_option('aicp_output_channel_configured', false)) return 3; if ($capabilities['input'] && !get_option('aicp_input_channel_configured', false)) return 4; if (!get_option('aicp_wizard_success_shown', false)) return 5; if ($this->settings->is_setup_complete()) return -1; return 5; } public function should_show_wizard() { $step = $this->get_current_step(); return $step >= 0; } public function get_step_title($step) { return isset($this->steps[$step]) ? $this->steps[$step]['title'] : ''; } public function get_step_description($step) { return isset($this->steps[$step]) ? $this->steps[$step]['description'] : ''; } public function get_blogai_api_url() { $api_url = $this->settings->get_api_url(); if (!empty($api_url)) return $api_url; return 'https://api.aicontentplan.com'; } public function ajax_generate_credentials() { check_ajax_referer('aicp_wizard_nonce', 'nonce'); if (!current_user_can('manage_aicp_settings')) { wp_send_json_error(array('message' => __('Permission denied.', 'ai-content-plan'))); } $credentials = $this->settings->generate_consumer_credentials(); if (is_wp_error($credentials)) { wp_send_json_error(array('message' => $credentials->get_error_message())); } wp_send_json_success(array( 'message' => __('Consumer credentials generated successfully.', 'ai-content-plan'), 'credentials' => $credentials, 'next_step' => 1 )); } public function ajax_register_with_blogai() { check_ajax_referer('aicp_wizard_nonce', 'nonce'); if (!current_user_can('manage_aicp_settings')) { wp_send_json_error(array('message' => __('Permission denied.', 'ai-content-plan'))); } $linking_code = isset($_POST['linking_code']) ? sanitize_text_field(wp_unslash($_POST['linking_code'])) : ''; if (empty($linking_code)) { wp_send_json_error(array('message' => __('Linking code is required.', 'ai-content-plan'))); } $consumer_key = $this->settings->get_consumer_key(); $consumer_secret = $this->settings->get_consumer_secret(); if (empty($consumer_key) || empty($consumer_secret)) { wp_send_json_error(array('message' => __('Consumer credentials not found.', 'ai-content-plan'))); } $response = $this->api->register_with_blogai(array( 'linking_code' => $linking_code, 'consumer_key' => $consumer_key, 'consumer_secret' => $consumer_secret, 'site_url' => get_site_url(), 'site_name' => get_bloginfo('name') )); if (is_wp_error($response)) { wp_send_json_error(array('message' => $response->get_error_message())); } $this->settings->set_api_key($response['api_key'] ?? ''); $this->settings->set_api_secret($response['api_secret'] ?? ''); $this->settings->set_connection_status('connected'); $this->settings->set_organization_name($response['organization_name'] ?? ''); wp_send_json_success(array( 'message' => __('Successfully linked to AI Content Plan!', 'ai-content-plan'), 'next_step' => 2 )); } public function ajax_save_capabilities() { try { check_ajax_referer('aicp_wizard_nonce', 'nonce'); } catch (Exception $e) { wp_send_json_error(array('message' => __('Security check failed. Please refresh the page.', 'ai-content-plan'))); } if (!current_user_can('manage_aicp_settings')) { wp_send_json_error(array('message' => __('Permission denied.', 'ai-content-plan'))); } // Support both JSON and form-encoded input if (isset($_POST['capabilities'])) { $capabilities = json_decode(stripslashes(sanitize_text_field(wp_unslash($_POST['capabilities']))), true); $has_output = !empty($capabilities['output']); $has_input = !empty($capabilities['input']); } else { $has_output = !empty($_POST['enable_output']); $has_input = !empty($_POST['enable_input']); } if (!$has_output && !$has_input) { wp_send_json_error(array('message' => __('Please select at least one capability.', 'ai-content-plan'))); } update_option('aicp_chosen_capabilities', array('output' => $has_output, 'input' => $has_input)); update_option('aicp_capabilities_chosen', true); $next_step = $has_output ? 3 : ($has_input ? 4 : 5); wp_send_json_success(array( 'message' => __('Capabilities saved successfully.', 'ai-content-plan'), 'next_step' => $next_step )); } public function ajax_configure_output_channel() { check_ajax_referer('aicp_wizard_nonce', 'nonce'); if (!current_user_can('manage_aicp_settings')) { wp_send_json_error(array('message' => __('Permission denied.', 'ai-content-plan'))); } $post_status = isset($_POST['post_status']) ? sanitize_text_field(wp_unslash($_POST['post_status'])) : 'draft'; $category = isset($_POST['default_category_id']) ? intval(wp_unslash($_POST['default_category_id'])) : 0; $category_name = isset($_POST['default_category_name']) ? sanitize_text_field(wp_unslash($_POST['default_category_name'])) : null; $author = isset($_POST['default_author_id']) ? intval(wp_unslash($_POST['default_author_id'])) : get_current_user_id(); $author_name = isset($_POST['default_author_name']) ? sanitize_text_field(wp_unslash($_POST['default_author_name'])) : null; $valid_statuses = array('draft', 'pending', 'publish', 'scheduled'); if (!in_array($post_status, $valid_statuses, true)) { $post_status = 'draft'; } // Resolve names from WordPress if not provided by the form if ($category > 0 && empty($category_name)) { $aicp_cat = get_category($category); if ($aicp_cat && !is_wp_error($aicp_cat)) { $category_name = $aicp_cat->name; } } if ($author > 0 && empty($author_name)) { $aicp_user = get_userdata($author); if ($aicp_user) { $author_name = $aicp_user->display_name; } } $this->settings->set_publishing_defaults(array( 'post_status' => $post_status, 'default_category_id' => $category, 'default_author_id' => $author )); $response = $this->api->configure_output_channel(array( 'post_status' => $post_status, 'category' => $category, 'category_name' => $category_name, 'author' => $author, 'author_name' => $author_name, )); if (is_wp_error($response)) { wp_send_json_error(array('message' => $response->get_error_message())); } update_option('aicp_output_channel_configured', true); // Check if we're in reconfiguration mode $is_reconfiguring = !empty($_POST['reconfiguring']); $capabilities = get_option('aicp_chosen_capabilities', array('output' => false, 'input' => false)); if ($is_reconfiguring && !$capabilities['input']) { // Reconfiguring and input doesn't need configuration - redirect to settings wp_send_json_success(array( 'message' => __('Output channel configured successfully.', 'ai-content-plan'), 'redirect_to_settings' => true )); } else { // Normal wizard flow or need to configure input channel next $next_step = $capabilities['input'] ? 4 : 5; wp_send_json_success(array( 'message' => __('Output channel configured successfully.', 'ai-content-plan'), 'next_step' => $next_step )); } } public function ajax_configure_input_channel() { check_ajax_referer('aicp_wizard_nonce', 'nonce'); if (!current_user_can('manage_aicp_settings')) { wp_send_json_error(array('message' => __('Permission denied.', 'ai-content-plan'))); } $content_types = isset($_POST['content_types']) ? json_decode(stripslashes(sanitize_text_field(wp_unslash($_POST['content_types']))), true) : array(); $auto_sync = !empty($_POST['auto_sync']); $sync_interval = isset($_POST['sync_interval']) ? intval(wp_unslash($_POST['sync_interval'])) : 60; if (!is_array($content_types)) { $content_types = array(); } $content_types = array_map('sanitize_text_field', $content_types); if ($sync_interval < 5) { $sync_interval = 5; } update_option('aicp_input_channel_defaults', array( 'content_types' => $content_types, 'auto_sync' => $auto_sync, 'sync_interval' => $sync_interval )); $response = $this->api->configure_input_channel(array( 'content_types' => $content_types, 'auto_sync' => $auto_sync, 'sync_interval' => $sync_interval )); if (is_wp_error($response)) { wp_send_json_error(array('message' => $response->get_error_message())); } update_option('aicp_input_channel_configured', true); // Check if we're in reconfiguration mode $is_reconfiguring = !empty($_POST['reconfiguring']); if ($is_reconfiguring) { // Reconfiguring - redirect to settings wp_send_json_success(array( 'message' => __('Input channel configured successfully.', 'ai-content-plan'), 'redirect_to_settings' => true )); } else { // Normal wizard flow - continue to completion step wp_send_json_success(array( 'message' => __('Input channel configured successfully.', 'ai-content-plan'), 'next_step' => 5 )); } } public function ajax_test_connection() { check_ajax_referer('aicp_wizard_nonce', 'nonce'); if (!current_user_can('manage_aicp_settings')) { wp_send_json_error(array('message' => __('Permission denied.', 'ai-content-plan'))); } $response = $this->api->test_connection(); if (is_wp_error($response)) { wp_send_json_error(array( 'message' => __('Connection test failed.', 'ai-content-plan'), 'details' => $response->get_error_message() )); } update_option('aicp_wizard_success_shown', true); update_option('aicp_setup_complete', true); wp_send_json_success(array( 'message' => __('Connection test successful!', 'ai-content-plan'), 'details' => $response )); } public function render_step($step) { $step = intval($step); if ($step < 0 || $step > 5) { return; } $aicp_template_path = plugin_dir_path(__FILE__) . "../admin/views/wizard-step-{$step}.php"; if (!file_exists($aicp_template_path)) { // Fallback to views dir relative to includes $aicp_template_path = plugin_dir_path(__FILE__) . "../views/wizard-step-{$step}.php"; } if (file_exists($aicp_template_path)) { include $aicp_template_path; } } /** * Check if user needs migration from legacy ak_/sk_ credentials * * @return bool */ public function needs_migration() { return $this->settings->is_legacy_auth() && !$this->settings->has_consumer_credentials(); } /** * Show migration admin notice for legacy users */ public function maybe_show_migration_notice() { if (!$this->needs_migration()) { return; } if (get_option('aicp_migration_dismissed', false)) { return; } add_action('admin_notices', function() { $aicp_wizard_url = admin_url('admin.php?page=aicp-bridge-wizard&step=0&migrate=1'); $aicp_dismiss_url = wp_nonce_url(admin_url('admin.php?page=aicp-bridge-settings&dismiss_migration=1'), 'aicp_dismiss_migration'); ?>