Tích hợp một loại bài đăng tùy chỉnh vào hệ thống phân cấp trang


14

Tôi đang tạo một chủ đề với loại bài đăng tùy chỉnh cho các thành viên trong nhóm, tôi cũng có cấu trúc trang sau:

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

Cấu trúc thứ ba ở đây sử dụng các trang về và thành viên nhóm, nhưng tiếp tục sử dụng sên loại bài tùy chỉnh để làm cho nó trông giống như cha mẹ của nó là thành viên nhóm và về. Tôi đã đạt được điều này bằng cách đặt các tùy chọn sau trên loại bài tùy chỉnh:

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

Điều này hoạt động rất tốt, tuy nhiên khi tôi xuống cấp độ bài viết của thành viên nhóm, tôi không còn nhận được các lớp tổ tiên hiện tại, trang hiện tại trên các trang mẹ. Tôi biết lý do tại sao, bởi vì chúng tôi không có kỹ thuật trên cha mẹ của những trang đó, tuy nhiên có cách nào để tôi có thể lừa / sửa / bodge để các trang KHÔNG làm cha mẹ không?

Tôi đã đạt được điều này một cách độc đáo bằng cách sử dụng các trang cho các thành viên trong nhóm, tuy nhiên loại bài đăng tùy chỉnh đã được chọn thay vì để dễ sử dụng cho quản trị viên.

Cảm ơn các chàng trai + cô gái!


bạn cần đặt id trang thành viên nhóm làm loại bài đăng tùy chỉnh post_parent.
Bai Internet

Tôi không thấy tùy chọn đó trong register_post_typetài liệu, bạn có thể hỗ trợ không?
Ben Everard

Câu trả lời:


6

Khi làm việc với các trang, bạn có thể chọn một trang mẹ và giá trị đó được lưu dưới dạng số id của trang mẹ trong trang con post_parent trong cơ sở dữ liệu.

Trong trường hợp của bạn, bạn đang sử dụng một loại bài đăng tùy chỉnh, do đó bạn sẽ cần phải tạo metabox của riêng mình cho trang mẹ; cái gì đó như:

/* 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;
}

Nó không có gì để làm với register_post_type. Bạn đang lừa WordPress nghĩ rằng đó là một trang con của một loại bài đăng (trang) khác.


1
Đúng vậy, vì vậy tôi có thể thấy WordPress "ngu ngốc" này nghĩ thế nào về một trang cụ thể là trang phụ, tuy nhiên nó không thêm lớp cha vào trang cha mẹ khi tôi wp_list_pages.
Ben Everard

1
Tôi đã nhận thấy điều này cũng gây rối với cấu trúc sên / permalink của tôi ...: S
Ben Everard

2
Tôi đang cố gắng để đạt được điều tương tự như Ben nhưng tôi sử dụng wp_nav_menu- post_parent là về / thành viên nhóm nhưng điều hướng làm nổi bật mục cha mẹ của các bài đăng trên blog "bình thường" của tôi ... có ý tưởng nào khác về cách tôi có thể khắc phục điều này không?
pkyeck

@BenEverard: Bạn đã tìm ra giải pháp cho mớ hỗn độn cấu trúc permalink chưa?
abaumg

0

Tôi đã đi với một người đi bộ tùy chỉnh để đạt được một cái gì đó tương tự ... tránh các nhu cầu cho các trường tùy chỉnh, nhưng tất cả các bài đăng thuộc loại phải ngồi dưới cùng một điểm trong cây trang.

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

Tuyên bố miễn trừ trách nhiệm: Sau khi dùng thử, điều này dường như không còn tồn tại đối với tôi, bởi vì - ít nhất là đối với tôi - nó chỉ hoạt động trên bản cài đặt WP 3.9.2 của tôi. Không thể tìm thấy một trình theo dõi lỗi mặc dù.


Tôi đã cùng nhau đưa ra một plugin nhỏ để kiểm tra điều này, có thể giúp được ai đó. Nhưng như tôi đã nói ở trên từ chối trách nhiệm ở trên, tôi không thể tái tạo vấn đề trong bản cài đặt wordpress hiện tại. Tôi đã tách plugin thành bốn tệp, chúng sẽ cùng nhau vào một thư mục bên trong thư mục plugin.

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

bao gồm-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 );
}

bao gồm-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;
}

bao gồm-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
    ;
}



  • Đây là một ví dụ mã hơi khái quát.
  • Nó phải được trang bị cho trường hợp sử dụng thực tế.

0

Một giải pháp khả thi là bất cứ khi nào loại bài đăng tùy chỉnh được lưu, bạn có thể đặt cha mẹ của nó thành chương trình about/team-members.

Dưới đây là các bước:

  1. Bạn có thể sử dụng hook save_post để 'bắt' bất cứ khi nào ai đó cố gắng lưu bài đăng.
  2. Nếu bài đăng đó là loại bài tùy chỉnh bạn đang theo sau, sau đó tiến hành.
  3. Đảm bảo đặt phụ huynh của bài đăng tùy chỉnh vào trang bạn muốn (bạn có thể mã hóa ID trang miễn là bạn không xóa nó). Bạn có thể sử dụng wp_update_post để cứu phụ huynh (Tôi đã không tự mình thử điều này, nhưng tôi không hiểu tại sao nó không hoạt động).

Tôi rất muốn xem một số mã cho việc này! Điều này sẽ là hoàn hảo, nhưng tôi không thể làm cho nó hoạt động được.
Johan Dahl

0

Tôi đã có thêm thời gian để tự mình nghiên cứu vấn đề này (xin lỗi nếu tôi lãng phí thời gian của bất kỳ ai) và tôi nghĩ rằng đối với tôi, cách tốt nhất để giải quyết vấn đề nổi bật sẽ là làm lại những gì _wp_menu_item_classes_by_context() đang làm, đó là lặp đi lặp lại tất cả cha mẹ và tổ tiên của mục menu đóng vai trò là cha mẹ của loại bài đăng tùy chỉnh của tôi và thêm các lớp thích hợp.

Vì tôi cũng muốn sửa trang cha mẹ cho loại bài đăng tùy chỉnh của mình và dễ dàng thay đổi mà không phải cập nhật tất cả các bài đăng khi phụ huynh thay đổi, tôi đã quyết định sử dụng một tùy chọn thay vì điền post_parent điền trường của bài đăng loại bài đăng tùy chỉnh của mình. Tôi đã sử dụng ACF cho điều đó vì dù sao tôi cũng đang sử dụng nó trong chủ đề của mình, nhưng sử dụng chức năng tùy chọn mặc định của WordPress tất nhiên cũng sẽ làm điều đó.

Đối với nhu cầu của tôi, tôi có thể sử dụng wp_nav_menu_objectsbộ lọc. Ngoài ra, tôi phải lọc page_for_poststùy chọn để nó trả về giá trị giả / trống, điều này cũng tránh trang bài viết mặc định được tô sáng.

Lưu ý rằng tôi đã không đi hết con đường, bộ lọc chỉ thêm current-menu-ancestorcurrent-menu-parentcác lớp, vì điều này là đủ cho nhu cầu của tôi!

/**
 * 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');

Để hoàn thiện, khi điền post_parent(xem câu trả lời của @ BaiNET ) thay vì sử dụng các tùy chọn, sau đó lấy ID cha có thể trông giống như thế này:

/**
 * 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;
}

Bạn đã không lãng phí thời gian của tôi :) Một điều nữa, chắc chắn đây vẫn là một vấn đề? Bởi vì trên bản cài đặt WP 3.9.2 của tôi, tôi không thể sao chép nó. Làm nổi bật các mục menu chính xác làm việc ra khỏi hộp.
Nicolai

Đúng, đó chắc chắn vẫn là một vấn đề @ialocin. Có thể là bạn đang thử nghiệm điều này với menu 0 cấp và loại bài đăng mặc định?
ndm

Không, đã thử nó với mã được đăng trong câu trả lời của tôi. Vì vậy, với một loại bài đăng tùy chỉnh và như mục menu cấp 1 và 2 cho một trang từ loại bài đăng theo. Tôi đã sử dụng các chủ đề đi kèm lõi wordpress để kiểm tra nó.
Nicolai

@ialocin Không chắc chắn nếu tôi hiểu bạn chính xác, bởi vì " đã thử với mã được đăng " và " ngoài hộp " là loại trừ lẫn nhau? ;) Bạn chỉ đề cập đến loại bài đăng tùy chỉnh, không phải là sửa chữa nổi bật?
ndm

Phải :) Ok, chính xác là, đối với kịch bản cần có CPT, vì vậy tất nhiên tôi đã đăng ký nó. Làm nổi bật hoạt động mà không cần sử dụng hộp meta và sửa lỗi tô sáng. Ví dụ: với cấu trúc menu: grandparent (page)> Parent (page)> Something (post)> other-thing (cpt)> one-more-thing (cpt) - mọi phần tử đều nhận được lớp css chính xác (es); chủ đề được sử dụng ở đây hai mươi mười ba.
Nicolai

-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

CHỈNH SỬA 1:

Vì con trỏ không hoạt động:

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

Có bạn đi. Đã thêm nó trong hook bộ lọc wp_nav_menu_objects.
aifrim
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.