Получить все дочерние страницы родительской страницы с помощью WP Query
Вот мой код
$my_wp_query = new WP_Query();
$all_wp_pages = $my_wp_query->query(array('post_type' => 'page','post_parent'=>$parid,'orderby'=>'title','order'=>'ASC' ));
Он отображает только дочерние страницы первого уровня. Мне нужны все дочерние страницы, дочерние страницы дочерних страниц... и все остальные. Я искал решение и могу получить все дочерние страницы с помощью get_pages и wp_list_pages.
Но мне действительно нужно отсортировать порядок по значению произвольного мета-поля. Поэтому я должен использовать пользовательский запрос.
пожалуйста, помогите. Спасибо

Почему бы просто не использовать get_pages()
?
Например:
<?php
// Определяем ID родительской страницы
$parent_page_id = ( '0' != $post->post_parent ? $post->post_parent : $post->ID );
// Получаем дочерние страницы в виде массива
$page_tree_array = get_pages( array(
'child_of' => $parent_page_id;
) );
?>
Но если действительно необходимо получить объект WP_Query()
, используйте аналогичный метод:
<?php
// Определяем ID родительской страницы
$parent_page_id = ( '0' != $post->post_parent ? $post->post_parent : $post->ID );
// Формируем массив аргументов для WP_Query()
$page_tree_query_args = array(
'post_parent' => $parent_page_id;
);
// Получаем дочерние страницы в виде объекта WP_Query()
$page_tree_query = new WP_Query( $page_tree_query_args );
?>

Если мы используем функцию get_pages(), мы не сможем реализовать сортировку (sort_column) для произвольных полей. Она принимает только поля таблицы post. Мне нужно реализовать сортировку для произвольного поля. Поэтому я использую wp_query(). Есть ли альтернативный способ?

Вы видели вторую часть моего ответа, где я использую WP_Query()
?

Я попробовал этот код, но он возвращает только страницы первого уровня подчинения. Мне нужны подстраницы >> их подстраницы >> и т.д. (множественные уровни вложенности страниц). В итоге я нашел решение. Спасибо за ваш ответ.

Проблема
То, с чем у вас возникают сложности — "Как сделать X?" Это не одношаговое действие, а многоэтапный процесс, который нужно разбить на части.
Вам не нужно делать так:
получить все записи, которые являются дочерними для X, отсортированные по метаполю
Вам нужно сделать так:
получить все записи, которые являются дочерними для X
для каждой дочерней записи получить все её дочерние записи
для каждой дочерней записи получить все её дочерние записи
...
упс, больше нет дочерних записей
Взять наш список записей и отсортировать их по метаполю
Общее решение
Чтобы понять, как делать это бесконечно, пока не достигнете конца, без жесткого кодирования, вам нужно понять рекурсивные функции.
Например:
function make_zero( $amount ) {
$amount = $amount - 1;
if ( $amount > 1 ){
return make_zero( $amount );
}
return $amount;
}
Применение рекурсии к этой проблеме для решения
Итак, ваш родительский элемент — это $parid
, а метаполе записи имеет ключ $metakey
.
Давайте передадим его в функцию для получения дочерних элементов.
$children = get_children_with_meta( $parid, $metakey );
Затем мы отсортируем массив $children, где ключи — это ID записей, а значения — значения метаполей.
asort($children);
И определим функцию следующим образом:
function get_children_with_meta( $parent_id, $metakey ) {
$q = new WP_Query( array( 'post_parent' => $parent_id, 'meta_key' => $metakey ));
if ( $q->have_posts() ) {
$children - array();
while ( $q->have_posts() ) {
$q->the_post();
$meta_value = get_post_meta(get_the_ID(), $metakey, true );
$children[get_the_ID() ] = $meta_value;
}
return $children;
} else {
// нет дочерних элементов!!
return array();
}
}
Это дает вам массив ID записей и их значений, отсортированных от наименьшего к наибольшему. Вы можете использовать другие функции сортировки PHP для обратного порядка.
А что насчет дочерних элементов дочерних элементов?
В середине нашего цикла нам нужно сделать рекурсивный вызов, передавая ID дочернего элемента вместо родительского.
Так что это:
$q->the_post();
$meta_value = get_post_meta(get_the_ID(), $metakey, true );
$children[get_the_ID() ] = $meta_value;
Превращается в это:
$q->the_post();
$meta_value = get_post_meta(get_the_ID(), $metakey, true );
$children[get_the_ID() ] = $meta_value;
// теперь получаем дочерние элементы дочерних элементов
$grandchildren = get_children_with_meta( get_the_ID(), $metakey );
// объединяем дочерние и дочерние дочерних элементов в один список
$children = array_merge( $children, $grandchildren );
С этим изменением функция теперь получает дочерние элементы, дочерние элементы дочерних элементов, дочерние элементы дочерних элементов дочерних элементов..... и так далее.
В конце вы можете обрезать значения массива, чтобы получить ID таким образом:
$post_ids = array_keys( $children );
$q = new WP_Query( array( 'post__in' => $post_ids );
// и т.д.
Используя эту стратегию, вы можете заменить значение метаполя на любой другой критерий или использовать рекурсивные функции другими способами.
Поскольку полный код требует лишь нескольких секунд базового понимания и быстрого копирования-вставки, я не буду оскорблять ваш интеллект полным блоком кода для копирования.
Преимущества
- С модификацией работает для любого типа записей и формы данных
- Может быть модифицирован для генерации вложенной разметки
- Легко кэшируется для ускорения, помещая возвращаемые массивы в транзиенты
- Может быть настроен с постраничной навигацией, применяя её к конечному WP_Query
Проблемы, с которыми вы столкнетесь
- У вас нет способа узнать, сколько дочерних элементов существует, пока вы их не найдете, поэтому производительность не масштабируется
- То, что вы хотите, сгенерирует множество запросов и по своей природе затратно из-за потенциальной глубины вложенности.
Моя рекомендация
Я бы рекомендовал либо упростить вашу иерархию страниц, либо использовать таксономию вместо этого. Например, если вы оцениваете записи, создайте таксономию "Рейтинг страницы" с терминами 1, 2, 3, 4 и 5 и т.д. Это предоставит вам список записей "из коробки".
Альтернативно, используйте навигационные меню и полностью обойдите эту проблему.

Рекурсивное получение всех дочерних страниц
Рекурсивный подход с использованием get_children
. Поместите следующий код в ваш файл functions.php
:
function get_all_subpages($page, $args = '', $output = OBJECT) {
// Проверка параметра 'page'
if (! is_numeric($page))
$page = 0;
// Настройка аргументов
$default_args = array(
'post_type' => 'page',
);
if (empty($args))
$args = array();
elseif (! is_array($args))
if (is_string($args))
parse_str($args, $args);
else
$args = array();
$args = array_merge($default_args, $args);
$args['post_parent'] = $page;
// Проверка параметра 'output'
$valid_output = array(OBJECT, ARRAY_A, ARRAY_N);
if (! in_array($output, $valid_output))
$output = OBJECT;
// Получение дочерних страниц
$subpages = array();
$children = get_children($args, $output);
foreach ($children as $child) {
$subpages[] = $child;
if (OBJECT === $output)
$page = $child->ID;
elseif (ARRAY_A === $output)
$page = $child['ID'];
else
$page = $child[0];
// Рекурсивное получение подстраниц
$subpages = array_merge($subpages, get_all_subpages($page, $args, $output));
}
return $subpages;
}
Как использовать
Используйте эту функцию там, где вам нужно, например так:
$all_current_subpages = get_all_subpages(0);
Функция поддерживает параметр args
(строка запроса или массив) и тип output
(см. выше).
Также можно использовать следующим образом:
$args = array(
'post_status' => 'private',
'order_by' => 'post_date',
'order' => 'DESC',
);
$all_current_subpages = get_all_subpages(42, $args, ARRAY_A);
Благодаря зависимости get_children
=> get_posts
=> WP_Query
вы можете использовать мета-значения, как изначально запрашивал автор вопроса.

Я создал рекурсивную функцию, которая получает все ID дочерних страниц родительской страницы. После получения ID мы делаем запрос для страниц и можем упорядочить результаты по мета-ключу/значению.
// Получает все ID дочерних страниц post_parent
function _get_children_ids( $post_parent ) {
$results = new WP_Query( array(
'post_type' => 'page',
'post_parent' => $post_parent
) );
$child_ids = array();
if ( $results->found_posts > 0 )
foreach ( $results->posts as $post ) // добавляем каждый ID дочерней страницы в массив
$child_ids[] = $post->ID;
if ( ! empty( $child_ids ) )
foreach ( $child_ids as $child_id ) // добавляем дальнейших потомков в массив
$child_ids = array_merge( $child_ids, _get_children_ids( $child_id ) );
return $child_ids;
}
$children_ids = _get_children_ids( 9 ); // используйте ваш числовой ID страницы или get_the_id()
$results = new WP_Query( array(
'post_type' => 'page',
'post__in' => $children_ids
#'meta_key' => 'meta_key', // ваш мета-ключ
#'orderby' => 'meta_key',
/* 'meta_query' => array( // опциональный meta_query
array(
'key' => 'meta_key', // ключ
'value' => array(3, 4), // значения
'compare' => 'IN', // оператор
)
) */
) );
var_dump( $results );
Если вам нужно отсортировать дочерние страницы по мета-ключу/значению в иерархическом порядке, вы должны передать значения meta_key и order_by в WP_Query внутри функции _get_children_ids (вместо финального WP_Query).
Если это не требуется, более простой способ получить все ID дочерних страниц:
$children = get_pages( 'child_of=9');
$children_ids = array();
if ( ! empty( $children ) )
foreach ( $children as $post )
$children_ids[] = $post->ID;

Не уверен, что это именно то, что вам нужно, но вы можете использовать функцию wp_list_pages с параметрами 'child_of' и 'depth'.
Подробнее об этом можно прочитать на странице Кодекса: http://codex.wordpress.org/Function_Reference/wp_list_pages

ЭТО РАБОТАЕТ, ПРОСТО СКОПИРУЙТЕ И ВСТАВЬТЕ КОД В ВАШ ФАЙЛ PAGE.PHP
//ПЕРЕНАПРАВЛЕНИЕ НА ПЕРВУЮ ДОЧЕРНЮЮ СТРАНИЦУ ИЗ РОДИТЕЛЬСКОЙ
// Формируем аргументы для WP_Query()
$page_tree_query_args = array(
'post_parent' => $post -> ID,
'post_type' => 'page',
'order' => 'asc'
);
// Получаем дочерние страницы в виде объекта WP_Query()
$page_tree_query = new WP_Query( $page_tree_query_args );
if(!empty($page_tree_query -> posts)){
$first_subpage = $page_tree_query -> posts[0] -> ID;
wp_redirect( get_permalink( $first_subpage ) );
exit;
}
