Mengintegrasikan jenis posting khusus ke dalam hierarki halaman

14

Saya membuat tema dengan jenis posting khusus untuk anggota tim, saya juga punya struktur halaman berikut:

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

Struktur ketiga di sini menggunakan halaman tentang dan anggota tim, tetapi selanjutnya menggunakan siput jenis pos khusus agar terlihat seperti orang tuanya adalah anggota tim dan tentang. Saya telah mencapai ini dengan menetapkan opsi berikut pada jenis posting khusus:

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

Ini bekerja dengan baik, tetapi ketika saya turun ke tingkat posting anggota tim saya tidak lagi mendapatkan halaman saat ini, kelas leluhur saat ini di halaman induk. Saya tahu mengapa ini, karena kami tidak secara teknis pada halaman sebagai induk dari halaman tersebut, namun apakah ada cara saya bisa mengelabui / memperbaiki / membuat badan sehingga halaman DO muncul sebagai orang tua?

Saya telah mencapai ini dengan baik dengan menggunakan halaman untuk anggota tim, namun jenis posting kustom dipilih sebagai gantinya mudah digunakan untuk administrator.

Terima kasih kawan-kawan + cewek!

Ben Everard
sumber
Anda perlu menetapkan id halaman anggota tim sebagai jenis posting kustom Anda post_parent.
Bainternet
Saya tidak melihat opsi itu dalam register_post_typedokumentasi, dapatkah Anda membantu?
Ben Everard

Jawaban:

6

Ketika Bekerja dengan halaman, Anda dapat memilih halaman induk dan nilai itu disimpan sebagai nomor id halaman induk di bidang halaman anak post_parentdalam database.

Dalam kasus Anda, Anda menggunakan jenis posting khusus sehingga Anda harus membuat kotak metabox sendiri untuk halaman induk; sesuatu seperti:

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

Itu tidak ada hubungannya dengan register_post_type. Anda menipu WordPress untuk berpikir bahwa itu adalah halaman anak dari jenis posting lain (halaman).

Bainternet
sumber
1
Righto, jadi saya bisa melihat bagaimana ini "bodoh" WordPress untuk berpikir halaman tertentu adalah orang tuanya, namun itu tidak menambahkan kelas induk halaman ke halaman induk ketika saya wp_list_pages.
Ben Everard
1
Saya perhatikan ini juga mengacaukan struktur slug / permalink saya ...: S
Ben Everard
2
Saya mencoba untuk mencapai hal yang sama seperti Ben tetapi saya menggunakan wp_nav_menu- post_parent adalah tentang / anggota tim tetapi navigasi menyoroti item induk dari posting blog "normal" saya ... ada ide lain bagaimana saya bisa memperbaikinya?
pkyeck
@ Beneverard: Apakah Anda menemukan solusi untuk kekacauan struktur permalink?
abaumg
0

Saya pergi dengan alat bantu berjalan khusus untuk mencapai sesuatu yang serupa ... menghindari kebutuhan untuk bidang khusus, tetapi semua tulisan jenis harus duduk di bawah titik yang sama di pohon halaman.

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

}
benlumley
sumber
0

Penafian: Setelah mencobanya ini sepertinya masalah yang sudah tidak ada lagi bagi saya, karena - setidaknya bagi saya - itu hanya berfungsi pada instalasi WP 3.9.2 saya. Tidak dapat menemukan pelacak bug yang sesuai.


Saya bersama-sama memiliki sedikit plugin untuk menguji ini, yang mungkin dapat membantu seseorang. Tapi seperti yang saya katakan di disclaimer di atas, saya tidak bisa mereproduksi masalah dalam instalasi wordpress saat ini. Saya telah memisahkan plugin menjadi empat file, mereka akan bersama menjadi satu direktori di dalam direktori 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';

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

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

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



  • Ini adalah contoh kode yang agak umum.
  • Itu harus dipasang ke use case yang sebenarnya.
Nicolai
sumber
0

Solusi yang memungkinkan adalah kapan pun jenis posting kustom disimpan, Anda dapat mengatur 'induknya menjadi about/team-membersprgrammatis.

Berikut langkah-langkahnya:

  1. Anda dapat menggunakan kait save_post untuk 'menangkap' setiap kali seseorang mencoba menyimpan posting.
  2. Jika posting itu adalah jenis posting kustom yang Anda cari, maka lanjutkan.
  3. Pastikan untuk mengatur orang tua kiriman khusus ke halaman yang Anda inginkan (Anda dapat melakukan hard-code ID halaman selama Anda tidak menghapusnya). Anda dapat menggunakan wp_update_post untuk menyelamatkan orang tua (saya belum mencoba ini sendiri, tetapi saya tidak mengerti mengapa itu tidak berhasil).
Shahar Dekel
sumber
Saya sangat ingin melihat beberapa kode untuk ini! Ini akan sempurna, tetapi saya tidak bisa membuatnya bekerja sendiri.
Johan Dahl
0

Saya memiliki lebih banyak waktu untuk menggali sendiri (maaf jika saya menyia-nyiakan waktu orang lain), dan saya pikir bagi saya, cara terbaik untuk menyelesaikan masalah penyorotan adalah dengan melakukan kembali apa yang _wp_menu_item_classes_by_context()sedang dilakukan, yaitu mengulangi semua orang tua dan leluhur dari item menu yang bertindak sebagai induk dari tipe posting kustom saya, dan menambahkan kelas dengan tepat.

Karena saya juga ingin memiliki halaman induk untuk jenis posting kustom saya diperbaiki, dan mudah diubah tanpa harus memperbarui semua posting setelah perubahan induk, saya telah memutuskan untuk menggunakan opsi daripada mengisi post_parentbidang posting jenis posting kustom saya. Saya telah menggunakan ACF untuk itu karena saya menggunakannya dalam tema saya, tapi menggunakan fungsi opsi WordPress default tentu saja akan melakukannya juga.

Untuk kebutuhan saya, saya dapat menggunakan wp_nav_menu_objectsfilter. Selain itu saya harus memfilter page_for_postsopsi sehingga mengembalikan nilai palsu / kosong, ini menghindari halaman posting default yang akan disorot juga.

Perhatikan bahwa saya tidak pergi jauh-jauh, filter hanya menambah current-menu-ancestordan current-menu-parentkelas, karena ini sudah cukup untuk kebutuhan saya!

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

Demi kelengkapan, saat mengisi post_parent (lihat jawaban @ Bainternet ) alih-alih menggunakan opsi, kemudian mengambil ID induk bisa terlihat seperti ini:

/**
 * 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;
}
ndm
sumber
Anda belum menyia-nyiakan waktu saya :) Hal lain, yakin ini masih menjadi masalah? Karena pada instalasi WP 3.9.2 saya, saya tidak dapat mereproduksinya. Menyoroti item menu yang benar berhasil di luar kotak.
Nicolai
Yap, itu pasti masih menjadi masalah @ialocin. Mungkinkah Anda menguji ini dengan menu level 0 dan jenis posting default?
ndm
Tidak, coba dengan kode yang diposting dalam jawaban saya. Jadi dengan jenis posting khusus dan sebagai item menu level 1 dan 2 ke halaman dari jenis posting yang sesuai. Saya menggunakan tema bundel inti wordpress untuk mengujinya.
Nicolai
@ialocin Tidak yakin apakah saya mengerti Anda dengan benar, karena " mencoba dengan kode yang diposting " dan "di luar kotak " agak saling eksklusif? ;) Apakah Anda hanya merujuk pada jenis pos khusus, bukan perbaikan penyorotan?
ndm
Benar :) Ok, tepatnya, untuk skenario CPT diperlukan, jadi tentu saja saya mendaftarkannya. Menyoroti bekerja tanpa menggunakan kotak meta dan perbaikan penyorotan. Misalnya dengan struktur menu: kakek-nenek (halaman)> induk (halaman)> sesuatu (posting)> hal lain (cpt)> satu hal lagi (cpt) - setiap elemen mendapatkan kelas css yang benar (es); tema yang digunakan di sini dua puluh tiga belas.
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

EDIT 1:

Karena pointer tidak berfungsi:

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;
}
aifrim
sumber
Ini dia. Menambahkannya dalam kait filter wp_nav_menu_objects.
aifrim