List Posts by Category In Navigation

WordPress is primarily a blog platform. Not infrequently it is used as a CMS. But not just static pages play a role, but also posts, because they are giving more opportunities, having better performance and be published in feeds. Therefore, I prefer to use, in the context of WP as a CMS, posts more than the static pages. From time to time are the wishes of a navigation layout very extra odinary. And so was it in my recent project, the requirement to list the posts from each category in the navigation.
This is unusual as in the long run, you will have many posts, and the navigation will be very confusing - still, in this project it made sense, since we won't have many posts.

The small function lists the category and below the posts. There is a parameter that restricts the output of the posts, so that in extreme cases, not too many will be listed, only the last posts - $mylimit. The value -1 for this parameter provides all posts. The function itself belongs to the functions.php of the theme or in a Plugin. An exemplary use can be found below the function.

function fb_posts_by_category() {
	global $wpdb, $post;
	
	$mylimit = '-1'; // limit for posts, -1 for all
	$sort_code = 'ORDER BY name ASC, post_date DESC';
	$the_output = '';

	$last_posts = (array)$wpdb->get_results("
		SELECT $wpdb->terms.name, $wpdb->terms.term_id
		FROM $wpdb->terms, $wpdb->term_taxonomy
		WHERE $wpdb->terms.term_id = $wpdb->term_taxonomy.term_id
		AND $wpdb->term_taxonomy.taxonomy = 'category'
		{$hide_check} 
	");

	if ( empty($last_posts) )
		return NULL;

	$used_cats = array();
	$i = 0;
	foreach ($last_posts as $posts) {
		if ( in_array($posts->name, $used_cats) ) {
			unset($last_posts[$i]);
		} else {
			$used_cats[] = $posts->name;
		}
		$i++;
	}
	$last_posts = array_values($last_posts);

	//$the_output .= '<ul>';
	foreach ($last_posts as $posts) {
		$class = 'cat-item cat-item-' . $posts->term_id;
		$catsy = get_the_category();
		$current_category = $catsy[0]->cat_ID;
		if ( isset($current_category) && $current_category && ($posts->term_id == $current_category) )
		$class .=  ' current-cat';
		elseif ( isset($_current_category) && $_current_category && ($posts->term_id == $_current_category->parent) )
		$class .=  ' current-cat-parent';
		
		$the_output .= '<li class="' . $class . '"><a class="category" href="' . get_category_link($posts->term_id) . '">' . apply_filters('list_cats', $posts->name, $posts) . '</a>';
		$where = apply_filters('getarchives_where', "WHERE post_type = 'post' AND post_status = 'publish'" , $r );
		
		if ('-1' !== $mylimit)
			$limit = ' LIMIT ' . (int) $mylimit;
		else
			$limit = '';
		
		$arcresults = $wpdb->get_results("SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' AND ID IN (Select object_id FROM $wpdb->term_relationships, $wpdb->terms WHERE $wpdb->term_relationships.term_taxonomy_id =" . $posts->term_id . ") ORDER BY post_date DESC$limit");
		if (isset($arcresults) && $arcresults) {
			$the_output .= '<ul>';
			foreach ( $arcresults as $arcresult ) {
				$class = 'post-item post-item-' . $arcresult->ID;
				$current_post = get_the_ID();
				if ( isset($current_post) && $current_post && is_singular() && ($arcresult->ID == $current_post) )
				$class .=  ' current-post';
				
				$the_output .= '<li class="' . $class . '"><a class="post" href="' . get_permalink($arcresult->ID) . '">' . apply_filters('the_title', $arcresult->post_title) . '</a></li>';
			}
			$the_output .= '</ul>';
		}
		
		$the_output .= '</li>';
	}
	//$the_output .= '</ul>';
	
	echo $the_output;
}

Here an example in a sidebar.php, which only uses Markup HTML5.

<div id="sidebar">
	<nav>
		<h3>Navigation</h3>
		<ul>
			<li><a title="to front page" href="<?php bloginfo('url'); ?>">Home</a></li>
			<?php
			fb_posts_by_category();
			
			wp_list_pages( 'title_li=&sort_column=menu_order&exclude=2,14,49' );
			?>
		</ul>
	</nav>
</div>

Comments are closed.

18 comments

  1. Konstantin

    You sure there's no better way of doing this?
    I really don't like to mess with SQL statements in WP, since there usually is always a function giving me what I need.

  2. Devin

    This would be good as a sidebar widget, perhaps to list the first 5 or so posts from the categories that the admin specifies.

  3. Erik

    Thank you for this! I immediately got use for it in my current project.

    I think the row
    “$limit = ' LIMIT ' . (int) $limit;”
    should be
    “$limit = ' LIMIT ' . (int) $mylimit;”
    no?

    and the line “$where = apply_filters('getarchives_where', "WHERE post_type = 'post' AND post_status = 'publish'" , $r );”

    isn't used in the posts query?

    also, when a post is active, the category is also active, which leads to theming issues.

  4. Dave

    very nice.

    I'll have to try this out .. perhaps integrate some sort of javascript accordion menu.

  5. sebastien

    Is it possible to exclude a category ?

  6. Diana

    That´s what I was looking for! Thank you so much!

  7. Frank

    @Konstantin: yes, it is evry good, when you use a function of WP. A SQL statepmant in in other sites faster and i dont find a function for this small request.

    @Erik: correctly - i had change this

    @Dave: yes, you can use a js for this, i make it with jquery and and a small script; example:

    jQuery(document).ready(function($) {
    	$(".cat-item ul").hide();
    	$(".current-cat ul").show();
    	
    	$(".page_item ul").hide();
    	$(".current_page_parent ul, .current_page_item ul").show();
    	
    	return false;
    });
    

    @sebastian: yes, you can add a sql statemant to the code for exclude a id of category or use the conditional tag is_category() and exclude the id.

  8. Josif

    Hi Frank

    Nice function - works well.
    Could you just give an example of excluding a category. I can't seem to get it to work.

    Thanks

  9. Frank

    @Josif:
    add this to the sql-query and inlcude all categories, do you will include this function:
    AND $wpdb->term_taxonomy.term_id IN (3,8,9)
    or use NOT IN for exclude a ID of a category.

  10. eavasi

    Hello Frank!
    Great Function! Good job! Work well! Thanx!

  11. Marjorie

    This is great!
    Exactly what I was looking for.
    I do have one question though. Is there a way to add a class, like the slug of the cat in the first level of li?

    Thank you soo much!

  12. Malcolm

    I'm running wordpress 3.0. This fix almost works like a dream, my live site looks great, but I get the following error (only in the admin section thus far) when posting new posts or editing posts...

    Warning: Cannot modify header information - headers already sent by (output started at /wp-content/themes/vidley/functions.php:268) in /wp-includes/pluggable.php on line 890

    Its certainly this fix as when I delete it then the problem is resolved. Any idea how to resolve this??

  13. Malcolm

    ok problem resolved.... white space before the php tags .... grrrr... silly php. Anyhow, thanks for the AWESOME fix.

  14. Marjorie

    I just added the name of the category inside the css class so that I can have a different bg depending on the category. This is great.
    I have another question concerning the order of the category. I use the plugin My category order and I'd like to know how to apply it on that script.
    Thanks for your help!!!

  15. Marj Wyatt

    I really thank you for sharing your work with those of us in the field. This is very elegant.

    My hope was that it would permit me to show all of the posts in one category. The display is a horizontal navigation and I want the posts to drop down within that one category.

    I succefully got the SQL to work and extract the single category that I want. I then added the function to the navigation list but the dropdowns are not working. What am I missing?

  16. Ehud

    Would it be possible to show the post thumbnails instead of titles?

  17. anabelle

    How can I use this function to list only the children of category id = 1, and it's child categories?

One pingback

  1. WordPress Picks for the Week [03/24] | Techtites