Instantly share code, notes, and snippets.
Last active
February 13, 2026 04:26
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save nickfmc/e319e455da9e7895483d7c3a80e5b82c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * GenerateBlocks Pro - Theme Integration | |
| * | |
| * Custom Walker for WordPress Navigation with Mega Menu Support | |
| * | |
| * This snippet allows you to use GenerateBlocks Pro overlay panels as mega menus | |
| * with standard WordPress navigation (wp_nav_menu) without requiring the | |
| * GenerateBlocks Navigation block. | |
| * | |
| * INSTRUCTIONS: | |
| * 1. Copy this file to your theme directory (e.g., /wp-content/themes/your-theme/) | |
| * 2. Include it in your theme's functions.php: | |
| * require_once get_template_directory() . '/theme_integration.php'; | |
| * 3. Use the walker in your wp_nav_menu() calls (see example at bottom) | |
| * | |
| * | |
| */ | |
| if ( ! defined( 'ABSPATH' ) ) { | |
| exit; // Exit if accessed directly. | |
| } | |
| /** | |
| * Custom Walker for GenerateBlocks Pro Mega Menus | |
| * | |
| * Extends WordPress's default menu walker to add support for overlay panels | |
| * configured as mega menus in the WordPress menu editor. | |
| */ | |
| class GB_Pro_Mega_Menu_Walker extends Walker_Nav_Menu { | |
| /** | |
| * Mega menu trigger type (click or hover) | |
| * | |
| * @var string | |
| */ | |
| private $trigger_type = 'click'; | |
| /** | |
| * Cache for mega menu visibility checks | |
| * | |
| * @var array | |
| */ | |
| private static $mega_menu_cache = []; | |
| /** | |
| * Constructor | |
| * | |
| * @param string $trigger_type The trigger type for mega menus ('click' or 'hover'). | |
| */ | |
| public function __construct( $trigger_type = 'click' ) { | |
| $this->trigger_type = in_array( $trigger_type, [ 'click', 'hover' ], true ) ? $trigger_type : 'click'; | |
| } | |
| /** | |
| * Check if a mega menu should be displayed | |
| * | |
| * Checks if the overlay exists, is published, and passes any display conditions. | |
| * | |
| * @param int $overlay_id The overlay post ID. | |
| * @return bool Whether the mega menu should be displayed. | |
| */ | |
| private function should_display_mega_menu( $overlay_id ) { | |
| // Check cache first. | |
| if ( isset( self::$mega_menu_cache[ $overlay_id ] ) ) { | |
| return self::$mega_menu_cache[ $overlay_id ]; | |
| } | |
| // Check if overlay exists and is published. | |
| $overlay_post = get_post( $overlay_id ); | |
| if ( ! $overlay_post || 'gblocks_overlay' !== $overlay_post->post_type || 'publish' !== $overlay_post->post_status ) { | |
| self::$mega_menu_cache[ $overlay_id ] = false; | |
| return false; | |
| } | |
| // Check display conditions if GenerateBlocks Pro is active. | |
| if ( class_exists( 'GenerateBlocks_Pro_Overlays' ) && class_exists( 'GenerateBlocks_Pro_Conditions' ) ) { | |
| $display_condition = GenerateBlocks_Pro_Overlays::get_overlay_meta( $overlay_id, '_gb_overlay_display_condition' ); | |
| $display_conditions = []; | |
| if ( $display_condition ) { | |
| $condition_post = get_post( $display_condition ); | |
| if ( $condition_post && 'publish' === $condition_post->post_status ) { | |
| $display_conditions = get_post_meta( $display_condition, '_gb_conditions', true ) ?? []; | |
| } | |
| } | |
| $show = true; | |
| if ( ! empty( $display_conditions ) ) { | |
| $show = GenerateBlocks_Pro_Conditions::show( $display_conditions ); | |
| $invert_condition = GenerateBlocks_Pro_Overlays::get_overlay_meta( $overlay_id, '_gb_overlay_display_condition_invert' ); | |
| // If invert is enabled, flip the result. | |
| if ( $invert_condition ) { | |
| $show = ! $show; | |
| } | |
| } | |
| self::$mega_menu_cache[ $overlay_id ] = $show; | |
| return $show; | |
| } | |
| // Default to showing if no conditions system is available. | |
| self::$mega_menu_cache[ $overlay_id ] = true; | |
| return true; | |
| } | |
| /** | |
| * Starts the element output. | |
| * | |
| * Adds mega menu support to menu items by: | |
| * - Adding data attributes for overlay triggers | |
| * - Adding ARIA attributes for accessibility | |
| * - Outputting the mega menu overlay content | |
| * | |
| * @param string $output Used to append additional content (passed by reference). | |
| * @param WP_Post $item Menu item data object. | |
| * @param int $depth Depth of menu item. Used for padding. | |
| * @param stdClass $args An object of wp_nav_menu() arguments. | |
| * @param int $id Current item ID. | |
| */ | |
| public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) { | |
| // Get mega menu ID from post meta. | |
| $mega_menu_id = get_post_meta( $item->ID, '_gb_mega_menu', true ); | |
| $has_mega_menu = $mega_menu_id && $this->should_display_mega_menu( $mega_menu_id ); | |
| // Build the standard menu item. | |
| $indent = ( $depth ) ? str_repeat( "\t", $depth ) : ''; | |
| $classes = empty( $item->classes ) ? [] : (array) $item->classes; | |
| $classes[] = 'menu-item-' . $item->ID; | |
| // Add mega menu class if applicable. | |
| if ( $has_mega_menu ) { | |
| $classes[] = 'menu-item-has-mega-menu'; | |
| } | |
| /** | |
| * Filters the arguments for a single nav menu item. | |
| * | |
| * @param stdClass $args An object of wp_nav_menu() arguments. | |
| * @param WP_Post $item Menu item data object. | |
| * @param int $depth Depth of menu item. Used for padding. | |
| */ | |
| $args = apply_filters( 'nav_menu_item_args', $args, $item, $depth ); | |
| /** | |
| * Filters the CSS classes applied to a menu item's list item element. | |
| * | |
| * @param string[] $classes Array of the CSS classes that are applied to the menu item's `<li>` element. | |
| * @param WP_Post $item The current menu item. | |
| * @param stdClass $args An object of wp_nav_menu() arguments. | |
| * @param int $depth Depth of menu item. Used for padding. | |
| */ | |
| $class_names = implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) ); | |
| $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : ''; | |
| /** | |
| * Filters the ID applied to a menu item's list item element. | |
| * | |
| * @param string $menu_id The ID that is applied to the menu item's `<li>` element. | |
| * @param WP_Post $item The current menu item. | |
| * @param stdClass $args An object of wp_nav_menu() arguments. | |
| * @param int $depth Depth of menu item. Used for padding. | |
| */ | |
| $id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth ); | |
| $id = $id ? ' id="' . esc_attr( $id ) . '"' : ''; | |
| $output .= $indent . '<li' . $id . $class_names . '>'; | |
| $atts = []; | |
| $atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : ''; | |
| $atts['target'] = ! empty( $item->target ) ? $item->target : ''; | |
| $atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : ''; | |
| $atts['href'] = ! empty( $item->url ) ? $item->url : ''; | |
| // Add mega menu attributes. | |
| if ( $has_mega_menu ) { | |
| $overlay_id = 'gb-overlay-' . $mega_menu_id; | |
| // Create a unique ID for this menu link that can be referenced for positioning. | |
| $anchor_id = 'gb-menu-anchor-' . $item->ID; | |
| $atts['id'] = $anchor_id; | |
| // Required attributes for mega menu functionality. | |
| $atts['data-gb-overlay'] = $overlay_id; | |
| $atts['data-gb-overlay-trigger-type'] = $this->trigger_type; | |
| $atts['aria-controls'] = $overlay_id; | |
| $atts['aria-haspopup'] = 'menu'; | |
| // Add role and aria-expanded for click-based menus. | |
| if ( 'click' === $this->trigger_type ) { | |
| $atts['role'] = 'button'; | |
| $atts['aria-expanded'] = 'false'; | |
| } | |
| } | |
| /** | |
| * Filters the HTML attributes applied to a menu item's anchor element. | |
| * | |
| * @param array $atts { | |
| * The HTML attributes applied to the menu item's `<a>` element, empty strings are ignored. | |
| * | |
| * @type string $title Title attribute. | |
| * @type string $target Target attribute. | |
| * @type string $rel The rel attribute. | |
| * @type string $href The href attribute. | |
| * @type string $aria_current The aria-current attribute. | |
| * } | |
| * @param WP_Post $item The current menu item. | |
| * @param stdClass $args An object of wp_nav_menu() arguments. | |
| * @param int $depth Depth of menu item. Used for padding. | |
| */ | |
| $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth ); | |
| $attributes = ''; | |
| foreach ( $atts as $attr => $value ) { | |
| if ( ! empty( $value ) ) { | |
| $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value ); | |
| $attributes .= ' ' . $attr . '="' . $value . '"'; | |
| } | |
| } | |
| /** This filter is documented in wp-includes/post-template.php */ | |
| $title = apply_filters( 'the_title', $item->title, $item->ID ); | |
| /** | |
| * Filters a menu item's title. | |
| * | |
| * @param string $title The menu item's title. | |
| * @param WP_Post $item The current menu item. | |
| * @param stdClass $args An object of wp_nav_menu() arguments. | |
| * @param int $depth Depth of menu item. Used for padding. | |
| */ | |
| $title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth ); | |
| $item_output = $args->before ?? ''; | |
| $item_output .= '<a' . $attributes . '>'; | |
| $item_output .= ( $args->link_before ?? '' ) . $title . ( $args->link_after ?? '' ); | |
| $item_output .= '</a>'; | |
| $item_output .= $args->after ?? ''; | |
| // Output the mega menu overlay content. | |
| if ( $has_mega_menu ) { | |
| $action_id = 'gb-mega-menu-' . $mega_menu_id; | |
| ob_start(); | |
| /** | |
| * Fires when outputting a mega menu overlay. | |
| * | |
| * GenerateBlocks Pro hooks into this action to output the overlay content. | |
| * | |
| * @param WP_Post $item The menu item object. | |
| */ | |
| do_action( $action_id, $item ); | |
| $mega_menu_content = ob_get_clean(); | |
| $item_output .= $mega_menu_content; | |
| } | |
| /** | |
| * Filters a menu item's starting output. | |
| * | |
| * The menu item's starting output only includes `$args->before`, the opening `<a>`, | |
| * the menu item's title, the closing `</a>`, and `$args->after`. Currently, there is | |
| * no filter for modifying the opening and closing `<li>` for a menu item. | |
| * | |
| * @param string $item_output The menu item's starting HTML output. | |
| * @param WP_Post $item Menu item data object. | |
| * @param int $depth Depth of menu item. Used for padding. | |
| * @param stdClass $args An object of wp_nav_menu() arguments. | |
| */ | |
| $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); | |
| } | |
| } | |
| /** | |
| * USAGE EXAMPLE | |
| * | |
| * Copy the code below to your theme template file (e.g., header.php) where you | |
| * want to display the navigation menu with mega menu support. | |
| * | |
| * ---------------------------------------------------------------------------- | |
| * | |
| * Example 1: Click-based mega menus (default) | |
| * | |
| * wp_nav_menu( array( | |
| * 'theme_location' => 'primary', | |
| * 'walker' => new GB_Pro_Mega_Menu_Walker( 'click' ), | |
| * 'container' => 'nav', | |
| * 'menu_class' => 'main-navigation', | |
| * ) ); | |
| * | |
| * ---------------------------------------------------------------------------- | |
| * | |
| * Example 2: Hover-based mega menus | |
| * | |
| * wp_nav_menu( array( | |
| * 'theme_location' => 'primary', | |
| * 'walker' => new GB_Pro_Mega_Menu_Walker( 'hover' ), | |
| * 'container' => 'nav', | |
| * 'menu_class' => 'main-navigation', | |
| * ) ); | |
| * | |
| * ---------------------------------------------------------------------------- | |
| * | |
| * CONFIGURING MEGA MENUS: | |
| * | |
| * 1. Go to Appearance > Menus in your WordPress admin | |
| * 2. Edit a menu item and expand it | |
| * 3. You'll see a "Mega Menu" dropdown field (added by GenerateBlocks Pro) | |
| * 4. Select the overlay panel you want to use as a mega menu | |
| * 5. Save the menu | |
| * | |
| * The mega menu will now appear when users interact with that menu item | |
| * (either click or hover, depending on your walker configuration). | |
| * | |
| * ---------------------------------------------------------------------------- | |
| * | |
| * POSITIONING: | |
| * | |
| * Mega menu positioning is controlled in the overlay panel editor, not in the menu settings. | |
| * | |
| * To configure positioning: | |
| * 1. Edit your overlay panel (the one set as type "Mega Menu") | |
| * 2. In the panel settings, configure: | |
| * - PLACEMENT: Choose where the overlay appears (Top Right, Top Left, Bottom Right, etc.) | |
| * - POSITION TO PARENT: Enter a CSS selector to position relative to a specific element | |
| * | |
| * Example positioning configurations: | |
| * - Position relative to the menu link: Use "#gb-menu-anchor-{MENU_ITEM_ID}" | |
| * (each menu link automatically gets an ID like gb-menu-anchor-123) | |
| * - Position relative to the menu item's <li>: Use ".menu-item-{MENU_ITEM_ID}" | |
| * - Position relative to the entire nav: Use your nav's ID or class (e.g., "#main-nav") | |
| * - Position relative to site header: Use your header selector (e.g., ".site-header") | |
| * | |
| * The walker automatically adds an ID to each menu link (gb-menu-anchor-{item-id}) which | |
| * you can reference in your overlay positioning settings if needed. | |
| * | |
| * ---------------------------------------------------------------------------- | |
| * | |
| * REQUIREMENTS: | |
| * - GenerateBlocks Pro plugin must be active | |
| * - You must have created overlay panels with the type set to "Mega Menu" | |
| * - The overlays must be assigned to menu items in the WordPress menu editor | |
| * | |
| * ---------------------------------------------------------------------------- | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment