Como definir o relacionamento pai-filho entre diferentes tipos de postagem personalizados

14

Acabei de configurar uma relação de postagem / pai entre um tipo de postagem "episódios" e um tipo de postagem "série de desenhos animados".

Usei esse bit de código para adicionar na caixa de meta para atribuir o pai de outro tipo de postagem:

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.
}

Isso funcionou na tela do administrador, permitindo-me definir a série como pai do episódio, mas quando tento visualizar a postagem, recebo um 404. A estrutura do URL é:

domain/episodes/series-name/episode-name

O URL da série é:

domain/cartoon-series/series-name

Eu gostaria que o URL do episódio fosse:

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

o que estou perdendo? É possível tornar uma postagem inteira o filho de outro tipo de postagem? Então, eu poderia até obter o URL da lista de episódios:

domain/cartoon-series/series-name/episodes

Obrigado! Matt


Conforme solicitado, eis o código para os dois tipos de postagem personalizados em questão:

$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 );

Estou usando o plug-in da interface do usuário do CPT, portanto não posso editar esse código diretamente. Esse é apenas o código de exportação que a interface do usuário da CPT fornece.

Não tenho outro código que vincule os dois CPTs. Talvez seja isso que estou sentindo falta. Acabei de encontrar o código online que coloca o metabox na página para fazer o link. Não é suficiente fazer o trabalho? Parece que define o post_parent.

Obrigado! Matt

Mattaton
fonte
Me desculpe, mas eu estava errado. O relacionamento pai-filho está definido corretamente. A meta-caixa não está usando um meta-campo (foi o que me confundiu na primeira vez), usa a parent_idconsulta var e não precisa de mais código para definir o relacionamento. O problema é que o URL gerado não é reconhecido pelo WordPress. Eu tenho tentado encontrar uma regra de reescrita que a faça funcionar, mas não tive sucesso. Agora estou investigando uma solução.
22418 cybmeta
Depois de alguma investigação, acho que você não pode fazê-lo funcionar da maneira que deseja. Não é possível ter um tipo de postagem como pai de outro tipo de postagem. Bem, é possível, com o seu código, que o relacionamento esteja realmente definido, mas ver o post filho não funciona no frontend. Eu tentei reescrever regras e conectar-me pre_get_postsa alterar a consulta sem êxito, algo mais complicado está envolvido que eu não consegui entender. Como ter um gato como pai de um cachorro. Eu sugiro usar apenas um tipo de postagem hierárquica ou definir o realtion usando metadados .
cybmeta
Eu acho que um tipo de post hirárquico se encaixa perfeitamente na sua situação.
cybmeta
2
Estou realmente tentando NÃO ser complicado com isso. Se uma solução mais elegante estiver disponível, sou todo ouvidos. Eu sou novo no WP em geral e me saí muito bem até agora, mas este me surpreendeu. Normalmente, eu apenas tornaria a série de desenhos animados uma categoria e a atribuiria ao episódio. O problema é que eu também tenho outros dados aninhados, além de episódios, para serem incluídos na série de desenhos animados. Então, parece que as séries de desenhos animados precisariam ser um CPT também. É complicado! :-D Você pode me explicar o que você quer dizer com usar apenas um tipo de postagem hierárquico?
Mattaton

Respostas:

9

Finalmente encontrei uma solução funcional. A série de desenhos animados pode ser registrada como você fez, mas os tipos de postagem personalizada de episódios não podem ser hirárquicos (acho que o WordPress espera que o conteúdo pai seja do mesmo tipo que o conteúdo filho, se o relacionamento for definido post_parentna wp_poststabela do banco de dados).

Ao registrar episódios, a regra de reescrita deve ser definida para a lesma desejada, ou seja cartoon-series/%series_name%. Em seguida, podemos filtrar o link dos episódios para substituir %series_name%pelo nome real do cartoon-seriestipo de postagem principal e uma regra de reescrita para dizer ao WordPress quando um tipo de postagem de série de desenho animado é solicitado e quando é um episódio.

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 : Lembre-se de liberar as regras de reescrita depois de salvar o código acima e antes de tentar. Vá para wp-admin/options-permalink.phpe clique em Salvar para regenerar as regras de reescrita.

NOTA 2 : Provavelmente, é necessário adicionar mais regras de reescrita, por exemplo, para trabalhar em postagens paginadas. Além disso, pode ser necessário mais trabalho para ter uma solução completa, por exemplo, ao excluir uma cartoon-seriesexclusão também todos os episódios filhos? Adicionar um filtro na tela de edição do administrador para filtrar episódios por postagem dos pais? Modificar o título do episódio na tela de edição do administrador para mostrar o nome da série pai?

cybmeta
fonte
Obrigado por olhar para isso! Parece que o código que você postou está removendo o nome da série de desenhos animados do URL. Em vez de substituir% series_name% pelo nome do episódio,% series_name% deve ser o nome do pai do episódio. O nome do episódio seria depois disso. Por alguma razão, a caixa Cartoon Series não está sendo preenchida para eu selecionar um pai. Por isso, pensei que os episódios precisavam ser hierárquicos. Tentando descobrir o porquê.
Mattaton
Sim, os episódios precisam ser hierárquicos para que a meta box Cartoon Series seja preenchida.
Mattaton
Com episódios hierárquicos para que eu possa definir o pai, o URL ficou ainda pior. Com a lesma, como você sugeriu, recebo o nome da série no URL duas vezes. Então, em vez de domain/episodes/series-name/episode-namecomo antes, eu conseguidomain/episodes/series-name/series-name/episode-name
Mattaton 14/03
Como eu disse, os episódios não podem ser hierárquicos. Modifiquei o código da meta box para ser preenchido com tipos de postagem não hierárquicos. Use o código exato que eu publiquei, testei e está funcionando. Se você usar outro código, não sei o que está errado. Basta copiar e colar o código da resposta e testá-lo. Pode ser necessário desativar o plug-in da interface do usuário do CPT ou, pelo menos, excluir os tipos de postagem personalizados do plug-in à medida que são registrados no código.
cybmeta
Ah, minhas desculpas, eu rapidamente digitalizei e pensei que essa parte era a mesma. Você está certo, a página é carregada agora e o URL parece correto.
Mattaton 14/03
-1

Você precisará escrever seu próprio código de análise de URL para isso, pois o wordpress precisa saber o tipo de postagem que ele tenta recuperar do banco de dados com base na estrutura da URL e sua estrutura de URL não dá nenhuma dica sobre isso.

Isso não é algo muito fácil de fazer com a API de regras de reescrita do wordpress, mas não há nada que o impeça de ignorar o mecanismo de reescrita e analisar os URLs sozinho. Algo como 1. execute o wordpress rewite rules. Se um conteúdo foi encontrado, exiba-o e saia 2. para obter a primeira parte do URL, verifique se há uma postagem que corresponda com o loop esperado do tipo de postagem 3. nas demais partes da URL, verifique se as postagens existem e estão no tipo certo. 4. Se tudo coincidir, exibir a última postagem encontrada, exibir uma página 404

Mark Kaplun
fonte