Contenu principal
WordPress Admin Bar

Modifier l’admin bar de WordPress 3.1

WordPress est passé hier en version 3.1, une version très attendue car elle apporte quelques nouveautés que les utilisateurs demandaient depuis un certain temps. Entre autres, l’apparition de l' »admin bar » : un « gadget » que nous allons aujourd’hui modifier.

Tout d’abord, si vous n’avez pas encore fait la mise à jour vers cette version 3.1, voici le lien vers la liste des changements.
 

Aujourd’hui nous allons donc parler de cette « fameuse Admin Bar », bien que ce ne soit pas la « killer feature » que nous attendions le plus (en fait, la nouveauté la plus attendue était de pouvoir faire des liens entre les articles sans se casser la tête… Nouveauté que je n’utiliserais donc pas à priori puisqu’elle n’apparait que dans l’éditeur tinymachin et que je n’utilise que l’éditeur html… Bref, je m’égare).

Hein?

Mais en fait, qu’est-ce que cette « Admin Bar »?
C’est une barre de menu qui va s’afficher lorsque nous sommes connecté. Son principal avantage (je trouve) c’est qu’elle s’affiche en front-end. C’est à dire que vous avez une barre de menu qui s’affiche en haut de votre fenêtre lorsque vous naviguez sur le site en étant connecté (oui, en front-end). Et si vraiment vous l’aimez, vous pouvez la garder dans l’administration. Pour cela, il suffit d’aller sur votre profil :

wp Admin Bar Config

Une barre que je vais garder un certaine temps, avant que je me dise que, vraiment, ça me sert à rien.
Je dois dire que malgré tout cela, je n’ai pas encore envie de supprimer cette barre. Or, la quasi-totalité de mes recherches sur le net m’ont mené vers des « tutoriels » pour supprimer ce menu (sauf 1). DONC! Oui, donc vous en avez marre de lire du blabla donc je passe à l’essentiel, la modifier plutôt que la supprimer.

Comment faire

Après quelques recherches dans les fichiers de WP 3.1 et dans le codex, on s’aperçoit que les 2 seuls fichiers qui vont nous aider dans notre tâche sont wp-includes/admin-bar.php et wp-includes/class-wp-admin-bar.php. Maintenant que nous avons nos fonctions de base, nous pouvons les « modifier ».
La fonction principale qui va nous intéresser est add_menus(), elle nous enseigne comment hooker le menu et on la trouve dans wp-includes/class-wp-admin-bar.php sous cette forme :

181182183184185186187188189190191192193194
function add_menus() {
	add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 10 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 30 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_shortlink_menu', 80 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 70 );

	if ( !is_network_admin() && !is_user_admin() ) {
		add_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 40 );
		add_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 50 );
		add_action( 'admin_bar_menu', 'wp_admin_bar_appearance_menu', 60 );
	}
	do_action( 'add_admin_bar_menus' );
}

A noter que la priorité indiquée en paramètre de add_action() (le nombre à la fin) va nous permettre de gérer l’ordre des boutons : plus le nombre sera grand, plus le bouton sera à droite.
Avec ça on retrouve presque tout ce qu’il nous faut. Il suffit ensuite de jeter un œil à ces fonctions pour s’apercevoir qu’elles utilisent add_menu() (sans « s »).
D’après ce que j’ai pu voir, la fonction add_menu() prend un array en argument : array('id', 'title', 'href').

Bien commencer

Commençons par créer la fonction de hook, que nous allons mettre dans le fichier functions.php de notre thème :

123456
function sf_admin_bar() {
	
	// Code
	
}
add_action('add_admin_bar_menus', 'sf_admin_bar');

Ainsi, on pourrait par exemple supprimer le bouton vers les commentaires :

1234
function sf_admin_bar() {
	remove_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 50 );
}
add_action('add_admin_bar_menus', 'sf_admin_bar');

Il m’arrive souvent de créer des sites WordPress avec uniquement des pages, sans posts. Donc autant supprimer le bouton « Nouvel article » et « Nouvelle page », et le remplacer un bouton avec uniquement « Nouvelle page » :

01020304050607080910
function wp_admin_bar_new_page() {
	global $wp_admin_bar;
	$wp_admin_bar->add_menu( array( 'id' => 'new-page', 'title' => __( 'Add New Page' ), 'href' => admin_url( 'post-new.php?post_type=page' ) ) );
}
function sf_admin_bar() {
	remove_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 40 );
	remove_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 50 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_new_page', 40 );
}
add_action('add_admin_bar_menus', 'sf_admin_bar');

On peut aussi rajouter des boutons vers certains plugins, comme par exemple wp Time Machine que j’aime assez :

0102030405060708091011121314151617
function wp_admin_bar_new_page() {
	global $wp_admin_bar;
	$wp_admin_bar->add_menu( array( 'id' => 'new-page', 'title' => __( 'Add New Page' ), 'href' => admin_url( 'post-new.php?post_type=page' ) ) );
}
function wp_admin_bar_time_machine() {
	if ( function_exists( 'wpTimeMachine_init' ) && current_user_can('manage_options') ) {
		global $wp_admin_bar;
		$wp_admin_bar->add_menu( array( 'id' => 'wp-time-machine', 'title' => __( 'Backup' ), 'href' => admin_url( 'admin.php?page=wpTimeMachineCore.php' ) ) );
	}
}
function sf_admin_bar() {
	remove_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 40 );
	remove_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 50 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_new_page', 40 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_time_machine', 65 );
}
add_action('add_admin_bar_menus', 'sf_admin_bar');

On peut également créer des boutons avec un sous-menu, comme le bouton « Apparence ». Pour cela il faut ajouter le paramètre « parent » à add_menu() et lui indiquer l’id du bouton parent. Rajoutons par exemple un sous-menu « Nouveau média » à notre bouton « Nouvelle page » :

010203040506070809101112131415161718
function wp_admin_bar_new_page() {
	global $wp_admin_bar;
	$wp_admin_bar->add_menu( array( 'id' => 'new-page', 'title' => __( 'Add New Page' ), 'href' => admin_url( 'post-new.php?post_type=page' ) ) );
	$wp_admin_bar->add_menu( array( 'parent' => 'new-page', 'id' => 'new-media', 'title' => __('New Media'), 'href' => admin_url('media-new.php') ) );
}
function wp_admin_bar_time_machine() {
	if ( function_exists( 'wpTimeMachine_init' ) && current_user_can('manage_options') ) {
		global $wp_admin_bar;
		$wp_admin_bar->add_menu( array( 'id' => 'wp-time-machine', 'title' => __( 'Backup' ), 'href' => admin_url( 'admin.php?page=wpTimeMachineCore.php' ) ) );
	}
}
function sf_admin_bar() {
	remove_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 40 );
	remove_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 50 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_new_page', 40 );
	add_action( 'admin_bar_menu', 'wp_admin_bar_time_machine', 65 );
}
add_action('add_admin_bar_menus', 'sf_admin_bar');

wp Admin Bar - New Media

[update]

Ajouter un bouton Akismet affichant le nombre de nouveaux spams.

Je viens de trouver le moyen de rajouter un bouton Akismet donc je vous en fait profiter.
Après un petit tour dans les entrailles du plugin, je découvre que la fonction qui permet d’afficher le nombre de nouveaux spams est akismet_spam_count(). Seul problème, cette fonction n’est disponible que dans l’administration. Donc encore une fois je vais réinventer la roue en dupliquant la fonction si elle n’est pas définie.
Mais commençons par le commencement :

010203040506070809101112131415
function wp_admin_bar_akismet() {
	if ( !current_user_can('moderate_comments') )		// Si la personne n'a pas la "capabilities" de gérer les commentaires, on zappe
		return;
	if ( !function_exists('akismet_spam_count') ) {		// Si la fonction d'Akismet n'existe pas, on la défini ici
		// La fonction d'Akismet ici
	}
	if ( $queue_count = akismet_spam_count() ) {		// On enregistre le nombre le nouveaux spams : s'il n'y en a pas on aura 0, donc au sautera au "else"
		// ...
	} else
		return;
}
function sf_admin_bar() {
	// Les autres boutons et menus
	add_action( 'admin_bar_menu', 'wp_admin_bar_akismet', 75 );
}

Maintenant rajoutons la fonction copiée dans Akismet :

0102030405060708091011121314151617181920212223242526272829303132333435
function wp_admin_bar_akismet() {
	if ( !current_user_can('moderate_comments') )		// Si la personne n'a pas la "capabilities" de gérer les commentaires, on zappe
		return;
	if ( !function_exists('akismet_spam_count') ) {		// Si la fonction d'Akismet n'existe pas, on la défini ici
		function akismet_spam_count( $type = false ) {
			global $wpdb;
			if ( !$type ) { // total
				$count = wp_cache_get( 'akismet_spam_count', 'widget' );
				if ( false === $count ) {
					if ( function_exists('wp_count_comments') ) {
						$count = wp_count_comments();
						$count = $count->spam;
					} else {
						$count = (int) $wpdb->get_var("SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = 'spam'");
					}
					wp_cache_set( 'akismet_spam_count', $count, 'widget', 3600 );
				}
				return $count;
			} elseif ( 'comments' == $type || 'comment' == $type ) { // comments
				$type = '';
			} else { // pingback, trackback, ...
				$type  = $wpdb->escape( $type );
			}
			return (int) $wpdb->get_var("SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = 'spam' AND comment_type='$type'");
		}
	}
	if ( $queue_count = akismet_spam_count() ) {		// On enregistre le nombre le nouveaux spams : s'il n'y en a pas on aura 0, donc au sautera au "else"
		// ...
	} else
		return;
}
function sf_admin_bar() {
	// Les autres boutons et menus
	add_action( 'admin_bar_menu', 'wp_admin_bar_akismet', 75 );
}

Puis nous rajoutons notre bouton, de la même manière que pour les précédents, sauf qu’il faut tenir compte du singulier/pluriel dans « Spam »/ »Spams » :

01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546
function wp_admin_bar_akismet() {
	if ( !current_user_can('moderate_comments') )		// Si la personne n'a pas la "capabilities" de gérer les commentaires, on zappe
		return;
	if ( !function_exists('akismet_spam_count') ) {		// Si la fonction d'Akismet n'existe pas, on la défini ici
		function akismet_spam_count( $type = false ) {
			global $wpdb;
			if ( !$type ) { // total
				$count = wp_cache_get( 'akismet_spam_count', 'widget' );
				if ( false === $count ) {
					if ( function_exists('wp_count_comments') ) {
						$count = wp_count_comments();
						$count = $count->spam;
					} else {
						$count = (int) $wpdb->get_var("SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = 'spam'");
					}
					wp_cache_set( 'akismet_spam_count', $count, 'widget', 3600 );
				}
				return $count;
			} elseif ( 'comments' == $type || 'comment' == $type ) { // comments
				$type = '';
			} else { // pingback, trackback, ...
				$type  = $wpdb->escape( $type );
			}
			return (int) $wpdb->get_var("SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = 'spam' AND comment_type='$type'");
		}
	}
	if ( $queue_count = akismet_spam_count() ) {		// Ajout du bouton si on a au moins 1 spam
		$link = 'edit-comments.php?comment_status=spam';
		$queue_text = sprintf(
			_n(
				'<span title="Il y a %1$s spam dans votre file d'attente">Spam %2$s</span>',
				'<span title="Il y a %1$s spams dans votre file d'attente">Spams %2$s</span>',
				$queue_count
			),
			number_format_i18n( $queue_count ),
			'<span id="ab-akismet">'.number_format_i18n( $queue_count ).'</span>'
		);
		global $wp_admin_bar;
		$wp_admin_bar->add_menu( array( 'id' => 'akismet', 'title' => $queue_text, 'href' => admin_url( $link ) ) );
	} else
		return;
}
function sf_admin_bar() {
	// Les autres boutons et menus
	add_action( 'admin_bar_menu', 'wp_admin_bar_akismet', 75 );
}

Dernier détail, WordPress n’a pas prévu que nous pourrions avoir besoin de rajouter un bouton ayant le même style que celui des mises à jour (avec le nombre dans un rond blanc). Il faut donc rajouter un peu de mise en forme dans le fichier css de votre thème :

123
/* ----------------------------------------------------------------------------- Admin Bar ------------------------------ */
#wpadminbar .quicklinks a span#ab-akismet{background:#eee;color:#333;text-shadow:none;display:inline;padding:2px 5px;font-size:10px;font-weight:bold;-moz-border-radius:10px;-khtml-border-radius:10px;-webkit-border-radius:10px;border-radius:10px;}
#wpadminbar .quicklinks a:hover span#ab-akismet{background:#fff;color:#000;}

Résultat :
WordPress Admin Bar Akismet

Touche finale

Il reste encore une chose que l’on peut modifier : la recherche à droite de la barre. En effet, elle a un truc qui me gène, elle n’est pas valide XHTML 1.0 Strict car les 2 inputs sont directement dans la balise form. Il faudrait englober ces 2 inputs dans une div pour avoir une page valide. Là, la méthode est différente car ce sont les fonctions render() et wp_admin_bar_render() qui gèrent l’affichage de ce formulaire. On va donc les copier, les modifier, et créer les hooks :

01020304050607080910111213141516171819202122232425262728293031323334353637
function sf_render() {
	global $wp_admin_bar; ?>
	<div id="wpadminbar">
		<div class="quicklinks">
			<ul>
				<?php foreach ( (array) $wp_admin_bar->menu as $id => $menu_item ) : ?>
					<?php $wp_admin_bar->recursive_render( $id, $menu_item ) ?>
				<?php endforeach; ?>
			</ul>
		</div>
		<div id="adminbarsearch-wrap">
			<form action="<?php echo home_url(); ?>" method="get" id="adminbarsearch">
				<div>
					<input class="adminbar-input" name="s" id="adminbar-search" type="text" value="" maxlength="150" />
					<input type="submit" class="adminbar-button" value="<?php _e('Search'); ?>"/>
				</div>
			</form>
		</div>
	</div>
	<?php
	$wp_admin_bar->menu = null;
}
function wp_admin_bar_sf_render() {
	global $wp_admin_bar;
	if ( ! is_admin_bar_showing() || ! is_object( $wp_admin_bar ) )
		return false;
	$wp_admin_bar->load_user_locale_translations();
	do_action_ref_array( 'admin_bar_menu', array( &$wp_admin_bar ) );
	do_action( 'wp_before_admin_bar_render' );
	sf_render();
	do_action( 'wp_after_admin_bar_render' );
	$wp_admin_bar->unload_user_locale_translations();
}
remove_action( 'wp_footer', 'wp_admin_bar_render', 1000 );
remove_action( 'admin_footer', 'wp_admin_bar_render', 1000 );
add_action( 'wp_footer', 'wp_admin_bar_sf_render', 1000 );
add_action( 'admin_footer', 'wp_admin_bar_sf_render', 1000 );

Nous avons donc crée la fonction sf_render() qui est identique à render(), on y a juste rajouté la div nécessaire. Pour l’appeler, nous avons eu besoin de créer wp_admin_bar_sf_render(). Dans les fonctions originales, on voit apparaitre des $this->, ils font référence à la classe php de l’admin bar. Comme nous ne sommes pas dans cette classe, il est nécessaire de les remplacer par des $wp_admin_bar-> et de déclarer cette variable en global en début de fonction. Il n’y a que $this->render() qui devient tout simplement sf_render() car notre fonction ne fait pas partie de la classe de l’admin bar.
Il ne reste plus qu’à annuler les actions par défaut avec remove_action() et ajouter les nôtres avec add_action().

Et voilà

Il ne vous reste plus qu’à trouver d’autres idées pour personnaliser votre Admin Bar.