WordPress Plugin Boilerplate

A few months ago, I released my WordPress Widget Boilerplate. Since then, it’s received several contributions from the community that’s made it a solid resource off of which to begin building WordPress Widgets.

In that same post, I mentioned that I was working on a boilerplate for plugins but had yet to finish it; however, today – with a little help of a few contributors that have already been watching the repository – I’m releasing the WordPress Plugin Boilerplate.

WordPress Plugin Boilerplate

Similar to the Widget Boilerplate, the WordPress Plugin Boilerplate includes the following features:

  • File Organization. The Boilerplate ships with both JavaScript sources and stylesheets for both the administrator and the client-side views. It provides a basic localization file to make it easy to localize the plugin. It also includes a stubbed out README that follows WordPress conventions.
  • Documented Code. Each file of the plugin and each method of the core code is clearly documented for its purpose in the overall plugin. Additionally, the core code includes various TODO’s to make it easy for your IDE to locate everything you need to populate when working on your plugin.
  • API Implementation. The Boilerplate is based on the WordPress API in order to enforce best practices when building on top of the WordPress platform. This makes it easy to develop conventional, familiar code and makes it easy to compare your work with the recommendations of the Codex.
  • Action and Filter References. One of the challenges of working with plugins is managing actions and filters. The Boilerplate includes references to all WordPress documentation of both and already includes two templates for both actions and filters.
You can check out the project on GitHub. Feel free to watch, fork, and/or contribute – I’d love for this to become a solid boilerplate for plugin development.

50 Comments

Thx for that boilerplate.

I just red a post about plugin development. They suggest to use a uninstall.php file to clear up after unstalling. (http://wp.tutsplus.com/tutorials/7-simple-rules-wordpress-plugin-development-best-practices/)

That file don’t fit for every plugins but it could be good for some.

This looks entirely awesome! Massive thanks for such a useful resource.

    Thanks so much for the comment. As far as what’ll go into the boilerplate, here’s what will, what won’t, and why:

    1. Most likely not. This isn’t something that includes work with the Settings API which is something that developers may often have to strip out in order to get a plugin going. I have an example for the Settings API already, but my goal for the boilerplate is to make a foundation off of which to build. The less to take away, the better.
    2. Yes. At the very least, the next version will include adding constants for versioning to make caching busting of JavaScript and stylesheets much easier.
    3. Not sure yet. There’s been some talk about it and I think there’s benefit, but it really depends on the functionality of the files being loaded. We’re already doing that some in the Widget Boilerplate for the views.

    Hopefully this answers your questions and gives a reasoning for my stance on certain things. I take all of the suggestions seriously so always appreciate the feedback.

      Thank you very much for you reply.

      1. Could you tell me how I should load the files to get this to work?
      https://github.com/tommcfarlin/WordPress-Settings-Sandbox
      2. Great
      3. There would not need to be alot of functionality if any just so that I can see how it should be loaded properly.

        1. You can just download the zip file and then install the theme in WordPress. That should do it (assuming that’s what you’re asking :)).
        2. :)
        3. Generally speaking, it’d just be a call to an include_once call, but the next version should take care of this as it’s going to demonstrate how to pull in an uninstall.php file.

          1. I have messed around with the settings in theme but was looking to integrate them in a plugin.
          3. Look forward to it.

          I working on a plugin and want to work along the best practices.

            The Settings API isn’t really any different than what occurs in a theme.

            You’d just need to adapt the various books for the menus, options, sections, settings, and fields that you see in the theme sandbox into a plugin.

            If you’re building your plugin with OOP practices, then the hooks will be registered in the constructor and the functions implemented as public functions in the class.

            Hope this helps!

I’ve been playing with custom themes for a few months now, and this is my first attempt at a plugin. Thanks for the boilerplate as a great starting point.

However, I’m stuck trying to add a shortcode to the plugin. I’ve been following another tutorial, plus reading a plugin dev book, but my code isn’t working correctly.

Do you have an example of how to add a simple shortcode to a plugin?

What I’ve done so far is:
1) add_action in the __construct() to call my register_shortcode().
2) public function register_shortcode() {
add_shortcode( ‘fun_staff_bio’, ‘rfsb_fun_staff_bio’ );
}
3) public function rfsb_fun_staff_bio() {
return ‘This is my SHORTCODE';
}

When I add the shortcode to a page, WordPress simply writes the actual shortcode text: [fun_staff_bio]

I thought it could have been a name conflict since my plugin is the same name as the shortcode, but changing the name of the shortcode didn’t help

Thanks for either an example or some pointers to my problem.

    Heya David,

    Based on what you’ve supplied above, the code in your constructor should be as follows:

    add_shortcode( 'fun_staff_bio', array( $this, 'rfsb_fun_staff_bio' ) );

    And then that should call your function:

    function rfsb_fun_staff_bio() { }

    Try that – it should work if all else is done correctly.

Combining your short course on Tuts+ with your boilerplate, I have learned how to create some pretty awesome plugins and I have committed myself to learning it “your way” because I find your preferences as good as any and better than most. So before I ask my question, I wanted to thank you for what you have added to the community so far and I look forward to the more that is coming.

Now, my question —

Niether in the course nor in the boilerplate do you use AJAX in the admin. I have a need to do so and as a foundation I created the functionality in a procedural plugin which works fine like this:

(1) I created the function in plugin.php as such:

function ppmhnh_add_location(){
global $wpdb;
$values = array();
parse_str($_POST[‘form’], $values);
$wpdb->insert(
‘ppm_hoopsandhits_locations’,
array(
‘locale’ => $values[‘locale’],
‘locale_city’ => $values[‘locale_city’],
‘locale_state’ => $values[‘locale_state’]
),
array( ‘%s’, ‘%s’, ‘%s’ )
);
echo “Added successfully!”;
die();
}
add_action(‘wp_ajax_ppmhnh_new_location’,’ppmhnh_add_location’);

(2) The jquery code looks like this:

$(‘#newLocation’).submit(function(e){
$(‘#wait-gif’).show();
$(‘#btnAddLocation’).attr(‘disabled’, true);
data = {
action: ‘ppmhnh_new_location’,
form: $(this).serialize()
};

$.post( ajaxurl, data, function(response){
//alert(response);
$(‘#wait-gif’).hide();
$(‘#btnAddLocation’).attr(‘disabled’, false);
location.reload();
});
return false;
});

The procedural way above works but it is not the clean approach I learned from you so I tried to move it into my OOP version.

(1) To the HoopsAndHits class, I placed an add_action(‘admin_ajax_new_location’,’ajax_add_location’);

(2) I added this public function:

public function ajax_add_location(){
global $wpdb;
$values = array();
parse_str($_POST[‘form’], $values);
$wpdb->insert(
‘ppm_hoopsandhits_locations’,
array(
‘locale’ => $values[‘locale’],
‘locale_city’ => $values[‘locale_city’],
‘locale_state’ => $values[‘locale_state’]
),
array( ‘%s’, ‘%s’, ‘%s’ )
);
echo “Added successfully!”;
die();
}

(3) I modified the jquery to this:

$(‘#newLocation’).submit(function(e){
$(‘#wait-gif’).show();
$(‘#btnAddLocation’).attr(‘disabled’, true);
data = {
action: ‘admin_ajax_new_location’,
form: $(this).serialize()
};

$.post( ajaxurl, data, function(response){
//alert(response);
$(‘#wait-gif’).hide();
$(‘#btnAddLocation’).attr(‘disabled’, false);
location.reload();
});
return false;
});

I thought that would work, but it doesn’t. The “Wait” spinner just spins and spins and nothing else happens. I don’t get any errors and I have tried to debug without success.

Would you set me straight???

Jon

    Unfortunately, questions like this normally require a bit more debugging and discussion via email rather than a blog comment.

    If the plugin works exactly as you expect given the procedural approach, but it’s failing on the object-oriented approach, then I’d say you may need to work to implement a bit of a hybrid as I’m not exactly sure that using the pure OOP approach works. For more information, see this page.

    Here’s what I’d do:

    Implement the singleton pattern on the plugin
    Have the Ajax callback get an instance of the plugin, then call the method that you want to trigger via Ajax
    Have the function then return the response to the caller

    For a super contrived example:

    function foo_example_function() {
    $plugin = Foo_Plugin::get_instance();
    $response = $plugin->perform_ajax_request();
    echo $response;
    }

    Hope this helps!

Hi!

I’m having a problem with activate and deactivate methods not being called.
I want to create a table in the database on activation but it doesn’t happen.
I tried adding error_log messages and even die() in the single_activate() method, but none of them seem to happen.

I’m running WordPress 3.7.1
Anyone else having this issue?

Hi Tom, I released a WordPress plugin in the WP repo, built on your helpful boilerplate.
I have some suggestions for the next boilerplate versions:

1. Added a function in the public class which checks the requirements on activation, i.d. checking the required WP version. Added a constant REQUIRED_WP_VERSION, too.
Under some circumstances because of this function the variable $plugin-slug had to be set as a constant in this class.

2. Deleted screen_icon() which is deprecated since WP 3.8.

3. Changed the call of the language file completely.
Instead of loading textdomain from the WP lang dir it loads plugin_textdomain from the plugin’s lang dir. I could not figure out why the first mentioned way was used.

The most sophisticated query to get the current locale / domain I found is the function wpcf7_load_textdomain() of the plugin “Contact Form 7″. Maybe you would found it useful to implement.

You can take a look into the plugin built on your boilerplate: http://wordpress.org/plugins/quick-featured-images/

    Martin – love this feedback. Thanks for providing all of this – I take it all seriously and will see what we can do about making the Boilerplate a bit easier to use in the next version :).

Great plugin, saves a lot of time! One question:
Would you say that saving plugin options within `admin > views > admin.php` is the way to go, or is there a better, more oop way to do it?

Great plugin, but Just one question.
I want to add a multilevel menu to the admin menu, and in add_plugin_admin_menu I see only one menu, with the $this->plugin_screen_hook_suffix = …
But how do I add more than one menu without damaging the $this->plugin_screen_hook_suffix ?

    You can opt to use a different string that the prefix if you’d like. Remember the Boilerplate is just a starting point – it’s absolutely capable of being flexible to suit your needs for doing what you need it do it :).

Hi Tom,

Great tool. Thanks for putting in the time.

I’m curious how I should configure the boilerplate to allow theme functions? E.g. I want to be able to call functions from, say, the public class in functions.php or theme files.

Thanks in advance

Chris

    There are a couple of ways to do this (more, really, but off the top of my head):

    1. You can implement hooks via do_action
    2. You can create some type of container object or reference object that implements the singleton pattern and maintains a reference to the plugin classes. Then you can grab an instance of the object from that container.

    Other suggestions you may come across include declaring something as global, but I highly recommend against doing that. It’s messier and is kind of a cheaper way of doing better architecture.

Hi Tom,
thank you for this wonderful project. It helped me a lot to move from procedural plugin development to oop. Right now I have an issue where I get stuck.
In my plugins I usually just register scripts at wp_enqueue_scripts and enqueue them later due to localization/parameter definition or simply because I load my scripts only if they are really needed (e.g. with a shortcode). This works perfect in a procedural approach. However I cant get it running with oop.

This works:

class my_class extends your_class {
	
	public function __construct() {
		add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'), 99);
		add_shortcode('my_shortcode', array($this, 'my_shortcode' ));
	}
	
	public function enqueue_scripts(){
		wp_register_script( 'my_js', plugins_url( '/js/my.js', __FILE__ ), array( 'jquery' ), '20140821', true );
		wp_localize_script( 'my_js', 'myajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'ajaxnid' => wp_create_nonce('my_ajax_nonce') ) ); 
		wp_enqueue_script( 'my_js' );
	}

	public function my_shortcode( $args=array() ) {
		// doing all the stuff  
	}

}
$my_class = new my_class();

Trying to enqueue the script later however fails and my.js does not get even loaded:

class my_class extends your_class {
	
	public function __construct() {
		add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'), 99);
		add_shortcode('my_shortcode', array($this, 'my_shortcode' ));
	}
	
	public function enqueue_scripts(){
		wp_register_script( 'my_js', plugins_url( '/js/my.js', __FILE__ ), array( 'jquery' ), '20140821', true );
	}

	public function my_shortcode( $args=array() ) {
		wp_localize_script( 'my_js', 'myajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'ajaxnid' => wp_create_nonce('my_ajax_nonce') ) ); 
		wp_enqueue_script( 'my_js' );

		// doing all the stuff  
	}

}
$my_class = new my_class();

What am I missing? I guess I have to deal somehow with $this-> as I do to call procedures or constants within the class. But how would I?

Any help is highly appreciated.

Michael

    Never mind. If I would have done it as described above it would have worked. In my real code I simply called wp_enqueue_script to late because I called it in a function that retrieves the return value of my shortcode. So actually I answered my own question while providing the example.

Hi I’m just wondering.
How can you add sub menus on this? Thanks

public function add_plugin_admin_menu() {
$this->plugin_screen_hook_suffix = add_menu_page(
__( ‘Word Search’, $this->plugin_slug ),
__( ‘Word Search’, $this->plugin_slug ),
‘manage_options’,
$this->plugin_slug,
array( $this, ‘display_plugin_admin_page’ )
);
}

Thanks for this Tom! Really nice of you!

Could you explain this comment and maybe provide some example? https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate/blob/master/plugin-name/trunk/admin/class-plugin-name-admin.php#L64-L74.

And where conditions ( is_admin() / ‘admin_init’ hook / global $pagenow == ‘nav-menus.php’ ) to ‘require_once’ only admin part of a plugin should be placed?

    Hey John,

    Comments like this will be handled when I get the documentation up and running for what I’m planning to start working on in January.

    Sit tight until then!

Great boilerplate, thanks for sharing.

I’m trying to create custom post types on plugin activation. The only way I could get this to work, was to hook into the init action and call a method within the main construct of the core plugin class, like so..

public function __construct() {

$this->plugin_name = ‘name';

$this->version = ‘1.0.0’;

$this->load_dependencies();

$this->set_locale();

$this->define_admin_hooks();

$this->define_public_hooks();

add_action(‘init’, array($this, ‘Gymme_Init’), 1);

//$this->loader->add_action(‘init’, ‘register_cpt’,array($this, ‘Gymme_Init’), 1);

}

Its working but In your opinion, whats the best way to init custom post types? Also I’ve tried using the loader method but its not firing.

Thanks

    I generally use the init hook to do so and I normally do so outside of the activation function.

    If this isn’t working in the Boilerplate, please open an issue on GitHub so I can track it there and take a look. It’s hard to keep track of those things here on the blog :).

Tom,

Gone through your boilerplate … and I think I get it !

Also read through the responses 2 days ago …

Today I realised there may be something missing in the boilerplate …

Perhaps someone already asked this in the responses … can’t remember and I’m not going to read through all those again …

So I’ll just ask.

Loading the plugin textdomain is hooked to the plugins_loaded action.

Doesn’t that mean that you should ALSO use the init hook to execute plugin code which includes calling translation functions like _e() and __() ? (Since the init action is done after the plugins_loaded action).

If your answer is yes that means I really get it …

If your answer is no I’m lost … ;-)

Thank you.

Daniël

    That’s a great question but the good news is that you don’t have to worry about doing anything extra for __() and _e() because they are part of WordPress core and are readily available as soon as both themes, plugins, extensions, etc., are loaded.

      Tom,

      Thank you for your prompt response …

      However it looks like I’ve left some room for misinterpretation of my question.

      I know _e() and __() functions are part of WP core and available …

      My questions was about from what point on these functions will actually produce translated strings … obviously this will depend on when/where the plugin textdomain is loaded …

      And since loading the plugin textdomain is hooked to the plugins_loaded action there is no point in using _e() and __() functions in for instance the main plugin class constructor (or in any class functions called from the constructor).

      Such code\functions should be hooked to actions which are performed AFTER the plugins_loaded action (such as init, admin_init etc).

      Right ? (I’m almost on my knees now … haha).

      (Really do think this topic would add extra value to the Plugin Boilerplate).

      Daniël

        Ah, I gotcha.

        So the translated strings are provided using a tool like POEdit and by looking at the plugin’s locale and the available translated files (which will be located in the languages directory of the Boilerplate), WordPress will pull the translations from the provided .mo file.

Hey,

Thanks for providing an awesome boilerplate. There was a time when I use to create a single plugin file, struggle while adding css and js scripts, and their “hooks”. And then one fine day I googled for a boilerplate, since then “Tom McFarlin” you are my redeemer, savior, and “O dude, you are awesome”.

Since then, I haven’t looked back. This is my third plugin now, and still, I am surprised at times by the simplicity of your code.

A few suggestions, you can add and comment out features like (until the much awaited generator :P )

Adding admin menu page and subpages
Adding shortcodes
Instructions for adding widgets into the plugin. For which, I again used your widget boilerplate class(thanks again) and insert it inside “includes” folder, then instantiated in the main plugin-name.php
AJAX in frontend(which again I got, in one of your replies).
nopriv actions… (I struggled for a day, figuring it out).

<

p>I would love to present a plugin made out of your boilerplate… https://wordpress.org/plugins/inboundio-marketing/

submitted one more yesterday, waiting for approval :)

Hi there, am having ishus creating and developing a wordpress plugin, with the update string, and the admin page show of.

Hey Tom,

Thanks for your plugin boilerplate ;)

Can you just tell me how to display the admin/partials/name-display.php in a menu item (add_options_page)?

I can’t figure it out.

Thanks

Regards

    You’d need to place the markup for the page in a partial, and then use the add_options_page callback argument to the function that includes the partial.

    This is the type of stuff I hope to have covered in the documentation that’s being worked on right now :).

      I see. Thanks for the reply.

      I was using the __construct() function in the loader class with:

      add_action( ‘admin_menu’, ‘function_name’ );

      And then in this file:

      public function function_name() {

      add_options_page([…]);

      }

      But the thing is, I tryed few callaback functions without success. The callback function used in add_options_page is already made or do I have to create it?

I put all the stuff in public function run() of the loader.

It’s better but still have the issue about the callback function.

Hey @Jerome, I have the same question.

I have setup a public function in the ‘admin/class-plugin-name-admin.php’ called setup_options.

From the ‘define_admin_hooks’ function in the main plugin class I add an admin_menu action to the loader that calls the setup_options function.

The setup_options function then does the following: add_options_page( $page_title, $menu_title, $capability, $menu_slug, $function);

However I can’t figure out how to set the callback function because it doesn’t seem to work when calling private/public function.

@Tom if you have any advice it would be greatly appreciated! Great plugin btw!!

    @Jerome & Tom, I figured it out,

    The callback function you set for the add_options_page needs to be an array. The first value of the array is $this, the second value a string representing the name of the function you’d like to call. I believe the function needs to be public.

    like so:

    add_options_page( ‘Page Title’, ‘Menu Title’, ‘manage_options’, ‘menu-slug’, array($this, ‘setup_options_view’))

    and you would need a public function in the plugin admin class called ‘setup_options_view’ and that function would do this:

    require_once plugin_dir_path( dirname( FILE ) ) . ‘admin/partials/fa-event-calendar-admin-display.php';

    @Tom let me know if that is the correct way.

    Thanks!

Leave a Reply

Name and email address are required. Your email address will not be published.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>