TechEarl

Fix 'Call to undefined function get_option()' in WordPress

How to fix the 'Call to undefined function get_option()' fatal error in WordPress. Covers premature WP function calls, the wp-load.php bootstrap, the modern WP-CLI alternative, and the plugin-developer checklist.

Ishan KarunaratneIshan Karunaratne⏱️ 12 min readUpdated
How to fix the 'Call to undefined function get_option()' fatal error in WordPress. Covers premature WP function calls, the wp-load.php bootstrap, the modern WP-CLI alternative, and the plugin-developer checklist.

Fatal error: Call to undefined function get_option() almost never means WordPress is broken. It means PHP reached a call to get_option() (or wp_insert_post(), or current_user_can(), or any other WordPress function) before wp-load.php had a chance to define it. The fix is to make sure WordPress is loaded before your code runs, or to restructure the code so it runs from inside a WordPress request lifecycle.

How do I fix 'Call to undefined function get_option()' in WordPress?

The error is raised when PHP encounters get_option() but the WordPress runtime isn't loaded — get_option only exists after wp-includes/option.php has been included by wp-settings.php, which is included by wp-load.php, which is the entry point for every WordPress request. If a standalone PHP file or a cron script is calling WordPress functions without bootstrapping WordPress first, the function doesn't exist yet and PHP throws a fatal.

The fast fix for standalone scripts that genuinely need WordPress functions: bootstrap WordPress by requiring wp-load.php before your code runs. The better fix for plugin and theme code: never call WordPress functions at file-load time. Wrap everything in a callback hooked to init, plugins_loaded, or whichever WordPress hook fires after the runtime is ready.

Jump to:

Root cause: when get_option() doesn't exist yet

The WordPress function load order is, simplified:

code
HTTP request → index.php → wp-blog-header.php → wp-load.php → wp-config.php → wp-settings.php
                                                                                      ↓
                                                                  wp-includes/option.php (defines get_option)
                                                                  wp-includes/plugin.php (defines do_action)
                                                                  ...500+ more files...
                                                                                      ↓
                                                                              plugins_loaded action
                                                                                      ↓
                                                                              init action
                                                                                      ↓
                                                                              the request proceeds

Any code that calls get_option() before that chain has completed gets the fatal error. The original 2015 framing of this error as "corrupted core files" is misleading in the vast majority of cases — corrupted core is one possible cause, but a far rarer one than premature function calls.

The most common scenarios

The five places I actually see this error in 2026:

1. A standalone PHP file accessed directly

A developer drops a file like /wp-content/themes/mytheme/scripts/import.php and hits it from the browser at https://example.com/wp-content/themes/mytheme/scripts/import.php. PHP serves the file directly — wp-load.php is never executed for that URL. The first get_option() call inside the file throws.

2. Custom cron script run from system cron

bash
# /etc/cron.d/site-cron
0 * * * * www-data php /var/www/html/wp-content/scripts/cleanup.php

Same problem: cleanup.php was invoked directly. PHP didn't go through Apache or Nginx, so the WordPress request lifecycle never fired.

3. Plugin code at file-level scope

php
// Bad: runs at require() time, before init has fired
$option = get_option( 'my_plugin_settings' );

If this is at the top of your plugin file and the plugin is loaded by wp-settings.php before all required files are included, get_option may not be defined yet — or worse, it's defined but the database connection isn't ready and get_option() returns garbage.

4. Composer autoload conflicts

A plugin uses Composer's autoloader and includes a class that calls get_option() in its constructor. If the class is instantiated during composer.json post-install hooks (or anywhere outside a normal WordPress request), get_option isn't loaded.

5. Truly corrupted core files

Rare in 2026 — but if you can confirm wp-includes/option.php is missing or contains a parse error, then yes, a core file replacement is the fix. This was much more common in shared-hosting eras when files genuinely got corrupted during FTP uploads.

The fast fix: bootstrap with wp-load.php

For a standalone script that legitimately needs WordPress functions, require wp-load.php at the top:

php
<?php
// /var/www/html/wp-content/scripts/cleanup.php

require_once dirname( __FILE__ ) . '/../../../wp-load.php';

// Now WordPress is loaded
$option = get_option( 'siteurl' );
echo $option;

The path navigation dirname( __FILE__ ) . '/../../../wp-load.php' walks three directories up from wp-content/scripts/ to the WordPress root. Adjust the count based on where your script actually lives.

This works but has costs:

  • It loads the entire WordPress stack — every plugin, every theme function, all the database connections. For a five-line cleanup task, that's a lot of overhead.
  • Errors in any active plugin during bootstrap will kill your script.
  • You inherit the request's user context (or none, for CLI), which can lead to permission-related surprises.

For one-off cleanup scripts it's fine. For anything you'll run regularly, prefer WP-CLI.

The modern preferred approach: WP-CLI

WP-CLI handles bootstrapping for you and gives you a per-command API:

bash
# Read a single option
wp option get siteurl

# List all options matching a pattern
wp option list --search='my_plugin_*' --format=table

# Update an option
wp option update my_plugin_settings '{"key":"value"}' --format=json

# Run arbitrary PHP with WordPress loaded
wp eval 'echo get_option("siteurl");'

# Run a PHP file with WordPress loaded
wp eval-file path/to/script.php

wp eval-file is the modern replacement for the "require wp-load.php" pattern. WP-CLI loads WordPress once and runs your file in that context. From cron:

bash
0 * * * * www-data /usr/local/bin/wp --path=/var/www/html eval-file /var/www/html/wp-content/scripts/cleanup.php --quiet

The --path flag tells WP-CLI where the WordPress install lives. --quiet suppresses non-error output (cron will email anything that hits stdout otherwise).

For one-off interactive debugging, wp shell drops you into a REPL with WordPress loaded — far better than dropping var_dump() calls into a theme file.

Hook into init instead of file-level scope

Inside a plugin or theme, never call WordPress functions at the top level of the file. The right pattern:

php
<?php
/**
 * Plugin Name: My Settings Reader
 */

// BAD: runs before WordPress may be ready
// $option = get_option( 'my_plugin_settings' );

// GOOD: defer until init
function my_plugin_load_settings() {
    $option = get_option( 'my_plugin_settings' );
    // ... use $option
}
add_action( 'init', 'my_plugin_load_settings' );

init fires after WordPress core, all active plugins, and the active theme's functions.php have finished loading. At that point every WordPress function is available, the database is connected, the current user is resolved, and you're safe to call anything.

For code that needs WordPress functions but must run before init (rare), use plugins_loaded — fires once all plugins are loaded but before init:

php
function my_plugin_early_setup() {
    // get_option is available here
    if ( get_option( 'my_plugin_feature_flag' ) ) {
        // register early hooks
    }
}
add_action( 'plugins_loaded', 'my_plugin_early_setup' );

Plugin developer checklist

When writing a plugin, the rules that prevent this error:

  1. No WordPress function calls outside a function body. Variable assignments at file scope using get_option() are the most common offender.
  2. No database queries before plugins_loaded. $wpdb is available earlier but using it before plugins are loaded can race with other plugins' table-creation hooks.
  3. Use register_activation_hook() for one-time setup. Don't run install logic at file load.
  4. Guard against direct file access. Add if ( ! defined( 'ABSPATH' ) ) { exit; } at the top of every PHP file in your plugin.
  5. Don't include files that include WordPress. A plugin file that does require 'wp-load.php' creates an infinite-loop scenario when WordPress loads the plugin.

The ABSPATH guard is the canonical defense against the entire class of "scripts being accessed directly" bugs:

php
<?php
/**
 * Plugin Name: My Plugin
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Prevent direct file access
}

// ... rest of plugin

If a curious visitor hits https://example.com/wp-content/plugins/my-plugin/my-plugin.php directly, PHP would otherwise execute the file with no WordPress context. The ABSPATH check turns that into a clean exit.

PHP 8.x vs PHP 7.x error format

The error message text shifted slightly between PHP versions:

PHP versionError text
PHP 7.xFatal error: Call to undefined function get_option() in /path/to/file.php on line 12
PHP 8.0+Fatal error: Uncaught Error: Call to undefined function get_option() in /path/to/file.php:12

PHP 8 wraps the fatal in an Error exception that includes a stack trace, which is significantly more useful for debugging. If you're still on PHP 7.x and seeing the older format, enabling display_errors and error_reporting=E_ALL in your wp-config.php will at least show the file and line number:

php
// wp-config.php (development only)
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

Errors go to wp-content/debug.log rather than the browser, which is safer in production-adjacent environments.

If the error is hitting your script before WordPress is loaded enough to set those constants, fall back to native PHP error logging:

php
ini_set( 'log_errors', '1' );
ini_set( 'error_log', '/var/log/php-errors.log' );

Troubleshooting matrix

SymptomLikely causeFix
Error in a standalone scriptScript doesn't bootstrap WordPressAdd require_once '/path/to/wp-load.php'; or run via WP-CLI
Error in plugin activationget_option called at file scopeWrap in a function and hook to register_activation_hook()
Error in cron jobScript invoked directly by cronSwitch cron to call wp eval-file via WP-CLI
Error only on multisitems_files_handler.php or premature multisite callUse is_multisite() only after plugins_loaded
Error after composer installClass instantiated outside WordPress lifecycleMove construction to a hook callback
Error after PHP upgradePlugin used a function deprecated in newer PHPCheck error_log for "deprecated" notices; update plugin
Error after WordPress core updateGenuinely corrupted core filesRe-download matching WordPress version, overwrite wp-admin and wp-includes
Error only at admin URLPlugin loads before pluggable.php in adminHook to admin_init instead of init
ABSPATH not definedDirect file access bypassing index.phpAdd if ( ! defined( 'ABSPATH' ) ) { exit; } and re-route via index.php

For specific WordPress-related PHP issues:

What to do next

For related WordPress troubleshooting:

FAQ

TagsWordPressErrorsDebuggingPHPTroubleshootingwp-load.phpWP-CLI
Share
Ishan Karunaratne

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

Rank the biggest files on a full disk with find -printf '%s %p' piped to sort -rn. The GNU one-liner, the BSD stat variant for macOS, why -xdev matters, human-readable sizes, and when du or ncdu beats find.

How to Find the Largest Files on Disk (find, sort, du)

find / -xdev -type f -printf '%s %p\n' | sort -rn | head -20 gives you a ranked list of the biggest files on a full disk. The GNU one-liner, the BSD/macOS stat variant, why -xdev matters, human-readable output with numfmt, when to switch to du or ncdu for per-directory totals, and the mistakes that send a scan into /proc.

Using regex in Nginx with location blocks and the rewrite directive: location modifier priority, the rewrite directive flags, return-based redirects, and copy-paste config for HTTPS redirects, www normalization, trailing slashes, 301 redirects, clean URLs, and blocking by user-agent or IP.

How to Use Regex in Nginx (location and rewrite)

Use regex in Nginx with location blocks and the rewrite directive: how location modifiers and matching priority work, why return beats rewrite for redirects, and copy-paste config for HTTPS, www, trailing slashes, 301s, clean URLs, and access blocking.