I have a lot of options in my custom theme and most of them are like: get_option('my_option')['depth']['more_depth'] as they are arrays. In order to write code in a "cleaner", more compact way I have created a function:

function my_options($key){
   $options = array(
      'depth_more_depth' => get_option('my_option')['depth']['more_depth']
   return $options[$key];

and I call the option like: my_options('depth_more_key'); Is this acceptable? I mean, the more functions you use, the slower the code compiles, especially in my case where the my_options() function gets called quite a lot. Is there a better, more efficient way - considered a "best practice" - to approach this?

  • I would avoid storing structured data in a single option, that means serialized PHP, which opens you up to security issues and several attack vendors with object deserialisation attacks. Would it not be better to have a my_option_depth_mor_depth option? A lot easier to debug, no serialisation, easy to modify, easy to update with SQL, human readable – Tom J Nowell Apr 15 '20 at 21:46
  • @TomJNowell Thanks for your answer. I decided to go with arrays as it makes more sense to me when it comes to options about a header where the header may have a "height" a "padding" etc. I think this is helpful at this time as I have a lot of options. – Arg Geo Apr 15 '20 at 21:55
  • Ok, these are just the comments not answers, but keep in mind there you gain only disadvantages by doing so, and add complexity. You did ask for best practice, which is not to store arrays inside options. You can put the retrieved data into an array in your function, but serialising data and putting it in the DB is bad practice. – Tom J Nowell Apr 16 '20 at 1:06

Is there a better, more efficient way - considered a "best practice" - to approach this?

Yes! Storing structured data in a single option is bad practice. You should use the option name to seperate your data.

Otherwise by using arrays and objects, WordPress cannot store those in the database, so it has to turn it into a string, meaning:

  • Clever users can insert serialised data, which gets turned into real arrays and objects when the option is retrieved on the next page load. This is called an object deserialisation attack, and has been known for a while
  • Debugging tools will show you serialised PHP rather than clean values
  • SQL queries that modify these values will mangle them, PHP serialised data contains the string length. So a naive site migration could break the site
  • It's impossible to use the options.php UI or the network admin UI to update the option values
  • By smushing all the options into a single option, you could run into the upper limit on option size
  • You've lost all control over which options are auto-loaded. Because they're all stored as a single option, either all of them are auto-loaded or none of them.
  • A lot of the checks and balances that WP and the Database would have done for you now need to be reproduced in PHP code, such as checking array keys exist, checking for empty arrays, etc

But most importantly, it's simply unnecessary to store them in an array, and it gives you no benefits.

So instead, use the option name to namespace your values, not arrays. e.g. my_option_depth_mor_depth. You could even use slashes similar to folder paths. Some popular plugins take this approach with action and filter names, e.g. ACF

I mean, the more functions you use, the slower the code compiles, especially in my case where the my_options() function gets called quite a lot.

To see this kind of slowdown you would need to define a lot of functions. Your single function will make your site slower by several microseconds. This will be imperceptible, and is statistically insignificant.

It's what your function does, not how many functions that matters.

However, I believe you're under the false assumption that every call to get_option makes a fresh call to the database. This is not the case.

  1. At the beginning of a request, WP fetches every option marked as autoload in a single query
  2. When options are loaded, they're stored in WP_Cache, along with any posts and their meta. A second call to get_option doesn't even touch the database.

So calling get_option repeatedly is cheap. If that is all your function does then you have nothing to fear. Don't speculate about these things, measure them.

Some additional notes:

  • The function calls get_option then immediatley uses the [] operator. It never checks that those array keys exist, or that the option even holds an array. As a result, this will crash the first time it's used if the option isn't set in advance
  • There's no validation on $key to check that such a key actually exists
  • There's no validation that $key is actually a string, it might be an array, an object, null, etc The parameter should have a type hint, e.g. ( string $key )
  • Use modern array syntax in line with the WP coding standards, e.g. [ 1,2,3,4 ] rather than array( 1,2,3,4 )
  • Run your code through PHPCodesniffer with the WPCS ruleset for the official WP coding standards. It will flag security and performance issues, including the storage of serialised data in the database.

Overall, the approach you tried to take with the function is of negligible performance impact. Trying to make it faster would be a micro-optimisation, no worthy of your time. There are very likely big performance gains to be had elsewhere. Such as avoiding DB writes on the frontend, eliminating HTTP requests, avoiding searching for posts via their post meta values, etc

A Note on Theme Mods

You mentioned your options are for theme settings, which means you're not using the correct API, you should be using theme mods instead.

Use get_theme_mod instead of get_option. WP will automatically namespace the values and keys to your theme so that even if another theme has the same names it won't matter. This is the API you should be using, ideally with the customizer.

  • Thanks for all the valuable information provided. I tried using get_theme_mod first but I switched to get_option as I really dislike the customizer. I find the user experience really unpleasant. – Arg Geo Apr 16 '20 at 19:50
  • Is there any way to use the theme mod API without having to deal with the wordpress customizer? – Arg Geo Apr 16 '20 at 20:17
  • get_theme_mod etc, the theme mod API is its own thing, and predates the customizer. Look up the docs for that function for examples – Tom J Nowell Apr 16 '20 at 20:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.