WordPress get_option(): Syntax, Defaults, Autoload & Pitfalls

WordPress get_option() function syntax, defaults, autoload, arrays and filters

Written by

in

Updated 16 October 2026 · By Abhilash Sahoo, Infyways

Quick answer: get_option() reads a single site-wide setting from the WordPress wp_options table.

$value = get_option( 'option_name', $default );
  • Returns the stored value (WordPress unserializes arrays and objects for you).
  • Returns false if the option doesn’t exist and you passed no default; otherwise it returns your $default.
  • Values usually come back as strings — even numbers (get_option('page_for_posts') → "0").
  • Autoloaded options are loaded once per request, so repeated calls don’t hit the database again.

Every result on this page was produced on a real WordPress 7.1.3 install (PHP 8.4) with WP-CLI — not copied from the manual.

What are the parameters and return value?

Real wp-cli output showing get_option return values and default parameter

The function signature from the official developer reference is:

get_option( string $option, mixed $default_value = false )
Parameter Type Notes
$option string The option name (the option_name column). Required.
$default_value mixed Returned when the option does not exist. Defaults to false.

Here is the real output for core settings, a missing option, and a missing option with a default:

get_option("blogname")          "WP Test"
get_option("admin_email")       "a@example.com"
get_option("page_for_posts")    "0"        // a string, not an int
get_option("does_not_exist")              false
get_option("does_not_exist","fallback")   "fallback"

How do I use get_option? (examples)

Read a core setting

$title = get_option( 'blogname' );
$email = get_option( 'admin_email' );
$per_page = (int) get_option( 'posts_per_page' ); // cast, because it's a string

Read your plugin’s settings array

get_option returning an array and the serialized value stored in wp_options

Store one array per plugin instead of dozens of separate options. WordPress serializes it on write and unserializes it on read automatically:

update_option( 'iw_settings', array( 'layout' => 'grid', 'cols' => 3 ) );
$opts = get_option( 'iw_settings', array() );   // always returns an array
echo $opts['layout'];                            // "grid"

In the database that single row holds a:2:{s:6:"layout";s:4:"grid";s:4:"cols";i:3;} — but you never call serialize() or unserialize() yourself.

Save, update and delete options

Real output of add_option, update_option and delete_option return values

get_option() has three partners. Watch their return values:

Function Does Returns
add_option() Creates an option (fails quietly if it exists) true / false
update_option() Creates or updates; the one you’ll use most true if changed, false if unchanged or failed
delete_option() Removes the option true / false

Real run:

update_option("iw_demo","world")   // true  (value changed)
update_option("iw_demo","world")   // false (same value — NOT an error)
delete_option("iw_demo")           // true
get_option("iw_demo","GONE")       // "GONE"

The second update_option() returning false trips people up constantly: it means “nothing changed”, not “it failed”. Don’t treat it as an error.

How does autoload work (and what changed in WordPress 6.6)?

WordPress 6.6+ autoload values auto, on and off verified on WordPress 7.1.3

Every option row has an autoload flag. Autoloaded options are pulled into memory in one query at the start of each request by wp_load_alloptions(), so reading them later is free. WordPress 6.6 changed the values stored in that column. Confirmed on WordPress 7.1.3:

How you add it Stored value (6.6+) Behaviour
add_option(,) (let core decide) 'auto' Core auto-decides based on size
Legacy 'yes' 'on' Always autoloaded
Legacy 'no' 'off' Loaded on demand

Before 6.6 the column only held 'yes'/'no'. If you query the autoload column directly, your code must now also handle 'auto', 'on' and 'off'. Passing 'yes'/'no' still works for backward compatibility. Keep large or rarely used options off autoload so they don’t bloat every page load — our WordPress plugin development work almost always starts with trimming an overgrown autoloaded options set.

Does get_option hit the database every time?

Autoloaded options add zero DB queries; pre_option and option filters demo

No. For an autoloaded option, we read it five times in a row and measured the queries:

5 × get_option("iw_auto")  →  0 extra DB queries

All autoloaded options are already in memory. A non-autoloaded option is fetched on first use and then cached (via the object cache if one is configured). So get_option() is cheap; the thing to manage is what you autoload, not how often you call it.

How do I filter or override a value?

Two filters wrap every read:

  • option_{$option} — change the value after it’s read from the database.
  • pre_option_{$option} — return any non-false value to short-circuit the read entirely (the database is never touched).
add_filter( 'option_iw_color', fn($v) => strtoupper($v) );   // "blue" → "BLUE"
add_filter( 'pre_option_iw_color', fn() => 'SHORTCIRCUIT' );  // DB skipped

Both verified live. pre_option_ is how plugins force a setting (for example, defining it as a constant in wp-config.php).

get_option vs post meta, theme mods and transients

get_option vs get_post_meta, get_theme_mod, get_transient and get_site_option

Pick the right storage API for the job:

Function Use it for Scope Expires?
get_option() Site-wide settings Whole site No
get_post_meta() Data attached to one post — see our update_post_meta guide A single post No
get_theme_mod() Theme / Customizer settings Active theme (stored as one option) No
get_transient() Temporary cached data (API responses, expensive queries) Whole site Yes
get_site_option() Network-wide settings on multisite Whole network No

Multisite note: on a network, get_option() reads the current site’s settings, while get_site_option() reads network-wide settings. A transient is just an option with an expiry — use it when the data can be regenerated, and get_option() when it must persist.

Reading options over the REST API

Settings that are registered with register_setting() and marked show_in_rest are exposed at /wp-json/wp/v2/settings (authenticated). We queried it on the test site and it returned the whitelisted options:

GET /wp/v2/settings → 200
title, description, timezone, posts_per_page, show_on_front, page_for_posts, ...
title = "WP Test"   posts_per_page = 10

Only options that are explicitly registered for REST appear here — your custom options won’t show up unless you register them. This is the modern, safe way for a block editor or headless front end to read and write settings without touching the database directly.

Common mistakes with get_option()

Mistake What happens Fix
Expecting an integer or boolean You get a string ("0", "1") Cast: (int), or compare loosely with care
Treating false as “error” A missing option and a stored false both return false Pass a unique default and compare, or use get_option() === false
Reading update_option() false as failure You throw an error when nothing was wrong Remember false = “value unchanged”
Autoloading huge options Every page load gets slower Add big/rarely used options with autoload off
Running get_option() too early Returns the default before options load Read inside a hook (e.g. init), not at file top level
Not escaping before output Stored HTML can break or XSS your page echo esc_html( get_option('blogname') );

Frequently asked questions

What does get_option() do in WordPress?

It reads one named setting from the wp_options table and returns its value, automatically unserializing arrays and objects. It’s the standard way to read site-wide configuration saved by WordPress core, themes and plugins.

What is the default return value of get_option()?

false. If the option doesn’t exist and you didn’t pass a second argument, you get false; if you passed a default, you get that default instead.

Why does get_option() return false?

Either the option name doesn’t exist, or the stored value genuinely is false. Because the two look identical, pass a unique default (get_option('key','__missing__')) and compare, so you can tell “not set” from a real false.

Does get_option() return a string or the original type?

Scalars (numbers, booleans you stored as text) usually come back as strings, so cast them. Arrays and objects are returned in their original type because WordPress unserializes them for you.

Is get_option() cached?

Yes. Autoloaded options are loaded once per request into memory, so repeated calls add no database queries. Non-autoloaded options are fetched on first use and cached after that (in the object cache if one is active).

How do I get an array from get_option()?

Store the array with update_option() and read it back with get_option('key', array()). WordPress handles serialization both ways, so you get a native PHP array. Passing array() as the default avoids errors when the option is missing.

What changed about autoload in WordPress 6.6?

The autoload column now stores 'auto', 'on' and 'off' instead of only 'yes'/'no'. Passing 'yes'/'no' still works, but code that inspects the raw column value must handle the new strings. Core also auto-decides autoload based on option size.

What’s the difference between get_option() and get_site_option()?

On a single site they’re effectively the same. On multisite, get_option() reads the current site’s settings and get_site_option() reads network-wide settings shared across all sites.

Should I use the Options API or the Settings API?

The Options API (get_option/update_option) is the low-level storage. The Settings API builds admin forms on top of it with validation and sections. Use the Settings API to register and render settings pages; it still stores everything as options you read with get_option().

How do I read an option over the REST API?

Register it with register_setting() using show_in_rest, then read it from /wp-json/wp/v2/settings with an authenticated request. Unregistered options are not exposed.

Working in WordPress regularly? You might also like our guides on update_post_meta(), getting the featured image URL, and getting the current page name.