How to bind Alpine js element into a Wordpress walker?

206 Views Asked by At

First i'm sorry about my english, that's not my native langage.

I want create my navigation menu using tailwind and alpine js in Wordpress.

That's my menu :

            <?php
            wp_nav_menu(array(
                'theme_location' => 'main-menu',
                'container' => 'nav',
                'container_class' => 'main-menu',
                'menu_class' => 'flex gap-4 items-center',
                'walker' => new Custom_Walker_Nav_Menu()
            ));
            ?>

Then my walker

class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
    public function start_lvl(&$output, $depth = 0, $args = null) {
        $indent = str_repeat("\t", $depth);

        // Ajoutez la classe 'hidden' pour cacher les sous-menus par défaut
        if ($depth === 0 && $args->walker->has_children) {
            // Cet élément principal de niveau 0 a des enfants, ajoutons la classe spéciale
            $output .= "$indent<ul x-show=\"open\" x-bind=\"dialog\" class=\"parent-menu-nav\">\n";
        } else {
            // Utilisez la classe par défaut pour les autres cas
            $output .= "$indent<ul class=\"sub-menu\">\n";
        }
        
    }

    public function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) {
        $indent = ($depth) ? str_repeat("\t", $depth) : '';
        $class_names = $value = '';
        $attributes = '';
    
        // Ajoutez ici les classes que vous souhaitez pour chaque élément de menu
        $classes = empty($item->classes) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;
    
        // Vérifiez si l'élément de menu a des sous-menus et ajoutez une classe spéciale
        if (in_array('menu-item-has-children', $item->classes)) {
            $classes[] = 'has-submenu';
    
            // Ajoutez les attributs Alpine.js uniquement si l'élément a des enfants
            // $attributes .= ' x-data="{ open: false }"';
            $attributes .= ' x-bind="trigger"';
        }
    
        $output .= $indent . '<li id="menu-item-' . $item->ID . '" ' . $value . ' class="' . implode(' ', $classes) . '"' . $attributes . '>';
    
        // Générez le lien de l'élément de menu
        $attributes .= !empty($item->url) ? ' href="' . esc_url($item->url) . '"' : '';
        $attributes .= !empty($item->target) ? ' target="' . esc_attr($item->target) . '"' : '';
        $attributes .= !empty($item->xfn) ? ' rel="' . esc_attr($item->xfn) . '"' : '';
        $attributes .= !empty($item->title) ? ' title="' . esc_attr($item->title) . '"' : '';
    
        $item_output = $args->before;
            // Ajoutez une div pour l'élément parent et les enfants
        if (in_array('menu-item-has-children', $item->classes)) {
            $item_output .= '<div class="submenuDiv relative"
            x-data="{ open: false }" @mouseenter="open = true" @mouseleave="open = false"
            x-data="drop()"
            >';
        } 

        $item_output .= '<a' . $attributes . '>';
        $item_output .= $args->link_before . apply_filters('the_title', $item->title, $item->ID) . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
    }


    public function end_el(&$output, $item, $depth = 0, $args = null) {
        $item_output = $args->before;
        $item_output .= $args->after;
        if (in_array('menu-item-has-children', $item->classes)) {
            $item_output .= '</div>';
        }
        $output .= "</li>\n";
    }
}

Sorry it's a bit long.

I have encountered two distinct issues in my project. First, I've successfully implemented the basic x-show feature from Alpine.js, which allows me to toggle the visibility of an element. However, when I added the "absolute top-10" class to this element, the dropdown closes immediately as soon as I move my cursor away from the trigger element. This behavior is not what I intend; instead, I want the dropdown to remain open when I hover over both the trigger and the dropdown menu. To address this, I'm attempting to utilize the x-bind directive.

The second issue relates to my attempt to integrate the x-bind directive into my code. However, I encountered two challenges:

First, I need to use an "id" to bind each individual element, but my initial attempt to do so was unsuccessful. Second, I encountered an error message stating that "trigger," "dialog," and "drop" are "not defined" in my code.

Here my index.js

import Alpine from 'alpinejs'

window.Alpine = Alpine

document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
    open: false,

    trigger: {
        ['x-ref']: 'trigger',
        ['@mouseenter']() {
            this.open = true;
        },
    },

    dialogue: {
        ['x-show']() {
            return this.open;
        },
        ['@mouseleave']() {
            this.open = false;
        },
    },
}))
});
Alpine.start()

Can you please give me some advice about :

  • the "not defined" (maybe i need to add the alpine script into the walker directly?)
  • how to bind dynamically my differents triggers and dialogs element?

Thank you.

0

There are 0 best solutions below