add_menu_page() con nome diverso per la prima voce del sottomenu
La documentazione di add_menu_page
indica di passare il titolo del menu come secondo parametro:
add_menu_page('Titolo Pagina', 'Titolo Menu', ...);
Quando si aggiungono altre pagine successivamente tramite add_submenu_page
, la pagina principale diventa la prima voce nel sottomenu:
Tuttavia, voglio che la prima voce nell'elenco abbia un nome diverso (ma che punti ancora alla stessa pagina), come fa WordPress stesso:
Come posso ottenere questo risultato nel mio plugin?

Puoi impostare lo 'slug' della pagina del sottomenu uguale a quello della pagina principale, e punteranno alla stessa posizione:
add_action('admin_menu', 'my_menu_pages');
function my_menu_pages(){
add_menu_page('Titolo della mia pagina', 'Titolo del mio menu', 'manage_options', 'my-menu', 'my_menu_output' );
add_submenu_page('my-menu', 'Titolo pagina sottomenu', 'Qualsiasi cosa tu voglia', 'manage_options', 'my-menu' );
add_submenu_page('my-menu', 'Titolo pagina sottomenu2', 'Qualsiasi cosa tu voglia2', 'manage_options', 'my-menu2' );
}
Esempio:

Ciò comporterebbe voci duplicate, poiché Wordpress crea automaticamente una sottopagina di menu per la pagina principale.

Ricordo di aver sfogliato il codice core la scorsa settimana e di aver trovato una nota che diceva qualcosa tipo: "Aggiungi la voce di sottomenu predefinita SE L'UTENTE NON L'HA GIÀ FATTO". Verifica se esiste già una voce di sottomenu che punta all'elemento di primo livello. Se esiste, non aggiunge quella predefinita.

Voglio che quando creo un menu personalizzato, voglio visualizzare alcune tabelle e dati come vengono visualizzate le altre schede, un link tutorial o qualche funzione sarebbe apprezzato

Funziona perfettamente. Assicurati di avere almeno un sottomenu oltre al primo, poiché il primo punta allo slug del genitore. Altrimenti i tuoi sottomenu non saranno visibili.

Ovviamente funziona ancora con WP 5.9. Dato che il callback per add_menu_page è opzionale, l'ho eliminato e mi sono semplicemente assicurato che lo slug per il menu e il primo sottomenu fossero gli stessi. Come ha detto @MichaelLewis, questo permette di eliminare il primo sottomenu predefinito/ridondante. Bravo!

Rendi lo slug del menu principale e del sottomenu uguali (primo elemento) come mostrato di seguito
function actions_recent_bids_add_admin_page(){
add_menu_page(
'Offerte Recenti',
'Report Aste',
'manage_options',
'wc-auction-reports',
'actions_recent_bids_list',
'dashicons-chart-area',
56
);
add_submenu_page(
'wc-auction-reports', // slug genitore
'Offerte Recenti', // titolo pagina
'Offerte Recenti', // titolo menu
'manage_options', // capacità
'wc-auction-reports', // slug
'acutions_customers_spendings_list' // callback
);
add_submenu_page(
'wc-auction-reports', // slug genitore
'Spese Clienti', // titolo pagina
'Spese Clienti', // titolo menu
'manage_options', // capacità
'wc-acutions-customers-spendings', // slug
'acutions_customers_spendings_list' // callback
);
add_submenu_page(
'wc-auction-reports', // slug genitore
'Offerte Clienti', // titolo pagina
'Offerte Clienti', // titolo menu
'manage_options', // capacità
'wc-acutions-customers-bids', // slug
'acutions_customers_bids_list' // callback
);
}
add_action('admin_menu','actions_recent_bids_add_admin_page');

Ciao, ho passato un sacco di tempo a cercare questa soluzione e il modo corretto non è elencato qui. Quello che vuoi usare è:
remove_submenu_page('parent_slug','parent_slug');
alla fine della tua funzione
Esempio:
function posts_sync_menu() {
// Voce Menu Principale (funge da contenitore)
add_menu_page(
'I Miei Post', // Titolo della pagina
'I Miei Post', // Titolo del menu
'manage_options', // Capability
'my-posts', // Slug del menu (necessario solo per l'inizializzazione)
'', // Nessuna funzione/callback necessaria
'dashicons-networking', // Icona
6 // Posizione
);
add_submenu_page(
'my-posts', // Slug genitore
'Elenco Miei Post', // Titolo della pagina
'Elenco Miei Post', // Titolo del menu
'manage_options', // Capability
'my-posts-listing', // Slug
'my_posts_callback' // Callback per renderizzare la pagina
);
// Rimuovi la voce del sottomenu genitore prendendo lo slug da "Elenco Miei Post"
remove_submenu_page('my-posts','my-posts');
}
Renderà questo risultato:
Quindi fondamentalmente avranno lo stesso slug con nomi di menu diversi proprio come richiesto.

Ma la domanda riguarda l'aggiunta di un menu duplicato, non la rimozione di uno?

Potrebbe essere realizzato rimuovendo la voce originale e poi aggiungendone una nuova con un nome diverso ma con lo stesso slug. Solo un'idea!

Aggiornamento!!! Se non sei sicuro che il menu genitore esista, puoi prima verificarlo come segue:
function contacts_page_submenu(){
// Verifica se il menu esiste (se il Genitore esiste), non ne abbiamo bisogno ma lui ha scritto :| (sono l'editor)
if(menu_page_url('contacts-parent-menu', false )){
// Cambia il testo del primo Sottomenu
add_submenu_page(
'contacts-parent-menu', // Slug del Genitore obbligatorio
'Impostazioni Contatti',
'Impostazioni Contatti',
'manage_options',
'contacts-parent-menu', // Slug del Genitore obbligatorio
'contacts_submenu_callback' // Nome della Callback del Genitore
);
}
}
add_action('admin_menu', 'contacts_page_submenu');
Testato e funzionante su WordPress 6.
Riferimento: https://developer.wordpress.org/reference/functions/add_submenu_page/

function content_adder_menu() {
add_menu_page(
'Contenuto', // Titolo della pagina
'Contenuto', // Titolo del menu
'manage_options', // Capacità richiesta per l'accesso
'content-adder', // Slug del menu
'content_adder_page' // Funzione callback per visualizzare la pagina
);
// Aggiungi una pagina sottomenu sotto il menu principale
add_submenu_page(
'content-adder', // Slug del menu genitore
'Aggiungi Contenuto', // Titolo della pagina
'Aggiungi Contenuto', // Titolo del menu
'manage_options', // Capacità richiesta per l'accesso
'add-content', // Slug del menu
'add_content_page' // Funzione callback per visualizzare la pagina
);
}
// Funzione callback per la pagina del menu principale
function content_adder_page() {
// Visualizza qui il contenuto della pagina del menu principale
echo '<div class="wrap">';
echo '<h1>Benvenuto in Contenuto</h1>';
// Recupera i post dal tipo di post 'post'
$args = array(
'post_type' => 'post', // Modifica il tipo di post se necessario
'post_status' => 'publish', // Recupera solo i post pubblicati
'posts_per_page' => -1, // Recupera tutti i post
);
$query = new WP_Query($args);
if ($query->have_posts()) {
echo '<h2>Lista dei Post</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(); // Ripristina i dati globali del post
} else {
echo '<p>Nessun post trovato.</p>';
}
echo '</div>';
}
// Funzione callback per la pagina del sottomenu
function add_content_page() {
// Visualizza qui il contenuto della pagina del sottomenu
echo '<div class="wrap">';
echo '<h1>Aggiungi Contenuto</h1>';
// Verifica se il form è stato inviato
if(isset($_POST['submit'])) {
// Elabora i dati del form qui
$url = sanitize_text_field($_POST['url']);
$content = wp_kses_post($_POST['content']);
// Salva o utilizza i dati inviati come necessario
// Ad esempio, puoi salvarli in un tipo di post personalizzato o visualizzarli
$new_post = array(
'post_title' => 'Titolo del tuo post',
'post_content' => $content, // Il contenuto che vuoi salvare
'post_status' => 'publish', // Pubblica il post
'post_author' => 1, // ID dell'autore (1 è tipicamente l'amministratore)
'post_type' => 'post', // Tipo di post (modifica se necessario)
);
$post_id = wp_insert_post($new_post);
if ($post_id) {
// Il post è stato inserito con successo
echo 'Post ID ' . $post_id . ' creato.';
} else {
// Si è verificato un errore
echo 'Errore nella creazione del post.';
}
echo "<p>URL: $url</p>";
echo "<div>Contenuto: $content</div>";
} else {
// Visualizza il form
echo '<form method="post">';
echo '<label for="url">Aggiungi URL:</label> <br>';
echo '<input type="text" name="url" id="url" /><br />';
echo '<label for="content">Aggiungi Contenuto:</label> <br>';
echo '<textarea name="content" id="content" rows="5" cols="40"></textarea><br />';
echo '<input type="submit" name="submit" value="Aggiungi Contenuto" class="button button-primary" />';
echo '</form>';
}
echo '</div>';
}
add_action('admin_menu', 'content_adder_menu');

add_submenu_page(
'tut_theme_settings', // slug genitore
'Elementi Front Page 2', // titolo pagina
'Front Page 2', // titolo menu
'manage_options', // capacità
'tut_theme_settings2', // slug
'theme_front_page_settings' // callback
);
se il nome del primo sottomenu è diverso, crea lo stesso slug del genitore e del primo figlio e chiama la stessa funzione
