Including WordPress in RESTful API

The question:

I’m using a great little open-source product called Restler to provide a RESTful API to a WordPress application. In order for this to work I want to be able to load the WordPress environment within a set of PHP classes that Restler will run when a request comes in.

The idea of loading the WP environment — without the load of the UI elements — is achieved by a script I have called AddWordpress.php:

<?php
error_reporting(E_ALL);
$site_name='yoursite';
$site_domain='www.yoursite.com';

/**
* Construct a fake $_SERVER global to get WordPress to load a specific site.
* This avoids alot of messing about with switch_to_blog() and all its pitfalls.
*/
$_SERVER=array(
'HTTP_HOST'=>$site_domain,
'REQUEST_METHOD'=>'GET',
'REQUEST_URI'=>"/{$site_name}/",
'SERVER_NAME'=>$site_domain,
);

// Remove all our bespoke variables as they'll be in scope as globals and could affect WordPress
unset($site_name,$site_domain);

// Pretend that we're executing an AJAX process. This should help WordPress not load all of the things.
define('DOING_AJAX',true);

// Stop WordPress doing any of its normal output handling.
define('WP_USE_THEMES',false);

// turn on debugging
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);

// Load WordPress - intentionally using an absolute URL due to issues with relative paths on the CLI.
include "/[path-to-root-www]/wp-load.php";

This works like a charm. I can now run scripts like this from the command line (php test.php where below script is test.php):

<?php
include "AddWordpress.php";
$terms = get_terms("actions");
echo json_encode($terms);

The problem I’m having is that if I want to include the “AddWordpress.php” not at the top of the file but inside of a method call — I know this sounds like a terribly bad idea but there are good reasons for it … please believe me — then all shit breaks loose and my day turns badly very quickly. More specifically, the test file now looks like this:

<?php
function do_that_wordpress_thing() {
    include "AddWordpress.php";
}
do_that_wordpress_thing();
$terms = get_terms("actions");
echo json_encode($terms);

and the errors I get are as follows:

Notice:  is_404 was called incorrectly. Conditional query tags do not work before the query is run. Before then, they always return false. Please see Debugging in WordPress for more information. (This message was added in version 3.1.) in /[path-to-www-root]/wp-includes/functions.php on line 2944
Notice:  is_home was called incorrectly. Conditional query tags do not work before the query is run. Before then, they always return false. Please see Debugging in WordPress for more information. (This message was added in version 3.1.) in /[path-to-www-root]/wp-includes/functions.php on line 2944
Notice:  is_search was called incorrectly. Conditional query tags do not work before the query is run. Before then, they always return false. Please see Debugging in WordPress for more information. (This message was added in version 3.1.) in /[path-to-www-root]/wp-includes/functions.php on line 2944
Notice:  is_archive was called incorrectly. Conditional query tags do not work before the query is run. Before then, they always return false. Please see Debugging in WordPress for more information. (This message was added in version 3.1.) in /[path-to-www-root]/wp-includes/functions.php on line 2944

... etc ...

* UPDATE *
On thing I picked up on PHP.net is this snippet on the include function def:

If the include occurs inside a function within the calling file, then all of the code contained in the called file will behave as though it had been defined inside that function. So, it will follow the variable scope of that function. An exception to this rule are magic constants which are evaluated by the parser before the include occurs.

I think this must have an important role in why this isn’t working but I’m still hopelessly lost. Can anyone explain why this could be happening? Any help would be VERY much appreciated.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

The credit for this answer really goes to @Wyck who correctly identified the source of the problem. Thank you very much. The reason for the problem is:

There is a variance between an import statement in the mainline code versus within a function. In WP or in in any of the plugins if variables aren’t explicitly set to global then they become locally scoped to the function they are being imported into.

It’s a shame there’s no import directive to explicitly direct variables to a particular namespace but in absence of this you can simply claim all the global variables as being “global” in the function. Using the same demonstration file from my original problem statement, this now works:

<?php
function do_that_wordpress_thing() {
    global $domain, $path, $base, $admin_page_hooks, $ajax_results, $all_links, $allowedposttags, $allowedtags, $authordata, $bgcolor, $cache_categories, $cache_lastcommentmodified, $cache_lastpostdate, $cache_lastpostmodified, $cache_userdata, $category_cache, $class, $comment, $comment_cache, $comment_count_cache, $commentdata, $current_user, $day, $debug, $descriptions, $error, $feeds, $id, $is_apache, $is_IIS, $is_macIE, $is_winIE, $l10n, $locale, $link, $m, $map, $max_num_pages, $menu, $mode, $month, $month_abbrev, $monthnum, $more, $multipage, $names, $newday, $numpages, $page, $page_cache, $paged, $pagenow, $pages, $parent_file, $preview, $previousday, $previousweekday, $plugin_page, $post, $post_cache, $post_default_category, $post_default_title, $post_meta_cache, $postc, $postdata, $posts, $posts_per_page, $previousday, $request, $result, $richedit, $single, $submenu, $table_prefix, $targets, $timedifference, $timestart, $timeend, $updated_timestamp, $urls, $user_ID, $user_email, $user_identity, $user_level, $user_login, $user_pass_md5, $user_url, $weekday, $weekday_abbrev, $weekday_initial, $withcomments, $wp, $wp_broken_themes, $wp_db_version, $wp_did_header, $wp_did_template_redirect, $wp_file_description, $wp_filter, $wp_importers, $wp_plugins, $wp_taxonomies, $wp_the_query, $wp_themes, $wp_object_cache, $wp_query, $wp_queries, $wp_rewrite, $wp_roles, $wp_similiesreplace, $wp_smiliessearch, $wp_version, $wpcommentspopupfile, $wpcommentsjavascript, $wpdb;
    global $load_sections; // for pagelines theme
    include "AddWordpress.php";
}
do_that_wordpress_thing();
$terms = get_terms("actions"); // I have a custom taxonomy named "actions"
echo json_encode($terms);

It’s also worth noting that if use autoloaders in your plugin; you should make them namespace compliant. For instance, instead of:

spl_autoload_register (  'autoloader_function_name' );

use this:

spl_autoload_register (  __NAMESPACE__ . '\autoloader_function_name' );


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment