WordPress.org

Ready to get started?Download WordPress

Forums

Random Post order not working with pagination (19 posts)

  1. matstillo
    Member
    Posted 2 years ago #

    Hey all,

    I've searched this one quite a bit, and can't quite find a resolved answer!

    Basically, I want to create a custom loop where I can set the post order to be random and the number of displayed posts to 10, for example. I then need the pagination to retain the original random post order from page to page.

    At the moment, each new page of 10 posts is randomising itself again, so you get duplicates or posts that are unlucky enough to never show!

    I did find this post, where they are able to do this, by a small addition to functions.php:

    http://wordpress.stackexchange.com/questions/31647/is-it-possible-to-paginate-posts-correctly-that-are-random-ordered

    This does seem to work for me, but the problem is, the answer given only ever offered a solution to using it on your main loop, which then overwrites all my default loops in the theme. I only want to use it on one custom loop!

    I'm just not up to the task of changing this small inclusion to the functions file so that it can just be called in a custom loop. Can anyone help?!

    Here is the code that can be added to functions.php to modify the main loop:

    session_start();
    
    add_filter('posts_orderby', 'edit_posts_orderby');
    
    function edit_posts_orderby($orderby_statement) {
    
        $seed = $_SESSION['seed'];
        if (empty($seed)) {
          $seed = rand();
          $_SESSION['seed'] = $seed;
        }
    
        $orderby_statement = 'RAND('.$seed.')';
        return $orderby_statement;
    }

    Thanks in advance for any help!

  2. vtxyzzy
    Member
    Posted 2 years ago #

    You can set a global variable in the template, just ahead of the custom query, and check for it in the function. Then clear the variable just after the custom query.

    That way, the filter will only affect the custom query. Here is an article that shows an example:

    http://wordpress.mcdspot.com/2011/12/24/consistent-random-set-of-posts/

    That example shows the same random order of posts for all viewers each day. To show a different set for each viewer session, use the function you showed, or set the global variable using the code from that function.

  3. matstillo
    Member
    Posted 2 years ago #

    Nice one, thanks for the reply!

    That's joined a few dots up for me. I'll take a look now 7 will post how I get on!

    Cheers

  4. matstillo
    Member
    Posted 2 years ago #

    Well, I've now noticed a further complication!

    The list of posts I am trying to randomise is actually coming from a query string (not sure if I am using the correct terminology there!)

    Basically, I am currently calling the posts at the moment like this:

    <?php
      query_posts($query_string . '&orderby=rand');
      if (have_posts()) : while (have_posts()) : the_post();
    ?>

    This is because I needed to retain the original query because the user gets to this page by selecting a category / sub category from a drop down. So the page url looks like this:

    http://www.mydomain.com/?cat=123&submit=view

    The subsequent paged urls are like this:

    http://www.mydomain.com/page/2/?cat=123&submit=view
    http://www.mydomain.com/page/3/?cat=123&submit=view

    So what I need to do is somehow keep this original query in the new code. I have tried simply adding $query_string before the $args array, but it then breaks the random items per page again & I'm back to square 1. I'm guessing that by adding the $query_string back in, I am negating the filter in some way?

  5. vtxyzzy
    Member
    Posted 2 years ago #

    Just leave the original query alone. The filters add to the query so the original terms should still be there. Unless, of course, there is something in the original query that would conflict with the filters, in which case it will be overridden.

  6. matstillo
    Member
    Posted 2 years ago #

    Just in case this helps anyone else out: I got this working just with a simple combo of the arguments from the code in vtxyzzy's link, and the code I was originally using.

    In line 22 of the code it calls the arguments outlined in that code:

    query_posts($args);

    & I just modified it to also retain the query string

    query_posts($query_string . '&' . $args);

    That way I am able to select a group of posts using a query string (a category drop down in my case), then randomise the order of the post list, with it keeping the same random order across all pages.

    Thanks for the help, vtxyzzy!

  7. Bad Feather
    Member
    Posted 1 year ago #

    Hey matstillo, would you mind posting your merged solution? Trying to do the same thing. Would be very helpful.

    Thanks

  8. atiquetedevelopers
    Member
    Posted 1 year ago #

    Hi, I'm trying to do the same!

    Any solutions? Thanks :-)

  9. Szyam
    Member
    Posted 1 year ago #

    Hey guys, glad i found this post. In a situation were I'm trying to do the same.
    I've just started using WP a few months ago so still getting comfortable. The code I'm using to show my custom post with random four posts is:

    <?php query_posts("posts_per_page=4&orderby=rand"); ?>
    <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

    Are you suggesting I can just place the code above into my functions.php and the
    $query_string . '&' . $args
    into the query_posts and get it working correctly?

    Thanks for any advice...

  10. matstillo
    Member
    Posted 1 year ago #

    Hi all,

    Sorry I'm not being much help in this thread. Mega busy at the moment. I'll just take a look at the Theme where I got this working & see if I can pull out the whole code.

  11. matstillo
    Member
    Posted 1 year ago #

    <?php
    
    // Retrieve consistent random set of posts with pagination
    function mam_posts_query($query) {
       global $mam_posts_query;
       if ($mam_posts_query && strpos($query, 'ORDER BY RAND()') !== false) {
          $query = str_replace('ORDER BY RAND()',$mam_posts_query,$query);
          //print_r("<p>$query</p>");
       }
       return $query;
    }
    add_filter('query','mam_posts_query');
    $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
    $seed = date('Ymd');  // Use date('Ymdh') to get an hourly change
    global $mam_posts_query;
    $mam_posts_query = " ORDER BY rand($seed) "; // Turn on filter
    $args = array(
       'caller_get_posts' => 1,  // Stickies will be repeated if this is not set
       'orderby' => 'rand',      // This MUST be in the query - the filter checks for it
       'paged' => $paged,
    );
    
    global $wp_query;
    query_posts(
       array_merge(
          $wp_query->query,
          $args
       )
    );
    
    $mam_posts_query = ''; // Turn off filter
    
    	if (have_posts()) : while (have_posts()) : the_post();
    ?>
    
    	<h1>Your stuff here</h1>
    
    <?php endwhile; ?>
    
    	<div>
    	   <div><?php next_posts_link('&laquo; Older Entries') ?></div>
    	   <div><?php previous_posts_link('Newer Entries &raquo;') ?></div>
    	</div>
    
    <? endif; ?>
  12. matstillo
    Member
    Posted 1 year ago #

    Not sure what happened in this thread, as I had posted a message earlier saying that it looked like I had NOT managed to get it working after all. That post is now missing!

    The code above is as far as I got, but still doesn't work. Each page is still being randomised.

    Hopefully someone can see what might be going on.

    Cheers!

  13. ngoodfellow
    Member
    Posted 1 year ago #

    Has this been resolved yet?

  14. lancemonotone
    Member
    Posted 1 year ago #

    I think I have this working. The second function is a template tag you can use in single.php for next and previous posts link to replace the native WP version. I made it wrap from last to first post and vice versa. If you don't want it to wrap, you'll need to change the logic a little after this line: '// Find the index of the next/prev items'

    // Randomly order posts upon home page load and allow pagination
    add_filter('posts_orderby', 'edit_posts_orderby');
    
    /**
     * Randomize posts, keeping same order on subsequent Home page and single post views
     * if referer is within the site.  Home page will randomize again if reloaded.
     *
     * @param string $orderby_statement
     * @return string Modified orderby statement
     */
    function edit_posts_orderby($orderby_statement) {
    	if(!is_admin()){
    		if(is_home() && !wp_get_referer()) unset($_SESSION['seed']);
    		$seed = $_SESSION['seed'];
    		if (empty($seed)) {
    			$seed = rand();
    			$_SESSION['seed'] = $seed;
    		}
    		$orderby_statement = 'RAND('.$seed.')';
    	}
    	return $orderby_statement;
    }
    
    /**
     * Display adjacent post link with random seed.
     *
     * @param string $format
     * @param string $link
     * @param bool $previous
     */
    function get_randomized_adjacent_post_link($format='« %link', $link='%title', $previous = true, $echo = true) {
    	global $wpdb, $post;
    	$seed = $_SESSION['seed'];
    	$query = "SELECT {$wpdb->posts}.ID
    			FROM {$wpdb->posts}
    			WHERE {$wpdb->posts}.post_type = 'post'
    			AND {$wpdb->posts}.post_status = 'publish'
    			ORDER BY RAND($seed)";
    	$results = $wpdb->get_col($query);
    	$current_index = array_search($post->ID, $results);
    	// Find the index of the next/prev items
    	if($previous) {
    		$id = $results[($current_index - 1 < 0 ) ? count($results) - 1 : $current_index - 1];
    	} else {
    		$id = $results[($current_index + 1 == count($results)) ? 0 : $current_index + 1];
    	}
    	$rel = $previous ? 'prev' : 'next';
    
    	$title = get_the_title($id);
    	$string = '<a href="'.get_permalink($id).'" rel="'.$rel.'">';
    	$link = str_replace('%title', $title, $link);
    	$link = $string . $link . '</a>';
    
    	$format = str_replace('%link', $link, $format);
    
    	$adjacent = $previous ? 'previous' : 'next';
    	$the_link = apply_filters( "{$adjacent}_post_link", $format, $link );
    	if($echo) echo $the_link;
    	else return $the_link;
    }
  15. curlybracket
    Member
    Posted 1 year ago #

    Hello,

    i saw a very similar function here : http://wordpress.stackexchange.com/questions/31647/is-it-possible-to-paginate-posts-correctly-that-are-random-ordered

    This works indeed, when adding this function to functions.php BUT it replaces every other custom order function (replaces the ordering of the main loop).

    I have a page template in which i allow custom ordering of posts, sth `like if ($_GET['order'] == "random") {
    // do wp_query using orderby = rand
    } else {
    // do wp_query using orderby = date
    }`

    How would I apply your function in this case?

  16. lancemonotone
    Member
    Posted 1 year ago #

    You could probably modify this function as such:

    /**
     * Randomize posts, keeping same order on subsequent Home page and single post views
     * if referer is within the site.  Home page will randomize again if reloaded.
     *
     * @global $_GET['order'] default or 'random' sets random, 'date' sets date.
     *
     * @param string $orderby_statement
     * @return string Modified orderby statement
     */
    function edit_posts_orderby($orderby_statement) {
    	if(!is_admin()){
    		switch ($_GET['order']) {
    			case "date":
    				break;
    			case "random":
    			default:
    				if(is_home() && !wp_get_referer()) unset($_SESSION['seed']);
    				$seed = $_SESSION['seed'];
    				if (empty($seed)) {
    					$seed = rand();
    							$_SESSION['seed'] = $seed;
    				}
    				$orderby_statement = 'RAND('.$seed.')';
    		}
    
    	}
    	return $orderby_statement;
    }
  17. curlybracket
    Member
    Posted 1 year ago #

    Thank you @lancemonotone.

    So, this is how i used your function and it works perfectly :

    session_start();
    add_filter('posts_orderby', 'myrandom');
    function myrandom($orderby_statement) {
        if(!is_admin()){
            switch ($_GET['order']) {
                case "random":
                    if(is_home() && !wp_get_referer()) unset($_SESSION['seed']);
                    $seed = $_SESSION['seed'];
                    if (empty($seed)) {
                        $seed = rand();
                                $_SESSION['seed'] = $seed;
                    }
                    $orderby_statement = 'RAND('.$seed.')';
                default:
                    break;
            }   
    
        }
        return $orderby_statement;
    }
  18. lancemonotone
    Member
    Posted 1 year ago #

    There's a logic bug in the function which will prevent the random seed from being reset if the page is home or if the referrer is not within the site. Updated code to come.

  19. lancemonotone
    Member
    Posted 1 year ago #

    /**
     * Randomize posts, keeping same order on subsequent Home page and single post views
     * if referer is within the site.  Home page will randomize again if reloaded.
     *
     * @global $_GET['order'] default or 'random' sets random, 'date' sets date.
     *
     * @param string $orderby_statement
     * @return string Modified orderby statement
     */
    function edit_posts_orderby($orderby_statement) {
    	if(!is_admin()){
    		switch ($_GET['order']) {
    			case "date":
    				break;
    			case "random":
    			default:
    				if(!isset($_SESSION['seed'])) {
    					echo 'New Grid';
    					$_SESSION['new_request'] = true;
    				} else {
    					// $refesh_flag will be true if $request_signatures match between page loads.
    					$request_signature = md5($_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING'].implode('',$_POST));
    					// $interior_flag will be true if the last page URL contains the base url but is not the base url.
    					$interior_flag = is_int(strpos(wp_get_referer(),home_url())) && home_url() != wp_get_referer();
    					// if we are home AND the page has been refreshed AND the last page was not an interior page,
    					// unset the seed and flag as a new request so the grid will appear the same upon return.
    					if(is_home() && $_SESSION['last_request'] == $request_signature && $interior_flag == true){
    					//echo 'True';
    						unset($_SESSION['seed']);
    						$_SESSION['new_request'] = true;
    					} else {
    								//echo 'False';
    						$_SESSION['new_request'] = false;
    						$_SESSION['last_request'] = $request_signature;
    					}
    						}
    				$seed = $_SESSION['seed'];
    				if (empty($seed)) {
    					$seed = rand();
    					$_SESSION['seed'] = $seed;
    				}
    				$orderby_statement = 'RAND('.$seed.')';
    		}
    	}
    	return $orderby_statement;
    }

Topic Closed

This topic has been closed to new replies.

About this Topic