Інтеграція користувацького типу публікації в ієрархію сторінки


14

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

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

Третя структура тут використовує сторінки "про" та "учасники команди", але продовжує використовувати користувацький шрифт типу "post", щоб він виглядав так, що батьки є членом команди та близько. Я досяг цього, встановивши наступні параметри для спеціального типу публікації:

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

Це чудово працює, однак, коли я переходжу на рівень команди члена команди, я більше не отримую класів поточних сторінок, поточних предків на батьківських сторінках. Я знаю, чому це так, оскільки технічно ми не є батьком сторінок цих сторінок, проте чи є спосіб, коли я можу підманути / виправити / передати тіло, щоб сторінки НЕ з'явилися як батьки?

Я домігся цього чудово, використовуючи сторінки для членів команди, проте замість нього було обрано спеціальний тип публікації для зручності використання адміністратором.

Дякую хлопцям + дівчатам!


вам потрібно встановити ідентифікатор сторінки учасників команди як власний тип публікації post_parent.
Bainternet

Я не бачу цього варіанту в register_post_typeдокументації, ви можете допомогти?
Бен Еверард

Відповіді:


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, думаючи, що це дочірня сторінка іншого типу публікації (сторінки).


1
Право, тому я бачу, як цей "дурить" WordPress, щоб думати, що конкретна сторінка є її батьківською, однак це не додавання батьківського класу сторінки до батьківської сторінки, коли я wp_list_pages.
Бен Еверард

1
Я помітив, що це також загрожує моєю структурою слюса / постійної посилання ...: S
Ben Everard

2
Я намагаюся досягти того ж, що і Бен, але я використовую wp_nav_menu- post_parent є про / членів команди, але навігація підкреслює батьківський елемент моїх "звичайних" дописів у блозі ... будь-яка інша ідея, як я можу це виправити?
pkyeck

@BenEverard: Ви знайшли рішення для безладу структури постійної посилання?
абаумг

0

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

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

Відмова: Після його спробу це здається вже не існуючою проблемою, оскільки - принаймні для мене - це просто працює на моїй установці 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
    ;
}



  • Це дещо узагальнений приклад коду.
  • Він повинен бути пристосований до фактичного випадку використання.

0

Можливим рішенням є те, що кожного разу, коли збережений спеціальний тип публікації, ви можете встановити його батьківським about/team-members програмно.

Ось такі кроки:

  1. Ви можете використовувати гачок save_post щоб "зловити", коли хтось намагається зберегти публікацію.
  2. Якщо ця публікація є типовим типом публікації, який ви шукаєте, тоді продовжуйте.
  3. Не забудьте встановити батьківський користувальницький користувачу на потрібну сторінку (ви можете жорстко кодувати ідентифікатор сторінки до тих пір, поки не видалите її). Ви можете використовувати wp_update_post, щоб зберегти батьків (я сам цього не пробував, але не бачу, чому він не повинен працювати).

Я дуже хотів би побачити для цього якийсь код! Це було б ідеально, але я не в змозі змусити його працювати місеф.
Йохан Даль

0

Я мав ще трохи часу, щоб розібратися в цьому сам (вибачте, якщо я втратив чийсь час), і я зрозумів, що для мене найкращим способом вирішити проблему виділення буде щось, щоб щось робити _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;
}

Ви не витратили мого часу :) Інша справа, ви впевнені, що це все-таки проблема? Оскільки на моїй установці WP 3.9.2 я не зміг її відтворити. Виділення правильного пункту меню працювало просто поза полем.
Миколай

Так, це, безумовно, все ще проблема @ialocin. Можливо, ви тестуєте це за допомогою меню рівня 0 та типу публікації за замовчуванням?
ndm

Ні, спробував це з кодом, розміщеним у моїй відповіді. Так із користувацьким типом публікації та як пунктом меню 1-го та 2-го рівня на сторінці від відповідного типу публікації. Для тестування я використав теми, що містять ядро ​​WordPress.
Миколай

@ialocin Не впевнений, чи я вас правильно зрозумів, оскільки " спробували з розміщеним кодом " і " поза коробкою " є своєрідними взаємовиключними? ;) Ви посилаєтесь лише на користувацький тип публікації, а не на виправлення підсвічування?
ndm

Правильно :) Добре, якщо бути точним, для сценарію потрібен CPT, тому я, звичайно, зареєстрував його. Виділення працює без використання мета-вікна та виправлення підсвічування. Наприклад, зі структурою меню: бабуся і дідусь (сторінка)> батьківська (сторінка)> щось (повідомлення)> інша річ (cpt)> одна-більше-річ (cpt) - кожен елемент отримує правильні класи (css); Тема, що використовується тут двадцять тринадцять.
Миколай

-1
<?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

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

Ось так. Додано його в гачок фільтра wp_nav_menu_objects.
aifrim
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.