Creating a Basic Wordpress Plugin

Published Friday 3rd of February 2012

I recently created my very first Wordpress plugin (I've been coding themes for a few years though) and I thought I'd write down a little getting started for other plugin noobs out there.

I'll cover how to configure your plugin, connect to the database using the WPDB, install and uninstall DB tables, create a page in the admin and submit forms.

I'll focus more on the WP specific stuff and less on PHP. If you don't know PHP you might find it hard to follow.

If you ever need more information about a WP function refer to the Wordpress codex. I won't go into as much detail as they do.

Let's code

All Wordpress plugins reside in the wp-content/plugins/ directory. Plugins can be as simple as a single PHP file or a directory full of PHP, CSS, JS, images and whatever else you can think of (just like a SleekPHP Module :).

To create a new plugin all we need to do is create a directory for our plugin in the plugins directory, and then create a PHP file with the same name as the directory we created:

  • wp-content/plugins/
    • wp-content/plugins/my-plugin/
      • wp-content/plugins/my-plugin/my-plugin.php

The first PHP comment in this file will hold our configuration:

<?php
/*
Plugin Name: My Plugin
Description: My first WP plugin

Author: You
Author URI: http://your-website.com

Version: 1.0
License: GPL
*/

That's enough for your plugin to show up in the admin, but at this point it won't do anything. Let's do something about that.

We'll start by setting up some handy CONSTANTS for use later in our code:

global $wpdb;

define('MYP_TITLE',        'My Plugin');
define('MYP_SLUG',        'my-plugin');
define('MYP_TABLE',        $wpdb->prefix 'myp_table');

define('MYP_DOCROOT',    dirname(__FILE__));
define('MYP_WEBROOT',    str_replace(getcwd(), home_url(), dirname(__FILE__)));

Now we're going to hook into Wordpress and tell it we want to perform certain actions at certain points. The first thing we want to do is tell it to run a function of ours when the plugin is activated, and another when it is deactivated. These functions are used for creating and dropping the database table:

register_activation_hook(__FILE__'myp_install');
register_deactivation_hook(__FILE__'myp_uninstall');

We'll also tell Wordpress to add a menu item in the admin for our plugin:

add_action('admin_menu''myp_menu');

Now we could go on and create these functions (mypinstall(), mypuninstall(), myp_menu()), do all the database logic and write all the HTML in this same file but that would look horrible so we're going to divide it up a bit.

Create two directories in your plugin directory: "lib" and "views". In lib create three files: install.php, model.php and controller.php.

Before we fill those files with juicy PHP code we'll put the last three lines in my-plugin.php which by now should look like this:

<?php
/*
Plugin Name: My Plugin
Description: My first WP plugin

Author: You
Author URI: http://your-website.com

Version: 1.0
License: GPL
*/

global $wpdb;

define('MYP_TITLE',        'My Plugin');
define('MYP_SLUG',        'my-plugin');
define('MYP_TABLE',        $wpdb->prefix 'myp_table');

define('MYP_DOCROOT',    dirname(__FILE__));
define('MYP_WEBROOT',    str_replace(getcwd(), home_url(), dirname(__FILE__)));

register_activation_hook(__FILE__'myp_install');
register_deactivation_hook(__FILE__'myp_uninstall');

add_action('admin_menu''myp_menu');

include 
'lib/model.php';
include 
'lib/install.php';
include 
'lib/controller.php';

With the three includes added at the bottom.

Let's start with install.php.

install.php

We'll put our two functions myp_install() and myp_uninstall() in this file and all they'll do is CREATE or DROP our plugin database table.

<?php
function myp_install () {
    global 
$wpdb;

    require_once 
ABSPATH 'wp-admin/includes/upgrade.php';

    
dbDelta('
        CREATE TABLE `' 
MYP_TABLE '` (
          `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
          `title` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
          `content` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
          `active` tinyint(4) NOT NULL,
          PRIMARY KEY (`id`),
          UNIQUE KEY `id` (`id`)
        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
    '
);

    
dbDelta('INSERT INTO `' SSB_TABLE '` VALUES ("", "Test", "This is a test", "1")');
}

function 
myp_uninstall () {
    global 
$wpdb;

    require_once 
ABSPATH 'wp-admin/includes/upgrade.php';

    
dbDelta('DROP TABLE `' MYP_TABLE '`');
}

Hopefully the SQL is self explanatory. The ludacris use of global variables and the "upgrade.php" include is Wordpress at its best. This is the way it's done in WP you just have to live with it.

That's enough for our install/uninstall hooks. Now let's create the function responsible for rendering the page we added to the admin.

controller.php

Whatever the myp_menu() function prints will be output on our plugin page in the admin. Instead of writing our HTML inside echo:s in our function we'll use a view for that. This function will only be responsible for getting or updating data and pass that data along to the view:

<?php
function myp_menu () {
    
add_menu_page(MYP_TITLE'My Plugin''administrator'MYP_SLUG'myp_main');
}

function 
myp_main () {
    
# Insert data
    
if (isset($_POST['myp_insert_data'])) {
        
MYP_Table::insert($_POST);
    }

    
# Delete data
    
if (isset($_POST['myp_delete_data'])) {
        
MYP_Table::delete($_POST['myp_id']);
    }

    
# Get data
    
$myp_data MYP_Table::get();

    
# Include view
    
include MYP_DOCROOT '/views/main.php';
}

As you can see if we POST certain data to this file it will insert or delete data in our table. But instead of putting all the SQL queries and DB logic in this file we're using our MYP_Table "model". This way we can insert, update and delete data in our table from anywhere, without repeating ourselves.

model.php

The model will handle all DB logic using WP's WPDB class:

<?php
class MYP_Table {
    public static function 
get () {
        global 
$wpdb;

        
$rows $wpdb->get_results('SELECT * FROM ' MYP_TABLEARRAY_A);

        return 
$rows;
    }

    public static function 
insert ($row) {
        global 
$wpdb;

        return 
$wpdb->insert(MYP_TABLE, array(
            
'title'        => stripslashes_deep($row['title']), 
            
'content'    => stripslashes_deep($row['content'])
        ));
    }

    public static function 
update ($id$row) {
        global 
$wpdb;

        
$update = array();

        if (isset(
$row['title'])) {
            
$update['title'] = stripslashes_deep($row['title']);
        }

        if (isset(
$row['content'])) {
            
$update['content'] = stripslashes_deep($row['content']);
        }

        if (isset(
$row['active'])) {
            
$update['active'] = $row['active'] ? '1' '0';
        }

        if (
count($update)) {
            return 
$wpdb->update(MYP_TABLE$update, array('id' => $id), array('%s''%s'), array('%d'));
        }

        return 
false;
    }

    public static function 
delete ($id) {
        global 
$wpdb;

        return 
$wpdb->query('DELETE FROM ' MYP_TABLE ' WHERE id = ' $wpdb->escape($id));
    }
}

Hopefully this code too should be quite clear. You have to use stripslashesdeep() on data from $POST (or GET, COOKIE etc) since WP 3 because they addslashes to all such variables early in the WP init code (WP shines again!). Obviously you'll need to change all this to match the table you want to use but you can use this as a template.

The only thing that's left is to create the view which will list all our data (with delete buttons) and allow users to add new data.

views/main.php

This is nothing more than standard HTML and some basic PHP loops:

<!-- the .wrap-class is required by WP to style the h2 like others in the admin (again, WP ftw!) -->
<section id="my-plugin" class="wrap">

    <!-- this ludacris display is how WP renders an icon -->
    <div id="icon-themes" class="icon32"><br></div>

    <h2>My Plugin</h2>

    <p>An intro text about my plugin</p>

    <h3>Add data</h3>

    <form method="post" action="">

        <p>
            <label>
                Title<br>
                <input type="text" name="title">
            </label>
        </p>

        <p>
            <label>
                Content<br>
                <textarea name="content" rows="10" cols="80"></textarea>
            </label>
        </p>

        <p>
            <input type="hidden" name="myp_insert_data" value="1">
            <input type="submit" value="Add data">
        </p>

    </form>

    <h3>Your data</h3>

    <?php if (count($myp_data)) : ?>
        <ul>
            <?php foreach ($myp_data as $data) : ?>
                <li>
                    <h4><?php echo $data['title'?></h4>

                    <?php echo $data['content'?>

                    <form method="post" action="" onsubmit="return confirm('Are you sure?')">
                        <p>
                            <input type="hidden" name="myp_delete_data" value="1">
                            <input type="hidden" name="myp_id" value="<?php echo $data['id'?>">
                            <input type="submit" value="Delete">
                        </p>
                    </form>
                </li>
            <?php endforeach ?>
        </ul>
    <?php else : ?>
        <p>You don't have any data yet.</p>
    <?php endif ?>

</section>

There you have it. Happy WPing.

Tags
Comments
No comments

Bookmark this Article

  • del.icio.us
  • Digg
  • Furl
  • Google
  • Technorati
  • Ma.gnolia
  • Blinklist
  • Blogmarks
  • Rojo
  • Stumbleupon
blog comments powered by Disqus

Random jQuery Plug-ins

  • Show Password

    This little plug inserts a "View password"-checkbox next to inputs of type password that allows the user to toggle the password's visibility. When the...

    Details

  • Center

    This little pluggy centers an element on the screen using either fixed or absolute positioning. Can be used to display messages, pop up images etc.

    Details

  • Numeric DL

    This tiny plug-in numbers definitions in a definition-list if there are more than one definition for a term. Can be useful for FAQs, actual lists of d...

    Details

More Plug-ins

Recent Comments

Powered by Disqus
Page cached. Loaded in: 0.0281 second(s).
Last DB change: 2012-04-02 11:06:05
Last file change: 2012-04-25 20:30:39
Cache created: 2012-05-18 03:42:02