PHP function that creates a nested ul li?

2020-03-08 07:29发布

I am attemptting to attach a small CMS to a website I am creating. However I have come across a small problem. The CMS uses PHP functions for inserting menus, these PHP functions create the HTML. The particular function I wish to use (treemenu) creates a nested ul li that can then be used for a drop down menu. However the nested ul li is structured like so:

<li>Projects (Menu Level 1)</li>
    <ul>
        <li>Project 1 (Menu Level 2)</li>
        <li>Project 2 (Menu Level 2)</li>
        <li>Project 3 (Menu Level 2)</li>
    </ul>
<li>News (Menu Level 1)</li>
<li>Contact (Menu Level 1)</li>

When creating a drop down menu in CSS I believe the Menu Level 1 li should wrap its children like so:

<li>Projects (Menu Level 1)
    <ul>
        <li>Project 1 (Menu Level 2)</li>
        <li>Project 2 (Menu Level 2)</li>
        <li>Project 3 (Menu Level 2)</li>
    </ul>
</li>
<li>News (Menu Level 1)</li>
<li>Contact (Menu Level 1)</li>

I have never before worked with PHP and therefore would not know how to alter the function in order to accomplish the above. I would hope it would be a simple change. Below is the PHP function that outputs the first example structure:

function treemenu($generat=0) {
global $pagenum, $menu, $selected, $extension, $set;
$count=0;
$out="\n";
$intend=0;
while($menu[$count][0] != "") {
    if(strpos($menu[$count][3],"#") === false) {
    if($menu[$count][2]=="0" && $intend==2) {
        $intend--;
        $out.="</ul>\n";
    }
    if($menu[$count][1]=="0" && $intend==1) {
        $intend--;
        $out.="</ul>\n";
    }
    if($menu[$count][1]!="0" && $intend<1) {
        $intend=1;
        $out.="<ul>\n";
    }
    if($menu[$count][2]!="0" && $intend<2) {
        $intend=2;
        $out.="<ul>\n";
    }
    $out.="<li class=\"LNE_menu\"><a ";
    if($menu[$count][4]==$selected['name'])
        $out.= 'class="selected" ';
    if(strpos($menu[$count][3],"*"))
        $out.='href="'.str_replace("*", "",$menu[$count][3]).'">';
    elseif($generat)
        $out.='href="'.$menu[$count][3].".".$set['extension'].'">';
    else
        $out.='href="'.$set['indexfile'].'?page='.$menu[$count][3].'">';
    $out.=$menu[$count][4]."</a></li>\n";
    }
    $count++;
}
return $out;
}

Could anyone possibly point me in the right direction as to how to make the closing li tag of a level 1 menu item wrap the ul immediately after, as in the second example?

标签: php css function
5条回答
手持菜刀,她持情操
2楼-- · 2020-03-08 07:52

This would be a excellent example of the use of recursion. An array (with sub-arrays within it) defines each level, and a function loops, calling itself whenever it finds a new array to process. As long as the function cleans up appropriately (closing the </li> & </ol>), it's largely automatic.

<?php
// I know which function I'd rather write....
$tree = array('Projects (Menu Level 1)',
              array('Project 1 (Menu Level 2)',
                    'Project 2 (Menu Level 2)',
                    'Project 3 (Menu Level 2)'),
              'News (Menu Level 1)',
              'Contact (Menu Level 1)');

// now quake beneath the power of this fully operational recursive function!
function olLiTree($tree)
{
    echo '<ul>';
    foreach($tree as $item) {
        if (is_array($item)) {
            olLiTree($item);
        } else {
            echo '<li>', $item, '</li>';
        }
    }
    echo '</ul>';
}
olLiTree($tree);  // kick off from the top level
查看更多
\"骚年 ilove
3楼-- · 2020-03-08 07:57

I think this outputs the correct HTML structure.

function GenerateMenu($arr)
{
foreach($arr as $val) {
    if (next($arr)) { $nextitem = current($arr); }
    if (is_array($val)) {
        $output .= "\n<ul>\n" . GenerateMenu($val, $output) . "</ul>\n</li>\n\n";
    }
    elseif (is_array($nextitem)) { $output .= "<li>" . $val; }
    else { $output .= "<li>" . $val . "</li>\n"; }
}
return $output;
}
$html = GenerateMenu($menu);
echo("<ul>\n" . $html . '</ul>');

Same test code as above:

$menu = array('Projects (Menu Level 1)',
          array('Project 1 (Menu Level 2)',
                'Project 2 (Menu Level 2)',
                'Project 3 (Menu Level 2)'),
          'News (Menu Level 1)',
          'Contact (Menu Level 1)');
查看更多
爱情/是我丢掉的垃圾
4楼-- · 2020-03-08 07:59

It appears Topbit already beat me to this, but mine is slightly differs in that it doesn't echo the value straight to the output stream, but saves it in a variable that you may echo at your convenience:

<?php

function GenerateMenu($arr)
{
    $output = "<ul>\n";
    foreach($arr as $val) {
        if (is_array($val)) {
            $output .= "<li>\n" . GenerateMenu($val, $output) . "</li>\n";
        }
        else {
            $output .= "<li>" . $val . "</li>\n";
        }
    }
    $output .= "</ul>\n";
    return $output;
}

$html = GenerateMenu($menu);

?>

Edit:

Thanks Gumbo and Topbit, now that I'm on my machine with PHP installed, I have tested it and it works fine.

查看更多
家丑人穷心不美
5楼-- · 2020-03-08 07:59

I wrote this utilizing the PHP DOMDocument class. It will create your list as long and as deep as the list you give it using one simple and easy to follow loop. If you want it organized, just ask your database for the list sorted by title (or whatever) first. It assumes your query object data is contained in $menu_categories and it at least has properties of ->id ->parent_id & ->title (change to your needs)

$dom = new DOMDocument();
$dom->validateOnParse = true;
$dom->loadHTML("<html>");


$root = $dom->createElement('ul');
$root->setAttribute('class', 'menu');
$dom->appendChild($root);


foreach($menu_categories as $count => $category){
    $pid = $category->parent_id;
    $parent = $dom->getElementById('simple-li-'.$pid);

    if($parent != null){

        $ul = $dom->getElementById('simple-ul-'.$pid);

        if($ul == null){
            $ul = $dom->createElement('ul');
            $ul->setAttribute('id', 'simple-ul-'.$pid);
            $parent->appendChild($ul);
        }
        $target = $ul;

    }else{ 
        $target = $root;
    }   

    $li = $dom->createElement('li', $category->title);
    $li->setAttribute('id', 'simple-li-'.$category->id);
    $target->appendChild($li);
}

echo $dom->saveHTML($root);
return;

Here's the commented version...

/**
 * This is pure and simple PHP!
 * @author Jamin Szczesny - Mar 2014
 * Assuming you have a returned query list of related rows named... 
 *  $menu_categories (the list can be in any order)
 * and it has valid attributes of.. 
 * ->id (category id)
 * ->title  (category title\name)
 * ->parent_id (categories parent)
 * 
 */

$dom = new DOMDocument();//create a document
$dom->validateOnParse = true;//this is a must
$dom->loadHTML("<html>");//you must load some valid html

//add a root list to the dom
$root = $dom->createElement('ul');
$root->setAttribute('class', 'menu');
$dom->appendChild($root);

//loop through all of your category rows
foreach($menu_categories as $count => $category){
    $pid = $category->parent_id;
    $parent = $dom->getElementById('simple-li-'.$pid);

    //see if we found a parent
    if($parent != null){ //parent found...
        //look for a ul within the parent
        $ul = $dom->getElementById('simple-ul-'.$pid);

        //check to see if that ul exists
        if($ul == null){//ul not created yet so create one
            $ul = $dom->createElement('ul');
            $ul->setAttribute('id', 'simple-ul-'.$pid);
            $parent->appendChild($ul);
        }
        $target = $ul;

    }else{ //no parent found...
        $target = $root;
    }   
    //create this list item
    $li = $dom->createElement('li', $category->title);
    $li->setAttribute('id', 'simple-li-'.$category->id);
    $target->appendChild($li);
}
//output only the html from our list
echo $dom->saveHTML($root);
return;
查看更多
我命由我不由天
6楼-- · 2020-03-08 08:06

A simple function is all you need.

function unorderedList($val)
{
    if (is_array($val)) {
        return '<ul><li>' . 
                implode('</li><li>', 
                    array_map('unorderedList', $val)) . 
            '</li></ul>';
    } else {
        return $val;
    }
}

Test code:

$menu = array('Projects (Menu Level 1)',
              array('Project 1 (Menu Level 2)',
                    'Project 2 (Menu Level 2)',
                    'Project 3 (Menu Level 2)'),
              'News (Menu Level 1)',
              'Contact (Menu Level 1)');


echo unorderedList($menu);
查看更多
登录 后发表回答