Fight Club

When it comes to introducing custom functionality into a WordPress project, the debate between functions.php vs. plugin usage is nothing new.

Generally speaking, I think of themes are presentation and plugins as functionality that transcend whatever theme or themes with which they’re installed.

But sometimes, this delineation isn’t so clear. For example, let’s say that you’re working on a theme that needs to introduce a custom meta box – or several – into the post editor screen.

Though this is presentation related in that it will impact what’s displayed to the users, it’s also a bit of custom functionality but it’s only relegated to this particular theme.

What then?

Functions.php vs. Plugin Files

Functions.php vs Plugin

A bit over dramatic, perhaps?

Here’s the thing: Conventional wisdom is the WordPress development community says that anything that exists in functions.php can exist in a plugin file.

This is true, although I think plugins – especially larger ones – should be developed using alternative techniques such as object-oriented programming which is something that functions.php cannot offer.

That said, we have to remember that when we’re working on our projects, it’s not always a matter of picking either functions.php or using a plugin especially when the custom functionality is unique to the theme yet impacts the presentation of the theme.

Anyone who has built relatively large themes or slightly complex web applications using WordPress knows that functions.php can get large very quickly. On top of that, no matter what amount of documentation you provide, the file simply gets larger which can make it difficult to locate whatever it is that you’re looking to find.

I think one thing that we often forget is maintenance factor that comes with creating and releasing a theme or application.

Finding Middle Ground

To that end, there is middle ground that exists between functions.php and plugins and that’s to use separate files and place them in a separate directory.

Perhaps it’s a lib directory, perhaps its an inc directory (which is short for includes), or whatever convention your theme uses.

Functions.php vs Plugin

Custom functionality located in the inc directory

The idea behind this strategy is to make sure that that core theme functionality is kept in functions.php. This includes features such as:

  • The content width
  • Theme features such as support for featured images
  • Functionality related to custom header and custom background support
  • …and more

Files kept in the inc directory are usually related to core theme functionality but are more specialized. They aren’t quite plugin territory because they don’t need to be made available to all themes, but they’re specific enough to warrant their own file.

This can include:

  • Custom post types
  • Meta boxes
  • Custom menu pages
  • …and more

Note that this strategy is also employed by a variety of boilerplates and starter themes such as Underscores.

And For What It’s Worth

If you find yourself torn between placing something in functions.php or writing a plugin, but still feeling as if both options are wrong, consider this third alternative.

Personally, when it comes to organizing code, I use lib directories to contain third-party libraries, source code, and so on. I also keep them organized on a per-language basis. This means that my JavaScript directory may have a lib directory, as will my CSS, and so on.

Then, I use inc as the directory for my own libraries, code, and functions that are used throughout the theme.

Ultimately, this comes down to a factor of maintenance – you can make a place for each piece of functionality without sacrificing the integrity of your project, and without having to generalize the functionality into a plugin.

Category:
Articles
Tags:

Join the conversation! 38 Comments

  1. Often had the same thoughts when working on a site, functions.php or plugins.

    I’ve since setup my own framework/boilerplate which I use to start all my own projects with the lib & inc folders, regardless of the size & complexity of the project.

    The inc folder has a lot of functions which I’ve written and use over & over on almost all my sites. It makes sense to me to keep them in the same folder across all the sites for quickly updating them in future should I need.

    It’s all just personal preference; I think it’s too difficult to say there’s a right or wrong way to do it.

    • It’s all just personal preference; I think it’s too difficult to say there’s a right or wrong way to do it.

      Exactly – that’s why I think the grey area has to be explored, for lack of a better term, or left open for usage rather than simply relegating something to an either/or scenario.

      There’s always often a third (and fourth, and fifth) option!

  2. Nice article, Tom. I’m of the same mindset as yourself where theme is presentation and plugin is functionality. But there is that gray space where the line is blurred. This is where I try and determine:
    1. Will this functionality only reside in this site, or possibly in others?
    2. Will this functionality ever grow, code-wise/feature-wise?

    If the answer to those are “yes” then I tend to lean on the side of plugin.

    Your use of lib and inc directories is exactly how I handle them as well. I like to think of it as lib (aka libraries) is something that I’m “borrowing” to make my app, just like the brick and mortar library. This methodology is also followed by Rails conventions as well.

    • 1. Will this functionality only reside in this site, or possibly in others?
      2. Will this functionality ever grow, code-wise/feature-wise?

      Exactly – that’s straight up plugin territory. The only thing is that that are times in which it’s unique functionality that can then be moved into its own file related only to the theme at hand.

      And yeah, I’m a big fan of Rails’ “convention over configuration” model and try to borrow that when I can, at least in my own projects.

  3. Phew! This has been on my mind for a while, I’ve taken one project apart and I’m on the verge of ripping it apart again because of this issue.
    It’s all about presentation and functionality or whether it needs to be site wide or theme wide. I never really thought about breaking it down into inc and lib’s like that before and this has now given me a bit of clarity so thanks Tom

  4. I haven’t read your full post yet, Tom. I had to stop at this:

    «[…] plugins – especially larger ones – should be developed using alternative techniques such as object-oriented programming which is something that functions.php cannot offer»

    functions.php has no such restrictions whatsoever. You can of course use all aspects of the PHP programming language in your functions.php. it’s just a PHP-file that gets included from wp-settings.php.

    The only «restriction» is that the first action available will be after_setup_theme. If you need to do something with an earlier action hook, you must use a plugin (or mu-plugin).

    There, will go back to reading the whole post now :-)

  5. I struggled with this too. I’ve developed a bunch of custom themes, and my way is something that just works for me, it’s not necessarily the best – but here’s what I do…

    1. I keep all of the initialization stuff in functions.php. I also have a shortcodes.php for shortcodes, a theme.php for menu registrations, widget registrations and other things ‘unique’ for this theme, a cron.php for scheduled tasks and lastly a common.php which has a bunch of handy, common functions that I like to have for each theme I develop.

    2. Extending any functionality or adding functionality goes in a separate php file for that particular class, post-type, widget, etc., in a ‘lib’ dir. In this way I can copy/paste my custom widgets from one project to another, or otherwise maintain them easily – without going all the way into making them plugins.

    3. If im adding non-theme specific functionality, like say… a Testimonials post type, widget, shortcodes etc… I will make the extra effort to part that out into a plugin. It’s a little over and above time-wise to do that, but for the next project wanting a cool testimonials feature I have it ready to go.

    • I like this particular scheme. Really clear and easy to understand what’s in each file.
      Like this, too – especially the use of the lib folder since it’s specialized and focused for you particular theme.
      As far as doing this as a plugin, do you bundle the plugin with the theme and them programmatically activate it, or just have the clients activate it in the plugin menu?

      • I normally handle development through to launch. So most of the time I have the opportunity to install my custom theme, activate the plugins and add the content to their site before launching it.

        I imagine if you were packaging themes for resale that having a plugin dependency could be troublesome… I’m not sure what you would do in that case. Maybe distribute it together as a package and require that those plugins are installed and activated? That doesn’t seem too friendly.

        This article on including plugins in your theme might be a step in the right direction?

        I did see a theme once that had a missing plugin dependency notice, that prompted you to download that particular plugin, but then you have to release it into the repository which is a fair amount of work.

        Hm… I’m gonna have to look into this

        • The reason I ask is because the only time I include plugins with my themes are when they’ve been developed as plugins specifically for the theme at hand.

          I then activate them programmatically as soon as the theme is installed.

          For what it’s worth – and maybe this is worth another post – I’m not a fan of bundling generalized plugins with themes and then activating them. There’s just so much that could go wrong, you know?

          So I like your approach. I was just curious from one developer to another :).

  6. Tom, like you said its just a personal preference on where to include the theme functionality. Either its /lib/ or /inc/ folder there wont be any issue as long we know where the code exactly is. I have been following the same for a while and it works great for me.

    • Yeah – love hearing from others who are doing the same!

    • I use a lib folder for organization, if the code is only needed for 1 website then I create a class in the lib folder to do it, if it’s something I could re-use then I turn it into a plugin and stick it in my code stash but that’s just me personally, I come from a OOP/MVC background and like order.

      Good article thou

      • I come from an OOP/MVC background as well which is why I spend so much time writing about various practices that come with this territory.

        As mentioned in the post, I tend to use `lib` for third-party libraries and `inc` for personal libraries. Purely personal preference, though.

  7. I think a theme specific plugin is the easier way.

  8. This makes a lot of sense (like much of your WordPress theme development organization).

    :)

  9. I’m late to the party, but I’ve been using this approach for about six months or so now. Having some many functions in functions.php was getting hard to manage. Now they’re separated out in a functions folder, each with it’s own file that’s included in functions.php.

    Where I struggle – some of my functions would by most definitions belong as a plugin instead—things like a custom photo slider or an HTML minifier. But for my clients, having a single “package” that’s gets installed is just easier. It’s also easier to turn off a plugin that then breaks some core functionality.

    Maybe I just want too much control?

    • Maybe I just want too much control?

      This is the inevitable dilemma that WordPress developers face at some point in their career. In short, it’s basically:

      • Do I bundle the plugins with with the theme?
      • Do I ship the theme and the plugins separate from the theme?

      I wish I could offer a perfect answer for you, but I can’t.

      In my experience, I’ve done both. Here’s the rule of thumb that I tend to follow:

      • If the code I’m working on is modular and works best as a plugin, but it’s tightly coupled to the theme, then I will often include it in a `lib` directory and will programmatically activate it.
      • If, on the other hand, I write a plugin for the theme, but it may work well with other themes then I may actually use distribute it with the plugin and manually install it for the client.

      From that point forward, there are a variety of ways that you can actually update the plugin automatically for your clients and your other users who aren’t using your product.

      Hopefully this helps. Again, there’s no perfect solution, but I think the above two are the best ones that I’ve found.

  10. One thing I’ve read over the few days that’s shifting my perspective on this: What happens when another developer is brought in a year or three from now? What happens when the owner of the site changes their theme?

    For certain functionality that they might want to continue to exist beyond the theme, plugins make the effort all-around easier. Swap out the theme, and all the data and shortcodes carry over. Now, I might argue that a developer doing custom theme development work should be able to easily carry over things using the lib structure you and I are both using now.

    I imagine my thinking on this will continue to evolve.

    • I like your point, we should consider the future of the site – even if it passes from our hands to another.

      I have a file in my lib folder dedicated to shortcodes (theme.shortcodes.php), and keep my custom widgets as (theme.widget-name.php), so hopefully they could copy/paste those and re-include them. Now, instead of that I could create a plugin – which would keep all of that together in a nice neat bundle – can’t argue that.

      Now that I think about it… I do a lot of custom WordPress themes, and I have over time created a library of shortcodes and simple widgets that I use on every site. Doing this as a plugin instead of includes, would be a huge benefit… And I’m going to start doing it on my next project. I could mass-deploy updates, bug fixes and new functionality without worrying about breaking my themes, or the time involved. whew!

      • The only caution for me with that approach is around ease for the site owner. What happens if they accidentally disable or delete a plugin? Will seeing an easily accessible list of functions they don’t really need to do anything with be more confusing.

        To me, the biggest benefit of the “linked in the functions.php file approach” is that you keep the messy stuff hidden from the client.

        I’d love to hear how the new approach works for your next project!

  11. What about Custom Post Types?
    If we added them to functions.php or in an /includes/ folder (which is what I currently do), and the user switches themes, then then not only will the custom post types not display on the front end but also the menu will disappear from the back end.
    I’m starting to think that a plugin would be more suitable in this case.
    What’s your thoughts?

    • My personal opinion is that custom post types work great within the context of custom built themes where the client is going to be using them for a specific purpose, but in general-use themes, I try to avoid them.

      If you use them in a general use them, the data is hidden as soon as the user changes to another theme.

      If you want to introduce a custom post type to a widely used theme (or themes, even) then I agree with you – go the plugin route.

    • I just made heavy use of custom post types in a recent client project, and decided to use a plugin instead. This is not just useful for the client, but helpful for me as a developer as well.

      It’s inevitable that at some point the client will change their theme, but the CPT data will need to be persistent. Using a plugin ensures that the data will not disappear (visually, it continues to live in the database regardless) just because the theme changes.

      Side benefit: If I’m the person who creates a new theme for them, I don’t need to worry about porting over a bunch of custom code into the functions.php file, and can instead simply include the appropriate CPT hooks in the theme templates. I’ve also started doing a check for the appropriate classes and functions before doing this. See http://php.net/manual/en/function.function-exists.php and http://php.net/manual/en/function.class-exists.php.

      • It’s inevitable that at some point the client will change their theme, but the CPT data will need to be persistent. Using a plugin ensures that the data will not disappear (visually, it continues to live in the database regardless) just because the theme changes.

        Bingo

        If I’m the person who creates a new theme for them, I don’t need to worry about porting over a bunch of custom code into the functions.php file, and can instead simply include the appropriate CPT hooks in the theme templates. I’ve also started doing a check for the appropriate classes and functions before doing this. See

        Nailed it. This is why I think planning the proper things as plugins and the proper things for themes is so important.

    • I think it’s best to decouple what is functionality and what is presentation. For the most part your theme should be presentation (and configuration) and your plugins should handle functionality.

      Let me give you an example. I have many small business clients, and they have many similar requirements. They want testimonials, rotating logos for sponsors, and other pretty general stuff like that. It is much easier for me to maintain a plugin that handles this functionality, and simply upload the new version as I go. I now have a suite of roughly 10 plugins that I’ve developed over my career, and I can pull from them whenever I need to; as my experience grows and the demand for new functionality grows – so do my plugins.

      So… TLDR: If this is a theme for public distribution, sequester your functionality in a plugin you bundle with the theme. For client sites, where you expect that you might require this for another project down the road, save yourself the headache and make it a plugin. If it’s a one-off theme, or your just starting out, hard-code it into the theme.

  12. Hi,

    I’m a newbi to wordpress and my problem is that I’m told to put stuff in functions.php,

    but don’t change your themes functions.php. Instead you should create a child theme with a separate functions.php – not such a simple task for a newbi.

    So I was wondering if using the plugin approach instead of changing functions.php means that I don’t need to create a child theme, then that’s a huge advantage for this approach which nobody mentioned, did I miss something?

    • Yep. This is a valid option.

      Overriding your theme with a child theme gives you some benefits, like the ability to easily override template files. Think of child themes as a way to -edit- your theme.

      The plugin option is best suited to adding -new- functionality, or tossing in some hooks/filters to modify existing functionality.

      Choose the option that works best for what you want to accomplish.

  13. I’m not a developer or what, I’m just an admin on a blog post owned by our company, and this post really helps me a lot. Easy to understand and the comments are fantastic. No jokes, I really learned, maybe not all the terminologies but really answers my questions in my mind. Thank you!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.