get_settings(); $defaults = array( 'trigger_icon_style' => 'hamburger', 'trigger_icon_color' => '#374151', 'trigger_bg_color' => '#ffffff', 'trigger_icon_size' => 40, 'trigger_padding' => '', 'trigger_position' => 'relative', 'trigger_top' => '', 'trigger_right' => '', 'trigger_z_index' => '', 'trigger_border' => 0, 'trigger_border_color' => '#e5e7eb', 'trigger_bg_opacity' => 100, ); $opts = wp_parse_args( $settings, $defaults ); $opts['trigger_icon_size'] = isset( $settings['trigger_icon_size'] ) ? absint( $settings['trigger_icon_size'] ) : 40; if ( $opts['trigger_icon_size'] < 24 ) { $opts['trigger_icon_size'] = 24; } if ( $opts['trigger_icon_size'] > 64 ) { $opts['trigger_icon_size'] = 64; } return $opts; } /** * Convert hex color to rgba string. * * @param string $hex Hex color e.g. #ffffff. * @param int $percent Opacity 0-100. * @return string rgba(r,g,b,a) */ private function hex_to_rgba( $hex, $percent ) { $hex = ltrim( $hex, '#' ); if ( strlen( $hex ) !== 6 ) { return 'rgba(255,255,255,1)'; } $r = (int) hexdec( substr( $hex, 0, 2 ) ); $g = (int) hexdec( substr( $hex, 2, 2 ) ); $b = (int) hexdec( substr( $hex, 4, 2 ) ); $a = max( 0, min( 100, (int) $percent ) ) / 100; return 'rgba(' . $r . ',' . $g . ',' . $b . ',' . $a . ')'; } /** * All shortcode attribute names for [aha_mobile_menu_trigger]. * Priority: shortcode params override options, options override defaults. * * @return array */ private function get_shortcode_atts_schema() { return array( 'style' => '', 'icon_color' => '', 'bg_color' => '', 'size' => '', 'padding' => '', 'position' => '', 'top' => '', 'right' => '', 'z_index' => '', 'border' => '', 'border_color' => '', 'bg_opacity' => '', ); } /** * Merge trigger values: 1) defaults, 2) plugin options, 3) shortcode atts (highest priority). * * @param array $opts From get_trigger_settings(). * @param array $atts shortcode_atts (string values). * @return array Final trigger config (keys as in $opts). */ private function merge_trigger_values( $opts, $atts ) { $out = array( 'trigger_icon_style' => $opts['trigger_icon_style'], 'trigger_icon_color' => $opts['trigger_icon_color'], 'trigger_bg_color' => $opts['trigger_bg_color'], 'trigger_icon_size' => $opts['trigger_icon_size'], 'trigger_padding' => $opts['trigger_padding'], 'trigger_position' => $opts['trigger_position'], 'trigger_top' => $opts['trigger_top'], 'trigger_right' => $opts['trigger_right'], 'trigger_z_index' => isset( $opts['trigger_z_index'] ) ? $opts['trigger_z_index'] : '', 'trigger_border' => $opts['trigger_border'], 'trigger_border_color' => $opts['trigger_border_color'], 'trigger_bg_opacity' => $opts['trigger_bg_opacity'], ); if ( '' !== $atts['style'] ) { $style = sanitize_key( $atts['style'] ); if ( in_array( $style, array( 'hamburger', 'hamburger-highlight', 'kebab', 'kebab-thick' ), true ) ) { $out['trigger_icon_style'] = $style; } } if ( '' !== $atts['icon_color'] ) { $c = sanitize_hex_color( $atts['icon_color'] ); if ( $c ) { $out['trigger_icon_color'] = $c; } } if ( '' !== $atts['bg_color'] ) { $c = sanitize_hex_color( $atts['bg_color'] ); if ( $c ) { $out['trigger_bg_color'] = $c; } } if ( '' !== $atts['size'] ) { $n = absint( $atts['size'] ); if ( $n >= 24 && $n <= 64 ) { $out['trigger_icon_size'] = $n; } } if ( '' !== $atts['padding'] ) { $n = absint( $atts['padding'] ); if ( $n >= 0 && $n <= 30 ) { $out['trigger_padding'] = (string) $n; } } if ( '' !== $atts['position'] ) { $p = sanitize_key( $atts['position'] ); if ( 'absolute' === $p || 'relative' === $p ) { $out['trigger_position'] = $p; } } if ( '' !== $atts['top'] ) { $out['trigger_top'] = (string) absint( $atts['top'] ); } if ( '' !== $atts['right'] ) { $out['trigger_right'] = (string) absint( $atts['right'] ); } if ( '' !== $atts['z_index'] && is_numeric( $atts['z_index'] ) ) { $out['trigger_z_index'] = (string) (int) $atts['z_index']; } if ( '' !== $atts['border'] ) { $out['trigger_border'] = in_array( strtolower( $atts['border'] ), array( '1', 'yes', 'true' ), true ) ? 1 : 0; } if ( '' !== $atts['border_color'] ) { $c = sanitize_hex_color( $atts['border_color'] ); if ( $c ) { $out['trigger_border_color'] = $c; } } if ( '' !== $atts['bg_opacity'] ) { $n = absint( $atts['bg_opacity'] ); if ( $n >= 0 && $n <= 100 ) { $out['trigger_bg_opacity'] = $n; } } return $out; } /** * Render shortcode [aha_mobile_menu_trigger] * * @param array $atts Optional. style, icon_color, bg_color, size, padding, position, top, right, border, border_color, bg_opacity. * @return string */ public function render( $atts = array() ) { $opts = $this->get_trigger_settings(); $atts = shortcode_atts( $this->get_shortcode_atts_schema(), $atts, 'aha_mobile_menu_trigger' ); $opts = $this->merge_trigger_values( $opts, $atts ); $style = $opts['trigger_icon_style']; $icon_color = $opts['trigger_icon_color']; $bg_color = $opts['trigger_bg_color']; $size = (int) $opts['trigger_icon_size']; if ( $size < 24 ) { $size = 24; } if ( $size > 64 ) { $size = 64; } $position = isset( $opts['trigger_position'] ) && 'absolute' === $opts['trigger_position'] ? 'absolute' : 'relative'; $top = isset( $opts['trigger_top'] ) && '' !== (string) $opts['trigger_top'] ? (int) $opts['trigger_top'] : null; $right = isset( $opts['trigger_right'] ) && '' !== (string) $opts['trigger_right'] ? (int) $opts['trigger_right'] : null; $z_index = isset( $opts['trigger_z_index'] ) && '' !== (string) $opts['trigger_z_index'] ? (int) $opts['trigger_z_index'] : null; $border = ! empty( $opts['trigger_border'] ); $border_color = isset( $opts['trigger_border_color'] ) ? $opts['trigger_border_color'] : '#e5e7eb'; $bg_opacity = isset( $opts['trigger_bg_opacity'] ) ? absint( $opts['trigger_bg_opacity'] ) : 100; wp_enqueue_style( 'aha-mobile-menu-trigger', AHA_MOBILE_MENU_URL . 'assets/css/trigger.css', array(), AHA_MOBILE_MENU_VERSION ); $padding = ( isset( $opts['trigger_padding'] ) && '' !== (string) $opts['trigger_padding'] ) ? max( 0, min( 30, absint( $opts['trigger_padding'] ) ) ) : 11; $bg_value = ( $bg_opacity >= 100 ) ? $bg_color : $this->hex_to_rgba( $bg_color, $bg_opacity ); $styles = array( 'width' => $size . 'px', 'height' => $size . 'px', 'min-width' => $size . 'px', 'min-height' => $size . 'px', 'padding' => $padding . 'px', 'background-color' => $bg_value, 'color' => $icon_color, 'position' => $position, ); if ( null !== $top ) { $styles['top'] = $top . 'px'; } if ( null !== $right ) { $styles['right'] = $right . 'px'; } if ( null !== $z_index ) { $styles['z-index'] = (string) $z_index; } if ( $border ) { $styles['border'] = '1px solid ' . $border_color; } $style_parts = array(); foreach ( $styles as $prop => $val ) { $style_parts[] = $prop . ':' . $val; } $style_attr = implode( ';', $style_parts ); $svg = $this->get_icon_svg( $style, $icon_color, $size - ( $padding * 2 ) ); $html = sprintf( '', esc_attr( $style ), esc_attr__( 'Open menu', 'aha-mobile-menu' ), esc_attr( $style_attr ), $svg ); return $html; } /** * Get SVG markup for the chosen icon style. * * @param string $style hamburger | hamburger-highlight | kebab | kebab-thick * @param string $color Hex color for strokes/fills * @param int $size_px Inner size of icon (approx). * @return string */ private function get_icon_svg( $style, $color, $size_px ) { $w = $size_px; $h = $size_px; $color = $color ? $color : '#374151'; if ( 'kebab' === $style || 'kebab-thick' === $style ) { // Thin dots (kebab) vs thick dots (kebab-thick) $r = ( 'kebab-thick' === $style ) ? max( 4, (int) round( $size_px / 6 ) ) // Thick dots : max( 2, (int) round( $size_px / 16 ) ); // Thin dots $cx = (int) round( $w / 2 ); // Thick dots: smaller edge gap = more space between dots so they don't look "colado" $gap = ( 'kebab-thick' === $style ) ? (int) round( $size_px / 6 ) : (int) round( $size_px / 4 ); $y1 = $gap; $y2 = (int) round( $h / 2 ); $y3 = $h - $gap; return sprintf( '', $w, $h, $w, $h, esc_attr( $color ), $cx, $y1, $r, $cx, $y2, $r, $cx, $y3, $r ); } // Hamburger: thin lines (hamburger) vs thick lines (hamburger-highlight) $stroke = ( 'hamburger-highlight' === $style ) ? max( 4, (int) round( $size_px / 8 ) ) // Thick lines : max( 2, (int) round( $size_px / 20 ) ); // Thin lines $gap = (int) round( $size_px / 6 ); $y1 = $gap; $y2 = (int) round( $h / 2 ); $y3 = $h - $gap; $margin = (int) round( $w * 0.15 ); $x1 = $margin; $x2 = $w - $margin; return sprintf( '', $w, $h, $w, $h, $x1, $y1, $x2, $y1, esc_attr( $color ), $stroke, $x1, $y2, $x2, $y2, esc_attr( $color ), $stroke, $x1, $y3, $x2, $y3, esc_attr( $color ), $stroke ); } }