Display Top Level parent page name?

Permalink 1 user found helpful
Hi,

I have a few levels of pages, and on the lower pages (3 levels down) i would like to display their category (top level page).

Is there a way to do it? I know the below code will display the parent page name, but can it call the top level page?

<?php
$parent = Page::getByID($c->getCollectionParentID()); echo $parent->getCollectionName();
?>


Thanks in advance

atlantisdigital
 
beebs93 replied on at Permalink Reply
beebs93
$c = Page::getCurrentPage();
// If not on the home page
if($c->cID > 1){
   $nh = Loader::helper('navigation');   
   $arrTrail = array_reverse($nh->getTrailToCollection($c));
   $objHomePage = $arrTrail[0]; // Home page object;
   // If we're on a top-level page then our $arrTrail array will only have the home page object
   // so we test to see if its Page object exists
   $objTopPage = is_object($arrTrail[1]) && $arrTrail[1] instanceof Page && !$arrTrail[1]->error ? $arrTrail[1] : NULL;
}


You can also parse out the first tier from $_SERVER['REQUEST_URI'] and do a Page::getByPath('path here'), but the first solution will ensure it will run successfully even if you're viewing the default for a page type through the dashboard (without any additional checks).
cmscss replied on at Permalink Reply
Thanks heaps for posting this example - very helpful.

I'm trying to do a similar thing and always display the ultimate parent (one down from the home page) no matter where you are in the tree - which looks like this:

Home
 |_Store
   |_Bed Linen
     |_Sheets
       |_Product 1
       |_Product 2
       |_Product 3
     |_Bedspreads
       |_Product 1
       |_Product 2
       |_Product 3


Using your example code, the following displays in the sub-nav's top position:
- Store: Fatal error: Call to a member function getCollectionName()
- Bed Linen: "Home" is displayed at the top
- Sheets: "Store" is displayed at the top
- Product 1: "Bed Linen" is displayed at the top

Basically it will only display two levels up with an error when there isn't two levels up. I could hard-code "Store" at the top but then I'd have to create a sub-menu template for each section in the site.

This is what I have so far:
$parentTrail = array_reverse($nh->getTrailToCollection($c));
$objHomePage = array_pop($parentTrail); // Home page Page object
$objTopPage = array_pop($parentTrail); // Current top page Page object      
$title = $objTopPage->getCollectionName();
$url = View::URL($objTopPage->getCollectionPath());         
// print parent
echo('<li><a class="current" href="' . $url . '"' . '>' . $title . '</a>' . '</li>');


Sorry for not understanding - am trying to do this with little to no PHP knowledge.

Any suggestions would be welcome.

Cheers

Ben
beebs93 replied on at Permalink Reply
beebs93
I've modified the original code since I realized it had a small flaw.

For your situation I guess this is close to what you're asking about:

$c = Page::getCurrentPage();
// If not on the home page
if($c->cID > 1){
   $nh = Loader::helper('navigation');   
   $arrTrail = array_reverse($nh->getTrailToCollection($c));
   $objHomePage = $arrTrail[0]; // Home page object;
   // If we're on a top-level page then our $arrTrail array will only have the home page object
   // so we test to see if its Page object exists
   $objTopPage = is_object($arrTrail[1]) && $arrTrail[1] instanceof Page && !$arrTrail[1]->error ? $arrTrail[1] : NULL;
   // If we have a valid top page Page object we retrieve 
   $title = $objTopPage ? $objTopPage->getCollectionName() : '';
   $url = $objTopPage ? $nh->getLinkToCollection($objTopPage) : '';
}


Are you just trying to hard-code a link to the current path's main parent on each page?
cmscss replied on at Permalink Reply
Mate, thank you so much for replying.

I get the following error:
"Catchable fatal error: Object of class Page could not be converted to string" then it gives me the line number of the echo statement.

I think my syntax is a bit screwy - is the generic autonav template code beforehand conflicting with your suggestion or is it my echo statement?

<!-- sub navigation -->
   <ul class="s-nav">
      <?php  defined('C5_EXECUTE') or die("Access Denied.");
         $aBlocks = $controller->generateNav();
         $c = Page::getCurrentPage();
         $containsPages = false;
         $nh = Loader::helper('navigation');
         // If not on the home page         
         if($c->cID > 1){
            $nh = Loader::helper('navigation');   
            $arrTrail = array_reverse($nh->getTrailToCollection($c));
            $objHomePage = $arrTrail[0]; // Home page object;
            // If we're on a top-level page then our $arrTrail array will only have the home page object
            // so we test to see if its Page object exists
            $objTopPage = is_object($arrTrail[1]) && $arrTrail[1] instanceof Page && !$arrTrail[1]->error ? $arrTrail[1] : NULL;


I don't know any php sorry but hope this is basic to fix!

No worries if it's too hard.

Cheers

Ben
beebs93 replied on at Permalink Reply
beebs93
Change that last line to:

// print parent (if on one of its subpages)
echo !is_null($objTopPage) ? '<li><a class="current" href="' . $url . '">' . $title . '</a>' . '</li>' : '';


It reads like: If we are on a sub page of any main parent page we echo a link, otherwise, we echo out nothing.
cmscss replied on at Permalink Reply
Mate - Works perfectly!

So what is this doing?
!is_null($objTopPage) ?
beebs93 replied on at Permalink Reply
beebs93
If we're not below one the main parent pages (a page directly under the home page) then that $nh->getTrailToCollection() function will only return the Page object (a.k.a. page information) for the home page.

We need to test to make sure we are on a sub page of the main parent page so we don't attempt to request information about an object that doesn't exist.

So that line in question is basically saying:

If the Page object (page information about the current main parent page) does NOT exist, then don't echo out a link to it since we're most likely already viewing it.

If the Page object DOES exist, then it means we're on one of its sub pages so we can safely request information from it (its name, link, etc.).

Hope that helps :)
cmscss replied on at Permalink Reply
OK, I'm beginning to understand - thanks for that, much appreciated.

So if I wanted to have the ultimate parent display in the menu when actually on the ultimate parent page (just for consistency - I would do something like this in an else statement?
<!-- sub navigation -->
   <ul class="s-nav">
      <?php  defined('C5_EXECUTE') or die("Access Denied.");
         $aBlocks = $controller->generateNav();
         $c = Page::getCurrentPage();
         $containsPages = false;
         $nh = Loader::helper('navigation');
         // If not on the home page         
         if ($c->cID > 1) {
            $nh = Loader::helper('navigation');   
           $arrTrail = array_reverse($nh->getTrailToCollection($c));
           $objHomePage = $arrTrail[0]; // Home page object;
           // If we're on a top-level page then our $arrTrail array will only have the home page object
           // so we test to see if its Page object exists
           $objTopPage = is_object($arrTrail[1]) && $arrTrail[1] instanceof Page && !$arrTrail[1]->error ? $arrTrail[1] : NULL;


As you can see, I'm just copying and modifying code that worked previously - which doesn't work!

Have you already defined the ultimate parent as a variable in your code which I could reuse in my else statement - or is what I've done the right idea, just the wrong execution?

Have also tried this for the else statement:
// If on the ultimate parent
         else {
            $title = getCollectionName();
            $url = getCollectionPath();
            // print parent (if on the ultimate parent)
            echo '<li><a class="current" href="' . $url . '"' . '>' . $title . '</a>' . '</li>';
beebs93 replied on at Permalink Reply
beebs93
Replace this IF statement

if($c->cID > 1){
   // blah blah blah
}


with this:

// If not on the home page         
if ($c->cID > 1) {
   $nh = Loader::helper('navigation');   
   $arrTrail = array_reverse($nh->getTrailToCollection($c));
   $objHomePage = $arrTrail[0]; // Home page object;
   // If we're on a top-level page then our $arrTrail array will only have the home page object
   // so we test to see if its Page object exists
   $objTopPage = is_object($arrTrail[1]) && $arrTrail[1] instanceof Page && !$arrTrail[1]->error ? $arrTrail[1] : $c;
   // If we have a valid top page Page object we retrieve 
   $title = $objTopPage->getCollectionName();
   $url = $nh->getLinkToCollection($objTopPage);
   // print parent (if on one of its subpages)
   echo '<li><a class="current" href="' . $url . '"' . '>' . $title . '</a>' . '</li>';
}


Now, we're saying that if we're not a sub page of the parent then we must be on the parent itself so we'll use whichever to get the name and URL so we can always show a link.

Let me know how that works out.
cmscss replied on at Permalink Reply
Mate - totally awesome!

So an important thing that has changed is that we're no longer checking for NULL here:
$arrTrail[1]->error ? $arrTrail[1] : NULL;


We have $c instead - is this the concrete5 class?
$arrTrail[1]->error ? $arrTrail[1] : $c;


Sorry to bug you - it works great so only answer if you have time.

Cheers

Ben
beebs93 replied on at Permalink Reply
beebs93
Glad to hear it's working - and don't worry about asking a lot of questions; it's good practice for me :)

$c is the current page's Page object which we retrieved by doing:

$c = Page:getCurrentPage();


It acts as a starting point to building the breadcrumb list when we call $nh->getTrailToCollection($c).
cmscss replied on at Permalink Reply
I think I'm understanding about 12% of what you're tailing about!

Got it - we're defining $c further up as you say.

Do you do consulting or are you employed?
beebs93 replied on at Permalink Reply
beebs93
Employed - hope my boss doesn't read this :)

Diving into editing concrete5's blocks can be pretty daunting especially if you don't have a basic grasp of PHP and the guts of the CMS itself.

Kudos for trying :)
cmscss replied on at Permalink Reply
Thanks mate - much appreciated!
SteamSynthetic replied on at Permalink Reply
This is something that worked for me if someone wanted to put it into the page template, and not into an autonav.

<h1><?php 
         $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 $parent->getCollectionName(); 
         }
         ?>
      </h1>


Basically, in your theme, it will check if its the homepage, and also check if its a top level navigation page. If it is, it displays the title. If its a 2nd level navigation page, it displays the parent title.

It works in a situation like this:
Home
About
Products
-Subcategory 1
-Subcategory 2
Where as the subcategory page will still display "Products" as the main title, then you can echo out the current page name as a subtitle.