I am currently working on a custom widget for Elementor and need to convert my Javascript functions into Ajax functions. My main issue has been figuring out how to pass variables from PHP to AJAX.
Here is the Javascript for the function in Question:
//Dynamic Price Calculator
$('#productQuant').keyup(function(){
// assign size from checked radio button
let productSize = $("input[type=radio][name=sizeRadio]:checked" ).val();
// assign quantity from values found in input text box
let productQuantity = $("#productQuant").val();
$.ajax({
// admin-ajax.php url
url: productDataAjax.url,
method: 'post',
dataType: 'json',
data:({
action: 'priceUpdate',
phpProductSize: productSize,
phpProductQuantity: productQuantity
}),
success:function(data){
console.log("Success");
// Text to product total
$('#productTotal').text(" " data.dynamicTotal);
}
});
}); // function end
})( jQuery );
Here is the PHP:
/* Enque Scripts and Styles */
function shop_plugin_assets(){
// Enqueue CSS
wp_enqueue_style( 'bootstrap','https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css', array(), '1.0', 'all' );
// remeber array(), null at the end to mak sure googlefonts load. family = family = etc throws it off
wp_enqueue_style( 'google-font', 'https://fonts.googleapis.com/css2?family=Bungee&family=Sintony&display=swap', array(), null );
// Enqueue JQuery and JS Files
wp_enqueue_script( 'jquery');
wp_enqueue_script( 'bootstrap-bundle-js', 'https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js', array(), '1.0', true );
wp_enqueue_script( 'my-scripts', get_template_directory_uri() . '/js-custom/my-scripts.js', array( 'jquery' ), '1.0', true );
$script_data_array = array(
'ajaxUrl' => admin_url('admin-ajax.php'),
);
wp_localize_script('my-scripts', 'productDataAjax', $script_data_array);
}
add_action( 'wp_enqueue_scripts', 'shop_plugin_assets', 20 );
function dynamicPriceCalc(){
$productSize = $_POST['phpProductSize'];
$productQuantity = $_POST['phpProductQuantity'];
$productPrice = 0;
$productTotal = 0;
$response = array();
if( $productSize === "small"){
$productPrice = 7.99;
$productTotal = number_format( (float) ($productPrice * $productQuantity), 2, '.', '');
$response["dynamicTotal"] = $productTotal;
echo json_encode($response);
}
else if( $productSize === "medium"){
$productPrice = 10.99;
$productTotal = number_format( (float) ($productPrice * $productQuantity), 2, '.', '');
$response["dynamicTotal"] = $productTotal;
echo json_encode($response);
}
else if( $productSize === "large"){
$productPrice = 14.99;
$productTotal = number_format( (float) ($productPrice * $productQuantity), 2, '.', '');
$response["dynamicTotal"] = $productTotal;
echo json_encode($response);
}
die();
}
add_action('wp_ajax_priceUpdate', 'dynamicPriceCalc');
add_action('wp_ajax_nopriv_priceUpdate', 'dynamicPriceCalc');
Here is the Elementor widget File:
<?php
class Elementor_Custom_Product_Archive_Food extends \Elementor\Widget_Base {
public function get_name() {
return 'Custom Product Archive Food';
}
public function get_title() {
return esc_html__( 'Custom Product Archive Food Service', 'elementor-addon' );
}
public function get_icon() {
return 'eicon-code';
}
public function get_categories() {
return [ 'basic' ];
}
public function get_keywords() {
return [ 'archive', 'product', 'food' ];
}
// Controls for widgets
protected function register_controls()
{
$this->start_controls_section(
'button_section',
[
'label' => esc_html__( 'Product Archive Food', 'custom_product_archive_food' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$this->add_control(
'button_align',
[
'label' => esc_html__( 'Alignment', 'custom_product_archive_food' ),
'type' => \Elementor\Controls_Manager::CHOOSE,
'options' => [
'text-start' => [
'title' => esc_html__( 'Left', 'custom_product_archive_food' ),
'icon' => 'eicon-text-align-left',
],
'text-center' => [
'title' => esc_html__( 'Center', 'custom_product_archive_food' ),
'icon' => 'eicon-text-align-center',
],
'text-end' => [
'title' => esc_html__( 'Right', 'custom_product_archive_food' ),
'icon' => 'eicon-text-align-right',
],
],
'default' => 'text-center',
'toggle' => true,
]
);
$this->end_controls_section();
} //end of controls
// Render the HTML and pulll data from controls to change classes or feed settings dynamic properties
protected function render() {
// settings pulls properties from control options to use within your html blocks
$settings = $this->get_settings_for_display();
$checkOutLink = wc_get_checkout_url();
// Radio Size selector
echo '<div >';
echo '<label> Choose a Size </label>';
echo '</div>';
echo '<div id="radioContainer">';
echo '<div >';
echo '<input type="radio" name="sizeRadio" id="smallRadio" value="small">';
echo '<label for="smallRadio">';
echo 'Small';
echo '</label>';
echo '</div>';
echo '<div >';
echo '<input type="radio" name="sizeRadio" id="medRadio" value="medium">';
echo '<label for="medRadio">';
echo 'Medium';
echo '</label>';
echo '</div>';
echo '<div >';
echo '<input type="radio" name="sizeRadio" id="largeRadio" value="large">';
echo '<label for="largeRadio">';
echo 'Large';
echo '</label>';
echo '</div>';
echo '</div>';
// Quantity / Logic Button / Redirect Button';
echo '<div >';
echo '<div >';
echo '<label id="productPrice"> Price: </label>';
echo '</div>';
echo '<input type="text" placeholder="Enter Quantity" aria-label="Quantity" id="productQuant">';
echo '<div >';
echo '<label id="productTotal"> Total:</label>';
echo '</div>';
echo '<button type="button" name="button" id="addCartSubmit"> Add to Cart </button>';
echo '<a href="'.$checkOutLink.'" > Proceed to Check Out</a>';
echo '</div>';
} // End of protected functions
} //end of class
It is my understanding that I am supposed to call the PHP function using action while sending whatever data I pull with JQuery, execute the PHP function, make an array of the result within that function, encode the result in JSON, and on success have the JSON data inserted into whatever JQuery function I need it for.
For some reason, the function won't work even after trying several variations of the solution seen above. I know the logic works as I've recreated the same solution with pure JQuery and it works without a hitch. I know that there is some type of response going through as I get undefined and a console log of success when I remove the dataType:'json'. I don't know what is happening in between these two things that is stopping me from getting the label change to reflect my new product total.
Some Images After Inputting Text into the Text Field. You'll notice the Total section remains blank:
Header Request showing it accepts Javascript and JSON
Response showing HTML - I think I need it to return JSON here
CodePudding user response:
The core issue was that I was not using the right name for my ajax url. In my case, the object declared in my functions.php needed to be written as productUpdate.ajaxUrl for my ajax url to have the correct url to follow. I thought I needed to writeit as just productUpdate.url
For reference this is where the array and the object were declared in functions.php:
function shop_plugin_assets(){
// Enqueue CSS
wp_enqueue_style( 'bootstrap','https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css', array(), '1.0', 'all' );
// remeber array(), null at the end to mak sure googlefonts load. family = family = etc throws it off
wp_enqueue_style( 'google-font', 'https://fonts.googleapis.com/css2?family=Bungee&family=Sintony&display=swap', array(), null );
// Enqueue JQuery and JS Files
wp_enqueue_script( 'jquery');
wp_enqueue_script( 'bootstrap-bundle-js', 'https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js', array(), '1.0', true );
wp_enqueue_script( 'my-scripts', get_template_directory_uri() . '/js-custom/my-scripts.js', array( 'jquery' ), '1.0', true );
$script_data_array = array(
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('product_nonce')
);
wp_localize_script('my-scripts', 'productDataAjax', $script_data_array);
}
add_action( 'wp_enqueue_scripts', 'shop_plugin_assets', 20 );
This is the what the proper ajax function looks like:
$('#productQuant').keyup(function(){
// assign size from checked radio button
let productSize = $("input[type=radio][name=sizeRadio]:checked" ).val();
// assign quantity from values found in input text box
let productQuantity = $("#productQuant").val();
$.ajax({
// admin-ajax.php url
url: productDataAjax.ajaxUrl,
method: 'post',
dataType: 'json',
data:({
action: 'priceUpdate',
phpProductSize: productSize,
phpProductQuantity: productQuantity,
_ajax_nonce: productDataAjax.nonce
}),
success:function(response){
console.log("success");
//Text to product total
$('#productTotal').text(" " response.dynamicTotal);
}
});
}); // function end
})( jQuery );
This is the full code after all changes have been made:
Functions.php
/* Enque Scripts and Styles */
function shop_plugin_assets(){
// Enqueue CSS
wp_enqueue_style( 'bootstrap','https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css', array(), '1.0', 'all' );
// remeber array(), null at the end to mak sure googlefonts load. family = family = etc throws it off
wp_enqueue_style( 'google-font', 'https://fonts.googleapis.com/css2?family=Bungee&family=Sintony&display=swap', array(), null );
// Enqueue JQuery and JS Files
wp_enqueue_script( 'jquery');
wp_enqueue_script( 'bootstrap-bundle-js', 'https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js', array(), '1.0', true );
wp_enqueue_script( 'my-scripts', get_template_directory_uri() . '/js-custom/my-scripts.js', array( 'jquery' ), '1.0', true );
$script_data_array = array(
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('product_nonce')
);
wp_localize_script('my-scripts', 'productDataAjax', $script_data_array);
}
add_action( 'wp_enqueue_scripts', 'shop_plugin_assets', 20 );
function dynamicPriceCalc(){
check_ajax_referer('product_nonce');
$productSize = $_POST['phpProductSize'];
$productQuantity = $_POST['phpProductQuantity'];
$productPrice = 0;
$productTotal = 0;
$response = array();
if( $productSize === "small"){
$productPrice = 7.99;
$productTotal = number_format( (float) ($productPrice * $productQuantity), 2, '.', '');
// stor return values in an array
$response["dynamicTotal"] = $productTotal;
// returns variables to ajax function making the call
echo json_encode($response);
// wp_ die() better for wordpress rather than just die()
wp_die();
}
else if( $productSize === "medium"){
$productPrice = 10.99;
$productTotal = number_format( (float) ($productPrice * $productQuantity), 2, '.', '');
// stor return values in an array
$response["dynamicTotal"] = $productTotal;
// returns variables to ajax function making the call
echo json_encode($response);
// wp_ die() better for wordpress rather than just die()
wp_die();
}
else if( $productSize === "large"){
$productPrice = 14.99;
$productTotal = number_format( (float) ($productPrice * $productQuantity), 2, '.', '');
// stor return values in an array
$response["dynamicTotal"] = $productTotal;
// returns variables to ajax function making the call
echo json_encode($response);
// wp_ die() better for wordpress rather than just die()
wp_die();
}
}
add_action('wp_ajax_priceUpdate', 'dynamicPriceCalc');
add_action('wp_ajax_priceUpdate', 'dynamicPriceCalc');
Javascipt File
$('#productQuant').keyup(function(){
// assign size from checked radio button
let productSize = $("input[type=radio][name=sizeRadio]:checked" ).val();
// assign quantity from values found in input text box
let productQuantity = $("#productQuant").val();
$.ajax({
// admin-ajax.php url
url: productDataAjax.ajaxUrl,
method: 'post',
dataType: 'json',
data:({
action: 'priceUpdate',
phpProductSize: productSize,
phpProductQuantity: productQuantity,
_ajax_nonce: productDataAjax.nonce
}),
success:function(response){
console.log("success");
//Text to product total
$('#productTotal').text(" " response.dynamicTotal);
}
});
}); // function end
})( jQuery );
The nonce was just added for some extra security. It has nothing to do with the actual solution. I'd like to thank everyone again who pitched in to help me fix this issue. Now I can get back to converting the rest of my Javascript into Ajax.
CodePudding user response:
the 'action'
needs to match the PHP Action. In your case:
$.ajax({
// admin-ajax.php url
url: productDataAjax.url,
method: 'post',
dataType: 'json',
data:({
action: 'dynamicPriceCalc',
phpProductSize: productSize,
phpProductQuantity: productQuantity
}),
success:function(data){
console.log("Success");
// Text to product total
$('#productTotal').text(" " data.dynamicTotal);
}
});
and your PHP function should be:
function dynamicPriceCalc(){
//Your function
}
add_action('wp_ajax_dynamicPriceCalc', 'dynamicPriceCalc');
add_action('wp_ajax_dynamicPriceCalc', 'dynamicPriceCalc');