Make wordpress menu

23 Ⅵ 2010

I was not entirely happy with the way wordpress handles menus for this (my own) website. I like the idea of making all the content posts so they're bound to a date and such. Then I'd like to see them in the menu based on the category they're in. There are category menus, and even nice folding ones, but I couldn't find one that displays all the posts per category in a nice way.

So I decided to hack one in myself. It's a very nasty hack... and I just put a bunch of code in the sidebar.php of my template. But that said… it works and I now have a menu that does what I want.

If you'd like to use this... just remember it's a great big bad hack and very inefficient!

Here's the html/php code I added to my template's sidebar.php:

// Get the id of the current post so we can give it a "current" class later.
$postid = $post->ID;
	
// Arguments for getting all the categories
$args = array(
'show_option_all'    => '',
'orderby'            => 'name',
'order'              => 'ASC',
'show_last_update'   => 0,
'style'              => 'list',
'show_count'         => 0,
'hide_empty'         => 1,
'use_desc_for_title' => 0,
'child_of'           => 0,
'feed'               => '',
'feed_type'          => '',
'feed_image'         => '',
'exclude'            => '',
'exclude_tree'       => '',
'include'            => '',
'hierarchical'       => true,
'title_li'           => '',
'number'             => NULL,
'echo'               => 0,
'depth'              => 0,
'current_category'   => 1,
'pad_counts'         => 0,
'taxonomy'           => 'category' );

// Get all categories (in a silly html menu)
$catmenu = wp_list_categories( $args );

// Split the menu to get all categories sepparately
$cats = split('<li class="cat-item cat-item-', $catmenu);

$catmenu = '';

// Loop through the categories.
foreach($cats as $key => $cat){

	$current = '';

	// Get the code and html sepparately
	list($id, $code) = split('"><a', $cat);
	
	// Make sure they're there.
	if($id && $code){
		
		// If this is the current category, then remove that text and remember for later
		if(strpos($id, ' current-cat') !== False){
			$current = ' current-cat';
			$id = str_replace(' current-cat', '', $id);
		}
		
		// In case we got an id... and this category doesn't have sub categories.
		if(is_numeric($id) && strpos($code, "<ul class='children'>") === False){
		
			// Arguments for getting the categorie's posts
			$args = array(
				'post_type' => 'post',
				'post_status' => 'published',
				'numberposts' => -1,
				'category' => $id
				); 
		
			// Get the posts
			 $myposts = get_posts($args);
			 
			 // If we got any posts returned
			 if(count($myposts)){
			 
				// Start a nice html post list
				$postlist = "\n".'<ul class="posts">';
			 
				// Check east post to see if it's current and add to the html
				 foreach($myposts as $post) {
					$current_post = '';
					if($postid == $post->ID){
						$current_post = ' class="current-post"';
						$current = ' current-cat';
					}
					$postlist .= "\n".' <li'.$current_post.'><a href="'.get_permalink($post->ID).'">'.$post->post_title.'</a></li>';
				 }
				 
				 $postlist .= "\n".'</ul>';
		
				// Add the post list to the code of the current category
				$code = str_replace('</a>', '</a>'.$postlist, $code);
				
			}
			
		}
		
		// Put everything that was split before back together
		$cat = '<li class="cat-item cat-item-'.$id.$current.'"><a'.$code;
		
	}
	
	// Add back into the complete category menu
	$catmenu .= $cat;
}
	
// Print out the category menu
echo '<li id="menu"><ul>'.$catmenu.'</ul></li>';

And here is the javascript code I added to my template’s header.php:

// Initialise javascript functions using jquery
jQuery(document).ready(function(){

	initMenu();
	
});

// Start the menu functionality
function initMenu(){
	// Hide all the submenus by default
	jQuery('#menu ul ul').hide();
	
	// Find the current post and make sure all the categories it's in are also "current", then show their kids.
	jQuery('#menu .current-post').parents('li[id!=menu]').addClass('current-cat').children('ul').show();
	
	// Replace the click event of all category menu items except for "news"
	// In stead make them fold down and up the sub menu
	jQuery('#menu a').click(function(event){
		
		thisItem = jQuery(this);
		
		childList = thisItem.siblings('ul');
	
		if(childList.length){
		
			if(!(thisItem.html() == 'News' && childList.is(':hidden'))){
			
				event.preventDefault();
				
				if(childList.is(':hidden')){
					
					thisItem.addClass('clicked');
					
					childList.slideDown('fast');
					
					jQuery('#menu ul:visible').each(function(){
					
						if(!(jQuery('.clicked', this).length || jQuery(this).siblings('.clicked').length)){
							jQuery(this).slideUp('fast');
						}
					
					});
					
					thisItem.removeClass('clicked');
					
				}else{
					childList.slideUp('fast');
				}
			}
			
		}
		
	});
}