Pour ceux qui modifient souvent leurs pages (ou custom posts) et qui aimeraient y avoir accès plus rapidement, voici une astuce pour les lister directement dans le menu d’administration de WordPress. Ce bout de code vous permettra d’insérer les liens vers l’édition de chacune de vos pages dans le menu, ou un sous-menu.
Méthode générale et options
D’abord nous créons une fonction sf_admin_menu() que nous allons « hooker » à admin_menu() de WordPress. Ensuite, nous créons des options pour personnaliser l’affichage de nos liens selon nos besoins :
- $in_sub : si
$in_sub = true
, les liens s’afficheront dans le sous-menu de « Pages », sinon sous forme de menu de 1er niveau, - $gal_pages_item : utile seulement pour l’affichage « Menu de 1er niveau », si
$gal_pages_item = true
, on affiche l’item général « Pages », sinon il est supprimé du menu, - $pages_in_trash : utile seulement pour l’affichage « Menu de 1er niveau », si
$pages_in_trash = true
, on affiche un lien vers les pages situées dans la corbeille.
Comme d’habitude, tout ce qui suit va aller dans le fichier functions.php de votre thème.
12345678
function sf_admin_menu() {
$in_sub = true;
$gal_pages_item = false;
$pages_in_trash = true;
$templ_url = get_bloginfo('template_directory');
global $wpdb, $menu, $submenu;
}
add_action('admin_menu', 'sf_admin_menu');
Par la même occasion nous créons la variable $templ_url pour enregistrer le chemin vers le dossier de notre thème, elle nous servira pour les images de menu/sous-menu. Nous aurons également besoin des variables globales $wpdb, $menu et $submenu de WordPress.
Requête
Pour créer nos entrées de menu/sous-menu nous aurons besoin pour chaque page d’aller chercher dans la base de données son identifiant unique, son titre et son statut. Le statut d’une page peut être « publish » (publiée), « draft » (brouillon), « pending » (en attente de relecture) ou « trash » (à la corbeille). Pour les posts et les custom posts types déclarés avec 'capability_type' => 'page'
, il y a aussi le statut « static » (mis en avant).
Nous allons donc demander les posts dont le « post_type » est égal à « page » et dont le « post_status » est différent de « trash » (car on ne peut pas éditer une page qui est à la corbeille, donc inutile de mettre un lien vers chaque article de la corbeille).
7
$pages_for_menu = $wpdb->get_results( "SELECT ID, post_title, post_status FROM $wpdb->posts WHERE post_type='page' AND post_status!='trash' ORDER BY post_title" );
Cette requête nous servira pour les deux modes d’affichage : menu de 1er niveau ou sous-menu.
Version « sous-menu »
Nous vérifions notre réglage
$in_sub
pour savoir si l’on souhaite un affichage en sous-menu, et si le résultat de notre requête n’est pas vide, nous utilisons la fonction add_submenu_page()
de WordPress bouclée avec foreach
:
010203040506070809101112131415161718
function sf_admin_menu() {
$in_sub = true;
$gal_pages_item = false;
$pages_in_trash = true;
$templ_url = get_bloginfo('template_directory');
global $wpdb, $menu, $submenu;
$pages_for_menu = $wpdb->get_results( "SELECT ID, post_title, post_status FROM $wpdb->posts WHERE post_type='page' AND post_status!='trash' ORDER BY post_title" );
if ($in_sub) {
if ($pages_for_menu){
foreach($pages_for_menu as $pagemenu){
add_submenu_page('edit.php?post_type=page', '', '<img title="'.$pagemenu->post_status.'" alt="['.$pagemenu->post_status.'] " src="'.$templ_url.'/images/admin/'.$pagemenu->post_status.'.png"/> '.$pagemenu->post_title, 'edit_pages', 'post.php?post='.$pagemenu->ID.'&action=edit');
}
}
} else {
// Affichage "Menu de 1er niveau"
}
}
add_action('admin_menu', 'sf_admin_menu');
Petite explication pour add_submenu_page()
:
'edit.php?post_type=page'
: il s’agit de l’item parent. Ici, l’item de menu « Pages »,''
: le deuxième paramètre est vide, c’est le titre de la page vers laquelle mène le lien. Inutilisable dans notre cas, WordPress ne nous permettra pas de changer celui par défaut,'<img title="'.$pagemenu->post_status.'" alt="['.$pagemenu->post_status.'] " src="' . $templ_url . '/images/admin/' . $pagemenu->post_status . '.png"/> ' . $pagemenu->post_title
: titre du lien. Ici, j’insère une image avant le titre, elle nous servira à différencier les pages publiées de celles en attente de relecture ou des brouillons. Le résultat sera sous la forme :'<img title="publish" alt="[publish] " src="http://www.mon-site.com/wp_content/themes/mon_theme/images/admin/publish.png"/> Titre de page'
. Tout ce dont vous aurez besoin ce sont 3 images 16px x 16px placées dans un sous-dossier ‘images/admin/’ de votre thème et les appeler publish.png, draft.png et pending.png.'edit_pages'
: capability pour accéder à la page d’édition,'post.php?post='.$pagemenu->ID.'&action=edit'
: le lien vers la page d’édition de votre page.
Version « menu »
Pour mettre nos pages au même niveau « Articles », « Médias », « Liens », etc., la première chose que nous devons voir c’est que nous n’aurons pas assez de place pour les insérer directement en dessous de l’item « Pages ». En effet, comme je l’avais indiqué lors de mon précédent article Personnaliser son administration WordPress au paragraphe « Ajouter ou supprimer des liens dans le menu d’administration », l’onglet « Pages » est à la position 20 dans la variable $menu, s’en suivent les « Commentaires » à la position 25, de quoi rentrer seulement 4 pages entre.
Cependant, le prochain onglet est un séparateur à la position 59, ça nous laisse assez de place pour tout mettre. Donc, nous allons créer un autre « bloc de menu » sous l’item « Commentaires » et supprimer l’item « Pages » d’origine.
1314151617181920212223242526
//... Notre code précédent...
} else {
if ($pages_for_menu){
$menu[29] = $menu[59]; // Séparateur
if($gal_pages_item) {
$menu[30] = $menu[20]; // On duplique l'item "Pages" pour l'insérer en position 30
$menu[30][4] = 'menu-top menu-top-first menu-icon-page'; // Pour avoir l'arrondi de "1er item" sur le nouvel item "Pages"
}
unset($menu[20]); // On supprime l'item original "Pages"
$menu[25][4] = 'menu-top menu-top-last menu-icon-comments'; // Pour avoir l'arrondi de "dernier item" sur "Commentaires"
// ...
}
// ...
}
Nous allons insérer nos page à partir de la position 30. Nous commençons par créer un séparateur à la position 29, en copiant celui existant à la position 59.
Ensuite, avec $gal_pages_item, on teste si on veut avoir l’onglet général « Pages » à la position 30. Si oui, on le crée en copiant celui déjà existant à la position 20, puis on lui ajoute la classe « menu-top-first » pour qu’il ait les coins supérieurs arrondis.
Étape suivante, nous supprimons l’onglet « Pages » d’origine (à la position 20) avec unset($menu[20])
, puis nous ajoutons la classe « menu-top-last » à l’onglet situé à la position 25 (c’est l’onglet « Commentaires », juste au-dessus du séparateur que nous venons de rajouter) pour qu’il ait les coins inférieurs arrondis.
Maintenant il nous faut une nouvelle boucle foreach()
pour ajouter nos pages. Le système est presque identique à la version « sous-menu » sauf qu’il nous faut indiquer à chaque fois la position du nouveau lien dans le menu. Nous commençons à 31.
1314151617181920212223242526272829303132
//... Notre code précédent...
} else {
if ($pages_for_menu){
$menu[29] = $menu[59]; // Séparateur
if($gal_pages_item) {
$menu[30] = $menu[20]; // On duplique l'item "Pages" pour l'insérer en position 30
$menu[30][4] = 'menu-top menu-top-first menu-icon-page'; // Pour avoir l'arrondi de "1er item" sur le nouvel item "Pages"
}
unset($menu[20]); // On supprime l'item original "Pages"
$menu[25][4] = 'menu-top menu-top-last menu-icon-comments'; // Pour avoir l'arrondi de "dernier item" sur "Commentaires"
$i = 31;
foreach($pages_for_menu as $pagemenu){
add_menu_page( '', $pagemenu->post_title, 'edit_pages', 'post.php?post='.$pagemenu->ID.'&action=edit', '', $templ_url.'/images/admin/'.$pagemenu->post_status.'.png', $i );
if($i == 31 && !$gal_pages_item)
$menu[$i][4] = 'menu-top menu-top-first'; // Pour avoir l'arrondi de "1er item" sur cette première page
$i++;
}
}
// ...
}
Petite explication pour add_menu_page()
:
''
: le titre de la page vers laquelle mène le lien. Inutilisable cette fois encore,$pagemenu->post_title
: titre du lien,'edit_pages'
: capability pour accéder à la page d’édition,'post.php?post='.$pagemenu->ID.'&action=edit'
: le lien vers la page d’édition de votre page,''
: fonction servant à afficher le contenu de la page vers laquelle le lien pointe. Inutile dans notre cas.$templ_url.'/images/admin/'.$pagemenu->post_status.'.png'
: url de l’image de l’item. C’est la même chose que pour la version « sous-menu »,$i
: la position de l’item dans le menu.
A la ligne suivante, on demande si $i est égal à 31, c’est à dire si nous nous sommes sur notre premier lien, et si $gal_pages_item est à false (on ne crée pas de nouvel item « Pages ») alors nous devons arrondir les coins supérieurs de ce lien puisqu’il s’agira effectivement du 1er lien de notre « bloc ».
On incrémente enfin notre compteur $i.
Dernière chose, il peut être utile d’avoir un lien vers la page listant les pages situées dans la corbeille, surtout si nous avons décidé de ne pas afficher le lien « Pages ». En plus, le lien affichera le nombre de pages dans la corbeille. C’est donc là que nous testons notre réglage $pages_in_trash.
303132333435363738
// ...
if ($pages_in_trash) {
$trashed_pages = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_type='page' AND post_status='trash'");
if($trashed_pages)
add_menu_page( '', 'Corbeille ('.$trashed_pages.')', 'edit_pages', 'edit.php?post_status=trash&post_type=page', '', $templ_url.'/images/admin/trash.png', $i );
}
}
}
add_action('admin_menu', 'sf_admin_menu');
Avec $trashed_pages, nous stockons directement le nombre de pages dans la corbeille.
Hé oui, vous avez bien vu, il vous faudra une image appelée trash.png avec les autres.
Conclusion
0102030405060708091011121314151617181920212223242526272829303132333435363738
function sf_admin_menu() {
$in_sub = true;
$gal_pages_item = false;
$pages_in_trash = true;
$templ_url = get_bloginfo('template_directory');
global $wpdb, $menu, $submenu;
$pages_for_menu = $wpdb->get_results( "SELECT ID, post_title, post_status FROM $wpdb->posts WHERE post_type='page' AND post_status!='trash' ORDER BY post_title" );
if ($in_sub) {
if ($pages_for_menu){
foreach($pages_for_menu as $pagemenu){
add_submenu_page('edit.php?post_type=page', '', '<img title="'.$pagemenu->post_status.'" alt="'.$pagemenu->post_status.'" src="'.$templ_url.'/images/admin/'.$pagemenu->post_status.'.png"/> '.$pagemenu->post_title, 'edit_pages', 'post.php?post='.$pagemenu->ID.'&action=edit');
}
}
} else {
if ($pages_for_menu){
$menu[29] = $menu[59]; // Séparateur
if($gal_pages_item) {
$menu[30] = $menu[20]; // On duplique l'item "Pages" pour l'insérer en position 30
$menu[30][4] = 'menu-top menu-top-first menu-icon-page'; // Pour avoir l'arrondi de "1er item" sur le nouvel item "Pages"
}
unset($menu[20]); // On supprime l'item original "Pages"
$menu[25][4] = 'menu-top menu-top-last menu-icon-comments'; // Pour avoir l'arrondi de "dernier item" sur "Commentaires"
$i = 31;
foreach($pages_for_menu as $pagemenu){
add_menu_page( '', $pagemenu->post_title, 'edit_pages', 'post.php?post='.$pagemenu->ID.'&action=edit', '', $templ_url.'/images/admin/'.$pagemenu->post_status.'.png', $i );
if($i == 31 && !$gal_pages_item)
$menu[$i][4] = 'menu-top menu-top-first'; // Pour avoir l'arrondi de "1er item" sur cette première page
$i++;
}
}
if ($pages_in_trash) {
$trashed_pages = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_type='page' AND post_status='trash'");
if($trashed_pages)
add_menu_page( '', 'Corbeille ('.$trashed_pages.')', 'edit_pages', 'edit.php?post_status=trash&post_type=page', '', $templ_url.'/images/admin/trash.png', $i );
}
}
}
add_action('admin_menu', 'sf_admin_menu');
$in_sub = true
: les liens s’afficheront dans le sous-menu de « Pages », sinon sous forme de menu de 1er niveau,$gal_pages_item = true
: on affiche l’item général « Pages », sinon il est supprimé du menu (affichage « Menu de 1er niveau »),$pages_in_trash = true
: on affiche un lien vers les pages situées dans la corbeille (affichage « Menu de 1er niveau »).
Quatre images (16px x 16px, format .png) dans le sous-dossier images/admin/ de votre thème : publish.png, draft.png, pending.png et trash.png (allez, je suis sympa, je vous file les miennes dans l’archive à télécharger :) ).
Si vous utilisez relativement peu de pages, ces quelques lignes vous seront peut-être utiles :)
See ya!
Commentaires
Commentaire de Cédric Charles.
Woaw quelle réactivité :) !!!
Merci beaucoup, ça fait plaisir !
Si jamais tu (si on peut toujours se tutoyer) te lances dans le multisites, n’hésites pas à me prévenir ;) !
Merci,
Cédric
Commentaire de Cédric Charles.
Alors… Désolé une fois de plus de te déranger :/ ! Je viens d’essayer ton code. Ça fonctionne très bien mais ce que j’aimerais faire c’est, comme je t’ai expliqué, qu’une page X devienne un sous menu d’un custom post type Y…
Y a-t-il une manière simple de le faire ou je dois d’abord mettre les pages en menu et ensuite du menu en sous-menu ?
Merci merci ;)
Commentaire de Cédric Charles.
Finalement j’ai trouvé… Par contre je viens de voir que dans la page d’édition d’une page, on peut supprimer des meta box. Moi j’aimerais supprimer la meta box du titre, c’est à dire que l’utilisateur ne puisse pas modifier le titre que je crée à la base. Tu peux m’aider ?
Commentaire de Greg.
Le problème c’est qu’apparemment (mais je peux me tromper), le titre n’est pas considéré de la même façon que les autres metabox, la fonction remove_meta_box() ne permet pas de la supprimer.
Le seul moyen que je vois pour désactiver l’édition du titre ou pour le supprimer, est de modifier directement un fichier de WordPress, modification qui disparaitra à chaque mise à jour de WP :/ (en plus, la partie qui nous concerne dans ce fichier n’est pas filtrable).
Commentaire de Cédric Charles.
C’est vachement embêtant ça :/ !
Comme je t’ai dit, en WordPress Multisite, il n’y a qu’un dossier de thème commun à tous les sous-sites. Modifier le nom du fichier php n’est donc pas possible puisqu’il sera alors inaccessibles aux futurs sous-sites :s !
Vois-tu une autre solution :s ?
Commentaire de Greg.
OK, je ne savais pas pour le dossier de thèmes commun.
Modifier le nom du fichier php n’est donc pas possible
Ha là tu parles de notre autre sujet de discussion ^^.
Il reste donc ma solution n°1 qui consistait à mettre la création des pages dans un plugin, et qui se déclencherait uniquement à l’activation du plugin -> donc pas de nouvelles requêtes ultérieures (je suppose donc qu’en multisites, les plugins sont activés indépendamment par site).
Ou alors ma solution n°3 qui utilise une option dans bdd -> une seule requête pour toutes les pages (si l’option n’existe pas dans la bdd, on crée les pages puis on ajoute l’option dans la bdd).
1234567
J’ai pas regardé comment est foutue get_option() mais je suppose qu’elle est légère, étant donné qu’elle va chercher seulement un champs dans une table. Ça me semble être un bon compromis, et indépendant du site (à moins qu’en multisites la bdd soit également commune à tous les sites?).
Commentaire de Cédric Charles.
La base de donnée n’est heureusement pas commune en multisites puisque les contenu des sites sont différents (du moins je le suppose, je te dit ça après test ;) ).
Merci pour ton aide ;) !
Commentaire de Cédric Charles.
J’ai bien réussi à lister mes pages dans le menu. Par contre, j’aimerais qu’elle ait comme icône l’icône de base des pages. Mais je ne vois pas comment faire ça :/ ?!
Commentaire de Greg.
Version « Menu » ou « Sous-menu »?
Commentaire de Cédric Charles.
Version menu. J’ai vu que les images se trouvent dans le sprite icons32.png, mais comment choisir l’image des pages :s…