Creating WordPress Plugins Step by Step

Last Updated May 31, 2023 by . First Published in 2007.

3,665 words, estimated reading time 14 minutes.

Creating WordPress Plugins Step by Step

Ready to take your WordPress skills to the next level? This guide will walk you through creating WordPress plugins, step by step.

If you're a WordPress user looking to expand your skills and customize your website even further, creating your own plugins can be a great option. This guide will take you through the process of creating a plugin from start to finish, including planning, coding, testing, and publishing. Whether you're a beginner or an experienced developer, you'll find valuable tips and resources to help you create high-quality plugins for your WordPress site.

What Are WordPress Plugins?

Before diving into creating your own WordPress plugins, it's important to understand the basics of what a plugin is and how it works. Essentially, a plugin is a piece of code that adds new functionality to your WordPress site. Plugins can be used to add features like contact forms, social media sharing buttons, or custom post types. They can also modify existing functionality, such as changing the appearance of your site or optimizing it for search engines. Understanding the basics of plugins will help you create effective and useful plugins for your site.

How To Create a Simple WordPress Plugin

Before you start creating your WordPress plugin, you'll need to set up your development environment. This includes installing a local server environment like XAMPP or MAMP, which will allow you to run WordPress on your own computer. You'll also need a code editor like Sublime Text or Visual Studio Code, which will allow you to write and edit your plugin code. Once you have your development environment set up, you can start creating your plugin!

What Will Your WordPress Plugin Do?

The first step is to identify the problem you want to solve or the functionality you want to add to WordPress. Once you have a clear idea of what you want to achieve, you can start writing your plugin code. It's important to follow best practices and WordPress coding standards to ensure your plugin is secure, efficient, and compatible with other plugins and themes. Don't forget to test your plugin thoroughly before releasing it to the public!

Start Coding Your WordPress Plugin

Once you have identified the problem you want to solve or the functionality you want to add to WordPress, it's time to start coding. This can be a challenging process, but there are many resources available to help you along the way. WordPress has a comprehensive documentation section that covers everything from basic plugin development to advanced topics like custom post types and taxonomies. You can also find tutorials and code snippets online that can help you get started. Remember to test your plugin thoroughly and follow best practices to ensure it is secure, efficient, and compatible with other plugins and themes.

Testing and Debugging WordPress Plugins

Testing and debugging your plugin is a crucial step in the plugin development process. Before releasing your plugin to the public, you should test it thoroughly to ensure that it works as intended and doesn't cause any conflicts with other plugins or themes. You can use tools like the WordPress Debugging Plugin or the WP_DEBUG constant to help you identify and fix any errors or issues in your code. It's also a good idea to test your plugin on different devices and browsers to ensure that it works well across different platforms. Once you have thoroughly tested your plugin, you can release it to the public and continue to monitor and update it as needed.

Publishing WordPress Plugins

Once you are happy with your plugin and if you want to publish it to the WordPress Plugin Directory you must first read through the plugin guidelines  which basically says to keep your code human-readable, comment your code and prefer WordPress functions instead of PHP functions when possible.

WordPress uses Subversion SVN for source control. Before you get access to the repository you must first submit your plugin for manual approval . You should also include a readme.txt which has all the details about the plugin, author, URL, description and so on. You can download a readme.txt template  on the WordPress site.

You can add banners, icons and screenshots which will display on the plugin homepage. These are specially named files which live in the assets directory within your plugin directory.

  • For banners create a JPG or PNG called banner-772×250.(jpg|png) for the regular banner and banner-1544×500.(jpg|png) for retina quality.
  • Icons should be named icon-128x128.(png|jpg) for normal display and icon-256×256.(jpg|png) for retina.
  • Screenshots are named sequentially starting with screenshot-1.(png|jpg)

How To Create New WordPress Shortcodes

WordPress Shortcodes are a great way to add dynamic content to posts, even for the non-techy. They can be as simple or complex as you need. I'm going to start with a very basic WordPress shortcode, one that is very easy to implement. It will display a YouTube video in the post, inline.

This code should go in your theme functions.php or plugin file depending on if you are wanting the shortcode in the theme you are developing.

Do not alter the functions.php of themes or plugins you downloaded, they will get overridden by automatic updates. Do not modify core files as these will also be overwritten and you will lose any changes.

What are WordPress Shortcodes?

As a security precaution, running PHP inside WordPress content is forbidden. To allow dynamic content, Shortcodes were introduced in WordPress 2.5. Shortcodes are macros that can be used to perform dynamic interactions with the content. i.e. creating a gallery from images attached to the post or rendering a video.

Built-in WordPress Shortcodes

There are several shortcodes that WordPress provides already. You may have already seen and used them.

  1. [caption] - allows you to wrap captions around content
  2. [gallery] - allows you to show image galleries
  3. [audio] - allows you to embed and play audio files
  4. [video] - allows you to embed and play video files
  5. [playlist] - allows you to display a collection of audio or video files
  6. [embed] - allows you to wrap embedded items

How to Create Custom WordPress Shortcodes

Shortcodes are added to WordPress by adding an action to the list of shortcodes. This is done using the add_shortcode function in much the same way as you add an action to a hook.

Let's first create the function that will handle our shortcode.

function youtube_shortcode($atts, $content = null)
  extract(shortcode_atts(array('id' => ''), $atts));
  return '<iframe width="640" height="360" src="'.$id.'?feature=player_detailpage" frameborder="0" allowfullscreen></iframe>';

This function is going to create a string that contains the embedded YouTube code (taken from the YouTube site) and it will replace the video ID with the PHP variable $id. The $id variable gets its value from the shortcode attribute id. Shortcodes must always return the value, not echo it.

The shortcode function takes in two parameters. $atts will hold the attributes passed in, for example id and $content contains any text that is between the start and end tags of the shortcode. In this first example, the shortcode has no end tag.

The extract method and the shortcode_atts function will convert the attribute values into PHP variables. In this example, it will create a $id variable which you can use to access the values passed into the id attribute. The array passed into shortcode_atts holds the default values.

      'id' => '123'
      'title' => 'Test Plugin'

Is a much neater way of writing

if (isset($atts['id']) $id = $atts['id'] else $id = '123');
if (isset($atts['title']) $title = $atts['title'] else $title = 'Test Plugin');

The return statement is going to return an HTML string containing the full markup that the shortcode will be replaced by. In this examples [youtube id=""] will be replaced by youtube iframe.

The final step is to register the new shortcode so WordPress knows what to do when it sees it in a post. To do this we call the add_shortcode function, specifying the parameters that the shortcode we want to create is called "youtube" and the function that will handle the result is "youtube_shortcode".

add_shortcode('youtube', 'youtube_shortcode');

And that is about it for this basic example. I said it easy! To use this shortcode once it is added to the file, simply create a post (or edit an existing one) and add the shortcode to the content:

&#91;youtube id="{INSERT_ID_HERE}"]

You can get the YouTube video ID from the URL in the address bar. It will look something like this:

How to Add YouTube Videos to Wordpress
How to Add YouTube Videos to Wordpress

When you view the post, this code will be replaced with the HTML in the youtube_shortcode function and you will hopefully see the YouTube video.

You can also add buttons to the shortcode in the editor to make it even easier. There is a great tutorial on WP Tuts+ , so I don't think I need to explain it again here.

Using Custom Fields in Plugins and Themes

One of the many features of WordPress you may have noticed whilst writing posts is the Custom Fields section that appears at the bottom of the new post screen. This is a very powerful feature allowing additional information to be attached to a post. WordPress Custom Fields is a method of storing information about a post, but not contained within the post itself (similar to categories and date stamps).

Wordpress Custom Fields
Wordpress Custom Fields

Custom fields have a name and a value. WordPress remembers previously used field names and can be selected in the drop-down list. You can also create a new field by typing the name into the text box provided. The "value" text area can contain any data you wish, from a single number or string to a whole paragraph or comma-separated list.

In this article, I will show you how I use custom fields on my blog to show image thumbnails on some posts.

Create or Modify an Existing Post

Create a new post as you would normally, or modify an existing post, scroll down to the bottom and find "Custom Fields". You may have to click on the + symbol to expand the full contents.

Create a new field called "pictures", and enter a comma-separated list of URLs. For this example, I will use "/images/icons/icon_lonewolf.jpg,/images/icons/icon_question.jpg". You will need to change these to images that exist on your website.

When you click on Add your new field will appear above and flash yellow. If it flashes red then there was some problem and an error will be displayed.

Save your post and view it, notice there is no mention of the custom field. That is because we need to tell WordPress what to do with the data before it is shown.

Modify your Plugin Theme

Now you need to modify your theme to process your custom fields.

In index.php (or any other file containing "the loop") we will retrieve the custom field and process it. I will use the default themes index.php as the example here.

"The Loop" in the default theme.

  while (have_posts()) : the_post(); ?>
    <div class="post" id="post-<?php the_ID(); ?>">
      <h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
      <small><?php the_time('F jS, Y') ?> <!-- by <?php the_author() ?> --></small><br/><br/>
      <div class="entry">  
        <?php the_content('Read the rest of this entry >'); ?>
      <p class="postmetadata"><?php the_tags('Tags: ', ', ', '
'); ?> Posted in <?php the_category(', ') ?> | <?php edit_post_link('Edit', '', ' | '); ?>  <?php comments_popup_link('No Comments', '1 Comment', '% Comments'); ?>

  <?php endwhile; 

Let's get the value of our field. Before the div containing the "rest of the entry" tag, add these lines:

      $pictures = get_post_meta($post->ID, "pictures", true);
      echo $pictures;

The first line will get the custom field called "pictures" for the current post as indicated by $post->ID You can change this id to any post number to get the custom field for that post. The second line simply outputs it to the screen. When you view your post now you should get back the value of your custom field you entered previously.

Now we need to do something useful with this custom field so let's add a few more lines to parse and output the images. Your finished script should look like this:

      $pictures = get_post_meta($post->ID, "pictures", true);
      //check that we have a custom field
      if ($pictures != "")
        // Separate our comma-separated list into an array
        $pictures = explode(",", $pictures);
        //loop through our new array
        foreach ($pictures as $picture)
          echo "<img src='" . $picture . "' />";

After retrieving the custom field, we need to check that we have some data otherwise posts without images will have script errors in them. Next, we use the explode function to split out a comma-separated list into an array of strings, then loop through all the array items in a foreach loop, outputting the picture to the browser in an img tag.

If all goes well you will now have two images in your post.

Clickable Thumbnails From WordPress Uploads

WordPress provides the ability to upload images and automatically generate thumbnails. There is a section where you can insert thumbnails or links into the body of the post. One of my clients did not wish to have the image code within the body but in a separate section. He also wanted to prevent images from showing in the RSS feeds. WordPress does not know what uploaded files are associated with a particular post, and you may wish to include attachments from another post, so the above method has been used and modified so that a given set of uploaded images can be displayed per post.

This code snippet assumes that images are uploaded using the standard file uploader.

When a file is uploaded, click on the edit link and you will see the URL listed in a read-only text box. We are interested in the last part of the URL, ignoring the static, so copy everything after uploads (e.g. "2008/01/my-sample-image.jpg")

Copy and paste this value from the URL field into a custom field called "pictures", if there is more than one image you wish to show, repeat the steps for each image and separate them with a comma. They should all be contained within the one-picture custom field.

You can also use the "browse all" tab to go through all uploaded images from the past. The code within the WordPress theme template should go like this within the loop:

  $pictures = get_post_meta($post->ID, "picture", true);
  if ($pictures != "")
    $pictures = explode(",", $pictures);
    foreach ($pictures as $picture)
      // convert image.jpg to image.thumbnail.jpg
      $thumbnail = str_replace(".jpg", ".thumbnail.jpg", $picture);
      // output a thumbnail linked to the large image 
      echo '<a href="/content/uploads/'.$thumbnail.'"><img src="'.$thumbnail.'"></a>';

Obviously, this code needs to be changed for your needs/template and the image tag needs width, height and alt tags to be W3C compliant but this should give you a head start.

How It Works on my Blog

Using a recent blog post about our new kitten as an example, the custom field holds the values:


The images and thumbnails have been uploaded onto my server's file system and the photograph details are stored within a database. The custom fields are then parsed by the following code:

    $images = get_post_meta($post->ID, "pictures", true);
    $count = 0;
    if (strlen($images) >0)
      echo "&amp;nbsp;

<span style="padding-left:8px; font-size:80%">Attached Thumbnails:</span><br/><div class="box">";
      $images = explode(",",$images);
      foreach($images as $image)
        $query = "SELECT * FROM XXXXXXXX WHERE XXXXXXXX = '$image' LIMIT 0,1";
        $result = executeQuery($query,"XXXXXXXXXX");
        $title = $nt[photoTitle];
        $thumb = $nt[thumbnail];
        echo '<a href="/pictures/'.$image.'/"><img src="/' . $thumb . '" alt="' . $title . '" title="' . $title . '" class="thumbnail" /></a>';
        // 4 images per row
        if ($count == 4)
          echo "<br/>";
          $count = 0;
      echo "</div>";

I am using a custom executeQuery function which performs some validation, error trapping and reporting, but it can easily be changed for $wpdb database calls. I have also obscured the database and table names for security reasons.

Creating Options/Settings/Configuration Pages for a Plugin

Creating WordPress Sidebar Widgets

WordPress Sidebar Widgets are a form of a plugin that can be used to add functionality and content to your website pages, usually in a sidebar. The WordPress API greatly simplifies the creation of WordPress widgets, and all widgets using the API benefit from settings pages, multiple instances and more.

At the most simplistic level, WordPress widgets now take the form of a Class (object orientation) which contains 4 functions. The basic structure of a WordPress widget is shown below.

class Sample_Widget extends WP_Widget 
  function Sample_Widget() { }
  function form($instance) { }
  function update($new_instance, $old_instance) { }
  function widget($args, $instance) { }
add_action( 'widgets_init', create_function('', 'return register_widget("Sample_Widget");') );

In this example, we are going to create a WordPress widget called "Sample_Widget" and tell PHP that it is going to extend (inherit from) the WP_Widget class. It is the WP_Widget class which makes your widget function, has settings and allows multiple instances so you don't have to.

You will need to rename every occurrence of "Sample_Widget" with the name of your widget.

The first method, Sample_Widget() in the example, is the class constructor which contains the code that is run every time the widget is loaded - either when activated, used on a page, updated and so on.

The second method, form(), contains the settings page on the Wordpress Widgets administration screen (Appearance -> Widgets). This method is always called form and never changes. Within this function, you add all the controls that will appear when the widget options are expanded. See below for an example.

The third method, update(), is called when the user clicks on "save" from the settings page on the Widgets administration screen. This automatically handles saving to the database of options. You can use this function to validate information before being saved. See the example below for basic operation.

Finally the widget() function contains the code that will be rendered to the sidebar when the widget is added. This is what your visitors will see when viewing your page.

Let's have a look at a very simple example "Hello World" widget.

Custom WordPress Widgets Example

This example shows how to create a widget which outputs "Hello World" to the sidebar. It also demonstrates adding a user-configurable title setting to the widget in the administration panel, saving and retrieving user settings and displaying the widget.

It shares the same structure as the basic example above but has been expanded to include the entire widget code. Simply copy and paste this into a text file called SampleWidget.php and upload it to your plugins folder. You can then activate and play around with it.

Plugin Name: Sample WordPress Widget
Plugin URI:
Version: 1.0
Description: How to create a WordPress Widget
Author: Tim Trott
Author URI:
class Sample_Widget extends WP_Widget
  function Sample_Widget()
    $widget_ops = array('classname' => 'Sample_Widget', 'description' => 'My Sample Widget Description');
    $this->WP_Widget('Sample_Widget', 'My Sample Widget', $widget_ops);
  function form($instance)
    $instance = wp_parse_args((array) $instance, array( 'title' => '' ));
    $title = $instance['title'];
  <label for="<?php echo $this->get_field_id('title'); ?>">Title: <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /></label>

  function update($new_instance, $old_instance)
    $instance = $old_instance;
    $instance['title'] = $new_instance['title'];
    return $instance;
  function widget($args, $instance)
    extract($args, EXTR_SKIP);
    echo $before_widget;
    $title = empty($instance['title']) ? '' : apply_filters('widget_title', $instance['title']);
    if (!empty($title))
      echo $before_title . $title . $after_title;;
    // Do Your Widgety Stuff Here...
    echo "<h1>Hello World</h1>";
    echo $after_widget;
add_action( 'widgets_init', create_function('', 'return register_widget("Sample_Widget");') );


In the Sample_Widget function (technically called the constructor) I created some configuration options which will help Wordpress (and the users of your widget) show a friendly title and description.

The form method takes in the current settings as the $instance so you can use this to output the current settings to the user so they can update.

The update method does not do anything too complex, if you add another setting property add a line in here for it otherwise it won't get updated.

Finally, the widget method will generate the output for the widget. Notice the $args parameter, this is the same as the $args parameter on the old-style widgets. $instance contains the settings for this particular widget. If you need help on the $before_widget etc... please see the previous tutorial for explanations.

Creating Widgets for Wordpress
Creating Widgets for Wordpress
Was this article helpful to you?

If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

This post has 26 comment(s). Why not join the discussion!

We respect your privacy, and will not make your email public. Hashed email address may be checked against Gravatar service to retrieve avatars. This site uses Akismet to reduce spam. Learn how your comment data is processed.

  1. MA

    On Saturday 22nd of December 2012, maria said

    I copy your code and works but I change for my blog and I get message each time:Warning: Missing argument 2 for WP_Widget::__construct(), called in wp-includeswidgets.php on line 320 and defined inwp-includeswidgets.php on line 93What is not working? Thx
  2. PI

    On Thursday 24th of May 2012, PhilippISN said

    You may use the __construct keyword instead of the classname; and also, it is good practice to call the constructer of your super class. I also prefeer to use public/private etc. keywords for the membersExample:public function __construct() { parent::__construct('Sample_Widget','Sample Widget', array('description' => __('This is the widget description',''),)); }But good article :-) and thanks alot!
  3. DE

    On Monday 16th of April 2012, Dean said

    Excellent post. Thank You.I simply created a folder undre plugins folder and copied the php file into there and it worked straight away :-)Now hacking it around to build a schools newsboard widget
  4. JA

    On Monday 2nd of April 2012, Jacob said

    Great tutorial, easy to follow and use. Then you dont have to invent the deep plate again :-)Thank you
  5. NA

    On Friday 24th of February 2012, Nameless666 said

    Thank you for you tutorials I find this very useful. you simplicity create the power of your posts thank you again for this as work.
  6. BR

    On Tuesday 14th of February 2012, Bruno Rico said

    Great info. Thanks for updating last post about widgets :)
  7. BI

    On Tuesday 6th of December 2011, bitacre said

    Thanks so much for your WP plugin tutorial it really helped me get started coding widgets quickly. Just wanted to let you know your site is fantastic and I've put your site in the acknowledgements section of every plugin I've made so far. Really great work, thanks again.
  8. SA

    On Sunday 27th of November 2011, Sabin said

    Thanks so much for putting this together, this example was tremendously helpful and really allowed me to get a solid foundation to expand from. I will be sure to mention you and your site in every WP plugin I make! Thanks again!
  9. FA

    On Friday 7th of October 2011, Fask said

    Hi,it's possible, converts the linebreaks to html's <br /> tag using PHP's nl2br() function. We then create an array with the explode() function using the <br /> tag as the separator of the different lines of data?(sorry for my english)
  10. AT

    On Sunday 7th of August 2011, Alan Trulock said

    Nice! I followed through this and the previous two tutorials. Very helpful!
  11. DE

    On Sunday 20th of March 2011, Doug E said

    This was great man, I finally found something simple enough to deconstruct to make my own widget :DOn the chance anybody is having the same problem as I, I've been trying to add my own html code somewhere to the widget that is the design to appear on the sidebar of my blog. In this example replace Hello World between the 's with your html. In your html replace the "s with 'sMine for example was a div containing a table with some classes and I couldn't figure out where to put this for the final output onto the sidebar.
  12. CH

    On Wednesday 16th of March 2011, Chris said

    In an ideal world, I'll have time to play with this more!Thanks for the help though...
  13. GE

    On Thursday 10th of March 2011, Gerard said

    Tim - I'm not sure if you covered it above, but can this code exist within functions.php or does it need to be bundled somewhere else? I'd like to create a widget to display recent posts with thumbnails, and bundle it with the theme I've created. What's the best way to achieve that?
    1. Lonewolf Online

      On Thursday 26th of May 2011, Lonewolf Online  Post Author replied

      Hi Gerard,When I do this I create the widget as a plugin, then create a widgets folder within the theme folder and include the widget file within functions.phpinclude_once("widgets/SampleWidget.php");Hope that helps
  14. RE

    On Tuesday 22nd of February 2011, Rotten Elf said

    I'm looking to make the display of my custom fields a little bit more aesthetically appealing to users. I would like to enclose the displayed custom fields' values within a box of some sort, or even have them appear atop an image. Does anyone know how to do this, or even point me in the right direction. I'm working on a directory and have taken the daunting task of using wordpress as the CMS, rather than purchasing an ugly directory script for the project. I would like to have the custom fields (which are the address, phone, city, state, etc.) appear a little more organized than the current ordered list that I've created. Any ideas????
  15. PA

    On Sunday 28th of November 2010, Pavel said

    Thank you for this article. It helped me to feel some gaps in my starting knowledge of WP.
  16. RA

    On Sunday 7th of November 2010, randaweb said

    I attempted to install this Sample Widget and it fails. I copied the code directly from your post into my file after I entered the info manually (practice). Still, did not work.I am using WordPress 3.0.1Thank you.
  17. EP

    On Thursday 18th of June 2009, Edward Palomo said

    I'm planning to use WordPress as CMS to our organization's website...nice tut here...
  18. JO

    On Wednesday 6th of May 2009, Jordan said

    Just wanted to say thanks for the well-written post. I was looking for info on customizing the display of custom fields in Wordpress and the examples in your post worked great! Wow, custom fields are really useful!
  19. RO

    On Tuesday 4th of November 2008, Rodney said

    I've read at least 6 other articles about custom fields. Including all the documentation at're a king among men.
  20. TY

    On Friday 17th of October 2008, tyler said

    In you code example box, which one is the code that will display the custom box?
  21. KI

    On Sunday 5th of October 2008, Kiten said

    Great post, i use this field tip more often :)
  22. IA

    On Friday 6th of June 2008, Iaan said

    Thanks for great post!

    I need some help with the captions of the photos though. Would it be possible to add separate captions for the separate photos? How will i go about doing this (first-time custom fields user ;-)

  23. MI

    On Wednesday 14th of May 2008, mike said

    hey there - great post! i was wondering how to go about linking that thumbnail to a different link, not the link to the enlarged picture. i&squot;m assuming, you&squot;d have to create another custom field to enter that specific url, which will tie it to the thumbnail, but that&squot;s just my best guess. would you be able to assist?
  24. RO

    On Thursday 7th of February 2008, Ross said

    Wow, this post is cool. I was thinking to customized my admin page php so that i can add a pic along with the post and i got the answer on this post. with the custom field section and the script you provided i can fully customize adding pics with the post plus i can position where to put the image where i exactly want. Thank for this post. This helped a newbie like me a lot.
  25. KA

    On Saturday 19th of January 2008, Kasper said

    Hi thanks for posting this. Its exactly what Im looking to do. Im just not getting the last part, Im not so strong in PHP.

    Are the thumbnail images created automatically here?

    I would appreciate if you could explain the last bit in more detail. If you don't want to do this in your comment section I would be happy to receive an email from you.

    Thanks anyway this will get me startet.