Writing Maintainable WordPress Widgets: Part 1 of 2

Writing Maintainable WordPress Widgets: Part 1 of 2

Tutorial Details
  • Program: WordPress V.?
  • Difficulty: ?
  • Estimated Completion Time: ? minutes
This entry is part 1 of 2 in the series Writing Maintainable WordPress Widgets and Plugins

Best of Wptuts 2011: Every week through January, we’re going to revisit some of our favorite posts from 2011. Plugin development can often feel like the wild west if you’re creating something from scratch without a boilerplate or a similar plugin to work from – Tom’s 2 part series on Maintainable WordPress Widgets/Plugins offers some practical guidelines that should keep you on the tracks!

When it comes to software development, frameworks and libraries are popular because they’re helpful, right? They provide a consistent way to write and organize code in hopes of making development and maintenance as easy as possible.


The thing is, these very same principles that apply to larger, enterprise level systems are just as applicable to smaller projects – such as WordPress plugins – developed by a small teams. And just as larger systems are full of moving parts, such is the case with WordPress plugins.

For example: you’ve got the core code that is responsible for communicating with WordPress (via filters, actions, and hooks), administration dashboards, client-side views, JavaScript files, style sheets, localization files, and so on all of which are achieved using at least four different programming languages.

During my time spent in WordPress Development, I’ve created a few boilerplates that I use to begin each of my projects. This tutorial will take a look at my WordPress Widget Boilerplate code, how to leverage it in new projects, and an example application in hopes of helping you get your next WordPress project off to a solid start.


A Widget Boilerplate

Organization

When it comes to development, I typically try to keep things as simple as possible by planning only for the necessary features; however, this is one case in which I aim to be exhaustive. It’s almost always easier to begin planning a boilerplate when you know all of the components that may go into the system.

A plugin can ultimately consist of the following:

  • Core plugin code
  • Style sheets
  • Java Scripts
  • Localization files
  • Markup
  • Images

Taking all of the above into consideration, the widget boilerplate directory is laid out like this:

We’ll take a look at each directory in detail later in the article.

The Skeleton

In addition to file organization, I also like to stub out the code used to drive the widget. The WordPress Codex[1] has a detailed explanation of the Widget API[2] and because there is a suggest way to craft them, I try to follow it.

Additionally, I’m a fan of writing my code in an object-oriented manner along with code comments to help explain what’s going on in each area of the code. As such, the initial widget code looks like this:

init_plugin_constants();
  
    // TODO: update classname and description
		$widget_opts = array (
			'classname' => PLUGIN_NAME, 
			'description' => __('Short description of the plugin goes here.', PLUGIN_LOCALE)
		);	
		
		$this->WP_Widget(PLUGIN_SLUG, __(PLUGIN_NAME, PLUGIN_LOCALE), $widget_opts);
		load_plugin_textdomain(PLUGIN_LOCALE, false, dirname(plugin_basename( __FILE__ ) ) . '/lang/' );
		
    // Load JavaScript and stylesheets
    $this->register_scripts_and_styles();
		
	} // end constructor

	/*--------------------------------------------------*/
	/* API Functions
	/*--------------------------------------------------*/
	
	/**
	 * Outputs the content of the widget.
	 *
	 * @args			The array of form elements
	 * @instance
	 */
	function widget($args, $instance) {
	
		extract($args, EXTR_SKIP);
		
		echo $before_widget;
		
    // TODO: This is where you retrieve the widget values
    
		// Display the widget
		include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/widget.php');
		
		echo $after_widget;
		
	} // end widget
	
	/**
	 * Processes the widget's options to be saved.
	 *
	 * @new_instance	The previous instance of values before the update.
	 * @old_instance	The new instance of values to be generated via the update.
	 */
	function update($new_instance, $old_instance) {
		
		$instance = $old_instance;
		
    // TODO Update the widget with the new values
    
		return $instance;
		
	} // end widget
	
	/**
	 * Generates the administration form for the widget.
	 *
	 * @instance	The array of keys and values for the widget.
	 */
	function form($instance) {
	
    // TODO define default values for your variables
		$instance = wp_parse_args(
			(array)$instance,
			array(
				'' => ''
			)
		);
	
    // TODO store the values of widget in a variable
		
		// Display the admin form
    include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/admin.php');
		
	} // end form
	
	/*--------------------------------------------------*/
	/* Private Functions
	/*--------------------------------------------------*/
	
  /**
   * Initializes constants used for convenience throughout 
   * the plugin.
   */
  private function init_plugin_constants() {
    
    /* TODO
     * 
     * This provides the unique identifier for your plugin used in
     * localizing the strings used throughout.
     * 
     * For example: wordpress-widget-boilerplate-locale.
     */
    if(!defined('PLUGIN_LOCALE')) {
      define('PLUGIN_LOCALE', 'plugin-name-locale');
    } // end if
    
    /* TODO
     * 
     * Define this as the name of your plugin. This is what shows
     * in the Widgets area of WordPress.
     * 
     * For example: WordPress Widget Boilerplate.
     */
    if(!defined('PLUGIN_NAME')) {
      define('PLUGIN_NAME', 'Plugin Name');
    } // end if
    
    /* TODO
     * 
     * this is the slug of your plugin used in initializing it with
     * the WordPress API.
     
     * This should also be the
     * directory in which your plugin resides. Use hyphens.
     * 
     * For example: wordpress-widget-boilerplate
     */
    if(!defined('PLUGIN_SLUG')) {
      define('PLUGIN_SLUG', 'plugin-name-slug');
    } // end if
  
  } // end init_plugin_constants
  
	/**
	 * Registers and enqueues stylesheets for the administration panel and the
	 * public facing site.
	 */
	private function register_scripts_and_styles() {
		if(is_admin()) {
      $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.js', true);
			$this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/admin.css');
		} else { 
      $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.css', true);
			$this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/widget.css');
		} // end if/else
	} // end register_scripts_and_styles

	/**
	 * Helper function for registering and enqueueing scripts and styles.
	 *
	 * @name	The 	ID to register with WordPress
	 * @file_path		The path to the actual file
	 * @is_script		Optional argument for if the incoming file_path is a JavaScript source file.
	 */
	private function load_file($name, $file_path, $is_script = false) {
		
    $url = WP_PLUGIN_URL . $file_path;
		$file = WP_PLUGIN_DIR . $file_path;
    
		if(file_exists($file)) {
			if($is_script) {
				wp_register_script($name, $url);
				wp_enqueue_script($name);
			} else {
				wp_register_style($name, $url);
				wp_enqueue_style($name);
			} // end if
		} // end if
    
	} // end load_file
	
} // end class
add_action('widgets_init', create_function('', 'register_widget("Plugin_Name");')); // TODO remember to change this to match the class definition above
?>

Notice there are a number of TODO’s throughout the code. These are useful especially in the context of writing your code on top of the boilerplate.

Note that there are three primary sections of code, as well:

  1. Constructor. This function is responsible for initializing the widget, importing localizing files, and including JavaScript sources and style sheets.
  2. API Functions. These functions are the three functions required for administering, displaying, and updating the widget.
  3. Helper Functions. These are private functions that I use to help with often repetitive or required tasks.

The three most important functions above, the API functions are required for developing your plugin.

  1. widget() extracts the stored values and rendering the public view
  2. update() is responsible for updating the previously saved values with the values provided by the user
  3. form() renders the administration form and provides functionality necessary for storing new values.

Because plugins are often divided between the administration functionality and the client-facing functionality, I divide my JavaScript source, style sheets, and HTML accordingly. I name these files accordingly and stub them out appropriately:

JavaScript Sources:

admin.js:

jQuery(function($) {
  // Place your administration-specific code here
});

widget.js:

jQuery(function($) {
  // Place your public facing JavaScript here
});

Style Sheets:

admin.css:

/* This style sheet is used to style the admin option form of the widget. */

widget.css:

/* This style sheet is used to style the public view of the widget. */
  

Views:



Easy, right? You can view (and fork!) this entire boilerplate including the localization files and the README on GitHub.

There’s now a place for everything and when it comes time to ship, you just exclude certain files from the final build..


A Working Example With Your Social Networks

When it comes to programming, practice helps in learning a new language or tip so here’s a quick example of how to use the above boilerplate to create a simple widget for making it easy to share your Twitter, Facebook, and Google+ links.

First, we’ll list out the requirements:

  • An administration view for entering values. This includes markup and styles.
  • A public facing view for displaying links to social networks. This also includes markup and styles.
  • Options for storing a Twitter username, Facebook username, and Google+ ID

Secondly, let’s open up the boilerplate and begin stubbing out the necessary parts.

First, we define out plugin name, slug, and locale values. These are used repeatedly throughout the code so it’s nice to store them as constants for easily retrieving them. Locate the init_plugin_constants() function and make sure that your code looks like this:

  private function init_plugin_constants() {

  if(!defined('PLUGIN_LOCALE')) {
    define('PLUGIN_LOCALE', 'my-social-network-locale');
  } // end if

  if(!defined('PLUGIN_NAME')) {
    define('PLUGIN_NAME', 'My Social Networks');
  } // end if

  if(!defined('PLUGIN_SLUG')) {
    define('PLUGIN_SLUG', 'My-Social-Networks');
  } // end if
  
} // end init_plugin_constants

After that, we need to prepare the constructor:

	function My_Social_Network() {

    // Define constants used throughout the plugin
    $this->init_plugin_constants();
  
		$widget_opts = array (
			'classname' => PLUGIN_NAME, 
			'description' => __('A simple WordPress widget for sharing a few of your social networks.', PLUGIN_LOCALE)
		);	
		
		$this->WP_Widget(PLUGIN_SLUG, __(PLUGIN_NAME, PLUGIN_LOCALE), $widget_opts);
		load_plugin_textdomain(PLUGIN_LOCALE, false, dirname(plugin_basename( __FILE__ ) ) . '/lang/' );
		
    // Load JavaScript and stylesheets
    $this->register_scripts_and_styles();
		
	} // end constructor
  

And stub out the API functions:

	function widget($args, $instance) {
	
		extract($args, EXTR_SKIP);
		
		echo $before_widget;
		
    $twitter_username = empty($instance['twitter_username']) ? '' : apply_filters('twitter_username', $instance['twitter_username']);
		$facebook_username = empty($instance['facebook_username']) ? '' : apply_filters('facebook_username', $instance['facebook_username']);
		$google_plus_id = empty($instance['google_plus_id']) ? '' : apply_filters('google_plus_id', $instance['google_plus_id']);
    
		// Display the widget
		include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/widget.php');
		
		echo $after_widget;
		
	} // end widget

	function update($new_instance, $old_instance) {
		
		$instance = $old_instance;
		
    $instance['twitter_username'] = strip_tags(stripslashes($new_instance['twitter_username']));
    $instance['facebook_username'] = strip_tags(stripslashes($new_instance['facebook_username']));
    $instance['google_plus_id'] = strip_tags(stripslashes($new_instance['google_plus_id']));
    
		return $instance;
		
	} // end widget
	
	function form($instance) {
	
		$instance = wp_parse_args(
			(array)$instance,
			array(
				'twitter_username' => '',
        'facebook_username' => '',
        'google_plus_id' => ''
			)
		);
    
    $twitter_username = strip_tags(stripslashes($new_instance['twitter_username']));
    $facebook_username = strip_tags(stripslashes($new_instance['facebook_username']));
    $google_plus_id = strip_tags(stripslashes($new_instance['google_plus_id']));

		// Display the admin form
    include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/admin.php');
		
	} // end form

The final version of the plugin should look like this:

 init_plugin_constants();
  
		$widget_opts = array (
			'classname' => PLUGIN_NAME, 
			'description' => __('A simple WordPress widget for sharing a few of your social networks.', PLUGIN_LOCALE)
		);	
		
		$this->WP_Widget(PLUGIN_SLUG, __(PLUGIN_NAME, PLUGIN_LOCALE), $widget_opts);
		load_plugin_textdomain(PLUGIN_LOCALE, false, dirname(plugin_basename( __FILE__ ) ) . '/lang/' );
		
    // Load JavaScript and stylesheets
    $this->register_scripts_and_styles();
		
	} // end constructor

	/*--------------------------------------------------*/
	/* API Functions
	/*--------------------------------------------------*/
	
	/**
	 * Outputs the content of the widget.
	 *
	 * @args			The array of form elements
	 * @instance
	 */
	function widget($args, $instance) {
	
		extract($args, EXTR_SKIP);
		
		echo $before_widget;
		
    $twitter_username = empty($instance['twitter_username']) ? '' : apply_filters('twitter_username', $instance['twitter_username']);
		$facebook_username = empty($instance['facebook_username']) ? '' : apply_filters('facebook_username', $instance['facebook_username']);
		$google_plus_id = empty($instance['google_plus_id']) ? '' : apply_filters('google_plus_id', $instance['google_plus_id']);
    
		// Display the widget
		include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/widget.php');
		
		echo $after_widget;
		
	} // end widget
	
	/**
	 * Processes the widget's options to be saved.
	 *
	 * @new_instance	The previous instance of values before the update.
	 * @old_instance	The new instance of values to be generated via the update.
	 */
	function update($new_instance, $old_instance) {
		
		$instance = $old_instance;
		
    $instance['twitter_username'] = strip_tags(stripslashes($new_instance['twitter_username']));
    $instance['facebook_username'] = strip_tags(stripslashes($new_instance['facebook_username']));
    $instance['google_plus_id'] = strip_tags(stripslashes($new_instance['google_plus_id']));
    
		return $instance;
		
	} // end widget
	
	/**
	 * Generates the administration form for the widget.
	 *
	 * @instance	The array of keys and values for the widget.
	 */
	function form($instance) {
	
		$instance = wp_parse_args(
			(array)$instance,
			array(
				'twitter_username' => '',
        'facebook_username' => '',
        'google_plus_id' => ''
			)
		);
    
    $twitter_username = strip_tags(stripslashes($new_instance['twitter_username']));
    $facebook_username = strip_tags(stripslashes($new_instance['facebook_username']));
    $google_plus_id = strip_tags(stripslashes($new_instance['google_plus_id']));

		// Display the admin form
    include(WP_PLUGIN_DIR . '/' . PLUGIN_SLUG . '/views/admin.php');
		
	} // end form
	
	/*--------------------------------------------------*/
	/* Private Functions
	/*--------------------------------------------------*/
	
  /**
   * Initializes constants used for convenience throughout 
   * the plugin.
   */
  private function init_plugin_constants() {

    if(!defined('PLUGIN_LOCALE')) {
      define('PLUGIN_LOCALE', 'my-social-network-locale');
    } // end if

    if(!defined('PLUGIN_NAME')) {
      define('PLUGIN_NAME', 'My Social Networks');
    } // end if

    if(!defined('PLUGIN_SLUG')) {
      define('PLUGIN_SLUG', 'My-Social-Networks');
    } // end if
  
  } // end init_plugin_constants
  
	/**
	 * Registers and enqueues stylesheets for the administration panel and the
	 * public facing site.
	 */
	private function register_scripts_and_styles() {
		if(is_admin()) {
      $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.js', true);
			$this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/admin.css');
		} else { 
      $this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/js/admin.css', true);
			$this->load_file(PLUGIN_NAME, '/' . PLUGIN_SLUG . '/css/widget.css');
		} // end if/else
	} // end register_scripts_and_styles

	/**
	 * Helper function for registering and enqueueing scripts and styles.
	 *
	 * @name	The 	ID to register with WordPress
	 * @file_path		The path to the actual file
	 * @is_script		Optional argument for if the incoming file_path is a JavaScript source file.
	 */
	private function load_file($name, $file_path, $is_script = false) {
		
    $url = WP_PLUGIN_URL . $file_path;
		$file = WP_PLUGIN_DIR . $file_path;
    
		if(file_exists($file)) {
			if($is_script) {
				wp_register_script($name, $url);
				wp_enqueue_script($name);
			} else {
				wp_register_style($name, $url);
				wp_enqueue_style($name);
			} // end if
		} // end if
    
	} // end load_file
	
} // end class
add_action('widgets_init', create_function('', 'register_widget("My_Social_Network");'));
?>
  

Next, let’s add some styles to the administration form. Locate /css/admin.css and add the following code:

.wrapper fieldset { border: 1px solid #ddd; width: 90%; padding: 5%; }
.option { margin: 12px 0 12px 0; }
.option input { width: 100%; }

And let’s write the markup that will render the view of the administration form:

Finally, we need to write some markup to render the public-facing view of the widget when it’s live on the actual blog:

    0) { ?>
  • 0) { ?>
  • 0) { ?>

Done and done. Not bad, huh? A fair amount of work and functionality done relatively quickly.

You can download the working source code (including an associated README) for this widget on GitHub or right here at Wptuts.

Ultimately, maintaining a software projects amounts to trying to organize complexity. Although the above boilerplate is not *the* way the organize or manage code, it’s an *effective* way to organize code and I’ve found is extremely helpful in many of my projects and hopefully it helps you with your future work.

Remember, you can grab a copy of both the boilerplate and the example project from their respective GitHub repositories. I also highly recommend bookmarking the WordPress Codex[1]. It’s a tremendous resource for anyone seeking to do advanced WordPress development.

  1. http://codex.wordpress.org
  2. http://codex.wordpress.org/Widgets_API

Moving on to Part Two…

Check out the second part of this tutorial series where we’ll be digging deeper into creating maintainable plugins! We’ll be looking at how to use hooks within WordPress – and then we’ll actually put our boilerplate to use to create another useful plugin. Ready for Part Two?


Other parts in this series:Writing Maintainable WordPress Widgets: Part 2 of 2
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.pantso.gr Pantso

    Great and thorough article ! Keep it coming guys ! WPTuts rocks !

    • http://tommcfarlin.com Tom McFarlin
      Author

      :)

  • http://www.webappsledger.com/ Joefrey Mahusay

    Great tutorial. This is useful indeed! Thanks for sharing..

    • http://tommcfarlin.com Tom McFarlin
      Author

      Sure thing, Joefrey – thanks!

  • http://www.lastrose.com LastRose

    Great Tutorial, and it will definitely help with an upcoming project I have. If this was really just part one, I’m really looking forward to part two

    • http://tommcfarlin.com Tom McFarlin
      Author

      Thanks a lot, LastRose – glad it provided some help!

  • http://tentblogger.com John (TentBlogger)

    a wonderful primer and overview. killer stuff here.

  • http://www.bensmann.no Thomas

    Java Scripts is not the same as JavaScript

    • http://tommcfarlin.com Tom McFarlin
      Author

      Just a typo :).

  • Pingback: Writing Maintainable WordPress Widgets: Part 2 of 2 | Wptuts+

  • http://coderbay.com Coderbay

    Thanks a lot. Waiting for more stuff

    • http://tommcfarlin.com Tom McFarlin
      Author

      Dropped Part 2 here :).

  • http://www.themer.me Methemer

    I have to bookmark this. I wish it wasn’t 03:30 AM right now… Thank you in advance :)

    • http://tommcfarlin.com Tom McFarlin
      Author

      Sure thing!

  • Pingback: How-To Write a Killer WordPress Plugin | ChurchMag

  • http://www.lastrose.com LastRose

    So far I love the widget boilerplate, however I find it would be a bit more flexible and easier to use if you declare a private options variable

    private $options = array(‘twitter_username’,'facebook_username’,'google_plus_id’)

    with a todo to populate it with correct options

    and then when needed just loop through it

    for example the form function would have

    $instance = wp_parse_args(
    (array)$instance,
    $this->options
    );
    foreach($this->options as $option){
    $$option = strip_tags(stripslashes($new_instance[$option]));
    }

    • http://tommcfarlin.com Tom McFarlin
      Author

      Dig this idea!

      Working on a plugin right now, actually. Gonna see about going this route and then coming back to update the boilerplate.

  • http://www.invitrostudio.com John

    Great read, guys! Wp Tuts rocks. I’ll be checking this tutorial in depth for sure.

    • http://tommcfarlin.com Tom McFarlin
      Author

      Awesome John – thanks for the comment!

  • HP

    Linking your boilerplate, very helpful.

    There seems to be an error in the code however:
    When registering scripts and styles you make a call to /js/admin.css i.o. /js/widget.js
    above as well as in the Github version.

    Thnx

    • http://tommcfarlin.com Tom McFarlin
      Author

      Nice catch – patched and committed to the repository.

      Thanks, HP!

  • Martin

    Nice tut. I have a question:

    // TODO: update classname and description
    $widget_opts = array (
    ‘classname’ => PLUGIN_NAME,
    ‘description’ => __(‘Short description of the plugin goes here.’, PLUGIN_LOCALE)
    );

    Those Constants, among others in your code (PLUGIN_SLUG, etc). Should I define them somewhere? If not, why the todo “Update classname”?

    • Martin

      Nevermind, I could just have looked at init_plugin_constants()

  • http://www.addiction.it/ Francesco

    Nice tutorial indeed!

    The only thing I don’t quite like it’s the use of constants. Why don’t you use class constants instead? In my opinion, it makes the code you write more self-contained and organised.

    • http://tommcfarlin.com Tom McFarlin
      Author

      This is a good suggestion and I’ll likely update the boilerplate to reflect this when I update the code again.

      The main reason for the constants declared as they are right now is more of a matter of habit in working with WordPress – lots of the WP core defines constants that way. Old habits die hard :).

      • Martin

        The thing is, constants are global scoped, so it would probably mess up if you add two widgets with the code – or am I wrong?

        http://php.net/manual/en/language.constants.php

        “Like superglobals, the scope of a constant is global. You can access constants anywhere in your script without regard to scope.”

        • http://www.addiction.it/ Francesco

          Yes, that’s one of the reasons I was suggesting to use class constants instead. All information stored in those constants essentially refers to Widget class, so I’d rather put it where it belongs :)

        • http://tommcfarlin.com Tom McFarlin
          Author

          Nope – you’re absolutely right!

          In plugins that I’ve written based on this boilerplate, I’ve actually modified the constants a bit so rather than PLUGIN_SLUG, I’ve said something like GRAVATAR_PLUGIN_SLUG and used it throughout.

  • http://chrisam.es Chris Ames

    Exactly the kind of comprehensive and drop-dead-useful posts I expect to find here. Good work.

    • http://tommcfarlin.com Tom McFarlin
      Author

      Thanks Chris!

  • http://luiszuno.com/ Ansimuz

    I downloaded the files and at the admin panel at the widgets window is not showing the fields. It displays an empty box. Is it for my WordPress version (v.3.2.1) ?

    • http://tommcfarlin.com Tom McFarlin
      Author

      Which did you download? The Social Network widget or the boilerplate? The former should work – just tried it on the latest version of WP fresh out of the repo. The latter has no fields.

  • Pingback: How To Publish To The WordPress Plugin Repository | Wptuts+

  • Pingback: Web Design Weekly #5 | Web Design Weekly

  • http://europcsolutions.com Daniel Lucas

    Great article,
    Really good folder organization and nice explication on developing widget.

    There’s a small typo on lines 7-9. It’s written emptyempty instead of emtpy ;)

    • http://tommcfarlin.com Tom McFarlin
      Author

      Yeah – nice catch! I think this was a problem with the syntax plugin. Either way, thanks for posting a comment – it’ll help others in case they come across the same thing :).

  • http://www.twitter.com/thomasweberdev Thomas

    Great tut Tom.

    But I think I’ve found a little problem with localization.
    I’ve let you some details in an issue on your GitHub repo : https://github.com/tommcfarlin/WordPress-Widget-Boilerplate/issues
    Have a look :)

    Thanks

    • http://tommcfarlin.com Tom McFarlin
      Author

      Thanks a lot, Thomas! Issue resolved :).

  • http://www.asingh.com.np Abhishek Singh

    Hi Tom,
    It’s really a nice tutorial. I used the example structure used in this tutorial to change my own widget. I’ve developed two widgets, each with your structure. But whenever I use “require_once ()” for the widget file, the second widget overrides the first one, and only the first widget is displayed in the widgets page. To make this clear, I’ve two widgets:
    1. Featured Widget
    2. SlideJs Widget

    and with require_once on both of them, the widget page displays like this image: http://i51.tinypic.com/x3y0x5.jpg (here you can see that the SlideJs Widget is not displayed)

    The code for SlideJS Widget is at http://fpaste.org/oCGS/ and the code for Featured Widget is at http://fpaste.org/FC3M/ . I could not find the root of this issue. Can you please help?

    • http://www.asingh.com.np Abhishek Singh

      I found the code causing the problem and solved it. Apparently, in the init_plugin_constants() method, it uses define() to define the plugin slug and plugin constant, and and hence only the define() for the last widget persist (overriding defines from other widgets), that’s why it’s displaying the widget name of only the last widget in all of the others. I changed it to use a local variable as below:

      private $pluginName;
      private $pluginSlug;

      private function init_plugin_constants() {
      if ( (!empty($this->pluginName)) || (!isset($this->pluginName)) || (is_null($this->pluginName)) ) {
      $this->pluginName = “My Plugin”;
      }

      if ( (!empty($this->pluginSlug)) || (!isset($this->pluginSlug)) || (is_null($this->pluginSlug)) ) {
      $this->pluginSlug = “my-plugin”;
      }
      } // end init_plugin_constants

      And use “$this->pluginName” instead of “PLUGIN_NAME” and “$this->pluginSlug” instead of “PLUGIN_SLUG”. Also in the constructor, I made these changes:

      $this->WP_Widget(false, $name=$this->pluginName, $widget_opts);

      This solved the problem for me.

      • http://tommcfarlin.com Tom McFarlin
        Author

        Thanks Abhisek – I’ll make a note and update the Boilerplate (if you feel so inclined, open an issue on GitHub and I’ll definitely take care of it).

  • http://8mediaeg.com 8MEDIA

    i like your post and may i will translate it in to arabic with a link for the original post , could i do ?

  • http://ChiefAlchemist.com Mark Simchock

    Thanks Tom.

    btw, I’m using Instant WP (http://instantwp.com) for dev’ing and I noticed that it likes plugins_url() but acts differently towards plugin_dir_path().

    While certainly not the fault of your boilerplate, I wanted to mention it before anyone lost as much blood as I have head-butting my desk :)

    Also, when do you think you might:

    (1) update this to reflect some of the comments?

    (2) release the plugin boilerplate I saw mentioned somewhere?

    • http://tommcfarlin.com Tom McFarlin
      Author

      Mark – if you don’t mind, open an issue on GitHub for this and I’ll be sure to take care of it. Love it when users catch this kind of stuff as it helps make it easy for everyone (myself included :D).

      And the Plugin Boilerplate has been released. Check it out on GitHub.

  • http://www.noggster.com Noggstaj

    Thanks a lot for these tutorials, made writing my own plugin a breeze. Very good job good sir!

  • http://noggster.com Noggstaj

    Hey, I just have a quick question regarding enqueueing scripts and styles. Using this boilerplate as backbone for my own plugin, I’m having trouble getting the plugin to fetch the javascript and css files.

    Do I need to change anything in widget.php on line 68-70 (in your finished code example) :

    /**
    * Helper function for registering and enqueueing scripts and styles.
    *
    * @name The ID to register with WordPress
    * @file_path The path to the actual file
    * @is_script Optional argument for if the incoming file_path is a JavaScript source file.
    */

    Do I need to make name, file_path and is_script to variables and give them values? If so, how?

    Once again, thanks for a great tut!

    • http://tommcfarlin.com Tom McFarlin
      Author

      Hey Noggstaj,

      This was a previous bug in the Boilerplate – thanks for pointing it out. If you check out the code on GitHub, you’ll see the update.

      Try that and let me know!
      Tom

  • http://www.paulund.co.uk Paul

    Awesome post thanks fort he boilerplate going to use it on my new widgets from now on.

  • http://ChiefAlchemist.com Mark Simchock

    I know this is an old – but still very helpful – post/article but I wanted to mention that:

    ‘classname’ => PLUGIN_NAME,

    should probably be

    ‘classname’ => PLUGIN_SLUG,

    the name could have spaces in it and if so it’s probably not the ideal string for a CSS class.

  • Pingback: Writing Maintainable WordPress Widgets - Tom McFarlin

  • Pingback: WordPress Widget Boilerplate - Tom McFarlin

  • Pingback: WordPress Widgets, Mobile Apps, CoffeeScript, Grids, & More - Tom McFarlin

  • http://webenvelopment.com Ben Racicot

    Great stuff! Never seen before and at the same time I can’t seem to get the field names to show. Very confused. Thanks for a great TUT!

  • Pingback: Best WordPress Widget Boilerplates : WPMayor

  • Pingback: Best WordPress Widget Boilerplates | CMS Radar