maybe_migrate_legacy_settings(); $this->fields_general = new AHA_Mobile_Menu_Settings_Fields( self::OPTION_GENERAL, array( $this, 'get_general_settings' ) ); $this->fields_content = new AHA_Mobile_Menu_Settings_Fields( self::OPTION_CONTENT, array( $this, 'get_content_settings' ) ); $this->fields_appearance = new AHA_Mobile_Menu_Settings_Fields( self::OPTION_APPEARANCE, array( $this, 'get_appearance_settings' ) ); $this->fields_exclusions = new AHA_Mobile_Menu_Settings_Fields( self::OPTION_EXCLUSIONS, array( $this, 'get_exclusions_settings' ) ); $this->fields_trigger = new AHA_Mobile_Menu_Settings_Fields( self::OPTION_TRIGGER, array( $this, 'get_trigger_settings' ) ); add_action( 'admin_menu', array( $this, 'register_menu' ) ); add_action( 'admin_init', array( $this, 'register_settings' ) ); add_action( 'admin_init', array( $this, 'maybe_save_uninstall_preference' ) ); add_action( 'aha_mobile_menu_settings_tab_action-buttons-addons', array( $this, 'render_action_buttons_addons_tab' ) ); add_filter( 'aha_mobile_menu_settings_tabs', array( $this, 'append_uninstall_tab' ), 100 ); } // ------------------------------------------------------------------------- // Migration // ------------------------------------------------------------------------- private function maybe_migrate_legacy_settings() { if ( get_option( 'aha_mobile_menu_migrated_to_per_tab', false ) ) { return; } $legacy = get_option( self::OPTION_LEGACY, null ); if ( null === $legacy || ! is_array( $legacy ) ) { update_option( 'aha_mobile_menu_migrated_to_per_tab', true, false ); return; } $field_map = array( self::OPTION_GENERAL => array( 'enable', 'position', 'animation', 'mobile_only', 'close_on_click_outside', 'close_on_navigation', 'trigger_classes' ), self::OPTION_CONTENT => array( 'logo', 'menu', 'enable_search', 'social_links' ), self::OPTION_APPEARANCE => array( 'bg_color', 'text_color', 'close_button_bg_color', 'close_button_icon_color', 'search_input_bg_color', 'search_input_border_color', 'search_input_text_color', 'search_icon_color', 'search_button_bg_color', 'menu_link_color', 'menu_link_active_color', 'menu_link_hover_color', 'social_bg_color', 'social_icon_color', 'action_button_1_bg_color', 'action_button_1_text_color', 'action_button_2_bg_color', 'action_button_2_text_color' ), self::OPTION_EXCLUSIONS => array( 'excluded_pages', 'excluded_post_types' ), self::OPTION_TRIGGER => array( 'trigger_icon_style', 'trigger_icon_color', 'trigger_bg_color', 'trigger_bg_opacity', 'trigger_icon_size', 'trigger_padding', 'trigger_position', 'trigger_top', 'trigger_right', 'trigger_z_index', 'trigger_border', 'trigger_border_color' ), ); foreach ( $field_map as $option => $fields ) { if ( false !== get_option( $option, false ) ) { continue; } $data = array(); foreach ( $fields as $field ) { if ( array_key_exists( $field, $legacy ) ) { $data[ $field ] = $legacy[ $field ]; } } update_option( $option, $data, false ); } update_option( 'aha_mobile_menu_migrated_to_per_tab', true, false ); } // ------------------------------------------------------------------------- // Per-tab settings getters // ------------------------------------------------------------------------- public function get_general_settings() { return wp_parse_args( get_option( self::OPTION_GENERAL, array() ), array( 'enable' => 1, 'position' => 'left', 'animation' => 'slide', 'mobile_only' => 1, 'close_on_click_outside' => 1, 'close_on_navigation' => 1, 'trigger_classes' => array(), ) ); } public function get_content_settings() { return wp_parse_args( get_option( self::OPTION_CONTENT, array() ), array( 'logo' => '', 'menu' => 0, 'enable_search' => 1, 'social_links' => array(), ) ); } public function get_appearance_settings() { return wp_parse_args( get_option( self::OPTION_APPEARANCE, array() ), array( 'bg_color' => '#ffffff', 'text_color' => '#000000', 'close_button_bg_color' => '#ededed', 'close_button_icon_color' => '#31322e', 'search_input_bg_color' => '', 'search_input_border_color' => '', 'search_input_text_color' => '', 'search_icon_color' => '', 'search_button_bg_color' => '', 'menu_link_color' => '', 'menu_link_active_color' => '', 'menu_link_hover_color' => '', 'social_bg_color' => '', 'social_icon_color' => '', 'action_button_1_bg_color' => '', 'action_button_1_text_color' => '', 'action_button_2_bg_color' => '', 'action_button_2_text_color' => '', ) ); } public function get_exclusions_settings() { $settings = wp_parse_args( get_option( self::OPTION_EXCLUSIONS, array() ), array( 'excluded_pages' => array(), 'excluded_post_types' => array(), ) ); if ( isset( $settings['excluded_pages'] ) && is_string( $settings['excluded_pages'] ) ) { $excluded = array_filter( array_map( 'trim', explode( "\n", $settings['excluded_pages'] ) ) ); $settings['excluded_pages'] = array_map( 'intval', array_filter( $excluded, 'is_numeric' ) ); } elseif ( ! isset( $settings['excluded_pages'] ) || ! is_array( $settings['excluded_pages'] ) ) { $settings['excluded_pages'] = array(); } return $settings; } public function get_trigger_settings() { return wp_parse_args( get_option( self::OPTION_TRIGGER, array() ), array( 'trigger_icon_style' => 'hamburger', 'trigger_icon_color' => '#374151', 'trigger_bg_color' => '#ffffff', 'trigger_bg_opacity' => 100, 'trigger_icon_size' => 40, 'trigger_padding' => '', 'trigger_position' => 'relative', 'trigger_top' => '', 'trigger_right' => '', 'trigger_z_index' => '', 'trigger_border' => 0, 'trigger_border_color' => '#e5e7eb', ) ); } // ------------------------------------------------------------------------- // Merged getter (public API - backward-compatible with frontend + Pro) // ------------------------------------------------------------------------- public function get_settings() { $settings = array_merge( $this->get_general_settings(), $this->get_content_settings(), $this->get_appearance_settings(), $this->get_exclusions_settings(), $this->get_trigger_settings() ); /** * Filter: aha_mobile_menu_get_settings * Add-ons hook here to inject their own settings fields. * * @since 1.0.7 * @param array $settings */ return apply_filters( 'aha_mobile_menu_get_settings', $settings ); } // ------------------------------------------------------------------------- // Per-tab sanitize callbacks // ------------------------------------------------------------------------- public function sanitize_general( $input ) { if ( ! is_array( $input ) ) { return get_option( self::OPTION_GENERAL, array() ); } $sanitized = array(); foreach ( array( 'enable', 'mobile_only', 'close_on_click_outside', 'close_on_navigation' ) as $field ) { $sanitized[ $field ] = ! empty( $input[ $field ] ) ? 1 : 0; } $sanitized['position'] = isset( $input['position'] ) && in_array( $input['position'], array( 'left', 'right' ), true ) ? $input['position'] : 'left'; $sanitized['animation'] = isset( $input['animation'] ) && in_array( $input['animation'], array( 'slide', 'fade' ), true ) ? $input['animation'] : 'slide'; if ( isset( $input['trigger_classes'] ) ) { if ( is_string( $input['trigger_classes'] ) ) { $classes = array_filter( array_map( 'trim', explode( "\n", $input['trigger_classes'] ) ) ); $sanitized['trigger_classes'] = array_map( 'sanitize_text_field', $classes ); } elseif ( is_array( $input['trigger_classes'] ) ) { $sanitized['trigger_classes'] = array_map( 'sanitize_text_field', $input['trigger_classes'] ); } else { $sanitized['trigger_classes'] = array(); } } else { $sanitized['trigger_classes'] = array(); } return $sanitized; } public function sanitize_content( $input ) { if ( ! is_array( $input ) ) { return get_option( self::OPTION_CONTENT, array() ); } $existing = get_option( self::OPTION_CONTENT, array() ); $sanitized = array(); $sanitized['enable_search'] = ! empty( $input['enable_search'] ) ? 1 : 0; $sanitized['logo'] = isset( $input['logo'] ) ? absint( $input['logo'] ) : 0; $sanitized['menu'] = isset( $input['menu'] ) ? absint( $input['menu'] ) : 0; if ( ! empty( $input['social_links_present'] ) ) { $sanitized['social_links'] = array(); if ( isset( $input['social_links'] ) && is_array( $input['social_links'] ) ) { foreach ( $input['social_links'] as $link ) { if ( isset( $link['url'], $link['network'] ) && ! empty( $link['url'] ) && ! empty( $link['network'] ) ) { $sanitized['social_links'][] = array( 'url' => esc_url_raw( $link['url'] ), 'network' => sanitize_text_field( $link['network'] ), ); } } } } elseif ( isset( $existing['social_links'] ) ) { $sanitized['social_links'] = $existing['social_links']; } return $sanitized; } public function sanitize_appearance( $input ) { if ( ! is_array( $input ) ) { return get_option( self::OPTION_APPEARANCE, array() ); } $sanitized = array(); $color_fields = array( 'bg_color', 'text_color', 'close_button_bg_color', 'close_button_icon_color', 'search_input_bg_color', 'search_input_border_color', 'search_input_text_color', 'search_icon_color', 'search_button_bg_color', 'menu_link_color', 'menu_link_active_color', 'menu_link_hover_color', 'social_bg_color', 'social_icon_color', 'action_button_1_bg_color', 'action_button_1_text_color', 'action_button_2_bg_color', 'action_button_2_text_color', ); foreach ( $color_fields as $field ) { if ( isset( $input[ $field ] ) ) { $sanitized[ $field ] = sanitize_hex_color( $input[ $field ] ); } } return $sanitized; } public function sanitize_exclusions( $input ) { if ( ! is_array( $input ) ) { return get_option( self::OPTION_EXCLUSIONS, array() ); } $sanitized = array(); if ( isset( $input['excluded_pages'] ) ) { if ( is_string( $input['excluded_pages'] ) ) { $lines = array_filter( array_map( 'trim', explode( "\n", $input['excluded_pages'] ) ) ); $sanitized['excluded_pages'] = array_map( 'intval', array_filter( $lines, 'is_numeric' ) ); } elseif ( is_array( $input['excluded_pages'] ) ) { $sanitized['excluded_pages'] = array_map( 'intval', array_filter( $input['excluded_pages'], 'is_numeric' ) ); } else { $sanitized['excluded_pages'] = array(); } } else { $sanitized['excluded_pages'] = array(); } $sanitized['excluded_post_types'] = array(); if ( isset( $input['excluded_post_types'] ) && is_array( $input['excluded_post_types'] ) ) { $all_post_types = $this->get_all_post_types(); foreach ( $input['excluded_post_types'] as $post_type ) { $post_type = sanitize_text_field( $post_type ); if ( isset( $all_post_types[ $post_type ] ) ) { $sanitized['excluded_post_types'][] = $post_type; } } } return $sanitized; } public function sanitize_trigger( $input ) { if ( ! is_array( $input ) ) { return get_option( self::OPTION_TRIGGER, array() ); } $sanitized = array(); if ( isset( $input['trigger_icon_style'] ) ) { $allowed = array( 'hamburger', 'hamburger-highlight', 'kebab', 'kebab-thick' ); $sanitized['trigger_icon_style'] = in_array( $input['trigger_icon_style'], $allowed, true ) ? $input['trigger_icon_style'] : 'hamburger'; } if ( isset( $input['trigger_icon_color'] ) && is_string( $input['trigger_icon_color'] ) ) { $sanitized['trigger_icon_color'] = sanitize_hex_color( $input['trigger_icon_color'] ) ?: '#374151'; } if ( isset( $input['trigger_bg_color'] ) && is_string( $input['trigger_bg_color'] ) ) { $sanitized['trigger_bg_color'] = sanitize_hex_color( $input['trigger_bg_color'] ) ?: '#ffffff'; } if ( isset( $input['trigger_icon_size'] ) ) { $sz = absint( $input['trigger_icon_size'] ); $sanitized['trigger_icon_size'] = $sz >= 24 && $sz <= 64 ? $sz : 40; } if ( array_key_exists( 'trigger_padding', $input ) ) { $sanitized['trigger_padding'] = ( '' === $input['trigger_padding'] || ! is_numeric( $input['trigger_padding'] ) ) ? '' : max( 0, min( 30, absint( $input['trigger_padding'] ) ) ); } if ( isset( $input['trigger_position'] ) ) { $sanitized['trigger_position'] = in_array( $input['trigger_position'], array( 'relative', 'absolute' ), true ) ? $input['trigger_position'] : 'relative'; } if ( array_key_exists( 'trigger_top', $input ) ) { $sanitized['trigger_top'] = ( '' === $input['trigger_top'] || ! is_numeric( $input['trigger_top'] ) ) ? '' : (int) $input['trigger_top']; } if ( array_key_exists( 'trigger_right', $input ) ) { $sanitized['trigger_right'] = ( '' === $input['trigger_right'] || ! is_numeric( $input['trigger_right'] ) ) ? '' : (int) $input['trigger_right']; } if ( array_key_exists( 'trigger_z_index', $input ) ) { $sanitized['trigger_z_index'] = ( '' === $input['trigger_z_index'] || ! is_numeric( $input['trigger_z_index'] ) ) ? '' : (int) $input['trigger_z_index']; } $sanitized['trigger_border'] = ! empty( $input['trigger_border'] ) ? 1 : 0; if ( isset( $input['trigger_border_color'] ) && is_string( $input['trigger_border_color'] ) ) { $sanitized['trigger_border_color'] = sanitize_hex_color( $input['trigger_border_color'] ) ?: '#e5e7eb'; } if ( isset( $input['trigger_bg_opacity'] ) ) { $op = absint( $input['trigger_bg_opacity'] ); $sanitized['trigger_bg_opacity'] = $op <= 100 ? $op : 100; } return $sanitized; } // ------------------------------------------------------------------------- // Admin menu // ------------------------------------------------------------------------- /** * Append Uninstall tab after add-ons register their tabs. * * @param array $tabs Tab slug => label. * @return array */ public function append_uninstall_tab( $tabs ) { if ( ! is_array( $tabs ) ) { $tabs = array(); } $tabs['uninstall'] = __( 'Uninstall', 'aha-mobile-menu' ); return $tabs; } /** * Save "remove data on uninstall" preference (Uninstall tab). * * @return void */ public function maybe_save_uninstall_preference() { if ( ! isset( $_POST['aha_mm_uninstall_prefs'] ) ) { return; } if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Permission denied.', 'aha-mobile-menu' ) ); } check_admin_referer( 'aha_mm_uninstall_prefs', 'aha_mm_uninstall_prefs_nonce' ); $erase = isset( $_POST['aha_mm_remove_data_on_uninstall'] ) ? '1' : '0'; update_option( AHA_MOBILE_MENU_UNINSTALL_DELETE_DATA_OPTION, $erase, false ); wp_safe_redirect( add_query_arg( array( 'page' => 'aha-mobile-menu', 'tab' => 'uninstall', 'aha_mm_uninstall_saved' => '1', ), admin_url( 'admin.php' ) ) ); exit; } /** * Register admin menu */ public function register_menu() { add_menu_page( __( 'Aha Mobile Menu', 'aha-mobile-menu' ), __( 'Aha Mobile Menu', 'aha-mobile-menu' ), 'manage_options', 'aha-mobile-menu', array( $this, 'render_settings_page' ), 'dashicons-menu', 76 ); } // ------------------------------------------------------------------------- // Settings registration // ------------------------------------------------------------------------- /** * Register settings */ public function register_settings() { register_setting( 'aha_mobile_menu_general_group', self::OPTION_GENERAL, array( 'sanitize_callback' => array( $this, 'sanitize_general' ) ) ); register_setting( 'aha_mobile_menu_content_group', self::OPTION_CONTENT, array( 'sanitize_callback' => array( $this, 'sanitize_content' ) ) ); register_setting( 'aha_mobile_menu_appearance_group', self::OPTION_APPEARANCE, array( 'sanitize_callback' => array( $this, 'sanitize_appearance' ) ) ); register_setting( 'aha_mobile_menu_exclusions_group', self::OPTION_EXCLUSIONS, array( 'sanitize_callback' => array( $this, 'sanitize_exclusions' ) ) ); register_setting( 'aha_mobile_menu_trigger_group', self::OPTION_TRIGGER, array( 'sanitize_callback' => array( $this, 'sanitize_trigger' ) ) ); // General tab add_settings_section( 'aha_mobile_menu_general', __( 'General Settings', 'aha-mobile-menu' ), array( $this->fields_general, 'render_section_general' ), 'aha-mobile-menu-general' ); add_settings_field( 'aha_mobile_menu_enable', __( 'Enable Sidebar', 'aha-mobile-menu' ), array( $this->fields_general, 'render_field_enable' ), 'aha-mobile-menu-general', 'aha_mobile_menu_general' ); add_settings_field( 'aha_mobile_menu_position', __( 'Sidebar Position', 'aha-mobile-menu' ), array( $this->fields_general, 'render_field_position' ), 'aha-mobile-menu-general', 'aha_mobile_menu_general' ); add_settings_field( 'aha_mobile_menu_animation', __( 'Animation', 'aha-mobile-menu' ), array( $this->fields_general, 'render_field_animation' ), 'aha-mobile-menu-general', 'aha_mobile_menu_general' ); add_settings_field( 'aha_mobile_menu_mobile_only', __( 'Mobile Only', 'aha-mobile-menu' ), array( $this->fields_general, 'render_field_mobile_only' ), 'aha-mobile-menu-general', 'aha_mobile_menu_general' ); // Behavior section (also on General tab) add_settings_section( 'aha_mobile_menu_behavior', __( 'Behavior', 'aha-mobile-menu' ), array( $this->fields_general, 'render_section_behavior' ), 'aha-mobile-menu-behavior' ); add_settings_field( 'aha_mobile_menu_close_on_click_outside', __( 'Close on Click Outside', 'aha-mobile-menu' ), array( $this->fields_general, 'render_field_close_on_click_outside' ), 'aha-mobile-menu-behavior', 'aha_mobile_menu_behavior' ); add_settings_field( 'aha_mobile_menu_close_on_navigation', __( 'Close on Navigation', 'aha-mobile-menu' ), array( $this->fields_general, 'render_field_close_on_navigation' ), 'aha-mobile-menu-behavior', 'aha_mobile_menu_behavior' ); add_settings_field( 'aha_mobile_menu_trigger_classes', __( 'Additional Trigger Classes', 'aha-mobile-menu' ), array( $this->fields_general, 'render_field_trigger_classes' ), 'aha-mobile-menu-behavior', 'aha_mobile_menu_behavior' ); // Content tab add_settings_section( 'aha_mobile_menu_content', __( 'Sidebar Content', 'aha-mobile-menu' ), array( $this->fields_content, 'render_section_content' ), 'aha-mobile-menu-content' ); add_settings_field( 'aha_mobile_menu_logo', __( 'Sidebar Logo', 'aha-mobile-menu' ), array( $this->fields_content, 'render_field_logo' ), 'aha-mobile-menu-content', 'aha_mobile_menu_content' ); add_settings_field( 'aha_mobile_menu_menu', __( 'Menu to Display', 'aha-mobile-menu' ), array( $this->fields_content, 'render_field_menu' ), 'aha-mobile-menu-content', 'aha_mobile_menu_content' ); add_settings_field( 'aha_mobile_menu_enable_search', __( 'Enable Search', 'aha-mobile-menu' ), array( $this->fields_content, 'render_field_enable_search' ), 'aha-mobile-menu-content', 'aha_mobile_menu_content' ); // Social section (also on Content tab) add_settings_section( 'aha_mobile_menu_social', __( 'Social Networks', 'aha-mobile-menu' ), array( $this->fields_content, 'render_section_social' ), 'aha-mobile-menu-social' ); add_settings_field( 'aha_mobile_menu_social_links', __( 'Social Links', 'aha-mobile-menu' ), array( $this->fields_content, 'render_field_social_links' ), 'aha-mobile-menu-social', 'aha_mobile_menu_social' ); // Appearance tab add_settings_section( 'aha_mobile_menu_design', __( 'Visual Customization', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_section_design' ), 'aha-mobile-menu-design' ); add_settings_field( 'aha_mobile_menu_color_palette', __( 'Color Palette', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_color_palette' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_bg_color', __( 'Background Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_bg_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_text_color', __( 'Text Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_text_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_close_button_divider', '', array( $this->fields_appearance, 'render_field_close_button_divider' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_close_button_title', '', array( $this->fields_appearance, 'render_field_close_button_title' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_close_button_bg_color', __( 'Close Button Background Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_close_button_bg_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_close_button_icon_color', __( 'Close Button Icon Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_close_button_icon_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_search_divider', '', array( $this->fields_appearance, 'render_field_search_divider' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_search_title', '', array( $this->fields_appearance, 'render_field_search_title' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_search_input_bg_color', __( 'Search Input Background Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_search_input_bg_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_search_input_border_color', __( 'Search Input Border Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_search_input_border_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_search_input_text_color', __( 'Search Input Text Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_search_input_text_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_search_icon_color', __( 'Search Icon Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_search_icon_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_search_button_bg_color', __( 'Search Button Background Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_search_button_bg_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_menu_links_divider', '', array( $this->fields_appearance, 'render_field_menu_links_divider' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_menu_links_title', '', array( $this->fields_appearance, 'render_field_menu_links_title' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_menu_link_color', __( 'Menu Link Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_menu_link_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_menu_link_active_color', __( 'Menu Link Active Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_menu_link_active_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_menu_link_hover_color', __( 'Menu Link Hover Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_menu_link_hover_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_social_divider', '', array( $this->fields_appearance, 'render_field_social_divider' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_social_title', '', array( $this->fields_appearance, 'render_field_social_title' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_social_bg_color', __( 'Social Icon Background Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_social_bg_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); add_settings_field( 'aha_mobile_menu_social_icon_color', __( 'Social Icon Color', 'aha-mobile-menu' ), array( $this->fields_appearance, 'render_field_social_icon_color' ), 'aha-mobile-menu-design', 'aha_mobile_menu_design' ); // Exclusions tab add_settings_section( 'aha_mobile_menu_exclusions', __( 'Page Exclusions', 'aha-mobile-menu' ), array( $this->fields_exclusions, 'render_section_exclusions' ), 'aha-mobile-menu-exclusions' ); add_settings_field( 'aha_mobile_menu_excluded_pages', __( 'Excluded Pages/Posts', 'aha-mobile-menu' ), array( $this->fields_exclusions, 'render_field_excluded_pages' ), 'aha-mobile-menu-exclusions', 'aha_mobile_menu_exclusions' ); add_settings_field( 'aha_mobile_menu_excluded_post_types', __( 'Excluded Post Types', 'aha-mobile-menu' ), array( $this->fields_exclusions, 'render_field_excluded_post_types' ), 'aha-mobile-menu-exclusions', 'aha_mobile_menu_exclusions' ); // Trigger tab add_settings_section( 'aha_mobile_menu_trigger', __( 'Menu trigger appearance', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_section_trigger' ), 'aha-mobile-menu-trigger' ); add_settings_field( 'aha_mobile_menu_trigger_icon_style', __( 'Icon style', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_icon_style' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_icon_color', __( 'Icon color', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_icon_color' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_bg_color', __( 'Background color', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_bg_color' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_bg_opacity', __( 'Background opacity (%)', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_bg_opacity' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_icon_size', __( 'Icon size (px)', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_icon_size' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_padding', __( 'Padding (px)', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_padding' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_position', __( 'Position', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_position' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_top_right', __( 'Top & Right (when absolute)', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_top_right' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_z_index', __( 'Z-index', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_z_index' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_border', __( 'Border', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_border' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); add_settings_field( 'aha_mobile_menu_trigger_border_color', __( 'Border color', 'aha-mobile-menu' ), array( $this->fields_trigger, 'render_field_trigger_border_color' ), 'aha-mobile-menu-trigger', 'aha_mobile_menu_trigger' ); } // ------------------------------------------------------------------------- // Tab => option group mapping // ------------------------------------------------------------------------- private function get_option_group_for_tab( $tab ) { $map = array( 'general' => 'aha_mobile_menu_general_group', 'content' => 'aha_mobile_menu_content_group', 'appearance' => 'aha_mobile_menu_appearance_group', 'exclusions' => 'aha_mobile_menu_exclusions_group', 'trigger' => 'aha_mobile_menu_trigger_group', ); $group = isset( $map[ $tab ] ) ? $map[ $tab ] : null; /** * Filter: aha_mobile_menu_tab_option_group * * Add-ons return their own option group for custom tabs. Returning null * renders the tab without a
(display/upsell tabs). * * @since 1.0.7 * @param string|null $group * @param string $tab */ return apply_filters( 'aha_mobile_menu_tab_option_group', $group, $tab ); } // ------------------------------------------------------------------------- // Page rendering // ------------------------------------------------------------------------- /** * Render settings page */ public function render_settings_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Tab is read-only for UI state. $active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'general'; $tabs = array( 'general' => __( 'General', 'aha-mobile-menu' ), 'content' => __( 'Content', 'aha-mobile-menu' ), 'appearance' => __( 'Appearance', 'aha-mobile-menu' ), 'exclusions' => __( 'Exclusions', 'aha-mobile-menu' ), 'trigger' => __( 'Menu appearance', 'aha-mobile-menu' ), 'shortcode' => __( 'Shortcode', 'aha-mobile-menu' ), 'action-buttons-addons' => __( 'Action Buttons', 'aha-mobile-menu' ), ); /** * Filter settings tabs (allows Pro to add e.g. License tab). * * @param array $tabs Associative array of tab_slug => label. */ $tabs = apply_filters( 'aha_mobile_menu_settings_tabs', $tabs ); if ( ! array_key_exists( $active_tab, $tabs ) ) { $active_tab = 'general'; } ?>
render_uninstall_tab(); ?>
render_shortcode_tab(); ?>
get_option_group_for_tab( $active_tab ); ?>
render_tab_content( $active_tab ); ?>
render_tab_content( $active_tab ); ?>
render_shortcode_tab(); break; default: if ( ! in_array( $active_tab, $core_tabs, true ) ) { /** * Action: aha_mobile_menu_settings_tab_{slug} * Add-ons (e.g. Pro) hook here to render their tab content. */ do_action( 'aha_mobile_menu_settings_tab_' . $active_tab ); } break; } } /** * Shortcode tab: hero box, attribute reference, and usage examples. * * @return void */ private function render_shortcode_tab() { $shortcode_attrs = array( 'style', 'icon_color', 'bg_color', 'size', 'padding', 'position', 'top', 'right', 'z_index', 'border', 'border_color', 'bg_opacity', ); ?>

[aha_mobile_menu_trigger style="kebab" size="44" position="absolute" top="14" right="20" z_index="9999"]

[aha_mobile_menu_trigger]
[aha_mobile_menu_trigger style="kebab"]
[aha_mobile_menu_trigger position="absolute" top="14" right="20" z_index="9999"]

style hamburger, hamburger-highlight, kebab, kebab-thick
size
padding
position relative / absolute
top
right
z_index
icon_color
bg_color
bg_opacity
border 1, yes, true / omit or 0
border_color

[aha_mobile_menu_trigger style="hamburger-highlight" size="52" icon_color="#ffffff" bg_color="#1e293b" padding="12"]
[aha_mobile_menu_trigger bg_opacity="0" border="0" icon_color="#111827"]
[aha_mobile_menu_trigger position="absolute" top="12" right="16" z_index="10050" border="1" border_color="#e5e7eb"]
[aha_mobile_menu_trigger style="kebab-thick" icon_color="#0f766e" bg_color="#ecfdf5" size="48"]

Menu appearance. Use attributes when a single page or header needs a different look.', 'aha-mobile-menu' ), $aha_mm_trigger_settings_url ), array( 'a' => array( 'href' => array(), ), ) ); ?>

get_settings(); if ( is_singular() ) { $current_post_type = get_post_type(); $excluded_post_types = isset( $settings['excluded_post_types'] ) && is_array( $settings['excluded_post_types'] ) ? $settings['excluded_post_types'] : array(); if ( ! empty( $excluded_post_types ) && in_array( $current_post_type, $excluded_post_types, true ) ) { return true; } } $excluded = $settings['excluded_pages']; if ( empty( $excluded ) || ! is_array( $excluded ) ) { return false; } $current_id = 0; if ( is_singular() ) { $current_id = get_queried_object_id(); } elseif ( is_front_page() && get_option( 'page_on_front' ) ) { $current_id = get_option( 'page_on_front' ); } elseif ( is_home() && get_option( 'page_for_posts' ) ) { $current_id = get_option( 'page_for_posts' ); } if ( ! $current_id ) { return false; } $excluded_ids = array_map( 'intval', $excluded ); return in_array( $current_id, $excluded_ids, true ); } /** * Get all registered post types (for sanitization). * * @return array */ private function get_all_post_types() { $post_types = get_post_types( array( 'public' => true ), 'objects' ); $result = array(); foreach ( $post_types as $post_type => $object ) { $result[ $post_type ] = $object->label; } return $result; } }