В скриптах используется MySQL-таблица `category` с полями `id`, `parent`, `name`, где поле `parent` содержит id родителя.
Оформление вложенности пробелами
Обычный пробел в начале текста элемента option не выводится, поэтому нужно использовать мнемонику
 
– широкий пробел.
В начале получаем все записи из БД в виде ассоциативного массива.
С помощью функции array_to_tree() преобразуем его в древовидный, к элементам массива добавляется элемент «children» в который перемещаются все дочерние элементы.
С помощью функции out_options() рекурсивно выводятся все элементы массива.
Во втором аргументе функции out_options() указывается id элемента, которому нужно установить selected.
<?php
$dbh = new PDO('mysql:dbname=таблица;host=localhost', 'логин', 'пароль');
$sth = $dbh->prepare("SELECT * FROM `category` ORDER BY `name`");
$sth->execute();
$category = $sth->fetchAll(PDO::FETCH_ASSOC);
$category = array_to_tree($category);
function array_to_tree($array, $sub = 0)
{
$a = array();
foreach($array as $v) {
if($sub == $v['parent']) {
$b = array_to_tree($array, $v['id']);
if(!empty($b)) {
$a[$v['id']] = $v;
$a[$v['id']]['children'] = $b;
} else {
$a[$v['id']] = $v;
}
}
}
return $a;
}
function out_options($array, $selected_id = 0, $level = 0)
{
$level++;
$out = '';
foreach ($array as $i => $row) {
$out .= '<option value="' . $row['id'] . '"';
if ($row['id'] == $selected_id) {
$out .= ' selected';
}
$out .= '>';
if ($level > 1) {
$out .= str_repeat('#emsp;', $level - 1);
}
$out .= $row['name'] . '</option>';
if (!empty($row['children'])) {
$out .= out_options($row['children'], $selected_id, $level);
}
}
return $out;
}
?>
<select name="category">
<option></option>
<?php echo out_options($category, 0); ?>
</select>
Результат:
Морепродукты Гребешки Икра горбуши Икра трески Кальмары Крабовое мясо Крабовые палочки Креветки Лобстер Мидии Раки Мороженое Мороженое батончик Мороженое брикет Мороженое ведро Мороженое весовое Мороженое колбаска Мороженое лакомка Мороженое на палочке Мороженое пломбир Мороженое рожок Мороженое рулет Овощи Баклажаны Горошек Грибы Белый гриб Вешенки Гриб моховик Лисички Маслята Опята Подберезовик Подосиновик Рыжики Шампиньоны Кабачки Капуста Картошка Кукуруза Лук репчатый Морковь Огурцы Перец Помидоры (томаты) Свекла Полуфабрикаты Готовые блюда Мясные полуфабрикаты Полуфабрикаты из теста Рыбные полуфабрикаты Смеси Грибные смеси Морской коктейль Овощные смеси Фруктовые смеси Ягодные смеси Фрукты Абрикос Ананас Апельсин Банан Гранат Груша Киви Лимон Манго Мандарины Персики Яблоки Ягоды Брусника Виноград Вишня Голубика Ежевика Земляника Клубника Крыжовник Малина Черешня Черника Черноплодная рябина
Оформление символами псевдографики
Оформление ветвей дерева с помощью символов ├ и └:
<?php
$dbh = new PDO('mysql:dbname=таблица;host=localhost', 'логин', 'пароль');
$sth = $dbh->prepare("SELECT * FROM `category` ORDER BY `name`");
$sth->execute();
$category = $sth->fetchAll(PDO::FETCH_ASSOC);
$category = array_to_tree($category);
function array_to_tree($array, $sub = 0)
{
$a = array();
foreach($array as $v) {
if($sub == $v['parent']) {
$b = array_to_tree($array, $v['id']);
if(!empty($b)) {
$a[$v['id']] = $v;
$a[$v['id']]['children'] = $b;
} else {
$a[$v['id']] = $v;
}
}
}
return $a;
}
function out_options($array, $selected_id = 0, $level = 0)
{
$level++;
$out = '';
foreach ($array as $i => $row) {
$out .= '<option value="' . $row['id'] . '"';
if ($row['id'] == $selected_id) {
$out .= ' selected';
}
$out .= '>';
if ($level > 1) {
if ($level > 2) {
$out .= str_repeat(' ', $level - 1);
}
$keys = array_keys($array);
$last_keys = $keys[count($array) - 1];
if ($last_keys != $i) {
$out .= '├';
} else {
$out .= '└';
}
}
$out .= $row['name'] . '</option>';
if (!empty($row['children'])) {
$out .= out_options($row['children'], $selected_id, $level);
}
}
return $out;
}
?>
<select name="category">
<option></option>
<?php echo out_options($category, 0); ?>
</select>
Результат:
Морепродукты ├Гребешки ├Икра горбуши ├Икра трески ├Кальмары ├Крабовое мясо ├Крабовые палочки ├Креветки ├Лобстер ├Мидии └Раки Мороженое ├Мороженое батончик ├Мороженое брикет ├Мороженое ведро ├Мороженое весовое ├Мороженое колбаска ├Мороженое лакомка ├Мороженое на палочке ├Мороженое пломбир ├Мороженое рожок └Мороженое рулет Овощи ├Баклажаны ├Горошек ├Грибы ├Белый гриб ├Вешенки ├Гриб моховик ├Лисички ├Маслята ├Опята ├Подберезовик ├Подосиновик ├Рыжики └Шампиньоны ├Кабачки ├Капуста ├Картошка ├Кукуруза ├Лук репчатый ├Морковь ├Огурцы ├Перец ├Помидоры (томаты) └Свекла Полуфабрикаты ├Готовые блюда ├Мясные полуфабрикаты ├Полуфабрикаты из теста └Рыбные полуфабрикаты Смеси ├Грибные смеси ├Морской коктейль ├Овощные смеси ├Фруктовые смеси └Ягодные смеси Фрукты ├Абрикос ├Ананас ├Апельсин ├Банан ├Гранат ├Груша ├Киви ├Лимон ├Манго ├Мандарины ├Персики ├Яблоки └Ягоды ├Брусника ├Виноград ├Вишня ├Голубика ├Ежевика ├Земляника ├Клубника ├Крыжовник ├Малина ├Черешня ├Черника └Черноплодная рябина
Использование optgroup
Использование optgroup label="" оправдано если необходимо выбрать только крайнюю категорию в дереве, но optgroup не поддерживает вложенность и никакие пробельные символы в начале label="...". Поэтому в примере используется — – широкое тире.
<?php
$dbh = new PDO('mysql:dbname=таблица;host=localhost', 'логин', 'пароль');
$sth = $dbh->prepare("SELECT * FROM `category` ORDER BY `name`");
$sth->execute();
$category = $sth->fetchAll(PDO::FETCH_ASSOC);
$category = array_to_tree($category);
function array_to_tree($array, $sub = 0)
{
$a = array();
foreach($array as $v) {
if($sub == $v['parent']) {
$b = array_to_tree($array, $v['id']);
if(!empty($b)) {
$a[$v['id']] = $v;
$a[$v['id']]['children'] = $b;
} else {
$a[$v['id']] = $v;
}
}
}
return $a;
}
function out_optgroup_options($array, $selected_id = 0, $level = 0)
{
$level++;
$out = '';
foreach ($array as $i => $row) {
if (empty($row['children'])) {
$out .= '<option value="' . $row['id'] . '"';
if ($row['id'] == $selected_id) {
$out .= ' selected';
}
$out .= '>';
if ($level > 1) {
$out .= str_repeat('#emsp;', $level - 1);
}
$out .= $row['name'] . '</option>';
} else {
$out .= '<optgroup label="';
if ($level > 1) {
$out .= str_repeat('—', $level - 1);
}
$out .= $row['name'] . '"></optgroup>';
$out .= out_optgroup_options($row['children'], $selected_id, $level);
}
}
return $out;
}
?>
<select name="category">
<option></option>
<?php echo out_optgroup_options($category, 0); ?>
</select>
Результат:
Гребешки Икра горбуши Икра трески Кальмары Крабовое мясо Крабовые палочки Креветки Лобстер Мидии Раки Мороженое батончик Мороженое брикет Мороженое ведро Мороженое весовое Мороженое колбаска Мороженое лакомка Мороженое на палочке Мороженое пломбир Мороженое рожок Мороженое рулет Баклажаны Горошек Белый гриб Вешенки Гриб моховик Лисички Маслята Опята Подберезовик Подосиновик Рыжики Шампиньоны Кабачки Капуста Картошка Кукуруза Лук репчатый Морковь Огурцы Перец Помидоры (томаты) Свекла Готовые блюда Мясные полуфабрикаты Полуфабрикаты из теста Рыбные полуфабрикаты Грибные смеси Морской коктейль Овощные смеси Фруктовые смеси Ягодные смеси Абрикос Ананас Апельсин Банан Гранат Груша Киви Лимон Манго Мандарины Персики Яблоки Брусника Виноград Вишня Голубика Ежевика Земляника Клубника Крыжовник Малина Черешня Черника Черноплодная рябина
multilevel_select.rar