web-dev-qa-db-ja.com

明示的に定義された順序でget_posts()の結果を返す方法

私は明示的に順序付けられた投稿のループを作成しようとしています、例えば:

<?php $args = array(
    'include'         => '1,3,8,4,12' ); ?>

<?php get_posts( $args ); ?> 

結果はデフォルトで日付順に並べられており、投稿を入力された順序で返すorderbyオプションはありません。これに関してTracでは複数のバグ/機能要求が投稿されていますが、これまでのところ運が悪いです。私は、コアファイルを少しあちこちに見回していますが、どこにも持っていません。

誰かがこの動作に対する回避策を提案できますか?

乾杯、ダルトン

5
Dalton

さて、私はこれを行う方法を見つけることを決心していた、そして私はそれを持っていると思う。もっと簡単な解決策を見つけて、新しいWP_Queryオブジェクトを使わないようにしたいと思っていましたが、それはループがどのように機能するかに深く関わっています。まず、ユーティリティ関数がいくつかあります。

// Set post menu order based on our list  
function set_include_order(&$query, $list) {
    // Map post ID to its order in the list:
    $map = array_flip($list);

    // Set menu_order according to the list     
    foreach ($query->posts as &$post) {
      if (isset($map[$post->ID])) {
        $post->menu_order = $map[$post->ID];
      }
    }  
}

// Sort posts by $post->menu_order.                                 
function menu_order_sort($a, $b) {
  if ($a->menu_order == $b->menu_order) {
    return 0;
  }
  return ($a->menu_order < $b->menu_order) ? -1 : 1;
}

これらは、私たち自身のリストに基づいてmenu_orderプロパティを設定し、それに基づいてクエリオブジェクトの投稿をソートすることを可能にします。

これが、投稿をクエリして並べ替える方法です。

$plist = array(21, 43, 8, 44, 12);
$args = array(
  'post_type' => 'attachment',
  'post_status' => 'any',
  'post__in' => $plist 
);

// Create a new query  
$myquery = new WP_Query($args);

// set the menu_order
set_include_order($myquery, $plist);

// and actually sort the posts in our query
usort($myquery->posts, 'menu_order_sort');

それで今、私たちは私たち自身のクエリオブジェクトを持っています、そして$myquery->postsは私たちのカスタムmenu_order_sort関数に従ってソートされます。唯一のトリッキーな部分は、カスタムクエリーオブジェクトを使ってループを構築しなければならないということです。

while($myquery->have_posts()) : $myquery->the_post();
  ?>
    <div><a id="post_id_<?php the_ID(); ?>" class="nb" href="<?php the_permalink(); ?>"><?php the_title(); ?></a> Post ID: <?php the_ID(); ?>
    </div>
  <?php

endwhile;
wp_reset_postdata();

明らかに、あなたはそこでループテンプレートコードを修正するでしょう。

おそらくquery_posts()を使用し、グローバル$wp_querypostsプロパティを置き換えることで、カスタムクエリオブジェクトを使用する必要がない解決策を見つけたいと思っていましたが、うまく動作させることができませんでした。もう少し時間をかけて作業をすれば、それは実行可能だったのかもしれません。

とにかく、それがあなたが行く必要があるところにあなたを導いてくれるかどうか見て?

6
Dougal Campbell

これを試すことができます:

add_filter('posts_orderby', 'enforce_specific_order');
$posts = get_posts($args);
remove_filter( current_filter(), __FUNCTION__ );

function enforce_specific_order($orderby) {
    global $wpdb;
    return "FIND_IN_SET(".$wpdb->posts.".ID, '1,3,8,4,12') ASC";
}
10
wyrfel

これがget_postsの結果を定義された順序で返す最も速い方法だと思います。それ以外にも、ハッキングのないネイティブソリューションです。

<?php

$posts_order = array('1,3,8,4,12');
$args = array(
    'post__in' => $posts_order,
    'orderby' => 'post__in'
); 
get_posts( $args ); 

?> 
6

WordPress 3.5以降、この機能はコアになりました。 "post__in"パラメータを使用して投稿を明示的に注文できます。 http://core.trac.wordpress.org/ticket/13729

3
Dalton

フィルタでorderbyをクリアするだけではどうですか?投稿をクエリする直前に、次のように入力してください。

add_filter('posts_orderby', '__return_false');

それでは、ループが終わったら:

remove_filter('posts_orderby', '__return_false');

フィルタを再度削除する理由は、通常の明示的な順序付けが必要になるページ上に他のループ(ウィジェットなどから)がある場合です。

0
Dougal Campbell