Make the Header Dynamic

Now that we’ve updated the logo link, lets make the header dynamically pull the top level of pages from our Concrete CMS site. In the past we may have used an Auto-Nav block to build this list of links, but the Auto-Nav’s settings make it possible to include far more pages than you actually need, making your header navigation a bottleneck for your site. Instead, let’s use the Concrete\Core\Page\PageList class directly, which is quick and we can be sure will only access the database for directly what it needs.

First, let’s import the Concrete\Core\Page\PageList class into the page by adding a use statement for it at the top of the script. Then let’s modify the script to include this source instead of the hard-coded navigation:

<div class="collapse navbar-collapse main-menu-item" id="navbarNav">
    <ul class="navbar-nav">
    <?php
        $c = Page::getCurrentPage();
        $currentPagePath = $c->getCollectionPath();
        $home = Page::getByID($c->getHomePageID());
        $list = new PageList();
        $list->filterByParentID($home->getCollectionID());
        $list->ignorePermissions();
        $list->sortByDisplayOrder();
        $results = $list->getResults();
        foreach($results as $page) { 
            $active = false;
            if (strpos($page->getCollectionPath(), $currentPagePath) === 0) {
                $active = true;
            }
    ?>
        <li class="nav-item <?php if ($active) { ?>active<?php } ?>">
            <a class="nav-link" href="<?=$page->getCollectionLink()?>"><?=$page->getCollectionName()?></a>
        </li>

    <?php } ?>
    </ul>
</div>

Let’s walk through this code. First, we retrieve the current page object. Why? Because we’re going to be checking the header pages against the current page object in order to determine whether we should add an active CSS class to a particular header page. That’s also why we retrieve the $currentPagePath in the next line.

Next, we retrieve the home page of the site from the current page, and store it in the $home variable. We need this because we’re going to filter our page list and display only pages directly beneath the home page. That’s what we’re doing in this code.

$list = new PageList();  
$list->filterByParentID($home->getCollectionID());

Next, we improve the performance of our page list by running ignorePermissions() on it. (Note: if you plan on having pages at the top level of your site that guest users will not be able to access, you should omit this line from your template.)

Finally, we sort the page list object by display order, which means that if we reorder the pages in our Dashboard sitemap, that order will be reflected in this header navigation.

Next, we get the results of this page list object. getResults() returns an array of Concrete\Core\Page\Page objects, or an empty array if none match the filters. We loop through the array, and compare the page path of each one of the pages with the current page path. If the first parts of each page path match, we add the active class to the page.

Let’s refresh our home page and see if it works:

It worked! Our top level Projects page shows up in the header.