วิธีการเชื่อมโยงออกเด็กตามหน้าปัจจุบัน


10

เมื่อเชื่อมโยงไปถึงหน้าเว็บที่มีรายการเมนูที่เป็นรายการหลักไปยังรายการเมนูหน้าอื่น ๆ ฉันต้องการแสดงรายการของรายการเมนูย่อยเหล่านั้น ฉันใช้รหัสต่อไปนี้

$trail = menu_get_active_trail();
menu_build_tree('main-menu', array(
  'expanded' => array($trail[1]['mlid'])
));

อย่างไรก็ตามอาร์เรย์ที่ส่งคืนจะมีลักษณะเช่นนี้ (พร้อมการลบที่ไม่จำเป็นจำนวนมาก)

array
'49950 PKY Truck Beauty 312' => 
array
  'link' => &
    array
      'menu_name' => string 'main-menu' (length=9)
      'mlid' => string '312' (length=3)
      'plid' => string '311' (length=3)
  'below' => 
    array
      '49952 Seminars 314' => 
        array
          'link' => &
            array
              'menu_name' => string 'main-menu' (length=9)
              'mlid' => string '314' (length=3)
              'plid' => string '311' (length=3)
      '50000 HDMA Breakfast 316' => 
        array
          'link' => &
            array
              'menu_name' => string 'main-menu' (length=9)
              'mlid' => string '316' (length=3)
              'plid' => string '311' (length=3)
      '50000 MATS Concert 315' => 
        array
          'link' => &
            array
              'menu_name' => string 'main-menu' (length=9)
              'mlid' => string '315' (length=3)
              'plid' => string '311' (length=3)

สังเกตว่า 314, 315 และ 316 อยู่ที่ 'ด้านล่าง' 312 หรือไม่ พวกเขาเป็นพี่น้องในโครงสร้างเมนูของฉันและดูเหมือนว่าจะได้รับการยืนยันโดยแต่ละรายการที่มีค่าเท่ากันสำหรับplid(311) เห็นได้ชัดว่าฉันสามารถแก้ไขได้โดยส่งอาร์เรย์ผ่านฟังก์ชั่นอื่น แต่ฉันอดไม่ได้ที่จะคิดว่าฉันเพิ่งพลาดบางอย่าง


ในความสนใจของเวลาฉันกำลังแก้ไขปัญหาด้วย CSS แม้ว่าฉันจะไม่พอใจกับมัน $tree = menu_build_tree('main-menu', array( 'expanded' => array($trail[1]['mlid']) )); drupal_render(menu_tree_output($tree))จากนั้นใช้ CSS ฉันสามารถจัดสไตล์ลิงก์เพื่อลบการulขยายออกทำให้พวกเขาปรากฏว่าพวกเขาทั้งหมดอยู่ในระดับเดียวกัน ไม่เหมาะ แต่มีประสิทธิภาพ แก้ไข: ขออภัยฉันไม่สามารถทราบวิธีการขึ้นบรรทัดใหม่เพื่อทำงาน
Chris Rockwell

คุณไม่สามารถโพสต์ภาพตัวอย่างของสิ่งที่คุณต้องการจะทำ ความจริงแล้วฉันพบว่าคำถามยุ่งเล็กน้อย (ฉันกล้าพูดอย่างนั้นเพราะยังไม่มีคำตอบที่เขียนไว้) คุณต้องการแสดงรายการย่อยที่ใด ทำไมโมดูลที่เกี่ยวข้องกับเมนูไม่เป็นที่พอใจ? โปรดอธิบายคำถามให้ละเอียดมากขึ้นและบางทีเราอาจหาทางออกที่ดีได้
Sk8erPeter

@ Sk8erPeter ฉันขอโทษถ้ามันยุ่ง วิธีการแก้ปัญหาผมไปกับ (อ้างอิงในความคิดเห็นของฉัน) จะถูกนำมาใช้ที่นี่: การเชื่อมโยง คำถามหลักคือ: ทำไม menu_build_tree () กลับอาร์เรย์ที่ซ้อนกันที่มีระดับที่ไม่คาดคิด (ลิงก์ทั้งหมดควรจะเหมือนกัน)? ในการดูว่าฉันกำลังแสดงรายการเด็กอยู่ที่ไหนให้ใช้ลิงค์ที่ฉันรวมไว้แล้วคลิกที่ลิงค์ใด ๆ ในแถบนำทางหลัก (css ใช้เพื่อแสดงภาพลวงตาที่ไม่สามารถคลิกได้)
Chris Rockwell

เกี่ยวกับโมดูล, คร่าวๆคร่าวๆไม่ได้ปรากฏขึ้นอะไรที่จะพอเพียง อาจเป็นเพราะฉันไม่ได้สนใจในการติดตั้งโมดูลอื่นสำหรับโซลูชันที่ควรทำในโค้ด 4 หรือ 5 บรรทัด ฉันมีโมดูล 'รวมถึง' ที่กำหนดเองที่ฉันใช้กับสิ่งต่าง ๆ เช่นนี้ ตอนนี้ฉันโทรจากที่ไหนก็ได้get_sub_menu_based_on_active_page()และฉันพร้อมแล้ว ฉันต้องดำเนินการต่อจากการพยายามหาปัญหาเกี่ยวกับการซ้อนเนื่องจาก css ทำให้ผู้ใช้ไม่มีความฉลาด
Chris Rockwell

1
ฉันโพสต์คำตอบด้วยวิธีอื่นฉันคิดว่านั่นเป็นหนึ่งในวิธีแก้ปัญหาที่ง่ายที่สุด และทำงานได้อย่างถูกต้อง โมดูลที่แนะนำนั้นเป็นที่นิยมในหมู่ผู้ใช้ Drupal
Sk8erPeter

คำตอบ:


8

แค่อยากติดตาม ฉันกลับมาที่คำถามนี้และพบสิ่งต่อไปนี้: /programming/2716787/how-to-get-all-the-menu-items-below-a-certain-parent-in-drupalซึ่งเป็น สิ่งที่ฉันต้องการ

รหัสคัดลอกมาจากลิงค์ที่กล่าวถึงข้างต้นและปรับเปลี่ยนให้เหมาะสมกับความต้องการของฉัน (ส่วนใหญ่จะใช้เส้นทางปัจจุบันเพื่อสร้างโครงสร้างเมนูจากแทนที่จะใช้ค่ารหัสตายตัว:

$parent = menu_link_get_preferred($_GET['q']);
$parameters = array(
  'active_trail' => array($parent['plid']),
  'only_active_trail' => FALSE,
  'min_depth' => $parent['depth']+1,
  'max_depth' => $parent['depth']+1,
  'conditions' => array('plid' => $parent['mlid']),
);

$children = menu_build_tree($parent['menu_name'], $parameters);

return '<div class="content-sub-menu content-padder">' . drupal_render(menu_tree_output($children)) . '</div>';

1
นี้ทำงานได้ดี แต่คุณควรจะใช้แทนcurrent_path() จะส่งคืนนามแฝงของเส้นทางซึ่งจะได้รับ node / id $_GET['q']$_GET['q']current_path()
mediaashley

6

สามารถทำได้อย่างง่ายดายโดยใช้โมดูลบล็อกเมนู (ใช้เวลาประมาณ 5 นาทีในการกำหนดค่า)

ภาพหน้าจอบล็อกเมนู

สิ่งที่คุณต้องทำคือ

  1. เปิดใช้งานโมดูล
  2. กำลังจะ admin/structure/block
  3. คลิก "เพิ่มบล็อกเมนู"
  4. ตั้งค่า "ระดับเริ่มต้น" เป็น "ระดับ 2 (รอง)" และตั้งค่าภูมิภาคที่ควรแสดงภายใต้"ระบุว่าจะแสดงชุดรูปแบบและภูมิภาคที่บล็อกนี้แสดงหรือไม่"

  5. ภาพหน้าจอ:

    • นี่คือลักษณะที่หน้าการกำหนดค่า

      ภาพหน้าจอ

    • หน้าผู้ดูแลระบบ / โครงสร้าง / บล็อกด้วยบล็อกโมดูลเมนูบล็อก

      ภาพหน้าจอ

    • ฉันสร้างเนื้อหา "หน้าพื้นฐาน" ด้วยโมดูล Devel และจัดเตรียมลิงก์เมนูให้กับพวกเขาและสร้างลำดับชั้นเมนูที่ซ้อนกัน

      • นี่คือหน้าแรกเริ่มต้นที่ไม่มีเมนูย่อย (บล็อก "เมนูหลัก - ระดับที่ 2" ไม่สามารถมองเห็นได้ในแถบด้านข้างซ้ายเนื่องจากไม่มีรายการระดับรองอยู่)

      ภาพหน้าจอ

      • นี่เป็นเมนูที่สองที่มีองค์ประกอบย่อยคุณสามารถเห็น "เมนูหลัก - ระดับที่ 2" ในแถบด้านข้างซ้าย แต่จะเห็นเฉพาะองค์ประกอบลูกระดับที่สอง

        ภาพหน้าจอ

        รายการระดับที่สอง

      • ตอนนี้จะลึก:

        องค์ประกอบลูกระดับที่สามยังสามารถเห็นได้

ฉันคิดว่าการใช้โมดูลเมนูบล็อกสำหรับงานนี้เป็นหนึ่งในโซลูชันที่ง่ายที่สุดและเร็วที่สุด


ฉันอยากรู้ว่าทำไมฉันถึงได้ลงคะแนนสำหรับโพสต์นี้ โมดูลที่แนะนำทำงานได้และฉันเขียนบทช่วยสอนทีละขั้นตอน ทำไม downvoter ถึงไม่แสดงความคิดเห็นถึงเหตุผล? (อาจจะมีประโยชน์ (อาจจะไม่ใช่) อย่างน้อยฉันก็สามารถตอบสนองได้)
Sk8erPeter

0

ตามที่ระบุไว้ในความคิดเห็นฉันลงเอยด้วยการใช้ฟังก์ชั่น API แล้วใส่สไตล์ด้วย CSS:

/* --------------- *\
    Sub-menus
    used on main pages
\* --------------- */
.content-sub-menu ul.menu {
  list-style: none;
  padding: 0;
  margin: 0;
}
.content-sub-menu > ul.menu {
  margin-bottom: 25px;
}
.content-sub-menu ul.menu a {
  font-size: 1.5em;
  padding: 10px;
  margin-top: 5px;
  display: inline-block;
  min-width: 33%;
}

0

ฟังก์ชันนี้ทำงานอย่างถูกต้องเพื่อรับเมนูย่อยของหน้าปัจจุบัน:

function build_left_menu()
{
    global $language_url;
    static $use_theme = NULL;
// Get the entire main menu tree
    $left_menu_tree = menu_tree_all_data('main-menu'); // Your main menu
$left_menu_tree_values = array_values($left_menu_tree); //get value only
    $html = "<div id=\"sidemenu\"><ul id=\"side-nav\" class=\"side-nav-content\"><h3>In this section:</h3>";
foreach ($left_menu_tree_values as $index => $item) {
        $link = $item["link"];
        if ($index === 0) {
            $item_class = "first-item panel side-menu ";
        } else {
            $item_class = "panel side-menu ";
        }
        $options_anchor = array();
        if ($item["below"]) {
            $options_anchor = array("attributes" => array('class' => array('dropdown-toggle'),
                'data-toggle' => 'dropdown',
                'data-delay' => 1000,
                'data-close-others' => "false",
                'data-hover' => "dropdown",
            )
            );
        }
        // Merge in defaults.
        $options_anchor += array(
            'attributes' => array(),
            'html' => FALSE,
        );

        //Default needed class
        $options['attributes']['class'][] = 'subpage-link collapsed';
        // Append active class.
        if (($link['link_path'] == $_GET['q'] || ($link['link_path'] == '<front>' && drupal_is_front_page())) &&
            (empty($options_anchor['language']) || $options_anchor['language']->language == $language_url->language)) {
            if ($item["below"]) {
                foreach ($item["below"] as $item_below) {
                    $link_below = $item_below["link"];
                    $options_anchor = array();
                    $html .= "<li class='" . $item_class . "'>";
                    $html .= override_left_l($link_below['link_title'], $link_below['link_path'], $options_anchor).'</li>';
                }
            }
        }
    }
    $html .= "</ul></div>";
    return $html;
}

หวังว่าจะช่วยได้!


ฟังก์ชั่นของคุณเรียกใช้ฟังก์ชั่นที่ไม่ได้กำหนด (override_left_l)!
DrCord

0

@Chris Rockwell และ @ Mario Awad

ฉันเป็นมือใหม่ใน Drupal ดังนั้นมันยากที่จะเข้าใจสำหรับฉันที่จะเพิ่มฟังก์ชั่นนี้ .. ฉันขอโทษสำหรับสิ่งนั้น แต่พวกคุณช่วยพูดถึงมันได้ไหมว่าเราควรจะเพิ่มฟังก์ชั่นนี้ในไฟล์ไหน?

ฉันพยายามสร้างการนำทางแถบด้านข้างที่จะแสดงเฉพาะองค์ประกอบลูกในแต่ละหน้า วิธีการสร้างเมนูการนำทางบนแถบด้านข้างพร้อมลิงค์การนำทางที่แตกต่างกันแสดงในหน้าต่างๆ

ข้าพเจ้าซาบซึ้ง!

ขอบคุณ!


0

ฉันเพิ่งโพสต์ฟังก์ชั่นที่รับไอเท็มเมนูลูกให้เป็นเส้นทางของโหนด คุณสามารถตรวจสอบได้ที่นี่: http://softkube.com/blog/getting-child-menu-items-drupal-menu-tree

ฉันรวมลิงก์ไปยังหลักฐานในอนาคตคำตอบในกรณีที่โพสต์ได้รับการปรับปรุงและฉันจะคัดลอก / วางรหัสเต็มในตอนท้าย

ในกรณีของคุณคุณสามารถเรียกใช้สิ่งนี้ในชุดรูปแบบของคุณเพื่อแสดงรายการเมนูลูกทั้งหมด ปรับเปลี่ยนechoคำสั่งและธีมตามที่คุณต้องการ

$path = current_path();
$nids = skl_get_all_menu_node_children_ids($path);
$children = node_load_multiple($nids);
foreach($children as $c) {
    echo $c->title . ': ' . url('node/' $c->nid) . '<br />';
}

และนี่คือรหัสเต็มของฟังก์ชัน ตรวจสอบลิงค์สำหรับการปรับปรุงในอนาคตที่เป็นไปได้

โชคดี.

/**
 * Returns node ids of all the child items, including children of children
 * on all depth levels, of the given node path. Returns an empty array
 * if any error occurs.
 * 
 * @param string $node_path
 * @return array
 */
function skl_get_all_menu_node_children_ids($node_path) {
    //Stop and return an empty array if node path is empty
    if(empty($node_path)) {
        return array();
    }

    //Init empty array to hold the results
    $nids = array();

    //Init parent keys. Check 'foreach' loop on parent keys for more info.
    $parent_keys = array('plid', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9');

    //Collect menu item corresponding to this path to begin updates.
    //Reference: http://stackoverflow.com/a/11615338/136696
    //Note: we couldn't find a way to get the sub-tree starting from this item
    //only and hence we had to get the whole menu tree built and then loop on
    //the current item part only. Not so bad considering that Drupal will
    //most probably have the whole menu cached anyway.
    $parent_menu_item = menu_link_get_preferred($node_path);

    //Stop and return empty array if a proper current menu item couldn't be found
    if(empty($parent_menu_item['menu_name']) || empty($parent_menu_item['mlid'])) {
        return array();
    }

    //Init parent item mlid for easier usage since now we know it's not empty
    $parent_menu_item_mlid = $parent_menu_item['mlid'];

    //Build whole menu based on the preferred menu_name gotten from this item
    $menu = menu_build_tree($parent_menu_item['menu_name']);

    //Reset menu cache since 'menu_build_tree' will cause trouble later on after 
    //you call pathauto to update paths as it can only be called once. 
    //Check: https://www.drupal.org/node/1697570
    menu_reset_static_cache();

    //Init processing array. This will hold menu items as we process them.
    $menu_items_to_process = array();

    //First run to fill up the processing array with the top level items
    foreach($menu as $top_level_menu_item) {
        $menu_items_to_process[] = $top_level_menu_item;
    }

    //While the processing array is not empty, keep looping into lower
    //menu items levels until all are processed.
    while(count($menu_items_to_process) > 0) {
        //Pop the top item from the processing array
        $mi = array_pop($menu_items_to_process);

        //Get its node id and add it to $nids if it's a current item child
        //Note that $parent_keys contains all keys that drupal uses to
        //set a menu item inside a tree up to 9 levels.
        foreach($parent_keys as $parent_key) {
            //First, ensure the current parent key is set and also mlid is set
            if(!empty($mi['link']['mlid']) && !empty($mi['link'][$parent_key])) {
                //If the link we're at is the parent one, don't add it to $nids
                //We need this check cause Drupal sets p1 to p9 in a way you
                //can easily use to generate breadcrumbs which means we will
                //also match the current parent, but here we only want children
                if($mi['link']['mlid'] != $parent_menu_item_mlid) {
                    //Try to match the link to the parent menu item
                    if($mi['link'][$parent_key] == $parent_menu_item_mlid) {
                        //It's a child, add it to $nids and stop foreach loop.
                        //Link_path has the path to the node. Example: node/63.
                        if(!empty($mi['link']['link_path'])) {
                            $nids[] = str_replace('node/', '', 
                                      $mi['link']['link_path']);
                            break;
                        }
                    }
                }
            }
        }

        //Add its child items, if any, to the processing array
        if(!empty($mi['below']) && is_array($mi['below'])) {
            foreach($mi['below'] as $child_menu_item) {
                //Add child item at the beginning of the array so that when
                //we get the list of node ids it's sorted by level with
                //the top level elements first; which is easy to attain
                //and also useful for some applications; why not do it.
                array_unshift($menu_items_to_process, $child_menu_item);
            }
        }
    }

    //Return
    return $nids;
}

ขอบคุณมาริโอ คุณสามารถแสดงความคิดเห็นเกี่ยวกับเหตุผลที่คุณเลือกนี้มากกว่าการใช้$parametersในmenu_build_tree?
Chris Rockwell

ขอบคุณสำหรับความคิดเห็น. ฉันไม่สามารถรับข้อมูลที่จำเป็นได้ไม่ว่า$parametersฉันจะใช้อะไรและเชื่อว่าฉันดูเยอะ ทั้งหมดที่ฉันต้องการคือให้เส้นทางรับรายการเมนูลูกทั้งหมดในทุกระดับและฉันก็หาทางไม่ได้ หากมีโปรดแจ้งฉันฉันจะดีใจที่ได้เรียนรู้และปรับปรุงคำตอบและโพสต์บล็อกของฉัน ไชโย
Mario Awad
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.