Is there a better way to do this?

Permalink
I'm always struggling with finding a way to get sub-pages to display a sidebar nav that shows ALL pages underneath the current top-level page.

I came up with this:

$current = Page::getCurrentPage();
$parent = Page::getByID($c->getCollectionParentID());
$grandParent = Page::getByID($parent->getCollectionParentID());
if(($current->getNumChildren() > 0 && $current->getCollectionName() != 'Home') 
|| ($parent->getCollectionName() != 'Home' && $parent->getNumChildren() > 0 )) {
   $navBT = BlockType::getByHandle('autonav');
   if($parent->getCollectionName() == 'Home' && $current->getNumChildren() > 0) {
      $navBT->controller->displayPages = 'below';
      echo '<h2>' .  $current->getCollectionName() .  '</h2>';
   }
   elseif($grandParent->getCollectionName()!= 'Home' && $parent->getNumChildren() > 0) {
      $navBT->controller->displayPages = 'above';
      echo '<h2>' .  $grandParent->getCollectionName() .  '</h2>';
   }
   elseif($parent->getCollectionName()!= 'Home' && $parent->getNumChildren() > 0) {


This basically is checking for a current page, parent page and grandparent page and seeing if those pages have children. If certain criteria are met, the nav controller is adjusted accordingly to always make sure I'm display all pages underneath the top-level parent page.

This only works down to three levels deep though (the grandparent page check).

Is there an easier way to do this?

Thanks!

leinteractive
 
Mainio replied on at Permalink Reply
Mainio
Not sure whether I got correctly what you wanted but I usually do something like this myself:

// Set your level here
// 0 = the first level after home page level (home => CHILD)
// 1 = the second level (home => child => CHILD)
// etc.
$level = 0;
$current = $p = Page::getCurrentPage();
$tree = array();
while ($p->getCollectionParentID() > HOME_CID) {
   array_push($tree, $p);
   $p  = Page::getByID($p->getCollectionParentID());
}
$tree = array_reverse($tree);
if (isset($tree[$level])) {
   $parent = $tree[$level];
   echo '<h2>' .  $parent->getCollectionName() .  '</h2>';


This would find the level X parent page (counting from bottom up, meaning that pages below the home page are at the very bottom).

Now sure though if it:
- Prints out the correct title that you want to
- Really works, just copied your code and modified it in notepad (has not been tested in any way!!!)
- Works as you intended it to

However, my point posting this is that you would get further from here by yourself. The key here is setting the $navBT->controller->displayPages to 'custom', so that you can control from which collection it takes the subpages with the displayPagesCID variable.


Br,
Antti / Mainio
Mnkras replied on at Permalink Reply
Mnkras
wow, both of you went over kill ;)

<?php
Loader::block('autonav');
$nh = Loader::helper('navigation');
$page = Page::getByPath("/some/page");
//$page = Page::getByID(HOME_CID);
$nav = AutonavBlockController::getChildPages($page);
foreach($nav as $n2) {
$cp = new Permissions($n2);
if ($cp->canRead()) {
?>
<li><a href="<?=$nh->getLinkToCollection($n2, false, true)?>"><?=t($n2->getCollectionName())?></a></li>
<? }
leinteractive replied on at Permalink Reply
leinteractive
That works but only under the page you specify.

What I want is a dynamic nav that works regardless of where in the site the user is currently at.

And also, your method doesn't add nested ULs for sub menus, nor does it do all the "Extras" that my AutoNav template does by adding custom css classes to each nav item for styling.
Mnkras replied on at Permalink Reply
Mnkras
ok. thats easy,

<?php
Loader::block('autonav');
$nh = Loader::helper('navigation');
$page = Page::getCurrentPage();
$nav = AutonavBlockController::getChildPages($page);
foreach($nav as $n2) {
$cp = new Permissions($n2);
if ($cp->canRead()) {
?>
<li><a href="<?=$nh->getLinkToCollection($n2, false, true)?>"><?=t($n2->getCollectionName())?></a></li>
<? }
leinteractive replied on at Permalink Reply
leinteractive
And will that output all pages under the current given top-level section or just the Child Pages under the current page?
Mnkras replied on at Permalink Reply
Mnkras
that just does the immediate children
leinteractive replied on at Permalink Reply
leinteractive
That's what I thought.

See...not as simple as you suspected! ;-)
Mnkras replied on at Permalink Reply
Mnkras
I though thats what you wanted, if you want it recursive just use the autonav block...
leinteractive replied on at Permalink Reply
leinteractive
I've tried the autonav block and it still doesn't work like I want it to. It doesn't seem to have a setting to display all pages underneath the current top-level path.

Every setting I've found in the autonav just displays the pages underneath the current page, and then clicking on one of the sibling pages no longer shows the rest of the sibling pages.
Mainio replied on at Permalink Reply
Mainio
Can you draw out some kind of tree structure what you exactly want? I'm not quite getting it...

Like this kind of explanation:
main 1
main 2
-main2 sub1
-main2 sub2
--main2 sub2 sub 1
--main2 sub2 sub 2
main 3
leinteractive replied on at Permalink Reply
leinteractive
Okay...let's say my site structure looks like this:

Home
-Sub 1
--Sub 1.1
--Sub 1.2
--Sub 1.3
-Sub 2
-Sub 3
--Sub 3.1
--Sub 3.2
---Sub 3.2.1
---Sub 3.2.2
---Sub 3.2.3
--Sub 3.2
-Sub 4

And let's say the user is on page Sub 3.2.3

I went my sidebar menu on every page under Sub 3 to display this:

<h2>Sub 3</h2>
--Sub 3.1
--Sub 3.2
---Sub 3.2.1
---Sub 3.2.2
---Sub 3.2.3
--Sub 3.2

But it should by dynamic enough to always pull in the top level parent name for the title and display children as many levels deep as I have in the sitemap, regardless of how deep the user is in the page structure.
Mainio replied on at Permalink Best Answer Reply
Mainio
Hi,

I think this can be achieved by adding few lines in my first example:
// Set your level here
// 0 = the first level after home page level (home => CHILD)
// 1 = the second level (home => child => CHILD)
// etc.
$level = 0;
$current = $p = Page::getCurrentPage();
$tree = array();
while ($p->getCollectionParentID() >= HOME_CID) {
   array_push($tree, $p);
   $p  = Page::getByID($p->getCollectionParentID());
}
$tree = array_reverse($tree);
if (isset($tree[$level])) {
   $parent = $tree[$level];
   echo '<h2>' .  $parent->getCollectionName() .  '</h2>';


I also tested that now so it should do what you want to. Please also note that you can/should set the $level variable there as you wish.

Br,
Antti / Mainio
leinteractive replied on at Permalink Reply
leinteractive
Mainio,

This seems to do exactly what I need it to do! I haven't tested fully, but so far it works great.

THANK YOU!
Mainio replied on at Permalink Reply
Mainio
At least I usually try to use the MVC structure built in and avoid custom printing out. This way I can take advantage of the c5 templates already included in the block folder. So you kinda "need to" overkill this one to use the block as it would be used when a new block is created.

Also, I don't really like that there's still A LOT of stuff in C5 that says e.g. echo '<table><tr><td>' etc. I know it's quite many times faster to do that and I also know that the autonav block's templates do this, but my personal opinion is that if you have HTML inside echo, it's not correct.

EDIT: This was @Mnkras comment on the overkilling, I think I clicked the reply button at the wrong place.