Zeigen Sie einen Teil / Zweig des Menübaums mit wp_nav_menu () an

Ich habe ein Menü in WP Admin definiert, das wie folgt aussieht:

Alt-Text

Ich möchte alle untergeordneten Links in der Seitenleiste anzeigen können, wenn ich auf einer übergeordneten Seite bin. Wenn sich der Benutzer beispielsweise auf meiner Seite “Über uns” befindet, möchte ich eine Liste der vier grün hervorgehobenen Links in der Seitenleiste anzeigen.

Ich schaute auf die Dokumentation für wp_nav_menu () und es scheint keine eingebaute Möglichkeit zu haben, einen bestimmten Knoten eines bestimmten Menüs als Ausgangspunkt beim Erzeugen der Links zu spezifizieren.

Ich habe eine Lösung für eine ähnliche Situation erstellt, die auf den Beziehungen basiert, die vom Seitenelternteil erstellt wurden, aber ich suche nach einer, die das Menüsystem spezifisch verwendet. Jede Hilfe wäre willkommen.

Solutions Collecting From Web of "Zeigen Sie einen Teil / Zweig des Menübaums mit wp_nav_menu () an"

Das war mir immer noch wichtig, also habe ich es noch einmal durchgesehen und diese Lösung zusammengestellt, die nicht so sehr auf dem Kontext beruht:

add_filter( 'wp_nav_menu_objects', 'submenu_limit', 10, 2 ); function submenu_limit( $items, $args ) { if ( empty( $args->submenu ) ) { return $items; } $ids = wp_filter_object_list( $items, array( 'title' => $args->submenu ), 'and', 'ID' ); $parent_id = array_pop( $ids ); $children = submenu_get_children_ids( $parent_id, $items ); foreach ( $items as $key => $item ) { if ( ! in_array( $item->ID, $children ) ) { unset( $items[$key] ); } } return $items; } function submenu_get_children_ids( $id, $items ) { $ids = wp_filter_object_list( $items, array( 'menu_item_parent' => $id ), 'and', 'ID' ); foreach ( $ids as $id ) { $ids = array_merge( $ids, submenu_get_children_ids( $id, $items ) ); } return $ids; } 

Verwendung

 $args = array( 'theme_location' => 'slug-of-the-menu', // the one used on register_nav_menus 'submenu' => 'About Us', // could be used __() for translations ); wp_nav_menu( $args ); 

@goldenapples: Ihre Walker-class funktioniert nicht. Aber die Idee ist wirklich gut. Ich habe einen Walker basierend auf Ihrer Idee erstellt:

 class Selective_Walker extends Walker_Nav_Menu { function walk( $elements, $max_depth) { $args = array_slice(func_get_args(), 2); $output = ''; if ($max_depth < -1) //invalid parameter return $output; if (empty($elements)) //nothing to walk return $output; $id_field = $this->db_fields['id']; $parent_field = $this->db_fields['parent']; // flat display if ( -1 == $max_depth ) { $empty_array = array(); foreach ( $elements as $e ) $this->display_element( $e, $empty_array, 1, 0, $args, $output ); return $output; } /* * need to display in hierarchical order * separate elements into two buckets: top level and children elements * children_elements is two dimensional array, eg. * children_elements[10][] contains all sub-elements whose parent is 10. */ $top_level_elements = array(); $children_elements = array(); foreach ( $elements as $e) { if ( 0 == $e->$parent_field ) $top_level_elements[] = $e; else $children_elements[ $e->$parent_field ][] = $e; } /* * when none of the elements is top level * assume the first one must be root of the sub elements */ if ( empty($top_level_elements) ) { $first = array_slice( $elements, 0, 1 ); $root = $first[0]; $top_level_elements = array(); $children_elements = array(); foreach ( $elements as $e) { if ( $root->$parent_field == $e->$parent_field ) $top_level_elements[] = $e; else $children_elements[ $e->$parent_field ][] = $e; } } $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' ); //added by continent7 foreach ( $top_level_elements as $e ){ //changed by continent7 // descend only on current tree $descend_test = array_intersect( $current_element_markers, $e->classes ); if ( !empty( $descend_test ) ) $this->display_element( $e, $children_elements, 2, 0, $args, $output ); } /* * if we are displaying all levels, and remaining children_elements is not empty, * then we got orphans, which should be displayed regardless */ /* removed by continent7 if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) { $empty_array = array(); foreach ( $children_elements as $orphans ) foreach( $orphans as $op ) $this->display_element( $op, $empty_array, 1, 0, $args, $output ); } */ return $output; } } 

Jetzt können Sie verwenden:

 < ?php wp_nav_menu( array( 'theme_location'=>'test', 'walker'=>new Selective_Walker() ) ); ?> 

Die Ausgabe ist eine Liste, die das aktuelle Root-Element und seine untergeordneten Elemente (nicht ihre untergeordneten Elemente) enthält. Def: Root-Element: = Der Top-Level-Menüpunkt, der der aktuellen Seite entspricht oder der Elternteil einer aktuellen Seite oder eines Elternteils eines Elternteils ist …

Dies beantwortet die ursprüngliche Frage aber nicht annähernd, da es immer noch den obersten Gegenstand gibt. Das ist für mich in Ordnung, weil ich das oberste Element als Überschrift der Seitenleiste haben möchte. Wenn Sie dies loswerden möchten, müssen Sie möglicherweise display_element überschreiben oder einen HTML-Parser verwenden.

Hallo @jessegavin :

Nav-Menüs werden in einer Kombination aus benutzerdefinierten Post-Typen und benutzerdefinierten Taxonomien gespeichert. Jedes Menü wird als Term gespeichert ( wp_terms “About Menu” , in wp_terms ) einer Custom Taxonomy ( nav_menu , gefunden in wp_term_taxonomy ).

Jedes Nav- post_type=='nav_menu_item' wird als Post von post_type=='nav_menu_item' (dh “Über die Firma” in wp_posts ) gespeichert, wobei seine Attribute als Post-Meta (in wp_postmeta ) unter Verwendung eines meta_key Präfixes von _menu_item_* _menu_item_menu_item_parent wobei _menu_item_menu_item_parent ist ID des übergeordneten Navigationselements Ihres Menüelements.

Die Beziehung zwischen Menüs und wp_term_relationships wird in wp_term_relationships gespeichert, wobei object_id mit der $post->ID für das Nav Menu Item und $term_relationships->term_taxonomy_id mit dem in wp_term_taxonomy und wp_terms definierten Menü wp_terms .

Ich bin mir ziemlich sicher, dass es möglich wäre, sowohl 'wp_update_nav_menu' als auch 'wp_update_nav_menu_item' um aktuelle Menüs in wp_terms und einen parallelen Satz von Relationen in wp_term_taxonomy und wp_term_relationships wo jedes Nav- wp_term_relationships mit Sub-Nav-Menüelementen ebenfalls wird eigenes Navigationsmenü.

Sie sollten auch 'wp_get_nav_menus' (was ich aufgrund einiger ähnlicher Arbeiten, die ich vor ein paar Monaten gemacht habe, zu WP 3.0 hinzugefügt habe) 'wp_get_nav_menus' um sicherzustellen, dass Ihre generierten Nav-Menüs nicht zur Bearbeitung durch den Benutzer im Admin angezeigt werden sonst würden sie sehr schnell aus dem Takt geraten und dann hätten Sie einen Daten-Albtraum auf Ihrer Hand.

Klingt wie ein lustiges und nützliches Projekt, aber es ist ein wenig mehr Code und Tests, als ich es mir jetzt leisten kann, zum Teil, weil alles, was Daten synchronisiert, ein PITA ist, wenn es darum geht, alle Bugs auszubügeln (und weil zahlende Kunden drängen mich, Dinge zu erledigen 🙂 Aber bewaffnet mit den obigen Informationen bin ich ein ziemlich motivierter WordPress-Plugin-Entwickler, der es codieren könnte, wenn er es wollte.

Natürlich wissen Sie jetzt, wenn Sie es kodieren, sind Sie verpflichtet, es hier wieder zu veröffentlichen, damit wir alle von Ihrer Großzügigkeit profitieren können! 🙂

Dies ist eine Walker-Erweiterung, die tun sollte, was Sie suchen:

 class Selective_Walker extends Walker_Nav_Menu { function walk( $elements, $max_depth) { $args = array_slice(func_get_args(), 2); $output = ''; if ($max_depth < -1) //invalid parameter return $output; if (empty($elements)) //nothing to walk return $output; $id_field = $this->db_fields['id']; $parent_field = $this->db_fields['parent']; // flat display if ( -1 == $max_depth ) { $empty_array = array(); foreach ( $elements as $e ) $this->display_element( $e, $empty_array, 1, 0, $args, $output ); return $output; } /* * need to display in hierarchical order * separate elements into two buckets: top level and children elements * children_elements is two dimensional array, eg. * children_elements[10][] contains all sub-elements whose parent is 10. */ $top_level_elements = array(); $children_elements = array(); foreach ( $elements as $e) { if ( 0 == $e->$parent_field ) $top_level_elements[] = $e; else $children_elements[ $e->$parent_field ][] = $e; } /* * when none of the elements is top level * assume the first one must be root of the sub elements */ if ( empty($top_level_elements) ) { $first = array_slice( $elements, 0, 1 ); $root = $first[0]; $top_level_elements = array(); $children_elements = array(); foreach ( $elements as $e) { if ( $root->$parent_field == $e->$parent_field ) $top_level_elements[] = $e; else $children_elements[ $e->$parent_field ][] = $e; } } $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' ); foreach ( $top_level_elements as $e ) { // descend only on current tree $descend_test = array_intersect( $current_element_markers, $e->classes ); if ( empty( $descend_test ) ) unset ( $children_elements ); $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output ); } /* * if we are displaying all levels, and remaining children_elements is not empty, * then we got orphans, which should be displayed regardless */ if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) { $empty_array = array(); foreach ( $children_elements as $orphans ) foreach( $orphans as $op ) $this->display_element( $op, $empty_array, 1, 0, $args, $output ); } return $output; } } 

Basierend auf dem Code von Mfields, auf den ich früher in meinem Kommentar verwiesen habe. Es wird nur überprüft, wenn das Menü durchlaufen wird, um festzustellen, ob das aktuelle Element (1) der aktuelle Menüeintrag oder (2) ein Vorgänger des aktuellen Menüeintrags ist und den darunter liegenden Teilbaum nur dann erweitert, wenn eine dieser Bedingungen zutrifft . Hoffe das funktioniert für dich.

Um es zu verwenden, fügen Sie einfach ein Argument “walker” hinzu, wenn Sie das Menü aufrufen, dh:

 < ?php wp_nav_menu( array( 'theme_location'=>'test', 'walker'=>new Selective_Walker() ) ); ?> 

Ich habe die folgende class für mich zusammengestellt. Es wird das oberste Navigations-Parent der aktuellen Seite finden, oder Sie können ihm eine Ziel-Top-Navigations-ID im Walker-Konstruktor geben.

 class Walker_SubNav_Menu extends Walker_Nav_Menu { var $target_id = false; function __construct($target_id = false) { $this->target_id = $target_id; } function walk($items, $depth) { $args = array_slice(func_get_args(), 2); $args = $args[0]; $parent_field = $this->db_fields['parent']; $target_id = $this->target_id; $filtered_items = array(); // if the parent is not set, set it based on the post if (!$target_id) { global $post; foreach ($items as $item) { if ($item->object_id == $post->ID) { $target_id = $item->ID; } } } // if there isn't a parent, do a regular menu if (!$target_id) return parent::walk($items, $depth, $args); // get the top nav item $target_id = $this->top_level_id($items, $target_id); // only include items under the parent foreach ($items as $item) { if (!$item->$parent_field) continue; $item_id = $this->top_level_id($items, $item->ID); if ($item_id == $target_id) { $filtered_items[] = $item; } } return parent::walk($filtered_items, $depth, $args); } // gets the top level ID for an item ID function top_level_id($items, $item_id) { $parent_field = $this->db_fields['parent']; $parents = array(); foreach ($items as $item) { if ($item->$parent_field) { $parents[$item->ID] = $item->$parent_field; } } // find the top level item while (array_key_exists($item_id, $parents)) { $item_id = $parents[$item_id]; } return $item_id; } } 

Navigationsaufruf:

 wp_nav_menu(array( 'theme_location' => 'main_menu', 'walker' => new Walker_SubNav_Menu(22), // with ID )); 

Update: Ich habe dies zu einem Plugin gemacht. Hier herunterladen


Ich musste das selbst lösen und schrieb schließlich einen Filter auf die Ergebnisse der Menü-Suche. Sie können wp_nav_menu wie wp_nav_menu , aber wählen Sie einen Unterabschnitt des Menüs basierend auf dem Titel des übergeordneten Elements. Fügen Sie dem Menü einen submenu wie folgt hinzu:

 wp_nav_menu(array( 'menu' => 'header', 'submenu' => 'About Us', )); 

Sie können sogar mehrere Ebenen tief gehen, indem Sie Schrägstriche einfügen:

 wp_nav_menu(array( 'menu' => 'header', 'submenu' => 'About Us/Board of Directors' )); 

Oder wenn Sie ein Array bevorzugen:

 wp_nav_menu(array( 'menu' => 'header', 'submenu' => array('About Us', 'Board of Directors') )); 

Es verwendet eine Slug-Version des Titels, die es Dinge wie Großbuchstaben und Interpunktion verzeihen sollte.

@davidn @hakre Hallo, ich habe eine hässliche Lösung ohne HTML-Parser oder überschreibe display_element.

  class Selective_Walker extends Walker_Nav_Menu { function walk( $elements, $max_depth) { $args = array_slice(func_get_args(), 2); $output = ''; if ($max_depth < -1) //invalid parameter return $output; if (empty($elements)) //nothing to walk return $output; $id_field = $this->db_fields['id']; $parent_field = $this->db_fields['parent']; // flat display if ( -1 == $max_depth ) { $empty_array = array(); foreach ( $elements as $e ) $this->display_element( $e, $empty_array, 1, 0, $args, $output ); return $output; } /* * need to display in hierarchical order * separate elements into two buckets: top level and children elements * children_elements is two dimensional array, eg. * children_elements[10][] contains all sub-elements whose parent is 10. */ $top_level_elements = array(); $children_elements = array(); foreach ( $elements as $e) { if ( 0 == $e->$parent_field ) $top_level_elements[] = $e; else $children_elements[ $e->$parent_field ][] = $e; } /* * when none of the elements is top level * assume the first one must be root of the sub elements */ if ( empty($top_level_elements) ) { $first = array_slice( $elements, 0, 1 ); $root = $first[0]; $top_level_elements = array(); $children_elements = array(); foreach ( $elements as $e) { if ( $root->$parent_field == $e->$parent_field ) $top_level_elements[] = $e; else $children_elements[ $e->$parent_field ][] = $e; } } $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' ); //added by continent7 foreach ( $top_level_elements as $e ){ //changed by continent7 // descend only on current tree $descend_test = array_intersect( $current_element_markers, $e->classes ); if ( !empty( $descend_test ) ) $this->display_element( $e, $children_elements, 2, 0, $args, $output ); } /* * if we are displaying all levels, and remaining children_elements is not empty, * then we got orphans, which should be displayed regardless */ /* removed by continent7 if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) { $empty_array = array(); foreach ( $children_elements as $orphans ) foreach( $orphans as $op ) $this->display_element( $op, $empty_array, 1, 0, $args, $output ); } */ /*added by alpguneysel */ $pos = strpos($output, ''); $topper= substr($output, 0, $pos).substr($output, $pos2+2); $pos3 = strpos($topper, '>'); $lasst=substr($topper, $pos3+1); $submenu= substr($lasst, 0, -6); return $submenu; } } 

Ich habe einen modifizierten Walker gemacht, der helfen sollte! Nicht perfekt – es hinterlässt ein paar leere Elemente, aber es macht den Trick. Die Modifikation ist im Grunde die $ current_branch Bits. Hoffe es hilft jemandem!

 class Kanec_Walker_Nav_Menu extends Walker { /** * @see Walker::$tree_type * @since 3.0.0 * @var string */ var $tree_type = array( 'post_type', 'taxonomy', 'custom' ); /** * @see Walker::$db_fields * @since 3.0.0 * @todo Decouple this. * @var array */ var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' ); /** * @see Walker::start_lvl() * @since 3.0.0 * * @param string $output Passed by reference. Used to append additional content. * @param int $depth Depth of page. Used for padding. */ function start_lvl(&$output, $depth) { $indent = str_repeat("\t", $depth); $output .= "\n$indent
    \n"; } /** * @see Walker::end_lvl() * @since 3.0.0 * * @param string $output Passed by reference. Used to append additional content. * @param int $depth Depth of page. Used for padding. */ function end_lvl(&$output, $depth) { global $current_branch; if ($depth == 0) $current_branch = false; $indent = str_repeat("\t", $depth); $output .= "$indent
\n"; } /** * @see Walker::start_el() * @since 3.0.0 * * @param string $output Passed by reference. Used to append additional content. * @param object $item Menu item data object. * @param int $depth Depth of menu item. Used for padding. * @param int $current_page Menu item ID. * @param object $args */ function start_el(&$output, $item, $depth, $args) { global $wp_query; global $current_branch; // Is this menu item in the current branch? if(in_array('current-menu-ancestor',$item->classes) || in_array('current-menu-parent',$item->classes) || in_array('current-menu-item',$item->classes)) { $current_branch = true; } if($current_branch && $depth > 0) { $indent = ( $depth ) ? str_repeat( "\t", $depth ) : ''; $class_names = $value = ''; $classes = empty( $item->classes ) ? array() : (array) $item->classes; $classes[] = 'menu-item-' . $item->ID; $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ); $class_names = ' class="' . esc_attr( $class_names ) . '"'; $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args ); $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : ''; $output .= $indent . '
  • '; $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : ''; $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : ''; $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : ''; $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : ''; $item_output = $args->before; $item_output .= ''; $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after; $item_output .= ''; $item_output .= $args->after; $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); } } /** * @see Walker::end_el() * @since 3.0.0 * * @param string $output Passed by reference. Used to append additional content. * @param object $item Page data object. Not used. * @param int $depth Depth of page. Not Used. */ function end_el(&$output, $item, $depth) { global $current_branch; if($current_branch && $depth > 0) $output .= "
  • \n"; if($depth == 0) $current_branch = 0; }

    }

    Schau dir den Code in meinem Plugin an oder benutze ihn für deinen Zweck;)

    Dieses Plugin fügt ein verbessertes “Navigationsmenü” -Widget hinzu. Es bietet viele Optionen, die eingestellt werden können, um die Ausgabe des benutzerdefinierten Menüs über das Widget anzupassen.

    Features sind:

    • Benutzerdefinierte Hierarchie – “Nur zugehörige Unterelemente” oder “Nur eng verknüpfte Unterelemente”.
    • Starttiefe und Maximalpegel zur Anzeige + flache Anzeige.
    • Zeigt alle Menüpunkte beginnend mit dem ausgewählten an.
    • Zeigt nur den direkten Pfad zum aktuellen Element oder nur die untergeordneten Elemente an
      Ausgewähltes Element (Option zum Einschließen des übergeordneten Elements).
    • Benutzerdefinierte class für einen Widgetblock.
    • Und fast alle Parameter für die function wp_nav_menu.

    http://wordpress.org/extend/plugins/advanced-menu-widget/

    Die Ausgabe des Nav-Menüs enthält viele classn für den aktuellen Gegenstand, den aktuellen Gegenstandsvorfahre usw. In einigen Situationen konnte ich tun, was Sie tun wollten, indem Sie den gesamten nav-Baum ausgeben lassen und dann css verwenden, um ihn zu zerlegen nur Kinder der aktuellen Seite usw.