Интеграция пользовательского сообщения вводит в иерархию страницы

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

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

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

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

Спасибо парни + девочки!

14
28.03.2011, 22:00
6 ответов

При Работе со страницами можно выбрать родительскую страницу, и то значение сохраняется как родительский идентификационный номер страницы на дочерней странице 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 в размышление, что это - дочерняя страница другого типа сообщения (страница).

6
19.02.2020, 21:59
  • 1
    Righto, таким образом, я вижу, как это "дурачит" WordPress для размышления определенной страницы, это - родитель, однако это не добавляет родительский класс страницы к родительской странице когда я wp_list_pages. –  Ben Everard 29.03.2011, 00:11
  • 2
    я заметил это также, смешивает с моим кратким заголовком / структура постоянной ссылки... :S –  Ben Everard 29.03.2011, 22:52
  • 3
    я пытаюсь достигнуть того же самого как Ben, но я использую wp_nav_menu - post_parent о/члены команды, но навигация выделяет родительский элемент моих "нормальных" сообщений в блоге... какая-либо другая идея, как я мог зафиксировать это? –  pkyeck 10.10.2011, 17:05

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

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

}
0
19.02.2020, 21:59

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


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

плагин-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';

включайте-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 );
}

включайте-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;
}

включайте-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
    ;
}



  • Это - несколько обобщенный пример кода.
  • Это должно быть приспособлено к фактическому варианту использования.
0
19.02.2020, 21:59

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

Вот шаги:

  1. Можно использовать рычаг save_post, чтобы 'поймать' каждый раз, когда кто-то пытается сохранить сообщение.
  2. Если то сообщение является пользовательским типом сообщения, Вы после, то продолжаете двигаться.
  3. Удостоверьтесь, что установили родителя пользовательского сообщения на страницу, которую Вы хотите (Вы можете твердый код страница ID, пока Вы не удаляете его). Можно использовать wp_update_post для сохранения родителя (я не попробовал это сам, но я не вижу, почему он не должен работать).
0
19.02.2020, 21:59
  • 1
    я очень хотел бы видеть некоторый код для этого! Это было бы прекрасно, но я не могу получить его работающий mysef. –  Johan Dahl 13.05.2015, 13:55

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

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

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

Обратите внимание, что я не пошел полностью, фильтр только добавляет current-menu-ancestor и 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;
}
0
19.02.2020, 21:59
  • 1
    Вы не потратили впустую мое время :) Другая вещь, уверены, что это - все еще проблема? Поскольку на моем WP 3.9.2 установок я не мог воспроизвести его. Выделение корректного пункта меню работало только из поля. –  Nicolai 26.08.2014, 19:36
  • 2
    Да, это - определенно все еще проблема @ialocin. Могло случиться так тестированием этого с 0 меню уровня и типом сообщения по умолчанию? –  ndm 26.08.2014, 20:22
  • 3
    Нет, попробовал его кодом, отправленным в моем ответе. Таким образом с пользовательским типом сообщения и как 1-й и 2-й пункт меню уровня к странице от согласно типу сообщения. Я использовал связанные темы ядра Wordpress для тестирования его. –  Nicolai 26.08.2014, 20:30
  • 4
    @ialocin, Не уверенный, если я понимаю Вас правильно, потому что "испытанный с кодом, отправленным" и "из поля", являются довольно взаимоисключающими?;) Вы только обращаетесь к пользовательскому типу сообщения, не, выделение фиксирует? –  ndm 26.08.2014, 20:36
  • 5
    Право :) Хорошо, чтобы быть точным, для сценария CPT необходим, поэтому конечно, я зарегистрировал его. Выделение работ без использования meta поля и выделения фиксирует. Например, со структурой меню: прародитель (страница)> родитель (страница)> что-то (сообщение)> другая-вещь (cpt)> еще-одна-вещь (cpt) - каждый элемент получает корректный класс (классы) CSS; тема, используемая здесь двадцать тринадцать. –  Nicolai 26.08.2014, 20:50
<?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;
}
-1
19.02.2020, 21:59
  • 1
    Там Вы идете. Добавленный это в wp_nav_menu_objects фильтрует рычаг. –  aifrim 01.09.2014, 20:54

Теги

Похожие вопросы