editor ) && $elementor->editor->is_edit_mode() ) || ( isset( $elementor->preview ) && $elementor->preview->is_preview_mode() ) ) { return true; } } if ( class_exists( 'FLBuilderModel' ) && FLBuilderModel::is_builder_active() ) { return true; } if ( function_exists( 'vc_is_inline' ) && vc_is_inline() ) { return true; } if ( function_exists( 'bricks_is_builder' ) && bricks_is_builder() ) { return true; } if ( function_exists( 'bricks_is_builder_iframe' ) && bricks_is_builder_iframe() ) { return true; } if ( function_exists( '\\Breakdance\\Editor\\isEditor' ) && \Breakdance\Editor\isEditor() ) { return true; } if ( function_exists( 'themify_builder_is_frontend_editor' ) && themify_builder_is_frontend_editor() ) { return true; } if ( defined( 'SHOW_CT_BUILDER' ) && SHOW_CT_BUILDER ) { return true; } $preview_keys = array( 'elementor-preview', 'elementor_library', 'ct_builder', 'ct_inner', 'oxygen_iframe', 'brizy-edit-iframe', 'brizy-edit', 'fl_builder', 'fl_builder_ui', 'bricks', 'brickspreview', 'breakdance', 'breakdance_iframe', 'vc_editable', 'vcv-action', 'tve', 'tve_editor', 'tb-preview', 'themify_builder_infinite_scroll', ); foreach ( $preview_keys as $key ) { // Read-only detection of page-builder editor modes; no data is changed. if ( isset( $_REQUEST[ $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return true; } } return (bool) apply_filters( 'amber_mega_menu_is_builder_preview', false ); } public static function init() { add_shortcode( 'amber_mega_menu', array( __CLASS__, 'shortcode' ) ); // Backward-compatible aliases for embeds created by earlier versions. add_shortcode( 'category_mega_menu', array( __CLASS__, 'shortcode' ) ); add_shortcode( 'smm_mega_menu', array( __CLASS__, 'shortcode' ) ); add_action( 'wp_enqueue_scripts', array( __CLASS__, 'register_assets' ) ); } public static function register_assets() { wp_register_style( 'smm-frontend', AMBER_MEGA_MENU_URL . 'assets/frontend.css', array(), AMBER_MEGA_MENU_VERSION ); wp_register_script( 'smm-frontend', AMBER_MEGA_MENU_URL . 'assets/frontend.js', array(), AMBER_MEGA_MENU_VERSION, true ); // Visual builders can inject shortcode HTML after wp_head has already run. // Load the lightweight stylesheet up front so their live canvas never shows // an unstyled menu while a shortcode preview is being refreshed. wp_enqueue_style( 'smm-frontend' ); } /** English defaults, optionally replaced per menu by the premium text module. */ protected static function frontend_text( $settings ) { $text = array( 'panel_title' => __( 'Categories', 'amber-mega-menu' ), 'search_label' => __( 'Search categories', 'amber-mega-menu' ), 'search_placeholder'=> __( 'Search categories…', 'amber-mega-menu' ), 'close_label' => __( 'Close categories', 'amber-mega-menu' ), 'cart_label' => __( 'View shopping cart', 'amber-mega-menu' ), 'empty_message' => __( 'There are currently no visible items in this menu.', 'amber-mega-menu' ), 'no_results' => __( 'No categories found.', 'amber-mega-menu' ), 'show_all' => __( 'Show all', 'amber-mega-menu' ), 'show_less' => __( 'Show less', 'amber-mega-menu' ), ); /** Premium distributions may replace any built-in message per menu. */ return apply_filters( 'amber_mega_menu_frontend_text', $text, $settings ); } public static function shortcode( $atts ) { $atts = shortcode_atts( array( 'id' => 0, 'layout' => '', 'display' => '', // adaptive | modal — overrides the saved desktop opening mode 'trigger' => '', 'columns' => '', 'depth' => '', 'open' => '', // "1" renders the panel always open (no trigger button) 'nav' => '', // "1" = panel only, opened by a WordPress nav menu item 'disable_link' => '', 'nav_for' => '', // key of the WordPress menu item link that opens this panel 'nav_item_id' => 0, ), $atts, 'amber_mega_menu' ); $post_id = (int) $atts['id']; if ( ! $post_id ) { $found = get_posts( array( 'post_type' => AMBER_MEGA_MENU_CPT, 'posts_per_page' => 1, 'fields' => 'ids', 'orderby' => 'ID', 'order' => 'ASC', ) ); $post_id = $found ? (int) $found[0] : 0; } if ( ! $post_id || AMBER_MEGA_MENU_CPT !== get_post_type( $post_id ) ) { return ''; } $s = Amber_Mega_Menu_Source::get_settings( $post_id ); if ( $atts['layout'] ) { $s['layout'] = ( 'sideways' === $atts['layout'] ) ? 'sideways' : 'columns'; } if ( $atts['display'] ) { $s['desktop_display'] = ( 'modal' === $atts['display'] ) ? 'modal' : 'adaptive'; } if ( '' !== $atts['trigger'] ) { $s['trigger'] = $atts['trigger']; } if ( $atts['columns'] ) { $s['columns'] = max( 2, min( 6, (int) $atts['columns'] ) ); } if ( '' !== (string) $atts['depth'] ) { // 0 = unlimited; anything higher is honoured up to a generous cap. $s['depth'] = max( 0, min( 20, (int) $atts['depth'] ) ); } $always_open = ( '1' === (string) $atts['open'] ); $nav_mode = ( '1' === (string) $atts['nav'] ); $nav_no_link = ( '1' === (string) $atts['disable_link'] ); $nav_for = sanitize_html_class( (string) $atts['nav_for'] ); $nav_item_id = absint( $atts['nav_item_id'] ); if ( $nav_mode ) { $always_open = false; } /** Final settings for this placement; premium modules may extend them. */ $s = apply_filters( 'smm_menu_settings', $s, $post_id, $atts ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- legacy 'smm_' prefix kept for compatibility between the free and premium distributions. $builder_preview = self::is_builder_preview(); if ( $builder_preview ) { // Render the real configured panel in place. The builder preview must show // the selected source, layout, depth, tabs and visual settings—not a proxy. $always_open = true; $nav_mode = false; $s['show_cart'] = 0; } $tree = self::visible( Amber_Mega_Menu_Source::merged_tree( $post_id, $s ), $s ); $empty_tree = empty( $tree ); wp_enqueue_style( 'smm-frontend' ); wp_enqueue_script( 'smm-frontend' ); /** Premium distributions enqueue their own assets for this placement. */ do_action( 'amber_mega_menu_enqueue_assets', $s, $post_id ); $uid = 'smm-' . $post_id . '-' . wp_rand( 1000, 9999 ); $text = self::frontend_text( $s ); ob_start(); ?>
style="--smm-panel-width:px;--smm-columns:;--smm-blue:;--smm-bg:;--smm-sideways-left-bg:;--smm-text:;--smm-navy:;--smm-muted:;--smm-line:;--smm-highlight:;--smm-font-family:;--smm-font-size:px;--smm-parent-font-size:px;--smm-category-font-weight:;--smm-radius:px;--smm-control-radius:px;--smm-image-size:px;--smm-image-radius:px;--smm-button-bg:;--smm-button-bg-hover:;--smm-button-text:;--smm-button-text-hover:;--smm-button-border:;--smm-button-border-hover:;--smm-button-border-width:px;--smm-button-radius:px;--smm-button-font-size:px;--smm-button-font-weight:;--smm-button-padding-y:px;--smm-button-padding-x:px;--smm-cart-bubble-bg:;--smm-cart-bubble-text:;">
>
'' !== trim( (string) $s['tab_label'] ) ? $s['tab_label'] : $text['panel_title'], 'tree' => $tree, ), ); /** Premium distributions may add further panes (e.g. extra menus as tabs). */ $panes = apply_filters( 'amber_mega_menu_panes', $panes, $s, $post_id ); do_action( 'smm_panel_before', $s, $post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- legacy 'smm_' prefix kept for compatibility between the free and premium distributions. if ( count( $panes ) > 1 ) : ?>
$pane ) : ?>
$pane ) { echo '
'; if ( 'sideways' === $s['layout'] ) { self::render_sideways( $pane['tree'], $s ); } else { self::render_columns( $pane['tree'], $s, $text ); } echo '
'; } do_action( 'smm_panel_after', $s, $post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- legacy 'smm_' prefix kept for compatibility between the free and premium distributions. ?>
' . (int) $node['count'] . ''; } /** Layout 1 — grid of parent columns. */ protected static function render_columns( $tree, $s, $text ) { echo '
'; foreach ( $tree as $parent ) { echo '
'; echo ''; if ( ! empty( $s['show_images'] ) && $parent['image'] ) { echo ''; } echo esc_html( $parent['label'] ) . wp_kses_post( self::count_label( $parent, $s ) ) . ''; if ( self::depth_allows( $s, 1 ) && ! empty( $parent['children'] ) ) { echo ''; if ( count( $parent['children'] ) > 6 ) { echo ''; } } echo '
'; } echo '
'; } /** Layout 2 — left rail of parents, hover/focus reveals the sub-level panel. */ protected static function render_sideways( $tree, $s ) { echo '
'; echo ''; echo '
'; foreach ( $tree as $i => $parent ) { $has = ( self::depth_allows( $s, 1 ) && ! empty( $parent['children'] ) ); if ( ! $has ) { continue; } echo '
'; echo ''; self::render_sub_lists( $parent, $s ); echo '
'; } echo '
'; echo '
'; } protected static function render_sub_lists( $parent, $s ) { echo '
'; foreach ( $parent['children'] as $child ) { echo '
'; echo '' . esc_html( $child['label'] ) . wp_kses_post( self::count_label( $child, $s ) ) . ''; self::render_nested( $child, $s, 2 ); echo '
'; } echo '
'; } /** Whether the configured depth shows $level (1 = children, 2 = grandchildren, ...). 0 means unlimited. */ protected static function depth_allows( $s, $level ) { $d = (int) $s['depth']; return 0 === $d || $d > $level; } /** * Levels below children, rendered recursively to any depth. Deeper levels * reuse the grandchildren list styles, which nest (indent + left border). */ protected static function render_nested( $node, $s, $level ) { if ( ! self::depth_allows( $s, $level ) || empty( $node['children'] ) ) { return; } echo ''; } }