Как установить родительско-дочерние отношения между разными типами записей

14

Я только что установил связь «пост / родитель» между типом поста «эпизоды» и типом поста «мультфильм-серия».

Я использовал этот фрагмент кода для добавления в мета-поле, чтобы назначить родителя из другого типа сообщения:

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

Это работало на экране администратора, позволяя мне установить сериал как родитель для эпизода, но когда я пытаюсь просмотреть пост, я получаю 404. Структура URL:

domain/episodes/series-name/episode-name

URL для серии:

domain/cartoon-series/series-name

Я хотел бы, чтобы URL для эпизода был:

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

Что мне не хватает? Можно ли сделать весь тип сообщения дочерним по отношению к другому типу сообщения? Итак, я мог бы даже получить URL для списка эпизодов:

domain/cartoon-series/series-name/episodes

Благодарность! Matt


Как и требовалось, вот код для двух пользовательских типов сообщений:

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

Я использую плагин CPT UI, поэтому я не могу редактировать этот код напрямую. Это только код экспорта, который предоставляет CPT UI.

У меня нет другого кода, который связывает два CPT. Может быть, это то, что я скучаю. Я только что нашел этот код в Интернете, который размещает метабокс на странице для создания ссылок. Разве этого недостаточно для выполнения работы? Похоже, он устанавливает post_parent.

Благодарность! Matt

Mattaton
источник
Извините, но я был неправ. Родительско-дочерние отношения установлены правильно. Мета-блок не использует мета-поле (это то, что меня смутило в первый раз), он использует parent_idзапрос var, и ему не нужно больше кода для установки отношений. Проблема в том, что созданный URL не распознается WordPress. Я пытался найти правило переписывания, которое заставило бы его работать, но у меня не было успеха. Я сейчас исследую решение.
Cybmeta
После некоторого расследования, я думаю, вы не можете заставить его работать так, как вы хотите. Иметь тип сообщения в качестве родителя другого типа сообщения, кажется невозможным. Что ж, возможно, с вашим кодом эти отношения действительно установлены, но просмотр дочернего поста не работает во внешнем интерфейсе. Я пытался переписать правила и подключиться, pre_get_postsчтобы изменить запрос, но безуспешно, что-то более сложное, что я не смог понять. Как будто кошка будет родителем собаки. Я предлагаю использовать только один иерархический тип сообщения или установить область с помощью мета-полей .
cybmeta
Я думаю, что один тип иерархического поста идеально подходит для вашей ситуации.
cybmeta
2
Я действительно пытаюсь НЕ быть сложным с этим. Если доступно более элегантное решение, я весь в ушах. Я новичок в WP в целом и до сих пор неплохо справился, но этот поставил меня в тупик. Как правило, я просто делаю сериал мультфильмов и назначаю его в эпизод. Проблема в том, что у меня есть и другие вложенные данные, кроме эпизодов, которые входят в серию мультфильмов. Таким образом, похоже, что мультсериал должен был бы быть также CPT. Это трудно! :-D Можете ли вы объяснить мне, что вы имеете в виду, используя только один иерархический тип сообщения?
Маттатон

Ответы:

9

Наконец-то я нашел рабочее решение. Мультяшной серии могут быть зарегистрированы , как вы делали , но эпизоды пользовательские почтовые типы не могут быть hirarchical (я думаю , WordPress ожидает родительский контент быть того же типа , как содержание ребенка , если отношения устанавливается с использованием post_parentв wp_postsтаблице базы данных).

При регистрации эпизодов правило перезаписи должно быть установлено на нужный вам слаг, то есть cartoon-series/%series_name%. Затем мы можем отфильтровать ссылку на эпизоды, чтобы заменить ее %series_name%реальным именем родительского cartoon-seriesтипа записи и правилом перезаписи, чтобы сообщить WordPress, когда запрашивается тип публикации серии мультфильмов и когда это эпизоды.

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

ПРИМЕЧАНИЕ . Не забудьте сбросить правила перезаписи после сохранения приведенного выше кода и перед его попыткой. Перейдите wp-admin/options-permalink.phpи нажмите «Сохранить», чтобы заново создать правила перезаписи.

ПРИМЕЧАНИЕ 2 : Вероятно, необходимо добавить больше правил переписывания, например, для постов постраничной публикации. Также может потребоваться дополнительная работа, чтобы иметь полное решение, например, при удалении cartoon-seriesудалить также все дочерние эпизоды? Добавить фильтр на экране редактирования администратора, чтобы фильтровать эпизоды по родительскому посту? Изменить заголовок эпизода на экране редактирования администратора, чтобы показать имя родительской серии?

cybmeta
источник
Спасибо за просмотр этого! Кажется, что код, который вы разместили, удаляет название мультсериала с URL. Вместо замены% series_name% именем эпизода,% series_name% должно быть именем родителя эпизода. Название эпизода будет после этого. По какой-то причине в поле «Серия мультфильмов» я не могу выбрать родителя. Вот почему я думал, что эпизоды должны быть иерархическими. Пытаюсь выяснить почему.
Маттатон
Да, эпизоды должны быть иерархическими, чтобы можно было заполнить метаблок мультипликационных серий.
Маттатон
С иерархическими эпизодами, так что я могу установить родителя, URL стал еще хуже. С слагом, как вы предложили, я дважды получаю название серии в URL. Итак, вместо того, domain/episodes/series-name/episode-nameкак раньше, я получилdomain/episodes/series-name/series-name/episode-name
Mattaton
Как я уже сказал, эпизоды не могут быть иерархическими. Я изменил код мета-бокса, чтобы он заполнялся неиерархическими типами записей. Используйте точный код, который я разместил, я проверил его, и он работает. Если вы используете другой код, я не могу знать, что не так. Просто скопируйте и вставьте код из ответа и протестируйте его. Вам может потребоваться отключить плагин пользовательского интерфейса CPT или, по крайней мере, удалить пользовательские типы записей из плагина, поскольку они зарегистрированы в коде.
cybmeta
Ах, мои извинения, я быстро отсканировал и подумал, что это то же самое. Вы правы, страница действительно загружается, и URL выглядит правильно.
Маттатон
1

Нет необходимости в жестком кодировании в этом случае ... Вы можете просто использовать этот плагин:

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

Вы даже можете получить код из него. Тем не менее, это не может быть полным решением.

T.Todua
источник
-1

Вам нужно будет написать свой собственный код парсинга URL для этого, так как wordpress должен знать тип поста, который он пытается извлечь из БД, на основе структуры URL, и ваша структура URL не дает на это никакого намека.

Это не то, что очень легко сделать с помощью API правил переписывания WordPress, но ничто не мешает вам обойти механизм перезаписи и самостоятельно проанализировать URL-адреса. Что-то вроде 1. Запустите правила переписывания WordPress. Если контент был найден, отобразите его и выйдите из 2. получите первую часть URL, проверьте, есть ли запись, соответствующая слагу с ожидаемым циклом типа 3. в остальных частях URL, убедитесь, что сообщения существуют и в правильном типе. 4. если все совпадает, отобразите последнее найденное сообщение, иначе отобразите страницу 404

Марк Каплун
источник