Never Set Defaults in the Database

Speaking of defaults, NEVER SET DEFAULTS IN THE DATABASE. Not ever. The theme options you store in the DB should always, always, *always* be something the user has selected. If the user selects the default, then that’s fine to set in the DB. but you don’t set it in the DB just because it’s not set at all. get_theme_mod has a second option for the default value. So does get_option for that matter. Use this.

Otto Wood, WordPress Core Developer on Custom Admin Screens

Thanks, Otto, for clearing that up :)

About the author

Konstantin Kovshenin

WordPress Core Contributor, ex-Automattician, public speaker and consultant, enjoying life in Moscow. I blog about tech, WordPress and DevOps.

9 comments

  • Setting defaults is the first problem. The second is a widespread failure to provide a routine to REMOVE those options entries when you’re uninstalling a theme. There’s nothing I hate more than having to dig into the options table to remove 100+ rows of theme options left over from an old theme.

  • Otto and I work together, get along great, enjoy good beer, and nearly always agree. But not in this one specific case. Whether to set defaults has actually spurred a lively argument onstage at a WordCamp at least once.

    I’m of the opinion that the best thing you can do is write good, clean code. If that means you wish to use the $default arguments for get_theme_mod() and get_option(), go right ahead. But if you are careful about what you are actually storing (and not storing a ton of options), I would store theme defaults in the database.

    Otto has a bad taste in his mouth in part because he found a theme that was changing core WordPress options on activation. Imagine if this occurred when previewing the theme — your live site is suddenly affected! This is seriously lame. But your own options, go for it.

    Note you should only ever do this on an admin hook, and never on the frontend. One, you always want to avoid performing write queries on the frontend. Two, this prevents the options from being instantiated during a theme preview.

    Since you’d only be doing it on the admin, you’ll also want to leverage $default — that’s fine! But it does allow you to benefit from fewer queries — WordPress needs to run a separate query for every option row that isn’t in the database to confirm it wasn’t there, as they (of course) weren’t autoloaded. (Also, don’t think this is me preaching lower query counts. In practice, these queries are likely so few and so fast, that it doesn’t matter. I just like disagreeing with Otto over it.)

    Twenty Ten doesn’t have any options, but Twenty Eleven stores its defaults in the database when you are in the admin. I wrote that, so don’t think that others are endorsing my opinion — but, no one complained. Well, Otto has. But I just act like I can’t hear him. :-)

    (N.B. Surprised I didn’t see this posted to themeoptions.wordpress.com.)

  • Nacin is wrong. Here is why: If you store defaults in the database, then they are no longer “defaults”.

    A default, by definition, is what you use when you encounter a condition through failure, absence, or lack of something.

    A default setting, therefore, would be what you use when there is no setting, or you failed to get the setting, or something else.

    If you put settings into the database just because the settings you expect are not there, then you do not have a default condition at all. You have no handler for errors. You have no handler for lack of settings. And you introduce side effects such as those Nacin described above.

    A better way is to use the default parameters so that when you attempt to get a setting from somewhere, then you will always get back a valid value. Even if the setting isn’t there, the default will be returned in that case. You no longer *need* to insert into the database, or to create side-effect inducing crap.

    I have not seen Twenty Eleven doing this, but if it is, then a) shame on you Nacin and b) quit doing it wrong!

  • BTW, mere activation of a theme should never change the database. This becomes even more important in 3.4 with the theme customizer, because a theme that is not active, but being customized will have it’s functions.php be loaded and all the theme will seem to think that it is active even though it is not.

    One of the main rules when programming anything: Don’t produce unexpected side effects.

  • The best way to get many, many people doing things better _in general_ seems to be simple rules — so the no defaults in the database rule is probably the best one to communicate.

    I’m surprised Otto only has one experience where a theme changed core options. Many of the free or not-fun-to-work-with frameworks seem to do this lately. Since self-serve clients often use these before finally escalating to a dev I’ve seen this coming from several small businesses.

    The solution to this come down to the convention vs. configuration argument for me. While I’ve used the database on occasion and want to agree with Nacin, the cases where I do that either have uninstall/deactivate code or have a thought-out assessment of how important ‘x’ is to a client. That’s the #1 thing I don’t see from themes that change defaults. And if they all cleaned up after themselves I wouldn’t care whether they changed defaults in the database or not.

    There are times this is good to break, like when deciding to enforce a client’s workflow. For example: clients who have a minimum wage counter-person posting from the register/computer may warrant having roles with very limited admin options available, or even having hardcoded settings in a functionality plugin. And then, when one of us has Nacin or Otto’s knowledge or skill in WP, they’re defining rules and can probably decide when to break them.

  • I changed my default-option handling in Oenology, in large part due to Otto’s influence.

    Originally, I set the defaults as the DB option, and then queried the DB option. That approach works, but I think Otto’s approach is better.

    Now, I query the DB option inside of a function, and array_merge() my defaults array with the DB option (with appropriate error handling, of course), then return the result of the array_merge(). That way, if the DB option isn’t set, the defaults are returned; and if the user has set options, they override the defaults.

    What’s especially nice about this approach is that I can seamlessly add new options in future versions, and the Theme will handle those new options without a problem. Previously, I had to determine if the option had been set in the options array, and if not, set it. Now, all of that Theme version-checking is completely gone.

  • I agree with Otto that one of the fundamental rules to creating software that works is having a stable set of default settings out-of-the-box. Options are optional; if there is no option, a smart default should be the fallback.

    The blanket statement makes more sense for themes than it does plugins, since the only real distinction between them is that themes are presentational, and plugins are mostly mechanical.

    bbPress for example, creates a new role, modifies capabilities, and adds custom post-types and a taxonomy that alter the rewrite rules. Without these database changes, bbPress doesn’t work correctly.

    bbPress also drops all of its default options into the database on activation, to (like Nacin said above) limit the number of queries before the defaults are placed into WordPress’s object cache. You can see how it does this at the bbPress trac.

    We all agree that having smart defaults is a must. I’ll add that if a theme or plugin drops something in the database automatically, it should come with a proper uninstall routine to clean up after itself.