【问题标题】:Hierarchical dropdown menu from array?数组中的分层下拉菜单?
【发布时间】:2013-01-02 18:39:55
【问题描述】:

我有以下代码从我的数据库中获取字段并将它们放入 html 表单的格式下拉菜单中。以目前的形式,我从我的数据库中获取了 3 次,代码的工作原理在代码的 cmets 中进行了解释:

$getSolos = $wpdb->get_results($wpdb->prepare("
        SELECT * FROM wp_terms p 
        LEFT OUTER JOIN wp_term_taxonomy t ON p.term_id = t.term_id
        WHERE t.taxonomy = 'format'
        AND t.parent = 0
        AND t.term_id NOT IN (SELECT parent FROM wp_term_taxonomy WHERE taxonomy = 'format' AND parent > 0)
        ORDER BY t.parent
        "));  // This fetches all rows that do not have children or parents.

$getParents = $wpdb->get_results($wpdb->prepare("
        SELECT * FROM wp_terms p 
        LEFT OUTER JOIN wp_term_taxonomy t ON p.term_id = t.term_id
        WHERE t.taxonomy = 'format'
        AND t.parent = 0
        AND t.term_id IN (SELECT parent FROM wp_term_taxonomy WHERE taxonomy = 'format' AND parent > 0)
        "));    // This fetches all rows that have children

$getChildren = $wpdb->get_results($wpdb->prepare("
        SELECT * FROM wp_terms p 
        LEFT OUTER JOIN wp_term_taxonomy t ON p.term_id = t.term_id
        WHERE t.taxonomy = 'format'
        AND t.parent > 0
        ORDER BY t.parent
        AND p.name
        "));    //This fetches all rows that ARE children

<select name="format">  //start the dropdown
    <option value="empty"></option>  //default field is empty
        <?php 
            foreach ($getSolos as $solo) {  //start loop through solos for output
                echo "<option value='".$solo->name."'>".$solo->name."</option>"; // output solos as options in the dropdown
            }
            foreach ($getParents as $parent) { //start loop through parents for output
                echo "<optgroup label='".$parent->name."'>"; // Spit out parent as an optgroup
                foreach ($getChildren as $child) { //Start loop through children for output
                    if ($child->parent == $parent->term_id) { // if child's parent value matches the ID of the parent
                        echo "<option value='".$child->name."'>    ".$child->name."</option>"; //Spit out the child as an option
                    }
                }
                echo "</optgroup>"; //close the optgroup
            }
        ?>
    </select> // end the dropdown

输出如下:

Entry Form
Twitter
Facebook
 - Entry Form
 - Page

数据库中的组合表如下所示:

term_id       name           slug                 taxonomy     parent
1             Entry Form     entry-form           format       0
2             Page           page                 format       3
3             Facebook       facebook             format       0
4             Entry Form     facebook-entry-form  format       3
5             Twitter        twitter              format       0

但是这种方法有问题。

1) 3次访问数据库效率低。

2) 一个孩子也有一个孩子是无效的。虽然 children 的孩子都进入 $getChildren,但代码只会吐出 1 级孩子,而忽略其余部分。

出于演示目的,如果我有第 6 行:

term_id       name          slug                  taxonomy     parent
6             Single        single                format       2

然后代码会这样做:

Entry Form
Twitter
Facebook
 - Entry Form
 - Page

注意 Single 被完全忽略,尽管它包含在 $getChildren 数组中。

那么如何才能让这段代码变得更好呢?

【问题讨论】:

  • 可以举个数据库源的例子吗?感觉这可以通过一些 sql 技巧来完成......
  • 示例已经提供。
  • 您提供了一张桌子,但在您的示例中使用了更多... 耸耸肩

标签: php html arrays forms drop-down-menu


【解决方案1】:

第 6 行有一个值为 2 的父项。虽然 term_id 为 2 的行有一个值为 3 的父项,因此不包含在您的父对象中。

我可能会使用一个函数来实现这一点;

$getTerms = $wpdb->get_results($wpdb->prepare("
              SELECT * FROM wp_terms p 
              WHERE t.taxonomy = 'format'
              ORDER BY p.name ASC"));

$terms = array();              
foreach($getTerms as $key => $term){
  $terms[$term->parent][$term->term_id] = $term;
} 

function printTerms($terms, $parent = 0, $deep = 0){
  if(count($terms[$parent]) > 0){

    $indent = "";
    for($i = 0; $i < $deep; $i++){
      $indent .= "&nbsp;&nbsp;&nbsp;";
    }

    foreach($terms[$parent] as $key => $term){

      if(count($terms[$term->term_id]) > 0){

        if($deep == 0){
          echo "<optgroup label='".$term->name."'></optgroup>";
        } else {
          echo "<option value='".$term->name."'>".$indent.$term->name."</option>";
        }

        printTerms($terms, $term->term_id, ($deep+1));

      } else {

        echo "<option value='".$term->name."'>".$indent.$term->name."</option>";

      }

    }
  }
}

?>    

<select name="format">
   <option value="empty"></option>
   <?php printTerms($terms); ?>
</select> 

【讨论】:

  • 嗯。这是一个开始,但理想情况下,optgroup 仅适用于顶级父级,而子父级是可选的。
  • 在这种情况下,您可以对 parent = 0 进行检查。当它不为 0 时,您可以简单地输出一个选项。明天我会更新答案,我正在打电话;)
  • 我编辑了 printTerms() 函数。它现在支持可选的子级别父级,optgroup 不支持可选标签,所以我使用缩进来可视化级别层次结构,具体取决于深度。
  • 也值得一提;我使用 1 个查询来检索我们需要的数据。让 PHP 为您完成工作! :)
  • 代码根本不输出任何缩进。它将 Facebook 打印为一个 optgroup,但它的孩子没有缩进,这些孩子的孩子也没有。我认为原因是因为它呼应了 "";在可以插入任何内容之前关闭 optgroup。
【解决方案2】:

您需要将输出设置为像这样显示以在选择中创建标题:

    <select>
  <optgroup label="Swedish Cars">
    <option value="volvo">Volvo</option>
    <option value="saab">Saab</option>
  </optgroup>
  <optgroup label="German Cars">
    <option value="mercedes">Mercedes</option>
    <option value="audi">Audi</option>
  </optgroup>
</select>

这意味着您需要以某种方式识别哪些输出应该是标签,哪些应该是选项。

【讨论】:

  • 我相信这是可能的,但我需要帮助才能实现这一目标。请查看我更新的问题以及新信息。
  • 您将需要退出 foreach 循环并在 while 循环中获取此信息。那么您只需要进行条件检查。 EX: if($format->parent) 做这个 ELSE 做这个
【解决方案3】:

没有测试,但我会先创建一个包含所有 ID 的分层数组:

$items = array();
$ids   = array();
foreach ($getFormats as $format) {
    $items[$format->term_id] = $format;
    if (isset($format->parent)) {
        $ids[$format->parent->term_id][] = $format->term_id;
    } else $ids[$format->term_id] = null;
}

然后很容易遍历这个数组并创建 HTML 代码:

foreach ($ids as $id => $subIds) {
    if (!empty($subIds)) {
        echo '<optgroup label="' . $items[$id]->name . '">';
        foreach ($subIds as $subId) 
            echo '<option value="' . $items[$subId]->name . '">' . $items[$subId]->name . '</option>';
        echo '</optgroup>';
    } else {
        echo '<option value="' . $items[$id]->name . '">' . $items[$id]->name . '</option>';
    }
}

【讨论】:

  • 好吧,它创建了下拉列表,但所有内容都被视为相同。 optgroup 似乎不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-05
相关资源
最近更新 更多