1

I have 1 Custom Post Type of products as well as two taxonomies of types and countries. I'm displaying my custom post type of products on my taxonomy.php page with paged pagination.

I am also using the custom post types and custom fields plugin to help with storing the data for the products such as "Name" and "Image".

This is how I am doing this in my taxonomy.php:

<div class="container">

<?php

//first get the current term
$current_term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );


  $args = array(
    'post_type'      => array( 'products' ),
    'orderby' => 'rand',
    'post_per_page' => '10',
    'tax_query' => array(
    array(
      'taxonomy' => $current_term->taxonomy,
      'field'    => 'slug',
      'terms'    => $current_term,
    ),
    ),
    'paged' => ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1 );

  $products_query = new WP_Query( $args );

  $temp = $wp_query; 
  $wp_query = null; 
  $wp_query = $products_query; 

  while ($products_query->have_posts()) : $products_query->the_post(); 
?>

<!--product image and title-->
<div>
  <a href="<?php the_permalink(); ?>"><img src="<?php the_field('image'); ?>" alt="Name of Product"></a>
</div><!--product-image-->

<div>
<?php the_field('title'); ?>
</div><!--title end-->

<?php endwhile; ?>


<?php 

//getting paginations in numbers
global $wp_query;

$total_pages = $wp_query->max_num_pages;

if ($total_pages > 1){

  $current_page = max(1, get_query_var('paged'));

  echo paginate_links(array(
      'base' => get_pagenum_link(1) . '%_%',
      'format' => '/page/%#%',
      'current' => $current_page,
      'total' => $total_pages,
      'before_page_number' => '<div class="pagination-navigation">',
      'after_page_number' => '</div>'

    ));
}
?>

<?php 
  $wp_query = null; 
  $wp_query = $temp;  // Reset
?>
<?php wp_reset_postdata(); ?>
</div><!--container end-->

So I had to change the main query to this because my pagination were not working correctly and would give me a 404 error every time I tried going to the next page. Anyways, that was working fine until yesterday when I noticed that my products repeat them selves when ever I go to the next page.

Example:

first page has 5 Cars

  1. Car1

  2. Car2

  3. Car3

  4. Car4

  5. Car5

Then when I go to the next page it will show the next series of prodcuts but atleast 1 or 2 will repeat theme selves like so.

  1. Car6

  2. Car7

  3. Car2 (already displayed in 1st page)

  4. Car8

  5. Car9

I dont really understand why it is doing this. Also in my admin area Reading > Setting I have my blog pages show at most set to 10 in case that matters.

Any suggestions?

UPDATE

So the solution of adding

session_start();

add_filter('posts_orderby', function ($orderby_statement) {

    $seed = $_SESSION['seed'];
    if (empty($seed)) {
      $seed = rand();
      $_SESSION['seed'] = $seed;
    }

    $orderby_statement = 'RAND('.$seed.')';
    return $orderby_statement;
});

to my function.php does work but all my items do not generate randomly. Every time I go to page 1 the same products will be there every time no matter how many times I refresh the page.

So my functions.php would look like so.

add_action( 'pre_get_posts', function ( $q ) {
    if( !is_admin() && $q->is_main_query() && $q->is_tax() ) {
        $q->set( 'posts_per_page', 2 );
        $q->set( 'orderby', 'rand' );
    }
});


//

session_start();

add_filter('posts_orderby', function ($orderby_statement) {

    $seed = $_SESSION['seed'];
    if (empty($seed)) {
      $seed = rand();
      $_SESSION['seed'] = $seed;
    }

    $orderby_statement = 'RAND('.$seed.')';
    return $orderby_statement;
});

Now I have tried the updated code and changed my functions to look like this:

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;
}

add_action( 'pre_get_posts', function ( $q ) {
    if( !is_admin() && $q->is_main_query() && $q->is_tax() ) {
        $q->set( 'posts_per_page', 2 );
        $q->set( 'orderby', 'rand' );
    }
});

remove_filter('posts_orderby', 'edit_posts_orderby');

now it will generate randomly but goes back to repeating an item

  • Why are you overriding taxonomy.php with a custom query when you can use taxonomy-taxonomynamegoeshere.php? – Tom J Nowell Dec 13 '14 at 20:38
  • oh ok will do. Give me about 10 mins and ill have it up in the form of a question @PieterGoosen – Lucas Santos Dec 15 '14 at 10:56
2

In all honesty, I really think that all your misery is caused by your pagination function as we have briefly discussed a while ago.

You do have a couple of issues here that are contributing factor to the problems you are experiencing

  • Changing the main query for a custom query for what ever reason is almost always a big headache and should be avoided at all times. The main query can be very easily modified by pre_get_posts to suite your needs. I have done a post a while ago about this complete issue that you can go and read up on

  • Nullifying the main query is exactly the same as using query_posts, which you should never use. This might be one of the big reasons why your pagination outright fails

Note: This function isn't meant to be used by plugins or themes. As explained later, there are better, more performant options to alter the main query. query_posts() is overly simplistic and problematic way to modify main query of a page by replacing it with new instance of the query. It is inefficient (re-runs SQL queries) and will outright fail in some circumstances (especially often when dealing with posts pagination).

I think the easiest way to debug this and moving forward is to get rid of your custom query. Copy this code and paste this in your taxonomy.php file.

<div class="container">

<?php 
while( have_posts() ) { 
    the_post(); 
?>

    <!--product image and title-->
    <div>
      <a href="<?php the_permalink(); ?>"><img src="<?php the_field('image'); ?>" alt="Name of Product"></a>
    </div><!--product-image-->

    <div>
    <?php the_field('title'); ?>
    </div><!--title end-->

<?php } ?>


<?php 

//getting paginations in numbers
global $wp_query;

$total_pages = $wp_query->max_num_pages;

  $current_page = max(1, get_query_var('paged'));

  echo paginate_links(array(
      'base' => get_pagenum_link(1) . '%_%',
      'format' => '/page/%#%',
      'current' => $current_page,
      'total' => $total_pages,
      'before_page_number' => '<div class="pagination-navigation">',
      'after_page_number' => '</div>'

    ));
?>

</div><!--container end-->

You should now at least get the correct posts, in order of post date. First make sure that this is working correctly. Don't worry if the pagination doesn't work, as I said, I get an idea something is wrong with your function

You can now use pre_get_posts to change the order of your posts and add custom posts_per_page

Paste the following in your functions.php

add_action( 'pre_get_posts', function ( $q ) {
    if( !is_admin() && $q->is_main_query() && $q->is_tax() ) {
        $q->set( 'posts_per_page', 10 );
        $q->set( 'orderby', 'rand' );
    }
});

Post type should be included by default on the taxonomy page so it would not be necessary to add this into your pre_get_posts action

This should give you the correct output from your template. As I said, make sure that this is working, if the pagination is not working, don't worry about that now, first get your output as it should.

If all is working fine, except pagination, you will need to look at your pagination function. Let me know if your pagination does not work after you have made all these changes

EDIT 1

I've searched a bit for possible solutions to this problem and came up with this article written by Hugh Lashbrooke

PROBLEM

As soon as you navigate to the second page of the results, the posts are returned randomly once again and you get an entirely different set of posts that may or may not contain posts that you have already viewed

SOLUTION

...we will use MySQL’s RAND() function and supply it with a seed value so it uses the same random order on every subsequent page load. To do this we will store a random string as a PHP session variable so it can be used by MySQL as a reference for the order to use for each page.

NOTE ABOUT THE CODE

You will notice one extra operation on line 7 of this snippet – we also reset the seed value every time the first page of the posts are loaded. This means that as long as someone stays on the paginated pages they will see a consistent set of results, but once they go back to the first page the randomisation will reset and they will see the posts in a completely different order.

session_start();

add_filter( 'posts_orderby', 'randomise_with_pagination' );
function randomise_with_pagination( $orderby ) {

    if( is_tax() ) {

        // Reset seed on load of initial archive page
        if( ! get_query_var( 'paged' ) || get_query_var( 'paged' ) == 0 || get_query_var( 'paged' ) == 1 ) {
            if( isset( $_SESSION['seed'] ) ) {
                unset( $_SESSION['seed'] );
            }
        }

        // Get seed from session variable if it exists
        $seed = false;
        if( isset( $_SESSION['seed'] ) ) {
            $seed = $_SESSION['seed'];
        }

            // Set new seed if none exists
            if ( ! $seed ) {
                $seed = rand();
                $_SESSION['seed'] = $seed;
            }

            // Update ORDER BY clause to use seed
            $orderby = 'RAND(' . $seed . ')';
    }

    return $orderby;
}

EDIT 2

This code is working perfectly, I have now tested it over and over again. If this does not work for you, you have to recheck your code. You have to take note of the following.

  • The code given only targets the taxonomy archive pages, that is why the is_tax() conditional tag is used. If you need this on any other template, you will need to modify/change that conditional tag

  • The posts don't duplicate, and the posts are only reset when the first post is visited, no other pages are affected. Make sure that your results are not being cached.

As a final attempt, here is the only code that you should have from this answer in your functions.php

add_action( 'pre_get_posts', function ( $q ) {
    if( !is_admin() && $q->is_main_query() && $q->is_tax() ) {
        $q->set( 'posts_per_page', 10 );
        $q->set( 'orderby', 'rand' );
    }
});
session_start();

add_filter( 'posts_orderby', 'randomise_with_pagination' );
function randomise_with_pagination( $orderby ) {

    if( is_tax() ) {

        // Reset seed on load of initial archive page
        if( ! get_query_var( 'paged' ) || get_query_var( 'paged' ) == 0 || get_query_var( 'paged' ) == 1 ) {
            if( isset( $_SESSION['seed'] ) ) {
                unset( $_SESSION['seed'] );
            }
        }

        // Get seed from session variable if it exists
        $seed = false;
        if( isset( $_SESSION['seed'] ) ) {
            $seed = $_SESSION['seed'];
        }

            // Set new seed if none exists
            if ( ! $seed ) {
                $seed = rand();
                $_SESSION['seed'] = $seed;
            }

            // Update ORDER BY clause to use seed
            $orderby = 'RAND(' . $seed . ')';
    }

    return $orderby;
}
| improve this answer | |
  • So in other words the session_start(); code is pointless because it still does not generate randomly. when I could just NOT use 'orderby', 'rand' – Lucas Santos Dec 13 '14 at 20:22
  • Well ill try my absolute best to see if I can get this to work and if not then I just wont use random ordering. Thank you so much for all your help Pieter you are the man! Yeah it's morning where im at so looks like your time zone is a lot different. Good Night and thank again – Lucas Santos Dec 13 '14 at 20:38
  • Hey Pieter so iv tried the updated session_start(); snippet and it still seems to be repeating. iv tried putting it above and below the pre_get_posts and it does generate randomly but still repeating some items. – Lucas Santos Dec 14 '14 at 12:45
  • It's ok youve helped me a lot thanks Pieter! I'll do my best to try and find or create a solution. But hey just one question about the pre_get_posts in my functions.php.. what if I was running 2 different queries in taxonomy.php like one for desktop and one for mobile and I wanted my mobile query to display 6 items and not 10. Then how would I go about that? – Lucas Santos Dec 15 '14 at 8:17
  • 1
    Then you are on your own here. I just can't reproduce your problem on my test install. Everything works as it should, tested, retested, retested.... I have really put in a lot of effort here to solve this. It is unfortunate that for some reason you cannot make it work on your install. But it is as I said, and also stated by Mark, random ordering and pagination was never meant to be – Pieter Goosen Dec 16 '14 at 7:49
0

In a random query you will get duplicates between two different draws. Since each draw is independently random from the other, there is no much meaning to paging.

If you set the random seed to constant then it is not random any more and you get paging working. Storing the seed in a cookie means that there is randomness for different users but not for the same user after his first page view. You might want to have a shorter expiry time for the cookie but then you will run again at the risk of having duplicate.

..... and once the site is live you put some caching plugin, lets say W3TC and there is randomness only once an hour (based on your cache settings).

I don't see a solution to your randomness+paging problem, you will have to relax one of them. One possibility is to keep the seed in a transient and change it every minute, you will get duplicates but might be less obvious.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.