Re: Filtering results from a category menu section

9 posts by 3 authors in: Forums > CMS Builder
Last Post: January 28, 2016   (RSS)

By garyhoffmann - January 26, 2016

Hi Jeff,

I don't know exactly what your end-goal is for this, so I'll do my best to describe what I do.

First - IT'S EXTREMELY IMPORTANT TO NOTE - I create a cms class in place of the normal routines that are shipped with CMSB.  I need this to play nice with other systems, so it was easier to create a class that I update when a new version comes in.  My class is defined as cmsbclass and is instantiated in $cmsbo.  Assume that $cmsbo->getCategories and $cmsbo->getRecords works almost exactly as the out-of-the-box getCategories and getRecords work.

I have at the "top" of all of my code (it's part of an included file)

//note: $thisPageNum is determined by URL - I have several ways this can be done (SEO type url gets converted, number at end of URL, etc.)

        list($allnavRecords, $selectedCategory) = $cmsbo->getCategories(array(
            'tableName'           => 'main_nav',
            'selectedCategoryNum' => $thisPageNum,
            'categoryFormat'      => 'showall',  // showall, onelevel, twolevel
            'rootCategoryNum'     => '0'
        ));

//then a bit later I have this to read the current record:

    list($main_navRecords, $main_navMetaData) = $cmsbo->getRecords(array(
        'tableName'   => 'main_nav',
        'where'       => $whereClause,
        'limit'       => '1',
        'allowSearch' => false,
    ));
    $main_navRecord = @$main_navRecords[0]; // get first record
    
//generally, $whereClause is something like "num={$thisPageNum}"

This gives me a list of all category records in "$allnavRecords" and the current page as $main_navRecord

Then, assuming I'm doing something like a side nav for a given top level entry selected, I would do something like this:

<?php
$startNum = 0;

foreach ($allnavRecords as $record) {
    if ($record['num']==$main_navRecord['num']) {
        if ($record['_hasChild']==1) {
            $startNum = $record['num'];
        } else {
            $startNum = $record['parentNum'];
        }
        break;
    }
}

if ($startNum != 0) {
    $sidebar = "<div class=\"right-sidebar-nav\">";
    $anyhere = false;
    //get the list of entries from startNum
    foreach ($allnavRecords as $record) {
        //figure out the link
        if ($record['num']==$startNum || $record['parentNum']==$startNum) {
            $anyhere = true;
            //here I have a bunch of code that figures out the link as I have all sorts of stuff that can override the link
            //when I'm done, I have $pageLink defined...
            //I also have $pageTarget defined (such as _blank) and whether or not this is the current item ($seltext)
            if ($record['num']==$startNum) {
                $sidebar .= "<h2>{$record['nav_text']}</h2>";
                if ($pageLink != "#" && $record['override_url'] == "") {
                    if (@$record['override_sidebar_nav_name'] == "") {
                        $theText = "Overview";
                    } else {
                        $theText = @$record['override_sidebar_nav_name'];
                    }
                    $sidebar .= "<a{$seltext} href=\"{$pageLink}\"{$pageTarget}>{$theText}</a>";
                }
            } else {
                $theText = $record['nav_text'];
                if (@$record['override_sidebar_nav_name'] != "") {
                    $theText = $record['override_sidebar_nav_name'];
                }
                $sidebar .= "<a{$seltext} href=\"{$pageLink}\"{$pageTarget}>{$theText}</a>";
            }
        }
    }
    $sidebar .= "</div>";
    
    if ($anyhere) {
        echo $sidebar;
    }
}

The important things here are the determination of what number I want to compare to ($startNum) by using either the current record number or the parent depending on if this has any children and then the loop that looks at each item in $allnavRecords to compare the record number and/or parentNum to the startNum.

By ross - January 26, 2016

Hi Garry

Thanks for jumping in on this one.

Let me know if there is anything I can lend a hand with.

-----------------------------------------------------------
Cheers,
Ross Fairbairn - Consulting
consulting@interactivetools.com

Hire me! Save time by getting our experts to help with your project.
Template changes, advanced features, full integration, whatever you
need. Whether you need one hour or fifty, get it done fast with
Priority Consulting: http://www.interactivetools.com/consulting/

By JeffC - January 26, 2016

My head hurts...

Thanks Gary, thanks Ross

Gary, your solution looks really comprehensive, thank you for taking the time to share. Please could you help me pick out the bits that I need. Here is a little bit more information about what I am trying to achieve. 

Below is a sample setup of my menu. (Record numbers in brackets)

Category One (1)
Sub category a (2)
Sub category b (3)

Category Two (4)
Sub category c (5)
Sub category d (6)

My existing code displays all of the records ie

Category One (1)
Sub category a (2)
Sub category b (3)
Category Two (4)
Sub category c (5)
Sub category d (6)

But I would like to filter the results so that I show only the children related to their particular parent.

So, If I was hard coding the site I would create two separate pages using

'rootCategoryNum'      => '1', //

To show 
sub category a (2)
Sub category b (3)

And 

rootCategoryNum'      => '4', //

To show
Sub category c (5)
Sub category d (6)

Since I am creating the pages dynamically I cannot hard code rootCategoryNum so I need another way to do it. I was a thinking that there could be a way to cross ref parentNum with num 

Jeff

By JeffC - January 26, 2016

My head hurts...

Thanks Gary, thanks Ross

Gary, your solution looks really comprehensive, thank you for taking the time to share. Please could you help me pick out the bits that I need. Here is a little bit more information about what I am trying to achieve. 

Below is a sample setup of my menu. (Record numbers in brackets)

Category One (1)
Sub category a (2)
Sub category b (3)

Category Two (4)
Sub category c (5)
Sub category d (6)

My existing code displays all of the records ie

Category One (1)
Sub category a (2)
Sub category b (3)
Category Two (4)
Sub category c (5)
Sub category d (6)

But I would like to filter the results so that I show only the children related to their particular parent.

So, If I was hard coding the site I would create two separate pages using

'rootCategoryNum'      => '1', //

To show 
sub category a (2)
Sub category b (3)

And 

rootCategoryNum'      => '4', //

To show
Sub category c (5)
Sub category d (6)

Since I am creating the pages dynamically I cannot hard code rootCategoryNum so I need another way to do it. I was a thinking that there could be a way to cross ref parentNum with num 

Jeff

By garyhoffmann - January 26, 2016

Assuming you have a field called "name" for the title of the category, you would first have to find out which page you are on.  I'm guessing you have some way of knowing that number.

So, you would use the part at the top of my last post to figure out which "category" you are in and then you'd have a pretty simple loop that would use parentNum

foreach ($allrecords as $record) {
    if ($record['parentNum']==$startNum) {
        //display the entry however you'd like...
    }
}


You'd still need the part that determines $startNum

By JeffC - January 28, 2016

Thanks Gary and Ross

I've cracked it. I didn't really use your solutions in the end, but your code certainly helped me figure out what I needed to do. The key aspect was finding out what page I was on in order to highlight the correct sub navs to display. Actually, just one line in the end! This is what I needed:

<?php foreach ($iw_pagesRecords as $categoryRecord): ?>
<?php if($categoryRecord['parentNum'] == $page['num']): ?>
<?php echo htmlencode($categoryRecord['name']) ?><br/><br/>
<?php endif ?>
<?php endforeach; ?>

Now that I have it working, it got me thinking about the issue of performance. Lets say we are loading a 1000 entries, then filtering them to show less than 10. Will this be an instance process, or will it significant;y slow the page load time? 

Jeff

By garyhoffmann - January 28, 2016

If you are loading 1000 entries to get 10, you'll want to do something a bit different.  You'll want to use getCategories starting with your current page's parentNum as the root and loading onelevel. This will dramatically reduce the number of records it needs to load and the memory footprint of the page.

If, on the other hand, you are loading 50 to get 10, that's a whole different game - the load time of 50 items is pretty quick and then the foreach loops will run fast as they run in memory..

The vast majority of our customers have between 30 and 100 main navigation items.  I have had to play with this a bit on larger systems.

Sorry for the difference in coding techniques.  I personally dislike wrapping every line with <?php ... ?> tags, so I tend to have blocks of PHP code.  Just a style difference.  Both are correct.

I'm glad you got it sorted out.

By JeffC - January 28, 2016

For today I shall just bask in the glory of achieving something that works. :)

If and when performance does slow down (it will several months before I have uploaded that much content) I will now know where the problem lies.

Thanks again
J

Jeff