Advertisement

Create a Custom WordPress Plugin From Scratch

by

This tutorial will describe the implementation of a Wordpress plugin starting from scratch. The plugin will connect to an external OSCommerce database and display random products on your Wordpress site. It also implements a configuration page for the Wordpress admin panel.


1. Introduction

Wordpress is gaining more and more popularity each day, not just as a blogging platform but also as a basic CMS, thus improving and extending its basic functionality becoming a day-to-day necessity for a lot of developers. Fortunately, the Wordpress developers have foreseen these needs and added the possibility of customizing the basic functionality by adding plugins. Basicaly, a Wordpress plugin is a (more or less) stand-alone piece of code that can be executed in different sections and stages within a page or site.

In today's tutorial we'll be talking about creating a Wordpress plugin that extracts and displays products from an external OSCommerce shop database. We will start by describing the file structure of a plugin and where it must be included in the Wordpress structure, then we'll be having a closer look at how to make our plugin visible for Wordpress and integrating it with actions run by its frame. Next, we'll be creating a configuration panel for our plugin to allow the site administrator to customize it to his/her needs. Once done, we'll be implementing the front-end functions themselves that will interact with the OSCommerce database and extract the required data. Finally, we'll be modifying the default template to display the extracted data in the sidebar. Excited? Let's get started!

Final Product

2. Getting started

While it would be possible to follow this tutorial by simply reading through it, I would recommend installing Wordpress on your computer and follow the tutorial implementing all the steps. For this, you'll need a local server running on your machine, like XAMPP for instance. Once you have it running, download and install Wordpress. You will find extensive information about the installation process and troubleshooting on the Wordpress site. For this tutorial we will be using release 2.7

Further on, you will need to set up an OSCommerce shop on your machine. You can download the latest release here: http://www.oscommerce.com/solutions/downloads


3. Files and folders

First, we'll need to create our basic files and folder structure. Wordpress stores its plugins in the wp-content/plugins/ folder. This is the place where we'll be adding our files as well. Normally, if your plugin is going to be very simple, you will include all the code inside one single PHP file. In this case, you will simply store the file in the folder mentioned above. However, in our case, we are going to use two files (one for the main plugin file and one for implementing the administration page) therefore we'll be putting all our files in a specific folder that we'll name oscommerce_importer. Go ahead and create this folder.


4. Creating the plugin file

Next, we must create our main plugin file. We'll name it oscommerce_importer.php. You can really name it whatever you want, it doesn't make any difference.

If you now open your Wordpress administration panel and navigate to the Plugins sections, your screen will look something like this:

Admin panel

As you can see, there is not the slightest sign of our new plugin. It's time to change that and tell Wordpress that our file is going to implement a plugin. The process to do so is very simple. All we need to do is add a plugin specific information header to our newly created file. This standard header will look like this:

	<?php 
		/*
		Plugin Name: OSCommerce Product Display
		Plugin URI: http://www.orangecreative.net
		Description: Plugin for displaying products from an OSCommerce shopping cart database
		Author: C. Lupu
		Version: 1.0
		Author URI: http://www.orangecreative.net
		*/
	?>

Simple enough, don't you think? You can, of course, change the content of this header to your liking but make sure you keep all the lines, otherwise Wordpress won't correctly recognize your plugin.

If you refresh your administration panel's plugin page, you'll now see our plugin listed along with the other ones.

Admin panel with deactivated plugin

See how all the relevant information like name, description, author, URL are extracted from the information header? This is why it is always important to correctly fill out this information. Let's go and activate our plugin by clicking Activate to the right of the plugin entry.


5. Working with action hooks

Our plugin is now shown in the administration panel so Wordpress is aware of it. However, it doesn't do anything as it contains nothing except of the information header. We are going to change this now.

Wordpress offers a great way to include your plugin code in different places all over the template, be it physical positions within a page or logical positions within the process of building up a page that is going to be displayed. First, we are going to have a closer look at the second category, the logical positions, better known as action hooks.

Action Hooks

You can view action hooks as callback function. Whenever Wordpress is executing a certain operation, like, for instance, displaying the page footer, it will allow your plugins to execute their own code that must be run at that exact moment.

For a better understanding, let's consider a generic plugin called my_plugin that implements a function called mp_footer() that has to be run whenever the page footer is displayed. We will tell Wordpress to call this function, at the moment of displaying the footer by using a special function called add_action():

		<php add_action('wp_footer', 'mp_footer'); ?>

The add_action() function takes the action hook name as its first parameter and the name of the function that must be executed, as a second parameter. This function call will be added to your main plugin file (the one containing the information header), usually, right under the function code that needs to be executed (mp_footer() in our example). You will find the full list of available action hooks in the Wordpress Codex.

We'll be using action hooks in the next chapter, where we are going to build the administration page for our plugin.


6. Creating the plugin's administration page

We'll start the implementation of the module by defining its configurable parameters and make these accessible to the site administrator. Let's see what these configuration bits would be:

  • Database settings
    • database host
    • database name
    • database user
    • database password
  • Store settings
    • store URL
    • folder for the product images

First, we need the database host, name, user and password in order to be able to connect to it and extract the needed data. Second, we need some general data about the store like its URL and the folder where the product images are stored. We need this information in order to be able to build the links because the paths contained in the database are all relative the previously mentioned product image folder.

Now that we know what we want to include in the configuration panel, it's time to implement it. We'll start by creating a new menu item to access the page and we'll place it inside the Settings menu. Remember our chat about the action hooks in the previous chapter? It's time to use this feature.

If you'll scroll over the list of action hooks, you'll see that Wordpress also provides one that gets called when the basic menu structure has been generated (admin_menu) so, this would be the optimal place to chime in and create our own menu item.

Now that we identified the action we are going to use, all we need is to define our own function that will be called when this action hook runs. We'll call our function oscimp_admin_actions() where oscimp_ stands for oscommerce importer and is used to create a possibly unique function name that will not get mismatched with any other function within Wordpress or any of its plugins. Let's see how the code will look like:

		function oscimp_admin_actions() {
    	
		}

		add_action('admin_menu', 'oscimp_admin_actions');

As you can see, we are creating our function oscimp_admin_actions() then associate it with the admin_menu action hook using the add_action() function. The next step would then be to add some code to our oscimp_admin_actions() function to actually create the new menu item.

As with most Wordpress things, adding a new menu item is also very easy. It all boils down to calling a single function. We would like to add our new menu item to the Settings menu so, in this case the function we need is add_options_page(). We'll add the code inside the oscimp_admin_actions() function.

		function oscimp_admin_actions() {
			add_options_page("OSCommerce Product Display", "OSCommerce Product Display", 1, "OSCommerce Product Display", "oscimp_admin");
		}

		add_action('admin_menu', 'oscimp_admin_actions');

If you refresh your admin page, you'll see the new menu item appear under Settings.

New menu item

Each existing menu has its own function to be used to add sub-menu items. For instance, if we would like to add our sub-menu item to the Tools menu instead of Settings, we would use the add_management_page() function instead of add_options_page(). You can find more details about the available options in the Adding Administration Menus section of the Wordpress Codex.

If we get back to the newly added code line, you'll probably notice the last parameter. This is actually a function name that will be called when the newly added menu item is clicked on and will be used to build the administration page of our plugin. Next, we'll be adding this new function. However, before proceeding we should stop for a moment and think about what will be implemented on this page.

We already defined the parameters we want to make configurable (database host, name, user, etc) so these will have to be included in a form in order to allow the user to send the data to the database. Once the form is defined, we'll need a bit of code that extracts the sent data from the form and saves it to the database. Last but not least, we need some code to extract the existing data from the database (if any) and pre-populate the form with these values. As you can see, there are quite a few things to do so, it might be a good idea to separate this functionality to its own file. We'll name the file oscommerce_import_admin.php. Now, go and create an empty file with the given name.

As already mentioned, we'll have to create the function that will display our plugin configuration page (we named this function oscimp_admin()). The code inside this function will be included from our newly created PHP file, oscommerce_import_admin.php

		function oscimp_admin() {
			include('oscommerce_import_admin.php');
		}
		
		function oscimp_admin_actions() {
			add_options_page("OSCommerce Product Display", "OSCommerce Product Display", 1, "OSCommerce Product Display", "oscimp_admin");
		}

		add_action('admin_menu', 'oscimp_admin_actions');

If you now click on the link under the Settings menu, you will be directed to an empty page. This is because our oscommerce_import_admin.phpfile is still empty.

Empty plugin configuration page

Next, we are going to create our form. For this we'll use the following code:

		<div class="wrap">
			<?php    echo "<h2>" . __( 'OSCommerce Product Display Options', 'oscimp_trdom' ) . "</h2>"; ?>
			
			<form name="oscimp_form" method="post" action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>">
				<input type="hidden" name="oscimp_hidden" value="Y">
				<?php    echo "<h4>" . __( 'OSCommerce Database Settings', 'oscimp_trdom' ) . "</h4>"; ?>
				<p><?php _e("Database host: " ); ?><input type="text" name="oscimp_dbhost" value="<?php echo $dbhost; ?>" size="20"><?php _e(" ex: localhost" ); ?></p>
				<p><?php _e("Database name: " ); ?><input type="text" name="oscimp_dbname" value="<?php echo $dbname; ?>" size="20"><?php _e(" ex: oscommerce_shop" ); ?></p>
				<p><?php _e("Database user: " ); ?><input type="text" name="oscimp_dbuser" value="<?php echo $dbuser; ?>" size="20"><?php _e(" ex: root" ); ?></p>
				<p><?php _e("Database password: " ); ?><input type="text" name="oscimp_dbpwd" value="<?php echo $dbpwd; ?>" size="20"><?php _e(" ex: secretpassword" ); ?></p>
				<hr />
				<?php    echo "<h4>" . __( 'OSCommerce Store Settings', 'oscimp_trdom' ) . "</h4>"; ?>
				<p><?php _e("Store URL: " ); ?><input type="text" name="oscimp_store_url" value="<?php echo $store_url; ?>" size="20"><?php _e(" ex: http://www.yourstore.com/" ); ?></p>
				<p><?php _e("Product image folder: " ); ?><input type="text" name="oscimp_prod_img_folder" value="<?php echo $prod_img_folder; ?>" size="20"><?php _e(" ex: http://www.yourstore.com/images/" ); ?></p>
				
			
				<p class="submit">
				<input type="submit" name="Submit" value="<?php _e('Update Options', 'oscimp_trdom' ) ?>" />
				</p>
			</form>
		</div>

Explaining the Code

If you are familiar with HTML and PHP, the code above will make some sense but, still, let us shortly walk through the lines.

  • We start by creating a div with the class wrap. This is a standard Wordpress class that will make our page look like any other page in the administration area.
  • The form will be using the POST method to send data back to itself. This means that the form data will be received by the same page so, we can add the database update code to the same file.
  • Next, there is a hidden field that will be used to determine whether the current page is displayed after the user has pressed the Update Options button or not. When the page receives the form data, the value of this field will be set to Y.
  • The next lines will create the form input fields for the database and store settings. As you can easily see, the value parameters are be set by the content of PHP variables. We'll talk about these soon.
  • Now if you refresh the admin page, you'll see our newly created form. However, pressing the Update Options button will have no effect other than refreshing the page and the form fields are empty.
Plugin configuration page with form

Handling the Data

Once the form is ready to go, we'll take care of the form data handling itself, updating the database and retrieving existing option values from the database. For this, we'll first have to decide whether the current page is displayed after the user has pressed the Update Options button or not. We'll do this by analyzing the value of the form's hidden field, oscimp_hidden. The following code will be added at the very beginning of our oscommerce_import_admin.php file, before the code for displaying the form:

	<?php 
		if($_POST['oscimp_hidden'] == 'Y') {
			//Form data sent
		} else {
			//Normal page display
		}
	?>

Next, we'll be handling the form data and update the plugin options in the database accordingly. For this we'll be using the update_option() function. The first parameter of this function is the option name which will be sued later to uniquely identify this option and its value. The second parameter is the value to be assigned.

	<?php 
		if($_POST['oscimp_hidden'] == 'Y') {
			//Form data sent
			$dbhost = $_POST['oscimp_dbhost'];
			update_option('oscimp_dbhost', $dbhost);
			
			$dbname = $_POST['oscimp_dbname'];
			update_option('oscimp_dbname', $dbname);
			
			$dbuser = $_POST['oscimp_dbuser'];
			update_option('oscimp_dbuser', $dbuser);
			
			$dbpwd = $_POST['oscimp_dbpwd'];
			update_option('oscimp_dbpwd', $dbpwd);
	
			$prod_img_folder = $_POST['oscimp_prod_img_folder'];
			update_option('oscimp_prod_img_folder', $prod_img_folder);
	
			$store_url = $_POST['oscimp_store_url'];
			update_option('oscimp_store_url', $store_url);
			?>
			<div class="updated"><p><strong><?php _e('Options saved.' ); ?></strong></p></div>
			<?php
		} else {
			//Normal page display
		}
	?>

The code above if pretty much self-explanatory but please note that here we are using the PHP variables we have previously mentioned while building the form. These variables will be updated with the current form data values and will be displayed in the form itself. Go, check it out! Refresh the configuration page and enter your OSCommerce database settings as well as your store parameters then press Update Options.

If everything was implemented like described above, you'll see an Options saved success message and the form fields will contain the data you have just entered.

Plugin configuration page with success message

Last but not least, we'll need to pre-populate the form with the database data when the user opens the configuration page. For this, we'll be using the get_option() function which retrieves the specified option from the database.

	<?php 
		if($_POST['oscimp_hidden'] == 'Y') {
			//Form data sent
			$dbhost = $_POST['oscimp_dbhost'];
			update_option('oscimp_dbhost', $dbhost);
			
			$dbname = $_POST['oscimp_dbname'];
			update_option('oscimp_dbname', $dbname);
			
			$dbuser = $_POST['oscimp_dbuser'];
			update_option('oscimp_dbuser', $dbuser);
			
			$dbpwd = $_POST['oscimp_dbpwd'];
			update_option('oscimp_dbpwd', $dbpwd);
	
			$prod_img_folder = $_POST['oscimp_prod_img_folder'];
			update_option('oscimp_prod_img_folder', $prod_img_folder);
	
			$store_url = $_POST['oscimp_store_url'];
			update_option('oscimp_store_url', $store_url);
			?>
			<div class="updated"><p><strong><?php _e('Options saved.' ); ?></strong></p></div>
			<?php
		} else {
			//Normal page display
			$dbhost = get_option('oscimp_dbhost');
			$dbname = get_option('oscimp_dbname');
			$dbuser = get_option('oscimp_dbuser');
			$dbpwd = get_option('oscimp_dbpwd');
			$prod_img_folder = get_option('oscimp_prod_img_folder');
			$store_url = get_option('oscimp_store_url');
		}
	?>

You can test the code above by simply navigating to another page within the admin area and then retuning to this page by clicking the OSCommerce Product Display sub-menu item in the Setting menu. If everything goes well, you will see the form with all the fields pre-populated with the data you have entered.

Plugin configuration page with pre-populated form

With this last piece of code, we have finished implementing the plugin's configuration page so, let's review what has been done in this chapter:

  • we defined what parameters need to be configured by the site administrator
  • we added an action hook for when the menu is displayed in the administration panel to help us add a new sub-menu item for our plugin
  • we have added a new sub-menu item to the Settings menu that will link to our plugin's configuration page
  • we have defined a function that will build the plugin's configuration page and separated its code in a second PHP file
  • we have built the form containing the user inputs for each of the configurable data bits
  • we have built the database update function
  • we have built a function that will pre-populate the form with the option values stored in the database

7. Creating the user function

Well, everything went quite fine so far but our plugin is yet unusable because we haven't implemented the part that will actually allow us to display the products in the front-end.

In order to allow our users to display the products in the front-end, we'll need to declare a function that can be called from the template's PHP code and which will return the HTML code to be inserted in the template. We are going to name this function oscimp_getproducts() and accept the number of products to be displayed as a function parameter. The function itself will be implemented in our plugin's main file, oscommerce_import.php

		function oscimp_getproducts($product_cnt=1) {
		
		}

As you can see, we are assigning a default value to our function parameter thus allowing our users to call the function both with and without a parameter. If the function is called with a parameter, like oscimp_getproducts(3), it will display three products. If the function is called without a parameter, like oscimp_getproducts(), it will only display one product.

First thing in our function would be to establish a connection to the OSCommerce database. Thanks to our plugin configuration page, we now have all the information we need: database host, name, user and password. We'll be using the built-in wpdb class to create a new database object.

		function oscimp_getproducts($product_cnt=1) {
			//Connect to the OSCommerce database
			$oscommercedb = new wpdb(get_option('oscimp_dbuser'),get_option('oscimp_dbpwd'), get_option('oscimp_dbname'), get_option('oscimp_dbhost'));
		}

Once this is done, we declare a variable that will contain the HTML code and start quering the OSCommerce database for each of the specified number of products. The code below merely implements this query loop and can be further-on improved by checking for duplicates, for instance, but this is not the subject of this tutorial so, we'll keep it simple for the sake of readability.

		function oscimp_getproducts($product_cnt=1) {
			//Connect to the OSCommerce database
			$oscommercedb = new wpdb(get_option('oscimp_dbuser'),get_option('oscimp_dbpwd'), get_option('oscimp_dbname'), get_option('oscimp_dbhost'));

			$retval = '';
			for ($i=0; $i<$product_cnt; $i++) {
				//Get a random product
				$product_count = 0;
				while ($product_count == 0) {
					$product_id = rand(0,30);
					$product_count = $oscommercedb->get_var("SELECT COUNT(*) FROM products WHERE products_id=$product_id AND products_status=1");
				}
				
				//Get product image, name and URL
				$product_image = $oscommercedb->get_var("SELECT products_image FROM products WHERE products_id=$product_id");
				$product_name = $oscommercedb->get_var("SELECT products_name FROM products_description WHERE products_id=$product_id");
				$store_url = get_option('oscimp_store_url');
				$image_folder = get_option('oscimp_prod_img_folder');
		
				//Build the HTML code
				$retval .= '<div class="oscimp_product">';
				$retval .= '<a href="'. $store_url . 'product_info.php?products_id=' . $product_id . '"><img src="' . $image_folder . $product_image . '" /></a><br />';
				$retval .= '<a href="'. $store_url . 'product_info.php?products_id=' . $product_id . '">' . $product_name . '</a>';
				$retval .= '</div>';
	
			}
			return $retval;
		}

Once this is done, all we have to do is insert the oscimp_getproducts() function call to the template. We'll be displaying three products at the bottom of the sidebar so, we are going to modify the sidebar.php file of our template, inserting the following code right below the list item containing the meta links:

		<li><?php echo oscimp_getproducts(3); ?></li>

If you refresh your front-end page now, you'll see the three random products displayed at the bottom of the sidebar.

Frontpage with random products

With this last piece of code, we have finished implementing the front-end function as well.


8. Conclusion

We have now implemented a Wordpress plugin from scratch. Let's summarize what has been done:

  • we defined the way we store our plugin files
  • we defined the information header in order to make our plugin visible for Wordpress
  • we talked about the action hooks and the way these are used
  • we defined what parameters need to be configured by the site administrator
  • we added an action hook for when the menu is displayed in the administration panel to help us add a new sub-menu item for our plugin
  • we have added a new sub-menu item to the Settings menu that will link to our plugin's configuration page
  • we have defined a function that will build the plugin's configuration page and separated its code in a second PHP file
  • we have built the form containing the user inputs for each of the configurable data bits
  • we have built the database update function
  • we have built a function that will pre-populate the form with the option values stored in the database
  • we have built our user function for use in the template
  • we connected to the OSCommerce database
  • we queried the OSCommerce database extracting the product ID, image and name
  • we have built the HTML code for displaying the extracted data
  • we have included the user function to the template sidebar

I hope this tutorial gave you all the information you need to build a Wordpress plugin from the beginning. Please feel free to post your comments below.

Thanks for reading! :)

  • Subscribe to the NETTUTS RSS Feed for more daily web development tuts and articles.