web-dev-qa-db-ja.com

オプションのメタキーで注文する?

私はカスタム投稿タイプの並べ替え機能を構築しています、そして私は "Featured"投稿のカスタムメタ値を持っています。この値はチェックボックスをチェックすると設定され、そうでなければ設定されません。

デフォルトのorderby=meta_valuemeta_key=featuredと一緒に使用すると、メタキーを持つ投稿のみが画面に表示されます。そうでなければ、彼らも現れません。

設定されていない場合は表示されますが、最後に表示されます。代わりにmeta_queryを使用する必要があると思いますが、それを機能させることもできませんでした。

WP_Query引数で空、偽、または存在しないメタキーを許可するにはどうすればよいですか。

私のコードは以下の通りです。これはダッシュボードで列をソートするためのものであるため、デフォルトのWP Query argsを変更しています。

function featured_sortable_order( $vars ) {
  if ( isset($vars['orderby']) && $vars['orderby'] == 'featured' ) {

    $vars = array_merge( $vars, array(
      'meta_key' => 'featured',
      'orderby' => 'meta_value',
      'order'     => isset($vars['order']) ? $vars['order'] : 'asc',
    ) );

  }
  return $vars;
}
add_filter( 'request', 'featured_sortable_order' );
6
Radley Sustaire

最初の公開後に完全に編集された

問題は、メタ値を注文するためには、WordPressがクエリ内の'meta_key'を何かに設定する必要があることです。 'meta_key'を何かに設定すると、WordPressは次のように追加します。

AND ( wp_postmeta.meta_key = 'the_meta_key' )

WHERE SQL句へ。そして何かのような

INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )

join節へ。そのため、queryはそのメタクエリを持つ投稿のみを返します。

バックエンドで作業していて、コラムを表示するために投稿ごとにget_post_meta( $postid, 'featured', true)を呼び出しても、get meta functionのWordPressキャッシュのおかげで2回呼び出すことはパフォーマンス上の大きな問題ではありません。

そのため、(メタキーにフィルタを追加せずに)すべての投稿を取得してから、'posts_results'フックを使用して投稿をフィルタリングし、「注目の」メタキーを見て投稿を注文するという考えです。

使用した直後にフィルタを削除します。

add_filter( 'posts_results', 'order_by_featured', PHP_INT_MAX, 2 );

function order_by_featured ( $posts, $query ) {
  // run only on admin, on main query and only if 'orderby' is featured
  if ( is_admin() && $query->is_main_query() && $query->get('orderby') === 'featured' ) {
    // run once
    remove_filter( current_filter(), __FUNCTION__, PHP_INT_MAX, 2 );
    $nonfeatured = array();
    $featured = array();
    foreach ( $posts as $post ) {
      if ( get_post_meta( $post->ID, 'featured', TRUE ) ) {
        $featured[] = $post;
      } else {
        $nonfeatured[] = $post;
      }
    }
    $order = strtoupper( $query->get('order') ) === 'ASC' ? 'DESC' : 'ASC';
    // if order is ASC put featured at top, otherwise put featured at bottm
    $posts = ( $order === 'ASC' )
      ? array_merge( $nonfeatured, $featured )
      : array_merge( $featured, $nonfeatured );
  }
  return $posts;
}

さらに、クエリに順序が設定されていない場合にデフォルトの順序として'pre_get_post'を使用するように、'ASC'にフィルタを追加します。

add_action( 'pre_get_posts', function( $query ) {
  // if no order is set set order to ASC
  if (
    is_admin() && $query->is_main_query()
    && $query->get('orderby') === 'featured' 
    && $query->get('order') === ''
  ) {
    $query->set( 'order', 'ASC' );
  }
});
6
gmazzap