最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

options - Settings API get_option best practices

programmeradmin5浏览0评论

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 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?

Share Improve this question asked Apr 15, 2020 at 21:12 Arg GeoArg Geo 4591 gold badge8 silver badges20 bronze badges 4
  • 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 Commented Apr 15, 2020 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 Commented Apr 15, 2020 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 Commented Apr 16, 2020 at 1:06
  • I don't think it's bad practice if you do it correctly. Only "bad practice" if the implementation is bad. Couldn't you checkout the Redux Framework? – Philip Commented Sep 30, 2023 at 18:16
Add a comment  | 

1 Answer 1

Reset to default 1

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.

发布评论

评论列表(0)

  1. 暂无评论