W ekosystemie WordPressa to WP_Query zgarnia całą chwałę, ale to WP_User_Query rządzi światem serwisów społecznościowych, intranetów i platform członkowskich.
Niezależnie od tego, czy budujesz prostą stronę “Nasz Zespół” (Team Page), czy skomplikowaną wyszukiwarkę “Znajdź Lekarza” z tysiącami specjalistów, poleganie na wtyczkach typu Ultimate Member do warstwy prezentacji jest często przesadą – i wąskim gardłem wydajnościowym.
W tym poradniku pominiemy interfejsy graficzne i zbudujemy wydajne, bezpieczne zapytania o użytkowników bezpośrednio w PHP. Omówimy granularne filtrowanie, cache’owanie wydajnościowe i krytyczne środki bezpieczeństwa, aby zapobiec wyciekom danych.
1. Development() vs. Wp_User_Query
Tak jak get_posts() jest nakładką na WP_Query, tak development() jest skonfigurowaną nakładką na WP_User_Query.
- Używaj
development()do prostych list (np. “Pokaż mi 5 administratorów”). Zwraca tablicę obiektówWP_User. - Używaj
WP_User_Query, gdy potrzebujesz zaawansowanych manipulacji SQL, szczegółowej logiki sortowania (‘orderby’) lub inspekcji nagłówków zapytania/wyników bezpośrednio.
W 95% przypadków będziemy używać tablicy argumentów, która ma zastosowanie do obu funkcji.
2. Podstawy: Budowa strony zespołu
Załóżmy, że chcemy wyświetlić siatkę pracowników (Redaktorów i Autorów) posortowaną według ich wyświetlanej nazwy.
$args = [
'role__in' => ['editor', 'author'],
'orderby' => 'display_name',
'order' => 'ASC',
'number' => 12, // Limit paginacji
'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. Zaawansowane filtrowanie (meta queries)
Tutaj WP_User_Query błyszczy. Wyobraź sobie, że masz katalog programistów i chcesz znaleźć tych, którzy:
- Są z “Warszawy”.
- Mają profil oznaczony jako “Publiczny”.
- Mają “PHP” na liście umiejętności.
$args = [
'role' => 'subscriber',
'meta_query' => [
'relation' => 'AND',
[
'key' => 'city',
'value' => 'Warszawa',
'compare' => '='
],
[
'key' => 'is_public_profile',
'value' => '1',
'compare' => '='
],
[
'key' => 'skills',
'value' => 'PHP',
'compare' => 'LIKE' // Wolne, ale skuteczne dla zserializowanych tablic
]
]
];
[!WARNING] Alert Wydajnościowy: Odpytywanie
wp_usermetajest kosztowne. W przeciwieństwie dowp_posts, tabele użytkowników rzadko są optymalnie indeksowane pod kątem złożonego filtrowania. Dla katalogów >10,000 użytkowników, rozważ przeniesienie indeksu wyszukiwania do Elasticsearch (przez ElasticPress) lub użycie własnej tabeli SQL.
4. Optymalizacja wydajności
Odpytując użytkowników na stronie o dużym ruchu, musisz oszczędnie gospodarować zasobami bazy danych.
A. Ogranicz zwracane pola (fields)
Domyślnie WordPress pobiera każdą możliwą daną o użytkowniku (wszystkie metadane). Jeśli potrzebujesz tylko imion i e-maili, powiedz WordPressowi, by był lekki.
$args = [
'role' => 'subscriber',
'number' => 100,
'fields' => ['ID', 'display_name', 'user_email'], // Zwraca obiekty stdClass, nie WP_User
];
Wynik: Zużycie pamięci RAM spada drastycznie.
B. Policz użytkowników bez ich Ładowania
Jeśli chcesz tylko pokazać “Mamy 500 członków!”, nie ładuj obiektów członków.
$args = [
'role' => 'subscriber',
'fields' => 'ID', // Pobierz tylko ID
];
$query = new WP_User_Query($args);
$count = $query->get_total(); // Używa logiki SQL_CALC_FOUND_ROWS
Lub dla ekstremalnej szybkości (ignorując złożone filtry), użyj count_users():
$count = count_users();
echo "Mamy " . $count['total_users'] . " użytkowników.";
5. Bezpieczeństwo: Zagrożenie “user enumeration”
Domyślnie WordPress jest dość “dziurawy”, jeśli chodzi o dane użytkowników.
- Nie ujawniaj Loginów: Nigdy nie wykonuj
echo $user->user_login. To połowa klucza potrzebnego do zhakowania konta administratora. Zawsze używajdisplay_namelubuser_nicename. - Ukrywaj E-maile: O ile to nie jest wewnętrzny intranet, nigdy nie wypisuj
user_emailw kodzie HTML, aby uniknąć botów spamujących.
Blokowanie archiwów autora
Hakerzy często skanują /?author=1, /?author=2, aby odkryć nazwy użytkowników. Jeśli budujesz stronę firmową, gdzie użytkownicy nie potrzebują publicznych archiwów, wyłącz tę trasę.
// Dodaj do functions.php
add_action('template_redirect', function() {
if (is_author()) {
wp_redirect(home_url(), 301);
exit;
}
});
6. Podsumowanie
Budowanie własnego katalogu użytkowników daje pełną kontrolę nad wydajnością i bezpieczeństwem.
- Używaj parametru
fields, aby zmniejszyć ślad pamięci. - Cache’uj wyniki używając Transients API, jeśli katalog nie zmienia się co godzinę.
- Sanityzuj dane wyjściowe bezlitośnie (zawsze
esc_html). - Chroń prywatność, ukrywając loginy i e-maile.
Użytkownicy w WordPressie to encje tak samo jak posty – zacznij ich odpytywać z tą samą precyzją.
7. Paginacja użytkowników
Przy dużych katalogach użytkowników, paginacja jest kluczowa dla wydajności i UX.
Paginacja numeryczna
function wppoland_paginated_users_list( $role = 'subscriber', $per_page = 20 ) {
$paged = isset( $_GET['paged'] ) ? max( 1, intval( $_GET['paged'] ) ) : 1;
$args = [
'role' => $role,
'number' => $per_page,
'paged' => $paged,
'fields' => ['ID', 'display_name', 'user_email', 'user_login'],
];
$user_query = new WP_User_Query( $args );
$users = $user_query->get_results();
$total_users = $user_query->get_total();
$total_pages = ceil( $total_users / $per_page );
// Wyświetl użytkowników
if ( ! empty( $users ) ) {
echo '<ul class="users-list">';
foreach ( $users as $user ) {
$profile_url = get_author_posts_url( $user->ID );
echo '<li>';
echo '<a href="' . esc_url( $profile_url ) . '">';
echo get_avatar( $user->ID, 48 );
echo '<span>' . esc_html( $user->display_name ) . '</span>';
echo '</a>';
echo '</li>';
}
echo '</ul>';
}
// Wyświetl paginację
if ( $total_pages > 1 ) {
echo '<nav class="pagination">';
echo paginate_links([
'base' => add_query_arg( 'paged', '%#%' ),
'format' => '?paged=%#%',
'current' => $paged,
'total' => $total_pages,
'prev_text' => '« Poprzednia',
'next_text' => 'Następna »',
]);
echo '</nav>';
}
echo '<p class="total-users">Łącznie: ' . $total_users . ' użytkowników</p>';
}
Nieskończone przewijanie (Infinite Scroll)
// AJAX handler dla infinite scroll
add_action( 'wp_ajax_wppoland_load_more_users', 'wppoland_load_more_users' );
add_action( 'wp_ajax_nopriv_wppoland_load_more_users', 'wppoland_load_more_users' );
function wppoland_load_more_users() {
$page = isset( $_POST['page'] ) ? intval( $_POST['page'] ) : 1;
$role = isset( $_POST['role'] ) ? sanitize_text_field( $_POST['role'] ) : 'subscriber';
$args = [
'role' => $role,
'number' => 12,
'paged' => $page,
'fields' => ['ID', 'display_name', 'user_email'],
];
$query = new WP_User_Query( $args );
if ( $query->get_results() ) {
foreach ( $query->get_results() as $user ) {
echo '<div class="user-card">';
echo get_avatar( $user->ID, 100 );
echo '<h3>' . esc_html( $user->display_name ) . '</h3>';
echo '<p>' . esc_html( $user->user_email ) . '</p>';
echo '</div>';
}
}
wp_die();
}
8. Filtrowanie według niestandardowych ról
WordPress pozwala na tworzenie własnych ról. Oto jak filtrować użytkowników według ról niestandardowych:
// Rejestracja roli niestandardowej
function wppoland_register_custom_roles() {
add_role(
'premium_member',
'Członek Premium',
[
'read' => true,
'edit_posts' => false,
'delete_posts' => false,
]
);
add_role(
'instructor',
'Instruktor',
[
'read' => true,
'edit_posts' => true,
'delete_posts' => true,
'upload_files' => true,
]
);
}
add_action( 'init', 'wppoland_register_custom_roles' );
// Wyświetl wszystkich instruktorów
function wppoland_list_instructors() {
$args = [
'role' => 'instructor',
'orderby'=> 'display_name',
'order' => 'ASC',
];
$query = new WP_User_Query( $args );
if ( $query->get_results() ) {
echo '<div class="instructors-grid">';
foreach ( $query->get_results() as $user ) {
$specialty = get_user_meta( $user->ID, 'specialty', true );
echo '<div class="instructor-card">';
echo get_avatar( $user->ID, 150 );
echo '<h3>' . esc_html( $user->display_name ) . '</h3>';
echo '<p class="specialty">Specjalizacja: ' . esc_html( $specialty ) . '</p>';
echo '<a href="' . esc_url( get_author_posts_url( $user->ID ) ) . '" class="button">Zobacz profil</a>';
echo '</div>';
}
echo '</div>';
}
}
9. Integracja z WooCommerce (lista klientów)
function wppoland_list_woocommerce_customers() {
$customers = [];
// Pobierz użytkowników, którzy złożyli zamówienia
$args = [
'role__in' => ['customer', 'subscriber', 'administrator'],
'number' => 50,
'paged' => isset( $_GET['paged'] ) ? intval( $_GET['paged'] ) : 1,
];
$query = new WP_User_Query( $args );
if ( $query->get_results() ) {
echo '<table class="customers-table">';
echo '<thead><tr><th>Klient</th><th>Email</th><th>Liczba zamówień</th><th>Suma wydana</th></tr></thead>';
echo '<tbody>';
foreach ( $query->get_results() as $user ) {
// Pobierz dane WooCommerce
$orders = wc_get_orders([
'customer' => $user->ID,
'status' => ['completed', 'processing'],
'limit' => -1,
]);
$order_count = count( $orders );
$total_spent = 0;
foreach ( $orders as $order ) {
$total_spent += $order->get_total();
}
echo '<tr>';
echo '<td>' . esc_html( $user->display_name ) . '</td>';
echo '<td><a href="mailto:' . esc_attr( $user->user_email ) . '">' . esc_html( $user->user_email ) . '</a></td>';
echo '<td>' . intval( $order_count ) . '</td>';
echo '<td>' . wc_price( $total_spent ) . '</td>';
echo '</tr>';
}
echo '</tbody></table>';
}
}
10. Wyszukiwanie użytkowników
function wppoland_user_search_form() {
?>
<form method="get" action="">
<input type="text" name="user_search" placeholder="Szukaj użytkownika..." value="<?php echo isset( $_GET['user_search'] ) ? esc_attr( $_GET['user_search'] ) : ''; ?>">
<button type="submit">Szukaj</button>
</form>
<?php
}
function wppoland_search_users( $search_term ) {
$args = [
'search' => '*' . sanitize_text_field( $search_term ) . '*',
'search_columns' => ['user_login', 'user_email', 'display_name'],
'number' => 20,
];
$query = new WP_User_Query( $args );
if ( $query->get_results() ) {
echo '<ul class="search-results">';
foreach ( $query->get_results() as $user ) {
echo '<li>';
echo get_avatar( $user->ID, 32 );
echo '<a href="' . esc_url( get_author_posts_url( $user->ID ) ) . '">';
echo esc_html( $user->display_name );
echo '</a>';
echo ' <small>(' . esc_html( $user->user_email ) . ')</small>';
echo '</li>';
}
echo '</ul>';
} else {
echo '<p>Nie znaleziono użytkowników.</p>';
}
}
11. Tworzenie katalogu z filtrami
function wppoland_advanced_user_directory() {
$role_filter = isset( $_GET['role'] ) ? sanitize_text_field( $_GET['role'] ) : '';
$city_filter = isset( $_GET['city'] ) ? sanitize_text_field( $_GET['city'] ) : '';
$search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : '';
$args = [
'number' => 12,
];
if ( $role_filter ) {
$args['role'] = $role_filter;
}
if ( $search ) {
$args['search'] = '*' . $search . '*';
$args['search_columns'] = ['display_name', 'user_email'];
}
if ( $city_filter ) {
$args['meta_query'] = [
[
'key' => 'city',
'value' => $city_filter,
'compare'=> 'LIKE',
]
];
}
$query = new WP_User_Query( $args );
// Wyświetl filtry
echo '<form method="get" class="user-filters">';
echo '<select name="role"><option value="">Wszystkie role</option>';
wp_dropdown_roles( $role_filter );
echo '</select>';
echo '<input type="text" name="city" placeholder="Miasto" value="' . esc_attr( $city_filter ) . '">';
echo '<input type="text" name="s" placeholder="Szukaj..." value="' . esc_attr( $search ) . '">';
echo '<button type="submit">Filtruj</button>';
echo '</form>';
// Wyświetl wyniki
if ( $query->get_results() ) {
echo '<div class="users-grid">';
foreach ( $query->get_results() as $user ) {
$city = get_user_meta( $user->ID, 'city', true );
echo '<div class="user-card">';
echo get_avatar( $user->ID, 100 );
echo '<h3>' . esc_html( $user->display_name ) . '</h3>';
echo '<p class="role">' . implode( ', ', $user->roles ) . '</p>';
if ( $city ) {
echo '<p class="city">📍 ' . esc_html( $city ) . '</p>';
}
echo '</div>';
}
echo '</div>';
} else {
echo '<p>Brak wyników.</p>';
}
}
12. Cache’owanie wyników
function wppoland_get_cached_users( $role = 'subscriber', $cache_time = HOUR_IN_SECONDS ) {
$cache_key = 'wppoland_users_' . md5( $role );
$users = get_transient( $cache_key );
if ( false === $users ) {
$args = [
'role' => $role,
'number' => -1,
'fields' => ['ID', 'display_name', 'user_email'],
];
$query = new WP_User_Query( $args );
$users = $query->get_results();
set_transient( $cache_key, $users, $cache_time );
}
return $users;
}
// Unieważnij cache przy nowej rejestracji
add_action( 'user_register', 'wppoland_invalidate_users_cache' );
function wppoland_invalidate_users_cache() {
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_wppoland_users_%'" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE '_transient_timeout_wppoland_users_%'" );
}
13. REST API dla użytkowników
// Rejestracja endpoint REST API
add_action( 'rest_api_init', function() {
register_rest_route( 'wppoland/v1', '/users', [
'methods' => 'GET',
'callback' => 'wppoland_get_users_api',
'args' => [
'role' => [
'default' => 'subscriber',
'sanitize_callback' => 'sanitize_text_field',
],
'limit' => [
'default' => 10,
'sanitize_callback' => 'absint',
],
'offset' => [
'default' => 0,
'sanitize_callback' => 'absint',
],
],
]);
});
function wppoland_get_users_api( $request ) {
$args = [
'role' => $request->get_param( 'role' ),
'number' => $request->get_param( 'limit' ),
'offset' => $request->get_param( 'offset' ),
'fields' => ['ID', 'display_name', 'user_email', 'user_login'],
];
$query = new WP_User_Query( $args );
$users = [];
foreach ( $query->get_results() as $user ) {
$users[] = [
'id' => $user->ID,
'name' => $user->display_name,
'email' => $user->user_email,
'username' => $user->user_login,
'avatar_url' => get_avatar_url( $user->ID ),
'profile_url' => get_author_posts_url( $user->ID ),
];
}
return rest_ensure_response([
'total' => $query->get_total(),
'users' => $users,
]);
}
14. Shortcode do wyświetlania użytkowników
add_shortcode( 'lista_uzytkownikow', 'wppoland_users_shortcode' );
function wppoland_users_shortcode( $atts ) {
$atts = shortcode_atts([
'role' => 'subscriber',
'limit' => 10,
'columns' => 3,
'avatar' => 'yes',
'bio' => 'no',
], $atts );
$args = [
'role' => $atts['role'],
'number' => intval( $atts['limit'] ),
'fields' => ['ID', 'display_name', 'user_email', 'user_login'],
];
$query = new WP_User_Query( $args );
if ( ! $query->get_results() ) {
return '<p>Brak użytkowników.</p>';
}
$output = '<div class="wppoland-users-shortcode" style="display: grid; grid-template-columns: repeat(' . intval( $atts['columns'] ) . ', 1fr); gap: 20px;">';
foreach ( $query->get_results() as $user ) {
$output .= '<div class="user-item" style="text-align: center; padding: 20px; border: 1px solid #eee; border-radius: 8px;">';
if ( 'yes' === $atts['avatar'] ) {
$output .= '<div class="user-avatar" style="margin-bottom: 10px;">' . get_avatar( $user->ID, 80 ) . '</div>';
}
$output .= '<h4 class="user-name" style="margin: 0 0 5px;">' . esc_html( $user->display_name ) . '</h4>';
$output .= '<p class="user-role" style="font-size: 0.8em; color: #666;">' . implode( ', ', $user->roles ) . '</p>';
if ( 'yes' === $atts['bio'] ) {
$bio = get_user_meta( $user->ID, 'description', true );
if ( $bio ) {
$output .= '<p class="user-bio" style="font-size: 0.9em;">' . esc_html( $bio ) . '</p>';
}
}
$output .= '</div>';
}
$output .= '</div>';
return $output;
}
15. Widget użytkowników
class WPPoland_Users_Widget extends WP_Widget {
public function __construct() {
parent: ':__construct('
'wppoland_users_widget',
'WPPoland: Lista Użytkowników',
['description' => 'Wyświetla listę użytkowników z wybraną rolą']
);
}
public function widget( $args, $instance ) {
echo $args['before_widget'];
$title = ! empty( $instance['title'] ) ? $instance['title'] : 'Użytkownicy';
$role = ! empty( $instance['role'] ) ? $instance['role'] : 'subscriber';
$limit = ! empty( $instance['limit'] ) ? intval( $instance['limit'] ) : 5;
echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
$query = new WP_User_Query([
'role' => $role,
'number' => $limit,
'orderby'=> 'registered',
'order' => 'DESC',
]);
if ( $query->get_results() ) {
echo '<ul class="users-widget-list">';
foreach ( $query->get_results() as $user ) {
echo '<li>';
echo '<a href="' . esc_url( get_author_posts_url( $user->ID ) ) . '">';
echo get_avatar( $user->ID, 40 );
echo '<span>' . esc_html( $user->display_name ) . '</span>';
echo '</a>';
echo '</li>';
}
echo '</ul>';
}
echo $args['after_widget'];
}
public function form( $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
$role = ! empty( $instance['role'] ) ? $instance['role'] : 'subscriber';
$limit = ! empty( $instance['limit'] ) ? intval( $instance['limit'] ) : 5;
?>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">Tytuł:</label>
<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
type="text" value="<?php echo esc_attr( $title ); ?>">
</p>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'role' ) ); ?>">Rola:</label>
<select class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'role' ) ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'role' ) ); ?>">
<?php
global $wp_roles;
foreach ( $wp_roles->roles as $role_name => $role_info ) {
echo '<option value="' . esc_attr( $role_name ) . '"' . selected( $role, $role_name, false ) . '>';
echo esc_html( $role_info['name'] );
echo '</option>';
}
?>
</select>
</p>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'limit' ) ); ?>">Liczba użytkowników:</label>
<input class="tiny-text" id="<?php echo esc_attr( $this->get_field_id( 'limit' ) ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'limit' ) ); ?>"
type="number" min="1" max="50" value="<?php echo esc_attr( $limit ); ?>">
</p>
<?php
}
public function update( $new_instance, $old_instance ) {
$instance = [];
$instance['title'] = sanitize_text_field( $new_instance['title'] );
$instance['role'] = sanitize_text_field( $new_instance['role'] );
$instance['limit'] = absint( $new_instance['limit'] );
return $instance;
}
}
function wppoland_register_users_widget() {
register_widget( 'WPPoland_Users_Widget' );
}
add_action( 'widgets_init', 'wppoland_register_users_widget' );
16. FAQ - Najczęściej zadawane pytania
Jak wyświetlić tylko użytkowników z konkretną rolą?
$args = [
'role' => 'administrator', // lub inna rola
];
$users = get_users( $args );
Jak ukryć użytkowników bez avatarów?
$args = [
'role' => 'subscriber',
'number' => 20,
];
$query = new WP_User_Query( $args );
foreach ( $query->get_results() as $user ) {
if ( get_avatar_url( $user->ID ) ) {
// Wyświetl użytkownika
}
}
Jak sortować użytkowników według daty rejestracji?
$args = [
'role' => 'subscriber',
'orderby'=> 'registered',
'order' => 'DESC', // najnowsi pierwszy
];
Jak wykluczyć użytkowników z listy?
$args = [
'role__not_in' => ['administrator', 'editor'],
'exclude' => [1, 2, 3], // ID do wykluczenia
];
Jak pobrać tylko liczbę użytkowników?
$args = [
'role' => 'subscriber',
'fields' => 'ID',
];
$query = new WP_User_Query( $args );
$count = $query->get_total();
Jak wyświetlić użytkowników online?
function wppoland_get_online_users() {
$transient_key = 'wppoland_online_users';
$online_users = get_transient( $transient_key );
if ( false === $online_users ) {
$ten_minutes_ago = time() - 600;
$users = get_users([
'fields' => ['ID', 'display_name'],
]);
$online = [];
foreach ( $users as $user ) {
$last_active = get_user_meta( $user->ID, 'last_activity', true );
if ( $last_active && $last_active > $ten_minutes_ago ) {
$online[] = $user;
}
}
$online_users = $online;
set_transient( $transient_key, $online_users, 300 );
}
return $online_users;
}
// Aktualizuj last_activity przy każdej wizycie
add_action( 'wp_footer', function() {
if ( is_user_logged_in() ) {
update_user_meta( get_current_user_id(), 'last_activity', time() );
}
});
Jak dodać własne pola do profilu użytkownika?
// Dodaj pola do formularza profilu
add_action( 'show_user_profile', 'wppoland_extra_profile_fields' );
add_action( 'edit_user_profile', 'wppoland_extra_profile_fields' );
function wppoland_extra_profile_fields( $user ) {
?>
<h3>Dodatkowe informacje</h3>
<table class="form-table">
<tr>
<th><label for="city">Miasto</label></th>
<td>
<input type="text" name="city" id="city" value="<?php echo esc_attr( get_user_meta( $user->ID, 'city', true ) ); ?>" class="regular-text">
</td>
</tr>
<tr>
<th><label for="phone">Telefon</label></th>
<td>
<input type="text" name="phone" id="phone" value="<?php echo esc_attr( get_user_meta( $user->ID, 'phone', true ) ); ?>" class="regular-text">
</td>
</tr>
</table>
<?php
}
// Zapisz pola
add_action( 'personal_options_update', 'wppoland_save_extra_profile_fields' );
add_action( 'edit_user_profile_update', 'wppoland_save_extra_profile_fields' );
function wppoland_save_extra_profile_fields( $user_id ) {
if ( ! current_user_can( 'edit_user', $user_id ) ) {
return false;
}
update_user_meta( $user_id, 'city', sanitize_text_field( $_POST['city'] ) );
update_user_meta( $user_id, 'phone', sanitize_text_field( $_POST['phone'] ) );
}
Podsumowanie
| Zadanie | Funkcja/Metoda | Przykład |
|---|---|---|
| Podstawowa lista | get_users() | get_users(['role' => 'author']) |
| Zaawansowane filtry | WP_User_Query | new WP_User_Query(['meta_query' => [...]]) |
| Paginacja | paginate_links() | Z WP_User_Query->get_total() |
| Wyszukiwanie | Parametr search | ['search' => '*tekst*'] |
| Cache | set_transient() | Cache’owanie wyników |
| REST API | register_rest_route() | Endpoint /wp-json/wppoland/v1/users |
| Shortcode | add_shortcode() | [lista_uzytkownikow role="editor"] |
| Widget | WP_Widget | Rejestracja własnego widgetu |
Kluczowe zasady:
- Używaj
fieldsdla oszczędności pamięci - Cache’uj wyniki dla dużych katalogów
- Chroń prywatność - nie ujawniaj loginów i emaili publicznie
- Paginate wyniki dla lepszej wydajności
- Sanityzuj wszystkie dane wyjściowe (
esc_html,esc_url)
Słowa kluczowe: WP_User_Query, get_users, lista użytkowników WordPress, katalog użytkowników, role użytkowników, filtrowanie użytkowników, paginacja użytkowników, shortcode użytkowników, widget użytkowników, cache użytkowników, REST API użytkownicy, bezpieczeństwo użytkowników, user enumeration, WooCommerce klienci, niestandardowe role.



