Пример рекурсивного меню
Вот как построена ёлочка слева на данном сайте, думаю по этому примеру можно сделать что угодно, за основу лучше брать функцию menu() в движке..В примере не происходит парсинга описания из шаблона, это немного долго, функция итак не особо быстрая из-за рекурсии всего дерева, даёт проседание в половину времени генерации страницы..
Добавляю данные функции обычно в конец /index.php или в файл шаблона.
PHP
function menul($typ,$p1='',$p2='',$p3=''){ global $menu,$g; static $next=0,$c1=0,$c2=0,$c3=0,$mtyp=''; if($mtyp!=$typ){$c1=0;$mtyp=$typ;}//Смена типа меню $p=1;$i=$c1; if(''!=$p1){ if(''==$p2 && ''==$p3){$p=2;$i=$c2;} elseif(''!=$p2 && ''==$p3){$p=3;$i=$c3;} elseif(''!=$p2 && ''!=$p3){$p=4;$i=0;} } for($w=$i;$w<MENUSIZE;$w++){ $r=$menu[$w]; if($r['typ']==$typ && 'no'!=$r['active'] && $r['par1']==$p1 && $r['par2']==$p2 && $r['par3']==$p3){ $x=$next;$pl='';$ishav=false; if($p==4){ $xlink=$r['par1'].'/'.$r['par2'].'/'.$r['par3'].'/'.$r['name']; $la='a4';$li='i4 '; } elseif($p==3){ $xlink=$r['par1'].'/'.$r['par2'].'/'.$r['name']; $la='a3';$li='i3 '; } elseif($p==2){ if('context'==$r['name'] || 'ip'==$r['name'])$ishav=1;//ручное управление.. ishave($typ,$r['par1'],$r['name']); $xlink=$r['par1'].'/'.$r['name']; $la='a2';$li='i2 '; } elseif($p==1){ if('speed'==$r['name'] || 'cp'==$r['name'] || 'templates'==$r['name'] || 'docs'==$r['name'] || 'modules'==$r['name'] || 'linux'==$r['name'] || 'changelog'==$r['name'] || 'any'==$r['name'])$ishav=1;//ishave($typ,$r['name']); $xlink=$r['name']; $la='';$li=''; } $ot=$r['text']; $hint=''!=$r['hint']?' title="'.$r['hint'].'"':''; $act=' class="none"'; if($r['name']==$g->item($p-1)){//открыт, подпункт $act=''; $pl=$ishav?'square-minus red" role="button" onclick="se(\''.$x.'\')':'arrow-right red';//красная стрелочка - выбран if(''!=$la)$la.=' ';$la=' class="'.$la.'onl"'; }else{ $pl=$ishav?'square-plus" role="button" onclick="se(\''.$x.'\')':'arrow-right'; if(''!=$la)$la=' class="'.$la.'"'; } if('reinstall'==$r['name'])echo'<div class="navp"></div>'; echo '<i id="i',$x,'" class="',$li,'fas fa-',$pl,'"></i><a href="/',P,$xlink,'"',$hint,$la,'>',$ot,'</a>'; if('final'==$r['name'])echo'<div class="navp"></div>'; $next++; if($p==3){ $c3=$i+1; if($ishav)echo '<div id="p',$x,'"',$act,'>'; menul($typ,$r['par1'],$r['par2'],$r['name']); if($ishav)echo '</div>'; } elseif($p==2){ $c3=0;$c2=$i+1; if($ishav)echo '<div id="p',$x,'"',$act,'>'; menul($typ,$r['par1'],$r['name']); if($ishav)echo '</div>'; } elseif($p==1){ $c2=0;$c1=$i+1; if($ishav)echo '<div id="p',$x,'"',$act,'>'; menul($typ,$r['name']); if($ishav)echo '</div>'; } } } }
JavaScript: (/inc/main.js [or older /inc/_.js])
var alist = []; function seen() { var a=[], i, c; alist=ff.sa(ff.c('seen')); for (i = 0; i < alist.length; i++){ if(ff.is(alist[i]) && ''!=alist[i]){ a.push(alist[i]); c = 'i' + alist[i]; ff.cr(c,'fa-square-plus'); ff.ca(c,'fa-square-minus'); ff.b('p'+alist[i]); } } alist = a; } function se(n){ var a=[], c='i' + n, i, t=''; for (i = 0; i < alist.length; i++){ if (alist[i] != n){a.push(alist[i]);t+=alist[i]+',';} } if (ff.d('p'+n) == 'none'){ ff.b('p'+n); ff.cr(c,'fa-square-plus'); ff.ca(c,'fa-square-minus'); a.push(n);t+=n+','; } else { ff.n('p'+n); ff.cr(c,'fa-square-minus'); ff.ca(c,'fa-square-plus'); } alist = a; ff.c('seen', t.slice(0, -1), 3600); } ff.onload(function(){ ff.init({...}); seen(); ... });