最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

custom post types - Combining sorted and random CPT

programmeradmin1浏览0评论

I have two Custom Post Types and would like to display one of them sorted (by title) and the other one at random places in the same query.

So CPT A (sorted) en CPT B (random):

A1 A2 A3 B2 A4 A5 B5 A6 A7 A8 A9 B1 ...
or
A1 B1 A2 A3 B5 A4 A5 A6 A7 A8 A9 B7 ...
or
B4 A1 A2 A3 A4 B3 A5 A6 A7 A8 B1 A9 ...

I tried merging the two CPT but that didn't work as expected.

$projectposts = get_posts(array(
 'posts_per_page' => -1,
 'post_type'      => 'project',
 'order'          => 'ASC'
));
        
//second query
$storieposts = get_posts(array(
 'posts_per_page' => -1,
 'post_type'      => 'storie',
 'order'          => 'rand'
));
        
$mergedposts = array_merge( $projectposts, $storieposts ); //combined querie

@kero:
I have this ↓ and it's almost working... It looks like this creates some empty entries in the array. (I'm 100% certain that there are no empty titles before merging.)
The query results in A3 A2 A4 A6 B2 (empty) (empty) (empty) A1 (empty) (empty) B1 B3 ...

   $projectposts = get_posts([
     'posts_per_page' => -1,
     'post_type'      => 'project',
     'order'          => 'ASC',
     'meta_query'     => array(
        array(
          'key'     => 'featured',
          'value'   => '"homepagina"',
          'compare' => 'LIKE'
        )
      )
   ]);
   
   $storieposts = get_posts([
       'posts_per_page' => -1,
       'post_type'      => 'story',
       'order'          => 'ASC',// not rand!
       'meta_query'     => array(
          array(
            'key'     => 'featured',
            'value'   => '"homepagina"',
            'compare' => 'LIKE'
          )
        )
   ]);
   
   function array_random_merge(array $a, array $b): array {
       while (count($b) > 0) {
           shuffle($b);
           // get one entry of $b
           $item = array_shift($b);
           // find random position inside $a
           $pos = mt_rand(0, count($a) - 1);
           // insert $item into $a
           array_splice($a, $pos, 0, $item);
       }
       return $a;
   }
   
   $mergedposts = array_random_merge($projectposts, $storieposts);
   
    if( $mergedposts ) {
      foreach( $mergedposts as $post ) { 
        
        echo '<h3>';
        echo the_title();
        echo '</h3>';
        
      }
    }
    wp_reset_postdata(); 
    

I have two Custom Post Types and would like to display one of them sorted (by title) and the other one at random places in the same query.

So CPT A (sorted) en CPT B (random):

A1 A2 A3 B2 A4 A5 B5 A6 A7 A8 A9 B1 ...
or
A1 B1 A2 A3 B5 A4 A5 A6 A7 A8 A9 B7 ...
or
B4 A1 A2 A3 A4 B3 A5 A6 A7 A8 B1 A9 ...

I tried merging the two CPT but that didn't work as expected.

$projectposts = get_posts(array(
 'posts_per_page' => -1,
 'post_type'      => 'project',
 'order'          => 'ASC'
));
        
//second query
$storieposts = get_posts(array(
 'posts_per_page' => -1,
 'post_type'      => 'storie',
 'order'          => 'rand'
));
        
$mergedposts = array_merge( $projectposts, $storieposts ); //combined querie

@kero:
I have this ↓ and it's almost working... It looks like this creates some empty entries in the array. (I'm 100% certain that there are no empty titles before merging.)
The query results in A3 A2 A4 A6 B2 (empty) (empty) (empty) A1 (empty) (empty) B1 B3 ...

   $projectposts = get_posts([
     'posts_per_page' => -1,
     'post_type'      => 'project',
     'order'          => 'ASC',
     'meta_query'     => array(
        array(
          'key'     => 'featured',
          'value'   => '"homepagina"',
          'compare' => 'LIKE'
        )
      )
   ]);
   
   $storieposts = get_posts([
       'posts_per_page' => -1,
       'post_type'      => 'story',
       'order'          => 'ASC',// not rand!
       'meta_query'     => array(
          array(
            'key'     => 'featured',
            'value'   => '"homepagina"',
            'compare' => 'LIKE'
          )
        )
   ]);
   
   function array_random_merge(array $a, array $b): array {
       while (count($b) > 0) {
           shuffle($b);
           // get one entry of $b
           $item = array_shift($b);
           // find random position inside $a
           $pos = mt_rand(0, count($a) - 1);
           // insert $item into $a
           array_splice($a, $pos, 0, $item);
       }
       return $a;
   }
   
   $mergedposts = array_random_merge($projectposts, $storieposts);
   
    if( $mergedposts ) {
      foreach( $mergedposts as $post ) { 
        
        echo '<h3>';
        echo the_title();
        echo '</h3>';
        
      }
    }
    wp_reset_postdata(); 
    
Share Improve this question edited Jan 13, 2021 at 19:36 zuperuser asked Jan 13, 2021 at 11:43 zuperuserzuperuser 111 silver badge3 bronze badges 6
  • 1 Just a note that using the rand order is extremely heavy/slow/expensive, always do the random part in PHP where possible, as a random order can involve a full table copy into a temporary table that gets shuffled randomly, queried, then destroyed. It would be significantly faster to fetch all stories and randomly sort them after the get_posts call – Tom J Nowell Commented Jan 13, 2021 at 12:28
  • In your example, is the following also fine B1 B2 B3 A1 A2 .. / A1 A2 B1 B2 A3 A4 B3 ..? If not, what are your other additional rules for the distribution of B? – kero Commented Jan 13, 2021 at 14:38
  • B1 B2 B3 A1 A2 .. / A1 A2 B1 B2 A3 A4 B3... is fine too, but B should –preferably– be 'inserted' randomly. – zuperuser Commented Jan 13, 2021 at 16:13
  • @kero I have updated my question (see above). The random placement and shuffle of 'B' is working correct, but it creates empty spaces (<h3></h3> in my case). – zuperuser Commented Jan 14, 2021 at 8:09
  • @zuperuser Thanks for editing it into your question! I cannot reproduce your problem - so I'm still thinking there might be some problem with the WP methods in there. Can you create a fiddle somewhere (e.g. the site I used) that shows the problem? – kero Commented Jan 14, 2021 at 9:54
 |  Show 1 more comment

2 Answers 2

Reset to default 1

Try to get two different arrays of posts and loop through array A. Before get post data of A element get random element from array B.

For example:

$array_a = ['post_id_a1', 'post_id_a2', 'post_id_a3'];
$array_b = ['post_id_b1', 'post_id_b2', 'post_id_b3'];

foreach ( $array_a as $a_post_id ) {
    $is_b_should_displayed = mt_rand( 0, 1 );

    if ( $is_b_should_displayed && $b_length = count( $array_b ) ){
        $b_to_show = mt_rand( 0, $b_length - 1 );

        // show random B post

        unset( $array_b[ $b_to_show ] );
        $array_b = array_values( $array_b ); // to reorder array after unset
    }

    // show A post
}

Or in same way create array C, and then loop through C to display posts. There is no warranty all B will displayed, so, if you need it, you could loop through B (if at least 1 element exist) after main A loop

Small note: rand using for key orderby not to order according to wp docs.

Hope it helps

I would probably do it like this:

$projects = get_posts([
    'posts_per_page' => -1,
    'post_type'      => 'project',
    'order'          => 'ASC',
]);

$stories = get_posts([
    'posts_per_page' => -1,
    'post_type'      => 'storie',
    'order'          => 'ASC',// not rand!
]);

function array_random_merge(array $a, array $b): array {
    while (count($b) > 0) {
        shuffle($b);
        // get one entry of $b
        $item = array_shift($b);

        // find random position inside $a
        $pos = mt_rand(0, count($a) - 1);
        // insert $item into $a
        array_splice($a, $pos, 0, $item);
    }
    return $a;
}

$merged = array_random_merge($projects, $stories);

The main idea here is the following:

  1. remove one $item from $b
  2. insert that at a random position in $a
  3. repeat 1 & 2 until $b is empty.

Per Tom's comment I removed rand order in the query and simple shuffle() the array.

发布评论

评论列表(0)

  1. 暂无评论