TL;DR: The 10-Second Fix
Most of the time, this error happens because you forgot to tell your function to look for the global database variable. Adding one line usually solves it immediately:
function get_my_data() {
global $wpdb; // This is the missing link
return $wpdb->get_results("SELECT * FROM {$wpdb->prefix}options WHERE option_name = 'siteurl'");
}
Why Your Code Is Crashing
PHP is fairly blunt. When it says it can't call a function on 'null,' it means the variable youâre usingâin this case, $wpdbâis currently empty. Itâs like trying to start a car when you donât even have the keys in your hand. In WordPress, $wpdb is the primary bridge to your MySQL database. If that bridge isn't built before you try to cross it, the script fails.
I see this happen most often for three reasons:
- **Variable Scope:** Your function is living in its own bubble and doesn't know `$wpdb` exists globally.
- **Bad Timing:** You're firing off a query before WordPress has finished loading its core database files.
- **Isolated Scripts:** You've created a custom `.php` file but didn't invite the WordPress environment to the party.
How to Fix It
1. Bring $wpdb Into Scope
PHP functions are isolated by design. Even if WordPress defines $wpdb at the very start, your specific function can't see it unless you explicitly pull it in. This is the culprit in about 90% of plugin and theme errors.
The Wrong Way:
function fetch_user_count() {
$count = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->users"); // Error: $wpdb is null here
}
The Right Way:
function fetch_user_count() {
global $wpdb;
$count = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->users");
return $count;
}
2. Respect the Loading Order
WordPress follows a strict boot sequence. If you place a database query at the very top of functions.php without wrapping it in a hook, it will likely fail. The $wpdb object hasn't been instantiated yet.
Always wait for WordPress to be ready. Use the init or plugins_loaded hooks to ensure the environment is stable before touching the database.
add_action('plugins_loaded', function() {
global $wpdb;
// Now it is safe to run your queries
$results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}posts LIMIT 5");
});
3. Bootstrapping External Scripts
If youâre running a standalone migration script or a custom API endpoint outside the WordPress folder structure, $wpdb won't exist by default. You need to manually load the WordPress core. Point your script to wp-load.php. This file acts as the gateway to all WordPress functions and variables.
<?php
// Adjust the path based on where your script lives
require_once( __DIR__ . '/wp-load.php' );
global $wpdb;
$user_count = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->users");
echo "Total users: " . $user_count;
?>
4. Working With Classes
Using global inside classes is common but can get messy. A cleaner approach is to pass $wpdb into your class constructor. This makes your code easier to test and much more readable.
class MyPluginHandler {
private $db;
public function __construct($database_object) {
$this->db = $database_object;
}
public function get_data() {
return $this->db->get_results("SELECT * FROM my_table");
}
}
// Usage
global $wpdb;
$my_handler = new MyPluginHandler($wpdb);
How to Verify Everything is Back to Normal
Don't just refresh the page and hope for the best. Open your wp-content/debug.log file. If youâve fixed the scope issue, the Fatal error entries should stop appearing. You can also add a simple check to see if the object exists before using it. This prevents a total site crash if something goes wrong later.
global $wpdb;
if (!isset($wpdb)) {
error_log('Database object is missing!');
return;
}
$data = $wpdb->get_results("...");

