Back to all posts

Building Navigation Menu With Child Menu


How to build this menu functionality

Code:

<?php
// Register shortcode to display a menu by ID
function custom_menu_shortcode($atts)
{
    // Extract shortcode attributes
    $atts = shortcode_atts(array(
        'menu_id' => '14', // Default menu ID
    ), $atts, 'custom_menu');

    if (empty($atts['menu_id'])) {
        return 'Menu ID not provided';
    }

    // Output buffer to capture the menu HTML
    ob_start(); ?>
    <style>
        /* mobile and tab menu */

        div#modal_overlay[data-active="true"] {
            position: fixed;
            height: 100%;
            width: 100%;
            left: 0;
            top: 0;
            z-index: -1;
            overflow: hidden;
            z-index: 0;
            background-color: rgba(0, 0, 0, 0.2);
        }

        .PrimaryNavigation_icon {
            position: relative;
            top: 0;
            right: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            width: 3.25rem;
            height: 3.25rem;
            border: 2px solid var(--primary);
            border-radius: 100%;
            pointer-events: all;
            z-index: 100;
            background-color: #fff;
        }

        .PrimaryNavigation_icon:hover,
        .PrimaryNavigation_icon:focus {
            background-color: #fff !important;
        }

        .PrimaryNavigation_line {
            position: absolute;
            width: 24px;
            height: 2px;
            background: var(--primary);
            will-change: transform;
            border-radius: 2px;
            transition: transform 0.3s cubic-bezier(0.75, 0, 0.25, 1);
        }

        .PrimaryNavigation_line:first-child {
            transform: translateY(-3px);
        }

        .PrimaryNavigation_line:last-child {
            transform: translateY(3px);
        }

        #header_menu_box[data-active="true"] .PrimaryNavigation_line:first-child {
            transform: translateY(0) rotate(45deg);
        }

        #header_menu_box[data-active="true"] .PrimaryNavigation_line:last-child {
            transform: translateY(0) rotate(-45deg);
        }

        .PrimaryNavigation_flyout {
            width: 350px;
            height: auto;
            background: var(--white);
            position: absolute;
            right: 0;
            top: 20px;
            z-index: 99;
            padding: 50px 30px 30px;
            border-radius: 20px;
            transform: scale(0.4);
            /* Initial scale */
            opacity: 0;
            /* Initial opacity */
            transform-origin: top right;
            transition: transform 0.3s ease-out, opacity 0.4s ease-out;
        }

        #header_menu_box[data-active="true"] .PrimaryNavigation_flyout {
            transform: scale(1);
            opacity: 1;
        }

        #header_menu_box[data-active="false"] .PrimaryNavigation_flyout {
            transform: scale(0.4);
            opacity: 0;
            pointer-events: none;
        }

        ul#header_menu_ul {
            margin: 0;
            display: flex;
            flex-direction: column;
            gap: 10px;
            list-style: none;
        }

        ul#header_menu_ul li a {
            display: flex;
            gap: 5px;
            align-items: center;
            text-decoration: none;
            color: var(--black);
            font-size: 1.125rem;
            font-size: 1rem;
            cursor: pointer !important;
        }

        ul#header_menu_ul li:hover a,
        a.submenu-open * {
            color: var(--primary) !important;
        }

        ul#header_menu_ul .menu-item {
            opacity: 0;
            /* Initially hidden */
            transition: opacity 0.5s ease-in-out;
            /* Smooth transition for opacity */
        }

        #header_menu_box[data-active="true"] ul#header_menu_ul .menu-item {
            opacity: 1;
        }

        ul#header_menu_ul ul.sub-menu {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }

        /* Rotate animation */
        @keyframes rotate-360 {
            0% {
                transform: rotate(0deg);
            }

            100% {
                transform: rotate(180deg);
            }
        }

        /* Apply rotation animation */
        .submenu-open #animated-svg {
            animation: rotate-360 0.3s linear forwards;
        }

        /* Hide the minus icon after animation with delay */
        .submenu-open #minus-icon {
            display: block;
            opacity: 1;
            animation: hide-icon 0.2s forwards;
            animation-delay: 0.25s;
        }

        @keyframes hide-icon {
            0% {
                opacity: 1;
            }

            100% {
                opacity: 0;
                display: none;
            }
        }

        /* menu mobile */

        ul#mobile-menu {
            display: flex !important;
            flex-direction: column !important;
            gap: 20px;
            list-style-type: none;
            margin: 0px;
        }

        ul#mobile-menu li a {
            display: block;
            color: #000;
            font-family: Poppins;
            font-size: 16px;
            font-style: normal;
            font-weight: 500;
            line-height: normal;
            text-transform: capitalize;
            text-decoration: none;
            padding: 10px 0px;
        }

        span#mobile_menu_toggler,
        span#modal_menu_close {
            padding: 10px;
            background: var(--primary);
            border-radius: 38px;
        }

        span#mobile_menu_toggler svg,
        span#modal_menu_close svg {
            width: 25px;
            height: 25px;
        }

        span#modal_menu_close {
            position: absolute;
            top: 10px;
            right: 10px;
        }

        div#mobile_menu_modal {
            position: absolute;
            width: 300px;
            background: #fffbff;
            border: 3px solid var(--primary);
            border-radius: 10px;
            right: -300px;
            top: 45px;
            transition: right 0.5s ease, opacity 0.5s ease;
            opacity: 0;
            display: none;
            padding: 75px 20px 30px;
        }

        span#modal_menu_close {
            position: absolute;
            top: 10px;
            right: 10px;
        }

        div#mobile_menu_modal.active {
            right: 0;
            opacity: 1;
            z-index: 99;
            display: inline-block !important;
        }
    </style>
    <div id="PrimaryNavigation">
        <button class="PrimaryNavigation_icon" data-modal-hide="true">
            <div class="PrimaryNavigation_line"></div>
            <div class="PrimaryNavigation_line"></div>
        </button>
        <aside class="PrimaryNavigation_flyout">
            <nav class="PrimaryNavigation_navigation">
                <ul id="header_menu_ul" class="menu">
                    <?php
                    wp_nav_menu(array(
                        'menu' => $atts['menu_id'], // Use the menu ID here
                        'container' => false,
                        'items_wrap' => '%3$s',
                        'walker' => new Custom_Walker_Nav_Menu(),
                    )); ?>
                </ul>
            </nav>
            <div class="PrimaryNavigation_background"></div>
        </aside>
        <figure class="PrimaryNavigation_pageOverlay"></figure>
    </div>


    <script>
        (function($) {
            $(document).ready(function() {

                // Cached selectors to avoid multiple DOM lookups
                const $menuButton = $("#PrimaryNavigation .PrimaryNavigation_icon");
                const $headerMenu = $("#header_menu_box");
                const $modalOverlay = $("#modal_overlay");
                const $mobileMenuModal = $("#mobile_menu_modal");

                // Toggle the mobile menu visibility
                function toggleMobileMenu() {
                    if (!$mobileMenuModal.hasClass("active")) {
                        $mobileMenuModal.css("display", "inline-block");
                        setTimeout(() => $mobileMenuModal.addClass("active"), 10); // Trigger transition
                    } else {
                        $mobileMenuModal.removeClass("active");
                        setTimeout(() => $mobileMenuModal.css("display", "none"), 500); // Match transition duration
                    }
                }

                // Toggle the main menu visibility
                function toggleMenu() {
                    const isActive = $headerMenu.attr("data-active") === "true";
                    $headerMenu.attr("data-active", !isActive);
                }

                // Toggle the modal overlay visibility
                function toggleModalOverlay() {
                    const isActive = $modalOverlay.attr("data-active") === "true";
                    $modalOverlay.attr("data-active", !isActive);
                }

                // Bind events to buttons and overlays
                $menuButton.on("click", () => {
                    toggleMenu();
                    toggleModalOverlay();
                });

                $modalOverlay.on("click", () => {
                    toggleMenu();
                    toggleModalOverlay();
                });

                $("#mobile_menu_toggler, #modal_menu_close").on("click", toggleMobileMenu);

                // Handle submenu toggling
                function handleSubMenuToggle(e) {
                    const $clickedElement = $(e.target);
                    const $parentItem = $(this).parent();
                    const $subMenu = $(this).next(".sub-menu");

                    // Prevent default if clicking on the icon
                    if ($clickedElement.closest(".svg-wrapper").length > 0) {
                        e.preventDefault();

                        if ($subMenu.is(":visible")) {
                            $subMenu.slideUp();
                            $parentItem.find("svg #minus-icon").hide();
                            $parentItem.find("svg #plus-icon").show();
                            $parentItem.removeClass("active");
                        } else {
                            // Close other submenus and open the current one
                            $parentItem.siblings().find(".sub-menu").slideUp();
                            $parentItem.siblings().find("svg #minus-icon").hide();
                            $parentItem.siblings().find("svg #plus-icon").show();
                            $parentItem.siblings().removeClass("active");

                            $subMenu.slideDown();
                            $parentItem.find("svg #plus-icon").hide();
                            $parentItem.find("svg #minus-icon").show();
                            $parentItem.addClass("active");

                            // Hide nested submenus
                            $parentItem.find(".sub-menu .menu-item-has-children .sub-menu").slideUp();
                            $parentItem.find(".sub-menu .menu-item-has-children svg #minus-icon").hide();
                            $parentItem.find(".sub-menu .menu-item-has-children svg #plus-icon").show();
                        }
                    }
                }

                // Initialize submenu states and bind events
                function initSubMenu() {
                    $(".sub-menu").hide();
                    $("svg #plus-icon").show();
                    $("svg #minus-icon").hide();
                    $(".menu-item-has-children > a").on("click", handleSubMenuToggle);
                }

                // Initialize all handlers and menu states
                function init() {
                    initSubMenu();
                }

                init(); // Run initialization
            });
        })(jQuery);
    </script>
<?php
    // Get the buffered content and clean the buffer
    $output = ob_get_clean();

    return $output;
}
add_shortcode('menus', 'custom_menu_shortcode');
?>