Life is full of firsts and movies like to make “first” experiences look so good. The movie 50 First Dates has a line where Drew Barrymore’s character says, “there is nothing like a first kiss.” Princess Diaries has a subplot point that revolves around a first kiss and how it should make your foot “pop.”
I remember my first kiss and I’m sure most of you do to. It probably wasn’t like the movies. I was young and awkward. The girl was too. We bumped foreheads, then noses, then finally our lips. I guess with nothing to compare it to I thought it was the best thing ever. Of course, experience taught my a lot and I’d like to think I’ve improved in kissing as well as other things … like making plugins. Get you minds out of the gutter.
I had a lot of help with my first plugin and that plugin has become fairly popular but I did several revisions to clean up code as well as add features. I want to do a full overhaul on the plugin though, because when I look at the code I keep asking “why did I do it like that?”
I think a lot of developers do the same thing and then we have a lot of plugins out there that need an overhaul but we’ve moved on and learned so much that it is almost painful to think about that first awkward plugin. I’m going to share some tips and ideas I’ve learned over the years so your first plugin can be better for it and maybe you’ll learn something to make your current plugins even better.
I made this part of my Genesis Explained series because I want to address some common errors I see in other plugins built for Genesis, but if you are building a WordPress plugin for any theme or all themes, you should find something useful here.
Why Build a Plugin
Some of you already have a great idea and know it is going to be the best possible plugin ever, but there are folks reading this that don’t think of themselves as a plugin developer. They make themes and that is good enough.
Listen, if you don’t want to build a plugin ever, that’s fine. I’m not going to look down on you and think you are an inferior developer. We’re cool. That said, you might want to keep reading because there are reasons for theme developers to learn to build good plugins too.
Theme features that aren’t theme specific
Bill Erickson got me started on the idea that theme developers should be making these core functionality plugins instead of building everything into their custom themes. He writes on this in more detail and in turn links to other developers who have written in even more detail. It’s a rabbit hole that just keeps going.
The short version is, features you might add to a site for a client like custom fields, custom post types, and short codes are part of the site, not the theme. If the client ever changed themes they would lose those features and that would be bad for the site. If you are developing themes for clients or even for yourself I’d recommend building core functionality plugins to pull some features into the plugin instead of the theme.
Just an example by experience. I added a lot of cool features to my site and each time I’d change themes I had to find the code and transfer it to the new theme. This caused a lot of frustration while changing themes. After Bill talked about this type of feature with me I decided to start moving features to the core functionality plugin. Now 75% or more of the features built into my site have been moved to the plugin. Only CSS and sidebars are really part of my theme. This has made it much easier any time I change themes, because I just focus on design, knowing my functionality is there.
Repeat Features
Clients love to think they are being cutting edge and unique, but 90% of the time clients give me a link to some cool thing they saw that they want on their site. The truth is, the more clients I have, the more I find I’m doing a lot of the same thing. Part of building a good core functionality plugin is learning what repeated things you are doing and build that for easy access. I can build out a custom project for a client and it might take 40 hours because I built ever line from scratch, but the next client will do some similar things and I already know what I’m doing so it may only take 30 hours or even less time. If I’m noticing that I keep getting asked for a portfolio, I can build a portfolio plugin. Then I include that for the client and focus on styling instead of having to develop a new portfolio for each client separately.
It saves me time, saves them money, and makes my development more consistent. The truth is, most of the features I built into plugins like the Genesis Featured Widget Extended were because of needs I had to make something for a client and I didn’t want to have to built a completely custom widget.
You have a great idea
I think most publicly released plugins probably fall under this. The movie Robots has a recurring line, “See a need, fill a need.” I think that is the heart of what WordPress plugin developers are all about. We often see things that need to happen and then ignore them because we assume that someone more skilled will make it happen … eventually. The truth is, if you see a need you can fill the need. Build your first plugin and then learn from it. You don’t have to be perfect the first time out. I know I wasn’t. Shoot, I often build out plugins for Copyblogger and find that it needs a lot of polish when I thought it was done. That’s ok.
If you have an idea for a plugin it is time to make it happen.
Build Your Plugin
Ok, so you have been convinced. You are ready to make your first plugin … now what? The developer who helped me get my first plugin out the door is Gary Jones. I think he would say the first thing you need to do is learn some code standards.
Why are code standards important?
The short answer is, so your code doesn’t suck.
Code standards mean your code is easier to read, easier to understand, and easier to fix.
PHP is a very forgiving language. You can do a lot of weird things in PHP that you can’t in other languages. Sure, when it breaks it is more cryptic about why things are broken, but relatively speaking, you have to work harder to break it. That doesn’t mean that you should just go hog wild because you can.
By learning to use proper white spacing, formatting, and documentation you will be better serving your users and (more importantly) your future self.
I’m at the point where I will sketch up ideas for a plugin then sit down and write. I can write up multiple files with hundreds of lines of code each then debug it. When I first started I had to run things in smaller chunks, but now I can conceptualize the entire project because I’ve done it often enough. When I debug things are bound to be broken though. So I’ll have to go in and find the issues and fix them.
Proper white spacing means it is easier to read the code. Using smaller functions means it is easier to follow what is happening and documenting as I go along means I will remember what I was thinking when I wrote a given bit of code.
Since WordPress and Genesis plugins mean you are working with other standards you need to learn those standards so you are compliant with that system. By doing so, someone who is familiar with reading WordPress code will be able to quickly read your code. It also means your plugin is more likely to work with the themes and plugins others have developed.
WordPress has a pretty good resource on coding standards for contributing to WP core.
After you have the basics down check out the WordPress Plugin Developer Handbook.
Once you learn the standards and are ready to build you will need to create your plugin.
Minimum requirements for a plugin
For your first plugin you need at least one php file and a readme.txt file. Many simple plugins use a single php file and there is no specific reason you need multiple files. That said, if your plugin will be using admin, front end, and general functions it may be good to break it up into separate files.
By moving functions to different files and loading them conditionally you make it easier to quickly identify what various parts of your code do and you make it load fewer resources at any given time. This may only result in a few milliseconds per page load in added speed but on a busy server that can be a pretty important savings.
Use Genesis Init for Genesis plugins
I’m going to be honest here. This is the main reason I’m writing this. I see a lot of Genesis plugins and most of them are pretty cool. The great thing about Genesis is the way it is built to be extended by child themes and plugins. I love that developers out there take things they think are cool and make very helpful plugins.
That said; folks, you got to use genesis_init
.
This hook is loaded on the WordPress init action. The biggest difference between loading your plugin on the init
hook and the genesis_init
hook is the later only exists if Genesis is being used. It is a super efficient way of making sure any genesis_
function is going to be available. Now, this doesn’t take the place of checking to make sure a function is available but if you run a version comparison you can know what functions and classes are available to you on the genesis_init
hook.
It isn’t enough to do a theme check when you activate the plugin.
When you do a theme check while activating your plugin, you only know that the theme functions are available at the time the plugin is activated. If users switch themes, you can white screen their site. More importantly, if they are using a tool that disables the theme in certain circumstances, you can white screen their site.
For example, let’s say someone is using JetPack. I’m not going to argue if this is a good or bad thing, but it is a popular tool so many users have it active. Jetpack activates a mobile theme by default. Again, I’m not saying this is good or very, very bad but a lot of people don’t know and leave it active. If your plugin loads on the init
hook and you don’t carefully check to make sure all of your Genesis functions are available before using them, people visiting the site via a mobile device will see a lovely white screen.
For safety, please use the genesis_init
hook when loading your plugin actions.
Example plugin file
Here is an example from a plugin I recently finished. I’ve added inline documentation to help explain everything:
<?php /* Plugin Name: Genesis Boilerplate Plugin URI: Description: A Simple plugin template used for building other plugins. Version: 0.1.0 Author: Nick_theGeek Author URI: https://designsbynickthegeek.com Text Domain: genesis-boilerplate Domain Path /languages/ */ /* The previous section is what defines the plugin. The Plugin Name line defines the name. The Plugin URI line is a link to where the plugin details can be found online Since this plugin isn't released I'm just linking to root domain The Description line is the short description that will show in the WordPress dashboard. The Version line defines the version of the plugin file The Author line defines the author. This should match your WordPress user name if uploading to the WordPress repo The Author URI provides a link to your Web site The text domain line allow you to hint at the domain that is used for internationalizing your text strings The domain path defines where WordPress should look for translation files. */ /* Prevent direct access to the plugin */ if ( !defined( 'ABSPATH' ) ) { die( "Sorry, you are not allowed to access this page directly." ); } /* I like to define a constant for the /lib/ and other directories so I don't have to call dirname() all the time */ define( 'GENESIS_BOILERPLATE_LIB', dirname( __FILE__ ) . '/lib/' ); /* One thing I'm skipping in this plugin is an activation hook action. This type of action loads when your plugin is activated. That is when you would want to check to see what version of Genesis is being used. I'm only using the genesis_get_option and genesis_get_image functions in this plugin. Those functions have been available for all public releases of Genesis so I'm just using the genesis_init hook. It's a bit of a cheat but it works and I hate loading code that I don't absolutely need. If I were doing something with functions that were added in 2.0 or something I'd run an activation hook or I'd do a "function exists" before continuing. */ /* Notice that this is loaded on genesis_init. If this was not a Genesis specific plugin I could just load on init Since I loaded on genesis_init I know certain Genesis functions like genesis_get_option will be available Also note that I have name spaced the function I created with "genesis_boilerplate" so I don't conflict with other plugins */ add_action( 'genesis_init', 'genesis_boilerplate_init', 99 ); /** * Loads plugin text domain and required files. Uses genesis_init to ensure Genesis functions are available * * @since 0.1.0 * * @uses GENESIS_BOILERPLATE_LIB * */ function genesis_boilerplate_init() { /** Load textdomain for translation */ load_plugin_textdomain( 'genesis-boilerplate', false, basename( dirname( __FILE__ ) ) . '/languages/' ); /* Checks to see if this is an admin screen and if the Genesis_Admin_Boxes class is available Since the admin class is not part of Genesis 1.0 I do a check here to make sure it is there I could have done the activation check to make sure Genesis 1.8 or higher was running but I went with this class_exists() check instead */ if ( is_admin() && class_exists( 'Genesis_Admin_Boxes' ) ) { require_once( GENESIS_BOILERPLATE_LIB . 'admin.php' ); } else { //if this is not an admin screen it is the front end and the appropriate files are loaded require_once( GENESIS_BOILERPLATE_LIB . 'front-end.php' ); } //this plugin doesn't load any common functions but if it did I would uncomment this line //require_once( GENESIS_BOILERPLATE_LIB . 'functions.php' ); }
Moving on
I’m looking at my word count and I’ve got well over 2000 words already. I have so much more I’d like to share. There are some important topics that I struggled with like “using subversion” and even handling versioning in GitHub during development. I didn’t even get a chance to cover the readme.txt file.
As much as I’d like to cover all these details, I also want to give opportunity for community feedback.
What are the most important lessons you have learned while making plugins?
What did I not cover that you really want to know?
Featured Image was obtained under a Creative Commons License.
Carrie Dils says
Thanks, Nick. Would love to see more posts on this from you.
Gary Jones also helped me get my first plugin out the door (I think he reduced the lines of code by 50% or something ridiculous). 🙂 In my case, I didn’t know what I didn’t know until it was pointed out. Thanks for the tip on genesis_init!
Carrie
nickthegeek says
Thanks for commenting Carrie. Making a plugin is a huge step but fortunately there are some really great people in the community like Gary who help make sure it is done well.
Jonathan says
That genesis_init thing is definitely good to know. I didn’t have it, but I had a check to see if the Genesis Framework was an activated parent theme. If I add genesis_init to my plugin, do I still need to keep that check?
nickthegeek says
Jonathan,
Great question. I briefly discussed it.
genesis_init
can be used to ensure that Genesis is available, but it doesn’t do much for a version check. I can’t remember if genesis_init was added at some point or if it was in Genesis 1.0. It’s been there for quite a while though.If the only functions you are using are genesis_custom_field(), genesis_image(), genesis_get_option(), and similar functions that have been around since 1.0 you don’t really need do to the activation hook. I skipped that in the example.
However, if you look in the example I do run a
class_exists()
to make sure that the admin class is available before I load it. That was added in Genesis 1.8 so you could do a version check on the init hook as a bit of a cheat to make sure that Genesis 1.8 or higher is being used.I think in practice it doesn’t hurt to use both. Doing the activation hook to check the version and notify the user “hey, I see you are using Genesis but you should update to 2.0 for this plugin to work” will cut down on support questions. Using the
genesis_init
hook to load the plugin functions means that the plugin won’t break the site in certain circumstances when the theme is hijacked.Scott Lesovic says
There are a few WordPress hooks fired between plugins loading and themes loading. If, in the plugin you need to know about Genesis sooner, you could do something like this:
$theme = wp_get_theme();
if ( $parent = $theme->parent() && 'Genesis' === $parent->Name ) {
// Genesis is present, do what you got to do
$genesis_version = $parent->Version;
}
nickthegeek says
Scott,
You can absolutely do that if you need to use a hook that runs before
init
. I usually try to get my plugin code to work on theinit
hook if possible and most of the time it is possible. If I do have some code that I need to run on an earlier hook for any reason, it isn’t going to have the theme functions available so I have to remember to “do it the hard way.” Generally this is only for a small part of the plugin and the rest of the plugin should be run ongenesis_init
.For what it’s worth, that code is similar to what I use when I need to do a version check as part of the activation hook.