The following is a guest post by Jason Witt. I’ve known for quite a while that I should port a lot of the stuff from my `functions.php` in my WordPress theme into a functionality plugin. But you know, hours in the day and all that. I recently had Jason work on this project for me, and he did a bang up job. If you have no idea what I’m talking about, read on.
Adding new functionality to a WordPress site can be as easy as searching for a plugin in the WordPress Plugin Repository and installing that plugin. But there is some custom functionality you might need that is either too basic or too customized for there to be a plugin for it. That’s where the `functions.php` file comes in. It’s essentially a functionality dumping grounds for a theme.
But some of the code we tend to put there would be better served elsewhere.
What is a Functionality Plugin?
A functionality plugin is just a plugin like any other plugin you’d find in the WordPress Plugin Repository. The main difference is that it wouldn’t be publicly distributed, because it’s specific to your site. It’s one custom plugin that encompasses all your site’s custom functionality.
What’s So Great About a Functionality Plugin?
Why would you want to spend the time building a plugin when putting your functionality in your `functions.php` file is so easy? The big advantage is that you can reuse your functionality from theme to theme. When updating/changing your theme, some code in the `functions.php` will stay the same and some will change. The idea behind a functionality plugin is to take the functionality that will not change from theme to theme, and place it into a plugin. That way instead of sorting through your `functions.php` file for what you want to keep, you can just dive into the design of your new theme.
What Goes Into the Plugin?
This is the million dollar question. What does actually go into a functionality plugin? The best way to approach this is to decide what is specific to the theme and what is specific to the site. For instance, a custom post type would be specific to a site, and adding thumbnail support is specific to a theme.
Let’s pause on that for a moment so it can be super clear.
Imagine your website has a section for meetups on it. You’ve built a custom post type for them, so they can be a special type of content. On the front end of the site, you display them in a special way. On the back end of the site, you collect special information specific to meetups. Like in this CSS-Tricks video. We’ll call that Theme A.
If you change the theme of your site (Theme B), is it likely you’ll want your meetups to go away? Probably not. That is site content that you’ll likely want to transcend any particular theme.
If you had declared all that custom post types stuff (e.g.
register_post_type())in your `functions.php` file of Theme A, then switched to Theme B – you might suffer a minor heart attack when you notice that all your meetups information is gone. Theme A’s `functions.php` file is no longer active, so all that code declaring the custom post type no longer runs. The menus are not added to the admin, the content will appear to be gone.
Rest assured, the data is still there, you just need to make sure the custom post types code runs again.
Why go through that at all? Just move that code into a functionality plugin and it will remain active even when switching themes.
Examples of things that make sense in `functions.php`
- The theme support functions e.g.
- Adding a custom post type to your home page post list
- Registering sidebars and nav menus
- Adding an external CSS file, for instance a custom font
Examples of things that make sense in a functionality plugin:
- Custom post types
- Custom Taxonomies
- Custom functionality for other plugins
- Custom meta fields
- Mostly custom stuff
If you’ve never make a WordPress plugin before, this is a great way to gain some experience.
To start, you’ll make a directory in you plugins directory. Name it whatever you want. Avoid using numbers and special characters; dashes and underscores are OK. I usually go with something
In you new plugin folder create a file with a similar name as the folder,
At the top of that file you want to ad the plugin file header information. Here’s an example to get you started.
/** * Plugin Name: Your Functionality Plugin Name * Plugin URI: http://example.com/plugin-name-uri/ * Description: This is a short description of what the plugin does. It's displayed in the WordPress admin area. * Version: 1.0.0 * Author: Your Name or Your Company * Author URI: http://example.com/ * License: GPL-2.0+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: plugin-name * Domain Path: /languages */
After that, go nuts and start adding your functionality below.
You can literally just cut-and-paste code from `functions.php` over to this file, and as long as this plugin is activated, it should work.
If you’re like me and like to keep things neat and tidy, this is a great time to use a modular approach to the code you place in your plugin.
One approach to keep things simple is to organize your functionality into similar groups and give each of them their own file. Then, include those files into the main file of the plugin using PHP includes. Make sure you notate your functions so when you return to them at a later date you know what’s going on.
include 'mysitename-functionality-post-types.php'; include 'mysitename-functionality-extra-rss-feeds.php'; include 'mysitename-functionality-remove-unwanted-assets.php';
Another approach is to use Object Oriented Programing (OOP). This involves creating PHP classes and methods. If you are not familiar with Object Oriented Programing there’s a great tutorial by Tom McFarlin called Object-Oriented Programming in WordPress. You should check it out if you’re interested in developing your WordPress coding skills. OOP is a great way to organize your code that’ll allow it grow as your functionality needs change.
If you’d like to poke around the CSS-Tricks functionality plugin, here’s a repo on GitHub you can check out.
After this transition here, the only thing left in the `functions.php` file is queuing up jQuery and a hook that overrides the default HTML comment output – both things very specific to the current theme.
Yup. Good stuff.
fwiw, I embrace DRY and abstract out as much functionality as possible into a framework / library. As a result a given project’s bespoke plugins / sub-plugins (read: the include’d bits) are only the “todo” args necessary to make a particular bit of magic happen. Any redundant WP excess is left to the parent class.
fyi – somewhere in all those repos is a getting started :) And yes, I’m working on fleshing out the docs, as well as using proper PHP namespacing.
Comments. Questions. And pull requests welcomed.
At least for sites that get handed off to a less-than-tech-savvy client, I think putting the functionality plugin into the
/mu-plugins/folder is the way to go!
For those who don’t know,
/mu-plugins/they are the best! “mu” stands for “must use” (confusingly, not “multi-user,” though it came from the old “WPMU” branch before there was multisite). Files in the
/mu-plugins/folder are run automatically (before other plugins, if I recall correctly) and cannot be disabled from the Plugins page (though you can view them from a small link at the top of the Plugins page).
For post types, taxonomies, and the like, the only times when you’d want to turn off a functionality plugin are probably times to just edit it anyway.
Thank you for pointing that out @Mark. I was already using modular design within functions.php but creating functionality plugins makes a lot of sense.
I totally agree! I’m trying to build sites now where any plugin (except mu-plugins) can always be safely removed. So that the site content or theme has no dependency on a plugin. This is hard to enforce but makes me think twice about installing plugins which come built-in with shortcodes and custom post types. Uninstalling those plugins can either break a site design or make user-entered data just disappear. At least being aware of these plugin dependencies is pretty important.
So there’s three places to put custom code:
/mu-plugins/– can affect site data or vital back-end functionality
/plugins/– no affect on site data or site theme if uninstalled
/functions.php– only affects site theme
@cornelius, I really like that “cascade” of plugin/functions locations. I’ll start thinking about it that way.
Custom post types are tricky in that they nearly always have some specific template code related to them. So while they are site specific they also theme specific.
That’s true, @sean, but I still think it provides a better experience for two reasons:
1) The alternative is to require a developer to extract and port the relevant code to a new theme’s
functions.phpfile. That’s more error prone and time consuming. Doing it as suggested by this article is cleaner, saves time down the road, and doesn’t add any time to the first pass of development.
2) While you’re 100% right that switching themes would lose some of the experience, making a functionality plugin at least ensures that the basic post information (Title, body, featured image, excerpt, etc.) are picked up by the new theme. Additionally, it gives site users a piece of mind that the data hasn’t been lost. It’s not lost either way, but that kind of thing matters when building a site for someone else.
I used to modularize my functionality in plugins, but now I just have a lib directory in my theme then my functions.php file contains a loop that iterates the files in that directory and includes them. I only extract to a plugin if I really feel like making that code universal and maintainable for multiple applications.
My previous comment provides a couple reasons why it’s still advantageous to do it the other way.
For a while I was putting everything in functionality plugins some of the same reasons you mentioned and more, but I ended up deciding that it was an unnecessary step for most bits of theme functionality. I found the opposite that putting things in plugins was more time consuming and a minor frustration. I find it less time consuming to put my bits of lib code in separate files under
theme/libthen iterating the files and including them.
I like for deployment to consist of using rsync to sparse copy a single directory and its children.
Keeping my functionality in the theme saves me time when I use that functionality in templates. Let’s say I write a function that I’m going to use around my theme. If it’s in a functionality plugin I have to fail-safe it by wrapping everything in a function that checks to make sure my functionality is defined. If that functionality plugin in disabled the theme will break. Checking if the function is defined every time I use it is annoying. And just being realistic, I’ll probably forget to wrap everything in that check anyway.
Another example. Sometimes I go back to a theme I haven’t hacked on in a couple years. If the functionality libraries are in a plugin then I have to go looking in another part of the directory structure to find them. It sounds minor, but these little extra steps add up fast.
The enable/disable capability sounded cool, but I have to go to the plugins and double-check that my plugins are enabled. I’m too lazy to do that. It also sounded useful for troubleshooting, but I can troubleshoot everything I need to by tailing the PHP log.
Maybe I’m just a negative nancy, but I used this way of building and found that it was only useful for my flavor of development when I had a bit of code that I wanted to make into a real “plugin” and use other places. Now I just make a file in my theme’s lib directory and rest assured that it’s being autoloaded when the theme is enabled. Keeping it simple.
Now all I have in my functions.php file is this. And everything is super organized down to files like
post_types.phpwhere I define posts types and
header.phpwhere I drop code that cleans the header.
Now I’m done wearing the black hat for today. ;)
As far as I remember, there is difference in the order mu-plugins and plugins are fired, and not all plugins are suitable for the mu-plugins folder.
Just something to take into account, when planning to use the mu-plugin folder.
Very good point. The relevant WP Codex page has a caveat’s section that gets into the limitations. That said, I’ve used it for exactly the type of stuff listed in this post without problem.
If anyone is interested, I have a WordPress plugin that can automate the creation of a functionality plugin so no file system access is required. http://wordpress.org/plugins/functionality/
@Shea Bunge, I will check your pluginut and take it for a spin. Inspired by this post I have decided to make my next Meetup presentation around the functions.php file, functionality plugins, and alternative ways to preserve custom functions.
Thanks @govertz. You may also be interested in another of my plugins which allows you to add and manage custom functions from the WordPress admin, which are then executed on the site as if they were in a plugin or theme functions.php file. http://wordpress.org/plugins/code-snippets