Intereting Posts
Отправить письмо активации пользователю после регистрации Исключить из сообщений запроса с meta_key и meta_value Как получить всех пользователей по пользовательскому метаму (массиву) текущего пользователя? Удалить текст в тегах заголовка в выдержке Как разрешить редакторам оставлять комментарии к сообщениям, которые еще не опубликованы? Как я могу комбинировать запросы meta_query? Система тегов, такая как Quora? Как запустить мой плагин только при отправке всей страницы? Будет ли permalinks работать, если блог передается в подкаталог? Как показать термины, используемые только для определенного типа пользовательских сообщений. Создание фильтра WP API игнорирует параметр фильтра Как выполнить короткий код за пределами содержимого / записи в теме? Вывод заголовка подкатегории И элементов на странице категории Невозможно изменить стиль ввода типа ввода? Как искать сообщения В ИСТОЧНИКЕ ИЛИ ИЛИ ИЛИ ИЛИ?

Интеграция настраиваемого типа сообщений в иерархию страниц

Я создаю тему с пользовательским типом сообщения для членов команды, у меня также есть следующая структура страницы:

about <-- this is a page about/team-members <-- this is a page, lists all the team members about/team-members/joe-bloggs <-- this is a custom post type (team member) entry 

Третья структура здесь использует страницы о членах и членах группы, но продолжает использовать пользовательский пул типа сообщения, чтобы он выглядел так, будто родители являются членами команды и о них. Я достиг этого, установив следующие параметры в настраиваемом типе сообщений:

 ... 'rewrite' => array( 'slug' => 'about/team-members', 'with_front' => false) ... 

Это отлично работает, однако, когда я перехожу на уровень должности члена команды, я больше не получаю классы текущей страницы, текущего-предка на родительских страницах. Я знаю, почему это происходит, потому что мы технически не являемся родителями этих страниц, но есть ли способ, которым я могу обмануть / исправить / разместить, чтобы страницы отображались как родители?

Я хорошо это сделал, используя страницы для членов команды, однако вместо этого был выбран тип персонализированного сообщения для удобства использования для администратора.

Спасибо, ребята, девочки!

При работе со страницами вы можете выбрать родительскую страницу, и это значение будет сохранено в качестве номера идентификатора родительской страницы в поле post_parent дочерней страницы в базе данных.

В вашем случае вы используете настраиваемый тип сообщений, поэтому вам нужно будет создать свой собственный обмен для родительской страницы; что-то вроде:

 /* Define the custom box */ add_action('add_meta_boxes', 'child_cpt_add_custom_box'); /* Adds a box to the main column on the custom post type edit screens */ function child_cpt_add_custom_box() { add_meta_box('child_cpt', __( 'My child_cpt parent'),'team_member_inner_custom_box','team_member'); } /* Prints the box content */ function team_member_inner_custom_box() { global $post; // Use nonce for verification wp_nonce_field( plugin_basename(__FILE__), 'team_member_inner_custom_box' ); echo 'Select the parent page'; $mypages = get_pages(); echo '<select name="cpt_parent">'; foreach($mypages as $page){ echo '<option value="'.$page->ID.'"'; if ($page->ID == $post->post_parent) {echo ' selected';} echo '>"'.$page->post_title.'</option>'; } echo '</select>'; } /* Do something with the data entered */ add_action('wp_insert_post_data', 'myplugin_save_postdata'); /* When the post is saved, saves our custom data */ function myplugin_save_postdata( $data, $postarr ) { global $post; // verify this came from the our screen and with proper authorization, // because save_post can be triggered at other times if ( !wp_verify_nonce( $_POST['team_member_inner_custom_box'], plugin_basename(__FILE__) ) ) return $data; // verify if this is an auto save routine. // If it is our form has not been submitted, so we dont want to do anything if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return $data; // OK, we're authenticated: we need to find and save the data if ($post->post_type == "team_member") $data['post_parent'] = $_POST['cpt_parent']; return $data; } 

Он не имеет ничего общего с register_post_type . Вы обманываете WordPress, думая, что это дочерняя страница другого типа сообщения (страница).

Я пошел с обычным ходоком, чтобы достичь чего-то подобного … избегает необходимости в настраиваемых полях, но все сообщения типа должны сидеть ниже одной и той же точки в дереве страниц.

 class Walker_Page_CustomPostTypeHack extends Walker_Page { function walk($elements, $max_depth) { $called_with = func_get_args(); // current page is arg 3... see walk_page_tree for why $current_page = $called_with[3]; // if there's no parent - see if we can find one. // some ACF options would be an easy way to make this configurable instad of constants if ($current_page === 0) { global $wp_query; $current_post = $wp_query->get_queried_object(); switch ($current_post->post_type) { case 'course': $current_page = POST_COURSES; break; case 'project': $current_page = POST_PROJECTS; break; case 'story': $current_page = POST_STORIES; break; } } // now pass on into parent $called_with[3] = $current_page; return call_user_func_array(array('parent', 'walk'), $called_with); } } 

Отказ от ответственности: после того, как вы попробуете, это кажется мне более не существующей проблемой, потому что – по крайней мере, для меня – это просто работает на моей установке WP 3.9.2. Однако не удалось найти соответствующий трекер ошибок.


У меня есть небольшой плагин, чтобы проверить это, что может помочь кому-то. Но, как я сказал выше, отказ от ответственности, я не мог воспроизвести проблему в текущей установке WordPress. Я разделил плагин на четыре файла, они объединяются в один каталог внутри каталога плагина.

plugin-cpt_menu_hierarchy.php :

 <?php defined( 'ABSPATH' ) OR exit; /** * Plugin Name: CPT Menu Hierarchy Fix? * Description: CPT Menu Hierarchy Fix? * Author: ialocin * Author URL: http://wordpress.stackexchange.com/users/22534/ialocin * Plugin URL: http://wordpress.stackexchange.com/q/13308/22534 */ // registering nonsense post type include 'include-register_post_type.php'; // adding meta box to nosense custom post type include 'include-cpt_parent_meta_box.php'; // menu highlighting fix include 'include-menu_highlighting.php'; 

include-register_post_type.php :

 <?php defined( 'ABSPATH' ) OR exit; // See: http://codex.wordpress.org/Function_Reference/register_post_type add_action( 'init', 'wpse13308_basic_reigister_post_type'); function wpse13308_basic_reigister_post_type() { $args = array( 'public' => true, 'label' => 'Nonsense' ); register_post_type( 'nonsense', $args ); } 

include-cpt_parent_meta_box.php :

 <?php defined( 'ABSPATH' ) OR exit; // pretty much like @bainternet's answer // Add Meta Box add_action( 'add_meta_boxes', 'nonsense_add_meta_box' ); function nonsense_add_meta_box() { add_meta_box( 'nonsense', __( 'Nonsense parent' ), 'nonsense_inner_meta_box', 'nonsense' ); } // Meta Box Content function nonsense_inner_meta_box() { global $post; wp_nonce_field( plugin_basename( __FILE__ ), 'nonsense_inner_meta_box' ); echo 'Parent Page:&nbsp;&nbsp;'; $mypages = get_pages(); echo '<select name="cpt_parent">'; foreach($mypages as $page){ echo '<option value="'.$page->ID.'"'; if ($page->ID == $post->post_parent) {echo ' selected';} echo '>'.$page->post_title.'</option>'; } echo '</select>'; } // Save Data From Meta Box add_action( 'wp_insert_post_data', 'nonsense_save_meta_box_data' ); function nonsense_save_meta_box_data( $data, $postarr ) { global $post; if ( ! wp_verify_nonce( $_POST['nonsense_inner_meta_box'], plugin_basename( __FILE__ ) ) ) { return $data; } if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) { return $data; } if ( $post->post_type == 'nonsense' ) { $data['post_parent'] = $_POST['cpt_parent']; } return $data; } 

include-menu_highlighting.php :

 <?php defined( 'ABSPATH' ) OR exit; // altering WordPress' nav menu classes via »nav_menu_css_class« filter add_filter( 'nav_menu_css_class', 'wpse13308_fix_nav_menu_highlighting', 10, 2 ); function wpse13308_fix_nav_menu_highlighting( $classes, $item ) { // data of the current post global $post; // setting up some data from the current post $current_post_post_type = $post->post_type; $current_post_parent_id = $post->post_parent; // id of the post the current menu item represents $current_menu_item_id = $item->object_id; // do this for a certain post type if( $current_post_post_type == 'nonsense' ) { // remove unwanted highlighting class via array_filter and callback // http://php.net/manual/de/function.array-filter.php $classes = array_filter( $classes, 'wpse13308_remove_highlighting_classes' ); // when the parents id equals the menu items id, we want to // highlight the parent menu item, so we check for: if( $current_post_parent_id == $current_menu_item_id ) { // use the css class used for highlighting $classes[] = 'replace-with-css-class'; } } return $classes; } // callback to remove highlighting classes function wpse13308_remove_highlighting_classes( $class ) { return ( // use the class(es) you need, overview over nav menu item css classes: // http://codex.wordpress.org/Function_Reference/wp_nav_menu#Menu_Item_CSS_Classes $class == 'highlight-class' // uncomment next line if you want to check for more then one class // repeat the line if you want to check for a third, fourth and so on // || $class == 'replace-with-css-class' ) ? false : true ; } 


  • Это несколько обобщенный пример кода.
  • Он должен быть установлен в фактическом варианте использования.

Возможное решение – всякий раз, когда пользовательский тип сообщения сохраняется, вы можете установить его «родительский», чтобы он был about/team-members запрограммирован.

Вот шаги:

  1. Вы можете использовать hook_post hook для «catch» всякий раз, когда кто-то пытается сохранить сообщение.
  2. Если это сообщение является настраиваемым типом сообщения, то вы продолжаете.
  3. Не забудьте установить родительский элемент пользовательской почты на нужную вам страницу (вы можете жестко закодировать идентификатор страницы, пока вы ее не удаляете). Вы можете использовать wp_update_post для сохранения родителя (я не пробовал это сам, но я не понимаю, почему он не должен работать).

У меня было еще немного времени, чтобы вникать в это сам (извините, если я потратил время на чью-то время), и я решил, что для меня лучший способ решить проблему подсветки – это любопытное _wp_menu_item_classes_by_context() того, что делает _wp_menu_item_classes_by_context() , то есть перебирать всех родителей и предков пункта меню, который действует как родительский элемент моего настраиваемого типа сообщений, и соответственно добавлять классы.

Поскольку я также хотел, чтобы родительская страница для моего настраиваемого типа сообщения была исправлена ​​и легко менялась, без необходимости обновлять все сообщения после изменения родительского post_parent , я решил использовать параметр вместо post_parent поля post_parent моих пользовательских сообщений типа сообщения , Я использовал ACF для этого, так как я использую его в своей теме в любом случае, но использование функциональности по умолчанию WordPress, конечно, тоже сделает это.

Для моих нужд я мог бы использовать фильтр wp_nav_menu_objects . Кроме того, мне пришлось отфильтровать параметр page_for_posts чтобы он возвращал ложно / пустое значение, это позволяет избежать выделения страницы сообщений по умолчанию, которая будет подсвечена.

Обратите внимание, что я не прошел весь путь, фильтр добавляет только current-menu-ancestor и current-menu-parent классы current-menu-parent , поскольку этого было достаточно для моих нужд!

 /** * Filters the `page_for_posts` option on specific custom post types in * order to avoid the wrong menu item being marked as * `current-page-parent`. * * @see _wp_menu_item_classes_by_context() */ function wpse13308_pre_option_page_for_posts_filter() { $types = array ( 'my_custom_post_type_x', 'my_custom_post_type_y', 'my_custom_post_type_z' ); if(in_array(get_post_type(), $types)) { return 0; } return false; } add_filter('pre_option_page_for_posts', 'wpse13308_pre_option_page_for_posts_filter'); /** * Returns the current posts parent page ID * * @return int */ function wpse13308_get_parent_page_id() { $postType = get_post_type(); $parentPageId = null; switch($postType) { case 'my_custom_post_type_x': case 'my_custom_post_type_y': case 'my_custom_post_type_z': $parentPageId = (int)get_field('page_for_' . $postType, 'options')->ID; break; case 'post': $parentPageId = (int)get_option('page_for_posts'); break; } return $parentPageId; } /** * Adds proper context based classes so that the parent menu items are * being highlighted properly for custom post types and regular posts. * * @param array $menuItems * @return array * * @see _wp_menu_item_classes_by_context() */ function wpse13308_wp_nav_menu_objects_filter(array $menuItems) { $parentPageId = wpse13308_get_parent_page_id(); if($parentPageId !== null) { $activeAncestorItemIds = array(); $activeParentItemIds = array(); foreach($menuItems as $menuItem) { if((int)$parentPageId === (int)$menuItem->object_id) { $ancestorId = (int)$menuItem->db_id; while ( ($ancestorId = (int)get_post_meta($ancestorId, '_menu_item_menu_item_parent', true)) && !in_array($ancestorId, $activeAncestorItemIds) ) { $activeAncestorItemIds[] = $ancestorId; } $activeParentItemIds[] = (int)$menuItem->db_id; } } $activeAncestorItemIds = array_filter(array_unique($activeAncestorItemIds)); $activeParentItemIds = array_filter(array_unique($activeParentItemIds)); foreach($menuItems as $key => $menuItem) { $classes = $menuItems[$key]->classes; if(in_array(intval($menuItem->db_id), $activeAncestorItemIds)) { $classes[] = 'current-menu-ancestor'; $menuItems[$key]->current_item_ancestor = true; } if(in_array($menuItem->db_id, $activeParentItemIds)) { $classes[] = 'current-menu-parent'; $menuItems[$key]->current_item_parent = true; } $menuItems[$key]->classes = array_unique($classes); } } return $menuItems; } add_filter('wp_nav_menu_objects', 'wpse13308_wp_nav_menu_objects_filter'); 

Для полноты, когда вы post_parent (см . Ответ @ Bainternet ) вместо использования опций, извлечение родительского идентификатора может выглядеть примерно так:

 /** * Returns the current posts parent page ID * * @return int */ function wpse13308_get_parent_page_id() { $parentPageId = null; $post = get_post(); switch($post->post_type) { case 'my_custom_post_type_x': case 'my_custom_post_type_y': case 'my_custom_post_type_z': $parentPageId = (int)$post->post_parent; break; case 'post': $parentPageId = (int)get_option('page_for_posts'); break; } return $parentPageId; } 
 <?php the_post(); // $postType holds all the information of the post type of the current post you are viewing $postType = get_post_type_object(get_post_type()); // $postSlug is the slug you defined in the rewrite column: about/team-members $postSlug = $postType->rewrite['slug']; // $datas = { [0] => 'about', [1] => 'team-members' } $datas = explode('/', $postSlug); // $pageSlug = 'about' $pageSlug = $datas[0]; // all the page information you require. $page = get_page_by_path($pageSlug, OBJECT, 'page'); ?> 

http://codex.wordpress.org/Function_Reference/get_post_type_object http://codex.wordpress.org/Function_Reference/get_page_by_path

ИЗМЕНИТЬ 1:

Поскольку указатели не работают:

 add_filter('wp_nav_menu_objects', 'my_menu_class_edit'); function my_menu_class_edit($items) { if (is_single()) { $postType = get_post_type_object(get_post_type()); $postSlug = $postType->rewrite['slug']; if($postSlug != 'about/team-members') return $items; $datas = explode('/', $postSlug); $pageAbout = get_page_by_path($datas[0], OBJECT, 'page'); $pageTeamMembers = get_page_by_path($datas[1], OBJECT, 'page'); foreach ($items as $item) { if ($item->title == $pageAbout->post_title) { $item->classes[] = 'current-ancestor'; } else if ($item->title == $pageTeamMembers->post_title) { $item->classes[] = 'current-page'; } } } return $items; }