I’m a huge fan of the DRY (Don’t repeat yourself) school of thought, and doing a thing once, and doing it well. Because of this, if I sense there’s any chance the code I’m writing is something that can be reused in the future (by me or others), I try to write my code in a way where it can be easily repurposed and reused. This means not using client-specific function prefixes, or project-specific variables, and instead using WordPress’ hooks and filters system. There are many differing opinions and schools of thought on the use of frameworks, but after working with the team at WebDevStudios for 5+ years, I’ve come to realize that the extra time/effort put into the code to make it into a durable and flexible library almost always pays off. A few examples of plugins/libraries I’ve worked on over the years which have become invaluable tools for me, for WebDevStudios and for many others:
- CMB2 (this was a library when I got to it. I credit it with initiating my enthusiasm for libraries)
- Google Top Content Widget
- TwitterWP
- WDS WP REST API Connect UI (and WDS WP REST API Connect)
- WordPress Shortcode Button
- WDS Shortcodes
- Even something as simple as Hash Link Scroll Offset
Since libraries for WordPress have become such a large part of what I do, I’ve had to grapple with one of the all-too-common challenges — dealing with version conflicts when the library happens to be used in more than one place (a plugin and the theme, or two plugins, etc) in your project. As a general rule, best practice has become to first check if the library exists by wrapping the library include with a class_exists()
or function_exists()
check. There are a couple issues with that solution. The first, we’re expecting a lot… The chances that SOMEBODY forgets that check is pretty high, and can result in fatal error/white screen for your users. Second, what happens if some other developer includes an older stale version, and their version happens to load before mine. You’re either stuck working with the lowest common denominator, or using various other methods to check which version of the library is loaded, or worse, assuming your version is loaded and yet again, possibly causing fatal errors or white screens for your users.
The struggle is real, amirite???
With the precursor to CMB2, Custom Metaboxes and Fields for WordPress, when the library started to become popular and included in more and more plugins/themes, we started to see each of these issues crop up at times. These version/loading issues were the primary motivator for forking the project into what would become CMB2. We needed:
- To allow any plugin or theme to bundle CMB2, or for CMB2 to live in mu-plugins
- Users not to have to worry about
class_exists()
orfunction_exists()
checks - The most up-to-date version to take precedent, precluding all others from loading
After much exploration and testing, the answer was actually fairly simple, as evidenced by that very first commit to CMB2. The CMB2 solution works like this:
- Name the library initiation class (we’ll call this the loader) with a unique class-name for each version release.
- This ensures the loader for each version is loaded and gets a chance to load the library.
- The loader then hooks into one of the first hooks available to all plugins/themes,
'init'
, with a very low priority (9999).- This priority is the key. When a new version is released, the priority in that version’s loader class will decrement, thereby increasing the hook priority.
- The library is included on that callback (after a final library
class_exists()
check).- The newest version will have the highest priority on the hook, and will load the library first. All subsequent loaders will stop here because the class already exists.
And that’s all there is to it! This system has been in place since that first Aug 16, 2014 commit, and hasn’t failed us yet (though I did manage to break it with the 2.2.0 release.. doh!).
Thanks to the success of the CMB2 loading system, I started on a boilerplate class that will allow me to leverage this loader with any library. Over the weekend, I finalized it, and even created a github.io page where you can generate your own library loader! In my opinion, short of a dependency loader in WordPress, this is a big deal, and I hope you check it out!