WP Plugin from Scratch


Muhammad Adnan
Adnan is a Google Summer of Code student and mentor as well as a Google Student Ambassador in 2013. He has been building custom WordPress themes since 2008, co-founded WPBrigade.com, and developed Google Analytics WordPress plugin Analytify.


1 Introduction

Hi, I am Adnan and I will be driving you to the new WordPress development world where you will discover what WordPress is and how to code a WordPress plugin from scratch.

This tutorial is for everyone who is ready to take flight in developing WordPress plugins. If you are a very beginner and don’t know what WordPress is, don’t worry. It is very easy to start at any time in WordPress. You should have at least beginner level knowledge of PHP, MYSQL, HTML, CSS and jQuery to grasp the flow of plugins.

1.1 What is WordPress?

WordPress is an open source CMS (Content Management System) coded in PHP and MySQL. WordPress is completely free and it allows us to easily customize the look of our website using its themes and plugins architecture. It also allows us to edit the content of our website using its rich administrative panel. According to Matt Mullenweg (co-founder of WordPress), 25% of the web is built using WordPress. It holds a huge community of designers, developers and business professionals who run their businesses on WordPress.

1.2 What is a WordPress plugin?

A WordPress Plugin is actually a single file or group of files which extends or enhances the functionality of a WordPress site. Without the use of plugins, WordPress is a little bit more like a blogging platform. For example, with the use of an e-commerce plugin, we can build e-commerce sites within WordPress. Using a membership plugin, a membership-based site can be built upon WordPress.

2 How do WordPress plugins work?

An important concept to understand in WordPress plugins are WordPress hooks, e.g. actions and filters. Hooks allows our plugins to run specific functionality at specific times within WordPress functions.

2.1 Actions

Actions are hooks triggered when WordPress performs events like publishing a post, initializing header and footer areas, creating a new user or deleting pages, etc. For example, the following is an action which runs specific functionality when admin menus are loaded in the administration panel:

add_action( 'admin_menu', ‘add_admin_menu' );

function add_admin_menu() {
// add a group of custom menus
}

admin_menu is an action hook provided by WordPress which allows us to run a function, add_admin_menu, for our needs right when WordPress is going to load administration menus.

2.2 Filters

In general, a filter function takes the input as unmodified data and returns the modified data. Filters sit between the database and browsers and perform certain operations on data, like when WordPress is generating pages or adding new posts in the database. For example, take a look at the following filter:

add_filter( 'comment_text',  'filter_words' );

function filter_words( $data ) {
// filter comment words and return the modified comment
}

In the above filter, comment_text is the filter name and filter_words is a callback function which will take the comments as input and filter the words, returning the modified comments to the output.

3 Setting up your goal

Suppose you are running your websites on WordPress and ran across a special need that is not built-in to WordPress by default. So, you see a problem there and start thinking to solve it and come up with a solution in the shape of a WordPress plugin.

While building Analytify, I found there is no plugin for WordPress that shows Google Analytics under the pages/posts in WordPress. Today, I will walk you through how you can build a simple version of the Analytify plugin where you will fetch the top 10 countries, cities and browsers of your WordPress blog visitors. This will help you to build your own WordPress plugins in the future as well.

Note: You can download the source for this plugin from GitHub, which will help you in implementing the steps of this tutorial.

4 Getting Started

Are you ready?? OK, lets get started to build plugin now. I would recommend you install WordPress from http://wordpress.org/ and go step-by-step. We are using the 4.0 release of WordPress for this tutorial.

WordPress stores its plugins in the /wp-content/plugins/ directory. A plugin can be one PHP file or a group of files containing PHP, CSS, JS and HTML files. If it is one PHP file, place it in the main plugins directory; otherwise create a folder in the /wp-content/plugins/ directory and store all of your files in it.

Create a folder named wp-analytify-simple for our plugin and create a PHP file with name wp-analytify-simple.php in it. So, our final file and folder structure will be /wp-content/plugins/wp-analytify-simple/wp-analytify-simple.php.

Next, open wp-analytify-simple.php in your favorite IDE. You’ll need to add some header information, like so:

<?php
/*
  Plugin Name: Analytify - Reshaping Google Analytics for WordPress
  Plugin URI: http://wp-analytify.com/
  Description: Analytify makes Google Analytics simple for everything in WordPress (posts,pages etc). It presents the statistics in a beautiful way under the WordPress Posts/Pages at front end, backend and in its own Dashboard. This provides Stats from Country, Referrers, Social media, General stats, New visitors, Returning visitors, Exit pages, Browser wise and Top keywords. This plugin provides the Real Time statistics in a new UI that is easy to understand and looks good.
  Version: 1.0
  Author: Muhammad Adnan
  Author URI: http://twitter.com/hiddenpearls
  License: GPLv2+
  Text Domain: wp-analytify-simple
*/
?>

Save the wp-analytify-simple.php file, and then open /wp-admin/plugins.php in your browser. You will see a list of all the plugins which are in your /wp-content/plugins/ directory, and you should see a new plugin with same name and description written in your plugin file.

We have told WordPress that we are building a plugin by adding the header information, but we still have to write the code to make the plugin work.

Let’s start coding our plugin in an Object Oriented Style in PHP. If you are familiar with OOP, following is a skeleton of our basic plugin which can be used for any plugin you develop in the future:

class WP_Analytify_Simple{

  // Constructor
    function __construct() {

        add_action( 'admin_menu', array( $this, 'wpa_add_menu' ));
        register_activation_hook( __FILE__, array( $this, 'wpa_install' ) );
        register_deactivation_hook( __FILE__, array( $this, 'wpa_uninstall' ) );
    }

    /*
      * Actions perform at loading of admin menu
      */
    function wpa_add_menu() {

        add_menu_page( 'Analytify simple', 'Analytify', 'manage_options', 'analytify-dashboard', array(
                          __CLASS__,
                         'wpa_page_file_path'
                        ), plugins_url('images/wp-analytics-logo.png', __FILE__),'2.2.9');

        add_submenu_page( 'analytify-dashboard', 'Analytify simple' . ' Dashboard', ' Dashboard', 'manage_options', 'analytify-dashboard', array(
                              __CLASS__,
                             'wpa_page_file_path'
                            ));

        add_submenu_page( 'analytify-dashboard', 'Analytify simple' . ' Settings', '<b style="color:#f9845b">Settings</b>', 'manage_options', 'analytify-settings', array(
                              __CLASS__,
                             'wpa_page_file_path'
                            ));
    }

    /*
     * Actions perform on loading of menu pages
     */
    function wpa_page_file_path() {



    }

    /*
     * Actions perform on activation of plugin
     */
    function wpa_install() {



    }

    /*
     * Actions perform on de-activation of plugin
     */
    function wpa_uninstall() {



    }

}

new WP_Analytify_Simple();

Let me explain the above code. We are creating a class named WP_Analytify_Simple; you should use a unique class name with a unique prefix so it doesn’t conflict with other plugin classes. __construct() is a constructor function which is called when a new object is instantiated from the class WP_Analytify_Simple.

new WP_Analytify_Simple(); is the line where we are instantiating a new object.

In the __construct() function, we are running multiple WordPress hooks which run callback functions and performs the required functionality:

add_action( 'admin_menu', array( $this, 'wpa_add_menu' ));

function wpa_add_menu() {

// statements to add menu

}

The WordPress action hook 'admin_menu' runs a callback function wpa_add_menuwhich creates a new menu in administration menus, at top left under the dashboard menu item. I suggest you go to the WordPress documentation and explore the functions add_menu_page and add_submenu_page.

There are two more hooks defined in the __construct function: register_activation_hook and register_deactivation_hook, which run their callbacks on activation and deactivation of the plugin and perform the required functionality like adding or erasing the plugin’s metadata.

Save the above code in your plugin file and reload the wp-admin dashboard in your browser. You will see a new menu named ‘Analytify’ under the dashboard on the top left side. This new menu item will have two sub-menus — ‘Dashboard’ and ‘Settings’.

Now, we need to create a few more folders to hold other materials. Your final files and folder structure will be:

  • /wp-content/plugins/wp-analytify-simple/wp-analytify-simple.php (main plugin file)
  • /wp-content/plugins/wp-analytify-simple/images/wp-analytics-logo.png (create an image with 16px * 16px dimensions)
  • /wp-content/plugins/wp-analytify-simple/css/
  • /wp-content/plugins/wp-analytify-simple/includes/
  • /wp-content/plugins/wp-analytify-simple/views/
  • /wp-content/plugins/wp-analytify-simple/lib/

Notice, I have created more directories like /css to store CSS files to style the statistics in our plugin dashboard, /includes for saving dashboard and settings pages, /viewsfolder for saving separate pages for countries, cities, and browsers statistics, and /libto save the Google APIs PHP Client library provided by Google.

Next, go to /images folder and place your plugin logo with the filename /wp-content/plugins/wp-analytify-simple/images/wp-analytics-logo.png. It will appear right next to your plugin menu in administration menus.

5 Connecting WordPress plugins with third-party APIs

As you know, if we are going to fetch the geolocation statistics portion from Google Analytics web profiles, we have to use third-party APIs. The Google API Client Library enables you to work with Google APIs such as Google+, Google Analytics, Drive, or YouTube on your server. We can use this library to fetch the statistics of YouTube videos and upload the files on Google Drive as well. It’s up to us which classes we use for our purpose.

You can download the PHP version of the library from Google’s GitHub repository. Unzip it and store these files in your /lib directory, which should look like /wp-content/plugins/wp-analytify-simple/lib/google-api-php-client-master/.

Next, we have to include these APIs in our main plugin file and connect with Google Analytics to load the required statistics. At this point, we need to create a project in the Google developers console and set ClientIDClientSecretDeveloperKey and redirect URIs. We have to put these console parameters in our __construct function and it will look like this:

// Constructor
function __construct() {

    if ( !class_exists( 'Google_Client' ) ) {

        require_once dirname(__FILE__) . '/lib/google-api-php-client-master/src/Google/Client.php';
        require_once dirname(__FILE__) . '/lib/google-api-php-client-master/src/Google/Service/Analytics.php';
    }

    $this->client = new Google_Client();
    $this->client->setApprovalPrompt( 'force' );
    $this->client->setAccessType( 'offline' );
    $this->client->setClientId( '958799092305-pfb9msi30152k3lfakbgauspuqr01g1d.apps.googleusercontent.com' );
    $this->client->setClientSecret( 'SUhMQfFcAwaIHswQtmw4utyh' );
    $this->client->setRedirectUri( 'urn:ietf:wg:oauth:2.0:oob' );
    $this->client->setScopes( 'https://www.googleapis.com/auth/analytics' ); 
    $this->client->setDeveloperKey( 'AIzaSyAn-70Vah_wB9qifJqjrOhkl77qzWhAR_w' ); 

    try{

        $this->service = new Google_Service_Analytics( $this->client );
        $this->wpa_connect();

    }
    catch ( Google_Service_Exception $e ) {

    }


    add_action( 'admin_menu', array( $this, 'wpa_add_menu' ) );
    add_action( 'admin_enqueue_scripts', array( $this, 'wpa_styles') );

    register_activation_hook( __FILE__, array( $this, 'wpa_install' ) );
    register_deactivation_hook( __FILE__, array( $this, 'wpa_uninstall' ) );
}

Notice in the above code, we have instantiated Google_Client and Google_Service_Analytics classes. After configuring Google_Client with Google console parameters, we are connecting to the API using wpa_connect function and getting the access_token. We save this access_token and use it to fetch the data from the API.

Next, write this connect function in our main plugin class:

public function wpa_connect() {

    $access_token = get_option('access_token');

    if (! empty( $access_token )) {

        $this->client->setAccessToken( $access_token );

    } 
    else{

        $authCode = get_option( 'access_code' );

        if ( empty( $authCode ) ) return false;

        try {

            $accessToken = $this->client->authenticate( $authCode );
        }
        catch ( Exception $e ) {
            return false;
        }

        if ( $accessToken ) {

            $this->client->setAccessToken( $accessToken );
            update_option( 'access_token', $accessToken );

            return true;
        }
        else {

            return false;
        }
    }

    $this->token = json_decode($this->client->getAccessToken());
    return true;

}

Next, pt_get_analytics_accounts will fetch a list of all the web profiles attached to your Google Analytics account and pa_get_analytics_dashboard will fetch your required statistics. You can fetch anything else by using the pa_get_analytics_dashboard function:

/**
 * Get profiles from user Google Analytics account profiles.
 */
public function pt_get_analytics_accounts() {

        try {

            if( get_option( 'access_token' ) !='' ) {
                $profiles = $this->service->management_profiles->listManagementProfiles( "~all", "~all" );
                return $profiles;
            }

            else{
                echo '<br /><p class="description">' . __( 'You must authenticate to access your web profiles.', 'wp-analytify' ) . '</p>';
            }

        }

        catch (Exception $e) {
            die('An error occured: ' . $e->getMessage() . '\n');
        }
}


/*
 * This function grabs the data from Google Analytics
 * For dashboard.
 */

 public function pa_get_analytics_dashboard($metrics, $startDate, $endDate, $dimensions = false, $sort = false, $filter = false, $limit = false){

        try{

            $this->service = new Google_Service_Analytics($this->client);
            $params        = array();

            if ($dimensions){
                $params['dimensions'] = $dimensions;
            }
            if ($sort){
                $params['sort'] = $sort;
            } 
            if ($filter){
                $params['filters'] = $filter;
            }
            if ($limit){
                $params['max-results'] = $limit;
            } 

            $profile_id = get_option("pt_webprofile_dashboard");
            if (!$profile_id){
                return false;
            }

            return $this->service->data_ga->get('ga:' . $profile_id, $startDate, $endDate, $metrics, $params);

        }

        catch ( Google_Service_Exception $e ) {

            // Show error message only for logged in users.
            if ( is_user_logged_in() ) echo $e->getMessage();

        }
    }

6 Building a WordPress plugin settings page

Not every plugin needs settings pages, but when you want to give flexibility for customization to your users, you must have settings pages. Let’s build settings page for our plugin where we will create two tabs, one for authentication and one for profile selection where we will load all of our web profiles in a select box. The authentication tab is where we will let our plugin users connect with their Google Analytics accounts and save the access code in an input box.

Following is the code of our settings page, which will be stored in the /includes folder with the name analytify-settings.php.

<?php
  $wp_analytify = new WP_Analytify_Simple();

  if (! function_exists( 'curl_init' ) ) {
      esc_html_e('This plugin requires the CURL PHP extension');
    return false;
  }

  if (! function_exists( 'json_decode' ) ) {
    esc_html_e('This plugin requires the JSON PHP extension');
    return false;
  }

  if (! function_exists( 'http_build_query' )) {
    esc_html_e('This plugin requires http_build_query()');
    return false;
  }

  $url = http_build_query( array(
                                'next'          =>  admin_url('admin.php?page=analytify-settings'),
                                'scope'         =>  'https://www.googleapis.com/auth/analytics',
                                'response_type' =>  'code',
                                'redirect_uri'  =>  'urn:ietf:wg:oauth:2.0:oob',
                                'client_id'     =>  '958799092305-pfb9msi30152k3lfakbgauspuqr01g1d.apps.googleusercontent.com'
                                )
                          );

  // Save access code
  if ( isset( $_POST["save_code"]) and isset($_POST["access_code"]) ) {

    if( $wp_analytify->wpa_save_data( $_POST["access_code"] )){
        $update_message = '<div id="setting-error-settings_updated" class="updated settings-error below-h2"><p><strong>Access code saved.</strong></p></div>';
    }
  }

// Clear Authorization and other data
  if (isset($_POST[ "clear" ])) {

delete_option( 'access_token' );    
delete_option( 'access_code' );
    $update_message = '<div id="setting-error-settings_updated" class="updated settings-error below-h2"> 
                        <p><strong>Authentication Cleared login again.</strong></p></div>';
  }

    // Saving Profiles
  if (isset($_POST[ 'save_profile' ])) {

    update_option( 'pt_webprofile_dashboard', $_POST[ 'webprofile_dashboard' ] );

    $update_message = '<div id="setting-error-settings_updated" class="updated settings-error below-h2"> 
                        <p><strong>Your Google Analytics Profile Saved.</strong></p></div>';
  }

?>

<div class="wrap">
  <span class='opt-title'><span id='icon-options-general' class='analytics-options'><img src="<?php echo plugins_url('wp-analytify/images/wp-analytics-logo.png');?>" alt=""></span>
    <?php echo __( 'Analytify Plugin Settings', 'wp-analytify'); ?>


  <?php
  if (isset($update_message)) echo $update_message;

  if ( isset ( $_GET['tab'] ) ) $wp_analytify-> pb_settings_tabs($_GET['tab']); 
  else $wp_analytify->pa_settings_tabs( 'authentication' );

  if ( isset ( $_GET['tab'] ) ) 
    $tab = $_GET['tab']; 
  else 
    $tab = 'authentication';

  // Authentication Tab section
  if( $tab == 'authentication' ) {
  ?>

  <form action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>" method="post" name="settings_form" id="settings_form">
    <table width="1004" class="form-table">
      <tbody>
      <?php if( get_option( 'access_token' ) ) { ?>
        <tr>
          <p>Do you want to re-authenticate ? Click reset button and get your new Access code.<p>

        </tr>
        <tr>
          <th><?php esc_html_e( 'Clear Authentication', 'wp-analytify' ); ?></th>
          <td><input type="submit" class="button-primary" value="Reset" name="clear" /></td>
        </tr>
      <?php 
      }
      else { ?>
        <tr>
          <th width="115"><?php esc_html_e( 'Authentication:' )?></th>
              <td width="877">
                    <a target="_blank" href="javascript:void(0);" onclick="window.open('https://accounts.google.com/o/oauth2/auth?<?php echo $url ?>','activate','width=700,height=500,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=1,left=0,top=0');">Click here to Authenticate</a>
              </td>
        </tr>
        <tr>
              <th><?php esc_html_e('Your Access Code:')?> </th>
              <td>
                <input type="text" name="access_code" value="" style="width:450px;"/>
              </td>
        </tr>
        <tr>
          <th></th>
          <td>
            <p class="submit">
              <input type="submit" class="button-primary" value = "Save Changes" name = "save_code" />
            </p>
          </td>
        </tr>
      <?php } ?>
      </tbody>
    </table>
  </form>
  <?php 
  } // endif
// Choose profiles for dashboard and posts at front/back.
if( $tab == 'profile' ){
  $profiles = $wp_analytify->pt_get_analytics_accounts();
  if( isset( $profiles ) ) { ?>
    <p><?php esc_html_e( 'Select profile for dashboard data.', 'wp-analytify' ); ?></p>

    <form action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>" method="post">
      <table width="1004" class="form-table">
        <tbody>
          <tr>
            <th width="115"><?php esc_html_e( 'Dashboard :', 'wp-analytify' );?></th>
            <td width="877">
                <select name='webprofile_dashboard' id='webprofile-dashboard'>
                  <?php foreach ($profiles->items as $profile) { ?>
                  <option value="<?php echo $profile[ 'id' ];?>"
                              <?php selected( $profile[ 'id' ], get_option( 'pt_webprofile_dashboard' )); ?>
                              >
                              <?php echo $profile[ 'websiteUrl' ];?> - <?php echo $profile[ 'name' ];?>
                  </option>
                  <?php } ?>
                </select>
            </td>
          </tr>
          <tr>
            <th></th>
            <td>
              <p class="submit">
                <input type="submit" name="save_profile" value="Save Changes" class="button-primary">
              </p>
            </td>
          </tr>
          <?php } ?>
      </tbody>
    </table>
  </form>
<?php } ?>

</div>
</div>
</div>

7 Building custom WordPress plugin pages

We have created our plugin settings page, now it’s time to create the dashboard page where we will load a set of statistics by using third-party Google Analytics APIs. Remember, there are 2 drop down menus in the administration menu for our plugin, like this:

  • Analytify → Dashboard
  • Analytify → Settings

For the settings menu, we have created a settings page already in the previous step. For the dashboard menu, we will create a page inside /includes named analytify-dashboard.php which will display the top 10 countries, cities, and browsers of our selected web profile. For now, paste the following code in analytify-dashboard.phppage:

<?php
$wp_analytify = new WP_Analytify_Simple();

$start_date_val =   strtotime("- 30 days"); 
$end_date_val   =   strtotime("now");
$start_date     =   date( "Y-m-d", $start_date_val);
$end_date       =   date( "Y-m-d", $end_date_val);

?>
<div class="wrap">
  <span class='opt-title'><span id='icon-options-general' class='analytics-options'><img src="<?php echo plugins_url('wp-analytify-simple/images/wp-analytics-logo.png');?>" alt=""></span>
    <?php echo __( 'Analytify Simple Dashboard', 'wp-analytify' ); ?>

  <?php

  $acces_token  = get_option( "access_code" );
  if( $acces_token ) {

  ?>
  <div id="col-container">
    <div class="metabox-holder">
      <div class="postbox" style="width:100%;">
          <div id="main-sortables" class="meta-box-sortables ui-sortable">
            <div class="postbox ">
              <div class="handlediv" title="Click to toggle"><br />
              </div>
              <span class="hndle">
                <span>
                    <?php 
                    echo _e('Complete Statistics Starting From ', 'wp-analytify'); 
                    echo _e(date("jS F, Y", strtotime($start_date))); 
                    echo _e(' to ', 'wp-analytify'); 
                    echo _e(date("jS F, Y", strtotime($end_date))); 
                    ?>
                </span>

              <div class="inside">
                <?php

                // Country stats //

                $country_stats = $wp_analytify->pa_get_analytics_dashboard( 'ga:sessions', $start_date, $end_date, 'ga:country', '-ga:sessions', false, 5);
                if ( isset( $country_stats->totalsForAllResults )) {
                  include ROOT_PATH . '/views/country-stats.php'; 
                  pa_include_country($wp_analytify,$country_stats);
                }

                // End Country stats //

                $city_stats = $wp_analytify->pa_get_analytics_dashboard( 'ga:sessions', $start_date, $end_date, 'ga:city', '-ga:sessions', false, 5);
                if ( isset( $city_stats->totalsForAllResults )) {
                  include ROOT_PATH . '/views/city-stats.php'; 
                  pa_include_city($wp_analytify,$city_stats);
                }


                // Browser stats //

                $browser_stats = $wp_analytify->pa_get_analytics_dashboard( 'ga:sessions', $start_date, $end_date, 'ga:browser,ga:operatingSystem', '-ga:sessions',false,5);
                if ( isset( $browser_stats->totalsForAllResults ) ) {
                  include ROOT_PATH . '/views/browser-stats.php'; 
                  pa_include_browser( $wp_analytify,$browser_stats );
                }

                // End Browser stats //

                ?>
              </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <?php 
  } 
  else{
    print(_e( 'You must be authenticate to see the Analytics Dashboard.', 'wp-analytify' ));
  }
  ?>
</div>

From above code, I will explain the country stats portion in detail; after that, the rest should be easy to understand.

$country_stats = $wp_analytify->pa_get_analytics_dashboard( 'ga:sessions', $start_date, $end_date, 'ga:country', '-ga:sessions', false, 5);
if ( isset( $country_stats->totalsForAllResults )) {
  include ROOT_PATH . '/views/country-stats.php'; 
  pa_include_country($wp_analytify,$country_stats);
}

pa_get_analytics_dashboard is a function written in our main plugin class which fetches the top 10 countries. We pass arguments like ga:country and ga:sessions to fetch the data from $start_date to $end_date.

$country_stats holds the results and we are passing this variable to another function, pa_include_country, which is written in a separate file called country-stats.php in the /views folder; country stats HTML is being pulled from this file.

In the /views folder we have created separate files for each statistic, taking a modular approach. It helps in managing large set of functions or files.

Create a new file in /views for browser statistics with name browser-stats.php and write the following code in it:

<?php
// View of Browser Statistics
function pa_include_browser( $current, $browser_stats ) {
?>
<div class="data_boxes">
  <div class="data_boxes_title"><?php echo _e('BROWSERS STATS', 'wp-analytify');?><div class="arrow_btn"></div></div>
  <div class="data_container">
    <?php
    if (!empty($browser_stats["rows"])){ ?>
       <div class="names_grids">
                <?php foreach ($browser_stats["rows"] as $c_stats){ ?>
                        <div class="stats">
                            <div class="row-visits">
                                <span class="large-count"><?php echo $c_stats[2];?></span>
                            Visits
                            </div>
                            <div class="visits-count">
                                <i><?php  echo $c_stats[0];?> (<?php  echo $c_stats[1];?>)</i>
                            </div>
                        </div>
                <?php } ?>
            </div>
    <?php } ?>
  </div>
  <div class="data_boxes_footer">
      <span class="blk"> 
        <span class="dot"></span> 
        <span class="line"></span> 
      </span> 
      <span class="information-txt"><?php echo _e('listing statistics of top five browsers.', 'wp-analytify');?></span>
  </div>
</div>
<?php } ?>

Then, create a new file in /views for city statistics with name city-stats.php and write the following code in it:

<?php 
// View of City wise Statistics
function pa_include_city( $current, $country_stats ) {
?>
<div class="data_boxes">
    <div class="data_boxes_title">TOP CITIES <div class="arrow_btn"></div></div>
        <div class="data_container">
            <?php
            if (! empty( $country_stats["rows"] ) ) { ?>
            <div class="names_grids">
                <?php foreach ($country_stats["rows"] as $c_stats){ ?>
                        <div class="stats">
                            <div class="row-visits">
                                <span class="large-count"><?php echo $c_stats[1];?></span>
                            Visits
                            </div>
                            <div class="visits-count">
                                <i><?php  echo $c_stats[0];?> </i>
                            </div>
                        </div>
                <?php } ?>

            </div>
            <?php } ?>
        </div>
    <div class="data_boxes_footer">
        <span class="blk"> 
            <span class="dot"></span> 
            <span class="line"></span> 
        </span> 
        <span class="information-txt">Listing statistics of top five cities.</span>
    </div>
</div> 
<?php } ?>

Finally, create a new file in /views for country statistics with name country-stats.phpand write the following code in it:

<?php 
// View of Country wise Statistics
function pa_include_country( $current, $country_stats ) {
?>
<div class="data_boxes">
    <div class="data_boxes_title">TOP COUNTRIES <div class="arrow_btn"></div></div>
        <div class="data_container">
            <?php
            if (! empty( $country_stats["rows"] ) ) { ?>

            <div class="names_grids">
                <?php foreach ($country_stats["rows"] as $c_stats){ ?>
                        <div class="stats">
                            <div class="row-visits">
                                <span class="large-count"><?php echo $c_stats[1];?></span>
                            Visits
                            </div>
                            <div class="visits-count">
                                <i><?php  echo $c_stats[0];?></i>
                            </div>
                        </div>
                <?php } ?>

            </div>
            <?php } ?>
        </div>
    <div class="data_boxes_footer">
        <span class="blk"> 
            <span class="dot"></span> 
            <span class="line"></span> 
        </span> 
        <span class="information-txt">Listing statistics of top five countries.</span>
    </div>
</div> 
<?php } ?>

8 Styling WordPress plugins with CSS

Sometimes, you need to style plugins with custom CSS. The standard way to load the CSS files is to add a callback function in a WordPress action hook in your plugin constructor like this:

add_action( 'admin_enqueue_scripts', array( $this, 'wpa_styles') );

Add the callback function outside of __construct function:

/**
 * Styling: loading stylesheets for the plugin.
 */
public function wpa_styles( $page ) {

    wp_enqueue_style( 'wp-analytify-style', plugins_url('css/wp-analytify-style.css', __FILE__));
}

In our plugin, we have to style our dashboard stats using CSS. Write the following CSS code in /css/wp-analytify-style.css:

.opt-title{
    font-size: 18px;
}
.analytics-options{
    margin: -1px 0 5px 0;
    display: inline-block;
    padding-top: 5px;
    float: left;
}
/*.error-own{
    position: absolute;
    top: 13px;
    left: 500px;
}*/
.themes-php .wrap p.description {
clear: both;
font-size: 15px;
margin-bottom: 20px;
}
.select2-container, .select2-drop, .select2-search, .select2-search input{
    width: 100%;
}
.data_boxes *{
    box-sizing:border-box;
    line-height: 1.6 !important;
}
.Real_Time_Statistics_table{
    width:100%;
    border-radius:5px;
    border-collapse:collapse;
    border: 1px solid #e2e5e8;
    clear:both;
}
.wd_1{
    width:50px;
    border:0 !important;
}
.wd_2{
    width:70px;
}
.Real_Time_Statistics_table th{
    background-color: #f9fafa;
    padding:5px 10px;
    border-left: 1px solid #e2e5e8;
    text-align:left;
}
.Real_Time_Statistics_table td{
    background-color: #fff;
    border-top: 1px solid #e2e5e8;
    padding:4px 6px;
}

.data_boxes{
    background: #fff;
    margin-bottom: 30px;
    position: relative;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    -ms-border-radius: 5px;
    -o-border-radius: 5px;
    border-radius: 5px;
    clear: both;
}
.data_boxes_title{
    padding:6px 30px;
    background-color: #F9845B;
    -webkit-border-radius: 5px 5px 0 0;
    -moz-border-radius: 5px 5px 0 0;
    -ms-border-radius: 5px 5px 0 0;
    -o-border-radius: 5px 5px 0 0;
    border-radius: 5px 5px 0 0;
    color: #fff;
    font-size: 24px;
    line-height: 1.6;
    position: relative;
}
.data_boxes_title.close{
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    -ms-border-radius: 5px;
    -o-border-radius: 5px;
    border-radius: 5px; 
    }
.arrow_btn{
    width:25px;
    height:16px;
    position:absolute;
    top:50%;
    right:10px;
    background:url(../images/arrow.png) no-repeat 0 0;
    margin-top: -8px;
}
.arrow_btn:hover{
    background:url(../images/arrow.png) no-repeat right 0;
    cursor: pointer;
}
.close .arrow_btn{
    background:url(../images/arrow.png) no-repeat 0 bottom;
}
.close .arrow_btn:hover{
    background:url(../images/arrow.png) no-repeat right bottom;
}
.data_container{
    overflow:hidden;
    border-left: 1px solid #e2e5e8;
    border-right: 1px solid #e2e5e8;
    padding:20px 0;
}
.data_boxes_footer{
    background-color: #f9fafa;
    border: 1px solid #e2e5e8;
    padding: 15px 30px;
    -webkit-border-radius:0 0 5px 5px;
    -moz-border-radius: 0 0 5px 5px;
    -ms-border-radius: 0 0 5px 5px;
    -o-border-radius: 0 0 5px 5px;
    border-radius: 0 0 5px 5px;
    overflow: hidden;
    position: relative;
}
.grids_auto_size{
    float:left;
    width:30.5%;
    min-height:220px;
    border: 1px solid #e2e5e8;
    margin:10px 0 10px 2%;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    -ms-border-radius: 5px;
    -o-border-radius: 5px;
    border-radius: 5px;
}
.grid_title{
    padding:6px 10px;
    background-color: #4fca74;
    color: #fff;
    font-size: 16px;
    line-height: 1.6;
    margin:0;
    margin:-1px;
    -webkit-border-radius: 5px 5px 0 0;
    -moz-border-radius: 5px 5px 0 0;
    -ms-border-radius: 5px 5px 0 0;
    -o-border-radius: 5px 5px 0 0;
    border-radius: 5px 5px 0 0;
}
.cen{
    text-align:center;
}
.grid_data{
}
.data_value{
    font-size:40px;
}
.grid_footer{
    padding:10px;
}
.chart {
  width: 100%; 
  height: 600px;
}
#tagcloud a:link, #tagcloud a:visited {
    text-decoration:none;
    color: #333;
}

#tagcloud a:hover {
    text-decoration: underline;
}

#tagcloud .keywordscont {
    color: #000;
    padding: 0 10px;
    float: left;
    width: 23%;
}
#tagcloud .visits_by_keyword:after{
    position: absolute;
    width: 15px;
    height: 15px;
    background: #ddd;
    content: "";
    top: 58%;
    left: -21px;
    border-radius: 30px;
    display: block;
    margin-top: -7px;
}
#tagcloud .smallest span {
    font-size: 25px;
    position: relative;
}

#tagcloud .small span{
    font-size: 30px;
    position: relative;
}

#tagcloud .medium span{
    font-size:40px;
    position: relative;
}

#tagcloud .large span{
    font-size:50px;
    position: relative;
}

#tagcloud .largest span{
    font-size:55px;
    position: relative;
}
.guest-show{
  display: block;
}
.stats {
        float: left;
        padding: 0px 20px;
        margin-bottom: 10px;
        width: 33%;
}
.stats:first-child{
  /*border-left: 0;*/
}
.names_grids{
        text-align: center;
        padding: 40px 0 10px;
        overflow: hidden;
        width: 87%;
        margin: 0 auto;
}
.realtime{
  overflow: hidden;
  padding: 10px 4%;
}
.pa-tdo-left{
    float:left;
    width:40%;
    border-right: 1px solid #e2e5e8;
}
.pa-online{
    display: block !important;
    width: 250px;
    height: 250px;
    border-radius: 1000px;
    line-height: 250px !important;
    background: #e2e5e8 !important;
    text-align: center;
    font-size: 66px;
    color: #fff;
    font-weight: 900;
}
.pa-bigtext {
    width: 20%;
    float: left;
    margin-bottom: 10px;
    text-align: center;
}
.pa-bigtext .source{
    display: block;
}
.pa-bigtext a {
    font-size: 15px;
    text-decoration: none;
    color: #857575;
}
.count-visits {
    font-size: 40px;
    border:2px solid #ccc;
    display: block;
    width: 100px;
    height: 100px;
    border-radius: 1000px;
    text-align: center;
    line-height: 100px !important;
    margin:0 auto;
}
.count-ex-visits {
    font-size: 40px;
    border:2px solid #ccc;
    display: inline-block;
    border-radius: 1000px;
    line-height: 100px !important;
    padding: 0 8px 0 8px;
}
.opt-title{
    overflow: hidden;
}
#icon-options-general img{
 margin-bottom: 5px;
 margin-right: 5px;
}
.left-area{
 float: left;
 width: 70%;
}
.right-area{
 float: right;
 width: 24%;
}
.right-area img{
 margin-top: 10px;
}
.large-count{
    font-size: 40px;
    line-height: 1 !important;
    position: relative;
}
.hide{
    display: none;
}
.visitor-stats{
    position: relative;
}

.visitor-stats-new .font-sizing{
        font-size: 13px;
        position: relative;
}
.visitor-stats-new,.visitor-stats-ret {
    position: relative;
    margin-left: 20px;
}
.font-sizing:after {
position: absolute;
width: 15px;
height: 15px;
background: #4fca74;
content: "";
top: 50%;
left: -17px;
margin-top: -8px;
border-radius: 30px;
}
.visitor-stats-ret .font-sizing{
        font-size: 13px;
        position: relative;
}
.visitor-stats-ret .font-sizing:after{
    background: #0E9236;
}
.large-count:after{
    position: absolute;
    width: 15px;
    height: 15px;
    background: #ddd;
    content: "";
    top: 50%;
    left: -21px;
    border-radius: 30px;
    display: block;
    margin-top: -7px;
}
.blk{
  height:30px;
  width:30px;
  text-align:center;
  display:block;
  background:#5fcf80;
  border-radius:50%;
  text-decoration:none;
  -webkit-box-sizing:border-box;
  -moz-box-sizing:border-box;
  box-sizing:border-box;
  padding: 1px;
  float: left;
  margin-right: 5px;
  position: absolute;
  top: 50%;
  margin-top: -15px;
}
.blk span{
  width:5px;
  display:block;
  margin:3px auto 2px auto;
  background:#fff;
}
.dot{
  height:5px;
  border-radius:50%;
}
.line{
  height:13px;
  border-radius: 5px;
}
.information-txt {
    margin-top: 4px;
    float: left;
    padding-left: 35px;
}
.btn-green{
    background-color: #5fcf80 !important;
    border-color: #3ac162 !important;
}
.pa-filter{
    margin-left: 20%;
    margin-top: 10px;
    margin-bottom: 10px;
}
.wpa_side_box{
    min-height: 10px !important;

}
.wpa_side_box a{
    text-decoration: none;
}
@media (max-width: 800px){
    .pa-tdo-left{
        width: 100%;
        float:none;
        margin-bottom: 10px;
        border:0;
    }
    .pa-tdo-right{
        width: 100%;
        float:none;
    }
    .pa-online{
        margin: 0 auto;
    }
    .pa-bigtext{
        width: 33%;
    }
    .pa-online{
        width: 200px;
        height: 200px;
        line-height: 200px !important;
    }
    .pa-filter{
        margin-left: 0 !important;
    }
    .grids_auto_size{
        min-height: 230px;
    }
}
@media (max-width: 650px){ 
    .grid_title{
        font-size: 13px; 
    }
    .data_value{
        font-size: 25px; 
    }
    #tagcloud .keywordscont{
        width: 32%;
    }
    .data_boxes_title{
        font-size: 17px;
        padding:6px 18px;
    }
    .hasDatepicker {
        width: 33%;
    }
}
@media (max-width: 480px){
    .count-visits{
        width: 75px;
        height: 75px;
        line-height: 75px !important;
    }
    .pa-bigtext a{
        font-size: 13px;
    }
    .grids_auto_size{
        width: 47%;
    }
    .stats{
        width: 50%;
    }
    #tagcloud .keywordscont{
        width: 47%;
    }

}
@media (max-width: 400px){
    .grids_auto_size{
        width: 98%;
    }
    .visits-count i{
        word-break:break-all;
    }
    #tagcloud .keywordscont{
        width: 97%;
    }
    .stats{
        width: 97%;
    }
    .hasDatepicker {
        width: 30%;
        font-size: 12px;
    }

}

9 Conclusion

Let’s summarize what were the steps taken in developing this WordPress plugin from scratch:

  • + Create a plugin folder and write the Plugin header information in main plugin file.
  • + Create a plugin class in OOP way and add your plugin menus into administration menus.
  • + Create a files and folder structure for your plugin to store css, images, third party libraries and includes files.
  • + Download Google Analytics PHP Client library from GitHub and include it in your plugin.
  • + Build a WordPress settings page.
  • + Build Custom WordPress plugin pages.
  • + Style your plugins using CSS.

Note: I hope you have learned a lot in this lengthy WordPress Plugin development tutorial. If you have any suggestions or ideas, do let us know in the comments below.

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s