Cómo buscar todos los meta de usuario de users.php en el administrador

14

El formulario de búsqueda en la parte superior de la lista de usuarios en el área de administración (wp-admin / users.php) es limitado y no busca en todos los metacampos del usuario, como biografías, identificadores de mensajería instantánea, etc. pude encontrar un complemento que puede agregar esto.

¿Alguien sabe de un complemento o una función que podría crear que podría ampliar esta búsqueda para toda la fecha en el _usermeta DB? Idealmente, incluso los campos adicionales creados por un complemento o función.

John Chandler
fuente

Respuestas:

24

Hola @ user2041:

Claramente, como sabe, debe modificar la búsqueda que se realiza, lo que puede hacer modificando los valores en la instancia de la WP_User_Searchclase utilizada para la búsqueda (puede encontrar el código fuente en /wp-admin/includes/user.phpsi desea estudiarlo).

El WP_User_Searchobjeto

Así print_r()es como se ve un objeto con WordPress 3.0.3 cuando busca el término " TEST" y sin ningún otro complemento que pueda afectarlo:

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] => 
)

El pre_user_searchgancho

Para modificar los valores del WP_User_Searchobjeto, usará el 'pre_user_search'gancho que recibe la instancia actual del objeto; Llamé print_r()desde ese gancho para obtener acceso a sus valores que mostré arriba.

El siguiente ejemplo que puede copiar al functions.phparchivo de su tema o puede usar en un archivo PHP para un complemento que está escribiendo agrega la capacidad de buscar en la descripción del usuario además de poder buscar en los otros campos. La función modifica query_fromy las query_wherepropiedades del $user_searchobjeto que necesita para sentirse cómodo con SQL para comprender.

SQL de modificación cuidadosa en ganchos

El código en la yoursite_pre_user_search()función asume que ningún otro complemento ha modificado la query_wherecláusula anterior; si otro plugin ha modificado la cláusula where de tal manera que la sustitución 'WHERE 1=1 AND ('con "WHERE 1=1 AND ({$description_where} OR"ya no funciona entonces esto va a romper también. Es mucho más difícil escribir una adición robusta que no pueda ser rota por otro complemento al modificar SQL de esta manera, pero es lo que es.

Agregue espacios iniciales y finales al insertar SQL en ganchos

También tenga en cuenta que cuando se utiliza SQL como esto en WordPress, siempre es una buena idea para incluir espacios iniciales y finales como a con " INNER JOIN {$wpdb->usermeta} ON "lo contrario su consulta SQL podría contener la siguiente donde no hay espacio antes "INNER", lo que por supuesto fallar: " FROM wp_postsINNER JOIN {$wpdb->usermeta} ON ".

Usar en "{$wpdb->table_name"}lugar de nombres de tabla de codificación fija

A continuación, asegúrese de usar siempre las $wpdbpropiedades para hacer referencia a los nombres de las tablas en caso de que el sitio haya cambiado el prefijo de la tabla 'wp_'a otra cosa. Por lo tanto, es mejor hacer referencia "{$wpdb->users}.ID" (con comillas dobles, no simples) en lugar de codificar "wp_users.ID".

Limite la consulta a solo cuando existan términos de búsqueda

Por último, modifique la consulta solo cuando haya un término de búsqueda que pueda probar inspeccionando la search_termpropiedad del WP_User_Searchobjeto.

La yoursite_pre_user_search()función para'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 búsqueda de cada par clave-valor meta requiere un SQL JOIN

Por supuesto, la razón probable por la que WordPress no le permite buscar en los campos de datos de usuario es que cada uno agrega un SQL JOINa la consulta y, de hecho, una consulta con demasiadas combinaciones puede ser lenta. Si realmente necesita buscar en muchos campos, entonces crearía un '_search_cache'campo en usermeta que recopila toda la otra información en un campo de usermeta para requerir solo una unión para buscarlo todo.

Los guiones bajos principales en Meta Keys le dicen a WordPress que no se muestre

Tenga en cuenta que el guión bajo destacado '_search_cache'le dice a WordPress que este es un valor interno y no es algo que nunca se muestre al usuario.

Crear una caché de búsqueda con los 'profile_update'y 'user_register'ganchos

Por lo tanto, deberá conectar ambos 'profile_update'y 'user_register'eso se activará al guardar un usuario y registrar un nuevo usuario, respectivamente. Puede tomar todas las claves meta y sus valores en esos ganchos (pero omita aquellos con valores que son series serializadas o codificadas en URL) y luego concatenarlas para almacenarlas como un valor meta largo usando la '_search_cache'clave.

Almacenar Meta como '|'pares de valor clave delimitados

Decidí tomar todos los nombres clave y todos sus valores y concatenarlos en una gran cadena con dos puntos (":") que separan las claves de los valores y las barras verticales ("|") que separan los pares clave-valor de esta manera (I los he envuelto a través de múltiples líneas para que pueda sin desplazarse hacia la derecha):

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

Permite búsquedas especializadas en Meta usando key:value

Agregar la clave y los valores como lo hicimos le permite realizar búsquedas como " rich_editing:true" para encontrar a todos los que tienen una edición enriquecida, o buscar " phone:null" para encontrar aquellos sin número de teléfono.

Pero cuidado con los artefactos de búsqueda

Por supuesto, el uso de esta técnica crea artefactos de búsqueda posiblemente no deseados, como la búsqueda de "negocios", y todos aparecerán en la lista. Si esto es un problema, entonces es posible que no desee utilizar un caché tan elaborado.

La yoursite_profile_update()función para 'profile_update'y'user_register'

Para la función yoursite_profile_update(), como yoursite_pre_user_search()arriba se puede copiar en el functions.phparchivo de su tema o puede usar en un archivo PHP para un complemento que está escribiendo:

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()Función actualizada que permite un SQL único JOINpara buscar todos los metavalores interesantes

Por supuesto, para yoursite_profile_update()que tenga algún efecto, deberá modificarlo yoursite_pre_user_search()para usar la '_search_cache'metaclave en lugar de la descripción, que tenemos aquí (con las mismas advertencias mencionadas anteriormente):

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
fuente
@MikeSchinkel ¡Excelente respuesta! Esta es una de las muchas veces en este sitio donde me gustaría poder regalar múltiples votos a favor de una respuesta tan bien investigada a una pregunta que no es de inventario.
MathSmath
Gracias @MathSmath - Aprender que la gente lo aprecia es lo que me mantiene en marcha. :)
MikeSchinkel
Mike, gracias por la respuesta completa! Trabajaré esto en mi tema más tarde hoy y veré a quién va.
John Chandler
Mike, estamos cerca, pero ...! Claramente esto me está quitando el comienzo correcto. El uso de la función única que menciona primero o las dos funciones para utilizar profile_update está funcionando en términos de la capacidad de buscar y obtener los resultados adecuados. Desafortunadamente, estas funciones están jugando con la lista cuando por primera vez accedo users.php (que no especifica ningún término de búsqueda). No muestra a todos los usuarios. Cuando hago clic en el filtro Todos, solo muestra dos (de cuatro), uno de los cuales soy yo, y cuando hago clic en el filtro Administradores no aparece ningún usuario, ¡ni siquiera yo! ¿Algunas ideas?
John Chandler
Un poco más de información. Edité la primera función para buscar un campo llamado 'compañía' que agregué a través del complemento de detalles de usuario adicional. Funciona cuando busco un usuario con el nombre de una empresa. Pero, parece que ordenar por Todos, sin búsqueda, solo devuelve los dos resultados que tienen datos en el campo de la compañía, y no devuelve los usuarios que no tienen datos en el campo de la compañía.
John Chandler
5

Realmente aprecié el enfoque de MikeSchinkel y la explicación detallada anterior. Esto fue muy útil. No pude hacer que funcione para mí ya que pre_user_search ha quedado en desuso y en realidad no funciona en 3.2. Intenté cambiarlo con pre_user_query pero tampoco funcionó. La cosa es que parece que $ user_search-> search_term ya no funciona, así que solo usé $ _GET ['s']. Hice un poco de pirateo y pude hacer que esto funcione en 3.2. Lo único que necesita establecer es su conjunto de metadatos de búsqueda.

//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);    
}

Espero que esto ayude a alguien.

David
fuente
¿Alguien tiene alguna experiencia reciente con algo de esto? Personalmente, no puedo hacer funcionar ninguno de estos bits de código, incluidos los más recientes. He probado algunas otras opciones, pero he encontrado problemas con la paginación de resultados .
Robert Andrews
1

Para su información, para las personas que buscan en este tema (cómo ajustar la consulta de búsqueda del panel de usuario) y encuentran esta excelente página, WP_User_Search ha sido desaprobado por WP_User_Query a partir de 3.1: http://codex.wordpress.org/Class_Reference/WP_User_Query .

FredHead
fuente
1

Aquí hay una solución para la versión más reciente 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
fuente
-1

Esto es lo que se me ocurrió para WordPress 4.7.1, que agrega la búsqueda con comodines a todos los metadatos del usuario.


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;
}

Básicamente, solo estamos uniendo las tablas users y user_meta en la identificación de usuario y reconstruyendo la cláusula WHERE para incluir la búsqueda en la columna meta_value.

wagontrader
fuente
1
¡Lo que estás sugiriendo aquí es muy peligroso ! Usted debe nunca, nunca pasar lo que sea proporcionada por un usuario en la base de datos. Podrían abandonar sus tablas, secuestrar su base de datos (ver la inyección SQL como frase de búsqueda) o simplemente cifrar todos sus datos. Haz un "%".like_escape( $_GET['s'] )."%"en su lugar. Lo mismo ocurre con todos los demás datos proporcionados por el usuario . De lo contrario, su campo de búsqueda se convierte en una puerta de acceso abierta a sus datos.
Kaiser