Cómo establecer una relación padre-hijo entre diferentes tipos de publicaciones personalizadas

14

Acabo de establecer una relación post / padre entre un tipo de episodio "episodios" y un tipo de publicación "serie de dibujos animados".

Usé este bit de código para agregar en el cuadro de meta para asignar el padre de otro tipo de publicación:

add_action('admin_menu', function() {
    remove_meta_box('pageparentdiv', 'episodes', 'normal');
});
add_action('add_meta_boxes', function() {
    add_meta_box('episodes-parent', 'Cartoon Series', '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' => __('(no parent)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // end empty pages check
    } // end hierarchical check.
}

Eso funcionó en la pantalla del administrador al permitirme configurar la serie como padre para el episodio, pero cuando trato de ver la publicación, obtengo un 404. La estructura de la URL es:

domain/episodes/series-name/episode-name

La url de la serie es:

domain/cartoon-series/series-name

Me gustaría que la url del episodio sea:

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

¿Qué me estoy perdiendo? ¿Es posible hacer que una publicación completa escriba el hijo de otro tipo de publicación? Entonces, incluso podría obtener la url para que la lista de episodios sea:

domain/cartoon-series/series-name/episodes

¡Gracias! Mate


Según lo solicitado, aquí está el código para los dos tipos de publicaciones personalizadas en cuestión:

$labels = array(
    "name" => "Cartoon Series",
    "singular_name" => "Cartoon Series",
    "menu_name" => "Cartoon Series",
    "all_items" => "All Cartoon Series",
    "add_new" => "Add New",
    "add_new_item" => "Add New Cartoon Series",
    "edit" => "Edit",
    "edit_item" => "Edit Cartoon Series",
    "new_item" => "New Cartoon Series",
    "view" => "View",
    "view_item" => "View Cartoon Series",
    "search_items" => "Search Cartoon Series",
    "not_found" => "No Cartoon Series Found",
    "not_found_in_trash" => "No Cartoon Series Found in Trash",
    "parent" => "Parent Cartoon Series",
    );

$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" => "Episodes",
    "singular_name" => "Episode",
    );

$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 complemento CPT UI, por lo 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 CPT. Tal vez eso es lo que me estoy perdiendo. Acabo de encontrar ese código en línea que coloca el metabox en la página para hacer el enlace. ¿No es suficiente hacer el trabajo? Parece que establece el post_parent.

¡Gracias! Mate

Mattaton
fuente
Lo siento pero me equivoqué. La relación padre-hijo está configurada correctamente. El cuadro meta no usa un campo meta (eso es lo que me confundió la primera vez), usa parent_idvar de consulta 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 tratando de encontrar una regla de reescritura que lo haga funcionar, pero no he tenido éxito. Ahora estoy investigando una solución.
cybmeta
Después de un poco de investigación, creo que no puedes hacer que funcione como quieres. Parece que no es posible tener un tipo de publicación como padre de otro tipo de publicación. Bueno, es posible, con su código esa relación se establece realmente, pero ver la publicación secundaria no funciona en la interfaz. He intentado reescribir reglas y conectarme pre_get_postspara alterar la consulta sin éxito, hay algo más complicado que no he podido entender. Es como tener un gato como padre de un perro. Sugiero usar solo un tipo de publicación jerárquica o establecer la relación mediante metacampos .
cybmeta
Creo que un tipo de publicación jerárquico se adapta perfectamente a su situación.
cybmeta
2
Realmente estoy tratando de NO ser complicado con esto. Si hay disponible una solución más elegante, soy todo oídos. Soy nuevo en WP en general y lo he hecho bastante bien hasta ahora, pero este me ha dejado perplejo. Por lo general, simplemente convertiría la serie de dibujos animados en una categoría y la asignaría al episodio. El problema es que también tengo otros datos anidados distintos de los episodios que se incluyen en la serie de dibujos animados. Entonces, parece que las series de dibujos animados también tendrían que ser un CPT. ¡Es complicado! :-D ¿Puedes explicarme a qué te refieres usando solo un tipo de publicación jerárquica?
Mattaton

Respuestas:

9

Finalmente encontré una solución de trabajo. La serie de dibujos animados se puede registrar como lo hizo, pero los tipos de publicaciones personalizadas de episodios no pueden ser jerárquicos (creo que WordPress espera que el contenido primario sea del mismo tipo que el contenido secundario si la relación se establece post_parenten la wp_poststabla de la base de datos).

Al registrar episodios, la regla de reescritura debe establecerse en la babosa que desee, es decir cartoon-series/%series_name%. Luego podemos filtrar el enlace de episodios para reemplazarlo %series_name%con el nombre real del cartoon-seriestipo de publicación principal y una regla de reescritura para decirle a WordPress cuándo se solicita un tipo de publicación de la serie de dibujos animados y cuándo se trata de un episodio.

add_action('init', function(){
    $labels = array(
        "name" => "Cartoon Series",
        "singular_name" => "Cartoon Series",
        "menu_name" => "Cartoon Series",
        "all_items" => "All Cartoon Series",
        "add_new" => "Add New",
        "add_new_item" => "Add New Cartoon Series",
        "edit" => "Edit",
        "edit_item" => "Edit Cartoon Series",
        "new_item" => "New Cartoon Series",
        "view" => "View",
        "view_item" => "View Cartoon Series",
        "search_items" => "Search Cartoon Series",
        "not_found" => "No Cartoon Series Found",
        "not_found_in_trash" => "No Cartoon Series Found in Trash",
        "parent" => "Parent Cartoon Series",
    );

    $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" => "Episodes",
        "singular_name" => "Episode",
    );

    $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', 'Cartoon Series', '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' => __('(no parent)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // end empty pages check
}

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 ) ) {
        //Lets go to get the parent cartoon-series name
        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 {
            //This seems to not work. It is intented to build pretty permalinks
            //when episodes has not parent, but it seems that it would need
            //additional rewrite rules
            //return str_replace( '/%series_name%', '', $link );
        }

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

NOTA : Recuerde eliminar las reglas de reescritura después de guardar el código anterior y antes de probarlo. Vaya wp-admin/options-permalink.phpy haga clic en Guardar para volver a clasificar las reglas de reescritura.

NOTA 2 : Probablemente es necesario agregar más reglas de reescritura, por ejemplo, para trabajar en publicaciones paginadas. ¿También puede necesitar algo más de trabajo para tener una solución completa, por ejemplo, al eliminar una cartoon-serieseliminación también todos los episodios secundarios? ¿Agregar un filtro en la pantalla de edición de administrador para filtrar episodios por publicación principal? ¿Modificar el título de los episodios en la pantalla de edición de administración para mostrar el nombre de la serie principal?

cybmeta
fuente
¡Gracias por mirar en esto! Parece que el código que ha 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 sería después de eso. Por alguna razón, el cuadro Serie de dibujos animados no se completa para que yo seleccione un padre. Por eso pensé que los episodios debían ser jerárquicos. Tratando de averiguar por qué.
Mattaton
Sí, los episodios deben ser jerárquicos para que se complete el metacuadro Cartoon Series.
Mattaton
Con episodios jerárquicos para poder establecer el padre, la url empeoró. Con la babosa como sugirió, obtengo el nombre de la serie en la url dos veces. Entonces, en lugar de domain/episodes/series-name/episode-namecomo antes, obtuvedomain/episodes/series-name/series-name/episode-name
Mattaton
Como dije, los episodios no pueden ser jerárquicos. Modifiqué el código de meta box para que se rellenara con tipos de publicaciones no jerárquicas. Usa el código exacto que publiqué, lo probé y está funcionando. Si usa otro código, no puedo saber qué está mal. Simplemente copie y pegue el código de la respuesta y pruébelo. Es posible que deba deshabilitar el complemento de la interfaz de usuario de CPT o, al menos, eliminar los tipos de publicación personalizados del complemento a medida que se registran en el código.
cybmeta
Ah, mis disculpas, escaneé rápidamente y pensé que esa parte era la misma. Tienes razón, la página se carga ahora y la URL parece correcta.
Mattaton
-1

Tendrá que escribir su 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 en función de la estructura de la URL y su estructura de URL no da 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 pasar por alto el mecanismo de reescritura y analizar las URL por ti mismo. Algo así como 1. ejecutar las reglas de reescritura de WordPress. Si se encontró un contenido, muéstrelo y salga 2. obtenga la primera parte de la url, verifique si hay una publicación que coincida con el bucle esperado del tipo de publicación 3. en el resto de las partes de la URL verifique que las publicaciones existan y estén en el tipo correcto 4. si todo coincide, muestra la última publicación encontrada; de lo contrario, muestra una página 404

Mark Kaplun
fuente