🗨 WordPress admin pointers for dummies

Ever wondered how to create WordPress admin pointers? Here’s a few pointers:

What are pointers?

Admin pointers are those cool-looking “hints” that point to an element in the admin screens and show some text. The hints are meant to help new users find UI elements easily. These should be dismissible by the user.

Why this article?

Even though pointers are a thing since WordPress 3.3, there are not many resources out there showcasing pointers for developers.

A few articles showcasing how to use pointers do exist, but they seemed a bit too convoluted for me. The articles I found, tell you how to create entire pointer frameworks, while I wanted a guide to the no-nonsense absolute bare minimum guide to pointers.

Read on, and soon you’ll be creating more pointers than you can point a stick at.

Loading the assets

First, enqueue the relevant assets on the in_admin_header action:

add_action(
    'in_admin_header',
    function() {
        wp_enqueue_script( 'jquery' );
        wp_enqueue_style( 'wp-pointer' );
        wp_enqueue_script( 'wp-pointer' );
    }
);

This will load jQuery (if it’s not already loaded), and the relevant JavaScript and CSS assets. If you’re interested, here’s the code:

https://github.com/WordPress/WordPress/blob/master/wp-includes/js/wp-pointer.js

https://github.com/WordPress/WordPress/blob/master/wp-includes/css/wp-pointer.css

Printing out the custom JavaScript

Once we’ve enqueued the assets, we need to also print out a JavaScript block of code in that same action, in_admin_header. Here’s an example of the JS code that you can hack:

<script>
jQuery(
	function() {
		jQuery('#menu-dashboard').first().pointer( 
			{
				content:
					"<h3>WordPress dashboard<\/h3>" +
					"<h4>Here is the admin dashboard<\/h4>" +
					"<p>But, I'm guessing, you already knew this, didn't you?</p>" +
					"<p>If so, you can <strong>dismiss<\/strong> this pointer, and it won't ever bother you again.</p>",


				position:
					{
						edge:  'top',
						align: 'left'
					},

				pointerClass:
					'wp-pointer arrow-top',

				pointerWidth: 420,
				
				close: function() {
					jQuery.post(
						ajaxurl,
						{
							pointer: 'my-pointer-slug',
							action: 'dismiss-wp-pointer',
						}
					);
				},

			}
		).pointer('open');
	}
);
</script>

OK, there’s a lot going on here, but it’s pretty straightforward:

  • We introduce a script that runs on document ready, after the DOM is fully loaded.
  • We use jQuery to locate the Dashboard menu item by HTML ID.
  • On this HTML element, we run the pointer() jQuery function, passing it an object of arguments.
  • The most important argument in the options object, is the content field. This is the pointer’s HTML content. Notice how we need to escape the forward slashes with backward slashes.
  • We add a few more options to control how the pointer is displayed. These are the position, pointerClass and pointerWidth fields. If you’re interested to learn more about these options, check here.
  • Finally, we define an action for the close event. This is triggered when the user clicks on “ⓧ Dismiss”. We need to tell the backend to remember that this pointer is dismissed, so it won’t be displayed again. We do an AJAX POST request, passing it two parameters: The action dismiss-wp-pointer, and a slug that uniquely identifies the pointer.

This is what we get with the above example:

Our pointer in action!
(Note to self: update some plugins on my dev machine)

Dismissing the pointer

We’ve already written the code that notifies the backend that “Dismiss” was clicked. Now we just need a handler that detects this, and saves a boolean as a user meta. Let’s hook this on admin_init. It doesn’t need to be complicated:

add_action(
	'admin_init',
	function() {

		if ( isset( $_POST['action'] ) && 'dismiss-wp-pointer' == $_POST['action'] ) {

			update_user_meta(
				get_current_user_id(),
				'my-pointer-slug-dismissed',
				$_POST['pointer'],
				true
			);
		}
	}
);

Now that we have a user meta that knows if the pointer was dismissed, we can wrap the JavaScript output in a conditional:

if (
	! get_user_meta(
		get_current_user_id(),
		'my-pointer-slug-dismissed',
		true
	)
):
	
?>
	<script>
	<!-- pointer code goes here -->
	</script>
<?php
endif;

If the user meta does not exist, then the pointer code will be sent to the browser.

Putting it all together

That’s it. The following link points to a gist that showcases the complete code, in plugin form.

https://gist.github.com/alex-georgiou/dafb963a2773b926109cd6ba980b4722

Leave a Reply

Your email address will not be published. Required fields are marked *