views:

599

answers:

2

I'm writing a Wordpress MU plugin, it includes a link with each post and I want to use ajax to call one of the plugin functions when the user clicks on this link, and then dynamically update the link-text with output from that function.

I'm stuck with the ajax query. I've got this complicated, clearly hack-ish, way to do it, but it is not quite working. What is the 'correct' or 'wordpress' way to include ajax functionality in a plugin?

(My current hack code is below. When I click the generate link I don't get the same output I get in the wp page as when I go directly to sample-ajax.php in my browser.)

I've got my code[1] set up as follows:

mu-plugins/sample.php:

<?php
/*
Plugin Name: Sample Plugin
*/
if (!class_exists("SamplePlugin")) {
  class SamplePlugin {
    function SamplePlugin() {}
    function addHeaderCode() {
      echo '<link type="text/css" rel="stylesheet" href="'.get_bloginfo('wpurl').
             '/wp-content/mu-plugins/sample/sample.css" />\n';
      wp_enqueue_script('sample-ajax', get_bloginfo('wpurl') .
             '/wp-content/mu-plugins/sample/sample-ajax.js.php',
             array('jquery'), '1.0');

    }
    // adds the link to post content.
    function addLink($content = '') {
        $content .= "<span class='foobar clicked'><a href='#'>click</a></span>";
        return $content;
    }
    function doAjax() { //
        echo "<a href='#'>AJAX!</a>";
    } 
  }
}
if (class_exists("SamplePlugin")) {
  $sample_plugin = new SamplePlugin();
}
if (isset($sample_plugin)) {
  add_action('wp_head',array(&$sample_plugin,'addHeaderCode'),1);
  add_filter('the_content', array(&$sample_plugin, 'addLink'));
}

mu-plugins/sample/sample-ajax.js.php:

<?php
if (!function_exists('add_action')) {
    require_once("../../../wp-config.php");
}
?>
jQuery(document).ready(function(){
    jQuery(".foobar").bind("click", function() {
        var aref = this;
        jQuery(this).toggleClass('clicked');
        jQuery.ajax({
          url: "http://mysite/wp-content/mu-plugins/sample/sample-ajax.php",
          success: function(value) {
            jQuery(aref).html(value);
          }
        });
    });
});

mu-plugins/sample/sample-ajax.php:

<?php
if (!function_exists('add_action')) {
  require_once("../../../wp-config.php");
}
if (isset($sample_plugin)) {
  $sample_plugin->doAjax();
} else {
  echo "unset";
}
?>

[1] Note: The following tutorial got me this far, but I'm stumped at this point. http://www.devlounge.net/articles/using-ajax-with-your-wordpress-plugin

+3  A: 

Sorry if this diverts a little from the question, but you might find it ends up solving your problem (or at least helps with debugging).

The only way you should make AJAX calls is point to a valid WordPress URL, with your own query parameter, and then check for the existance of this parameter with a 'hooked' init function.

For example, for use in the admin, the URL code would be;

echo admin_url('?my-ajax=true');

Then something like this in your plugin file;

function my_ajax_handler()
{
    if (!isset($_GET['my-ajax']))
        return true;

    // run ajax
    die($ajax_message);
}
add_action('admin_init', 'my_ajax_handler');
TheDeadMedic
So to do it this way I'd have to add a filter hook to the plugin as well to add custom a query var, correct? Something like:function add_QueryVar($vars) { $vars[] = 'my-ajax'; return $vars;}add_filter('query_vars', array( Also I'm not quite sure what you mean by 'for use in the admin' above? Oh, maybe you're showing how to get the appropriate url to reference in the ajax call?
Bee
I selected the other answer as the 'correct' one because it's somewhat simpler than adding a new query var and handler for it, though this is a great explanation of how do that. I'm curious, though perhaps it's too off-topic, if there are advantages to doing it your way, or cases when the admin-ajax wouldn't work?
Bee
@Bee, you need not worry with query vars using either method. Query vars are predominately for use with front-end work and manipulating data based on the URL.Technically John P's method is the 'correct' one, since it's utilizing WP's built-in support, but I wouldn't say there is anything *wrong* with my method :)Just make sure you never try to load WordPress by yourself (like including the `wp-config.php` file), or assuming the file structure of the WordPress install (stick to known constants like `ABSPATH`, `WP_CONTENT_DIR`, and `WP_PLUGIN_DIR`).
TheDeadMedic
+4  A: 

TheDeadMedic is not quite right. WordPress has built in AJAX capabilities. Send your ajax request to /wp-admin/admin-ajax.php using POST with the argument 'action':

jQuery(document).ready(function(){
    jQuery(".foobar").bind("click", function() {
        jQuery(this).toggleClass('clicked');
        jQuery.ajax({
          type:'POST',
          data:{action:'my_unique_action'},
          url: "http://mysite/wp-admin/admin-ajax.php",
          success: function(value) {
            jQuery(this).html(value);
          }
        });
    });
});

Then hook it in the plugin like this if you only want it to work for logged in users:

add_action('wp_ajax_my_unique_action',array($sample_plugin,'doAjax'));

or hook it like this to work only for non-logged in users:

add_action('wp_ajax_nopriv_my_unique_action',array($sample_plugin,'doAjax'));

Use both if you want it to work for everybody.

admin-ajax.php uses some action names already, so make sure you look through the file and don't use the same action names, or else you'll accidentally try to do things like delete comments, etc.

EDIT

Sorry, I didn't quite understand the question. I thought you were asking how to do an ajax request. Anyway, two things I'd try:

First, have your function echo just the word AJAX without the a tag. Next, try changing your ajax call so it has both a success and a complete callback:

jQuery(document).ready(function(){
    jQuery(".foobar").bind("click", function() {
        var val = '';
        jQuery(this).toggleClass('clicked');
        jQuery.ajax({
          type:'POST',
          data:{action:'my_unique_action'},
          url: "http://mysite/wp-admin/admin-ajax.php",
          success: function(value) {
            val = value;
          },
          complete: function(){
            jQuery(this).html(val);
          }
        });
    });
});
John P Bloch
I forgot to add that admin-ajax.php takes care of loading the whole WordPress environment, so you don't need to worry about including any files in your plugin.
John P Bloch
Your original answer was great. Thanks for showing me the correct way to do ajax in wp. Your explanation makes clear what I've seen in other code I've read.Note: I also had a javascript scoping error that I corrected above in the question, so it could be a more useful wp reference question than a 'fix my specific dumb bug' question. (was referencing 'this' inside the success fn for the ajax call).
Bee
John P is dead right, I do apologize, my solution is **not** the only way, but it's a method I find easy for quick AJAX, without having to load WordPress myself.
TheDeadMedic
Forgot to mention in John P's method you can use the JavaScript variable `ajaxurl` rather than hardcoding the URL (or the property `userSettings.ajaxurl` in WP 3.0).
TheDeadMedic