Advertisement
Theme Development

Integrating With WordPress’ UI: Admin Pointers

by

This is part 3 of a series of articles looking at how your plugin or theme can best integrate into the WordPress admin user interface. In this part we are going to look at how you can use WordPress' 'admin pointers' in your plugins.

Admin pointers first appeared in 3.3, and were intended to highlight just a few of the new features that come with every major release (The theme customiser in 3.4, for instance).

When used properly these can be very effective at drawing attention to the latest features you've added.

Disclaimer: The admin pointers are still in the early stages of their life - and there's the possibility that they could change. If WordPress core ever develop a public API - you should adopt that.


Use Sparingly...

A decent user interface is not gimmicky tooltips. In fact, an ideal user interface wouldn't need any. They are very useful at pointing out the occasional new feature, particularly ones that your end user may have missed. In this they can improve the 'user experience', but if you are using them for any other purpose, or simply using too many, then you're doing it wrong. Rather than improving the plugin for the end user, you'll just end up frustrating them.

So how many is too many? Remember that there will be other plugins installed, and each may be using (or abusing) these pointers as well. WordPress too (obviously) uses them. It would be interesting to gauge people's opinion on this but I myself wouldn't add any more than two in any major update (none on minor ones), and certainly no more than one on any given page.

Importantly, without a core API, there isn't a way of managing multiple pointers: if twenty pointers are added to one page then twenty will be displayed. Since you don't know what other plugins are doing - please use them sparingly.


Creating a Helper Function

When using admin pointers in a plugin or theme, it'll be useful to be able to easily and quickly add extra pointers as your plugin evolves. To this end, we're going to create a helper function that will deal with the internal handling of the pointers. It'll make use of WordPress' much loved hook API, and trigger a filter of the form:

wptuts_admin_pointers_{screen-id}

Where {screen-id} is the ID of the page being viewed. To add a pointer to the post edit page, for example, we would hook onto the filter:

wptuts_admin_pointers_post

In this way, we can add extra pointers, with minimal code. The role of this helper function will be to create an array of pointers which will be printed to the admin page as an array of JavaScript objects - each object corresponding to one pointer. Each pointer object contains the following parameters:

  • pointer_id - a unique identifier for the pointer. A good idea is to include the version for which it is relevant. This must only contain lowercase alphanumerics, underscores and dashes.
  • target - a selector for the target of the pointer, i.e. what it's pointing to (e.g. #some_id, or .some-class)
  • options - This is an array of options. We can use this to alter completely how the pointer looks and behaves, but for our purposes we only need to consider the following: content (the text that appears in the pointer) and position. The position property is determined by:

    • edge - which edge (left, right, top, bottom) should be adjacent to the target.
    • align - how the pointer should be aligned on this edge, relative to the target (top, bottom, left, right, middle).

A typical pointer object might be of the form:

{
	pointer_id: 'xyz_v110',
	target: '#some_id',
	options: {
		content: '<h3> New feature: xyz </h3> <p> Lorem ipsum dolor sit amet...</p>',
		position: {
			edge: 'left',
			align: 'top'
		}
	}
}

Once the pointer objects are printed to the admin page we can make use of the WordPress pointer widget defined here.


Defining the Helper Function

As discussed in the previous section, the overall aim of our function is to print some JavaScript objects to the page and load some custom script. So our helper function will be hooked onto the wp_enqueue_scripts action (though, we could call it later).

	add_action( 'admin_enqueue_scripts', 'wptuts_pointer_load');
	function wptuts_pointer_load( $hook_suffix ) {
		// Helper function goes here
	}

Remember, if you're using this code in a plugin or theme, you should rename the function, ensuring it's unique and preferably pre-fixing it with your plugin or theme name. The first part of this function filters an empty array, using the hook wptuts_admin_pointers-{screen_id}. This allows us to add pointers into that array. If nothing is added, we stop.

	// Don't run on WP < 3.3
	if ( get_bloginfo( 'version' ) < '3.3' )
		return;

	// Get the screen ID
	$screen = get_current_screen();
	$screen_id = $screen->id;

	// Get pointers for this screen
	$pointers = apply_filters( 'wptuts_admin_pointers-' . $screen_id, array() );

	// No pointers? Then we stop.
	if ( ! $pointers || ! is_array( $pointers ) )
		return;

Now these pointers may include ones that the user has seen before, and 'dismissed'. We don't want these appearing again for this user, so next we obtain an array of pointers that they have already seen and closed, and remove these from our array. We also perform some sanity checks on our pointers:

	// Get dismissed pointers
	$dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
	$valid_pointers = array();

	// Check pointers and remove dismissed ones.
	foreach ( $pointers as $pointer_id => $pointer ) {

		// Sanity check
		if ( in_array( $pointer_id, $dismissed ) || empty( $pointer )  || empty( $pointer_id ) || empty( $pointer['target'] ) || empty( $pointer['options'] ) )
			continue;

		$pointer['pointer_id'] = $pointer_id;

		// Add the pointer to $valid_pointers array
		$valid_pointers['pointers'][] = $pointer;
	}

 	// No valid pointers? Stop here.
	if ( empty( $valid_pointers ) )
		return;

Finally we enqueue the necessary scripts and styles, and print the valid pointers to the page, using wp_localize_script.

	// Add pointers style to queue.
	wp_enqueue_style( 'wp-pointer' );

	// Add pointers script and our own custom script to queue.
	wp_enqueue_script( 'wptuts-pointer', plugins_url( 'js/wptuts-pointer.js', __FILE__ ), array( 'wp-pointer' ) );

	// Add pointer options to script.
	wp_localize_script( 'wptuts-pointer', 'wptutsPointer', $valid_pointer );

The Function in Full

add_action( 'admin_enqueue_scripts', 'wptuts_pointer_load', 1000 );

function wptuts_pointer_load( $hook_suffix ) {

	// Don't run on WP < 3.3
	if ( get_bloginfo( 'version' ) < '3.3' )
		return;

	$screen = get_current_screen();
	$screen_id = $screen->id;

	// Get pointers for this screen
	$pointers = apply_filters( 'wptuts_admin_pointers-' . $screen_id, array() );

	if ( ! $pointers || ! is_array( $pointers ) )
		return;

	// Get dismissed pointers
	$dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
	$valid_pointers =array();

	// Check pointers and remove dismissed ones.
	foreach ( $pointers as $pointer_id => $pointer ) {

		// Sanity check
		if ( in_array( $pointer_id, $dismissed ) || empty( $pointer )  || empty( $pointer_id ) || empty( $pointer['target'] ) || empty( $pointer['options'] ) )
			continue;

		$pointer['pointer_id'] = $pointer_id;

		// Add the pointer to $valid_pointers array
		$valid_pointers['pointers'][] =  $pointer;
	}

	// No valid pointers? Stop here.
	if ( empty( $valid_pointers ) )
		return;

	// Add pointers style to queue.
	wp_enqueue_style( 'wp-pointer' );

	// Add pointers script to queue. Add custom script.
	wp_enqueue_script( 'wptuts-pointer', plugins_url( 'js/wptuts-pointer.js', __FILE__ ), array( 'wp-pointer' ) );

	// Add pointer options to script.
	wp_localize_script( 'wptuts-pointer', 'wptutsPointer', $valid_pointers );
}

The JavaScript

The script is very simple, since the pointer widget does most of the work. At this pointer all we really need to define is what happens when the pointer is dismissed. In particular, we send an ajax request with the action 'dismiss-wp-pointer' and the pointer to set to the unique identifier we specify when adding the pointer.

jQuery(document).ready( function($) {
	wptuts_open_pointer(0);
	function wptuts_open_pointer(i) {
		pointer = wptutsPointer.pointers[i];
		options = $.extend( pointer.options, {
			close: function() {
				$.post( ajaxurl, {
					pointer: pointer.pointer_id,
					action: 'dismiss-wp-pointer'
				});
			}
		});

		$(pointer.target).pointer( options ).pointer('open');
	}
});

That is all the code we need to add since WordPress handles the ajax request.


Adding Pointers

As promised, adding pointers is very easy. To add a pointer to the 'post' screen, for example:

add_filter( 'wptuts_admin_pointers-post', 'wptuts_register_pointer_testing' );
function wptuts_register_pointer_testing( $p ) {
	$p['xyz140'] = array(
		'target' => '#change-permalinks',
		'options' => array(
			'content' => sprintf( '<h3> %s </h3> <p> %s </p>',
				__( 'Title' ,'plugindomain'),
				__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.','plugindomain')
			),
			'position' => array( 'edge' => 'top', 'align' => 'middle' )
		)
	);
	return $p;
}

Note: When storing the dismissed pointer, WordPress passes the pointer ID through sanitize_key - so be sure to use only lowercase alpha numerics, dashes and underscores.

Related Posts
  • Code
    Theme Development
    How to Pass PHP Data and Strings to JavaScript in WordPressPhp js 400
    It's good practice to put all your data in static strings in your PHP files. If you need to use some data in JavaScript later on, it's also good practice to put your data as data-* attributes in your HTML. But in some certain scenarios, you have no choice but to pass strings directly to your JavaScript code. If you are including a JavaScript library, and you've found yourself initializing a JavaScript object inside your header.php then assigning data to its properties, then this article is for you. This article will teach you on how to properly pass PHP data and static strings to your JavaScript library.Read More…
  • Code
    Creative Coding
    Using the Included Password Strength Meter Script in WordPressPassword meter 400
    WordPress uses a pretty nifty password strength script that is used to display whether the passwords you entered in the WordPress admin are: not the same, very weak, weak, medium or strong. Currently this script is only used when creating creating new users and when changing your password in your admin. In this article, I will be teaching you on how to use the WordPress' password strength meter in your own forms.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: The Footer FileCreating wordpress theme from html 400
    In this series, you've been learning how to create a WordPress theme form static HTML. Up to this point, you have: prepared your markup for WordPress converted your HTML to PHP and split your file into template files edited the stylesheet and uploaded your theme to WordPress added a loop to your index file added meta tags, the wp_head hook and the site title and description to your header file added a navigation menu added widget areas to the header and sidebar. Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Creating Template FilesCreating wordpress theme from html 400
    In the first part of this series, I showed you how to prepare your HTML and CSS files for WordPress, ensuring the structure would work, the code was valid and that the correct classes were being used. In this tutorial you'll learn how to take your index.html file and split it up into a set of template files for use by WordPress.Read More…
  • Code
    Plugins
    Using HighCharts in WP-AdminHighcharts 400
    Charts are a great way to present data. They make data more digestible by making it visually appealing. In WordPress, there is no built-in method for getting posts and pages data in a graphical form. Although, there are certain plugins available which integrate Google Analytics with WordPress, but they are overkill if you want to get only a portion of that data. Also, nothing should keep you from learning new techniques and to dive straight into the subject is the best way to learn.Read More…
  • Code
    Cheat Sheets
    The Complete Guide to Proper JavaScript Usage With WordPressJavascript 400
    I remember thinking "What the heck do we need JavaScript for, when we have Flash?" when I was fourteen. Although I still remember how I enjoyed coding stuff with ActionScript 2.0 back then, I saw how much one can achieve with JavaScript and fell in love with it. I'm not an expert on JavaScript (yet) but I can say I'm over and done with Flash for a long time. When it comes to WordPress, the biggest blogging platform and content management system worldwide, JavaScript is - of course - very useful for many things: content sliders, lightbox galleries, slick shopping carts, UI elements like tabs or accordions... you name it. But how exactly should we use JavaScript with WordPress? Returning or echoing a bunch of HTML script elements is one way to do it - and it's wrong. In this tutorial, we're going to see how to enqueue JavaScript files inside our pages and how to pass translatable data to the JavaScript code.Read More…