tabbed browsing of categories

Random stuff about serendipity. Discussion, Questions, Paraphernalia.
carl_galloway
Regular
Posts: 1331
Joined: Sun Dec 04, 2005 5:43 pm
Location: Andalucia, Spain
Contact:

Post by carl_galloway »

Garvin,

I found this explanation at sitepoint. It was written in 2002 but I assume it is still current. In other site I found a reference to built-in speed tweaks of smarty, but it didn't say what these were.
Pakito
Regular
Posts: 6
Joined: Thu Feb 07, 2008 6:56 pm

Post by Pakito »

Reviving an old thread (2 years old exactly!), dealing with a horizontal navigation bar with dropdown menu populated with the categories tree.
I'm new to s9y and php, and since I spent quite some time trying to achieve this navbar I feel like sharing.
Using Judebert's code I ran intoa bug.
judebert wrote:Okay, Carl, here come the goodies!

Actually, not as good as I want. The parents should marked in walkRecursive. I'll try that out later, and see about getting it into the core.

Meanwhile, this creates the nested list you're looking for, with markup better than you expected.

config.inc.php:

Code: Select all

<?php
$probelang = dirname(__FILE__) . '/lang_' . $serendipity['lang'] . '.inc.php';
if (file_exists($probelang)) {
    include $probelang;
} else {
    include dirname(__FILE__) . '/lang_en.inc.php';
}

$serendipity['smarty']->assign('CONST', get_defined_constants());

function smarty_getCategories($params, &$smarty) {
    $allcats = serendipity_fetchCategories();
    $cats = serendipity_walkRecursive($allcats, 'categoryid', 'parentid', VIEWMODE_THREADED);
    $returncats = array();
    $prevx = -1;
    $lastdepth = 0;
    foreach($cats AS $cat) {
        if ($cat['depth'] > $lastdepth) {
	  $returncats[$prevx]['has_children'] = true;
	}
	$lastdepth = $cat['depth'];
        $cat['url']           = serendipity_categoryURL($cat, 'serendipityHTTPPath');
        $cat['category_name'] = htmlspecialchars($cat['category_name']);
        $returncats[] = $cat;
	$prevx++;
    }

    return $returncats;
}

$serendipity['smarty']->register_function('smarty_getCategories', 'smarty_getCategories');
$serendipity['smarty']->assign('category', $serendipity['GET']['category']);
$serendipity['smarty']->assign('categories', smarty_getCategories(null, $serendipity['smarty']));
?> 
You see, we previously continued whenever depth was not 0, skipping all the child categories. This keeps the children around. It also marks parent categories with "has_children", so we can mark the parent link and make the submenu visible.

index.tpl tabbed menu snippet:

Code: Select all

<!-- TABMENU START -->
<div class="tabmenu">
   <ul>
   {assign var="lastdepth" value=0}
   {foreach from=$categories item="ccategory"}
      {if $ccategory.has_children}
         {* Add link and subcategory list *}
         <li class="level_{$ccategory.depth} submenu">
            <a href="{$ccategory.url}">{$ccategory.category_name}</a>
            {* We can't end the LI yet!  It has subcategories! *}
            <ul>
            {* Remember how far down we are *}
            {assign var="lastdepth" value=$ccategory.depth}
      {else}
         {if $ccategory.depth < $lastdepth}
            {* We just exited from a subcategory.  We need to end the subcategory UL and the parent's LI.  For each level.*}
            {section name="surface" start=$ccategory.depth loop=$lastdepth step=1}
               </ul>
            </li>
            {/section}
            <li class="level_{$ccategory.depth}">
               <a href="{$ccategory.url}">{$ccategory.category_name}</a>
	    </li>
            {assign var="lastdepth" value=$ccategory.depth}
         {else}
            {* We have no subcategories, but we didn't just exit from a subcategory either.  We're an LI in a bigger list. *}
            <li class="level_{$ccategory.depth}">
               <a href="{$ccategory.url}">{$ccategory.category_name}</a>
            </li>
            {assign var="lastdepth" value=$ccategory.depth}
	 {/if}
      {/if}
   {/foreach}
   {* Terminate the ULs and LIs we're in. *}
   {section name="surfaceall" start=0 loop=$lastdepth step=1}
      </ul>
   </li>
   {/section}
</div> 
<!-- TABMENU END -->
Our previous code created an imaginary parent category to create the first UL; now we just start with the top-level UL. We marked all the actual parent categories earlier, so we use that mark now to create a UL and mark the parent category with class "submenu". We still have to keep track of our depth, so when we exit from a subcategory we know how far back to go. We also get to terminate our LIs as soon as possible, since we know which ones have children and which ones don't.

I tested it on my testbed site with multiple category configurations, but I still might have missed something. If you find a problem, let me know.

Good Luck!
In the tabmenu script (to be inserted in the index.tpl), the closing of a subcategory is not done properly when the next category has children.
Here's a code that corrects this (bear with me, this could still be improved, I'm a mere beginner):

Code: Select all

<!-- TABMENU START -->

<div id="sitenav" class="tabmenu">
   <ul id="_sitenav">
   {assign var="lastdepth" value=0}
   {foreach from=$categories item="ccategory"}
      {if $ccategory.has_children}
	{if $ccategory.depth < $lastdepth}
            {* We just exited from a subcategory.  We need to end the subcategory UL and the parent's LI.  For each level.*}
            {section name="surface" start=$ccategory.depth loop=$lastdepth step=1}
		</ul>
		</li>
            {/section}
  	{/if}
         {* Add link and subcategory list *}
         <li class="level_{$ccategory.depth} submenu">
            <a href="{$ccategory.url}">{$ccategory.category_name}</a>
            {* We can't end the LI yet!  It has subcategories! *}
            <ul>
            {* Remember how far down we are *}
            {assign var="lastdepth" value=$ccategory.depth}
      {else}
	{if $ccategory.depth < $lastdepth}
            {* We just exited from a subcategory.  We need to end the subcategory UL and the parent's LI.  For each level.*}
            {section name="surface" start=$ccategory.depth loop=$lastdepth step=1}
		</ul>
		</li>
            {/section}
            <li class="level_{$ccategory.depth}"><a href="{$ccategory.url}">{$ccategory.category_name}</a>
            </li>
            {assign var="lastdepth" value=$ccategory.depth}
	{else}
            {* We have no subcategories, but we didn't just exit from a subcategory either.  We're an LI in a bigger list. *}
            <li class="level_{$ccategory.depth}">
               <a href="{$ccategory.url}">{$ccategory.category_name}</a>
            </li>
            {assign var="lastdepth" value=$ccategory.depth}
    	{/if}
      {/if}
   {/foreach}
   {* Terminate the ULs and LIs we're in. *}
   {section name="surfaceall" start=0 loop=$lastdepth step=1}
      </ul>
   </li>
   {/section}
   </ul>
</div>
<!-- TABMENU END -->
Thanks for this great code Judebert.
Also, for people interested in achieving this navbar, it might also help to point to the son of suckerfish technique for the dropdown menu effect. Gives good insight on the CSS to accompany it.

My dream as a beginner in s9y would be to have this as a theme option for the navbar, or a plugin (but that would require to be able to put plugins in the header).

Cheers!

Pakito
Last edited by Pakito on Fri Feb 15, 2008 6:31 am, edited 1 time in total.
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

Holy cow, I've been doing this for two years? I'm obviously addicted.

Thanks for the corrections, Pakito! I was a beginner once, too. I hope you join us in the s9y community!
Judebert
---
Website | Wishlist | PayPal
Pakito
Regular
Posts: 6
Joined: Thu Feb 07, 2008 6:56 pm

Post by Pakito »

Thanks Judebert, I'll help as much as I can: this project is really interesting.
One last note: I edited my post to make another correction: the final closing </ul> was missing.

Bye
Atratus
Regular
Posts: 51
Joined: Fri Feb 09, 2007 7:41 pm

Post by Atratus »

hey guys,
I wanted to have a box with all categories in on my header and so I decided to use the 3. way garvin explained on his post in this thread.
first it seems to work fine, but I recognized that the second link does not work. it links to mainpage not to the category.
does anyone know where the problem might be?

greets, a.
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

Can you give us a link to your blog, so we can check out the source?
Judebert
---
Website | Wishlist | PayPal
Atratus
Regular
Posts: 51
Joined: Fri Feb 09, 2007 7:41 pm

Post by Atratus »

of cause! look here: http://www.terra-zone.de/polystrom/
Don't wonder, I'm still working on it!

hm, ... when I click on the author name it always leads to entries of one author... e.g. clicking on "TIM" leads to "entries of STEFAN", why this?!
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

hm, ... when I click on the author name it always leads to entries of one author... e.g. clicking on "TIM" leads to "entries of STEFAN", why this?!
Hm, the %id% part of the authors permalink is removed, thus s9y needs to make a lookup in the serendipity_permalinks Database table. Can you check if these hold the authors you are trying toa ccess, or if the table is missing the entries?

Usually when you change the permalink in the s9y configuration, s9y should recreate all permalinks in the database...

Regards,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Atratus
Regular
Posts: 51
Joined: Fri Feb 09, 2007 7:41 pm

Post by Atratus »

thank you very much! It was my own fault :oops: I changed the permalink-mask and missed the %id% part!
Now everything works fine to me.

btw: thank you so much for this nice support. I had a lot of questions and you always answer kindly, fast and in a very easy to understand way :D
Merci! A great team for a great software!
Atratus
Regular
Posts: 51
Joined: Fri Feb 09, 2007 7:41 pm

Post by Atratus »

Hum, sorry, but I have another question:

Is it possible to sort the categories by their ID? At the moment they're sorted by name...
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi!
Atratus wrote:Hum, sorry, but I have another question:

Is it possible to sort the categories by their ID? At the moment they're sorted by name...
The categories sidebar plugins hould have a config option that indicates on which field to sort by...

HTH,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Atratus
Regular
Posts: 51
Joined: Fri Feb 09, 2007 7:41 pm

Post by Atratus »

yes I know, but I don't use this plugin, because I want to have the categories in my header and so I used Point 3. of this Post...

I thought maybe it's possible to install categories-plugin, sort by ID and then uninstall it, but this does not work (as I expected it to)...
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi!

Ah, okay. The serendipity_fetchCategories plugin can take an order by statement, I believe. Maybe you can look up the function parameters inside the include/functions_categories.inc.php file to see which parameters it supports.

Regards,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Atratus
Regular
Posts: 51
Joined: Fri Feb 09, 2007 7:41 pm

Post by Atratus »

I'm really sorry, but I don't know what to do :oops:
I even couldn't find the "include/functions_categories.inc.php" but in "include/functions_entries.inc.php" I found this "serendipity_fetchCategories"-Thing but the only thing that might fit is

Code: Select all

$order = 'category_name ASC'; 
and this

Code: Select all

$group    = 'GROUP BY c.categoryid';
But I'm not really in php (still learning :?) and so I don't know what to do with this?
Would be great if you could give me some more information, I'm really willing to get this to work by myself, but I'm not sure whether I'm able to...
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi!

That'S the right file. The function header says the third parameter is the $order statement, so if you call the function like this:

serendipity_fetchCategories(null, null, 'categoryid DESC');

you could sort by categoryid.

HTH,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
Post Reply