J'ai besoin d'inclure des profils d'utilisateurs, ainsi que des publications et des pages, dans les recherches frontales.
J'ai cherché des solutions à ce problème (à la fois ici sur WSE et ailleurs sur le Web) et n'ai pas trouvé doit aider. Les plus proches que j'ai trouvés, dans la mesure de mes besoins, sont Inclure le profil de l'auteur dans les résultats de la recherche et Etendre la recherche WordPress à la recherche d'utilisateurs , qui n'ont pas de réponses raisonnables.
Pour être plus clair sur l'exigence: le site a des publications, des pages et (bien sûr) des utilisateurs. Lorsqu'un utilisateur final effectue une recherche sur le front-end, les résultats de la recherche doivent contenir des publications et des pages dont les titres ou post_content contiennent les termes de la recherche (comme il est normal pour les recherches frontales). plus les profils des utilisateurs qui correspond les termes de recherche (voir ci-dessous la signification d'un utilisateur correspondant les termes de recherche).
Le point important est que je pas parle de la recherche de messages qui ont été créés par un utilisateur donné!
Pour aider à comprendre pourquoi j'ai cette exigence, il peut être utile de savoir qu'une partie du site répertorie tous les profils d'utilisateur et qu'un utilisateur final peut cliquer sur le nom de n'importe quel utilisateur pour voir son profil. . Sur le profil utilisateur, plusieurs usermeta
name __ sont affichés. Du point de vue de l'utilisateur final, il n'y a pas de différence entre les profils utilisateur et les articles/pages auxquels ils peuvent accéder sur le front-end.
Supposons que le profil utilisateur d’un utilisateur donné affiche la chaîne "foo" (c’est-à-dire que l’un des usermeta
name __ affichés pour cet utilisateur contient "foo"). Lorsqu'un utilisateur final recherche "foo", il s'attend alors à ce que son profil apparaisse dans les résultats de la recherche.
Voici la solution que j'ai proposée. Cette solution fonctionne, mais j'estime qu'il doit exister un moyen meilleur, plus simple et moins fragile pour ce faire:
user_register
. insérez une publication de type 'mon_utilisateur_profil' et ajoutez un postmeta
(dites 'mon_utilisateur_id') dont la valeur est l'ID du nouvel utilisateur enregistréthe_posts
. Lorsque is_search()
est true, effectuez une get_users()
qui recherche dans usermeta
les termes recherchés dans la recherche end-user; faites ensuite un get_posts()
pour les posts de type 'mon_utilisateur_profil' avec postmeta
'mon_utilisateur_id' "IN" les identifiants utilisateur trouvés dans le get_users()
; puis renvoyez la fusion des publications trouvées par la recherche d'origine avec les publications de type 'mon_utilisateur_profil' trouvées par ma get_posts()
.post_type_link
(qui est appelé par get_permalink()
). Lorsque le $post->post_type
est 'mon_utilisateur_profil', retournez get_author_posts_url()
sur l'utilisateur dont l'ID est indiqué dans 'mon_utilisateur_id' postmeta
nom__ de $post
. Ceci afin que le search.php
du thème ne doive pas contenir de code avec une connaissance spécifique de la manière dont les étapes ci-dessus ont "augmenté" les résultats de la recherche.get_the_excerpt
. Lorsque $post->post_type
est 'mon_utilisateur_profil', retournez la valeur d'un usermeta
(dites 'my_excerpt') spécifique pour l'utilisateur dont l'ID se trouve dans 'my_user_id' postmeta
of $post
. Ceci afin que le search.php
du thème ne doive pas contenir de code avec une connaissance spécifique de la manière dont les étapes ci-dessus ont "augmenté" les résultats de la recherche.[note: le code de l'étape 3 a été modifié pour corriger un bogue introduit lors de la transcription (et de la désinfection) de mon code de travail]
Voici le code de ma solution provisoire:
// 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;
}
Comme je l'ai dit, ce qui précède fonctionne, mais je ne peux pas m'empêcher de penser qu'il existe un moyen plus simple auquel je n'ai pas pensé.
Une alternative à laquelle j’ai pensé, mais que j’ai rejetée parce qu’elle semble plus complexe/fragile que la solution ci-dessus, est la suivante:
personal_options_update
. Pour chaque usermeta
que je suis déjà en train de stocker pour un utilisateur, ajoutez-le en tant que postmeta
à la publication de type 'mon_utilisateur_profil' associée à l'utilisateur donné.posts_join
et posts_where
pour rechercher les différents postmeta
ajoutés à l’étape 3Quelqu'un a-t-il une solution plus simple/moins fragile?
Je n'ai pas de solution prête à l'emploi. Cependant, je pense que vous devriez améliorer la requête, de sorte que vous ayez le champ des utilisateurs à l'intérieur. Je pense que l'exemple suivant le démontre plus.
Les deux crochets de filtre sont nécessaires et donnent un résultat pour la requête comme ceci:
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
Vous pouvez également lire cette requête sur vos tests très facilement via un plugin, comme des objets de débogage ou un moniteur de requêtes. La requête SQL n'est qu'un exemple et ne constitue certainement pas le résultat. Vous devez jouer avec eux et inclure les crochets ci-dessous pour obtenir le bon résultat. La source ne reçoit qu'un exemple pour ajouter un champ de la table users, le display_name
. Peut-être qu'un "nerd" sql peut aider.
// 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 );