This is an updated version of my “How to create WordPress Plugin from a scratch” tutorial which i published originally in August 2007 … yikes, that is over 10 years ago. The blog on which i originally posted this article will soon be removed so i am moving it here as it is still relevant.

WordPress blogs are getting more popular than ever, there are literally hundreds of new weblogs popping up every day. However WordPress is not a new software, so I think it is about time to learn how to create decent plugins for it, and once you learn how to write plugins you will discover that this is not only fun but can be very profitable as well.

The Plugin Idea

I want to show you how to write very simple WordPress (WP) plugin. General purpose behind every plugin is to enhance WP functionality in some way or another, so I started to think: what kind of plugin will contain no more then 100 lines of code, (so someone who is new to WordPress API won’t get lost in tons of code) and will be somewhat useful at the same time.

I decided that together we will write a plugin which will count search engine bots visits.

Let me explain shortly what I mean by “search engine bots”, every search engine has some kind of bot that is responsible for indexing pages on the Internet, and as you probably already know there is no other way of indexing pages, then visiting them via HTTP or HTTPS protocol. Basically, that makes all bots virtual Internet users, the one thing that makes them different from real Web users is the fact that bots use other browsers (or rather browser signatures in HTTP_USER_AGENT header) than us.

For example, Googlebot uses a web browser that is compatible with Firefox, but its name is actually “googlebot” and we can check that with $_SERVER[‘HTTP_USER_AGENT’] variable in PHP.

Knowing this info we will want to design our plugin in a way that, every time WordPress page is loaded our plugin will check this variable to find out if person which is currently viewing our site is a bot or a real person. If bot then the script will increase bot visits count variable (which we will store in database).

That’s it. Nice little plugin. I know it may be very easy for you to write such script, but our goal is actually not the script itself. Our goal is to understand how WordPress plugin API works, this is what is important not the code.

If I convinced you to read further this article then great, I am confident you will enjoy it.

Getting Started With WordPress Plugin Development

If you do not have WP installed on your localhost or yet, then go get it at www.wordpress.org do not make a common mistake of thinking that you can understand everything by just reading this text, you will actually need to do the work.

The first thing we need to know is where to put our plugin, WordPress programmers selected specific folder for all plugins, if you start browsing will start browsing WordPress directories you will find out by yourself that all plugins located in: /wp-content/plugins/ folder.

Note that it is not necessary to create a new folder for your plugin, you can put your files straight into plugin directory, but I think it is good to do so only if your plugin is just a single PHP file.

We will use two files so let’s create directory and name it bot, so the path to our plugin will be wp-content/plugins/bot/.

You may be thinking if there will be more than one file in a directory how will WordPress know which file to use, which file should be started first?

This is a great question, with a very simple answer: files which are treated by WP as main plugin files are those with specific info called: standard plugin information header. You won’t make your plugin work without this information, mainly because, WordPress will have no idea that your plugin exists, and it will not be listed at Plugin Management page, and you won’t be able to activate it.

My information header looks like this:

/*
Plugin Name: Bot Counter
Plugin URI: http://wpadverts.com/bot-plugin/
Description: Plugin is counting bots visits
Author: Greg Winiarski
Version: 1.0
Author URI: http://wpadverts.com/
*/

You are of course free to edit this information but do not remove any line, they all need to stay there. If you wish to you can copy and paste this info to your file and save it as “bots.php” in our “bot” directory, it should look like this:

/wp-content/plugins/bot/bots.php

Now you can go to the wp-admin / Plugins page, browse available plugins and you will find out that list of plugins already contains your plugin, moreover, it looks like it is ready to be activated.

We know it actually does nothing, so we need to “teach” our plugin what to do and when. These is very simple thanks to “Plugin Hooks”.

Let me explain it. You can think of every Plugin Hook as an action, and in WP action can almost anything: publishing post, editing comment, loading header and so on. However all actions are predefined by WordPress programmers, so you can’t write whatever you want. For more info on this check out http://codex.wordpress.org/Plugin_API/Action_Reference for a complete list of actions.

When we finally choose an action that suits as best, we need to assign a function to it, we do this by using add_action($predefined_plugin_hook, $our_function_name); command. Predefined plugin hook is one of the actions, while “function name” is a function which we wrote, or which we will write in our case.

Plugin Installation and Activation

Enough talking it is time to write some code, let’s start with function, which will be responsible for creating an additional table in our database and populating it with two records. In this table, we will keep information about different bots and their visits number.

function bot_install()
{
    global $wpdb;
    $table = $wpdb->prefix."bot_counter";
    $structure = "CREATE TABLE $table (
        id INT(9) NOT NULL AUTO_INCREMENT,
        bot_name VARCHAR(80) NOT NULL,
        bot_mark VARCHAR(20) NOT NULL,
        bot_visits INT(9) DEFAULT 0,
	UNIQUE KEY id (id)
    );";
    $wpdb->query($structure);
 
    // Populate table
    $wpdb->query("INSERT INTO $table(bot_name, bot_mark)
        VALUES('Google Bot', 'googlebot')");
    $wpdb->query("INSERT INTO $table(bot_name, bot_mark)
        VALUES('Yahoo Slurp', 'yahoo')");
}

I admit, the whole script can be written without using MySQL and it would be much better solution than creating additional table like we did, but again it is not about the script it is about learning WordPress API, and I thought: if you will want to write plugin by yourself later then you will be probably using MySQL, so I decided to show you how WP want us to do it.

About our function, it names can be whatever you want I choose bot_install, because this is what this function really does (installs our plugin), but you can name func1 as well, it is not how you name it, but rather how you assign it to certain Plugin Hook, however it is good practice to avoid function names that were already used by WordPress programmers, then try keeping your function names unique.

Earlier I talked about assigning a function to a certain action, so how to do it and which action choose?

Obviously, we want action that will run once, possibly right after activating our plugin, we do not want to create new tables over and over again, so our best shot will be “activate” Plugin Hook, but be careful this one is a bit tricky.

All of WordPress actions are predefined, all except this one. Look at the code:

add_action('activate_bot/bots.php', 'bot_install');

Like was said before the first argument is Plugin Hook, it is let’s call it half predefined, what I mean by this is simply that first part ‘activate_’ is constant, but the second part of the argument is a path to the script which contains activate the function. We keep our install function in the same file as the rest of functions so we need to point to file we are editing right now.

Also, note that you need to use a relative path, WordPress knows that install file must be located somewhere in wp-content/plugins/ directory, so we only need to show him which file in this directory it really is.

The second argument is our function name, nothing more nothing less.

Inside our bot_insall function we use global variable $wpdb, it is object responsible for communication with the database, of course, we still can use old-fashioned mysql_query() instead of $wpdb->query(), but let’s make these script like WordPress team wanted us to make it look.

I believe I do not have to comment on the rest of the code there are only three MySQL queries so I am confident you easily understand what these scripts do.

If we activate our plugin now, bot_install function will start, the additional table will be created and some data will be added, finally, our plugin can actually do something, besides being visible in the admin area.

Using Actions and Filters

Now we will create a function which will be responsible for counting bots visits:

function bot()
{
    global $wpdb;
    $browser_name = $_SERVER['HTTP_USER_AGENT'];
    $bots = $wpdb->get_results("SELECT * FROM ".
        $wpdb->prefix."bot_counter");
 
    foreach($bots as $bot)
    {
        if(eregi($bot->bot_mark, $browser_name))
        {
            $wpdb->query("UPDATE ".$wp->prefix."bot_counter 
                SET bot_visits = bot_visits+1 WHERE id = ".$bot->id);
 
            break;
        }
    }
}

This is very simple as well, first, we make $wpdb variable “visible” for our function by making it global. Then we select all data from the table we created earlier and we loop thru results by using foreach loop. When it turns out that $browser_name, contains $bot->bot_mark value, the script makes a MySQL query which increases bot_visits field value by one, then we brake foreach because it is impossible to have two bots using one browser.

When I first wrote these function I assigned it to wp-head Plugin Hook, it means that WordPress will start this function when header is loading, but then I decided to reassign it to wp-footer action because this function will only make simple operations in our database without even showing results to visitor, so I think you will agree with me on this one, that it is a good idea to send page to client first and then call this function. It will save some time to our visitor which is always great

add_action('wp_footer', 'bot');

Almost everything is ready, a new table can be created by our plugin, bots visits are counted now we want to see how many bots visited our blog, but we want these data to be visible only to blog admin and displayed in the administration area.

Creating a New Section In wp-admin Panel

Sounds like a lot of work? Actually, it is NOT. WordPress programmers created a set of Plugin Hooks that will allow us to add pages to the wp-admin area, these new pages will be automatically shown in admin panel in an appropriate category selected by us.

First, we need to write a function which will create the whole layout for our new page at admin site, then we need to use add_option_page(…) function, but we have to add it to some kind of let’s call it “container”. What is the container? Basically, the container is another function which has got set of add_option_page(…) commands within it.

Note that we are not limited to creating only one additional admin page, by using container we are able to create many pages in different categories, for example, one in “users” category and another in “options” category. However, we are writing quite a small plugin so we will create only one additional page.

function bot_menu()
{
    global $wpdb;
    include 'bot-admin.php';
}
 
function bot_admin_actions()
{
    add_options_page("Bot Counter", "Bot Counter", 1,
"Bot-Counter", "bot_menu");
}
 
add_action('admin_menu', 'bot_admin_actions');

Look at bot_menu function it includes bot-admin.php file which currently does not exists, but this is not important for now, we will create it a bit later.

More interesting then bot_menu is bot_admin_actions function – this is our container.

Whole code works like that: first add_action function is run with Plugin Hook admin_menu, so WordPress knows that something will be added to admin menu. What will be added? He has to check it by executing bot_admin_actions function, second parameter of add_action, bot_admin_function tells WordPress that he has to add to options page (add_option_page) new menu item named “Bot Counter” and when user will click this menu item then WordPress will have to get code for it from bot_menu function, simple isn’t it?

But in order to make it work we have to create bot-admin.php file, because bot_menu uses it, so let’s create this file and put some code into it:

<?php query("UPDATE ".$wpdb->prefix."bot_counter SET bot_visits = 0");?>
<div id="message" class="updated fade">
 
Bot Counter Stats <strong>Reseted</strong>.</div>
<div class="wrap">
<h2>Bot Counter Admin</h2>
<?php
get_results("SELECT * FROM ".$wpdb->prefix."bot_counter");
foreach($results as $result)
{
    echo $result->bot_name." : ";
    echo $result->bot_visits."";
}
?>
 
<a href="?page=<?php echo $_GET['page']; ?>&bot-counter=reset">
    Reset Stats
</a>
</div>

Not much to talk about here, this script shows us how many times particular bot visited our website and at the end is a link which allows us to reset stats. Notice that we are using <div id=”message” class=”updated fade”>…</div> and <div class=”wrap”>…</div> These will make our admin page look similar to other admin pages.

Also take a look at our <a> tag, we can submit forms and click URLs within our admin page, but we need to remember to always send ‘page’ parameter via GET (page=<?php echo $_GET[‘page’]; ?>), otherwise WordPress won’t display our admin page.

For more information on adding administration menu visit http://codex.wordpress.org/Adding_Administration_Menus

That is pretty much it. The last thing we can do is to display bots visits count to people who are visiting our site, but it requires to edit templates if we want to display bots stats in a certain position like a sidebar for example.

The best way to embed our stats into the template is to write (in bots.php file) function which will display these stats, then all you need to add in WordPress template is or whatever you named your function.

Conclusion

My goal was to show you as much WordPress Plugins API features as possible, however, if you didn’t found here answers to questions you had before reading this article then my best advice for you is to go to www.wordpress.org and read WP API documentation. I am confident that with the knowledge you gained by reading these text you will have no problems with finding solutions and answers to all questions you have.