ThemeShaper Forums » Thematic

[closed]

Filtering One Category from Index Loop

(20 posts)
  • Started 3 years ago by nimrod
  • Latest reply from helgatheviking
  • This topic is resolved
  1. nimrod
    Member

    Looked all about in this forum but didn't see how modify the index loop to omit a single category.

    For convenience and best practice, I want this done in the child theme functions.php file.

    I found the following code that takes the Thematic default index code and puts it into the child theme functions.php file:

    function remove_thematic_index_loop(){
    	remove_action('thematic_indexloop','thematic_index_loop');
    	}
    add_action('init', 'remove_thematic_index_loop');
    
    function child_index_loop(){
    	global $options;
    	foreach ($options as $value) {
        	if (get_option( $value['id'] ) === FALSE) { $$value['id'] = $value['std']; }
        	else { $$value['id'] = get_option( $value['id'] ); }
        }
    		/* Count the number of posts so we can insert a widgetized area */ $count = 1;
    		while ( have_posts() ) : the_post() ?>
    
    			<div id="post-<?php the_ID() ?>" class="<?php thematic_post_class() ?>">
        			<?php thematic_postheader(); ?>
    				<div class="entry-content">
    <?php thematic_content(); ?>
    
    				<?php wp_link_pages('before=<div class="page-link">' .__('Pages:', 'thematic') . '&after=</div>') ?>
    				</div>
    				<?php thematic_postfooter(); ?>
    			</div><!-- .post -->
    
    				<?php comments_template();
    
    				if ($count==$thm_insert_position) {
    						get_sidebar('index-insert');
    				}
    				$count = $count + 1;
    		endwhile;
    }
    add_action('thematic_indexloop', 'child_index_loop');

    However, I can't figure out how to modify this to display all post categories EXCEPT for one (in my case Category ID 13).

    Normally, I'd look up the code from the WordPress Codex and insert it to the index.php file in the theme something like so:

    <?php query_posts($query_string . '&cat=-13'); ?>
     <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

    I can't figure out how to integrate the query_posts() addition to the above functions.php code. Or is there another better way?

    Thanks for any help!

    Posted 3 years ago #
  2. http://codex.wordpress.org/Function_Reference/query_posts

    from the codex it looks like the new query goes before the while loop begins and then you reset the query after the endwhile

    Posted 3 years ago #
  3. nimrod
    Member

    Finally! After much fiddling with the maze of PHP bits in conjunction with Thematic functions, it works:

    function remove_thematic_index_loop(){
    	remove_action('thematic_indexloop','thematic_index_loop');
    	}
    add_action('init', 'remove_thematic_index_loop');
    
    function child_index_loop(){
    	global $options;
    	foreach ($options as $value) {
        	if (get_option( $value['id'] ) === FALSE) { $$value['id'] = $value['std']; }
        	else { $$value['id'] = get_option( $value['id'] ); }
        }
        		query_posts($query_string . '&cat=-13');
    		/* Count the number of posts so we can insert a widgetized area */ $count = 1;
    		while ( have_posts() ) : the_post() ?>
    
    			<div id="post-<?php the_ID() ?>" class="<?php thematic_post_class() ?>">
        			<?php thematic_postheader(); ?>
    				<div class="entry-content">
    <?php thematic_content(); ?>
    
    				<?php wp_link_pages('before=<div class="page-link">' .__('Pages:', 'thematic') . '&after=</div>') ?>
    				</div>
    				<?php thematic_postfooter(); ?>
    			</div><!-- .post -->
    
    				<?php comments_template();
    
    				if ($count==$thm_insert_position) {
    						get_sidebar('index-insert');
    				}
    				$count = $count + 1;
    		endwhile;
    		rewind_posts();
    }
    add_action('thematic_indexloop', 'child_index_loop');

    Note that the category filter is one line above the $count = 1; line and, like helga suggested, rewind_posts(); is inserted after the endwhile.

    Seems to work fine.

    Note also that it's simple to filter out multiple categories like so:

    query_posts($query_string . '&cat=-13,-17');

    Or, only include one or more categories:

    query_posts($query_string . '&cat=13,17,22');

    Posted 3 years ago #
  4. nimrod
    Member

    Oops, this leads to a minor but worthy issue: the Previous and Next nav links at the bottom of the single post pages still see all categories.

    I will need to only be able to navigate between posts in category 13 when viewing a single post from that category. Likewise, single posts from all other categories should not be navigable to any posts in category 13.

    Hmm...

    Ugh, it also causes PageNavi plugin to malfunction. Ah, the joys of hacking together "CMS" sites in WordPress...

    Posted 3 years ago #
  5. nimrod
    Member

    Oh wait. The above code doesn't actually work at all.

    I didn't notice at first, but it creates a loop where the same posts show on each page.

    So, I can see the front page posts fine, but then clicking the pagination links at the bottom led to the second page WITH THE SAME POSTS as the first. Same result with the third page.

    Bummer. Back to the staring at code...

    Posted 3 years ago #
  6. bummer. i don't know if this will help at all, but this is the query code Devin is using in his Thematic Options blog page template. Supposedly it was to fix pagination issues.

    $wp_query = new WP_Query();
    $wp_query->query( array( 'posts_per_page' => get_option( 'posts_per_page' ), 'paged' => $paged ) );
    $more = 0;

    what about using get_posts? http://codex.wordpress.org/Template_Tags/get_posts

    and the codex refers to wp_reset_query() i didn't see rewind_posts. just tossin' out ideas here. wish i knew more that could help

    Posted 3 years ago #
  7. nimrod
    Member

    Thanks. I wish I knew how to integrate get_posts or the pagination fix above into a function for a child theme.

    This is always been a problem with frameworks for me: along with advantages, you have to deal with another layer of coding where the old basic code of the system has to somehow fit in with the new framework.

    Hence, something like a category filter that would take one line of easily understood code in a new template file for a custom theme is muddled within the complicated new layer of a framework.

    Posted 3 years ago #
  8. "with great power comes great responsibility" :)

    did you try replacing: query_posts($query_string . '&cat=-13'); in your function above w/ my new query?

    Posted 3 years ago #
  9. nimrod
    Member

    Yes, but all categories still show.

    Posted 3 years ago #
  10. well you would atleast have to integrate the 2 commands as the exclude code isn't part of the code i posted. add it to the array.

    $wp_query->query( array( 'posts_per_page' => get_option( 'posts_per_page' ), 'paged' => $paged, 'cat' => -13) );

    no guarantees of course.

    Posted 3 years ago #
  11. Hi,

    you don't need to change the loop.

    function remove_category() {
    	global $query_string;
    	query_posts('cat=-13');
    }
    add_action ('thematic_above_indexloop', 'remove_category');

    This should remove the category 13.

    Chris

    Posted 3 years ago #
  12. nimrod
    Member

    Thanks for that easy line!

    Unfortunately, it's just what I WAS looking for.

    Now I do need to access the whole loop because I've added a few More Fields custom bits that have to go between the_content and the wp_link_pages hooks.

    Is there still a way to remove one category from the whole loop?

    Posted 3 years ago #
  13. Sorry .. don't know what you mean with the whole loop.

    The part about the next / previous post links for the single posts?

    Posted 3 years ago #
  14. nimrod
    Member

    Hm, well, I meant to say above the thematic_postfooter (not wp_link_pages which is used in Single Pages). Also, I'm pretty new to Thematic and php so I may be assuming incorrectly on many levels. I would love any confirmation or schooling on my logic here:
    ________

    The way I've been working with customizing a child theme is that, basically, I can employ Hook and Actions in the child functions.php.

    A Hook seems to be a way injecting an Action into a certain location in the loading of a page. But these Hooks also seem limited to certain locations and not others.

    So, in this case, I want to inject More Fields code after the content but before loop footer bits like the post's links to its other categories and adding a comment, etc.

    Under this logic then I can check the content-extensions.php for suitable Hooks. But, having not found one that allowed me to hook in More Field code in that area directly below the content, I sought to kill the entire index loop and then completely reproduce it in the child functions.php file. This way I can add custom code wherever I like.
    _________

    With your category removal code, I can just do that and not also add More Fields code in the proper location. I would like to do both.

    Here's a slightly cleaner example (taken from "The Index Loop" section of content-extensions.php) of my working child theme function with the More Fields code below the content (see "author-details" div):

    function remove_thematic_index_loop(){
    	remove_action('thematic_indexloop','thematic_index_loop');
    	}
    add_action('init', 'remove_thematic_index_loop');
    
    function child_index_loop(){
    
    		/* Count the number of posts so we can insert a widgetized area */ $count = 1;
    		while ( have_posts() ) : the_post() ?>
    
    			<div id="post-<?php the_ID() ?>" class="<?php thematic_post_class() ?>">
        			<?php thematic_postheader(); ?>
    				<div class="entry-content">
    				<?php thematic_content(); ?>
    
    				<div class="author-details">
    				<?php $key = "author-name"; meta($key); ?>, <?php $key = "author-occupation"; meta($key); ?>, <?php $key = "author-location"; meta($key); ?>
    				</div>
    
    				</div>
    				<?php thematic_postfooter(); ?>
    			</div><!-- .post -->
    
    				<?php comments_template();
    
    				if ($count==$thm_insert_position) {
    						get_sidebar('index-insert');
    				}
    				$count = $count + 1;
    		endwhile;
    }
    add_action('thematic_indexloop', 'child_index_loop');
    Posted 3 years ago #
  15. OK .. now I got it. You could create a filter for 'the_content' adding the needed code bits, but in this case the wp_link_pages would show up after your author related code.

    I'll add a hook before and one right after wp_link_pages, but not for the upcoming version. This one is on code freeze.

    Let me know, if you need more action hooks.

    And .. before I forget this part .. just in case you want to keep navigation inside the one category for your single post navigation. If you open a post not in this one category, everything from the one category will be excluded.

    function remove_category_from_link($args) {
    	global $post;
    	if (in_category('Uncategorized')) {
    		$args['in_same_cat'] = true;
    	} else {
    		$args['excluded_categories'] =  get_cat_ID( 'Uncategorized' );
    	}
    	return $args;
    }
    add_filter('thematic_previous_post_link_args', 'remove_category_from_link');
    add_filter('thematic_next_post_link_args', 'remove_category_from_link');

    Chris

    Posted 3 years ago #
  16. nimrod
    Member

    I'm overjoyed! Thank you so much. I think I'm getting the hang of Thematic finally (at least in a slightly less general way :-).

    So, I kept the code I had built for adding the More Fields bits and added both the single category elimination function on the index page plus the prev / next nav code immediately above.

    It all seems to work perfectly. Thanks again.

    Posted 3 years ago #
  17. lxwx
    Member

    I'm trying something similar to Chris's code snippet, from above, but restricting home page posts to a specific category. So instead of:

    function remove_category() {
    global $query_string;
    query_posts('cat=-13');
    }
    add_action ('thematic_above_indexloop', 'remove_category');

    I have:

    function restrict_category() {
    global $query_string;
    query_posts('cat=7');
    }
    add_action ('thematic_above_indexloop', 'restrict_category');

    Unfortunately, this seems to break is_home() inside subsequent code! (It returns false on the home page.) I guess it makes the query "look like" a category instead of the home page. So, three questions:

    1. Is there a nice way around this, to make is_home() work again?

    2. Is there a better way to make only a certain category appear on the home page?

    3. Should the global $query_string be used in building the query? (I tried query_posts( $query_string . '&cat=7' ); but it has the same effect.)

    Thanks!

    Posted 3 years ago #
  18. @lxwx

    This is what I do in that situation
    Create a page to use as the home page eg 'home'

    create a template file home.php and set the page to use that. The contents of home.php are as follows

    <blockqoute>

    <?php
    /*
    Template Name: Home
    */
    ?>
    
    <?php
    	include TEMPLATEPATH . "/index.php";
    ?>

    </blockqoute>
    Now use is_page_template('home.php') eg..
    <blockqoute>

    function restrict_category() {
         $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
         if(is_page_template('home.php')){
            query_posts("category_name=my_category&paged=$paged");
         }
    }
    add_action ('thematic_abovecontainer', 'restrict_category');

    </blockqoute>
    By also sending the paged value you retain the 'older posts' link when you exceed the number of posts displayable on one page (but only if you filter the query above the container)

    Hope this helps.

    I nearly didn't see it as it is in a 'resolved' thread.

    Posted 3 years ago #
  19. wow i've come a long way from back then. chris is on the right track, but that should also kill pagination. going back to the Codex i reffed above

    http://codex.wordpress.org/Function_Reference/query_posts

    i think it is safest to merge your new query params (restricting categories or whatever) with the existing query so you don't have to worry about recreating or accidentally overwriting the $paged variable

    for instance, if i wanted to exclude category 15 from my index loop

    function remove_category() {
          global $wp_query;
          $args = array_merge( $wp_query->query, array( 'cat'=>-15 ) );
          query_posts( $args );
    }
    add_action ('thematic_above_indexloop', 'remove_category');
    Posted 3 years ago #
  20. evolving further, i like this method of hooking into pre_get_posts() the best:

    http://codex.wordpress.org/Custom_Queries#Category_Exclusion

    i'd probably go so far as to say this is currently the definitive method for modifying an existing/default query. query_posts is still the perfect choice for multiple loops.

    add_action('pre_get_posts', 'kia_exclude_category' );
    
    function kia_exclude_category( ){
      global $wp_query;
      $excluded_id = 15;
    
      // only exclude on home page
      if( is_home()) {
         $wp_query->query_vars['cat'] = '-' . $excluded_id;
      }
    }
    Posted 2 years ago #

RSS feed for this topic

Topic Closed

This topic has been closed to new replies.