1. Code
  2. WordPress

The Fundamentals of Building a WordPress Server Dashboard

Scroll to top
18 min read
Final product imageFinal product imageFinal product image
What You'll Be Creating

People often complain that WordPress is slow. Whether or not this is true depends on many factors, but if we can see server resources inside the WordPress dashboard, then it may give some insight about how well our WordPress installation is operating. 

In this tutorial, we will be crafting a plugin to show server status including disk space, memory consumptions, CPU usage, and process usage. 

We will also learn about WordPress cache to avoid querying these metric over and over and we will also cover WordPress cron jobs to generate this data automatically.

The administrator dashboard, by default, presents us with a couple of blocks called widgets. These include: 

The widgets can be re-ordered by preference, and can be shown or hidden - generally speaking, the dashboard is customizable.

Since widgets are very flexible and available right on the first screen of the administrator screen, we can use them to show server resource: disk status, RAM usage, CPU usage, and operating system information. We will call these resources "metrics" for short.

Throughout this serious we will learn the Dashboard Widgets API and Roles and Capabilities to make these widgets available to some users because the data could be sensitive. 

To do that, we will also learn some basic Linux commands to pull server information and seed to our widget dashboard. We will use Transients API to cache these data. Cronjobs will be leveraged to automatically pull these data instead of getting them on demand on every request.

The work of our plugin is inspired by Linux Dash.

Our plugin supports nine kinds of metrics. As a result, we will have nine dashboard widgets.

  1. Server information: the operating system, the Linux kernel, the up time, etc.
  2. CPU load: average load of CPU in 1, 5 and 15 minutes
  3. RAM usage of physical RAM and swap file
  4. Disk usage
  5. Installed software
  6. Processes
  7. Ethernet
  8. Network performance
  9. IO stat

Requirements

  1. A Linux environment. Mac OS X is still an option but some of the commands to check the above metrics aren't available, so if you receive a command not found error, then you know there is no Mac support for that command.
  2. Basic understanding of the shell
  3. Basic WordPress plugin understanding.

The Plugin Skeleton Structure

Let's create a simple plugin and call it Server Dashboard. We will start with some basic things. A traditional Hello World will help you have a taste of adding a widget to dashboard. 

It's easy, actually. 

Creating a folder call Server Dashboard inside wp-content/plugins, and a file serverdashboard.php. The folder layout looks like this. Just focus on the main file and ignore the bin, tests, widgets and so on.

Use this code for serverdashboard.php

1
<?php
2
/*

3
Plugin Name: Server Dashboard

4
Version: 0.1-alpha

5
Description: Server Status Dashboard

6
Author: Vinh

7
Author URI: http://axcoto.com

8
Plugin URI: http://axcoto.com

9
Text Domain: Server Dashboard

10
Domain Path: /languages

11
 */
12
namespace AX\StatBoard;
13
require_once plugin_dir_path( __FILE__ ) . '/widget.php' ;
14
15
class Dashboard {
16
  protected static $_instance=NULL;
17
18
  function __construct() {
19
  }
20
21
  /**

22
   * Create an unique instance throught the app

23
   */
24
  public static function instance() {
25
    return self::$_instance = self::$_instance ?: new self();
26
  }
27
28
  /**

29
   * Start to setup hook

30
   */
31
  public function run() {
32
    add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widgets' ) );
33
  }
34
35
  function remove_dashboard_widgets() {
36
37
  }
38
39
  function add_dashboard_widgets() {
40
    syslog(LOG_DEBUG, "Run"); 
41
42
    wp_add_dashboard_widget(
43
        'hello_world_dashboard_widget', // A Slug to identify this widget

44
                 'Hello World', //Widget title

45
                 function () {
46
                   echo 'Hey, I\'m the body of widget. Thanks for bring me to the life.';
47
                 } //function to render content of widget, I'm using a closure here

48
      );    
49
50
    }
51
 
52
}
53
54
Dashboard::instance()->run();
55
?><br><br>
I used namespace AX\StatBoard to avoid name collision with different plugins class, function name of themes, and other plugins. 

I also used the Singleton Pattern for get an unique instance of plugin class. I created a method run to register hook or filter with WordPress.

To add a widget, we have to hook into action wp_dashboard_setup. This hooks grant us access to Dashboard's related customization option. It enables us to add or remove the dashboard widget from WordPress. 

Inside the hook function, we use wp_add_dashboard_widget to register a widget. It requires arguments in this order:

  1. Widget ID is used to identify slug for your widget. This slug is used when rendering CSS id,class and as keys in widget array.
  2. Widget Title displays on title of widget box
  3. Callback to render the content of widget. It should output content directly, doesn't need to return.
Most of time, we will encounter callbacks as a single function, an anonymous function, an array of object and method, or array of class and static method.
Refresh your dashboard. Our plugin shows its widget. Notice the id of widget div element.

Our plugin is widget is showing up with its ID and content

Let's advance this. We will show a pie chart with some dummy data. To keep thing simple, I'll be using the Google Chart API. We will extensively use it later for server metrics because it's better to visualize this kind of data. 

If you don't like Google Chart, you can get rid of it and put your favorite chart library. Remember that this is a tutorial, so don't limit yourself - use whatever it is you're comfortable with using!

We need to load the Google Chart script. Change your run() method to register one more hook.

1
  public function run() {
2
    add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widgets' ) );
3
    add_action( 'admin_enqueue_scripts', array($this, 'add_asset'));
4
  }

admin_enqueue_scripts is the action that you need to hook into for adding your own script in administrator dashboard. We will add one more method call add_asset in our class to handle script loading. The implement of add_asset.

1
  /**

2
   * Add javascript

3
   */ 
4
  function add_asset() {
5
    wp_enqueue_script( 'google-chart', 'https://www.google.com/jsapi' );
6
  }
7
We have the chart library. Now we have to render it inside our dashboard. You can play around with Google Chart. We will just re-use their example now.

1
function add_dashboard_widgets() {
2
    syslog(LOG_DEBUG, "Run"); 
3
4
    wp_add_dashboard_widget(
5
        'hello_world_dashboard_widget', // A Slug to identify this widget

6
                 'Hello World', //Widget title

7
                 function () {
8
                   echo <<<'EOD'
9
Hey, I'm the body of widget. Thanks for bring me to the life.

10
      <div id="hello_piechart">

11
      </div>

12
      <script type="text/javascript">

13
      google.load("visualization", "1", {packages:["corechart"]});

14
      google.setOnLoadCallback(drawChart);

15
      function drawChart() {

16
        var data = google.visualization.arrayToDataTable([

17
          ['Task', 'Hours per Day'],

18
          ['Work',     11],

19
          ['Eat',      2],

20
          ['Commute',  2],

21
          ['Watch TV', 2],

22
          ['Sleep',    7]

23
        ]);

24


25
        var options = {

26
          title: 'Sample Pie Chart',

27
          is3D: true,

28
        };

29


30
        var chart = new google.visualization.PieChart(document.getElementById('hello_piechart'));

31
        chart.draw(data, options);

32
      }

33
    </script>

34
EOD;

35
                  } //function to render content of widget, I'm using a closure here
36
      );    
37
<br><br>
We simply add one more div element with id hello_piechart and render chart into that element. Let's see what we got now:
Notice the ID of widget element.

Now that we know how to add our own widget block to the dashboard, and now that we know how to get Google Chart to render information, we can combine the two in order to show more information. 

In next section, we will learn how to grab server metrics, and render content for each type of server metric that we've previously discussed.

Pulling Server Metrics

When pulling server metrics, we will use the command of Linux to get this information. In PHP, we can use backtick `` or shell_exec to invoke a shell command, and retrieve the output. 

We can parse the output to get server data. For example, to get disk usage status we can use command df -h. We know the format of output, so we can parse it to get what we want.

1
    $df = `df -h`;
2
    $df = explode("\n", $df);
3
    if (is_array($df) && count($df)>=2) {
4
      array_shift($df); //Get rid the first line

5
      $df = array_map(function ($line) {
6
        if (empty($line)) {
7
          return NULL;
8
        }
9
        $segment=preg_split('/\s+/', $line);
10
        
11
        return array(
12
          'filesystem' => $segment[0],
13
          'size' => $segment[1],
14
          'used' => $segment[2],
15
          'available' => $segment[3],
16
          'use_percent' => $segment[4],
17
        );
18
      }, $df);
19
      var_dump($df);
20
    }

Cleaning Up with AWK

To help cleanup the output right from the shell command, we can combine with awk. That link looks scary with lots of information but we will just being using a very small amount of it in this tutorial.  Explaing awk is out of scope of this tutorial.

If you want to learn more about awk, use this cheatsheet. Basically, we use awk to process every line of output, and on each line, the string will be split by tab or space, and the element can be access as variable with $1 for first element, $2 for second element and so on. The syntax is: [command_we_run] | awk ' { print $1, $3, ...}'

Let's look at following example:

1
☁  Server Dashboard [master] ls -lh
2
total 32
3
-rw-r--r--   1 kureikain  staff   2.6K Apr 11 00:46 Server Dashboard.php
4
drwxr-xr-x   3 kureikain  staff   102B Mar 29 01:27 bin
5
-rw-r--r--   1 kureikain  staff    98B Apr  5 18:53 loader.js
6
-rw-r--r--   1 kureikain  staff   321B Mar 29 01:27 phpunit.xml
7
drwxr-xr-x   4 kureikain  staff   136B Mar 29 01:27 tests
8
drwxr-xr-x  12 kureikain  staff   408B Apr 13 17:37 widget
9
-rw-r--r--   1 kureikain  staff   1.1K Apr  6 01:04 widget.php
10
☁  Server Dashboard [master] ls -lh | awk ' {print $3, $4, $5, $9} '
11
12
kureikain staff 2.6K Server
13
kureikain staff 102B bin
14
kureikain staff 98B  loader.js
15
kureikain staff 321B phpunit.xml
16
kureikain staff 136B tests
17
kureikain staff 408B widget
18
kureikain staff 1.1K widget.php<br><br>
As you can see the each line of ls -la contains nine fields:

1
drwxr-xr-x   4 kureikain  staff   136B Mar 29 01:27 tests
Separating by spaces, these 9 fields are:

  1. drwxr-xr-x  
  2. 4
  3. kureikain 
  4. staff  
  5. 136B
  6. Mar
  7. 29
  8. 01:27
  9. tests
I can use awk to just grab the name, group, size and file/folder name in corresponding field 3, 4, 5, 9 awk ' {print $3, $4, $5, $9} ' and I'll see:

1
kureikain staff 136B tests<br>

Therefore, utilizing awk we can clean up the output a little bit more before feeding into our PHP processing function.

Cleaning Up with GREP

Some commands output extra data that we don't need; therefore, it requires a little bit of extra effort with PHP to clean it up.

For example:

1
[vagrant@vagrant-centos64 ~]$ free -m
2
             total       used       free     shared    buffers     cached
3
Mem:           589        537         51          0          8        271
4
-/+ buffers/cache:        258        330
5
Swap:          255          0        255
free -m shows us the RAM usage with memory and swap file; however it includes two other lines with total/used/free and -/+ buffers/cache that we may not need. 

We only want to pull information of Mem and Swap - that is, line 3 and line 5. One of the ways to achieve this is using grep with -E switch. That switch allows use to use regular express for searching. Because we want to find the line with words Mem and Swap, let combine with grep -E "Mem|Swap"

Here is the result.

1
[vagrant@vagrant-centos64 ~]$ free -m | grep -E "Mem|Swap"
2
Mem:           589        536         52          0          8        271
3
Swap:          255          0        255
So it's much cleaner. Combine both of grep and awk we can clean up data and get only what we need.

1
[vagrant@vagrant-centos64 ~]$ free -m | grep -E "Mem|Swap" | awk '{print $1, $2, $3, $4}'
2
Mem: 589 537 52
3
Swap: 255 0 255

Linux Commands to Get Server Information

We've gotta learn some commands to pull server metrics, so let's open our server shell, and try to type below command to have a quick taste.

Check Network Traffic

1
$netstat -in
2
3
Kernel Interface table
4
Iface       MTU Met    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
5
eth0       1500   0 5538339494      0      0      0 6216082004      0      0      0 BMRU
6
eth0:1     1500   0      - no statistics available -                            BMRU
7
eth1       1500   0 96707328840      0      0      0 102776317608      0      0      0 BMRU
8
eth2       1500   0       33      0      0      0        7      0      0      0 BMRU
9
lo        16436   0 29461422      0      0      0 29461422      0      0      0 LRU

Check Disk Usage

1
df -h
2
Filesystem            Size  Used Avail Use% Mounted on
3
/dev/sda7             2.0G  660M  1.3G  35% /
4
/dev/sda8             1.0T  632G  340G  66% /home
5
/dev/sda6             2.0G   68M  1.9G   4% /tmp
6
/dev/sda5              20G  1.5G   18G   8% /var
7
/dev/sda2              20G  2.1G   17G  12% /usr
8
/dev/sda1             194M   25M  160M  14% /boot
9
/dev/hdb1             459G  277G  159G  64% /backup
10
tmpfs                  16G     0   16G   0% /dev/shm

Check RAM Usage

1
free -m
2
             total       used       free     shared    buffers     cached
3
Mem:         32189      32129         59          0        419       9052
4
-/+ buffers/cache:      22656       9532
5
Swap:        32767          4      3276
We will use more command later, but above ones give you some fundamental command to see what we can get from server right on the command line.

Building the Widget

We will refactor our original class in previous section a little bit. Note that, unless clearly stating otherwise, we'll be creating all files and folders within our plugin directory.

First, we won't want to manually include files. We will write an auto class loader for that purpose. When a missing class is initialized, we will check the class name and try to include the source file that hold class definition. 

We will use namespaces as the path and class name as the file name. For example, a class foo in namespace AX\StatBoard should be in the root of plugin folder. A class buzz in namespace AX\StatBoard\Bar should be in Bar\buzz.php

Folder layout structure with namespace, class name and file name for auto loading.

With that in mind, let's go ahead and start crafting our auto loader method:

1
<?php
2
namespace AX\StatBoard;
3
4
class Dashboard {
5
  //..

6
  public function load_class($classname)
7
  {
8
    if (FALSE === $pos = strpos($classname, 'AX\StatBoard')) {
9
      return false;
10
    }
11
    $classname = substr($classname, $pos+1 + strlen('AX\StatBoard'));
12
    $filepath = $this->_plugin_dir . strtolower(str_replace('\\', '/', $classname) . '.php');
13
    if (!file_exists($filepath)) {
14
      return false;
15
    }
16
    include $filepath;
17
  } <br><br>  /**<br>   * Setup variable and intialize widget provider<br>   */<br>  function __construct() {<br>    $this->_plugin_dir =  plugin_dir_path( __FILE__ ) ;<br>    spl_autoload_register(array($this, 'load_class'));<br>  }<br><br>
18
  //..

19
}
So, what happens here? Our plugin use namespace AX\StatBoard. So we make sure the requested class under this namespace should be handle by our plugin, otherwise our auto loader isn't capable to load them. We then strip the AX\StatBoard in class name and replace it with the path of plugin folder. The backslash \ in namespace is replaced with / path separator, and append php extension. That mean that the namespace will be used as the path to folder contains class file, and the class name is the file name. Including only occurs if the file exists. Now, we got the auto loader, we still need to let PHP know that we got an auto loader and we want to use it. PHP includes spl_autoload_register for this purpose. We put it in our class constructor.

Secondly, let's design our widgets class. We have multiple types of server metric to display. It's better to display each of metric in a separate widget block so those widgets can be sorted or arrange, or customized to hide or show. Putting all information into the same widget will put the cost of control showing/hiding each of metric to our plugin. 

Assuming that you know about the function wp_add_dashboard_widget, we have to give it the title and content. Corresponding to each widget, we will have a class to render title and content for it. We call these class are widget Provider. All widget provider must define get_title() and get_content() to render content.

To that end, we will create a Provider interface, and have our widget provider class implement this interface. We also need to create one more method call get_metric() to pull server data.

Create file widget/provider.php with this content:

1
<?php
2
namespace AX\StatBoard\Widget;
3
4
interface Provider {
5
  
6
  function get_title();
7
  function get_content();
8
  function get_metric();
9
}
This is an interface. We required that every widget provider has to implement this interface, and therefore we ensure tat widget provider class always has these three methods.

We will create one more class Widget to manage these providers. We create provider classes, then hand them out to Widget class, and view Widget class as a single point for us to ask for a provider when we need. We can simply put everything into our main plugin file, and just create class instance with new operator when we need but it's hard to maintain later. 

When we break thing down into many layer, it's easier to test and extend. Once we make all providers to be managed by a single class, we can use that single class to do same thing over the set of providers. We can easily add more provider at any point, by just create an object that implement provider class and feed them to Widget class

Compose a file widget.php in root directory of plugin folder.

1
<br><?php<br>namespace AX\StatBoard;<br>use AX\StatBoard\Widget\Provider;<br><br>class Widget {<br>  const WIDGET_SLUG_PREFIX = 'AX';<br><br>  protected $_providers = array();<br>  protected static $_instance;<br><br>  static function instance() {<br>    return self::$_instance = self::$_instance ?: new self();<br>  }<br><br>  function __construct() {<br>  }<br><br>  /**<br>   * Add a widget provider<br>   * @param string widget name<br>   * @param provider object to handle widget content rendering<br>   */ <br>  public function add_provider($name, Provider $handler) {<br>    $this->_providers[$name] = $handler;<br>    return $this;<br>  }<br><br>  /**<br>   * Get all provider or a particular provider<br>   */<br>  public function get_provider($name=NULL) {<br>    if (!$name) {<br>      return $this->_providers;<br>    }<br>    return $this->_providers[$name];<br>  }<br><br>  /**<br>   * Register a widget to render it.<br>   */<br>  public function register($name) {<br>    $slugid = self::WIDGET_SLUG_PREFIX . $name;<br>    $widget_provider = $this->get_provider($name);<br>    if (empty($widget_provider)) {<br>      return false;<br>    }<br><br>    wp_add_dashboard_widget(<br>      $slugid,<br>      $widget_provider->get_title(),<br>      array($widget_provider, 'get_content'));<br>    return true;<br>  }<br>}<br><br>
Again, we're using the Singleton Pattern for our Widget class. A quick summary of our method here.
  1. The add_provider method will add a widget provider object to the widget provider list. We also use type hinting to make sure that object pass to add_provider has to be a Provider by implementing our Provider interface.
  2. The get_provider method can return a list of all provider, or a particular provider.
  3. The register method will actually register our provider object with WordPress to render a dashboard widget with wp_add_dashboard_widget. The ID of widget is generated based on the prefix, a pre defined constant, and the class name of widget. The title will and content will be pull via get_title and get_content of provider. We made sure they implement our Provider interface. With this register method, we abstract the implementation of adding the widget to dashboard. All we need to do now is to call register with the name of provider which we add before with add_provider. With this in mind, when WordPress API changes, we don't need to go to every place of wp_add_dashboard_widget, we just update in one place.

Coming back our original main plugin file serverdashboard.php, we will initialize all providers and add them to provider list of Widget object.

1
  <?php
2
  
3
  /**

4
   * Setup variable and intialize widget provider

5
   */
6
  function __construct() {
7
    $this->_plugin_dir =  plugin_dir_path( __FILE__ ) ;
8
    spl_autoload_register(array($this, 'load_class'));
9
10
    $this->_dashboard_widget = array(
11
      'server',
12
      'cpu_load',
13
14
      'ram',
15
      
16
      'disk',
17
      'diskio',
18
19
      'software',
20
      'ethernet',
21
      
22
      'internetspeed',
23
      'networkio',
24
      'process',
25
    );
26
27
    foreach ($this->_dashboard_widget as $item) {
28
      if (!file_exists($this->_plugin_dir . '/widget/' . $item . '.php')) {
29
        continue;
30
      }
31
      $classname = 'AX\\StatBoard\\Widget\\' . ucwords($item);
32
      Widget::instance()->add_provider($item, new $classname());
33
    }
34
  }<br><br>
We will put all widget provider classes under namespace AX\StatBoard\Widget and therefore they will sit inside folder widget. We support nine kinds of metric and we name the class corresponding to the array _dashboard_widgets above. 

For each of widget, we create a new instance of its provider, and add into Widget class. Here is what we will get later with this structure:
Remember that we hooked into wp_dashboard_setup, and inside it we call the function wp_add_dashboard_widget to add new widget to dashboard. Next, we have our register method for this purpose. We will loop over all added providers, and register them. Update the content of add_dashboard_widgets of serverdashboard.php become:

1
 <br>  /**
2
   * Register dashboard widget proider to show up on dashboard
3
   */
4
  function add_dashboard_widgets() {
5
    $widget = Widget::instance();
6
    foreach ($widget->get_provider() as $name=>$provider) {
7
      $widget->register($name);
8
    }
9
  }<br><br>

Next, we will hook into admin_footer to output inline JavaScript at bottom of admin page for initializing Google Chart class package. Our run() method is also updated for new hook.

1
  /**

2
   * Start to setup hook

3
   */
4
  public function run() {
5
    add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widgets' ) );
6
    add_action( 'admin_enqueue_scripts', array($this, 'add_asset'));
7
    add_action( 'admin_footer', array($this, 'footer'));
8
  }
9
  
10
  /**

11
   * Inline JavaScript for chart

12
   */
13
  function footer() {
14
    echo '

15
      <script>google.load("visualization", "1", {packages:["corechart"]})</script>

16
';
17
  }

At this moment, we completed the basic, and the main plugin file should look like this.
1
<?php
2
/*

3
Plugin Name: Server Dashboard

4
Version: 0.1-alpha

5
Description: Server Status Dashboard

6
Author: Vinh

7
Author URI: http://axcoto.com

8
Plugin URI: http://axcoto.com

9
Text Domain: Server Dashboard

10
Domain Path: /languages

11
 */
12
namespace AX\StatBoard;
13
14
use AX\StatBoard\Widget;
15
16
class Dashboard {
17
  protected static $_instance=NULL;
18
  protected $_dashboard_widget = array();
19
  protected $_plugin_dir=NULL;
20
21
  /**

22
   * Auto load class under namespace of this plugin

23
   */
24
  public function load_class($classname)
25
  {
26
    if (FALSE === $pos = strpos($classname, 'AX\StatBoard')) {
27
      return false;
28
    }
29
    $classname = substr($classname, $pos+1 + strlen('AX\StatBoard'));
30
    $filepath = $this->_plugin_dir . strtolower(str_replace('\\', '/', $classname) . '.php');
31
    if (!file_exists($filepath)) {
32
      return false;
33
    }
34
    include $filepath;
35
  } 
36
  
37
  /**

38
   * Setup variable and intialize widget provider

39
   */
40
  function __construct() {
41
    $this->_plugin_dir =  plugin_dir_path( __FILE__ ) ;
42
    spl_autoload_register(array($this, 'load_class'));
43
44
    $this->_dashboard_widget = array(
45
      'server',
46
      'cpuload',
47
      'ram',
48
      'disk',
49
      'software',
50
      'process',
51
      'ethernet',
52
      'networkio',
53
      
54
      'iostat',
55
    );
56
57
    foreach ($this->_dashboard_widget as $item) {
58
      if (!file_exists($this->_plugin_dir . '/widget/' . $item . '.php')) {
59
        continue;
60
      }
61
      $classname = 'AX\\StatBoard\\Widget\\' . ucwords($item);
62
      Widget::instance()->add_provider($item, new $classname());
63
    }
64
  }
65
66
  /**

67
   * Create an unique instance throught the app

68
   */
69
  public static function instance() {
70
    return self::$_instance = self::$_instance ?: new self();
71
  }
72
73
  /**

74
   * Start to setup hook

75
   */
76
  public function run() {
77
    add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widgets' ) );
78
    add_action( 'admin_enqueue_scripts', array($this, 'add_asset'));
79
    add_action( 'admin_footer', array($this, 'footer'));
80
  }
81
  
82
  /**

83
   * Register dashboard widget proider to show up on dashboard

84
   */
85
  function add_dashboard_widgets() {
86
    $widget = Widget::instance();
87
    foreach ($widget->get_provider() as $name=>$provider) {
88
      $widget->register($name);
89
    }
90
  }
91
92
  /**

93
   * Assets load: stylesheet, JS. 

94
   */ 
95
  function add_asset() {
96
    syslog(LOG_DEBUG, "Loaded"); 
97
    wp_enqueue_script( 'google-chart', 'https://www.google.com/jsapi' );
98
    //wp_enqueue_script( 'plugin_dir_url', plugin_dir_url(__FILE__) . '/loader.js');

99
  }
100
101
  /**

102
   * Inline JavaScript for chart

103
   */
104
  function footer() {
105
    echo '

106
      <script>google.load("visualization", "1", {packages:["corechart"]})</script>

107
';
108
  }
109
}
110
111
Dashboard::instance()->run();
We basically create an instance of main plugin class and call the run method. Which in turn just set up a list of hook. Each hook is another method inside the class. We also create and register our provider object with Widget object.

What's Next?

At this point, we still aren't display anything; however, we laid out a structure for our plugin ad began hooking into Google Charts.

You can download the complete script from the download links at the top of this article. We will go into the implement detail of each widget provider in next article, so make sure you follow the next part. 

I hope you enjoyed this article. Leave comments with any of your thoughts and I will be sure to answer them.




Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.