Случайные записи в wp_query

23 авг. 2017 г., 15:16:44
Просмотры: 25.6K
Голосов: 1

Я хочу показывать все записи в виде mywebsite.com/postname/1/, mywebsite.com/postname/2/ ...... mywebsite.com/postname/7/ ..

Код ниже работает отлично, единственная проблема в том, что он показывает только первые записи mywebsite.com/postname/...

Как это можно реализовать?

<?php
/**
 * Template Name: Random Post
 * Этот шаблон будет отображать только контент, который вы ввели в редакторе страниц
 */
?>

<html>
<head>

</head>
<body>

<?php
/*
Выбор случайной записи
Используйте на странице для перенаправления посетителя на случайную запись с возможностью модификации запроса
*/

// установка аргументов для WP_Query для получения 1 случайной опубликованной записи
$args = array(
    'post_type' => 'post',
    'post_status' => 'publish',
    'orderby' => 'rand',
    'order' => 'DESC',

    // Использование date_query для фильтрации записей за последнюю неделю
    'date_query' => array(
        array(
            'after' => '2 week ago'
        )
    )
); 

// Время пришло! Идем в случайное место
$my_random_post = new WP_Query ( $args );

while ( $my_random_post->have_posts () ) {
  $my_random_post->the_post ();

  // перенаправление на случайную запись
  wp_redirect ( get_permalink () );
  exit;
}
?>

</body>
</html>
3
Комментарии

Имейте в виду, что сортировка с помощью rand чрезвычайно медленная и ресурсоемкая, а эта страница не может кэшироваться. Любой более-менее компетентный хакер теперь может легко запустить атаку типа "отказ в обслуживании", просто многократно запрашивая этот URL, чтобы перегрузить ваш сервер базы данных из-за исчерпания ресурсов.

Tom J Nowell Tom J Nowell
23 авг. 2017 г. 16:01:21

Я думаю, у хакера найдется дела поважнее, чем атаковать мой сервер.it — это всего лишь локальный сайт, а не топовый ресурс. Что касается "медленно" — одновременно онлайн будет не больше 50-100 пользователей. Но мы все же можем заменить "rand" на что-то другое. Сначала мне нужно добиться, чтобы все работало так, как я хочу.

adi kica adi kica
23 авг. 2017 г. 16:23:49

Я имел в виду всего 4-5 одновременных пользователей, когда писал свой комментарий, но эту проблему можно полностью обойти — мое решение ниже будет масштабироваться до миллиардов одновременных пользователей, обеспечивая при этом значительно более быструю загрузку страниц.

Tom J Nowell Tom J Nowell
23 авг. 2017 г. 16:36:37
Все ответы на вопрос 3
10

Делать это в PHP — ужасная идея:

  • Эту страницу невозможно кэшировать
  • Сортировка в случайном порядке крайне ресурсоемка для запроса, так как включает создание временных таблиц в базе данных, полное сканирование, поскольку необходимо скопировать всю таблицу постов, затем случайным образом переупорядочить записи, и только после этого выполнить фактический запрос к новой таблице перед ее уничтожением
  • Это делает вас уязвимыми к атакам на исчерпание ресурсов

Например, эта команда будет многократно обращаться к вашему URL со случайным постом. Если выполнить ее достаточное количество раз на достаточном количестве компьютеров, это приведет к отказу базы данных:

for i in `seq 1 20000`; do curl http://mywebsite.com/postname; done

Если вы используете дешевый shared-хостинг, может быть достаточно открыть ваш URL в нескольких вкладках браузера одновременно, чтобы вызвать проблемы.

Не говоря уже о том, что ваш редирект отправляет HTTP-заголовки, но код выводит теги заранее, поэтому заголовки уже были отправлены, что приводит к ошибкам и предупреждениям PHP.

Супербыстрая и простая альтернатива

Вместо этого выполните обычный запрос, упорядоченный по дате, и выведите данные в формате JSON. Затем в JavaScript на стороне браузера случайным образом выберите один из этих постов и выполните редирект на клиентской стороне.

Таким образом, страница может кэшироваться, ваша база данных защищена, а вся тяжелая работа выполняется браузером. Запрос к базе данных будет выполняться гораздо быстрее.

Теперь ваша задача сводится к выводу данных в виде списка, случайному выбору элемента из этого списка в JS и использованию window.location= ... для редиректа. Знания WP для этого не требуются.

23 авг. 2017 г. 16:11:09
Комментарии

+1 за клиентскую альтернативу. Но один вопрос: установка random в WP_Query выберет случайный пост из, скажем, 15 000 постов. Но эффективно ли отправлять JSON-ответ, содержащий как минимум 15К строк в браузер?

Johansson Johansson
25 авг. 2017 г. 17:11:30

Нет, отправка 15k постов неэффективна, как и запрос 15k постов. Любые операции с random и базами данных будут чрезмерно затратными. Вместо этого предоставьте более разумный выбор, например, 20 последних постов или 20 постов с наибольшим количеством комментариев. Существует так много альтернатив random при выводе постов, и random редко означает то, что люди под ним подразумевают. Если сайт вернет один и тот же пост 10 раз, это будет валидным результатом действительно случайного выбора, как и 5 постов подряд, но люди обычно имеют в виду 10 постов, равномерно распределенных по всему диапазону.

Tom J Nowell Tom J Nowell
25 авг. 2017 г. 19:56:04

Итак, что вы предлагаете для блога с тысячами постов? Хорошая ли идея — установить случайное смещение (offset) и затем запрашивать 1 пост?

Johansson Johansson
25 авг. 2017 г. 20:54:48

нет, мое предложение — не пытаться случайным образом выбирать из тысяч постов, так же как снятие £1 млн из банка одинаково затратно, независимо от того, делаете ли вы это через карту, чек или другими способами. Случайный выбор — плохая идея, по-настоящему случайный — еще хуже, вам придется идти на компромисс и создавать видимость случайности или ограничивать область выбора. Существует огромное количество альтернатив, которые выглядят так же, но получить по-настоящему случайное число из 15 тыс. постов, не зная их всех заранее, принципиально дорого

Tom J Nowell Tom J Nowell
25 авг. 2017 г. 21:40:31

Интересно. Но если пользователь просматривает кэшированную версию страницы (кэширование страниц), это не имеет значения, верно? Очевидно, случайно выбранный пост останется тем же, пока кэш не будет сброшен. Если только, конечно, 'orderby' => 'rand' не вызывает фрагментированное кэширование...

Christine Cooper Christine Cooper
11 июн. 2018 г. 13:59:15

Да, вам придется кэшировать только эти части страницы, если только вы не сделаете это через JavaScript. В любом случае, случайный выбор — ужасная идея, и он никогда не означает то, что вы задумали

Tom J Nowell Tom J Nowell
11 июн. 2018 г. 18:34:49

Привет, Том, я знаю, что этот пост старый, но не мог бы ты привести пример с использованием JSON? Я даже не знаю, с чего начать.

rudtek rudtek
13 мар. 2019 г. 21:17:18

@rudtek любой REST API endpoint возвращает данные в формате JSON, а JSON — это то же самое, что объекты и массивы в JavaScript. Например, [1,2,3,4,5] — это JSON, а также массив в JavaScript. Как случайно выбрать элемент из массива в JS — это вопрос для StackOverflow. Как декодировать JSON-ответ из AJAX-запроса — тоже вопрос для StackOverflow. Как включить массив элементов в HTML-страницу для использования в JS — аналогично. Для всего остального есть json_encode, стандартный ванильный PHP. Честно говоря, тут очень мало связано с WordPress, если вообще есть.

Tom J Nowell Tom J Nowell
13 мар. 2019 г. 22:17:30

Также есть промежуточный способ в PHP: shuffle($my_random_post->posts) — если использовать его непосредственно перед циклом — создаст "случайный" порядок. Но учтите, что сортировка большого количества постов СЛУЧАЙНЫМ образом всегда будет очень затратной, и лучше обрабатывать это в браузере, как предлагает @TomJNowell!

jave.web jave.web
11 авг. 2019 г. 08:24:40

Перемешивание также работает в PHP, основная нагрузка связана с тем, что случайность обрабатывается базой данных. Если вы можете перенести эту задачу в другое место — будь то PHP, браузер или предварительные вычисления — это даст значительный прирост производительности.

Tom J Nowell Tom J Nowell
12 авг. 2019 г. 16:36:25
Показать остальные 5 комментариев
6

Только один пост отображается на вашей стороне, потому что вы используете exit() в вашем цикле. В вашем коде, когда WP_Query начинает работу, цикл завершается после первого прохода. Удалите exit() и используйте этот код:

<?php
/*
 * Выбор случайного поста
 * Используйте на странице для перенаправления посетителя на случайный пост с возможностью модификации запроса
 */

// Устанавливаем аргументы для WP_Query, чтобы получить 1 случайный опубликованный пост
$args = array(
    'post_type' => 'post',
    'post_status' => 'publish',
    'orderby' => 'rand',
    'order' => 'DESC',

    // Используем date_query для фильтрации постов за последние 2 недели
    'date_query' => array(
        array(
            'after' => '2 week ago'
        )
    )
);

// Время действовать! Переходим на случайный пост
$my_random_post = new WP_Query ( $args );
if($my_random_post->have_posts()){
    while ( $my_random_post->have_posts () ) {
        $my_random_post->the_post ();
        echo '<a href="'.get_the_permalink().'">'.get_the_title().'</a>';
    }
}
?>
23 авг. 2017 г. 15:50:20
Комментарии

Я хочу, чтобы отображалась только одна запись, и чтобы происходил редирект на полный пост. Шаблон использует "mywebsite.com/random/,,,, когда посетитель использует mywebsite.com/random/, я хочу, чтобы пользователь перенаправлялся на полный пост, но случайным образом среди всех постов, как я объяснил "mywebsite.com/postname/15/..... и так далее, пост выглядит как галерея с кнопкой "следующий пост". Я хочу, чтобы посетитель перенаправлялся случайным образом на какой-то номер поста, а не просто на пост.

adi kica adi kica
23 авг. 2017 г. 16:08:28

Вы хотите перенаправить пользователя на другую страницу.

Jitender Singh Jitender Singh
23 авг. 2017 г. 16:38:08

Используя мою случайную страницу, я перенаправляю пользователей на случайный пост. Тот же домен. mypage.com/random/ на mypage.com/somepost/ .... mypage.com/anotherpost/.... до этого момента все ок, я хочу больше... > mypage.com/somepost/2/..mypage.com/somepost/3

adi kica adi kica
23 авг. 2017 г. 16:45:56

Извините, я не понял вас. Скажите сначала: эта ссылка на код не работает или вы хотите изменить постоянные ссылки записей? Пожалуйста, уточните вашу задачу.

Jitender Singh Jitender Singh
23 авг. 2017 г. 17:05:07

@adikica если вы делаете редирект средствами PHP => вы должны сделать это ДО вывода любого HTML-кода ... а не в середине шаблона - вы можете использовать клиентский редирект на JavaScript или хук template_redirect

jave.web jave.web
11 авг. 2019 г. 08:20:15

@adikica Также, если вы вызываете exit() после первой записи, то это не цикл - так что используйте просто оператор if

jave.web jave.web
11 авг. 2019 г. 08:21:00
Показать остальные 1 комментариев
0

Вам не нужно перенаправлять пользователя на страницу со случайной записью, и вы даже не сможете этого сделать, если захотите, так как нельзя перенаправить одновременно в несколько мест.

Поэтому просто выводите случайные записи внутри вашего цикла:

while ( $my_random_post->have_posts () ) {
  $my_random_post->the_post ();
  echo '<a href="'.get_the_permalink().'">'.get_the_title().'</a>';
}
23 авг. 2017 г. 15:36:03