A neat/annoying (delete as appropriate) feature was introduced in WordPress 3.3 which, while it doesn’t have a published API, is worth knowing about (and, I believe, about to get a revamp in WP 3.4): Pointers.

Pointer from Yoast WordPress SEO pluginPointers are glorified pop-up “tooltips” that were introduced to allow new features to be pointed out to users in the WordPress core. The image on the right shows one used by the excellent WordPress SEO Plugin from Yoast.

It turns out that these are pretty easy to make use of in your own code and, while advanced users may find them annoying, they’re good for pointing our new features to users. I would recommend caution though – overuse of pointers would represent bad UI, so use them sparingly for important changes only.

Oh, and they only work for logged in users as the settings stating which pointers have been dismissed are stored on a per-user basis in the WordPress back-end.

My Example

I had a case where I was changing the default setting of a checkbox on a form. This checkbox controlled whether the information being entered by the user was public or private, so changing the default was a pretty big deal and I needed to make users aware.

I am, as usual, indebted to other bloggers for providing most of the info on how to use pointers.  I’d recommend the articles by:

  • Theme.FM (doesn’t tell you how to create the “close” function properly)
  • GeneralThreat (pretty complete, including localisation, but no Pointer positioning)
  • Or just browse the WP_Interal_Pointers class that’s currently defined in wp-admin/includes/template.php

I had a little trouble positioning the Pointer. There is a position option to pass to the Pointer but it’s not clear what the parameters are and how they work. Hopefully this will be documented in WP 3.4, but I managed to get what I needed by playing with the “at”, “my” and “offset” properties.

I also had a little issue because I was building a Pointer to go in the front-end of the site (yes, it was fine that only logged-in users could see this).  In this case I couldn’t get the dismissal to be remembered – the Pointer kept coming back! Stupid me had forgotten that the ajaxurl JavaScript variable is set to /wp-load.php when you’re in the front end, and it turns out, the dismiss-wp-pointer action is only defined in admin-ajax.php. So I had to explicitly reference that as the POST URL for my close action.

So…my code (excluding localisation – my users are English only) is as follows:

In functions.php:

// This function adds scripts to allow pointers on certain pages
add_action( 'wp_enqueue_scripts', 'mytheme_add_pointers' );
function mytheme_add_pointers () {
	if (is_page ( 'page-with-form' )) {
		wp_enqueue_style( 'wp-pointer' );
		wp_enqueue_script( 'wp-pointer' );
	}	
}

In my template file:

<?php
	// Print a pointer bubble to highlight new feature

	// Get the list of dismissed pointers for the user
	$dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
 
	// Check whether our pointer has been dismissed
	if ( ! in_array( 'my_pointer', $dismissed ) ) :
?>
	<script type="text/javascript">
		jQuery(document).ready( function () { 
			/** Check that pointer support exists AND that text is not empty */
			if(typeof(jQuery().pointer) != 'undefined') {
				jQuery('#my-checkbox').pointer({
					content    : '<h3>Default is now private</h3><p>Please note that the default privacy setting is now private.</p>',
					position : {
						at: 'left top',
						my: 'left top',
						offset: '-60 13'
					},
					close  : function() {
						jQuery.post( '<?php bloginfo('wpurl'); ?>/wp-admin/admin-ajax.php', {
							pointer: 'my_pointer',
							action: 'dismiss-wp-pointer'
						});
					}
				}).pointer('open');
			}
		});					
	</script>