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
);
}
}