フロントエンド検索に、ユーザープロファイルと投稿とページを含める必要があります。
私はこの問題の解決策を探しましたが(ここではWSEとWebの両方で)、助けにならなければ見つかりませんでした。必要な限り、私が見つけた最も近いものは 検索結果に著者のプロフィールを含める と ユーザー検索を含めるためにWordPress検索を拡張する であり、どちらも合理的な答えがあります。
要件をより明確にするために、サイトには投稿、ページ、および(もちろん)ユーザーがいます。 end-userがfront-endで検索を実行する場合、タイトルまたはpost_contentに検索用語が含まれる投稿およびページを検索結果に含める必要があります(通常どおり)フロントエンド検索の場合)plus検索用語に一致するユーザーのプロファイル(ユーザーの意味については以下を参照matching検索語)。
重要なポイントは、私がnot特定のユーザーによってauthoredされた投稿の検索について話しているということです!
whyこの要件があることを理解するために、サイトの一部にすべてのユーザープロファイルがリストされ、end-userが任意の名前ユーザーのプロファイルを表示します。ユーザープロファイルには、さまざまなusermeta
name__が表示されます。 end-user'sの観点からは、フロントエンドでアクセスできるユーザープロファイルと投稿/ページに違いはありません。
特定のユーザーのユーザープロファイルに文字列 "foo"(つまり、そのユーザーに表示されるusermeta
name__の1つに "foo"が含まれている)が表示されているとします。 end-userが「foo」を検索すると、そのユーザーのプロファイルが検索結果に表示されることが期待されます。
以下は、私が思いついた解決策です。この解決策は機能しますが、これを達成するためのより良い/簡単な/壊れにくい方法が必要だと感じています:
user_register
にフックします。タイプ 'my_user_profile'の投稿を挿入し、値が新しく登録されたユーザーのIDであるpostmeta
name__(たとえば 'my_user_id')を追加しますthe_posts
にフックします。 is_search()
がtrueの場合、さまざまなusermeta
name__でend-user's検索の検索用語を検索するget_users()
を実行します。次に、postmeta
'my_user_id'でタイプ 'my_user_profile'の投稿に対してget_posts()
を実行し、get_users()
で見つかったユーザーIDを「IN」します。そして、元の検索で見つかった投稿と、myget_posts()
で見つかったタイプ「my_user_profile」の投稿のマージを返します。post_type_link
(get_permalink()
によって呼び出されます)にフックします。 $post->post_type
が 'my_user_profile'の場合、$post
の 'my_user_id' postmeta
name__にIDがあるユーザーにget_author_posts_url()
を返します。これは、テーマのsearch.php
に、上記の手順が検索結果を「拡張」した方法に関する特定の知識を持つコードを含める必要がないようにするためです。get_the_excerpt
にフックします。 $post->post_type
が 'my_user_profile'の場合、IDが$post
の 'my_user_id' usermeta
name__にあるユーザーの特定のpostmeta
name__(たとえば 'my_excerpt')の値を返します。これは、テーマのsearch.php
に、上記の手順が検索結果を「拡張」した方法に関する特定の知識を持つコードを含める必要がないようにするためです。[注:ステップ3のコードは、作業中のコードを転写(およびサニタイズ)するときに導入したバグを修正するために編集されています]
暫定ソリューションのコードは次のとおりです。
// step #1
add_action( 'init', 'wpse_register_post_type' );
function wpse_register_post_type() {
$args = array(
'public' => false,
'show_ui' => false,
'supports' => array(
'title',
'author',
),
);
register_post_type( 'my_user_profile', $args );
}
// step #2
add_action( 'user_register', 'wpse_add_user_profile_post' );
function wpse_add_user_profile_post( $my_user_id ) {
$user = get_user_by( 'ID', $my_user_id );
$args = array(
'post_type' => 'my_user_profile',
// so that I can find them easier when manually looking thru the wp_posts table
'post_title' => $user->display_name,
'post_status' => 'publish',
);
$post_id = wp_insert_post( $args );
if ( ! is_wp_error( $post_id ) ) {
update_post_meta( $post_id, 'my_user_id', $my_user_id );
}
return;
}
// step #3
add_filter( 'the_posts', array( $this, 'wpse_user_search' ), 10, 2 );
function wpse_user_search( $posts, $query ) {
if ( ! is_search() ) {
return $posts;
}
$search_terms = explode( ' ', $query->get( 's' ) );
$user_meta_keys = array( /* my usermeta keys */ );
$args = array(
'fields' => 'ID',
'meta_query' => array( 'relation' => 'OR' ),
);
// build the meta_query
foreach ( $user_meta_keys as $meta_key ) {
foreach ( $search_terms as $search_term ) {
$args['meta_query'][] = array(
'key' => $meta_key,
'value' => $search_term,
'compare' => 'LIKE',
);
}
}
$users = get_users( $args );
// get the my_user_profile posts associated with $users
$args = array(
'post_type' => 'my_user_profile',
'meta_query' => array(
array(
'key' => 'my_user_id',
'value' => $users,
'compare' => 'IN',
),
)
);
// make sure we don't call ourselves in the get_posts() below
remove_filter( 'the_posts', array( $this, 'user_search' ) );
$user_posts = get_posts( $args );
add_filter( 'the_posts', array( $this, 'user_search' ), 10, 2 );
$posts = array_merge( $posts, $user_posts );
return $posts;
}
// step 4
add_filter( 'post_type_link', array( $this, 'wpse_user_profile_permalink' ), 10, 2 );
function wpse_user_profile_permalink( $post_link, $post ) {
if ( 'my_user_profile' !== $post->post_type ) {
return $post_link;
}
// rely on WP_Post::__get() magic method to get the postmeta
return get_author_posts_url( $post->my_user_id );
}
// step 5
add_filter( 'get_the_excerpt', array( $this, 'wpse_user_profile_excerpt' ), 10, 2 );
function wpse_user_profile_excerpt( $excerpt, $post ) {
if ( 'my_user_profile' !== $post->post_type ) {
return $excerpt;
}
// rely on WP_Post::__get() magic method to get the postmeta
$user = get_user_by( 'ID', $post->my_user_id );
// rely on WP_User::__get() magic method to get the usermeta
return $user->my_excerpt;
}
私が言ったように、上記は機能しますが、私は考えもしなかったもっと簡単な方法があると思わずにはいられません。
私が考えた代替案の1つは、上記の解決策よりも複雑/脆弱に思われるため拒否されました。
personal_options_update
にフックします。ユーザー用に既に保存している各usermeta
name__について、それらをpostmeta
name__として、特定のユーザーに関連付けられたタイプ 'my_user_profile'の投稿に追加しますposts_join
およびposts_where
にフックして、ステップ#3で追加されたさまざまなpostmeta
name__を検索します誰もがよりシンプルな/壊れにくいソリューションを持っていますか?
私は解決策を使う準備ができていません。しかし、私はあなたがこの中にユーザの分野を持つように、あなたは問い合わせを強化するべきだと思います。以下の例は、それをさらに実証していると思います。
2つのフィルタフックが必要で、次のようにクエリの結果を取得します。
SELECT SQL_CALC_FOUND_ROWS wpbeta_posts.ID
FROM wpbeta_posts JOIN wpbeta_users
WHERE 1=1
AND (((wpbeta_posts.post_title LIKE '%search_string%')
OR (wpbeta_posts.post_excerpt LIKE '%search_string%')
OR (wpbeta_posts.post_content LIKE '%search_string%')))
AND wpbeta_posts.post_type IN ('post', 'page', 'attachment')
AND (wpbeta_posts.post_status = 'publish'
OR wpbeta_posts.post_status = 'private')
OR (wpbeta_users.display_name LIKE '%search_string%')
ORDER BY wpbeta_posts.post_title LIKE '%search_string%' DESC, wpbeta_posts.post_date DESC
LIMIT 0, 10
また、Debug ObjectsやQuery Monitorなどのプラグインを使って、このクエリをテスト上で簡単に読むこともできます。 sqlクエリは一例にすぎず、それを使用した結果ではありません。正しい結果を得るためには、それらを一緒にプレイして以下のフックを含める必要があります。このソースは、usersテーブルから1つのフィールドdisplay_name
を追加するための例にすぎません。多分SQL "オタク"が助けることができる。
// Enhance the JOIN clause of the WP Query with table users.
add_filter( 'posts_join', function( $join, $wp_query ) {
// No search string, exit.
if ( empty( $wp_query->query_vars['s'] ) ) {
return $join;
}
global $wpdb;
$join .= ' JOIN ' . $wpdb->users;
return $join;
}, 10, 2 );
// Enhance WHERE clause of the WP Query with user display name.
add_filter( 'posts_where', function( $where, $wp_query ) {
// No search, exit.
if ( ! is_search() ) {
return $where ;
}
global $wpdb;
$where .= ' OR (' . $wpdb->users . '.display_name LIKE \'%' . esc_sql( $wp_query->query_vars['s'] ) . '%\')';
return $where ;
}, 10, 2 );