Wordpress 分层自定义 post 类型自动添加到菜单
Wordpress Hierarchical custom post type automatically added to menu
这可能是重复的,但我并没有真正看到我在搜索时找到的内容与我的问题有何关联。
我在插件中创建了分层自定义 post 类型。我正在尝试为这种自定义 post 类型自动添加菜单项,这样当我添加新条目时,它将显示在根据层次结构正确排列的 drop-down 菜单中。我可以接受必须 select 一个条目,只要它的所有 children 正确填充在菜单中,而不必每次创建新条目时都手动添加它们。
我已经能够在菜单中添加一个条目。但它不添加 children。我试过 "automatically add new top-level entries" 选项,但它也没有做任何事情。我发现一些东西说要向 wp_get_nav_menu_items 添加过滤器,但要么我把它放在错误的位置(我在自定义 post 类型定义 class 中有它),要么它没用并且不符合我的要求。
看起来这应该是一件相对简单的事情——看起来所有的功能都会存在,我只是没有找到如何link它。
感谢您的帮助。
建议编辑后共享整个文件,以防万一。
<?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> </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;
可能还有其他可能的解决方案,但您绝对可以使用 wp_get_nav_menu_items
过滤器来做到这一点。下面是使用此挂钩更改菜单的示例代码。您可以将它插入到插件的主文件中,但可以更改回调顶部的参数以满足您的需要。
基本上这会创建一个“虚拟”顶级菜单项,并在此菜单项下插入自定义 post 条目。最后,您可以修改它以使用其中一个海关 post 作为顶级项目,并将其余项目列在下面。此外,好处是基于 menu_item_parent
和 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);
我接受了 dferenc 的回答,因为没有他的帮助我根本不可能来到这里。然而,有了所有的细节和评论,我想显示最终结果,如下所示。 add_filter
调用 match_locations_filter
,后者依次为每个子级调用 match_menu_children
以创建整个层次结构。要使其正常工作,您可以将任何自定义 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;
}
这可能是重复的,但我并没有真正看到我在搜索时找到的内容与我的问题有何关联。
我在插件中创建了分层自定义 post 类型。我正在尝试为这种自定义 post 类型自动添加菜单项,这样当我添加新条目时,它将显示在根据层次结构正确排列的 drop-down 菜单中。我可以接受必须 select 一个条目,只要它的所有 children 正确填充在菜单中,而不必每次创建新条目时都手动添加它们。
我已经能够在菜单中添加一个条目。但它不添加 children。我试过 "automatically add new top-level entries" 选项,但它也没有做任何事情。我发现一些东西说要向 wp_get_nav_menu_items 添加过滤器,但要么我把它放在错误的位置(我在自定义 post 类型定义 class 中有它),要么它没用并且不符合我的要求。
看起来这应该是一件相对简单的事情——看起来所有的功能都会存在,我只是没有找到如何link它。
感谢您的帮助。
建议编辑后共享整个文件,以防万一。
<?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> </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;
可能还有其他可能的解决方案,但您绝对可以使用 wp_get_nav_menu_items
过滤器来做到这一点。下面是使用此挂钩更改菜单的示例代码。您可以将它插入到插件的主文件中,但可以更改回调顶部的参数以满足您的需要。
基本上这会创建一个“虚拟”顶级菜单项,并在此菜单项下插入自定义 post 条目。最后,您可以修改它以使用其中一个海关 post 作为顶级项目,并将其余项目列在下面。此外,好处是基于 menu_item_parent
和 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);
我接受了 dferenc 的回答,因为没有他的帮助我根本不可能来到这里。然而,有了所有的细节和评论,我想显示最终结果,如下所示。 add_filter
调用 match_locations_filter
,后者依次为每个子级调用 match_menu_children
以创建整个层次结构。要使其正常工作,您可以将任何自定义 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;
}