Wordpress分层自定义帖子类型自动添加到菜单

Wordpress分层自定义帖子类型自动添加到菜单,wordpress,custom-wordpress-pages,Wordpress,Custom Wordpress Pages,这可能是重复的,但我并没有真正看到我在搜索时发现的内容与我的问题有什么关系 我在一个插件中创建了一个分层自定义帖子类型。我正在尝试为这个自定义帖子类型自动添加菜单项,这样当我添加一个新条目时,它将显示在一个下拉菜单中,并根据层次结构正确排列。我可以选择一个条目,只要它的所有子条目都正确地填充到菜单中,而不必在每次创建新条目时手动添加它们 我已经可以在菜单上添加一个条目了。但它没有添加孩子。我已经尝试了自动添加新的顶级条目选项,但它也没有做任何事情。我发现了一些东西,上面说要在wp_get_nav

这可能是重复的,但我并没有真正看到我在搜索时发现的内容与我的问题有什么关系

我在一个插件中创建了一个分层自定义帖子类型。我正在尝试为这个自定义帖子类型自动添加菜单项,这样当我添加一个新条目时,它将显示在一个下拉菜单中,并根据层次结构正确排列。我可以选择一个条目,只要它的所有子条目都正确地填充到菜单中,而不必在每次创建新条目时手动添加它们

我已经可以在菜单上添加一个条目了。但它没有添加孩子。我已经尝试了自动添加新的顶级条目选项,但它也没有做任何事情。我发现了一些东西,上面说要在wp_get_nav_menu_项中添加一个过滤器,但是要么我把它放在了错误的位置,要么我把它放在了自定义的post类型定义类中,要么它没用,不能做我想做的事情

看起来这应该是一件相对简单的事情——看起来所有的功能都会出现,我只是不知道如何将它链接起来

谢谢你的帮助

编辑以在建议的编辑后共享整个文件,以防万一会有所帮助

<?php
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) exit;

if ( ! class_exists( 'Wrestleefedmanager_Match' ) ) :

class Wrestleefedmanager_Match {

    /**
     * Constructor
     */
    public function __construct() {
        // Hooking up our function to theme setup
        add_action( 'init',             array( $this, 'create_match_page_type' ) ); 
        add_action( 'save_post',        array( $this, 'save_match') );      
        add_filter ('template_include', array($this, 'display_match_template' ) );
        add_filter( 'wp_get_nav_menu_items', array($this, 'match_locations_filter'), 10, 3 );

    }


    function match_locations_filter( $items, $menu, $args ) 
    {

        //$menuLocation = 'MENU_NAME';// Registered menu location
        $customPostType = 'match';// Custom post type name
        $newRootMenuName = 'Shows';// Name that will appear in the menu

        // Do not show the customized list in the admin pages
        // and customize only the chosen menu
        if (is_admin() ) //|| !($menu->slug === $menuLocation)) {
        {
            return $items;
        }

        $rootMenuItemId = 47122;

        // Adding a new root level menu item
        $items[] = (object)[
        'ID'                => 0,
        'title'             => $newRootMenuName,
        'url'               => '#',
        'menu_item_parent'  => 0,
        'post_parent'       => 0,
        'menu_order'        => count($items) + 1,
        'db_id'             => $rootMenuItemId,

        // These are not necessary for the functionality, but PHP warning will be thrown if not set
        'type'              => 'custom',
        'object'            => 'custom',
        'object_id'         => '',
        'classes'           => [],
        ];

        // Querying custom posts
        $customPosts = get_posts([
        'post_type'        => $customPostType,
        'posts_per_page'   => -1,
        ]);

        // Adding menu item specific properties to `$post` objects
        foreach ($customPosts as $i => $post) {
            $post->title = $post->post_title;
            $post->url = get_permalink($post);
            $post->menu_item_parent = $post->post_parent ? $post->post_parent : $rootMenuItemId;
            $post->menu_order = $i;
            $post->db_id = $post->ID;
        }

        // Merge custom posts into menu items
        $items = array_merge($items, $customPosts);

        return $items;  


        /*
      $child_items = array(); 
      $menu_order = count($items); 
      $parent_item_id = 0;

      foreach ( $items as $item ) {
        if ( in_array('locations-menu', $item->classes) ){ //add this class to your menu item
            $parent_item_id = $item->ID;
        }
      }

      if($parent_item_id > 0){

          foreach ( get_posts( 'post_type=matches&numberposts=-1' ) as $post ) {
            $post->menu_item_parent = $parent_item_id;
            $post->post_type = 'nav_menu_item';
            $post->object = 'custom';
            $post->type = 'custom';
            $post->menu_order = ++$menu_order;
            $post->title = $post->post_title;
            $post->url = get_permalink( $post->ID );
            array_push($child_items, $post);
          }

      }

      return array_merge( $items, $child_items );*/
    }


    function display_match_template ($template_path) {
        if ( get_post_type() == 'match' ) {
        if ( is_single() ) {
            // checks if the file exists in the theme first,
            // otherwise serve the file from the plugin
            if ( $theme_file = locate_template( array ( 'single-match.php' ) ) ) {
                $template_path = $theme_file;
            } else {
                $template_path = plugin_dir_path( __FILE__ ) . '/single-match.php';
                }
            }
        }
    return $template_path;
    }


    // Our custom post type function
    function create_match_page_type() {

     $matchlabels = array(
        'name'                => _x( 'Matches', 'Post Type General Name'),
        'singular_name'       => _x( 'Match', 'Post Type Singular Name'),
        'menu_name'           => __( 'Matches'),
        'parent_item_colon'   => __( null),
        'all_items'           => __( 'All Matches'),
        'view_item'           => __( 'View Match'),
        'add_new_item'        => __( 'Add New Match'),
        'add_new'             => __( 'Add New'),
        'edit_item'           => __( 'Edit Match'),
        'update_item'         => __( 'Update Match'),
        'search_items'        => __( 'Search Matches'),
        'not_found'           => __( 'Not Found'),
        'not_found_in_trash'  => __( 'Not found in Trash'),
    );

    $matchargs = array(
        'label'               => __( 'Matches' ),
        'description'         => __( 'Matches' ),
        'labels'              => $matchlabels,
        // Features this CPT supports in Post Editor
        'supports'            => array( 'title', 'editor', 'page-attributes',),
        // You can associate this CPT with a taxonomy or custom taxonomy. 
        //'taxonomies'          => array( 'weightclass', 'division', 'gender', 'title' ),
        /* A hierarchical CPT is like Pages and can have
        * Parent and child items. A non-hierarchical CPT
        * is like Posts.
        */ 
        'hierarchical'        => true,
        'public'              => true,
        'show_ui'             => true,
        'show_in_menu'        => true,
        'show_in_nav_menus'   => true,
        'show_in_admin_bar'   => true,
        'menu_position'       => 19,
        'can_export'          => true,
        'has_archive'         => true,
        'exclude_from_search' => false,
        'publicly_queryable'  => true,
        'capability_type'     => 'page',
        'register_meta_box_cb' => array( $this, 'initialize_match_page_type'),
    );

        register_post_type( 'match', $matchargs);
    }


    function save_match(){
        global $post;

        update_post_meta($post->ID, "competitors", $_POST["match_competitors"]);
        update_post_meta($post->ID, "referee", $_POST["match_referee"]);
        update_post_meta($post->ID, "rating", $_POST["match_rating"]);
        update_post_meta($post->ID, "victors", $_POST["match_victors"]);
        update_post_meta($post->ID, "time", $_POST["match_time"]);
        update_post_meta($post->ID, "finisher", $_POST["match_finisher"]);
        update_post_meta($post->ID, "title", $_POST["match_title"]);
        update_post_meta($post->ID, "titleupdate", $_POST["match_title_result"]);
    }

    function initialize_match_page_type() {
        add_meta_box("competitors", "Competitors", array( $this, 'match_competitors'), "match", "normal", "low");       
        add_meta_box("results", "Results", array( $this, 'match_results'), "match", "normal", "low");
        add_meta_box("championships", "Title Updates", array($this, 'match_titles'), "match", "normal", "low");
        add_meta_box("referee", "Referee", array( $this, 'match_referee'), "match", "side", "low");
        add_meta_box("rating", "Rating", array( $this, 'match_rating'), "match", "side", "low");

        add_meta_box("weightclass", "Weight Class", array( $this, 'match_weightclass'), "match", "side", "low");
        add_meta_box("gender", "Gender", array( $this, 'match_gender'), "match", "side", "low");
        add_meta_box("division", "Company/Division", array( $this, 'match_division'), "match", "side", "low");

    }   

    function match_titles()
    {
        global $post;
        $custom = get_post_custom($post->ID);
        $belts = $custom["title"][0];
        $result = $custom["titleupdate"][0];
        ?>
        <table>
        <tr><th>Title</th><th>Result</th></tr>
        <tr><td> <?php
            efed_select_from_entries('match_title', 'championship', $belts); ?>
        </td><td>
            <select name='match_title_result'>
                <option>&nbsp;</option>
                <option value="defense" <?php if ($result == "defense") echo 'selected' ?>>Successful Defense</option>
                <option value="newchamp" <?php if ($result == "newchamp") echo 'selected' ?>>New Champion</option>
                <option value="vacate" <?php if ($result == "vacate") echo 'selected' ?>>Vacated</option>
            </select>
        </td>
        </tr>
        </table>
        <?php
    }

    function match_weightclass()
    {
        global $post;
        $custom = get_post_custom($post->ID);
        $wc = $custom["weightclass"][0];
        //echo 'Saved value : ' . $wc . '<br />';
        efed_select_from_entries('match_weightclass', 'weightclasses', $wc);
    }
    function match_gender()
    {
        global $post;
        $custom = get_post_custom($post->ID);
        $gender = $custom["gender"][0];
        efed_select_from_entries('match_gender', 'genders', $gender);
    }
    function match_division()
    {
        global $post;
        $custom = get_post_custom($post->ID);
        $div = $custom["division"][0];
        efed_select_from_entries('match_division', 'feds', $div, true, true);
    }

    function match_competitors() {
        global $post;
        $custom = get_post_custom($post->ID);
        $competitors = $custom["competitors"][0];
        efed_select_from_entries('match_competitors', 'workers', $competitors, true);
    }

    function match_results() {
        global $post;
        $custom = get_post_custom($post->ID);
        $victors = $custom["victors"][0];
        $time = $custom["time"][0];
        $finisher = $custom["finisher"][0];
        $titledefense = $custom["titledefense"][0];
        ?>
        <table>
        <tr><td><label>Victor(s):</label></td><td><?php efed_select_from_entries('match_victors', 'workers', $victors, true);?></td></tr>
        <tr><td><label>Time:</label></td><td><input name="match_time" type="text" style="width:100%;box-sizing:border-box;" value="<?php echo $time; ?>" /></td></tr>
        <tr><td><label>Finish:</label></td><td><input name="match_finisher" type="text" style="width:100%;box-sizing:border-box;" value="<?php echo $finisher; ?>" /></td></tr></table>
        <?php
    }

    function match_referee() {
        global $post;
        $custom = get_post_custom($post->ID);
        $referee = $custom["referee"][0];
        ?>
        <input name="match_referee" type="text" value="<?php echo $referee; ?>" />
        <?php
    }

    function match_rating() {
        global $post;
        $custom = get_post_custom($post->ID);
        $rating = $custom["rating"][0];
        ?>
        <input name="match_rating" type="text" value="<?php echo $rating; ?>" />
        <?php
    }

}
endif;

可能还有其他可能的解决方案,但您肯定可以使用过滤器来实现这一点。下面是使用此钩子更改菜单的示例代码。您可以将其插入插件的主文件,但可以更改回调顶部的参数以满足您的需要

基本上,这会创建一个“虚拟”顶级菜单项,并在此菜单项下插入自定义的post条目。最终,您可以修改它,将其中一个海关哨所用作顶级物品,并将其余物品列在下面。另外,好的方面是,基于菜单项父项和db id属性,它保留了整个层次结构

/**
 * Blend custom posts into a nav menu
 */
add_filter('wp_get_nav_menu_items', function ($items, $menu, $args) {
    // Change these parameters
    $menuLocation = 'MENU_NAME';// Registered menu location
    $customPostType = 'CUSTOM_POST_TYPE';// Custom post type name
    $newRootMenuName = 'MY_CUSTOM_POSTS';// Name that will appear in the menu

    // Do not show the customized list in the admin pages
    // and customize only the choosen menu
    if (is_admin() || !($menu->slug === $menuLocation)) {
        return $items;
    }

    $rootMenuItemId = PHP_INT_MAX;

    // Adding a new root level menu item
    $items[] = (object)[
        'ID'                => 0,
        'title'             => $newRootMenuName,
        'url'               => '#',
        'menu_item_parent'  => 0,
        'post_parent'       => 0,
        'menu_order'        => count($items) + 1,
        'db_id'             => $rootMenuItemId,

        // These are not necessary for the functionality, but PHP warning will be thrown if not set
        'type'              => 'custom',
        'object'            => 'custom',
        'object_id'         => '',
        'classes'           => [],
        'target'            => '',
        'xfn'               => '',
    ];

    // Querying custom posts
    $customPosts = get_posts([
        'post_type'        => $customPostType,
        'posts_per_page'   => -1,
    ]);

    $max_menu_order = 0;
    foreach ($items as $item) {
      $max_menu_order = max($max_menu_order,$item->menu_order);
    }

    // Adding menu item specific properties to `$post` objects
    foreach ($customPosts as $i => $post) {
        $post->title = $post->post_title;
        $post->url = get_permalink($post);
        $post->menu_item_parent = $post->post_parent ? $post->post_parent : $rootMenuItemId;
        $post->menu_order = $max_menu_order + 1 + $i;
        $post->db_id = $post->ID;
    }

    // Merge custom posts into menu items
    $items = array_merge($items, $customPosts);
    
    return $items;
}, null, 3);

我接受了德弗伦克的回答,因为如果没有他的帮助,我根本不可能来到这里。尽管有了所有的细节和评论,我还是想显示最终结果,如下所示。添加\u filter调用match\u locations\u filter,按顺序为每个子级调用match\u菜单\u子级以创建整个层次结构。要使其正常工作,您可以向菜单中添加任何自定义的post类型条目,并且它应该自动包含它的所有子项

function match_menu_children($parent_menu_ID, $parent_post_id, $ordermin)
    {
        $items = array();

        $childPosts = get_posts([
            'post_type'         => 'match',
            'posts_per_page'    => -1,
            'order_by'          => 'menu_order',
            'order'             => 'ASC',
            'post_parent'       => $parent_post_id,
            ]);
        //print_r($childPosts);

        foreach ($childPosts as $item)
        {       
            $items[] = (object)[
            'ID'                => $item->ID,
            'title'             => $item->post_title,
            'url'               => get_permalink($item),
            'menu_item_parent'  => $parent_menu_ID,
            'post_parent'       => $parentID,
            'menu_order'        => ++$ordermin,
            'db_id'             => $item->ID,
            'type'              => 'custom',
            'object'            => 'custom',
            'object_id'         => '',
            'classes'           => [],
            ];

            $newitems = $this->match_menu_children($item->ID, $item->ID, $ordermin);
            if (count($newitems > 0))
            {
                $ordermin = $ordermin + count($newitems);
                $items = array_merge($items, $newitems) ;       
            }           
        }       
        return $items;
    }

    function match_locations_filter( $items, $menu, $args ) 
    {
        $customPostType = 'match';// Custom post type name      
        $ordermin = count($items) + 1;

        $customPosts = get_posts([
        'post_type'         => $customPostType,
        'posts_per_page'    => -1,
        'order_by'          => 'menu_order',
        'order'             => 'ASC',
        ]);

        foreach ($items as $menuitem)
        {
            foreach ($customPosts as $match)
            {
                if ($menuitem->object_id == $match->ID)
                {   
                    // This menu item IS a match entry.  Populate it with it's children.
                    $newitems = $this->match_menu_children($menuitem->db_id, $match->ID, $ordermin);
                    $ordermin = $ordermin + count($newitems);
                    $items = array_merge($items, $newitems) ;
                }
            }
        }
        return $items;
    }

这看起来很像我已经发现的似乎不起作用的东西。我想我缺少的是如何把它连接起来。我是否需要制作一个自定义链接菜单项或将其绑定到的东西?为了使其工作,您必须知道菜单的名称和位置。在上面的示例中,您必须用该名称替换菜单名称。此位置名称是在register_nav_菜单调用中设置的位置名称。然后还提供自定义帖子类型的名称。我在编写代码时已经测试过了,所以应该可以用了。如果我没有注册导航菜单电话?我一直假设‘show_in_menu’=>true就可以了。这也是必需的吗?使用中的每个菜单都有一个位置名称,所以如果您的主题至少使用了一个,那么应该在那里注册。但是,要测试和评估代码,可以删除| |$menu->slug===$menuLocation部分来自上述示例。这将在每个菜单中插入自定义帖子。只不过刚刚设法回到插件。在某种程度上,它是有效的。它确实显示了菜单中的所有页面,但它们都在根菜单上,而不是在层次结构/下拉列表中,而且它们似乎覆盖了我在菜单中输入的内容,尽管这可能只是因为有太多的页面无法显示。我想我已经弄清楚了每一行应该做什么,所以这个结果对我来说没有意义。