Случайный сортировка по уже отсортированному запросу

У меня есть рабочий запрос, который возвращает набор пользовательских сообщений, которые упорядочены по их идентификатору пакета (ASC). Для запроса с 9 результатами это может вернуться, например:

4 сообщения (Идентификатор сообщения 1,2,3,4) с идентификатором пакета 1

3 сообщения (5,6,7 идентификаторов сообщений) с идентификатором пакета 2

2 сообщения (идентификатор сообщения 8,9) с идентификатором пакета 3

Когда эти сообщения отображаются, они всегда находятся в одном порядке. Другими словами, они отображаются в порядке от Почтового Идентификатора 1 к сообщению ID 9.

То, что я пытаюсь достичь, – сортировать результаты каждого подмножества (определяемого идентификатором пакета) случайным образом. Таким образом, сообщения будут отображаться как таковые:

Случайное отображение идентификаторов сообщений от 1 до 4 (например, 2,1,4,3)

Случайное отображение идентификационных номеров от 5 до 7 (например, 6,5,7)

Случайное отображение сообщений от 8 до 9 (например, 8,9)

Таким образом, сообщения по-прежнему группируются по идентификатору пакета, но сообщения в каждом пакете отображаются случайным образом.

Вот как выглядит мой текущий запрос:

$args = array( 'post_type' => 'custom_post_type', 'post_status' => 'publish', 'posts_per_page' => 9, 'meta_key' => 'pkg_id', 'orderby' => 'pkg_id', 'order' => 'ASC' ); 

То, что я думал, «может» работать, но не делает:

 $args = array( 'post_type' => 'custom_post_type', 'post_status' => 'publish', 'posts_per_page' => 9, 'meta_key' => 'pkg_id', 'orderby' => array( 'pkg_id' => 'ASC', 'rand' ) ); 

Любые предложения, поскольку я полностью в тупике!

Solutions Collecting From Web of "Случайный сортировка по уже отсортированному запросу"

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

Я полагаю, что это пользовательский запрос из того, что я прочитал в вашем вопросе, поэтому мы можем сделать следующее:

  • Во-первых, мы хотим ввести пользовательский параметр WP_Query чтобы мы могли использовать этот параметр в качестве триггера для нашего фильтра the_posts . Мы будем называть этот параметр n wpse_custom_sort и он примет значение true , чтобы вызвать фильтр

  • Затем мы будем использовать фильтр the_posts для сортировки сообщений в соответствии с настраиваемым полем, а затем сортируем их по произвольно на пользовательское поле и, наконец, возвращаем отсортированные сообщения

КОД

Всего несколько заметок, хотя

  • Код непроверен и требует, по крайней мере, PHP 5.4

  • Я использовал get_post_meta() чтобы возвращать значения настраиваемого поля за сообщение, поскольку вы используете ACF, вам может потребоваться настроить это, чтобы использовать get_field() . Я не знаком с ACF, поэтому вам нужно будет отсортировать эту часть. Логика все равно осталась бы такой же, хотя

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

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

 // Run your query normally $args = [ 'wpse_custom_sort' => true, // This parameter will trigger or the_posts filter // Your query args here ]; $q = new WP_Query( $args ); // Your loop as normal 

Теперь мы запустим наш фильтр ( это входит в functions.php или предпочтительно в пользовательский плагин )

 /** * Function to flatten a multidimentional array (for later use) * * Credit to zdenko * @link https://gist.github.com/kohnmd/11197713 */ function flatten_array( $arg ) { return is_array( $arg ) ? array_reduce( $arg, function ( $c, $a ) { return array_merge( $c, flatten_array( $a ) ); }, [] ) : [$arg]; } // The the_posts filter add_filter( 'the_posts', function ( $posts, $q ) { // First we need remove our filter remove_filter( current_filter(), __FUNCTION__ ); // Check if our custom parameter is set and is true, if not, bail early if ( true !== $q->get( 'wpse_custom_sort' ) ) return $posts; // Before we do any work, and to avoid WSOD, make sure that the flatten_array function exists if ( !function_exists( 'flatten_array' ) ) return $posts; // Our custom parameter is available and true, lets continue // Loop through the posts $major_array = []; foreach ( $posts as $p ) { $meta = get_post_meta( $p->ID, 'pkg_id', true ); // Bail if we do not have a $meta value, just to be safe if ( !$meta ) continue; // Sanitize the value $meta = filter_var( $meta, FILTER_SANITIZE_STRING ); // Lets build our array $major_array[$meta][] = $p; } // Make sure we have a value for $major_array, if not, bail if ( !$major_array ) return $posts; // Lets randomize the posts under each custom field $sorted = []; foreach ( $major_array as $field ) $sorted[] = shuffle( $field ); // Lets flatten and return the array of posts $posts = flatten_array( $sorted ); return array_values( $posts ); }, 10, 2 ); 

Невозможно с одним запросом вам нужно будет сделать 3 отдельных запроса, каждый из которых будет нацелен на разные «Идентификаторы пакетов» и закажет эти запросы как rand.

 $args1 = array( 'post_type' => 'custom_post_type', 'orderby' => 'rand', 'meta_query' => array( array( 'key' => 'pkg_id', 'value' => 1, // you will have to check if this is correct ) ) ); $args2 = array( 'post_type' => 'custom_post_type', 'orderby' => 'rand', 'meta_query' => array( array( 'key' => 'pkg_id', 'value' => 2, // you will have to check if this is correct ) ) ); $args3 = array( 'post_type' => 'custom_post_type', 'orderby' => 'rand', 'meta_query' => array( array( 'key' => 'pkg_id', 'value' => 3, // you will have to check if this is correct ) ) ); 

Это будет разделять ваши сообщения в их «Идентификатор пакета» и заказывать каждый набор как Random

Если мы используем:

 $args = array( 'post_type' => 'custom_post_type', 'post_status' => 'publish', 'posts_per_page' => 9, 'meta_key' => 'pkg_id', 'orderby' => array( 'pkg_id' => 'ASC', 'rand' => 'DESC' ) ); 

то мы получаем часть заказа как:

 ORDER BY wp_postmeta.meta_value ASC, RAND() DESC 

Это похоже на работу, но DESC не требуется.

Но обратите внимание, что упорядочение по RAND() не очень хорошо масштабируется. В этом случае метод @PieterGoosen может быть лучше подходит вам.