Check out the first part of this article here.
Now, check the more neat and cleaner and recommended method for implementing Ajax with Wordpress. So let's check out our new process ...
1. Same old template-ajax-page.php will be our page template, where we would be writing the jQuery call. The jQuery POST method will have a small change here. Let's check it out.
<script>
function call_me()
{
jQuery.post(
// Check the Target URL admin-ajax.php
"<?php echo get_site_url();?>/wp-admin/admin-ajax.php",
{
'action': 'fetch_posts',
'data' : 'posts_per_page=5' +
'&post_status=publish'
},
function(response)
{
// Put the response in a particular place
jQuery('#post_lists').html(response);
});
}
</script>
Here, the change is done only to the AJAX target URL which is "wp-admin/admin-ajax.php". Wordpress includes this file for handling AJAX request.
2. Next, we need to open our theme's function.php and add new hooks in there. It is shown below.
<?php
// Our custom function's definition
function my_custom_fetch_posts()
{
}
// The below statement is for situations
// when User is logged in
add_action( 'wp_ajax_fetch_posts', 'my_custom_fetch_posts');
// The below statement is for situations
// when User is not logged in
add_action( 'wp_ajax_nopriv_fetch_posts', 'my_custom_fetch_posts');
?>
The above lines are very important. Let me explain them.
In our jQuery POST method above, as our 'action' is 'fetch_posts', our target action hooks will be "wp_ajax_fetch_posts" (when user is logged in) and "wp_ajax_nopriv_fetch_posts" (when user is not logged in). The names of these two hooks can be different from each other. This hooks are created in admin-ajax.php ( our AJAX target file ) and our custom function 'my_custom_fetch_posts' is just added to the above hooks. So, in admin-ajax.php, when the action hook 'wp_ajax_fetch_posts' or 'wp_ajax_nopriv_fetch_posts' is triggered through do_action() calls, our custom function my_custom_fetch_posts() is called and executed eventually.
So, the basic is, as soon as our jQuery POST is triggered, and if 'add_foobar' is passed as 'action', target AJAX handler admin-ajax.php file fires authenticated AJAX action hook "wp_ajax_add_foobar" ( 'wp_ajax_' . $_REQUEST['action'] ) and if we add/attach our custom function "my_function" to that hook, my_function() will eventually be executed and the output will be returned back to the browser as a result of the AJAX call.
3. So, before above two add_action statements, we would be supplying the definition of our custom function as shown below.
<?php
// Our custom function
function prefix_ajax_fetch_posts()
{
// CHECK the action parameter
if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'fetch_posts' )
{
// Extract the data part
parse_str( $_REQUEST['data'] );
// So now we have variables like $posts_per_page
// $post_status and $category__in
// NOw we BUILD the arguments for WP_QUERY
$arg = array();
// SET number of posts
if(isset($posts_per_page))
{
$arg['posts_per_page'] = $posts_per_page;
}
// SET POST status
if(isset($post_status))
{
$arg['post_status'] = $post_status;
}
// SET Category IDs
if(isset($category__in))
{
$arg['category__in'] = explode(",",$category__in);
}
// The QUERY
$the_query = new WP_Query( $arg );
// Now do what you want to do
// The Loop
$output = "";
while ( $the_query->have_posts() )
{
$the_query->the_post();
// GET ID, Title etc
$title = get_the_title();
$id = get_the_id();
// BUILD the Output
$output .= '<div class="post_details ">' .
get_the_post_thumbnail( $a, 'thumbnail' ) .
'<div class="post_title"> <a href="'. get_permalink().
'">'.$title.'</a> </div>';
}
// output
echo $output;
}
// IF ends here
die();
}
// Attach our function to the Hook
add_action( 'wp_ajax_fetch_posts', 'prefix_ajax_fetch_posts');
add_action( 'wp_ajax_nopriv_fetch_posts', prefix_ajax_fetch_posts');
?>
The statements within the above function "prefix_ajax_fetch_posts()" are same as we saw in the article discussing uglier AJAX technique. Here, they are just wrapped within a function definition. It just builds parameters to generate a WP_Query and prints the result of the query and sends back to browser.
In the above screenshot, some posts' titles are returned by server as per our logic and printed in a DIV.
Hope this helps.
In this article, I am going to share how we can implement ajax within Wordpress.
We can choose between two methods, one is uglier and the second one the recommended method.
Let's start with the uglier method.
Method 1 ::
a. Here, we are going to create a new page where we would be demonstrating the ajax call.
b. We would be creating a new template for this also.
c. We would be requiring jQuery ajax post methods for submitting our requests.
1. So, let's create a new template within the theme folder. In my case, the active theme is 'twentyfourteen'. So, within twentyfourteen/page-templates folder, we create a new template file called "template-ajax-page.php". It's content is shown below ::
This new template can be created by copy-pasting old template files (even copying page.php is also ok) and modifying the comment section as shown below.
<?php
/**
* Template Name: AJAX PAGE
*/
?>
So, our template file is ready. Now, on this page, we would be adding our custom jQuery post() function which would send requests to the server asynchronously and show the response on screen.
If we have created the template by copying page.php or any other template file of our choice, we would not touch any other part of the template code, but we would add a button with title "Click to call AJAX" and a custom JS function "call_me" which would be executed when click the button.
<script>
// Our custom JS function which submits the
// request asynchronously
function call_me()
{
jQuery.post(
"<?php echo get_site_url() . "/test-ajax.php"; ?>",
{
'action': 'add_foobar',
'data': 'name=admin&age=34&roll_no=23'
},
function(response)
{
console.log('The server responded: <br>' + response);
}
);
} // Function ends
</script>
<!-- Our Button -->
<input type="button" value="Click to call ajax" onclick="call_me()">
Check the jQuery.post() function structure. The first parameter is the target PHP file (test-ajax.php) which would handle the AJAX request. Second parameter of this jQuery.post() function consists of an object with member like 'action', 'data' etc. These members' names can be anything. Third parameter is the callback handler which handles the return response. Here, we have printed the response in browser console.
We can put the button HTML anywhere within the page. The test-ajax.php (Ajax Handler at the server side) can be placed within any directory within Wordpress installation, but it's path must be specified properly while calling jQuery.post() function.
So, the gist is, when the above button is clicked, "call_me" function is called which posts the 2nd parameter object (passed through jQuery.post() function). And when the server response is received, it is printed in the console.
2. So far so good, next, we would create a page and assign the above template to it. By doing this, we are making the our ajax functionality available at the front-end. So, we have created a page called "Ajax Page" and setting its template as shown below ...
And, see, how it looks like at the front-end.
The content of the page can be shown in anyway we want. That's why I said to not to touch other part of the template file. This way, we are just adding our functionality to the existing working template (as this was copied from page.php or any other template file).
3. Now, let's create the PHP page which will handle the AJAX request. In our example, the file's name is test-ajax.php and we would create this file at the root folder of our Wordpress installation. And this would match with the path provided in the jQuery.post() function's first parameter.
Let's check the content of test-ajax.php ...
<?php
// The below file is important to load Wordpress
// Core functionalities
require( dirname( __FILE__ ) . '/wp-blog-header.php' );
// Clear the Buffer
// This is Important, otherwise default
// WORDPRESS-generated htmls will be available to us
ob_end_clean();
// PRINT the REQUEST
print_r($_REQUEST);
?>
We have included the "wp-blog-header.php" file at the top to get the Wordpress functionality, so $wpdb object, WP_Query() functions will be automatically available to us.
With this much of arrangement, let's see what happens when we click on the "Click to call ajax" button above. Check the output below ::
The server responded:
Array
(
[action] => add_foobar
[data] => name=admin&age=34&roll_no=23
)
This output was captured at the console of the browser. So, it is clear that the data part ( 2nd Parameter of jQuery.post() function ) was successfully posted to Server. The post data "name=admin&age=34&roll_no=23" can be easily parsed and output can be generated accordingly.
Now, let's write a new jQuery which requests the server for the details of all the posts created and published within Wordpress.
jQuery.post(
"<?php echo get_site_url() . "/test-ajax.php"; ?>",
{
'action': 'fetch_posts',
'data' : 'posts_per_page=5' +
'&post_status=publish' +
'&category__in=1,2,3,4'
},
function(response)
{
// Put the response in a particular place
jQuery('#post_lists').html(response);
});
Here, we have added "category__in" parameter i.e our query would check if the post belongs to category ID 1,2,3 or 4. Check, how we can parse the AJAX request at the server side below.
<?php
if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'fetch_posts' )
{
// Extract the data part
parse_str( $_REQUEST['data'] );
// So now we have variables like $posts_per_page
// $post_status and $category__in
// NOw we BUILD the arguments for WP_QUERY
$arg = array();
// SET number of posts
if(isset($posts_per_page))
$arg['posts_per_page'] = $posts_per_page;
// SET POST status
if(isset($post_status))
$arg['post_status'] = $post_status;
// SET Category IDs
if(isset($category__in))
{
$arg['category__in'] = explode(",",$category__in);
}
// The QUERY
$the_query = new WP_Query( $arg );
// Now do what you want to do
// The Loop
$output = "";
while ( $the_query->have_posts() )
{
$the_query->the_post();
// GET ID, Title etc
$title = get_the_title();
$id = get_the_id();
// BUILD the Output
$output .= '<div class="post_details ">' .
get_the_post_thumbnail( $a, 'thumbnail' ) .
'<div class="post_title"> <a href="'.get_permalink().
'">'.$title.'</a> </div>';
}
// output
echo $output;
}
?>
The above code is quite simple.
Check how we have set the data ( 2nd parameter in jQuery.post() function ) part in our browser AJAX request.
{
'action': 'fetch_titles',
'data': 'posts_per_page=5' +
'&post_status=publish' +
'&category__in=1,2,3,4'
}
Then, we are checking at the server-side for right POST variable.
if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'fetch_posts' )
and then we just extract parameters from the received data 'posts_per_page=5&post_status=publish&category__in=1,2,3,4' and build an array $args with which we finally create the WP_QUERY object.
Next, we just loop through all the results returned by WP_QUERY, generate a suitable HTML and output it.
On the browser side, the jQuery has a callback function defined ::
function(response)
{
// Put the response in a particular place
jQuery('#post_lists').html(response);
}
which places/puts the response (server generated HTML) in a target DIV (with ID post_lists).
So, this is the simple AJAX implementation within Wordpress. Check the better method in my next article.
Let's try some more stuffs using PHP Arrays. Check the previous Array articles
Arrays in PHP - 2, Arrays in PHP
1. Problem :: How to get the last element in an array without using a loop.
Solution :: We need to use key() and end() functions in order to achieve this. Check out the code below.
<?php
// Define the Array
$arr = array( 's1' => "100", 's2' => 300, 's3' => 100, 's4' => 200, 's5' => 300 );
// moves the array pointer to the end
// of the Array and return the value
$l = end($arr);
// Get that element's key
$k = key($arr);
// Print Key and Value
echo "<br>$k :: $l";
// Bring back the array pointer to the
// beginning of the array
reset($arr);
// Get the Current item's key
$k = key($arr);
// Get the Value
$l = current($arr);
echo "<br>$k :: $l";
// Print Key and Value
echo "<br>$k :: $l";
?>
2. Problem :: We have the following array and find all the keys where the value is 100.
$arr = array( 's1' => "100", 's2' => 300, 's3' => 100, 's4' => 200, 's5' => 300 );
Solution :: We'll be using array_search() function which returns keys of the array. If we pass only the array name as the first parameter, all the keys are returned as array. However, if we give any value as second parameter, that value will be searched within the array and if found all respective keys are returned as array.
<?php
// Define the Array
$arr = { 's1' => "100", 's2' => 300, 's3' => 100, 's4' => 200, 's5' => 300};
// Print all Keys wihtin the array
print_r( array_keys( $arr ) );
// Print all keys where value is 100
print_r( array_keys( $arr, 100 ) );
?>
As PHP values can be implicitly typecast to other types (like integer to string), a string value "100" will be considered as a match while array_key() searches for integer 100.
3. Problem :: Passing Arrays to a function using call-by-reference.
Solution :: As of PHP 5.3, passing arrays as reference to function is deprecated. To force it, we need to set 'allow_call_time_pass_reference' to true in php.ini.
So, in general Arrays are passed by values to functions. Hence any changes made to the passed array within the called function does not make alterations to the original array. Here is a small example :
<?php
// Define the Array
$arr = array( "100", 300, 100, 200, 300 );
// Define Function
$f = create_function( '$a', '
for($i=0; $i<count($a);$i++)
$a[$i]++;
');
// Call Function
$f($arr);
// Print the Array
echo '<br>After function call :: ';
print_r ($arr);
?>
The output of the above program will be same as the original array declared at the beginning of the program.
4. Strings can be treated as an array of characters. The same behaviour can be seen in C, C++ and Python. Check the code below ..
<?php
// Sample String
$str = "This is a Balloon";
// Start iterating with the
// index starting at zero
for($i=0;$i<strlen($str);$i++)
echo $str[$i];
?>
The same is applicable to array of strings which can be printed character by character... just the way we do it in case of multi-dimensional arrays. Check the example below :
<?php
// Declare array of Strings
$arr = array(
"Jackie",
"Johnny",
"Varun",
"Catherine"
) ;
// For loop to track strings
for($i=0;$i<count($arr);$i++)
{
echo "<br>";
// Now loop through characters in each strings
for($j=0;$j<strlen($arr[$i]);$j++)
{
// Access each character as
// a multi-dimensional arrays
echo $arr[$i][$j];
}
}
?>
Scenario: We want to set Free Shipping if any Buyer purchases Product X and Product Y along with 0 or more other products from our Magento store.
Solution : We may create shopping cart rules to achieve this, but when I tried to do it, it did not work out. So, it is better to create a new Module and write an observer. That observer will apply the 'Free Shipping' to the cart when Product X and Product Y are found within the cart. But for this, the 'Free Shipping' shipping method must be enabled from Admin Panel.
For this, let's create the new module called 'Chandan_Freeshipping'. The required files to be created are as follows :
1. app/etc/modules/Chandan_Freeshipping.xml
2. app/code/local/Chandan/Freeshipping/etc/config.xml
3. app/code/local/Chandan/Freeshipping/Model/Observer.php
"Chandan" is the Namespace/Company name and module name is 'Freeshipping'
So, let's start with the first file Chandan_Freeshipping.xml. Here is its contents :
<?xml version="1.0"?>
<config>
<modules>
<Chandan_Freeshipping>
<active>true</active>
<codePool>local</codePool>
</Chandan_Freeshipping>
</modules>
</config>
Here we just mentioned that the corresponding module's files are stored in "local" codepool.
Now, the content of "config.xml" ...
<?xml version="1.0"?>
<config>
<modules>
<Chandan_Freeshipping>
<version>0.1.0</version>
</Chandan_Freeshipping>
</modules>
<frontend>
<events>
<checkout_cart_product_add_after>
<observers>
<Chandan_Freeshipping_Model_Observer>
<type>singleton</type>
<class>
Chandan_Freeshipping_Model_Observer
</class>
<method>checkfreeshipping</method>
</Chandan_Freeshipping_Model_Observer>
</observers>
</checkout_cart_product_add_after>
<checkout_controller_onepage_save_shipping_method>
<observers>
<Chandan_Freeshipping_Model_Observers>
<type>singleton</type>
<class>
Chandan_Freeshipping_Model_Observer
</class>
<method>applyfreeshipping</method>
</Chandan_Freeshipping_Model_Observers>
</observers>
</checkout_controller_onepage_save_shipping_method>
<paypal_prepare_line_items>
<observers>
<Chandan_Freeshipping_Model_Observer_Paypal>
<type>singleton</type>
<class>
Chandan_Freeshipping_Model_Observer
</class>
<method>applyfreeshipping</method>
</Chandan_Freeshipping_Model_Observer_Paypal>
</observers>
</paypal_prepare_line_items>
</events>
</frontend>
</config>
In the above XML, couple of points should be noticed :
1. We are capturing 3 events
i. checkout_cart_product_add_after : The event is fired when a product is added to the cart. At this point, if we see product X and Y are within the cart, we just show a message like "You'll get the FreeShipping at the final Checkout". Check the screenshot below.
ii. checkout_controller_onepage_save_shipping_method : This event is fired when Shipping method is saved in Final Checkout. Check the screenshot below.
Even though any other shipping method can be selected, but ONLY "Freeshipping" method will be finally applied as our observer is in work. Check the screenshot below.
iii. paypal_prepare_line_items : This event is fired when user selects Paypal payment method and comes back to Order Review page. At that point of time, only one shipping method "FreeShipping" will be available to the purchaser as our observer captures this event and forces this method.
2. Check the construct of the event and observer mentioned in the above XML file.
<checkout_cart_product_add_after>
<observers>
<Chandan_Freeshipping_Model_Observer>
<type>singleton</type>
<class>Chandan_Freeshipping_Model_Observer</class>
<method>checkfreeshipping</method>
</Chandan_Freeshipping_Model_Observer>
</observers>
</checkout_cart_product_add_after>
The whole block is wrapped by tag having event name ('checkout_cart_product_add_after') being captured. Now the observer name is 'Chandan_Freeshipping_Model_Observer' having class name 'Chandan_Freeshipping_Model_Observer' and method name 'checkfreeshipping'. So, this 'checkfreeshipping' method of class 'Chandan_Freeshipping_Model_Observer' will handle the event.
3 different observers mentioned above have different names. It is better if these names are different from each other. For 3 events, we will create a new class 'Chandan_Freeshipping_Model_Observer' and the methods 'checkfreeshipping', 'applyfreeshipping' as mentioned in above XML.
Next, let's check the content of Observer.php where, as said above, we need to define the observer class and its methods.
<?php
class Chandan_Freeshipping_Model_Observer
{
// SKUs of Product X and Product Y
private $fsprod1 = "acj0006s";
private $fsprod2 = "acj003";
// A method which searches for Product X
// and Product Y within the CART
private function ifFreeShippingApplicable()
{
// Define an SKU array
$sku_list = array();
// GET CART Items
$quote = Mage::getSingleton('checkout/session')->getQuote();
$cartItems = $quote->getAllVisibleItems();
// LOOP Thru Cart Items
foreach ($cartItems as $item)
{
$productId = $item->getProductId();
$product = Mage::getModel('catalog/product')->load($productId);
// Insert the Product SKU into that array
$sku_list[] = $product->getSku() ;
}
// Check if Products X, Y are in the Cart
if(in_array($this->fsprod1,$sku_list) && in_array($this->fsprod2,$sku_list))
{
return true;
}
else
{
return false;
}
}
// Show message that FreeShipping will
// be applied on Cart
public function checkfreeshipping(Varien_Event_Observer $observer)
{
if( $this->ifFreeShippingApplicable() )
{
// Product X and Y Found,
// Hence show Message
Mage::getSingleton('checkout/session')->addSuccess("You will get Free Shipping at final checkout");
}
}
// Method for applying the 'Freeshipping' method
public function applyfreeshipping(Varien_Event_Observer $observer)
{
// Check for Product X & Y
if( $this->ifFreeShippingApplicable() )
{
// GEt Quote
$quote = Mage::getSingleton('checkout/session')->getQuote();
// Apply the Free Shipping
$address = $quote->getShippingAddress();
$address->setShippingMethod('freeshipping_freeshipping');
}
}
}
?>
The code above is quite self-explanatory, it contains the class 'Chandan_Freeshipping_Model_Observer' and its methods which are executed when certain events are fired.
Hope this helps.