admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ability_admin'),
'tier' => function_exists('ability_get_tier') ? ability_get_tier() : 'basic',
'isPro' => function_exists('ability_is_pro') ? ability_is_pro() : false,
'i18n' => [
'saveStepFailed' => __('Failed to save step', 'ability'),
'unknownError' => __('Unknown error', 'ability'),
'completeSetup' => __('Completing setup...', 'ability'),
'completeSetupFailed' => __('Failed to complete setup.', 'ability'),
'skipConfirm' => __('Are you sure you want to skip the setup wizard? Default settings will be used.', 'ability'),
'skippingWizard' => __('Skipping wizard...', 'ability'),
'skipWizardFailed' => __('Failed to skip wizard.', 'ability'),
'working' => __('Working...', 'ability'),
'updating' => __('Updating...', 'ability'),
'settingsUpdated' => __('Settings Updated!', 'ability'),
'defaultsApplied' => __('Defaults applied.', 'ability'),
],
]);
}
public function maybe_redirect_to_wizard() {
if (is_network_admin() || (defined('DOING_AJAX') && DOING_AJAX)) return;
if (get_transient('ability_activation_redirect') && current_user_can('manage_options')) {
delete_transient('ability_activation_redirect');
if (get_option('ability_wizard_done', 'no') === 'no') {
wp_safe_redirect(admin_url('admin.php?page=ability-wizard'));
exit;
}
}
}
/**
* Adjust top-level wizard menu icon HTML to match requested markup.
*/
public function adjust_menu_icon_markup() {
?>
render_limited_wizard();
return;
}
$wizard_done = get_option('ability_wizard_done', 'no') === 'yes';
if ($wizard_done) {
$this->render_completed_prompt();
return;
}
// Load previously saved settings
$wizard_settings = get_option('ability_wizard_settings', []);
$is_pro = function_exists('ability_is_pro') ? ability_is_pro() : false;
$free_scan_limit = class_exists('ABILITY\Config') ? \ABILITY\Config::get_free_scan_limit() : 5;
?>
__('Insufficient permissions', 'ability')]);
}
if (!wp_verify_nonce(wp_unslash($_POST['nonce'] ?? ''), 'ability_admin')) {
wp_send_json_error(['message' => __('Invalid nonce', 'ability')]);
}
$is_pro = function_exists('ability_is_pro') ? ability_is_pro() : false;
$free_scan_limit = class_exists('ABILITY\Config') ? \ABILITY\Config::get_free_scan_limit() : 5;
$requested_scan_limit = absint(wp_unslash($_POST['max_files_per_scan'] ?? $free_scan_limit));
$settings = [
'scan_enabled' => !empty($_POST['scan_enabled']),
'scan_schedule' => sanitize_text_field(wp_unslash($_POST['scan_schedule'] ?? 'daily')),
// Align with Config::get_defaults() and enforce edition limits server-side.
'max_files_per_scan' => $is_pro ? max(1, min(999, $requested_scan_limit ?: 999)) : max(1, min($free_scan_limit, $requested_scan_limit ?: $free_scan_limit)),
'auto_fix_enabled' => $is_pro && !empty($_POST['auto_fix_enabled']),
'widget_enabled' => !empty($_POST['widget_enabled']),
'widget_position' => sanitize_text_field(wp_unslash($_POST['widget_position'] ?? 'bottom-right')),
'widget_style' => sanitize_text_field(wp_unslash($_POST['widget_style'] ?? 'modern')),
'compliance_level' => sanitize_text_field(wp_unslash($_POST['compliance_level'] ?? 'wcag_2_1_aa')),
'generate_reports' => $is_pro && !empty($_POST['generate_reports']),
];
update_option('ability_wizard_settings', $settings, false);
update_option('ability_wizard_done', 'yes');
// Update the authoritative runtime settings model. Keep the wizard's
// generate_reports key for wizard-state compatibility while mapping it to
// the canonical compliance_reports option used by the runtime/admin UI.
if (class_exists('ABILITY\Config')) {
$runtime_settings = $settings;
$runtime_settings['compliance_reports'] = !empty($settings['generate_reports']);
unset($runtime_settings['generate_reports']);
\ABILITY\Config::update_settings($runtime_settings);
}
wp_send_json_success([
'message' => __('Settings saved successfully.', 'ability'),
'redirect' => admin_url('admin.php?page=ability-dashboard'),
]);
}
public function ajax_skip_wizard() {
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => __('Insufficient permissions', 'ability')]);
}
if (!wp_verify_nonce(wp_unslash($_POST['nonce'] ?? ''), 'ability_admin')) {
wp_send_json_error(['message' => __('Invalid nonce', 'ability')]);
}
update_option('ability_wizard_done', 'yes');
wp_send_json_success([
'message' => __('Wizard skipped. Using default settings.', 'ability'),
'redirect' => admin_url('admin.php?page=ability-dashboard'),
]);
}
public function ajax_save_wizard() {
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => __('Insufficient permissions', 'ability')]);
}
if (!wp_verify_nonce(wp_unslash($_POST['nonce'] ?? ''), 'ability_admin')) {
wp_send_json_error(['message' => __('Invalid nonce', 'ability')]);
}
$step = intval(wp_unslash($_POST['step'] ?? 0));
$raw = wp_unslash($_POST['data'] ?? '{}');
$data = is_string($raw) ? json_decode($raw, true) : (array)$raw;
if (!is_array($data)) $data = [];
if ($step < 1 || $step > 4) {
wp_send_json_error(['message' => __('Invalid step number', 'ability')]);
}
$wizard_settings = get_option('ability_wizard_settings', []);
switch ($step) {
case 1:
if (array_key_exists('scan_enabled', $data)) {
$wizard_settings['scan_enabled'] = !empty($data['scan_enabled']);
}
if (array_key_exists('scan_schedule', $data)) {
$wizard_settings['scan_schedule'] = sanitize_text_field($data['scan_schedule']);
}
if (array_key_exists('max_files_per_scan', $data)) {
$is_pro = function_exists('ability_is_pro') ? ability_is_pro() : false;
$free_scan_limit = class_exists('ABILITY\Config') ? \ABILITY\Config::get_free_scan_limit() : 5;
$requested_scan_limit = absint($data['max_files_per_scan']);
$wizard_settings['max_files_per_scan'] = $is_pro
? max(1, min(999, $requested_scan_limit ?: 999))
: max(1, min($free_scan_limit, $requested_scan_limit ?: $free_scan_limit));
}
break;
case 2:
if (array_key_exists('widget_enabled', $data)) {
$wizard_settings['widget_enabled'] = !empty($data['widget_enabled']);
}
if (array_key_exists('widget_position', $data)) {
$wizard_settings['widget_position'] = sanitize_text_field($data['widget_position']);
}
break;
case 3:
if (array_key_exists('compliance_level', $data)) {
$wizard_settings['compliance_level'] = sanitize_text_field($data['compliance_level']);
}
break;
}
update_option('ability_wizard_settings', $wizard_settings, false);
wp_send_json_success([
'message' => __('Step saved successfully', 'ability'),
'step' => $step,
]);
}
public function ajax_reset_wizard() {
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => __('Insufficient permissions', 'ability')]);
}
if (!wp_verify_nonce(wp_unslash($_POST['nonce'] ?? ''), 'ability_admin')) {
wp_send_json_error(['message' => __('Invalid nonce', 'ability')]);
}
update_option('ability_wizard_done', 'no');
delete_option('ability_wizard_settings');
wp_send_json_success([
'message' => __('Wizard reset successfully. Page will refresh.', 'ability'),
]);
}
public function ajax_apply_defaults() {
if (!current_user_can('manage_options')) {
wp_send_json_error(['message' => __('Insufficient permissions', 'ability')]);
}
if (!wp_verify_nonce(wp_unslash($_POST['nonce'] ?? ''), 'ability_admin')) {
wp_send_json_error(['message' => __('Invalid nonce', 'ability')]);
}
$defaults = [
'scan_enabled' => true,
'scan_schedule' => 'daily',
'max_files_per_scan' => class_exists('ABILITY\Config') ? \ABILITY\Config::get_scan_limit() : 5,
'auto_fix_enabled' => false,
'widget_enabled' => true,
'widget_position' => 'bottom-right',
'widget_style' => 'modern',
'compliance_level' => 'wcag_2_1_aa',
'generate_reports' => false,
];
update_option('ability_wizard_settings', $defaults, false);
update_option('ability_wizard_done', 'yes');
if (class_exists('ABILITY\Config')) {
$runtime_defaults = $defaults;
$runtime_defaults['compliance_reports'] = false;
unset($runtime_defaults['generate_reports']);
\ABILITY\Config::update_settings($runtime_defaults);
}
wp_send_json_success([
'message' => __('Defaults applied successfully. Page will refresh.', 'ability'),
]);
}
}