Как отобразить пагинацию для WP_User_Query?
Я почти добился нужного результата, но не могу заставить работать ссылки пагинации для списка авторов, который я создаю.
Мой код приведен ниже, но я не знаю, как сделать рабочие ссылки для навигации между страницами с авторами. Может кто-нибудь помочь? У меня есть ощущение, что это может пригодиться, но я не знаю, как это реализовать:
Спасибо,
Osu
<?php
/* ****************************************************************** */
/* !СПИСОК АВТОРОВ */
/* ****************************************************************** */
// БЛАГОДАРНОСТИ:
// http://www.mattvarone.com/wordpress/list-users-with-wp_user_query/
// пагинация
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; // Необходимо для пагинации
$paged -= 1;
$limit = 2;
$offset = $paged * $limit;
// подготовка аргументов
$args = array(
// поиск только для роли Subscriber
'role' => 'Subscriber',
// сортировка по display_name
'orderby' => 'display_name',
// возвращаем все поля
'fields' => 'all_with_meta',
'number' => $limit,
'offset' => $offset
);
// Создаем объект WP_User_Query
$wp_user_query = new WP_User_Query($args);
// Получаем результаты
$authors = $wp_user_query->get_results();
// Проверяем наличие результатов
if (!empty($authors))
{
echo '<div class="author-entry">';
// цикл по каждому автору
foreach ($authors as $author)
{
$author_info = get_userdata($author->ID); ?>
<span style="float:left;padding:0 5px 0 0;"><?php echo get_avatar( $author->ID, 50 ); /* http://codex.wordpress.org/Function_Reference/get_avatar */ ?></span>
<span class="fn"><strong>Имя</strong> : <?php echo $author_info->first_name; ?></span><br />
<span class="ln"><strong>Фамилия</strong> : <?php echo $author_info->last_name; ?></span><br />
<span class="em"><strong>Email</strong> : <a href="mailto:<?php echo $author_info->user_email; ?>"><?php echo $author_info->user_email; ?></a></span><br />
<span class="we"><strong>Сайт</strong> : <a href="<?php echo $author_info->user_url; ?>"><?php echo $author_info->user_url; ?></a></span><br />
<span class="de"><strong>Биография</strong> :<br /><?php echo $author_info->description ; ?></span>
<div class="clear"> </div>
<?php
}
echo '</div>';
} else {
echo 'Авторы не найдены';
}
?>
<?php /* ЧТО Я ДОЛЖЕН ВСТАВИТЬ ЗДЕСЬ ДЛЯ СОЗДАНИЯ ССЫЛОК ПАГИНАЦИИ? */ ?>

Это должно приблизить вас к решению. Я не тестировал код, но он практически идентичен настройке, которую использовал несколько раз.
/*
* Начинаем с запроса для получения всех пользователей
* Нам нужно общее количество пользователей, чтобы рассчитать количество страниц
*/
$count_args = array(
'role' => 'Подписчик',
'fields' => 'all_with_meta',
'number' => 999999
);
$user_count_query = new WP_User_Query($count_args);
$user_count = $user_count_query->get_results();
// подсчитываем количество пользователей, найденных в запросе
$total_users = $user_count ? count($user_count) : 1;
// получаем номер текущей страницы и устанавливаем 1, если номер страницы не задан
$page = isset($_GET['p']) ? $_GET['p'] : 1;
// количество пользователей на странице
$users_per_page = 5;
// вычисляем общее количество страниц
$total_pages = 1;
$offset = $users_per_page * ($page - 1);
$total_pages = ceil($total_users / $users_per_page);
// основной запрос пользователей
$args = array(
// ищем только роль Подписчика
'role' => 'Подписчик',
// сортируем результаты по display_name
'orderby' => 'display_name',
// возвращаем все поля
'fields' => 'all_with_meta',
'number' => $users_per_page,
'offset' => $offset // пропускаем количество пользователей на странице
);
// Создаем объект WP_User_Query
$wp_user_query = new WP_User_Query($args);
// Получаем результаты
$authors = $wp_user_query->get_results();
// проверяем, есть ли пользователи
if (!empty($authors))
{
echo '<div class="author-entry">';
// перебираем каждого автора
foreach ($authors as $author)
{
$author_info = get_userdata($author->ID); ?>
<span style="float:left;padding:0 5px 0 0;"><?php echo get_avatar( $author->ID, 50 ); /* http://codex.wordpress.org/Function_Reference/get_avatar */ ?></span>
<span class="fn"><strong>Имя</strong> : <?php echo $author_info->first_name; ?></span><br />
<span class="ln"><strong>Фамилия</strong> : <?php echo $author_info->last_name; ?></span><br />
<span class="em"><strong>Email</strong> : <a href="mailto:<?php echo $author_info->user_email; ?>"><?php echo $author_info->user_email; ?></a></span><br />
<span class="we"><strong>Сайт</strong> : <a href="<?php echo $author_info->user_url; ?>"><?php echo $author_info->user_url; ?></a></span><br />
<span class="de"><strong>Биография</strong> :<br /><?php echo $author_info->description ; ?></span>
<div class="clear"> </div>
<?php
}
echo '</div>';
} else {
echo 'Авторы не найдены';
}
// получаем текущие параметры запроса
$query_string = $_SERVER['QUERY_STRING'];
// Переменная $base хранит полный URL нашей страницы, включая текущий аргумент страницы
// если в админке, базовый URL должен быть админ URL + ваша страница
$base = admin_url('your-page-path') . '?' . remove_query_arg('p', $query_string) . '%_%';
// если на фронтенде, базовый URL - текущая страница
//$base = get_permalink( get_the_ID() ) . '?' . remove_query_arg('p', $query_string) . '%_%';
echo paginate_links( array(
'base' => $base, // базовый URL, включая аргумент запроса
'format' => '&p=%#%', // определяет параметр запроса, который будет использоваться (в данном случае "p")
'prev_text' => __('« Назад'), // текст для предыдущей страницы
'next_text' => __('Вперед »'), // текст для следующей страницы
'total' => $total_pages, // общее количество страниц
'current' => $page, // текущая страница
'end_size' => 1,
'mid_size' => 5,
));

Спасибо за это @Pippin, я попробую, когда доберусь до студии. Один вопрос: что мне вставлять в часть 'your-page-path' в admin_url? Это корень моего сайта?

Страница, которая показывает ваших пользователей, находится в админке или на фронтенде?

Привет @Pippin, это на фронтенде, но мне было интересно, для чего нужна эта часть кода :)

Эта часть кода необходима для генерации ссылок пагинации. Функция paginate_links() должна знать, к какому URL добавлять параметры запроса. Я просто привел вам пример для админки и для фронтенда, но версию для админки можно игнорировать.

Мне очень нравится этот шаблон. Полностью рабочий вариант ;) большое спасибо. Для тех, кто копирует и вставляет (и, возможно, редактирует) — переменную $limit нужно заменить на $users_per_page. Похоже, это упустили, когда добавляли пояснения.

Интересный подход. Я заметил, что вы выполняете здесь 2 запроса: первый — чтобы получить всех пользователей, а второй — только пользователей на нужной странице. Не будет ли производительнее использовать всего 1 запрос, а затем разбивать результаты на страницы с помощью array_slice? Кажется, что раз вы работаете с одними и теми же данными в двух разных запросах, можно сэкономить ресурсы, убрав один из них.

Вам действительно не стоит использовать ответ от Pippin. Этот запрос очень неэффективен. В примере $user_count_query
может вернуть до 999,999 пользователей из вашей базы данных в скрипт, со всеми полями пользователей. Это почти наверняка приведёт к превышению лимитов памяти и/или времени выполнения PHP, если/когда ваш сайт вырастет достаточно большим.
Но в 2012 году это могло быть единственным решением.
Вот более правильный способ. В этом примере у меня есть только следующая и предыдущая страницы, но если вам нужна нумерованная пагинация, переменные для её реализации уже есть. Насколько мне известно, в WordPress нет встроенной функции пагинации, совместимой с WP_User_Query.
<?php
// Переменные пагинации
$current_page = get_query_var('paged') ? (int) get_query_var('paged') : 1;
$users_per_page = 2; // УВЕЛИЧЬТЕ ЭТО ЗНАЧЕНИЕ ПОСЛЕ ТЕСТИРОВАНИЯ ;)
$args = array(
'number' => $users_per_page, // Сколько пользователей на странице
'paged' => $current_page // Какую страницу получить, начиная с 1.
);
$users = new WP_User_Query( $args );
$total_users = $users->get_total(); // Общее количество пользователей (вне текущей страницы)
$num_pages = ceil($total_users / $users_per_page); // Сколько всего страниц с пользователями потребуется
?>
<h3>Страница <?php echo $current_page; ?> из <?php echo $num_pages; ?></h3>
<p>Отображается <?php echo $users_per_page; ?> из <?php echo $total_users; ?> пользователей</p>
<table>
<thead>
<tr>
<th>Имя</th>
<th>Фамилия</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<?php
if ( $users->get_results() ) foreach( $users->get_results() as $user ) {
$firstname = $user->first_name;
$lastname = $user->last_name;
$email = $user->user_email;
?>
<tr>
<td><?php echo esc_html($firstname); ?></td>
<td><?php echo esc_html($lastname); ?></td>
<td><?php echo esc_html($email); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
<p>
<?php
// Предыдущая страница
if ( $current_page > 1 ) {
echo '<a href="'. add_query_arg(array('paged' => $current_page-1)) .'">Предыдущая страница</a>';
}
// Следующая страница
if ( $current_page < $num_pages ) {
echo '<a href="'. add_query_arg(array('paged' => $current_page+1)) .'">Следующая страница</a>';
}
?>
</p>
Пример, показывающий страницу 2:
Обновление 8.06.2018: Как добавить номера страниц вместо "Следующая/Предыдущая"
Если вы хотите иметь нумерацию страниц вместо ссылок "Следующая/Предыдущая", вот как это можно реализовать. Обратите внимание, что вам нужно будет заменить номера на ссылки страниц, в этом примере они не кликабельны (основано на https://stackoverflow.com/a/11274294/470480, модифицировано для отображения постоянного количества средних номеров и без добавления "..." если страницы не пропущены).
Вы также можете посмотреть мой gist-файл, который содержит переиспользуемую функцию для этой цели.
$current_page = 5; // Пример
$num_pages = 10; // Пример
$edge_number_count = 2; // Можно изменить, необязательно
$start_number = $current_page - $edge_number_count;
$end_number = $current_page + $edge_number_count;
// Минус один, чтобы не разделять начальный номер без необходимости, например: "1 ... 2 3" должно начинаться как "1 2 3"
if ( ($start_number - 1) < 1 ) {
$start_number = 1;
$end_number = min($num_pages, $start_number + ($edge_number_count*2));
}
// Плюс один, чтобы не разделять конечный номер без необходимости, например: "8 9 ... 10" должно оставаться "8 9 10"
if ( ($end_number + 1) > $num_pages ) {
$end_number = $num_pages;
$start_number = max(1, $num_pages - ($edge_number_count*2));
}
if ($start_number > 1) echo " 1 ... ";
for($i=$start_number; $i<=$end_number; $i++) {
if ( $i === $current_page ) echo " [{$i}] ";
else echo " {$i} ";
}
if ($end_number < $num_pages) echo " ... {$num_pages} ";
Вывод (со страницы 1 по 10):
[1] 2 3 4 5 ... 10
1 [2] 3 4 5 ... 10
1 2 [3] 4 5 ... 10
1 2 3 [4] 5 ... 10
1 ... 3 4 [5] 6 7 ... 10
1 ... 4 5 [6] 7 8 ... 10
1 ... 6 [7] 8 9 10
1 ... 6 7 [8] 9 10
1 ... 6 7 8 [9] 10
1 ... 6 7 8 9 [10]

Согласен. Ответ Pippin требует 2 запроса к базе данных, чего по возможности следует избегать.

Привет @radley-sustaire, это отличное решение, но мне интересно, есть ли способ изменить часть "displaying 2 of 6 users" на фактический диапазон пользователей на странице. Например, "displaying 1-2 of 6" для страницы 1, "3-4 of 6" для страницы 2 и "5-6 of 6" для страницы 3. Сейчас везде отображается просто "2 of 6".

@damienoneill2001 Хорошая идея, можно начать с чего-то вроде: $start_user_num = (($current_page-1) * $users_per_page) + 1;
и $end_user_num = $start_user_num + count($users->get_results());
.

@RadleySustaire отлично, спасибо за это. Сначала я получил следующую ошибку: Call to a member function get_results() on a non-object
, поэтому я изменил $end_user_number
на $start_user_num + ($users_per_page-1);
, и это решило проблему. Ещё раз спасибо!

Оказалось, я поторопился с этим выводом. Когда я перехожу на последнюю страницу, которая не содержит полного списка пользователей, очевидно, отображается неправильное значение для $end_user_number
в моём решении. Придётся вернуться к чертёжной доске, ха!

Полная заслуга принадлежит @radley-sustaire за его ответ, но я заметил небольшую ошибку в нем, поэтому делюсь своей версией ответа здесь.
В моей версии я также фильтровал результаты по местоположению, ключевым словам и т.д., поэтому на некоторых страницах было меньше результатов, чем указано в переменной '$users_per_page'. Например, если у меня было установлено отображать 10 пользователей на странице, но результаты фильтра возвращали только 3 пользователя, вверху страницы появлялось сообщение "Displaying 10 of 3 users". Очевидно, это не имело смысла, поэтому я добавил простое условие "if" для проверки, является ли количество результатов больше переменной '$users_per_page'.
Radley, если ты отредактируешь свой ответ с этим обновлением, я с радостью проголосую за него как за правильный ответ, так как считаю его лучше решения Pippin.
Вот окончательный код для тех, кому он нужен.
<?php
// Переменные пагинации
$current_page = get_query_var('paged') ? (int) get_query_var('paged') : 1;
$users_per_page = 10;
$args = array(
'number' => $users_per_page, // Сколько показывать на странице
'paged' => $current_page // Какую страницу получать, начиная с 1.
);
$users = new WP_User_Query( $args );
$total_users = $users->get_total(); // Общее количество пользователей (за пределами текущей страницы)
$num_pages = ceil($total_users / $users_per_page); // Сколько страниц с пользователями нам понадобится
if ($total_users < $users_per_page) {$users_per_page = $total_users;}
?>
<h3>Страница <?php echo $current_page; ?> из <?php echo $num_pages; ?></h3>
<p>Показано <?php echo $users_per_page; ?> из <?php echo $total_users; ?> пользователей</p>
<table>
<thead>
<tr>
<th>Имя</th>
<th>Фамилия</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<?php
if ( $users->get_results() ) foreach( $users->get_results() as $user ) {
$firstname = $user->first_name;
$lastname = $user->last_name;
$email = $user->user_email;
?>
<tr>
<td><?php echo esc_html($firstname); ?></td>
<td><?php echo esc_html($lastname); ?></td>
<td><?php echo esc_html($email); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
<p>
<?php
// Предыдущая страница
if ( $current_page > 1 ) {
echo '<a href="'. add_query_arg(array('paged' => $current_page-1)) .'">Предыдущая страница</a>';
}
// Следующая страница
if ( $current_page < $num_pages ) {
echo '<a href="'. add_query_arg(array('paged' => $current_page+1)) .'">Следующая страница</a>';
}
?>
</p>
