En el ecosistema WordPress, WP_Query se lleva toda la gloria, pero WP_User_Query es la fuerza detras de los sitios de membresia, intranets y plataformas comunitarias.
Conozca más sobre los servicios de seguridad WordPress en WPPoland.
Ya sea que este construyendo una simple página de “Nuestro Equipo” o un complejo motor de búsqueda “Encontrar un Doctor” con miles de profesionales, depender de plugins como Ultimate Member para la capa de presentacion es a menudo excesivo y un cuello de botella de rendimiento.
En esta guía, evitaremos la interfaz grafica y construiremos consultas de usuario eficientes y seguras directamente en PHP. Cubriremos filtrado granular, cache de rendimiento y medidas de seguridad criticas para prevenir fugas de datos.
1. get_users() vs. WP_User_Query
Al igual que get_posts() es un wrapper para WP_Query, get_users() es un wrapper preconfigurado para WP_User_Query.
- Use
get_users()para listas simples (ej. “Muestrame 5 administradores”). Retorna un array de objetosWP_User. - Use
WP_User_Querycuando necesite manipulaciones SQL avanzadas, lógica detallada de ‘orderby’ o inspeccion directa de los encabezados/resultados de la consulta.
Para el 95% de los casos de uso, usaremos el array de argumentos, que aplica a ambos.
2. Lo básico: Construir una página de equipo
Digamos que queremos mostrar una cuadricula de empleados (Editores y Autores) ordenados por su nombre para mostrar.
$args = [
'role__in' => ['editor', 'author'],
'orderby' => 'display_name',
'order' => 'ASC',
'number' => 12, // Limite de páginacion
'paged' => 1,
];
$user_query = new WP_User_Query($args);
$results = $user_query->get_results();
if (!empty($results)) {
echo '<div class="team-grid">';
foreach ($results as $user) {
$avatar = get_avatar($user->ID, 128);
$name = esc_html($user->display_name);
$bio = esc_html(get_user_meta($user->ID, 'description', true));
echo "<article class='team-member'>
<figure>{$avatar}</figure>
<h3>{$name}</h3>
<p>{$bio}</p>
</article>";
}
echo '</div>';
}
3. Filtrado avanzado (meta queries)
Aqui es donde WP_User_Query brilla. Imagine que tiene un directorio de desarrolladores y quiere encontrar aquellos que:
- Estan basados en “Madrid”.
- Tienen su perfil marcado como “Público”.
- Tienen “PHP” listado como habilidad.
$args = [
'role' => 'subscriber',
'meta_query' => [
'relation' => 'AND',
[
'key' => 'city',
'value' => 'Madrid',
'compare' => '='
],
[
'key' => 'is_public_profile',
'value' => '1',
'compare' => '='
],
[
'key' => 'skills',
'value' => 'PHP',
'compare' => 'LIKE' // Lento, pero efectivo para arrays serializados
]
]
];
Alerta de rendimiento: Consultar
wp_usermetaes costoso. A diferencia dewp_posts, las tablas de usuarios raramente estan indexadas optimamente para filtrado complejo. Para directorios con más de 10.000 usuarios, considere descargar el indice de búsqueda a Elasticsearch (via ElasticPress) o usar una tabla personalizada.
4. Optimización de rendimiento
Cuando consulta usuarios en un sitio de alto tráfico, debe ser frugal con los recursos de base de datos.
A. Limitar los campos de retorno
Por defecto, WordPress obtiene cada pieza de datos sobre el usuario (todos los metadatos). Si solo necesita nombres y correos, diga a WordPress que sea ligero.
$args = [
'role' => 'subscriber',
'number' => 100,
'fields' => ['ID', 'display_name', 'user_email'], // Retorna objetos stdClass, no WP_User
];
Resultado: El uso de memoria se reduce significativamente.
B. Contar usuarios sin cargarlos
Si solo quiere mostrar “Tenemos 500 miembros!”, no cargue los miembros.
$args = [
'role' => 'subscriber',
'fields' => 'ID', // Solo obtener IDs
];
$query = new WP_User_Query($args);
$count = $query->get_total(); // Usa logica SQL_CALC_FOUND_ROWS
O para velocidad extrema (ignorando filtrado complejo), use count_users():
$count = count_users();
echo "Tenemos " . $count['total_users'] . " usuarios.";
C. Cache con transients
Para directorios que no cambian frecuentemente, almacene los resultados en transients:
$cache_key = 'directorio_miembros_página_1';
$results = get_transient($cache_key);
if (false === $results) {
$user_query = new WP_User_Query($args);
$results = $user_query->get_results();
set_transient($cache_key, $results, HOUR_IN_SECONDS);
}
5. Seguridad: La amenaza de “enumeracion de usuarios”
Por defecto, WordPress es bastante permisivo respecto a los datos de usuario.
- No exponga nombres de login: Nunca ejecute
echo $user->user_login. Esto es la mitad de la clave necesaria para hackear una cuenta de administrador. Siempre usedisplay_nameouser_nicename. - Oculte correos electronicos: A menos que sea una intranet interna, nunca muestre
user_emailen el código fuente HTML para evitar bots rastreadores.
Bloquear archivos de autor
Los hackers a menudo escanean /?author=1, /?author=2 para descubrir nombres de usuario. Si esta construyendo un sitio donde los usuarios no necesitan archivos publicos (como un sitio corporativo), desactive esta ruta.
// Agregar a functions.php
add_action('template_redirect', function() {
if (is_author()) {
wp_redirect(home_url(), 301);
exit;
}
});
Sanitizacion de salida
Siempre escape los datos de usuario antes de mostrarlos:
// Correcto - siempre escapar
echo esc_html($user->display_name);
echo esc_url(get_author_posts_url($user->ID));
// Incorrecto - nunca confiar en datos sin escapar
echo $user->display_name; // Vulnerable a XSS
6. Páginación de directorios
Para directorios grandes, la páginación es esencial:
$paged = max(1, get_query_var('paged'));
$per_page = 12;
$args = [
'role__in' => ['editor', 'author'],
'number' => $per_page,
'paged' => $paged,
'orderby' => 'display_name',
'order' => 'ASC',
];
$user_query = new WP_User_Query($args);
$total_users = $user_query->get_total();
$total_pages = ceil($total_users / $per_page);
// Renderizar páginacion
echo páginate_links([
'total' => $total_pages,
'current' => $paged,
'format' => '?paged=%#%',
]);
7. Búsqueda de usuarios
Implemente búsqueda en tiempo real para directorios:
$search_term = sanitize_text_field($_GET['buscar'] ?? '');
if ($search_term) {
$args['search'] = "*{$search_term}*";
$args['search_columns'] = ['display_name', 'user_nicename'];
}
Para búsquedas más avanzadas que incluyan metadatos, combine search con meta_query.
8. Integración con REST API
Para directorios interactivos con JavaScript, exponga datos de usuario a través de la REST API:
// Registrar endpoint personalizado
add_action('rest_api_init', function() {
register_rest_route('directorio/v1', '/miembros', [
'methods' => 'GET',
'callback' => 'obtener_miembros_directorio',
'permission_callback' => '__return_true',
]);
});
function obtener_miembros_directorio($request) {
$args = [
'role__in' => ['editor', 'author'],
'number' => 12,
'paged' => $request->get_param('page') ?: 1,
'fields' => ['ID', 'display_name'],
];
$query = new WP_User_Query($args);
$members = [];
foreach ($query->get_results() as $user) {
$members[] = [
'id' => $user->ID,
'name' => $user->display_name,
'avatar' => get_avatar_url($user->ID, ['size' => 128]),
];
}
return new WP_REST_Response([
'members' => $members,
'total' => $query->get_total(),
]);
}
Resumen
Construir un directorio de miembros personalizado le da control total sobre rendimiento y seguridad.
- Use el parametro
fieldspara reducir la huella de memoria. - Cachee sus resultados usando transients si el directorio no cambia cada hora.
- Sanitice la salida implacablemente (siempre
esc_html). - Proteja la privacidad ocultando logins y correos electronicos.
- Considere Elasticsearch para directorios con más de 10.000 usuarios.
Los usuarios de WordPress son entidades como las entradas: comience a consultarlos con la misma precision.
Conozca más sobre los servicios de desarrollo WordPress y la auditoria de seguridad WordPress en WPPoland.


