How to create WordPress dashboard widgets

A step-by-step guide on how you can start to enhance your WordPress dashboard with bespoke widgets.

By Luke Whitehouse on

PHPWordPress

Tutorial

By default WordPress comes with some great tools to get you started, such as a ‘Quick draft’ form and a ‘Recent Comments’ feed. Despite this, the Dashboard is catered heavily towards blogging, which is rightly so seeing as WordPress started off as a blogging platform. However, these days WordPress is used for much more than just blogging, so how can we modify the Dashboard to meet our client's needs?

This post will take a look at how we can utilise the Dashboard Widgets API (added to WordPress in 2.7) to provide our clients with a little more control when working with the Admin interface. To do so, we'll create a 'User Status Widget' that will provide an overview of who’s currently logged into the admin area; a very useful stat to have when you have multiple people working on a website at once.

Ready, set, go!

Setup

First things first, as we're looking to modify WordPress, everything will be added to the functions.php file of your theme. However, we're not going to add all our logic into one file as things will start to become a nightmare to maintain in the long run, so lets separate this out into multiple files.

If you don't have a functions.php file in the root of your theme then create one and add the following. If you do have a functions.php then you can add the following to the bottom of that file.

require_once('inc/asrt-user-widget-setup.php');
require_once('inc/asrt-user-widget-populate.php');
require_once('inc/asrt-user-widget-appearance.php');

If you're unfamiliar with the concept of require in PHP its essentially saying, "Go grab this file and run whatever's in it before you go any further". You can get a full run down on the ins and outs of it over on Stack Overflow, where it goes into the differences between require, require_once, include and include_once.

Now lets create each of those files within a folder called inc. Goes without saying but we're working with PHP so each of the files will need an opening <?php tag. In addition, throughout this tutorial you'll notice I prefix my files and functions with asrt to ensure I don't get any naming conflicts with everything being in the global namespace.

Registration

To register a widget on the WordPress dashboard we can use the aptly named wp_add_dashboard_widget() function, which takes the following parameters:

  • $widget_id - Despite the confusing label, this is an identifying string (series of characters within quotes) that WordPress will use for class names, IDs, etc.
  • $widget_name - The title of the Widget, which will predominantly be displayed in it's header.
  • $callback - The name of the function that will display the widget’s contents. More on this later.
  • $control_callback - Similar to the first $callback, however, this is the name of a separate function which will setup any form elements and functionality you’re looking to create in your Widget (if any). In our case we will not require this argument for today’s tutorial, but this would have been instrumental in creating the default 'Quick Draft' widget.
  • $callback_args - Provides you to pass through any values to your callback function. As we're not calling the function in the traditional sense, WordPress does that for us.

Open up your newly created inc/asrt-user-widget-setup.php and create a function that calls wp_add_dashboard_widget().

/**
* Create a new widget on the WP dashboard
*/
function asrt_add_user_status_dashboard_widget() {
  wp_add_dashboard_widget('asrt-user-status-dashboard-widget', 'User status', 'asrt_user_status_dashboard_widget');
}

To activate this function we need to use a WordPress hook. Think of these as checkpoints that allow you to run a function at the exact point this checkpoint is situated. For this one, we will need to use the wp_dashboard_setup hook, as this is a checkpoint for when the dashboard's widgets are being created.

Underneath your function, we're going to call another called add_action(), where it's first parameter will be the name of the hook and it's second being the name of the function that you want to run at this checkpoint.

add_action('wp_dashboard_setup', 'asrt_add_user_status_dashboard_widget' );

Population

OK now that we have the Widget registered we can start populating it. As we've already set our function to be called asrt_user_status_dashboard_widget(), lets go with that!

Within inc/asrt-user-widget-populate.php create a new function called asrt_user_status_dashboard_widget and echo out some text so that we can test the widget has been registered correctly.

function asrt_user_status_dashboard_widget() {
  echo 'Widget has registered successfully';
}

If you navigate to your dashboard you'll see your newly created Widget with the echo'ed text from above.

Fig 1: Example of a successfully registered Dashboard Widget

Moving back to our code, remove the echo statement. We're going to populate this widget with a table of our WordPress users. To do so, we can call a new instance of the WP_User_Query class within our function.

function asrt_user_status_dashboard_widget() {
  // Get all users based on roles accepted
  $users = new WP_User_Query([
    'role__in' => ['administrator', 'editor', 'author'],
    'order'    => 'ASC',
    'orderby'  => 'name'
  ]);
}

Before we create our table of users we'll need to check whether or not we have users in the first place. Underneath our WP_User_Query class, add a new if statement to check for this.

function asrt_user_status_dashboard_widget() {
  // Get all users based on roles accepted
  $users = new WP_User_Query([
    'role__in' => ['administrator', 'editor', 'author'],
    'order'    => 'ASC',
    'orderby'  => 'name'
  ]);
  
  // If we have found any users
  if($users) {
    // Table to be created here
  } else {
    // If no users, send error message
    echo 'It seems no users can be found, please contact your site administrator.';
  }
}

Great, we've now got all the users that have been assigned the roles of administrator, editor, or author (default WordPress roles) and we have checked whether any actually exist in the first place. Now, lets use this to create our table.

Within our if statement, remove the comment which says Table to be created here, we're going to loop through the users we have and output their data. To do this we'll use a method of WP_User_Query called get_results() which results an array of users to us.

// Loop through the users
foreach($users->get_results() as $user) {
  echo $user->display_name;
  echo $user->user_email;
}

As this is going to be tabular data, lets get semantic.

echo '<table class="user-status-table">';
echo '<thead>';
  echo '<th>Name</th>';
  echo '<th>Email</th>';
echo '</thead>';
echo '<tbody>';

  // Loop through the users
  foreach($users->get_results() as $user) {
    echo '<tr>';
    echo '<td>' . $user->display_name . '</td>';
    echo '<td>' . $user->user_email . '</td>';
      echo '</tr>';
  }

echo '</tbody>';
echo '</table>';

Its not exactly the sexiest thing in the world, but it'll do! Bare in mind the indentation of code does nothing here, it makes it a little more legible. Complete personal preference though!

Creating 'last online' functionality

Admittedly, I've got a slight confession. By default WordPress doesn't provide its own 'last online' entry to the Database, so we'll have to create our own.

Within inc/asrt-user-widget-setup.php lets add a function to the init hook which will be used to setup the functionality we're looking for.

add_action('init', 'asrt_set_user_last_online');

Underneath it we'd better create that function too. To do so we'll get the current date and time in the U format, which is described as: 'Seconds since the Unix Epoch'. More on that later. Next, we'll get the current user and add/update (depending on if its already set for that user) a new record to the wp_usermeta table for our asrt_last_online stat.

function asrt_set_user_last_online() {
  $date = date('U');
  $user = wp_get_current_user();

  update_user_meta($user->ID, 'asrt_last_online', $date);
}

Now every time a user logs into the website we'll update that record with the current date and time, allowing us to perform tests for whether the user is currently logged in or not.

If you take a look at your database you'll see that record on the wp_usermeta table, where:

  • the first column (umeta_id) is the unique ID of that field (irrelevant for this tutorial);
  • the second (user_id) is the ID of the user this record is assigned to;
  • the third (meta_key) is the name of the key we've created, in our case that would be asrt_last_online;
  • and finally the fourth (meta_value) is the value of that record, which we assigned to be date('U') earlier.

OK, now that we've got the record in place, lets add that to our Widget. Back within inc/asrt-user-widget-populate.php, add a new cell to our <thead> called 'Status' like so

echo '<thead>';
  echo '<th>Name</th>';
  echo '<th>Email</th>';
  echo '<th>Status</th>';
echo '</thead>';

Then within our foreach loop get the value of our current user's asrt_last_online from the database, and check whether its older than 5 minutes.

$last_login = get_user_meta($user->ID, 'asrt_last_online', true);
$elapsed_time = time() - $last_login;
$online_status = $elapsed_time <= 300 ? 'Online' : 'Offline';

// Echo <td> cells here

Now we can add this in our foreach loop and assign the 'Online Status' to a new <td>, resulting in the final code.

echo '<table class="user-status-table">';
echo '<thead>';
  echo '<th>Name</th>';
  echo '<th>Email</th>';
  echo '<th>Status</th>';
echo '</thead>';
echo '<tbody>';

  // Loop through the users
  foreach($users->get_results() as $user) {
    $last_login = get_user_meta($user->ID, 'asrt_last_online', true);
    $elapsed_time = time() - $last_login;
    $online_status = $elapsed_time <= 300 ? 'Online' : 'Offline';

    echo '<tr>';
      echo '<td>' . $user->display_name . '</td>';
      echo '<td>' . $user->user_email . '</td>';
      echo '<td class="'. $online_status .'">' . $online_status . '</td>';
    echo '</tr>';
  }

echo '</tbody>';
echo '</table>';

Open it up in a browser and test it out.

Fig 2: The 'User Status' Dashboard Widget without styling

Stylisation

So functionality-wise, we're set. We now have a quick overview of all our users and whether or not they're currently logged into the website (albeit rudimentary). However, it looks like a dog's dinner... lets change that.

Within inc/asrt-user-widget-appearance.php create a new function to be executed on the admin_enqueue_scripts hook. It pretty much does what it says on the tin, allows you to run something when all other admin scripts/stylesheets are being loaded.

add_action('admin_enqueue_scripts', 'asrt_enqueue_user_status_widget_styles');

function asrt_enqueue_user_status_widget_styles() {
}

Within this new function, we can use the wp_enqueue_style function to register a new stylesheet. This function takes 5 parameters:

  • $handle - An identifying name of the stylesheet we're looking to create. Generally speaking I'll mimic the name of the file itself where appropriate.
  • $src - The absolute path to the stylesheet or a URL if external (read: not hosted in the same place as your WordPress project).
  • $deps - An optional array of dependencies that should be executed before this stylesheet. The names will correlate to the $handle argument of already called stylesheets.
  • $ver - The current version of the stylesheet if appropriate. This will be appended to the URL as a query string for cache busting purposes.
  • $media - Optionally set the different media this stylesheet should be used for. This will create inline media queries for the <link> element it creates. For example, you might put screen and (min-width: 768px).

This time though, we'll only need to define the $handle and $src parameters.

function asrt_enqueue_user_status_widget_styles() {
  wp_enqueue_style( 'asrt-user-status-widget', get_template_directory_uri() . '/inc/asrt-user-status-widget.css');
}

Now go ahead and created a CSS new file at inc/asrt-user-status-widget.css.

Upon doing so, we'll provide our User Status table with some eye candy.

.user-status-table {
  width: 100%;
  border-collapse: collapse;
}

.user-status-table thead tr {
  background: #eee;
}

.user-status-table tr:nth-child(even) {
  background: #f9f9f9;
}

.user-status-table th,
.user-status-table td {
  padding: 5px;
  border: 1px solid #eee;
}

.user-status-table th {
  text-align: left;
}

.user-status-table .Online {
  color: #fff;
  background: #4CAF50;
}

.user-status-table .Offline {
  background: #CCC;
}

Navigating back to the WordPress dashboard you'll see our widget is styled in a much more presentable (and more importantly readable) manner.

Fig 3: The 'User Status' Dashboard Widget with styling

Looking good... User Status Widget!

View the code for this tutorial on Github

Taking things a step further

There are still many things we can do to improve this widget, however, I hope this gives you a quick introduction to the WordPress dashboard API and how we can use it to provide a little more information for our clients up front.

If you'd like to take this to the next level then have a think about how you could:

  • Compile your CSS from a [series of] Sass file(s) to provide further styling control to our widgets.
  • Use Cookies to provide a more robust 'Last online' functionality.
  • Enqueue JavaScript using the wp_enqeue_script function.
  • Move all of this functionality into a WordPress plugin.

Until next time!

Follow us on Twitter, Facebook or Github.
© Copyright 2021 Assortment.
Created and maintained by Luke Whitehouse.