WordPress – woher weiß ich, ob ein Menüpunkt Kinder hat?

Lesezeit: 9 Minuten

Wordpress woher weis ich ob ein Menupunkt Kinder hat
kikito

Ich entwickle ein WordPress-Theme mit verschachtelten Untermenüs. Ich muss die Elemente ohne Kinder optisch von denen mit Kindern unterscheiden. Im Moment habe ich dieses Menü, aber das könnte sich ändern:

A
  a1
  a2
B
  b1
  b2
C

Wie Sie sehen können, haben A und B Kinder. C nicht – ich brauche es, um in der CSS-Ebene anders zu sein.

Idealerweise hätte ich gerne eine has-children Klasse in A und B, aber nicht in C.

Bisher habe ich es geschafft, eine „Menu Walker“-PHP-Klasse zu erstellen, die ich instanziieren und an die ich übergeben kann wp_nav_menu . Sein Konstruktor sieht so aus:

class My_Walker_Nav_Menu extends Walker_Nav_Menu {
  function start_el(&$output, $item, $depth, $args) {
    ...
    if(??? $item has children???) {
      // I know what to do here
    }
  }
}

Also, wie erkenne ich, ob $item hat Kinder, oder ist ein Blatt?

BEARBEITEN: Diese Frage wurde von jemandem namens “keesiemeijer” in den WordPress-Foren beantwortet. Ich lasse dieses Kopfgeld verfallen, nur für den Fall, dass er es zurückfordern will. Andernfalls werde ich meine eigene Antwort als gültig markieren.

1645907952 772 Wordpress woher weis ich ob ein Menupunkt Kinder hat
janw

Fügen Sie dies hinzu functions.php es wird die ‘Dropdown’-Klasse zu den Eltern hinzufügen

Neue Weise besser für Leistung

function menu_set_dropdown( $sorted_menu_items, $args ) {
    $last_top = 0;
    foreach ( $sorted_menu_items as $key => $obj ) {
        // it is a top lv item?
        if ( 0 == $obj->menu_item_parent ) {
            // set the key of the parent
            $last_top = $key;
        } else {
            $sorted_menu_items[$last_top]->classes['dropdown'] = 'dropdown';
        }
    }
    return $sorted_menu_items;
}
add_filter( 'wp_nav_menu_objects', 'menu_set_dropdown', 10, 2 );

Alt: intensiv auf der DB

add_filter( 'nav_menu_css_class', 'check_for_submenu', 10, 2);
function check_for_submenu($classes, $item) {
    global $wpdb;
    $has_children = $wpdb->get_var("SELECT COUNT(meta_id) FROM wp_postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value="".$item->ID.""");
    if ($has_children > 0) array_push($classes,'dropdown'); // add the class dropdown to the current list
    return $classes;
}

  • Beachten Sie, dass diese Methode eine weitere Datenbankabfrage für jeden Ihrer Menüpunkte hinzufügt und Ihre Website verlangsamen kann, wenn Sie viele Menüpunkte haben!

    – Ahrengot

    9. Januar 2013 um 22:36 Uhr

  • @Ahrengot sehe meinen neuen Weg viel besser für die Datenbank;)

    – jaw

    10. Januar 2013 um 16:13 Uhr

  • es hat keine wirkung in wp 3.6? etwas anderes hinzuzufügen oder zu entfernen? ich benutze wp_nav_menu()

    – ausschlaggebend

    30. September 2013 um 14:36 ​​Uhr

  • @RashidShafique es funktioniert in 3.6 Hast du ein Menü in der zugewiesen wp-admin? Habe es mit einer sauberen Installation getestet twentyeleven und kein anderes Plugin

    – jaw

    30. September 2013 um 18:37 Uhr

  • Tolle Lösung, aber hat jemand eine Idee, warum dies in Unter-Untermenüs nicht funktioniert? (ein Dropdown-Menü in einem Dropdown-Menü)

    – radu.luchian

    24. Februar 2014 um 14:46 Uhr

Wordpress woher weis ich ob ein Menupunkt Kinder hat
Sternennacht.1406

Einfach so verwenden:

Erklären Sie: Ich erstelle ein Menü mit “Walker”:

$walker = new Nav_Walker;
wp_nav_menu(array(
        'container'=>'nav',
        'container_class'=>'menu',
        'menu_class'=>'list-unstyled list-inline',
        'walker'=>$walker
    ));

Klasse Walker:

class Nav_Walker extends Walker_Nav_Menu
{ 
      public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
    {
        if($args->walker->has_children)
        {
            //code...
        }   
    }
}

Wir haben das Objekt ‘Walker’, das können Sie var_dump($args) um mehr Dinge zu sehen. Ich verwende für mein Projekt!

  • Willkommen bei SO, Sternennacht und vielen Dank für Ihre erste Antwort. Einige Ratschläge, um eine bessere Punktzahl für Ihre Antworten zu erhalten: Fügen Sie eine Erklärung dazu bei warum Ihr Code wird das Problem des OP lösen.

    – nikolaus-hee

    29. Juni 2015 um 4:27 Uhr

1645907954 382 Wordpress woher weis ich ob ein Menupunkt Kinder hat
Jörg Bucaran

Das Problem scheint endlich gelöst zu sein. Die neueste WordPress-Beta ab aktuellem Schreiben 4.0 hat die Walker_Nav_Menu-Klasse aktualisiert und eine hinzugefügt $has_children Eigentum.

/**
 * Whether the current element has children or not.
 *
 * To be used in start_el().
 *
 * @since 4.0.0
 * @access protected
 * @var bool
 */
protected $has_children;

Also müssen wir nicht hacken function display_element(...) mehr.

  • Ja, es wird jetzt automatisch hinzugefügt.

    – Salem

    6. Februar um 6:47 Uhr

Ich fragte im WordPress-Forum und keesiemeijer hat mich darauf hingewiesen dieser andere Beitragin dem sie Folgendes taten:

Anstatt zu modifizieren start_elsie modifizierten display_elementindem Sie die folgenden zwei Zeilen hinzufügen (Zeile 37-38 Hier):

//display this element (THESE ARE NOT THE LINES)
if ( is_array( $args[0] ) )
  $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );

// THESE TWO ARE THE LINES:               
if( ! empty( $children_elements[$element->$id_field] ) )
  array_push($element->classes,'parent');

Ich habe die beiden vorherigen Zeilen als räumliche Referenz und auch als Kommentar zu anderen Antworten in diesem Beitrag hinterlassen. Es scheint, dass WordPress “versucht”, eine ´has_children´-Eigenschaft zu setzen $args, aber es macht es entweder falsch oder auf eine Weise, die ich nicht verstehe. Das jedenfalls has_children Parameter wird niemals weitergegeben start_el (siehe Beispiel var_dump einer $args Hier)

Dies könnte ein Fehler in der WordPress-Version sein, die ich habe (3.2.1), und wurde möglicherweise in der neuesten Version behoben.

Auf jeden Fall ist die Antwort, die ich im WordPress-Forum erhalten habe, diejenige, die mir geholfen hat, das Problem zu beheben, also betrachte ich das als erledigt. Ich werde warten, bis das Kopfgeld abgelaufen ist, falls Keesiemeijer seine Antwort hier posten möchte.

class My_Walker_Nav_Menu extends Walker_Nav_Menu {
  function start_el(&$output, $item, $depth, $args) {
    ...
    if($args['has_children']) {
      // I know what to do here
    }
  }
}

  • Ich fürchte, das wird nicht funktionieren. Aus zwei Gründen – erstens, $args ist ein stdObjectnicht ein array – so wäre die Syntax $args->has_children. Und zweitens, $args hat kein has_children Attribut (Ich habe mit überprüft var_dump($args)). Weder es noch $item scheinen ein solches Attribut zu haben.

    – kikito

    12. Dezember 2011 um 10:16 Uhr

  • @kikito könntest du die Ergebnisse von var_dump($args) posten?

    – Eugen Manuilov

    12. Dezember 2011 um 12:43 Uhr

  • @kikito seltsam, es hat “has_children” arg an meinem Ende.

    – Eugen Manuilow

    13. Dezember 2011 um 15:27 Uhr

  • if ($args->walker->has_children)

    – Steven Vachon

    9. Februar 2016 um 0:50 Uhr

1645907955 213 Wordpress woher weis ich ob ein Menupunkt Kinder hat
Gemeinschaft

Kikitos obige Antwort macht den Trick fertig, aber nicht auf die wiederverwendbarste Weise. Meiner Meinung nach ist der bessere Ansatz so:

function display_element($element, &$children_elements, $max_depth, $depth=0, $args, &$output) {
    // the first few lines of the method...

    //display this element; handle either arrays or objects gracefully
    if ( is_array( $args[0] ) )
        $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );

    elseif ( is_object($args[0]) )
        $args[0]->has_children =  ! empty( $children_elements[$element->$id_field] );

    // the rest of the method...
}

Überschreiben Walker::display_element() ist der richtige Schritt, aber es ist aus zwei Gründen besser, das Problem tatsächlich an der Wurzel des Problems anzugehen, als an dieser Stelle einfach eine Klasse anzuhängen. Erstens ist das eigentliche Problem nicht eine fehlende Klasse, sondern der nicht gepatchte Fehler in WordPress, den Kikito bemerkt hat: Das Problem ist das $args[0] ist nicht immer ein Array. Das scheint der typische erwartete Typ für zu sein Walker::display_element()aber eigentlich haben wir es hier mit zu tun Walker_Nav_Menu::display_element()und in diesem Fall args wird als Standardobjekttyp und nicht als Arraytyp übergeben. Als solche müssen wir einfach die hinzufügen has_children -Element, das die Objektnotation anstelle der Array-Notation verwendet. Problem gelöst![1]

Das hinzufügen elseif Konten für den gewöhnlichen Nav-Menü-Fall. Dies ist die gleiche Form, die es hoffentlich in die Kernklasse schaffen wird dieser Patch, dann müssen Sie es nicht mehr verlängern. Sie sollten es wahrscheinlich weiter patchen, um den Fall zu berücksichtigen $args[0] ist weder ein Array noch ein Objekt, aber ich erwarte nicht, dass das passiert.

Zweitens, um eine gute Trennung zwischen den verschiedenen Methoden zu gewährleisten, sollten wirklich Klassen in hinzugefügt werden start_el() Methode oder anderswo, da display_element() tut nichts von der Klassenhandhabung.

Als Ergebnis können Sie dann überschreiben start_el() wie Sie möchten: Sie können Ihre eigenen benutzerdefinierten Klassen hinzufügen oder Elemente vollständig ignorieren oder benutzerdefinierten Text bereitstellen oder was auch immer Sie möchten. (In meinem Fall arbeite ich um eine vorhandene Javascript-Menüimplementierung herum, die sehr spezifische Klassifizierungsanforderungen basierend auf Eltern hat und Kinder, also kann ich nicht einfach die gleichen Klassen zu allem hinzufügen, was ein Kind hat – genau deshalb ist diese Trennung von Bedenken wichtig.) In meinem Code:

function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
    $class_names = $value="";

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;

    $has_children = (is_object($args) && $args->has_children) || (is_array($args) &&  $args['has_children']);
    if ($has_children) {
        // do whatever you need to do
    }

    // everything else the method does...
}

[1] Dies ist natürlich eine der potenziellen Fallstricke von dynamisch typisierten Sprachen wie PHP … es ist kein Problem, solange Sie vorsichtig sind. Hier haben die WordPress-Entwickler nicht aufgepasst.

  • Ich fürchte, das wird nicht funktionieren. Aus zwei Gründen – erstens, $args ist ein stdObjectnicht ein array – so wäre die Syntax $args->has_children. Und zweitens, $args hat kein has_children Attribut (Ich habe mit überprüft var_dump($args)). Weder es noch $item scheinen ein solches Attribut zu haben.

    – kikito

    12. Dezember 2011 um 10:16 Uhr

  • @kikito könntest du die Ergebnisse von var_dump($args) posten?

    – Eugen Manuilow

    12. Dezember 2011 um 12:43 Uhr

  • @kikito seltsam, es hat “has_children” arg an meinem Ende.

    – Eugen Manuilow

    13. Dezember 2011 um 15:27 Uhr

  • if ($args->walker->has_children)

    – Steven Vachon

    9. Februar 2016 um 0:50 Uhr

1645907956 971 Wordpress woher weis ich ob ein Menupunkt Kinder hat
Zachary Schüssler

Wenn Sie den Aufwand einer harten Abfrage oder Funktion nicht möchten, können Sie dies in jQuery tun:

(function() {
    // Add 'has_children' class to menus
    jQuery.each(jQuery('.menu-item').has('ul.sub-menu'), function() {
        jQuery(this).addClass('has_children');
    });
})();

  • Eine serverseitige PHP-Funktion fügt mit ziemlicher Sicherheit weniger “Overhead” hinzu als ein jQuery-Aufruf am Frontend, insbesondere wenn Sie das Caching berücksichtigen. Darüber hinaus geht diese Lösung (1) davon aus, dass jQuery bereits verwendet wird und (2) dass eine solche Vorgehensweise keine anderen menüorientierten JS im Backend beeinträchtigen würde.

    – Chris Krycho

    18. April 2013 um 14:42 Uhr


  • @ChrisKrycho jQuery wird mit WordPress geladen. Das Hinzufügen einer neuen Klasse hat keine Auswirkungen auf das Backend. Auf Servern mit hoher Auslastung sollten Sie eine weitere Abfrage vermeiden. Und natürlich ist dies nur eine Lösung, für die Sie sich entscheiden sollten.

    – Zachary Schüssler

    18. April 2013 um 14:54 Uhr


  • Ah, guter Punkt, das hatte ich vergessen (da ich am Ende immer die gelieferte Version ziehe und meine eigene pushe, weil die gelieferte Version fast nie die neueste ist).

    – Chris Krycho

    18. April 2013 um 15:06 Uhr

867980cookie-checkWordPress – woher weiß ich, ob ein Menüpunkt Kinder hat?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy