WordPress.org

Ready to get started?Download WordPress

Forums

Generate repeatable random post ordering (4 posts)

  1. Parakoos
    Member
    Posted 1 year ago #

    Hello,

    I am the author of the Image Wall plugin. In short, it displays all images in a wordpress site on an infinitely scrollable page with each image linking back to its parent post or page.

    The Problem

    The images are batched so that the plugin doesn't try to load EVERY image in one go. New images are displayed as you scroll down, bringing in more and more batches of images.

    The images are also displayed in random order. This means that the random order of the images has to be 'remembered' across pagination requests to avoid duplicates.

    Current Solution

    I've solved this issue for now by generating a hash of the image ID (plus a time stamp) and attaching this hash as a meta data to each image, and then retrieving the images ordered by this hash.

    The code below is part of what gets run when the plugin is first activated, creating and attaching the hashes to all media files.

    $myposts = get_posts( array(
    	'post_type' 	=> 'attachment',
    	'nopaging' 	=> true,
    	'post_status' 	=> 'all',
    	'post_parent' 	=> null
    ) );
    
    $tmn_time = time();
    foreach( $myposts as $mypost ) {
    	update_post_meta($mypost->ID, 'tmn-iw-hash', md5($mypost->ID + $tmn_time));
    }

    And then I bring back the images using the following query:

    $iw_query = new WP_Query( array(
    	'post_type' 	 => 'attachment',
    	'post_mime_type' =>'image',
    	'posts_per_page' => $batch_size,
    	'nopaging' 	 => false,
    	'post_status' 	 => 'all',
    	'meta_key' 	 => 'tmn-iw-hash',
    	'orderby' 	 => 'meta_value',
    	'paged' 	 => $tmn_page
    ) );

    Problem with the current solution.

    The problem I have, and hope you might help me with, is that the task of bringing back every image in wordpress, loop over them, generating hashes and attaching them one by one is not very scalable. It takes time, and during this time, no images are displayed leaving the plugin users to think that it isn't working. I've also had reports of the process not finishing.

    I'm open to any creative idea that can help make this more efficient and scalable.

    I have two approaches, but not enough coding skill to figure them out myself.

    1. Execute the hashing in one fast and efficient SQL statement.

    If there was some SQL statement that could generate a new hash for every image and update the meta-data table without bringing all the images back and looping over them in PHP, that might be more scalable.

    Trouble is, I don't know SQL very well. I don't even know if this is feasable.

    2. Ditch the hash, bring back the images in a random order and save it for later retrieval.

    If I could use the query argument `orderby=rand' and somehow save the random order it generates so I can still use paging, that would be much better. Only, I don't know how this might be done.

    If you can figure this out, please let me know!

    Thank you for sticking with this overlong plea for help!

    Regards,
    Gustav

  2. bcworkz
    Member
    Posted 1 year ago #

    You should be able to get a repeatable but random ordering in mySQL by using the RAND() function with the same seed, and used as the ORDERBY argument. This is not the same as WP_Query's orderby=rand argument.

    So for the initial query, you would pick a quasi random seed value from mtimer or something and use it to RAND(seed) order the query, and saving the seed for later reuse. Future queries using the same seed should yield results in the same order as the first one.

    To use the SQL RAND() function with WP_Query, hook the "posts_orderby" filter. There are no WP_Query arguments that will implement it. All WP_Query queries go through this even if the query is not for posts. You could also use $wpdb methods instead.

  3. Parakoos
    Member
    Posted 1 year ago #

    Excellent! I got it working by implementing this walkthrough.

    While researching how to do it, I came across a lot of articles warning against using ORDER BY RAND() as it was very inefficient. Any reasons why this doesn't apply in this case? Is it worth keeping my existing solution (where the randomness is generated once instead of repeatedly) and fall back on this RAND(seed) solution only if the first has failed?

  4. bcworkz
    Member
    Posted 1 year ago #

    I think your case is exactly how it's inefficient. I believe SQL is essentially doing a variation of your hash sort. It's probably faster than the php implementation, so it's an improvement, though less than ideal.

    I probably haven't thought this through, but maybe you could consider this approach:

    Go ahead and query for all the images in the default order. The returned attachments are stored in the global object $wp_query. The array of attachments are available as $wp_query->posts.

    Apply the php shuffle() to the array. If any other queries occur while you need this randomized list, save it to your own global so it doesn't get overwritten.

    Serve up the first batch of images from the top of the array, working down through the array for each subsequent batch. You have an ordered list of all images to reference until the user reloads the page. I'm not sure how efficient shuffle() is, but I think it's better than your other options.

Topic Closed

This topic has been closed to new replies.

About this Topic