Support » Fixing WordPress » Prioritizing posts by category in a date-sorted loop

  • Resolved ggg377

    (@ggg377)


    Hi. To start it off, my loop is sorted by dates. The posts are grouped and the dates appear once on top of posts of the same date like this:

    –Date–
    Post1
    Post2
    Post3

    –Date before that–
    Post 4
    Post 5

    etc

    I’m trying to achieve a result, where if a post belongs to a certain predetermined category, it would be moved above others under a date as such:

    –Date–
    Post3 (special category)
    Post1
    Post2

    –Date before that–
    etc

    I can’t think of anything. Is achieving such a result even possible with php and WordPress codex? I would be glad if anyone could point me towards helpful materials or some code, because I lack the general idea of how to execute this concept.

    My loop: http://pastebin.com/Pp0rA5j7
    Sample site: http://goldenred.web44.net (I would like to move the post test 6 with the category “test” above others under February 3, 2013)

    I would be really thankful if anyone could help.

Viewing 15 replies - 16 through 30 (of 39 total)
  • Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    Yes, I also found some issues with pagination, that’s why I moved most of the functionality to the functions.php file.
    Try it with this in your theme’s functions.php file: http://pastebin.com/BuH4CH3c
    You can change the $dates_per_page and $top_category_id in:

    // change these two values
    $dates_per_page = 4; // four dates to loop through (dates can have multiple posts)
    $top_category_id = 1; // category you want on top of same date posts

    Just as a warning, this will only work on your home page.

    In your index.php you can now use a normal loop to display the posts:

    <?php while ( have_posts() ) : the_post(); ?>
      <!-- put your loop code here -->
      <?php the_title(); ?>
    <?php endwhile; ?>

    For getting the right pagination links you can use the functions
    previous_date_link() and next_date_link() that are now in your theme’s functions.php. You’ll need to pass the $dates_per_page and (optional) a label to these functions. Example:

    <?php
    $dates_per_page = 4; // four dates to loop through (dates can have multiple posts)
    // 'Previous Page' and 'Next Page' are labels
    echo previous_date_link( $dates_per_page, 'Previous Page' );
    echo next_date_link( $dates_per_page, 'Next Page' );
    ?>

    I hope this will work as you want it to.

    keesiemeijer, this is, simply put – awesome. The code indeed does the job exactly as intended. I double-checked and nothing seems to be hidden anymore. The main functionality works.

    However, one more issue (that I mentioned earlier) still remains, it broke a bit of code from my old loop. First, “Today” and “Yesterday” get duplicate date labels for each post. “the_date” works as intended for some reason, posts under that get grouped correctly. Code:

    <?php $w_h = $w_d = $last = 0; ?>
    
                    <div class="indexdate"><?php
        if ( date('Yz') == get_the_time('Yz') ) {
            if (!$w_d++) echo '<h6>Today</h6>';
        } elseif ( date('Yz')-1 == get_the_time('Yz') ) {
            if (!$w_h++) echo '<h6>Yesterday</h6>';
        } else {
            echo the_date('', '<h3>', '</h3>');
        };
    ?>

    Second, the class “#post.first” gets applied to all posts instead of being applied to the first posts of respective categories only. Code:

    <div id="post" <?php if( get_the_time('Yz') != $last ) { $last = get_the_time('Yz'); echo ' class="first" '; } ?>>

    I also drew some illustrations so it would be easier to understand:
    Labels: http://i.imgur.com/C0SO5gz.jpg
    Borders: http://i.imgur.com/S4KfxZo.jpg

    I hope you have some comments or ideas on these issues. Both of these work normally without the enhanced loop. I’ve had both of these problems since your first scripts. Really hope it’s possible to get these fixed.

    We’ve ventured quite far into unmarked WordPress territory. I hope other WordPress users will find this useful in the future.

    Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    Try it with a loop like this:

    <?php
     $w_h = $w_d = $last = 0;
     $date =  date('Yz');
    ?>
    <?php while ( have_posts() ) : the_post(); ?>
    
    <?php
        $post_date = get_the_time('Yz');
        $class = '';
    
        if ($date == $post_date) {
            if (!$w_d++) echo '<div class="indexdate"><h6>Today</h6></div>';
        } elseif (  $date -1 == $post_date ) {
            if (!$w_h++) echo '<div class="indexdate"><h6>Yesterday</h6></div>';
        } else {
            echo '<div class="indexdate"><h3>' . get_the_date() . '</h3></div>';
        };
    
        if( $post_date != $last ) {
          // new post date
          $last = $post_date;
          $class = ' class="first" ';
        }
    ?>
    
    <div id="post"<?php echo $class ?>>
    
      <!-- put your post code here -->
      <?php the_title(); ?>
    
    </div>
    <?php endwhile; ?>

    keesiemeijer, thank you once again. That almost did it, “Today” and “Yesterday” are perfect, but now, posts under “get_the_date” get labels for each post. #post.first class seems to work correctly everywhere. I hope the label issue can be easily solved.

    For quick reference:

    index.html: http://pastebin.com/nYamPBQV
    Example of everything almost working: http://goldenred.web44.net

    Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    Try changing this:

    echo '<div class="indexdate"><h3>' . get_the_date() . '</h3></div>';

    to this:

    if( $post_date != $last ) {
      echo '<div class="indexdate"><h3>' . get_the_date() . '</h3></div>';
    }

    Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    Also for pagination try to change this:

    <div id="postnavi_index">
       <div class="right"><?php next_posts_link('Older &raquo;') ?></div>
       <div class="left"><?php previous_posts_link('&laquo; Newer') ?></div>
    </div>

    to this:

    <div id="postnavi_index">
      <?php $dates_per_page = 4; ?>
       <div class="right"><?php echo previous_date_link( $dates_per_page, 'Older &raquo;' ); ?></div>
       <div class="left"><?php echo next_date_link( $dates_per_page, '&laquo; Newer' ); ?></div>
    </div>

    It worked, which also means this thread has reached its conclusion. You definitely helped solve a complex issue and I am most thankful for that. Your skills are impressive. Instead of just showering you with praise though, I’ll try to help people out on the forum instead at times and I’ll also try to understand the code, which you wrote, better. This was such a huge help, that it deserves more than just a thank you in my opinion. I hope this knowledge will be useful for other WordPress users as well.

    As a last thing, I figured if you have an idea how to wrap the pagination function in nav tags? I actually used twentytwelve’s pagination functions before, which looked like this:

    index.php:

    <?php twentytwelve_content_nav( 'nav-below' ); ?>

    functions.php:

    if ( ! function_exists( 'twentytwelve_content_nav' ) ) :
    /**
     * Displays navigation to next/previous pages when applicable.
     *
     * @since Twenty Twelve 1.0
     */
    function twentytwelve_content_nav( $html_id ) {
    	global $wp_query;
    
    	$html_id = esc_attr( $html_id );
    
    	if ( $wp_query->max_num_pages > 1 ) : ?>
    		<nav id="<?php echo $html_id; ?>" class="navigation" role="navigation">
    			<h3 class="assistive-text"><?php _e( 'Post navigation', 'twentytwelve' ); ?></h3>
    			<div class="nav-previous alignleft"><?php next_posts_link( __( '<span class="meta-nav">โ†</span> Older posts', 'twentytwelve' ) ); ?></div>
    			<div class="nav-next alignright"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">โ†’</span>', 'twentytwelve' ) ); ?></div>
    		</nav><!-- #<?php echo $html_id; ?> .navigation -->
    	<?php endif;
    }
    endif;

    The important thing was that with this implementation, I received selectors like this: navigation (section) selector: #content nav, next (page) selector: #content nav a. I tried wrapping the functions in your code in nav tags, but it didn’t work:

    function next_date_link( $dates_per_page = 10, $label = 'Next Page' ){
                    return previous_date_link( $dates_per_page, $label, false );
            }
    
            function previous_date_link( $dates_per_page = 10, $label = 'Previous Page', $prev = true ){
    
                    $paged = ( get_query_var('paged') ) ? get_query_var('paged') : 1;
    
                    if ( $prev ) {
    
                            $count = (($paged -1) * $dates_per_page) + $dates_per_page;
                            $limit = ' LIMIT ' . $count . ', 1';
    
                    } else {
    
                            $count = (($paged -1) * $dates_per_page)-1;
    
                            if ( ($count+1) < $dates_per_page )
                                    return '';
    
                            $limit = ' LIMIT ' . $count . ', 1';
    
                    }

    Anyway you can leave this for me to figure out. I’m not asking you to help me out with this. It is my last question however.

    Best regards ๐Ÿ™‚

    ggg377

    Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    The pagination code doesn’t use the global $wp_query object that WordPress uses for your home and paged home pages. That’s why you can’t use this:

    if ( $wp_query->max_num_pages > 1 ) :

    What you could do is something like this in the twentytwelve_content_nav function [untested]:

    <?php if ( is_home() ) :
      // pagination on the home page
      $dates_per_page = 4;
      $prev = previous_date_link( $dates_per_page, 'Older ยป' );
      $next = next_date_link( $dates_per_page, 'ยซ Newer' ); ?>
      <?php if($prev || $next) : ?>
        <nav id="<?php echo $html_id; ?>" class="navigation" role="navigation">
          <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentytwelve' ); ?></h3>
          <div class="nav-previous alignleft"><?php echo $prev;  ?></div>
          <div class="nav-next alignright"><?php echo $next; ?></div>
        </nav><!-- #<?php echo $html_id; ?> .navigation -->
      <?php endif; ?>
    
    <?php else :
    // pagination on all other pages
    ?>
    
      <?php if ( $wp_query->max_num_pages > 1 ) : ?>
        <nav id="<?php echo $html_id; ?>" class="navigation" role="navigation">
          <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentytwelve' ); ?></h3>
          <div class="nav-previous alignleft"><?php next_posts_link( __( '<span class="meta-nav">โ†</span> Older posts', 'twentytwelve' ) ); ?></div>
          <div class="nav-next alignright"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">โ†’</span>', 'twentytwelve' ) ); ?></div>
        </nav><!-- #<?php echo $html_id; ?> .navigation -->
      <?php endif; ?>
    
    <?php endif; ?>

    This was a complex problem which I think we’ve solved with the least amount of (large) queries to the database.

    I’m glad you’ve got it resolved ๐Ÿ™‚

    Placing that code within this function resulted in a nasty syntax error no matter how I did it:

    function twentytwelve_content_nav( $html_id ) {code here}

    In the end for me it’s not that important to use twentytwelve’s function, but to get working selectors for #content nav and #content nav a. If that could be done easier within your function, while getting the same functionality then that would be great too. However if I placed your code wrong, then repairing that would be just fine.

    Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    Try it with this in your theme’s functions to show pagination with the same format as in twentytwelve_content_nav():

    function get_index_pagination_nav( $html_id ) {
    
    	$html_id = esc_attr( $html_id );
    
    	if ( is_home() ) :
    
    		// pagination on the home page
    		$dates_per_page = 4;
    		$prev = previous_date_link( $dates_per_page, 'Older ยป' );
    		$next = next_date_link( $dates_per_page, 'ยซ Newer' );
    
    		if( $prev || $next ) : ?>
    
    			<nav id="<?php echo $html_id; ?>" class="navigation" role="navigation">
    				<h3 class="assistive-text"><?php _e( 'Post navigation', 'twentytwelve' ); ?></h3>
    				<div class="nav-previous alignleft"><?php echo $prev;  ?></div>
    				<div class="nav-next alignright"><?php echo $next; ?></div>
    			</nav><!-- #<?php echo $html_id; ?> .navigation -->
    
    		<?php endif; 
    
    	else :
    		// check if the function exists (index.php is a fallback template for other pages)
    		if ( function_exists( 'twentytwelve_content_nav' ) ) {
    		 	twentytwelve_content_nav( $html_id );
    		}
    
    	endif;
    
    } // end of function get_index_pagination_nav

    Replace the twentytwelve_content_nav function in your index.php with this:

    <?php get_index_pagination_nav( 'nav-below' ); ?>

    That did it keesiemeijer. I don’t have any more questions. Thank you for your help and co-operation. I’ll try to make it up in time. I hope solving this issue was at least somewhat fun and interesting for you.

    ggg377

    Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    I hope solving this issue was at least somewhat fun and interesting for you.

    It was. As you can see on my profile page, one of my interests is puzzles, and this was one ๐Ÿ™‚

    Maybe one last advise would be to style the post navigation for people who browse with javascript off (I see you installed infinite scrolling). Maybe switch the pagination functions around?
    http://goldenred.web44.net/page/2/

    And thank you for contributing to these forums ๐Ÿ™‚

    I’m glad it was a fun challenge. Thanks for pointing out the potential improvement for non-javascript users. I’ll look into stylizing the links. On another note, I’ve tested the loop a bit now and so far it seems perfect. Thank you so much!

    Moderator keesiemeijer

    (@keesiemeijer)

    moderator

    Just as an update, just today I found out about a cool sql feature “group_concat”. With this feature I was able to reduce the queries to the database to one main sql query that returns all post ids sorted by (first) category. I’ve done some testing and this is much faster than what you have now.

    Back up your functions.php (We know that works).
    remove all my code and replace it with this functions.php code: http://pastebin.com/8uvGYXkb

    Change these values as you like:

    // change these two values
    $dates_per_page = 4; // four dates to loop through (dates can have multiple posts)
    $top_category_id = 1; // category you want on top of same date posts

    The only change I made to the pagination functions is that you have to give the “get_index_pagination_nav” function the $dates_per_page variable, otherwise it will default to 10 dates.
    In index.php:

    <?php
    $dates_per_page = 4;
    get_index_pagination_nav( 'nav-below', $dates_per_page);
    ?>

    Test it out ๐Ÿ™‚

    Hey keesiemeijer, thanks for the code. I implemented it, but it doesn’t seem to work properly. Some sorting does take place, but that is very occasional and I couldn’t find a pattern why some posts got moved. Moving of posts from the default arrangement was very rare.

    functions.php: http://pastebin.com/P1LPxmdH
    index.php (switched the code I had for pagination for this):

    <?php
    $dates_per_page = 4;
    get_index_pagination_nav( 'nav-below', $dates_per_page);
    ?>

    I also left the bugged implementation up at the example site.

    It would definitely be cooler to use a more optimized code, so I’m all in as far as co-operation ๐Ÿ™‚

Viewing 15 replies - 16 through 30 (of 39 total)
  • The topic ‘Prioritizing posts by category in a date-sorted loop’ is closed to new replies.