Obtener todas las subpáginas del padre usando wp query
Aquí está mi código
$my_wp_query = new WP_Query();
$all_wp_pages = $my_wp_query->query(array('post_type' => 'page','post_parent'=>$parid,'orderby'=>'title','order'=>'ASC' ));
Esto muestra solo las subpáginas del primer nivel. Necesito todas las subpáginas, las subpáginas de las subpáginas... y todas. He buscado una solución y puedo obtener todas las subpáginas usando get_pages y wp_list_pages.
Pero realmente necesito ordenar por valor de meta personalizado. Así que tengo que usar una consulta personalizada.
Por favor ayuda. Gracias

¿Por qué no simplemente usar get_pages()
?
Por ejemplo:
<?php
// Determinar el ID de la página padre
$parent_page_id = ( '0' != $post->post_parent ? $post->post_parent : $post->ID );
// Obtener páginas hijas como un array
$page_tree_array = get_pages( array(
'child_of' => $parent_page_id;
) );
?>
Pero si realmente debe ser un objeto WP_Query()
, usa un método similar:
<?php
// Determinar el ID de la página padre
$parent_page_id = ( '0' != $post->post_parent ? $post->post_parent : $post->ID );
// Construir el array de argumentos para WP_Query()
$page_tree_query_args = array(
'post_parent' => $parent_page_id;
);
// Obtener páginas hijas como objeto WP_Query()
$page_tree_query = new WP_Query( $page_tree_query_args );
?>

Si usamos la funcionalidad get_pages() no podríamos implementar el ordenamiento (sort_column) para campos personalizados. Solo acepta campos de la tabla de posts. Necesito implementar el ordenamiento para campos personalizados. Por eso usé wp_query(). ¿Hay alguna alternativa?

Probé este código pero solo devuelve las subpáginas de primer nivel. Necesito subpágina >> sub de sub >> etc... (múltiples niveles inferiores de páginas). Finalmente encontré la solución. Gracias por tu respuesta

El Problema
Lo que te está costando entender es "¿Cómo hago X?" Esto no es una acción de un solo paso, es un proceso de múltiples pasos y necesita ser desglosado.
No necesitas hacer esto:
obtener todos los posts que son hijos de X ordenados por meta
Necesitas hacer esto:
obtener todos los posts que son hijos de X
para cada hijo, obtener todos los posts que son hijos
para cada hijo de ese hijo obtener todos los posts que son hijos
...
hmmm ya no nos quedan más hijos
Tomar nuestra lista de posts y ordenarlos por meta
La Solución General
Entonces, para entender cómo hacerlo infinitamente hasta llegar al final, sin codificarlo manualmente, necesitas comprender las funciones recursivas.
ejemplo:
function make_zero( $amount ) {
$amount = $amount - 1;
if ( $amount > 1 ){
return make_zero( $amount );
}
return $amount;
}
Aplicando Recursión a Este Problema para una Solución
Entonces tu padre es $parid
, y tu meta post tiene una clave de $metakey
.
Vamos a pasarlo a una función para obtener sus hijos.
$children = get_children_with_meta( $parid, $metakey );
Luego ordenaremos el array $children, las claves serán los IDs de los posts y los valores serán los valores meta.
asort($children);
y definamos la función como:
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 {
// ¡¡no hay hijos!!
return array();
}
}
Esto te da un array de IDs de posts y valores, ordenados de menor a mayor. Puedes usar otras funciones de ordenamiento de PHP para hacerlo de mayor a menor.
¿Y Qué Hay de los Hijos de los Hijos?
En medio de nuestro bucle, necesitamos hacer una llamada recursiva, pasando el ID del hijo en lugar del ID del padre.
Entonces esto:
$q->the_post();
$meta_value = get_post_meta(get_the_ID(), $metakey, true );
$children[get_the_ID() ] = $meta_value;
Se convierte en esto:
$q->the_post();
$meta_value = get_post_meta(get_the_ID(), $metakey, true );
$children[get_the_ID() ] = $meta_value;
// ahora obtenemos los hijos de los hijos
$grandchildren = get_children_with_meta( get_the_ID(), $metakey );
// fusionamos los nietos y los hijos en la misma lista
$children = array_merge( $children, $grandchildren );
Con esta modificación, la función ahora recupera los hijos, los hijos de los hijos, los hijos de los hijos de los hijos..... etc.
Al final puedes recortar los valores del array para obtener IDs así:
$post_ids = array_keys( $children );
$q = new WP_Query( array( 'post__in' => $post_ids );
// etc
Usando esta estrategia, puedes reemplazar el valor de la clave meta con cualquier otra métrica, o usar funciones recursivas de otras maneras.
Dado que el código completo requiere solo unos segundos de comprensión básica y un rápido copiar y pegar, no insultaré tu inteligencia con un bloque de código completo para copiar y pegar.
Ventajas
- Con modificación funciona para cualquier tipo de post y forma de datos
- Puede modificarse para generar marcado anidado
- Fácilmente cacheable para acelerar guardando los arrays retornados en transients
- Se puede configurar con paginación aplicándola al WP_Query final
Problemas que Encontrarás
- No tienes forma de saber cuántos hijos hay hasta que los hayas encontrado, por lo que los costos de rendimiento no escalan
- Lo que quieres generará muchas consultas y es inherentemente costoso debido a las posibles profundidades involucradas.
Mi Recomendación
Recomendaría que aplanes tu jerarquía de páginas o uses una taxonomía en su lugar. Ej. si estás calificando posts, ten una taxonomía "Page Rating" con los términos 1,2,3,4 y 5 etc. Esto te proporcionará un listado de posts listo para usar.
Alternativamente, usa menús de navegación y evita este problema por completo

Obtener recursivamente todas las subpáginas actuales
Aquí tienes un enfoque recursivo usando get_children
. Coloca lo siguiente en tu functions.php
:
function get_all_subpages($page, $args = '', $output = OBJECT) {
// Validar parámetro 'page'
if (! is_numeric($page))
$page = 0;
// Configurar argumentos
$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;
// Validar parámetro 'output'
$valid_output = array(OBJECT, ARRAY_A, ARRAY_N);
if (! in_array($output, $valid_output))
$output = OBJECT;
// Obtener hijos
$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];
// Obtener subpáginas mediante recursión
$subpages = array_merge($subpages, get_all_subpages($page, $args, $output));
}
return $subpages;
}
Cómo usarla
Usa la función anterior donde quieras, por ejemplo así:
$all_current_subpages = get_all_subpages(0);
La función soporta un parámetro args
(cadena de consulta o array) y un tipo de output
(ver arriba).
Así que también podrías usarla así:
$args = array(
'post_status' => 'private',
'order_by' => 'post_date',
'order' => 'DESC',
);
$all_current_subpages = get_all_subpages(42, $args, ARRAY_A);
Y debido a la dependencia get_children
=> get_posts
=> WP_Query
puedes usar valores meta, como inicialmente solicitó el autor de esta pregunta.

He creado una función recursiva que obtiene todos los IDs de las páginas hijas de una página padre. Una vez que tenemos los IDs, hacemos una consulta para las páginas y podemos ordenar los resultados por clave/valor meta.
// Obtiene todos los IDs de los hijos de 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 ) // añade cada ID hijo al array
$child_ids[] = $post->ID;
if ( ! empty( $child_ids ) )
foreach ( $child_ids as $child_id ) // añade más hijos al array
$child_ids = array_merge( $child_ids, _get_children_ids( $child_id ) );
return $child_ids;
}
$children_ids = _get_children_ids( 9 ); // usa tu ID de página numérico o get_the_id()
$results = new WP_Query( array(
'post_type' => 'page',
'post__in' => $children_ids
#'meta_key' => 'meta_key', // tu clave meta
#'orderby' => 'meta_key',
/* 'meta_query' => array( // meta_query opcional
array(
'key' => 'meta_key', // clave
'value' => array(3, 4), // valores
'compare' => 'IN', // operador
)
) */
) );
var_dump( $results );
Si necesitas ordenar los hijos por clave/valor meta de manera jerárquica, deberías pasar los valores meta_key y order_by al WP_Query en la función _get_children_ids (en lugar de al WP_Query final).
Si no, un método más simple para obtener todos los IDs hijos es:
$children = get_pages( 'child_of=9');
$children_ids = array();
if ( ! empty( $children ) )
foreach ( $children as $post )
$children_ids[] = $post->ID;

No estoy seguro si esto es exactamente lo que buscas, pero podrías usar la función wp_list_pages y utilizar los parámetros 'child_of' y 'depth'.
Consulta la siguiente página en el Codex para más información: http://codex.wordpress.org/Function_Reference/wp_list_pages

ESTO FUNCIONA, SOLO COPIA Y PEGA EL CÓDIGO EN TU ARCHIVO PAGE.PHP
//REDIRIGIR AL PRIMER HIJO DESDE LA PÁGINA PADRE
// Construir el array de argumentos para WP_Query()
$page_tree_query_args = array(
'post_parent' => $post -> ID,
'post_type' => 'page',
'order' => 'asc'
);
// Obtener páginas hijas como objeto 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;
}
