How to Use AJAX in a WordPress Shortcode?
Nice question!
But, as your code starts with a bad practice - require_once('wp-load.php');
-, I decided to pick one of my working snippets and adapt it.
Observations:
- Differently from your code, no external
quotes.txt
is being grabbed, here a Post Type is used as source (post
), in the methodget_random_post
- There can only be one instance of the shortcode in a given page, as it is based on specific element ID's (
#newpost-shortcode
and#randomposts
) - As usual, it's better to create a plugin for this. Follow the code comments.
/wp-content/plugins/so-ajax-shortcode/so-ajax-shortcode.php
<?php/** * Plugin Name: (SO) Ajax Shortcode * Description: Demonstration of WordPress Ajax working as a shortcode. * Plugin URI: http://stackoverflow.com/a/13614297/1287812 * Version: 2013.10.25 * Author: Rodolfo Buaiz * Author URI: https://wordpress.stackexchange.com/users/12615/brasofilo * License: GPLv3 */add_action( 'plugins_loaded', array ( B5F_SO_13498959::get_instance(), 'plugin_setup' ));class B5F_SO_13498959{ private $cpt = 'post'; # Adjust the CPT protected static $instance = NULL; public $plugin_url = ''; public function __construct() {} public static function get_instance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } /** * Regular plugin work */ public function plugin_setup() { $this->plugin_url = plugins_url( '/', __FILE__ ); add_shortcode( 'randomposts', array( $this, 'shortcode') ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ) ); add_action( 'wp_ajax_query_rand_post', array( $this, 'query_rand_post' ) ); add_action( 'wp_ajax_nopriv_query_rand_post', array( $this, 'query_rand_post' ) ); } /** * SHORTCODE output */ public function shortcode( $atts ) { # First post if( ! $random_post = $this->get_random_post() ) $random_post = __( 'Could not retrieve a post.' ); # Prepare output $output = sprintf( '<div id="randomposts">%s</div> <button id="newpost-shortcode" type="button" title="%s">%s</button>', $random_post, __( 'Gimme a new one!' ), __( 'New random post' ) ); return $output; } /** * ACTION Enqueue scripts */ public function enqueue() { # jQuery will be loaded as a dependency ## DO NOT use other version than the one bundled with WP ### Things will BREAK if you do so wp_enqueue_script( 'ajax-random-post', "{$this->plugin_url}ajax.js", array( 'jquery' ) ); # Here we send PHP values to JS wp_localize_script( 'ajax-random-post', 'wp_ajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'ajaxnonce' => wp_create_nonce( 'ajax_post_validation' ), 'loading' => 'http://i.stack.imgur.com/drgpu.gif' ) ); } /** * AJAX query random post * * Check for security and send proper responses back */ public function query_rand_post() { check_ajax_referer( 'ajax_post_validation', 'security' ); $random_post = $this->get_random_post(); if( !isset( $random_post ) ) wp_send_json_error( array( 'error' => __( 'Could not retrieve a post.' ) ) ); else wp_send_json_success( $random_post ); } /** * AUX FUNCTION * Search a random Post Type and return the post_content */ public function get_random_post() { $array = get_posts( array( 'post_type' => $this->cpt, 'numberposts' => -1 ) ); if( empty( $array ) ) return false; # Select a random post index number from the current array $r = rand( 0, count($array) - 1 ); return $array[$r]->post_content; }}
/wp-content/plugins/so-ajax-shortcode/ajax.js
/* * @plugin SO Ajax Shortcode */jQuery( document ).ready( function( $ ) { var data = { action: 'query_rand_post', security: wp_ajax.ajaxnonce }; var image = '<img src="' + wp_ajax.loading + '" alt="Loading ..." width="16" height="16" />'; $( '#newpost-shortcode' ).click( function(e) { e.preventDefault(); $( '#randomposts' ).html( image ); $.post( wp_ajax.ajaxurl, data, function( response ) { // ERROR HANDLING if( !response.success ) { // No data came back, maybe a security error if( !response.data ) $( '#randomposts' ).html( 'AJAX ERROR: no response' ); else $( '#randomposts' ).html( response.data.error ); } else $( '#randomposts' ).html( response.data ); } ); }); // end click});
Here sample plugin as answer to the question. Using ajaxurl at frontend.
so-random-quotes.php
<?php/*Plugin Name: SO Random QuotesPlugin URI: http://azzrael.ruDescription: Reference to http://stackoverflow.com/questions/13498959/how-to-use-ajax-in-a-wordpress-shortcodeVersion: 1.0.0Author: AzzraelAuthor URI: http://azzrael.ru*/new SoRandomQuotes();/** * Class SoRandomQuotes */class SoRandomQuotes{ const SHORTCODE_KEY = 'randomquotes'; // usage [randomquotes path='/path/to/file/another.quotes.csv'] const AJAX_ACTION = 'so_getnewquote'; // ajax action const DOM_TARGET = 'randomquotes'; // dom element to put the quotes /** * SoRandomQuotes constructor. * init actions */ function __construct() { // adding shortcode add_shortcode('randomquotes', array($this, 'addShortcode')); // adding ajax callbacks add_action( 'wp_ajax_'.self::AJAX_ACTION, array($this, 'getQuoteAjax')); // admin add_action( 'wp_ajax_nopriv_'.self::AJAX_ACTION, array($this, 'getQuoteAjax')); // front } /** * Shortcode callback * @param $atts * @return string */ public function addShortcode($atts){ // getting path value from shortcode atts $got =shortcode_atts( array( 'path' => plugin_dir_path( __FILE__ ).'quotes.txt', ), $atts ); // shortcode replacement $out = sprintf( '<div id="%s">%s</div><a id="newquote" class="button" href="#" title="Gimme a new one!">New Quote</a>', self::DOM_TARGET, $this->getQuote($got['path']) ); // loading js // jquery depends wp_enqueue_script('sorandquo-js', plugin_dir_url( __FILE__ ).'quote-loader.js', array('jquery')); // passing to js needed vars wp_localize_script( 'sorandquo-js', 'ajaxParams', array( 'path' => $got['path'], // path to qoutes file 'targetDom' => '#'.self::DOM_TARGET, // dom path to put resulting qoute 'ajaxurl' => admin_url( 'admin-ajax.php'), // for frontend ( not admin ) 'action' => self::AJAX_ACTION, // ) ); // render shortcode replacement return $out; } /** * Ajax Callback */ public function getQuoteAjax(){ echo $this->getQuote($_POST['path']); die(); } /** * Getting random Qoute from the file * @param $path * @return mixed */ public function getQuote($path){ $quotesFile = is_file($path) ? file_get_contents($path):"File {$path} not found"; $quotesArr = $quotesFile ? explode("\n", $quotesFile):['Quotes File is empty']; return $quotesArr[array_rand($quotesArr)]; }}
quote-loader.js
jQuery.noConflict();jQuery(document).ready(function($) { $(document).on('click', '#newquote', function (e) { e.preventDefault(); $.post(ajaxParams.ajaxurl, { 'action':ajaxParams.action, 'path' :ajaxParams.path }, function (ret) { $(ajaxParams.targetDom).html(ret); }, 'html'); });});
Wordpress shortcode same like function where you give parameters,
for creating ajax request you can use jQuery.ajax or xmlhttp in your header or function file with add_action wp_head
hook.
you should create ajax.php in your theme folder and on the top of file you should include wp-load.php. and place all your ajax functions in proper manner.