Comment rechercher toutes les méta d'utilisateurs à partir de users.php dans l'administrateur

14

Le formulaire de recherche en haut de la liste des utilisateurs dans la zone d'administration (wp-admin / users.php) est limité et ne recherche pas tous les champs méta des utilisateurs, tels que la bio, les poignées de messagerie instantanée, etc. Je n'ai pas été en mesure de trouver un plugin qui peut ajouter cela.

Est-ce que quelqu'un connaît un plugin ou une fonction que je pourrais créer qui pourrait étendre cette recherche à toute la date dans la base de données _usermeta - idéalement même des champs supplémentaires créés par un plugin ou une fonction.

John Chandler
la source

Réponses:

24

Salut @ user2041:

De toute évidence, comme vous le savez, vous devez modifier la recherche effectuée, ce que vous pouvez faire en modifiant les valeurs dans l'instance de la WP_User_Searchclasse utilisée pour la recherche (vous pouvez trouver le code source à /wp-admin/includes/user.phpsi vous souhaitez l'étudier).

L' WP_User_Searchobjet

Voici à quoi ressemble un print_r()de ces objets avec WordPress 3.0.3 lors de la recherche du terme " TEST" et sans aucun autre plugin qui pourrait l'affecter:

WP_User_Search Object
(
  [results] => 
  [search_term] => TEST
  [page] => 1
  [role] => 
  [raw_page] => 
  [users_per_page] => 50
  [first_user] => 0
  [last_user] => 
  [query_limit] =>  LIMIT 0, 50
  [query_orderby] =>  ORDER BY user_login
  [query_from] =>  FROM wp_users
  [query_where] =>  WHERE 1=1 AND (user_login LIKE '%TEST%' OR user_nicename LIKE '%TEST%' OR user_email LIKE '%TEST%' OR user_url LIKE '%TEST%' OR display_name LIKE '%TEST%')
  [total_users_for_query] => 0
  [too_many_total_users] => 
  [search_errors] => 
  [paging_text] => 
)

Le pre_user_searchcrochet

Pour modifier les valeurs de l' WP_User_Searchobjet, vous utiliserez le 'pre_user_search'crochet qui reçoit l'instance actuelle de l'objet; J'ai appelé à print_r()partir de ce crochet pour accéder à ses valeurs que j'ai affichées ci-dessus.

L'exemple suivant que vous pouvez copier dans le functions.phpfichier de votre thème ou que vous pouvez utiliser dans un fichier PHP pour un plugin que vous écrivez ajoute la possibilité de rechercher sur la description de l'utilisateur en plus de pouvoir rechercher sur les autres champs. La fonction modifie les query_fromet les query_wherepropriétés de l' $user_searchobjet que vous devez maîtriser avec SQL pour comprendre.

Modification soignée de SQL dans les hooks

Le code de la yoursite_pre_user_search()fonction suppose qu'aucun autre plugin n'a modifié la query_whereclause avant elle; si un autre plugin a modifié la clause where de telle sorte que le remplacement 'WHERE 1=1 AND ('par "WHERE 1=1 AND ({$description_where} OR"ne fonctionne plus, cela cassera également. Il est beaucoup plus difficile d'écrire un ajout robuste qui ne peut pas être rompu par un autre plugin lors de la modification de SQL comme celui-ci, mais c'est ce que c'est.

Ajouter des espaces de début et de fin lors de l'insertion de SQL dans des crochets

A noter également que lors de l' utilisation de SQL comme ça dans WordPress , il est toujours une bonne idée d'inclure les espaces de fuite avec un tel " INNER JOIN {$wpdb->usermeta} ON "sinon votre requête SQL peut contenir les éléments suivants où il n'y a pas d' espace avant "INNER", qui d'échec cours: " FROM wp_postsINNER JOIN {$wpdb->usermeta} ON ".

Utiliser à la "{$wpdb->table_name"}place des noms de table de codage en dur

Assurez-vous ensuite de toujours utiliser les $wpdbpropriétés pour référencer les noms de table au cas où le site aurait changé le préfixe de la table 'wp_'en autre chose. Il est donc préférable de s'y référer "{$wpdb->users}.ID" (avec des guillemets doubles, pas des guillemets simples) au lieu de coder en dur "wp_users.ID".

Limiter la requête uniquement lorsque des termes de recherche existent

Enfin, ne modifiez la requête que s'il existe un terme de recherche que vous pouvez tester en inspectant la search_termpropriété de l' WP_User_Searchobjet.

La yoursite_pre_user_search()fonction pour'pre_user_search'

add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
  global $wpdb;
  if (!is_null($user_search->search_term)) {
    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " . 
      "{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " .
      "{$wpdb->usermeta}.meta_key='description' ";
    $description_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
      "%{$user_search->search_term}%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (',
      "WHERE 1=1 AND ({$description_where} OR ",$user_search->query_where);    
  }
}

La recherche de chaque paire méta clé-valeur nécessite un SQL JOIN

Bien sûr, la raison probable pour laquelle WordPress ne vous permet pas de rechercher dans les champs usermeta est que chacun ajoute un SQL JOINà la requête et qu'une requête avec trop de jointures peut être lente en effet. Si vous avez vraiment besoin de rechercher sur de nombreux champs, je '_search_cache'créerais un champ dans usermeta qui recueille toutes les autres informations dans un champ usermeta pour ne nécessiter qu'une seule jointure pour tout rechercher.

Les soulignements principaux des méta-clés indiquent à WordPress de ne pas s'afficher

Notez que le soulignement principal '_search_cache'indique à WordPress qu'il s'agit d'une valeur interne et non de quelque chose à afficher à l'utilisateur.

Créer un cache de recherche avec les crochets 'profile_update'et'user_register'

Vous devrez donc connecter les deux 'profile_update'et 'user_register'qui sont déclenchés lors de l'enregistrement d'un utilisateur et de l'enregistrement d'un nouvel utilisateur, respectivement. Vous pouvez récupérer toutes les méta-clés et leurs valeurs dans ces crochets (mais omettre celles dont les valeurs sont des tableaux sérialisés ou encodés par URL) , puis les concaténer pour les stocker en une seule méta-valeur longue à l'aide de la '_search_cache'clé.

Stocker la méta en tant que '|'paires de valeurs-clés délimitées

J'ai décidé de saisir tous les noms de clés et toutes leurs valeurs et de les concaténer en une seule grande chaîne avec des deux-points (":") séparant les clés des valeurs et des barres verticales ("|") séparant les paires clé-valeur comme ceci (I les ai enroulés sur plusieurs lignes pour que vous puissiez les faire défiler vers la droite):

nickname:mikeschinkel|first_name:mikeschinkel|description:This is my bio|
rich_editing:true|comment_shortcuts:false|admin_color:fresh|use_ssl:null|
wp_user_level:10|last_activity:2010-07-28 01:25:46|screen_layout_dashboard:2|
plugins_last_view:recent|screen_layout_post:2|screen_layout_page:2|
business_name:NewClarity LLC|business_description:WordPress Plugin Consulting|
phone:null|last_name:null|aim:null|yim:null|jabber:null|
people_lists_linkedin_url:null

Permet des recherches spécialisées sur Meta Using key:value

L'ajout de la clé et des valeurs comme nous l'avons fait vous permet de faire des recherches comme " rich_editing:true" pour trouver tous ceux qui ont une édition riche, ou rechercher " phone:null" pour trouver ceux sans numéro de téléphone.

Mais attention aux artefacts de recherche

Bien sûr, l'utilisation de cette technique crée des artefacts de recherche potentiellement indésirables tels que la recherche de "business" et tout le monde sera répertorié. Si c'est un problème, vous ne voudrez peut-être pas utiliser un cache aussi élaboré.

La yoursite_profile_update()fonction pour 'profile_update'et'user_register'

Pour la fonction yoursite_profile_update(), comme yoursite_pre_user_search()ci-dessus peut être copiée dans le functions.phpfichier de votre thème ou vous pouvez utiliser dans un fichier PHP pour un plugin que vous écrivez:

add_action('profile_update','yoursite_profile_update');
add_action('user_register','yoursite_profile_update');
function yoursite_profile_update($user_id) {
  $metavalues = get_user_metavalues(array($user_id));
  $skip_keys = array(
    'wp_user-settings-time',
    'nav_menu_recently_edited',
    'wp_dashboard_quick_press_last_post_id',
  );
  foreach($metavalues[$user_id] as $index => $meta) {
    if (preg_match('#^a:[0-9]+:{.*}$#ms',$meta->meta_value))
      unset($metavalues[$index]); // Remove any serialized arrays
    else if (preg_match_all('#[^=]+=[^&]\&#',"{$meta->meta_value}&",$m)>0)
      unset($metavalues[$index]); // Remove any URL encoded arrays
    else if (in_array($meta->meta_key,$skip_keys))
      unset($metavalues[$index]); // Skip and uninteresting keys
    else if (empty($meta->meta_value)) // Allow searching for empty
      $metavalues[$index] = "{$meta->meta_key }:null";
    else if ($meta->meta_key!='_search_cache') // Allow searching for everything else
      $metavalues[$index] = "{$meta->meta_key }:{$meta->meta_value}";
  }
  $search_cache = implode('|',$metavalues);
  update_user_meta($user_id,'_search_cache',$search_cache);
}

yoursite_pre_user_search()Fonction mise à jour permettant à un seul SQL JOINde rechercher toutes les méta-valeurs intéressantes

Bien sûr, pour yoursite_profile_update()avoir un effet, vous devrez modifier yoursite_pre_user_search()pour utiliser la '_search_cache'touche méta au lieu de la description, que nous avons ici (avec les mêmes mises en garde que celles mentionnées ci-dessus):

add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
  global $wpdb;
  if (!is_null($user_search->search_term)) {
    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " . 
      "{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " . 
      "{$wpdb->usermeta}.meta_key='_search_cache' ";
    $meta_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
      "%{$user_search->search_term}%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (',
      "WHERE 1=1 AND ({$meta_where} OR ",$user_search->query_where);
  }
}
MikeSchinkel
la source
@MikeSchinkel Excellente réponse complète! C'est l'une des nombreuses fois sur ce site où j'aimerais pouvoir donner plusieurs votes positifs pour une réponse aussi bien documentée à une question non courante.
MathSmath
Merci @MathSmath - Apprendre que les gens l'apprécient est ce qui me fait avancer. :)
MikeSchinkel
Mike, merci pour la réponse complète! Je travaillerai cela dans mon thème plus tard dans la journée et je verrai qui ça va.
John Chandler
Mike, nous sommes proches, mais ..! De toute évidence, cela me permet de prendre un bon départ. L'utilisation de la fonction unique que vous mentionnez en premier ou des deux fonctions pour utiliser profile_update fonctionne en termes de capacité à rechercher et à obtenir les résultats appropriés. Malheureusement, ces fonctions gâchent la liste lorsque je tire pour la première fois users.php (aucun terme de recherche spécifié). Il ne montre pas tous les utilisateurs. Lorsque je clique sur le filtre Tous, il n'en montre que deux (sur quatre), dont l'un est moi, et quand je clique sur le filtre Administrateurs, il n'y a pas d'utilisateurs - pas même moi! Des idées?
John Chandler
Un peu plus d'infos. J'ai édité la première fonction pour rechercher un champ appelé «entreprise» que j'ai ajouté via le plugin de détails utilisateur supplémentaires. Cela fonctionne lorsque je recherche un utilisateur avec un nom de société. Mais, il semble que le tri par Tous, sans recherche, renvoie uniquement les deux résultats qui contiennent des données dans le champ société et non les utilisateurs qui n'ont pas de données dans le champ société.
John Chandler
5

J'ai vraiment apprécié l'approche de MikeSchinkel et l'explication approfondie ci-dessus. C'était super utile. Je n'ai pas pu le faire fonctionner pour moi car pre_user_search a été déprécié et ne fonctionne pas réellement dans 3.2. J'ai juste essayé de le désactiver avec pre_user_query mais cela n'a pas fonctionné non plus. Le truc c'est qu'il semble que $ user_search-> search_term ne fonctionne plus donc j'ai juste utilisé $ _GET ['s']. J'ai fait du piratage et j'ai réussi à faire fonctionner cela en 3.2. La seule chose que vous devez définir est votre tableau de métadonnées consultables.

//Searching Meta Data in Admin
add_action('pre_user_query','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
    global $wpdb;
    if (!isset($_GET['s'])) return;

    //Enter Your Meta Fields To Query
    $search_array = array("customer_id", "postal_code", "churchorganization_name", "first_name", "last_name");

    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON {$wpdb->users}.ID={$wpdb->usermeta}.user_id AND (";
    for($i=0;$i<count($search_array);$i++) {
        if ($i > 0) $user_search->query_from .= " OR ";
            $user_search->query_from .= "{$wpdb->usermeta}.meta_key='" . $search_array[$i] . "'";
        }
    $user_search->query_from .= ")";        
    $custom_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'", "%" . $_GET['s'] . "%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (', "WHERE 1=1 AND ({$custom_where} OR ",$user_search->query_where);    
}

J'espère que cela aide quelqu'un.

David
la source
Quelqu'un at-il des expériences récentes avec tout cela? Personnellement, je ne peux pas faire fonctionner ces morceaux de code, y compris les derniers. J'ai essayé d'autres options, mais j'ai rencontré des problèmes avec la pagination des résultats .
Robert Andrews
1

Voici une solution pour la dernière version de wordpress.

add_action( 'pre_user_query', 'yoursite_pre_user_search'  );
    function yoursite_pre_user_search( $query ) {
        $query->query_where .= "YOUR QUERY '" . str_replace("*", "%", $query->query_vars[ 'search' ] ) . "')";
    }
Patrik Grinsvall
la source
-1

C'est ce que j'ai proposé pour WordPress 4.7.1 qui ajoute la recherche générique à toutes les métadonnées utilisateur.


add_action( 'pre_user_query', 'ds_pre_user_search'  );
function ds_pre_user_search( $query ) {
    global $wpdb;

    if( empty($_REQUEST['s']) ){return;}
    $query->query_from .= ' LEFT JOIN '.$wpdb->usermeta.' ON '.$wpdb->usermeta.'.user_id = '.$wpdb->users.'.ID';
    $query->query_where = "WHERE 1=1 AND (user_login LIKE '%".$_REQUEST['s']."%' OR ID = '".$_REQUEST['s']."' OR meta_value LIKE '%".$_REQUEST['s']."%')";
    return $query;
}

Fondamentalement, nous joignons simplement les utilisateurs et les tables user_meta sur l'ID utilisateur et reconstruisons la clause WHERE pour inclure la recherche dans la colonne meta_value.

wagontrader
la source
1
Ce que vous proposez ici est très dangereux ! Vous ne devez jamais, jamais transférer tout ce qui est fourni par un utilisateur dans la base de données. Ils pourraient supprimer vos tables, pirater votre base de données (voir l'injection SQL comme expression de recherche) ou tout simplement chiffrer toutes vos données. Faites "%".like_escape( $_GET['s'] )."%"plutôt un . Il en va de même pour toutes les autres données fournies par l'utilisateur . Sinon, votre champ de recherche devient une passerelle ouverte vers vos données.
kaiser