Wordpress custom templates and Javascript

September 27, 2009

Now that I have solved the recent unauthenticated Ajax problem in my Private Geocache Manager plugin, it’s time to move on to the second big problem that has plagued me for a while. I wasn’t even aware of it until I tried to demo the system to a user who worked at a place where Firefox isn’t available. I developed the plugin entirely in Firefox using only what I thought to be cross-platform utilities. The only thing that would even be close to non-standard code in the entire script library is jsfade, which itself is not complicated and which clearly takes into consideration the Internet Explorer quirks when performing the fade effect.

Nonetheless I still have a couple of Javascript issues outstanding which pretty much kill the whole deal since the Google Maps API is entirely a client side, Javascript environment and a big majority of folks still use Internet Explorer.

The first issue is the getElementById method somehow can’t figure out that the map canvas div element is in the DOM tree when it clearly is, throwing an ‘object expected’ error. I am accessing the elements from ajax calls so the entire page has loaded at the time of the calls so the div has obviously been declared by the time it is accessed. I think what I have to do here is check to see if the element is in the DOM tree before trying to access it. Firefox is smart enough to figure it out but I guess IE needs more explicit directions.

The second issue is that my ajax call is throwing the dreaded ‘unspecified error’. Debugging shows the error occurs at the mySACK.runAJAX() line. It is a simple ajax call using a standard implementation of the Simplified Ajax Code Kit, or SACK, and the code works perfectly in Firefox.

    function readMapData(arg) {
      mysack = new sack(ajaxurl); //wordpress admin url for ajax hook
      mysack.setVar('action', 'getVectorMarkers');
      mysack.execute = 0;
      mysack.method = 'POST';
      mysack.setVar('id', arg);
      mysack.onCompletion  = loadOverlay;
      mysack.onError = function() { alert('Ajax error ... '); };
      mysack.runAJAX();
      return true;
    }

The onCompletion callback never fires nor does the onError callback. Since I know there is not an error on the server side the next place I need to debug is inside the SACK ‘onCompletion’ code, which I’m not too crazy about. This is where you go, hmmm, maybe I should have just used jQuery for my Ajax in the first place.

So instead of editing a bunch of code that isn’t mine (the SACK wrapper class) I downloaded and installed the MS Script Editor and used it to find the exact bit of code throwing the error:

  if (this.method == "GET") {
     var totalurlstring = this.requestFile + "?" + this.URLString;
     this.xmlhttp.open(this.method, totalurlstring, true);
  }else{
      this.xmlhttp.open(this.method, this.requestFile, true);
  }

I’m using POST method so it’s the last line throwing the error. This.request is set to the parameter passed when creating the new sack object, in our case the wp_admin url, so the code would translate into

xmlhttp.open('POST', 'http://.../wp-admin/admin-ajax.php', true);

And that’s the benefit of writing these posts. Many times you figure out the problem by the time you finish describing it. When I went to copy the ajaxurl from the editor I noticed a typo in the URL which Firefox can obviously parse but IE can’t–I had the first pair of slashes escaped, eg http:///gulfcoastgeocache.com….

Grr….

So that still leaves me with the aggravating problem of getElementById not working properly. I’m debugging that now. Once I get that one sorted out I will be 90% complete with the plugin leaving only the initial setup script and the options page to finish.

  • Share/Bookmark

Wordpress ajax and $wpdb

September 20, 2009

Anyone who does any tinkering with Wordpress templates or plugins is likely familiar with the Wordpress class for interfacing with the Wordpress MySQL database, $wpdb. In the previous article here in The Garage, Viewer-facing Ajax in Wordpress Plugin, I described a problem I was having with Ajax requests from the public side of a website from a user who is not logged in. Pesky little problem it has been.

In a nutshell, if the user is not logged in they do not have access to any of the built-in Wordpress Ajax functionality so you have to write your own Ajax handler, which is not a problem until you need to access the database using $wpdb since the $wpdb class is not normally available to a page or script that is loaded outside the Wordpress context. My research led me to a couple tricks around this limitation such as a template redirect or loading the core Worpdress files in the external Ajax handling script, eg,

include_once(‘wp-config.php’);
include_once(‘wp-load.php’);
include_once(‘wp-includes/wp-db.php’);

In theory, after loading those core files I can now make calls to the MySQL tables using the $wpdb class just as if I was logged in to the admin panel. In the back of my mind I am thinking that maintaining extra scripts for anonymous db access is a lot of work and loading the core Wordpress files is a lot of overhead just to run a couple of simple queries. Really not optimal.

So I was still looking for a better solution even as I was working on making the above work when I stumbled upon the better solution. Somewhere around March Wordpress released an update (v2.8 I believe) which has support for Ajax actions initiated by a user who is not logged in. Along with the ‘wp_ajax’ hook there is now also a ‘wp_ajax_nopriv’ hook that provides the same functionality but for users that are not logged in. So when your main plugin code is loading all you need to do is check to see if the user is logged in or not and then initialize the appropriate action hook.

//load nopriv ajax handlers for front-end ajax users not logged in
if ( is_user_logged_in() ) {
    add_action('wp_ajax_getVectorMarkers', 'getVectorXML');
    add_action('wp_ajax_getVectorMarkersText', 'getVectorXMLText');
} else {
    add_action('wp_ajax_nopriv_getVectorMarkers', 'getVectorXML');
    add_action('wp_ajax_nopriv_getVectorMarkersText', 'getVectorXMLText');
};

Using the ‘wp_ajax_nopriv’ hook allowed me get rid of a lot of code that was written specifically for displaying custom maps to users who are not logged in. It makes me very happy!

Evidently not too many people know about ‘nopriv’ as the info was difficult for me to Google down. (Click here to see the thread where I found the information.) The alternative methods are also discussed in the thread if you are not in the position to upgrade to the latest Wordpress version with the ‘nopriv’ option. (Here is the Wordpress Trac nopriv change documentation.)

I can verify that wp_ajax_nopriv also works with Wordpress Mu version 2.8.2.

  • Share/Bookmark

Viewer-facing ajax in Wordpress plugin

September 3, 2009

It’s rare that I can’t solve a programming problem no matter how complex and thus I rarely leave a question on a support forum. I can’t even remember the last time; probably over a decade ago. Here is one I left recently at the supposedly fantastic Wordpress.org plugin support forum.

I am writing a plugin to manage map resources and I having a couple a issues that I have been unable to figure out. I have a test site set up here –> http://gulfcoastgeocache.com/

I am using the Google Map API and lots of ajax both admin and viewer-facing to display custom maps. On the viewer facing side I am using SACK to call a small php script that in turn calls the actual function inside the plugin class.

$gcgc_path  = str_replace('\\','/',dirname(__FILE__));
require_once($gcgc_path.'/gcgcclass.php');
$gcgc_Manager->getVectorXML($_POST[id]);

The class function:

function getVectorXML(){
    header("Content-type: text/xml");
    $parms = array('id' => $_POST['id'],
                   'id_type' => 'vector_id'
                    );                         

    $cachets = $this->getVectorMapData($parms);
    $xhtml = "";
    $xhtml .= "";
    if($cachets){
      $xhtml .= "";
    	foreach ($cachets as $c){
    		$xhtml .= "";
    		}
    }
    $xhtml .= "";
    die($xhtml);
  }

Works fine if the user is logged in but is failing if user is not logged in. More accurately, the ajax round trip succeeds but my xml response is -1 if user is not logged in. No data is coming back.

The codex example for ajax does not illustrate a cookie being sent on the viewer-facing side but this is where I am thinking the problem lies, but really I am at a loss for an idea right now.

This is my first WP plugin so I may be having a noob moment. I’ve been revisiting this issue repeatedly over the past couple of months and, I hate to admit, I can’t figure it out. Any help would be greatly appreciated.

I posted that five days ago and not a peep. I even bumped it a couple of days ago. Still nothing. I’m not sure if the question is too stupid to warrant a response or if maybe it is too hard. I think the only way to get a quick response, or any response at all, for that matter, is to leave your query in broken English and to ask a question that indicates you don’t have a clue about what you are doing.

I’m not impressed. If anyone has a clue about the ajax, please let me know.

  • Share/Bookmark