sNews 1.7 (current stable version) > 3rd party applications

Multi level tabbed menu using pages/categories as top level

(1/4) > >>

Here is my tabbed drop down menu system.  It is for a site that uses a small number of categories so that the pages and categories can form the top level tabs.

It is implemented on my test site for a client that is currently at
When the client site is implemented (this week) I will update this link.

The software I used is:
•   A sliding doors tabbed menu system based on the one from CSS Tab Designer -download free from

•   The All Levels Navigational Menu (v2.1) from Dynamic Drive download from

Note that Dynamic Drive also has an All Levels Menu Generator with 12 varieties of horizontal menu at .  Not all of these will work unchanged with my code – some of them have their hooks to the menu software in different places and so you would have to modify my Sitemap mod to suit.

The menu system has a vertical option which would make more sense if you had many categories.

Note that for this menu system to display properly, your document MUST BE XHTML STRICT otherwise there will be stray areas at the top/bottom of the sublinks.  Also, your sub link boxes must be formatted so they are wide enough to contain you longest article/subcategory name.  Longer names will break the formatting.

To make this software work, I made a copy of the sitemap() function and modified it to generate the lists required by this menu.  This menu requires that the top level menu items be written where the menu will appear.  However, the article, subcategory and ‘sub-articles’ lists need to be separate and initially written to the very bottom of the page.  The menu CSS formats these display: none; until they are needed.

At the same time, I created a separate list of article links.  If you don’t want these, you can delete them.  How I use them is I put the list in a scrollable box on the admin page.  This way, if I want insert a hyperlink in an article referring to another article, I have the page addresses right there so I can just copy/paste them into the article without fumbling around going back and forth to copy the page link.  Yes, I’d rather spend 2 hours writing a program to do this than spend 5 minutes locating the link!!

Anyhow, here is my function (variation of sitemap() ) that creates the menu lists:

--- Code: ---<?php
// Navigation site map
function nav_sitemap($exclude=false) {
if(!$exclude)$exclude = array();
//Functions to write lists
function makeA($url,$ltext,$rel=''){
    return '<a'.mAttr('href',$url).mAttr('rel',$rel).">$ltext</a>";
function mAttr($name,$value){
    return ($value)?" $name='$value' ":'';
function makeLI($ltext,$cat=false){
$current = " id='current' ";
$id = ( $reqcat === $cat OR ( !isset($_GET['category']) && $cat == 'home' ))?$current:'';
return "<li$id>$ltext</li>\n";
function makeUL($items,$id='',$class=''){
    $list = is_array($items)?implode('',$items):$items;
    return '<ul'.mAttr('id',$id).mAttr('class',$class).">\n$list</ul>\n";
function makeLinkText($href){
return makeA($href,$href)."<br /><br />\n";
$linktext ='';
//Fixed page nav links
$topitems['home'] = makeLI(makeA(_SITE,'Home'),'home');
$linktext .= makeLinkText('./');
$topitems['archive'] = makeLI(makeA(_SITE.'archive/','Archive'),'archive');
$linktext .= makeLinkText('archive/');
$topitems['contact'] = makeLI(makeA(_SITE.'contact/','Contact'),'contact');
$linktext .= makeLinkText('contact/');
$topitems['sitemap'] = makeLI(makeA(_SITE.'sitemap/','Sitemap'),'sitemap');
$linktext .= makeLinkText('sitemap/');

$query = "SELECT title,seftitle
FROM "._PRE.'articles'."
WHERE position = 3
AND published = 1
AND visible = 'YES'
ORDER BY artorder ASC, date, id";
$result = mysql_query($query);
while ($r = mysql_fetch_array($result)) {
//Page nav links
$topitems[$category_title] = makeLI(makeA(_SITE.$r['seftitle'].'/',$r['title'],$r['seftitle']),$r['seftitle']);
$linktext .= makeLinkText($r['seftitle'])."<br />\n";

$art_query = 'SELECT title, seftitle, date
FROM '._PRE.'articles'.'
WHERE position = 1
AND published = 1
AND visible = \'YES\'';

$cat_query = 'SELECT id, name, seftitle, description, subcat
FROM '._PRE.'categories'.'
WHERE published = \'YES\'
AND subcat = 0
ORDER BY catorder,id';
$cat_result = mysql_query($cat_query);

  if (mysql_num_rows($cat_result) != 0) {
   while ($c = mysql_fetch_array($cat_result)) {
$category_title = $c['seftitle'];      
      if(in_array($category_title,$exclude) )continue;      
      //Category link
$topitems[$category_title] = makeLI(makeA(_SITE.$category_title.'/',$c['name'],$category_title),$category_title);
$linktext .= makeLinkText($category_title.'/');
$catid = $c['id'];
$query = $art_query.' AND category = '.$catid.' ORDER BY artorder ASC';
$result = mysql_query($query);
while ($r = mysql_fetch_array($result)) {
        //Category link
$catlist[$category_title][] = makeLI(makeA(_SITE.$category_title.'/'.$r['seftitle'],$r['title']));
$linktext .= makeLinkText($category_title.'/'.$r['seftitle'].'/');

$subcat_result = mysql_query('SELECT id, name, seftitle, description, subcat
FROM '._PRE.'categories'.'
WHERE published = \'YES\'
AND subcat = '.$c['id'].'
ORDER BY catorder ASC');

while ($s = mysql_fetch_array($subcat_result)) {
$subcat_title = $s['seftitle'];
$subcat_name = $s['name'];
        //Subcategory link
$subcatitem = makeA(_SITE.$category_title.'/'.$subcat_title.'/',$subcat_name);
$linktext .= makeLinkText($category_title.'/'.$subcat_title.'/');
        $subcatid = $s['id'];
$query = $art_query.' AND category = '.$subcatid.' ORDER BY artorder ASC';
$artresult = mysql_query($query);
while ($r = mysql_fetch_array($artresult)) {
          //Subcategory article list item
=makeLI(makeA(_SITE.$category_title.'/'.$subcat_title.'/'.$r['seftitle'].'/',$r['title']) );
$linktext .= makeLinkText($category_title.'/'.$subcat_title.'/'.$r['seftitle'].'/');
//Subcategory list of articles
$subcatitem .= makeUL($subcatlist[$category_title][$subcat_title]);
//Subcategory link list item
$catlist[$category_title][] = makeLI($subcatitem);
//end subcategory articles
// List of all articles, subcategories and subcategory articles for a category
$navitems['sub'] .= makeUL($catlist[$category_title],$category_title,'ddsubmenustyle');
// Make top menu list for tabs
$navitems['top'] = makeUL($topitems,'','noprint');

// $navitems array used if (_ADMIN) while menus may be changing

 // Menu is written to files for regular use
  // Remove id='current' before writing to file - it will be determined when the page is loaded
  $current = " id='current' ";
  $navitems_nocurrent = str_replace($current,'',$navitems['top']);
  $bytes = file_put_contents(F_ROOT.'includes/topNavLinks.txt',$navitems_nocurrent,LOCK_EX);
  $bytes = file_put_contents(F_ROOT.'includes/subNavLinks.txt',$navitems['sub'],LOCK_EX);  
  $bytes = file_put_contents(F_ROOT.'includes/linktext.txt',$linktext,LOCK_EX);
//Return current values for use in page if _ADMIN
  return $navitems;

--- End code ---

The above function DOES NOT replace the sitemap() function.  I just put it in a separate file that I included in my template.

My list of links is in the variable $linktext written to the file linktext.txt so you can comment out / delete references to this if you don’t need it.

The links for the top of the page are put into the variable $navitems['top'] and written to the file named topNavLinks.txt

The rest of the links are put in the variable $navitems['sub'] and written to the file namedsubNavLinks.txt

When _ADMIN is false, the files are read and the links displayed from there.  However, if _ADMIN is true, because content is changing, the links are created anew with each page refresh and written again to the files.  For the _ADMIN user, the links are written to the page from $navitems instead of being read in from the files.

Install the menu system using the instructions given at the Dynamic Drive site.

In my template, at the top of the page, where I have the top menus my logic is

--- Code: ---<?php
      $exclude = array('archive','sitemap','welcome','general');
// Read navigation links from file
$nav_array = explode("\n",$nav_links['top']);
foreach ($nav_array as $key=>$value) {
    if(!empty($categorySEF) AND stripos($nav_array[$key],"/$categorySEF") ) {
     $nav_array[$key] = str_ireplace('<li>',"<li id='current' >",$nav_array[$key]);
           }else if((empty($categorySEF) OR in_array($categorySEF,$exclude)) AND stripos($nav_array[$key],"home")) {
                    $nav_array[$key] = str_ireplace('<li>',"<li id='current' >",$nav_array[$key]);
     $nav_links['top'] = implode("\n",$nav_array);
} else {
// Create new navigation links
// They will be saved by nav_sitemap() 
include 'snews/navSiteMap.php';
$nav_links = nav_sitemap($exclude);

<div id="ddtopmenubar" class="tabs">
<?php echo $nav_links['top']; ?>
        <script type="text/javascript">ddlevelsmenu.setup("ddtopmenubar", "topbar")</script>
<!-- <br class='clear' /> -->

--- End code ---
The $exclude array contains the page/category names that I don’t want in the navigation tabs.
The logic steps through the array to find the current page name so that id=current can be written into that link.

At the VERY bottom of my page, I put the rest of the links

--- Code: ---<!-- Must stay at very end of page -->
if(!_ADMIN)include 'subNavLinks.txt';
else echo $nav_links['sub'];

--- End code ---
Notice that is the VERY last thing on the page, outside all the rest of the page content.  This is described in the Dynamic Drive documentation.  I don’t know what would happen if it was anywhere else – I didn’t bother trying that.

I then took the ddlevels css file that formatted the top menu and replaced it with my css from my tabs, modifying it where I needed to (though it required very little modification to work.)

There you have it.  This is not a ‘mindless’ mod – you have to understand your CSS and the how the php works to create the lists but at least the ground work is done for you.

I hope that this is useful to someone.  Maybe you templaters can use it as a starting point.

Hello Jean,
Did the test on localhost and it is working.
Only I had to change:

--- Code: ---$bytes = file_put_contents(F_ROOT.'includes/topNavLinks.txt',$navitems_nocurrent,LOCK_EX);
  $bytes = file_put_contents(F_ROOT.'includes/subNavLinks.txt',$navitems['sub'],LOCK_EX); 
  $bytes = file_put_contents(F_ROOT.'includes/linktext.txt',$linktext,LOCK_EX);
--- End code ---

--- Code: --- $bytes = file_put_contents('topNavLinks.txt',$navitems_nocurrent,LOCK_EX);
  $bytes = file_put_contents('subNavLinks.txt',$navitems['sub'],LOCK_EX); 
  $bytes = file_put_contents('linktext.txt',$linktext,LOCK_EX);
--- End code ---
Is this normal?

Second: If I add a page the submenu is not working, a second page not showing.

Thanks for sharing


Yes, sorry the F_ROOT constant is unique to my website and set outside this code.
You can tell I am totally new to posting my code for others to use!!

I use xampp locally but not with virtual servers.  So my xampp sites do not operate from the actual web root. 
I  use this constant to set the path to the web root to the xampp path if it finds 'xampp' in $_SERVER['DOCUMENT_ROOT'] and to the website root path otherwise.  This reduces the changes i have to make when I move a site from xampp to on line.

Thanks for trying this out hope it is useful.


doesn't snews' _SITE constant work for you in xampp

Not everywhere but I tested it and it works with this mod.
So this mod should have _SITE instead of F_ROOT and it would work for everyone else.
Thanks philmoz.


[0] Message Index

[#] Next page

Go to full version