I don’t mean you need to design all your code to have special Multisite features. I mean that if you’re not writing code to work on multisite, you’re probably doing a lot of things non-optimally and not fully WordPressy. When you write your code with Multisite in mind, you’re actually writing it with the basic tenants of WordPress itself. It forces you to think about how WordPress is used, how it might be used, and how you can be flexible and extendable.
Let’s throw out the idea of network options and activation for a moment and consider the ways we can write our code to make it work for Multisite and the world. The truth is that if you’re coding ‘for Multisite’ in many ways your coding for WordPress in the best way possible.
Calling Files
There’s a time and a place for ABSPATH
but it’s as a last resort. There’s a time and a place for get_bloginfo('url')
but it’s not to call .'/wp-admin/admin.php
either. Did you know admin_url()
will get the url to the admin area using the right protocol (http or https) for you? And it works for Multisite. Instead of hardcoding your paths or assuming everyone has WordPress installed in the root of their website (they don’t), use the functions and template calls WordPress has created.
Oh and stop supporting the old WordPress 2.x ways of determining folders. It’s 2015. We’re good.
Saving Files
Saving data to the disk means everyone can read it. Duh, right? Well, where do you save uploaded files? You use wp_upload_dir
of course. That works on Multisite just fine. Instead, if you hardcode in /wp-content/uploads/myplugin/
then you’re saving things for everyone. If you’re not using the WordPress options to grab the upload directory, then your code won’t work on Multisite and everyone will be sad.
This extends to where you save your cache files. Did you know there’s a plugin that saves the cache to the plugin folder itself? Besides the fact that the cache didn’t have a way to flush and grew to 700megs over the year the person used it, that cache was for all the sites in the network. All. Saving the cache to a unique location (I suggest /wp-content/pluginname-cache/siteID
) prevents cross contamination of cache.
Saving Options
If you write a plugin that, to save its data, it creates a new DB table and saves it there, that can be okay. But if your plugin on update then drops that table and recreates it… That was not pulled at random, by the way, I was reviewing a plugin that did that. Instead he should have been using the function update_option()
to create (and update) the options. And yes, it knows.
But that’s an extreme, I admit. What isn’t an extreme is people creating their own tables. It happens a lot. And when they do, they often forget that we have $wpdb->prefix
which means they force create wp_mypluginname
instead of $wpdb->prefix . "mypluginname"
… guess which one’s smart enough to know it’s on Multisite?
(If you want to make a network table use $wpdb->base_prefix
and use update site option
for network wide options, yes, we know the naming conventions are weird.)
Theme Customizer
Not everyone can edit theme files. Not everyone can make child themes. On a Multisite, the only person who can do that is the Super Admin. Site Admins have no access to edit files or upload themes. Worse, if you make a change to a theme, everyone who uses that theme gets the change. What happens when a site wants a special header and your theme doesn’t allow those to be edited via the customizer? The customizer is there for a reason. Use it. At the very least make things hookable to allow plugins to do simple things like change footers. Please. Please. That’s one of the things that themes get wrong constantly.
What Else?
What do you think would be improved if people ‘coded for Multisite’?
Comments
3 responses to “Design for Multisite or DIE”
I’d like to point out that, not only are you helping multisite owners when you use the various helper functions that locate items inside of wp-content (wp_upload_dir, plugins_url, etc.), you’re also making sure your plugin actually works on any installations where the wp-content directory isn’t actually called “wp-content”. It’s not only friendly to “edge cases” today, it’s also future-friendly (who knows if WP core will ever decide to name that folder something different).
One minor pet peeve of mine is also the way plugin authors set the “action” attribute for their plugin’s options page form. I’ve seen a handful that use “/wp-admin/options.php” rather than something like admin_url( ‘options.php’ ); when WordPress is installed in a sub-directory (or in a sub-directory multisite instance), that sends the user to the wrong place when they save the form.
So, as you alluded to, this isn’t just a matter of making things work for multisite instances, it’s really a matter of doing things correctly so that they work on any non-vanilla WordPress install (whether that’s an installation in a subdirectory, an installation where the WP URL and the site URL are different, an installation where the content directory isn’t actually called wp-content, etc.). WordPress is built the way it is in order to make it extensible and customizable; writing plugins that seem to assume the installation hasn’t been customized in any way completely contradicts that idea.
That said, I would also like to advocate for a little bit of pre-planning (I know, I’m asking a lot) when developing a plugin. If your plugin has options/settings, you should consider for a moment how those should be handled in multisite.
If it makes sense for the settings to be global (or, in some cases, if that’s the only way they really can work – for instance, if your plugin needs to modify my .htaccess file for some reason), then you really need to use the network admin functions/settings API rather than using individual sites’ admin functions when the plugin is used on multisite (also, if that’s the case, setting the Network: true comment in the plugin header is a good idea).
If, however, your plugin should actually allow individual sites to use their own settings, then do it the regular way.
That said, it would be nice to see the network settings API catch up with the normal admin settings API. There are a lot of helper functions available in individual site admins that aren’t available in network admin. I think we’d see at least a small up-tick in people handling network admin settings if we reached that point (not casting stones – I fully recognize I haven’t contributed a single line of code toward that pursuit).
One last thing – even when designing for multisite, plugin authors also shouldn’t assume that the root “blog” or even the “site” (network) they’re trying to work on has an ID of 1. Some rare installations have IDs of something other than 1 for either of those items, and then there are some multi-network installs that have multiple “site” (network) IDs.
@Curtiss Grymala: WoW! Great responses, and imo pre-planning plugin design is not really too much to ask =)
Thanks for the perspicacity @Ipstenu, it was a pleasure to forward this 😀
Another to add to the list: user settings.
The update_user_meta() / get_user_meta() function pair does global user settings. That’s usually what you want, but when adding a new user setting, plugin writers should first consider whether maybe the setting should be per-site, not global.
If it should be something they can set per-site, then use update_user_option() / get_user_option() instead; etc. for the other functions in those sets.