A common issue with plugins is where people insist they must call wp-load.php directly so that they can call WordPress functions and data when WordPress isn’t loaded. When I push back on that code, the common rationale is that there’s an external service that needs to ping a reliable URL to run code.

You Don’t Know Where WordPress Is

When you hardcode in paths, or assume that everyone has WordPress in the root of their domain, you cause anyone using ‘Giving WordPress it’s own directory’ (a very common setup) to break. In addition, WordPress allows users to change the name of the wp-content folder, so any plugin that tries to guess where it is would break on any site that choses to do so.

This cuts both ways. First your clever script that tries to go to example.com/wp-content/plugins/your-plugin/yourfile.php is going to fail if someone moves that folder. Second your clever file that looks for wp-load.php by going up a couple folders will also fail.

You can’t know where WordPress is. The only way to know all that would be to do things from within WordPress.

Never Call Files Directly

The only files you should ever call directly in your code is your code’s files or if you’re checking for the existence of another plugin or theme. This is the only time it’s smart to be hardcoding in paths of other code directly into your code.

if ( is_plugin_active( 'plugin-directory/plugin-file.php' ) ) { } 

Since most people call these files to have access to WordPress ‘without loading WordPress,’ the actual correct fix is to tie processing functions (the ones that need but don’t have access to core functions) into an action hook, such as “init” or “admin_init”.

Code you add to WordPress should be inside WordPress, only accessible to people who are logged in and authorized, if it needs that kind of access. Plugin’s pages should be called via the dashboard like all the other settings panels, and in that way, they’ll always have access to WordPress functions.

What’s The Right Answer?

Okay. There’s one case where it makes sense that you might possibly need to call a URL directly. If you’re hooking WordPress up to a service and you want to have a good URL to call, then yes, you would be well served by having one of the following:

  • example.com/?myplugin=runstuff
  • example.com/myplugin/

Don’t those look nice? There are two main ways to get there.

External Rules

An external rule is basically you adding an redirect rule for a URL to point to a file. You could do this in .htaccess or nginx.conf but if you do it in WordPress, it looks like this:

add_action( 'init', 'myplugin_external_rules' );
function myplugin_external_rules() {
    global $wp_rewrite;
    $plugin_url = plugins_url( 'yourfile.php', __FILE__ );
    $plugin_url = substr( $plugin_url, strlen( home_url() ) + 1 );
    $wp_rewrite->add_external_rule( 'myplugin$', $plugin_url );
}

Now the obvious issue here is that you’re still calling a php file directly, which means you don’t get any access to WordPress functions. Boo. Thankfully there’s another answer.

Internal Rules

While more complicated and weird, this is a better solution.

First you need to actually make the rule:

add_action( 'init', 'myplugin_internal_rules' );
function myplugin_internal_rules() {
    add_rewrite_rule( 'myplugin', 'index.php?myplugin=runstuff', 'top' );
}

This means that those two example URLs I pitched before are the same thing.

Next you need to tell WordPress not to stomp all over the query variables:

add_filter( 'query_vars', 'myplugin_query_vars' );
function myplugin_query_vars( $query_vars ) {
    $query_vars[] = 'myplugin';
    return $query_vars;
}

You have to do this because otherwise WordPress won’t know what to do with the query variable.

Finally we tell WordPress what to actually do with your variable:

add_action( 'parse_request', 'myplugin_parse_request' );
function myplugin_parse_request( &$wp ) {
    if ( array_key_exists( 'myplugin', $wp->query_vars ) ) {
        include 'yourfile.php';
        // Call your functions here!
        // function_name_thingy();
        exit();
    }
    return;
}

You’ll notice that // your functions here code is waiting for your code. That’s because this time we’re including the PHP file and then in there you’ve theoretically written your code in a nice little function. And that function? Uses WordPress functions because it is one.

Reader Interactions

%d bloggers like this: