add_menu_page() с разным названием для первого пункта подменю
Документация add_menu_page
указывает передавать заголовок меню вторым параметром:
add_menu_page('Page Title', 'Menu Title', ...);
При добавлении дополнительных страниц через add_submenu_page
, главная страница становится первым элементом в подменю:
Однако я хочу, чтобы первый пункт в списке имел другое название (но по-прежнему указывал на ту же страницу), как это делает сам WordPress:
Как я могу реализовать это в своем плагине?

Вы можете сделать 'slug' для страницы подменю таким же, как у страницы верхнего уровня, и они будут вести на одно и то же место:
add_action('admin_menu', 'my_menu_pages');
function my_menu_pages(){
add_menu_page('Мой заголовок страницы', 'Мой заголовок меню', 'manage_options', 'my-menu', 'my_menu_output' );
add_submenu_page('my-menu', 'Заголовок страницы подменю', 'Что угодно', 'manage_options', 'my-menu' );
add_submenu_page('my-menu', 'Заголовок страницы подменю2', 'Что угодно2', 'manage_options', 'my-menu2' );
}
Например:

Это приведет к дублированию записей, так как WordPress автоматически создает подстраницу меню для главной страницы.

Я помню, что на прошлой неделе бегло просматривал исходный код и наткнулся на заметку, в которой было что-то вроде: "Добавить подменю по умолчанию, ЕСЛИ ПОЛЬЗОВАТЕЛЬ ЕЩЕ НЕ ДОБАВИЛ". Он проверяет, есть ли подменю, указывающее на элемент верхнего уровня. Если есть, то по умолчанию не добавляется.

Я хочу, чтобы при создании пользовательского меню отображались некоторые таблицы и данные, как в других вкладках, где показывается ссылка на обучающий материал или справку. Буду признателен за помощь с функционалом.

Работает отлично. Убедитесь, что у вас есть хотя бы одно подменю, кроме первого, так как первое указывает на родительский слаг. Если его нет, ваши подменю не будут видны.

Очевидно, всё ещё работает в WP 5.9. Поскольку callback для add_menu_page является необязательным, я его убрал и просто убедился, что slug для меню и первого подменю совпадают. Как сказал @MichaelLewis, это позволяет убрать первое стандартное/избыточное подменю. Браво!

Сделайте slug родительского пункта меню и подменю одинаковыми (первый пункт), как показано ниже
function actions_recent_bids_add_admin_page(){
add_menu_page(
'Recent Bids', // заголовок страницы
'Auction Reports', // название в меню
'manage_options', // права доступа
'wc-auction-reports', // slug
'actions_recent_bids_list', // функция вывода
'dashicons-chart-area', // иконка
56 // позиция в меню
);
add_submenu_page(
'wc-auction-reports', // slug родителя
'Recent Bids', // заголовок страницы
'Recent Bids', // название в меню
'manage_options', // права доступа
'wc-auction-reports', // slug (должен совпадать с родителем)
'acutions_customers_spendings_list' // функция вывода
);
add_submenu_page(
'wc-auction-reports', // slug родителя
'Customer Spending', // заголовок страницы
'Customer Spending', // название в меню
'manage_options', // права доступа
'wc-acutions-customers-spendings', // slug
'acutions_customers_spendings_list' // функция вывода
);
add_submenu_page(
'wc-auction-reports', // slug родителя
'Customer Bids', // заголовок страницы
'Customer Bids', // название в меню
'manage_options', // права доступа
'wc-acutions-customers-bids', // slug
'acutions_customers_bids_list' // функция вывода
);
}
add_action('admin_menu','actions_recent_bids_add_admin_page');

Привет, я потратил кучу времени на поиски, и правильного решения здесь нет. Вам нужно использовать
remove_submenu_page('parent_slug','parent_slug');
в конце вашей функции.
Пример:
function posts_sync_menu() {
// Основной пункт меню (выступает как контейнер)
add_menu_page(
'Мои записи', // Заголовок страницы
'Мои записи', // Заголовок меню
'manage_options', // Права доступа
'my-posts', // Слаг меню, нужен только для инициализации.
'', // Функция/колбэк не нужны
'dashicons-networking', // Иконка
6 // Позиция
);
add_submenu_page(
'my-posts', // Родительский слаг
'Список моих записей', // Заголовок страницы
'Список моих записей', // Заголовок меню
'manage_options', // Права доступа
'my-posts-listing', // Слаг
'my_posts_callback' // Колбэк для отображения страницы
);
// Удаляем подменю родителя и берем слаг из "Список моих записей"
remove_submenu_page('my-posts','my-posts');
}
Результат будет таким:
По сути, у них будет один и тот же слаг, но разные названия в меню, как и требовалось.

Это можно реализовать, удалив оригинальную запись и затем добавив новую с другим именем, но тем же самым ярлыком. Просто идея!

Обновление!!! Если вы не уверены, существует ли родительское меню, вы можете сначала проверить его следующим образом:
function contacts_page_submenu(){
// Проверяем существование меню (если родительский элемент существует), нам это не нужно, но он написал :| (я редактор)
if(menu_page_url('contacts-parent-menu', false )){
// Изменяем текст первого подменю
add_submenu_page(
'contacts-parent-menu', // Слаг родителя обязателен
'Настройки контактов',
'Настройки контактов',
'manage_options',
'contacts-parent-menu', // Слаг родителя обязателен
'contacts_submenu_callback' // Указываем название callback-функции родителя
);
}
}
add_action('admin_menu', 'contacts_page_submenu');
Протестировано и работает на WordPress 6.
Ссылка на документацию: https://developer.wordpress.org/reference/functions/add_submenu_page/

function content_adder_menu() {
add_menu_page(
'Контент', // Заголовок страницы
'Контент', // Заголовок меню
'manage_options', // Требуемые права доступа
'content-adder', // Ярлык меню
'content_adder_page' // Функция обратного вызова для отображения страницы
);
// Добавляем подменю к основному меню
add_submenu_page(
'content-adder', // Ярлык родительского меню
'Добавить контент', // Заголовок страницы
'Добавить контент', // Заголовок меню
'manage_options', // Требуемые права доступа
'add-content', // Ярлык меню
'add_content_page' // Функция обратного вызова для отображения страницы
);
}
// Функция обратного вызова для страницы основного меню
function content_adder_page() {
// Отображаем содержимое страницы основного меню
echo '<div class="wrap">';
echo '<h1>Добро пожаловать в раздел Контента</h1>';
// Получаем записи типа 'post'
$args = array(
'post_type' => 'post', // Укажите нужный тип записи
'post_status' => 'publish', // Только опубликованные записи
'posts_per_page' => -1, // Все записи
);
$query = new WP_Query($args);
if ($query->have_posts()) {
echo '<h2>Список записей</h2>';
echo '<ul>';
while ($query->have_posts()) {
$query->the_post();
echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
}
echo '</ul>';
wp_reset_postdata(); // Восстанавливаем глобальные данные записи
} else {
echo '<p>Записи не найдены.</p>';
}
echo '</div>';
}
// Функция обратного вызова для страницы подменю
function add_content_page() {
// Отображаем содержимое страницы подменю
echo '<div class="wrap">';
echo '<h1>Добавить контент </h1>';
// Проверяем отправку формы
if(isset($_POST['submit'])) {
// Обрабатываем данные формы
$url = sanitize_text_field($_POST['url']);
$content = wp_kses_post($_POST['content']);
// Сохраняем или используем отправленные данные
// Например, сохраняем как запись или выводим
$new_post = array(
'post_title' => 'Заголовок записи',
'post_content' => $content, // Содержимое для сохранения
'post_status' => 'publish', // Публикуем запись
'post_author' => 1, // ID автора (1 обычно администратор)
'post_type' => 'post', // Тип записи (измените при необходимости)
);
$post_id = wp_insert_post($new_post);
if ($post_id) {
// Запись успешно создана
echo 'Запись с ID ' . $post_id . ' создана.';
} else {
// Произошла ошибка
echo 'Ошибка при создании записи.';
}
echo "<p>URL: $url</p>";
echo "<div>Содержимое: $content</div>";
} else {
// Отображаем форму
echo '<form method="post">';
echo '<label for="url">Добавить URL:</label> <br>';
echo '<input type="text" name="url" id="url" /><br />';
echo '<label for="content">Добавить содержимое:</label> <br>';
echo '<textarea name="content" id="content" rows="5" cols="40"></textarea><br />';
echo '<input type="submit" name="submit" value="Добавить контент" class="button button-primary" />';
echo '</form>';
}
echo '</div>';
}
add_action('admin_menu', 'content_adder_menu');

add_submenu_page(
'tut_theme_settings', // родительский slug
'Элементы главной страницы 2', // заголовок страницы
'Главная 2', // заголовок меню
'manage_options', // capability
'tut_theme_settings2', // slug
'theme_front_page_settings' // callback-функция
);
если имя первого подменю отличается, создайте одинаковый slug для родителя и первого дочернего элемента и вызовите ту же функцию
