Skip to content

Instantly share code, notes, and snippets.

@SchneiderSam
Forked from diggeddy/gp-mega-menu.php
Last active January 26, 2024 07:13
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SchneiderSam/8549b6bf0a5c90222f3e9804bdfc3d79 to your computer and use it in GitHub Desktop.
Save SchneiderSam/8549b6bf0a5c90222f3e9804bdfc3d79 to your computer and use it in GitHub Desktop.
Create a sub menu item container with action hook (Mega Menu with GeneratePress and GenerateBlocks)
<?php
add_filter( 'walker_nav_menu_start_el', 'db_sub_menu_item_hook', 10, 4 );
function db_sub_menu_item_hook( $item_output, $item, $depth, $args ) {
// Specify menu item class to target
$class_string = 'gp_mega_item';
$menu_item_classes = $item->classes;
if ( empty( $menu_item_classes ) || !in_array( $class_string , $menu_item_classes ) ) {
return $item_output;
}
$menu_item_slug = $item->post_name;
// create custom hook from $class_string and $menu_item_slug
// example result gp_mega_menu-{menu-item-name}
$custom_hook_name = $class_string . '_' . $menu_item_slug;
// Add our common and specific hooks
ob_start();
?>
<ul class="sub-menu custom-sub-menu">
<li>
<?php do_action('gp_before_mega_item'); ?>
<?php do_action($custom_hook_name); ?>
<?php do_action('gp_after_mega_item'); ?>
</li>
</ul>
<?php
$custom_sub_menu_html = ob_get_clean();
// return the output after the menu items anchor
$item_output .= $custom_sub_menu_html;
return $item_output;
}
@SchneiderSam
Copy link
Author

SchneiderSam commented Jun 5, 2023

First and foremost, I would like to express my gratitude to David for his excellent support. With his help, I was able to create a Mega Menu in WordPress with GeneratePress and GenerateBlocks, and I thought it would be useful to share a detailed walkthrough of my process. I hope this will benefit many others seeking similar solutions.

So, let's begin:

1. Adding the PHP Function:

Please ensure to backup your website before proceeding, as these changes could potentially disrupt your website's functionality.

The following PHP function should ideally be added to your child theme's functions.php file or through a plugin like "Code Snippets", which would allow the changes to persist even after theme updates. Please take a look at this https://docs.generatepress.com/article/adding-php/ and this https://docs.generatepress.com/article/using-child-theme/ documentation.

add_filter( 'walker_nav_menu_start_el', 'db_sub_menu_item_hook', 10, 4 );
function db_sub_menu_item_hook( $item_output, $item, $depth, $args ) {

    // Specify menu item class to target
    $class_string = 'gp_mega_item';
    $menu_item_classes = $item->classes;
	
    if ( empty( $menu_item_classes ) || !in_array( $class_string , $menu_item_classes ) ) {
        return $item_output;
    }
    $menu_item_slug =  $item->post_name;
    // create custom hook from $class_string and $menu_item_slug
    // example result gp_mega_menu-{menu-item-name}
    $custom_hook_name = $class_string . '_' . $menu_item_slug;
    
    // Add our common and specific hooks
    ob_start(); 
    ?>
    <ul class="sub-menu custom-sub-menu">
	<li>
        <?php do_action('gp_before_mega_item'); ?>
	<?php do_action($custom_hook_name); ?>
	<?php do_action('gp_after_mega_item'); ?>
	</li>
    </ul>
    <?php
    $custom_sub_menu_html = ob_get_clean();
    // return the output after the menu items anchor
    $item_output .= $custom_sub_menu_html;

    return $item_output;
}

If these options aren't possible, you may add this PHP function to the functions.php file of your active theme through the WordPress admin area. Here's how:

Login to your WordPress admin area, navigate to "Appearance" -> "Theme Editor". Locate the functions.php file of your active theme on the right side. Scroll to the end of the file and paste the PHP function provided above. Click on "Update File" to save the changes.

2. Adding the CSS:

Add the following CSS rules to adjust the positioning of your Mega Menu items. This can be done via the Customizer under "Additional CSS". See this documentation: https://docs.generatepress.com/article/adding-css/

.gp_mega_item {
	position: static !important;
}
#site-navigation .gp_mega_item .sub-menu.custom-sub-menu {
	width: unset;
	left: 0;
	right: 0;
	box-shadow: none !important;
	background-color: transparent;
}

3. Adding a New Top-Level Menu Item:

Create a new top-level menu item using the WordPress menu management feature. Navigate to "Appearance" -> "Menus". Choose the menu you want to modify or create a new one. Click on "Add Item" to insert a new menu item. Assign a label to the menu item and add it to the menu. Click on the menu item to reveal its options, and add "gp_mega_item" and "menu-item-has-children" to the "CSS Classes" field. Click "Save Menu" to secure your changes.

At this point, you should have a top-level menu item with a custom sub-menu, using the generated hook name and the specified CSS.

4. Creating a Block Hook:

The subsequent step is to establish a Block Hook. Start by creating a new Block Hook. In the Hook Name field, input the relevant hook name that we generated earlier. Following this, start designing with GenerateBlocks.

And there you have it! You have successfully created a personalized Mega Menu. Feel free to marvel at your creation. Isn't it amazing?

Thanks to...
Special thanks to David for his invaluable assistance.
Ben00 and alin.teodosiu for ideas and suggestions.

Original Post: https://generate.support/topic/assistance-needed-in-creating-a-mega-menu-with-generateblocks/#post-15498

@alin-teodosiu
Copy link

alin-teodosiu commented Jun 14, 2023

In order to fix a common issue (sub menu isn't center aligned, full-width to the content) I'd like to propose this change to the css above at #2

5. (Optional) Center align the sub menu to the width of the content:

If you want the sub menu to be center aligned to the width of the content, you can add the following css instead of the one above at #2. It will make the menu look similar to the attached screenshot.

Note:

  • the code below assumes that your content width for the website is 1200 px; if it's not you will need to adjust the values for "width" and "left" accordingly
  • depending on the horizontal size of the navigation menu you will need to adjust the negative value of "left" (in the screenshot for example, -110% was just right for us)
  • the first snippet "@media(min-width: 720px)" is used for mobile view on tablet and should be ok for most resolutions but do feel free to change is necessary
  • if you'd like your sub menu to be closer to the top level menu, edit the value for "top"
.gp_mega_item {
	position: static !important;
}

@media(min-width: 720px) {
	#site-navigation .gp_mega_item .sub-menu.custom-sub-menu {
	width: 720px;
	left: -175px;
	right: 0;
	top: 100px;
	box-shadow: none !important;
	background-color: transparent;
}

@media(min-width: 1280px) {
	#site-navigation .gp_mega_item .sub-menu.custom-sub-menu {
	width: 1200px;
	left: -110%;
	right: 0;
	top: 100px;
	box-shadow: none !important;
	background-color: transparent;
}

Center Mega Menu

@DavidKeevis
Copy link

DavidKeevis commented Jul 8, 2023

Got it going and I really like it. Thanks for this post Sam and the additional CSS from Alin.

Update after some experimentation. Recommend considering this CSS approach:

.gp_mega_item {
position: static !important;
}

#site-navigation .gp_mega_item .sub-menu.custom-sub-menu {
width: max-content;
top: 0;
right: 0;
box-shadow: none !important;
background-color: transparent;
}

This provides the basic environment for the element to display in and shifts all the width control to the element. In the element, set the outer container width in px, em, rem - whatever units you're working in (i.e. 1200px). If the Set up desired width in tablet (i.e. 720px). Hide on mobile in the element's Advanced section. May wish to consider compensating for the header padding that's set in the customizer. Can tinker with the margin values also, especially top margin. Keeps everything nicely packaged and easy to plug into another site.

This also lets you to easily use flex containers inside the element for positioning and responsiveness which takes this to a whole higher level.

@alin-teodosiu
Copy link

Addendum to the css I initially posted above for mouse hover over activates menu:
If you select in generate press the option for the nav menu to activate on mouse hover and your add any value to ”top”, the menu will instantly disappear when trying to move over it.

You can remove top or if you still want some space between the dropdown and the menu (as in the picture above), add instead ”padding-top” and it work that way.

@DavidKeevis
Copy link

Hi Alin - Working on a newer implementation and noted your comment about the hover event. You can add a value to the top property. However, this value cannot be greater than the value set in the Menu Item Height property of the navigation element you're working with - typically Primary Nav. The key factor is the mouse pointer focus must transition from the menu item to the submenu item without a gap. Thanks for your additional CSS - I'm tweaking on some things that are proving to be really nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment