サポート » 使い方全般 » 記事一覧のソートをpre_get_postsで出来るようにしたい

  • こんにちは

    記事一覧ページで、以下のコードでソートを行っています。

    <?php $uri = home_url( '/' ); ?>
        <?php if( is_category() or is_tag() or is_tax() ) : ?>
          <?php $term = get_queried_object(); ?>
          <?php if ( $term ) : ?>
            <?php $uri = get_term_link( $term , $term->taxonomy ); ?>
          <?php endif; ?>
        <?php endif; ?>
    	<?php echo $uri; ?>
    
        <div class="sort">
        <select name="original-sort-dropdown" onchange='document.location.href=this.options[this.selectedIndex].value;'>
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'date' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'date' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>日付の新しい順</option>
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'date' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'date' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>日付の古い順</option>  
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'title' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'title' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>タイトル順(あ~わ・A~Z)</option>
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'title' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'title' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>タイトル順(わ~あ・Z~A)</option>  
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'ratings_average' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'ratings_average' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>評価の高い順(平均)</option>
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'ratings_average' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'ratings_average' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>評価の低い順(平均)</option>
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'ratings_score' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'ratings_score' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>評価の高い順(総合)</option>
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'ratings_score' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'ratings_score' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>評価の低い順(総合)</option>  
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'ratings_users' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'ratings_users' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>評価数の多い順</option>
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'ratings_users' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'ratings_users' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>評価数の少ない順</option>
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'comment_count' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'comment_count' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>コメント数の多い順</option>
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'comment_count' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'comment_count' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>コメント数の少ない順</option>
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'views' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'views' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>閲覧数の多い順</option>
    
          <?php $Selected = ''; if( !empty( $_GET["meta_key"] ) && !empty( $_GET["order"] ) ) : if( $_GET["meta_key"] == 'views' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'meta_key' => 'views' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>閲覧数の少ない順</option>
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'author' && $_GET["order"] == 'ASC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'author' , 'order' => 'ASC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>投稿者順(A~Z・あ~わ)</option>
    
          <?php $Selected = ''; if( !empty( $_GET["orderby"] ) && !empty( $_GET["order"] ) ) : if( $_GET["orderby"] == 'author' && $_GET["order"] == 'DESC' ) : $Selected = 'selected="selected"'; endif; endif; ?>
          <option value="<?php echo add_query_arg( array( 'orderby' => 'author' , 'order' => 'DESC' , "s" => get_query_var('s') ), $uri ); ?>" <?php echo $Selected ?>>投稿者順(わ~あ・Z~A)</option>  
    
        </select>
            </div>   
    
        <?php
        // 何の指定もないときのデフォルトのソート順
    	$paged = get_query_var( 'paged' );
    	if( empty( $paged ) ) {
    		$paged = 0;
    	}
        $args = array( 'posts_per_page' => get_option('posts_per_page') , 'orderby' => 'date' , 'order' => 'DESC' , 'paged' => $paged );
    
        if( is_category() ) {
          $args["cat"] = get_query_var( "cat" );
        } elseif( is_tag() ) {
          $args["tag"] = get_query_var( "tag" );
        }
        $taxonomy = get_query_var( "taxonomy" );
        if( !empty( $taxonomy ) ) {
          $args[$taxonomy] = get_query_var( "term" );
        }
        $args["s"] = get_query_var( "s" );
    
        if( !empty( $_GET["meta_key"] ) ) {
          $args["meta_key"] = strip_tags( $_GET["meta_key"] );
          $args["orderby"] = 'meta_value_num';
          } elseif( !empty( $_GET["orderby"] ) ) {
          $args["orderby"] = strip_tags( $_GET["orderby"] );
          unset( $args["meta_key"] );
    
        }
    
        if( !empty( $_GET["order"] ) ) {
          $args["order"] = strip_tags( $_GET["order"] );
        }
        ?>
    
        <?php query_posts( $args ); ?>
    	<pre><?php print_r($args); ?></pre>
    
    	<section id="primary" class="site-content">
    		<div id="content" role="main">
    
    		<?php if ( have_posts() ) : ?>
    
    			<header class="page-header">
    				<h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'twentytwelve' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
    			</header>
    
    			<?php twentytwelve_content_nav( 'nav-above' ); ?>
    
    			<?php /* Start the Loop */ ?>
    			<?php while ( have_posts() ) : the_post(); ?>
    				<?php get_template_part( 'content', get_post_format() ); ?>
    			<?php endwhile; ?>
    
    			<?php twentytwelve_content_nav( 'nav-below' ); ?>
    
    		<?php else : ?>
    
    			<article id="post-0" class="post no-results not-found">
    				<header class="entry-header">
    					<h1 class="entry-title"><?php _e( 'Nothing Found', 'twentytwelve' ); ?></h1>
    				</header>
    
    				<div class="entry-content">
    					<p><?php _e( 'Sorry, but nothing matched your search criteria. Please try again with some different keywords.', 'twentytwelve' ); ?></p>
    					<?php get_search_form(); ?>
    				</div><!-- .entry-content -->
    			</article><!-- #post-0 -->
    
    		<?php endif; ?>
    
    		</div><!-- #content -->
    	</section><!-- #primary -->
    
    <?php get_sidebar(); ?>
    <?php get_footer(); ?>

    大変使いやすく、重宝しています。

    調べていてわかったのですが、
    最近はquery_postsではなく、pre_get_postsが推奨されている
    ということでした。

    そこで、自分でいろいろと調べたのですが、
    推奨と非推奨の話が多く、具体的にどのようにすればいいのかが
    分かりませんでした。

    そこで、上に記載しましたコードを例にして、
    query_postsではなく、pre_get_postsの場合はどうなのか、
    具体的にするとどのようになるのか、ということを
    教えていただきたいと思い、今回トピックをたてました。

    迷惑かもしれないですが、分かる方、お願いします。

5件の返信を表示中 - 1 - 5件目 (全5件中)
  • gakuseiさん

    pre_get_posts については下記のブログ等を読めば多分、分かるのではないかと思います。

    query_postsではなく、pre_get_postsの場合はどうなのか、
    具体的にするとどのようになるのか

    gakuseiさんのコードの場合ですが、$argsquery_posts で指定する値を全て格納しているので、$args を定義している部分から query_posts までを、pre_get_posts に置き換える流れになると思います。

    <?php
    // 何の指定もないときのデフォルトのソート順
    $paged = get_query_var( ‘paged’ );
    if( empty( $paged ) ) {
    $paged = 0;
    }
    $args = array( ‘posts_per_page’ => get_option(‘posts_per_page’) , ‘orderby’ => ‘date’ , ‘order’ => ‘DESC’ , ‘paged’ => $paged );

    if( is_category() ) {
    $args[“cat”] = get_query_var( “cat” );
    } elseif( is_tag() ) {
    $args[“tag”] = get_query_var( “tag” );
    }
    $taxonomy = get_query_var( “taxonomy” );
    if( !empty( $taxonomy ) ) {
    $args[$taxonomy] = get_query_var( “term” );
    }
    $args[“s”] = get_query_var( “s” );

    if( !empty( $_GET[“meta_key”] ) ) {
    $args[“meta_key”] = strip_tags( $_GET[“meta_key”] );
    $args[“orderby”] = ‘meta_value_num’;
    } elseif( !empty( $_GET[“orderby”] ) ) {
    $args[“orderby”] = strip_tags( $_GET[“orderby”] );
    unset( $args[“meta_key”] );

    }

    if( !empty( $_GET[“order”] ) ) {
    $args[“order”] = strip_tags( $_GET[“order”] );
    }
    ?>

    <?php query_posts( $args ); ?>

    具体的にはこの部分です。
    query_postsでのコードを、直接テンプレートに記載していると思いますが、functions.php
    にpre_get_postsは記載してください。

    具体的な書き方ですが、例えばカテゴリ一覧の場合は、

    function sample_custom( $query ) {
    
    	if ( !$query->is_admin && $query->is_main_query() ) {
    
    		// 表示を変更したい一覧
    		if( $query->is_category ) {
    
    			// 分岐
    			if( $query->is_category ) {
    				$query->set( 'cat', get_query_var( "cat" ) );
    			}
    
    			if( !empty( $_GET["meta_key"] ) ) {
    				$query->set( 'meta_key' , strip_tags( $_GET["meta_key"] ) );
    				$query->set( 'orderby' , 'meta_value_num' );
    			} elseif( get_query_var( 'orderby' ) ) {
    				$query->set( 'orderby' , get_query_var( 'orderby' ) );
    			}
    
    			if( get_query_var( 's' ) ) {
    				$query->set( 's' , get_query_var( 's' ) );
    			}
    
    			if( get_query_var( 'order') ) {
    				$query->set( 'order' , get_query_var( 'order') );
    			}
    
    			if( get_query_var( 'paged') ) {
    				$query->set( 'paged' , get_query_var( 'paged') );
    			}
    
    			// 確認用
    			print_r($query);
    
    		}
    
    	}
    
    }
    add_action( 'pre_get_posts', 'sample_custom' );

    このようになるのではないかと思います。
    これで予定通りの動きをするなら、あとはタグ一覧や検索結果用に条件分岐等を追加していく流れになります。

    モデレーター Takuro Hishikawa

    (@hissy)

    コードを拝見しましたが、query_posts や pre_get_posts を使わなくても、functions.php に記述するのはこれだけで十分だと思います。あとはパラメーターで指定した通りの条件でWordPressがよろしくやってくれます。

    ▼ meta_keyをクエリーパラメーターに追加している

    function add_query_vars( $public_query_vars ) {
        $public_query_vars[] = 'meta_key';
        return $public_query_vars;
    }
    add_filter( 'query_vars', 'add_query_vars');

    フォーム部分のコードがちょっと読みにくかったので、こんな感じのコードをテーマに追加してテストしました。やってることはほぼ同じだと思います。

    <form action="<?php echo home_url(); ?>" method="get">
    <?php if(is_category()){
    	$cat_id = get_queried_object_id(); ?>
    	<input type="hidden" name="cat" value="<?php echo esc_attr($cat_id); ?>" />
    <?php } ?>
    <?php if(is_tag()){
    	$tag = get_query_var('tag'); ?>
    	<input type="hidden" name="tag" value="<?php echo esc_attr($tag); ?>" />
    <?php } ?>
    <?php if(is_search()){
    	$search = get_query_var('s'); ?>
    	<input type="hidden" name="s" value="<?php echo esc_attr($search); ?>" />
    <?php } ?>
    	<select name="orderby" onchange="submit(this.form)">
    		<option value="date" <?php selected(get_query_var('orderby'),'date'); ?>>日付</option>
    		<option value="title" <?php selected(get_query_var('orderby'),'title'); ?>>タイトル</option>
    		<option value="meta_value_num" <?php selected(get_query_var('orderby'),'meta_value_num'); ?>>カスタムフィールド</option>
    	</select>
    	<select name="meta_key" onchange="submit(this.form)">
    		<option value="">カスタムフィールド指定なし</option>
    		<option value="test_field_key" <?php selected(get_query_var('meta_key'),'test_field_key'); ?>>カスタムフィールド指定する</option>
    	</select>
    	<select name="order" onchange="submit(this.form)">
    		<option value="DESC" <?php selected(get_query_var('order'),'DESC'); ?>>降順</option>
    		<option value="ASC" <?php selected(get_query_var('order'),'ASC'); ?>>昇順</option>
    	</select>
    </form>

    hissy さん

    add_filter( ‘query_vars’, ‘add_query_vars’);

    こんなフィルターフックがあったんですね。
    とても参考になりました。ありがとうございます。

    モデレーター Takuro Hishikawa

    (@hissy)

    query_posts はメインクエリーを完全に上書きしてしまうため、冒頭に挙げられていたコードのように、$_GET["orderby"] などパラメーターの値を再取得して、再度条件分岐して、query_postsに突っ込むという作業が必要になり、ここが冗長で意図しない動作を引き起こしやすい、という問題があります。query_postsを使わなければ、ほとんど書く必要のないコードを書かないといけない。

    ただし、query_postsを使わないためにはフィルターフックを使いこなす必要があり、WP_Queryのコードをある程度理解しないといけません。なので、デメリットを理解した上であればquery_postsを使っても良いと思います。非推奨になる?という記事を書いた本人ですが、その後Codexの表現も改められ「query_posts以外の手段を使うことを強く推奨する」と変わっています。

    hissyさん

    hissyさんがこちらのトピックでおっしゃっていた

    要は、URLにパラメーターを正しく渡せば、WordPressはソートして表示してくれる機能を標準で持っていますので。

    こちらは理解していましたが、public_query_varsを拡張できる事までは理解していませんでした。
    meta_keyを指定する為にquery_postsでのコードをgakuseiさんに提供し、その後pre_get_postsの存在を知り、gakuseiさんに今後はpre_get_postsでの処理にしたほうがいいいと思います。
    とご説明していました。

    おかげでCodex Custom_Queriesの参考も見つける事ができました。
    丁寧なご説明ありがとうございます。

    gakuseiさん

    WP_Queryのコードをある程度理解しないといけません。

    こちら次第ですが、私もhissyさんのコードのほうがシンプルでわかりやすいと思います。

    ドロップダウンメニューについては微妙な所が違うのでどちらを利用されるかは分かりませんが、もし私が書いたドロップダウンメニューのコードを使用する場合は、ドロップダウンメニューのURL部分にorderbyにmeta_value_numを追加されるようにすると、動作すると思います。
    例えば
    http://example.com/?meta_key=ratings_average&order=asc
    こうなるようにです。
    http://example.com/?meta_key=ratings_average&order=asc&orderby=meta_value_num

5件の返信を表示中 - 1 - 5件目 (全5件中)
  • トピック「記事一覧のソートをpre_get_postsで出来るようにしたい」には新たに返信することはできません。