UPDATE: As of WordPress 3.3, you shouldn't use the wp_print_styles hook, I've updated the Adding JavaScript section below to reflect this change.

You can create a personalized plugin template by using my WordPress Plugin Template Creator

When I  rewrote my WP-DenyHost plugin, I wanted to do it as fast as possible. Instead of reinventing the wheel (again), I googled after a plugin template and found a very good one at Pressography. It had most of what I needed in a plugin template.

Modifications to the Pressography plugin template

I've made some changes to the Pressography plugin template and I have explained them below. Before you continue to read this article, you should view the video at Pressography, it presents the idea behind the plugin template and how it works. You get the full source of my modified plugin template by using my WordPress Plugin Template Creator

Being able to use new functionality in WordPress, I've decided that my plugins will only support WordPress one minor version lower than the current i.e. the current is 2.9 and hence my plugins and this plugin template will only supports WordPress 2.8 and later.

plugins_url()

WordPress 2.8 extended the plugins_url() function which makes it easy to find the plugin location. In the plugin template constructor, I use plugins_url() to find the languages files and the plugin itself:

[sourcecode language="php" gutter="false"]
function __construct(){
//Language Setup
$locale = get_locale();
$mo = plugin_dir_path(__FILE__) . 'languages/' . $this->localizationDomain . '-' . $locale . '.mo';
load_textdomain($this->localizationDomain, $mo);

//"Constants" setup
$this->url = plugins_url(basename(__FILE__), __FILE__);
$this->urlpath = plugins_url('', __FILE__);

//Initialize the options
$this->getOptions();

//Actions
add_action("admin_menu", array(&$this,"admin_menu_link"));
add_action('admin_enqueue_scripts', array(&$this,'{plugin_slug}_script')); // or wp_enqueue_scripts or login_enqueue_scripts
add_action("init", array(&$this,"{plugin_slug}_init"));
}
[/sourcecode]

Adding JavaScript

I've done it and I still see plugin authors adding scripts using the wp_head function. There's only one correct way of adding scripts, and that's using wp_enqueue_script via one of the script hooks (admin_print_scripts, wp_print_scripts wp_enqueue_scripts, login_enqueue_scripts and admin_enqueue_scripts). wp_enqueue_script makes sure that the script loads in the correct order and that a script is only loaded once (e.g. If another plugin has already loaded jQuery, my plugin will not load jQuery, but use the script already loaded).

I've added the wp_print_scripts admin_enqueue_scripts hook to the plugin template (see the constructor above). Use the wp_enqueue_scripts or login_enqueue_scripts if you want to load the script on the front-end or login page. The wp_print_scripts admin_enqueue_scripts hook adds the  {plugin_slug}_script function in which  I enqueue the scripts:

[sourcecode language="php" gutter="false"]
function {plugin_slug}_script() {
wp_enqueue_script('jquery'); // other scripts included with Wordpress: http://tinyurl.com/y875age
wp_enqueue_script('jquery-validate', 'http://ajax.microsoft.com/ajax/jquery.validate/1.6/jquery.validate.min.js', array('jquery'));
wp_enqueue_script('{plugin_slug}_script', $this->url.'?{plugin_slug}_javascript', array('jquery-validate')); // load embedded javascript
wp_localize_script( '{plugin_slug}_script', '{plugin_slug}_lang', array(
'required' => __('Please enter a number.', $this->localizationDomain),
'number' => __('Please enter a number.', $this->localizationDomain),
'min' => __('Please enter a value greater than or equal to 1.', $this->localizationDomain),
));
}
[/sourcecode]

wp_localize_script, in the code above, creates a JavaScript object that passes the language strings to the embedded JavaScript:

[sourcecode language="javascript" gutter="false"]
<script type='text/javascript'>
/* CDATA[ */
var {plugin_slug}_lang = {
required: "Please enter a number.",
number: "Please enter a number.",
min: "Please enter a value greater than or equal to 1."
};
/* ]]> */
</script>
[/sourcecode]

Embedding JavaScript

When I write my plugins I like to keep the code in one file, that's why I also embed the JavaScript code:

[sourcecode language="php" gutter="false"]
if (isset($_GET['{plugin_slug}_javascript'])) {

Header("content-type: application/x-javascript");
echo<<<ENDJS
/**
* @desc {Full Plugin Name}
* @author {Author} - {URL}
*/

jQuery(document).ready(function(){
jQuery("#{plugin_slug}_options").validate({
rules: {
{plugin_slug}_option1: {
required: true,
number: true,
min: 1
}
},
messages: {
{plugin_slug}_option1: {
// the {plugin_slug}_lang object is define using wp_localize_script() in function {plugin_slug}_script()
required: {plugin_slug}_lang.required,
number: {plugin_slug}_lang.number,
min: {plugin_slug}_lang.min
}
}
});
});

ENDJS;
}
[/sourcecode]

Note: If you prefer to keep your JavaScript code in a separate file, you can add it by adding the following to {plugin_slug}_script:

[sourcecode language="php" gutter="false" highlight="5"]
function {plugin_slug}_script() {
if (is_admin()){ // Only run when in wp-admin. Other conditional tags at http://codex.wordpress.org/Conditional_Tags
wp_enqueue_script('jquery'); // other scripts included with Wordpress: http://tinyurl.com/y875age
wp_enqueue_script('jquery-validate', 'http://ajax.microsoft.com/ajax/jquery.validate/1.6/jquery.validate.min.js', array('jquery'));
wp_enqueue_script('{plugin_slug}_script', $this->urlpath.'/myscript.js', array('jquery)); //load your script
wp_localize_script( '{plugin_slug}_script', '{plugin_slug}_lang', array(
'required' => __('Please enter a number.', $this->localizationDomain),
'number' => __('Please enter a number.', $this->localizationDomain),
'min' => __('Please enter a value greater than or equal to 1.', $this->localizationDomain),
));
}
}
[/sourcecode]

WordPress Plugin Template Creator

While writing this article, I decided to create a tool that will create a personalized plugin template. The WordPress Plugin Template Creator takes your input, creates the necessary slugs and returns a personalized plugin template you can build your own plugin with.