Don't include wp-load, please.

Edit: This post has moved to here: http://ottopress.com/2010/dont-include-wp-load-please/. Take your comments there.

Time for Otto’s general griping: WordPress plugin programming edition.

Here’s a practice I see in plugins far too often:

  1. Plugin.php file adds something like this to the wp_head:
    <script src='http://example.com/wp-content/plugins/my-plugin/script.js.php'>
  2. Script.js.php has code like the following:
    <?php
    include "../../../wp-load.php";
    ?>
    ... javascript code ...
    

The reason for this sort of thing is that there’s some option or code or something that the javascript needs from the database or from WordPress or whatever. This PHP file is, basically, generating the javascript on the fly.

Usually, the case for this turns out to be something minor. The code needs the value from an option, or some flag to turn it on or off. Or whatever.

Problem is that finding wp-load.php can be a bit of a chore. I’ve seen extreme efforts to find and load that file in plugins before, including searching for it, examining the directory structure to make decent guesses, etc. This sort of thing has existed even before wp-load.php came around, with people trying to load wp-config.php themselves and such.

But the real problem is simpler: This is always the wrong way to do it.

Why this is wrong

  1. You don’t have the first clue where wp-load.php actually is. Both the plugin directory and the wp-content directory can be moved around in the installation. ALL the WordPress files could be moved about in this manner, are you going to search around for them?
  2. You’ve instantly doubled the load on that server. WordPress and the PHP processing of it all now have to get loaded twice for every page load. Once to produce the page, and then again to produce your generated javascript.
  3. You’re generating javascript on the fly. That’s simply crap for caching and speed and such.

The right way? Well, there’s two options.

Right Way the First

Generate your options separately, put them in using wp_print_scripts.

Examine this pseudo-code:

add_action('wp_print_scripts','myscript');
function myscript() {
?>
<script type="text/javascript">
  var plugin_option= <?php echo json_encode(get_option('plugin_option')); ?>;
</script>
<?php
}
wp_enqueue_script('myscript','...myscript.js',...);

Basically, the plugin option value is inserted directly into the page. The myscript.js file that loads shortly afterwards can use this value however it likes.

Why this is better:

  1. No searching for wp-load.php.
  2. The javascript is static, only your options are variable. No added load on the site.
  3. Static scripts mean you get great speed from caching.

Sidenote: Note the use of json_encode? You should always use this when producing javascript variables from PHP variables. It handles quoting and escaping and everything for you. It can even turn PHP arrays into javascript arrays nicely! Handy for storing all your options in one place.

What if you have a ton of plugin options though? What if you really WANT to generate that javascript on-the-fly?

Right Way the Second

Generate the javascript from a call to WordPress itself, not to a separate file.

Examine this pseudo-code:

add_filter('query_vars','plugin_add_trigger');
function plugin_add_trigger($vars) {
    $vars[] = 'plugin_trigger';
    return $vars;
}

add_action('template_redirect', 'plugin_trigger_check');
function plugin_trigger_check() {
	if(intval(get_query_var('plugin_trigger')) == 1) {
	?>
function javascript_code() {
...
}
<?php
	exit;
	}
}

That code does something a little clever. Basically it’s adding a new query variable to be used as the “trigger”. When the trigger gets pulled, a bunch of javascript is generated, then the code *exits*, stopping WordPress from proceeding any further.

So, with that code in a plugin, a call to http://example.com/?plugin_trigger=1 will now produce your javascript code. This is running entirely within the content of a WordPress call, so you get all the WP functions and database access with which you can generate your code as well.

Thus, you can happily put your

<script src="http://example.com/?plugin_trigger=1">

code into the page and it’ll load up that “file” just fine.

Why this is better:

  1. No searching for load.php
  2. … Well, okay, there is no other reason. The load problem still exists, and your caching issues still exist. You’re programmatically generating code here, after all. It’s not a particularly good practice to do. Still, sometimes this is easier and faster to develop, even if it’s never actually “necessary”.

Also see that while I’m using the number 1 there as the value I’m checking for, that value can be anything you like. If you want to be a smartass about it and have all sorts of different things that could be generated, you can do them all with that one trigger. It’s still a generally bad idea because of the added load, but hey, maybe you have a legitimate reason. I’ve seen one or two valid reasons to do this before.

Wrap up

Also note all of the above also applies to “generating” CSS code. It’s just as unnecessary. Usually more so.

So please, stop including wp-load. It’s just wrong. Let WordPress load itself, and make your plugin do the output it needs to produce in the right places.

48 thoughts on “Don't include wp-load, please.

  1. Thanks for this post! I was trying to figure out how to cleanly access WP variables inside my javascrip. Perfect timing!

  2. “Right Way the Second” makes WP do too much unnecessary work. Instead, attach your callback to “init”, check for the $_GET argument (your web server has already done that parsing for you–no need to duplicate it within WP), print your js and then exit before wp() gets called to do a bunch of unnecessary parsing work.

    1. True, if you hook it at the “init” action, then the wp() call has not been made yet, meaning that the main posts query hasn’t run and such. Depending on what you need initialized already, this may be valid and would certainly save some time and processing, if you just need a valid wpdb object and/or options loaded.

      But then again, sometimes you need the main query. In which case you’d want to hook to the template loader as I’ve shown.

      1. But then again, sometimes you need the main query. In which case you’d want to hook to the template loader as I’ve shown.

        If you need the main query, then skip the parsing and just call query_posts() directly. Since you already know what results you want, there’s never a need for wp() to parse the request that you’re making. The whole point of parsing is to determine the purpose of the request, which the “plugin_trigger” argument has already sufficiently determined.

        1. Not necessarily. The one time I’ve actually seen that used in a useful manner was in the WP-Microsummary plugin. And it gives different results based on the URL preceding the ?microsummary=1 part of the URL. Works nicely.

          Anyway, I recommended against the second way in general. The first way is definitely preferred.

  3. Hi Otto,

    thanks for this post!

    I have a similar question that is also related to the wp-load.php: A lot of plugins try to load wp-load.php to answer AJAX requests (i.e. they include something like html = jquery.get('http://www.example.com/.../plugins/.../my-ajax.php'); and my-ajax.php calls wp-load.php).

    This obviously has the same problems and disadvantages. Unfortunately I have not found any good posts/tutorials on the correct alternatives (well ok, found some older ones, but they don’t take into account the latest developments on non-logged-in actions).

    Thus, I wondered, if you know any such tuturials (or maybe could write one in addition to this post here), as you seem to know the trouble of wp-load.php pretty well.

    Regards,
    Tobias

    1. Rewrite the plugin so the ajax uses wp-load.php directly rather than calling a php file in the plugin. If a plugin author wants to see how that’s done, the P2 theme is a good example.

  4. Is using the query vars compatible with WP Super Cache etc?

    My main problem is that the plugin caches even query pages so, e.g. in my plugin that needs that the query result not be cached, the method backfires.

    I have been thinking of adding an extra query var in the form of wp_nonce. Would this work?

    1. No, not by itself. Using Super Caching bypasses WordPress entirely, so no PHP code gets run at all on those cases where the straight HTML is served.

        1. If you need to make a plugin work with Super Cache, then you can either:

          a) Use a “Half on” mode and write a Super Cache plugin to do what you need to do.

          b) Or, make the code as static as possible, using all static JS, then retrieve the data you need with a direct AJAX call to admin-ajax.php. Super-cache won’t cache those.

    1. Quite simply, you should never need to do that. Your plugin loads as part of WordPress. Instead of calling your plugin directly, you should call WordPress under a condition such that your plugin can recognize the situation and take different actions. That’s what I’m getting at here.

    1. While that’s not exactly what it’s meant to do, yes, you could use it to pass pretty much any variables you like to a static script.

  5. All things right here.

    Another alternative is simply to have a WP independent javascript file where options can be passed as query string. For instance, if you need plugin options $stuff and $thing: include script.js.php?stuff=xxx&thing=yyy then get (and sanitize) values .

    1. If the values are such that they can be passed in that manner, then yes. However this still causes caching problems (still building javascript on the fly), so putting those values in with wp_print_scripts makes more sense.

    2. I suggested this a while ago and the idea was slammed by Otto and a few others as being stupid.

      I’m now printing stuff in the head, but it makes for bloated page sizes and horrid looking code unfortunately.

      I’ve been considering caching it as a static file, but obviously that would only work when the folder was writable.

      1. I doubt I called it “stupid”. My problem with it is that it’s not really any better. It does prevent loading wordpress, but you’re still using server time to dynamically build script code. Fir a small number of variables, putting it in the wp_head is just more efficient.

        An approach like this which puts variable data into a get request still means putting all your data in that page itself, as a URL. So you’re not really saving on size and you create the server load and still can’t cache properly. I just don’t see what possible advantages the technique offers.

  6. JavaScript should never need to be generated on the fly. I have never seen a use for it. Ever. Localized JavaScript variables negate the need for dynamic JavaScript.

    Dynamic CSS, on the other hand, that’s another story. I used PHP and passed query variables instead of searching for wp-load.

    I really liked your json_encode sample since it encouraged localization. One other thing you might want to mention is the wp_localize_script function, which behaves similarly to your json_encode example.

    In all, I learned a lot. My plugin makes use of wp-load in various places (not in JS files), and I will use this information to re-work some of the code.

    Take care.

  7. As a heads up, I couldn’t get json_encode to work, as it uses a header (check class-json.php, line 238) and results in a PHP error.

    Instead, I found that calling the encodeUnsafe method in the json class directly results in satisfactory results.

    <script type='text/javascript'>
    /* <![CDATA[ */
    var wpajaxeditcomments =
    <?php
    require_once(ABSPATH . '/wp-includes/class-json.php' );
    $wp_json = new Services_JSON();
    echo stripslashes($wp_json->encodeUnsafe($this->get_js_vars($post->ID)));
    ?>;
    /* ]]> */
    </script>

    My get_js_vars function returns an array. I like this method over wp_localize_script just because the encodeUnsafe method prints them all on one line. wp_localize_script puts them each on a separate line and increases pageload.

    1. That header problem is fixed in WordPress 2.9.1. Check compat.php and see that json_encode uses the encodeUnsafe function, not the normal encode one (which produces the header).

      Also, you cannot rely on calling the json class stuff directly like that, because it might not get loaded at all. PHP 5 and later versions have a json_encode function built into them. The compat one only gets loaded when the site is running PHP 4.

      So you should use json_encode, always. And upgrade WordPress.

  8. Thanks for writing this up Otto. I’ve discussed this a lot with various people over the past year and no one has come up with a reasonable solution.

    I never liked the idea of loading WordPress directly as in “Right Way the Second” as I was concerned it would load too much unneeded junk in the process, but filosofo’s suggestion seems to get around that quite nicely.

    1. The first method is still the preferred approach. It is the fastest code, the quickest to load, it caches properly, and it produces the smallest total page sizes. Best to stick with that if you possibly can.

      1. I agree on that now for scripts, however there are other uses, including dynamically created CSS for when you can’t write to the WP installation to cache the CSS file statically and so using this technique is the only option to use without loading the CSS directly into each page. In my experience, the difference in page load times is too small to measure on most servers, but on some servers it totally blows out the load times really badly.

        I assume the exact same techinque would be used for processing AJAX data too.

        1. I spoke too soon. I just saw your comment above about AJAX and it seems this is not the correct way to handle those either …. back to the drawing board for me :p

        2. I have used the second method I detailed above for CSS before. I’m not proud of that, but it was necessary in the given context.

          For speed reasons alone, I would recommend generating the CSS whole, storing it all in a single place, then merely outputting it on demand, instead of generating it fresh from options each and every time.

          1. In the past I stored the CSS whole inside the WP database, then outputted it via a file which loaded wp-load.php. I’m now caching that in a static file, with a fall-back to wp-load.php when the static file does not exist. It seems to be working well so far.

          2. I have a plugin which stores custom CSS whole in the database in the same way. Currently, I output it like this. Right at the top of the plugin:

            if ($_GET[‘trigger’] == 1) { ?>
            $options = get_option(‘plugin_options’);
            header( ‘Content-Type: text/css; charset=utf-8′ );
            echo $options[‘custom_css’];
            exit;
            }

            This is the fastest way I can find to output the data without actually writing it to a static file. This stops WordPress as early as possible, right at the plugin loading, minimizing the impact on the system. Still not ideal, of course, but it works. And in my case, the custom CSS is being read by a third party which does static caching separately from me, it’s not being read by the browser directly, so it’s fairly minimal to begin with.

    1. Yes that works, I use that method myself. Unfortunately it of course only works when people visit one of your pages a second time :(

Comments are closed.