Add Dropdowns to Main Menu Through the Site Admin (Copy & Paste into Site Header/Footer Injections)

To add dropdowns to your main menu through your site admin area.

These instructions are just a simplification of the @themeix drop down mentioned here, but for more noobish front-enders (as this is without modifying templates or other theme files)…

Paste the following CSS in your Site Header Injection:

<style>

/* For Dropdown Menus */    
li.menu-item-has-children {
    position: relative;
    padding-right: 25px!important;
    display: inline;
}
    
li.menu-item-has-children:hover ul.ghost-submenu {
    visibility: visible!important;
    opacity: 1!important;
    top: 50px!important;
}

.menu-item-has-children svg {
    position: absolute;
    right: 0px;
    top: 60%;
    transform: translate(-0%, -50%) scale(1.1);
}

ul.ghost-submenu li {
    list-style: none;
    white-space: nowrap;
}

ul.ghost-submenu {
    border-radius: 5px;
    position: absolute;
    visibility: hidden;
    z-index: 1;
    opacity: 0;
    top: 30px;
    transition: 0.3s;
    box-shadow: 0 1px 5px 0 rgb(0 0 0 / 14%);
    max-width: unset !important;
    
    /* Edit below to adjust Dropdown Menu positioning and color */
    left: 0;
    margin-top: -15px;
    padding: 5px 20px 10px 10px;
    background: #fff;
    color: #000;
}

</style>

And paste the following Javascript into your Site Footer Injection:

<script>
// For Dropdown Menu
(function($) {
    "use strict";
    function ghost_dropdown(options) {
       let defultOptions = {
            targetElement: "ul li",
            hasChildrenClasses: "menu-item-has-children",
            hasChildrenIcon: "<svg xmlns='http://www.w3.org/2000/svg' width='11' height='7' fill='currentColor' class='bi bi-caret-down' viewBox='0 0 11 7'><path d='M5.4999 6.20003L0.649902 1.35003L1.3499 0.650024L5.4999 4.80002L9.6499 0.650024L10.3499 1.35003L5.4999 6.20003Z'/></svg>",
            hasChildDetectText: "[has_child]",
            submenuUlClasses: "ghost-submenu",
            subitemDetectText: "[subitem]",
            subitemLiClasses: "subitem"
        }
        options = {
            ...defultOptions,
            ...options
        }
        console.log(options);
        // Target Element
        let targetElement = options.targetElement;
        //Default value 
        let hasChildrenClasses = options.hasChildrenClasses;
        let hasChildrenIcon = options.hasChildrenIcon;
        let hasChildDetectText = options.hasChildDetectText;
        let submenuUlClasses = options.submenuUlClasses;
        let subitemDetectText = options.subitemDetectText;
        let subitemLiClasses = options.subitemLiClasses;
        // Declare neccesary variable
        let parentEl = $(targetElement);
        let childEL = $(targetElement);
        let parentLen = 0;
        let domArrayElement = [];
        let indexPush = [];
        let elIndex = 0;
        let parentIndex = [];
        $(`${targetElement}`).parent().addClass('ghost-dropdown-menu');
        // Find Dropdown parent element
        parentEl.each(function(index, element) {
            if ($(this).text().indexOf(hasChildDetectText) >= 0) {
                parentIndex.push(index); // Make dropdown parent array index
                parentLen++;
                $(this).push(element);
                $(this).addClass(hasChildrenClasses); // Add class in dropdown element
                $(this).append(`<ul class='${submenuUlClasses}'></ul>`); // Append submenu element
                $(targetElement).css("opacity", "1");
            }
        });
        $(`.${hasChildrenClasses}`).append(hasChildrenIcon);
        // Using loop to reach dropdown parent element
        for (let i = 0; i < parentLen; i++) {
            elIndex = 0 // Initial element value
            // Find subitem element
            childEL.each(function(index, element) {
                let subitem = $(this).text().includes(subitemDetectText); // Find subitem element
                if (subitem) {
                    if (elIndex >= parentIndex[i + 1]) { // Each loop will be break
                        return false; //Stoped each loop 
                    }
                    if (elIndex <= parentIndex[i + 1] || elIndex >= parentIndex[parentIndex.length - 1]) {
                        if (!indexPush.includes(index)) { //Check if not index already insert 
                            $(this).addClass(subitemLiClasses); // Add class in subitem element
                            let st = $(this).children().text(); // Find subitem inner text
                            $(this).children().text(st.replaceAll(subitemDetectText, "")); // Replace subitem inner text
                            domArrayElement.push(element); // Incert subitem element in dom array
                            indexPush.push(index); // incert subitem index in indexPush array
                        }
                    }
                }
                elIndex++; // increase element index value
            });
            $(`.${hasChildrenClasses} ul.${submenuUlClasses}:eq(${i})`).append(domArrayElement); // Append related subitem dom element into submenu 
            // console.log(domArrayElement);
            domArrayElement = []; // Make dom array element empty. 
        }
        const hasChildEl = $(`.${hasChildrenClasses}`);
        hasChildEl.each(function() {
            if ($(this).find("> a:first").text().includes(hasChildDetectText)) {
                console.log($(this).find("> a").text());
                let hasChildText = $(this).find("> a:first").text(); // Find has child inner text
                $(this).find("> a:first").text(hasChildText.replaceAll(hasChildDetectText, ""));
            }
        });
    }
    $(document).ready(function() {
        ghost_dropdown();
    });
}(jQuery));
</script>

Then, just add the menu items in your ghost admin dashboard like so…


The above code should work as-is in Casper for single-level dropdown menus, but you might need to adapt the CSS to fit your and/or tweak the selectors for other themes.

**If you need multi-level drop downs, or full mega-menus that you can also manage strictly through the admin interface, @themeix Newsfeed Theme has that as well.

3 Likes

With Casper 5.X the CSS
Captura de pantalla 2022-06-02 a las 20.12.15
not work correctly…

@Joan thanks for testing that. I’ve corrected the Header Injection code snippet above so it works correctly in the current Casper.

1 Like

Great post… it will help others. Thanks mate for your sharing.

Now yes! Thanks you so much! It’s would possible to add a divider between two links in submenu?

@Joan – so, to add lines below each submenu item (except the last one, which would look strange) like this…

You need to modify the CSS like so…

ul.ghost-submenu li {
    list-style: none;
    white-space: nowrap;
    border-bottom: 1px solid #ddd;
}
    
ul.ghost-submenu li:last-child {
    border: none;
}

So you are adding the following into the CSS…

1 Like

Thanks for all mate!!! :slight_smile: