Walker pentru Meniu Mega
Încerc să creez un walker pentru meniu mega. Din păcate, walker-ele depășesc cunoștințele mele de codare. Aș avea nevoie de ajutor pentru a-l face funcțional. Iată caracteristicile de care am nevoie:
- Înconjoară al doilea nivel
<ul>
într-un<section>
. [COMPLET] - Când un utilizator setează clasa "break" pe un
<li>
din al doilea nivel<ul>
, să facă acel<li>
să înceapă un nou<ul>
. Dacă este primul<li>
din listă, să nu facă nimic, pentru a preveni formarea de liste neordonate goale. [COMPLET] - Când un utilizator setează clasa "widget" pe un
<li>
din primul nivel care are un sub<ul>
, să adauge un widget la sfârșitul acelui<ul>
. [COMPLET] - Să adauge clasa
mega-menu-columns-#
la elementele<li>
de prim nivel care conțin meniuri derulante cu multiple coloane și/sau un widget. # reprezintă numărul de elemente<ul>
, +1 pentru widget dacă există. [COMPLET]
Am un pic de cod care face unele dintre aceste lucruri, dar nu pe toate. Există secțiuni tăiate mai jos:
Înconjoară al doilea nivel <ul>
în <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";
}
}
Generează HTML-ul pentru widget:
ob_start();
dynamic_sidebar("Navigation Callout");
$widget = ob_get_contents();
ob_end_clean();
HTML-ul rezultat ar fi:
<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/">
Despre Noi
</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/">
Profilul Companiei
</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/">
Echipa de Conducere
</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/">
Afilieri Profesionale
</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/">
Clienți
</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/">
Parteneriate
</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/">
Servicii
</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/">
Inginerie Civilă
</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/">
Planificare Terenuri
</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/">
Topografie
</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/">
Tehnologia Informației
</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/">
Inginerie Subterană
</a>
</li>
</ul>
<aside>
<h6>Titlu Widget</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/">
Contactați-ne
</a>
</li>
</ul>
ACTUALIZARE: Contoarele mele îmi dau bătăi de cap. Numără doar după ce a fost generat submeniul, ceea ce nu mă ajută. Uită-te la această captură de ecran pentru a înțelege ce vreau să spun:
Numerele de sus sunt preluate în start_el
. Numerele de jos sunt preluate în end_el
. După cum poți vedea, numerele de sus nu numără clasele mele .breaks
așa cum ar trebui. Numără clasa widget pentru că acelea sunt numărate în $depth = 0
. Cineva, vă rog, să mă salveze de această grozăvie!
// walker pentru meniu mega
/*
UN BUG RĂMAS:
- Trebuie să adaug clasa la LI care conține mega-menu-columns-#
*/
class megaMenuWalker extends Walker_Nav_Menu {
private $column_limit = 3; /* trebuie setat pentru fiecare 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) {
/* trebuie adăugat la li de nivel 0 */
$column_count_class = " mega-menu-columns-" . $this->column_count;
$output .= $column_count_class;
/* sfârșit */
$this->column_count = 0;
}
$output .= "</li>";
}
}
ACTUALIZARE 2: Iată un exemplu de output cu comentarii care descriu cum ar trebui să numere clasa mega-menu-columns-
:
<ul>
<!-- +1 pentru că are clasa "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/">
Despre Noi
</a>
<!-- +1 pentru că există un meniu derulant -->
<!-- adăugat de walker-ul meu -->
<section>
<!-- sfârșit adăugat de walker-ul meu -->
<ul class="sub-menu">
<!-- +0 pentru că acest "break" este primul copil -->
<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/">
Profilul Companiei
</a>
<ul>
<!-- +0 pentru că acest "break" este în nivelul 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/">
Echipa Noastră
</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/">
Echipa de Conducere
</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/">
Afilieri Profesionale
</a>
</li>
<!-- adăugat de walker-ul meu -->
</ul>
<ul class="sub-menu">
<!-- sfârșit adăugat de walker-ul meu -->
<!-- +1 pentru că acest "break" este în nivelul 1 și nu este primul copil -->
<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/">
Clienți
</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/">
Parteneriate
</a>
</li>
</ul>
<!-- adăugat de walker-ul meu pentru .widget -->
<section>
<header>
<h1>Titlu Widget</h1>
</header>
<p>Acesta este un widget. A fost greu să-l fac să apară!</p>
</section>
<!-- sfârșit adăugat de walker-ul meu pentru .widget -->
<!-- adăugat de walker-ul meu -->
</section>
<!-- sfârșit adăugat de walker-ul meu -->
</li>
</ul>
ACTUALIZARE: Iată Walker-ul meu final și Funcțiile. Acesta face exact ceea ce am vrut să facă. Mulțumesc pentru ajutor!
// walker pentru meniu mega
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)); // setează array-ul de clase care vor fi adăugate fiecărui 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>";
}
}
// adaugă clase mega-menu-columns-#
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;
};
// adaugă clasele pentru coloane
add_filter("wp_nav_menu_args", function($args) {
if ($args["walker"] instanceof megaMenuWalker) {
add_filter("wp_nav_menu_objects", "add_column_number");
}
return $args;
});
// oprește funcția pentru clasele de coloane
add_filter("wp_nav_menu", function( $nav_menu ) {
remove_filter("wp_nav_menu_objects", "add_column_number");
return $nav_menu;
});
Dacă am înțeles corect configurația problemei, ai putea încerca să numeri clasele break și widget în cadrul filtrului wp_nav_menu_objects
.
Iată un exemplu actualizat, este destul de extins din cauza părții de depanare adăugate:
add_filter( 'wp_nav_menu_objects',
function( $items, $args ) {
// Se aplică doar pentru meniul 'principal':
if( 'primary' !== $args->theme_location )
return $items;
// Aici "x_" se referă la ultimul element li rădăcină (adâncime 0)
static $x_pid = 0; // ID-ul postului ultimului li rădăcină (adâncime 0)
static $x_key = 0; // cheia din array a ultimului li rădăcină (adâncime 0)
static $x_cols = 0; // n break-uri sau widget-uri oferă n+1 coloane
static $x_has_dropdown = false; // dacă ultimul li rădăcină (adâncime 0) are dropdown
// Intern:
$tmp = array();
$debug_string = '';
$show_debug = true; // Modifică după nevoie:
foreach( $items as $key => $item )
{
// Depanare:
$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;
// Colectează incrementele coloanelor:
$inc = 0;
// Adâncime 0:
if( 0 == $item->menu_item_parent )
{
$debug['depth'] = 0;
// Resetează:
$x_key = $key;
$x_pid = $item->ID;
$x_cols = 0;
$x_has_dropdown = false;
// Dacă există clasa widget:
if( in_array( 'widget', $item->classes, 1 ) )
{
$debug['has_widget_class'] = '1';
$inc++;
}
}
// Adâncime 1:
if( $x_pid == $item->menu_item_parent )
{
$debug['depth'] = 1;
// Crește numărul de coloane pentru un dropdown existent:
if( ! $x_has_dropdown )
{
$inc++;
$x_has_dropdown = true;
}
// Verifică clasa 'break':
if( in_array( 'break', $item->classes, 1 ) )
{
$debug['x_has_break_class'] = 1;
// Primul copil li:
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;
// Crește numărul de coloane:
$debug['x_cols_increase'] = $inc;
$x_cols += $inc;
$debug['x_cols'] = $x_cols;
// Colectează informațiile de depanare:
$debug_string .= print_r( $debug, 1 );
} // end foreach
// Afișează informațiile de depanare:
if( $show_debug )
printf( "<!-- debug: %s -->", $debug_string );
// Inserează noua clasă 'mega-menu' în obiectul de meniu corespunzător:
foreach( $t as $key => $value )
{
$items[$key]->classes[] = sprintf( 'mega-menu-columns-%d', $value );
}
return $items;
}
, PHP_INT_MAX, 2 );
Cu structura ta curentă de meniu, primesc aceste informații de depanare:
<!-- debug: Array
(
[ID] => 3316
[title] => Despre Noi
[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] => Profilul Companiei
[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] => Echipa Noastră
[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] => Echipa de Conducere
[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] => Afilieri Profesionale
[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] => Clienți
[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] => Parteneriate
[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
)
-->
Dacă dorești să verifici dacă obiectul walker este de clasa megaMenuWalker
, poți folosi:
if( ! is_object( $args->walker ) || ! is_a( $args->walker, 'megaMenuWalker' ) )
return $items;
în loc de
if( 'primary' !== $args->theme_location )
return $items;
Sper că acest lucru te ajută.

Ciudat, acesta afișează 1 ca număr. Vezi http://hfracquetandfitness.myweblinx.net/ (inspectează primul li din navigația de sus). EDIT -- Cred că știu de ce. Break se adaugă la elementele <li>
copil direct, nu la elementul <li>
curent. Trebuie să verifice dacă este un copil direct, și nu primul copil care are și clasa break
.

Am actualizat răspunsul, aveam o greșeală de scriere (&& în loc de ||).

A, asta a ajutat puțin, dar văd că numără dacă elementul curent de listă are clasa break
. De fapt, trebuie să numere dacă copiii direcți au clasa break
, nu el însuși, și să excludă primul copil li
din ul
copil, dacă are sens.

Presupun că elementele rădăcină <li>
sunt la adâncimea 0
, apoi număr clasele break/widget ale sub-elementelor <li>
de la adâncimea 1
. Cred că ar trebui să încep $x_cols
de la 1
în loc de 0
, deoarece n
break-uri dau n+1
coloane.

Da, ca în walker-ul meu, dacă are orice copii, ar trebui să înceapă de la 1. Vezi întrebarea mea actualizată pentru o descriere mai clară (în ~2 minute).

Nu voi putea testa complet până luni (am uitat să notez datele de login WP înainte să plec de la serviciu), dar se pare că va număra primul copil li
din listă dacă are clasa break`. Trebuie să exclud acel element. Este posibil acest lucru?

Am reușit să resetez parola, acest lucru numără cu siguranță primul li
din listă dacă are clasa break
, ceea ce nu ar trebui să se întâmple.

De fapt, am reușit să rezolv această problemă. Există vreo modalitate de a adăuga asta în Walker sau de a o declanșa când Walker rulează? Aș prefera să configurez un singur lucru când setez acest lucru pe site-uri, în loc de două. Dacă nu, mă pot descurca.

Bine, perfect. Tocmai am actualizat răspunsul, cu câteva informații suplimentare pentru depanare care să te ajute să navighezi prin asta. Sperăm că ne apropiem de soluție. Poate există o modalitate de a face asta în Walker, dar ar trebui să mă gândesc mai mult la asta ;-) În loc să activăm asta pentru meniul principal, am putea folosi altceva pentru a-l declanșa, de exemplu titlul meniului sau un subșir din titlul meniului sau orice altceva preferi ;-)

Am publicat codul meu final mai sus. În mod ideal, ar trebui să se declanșeze de fiecare dată când walker-ul rulează, dar oricum. Mulțumesc pentru ajutor!
