Making a category based menu with posts in wordpress 2.9.2

Sunday, May 23rd, 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:

  1. // Get the id of the current post so we can give it a "current" class later.
  2. $postid = $post->ID;
  3.  
  4. // Arguments for getting all the categories
  5. $args = array(
  6. 'show_option_all'    => '',
  7. 'orderby'            => 'name',
  8. 'order'              => 'ASC',
  9. 'show_last_update'   => 0,
  10. 'style'              => 'list',
  11. 'show_count'         => 0,
  12. 'hide_empty'         => 1,
  13. 'use_desc_for_title' => 0,
  14. 'child_of'           => 0,
  15. 'feed'               => '',
  16. 'feed_type'          => '',
  17. 'feed_image'         => '',
  18. 'exclude'            => '',
  19. 'exclude_tree'       => '',
  20. 'include'            => '',
  21. 'hierarchical'       => true,
  22. 'title_li'           => '',
  23. 'number'             => NULL,
  24. 'echo'               => 0,
  25. 'depth'              => 0,
  26. 'current_category'   => 1,
  27. 'pad_counts'         => 0,
  28. 'taxonomy'           => 'category' );
  29.  
  30. // Get all categories (in a silly html menu)
  31. $catmenu = wp_list_categories( $args );
  32.  
  33. // Split the menu to get all categories sepparately
  34. $cats = split('
  35. <li class="cat-item cat-item-', $catmenu);
  36.  
  37. $catmenu = '';
  38.  
  39. // Loop through the categories.
  40. foreach($cats as $key => $cat){
  41.  
  42.         $current = '';
  43.  
  44.         // Get the code and html sepparately
  45.         list($id, $code) = split('"><a', $cat);
  46.  
  47.         // Make sure they're there.
  48.         if($id && $code){
  49.  
  50.                 // If this is the current category, then remove that text and remember for later
  51.                 if(strpos($id, ' current-cat') !== False){
  52.                         $current = ' current-cat';
  53.                         $id = str_replace(' current-cat', '', $id);
  54.                 }
  55.  
  56.                 // In case we got an id... and this category doesn't have sub categories.
  57.                 if(is_numeric($id) && strpos($code, "
  58. <ul class='children'>") === False){
  59.  
  60.                         // Arguments for getting the categorie's posts
  61.                         $args = array(
  62.                                 'post_type' => 'post',
  63.                                 'post_status' => 'published',
  64.                                 'numberposts' => -1,
  65.                                 'category' => $id
  66.                                 );
  67.  
  68.                         // Get the posts
  69.                          $myposts = get_posts($args);
  70.  
  71.                          // If we got any posts returned
  72.                          if(count($myposts)){
  73.  
  74.                                 // Start a nice html post list
  75.                                 $postlist = "\n".'
  76. <ul class="posts">';
  77.  
  78.                                 // Check east post to see if it's current and add to the html
  79.                                  foreach($myposts as $post) {
  80.                                         $current_post = '';
  81.                                         if($postid == $post->ID){
  82.                                                 $current_post = ' class="current-post"';
  83.                                                 $current = ' current-cat';
  84.                                         }
  85.                                         $postlist .= "\n".'
  86. <li'.$current_post.'><a href="'.get_permalink($post->ID).'">'.$post->post_title.'</a></li>
  87.  
  88. ';
  89.                                  }
  90.  
  91.                                  $postlist .= "\n".'</ul>
  92.  
  93. ';
  94.  
  95.                                 // Add the post list to the code of the current category
  96.                                 $code = str_replace('</a>', '</a>'.$postlist, $code);
  97.  
  98.                         }
  99.  
  100.                 }
  101.  
  102.                 // Put everything that was split before back together
  103.                 $cat = '
  104. <li class="cat-item cat-item-'.$id.$current.'"><a'.$code;
  105.  
  106.         }
  107.  
  108.         // Add back into the complete category menu
  109.         $catmenu .= $cat;
  110. }
  111.  
  112. // Print out the category menu
  113. echo '
  114. <li id="menu">
  115. <ul>'.$catmenu.'</ul>
  116. </li>
  117.  
  118. ';

Display clean php code for copying

// 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('
  • ") === 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".'
      '; // 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".' '.$post->post_title.' '; } $postlist .= "\n".'
    '; // Add the post list to the code of the current category $code = str_replace('', ''.$postlist, $code); } } // Put everything that was split before back together $cat = '
    • '.$catmenu.'
  • ';

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

    1. // Initialise javascript functions using jquery
    2. jQuery(document).ready(function(){
    3.  
    4.         initMenu();
    5.  
    6. });
    7.  
    8. // Start the menu functionality
    9. function initMenu(){
    10.         // Hide all the submenus by default
    11.         jQuery('#menu ul ul').hide();
    12.  
    13.         // Find the current post and make sure all the categories it's in are also "current", then show their kids.
    14.         jQuery('#menu .current-post').parents('li[id!=menu]').addClass('current-cat').children('ul').show();
    15.  
    16.         // Replace the click event of all category menu items except for "news"
    17.         // In stead make them fold down and up the sub menu
    18.         jQuery('#menu a').click(function(event){
    19.  
    20.                 thisItem = jQuery(this);
    21.  
    22.                 childList = thisItem.siblings('ul');
    23.  
    24.                 if(childList.length){
    25.  
    26.                         if(!(thisItem.html() == 'News' && childList.is(':hidden'))){
    27.  
    28.                                 event.preventDefault();
    29.  
    30.                                 if(childList.is(':hidden')){
    31.  
    32.                                         thisItem.addClass('clicked');
    33.  
    34.                                         childList.slideDown('fast');
    35.  
    36.                                         jQuery('#menu ul:visible').each(function(){
    37.  
    38.                                                 if(!(jQuery('.clicked', this).length || jQuery(this).siblings('.clicked').length)){
    39.                                                         jQuery(this).slideUp('fast');
    40.                                                 }
    41.  
    42.                                         });
    43.  
    44.                                         thisItem.removeClass('clicked');
    45.  
    46.                                 }else{
    47.                                         childList.slideUp('fast');
    48.                                 }
    49.                         }
    50.  
    51.                 }
    52.  
    53.         });
    54. }

    Display clean javascript code for copying

    // 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');
    				}
    			}
    
    		}
    
    	});
    }