Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Building a multilevel Navigation
#1
Hi,

first I want to say how great this project ist. After only 2 Minutes of reading through the Docu it seams clear how to build a complete Theme. - you really keep it simple here.

What I miss in GetSimple is an easy way to build a multilevel navigation. There is a way to create the structure in the backend, but none to print it out in the frontend.

WHat I want to do is building a top-level with Home, private, work, contact - and under private there would be images, links ...
the later should only be visible if the user is somewhere in "private"

As far as I know the only way to do this is by using menu_data('p'), (with a slug that not exists) to get the complete structure of my site. Next step is to loop through the array to build a navigation structure,
check for Pages where (parent-slug == [current slug]) or (parent_slug == [current page parent_slug])
and print out the subnavigation.

What is the best way to get the complete list? using an undefined slug seems hacky to me.
Why can't I ask for the menudata under a specified parent? (menu_data('private/') or menu_data('private') won't give me what I expect.

there is a very rapid update-cycle for getSimple at the moment. Can we expect thet multilevel-navigations will be supported out of the box in near future?

thanks and greetings
Stil
*******************
http://blog.projekt2k.de
*******************
Reply
#2
I hacked something together which does what I need:
  • create a first level nav <ul class="lvl_1">
  • add a li for every first level-element
  • add a <ul class="lvl-2"> in the current li for the level the user currently is in
so this shows only sublevels if the user clicked the parent

2 problems had to been worked around :
  • menu_data(); wont give all date but only for the current page - so I pass a not existing slug - that helped
  • menu_data(); wont add the slug for the index page (wtf??) so I hardcode it in if no slog is found.

I added the classnames as they are used in GetSimple - every list entry has class="slug" and "current" if selected.

I'm not a PHP guru - some things my have been done in better ways - let me know about possible optimization.

EDIT - don't use this - see my later post http://get-simple.info/forum/viewtopic.p...1107#p1107
Code:
<ul class="lvl_1">
    <?php
        $navdata        = menu_data('pxp');        // I managed only to get all menu data by passing a not existing slug
        $current_slug    = return_page_slug();    // slug uf current page
        $parent_slug    = $current_slug."/";    // set default parent - the current page
        
        // if user is already on a subpage - find parent-slug
        foreach ($navdata as $navpoint) {
            // if in a sublever-page - search the current in array - set parent
            if( ($navpoint['slug']==$current_slug) AND ($navpoint['parent_slug'] != '')) {
                $parent_slug = $navpoint['parent_slug'];
            }
        }

        // prepare sublevels fur current category - if there are any
        $sublevel = "";
        foreach ($navdata as $navpoint) {
            if($navpoint['parent_slug'] == $parent_slug) {
                // got one - add it
                
                $classnames = $navpoint['slug'];
                if($navpoint['slug'] == $current_slug) {
                    // found current page !!
                    $classnames .= " current";
                }
                
                $sublevel .= '<li class="'.$classnames.'"><a href="'.$navpoint['url'].'">'.$navpoint['menu_text'].'</a></li>';
            }
        }
        
        foreach ($navdata as $navpoint) {
            if($navpoint['parent_slug'] == '') {
                // first level Navpoints
                
                // there is a big - startpage hasn't got its slug in the data - workaround
                // in my case the slug for the startpage is "index"
                if($navpoint['slug'] == '') {
                    $navpoint['slug'] = 'index';
                }
                
                $classnames = $navpoint['slug'];
                if($navpoint['slug'] == $current_slug) {
                    // found current page !!
                    $classnames .= " current";
                }
                
                echo '<li class="'.$classnames.'">';
                echo '<a href="'.$navpoint['url'].'">'.$navpoint['menu_text'].'</a>';
                // now check for subcategories
                if( ($navpoint['slug'].'/' == $parent_slug) AND ($sublevel != '') ) {
                    echo '<ul class="lvl_2">'.$sublevel.'</ul>';
                }
                echo '</li>';
            }
        }
    ?>
</ul>

hope that helps others.

@GetSimple : keep doing your great work - maybe solve the index->noSlug problem ;-)
*******************
http://blog.projekt2k.de
*******************
Reply
#3
hi,

thanks for your post... after reading your thread, I looked into the code and didn't understand why menu_data() only answers the menu data if the menu is marked as "Add to Menu?" on line 188 in theme_functions.php
Code:
if ($page['menuStatus'] == 'Y' && $page['private'] != 'Y') { ... }

so i changed it to:
Code:
if ($page['private'] != 'Y') { ... }

i modified your code, writing a small function which gets the slug-id and responds with the children-slugs
Code:
function get_submenu_data($id) {
    $navdata      = menu_data("doesnotexist");
    $parent_slug  = $id."/";
    $result       = array();
    foreach ($navdata as $navpoint) {
        if ($navpoint['parent_slug']==$parent_slug) {
            $result[] = menu_data($navpoint['slug']);
        }
    }
    return $result;
}

a developer can write a wrapper function and use that for rendering the submenu
Reply
#4
Thank you guys for your code...

the menu_data() function is still in it's infancy, and may change slightly from what is currently distributed with version 1.5. I would be cautious where you use this function because of that. This is the only function in this stage as it was added in 1.5 with no intention of it being used - i just accidentally mentioned it in one post, and now it has taken off...
- Chris
Thanks for using GetSimple! - Download

Please do not email me directly for help regarding GetSimple. Please post all your questions/problems in the forum!
Reply
#5
@Chris: Any changes to this in the newer versions? Tried to add pages with a parent page and saw that there is no multi-level navigation yet. Hope this can be added or is there a chance to include some own plugins?

@StilgarBF: Thanks for your post, added this and the naviagation works fine. Even though i was feeling a bit that i will need another level at some time, and don't know currently how to fix this. Currently your code displays all post, just thrown into an array of <li> points. I do not know much about the menu_data() function, but is there a possibility to display the list points in a certain order?

Thanks for your help,

Mike
Reply
#6
menu_data() is not set up to automatically give you multilevel navigation. It just provides all the data needed...
- Chris
Thanks for using GetSimple! - Download

Please do not email me directly for help regarding GetSimple. Please post all your questions/problems in the forum!
Reply
#7
I was wondering about this myself, and I ended up crafting a workaround for a client project.

Each primary section of the site has its own template. Within that template, I used a component that included the sub-navigation for that particular section.

So the "widgets" section includes a component called "widgets-nav", for example. And then "gadgets" gets "gadgets-nav", and so on.

It's not the prettiest thing (and definitely not scalable, but GS is for small sites, not large). If you're comfortable with the system and know that you won't be changing your navigation structure on a regular basis, it should be sufficient.
Reply
#8
I reused my original-code (first post) with a version 1.7 site and found that menu_data() is not returning all data.
['slug'] is allwas empty. 'url' does not contain a slug so this url is unusable. am I doing something wrong?
my code is a simple:
Code:
<pre>
<?php
     var_dump(menu_data());
?>
</pre>
*******************
http://blog.projekt2k.de
*******************
Reply
#9
StilgarBF Wrote:I reused my original-code (first post) with a version 1.7 site and found that menu_data() is not returning all data. ['slug'] is allwas empty. 'url' does not contain a slug so this url is unusable. am I doing something wrong?

my 1.7 works with that empty syntax, but please try this - using a slug that does really NOT exist:

Code:
<?php var_dump(menu_data("doesnotexist")); ?>
Reply
#10
I have same problem!

Slug is empty

Anybody have a decision?
Reply
#11
Alexey Wrote:I have same problem!
Slug is empt
Anybody have a decision?

I patched theme_function.php (/admin/inc/) to make my multilevel-navigation work.
I give no guarantee this won't make any problems elsewhere:
Code:
starting from line Line 203
                    if ($PRETTYURLS == '1') {
                        if ($parent != '') {$parent = tsl($parent); }
                        if ($slug == 'index' ) { $slugs = ''; } else { $slugs = $slug; }
                        $url = $SITEURL . @$parent . $slugs;
                    } else {
                        if ($slug == 'index' ) { $slugs = ''; } else { $slugs = '?id='.$slug; }
                        $url = $SITEURL .'index.php'.$slugs;
                    }
                    
                    $specific = array("slug"=>$slug,"url"=>$url,"parent_slug"=>$parent,"title"=>$title,"menu_priority"=>$pri,"menu_text"=>$text,"menu_status"=>$menuStatus,"private"=>$private);

my multilevelnavi has changed completely:
Code:
<ul id="navigation">
    <?php
        $navdata        = menu_data();            // I managed only to get all menu data by passing a not existing slug
        $current_slug    = return_page_slug();   // slug of current page
        $parent_slug    = $current_slug."/";    // set default parent - the current page
  
        // if user is already on a subpage - find parent-slug
        foreach ($navdata as $navpoint) {
            // if in a sublever-page - search the current in array - set parent
            if( ($navpoint['slug']==$current_slug) AND ($navpoint['parent_slug'] != '')) {
                $parent_slug = $navpoint['parent_slug'];
                break;
            }
        }
        
        function hasSublevel($parentSlug, $nd) {
            foreach ($nd as $navpoint) {
                if($navpoint['parent_slug']==$parentSlug) {
                    return true;
                }
            }
            return false;
        }
        
        function isParentOfActive($slug, $nd) {
            $current_slug    = return_page_slug();
            foreach ($nd as $navpoint) {
                if(($navpoint['slug']==$current_slug) AND ($navpoint['parent_slug'] == $slug)) {
                    return true;
                }
            }
            return false;
        }
        
        function printSublevel($parentSlug, $nd) {
            $current_slug    = return_page_slug();
            foreach ($nd as $navpoint) {
                if($navpoint['parent_slug']==$parentSlug) {
                    // found a subpage of this parent
                    $classnames = $navpoint['slug'];
                    if($navpoint['slug'] == $current_slug) {
                        // found current page !!
                        $classnames .= " current";
                    }
                    echo '<li class="'.$classnames.'">';
                    echo '<a href="'.$navpoint['url'].'">'.$navpoint['menu_text'].'</a>';
                    echo '</li>';
                }
            }
        }
        
        foreach ($navdata as $navpoint) {
            if($navpoint['parent_slug'] == '') {
                // first level Navpoints
                
                $classnames = $navpoint['slug'];
                if(($navpoint['slug'] == $current_slug) or isParentOfActive($navpoint['slug'], $navdata)) {
                    // found current page !!
                    $classnames .= " current";
                }
                
                echo '<li class="'.$classnames.'">';
                echo '<a href="'.$navpoint['url'].'">'.$navpoint['menu_text'].'</a>';
                // now check for subcategories
                if( (($navpoint['slug'].'/' == $parent_slug) AND hasSublevel($navpoint['slug'], $navdata)) OR isParentOfActive($navpoint['slug'], $navdata) ) {
                    echo '<ul class="lvl_2">';
                    printSublevel($navpoint['slug'], $navdata);
                    echo '</ul>';
                }
                echo '</li>';
            }
        }
    ?>
</ul>

Now this shows the subcategories even if you are IN the subcategory
It highlights the current subcategory and the parent category.
It's working only for 2 levels (root and one sublevel)

Once again I can not guarantee this will work under al circumstances.
It's a bit quick'n dirty I know - needed to finish this. If anyone has ideas how to improve this - let me know.


Stil
*******************
http://blog.projekt2k.de
*******************
Reply
#12
@Stil

Thank you!
I found decision!

And finalize now my dropdown menu

Here is pict
Reply
#13
This could easily be achieved by returning the data as XML from "menu_data()" as added in 1.7
and using xpath to query the results ...

You'll need to add code to check for current pages and add style ti the lists...

Code:
// returns menu with submenus
// submenu items are children of menu items.
$data=simplexml_load_string(menu_data('',true));
$topmenu= subval_sort($data->xpath("//*[menuStatus='Y']"),'menuOrder');
foreach ($topmenu as  $menu){
// output the top level menu items
   echo "<li>".$menu->slug."</li>";
   $submenus= $data->xpath("//*[parent='".$menu->slug."']");
// output submenu if it exists
   if (count($submenus) != 0) {  
     echo "<ul>";
     foreach ($submenus as $submenu){
       echo "<li class='submenu'>".$submenu->slug."</li>";
     }
   echo "</ul>";
    }
}

Mike.


edit. just changed the variable names...
My Github Repos: Github
Website: DigiMute
Reply
#14
n00dles101 Wrote:This could easily be achieved by returning the data as XML from "menu_data()" as added in 1.7
and using xpath to query the results ...

You'll need to add code to check for current pages and add style ti the lists...
....

Mike.
I'll give this a try - looks smart!

thx
*******************
http://blog.projekt2k.de
*******************
Reply
#15
n00dles101 Wrote:This could easily be achieved by returning the data as XML from "menu_data()" as added in 1.7
and using xpath to query the results ...

You'll need to add code to check for current pages and add style ti the lists...

Hi n00dles101,

sorry if this is a stupid question Smile can you tell me where exactly I should insert the latest code (your post October 22nd just above)

and is that the only modification (beside css change to style <ul> <li> of course) ?

many thanks in advance for your help
Patricia
Reply
#16
Hi Patricia,

You could just put it directly into your template.php, and replace the call to <?php get_navigation(); ?>

adn replace it with:

Code:
<?php
$data=simplexml_load_string(menu_data('',true));
$topmenu= subval_sort($data->xpath("//*[menuStatus='Y']"),'menuOrder');
foreach ($topmenu as  $menu){
// output the top level menu items
   echo "<li>".$menu->slug."</li>";
   $submenus= $data->xpath("//*[parent='".$menu->slug."']");
// output submenu if it exists
   if (count($submenus) != 0) {  
     echo "<ul>";
     foreach ($submenus as $submenu){
       echo "<li class='submenu'>".$submenu->slug."</li>";
     }
   echo "</ul>";
    }
}
?>


I would instead put it in the theme functions file as a function and call that instead.

Mike.
My Github Repos: Github
Website: DigiMute
Reply
#17
I thank you very much, this is actually what I did the first time, but as I didn't manage so I asked my previous question.

in my pages I have the home page, the page 2, and "page-22-sub" as child of page2

so I added this new function to the admin/inc/theme_functions.php
Code:
function get_fullnavigation($currentpage) {
        $data=simplexml_load_string(menu_data('',true));
        $topmenu= subval_sort($data->xpath("//*[menuStatus='Y']"),'menuOrder');
        foreach ($topmenu as  $menu){
         // output the top level menu items
           echo "<li>".$menu->slug."</li>";
           $submenus= $data->xpath("//*[parent='".$menu->slug."']");
        // output submenu if it exists
           if (count($submenus) != 0) {  
             echo "<ul>";
             foreach ($submenus as $submenu){
               echo "<li class='submenu'>".$submenu->slug."</li>";
             }
           echo "</ul>";
            }
        }
    }

but I get this menu (not even showing Home anymore)
Code:
<ul id="nav">
            <li>page-2</li><li></li><ul><li class="submenu"></li><li class="submenu">page-2</li></ul><li>page-22-sub</li>        </ul>

but the correct menu code should be something like:
Code:
<ul id="nav">
    <li><a href="http://localhost/process/GetSimple/home" title="Home">Home</a></li>
    <li><a href="http://localhost/process/GetSimple/page-2" title="Page 2">Page 2</a>
        <ul>
            <li class="submenu"><a href="http://localhost/process/GetSimple/page-2/page-22-sub" title="Page 2.2 sub">Page 2.2 sub</a></li>
        </ul>
    </li>
</ul>

for info, with the original get_navigation, I get :
Code:
<ul id="nav">
            <li class="page-22-sub"><a href="http://localhost/process/GetSimple/page-2/page-22-sub" title="Page 2.2 sub">Page 2.2 sub</a></li>
<li class="current index"><a href="http://localhost/process/GetSimple/" title="Welcome to GetSimple!">Home</a></li>
<li class="page-2"><a href="http://localhost/process/GetSimple/page-2" title="Page 2">Page 2</a></li>
        </ul>

so the replacement code:
- do not insert <a> tags, --> missing the link
- miss the home page
- do not nest sub <ul> inside the parent <li>, and add unnecessary <li></li>

or maybe I missed something? (where/what)?

I know it should be easy to modify... but for me a simple change will take hours (days Smile ) LOL
I will look into it anyway

thx again
Patricia
Reply
#18
another small request for the multi-level navigation:

the parent slug of the current can't be highlighted via css if the current slug is a child of the parent (getsimple 1.7, admin/inc/theme_functions.php, line 326)
Code:
if ("$currentpage" == "$url_nav") {
    $classes = "current ". $url_nav;
} else {
    $classes = $url_nav;
}

so, i changed this line to the following... now, the parent slug of a current gets the 'current'-css-class, too
Code:
$menudata = menu_data($currentpage);
if ("$currentpage" == "$url_nav" || $menudata['parent_slug'] == $url_nav) {
    $classes = "current ". $url_nav;
} else {
    $classes = $url_nav;
}

ccagle8: for usability reasons, it would be nice to have it. could you accept that for next version of gs?
Reply
#19
Can someone post the final working code?

When a post gets long, with many revisions and add-ons, it's easy to get lost.

Thanks.

homershines
Reply
#20
Yes, I agree, thanks guy for the code. But someone needs (please) to pull this together.

Too me it's (at the moment) a bit unclear which code to use ans which modification to make AND how to call the nav-menu in the end.
For example, I just get "sublevel"-menu-entries for the top-pages and NOT the sub-pages. Very strange.

for example starting on the Top-Page1:
Code:
-Top-Page1
-Top-Page2
-Top-Page3
-Top-Page4
then changing to Top-Page2, I get a sub-menu, displaying top-pages 1to4 under top-page1:
Code:
-Top-Page1
       -Top-Page1
       -Top-Page2
       -Top-Page3
       -Top-Page4
-Top-Page2
-Top-Page3
-Top-Page4

When changing to a sub-page, just the top-pages get diplayed in the menu.

Still trying to figure it out (new to php), but would be nice if someone could put this together and give a short example. Thank you!
Reply
#21
homershines Wrote:Can someone post the final working code?
Texta Wrote:Yes, I agree, thanks guy for the code. But someone needs (please) to pull this together.

Can't give you the exact code they have been talking about here, but I can give you mine. As I just published it here on the forum.
“Don’t forget the important ˚ (not °) on the a,” says the Unicode lover.
Help us test a key change for the core! ¶ Problems with GetSimple? Be sure to enable debug mode!
Reply
#22
Thank you very much, Zegnåt!
Reply




Users browsing this thread: 1 Guest(s)