Load WP_Query via AJAX breaks WooCommerce Product JS - php

I am planning to create a menu to sort my products dynamically. Each time a sorting method is selected (i.e. by price) I want to refresh the products and have an ajax call load in a new WP_Query.
I am successful so far at loading the products via a button which triggers an AJAX call, but my problem is that once the products load there are some issues with their normal functionality.
The products are variables, and usually when you have selected which variable options you like a price will be outputted. This no longer happens and I'm wondering how I can refresh the variable product's JS so that it works.
Here is what my functions.php look like.
//Enqueue Ajax Scripts
function enqueue_product_show_ajax() {
wp_register_script( 'product-show-ajax-js', get_template_directory_uri() . '/js/product-show-ajax.js', array( 'jquery' ), '', true );
wp_localize_script( 'product-show-ajax-js', 'product_show_ajax', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
wp_enqueue_script( 'product-show-ajax-js' );
}
add_action('wp_enqueue_scripts', 'enqueue_product_show_ajax');
function ajax_show_product() {
$args = array(
'post_type' => 'product',
'posts_per_page' => 12,
// Indicate the product category - in this case "Training"
'product_cat' => 'training',
'orderby' => '_price',
'order' => 'desc'
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post(); ?>
<div class="product-node">
<?php wc_get_template_part( 'content', 'single-product' ); ?>
</div>
<?php endwhile;
}
wp_reset_postdata();
die();
}
//Add Ajax Actions
add_action('wp_ajax_show_product', 'ajax_show_product');
add_action('wp_ajax_nopriv_show_product', 'ajax_show_product');
Here is my AJAX call in my product-show-ajax.js
$('.ajax').on('click', function(){
show_products();
});
//Main ajax function
function show_products() {
$.ajax({
type: 'GET',
url: product_show_ajax.ajax_url,
data: {
action: 'show_product',
},
beforeSend: function ()
{
//Eventually show a loader here
},
success: function(data)
{
//Eventually hide loader here
$( '.product-container' ).html(data);;
},
error: function()
{
//If an ajax error has occured, do something here...
$(".product-container").html('<p>There has been an error</p>');
}
});
}
So to recap, my problem is that WooCommerce specific JS to do with variable products isn't running, I'm guessing because it's loaded before the products and so when the ajax function shows the products the JS that was loaded for them hasn't binded to any of the elements.
How can I make sure WooCommerce specific JS is reloaded once my product loads?
Thanks All!

Related

Count how many times button is clicked Wordpress

My ajax call on click redirects me to /undefined, /wp-admin/admin-ajax.php has value 0
I'm using Divi theme, custom ajax script which is localized:
function my_enqueue() {
wp_enqueue_script( 'increment_counter', get_stylesheet_directory_uri() . '/js/slug-ajax.min.js', array('jquery') );
wp_localize_script( 'increment_counter', 'my_ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue' );
Counter function:
add_action('wp_ajax_increment_counter', 'my_increment_counter');
add_action('wp_ajax_nopriv_increment_counter', 'my_increment_counter');
function my_increment_counter(){
// Name of the option
$option_name = 'my_click_counter';
// Check if the option is set already
if ( get_option( $option_name ) !== false ) {
$new_value = intval(get_option($option_name)) + 1;
// The option already exists, so update it.
update_option( $option_name, $new_value );
} else {
// The option hasn't been created yet, so add it with $autoload set to 'no'.
$deprecated = null;
$autoload = 'no';
add_option( $option_name, 1 , $deprecated, $autoload );
}
}
Ajax file has this jQuery code for increment counter:
jQuery(document).ready(function($){
$('.activate-popup-animation').click(function(e){
e.preventDefault();
$.ajax({
url: my_ajax_object.ajaxurl,
data: {
action: 'increment_counter',
},
type: 'POST',
})
.done(function(){
// go to the link they clicked
window.location = $(this).attr('href');
})
.fail(function(xhr){
console.log(xhr);
})
});
});
Now, plan is to create custom widget in dashboard and call this function:
get_option('my_click_counter')
Where I'm making mistake, is that url problem with call action?
Your ajax function should call some action, in this case "my_increment_counter", but instead you wrote "increment_counter", same with wordpress hooks. It should be:
add_action('wp_ajax_my_increment_counter', 'my_increment_counter');
add_action('wp_ajax_nopriv_my_increment_counter', 'my_increment_counter');

is_page() conditional not working inside an AJAX function

I am doing filtering posts using ajax.
I wish $ array was different for pages "Products" and "Faq"
If this is executed within an ajax request, is_page() won't be set. the page you're making the request from was a previous request. you need to set something on the originating page to pass with your ajax request to let it know it's for your special case page.
functions.php
function load_scripts() {
wp_enqueue_script( 'ajax', get_template_directory_uri() . '/vendor/jquery/main.js', array( 'jquery' ), NULL, true );
wp_localize_script( 'ajax', 'wp_ajax',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'is_page' => is_page( 420 ), // Whatever you want to pass. Add as many key pairs as needed.
)
);
}
add_action( 'wp_enqueue_scripts', 'load_scripts');
add_action( 'wp_ajax_nopriv_filter', 'filter_ajax' );
add_action( 'wp_ajax_filter', 'filter_ajax' );
function filter_ajax() {
$category = $_POST['category'];
if(isset($_POST['is_page']) && $_POST['is_page'] === 'faq'){
$cat__in = 10;
print_r( $_POST );
echo "FAQ";
} else{
$cat__in = 4;
print_r( $_POST );
echo "Products";
}
$args = array(
'post_type' => 'post',
'posts_per_page' => 50,
'category__in' => $cat__in,
);
if(isset($category)) {
$args['category__in'] = array($category);
}
$query = new WP_Query($args);
if($query->have_posts()) :
while($query->have_posts()) : $query->the_post();
the_title('<h2>', '</h2>');
the_content('<p>', '</p>');
endwhile;
endif;
wp_reset_postdata();
die();
}
faq.php
<div class="js-filter">
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 100,
'child_of' => 10,
'exclude' => array(1),
);
$query = new WP_Query(array( 'cat' => 10 ));
if($query->have_posts()) :
while($query->have_posts()) : $query->the_post();
the_title('<h2>', '</h2>');
the_content('<p>', '</p>');
endwhile;
endif;
wp_reset_postdata(); ?>
</div>
<div class="categories">
<ul>
<?php
$cat_args = array(
'exclude' => array(1),
'child_of' => 10
);
?>
<?php
global $post;
$category = reset(get_the_category($post->ID));
$category_id = $category->cat_ID;
?>
<li class="js-filter-item">All</li>
<?php $categories = get_categories($cat_args); foreach($categories as $cat) : ?>
<li class="js-filter-item"><a data-category="<?= $cat->term_id; ?>" href="<?= get_category_link($cat->term_id); ?>"><?= $cat->name; ?></a></li>
<?php endforeach; ?>
</ul>
</div>
products.php
<div class="js-filter">
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 100,
'child_of' => 6,
'exclude' => array(1,10),
);
$query = new WP_Query(array( 'cat' => 6 ));
if($query->have_posts()) :
while($query->have_posts()) : $query->the_post();
the_title('<h2>', '</h2>');
the_content('<p>', '</p>');
endwhile;
endif;
wp_reset_postdata(); ?>
</div>
<div class="categories">
<ul>
<?php
$cat_args = array(
'exclude' => array(1,10),
'child_of' => 6
);
?>
<?php
global $post;
$category = reset(get_the_category($post->ID));
$category_id = $category->cat_ID;
?>
<li class="js-filter-item">All</li>
<?php $categories = get_categories($cat_args); foreach($categories as $cat) : ?>
<li class="js-filter-item"><a data-category="<?= $cat->term_id; ?>" href="<?= get_category_link($cat->term_id); ?>"><?= $cat->name; ?></a></li>
<?php endforeach; ?>
</ul>
</div>
main.js
jQuery(function($){
$(document).on('click', '.js-filter-item > a', function(e){
e.preventDefault();
var category = $(this).data('category');
$.ajax({
url: wp_ajax.ajax_url,
data: {
action: 'filter',
is_page: wp_ajax.is_page, // This param will be passed to your ajax function.
category: category,
pageslug: location.pathname.replace(/\//g,'')
},
type: 'post',
success: function(result) {
$('.js-filter').html(result);
},
error: function(result) {
console.warn(result);
}
});
});
});
do you have any idea how to solve it? After clicking on the "All" button, it displays posts from the "ID = 6" category
You can pass your parameter by using the localize script feature. Since the page isn't passed to your ajax function, you need to set your params in localize script, then pass to your ajax as part of the localized array.
function load_scripts() {
wp_enqueue_script( 'ajax', get_template_directory_uri() . '/vendor/jquery/main.js', array( 'jquery' ), NULL, true );
wp_localize_script( 'ajax', 'wp_ajax',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'is_page' => is_page( 420 ), // Whatever you want to pass. Add as many key pairs as needed.
)
);
}
add_action( 'wp_enqueue_scripts', 'load_scripts');
In the case above, is_page is either true or false, and will pass to your javascript via the localized script. So in the JS file, wp_ajax.is_page will be either true or false (you can view this by inspecting your js object on the page. It should be a 0 or a 1.
If you wanted to pass other objects, you can create as many items to your array and then pass to your js template.
Your AJAX:
jQuery(function($){
$(document).on('click', '.js-filter-item > a', function(e){
e.preventDefault();
var category = $(this).data('category');
$.ajax({
url: wp_ajax.ajax_url,
data: {
action: 'filter',
is_page: wp_ajax.is_page, // This param will be passed to your ajax function.
category: category,
pageslug: location.pathname.replace(/\//g,'')
},
type: 'post',
success: function(result) {
$('.js-filter').html(result);
},
error: function(result) {
console.warn(result);
}
});
});
});
Then in your updated php ajax action.
function filter_ajax() {
$category = $_POST['category'];
// If it's page 420... then $_POST['is_page'] will equal a string 1.
if ( isset( $_POST['is_page'] ) && $_POST['is_page'] === '1' ) {
$cat__in = 10;
print_r( $_POST );
echo "FAQ";
} else {
$cat__in = 4;
print_r( $_POST );
echo "Products";
}
// .... rest of function
}
is_page() is not supposed to work in wp_ajax_ functions.
Check this answer: Why doesn't is_page(id) work in functions.php?
is_page() relies on a complete global $wp_query object. If you call it before the action template_redirect has been fired, it might be impossible to get that data.
Instead of using is_page(), you can pass the slug as ajax data array value.
To pass as slug, edit main.js to replace
data: { action: 'filter', category: category },
with
data: {
action: 'filter',
category: category,
pageslug: location.pathname.replace(/\//g,'')
},
Then, in functions.php in filter_ajax() function, replace
if (is_page('faq'))
with
if(isset($_POST['pageslug']) && $_POST['pageslug'] === 'faq')

Getting the contents of a WooCommerce basket with JQuery

I've been working with WooCommerce recently and I was wondering if it was possible to get cart items via JavaScript or JQuery
I know you can use PHP functions to retrieve the contents of the cart but currently I do not have access to the backend of the site.
I've found a similar question here: WooCommerce cookies and sessions - Get the current products in cart
In the session there is a wc_fragment that contains the HTML of the cart.
{"div.widget_shopping_cart_content":"<div class=\"widget_shopping_cart_content\">\n\n\t<ul class=\"woocommerce-mini-cart cart_list product_list_widget \">\n\t\t\t\t\t\t<li class=\"woocommerce-mini-cart-item mini_cart_item\">\n\t\t\t\t\t×\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t<img width=\"800\" height=\"450\" src=\"https://cdn2.co.uk/app/uploads/Overlapped-800x450.jpg\" class=\"attachment-woocommerce_thumbnail size-woocommerce_thumbnail\" alt=\"\" />Raspberry Drinking Yogurt - 1 drink\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"quantity\">1 × <span class=\"woocommerce-Price-amount amount\"><span class=\"woocommerce-Price-currencySymbol\">£</span>1.50</span></span>\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\n\t<p class=\"woocommerce-mini-cart__total total\">\n\t\t<strong>Subtotal:</strong> <span class=\"woocommerce-Price-amount amount\"><span class=\"woocommerce-Price-currencySymbol\">£</span>1.50</span>\t</p>\n\n\t\n\t<p class=\"woocommerce-mini-cart__buttons buttons\">View basketCheckout</p>\n\n\t\n\n</div>"}
Would it be possible to extract the elements from this?
I've found a solution for you. Maybe there is a better one but's how I would do it.
First create a custom JS file and register it. Also add a custom ajaxurl (in case you don't did this already):
add_action( 'wp_enqueue_scripts', 'wp_enqueue_scripts_action' );
function wp_enqueue_scripts_action() {
wp_register_script( 'child-theme', get_stylesheet_directory_uri() . '/assets/child.js', [ 'jquery' ] );
wp_enqueue_script( 'child-theme' );
wp_localize_script( 'child-theme', 'child_theme', [
'ajaxurl' => admin_url( 'admin-ajax.php' )
]
);
}
Now add an AJAX endpoint:
add_action( 'wp_ajax_get_cart_items', 'wp_ajax_get_cart_items_action' );
add_action( 'wp_ajax_nopriv_get_cart_items', 'wp_ajax_get_cart_items_action' );
function wp_ajax_get_cart_items_action() {
$cart = WC()->cart;
if ( $cart ) {
wp_send_json_success( $cart->get_cart_contents() );
/** #noinspection ForgottenDebugOutputInspection */
wp_die();
}
}
This will return the content of the cart in case a cart is available. Now call it inside your JS function. In my case for testing directly in the document.ready method:
(function ( $ ) {
$( document ).ready( function () {
let data = {
action: 'get_cart_items'
};
$.post( child_theme.ajaxurl, data, function () {
} ).done( function ( response ) {
console.log( response );
} ).fail( function ( response ) {
console.log( 'Fail' );
} );
} );
})( jQuery );
This will return for example:
077e29b11be80ab57e1a2ecabb7da330: {key:
"077e29b11be80ab57e1a2ecabb7da330", product_id: 249, variation_id: 0,
variation: Array(0), quantity: 1, …}
I think you need to add some null checks but all in all its a working solution.

My function containing a mysql query launched by ajax is not working in wordpress. What am I missing?

I am trying to insert rows into a table I've set up based on user's answers. I have made a child theme and a custom template for the page with the form. My issue is that I have no way of knowing what's going wrong where and why the data isn't being inserted. my js onclick function is as follows, and this file is called question_submit.js:
jQuery(document).ready(function(){
jQuery("#questionSubmit").click(function(){
alert("clicked");
jQuery.ajax({
type: 'POST',
dataType: 'json',
url: my_ajax_object.ajax_url,
data: {
'action' : 'dbtest',
'option': 1,
},
success: function(data){
alert(data);
}
});
})
});
Here is where I enqueue the script:
function my_enqueue() {
wp_enqueue_script( 'question_submit', get_stylesheet_directory_uri() . '/assets/js/question_submit.js', array('jquery') );
wp_localize_script( 'question_submit', 'my_ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue' );
And finally here is the function that's binded to the action:
function dbtesting(){
global $wpdb;
$data = $_POST['data'];
//$option = sanitize_text_field($_POST["option"]);
$tableName = 'user_answers';
$insert_row = $wpdb->insert(
$tableName,
array(
'user_id' => 2,
'module_id' => 3,
'section_id' => 1,
'question_id' => 2,
'option_no' => 1,
)
);
// if row inserted in table
if($insert_row){
echo json_encode(array('res'=>true, 'message'=>__('New row has been inserted.')));
}else{
echo json_encode(array('res'=>false, 'message'=>__('Something went wrong. Please try again later.')));
}
wp_die();
}
add_action( 'wp_ajax_dbtest', 'dbtesting' );
add_action( 'wp_ajax_nopriv_dbtest', 'dbtesting' );
Both of these functions are in my child theme's functions.php file. Right now I am using hard-coded values jsut to test the functionality, later these values will be dependent on the form answers.
When I click the submit button, there is no change in my table but also no php errors.

Wordpress Admin Ajax 400 (Bad Request)

I have used Wordpress Admin Ajax and the console shows that 400 (Bad Request)
jQuery('#submitid').click(function(e){
e.preventDefault();
//var newCustomerForm = jQuery(this).serialize();
jQuery.ajax({
type: "POST",
url: "wp-admin/admin-ajax.php",
data: {status: 'status', name: 'name'},
success:function(data){
jQuery("#result").html(data);
}
});
});
The Wordpress AJAX process has some basic points that should be followed if you want it to work correctly:
1.In functions.php add the action you'd like to call from the frontend:
function logged_in_action_name() {
// your action if user is logged in
}
function not_logged_in_action_name() {
// your action if user is NOT logged in
}
add_action( 'wp_ajax_logged_in_action_name', 'logged_in_action_name' );
add_action( 'wp_ajax_nopriv_not_logged_in_action_name', 'not_logged_in_action_name' );
2.Register the localization object in functions.php
// Register the script
wp_register_script( 'some_handle', 'path/to/myscript.js' );
// Localize the script with new data
$some_object = array(
'ajax_url' => admin_url( 'admin-ajax.php' )
);
wp_localize_script( 'some_handle', 'ajax_object', $some_object );
// Enqueued script with localized data.
wp_enqueue_script( 'some_handle' );
3.Create the AJAX request on the frontend
// source: https://codex.wordpress.org/AJAX_in_Plugins
var data = {
'action': 'not_logged_in_action_name',
'whatever': 1234
};
jQuery.post( ajax_object.ajax_url, data, function( response ) {
console.log( response );
}
All Wordpress Ajax call must have action param which points to hook wp_ajax_{action_param} or wp_ajax_nopriv_{action_param} and from there you jump to function from that hooks.
From Codex:
add_action( 'wp_ajax_my_action', 'my_action' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action' );
function my_action() {
$status = $_POST['status'];
}
first you shouldn't write the url by yourself. You could use the localize function to add the url to your javascript file:
wp_enqueue_script('myHandle','pathToJS');
wp_localize_script(
'myHandle',
'ajax_obj',
array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) )
);
After this you can use ajax_obj.ajax_url within your script to receive the url.
Second, did you implement the correct hook?
// Only accessible by logged in users
add_action( 'wp_ajax_my_action', 'my_action_callback' );
// Accessible by all visitors
add_action( 'wp_ajax_nopriv_my_action', 'my_action_callback' );
Best Regards

Categories