前提
wordpressを使って、クックパッドのようなサービスを作っています。
具体的には
・ユーザー登録
・ログイン、ログアウト
・レシピの投稿
・いいね、お気に入り機能
・検索機能
などを実装したクックパッドのクローンです。
webサービスの簡単な仕組み
プラグイン「user frontend」を使い、管理画面外から投稿が可能です。
投稿する項目が必須事項含め複数存在するので投稿には必然的にカスタムフィールドが存在します。
レシピを投稿すると、
カスタムフィールド『article』に、それぞれ
『レシピ名(recipe_name)』
『材料(material)』
『作り方(how_to_make)』
『コツ・注意点(notice_and_teck)』
『きっかけ(trigger)』
のカスタムフィールドに値が入る仕組みです。
検索を行うと、**『レシピ名』『材料』『作り方』**からキーワードが存在する投稿をloop式で表示します。ちなみに投稿順です。
しかし、『レシピ名』にキーワードがない投稿が上にきてしまうため少し見づらくなっています。
実現したいこと
「検索結果を、
カスタム投稿タイプ『article』の
カスタムフィールド『レシピ名(recipe_name)』に
『検索したキーワードが存在する投稿が上』になるように
並べ替えたい。
その上で、カスタムフィールド『レシピ名』『材料』『作り方』でキーワードに該当する投稿も表示したい」
例えば、
「『レシピ名』にキーワードが存在する投稿 今日」
「『レシピ名』にキーワードが存在しない投稿 今日」
「『レシピ名』にキーワードが存在する投稿 昨日」
「『レシピ名』にキーワードが存在しない投稿 昨日」
…
のような感じです。
コード
検索結果画面のコードです。
search.php
php
1 <div class="container"> 2 <p>「<?php the_search_query(); ?>」の検索結果</p> 3 <div class="flexer"> 4 <ul class="panel recipe_list"> 5 <?php 6 $args_ct = array( 7 'post_type' => 'article', 8 'post_status' => 'publish', 9 'posts_per_page' => 6, 10 ); 11 $the_query_ct = new WP_Query($args_ct); 12 13 ?> 14 <?php if($the_query_ct->have_posts()): ?> 15 --- 略 --- 16 <?php while($the_query_ct->have_posts()): $the_query_ct->the_post();?> 17 <?php get_template_part('template-parts/loop','article') ?> 18 <?php endwhile; ?> 19 <?php else: ?> 20 <p>検索結果がありません</p> 21 <?php endif; ?> 22 </ul> 23 24 </div><!-- .flexer --> 25 </div><!-- .container --> 26
functions.phpの以下コードを使い、「検索対象をカスタム投稿タイプ『article』のカスタムフィールド『recipe_name』『material』『how_to_make』に限定する」処理をしています。
functions.php
php
1 /* search.phpで検索する範囲を「特定のカスタムフィールド」に限定する */ 2 function custom_search($search, $wp_query) { 3 global $wpdb; 4 5 if (!$wp_query->is_search) return $search; 6 if (!isset($wp_query->query_vars)) return $search; 7 8 $search_words = explode(' ', isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : ''); 9 if ( count($search_words) > 0 ) { 10 $search = ''; 11 $search .= "AND post_type = 'article'"; 12 foreach ( $search_words as $word ) { 13 if ( !empty($word) ) { 14 $search_word = '%'.esc_sql( $word ).'%'; 15 $search .= " AND ( 16 {$wpdb->posts}.post_content LIKE '{$search_word}' 17 OR {$wpdb->posts}.ID IN ( 18 SELECT distinct post_id 19 FROM {$wpdb->postmeta} 20 WHERE {$wpdb->postmeta}.meta_key IN ('recipe_name','material', 'how_to_make') AND meta_value LIKE '{$search_word}' 21 ) 22 ) "; 23 } 24 } 25 } 26 return $search; 27 } 28 add_filter('posts_search','custom_search', 10, 2); 29// https://kazunori-miura.tumblr.com/post/189502558056/wordpress%E3%81%AE%E6%A4%9C%E7%B4%A2%E5%AF%BE%E8%B1%A1%E3%82%92%E7%89%B9%E5%AE%9A%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AE%E5%80%A4%E3%81%AB%E9%99%90%E5%AE%9A%E3%81%99%E3%82%8B
このコードだけ見るなら、「$search .= 」からのSQLコードで「特定のカスタム投稿タイプ内のカスタムフィールド」を取得しているようです。
試したこと
調べてみると、「『本文(the_content)』に値がある投稿を優先して並べ替える」方法を見つけました。
このコードがヒントになると考えたのですが、応用ができないので挫折している最中です。
search.php?
php
1$the_query = new WP_Query( array( 2 'custom_orderby' => true, // <-追加 3) );
functions.php
php
1function my_posts_orderby( $orderby, $query ) { 2 global $wpdb; 3 if ( $query->get( 'custom_orderby' ) ) { 4 $orderby = "trim({$wpdb->posts}.post_content) = '' DESC, {$wpdb->posts}.post_date DESC"; 5 } 6 return $orderby; 7} 8add_filter( 'posts_orderby', 'my_posts_orderby', 10, 2 );
具体的には、「カスタム投稿タイプ『article』のカスタムフィールド『recipe_name』の投稿」が取り出せるような応用ができていない状態です。
お時間をいただき、ありがとうございます。
補足情報(FW/ツールのバージョンなど)
ブラウザ:chrome(最新のバージョン)
テキストエディタ:atom(ver:1.32.2)
あなたの回答
tips
プレビュー