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
andpointerWidth
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 actiondismiss-wp-pointer
, and a slug that uniquely identifies the pointer.
This is what we get with the above example:
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