. Give the wizard a real one. */ public function filter_admin_title($admin_title, $title) { if (sanitize_key(wp_unslash($_GET['page'] ?? '')) === 'allaccessible-wizard') { /* translators: 1: page title, 2: site name */ return sprintf(__('%1$s ‹ %2$s — WordPress', 'allaccessible'), __('AllAccessible Setup', 'allaccessible'), get_bloginfo('name')); } return $admin_title; } /** * Enqueue CSS and JS for wizard page */ public function enqueue_assets($hook) { // Check if we're on the wizard page if (sanitize_key(wp_unslash($_GET['page'] ?? '')) !== 'allaccessible-wizard') { return; } // Legacy Tailwind utility stylesheet (still ships with the build) wp_enqueue_style( 'allaccessible-admin', AACB_CSS . 'admin.css', array(), AACB_VERSION ); // Admin v2 design system — single source of truth for the redesign wp_enqueue_style( 'aacx-v2-admin', AACB_CSS . 'admin-v2.css', array(), aacb_asset_ver('admin-v2.css') ); // Hide WordPress admin notices on the wizard page for a clean experience $custom_css = " .notice, .updated, .error, .update-nag, div.notice, div.updated, div.error, div.update-nag { display: none !important; } /* Soften the wp-admin chrome around the wizard */ #wpcontent { padding-left: 0 !important; } .aacx-v2-wizard-shell { min-height: calc(100vh - 32px); background: var(--aacx-bg, #f8fafc); } "; wp_add_inline_style('aacx-v2-admin', $custom_css); } /** * Render the wizard UI */ public function render_wizard() { // Remove all admin notices on wizard page for clean experience remove_all_actions('admin_notices'); remove_all_actions('all_admin_notices'); $site_url = get_bloginfo('wpurl'); $admin_email = get_bloginfo('admin_email'); // Step labels for the stepper: a single "Get started" step // (email + plan picker + Continue on one screen), then First scan. $steps = array( 1 => __('Get started', 'allaccessible'), 2 => __('First scan', 'allaccessible'), 3 => __('Accessibility statement', 'allaccessible'), ); /* translators: 1: current step number, 2: total steps */ $eyebrow = __('Step %1$d of %2$d', 'allaccessible'); ?>

about-us 87 /100
✓ ⚠

<button>🛒</button>
✦ <button aria-label="Add to cart">🛒</button>

✦ ""

' . esc_html__('Terms & Conditions', 'allaccessible') . '', '' . esc_html__('Privacy Policy', 'allaccessible') . '' ); ?>

5yrs

5.0★

23

__('Permission denied', 'allaccessible'))); } update_option('aacb_wizard_completed', true); // Wizard finish if (class_exists('AllAccessible_PostLinkBackfill')) { AllAccessible_PostLinkBackfill::on_activate(); } wp_send_json_success(); } /** * AJAX handler for skipping wizard */ public function ajax_skip_wizard() { check_ajax_referer('aacb_wizard_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(); } update_option('aacb_wizard_completed', true); // Wizard finish if (class_exists('AllAccessible_PostLinkBackfill')) { AllAccessible_PostLinkBackfill::on_activate(); } wp_send_json_success(); } /** * AJAX relay: account creation / site linking. * * The browser posts same-origin to admin-ajax and PHP relays to the * AllAccessible API server-to-server. The old direct cross-origin * call from wp-admin was silently killed by ad blockers, security * plugins, and CORS-mangling proxies on some hosts. */ public function ajax_add_site() { check_ajax_referer('aacb_wizard_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Permission denied', 'allaccessible')), 403); } $email = sanitize_email(wp_unslash($_POST['email'] ?? '')); $tier = sanitize_key(wp_unslash($_POST['tier'] ?? 'trial')); if (!is_email($email)) { wp_send_json_error(array('message' => __('Please enter a valid email address.', 'allaccessible'))); } $response = wp_remote_post('https://app.allaccessible.org/api/add-site', array( 'timeout' => 20, 'headers' => array( 'Content-Type' => 'application/json', 'Accept' => 'application/json', ), 'body' => wp_json_encode(array( 'email' => $email, // MUST be get_site_url() (== get_bloginfo('wpurl'), what the // wizard posted before this handler existed, and what // ApiClient::fetch_plugin_secret() looks the site up with). // Registering under home_url() breaks every install where Site // Address differs from WordPress Address (WP in its own // directory, www/non-www split): the site provisions under one // URL, /secret is queried for the other, and every signed // feature silently returns empty forever. 'url' => get_site_url(), 'tier' => $tier, 'source' => 'wordpress-v2-unified', )), )); if (is_wp_error($response)) { wp_send_json_error(array('message' => __('We could not reach AllAccessible. Please try again.', 'allaccessible'))); } $body = (string) wp_remote_retrieve_body($response); $data = json_decode($body, true); $account_id = ''; $action = 'created'; if (is_array($data)) { if (!empty($data['error'])) { wp_send_json_error(array('message' => sanitize_text_field((string) $data['error']))); } $account_id = (string) ($data['accountID'] ?? $data['account'] ?? $data['id'] ?? ''); $action = (string) ($data['action'] ?? (!empty($data['created']) ? 'created' : 'linked-existing-account')); } elseif (strlen(trim($body, "\" \t\r\n")) > 4) { // Legacy bare-string accountID response. $account_id = trim($body, "\" \t\r\n"); } if ($account_id === '') { wp_send_json_error(array('message' => __('We received an unexpected response. Please try again.', 'allaccessible'))); } update_option('aacb_accountID', sanitize_text_field($account_id)); wp_send_json_success(array( 'accountID' => $account_id, 'action' => $action, )); } /** * AJAX relay: email/site precheck (create vs link vs reconnect UX). */ public function ajax_precheck() { check_ajax_referer('aacb_wizard_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(array(), 403); } $email = sanitize_email(wp_unslash($_POST['email'] ?? '')); if (!is_email($email)) { wp_send_json_error(); } $response = wp_remote_post('https://app.allaccessible.org/api/check-site-account', array( 'timeout' => 5, 'headers' => array('Content-Type' => 'application/json'), // get_site_url() to match the add-site payload above and the // secret lookup; home_url() would make returning customers on // split-URL installs look like brand-new accounts. 'body' => wp_json_encode(array('url' => get_site_url(), 'email' => $email)), )); if (is_wp_error($response)) { wp_send_json_error(); } $data = json_decode((string) wp_remote_retrieve_body($response), true); if (!is_array($data)) { wp_send_json_error(); } wp_send_json_success(array( 'site_exists' => !empty($data['site_exists']), 'user_matches' => !empty($data['user_matches']), 'user_exists' => !empty($data['user_exists']), 'account_id' => sanitize_text_field((string) ($data['account_id'] ?? '')), 'error' => !empty($data['error']), )); } } // Initialize onboarding wizard after WordPress is fully loaded add_action('plugins_loaded', function() { AllAccessible_OnboardingWizard::get_instance(); });