Cómo establecer una relación padre-hijo entre diferentes tipos de contenido personalizados

14 mar 2015, 00:20:15
Vistas: 27.4K
Votos: 23

Acabo de configurar una relación post/padre entre un tipo de contenido "episodes" y un tipo de contenido "cartoon-series".

Utilicé este código para agregar el meta box que asigna el padre desde otro tipo de contenido:

add_action('admin_menu', function() {
    remove_meta_box('pageparentdiv', 'episodes', 'normal');
});
add_action('add_meta_boxes', function() {
    add_meta_box('episodes-parent', 'Series de Dibujos', 'episodes_attributes_meta_box', 'episodes', 'side', 'default');
});

function episodes_attributes_meta_box($post) {
    $post_type_object = get_post_type_object($post->post_type);
    if ( $post_type_object->hierarchical ) {
        $pages = wp_dropdown_pages(array('post_type' => 'cartoon-series', 'selected' => $post->post_parent, 'name' => 'parent_id', 'show_option_none' => __('(sin padre)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // fin de verificación de páginas vacías
    } // fin de verificación jerárquica
}

Eso funcionó en la pantalla de administración permitiéndome establecer la serie como padre del episodio, pero cuando intento ver la entrada, obtengo un 404. La estructura de URL es:

domain/episodes/series-name/episode-name

La URL para la serie es:

domain/cartoon-series/series-name

Me gustaría que la URL para el episodio fuera:

domain/cartoon-series/series-name/episode-name

¿Qué me estoy perdiendo? ¿Es posible hacer que un tipo de contenido completo sea hijo de otro tipo de contenido? De esta manera, incluso podría obtener la URL para la lista de episodios como:

domain/cartoon-series/series-name/episodes

¡Gracias! Matt


Como solicitado, aquí está el código para los dos tipos de contenido personalizados en cuestión:

$labels = array(
    "name" => "Series de Dibujos",
    "singular_name" => "Serie de Dibujos",
    "menu_name" => "Series de Dibujos",
    "all_items" => "Todas las Series de Dibujos",
    "add_new" => "Añadir Nueva",
    "add_new_item" => "Añadir Nueva Serie de Dibujos",
    "edit" => "Editar",
    "edit_item" => "Editar Serie de Dibujos",
    "new_item" => "Nueva Serie de Dibujos",
    "view" => "Ver",
    "view_item" => "Ver Serie de Dibujos",
    "search_items" => "Buscar Series de Dibujos",
    "not_found" => "No se encontraron Series de Dibujos",
    "not_found_in_trash" => "No se encontraron Series de Dibujos en la papelera",
    "parent" => "Serie de Dibujos Padre",
    );

$args = array(
    "labels" => $labels,
    "description" => "",
    "public" => true,
    "show_ui" => true,
    "has_archive" => true,
    "show_in_menu" => true,
    "exclude_from_search" => false,
    "capability_type" => "post",
    "map_meta_cap" => true,
    "hierarchical" => true,
    "rewrite" => array( "slug" => "cartoon-series", "with_front" => true ),
    "query_var" => true,
    "supports" => array( "title", "revisions", "thumbnail" ),           );
register_post_type( "cartoon-series", $args );

$labels = array(
    "name" => "Episodios",
    "singular_name" => "Episodio",
    );

$args = array(
    "labels" => $labels,
    "description" => "",
    "public" => true,
    "show_ui" => true,
    "has_archive" => true,
    "show_in_menu" => true,
    "exclude_from_search" => false,
    "capability_type" => "post",
    "map_meta_cap" => true,
    "hierarchical" => true,
    "rewrite" => array( "slug" => "episodes", "with_front" => true ),
    "query_var" => true,
    "supports" => array( "title", "revisions", "thumbnail" ),           );
register_post_type( "episodes", $args );

Estoy usando el plugin CPT UI, así que no puedo editar ese código directamente. Ese es solo el código de exportación que proporciona CPT UI.

No tengo ningún otro código que vincule los dos CPTs. Tal vez eso es lo que me falta. Solo encontré ese código en línea que coloca el metabox en la página para hacer la vinculación. ¿No es suficiente para hacer el trabajo? Parece que establece el post_parent.

¡Gracias! Matt

4
Comentarios

Lo siento pero estaba equivocado. La relación padre-hijo está correctamente establecida. El meta box no está usando un campo meta (eso fue lo que me confundió al principio), utiliza la variable de consulta parent_id y no necesita más código para establecer la relación. El problema es que la URL generada no es reconocida por WordPress. He estado intentando encontrar una regla de reescritura que haga que funcione pero no he tenido éxito. Ahora estoy investigando una solución.

cybmeta cybmeta
14 mar 2015 20:19:46

Después de alguna investigación, creo que no puedes hacer que funcione como quieres. Tener un tipo de publicación como padre de otro tipo de publicación parece no ser posible. Bueno, es posible, con tu código esa relación se establece realmente, pero ver la publicación hija no funciona en el frontend. He probado reglas de reescritura y enganchando en pre_get_posts para alterar la consulta sin éxito, algo más complicado está involucrado que no he sido capaz de entender. Como tener un gato como padre de un perro. Sugiero usar solo un tipo de publicación jerárquico o establecer la relación usando campos meta.

cybmeta cybmeta
14 mar 2015 21:12:59

Creo que un tipo de publicación jerárquico se ajusta perfectamente a tu situación.

cybmeta cybmeta
14 mar 2015 21:19:12

Realmente estoy tratando de NO complicar esto. Si hay una solución más elegante disponible, estoy todo oídos. Soy nuevo en WP en general y me ha ido bastante bien hasta ahora, pero este me tiene perplejo. Normalmente, simplemente haría que la serie de caricaturas fuera una categoría y la asignaría al episodio. El problema es que también tengo otros datos anidados además de los episodios que van bajo la serie de caricaturas. Entonces, parece que la serie de caricaturas también necesitaría ser un CPT. ¡Es complicado! :-D ¿Puedes explicarme qué quieres decir con usar solo un tipo de publicación jerárquico?

Mattaton Mattaton
14 mar 2015 22:40:15
Todas las respuestas a la pregunta 3
7
18

Finalmente encontré una solución funcional. Las series de caricaturas pueden registrarse como lo hiciste, pero los tipos de contenido personalizados para episodios no pueden ser jerárquicos (creo que WordPress espera que el contenido padre sea del mismo tipo que el contenido hijo si la relación se establece usando post_parent en la tabla de base de datos wp_posts).

Al registrar los episodios, la regla de reescritura debe configurarse con el slug que deseas, es decir cartoon-series/%series_name%. Luego podemos filtrar el enlace de los episodios para reemplazar %series_name% con el nombre real del tipo de contenido padre cartoon-series y una regla de reescritura para indicarle a WordPress cuándo se solicita un tipo de contenido de serie de caricaturas y cuándo es un episodio.

add_action('init', function(){
    $labels = array(
        "name" => "Series de Caricaturas",
        "singular_name" => "Serie de Caricaturas",
        "menu_name" => "Series de Caricaturas",
        "all_items" => "Todas las Series",
        "add_new" => "Añadir Nueva",
        "add_new_item" => "Añadir Nueva Serie",
        "edit" => "Editar",
        "edit_item" => "Editar Serie",
        "new_item" => "Nueva Serie",
        "view" => "Ver",
        "view_item" => "Ver Serie",
        "search_items" => "Buscar Series",
        "not_found" => "No se encontraron Series",
        "not_found_in_trash" => "No hay Series en la Papelera",
        "parent" => "Serie Padre",
    );

    $args = array(
        "labels" => $labels,
         "description" => "",
        "public" => true,
        "show_ui" => true,
        "has_archive" => true,
        "show_in_menu" => true,
        "exclude_from_search" => false,
        "capability_type" => "post",
        "map_meta_cap" => true,
        "hierarchical" => true,
        "rewrite" => array( "slug" => "cartoon-series", "with_front" => true ),
        "query_var" => true,
        "supports" => array( "title", "revisions", "thumbnail" )
    );

    register_post_type( "cartoon-series", $args );

    $labels = array(
        "name" => "Episodios",
        "singular_name" => "Episodio",
    );

    $args = array(
        "labels" => $labels,
        "description" => "",
        "public" => true,
        "show_ui" => true,
        "has_archive" => true,
        "show_in_menu" => true,
        "exclude_from_search" => false,
        "capability_type" => "post",
        "map_meta_cap" => true,
        "hierarchical" => false,
        "rewrite" => array( "slug" => "cartoon-series/%series_name%", "with_front" => true ),
        "query_var" => true,
        "supports" => array( "title", "revisions", "thumbnail" )
    );

    register_post_type( "episodes", $args );

});

add_action('add_meta_boxes', function() {
    add_meta_box('episodes-parent', 'Series de Caricaturas', 'episodes_attributes_meta_box', 'episodes', 'side', 'default');
});

function episodes_attributes_meta_box($post) {
        $pages = wp_dropdown_pages(array('post_type' => 'cartoon-series', 'selected' => $post->post_parent, 'name' => 'parent_id', 'show_option_none' => __('(sin padre)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // fin de verificación de páginas vacías
}

add_action( 'init', function() {

    add_rewrite_rule( '^cartoon-series/(.*)/([^/]+)/?$','index.php?episodes=$matches[2]','top' );

});

add_filter( 'post_type_link', function( $link, $post ) {
    if ( 'episodes' == get_post_type( $post ) ) {
        //Vamos a obtener el nombre de la serie padre
        if( $post->post_parent ) {
            $parent = get_post( $post->post_parent );
            if( !empty($parent->post_name) ) {
                return str_replace( '%series_name%', $parent->post_name, $link );
            }
        } else {
            //Esto parece no funcionar. Está destinado a construir enlaces permanentes bonitos
            //cuando los episodios no tienen padre, pero parece que necesitaría
            //reglas de reescritura adicionales
            //return str_replace( '/%series_name%', '', $link );
        }

    }
    return $link;
}, 10, 2 );

NOTA: Recuerda limpiar las reglas de reescritura después de guardar el código anterior y antes de probarlo. Ve a wp-admin/options-permalink.php y haz clic en guardar para regenerar las reglas de reescritura.

NOTA 2: Es probable que haya que añadir más reglas de reescritura, por ejemplo para que funcione con posts paginados. También puede necesitar más trabajo para tener una solución completa, por ejemplo, al eliminar una cartoon-series, ¿eliminar también todos los episodios hijos? ¿Añadir un filtro en la pantalla de edición del admin para filtrar episodios por padre? ¿Modificar el título de los episodios en la pantalla de edición del admin para mostrar el nombre de la serie padre?

14 mar 2015 22:44:56
Comentarios

¡Gracias por revisar esto! Parece que el código que has publicado está eliminando el nombre de la serie de dibujos animados de la URL. En lugar de reemplazar %series_name% con el nombre del episodio, %series_name% debería ser el nombre del padre del episodio. El nombre del episodio iría después de eso. Por alguna razón, el cuadro de Cartoon Series no se está llenando para que pueda seleccionar un padre. Por eso pensé que los episodios necesitaban ser jerárquicos. Estoy tratando de averiguar por qué.

Mattaton Mattaton
14 mar 2015 22:58:24

Sí, los episodios tienen que ser jerárquicos para que el cuadro de metadatos de Cartoon Series se pueda llenar.

Mattaton Mattaton
14 mar 2015 22:59:40

Con los episodios jerárquicos para poder establecer el padre, la URL empeoró. Con el slug como sugieres, obtengo el nombre de la serie en la URL dos veces. Entonces, en lugar de domain/episodes/series-name/episode-name como antes, obtuve domain/episodes/series-name/series-name/episode-name

Mattaton Mattaton
14 mar 2015 23:03:40

Como dije, los episodios no pueden ser jerárquicos. Modifiqué el código del meta box para que se llene con tipos de posts no jerárquicos. Usa el código exacto que publiqué, lo probé y está funcionando. Si usas otro código no puedo saber qué está mal. Solo copia y pega el código de la respuesta y pruébalo. Puede que necesites desactivar el plugin CPT UI o, al menos, eliminar los tipos de posts personalizados del plugin ya que están registrados en el código.

cybmeta cybmeta
14 mar 2015 23:06:57

Ah, mis disculpas, lo revisé rápidamente y pensé que esa parte era igual. Tienes razón, la página ahora carga y la URL se ve correcta.

Mattaton Mattaton
14 mar 2015 23:10:58

Si esto responde a tu pregunta, por favor, marca la respuesta como aceptada marcando la palomita debajo de las flechas de votación en la parte superior izquierda de la respuesta.

cybmeta cybmeta
14 mar 2015 23:14:03

¡Incluso 8 años después, esto sigue funcionando perfectamente! ¡Gracias!

Gavin Gavin
19 jun 2023 19:20:39
Mostrar los 2 comentarios restantes
0

No es necesario codificar manualmente en este caso, puedes simplemente usar este plugin:

https://wordpress.org/plugins/add-hierarchy-parent-to-post/

Incluso puedes tomar código de él. Sin embargo, puede que no sea una solución completa.

7 feb 2017 10:29:43
0
-1

Necesitarás escribir tu propio código de análisis de URL para eso, ya que WordPress necesita saber el tipo de publicación que intenta recuperar de la base de datos según la estructura de la URL, y tu estructura de URL no proporciona ninguna pista sobre esto.

Esto no es algo muy fácil de hacer con la API de reglas de reescritura de WordPress, pero no hay nada que te impida omitir el mecanismo de reescritura y analizar las URLs por tu cuenta. Algo como:

  1. Ejecutar las reglas de reescritura de WordPress. Si se encuentra contenido, mostrarlo y salir.
  2. Obtener la primera parte de la URL, verificar si hay una publicación que coincida con ese slug y el tipo de publicación esperado.
  3. Iterar sobre el resto de las partes de la URL, verificando que las publicaciones existan y sean del tipo correcto.
  4. Si todo coincide, mostrar la última publicación encontrada; de lo contrario, mostrar una página 404.
14 mar 2015 21:28:55