[ 'high-contrast-toggle' => 1, 'line-spacing-toggle' => 1, 'focus-indicators-toggle' => 1, 'screen-reader-mode-toggle' => 1, 'voice-navigation-toggle' => 1, 'dyslexia-font-toggle' => 1, 'reduce-motion-toggle' => 1, 'adhd-mode-toggle' => 1, 'font-size-controls' => 1, ], 'default_states' => [ 'high-contrast-toggle' => 0, 'line-spacing-toggle' => 0, 'focus-indicators-toggle' => 0, 'screen-reader-mode-toggle' => 0, 'voice-navigation-toggle' => 0, 'dyslexia-font-toggle' => 0, 'reduce-motion-toggle' => 0, 'adhd-mode-toggle' => 0, ], 'skip_links_position' => 'body_open', 'hide_footer_skip_links' => 1, 'enable_structured_data' => 0, 'initial_font_scale' => '1.0', 'enable_legacy_toolbar' => 0, 'legacy_toolbar_position'=> 'bottom_right', 'legacy_features' => [ 'contrast' => 1, 'font_size' => 1, 'keyboard' => 1, 'aria_landmarks' => 1, 'line_spacing' => 1, 'focus_indicators' => 1, 'screen_reader_mode' => 0, 'voice_navigation' => 0, 'dyslexia_font' => 0, 'reduce_motion' => 0, ], 'presentation_mode' => 'classic', // Skip link target IDs 'skip_link_main_id' => 'main-content', 'skip_link_nav_id' => 'navigation', 'skip_link_footer_id' => 'footer', // Widget toggle button position (top_right by default, avoids CookieJar bottom-right) 'widget_position' => 'top_right', 'widget_position_mobile' => 'bottom_right', // Panel branding (Pro/Enterprise can disable for white-label) 'panel_show_branding' => 1, 'panel_brand_text' => '', ]; public function __construct() { add_action( 'admin_menu', [ $this, 'menu' ] ); add_action( 'admin_init', [ $this, 'register' ] ); add_action( 'wp_body_open', [ $this, 'maybe_render_skip_links_body' ], 5 ); } private function get_settings() { $raw = get_option( self::OPTION, [] ); return wp_parse_args( $raw, $this->defaults ); } public function menu() { add_options_page( __( 'Accessibility Toolkit (Advanced)', 'ability' ), __( 'Accessibility Toolkit (Advanced)', 'ability' ), 'manage_options', 'ability-accessibility-advanced', [ $this, 'render_page' ] ); } public function register() { register_setting('ability_a11y_group', self::OPTION, [ $this, 'sanitize' ]); add_settings_section( 'ability_a11y_main', __( 'Front-end Control Configuration', 'ability' ), function() { echo '
' . esc_html__( 'Configure widget controls, defaults, skip links, structured data, and optionally enable the legacy mini-toolbar.', 'ability' ) . '
'; }, 'ability-accessibility-advanced' ); add_settings_field('enable_legacy_toolbar', __( 'Enable Legacy Mini-Toolbar', 'ability' ), [ $this, 'field_enable_legacy_toolbar' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('legacy_toolbar_position', __( 'Legacy Toolbar Position', 'ability' ), [ $this, 'field_legacy_toolbar_position' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('legacy_features', __( 'Legacy Toolbar Features', 'ability' ), [ $this, 'field_legacy_features' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('show_controls', __( 'Show Controls (Advanced Widget)', 'ability' ), [ $this, 'field_show_controls' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('default_states', __( 'Default Enabled States', 'ability' ), [ $this, 'field_default_states' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('widget_position', __( 'Widget Toggle Position (Desktop)', 'ability' ), [ $this, 'field_widget_position' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('widget_position_mobile', __( 'Widget Toggle Position (Mobile)', 'ability' ), [ $this, 'field_widget_position_mobile' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('panel_show_branding', __( 'Panel Branding', 'ability' ), [ $this, 'field_panel_branding' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('skip_links_position', __( 'Skip Links Position', 'ability' ), [ $this, 'field_skip_links_position' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('skip_link_ids', __( 'Skip Link Target IDs', 'ability' ), [ $this, 'field_skip_link_ids' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('hide_footer_skip_links', __( 'Hide Footer Skip Links', 'ability' ), [ $this, 'field_hide_footer_skip_links' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('enable_structured_data', __( 'Enable Structured Data', 'ability' ), [ $this, 'field_enable_structured_data' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('initial_font_scale', __( 'Initial Font Scale', 'ability' ), [ $this, 'field_initial_font_scale' ], 'ability-accessibility-advanced', 'ability_a11y_main'); add_settings_field('presentation_mode', __( 'User Interface Style', 'ability' ), [ $this, 'field_presentation_mode' ], 'ability-accessibility-advanced', 'ability_a11y_main'); } public function sanitize($input) { $out = $this->defaults; if (isset($input['show_controls']) && is_array($input['show_controls'])) { foreach ($out['show_controls'] as $id => $val) { $out['show_controls'][$id] = empty($input['show_controls'][$id]) ? 0 : 1; } } if (isset($input['default_states']) && is_array($input['default_states'])) { foreach ($out['default_states'] as $id => $val) { $out['default_states'][$id] = empty($input['default_states'][$id]) ? 0 : 1; } } // Position (skip links + widget) $pos = isset($input['skip_links_position']) ? $input['skip_links_position'] : 'body_open'; $out['skip_links_position'] = in_array($pos, ['body_open','footer'], true) ? $pos : 'body_open'; $allowed_widget_pos = ['bottom_right','bottom_left','top_right','top_left']; $wpos = isset($input['widget_position']) ? $input['widget_position'] : 'top_right'; $out['widget_position'] = in_array($wpos, $allowed_widget_pos, true) ? $wpos : 'top_right'; $wmpos = isset($input['widget_position_mobile']) ? $input['widget_position_mobile'] : 'bottom_right'; $out['widget_position_mobile'] = in_array($wmpos, $allowed_widget_pos, true) ? $wmpos : 'bottom_right'; $out['panel_show_branding'] = empty($input['panel_show_branding']) ? 0 : 1; $out['panel_brand_text'] = isset($input['panel_brand_text']) ? sanitize_text_field($input['panel_brand_text']) : ''; $out['hide_footer_skip_links'] = empty($input['hide_footer_skip_links']) ? 0 : 1; $out['enable_structured_data'] = empty($input['enable_structured_data']) ? 0 : 1; $out['enable_legacy_toolbar'] = empty($input['enable_legacy_toolbar']) ? 0 : 1; $ltp = isset($input['legacy_toolbar_position']) ? $input['legacy_toolbar_position'] : 'bottom_right'; $allowed_pos = ['bottom_right','bottom_left','top_right','top_left']; $out['legacy_toolbar_position'] = in_array($ltp, $allowed_pos, true) ? $ltp : 'bottom_right'; if (isset($input['legacy_features']) && is_array($input['legacy_features'])) { foreach ($out['legacy_features'] as $key => $val) { $out['legacy_features'][$key] = empty($input['legacy_features'][$key]) ? 0 : 1; } } $presentation_mode = isset($input['presentation_mode']) ? sanitize_key($input['presentation_mode']) : 'classic'; $out['presentation_mode'] = in_array($presentation_mode, ['classic', 'modern'], true) ? $presentation_mode : 'classic'; // Skip link IDs $out['skip_link_main_id'] = sanitize_title_with_dashes($input['skip_link_main_id'] ?? 'main-content'); $out['skip_link_nav_id'] = sanitize_title_with_dashes($input['skip_link_nav_id'] ?? 'navigation'); $out['skip_link_footer_id'] = sanitize_title_with_dashes($input['skip_link_footer_id'] ?? 'footer'); $scale = isset($input['initial_font_scale']) ? trim($input['initial_font_scale']) : '1.0'; if (!is_numeric($scale)) $scale = '1.0'; $f = floatval($scale); $f = max(0.8, min(2.0, $f)); $out['initial_font_scale'] = (string) $f; return $out; } private function settings() { return $this->get_settings(); } public function field_enable_legacy_toolbar() { printf( '%4$s
', esc_attr(self::OPTION), checked($this->settings()['enable_legacy_toolbar'], 1, false), esc_html__('Use the legacy mini-toolbar instead of the advanced accessibility widget.', 'ability'), esc_html__('When enabled, the advanced dialog widget will not render.', 'ability') ); } public function field_legacy_toolbar_position() { $val = $this->settings()['legacy_toolbar_position']; $opts = [ 'bottom_right' => __( 'Bottom Right', 'ability' ), 'bottom_left' => __( 'Bottom Left', 'ability' ), 'top_right' => __( 'Top Right', 'ability' ), 'top_left' => __( 'Top Left', 'ability' ), ]; echo ''.esc_html__('Applies when legacy toolbar is enabled.', 'ability').'
'; } public function field_legacy_features() { $features = $this->settings()['legacy_features']; $labels = [ 'contrast' => __( 'High Contrast', 'ability' ), 'font_size' => __( 'Increase Font Size', 'ability' ), 'keyboard' => __( 'Keyboard Navigation', 'ability' ), 'aria_landmarks' => __( 'Show Landmarks', 'ability' ), 'line_spacing' => __( 'Increased Line Spacing', 'ability' ), 'focus_indicators' => __( 'Enhanced Focus Indicators', 'ability' ), 'screen_reader_mode' => __( 'Screen Reader Optimized Mode', 'ability' ), 'voice_navigation' => __( 'Voice Read-Out', 'ability' ), 'dyslexia_font' => __( 'Dyslexia-Friendly Font', 'ability' ), 'reduce_motion' => __( 'Reduce Motion', 'ability' ), ]; foreach ($features as $key => $on) { printf( ''.esc_html__('Affects only the advanced widget.', 'ability').'
'; } public function field_default_states() { $states = $this->settings()['default_states']; foreach ($states as $id => $on) { printf( ''.esc_html__('Applied on first visit when no stored preferences exist.', 'ability').'
'; } public function field_presentation_mode() { $val = $this->settings()['presentation_mode']; $field_id = esc_attr(self::OPTION . '_presentation_mode'); $opts = [ 'classic' => __( 'Original / Classic', 'ability' ), 'modern' => __( 'Modern Contrast', 'ability' ), ]; echo ''; echo ''; echo '' . esc_html__('Classic preserves the existing ABILITY presentation. Modern Contrast uses the updated high-contrast presentation while retaining the same accessibility controls and settings.', 'ability') . '
'; } public function field_widget_position() { $val = $this->settings()['widget_position']; $opts = [ 'top_right' => __( 'Top Right (Recommended)', 'ability' ), 'top_left' => __( 'Top Left', 'ability' ), 'bottom_right' => __( 'Bottom Right', 'ability' ), 'bottom_left' => __( 'Bottom Left', 'ability' ), ]; echo ''.esc_html__('Desktop position of the floating accessibility toggle button. Top Right avoids conflicts with CookieJar and other bottom-positioned widgets.', 'ability').'
'; } public function field_widget_position_mobile() { $val = $this->settings()['widget_position_mobile']; $opts = [ 'bottom_right' => __( 'Bottom Right (Recommended for mobile)', 'ability' ), 'bottom_left' => __( 'Bottom Left', 'ability' ), 'top_right' => __( 'Top Right', 'ability' ), 'top_left' => __( 'Top Left', 'ability' ), ]; echo ''.esc_html__('Position on mobile/tablet screens (below 782px). Can differ from desktop for better thumb reach.', 'ability').'
'; } public function field_panel_branding() { $s = $this->settings(); $is_pro = function_exists('ability_is_pro') ? ability_is_pro() : false; printf( '', esc_attr(self::OPTION), checked($s['panel_show_branding'], 1, false), esc_html__('Show ABILITY logo and name in the accessibility panel header.', 'ability') ); if ($is_pro) { echo ''.esc_html__('Pro/Enterprise: Customize or remove branding for white-label deployments. Uncheck the box above to fully hide branding.', 'ability').'
'; } else { echo ''.esc_html__('Pro/Enterprise users can customize or remove this branding for white-label use.', 'ability').'
'; } } public function field_skip_links_position() { $val = $this->settings()['skip_links_position']; $opts = [ 'body_open' => __( 'Early (recommended)', 'ability' ), 'footer' => __( 'Footer (legacy)', 'ability' ), ]; echo ''; } public function field_skip_link_ids() { $s = $this->settings(); printf( ''.esc_html__('Customize target element IDs used by skip links.', 'ability').'
'; } public function field_hide_footer_skip_links() { printf( '%4$s
', esc_attr(self::OPTION), checked($this->settings()['hide_footer_skip_links'], 1, false), esc_html__('Hide footer duplicate when early skip links are enabled.', 'ability'), esc_html__('Prevents duplicate tab stops.', 'ability') ); } public function field_enable_structured_data() { printf( '', esc_attr(self::OPTION), checked($this->settings()['enable_structured_data'], 1, false), esc_html__('Output conservative WebSite structured data on the front page. ABILITY does not emit site-wide accessibility or conformance claims by default.', 'ability') ); } public function field_initial_font_scale() { printf( ' %3$s', esc_attr(self::OPTION), esc_attr($this->settings()['initial_font_scale']), esc_html__('Applied only if user has no prior font size preference.', 'ability') ); } private function readable($id) { $map = [ 'high-contrast-toggle' => __( 'High Contrast Mode', 'ability' ), 'line-spacing-toggle' => __( 'Increased Line Spacing', 'ability' ), 'focus-indicators-toggle' => __( 'Enhanced Focus Indicators', 'ability' ), 'screen-reader-mode-toggle' => __( 'Screen Reader Optimized Mode', 'ability' ), 'voice-navigation-toggle' => __( 'Voice Read-Out', 'ability' ), 'dyslexia-font-toggle' => __( 'Dyslexia-Friendly Font', 'ability' ), 'reduce-motion-toggle' => __( 'Reduce Motion', 'ability' ), 'adhd-mode-toggle' => __( 'Distraction-Free Mode (ADHD/ADD)', 'ability' ), 'font-size-controls' => __( 'Font Size Controls', 'ability' ), ]; return $map[$id] ?? $id; } public function render_page() { if (!current_user_can('manage_options')) return; $s = $this->get_settings(); ?>