Nirmal Ram
Nirmal Ram

Reputation: 1732

Wordpress order posts by post type

I am trying to create a system which fetches post from 2 post types and i want to display the posts order by their post type. I am trying to first show the posts from one post type and then another post type but the query i used mixes it all. Can any one suggest a good solution for this. Here is my code.

    $paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
 $args = array(

     'post_type' => array('review','directory'),
     'orderby' => 'name',
     'order' => 'ASC',
     'posts_per_page'  => '4',
     'paged'          => $paged ,
     'tax_query' => array( array(
        'taxonomy' => 'Reviews',
        'field' => 'id',
        'terms' => $cat_id
    ), ),
     );

 query_posts($args);
        if (have_posts()) :
       while (have_posts()) : the_post();
      $product_terms = wp_get_post_terms(get_the_ID(), 'Reviews', array("fields" => "all", "order" => "DESC"));
      $postype=get_post_type( get_the_ID() );
      if($postype=='review')
      {
     ?>   

        <div class="review-post">
          <a href="http://<?php the_permalink(); ?>" target="_blank"><h3><?php the_title(); ?></h3></a>
          <div class="review-cat-new">
            <?php echo get_the_term_list( $post->ID, 'Reviews', 'Category: ', ', ', '' ); ?>
          </div>

          <?php
          if(get_field('see_it'))
              $seeit_text= get_field('see_it');
         if(get_field('skip_it'))
              $skipit_text= get_field('skip_it');
         ?>
          <div class="see-skip">
            <p class="see-it"><span>See it:</span>
                <?php echo $seeit_text; ?>
            </p>
            <p class="skip-it"><span>Skip it:</span>
                <?php echo $skipit_text;  ?>
            </p>
          </div>
          <?php echo custom_field_excerpt(); ?>
        </div>
          <?php }
          else
          {
              ?>
                <div class="review-post">
          <a href="h<?php the_permalink(); ?>" target="_blank"><h3><?php the_title(); ?></h3></a>
          <div class="review-cat-new">
            <?php echo get_the_term_list( get_the_ID(), 'Reviews', 'Category: ', ', ', '' ); ?>
          </div>


          <?php echo the_field('enter_content_direc'); ?>
          <?php
          if(get_field('enter_textdirec'))
              $text= get_field('enter_textdirec');
         if(get_field('enter_linkdirec'))
              $textlink= get_field('enter_linkdirec');
         ?>
          <div class="see-skip">
            <p class="see-it direc"><span><a  target="_blank" style="color:#5D6D71; text-transform: lowercase;" href="<?php echo $textlink;?>"><?php echo $textlink;?>  </a></span>

            </p>
          </div>
        </div>
          <?php }
          endwhile;
                  echo '<div class="paging">';
                 wp_pagenavi();
                 echo '</div>';
                endif;

So is there a way so that i can first show the posts form reviews and then directory?

Upvotes: 4

Views: 20834

Answers (5)

rafa226
rafa226

Reputation: 546

As seen in the docs https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters , you can use the regular wp query by passing an array to 'orderby' :

$wp_query = new WP_Query(
  array(
      's' => $search,
      'orderby'=> array('type'=>'DESC', 'title'=>'ASC'),
      'paged'=>$paged
  )
);
if ( $wp_query->have_posts() ) {
    while ( $wp_query->have_posts() ) {
        $wp_query->the_post();
        // do your loop stufff here
    }
}

Upvotes: 5

Musi
Musi

Reputation: 41

Since Wordpress 4.0 you can just pass the option type (post_type) to the orderby parameter in the WP_Query object.

orderby (string | array) - Sort retrieved posts by parameter. To order by post type just pass:

  • 'type' - Order by post type (available since Version 4.0). ('post_type' is also accepted.)

Upvotes: 4

Bobz
Bobz

Reputation: 2399

Order per post types with custom post type order:

add_filter('pre_get_posts', function ($query) {

    if ($query->is_search && !is_admin()) :
        $query->set('post_type', [ 'cpt-1', 'cpt-2', 'post', 'cpt-3']);
    endif;

    return $query;
});



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

    if ( ! is_admin() ) :

        if ( is_search() && is_main_query() ) :

            global $wpdb;
            $order = "FIELD( post_type, 'cpt-1', 'cpt-2', 'post' ), {$wpdb->posts}.post_modified DESC";      
        endif;

    // Disable this filter for future queries!
    remove_filter( current_filter(), __FUNCTION__);
    endif;

    return $order;
});

Upvotes: 2

Nirmal Ram
Nirmal Ram

Reputation: 1732

Finally i got the solution and it can be done using a filter.

The solution looks like this.

add_filter( 'posts_request' , 'modify_request' );
function modify_request( $query) {
    global $wpdb;
    if(strstr($query,"post_type IN ('review', 'directory')")){
        $where = str_replace("ORDER BY {$wpdb->posts}.post_date","ORDER BY {$wpdb->posts}.post_type",$query);
    }
    return $where;
}

Upvotes: 3

Karol
Karol

Reputation: 8053

First solution which comes to my mind is to get posts only for first category. Reset query (wp_reset_query()) and get them again for second category. You need to double up your code of course, but I don't see any other solution - it's WordPress - you're very limited.

Second solution is to query database directly like this:

$result = mysql_query('SELECT * 
FROM  `wp_posts` 
WHERE post_type =  "page"
OR post_type =  "post"
ORDER BY post_type ASC , post_date DESC ');

$posts = array();

if($result) {
    while ($row = mysql_fetch_assoc($result)) {
        $posts[] = $row;
    }
}

mysql_free_result($result);

echo('<pre>');
var_dump($posts);
echo('</pre>');
die();

Notice that I've used post and page types as these are default, and exist in my WP installation. But you can use different. You can play with this query as much as you want.

Upvotes: 0

Related Questions