it-swarm.com.de

Mega Menu Walker

Ich versuche einen Mega Menu Walker zu erstellen. Leider entziehen sich Wanderer meinem Codierungswissen vollständig. Ich könnte wirklich etwas Hilfe gebrauchen, damit es funktioniert. Hier sind die Funktionen, die ich brauche:

  • Wickeln Sie den <ul> der zweiten Ebene in <section> ein. [KOMPLETT]
  • Wenn ein Benutzer die Klasse "break" für einen <li> in der zweiten Ebene <ul> festlegt, muss dieser <li> zum Starten eines neuen <ul> verwendet werden. Wenn es der erste <li> in der Liste ist, tun Sie nichts, um die Bildung leerer ungeordneter Listen zu verhindern. [KOMPLETT]
  • Wenn ein Benutzer die Klasse "Widget" für einen <li> in der ersten Ebene mit einem untergeordneten <ul> festlegt, fügen Sie ein Widget an das Ende dieses <ul> an. [KOMPLETT]
  • Fügen Sie die Klasse mega-menu-columns-# zu den <li>-Elementen der ersten Ebene hinzu, die Dropdowns mit mehreren Spalten und/oder einem Widget enthalten. Das # steht für die Anzahl der <ul> -Elemente, +1 für das Widget, falls vorhanden. [KOMPLETT]

Ich habe ein bisschen Code, um etwas davon zu tun, aber nicht alles. Es gibt Ausschnitte unten:

Wrap zweite Ebene <ul> in <section>:

function start_lvl(&$output, $depth = 0, $args = array()) {
    if ($depth == 0) {
        $output .= "<section>";
    }
    $output .= "<ul class=\"sub-menu\">";
}
function end_lvl(&$output, $depth = 0, $args = array()) {
    $output .= "</ul>";
    if ($depth == 0) {
        $output .= "</section>\n";
    }
}

Generiere das Widget HTML:

ob_start();
dynamic_sidebar("Navigation Callout");
$widget = ob_get_contents();
ob_end_clean();

Das Ausgabe-HTML wäre:

<ul>
    <li id="menu-item-1" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-1 mega-menu-columns-2">
        <a href="http://www.example.com/about/">
            About Us
        </a>
        <section>
            <ul class="sub-menu">
                <li id="menu-item-2" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-2">
                    <a href="http://www.example.com/about/company-profile/">
                        Company Profile
                    </a>
                </li>
                <li id="menu-item-3" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-3">
                    <a href="http://www.example.com/about/leadership-team/">
                        Leadership Team
                    </a>
                </li>
                <li id="menu-item-4" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4">
                    <a href="http://www.example.com/about/professional-affiliations/">
                        Professional Affiliations
                    </a>
                </li>
            </ul>
            <ul class="sub-menu">
                <li id="menu-item-5" class="break menu-item menu-item-type-post_type menu-item-object-page menu-item-5">
                    <a href="http://www.example.com/about/clients/">
                        Clients
                    </a>
                </li>
                <li id="menu-item-6" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-6">
                    <a href="http://www.example.com/about/partnerships/">
                        Partnerships
                    </a>
                </li>
            </ul>
        </section>
    </li>
    <li id="menu-item-7" class="widget menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-7 mega-menu-columns-3">
        <a href="http://www.example.com/services/">
            Services
        </a>
        <section>
            <ul class="sub-menu">
                <li id="menu-item-8" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-8">
                    <a href="http://www.example.com/services/civil-engineering/">
                        Civil Engineering
                    </a>
                </li>
                <li id="menu-item-9" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-9">
                    <a href="http://www.example.com/services/land-planning/">
                        Land Planning
                    </a>
                </li>
                <li id="menu-item-10" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-10">
                    <a href="http://www.example.com/services/surveying/">
                        Surveying
                    </a>
                </li>
            </ul>
            <ul class="sub-menu">
                <li id="menu-item-11" class="break menu-item menu-item-type-post_type menu-item-object-page menu-item-11">
                    <a href="http://www.example.com/services/information-technology/">
                        Information Technology
                    </a>
                </li>
                <li id="menu-item-12" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-12">
                    <a href="http://www.example.com/services/subsurface-utility-engineering/">
                        Subsurface Utility Engineering
                    </a>
                </li>
            </ul>
            <aside>
                <h6>Widget Title</h6>
                <p>Maecenas quis semper arcu. Quisque consequat risus nisi. Sed venenatis urna porta eros malesuada euismod. Nulla sollicitudin fringilla posuere. Nulla et tellus eu nisi sodales convallis non vel tellus.</p>
            </aside>
        </section>
    </li>
    <li id="menu-item-13" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-15">
        <a href="http://www.example.com/contact/">
            Contact Us
        </a>
    </li>
</ul>

UPDATE: Meine Zähler geben mir Kummer. Sie zählen erst, nachdem das Untermenü erstellt wurde, was mir nicht hilft. Sehen Sie sich diesen Screenshot an, um zu verstehen, was ich meine:

Die Top-Nummern werden in start_el gezogen. Die unteren Zahlen werden in end_el gezogen. Wie Sie sehen, zählen die Top-Nummern meinen .breaks nicht so, wie sie sollten. Sie zählen die Widget-Klasse, weil diese in $depth = 0 gezählt werden. Jemand bitte rette mich vor dieser Schrecklichkeit!

// mega menu walker
/*
    ONE REMAINING BUG:
    - Need to add class to LI containing mega-menu-columns-#
*/
class megaMenuWalker extends Walker_Nav_Menu {
    private $column_limit = 3; /* needs to be set for each site */
    private $show_widget = false;
    private $column_count = 0;
    static $li_count = 0;
    function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
        $classes = empty($item->classes) ? array() : (array) $item->classes;
        $item_id = $item->ID;
        if ($depth == 0) self::$li_count = 0;
        if ($depth == 0 && in_array("widget", $classes)) {
            $this->show_widget = true;
            $this->column_count++;
        }
        if ($depth == 1 && self::$li_count == 1) {
            $this->column_count++;
        }
        if ($depth == 1 && in_array("break", $classes) && self::$li_count != 1 && $this->column_count < $this->column_limit) {
            $output .= "</ul><ul class=\"sub-menu\">";
            $this->column_count++;
        }
        if ($depth == 0 && $this->column_count > 0) {
            $mega_menu_class = " mega-menu-columns-" . $this->column_count;
        }
        $class_names = join(" ", apply_filters("nav_menu_css_class", array_filter($classes), $item));
        $class_names = " class=\"" . esc_attr($class_names . $mega_menu_class) . "\"";
        $output .= sprintf(
            "<li id=\"menu-item-%s\"%s><a href=\"%s\">%s</a>",
            $item_id,
            $class_names,
            $item->url,
            $item->title
        );
        self::$li_count++;
    }
    function start_lvl(&$output, $depth = 0, $args = array()) {
        if ($depth == 0) {
            $output .= "<section>";
        }
        $output .= "<ul class=\"sub-menu\">";
    }
    function end_lvl(&$output, $depth = 0, $args = array()) {
        $output .= "</ul>";
        if ($depth == 0) {
            if ($this->show_widget) {
                ob_start();
                dynamic_sidebar("Navigation Callout");
                $widget = ob_get_contents();
                ob_end_clean();
                $output .= $widget;
                $this->show_widget = false;
            }
            $output .= "</section>";
        }
    }
    function end_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
        if ($depth == 0 && $this->column_count > 0) {
            /* needs to be added to opening level 0 li */
            $column_count_class = " mega-menu-columns-" . $this->column_count;
            $output .= $column_count_class;
            /* end */
            $this->column_count = 0;
        }
        $output .= "</li>";
    }
}   

UPDATE 2: Hier ist ein Beispiel für eine Ausgabe mit Kommentaren, die beschreiben, wie die Klasse mega-menu-columns- die Dinge zählen soll:

<ul>
    <!-- +1 because this has a class of "widget" -->
    <li id="menu-item-1" class="widget menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-1 mega-menu-columns-3">
        <a href="http://www.example.com/about/">
            About Us
        </a>
        <!-- +1 because a drop down exists -->
        <!-- gets added by my walker -->
        <section>
        <!-- end gets added by my walker -->
            <ul class="sub-menu">
                <!-- +0 because this "break" is the first child -->
                <li id="menu-item-2" class="break menu-item menu-item-type-post_type menu-item-object-page menu-item-2">
                    <a href="http://www.example.com/about/company-profile/">
                        Company Profile
                    </a>
                    <ul>
                        <!-- +0 because this "break" is in level 2 -->
                        <li id="menu-item-3" class="break menu-item menu-item-type-post_type menu-item-object-page menu-item-3">
                            <a href="http://www.example.com/about/our-team/">
                                Our Team
                            </a>
                        </li>
                    </ul>
                </li>
                <li id="menu-item-4" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-4">
                    <a href="http://www.example.com/about/leadership-team/">
                        Leadership Team
                    </a>
                </li>
                <li id="menu-item-5" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-5">
                    <a href="http://www.example.com/about/professional-affiliations/">
                        Professional Affiliations
                    </a>
                </li>
            <!-- gets added by my walker -->
            </ul>
            <ul class="sub-menu">
            <!-- end gets added by my walker -->
                <!-- +1 because this "break" is in level 1 and not the first child -->
                <li id="menu-item-6" class="break menu-item menu-item-type-post_type menu-item-object-page menu-item-6">
                    <a href="http://www.example.com/about/clients/">
                        Clients
                    </a>
                </li>
                <li id="menu-item-7" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-7">
                    <a href="http://www.example.com/about/partnerships/">
                        Partnerships
                    </a>
                </li>
            </ul>
            <!-- gets added by my walker for .widget -->
            <section>
                <header>
                    <h1>Widget Title</h1>
                </header>
                <p>This is a widget. It was hard to make appear!</p>
            </section>
            <!-- end gets added by my walker for .widget -->
        <!-- gets added by my walker -->
        </section>
        <!-- end gets added by my walker -->
    </li>
</ul>

UPDATE: Hier ist meine letzte Walker und Funktionen. Das macht genau was ich wollte. Danke für die Hilfe!

// mega menu walker
class megaMenuWalker extends Walker_Nav_Menu {
    private $column_limit = 3;
    private $show_widget = false;
    private $column_count = 0;
    static $li_count = 0;
    function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
        $classes = empty($item->classes) ? array() : (array) $item->classes;
        $item_id = $item->ID;
        if ($depth == 0) {
            self::$li_count = 0;
        }
        if ($depth == 0 && in_array("widget", $classes)) {
            $this->show_widget = true;
            $this->column_count++;
        }
        if ($depth == 1 && self::$li_count == 1) {
            $this->column_count++;
        }
        if ($depth == 1 && in_array("break", $classes) && self::$li_count != 1 && $this->column_count < $this->column_limit) {
            $output .= "</ul><ul class=\"sub-menu\">";
            $this->column_count++;
        }
        $class_names = join(" ", apply_filters("nav_menu_css_class", array_filter($classes), $item)); // set up the classes array to be added as classes to each li
        $class_names = " class=\"" . esc_attr($class_names) . "\"";
        $output .= sprintf(
            "<li id=\"menu-item-%s\"%s><a href=\"%s\">%s</a>",
            $item_id,
            $class_names,
            $item->url,
            $item->title
        );
        self::$li_count++;
    }
    function start_lvl(&$output, $depth = 0, $args = array()) {
        if ($depth == 0) {
            $output .= "<section>";
        }
        $output .= "<ul class=\"sub-menu\">";
    }
    function end_lvl(&$output, $depth = 0, $args = array()) {
        $output .= "</ul>";
        if ($depth == 0) {
            if ($this->show_widget) {
                ob_start();
                dynamic_sidebar("Navigation Callout");
                $widget = ob_get_contents();
                ob_end_clean();
                $output .= $widget;
                $this->show_widget = false;
            }
            $output .= "</section>";
        }
    }
    function end_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
        if ($depth == 0 && $this->column_count > 0) {
            $this->column_count = 0;
        }
        $output .= "</li>";
    }
}

// add mega-menu-columns-# classes
function add_column_number($items, $args) {
    static $column_limit = 3;
    static $post_id = 0;
    static $x_key = 0;
    static $column_count = 0;
    static $li_count = 0;
    $tmp = array();
    foreach($items as $key => $item) {
        if (0 == $item->menu_item_parent) {
            $x_key = $key;
            $post_id = $item->ID;
            $column_count = 0;
            $li_count = 0;
            if (in_array("widget", $item->classes, 1)) {
                $column_count++;
            }
        }
        if ($post_id == $item->menu_item_parent) {
            $li_count++;
            if ($column_count < $column_limit && $li_count == 1) {
                $column_count++;
            }
            if (in_array("break", $item->classes, 1) && $li_count > 1 && $column_count < $column_limit) {
                $column_count++;
            }
            $tmp[$x_key] = $column_count;
        }
    }
    foreach($tmp as $key => $value) {
        $items[$key]->classes[] = sprintf("mega-menu-columns-%d", $value);
    }
    unset($tmp);
    return $items;
};

// add the column classes
add_filter("wp_nav_menu_args", function($args) {
    if ($args["walker"] instanceof megaMenuWalker) {
        add_filter("wp_nav_menu_objects", "add_column_number");
    }
    return $args;
});

// stop the column classes function
add_filter("wp_nav_menu", function( $nav_menu ) {
    remove_filter("wp_nav_menu_objects", "add_column_number");
    return $nav_menu;
});
10
JacobTheDev

Wenn ich das Problemsetup richtig verstehe, können Sie versuchen, die break und widget class im wp_nav_menu_objects-Filter zu zählen.

Hier ist ein aktualisiertes Beispiel, das aufgrund des zusätzlichen Debug-Teils etwas erweitert wurde:

add_filter( 'wp_nav_menu_objects', 
    function( $items, $args  ) {

        // Only apply this for the 'primary' menu:    
        if( 'primary' !== $args->theme_location ) 
            return $items;

        // Here "x_" means the latest root li (depth 0)
        static $x_pid           = 0;      // post ID of the latest root li (depth 0) 
        static $x_key           = 0;      // array key of the latest root li (depth 0)
        static $x_cols          = 0;      // n breaks or widgets gives n+1 columns  
        static $x_has_dropdown  = false;  // if the latest root li (depth 0) has dropdown

        // Internals:
        $tmp            = array();  
        $debug_string   = '';
        $show_debug     = true;  // Edit this to your needs:

        foreach( $items as $key => $item )
        {
            // Debug:
            $debug                              = array();
            $debug['ID']                        = $item->ID;
            $debug['title']                     = $item->title;
            $debug['key']                       = $key;
            $debug['x_key']                     = $x_key;
            $debug['depth']                     = '';
            $debug['menu_item_parent']          = $item->menu_item_parent;
            $debug['has_widget_class']          = 0;
            $debug['is_depth_1_first_child']    = 0;
            $debug['x_has_dropdown']            = 0;
            $debug['has_break_class']           = 0;
            $debug['x_cols_increase']           = 0;

            // Collect columns increaments:
            $inc = 0;

            // Depth 0:
            if( 0 == $item->menu_item_parent )
            {
                $debug['depth'] = 0;

                // Resets:
                $x_key          = $key;
                $x_pid          = $item->ID;                            
                $x_cols         = 0;
                $x_has_dropdown = false;

                // If widget class exists:
                if( in_array( 'widget', $item->classes, 1 ) )
                {
                    $debug['has_widget_class'] = '1';
                    $inc++; 
                }       
            }

            // Depth 1:
            if( $x_pid == $item->menu_item_parent )
            {   
                $debug['depth'] = 1;

                // Increase the columns count for an existing dropdown:
                if( ! $x_has_dropdown )
                {
                    $inc++;
                    $x_has_dropdown = true;
                }

                // Check for the 'break' class: 
                if( in_array( 'break', $item->classes, 1 ) )
                {
                    $debug['x_has_break_class'] = 1;

                    // First li child:
                    if( $x_key+1 == $key+0 )
                    {
                        $debug['is_depth_1_first_child'] = 1;
                    }
                    else
                    {
                        $debug['is_depth_1_first_child'] = 0;
                        $inc++; 
                    }
                }

                $t[$x_key] = $x_cols;
            }           

            $debug['x_has_dropdown'] = (int) $x_has_dropdown;

            // Increase the columns count:
            $debug['x_cols_increase'] = $inc;           
            $x_cols += $inc;
            $debug['x_cols'] = $x_cols;

            // Collect the debug:
            $debug_string .= print_r( $debug, 1 );
        } // end foreach

        // Show debug info:
        if( $show_debug ) 
            printf( "<!-- debug: %s -->", $debug_string );

        // Insert the new 'mega menu' class to the corresponding menu object:
        foreach( $t as $key => $value )
        {
            $items[$key]->classes[] = sprintf( 'mega-menu-columns-%d', $value );
        }

        return $items;

    }
, PHP_INT_MAX, 2 );

Mit Ihrem aktuellen Menübaum erhalte ich folgende Debug-Informationen:

<!-- debug: Array
(
    [ID] => 3316
    [title] => About Us
    [key] => 1
    [x_key] => 0
    [depth] => 0
    [menu_item_parent] => 0
    [has_widget_class] => 1
    [is_depth_1_first_child] => 0
    [x_has_dropdown] => 0
    [has_break_class] => 0
    [x_cols_increase] => 1
    [x_cols] => 1
)
Array
(
    [ID] => 3317
    [title] => Company Profile
    [key] => 2
    [x_key] => 1
    [depth] => 1
    [menu_item_parent] => 3316
    [has_widget_class] => 0
    [is_depth_1_first_child] => 1
    [x_has_dropdown] => 1
    [has_break_class] => 0
    [x_cols_increase] => 1
    [x_has_break_class] => 1
    [x_cols] => 2
)
Array
(
    [ID] => 3318
    [title] => Our Team
    [key] => 3
    [x_key] => 1
    [depth] => 
    [menu_item_parent] => 3317
    [has_widget_class] => 0
    [is_depth_1_first_child] => 0
    [x_has_dropdown] => 1
    [has_break_class] => 0
    [x_cols_increase] => 0
    [x_cols] => 2
)
Array
(
    [ID] => 3319
    [title] => Leadership Team
    [key] => 4
    [x_key] => 1
    [depth] => 1
    [menu_item_parent] => 3316
    [has_widget_class] => 0
    [is_depth_1_first_child] => 0
    [x_has_dropdown] => 1
    [has_break_class] => 0
    [x_cols_increase] => 0
    [x_cols] => 2
)
Array
(
    [ID] => 3320
    [title] => Professional Affiliations
    [key] => 5
    [x_key] => 1
    [depth] => 1
    [menu_item_parent] => 3316
    [has_widget_class] => 0
    [is_depth_1_first_child] => 0
    [x_has_dropdown] => 1
    [has_break_class] => 0
    [x_cols_increase] => 0
    [x_cols] => 2
)
Array
(
    [ID] => 3321
    [title] => Clients
    [key] => 6
    [x_key] => 1
    [depth] => 1
    [menu_item_parent] => 3316
    [has_widget_class] => 0
    [is_depth_1_first_child] => 0
    [x_has_dropdown] => 1
    [has_break_class] => 0
    [x_cols_increase] => 1
    [x_has_break_class] => 1
    [x_cols] => 3
)
Array
(
    [ID] => 3322
    [title] => Partnerships
    [key] => 7
    [x_key] => 1
    [depth] => 1
    [menu_item_parent] => 3316
    [has_widget_class] => 0
    [is_depth_1_first_child] => 0
    [x_has_dropdown] => 1
    [has_break_class] => 0
    [x_cols_increase] => 0
    [x_cols] => 3
)
 -->

Wenn Sie überprüfen möchten, ob das Walker-Objekt zur Klasse megaMenuWalker gehört, können Sie Folgendes verwenden:

if( ! is_object( $args->walker ) || ! is_a( $args->walker, 'megaMenuWalker' ) )
    return $items;

anstatt

if( 'primary' !== $args->theme_location ) 
            return $items;

Ich hoffe das hilft.

7
birgire