I am trying to build a simple interface in Woocommerce where a product gets added straight to the mini cart next to it with AJAX, rather than having the page refresh every time you add an item to the cart. Unfortunately I cannot get the AJAX to work and the page just keeps refreshing.
woocommerce.php - the default woocommerce page:
<?php
//LOOP THROUGH ALL PRODUCTS
$args = array( 'post_type' => 'product');
$loop = new WP_Query( $args );
echo "<ul class='mylisting'>";
while ( $loop->have_posts() ) : $loop->the_post();
global $product;
$id = $product->get_id();
$item_name = $product->get_name();
if( $product->is_type( 'variable' ) ){
$class = "variable-product";
} else {
$class = NULL;
}
//OUTPUT PRODUCTS
?>
<li>
<a class="menu-link <?php echo $class; ?>" data-product_id="<?php echo $id; ?>" href="/wpdev/shop/?add-to-cart=<?php echo $id; ?>"><?php echo $item_name." - ".$id; ?></a>
</li>
<?php if( $product->is_type( 'variable' ) ) : ?>
<div id="product-popup-<?php echo $id; ?>" class="product-popup">
<div class="popup-inner">
<?php woocommerce_variable_add_to_cart(); ?>
</div>
</div>
<?php endif; ?>
<?php
endwhile;
echo "</ul>";
wp_reset_query();
?>
<!-- DISPLAY MINI CART -->
<div id="mini-cart-container">
<?php woocommerce_mini_cart(); ?>
</div>
main.js - Main javascript file:
$('.menu-link').click(function(){
jQuery.ajax({
url : woocommerce_params.ajax_url,
type : 'post',
data : {
'action': 'ajax_update_mini_cart'
},
success : function( response ) {
$('#mini-cart-container').html(response);
}
});
});
functions.php
function ajax_update_mini_cart() {
echo wc_get_template( 'cart/mini-cart.php' );
die();
}
add_filter( 'wp_ajax_nopriv_ajax_update_mini_cart', 'ajax_update_mini_cart' );
add_filter( 'wp_ajax_ajax_update_mini_cart', 'ajax_update_mini_cart' );
The goal is to get the woocommerce_mini_cart() function to update with ajax. Is this possible?
I suspect the problem lies with the way I have coded the javascript ajax function, but I'm not sure. Any help would be greatly appreciated.
UPDATE: Moe's solution below has now been added, which has stopped the page reloading but the cart still doesn't update. Echoing some text inside the ajax_update_mini_cart() function does ajax that text inside the mini-cart-container div where the mini-cart should be, which proves (I think) that the javascript function and the php function is working. I think for some reason the problem comes when the echo wc_get_template( 'cart/mini-cart.php' ); is placed inside the function. Does anyone know why this is?
its following the href. try the following
$('.menu-link').click(function(e){
e.preventDefault();
jQuery.ajax({
url : woocommerce_params.ajax_url,
type : 'post',
data : {
'action': 'ajax_update_mini_cart'
},
success : function( response ) {
$('#mini-cart-container').html(response);
}
});
});
Related
The most frustrating thing is that this code was working then suddenly it startet returning an entire page of HTML rather than just the HTML code from the template below.
I'm calling an ajax function and passing it an object that looks like this (result of console.log(data)):
Here is my ajax function:
function mapResults (data) {
//console.log(data);
$.ajax({
type: 'post',
url: wp_ajax.wp_url,
data: {action: 'marker_in_viewport', resultsArray: data},
success: function(result) {
$('#map-results').html(result);
},
error: function(result) {
console.warn(result);
}
});
}
Here is the PHP code that handles the request:
<?php
add_action( 'wp_ajax_nopriv_marker_in_viewport', 'marker_in_viewport');
add_action( 'wp_ajax_marker_in_viewport', 'marker_in_viewport');
function marker_in_viewport() {
$locationResults = $_POST['resultsArray'];
$posts = get_posts(array(
'post_type' => 'accommodation',
'post__in' => $locationResults,
));
?>
<?php
//require result template
//require_once ('map-results.php');
if( $posts ) { ?>
<?php foreach( $posts as $post ) {
$id = $post->ID;
$title = get_the_title($id);
$location = get_field('location', $id);
$permalink = get_permalink( $id );
$rooms_available_from = get_field('rooms_available_from', $id);
$gallery = get_field('gallery', $id);
?>
<div class="col-md-4 accom-results-cont pb-3">
<?php if ($gallery) : ?>
<a href="<?= $permalink; ?>" title="Learn more about <?= $title; ?>">
<div class="accom-results-img-cont">
<img class="img-fluid" src="<?= $gallery['url']; ?>" alt="An image of <?= $title; ?>" >
</div>
<?php endif; ?>
<div class="accom-results-data-cont pr-3 pt-3">
<?php if ( $title ) : ?>
<p class="results-title"><b><?= $title ?></b></p>
<?php endif; ?>
</div>
</a>
</div>
<?php } ?>
<?php } ?>
<?php wp_die(); ?>
<?php } ?>
And in my page template I have the following div where I want the results to be populated:
<div id="map-results"class="row py-5"></div>
Any ideas what I have done wrong?
I revised your code. try the below code.
function mapResults (data) {
$.ajax({
type: 'post',
dataType : "json",
url: wp_ajax.wp_url,
data: {action: 'marker_in_viewport', resultsArray: data},
success: function(result) {
$('#map-results').html(result.data.html);
},error: function(result) {
console.warn(result);
}
});
}
You can use ob_start() and ob_get_clean().
add_action( 'wp_ajax_nopriv_marker_in_viewport', 'marker_in_viewport');
add_action( 'wp_ajax_marker_in_viewport', 'marker_in_viewport');
function marker_in_viewport() {
$locationResults = $_POST['resultsArray'];
$posts = get_posts(array(
'post_type' => 'accommodation',
'post__in' => $locationResults
));
ob_start();
if( $posts ) { foreach( $posts as $post ) {
$id = $post->ID;
$title = get_the_title($id);
$location = get_field('location', $id);
$permalink = get_permalink( $id );
$gallery = get_field('gallery', $id);
$rooms_available_from = get_field('rooms_available_from', $id);
?>
<div class="col-md-4 accom-results-cont pb-3">
<a href="<?php echo $permalink; ?>" title="Learn more about <?php echo $title; ?>">
<?php if ( $gallery ) : ?>
<div class="accom-results-img-cont">
<img class="img-fluid" src="<?php echo $gallery['url']; ?>" alt="An image of <?php echo $title; ?>" >
</div>
<?php endif; ?>
<div class="accom-results-data-cont pr-3 pt-3">
<?php if ( $title ) : ?>
<p class="results-title"><b><?php echo $title; ?></b></p>
<?php endif; ?>
</div>
</a>
</div>
<?php } }
$html = ob_get_clean();
wp_send_json_success(array(
'html' => $html
));
}
USEFUL LINKS
ob_start()
ob_get_clean()
wp_send_json_success()
Finally got this working after about a week of trying!!
Here is my AJAX Function inside js/script.js
$.ajax({
type: 'post',
//dataType: 'json',
url: map_ajax_obj.ajaxurl,
data: {action: 'marker_in_viewport', resultsArray: data, nonce: map_ajax_obj.nonce},
success: function(result) {
//console.log(result);
$('#map-results').html(result);
},
error: function(result) {
console.warn(result);
}
});
Inside my functions.php file I have enqueued and localised my wp-admin.php like this
function load_req_scripts()
{
wp_register_script( 'custom-js-script', get_template_directory_uri() . '/js/script.js', array( 'jquery'), '', true);
wp_enqueue_script( 'custom-js-script' );
wp_localize_script(
'custom-js-script', //I think this is a dependancy on the above script though not entirely sure
'map_ajax_obj',
array (
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ajax_nonce')
)
);
}
add_action( 'wp_enqueue_scripts', 'load_req_scripts' );
require_once('ajax/accommodation-ajax.php'); //where to handle and return the data to the ajax call
here is the function in my accommodation-ajax.php file
<?php
function marker_in_viewport() {
$locationResults = $_POST['resultsArray'];
if (!empty($locationResults)) {
$posts = get_posts(array(
'post_type' => 'accommodation',
'post__in' => $locationResults
));
if( $posts ) {
foreach( $posts as $post ) {
$id = $post->ID;
$title = get_the_title($id);
$location = get_field('location', $id);
$permalink = get_permalink( $id );
$gallery = get_field('gallery', $id);
$rooms_available_from = get_field('rooms_available_from', $id);
?>
<div class="col-md-4 accom-results-cont pb-3">
<a href="<?php echo $permalink; ?>" title="Learn more about <?php echo $title; ?>">
<?php if ( $gallery ) : ?>
<div class="accom-results-img-cont">
<img class="img-fluid" src="<?php echo $gallery['url']; ?>" alt="An image of <?php echo $title; ?>" >
</div>
<?php endif; ?>
<div class="accom-results-data-cont pr-3 pt-3">
<?php if ( $title ) : ?>
<p class="results-title"><b><?php echo $title; ?></b></p>
<?php endif; ?>
</div>
</a>
</div>
<?php } //end for each
} //end if posts
} //end if not empty
else {
echo "No results found please search again!";
}
wp_die();
}
add_action( 'wp_ajax_nopriv_marker_in_viewport', 'marker_in_viewport');
add_action( 'wp_ajax_marker_in_viewport', 'marker_in_viewport');
As to why this now works compared to what I posted above I have no idea!! Could it be the NONCE? though I'm not using it to authenticate in the PHP function. Anyway hope this helps someone or my future self next time I'm banging my head against the wall with wordpress ajax calls.
UPDATE So this stopped working for me again then I realised that it was working when logged in as admin and not workign for logged out and all other users. Because this is a membership site I wanted to block anyone that wasn't an admin form the admin area. Didn't realise that this function was also blocking access to the admin-ajax.php file too. This was redirecting to the Homepage hence why the AJAX call was returning the entire page HTML.
SO I needed to update my function to include:
&& ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX )
to the following:
//block users from admin if not admin
function blockusers_wps_init() {
if ( is_admin() && ! current_user_can( 'administrator' ) && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) {
wp_redirect( home_url() );
exit;
}
}
add_action( 'init', 'blockusers_wps_init' );
Don’t use wp_die() it’s returning html, use just die()
I'm using the ACF gallery field to let users create a gallery on front end and then I have an ajax call to save the gallery without page refresh.
If I remove the ajax save and use the default update post, all images in the gallery save correctly, but when I use my ajax save method only the last image in the gallery saves.
Here's my code:
Single post / form
<?php acf_form_head(); ?>
<?php get_header(); ?>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php $args = array(
'form_attributes' => array(
'id'=>'modalAjaxTrying'
),
'submit_value' => __("update this badboy", 'acf'),
);
acf_form( $args );
?>
<?php endwhile; endif; ?>
<?php acf_enqueue_uploader();?>
<?php get_footer(); ?>
Ajax save in JS file
jQuery('form#modalAjaxTrying :submit').click(function(event){
event.preventDefault();
var form_data = {'action' : 'acf/validate_save_post'};
jQuery('form#modalAjaxTrying :input').each(function(){
form_data[jQuery(this).attr('name')] = jQuery(this).val()
})
form_data.action = 'save_my_data';
jQuery.post(ajaxurl, form_data)
.done(function(save_data){
alert('Added successFully :');
})
})
Functions.php
add_action( 'wp_ajax_save_my_data', 'acf_form_head' );
add_action( 'wp_ajax_nopriv_save_my_data', 'acf_form_head' );
Anyone looking to get ajax save to play nice with ACF gallery here ya go.
In your functions.php
add_action('acf/submit_form', 'my_acf_submit_form', 10, 2);
function my_acf_submit_form( $form, $post_id ) {
if(is_admin())
return;
//Test if it's a AJAX request.
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
echo $form['updated_message'];
die();
}
}
add_action( 'wp_ajax_save_my_data', 'acf_form_head' );
add_action( 'wp_ajax_nopriv_save_my_data', 'acf_form_head' );
function my_acf_save_post( $post_id ) {
// get new values
$value = get_field('add_images', $post_id);
In your JS file
acf.do_action('ready', $('body'));
$('form#modalAjaxTrying').on('submit', function(e){
e.preventDefault();
});
acf.add_action('submit', function($form){
$.ajax({
url: window.location.href,
method: 'post',
data: $form.serialize(),
success: function(data) {
acf.validation.toggle($form, 'unlock');
alert(data);
}
});
});
I have been looking at this code for far too long and am getting nowhere so hopefully someone can help me!
I am building a wordpress site, and for the main blog page, I want to display the content as tiles, but every 3 or 7, I want to display a promo content post-type. I can do this fine, but when I add a Load More Posts button, it resets the counter that I have keeping track of my extra promo content back to 0, therefore only showing the first 2 promo pieces over and over with each new load.
I would appreciate any help. I'm going in circles now.
the important parts of the home.php file :
<div class="blog-post-tiles">
<?php
//variables
$counter = 0;
$promo_counter = 0;
$args = array(
'post_type' => 'promo',
);
//$postlist = new WP_Query( $args );
$postlist = get_posts($args);
$posts = array();
foreach ( $postlist as $post ) {
$promo_posts_array[] += $post->ID;
}
?>
<?php if ( have_posts() ) : ?>
<?php $query = new wp_query( $query_string.'&cat=-16' );
while ( $query->have_posts() ) : $query->the_post() ?>
<?php
// print post loop
get_template_part( 'template-parts/content', get_post_format() );
$counter++;
//display promo content ever 3rd or 10th spot
if (($counter == 3) || ($counter % 10 == 0) || ($counter % 10 == 3)) {
if ($promo_counter < count($promo_posts_array)){
$print_post = $promo_posts_array[$promo_counter];
$promo_thumbnail_src = wp_get_attachment_image_src( get_post_thumbnail_id($print_post), array( 200,200 ), false, '');
?>
<div class="posts_page_tile promo-tile" id="id-<?php echo $print_post; ?>">
<div class="entry-content">
<div class="promo-image" style="background-image:url('<?php echo $promo_thumbnail_src[0]; ?>'); background-color:<?php echo get_post_meta($print_post, 'bgcolor', true) ?>">
<h3><?php echo get_the_title($print_post); ?></h3>
<div class="promo_button_white_border"><?php echo get_post_meta($print_post, 'cta', true); ?>
</div>
</div>
</div>
</div>
<?php
}
$promo_counter++;
wp_reset_postdata();
}
?>
<?php endwhile; ?>
I'm using this load more posts plugin.
Im developing a Form with a (jQuery) onClick button so I can import results from other documents straight into WP Custom Fields.
To do this I MUST include this script to my Form:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>
If I don't include this script then my Form wont work :(
And if I include this script then I can ADD NEW POST and use my Form + Button but then the EDIT POST page wont show up and I only see a WHITE SCREEN.
Finally I figured out if I insert this CODE to LINE 59 in admin-header.php:
<?php if ( is_admin() && $parent_file == 'edit.php') { ?>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<?php } ?>
Then everything will work 100% as I want :D
I thought WP already was using/including this script by default but this is NOT true as I can see. At least not for WP-Backend (Post page).
The problem is: I dont want to edit WP CORE files, so my question is how can I get the same result using functions.php instead of editing admin-header.php?
Just to show you how admin-header looks like from LINE 50 to LINE 73:
<title><?php echo $admin_title; ?></title>
<?php
wp_enqueue_style( 'colors' );
wp_enqueue_style( 'ie' );
wp_enqueue_script('utils');
$admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
?>
<?php if ( is_admin() && $parent_file == 'edit.php') { ?>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<?php } ?>
<script type="text/javascript">
addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
pagenow = '<?php echo $current_screen->id; ?>',
typenow = '<?php echo $current_screen->post_type; ?>',
adminpage = '<?php echo $admin_body_class; ?>',
thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
isRtl = <?php echo (int) is_rtl(); ?>;
</script>
As you can se my CODE is on LINE 11,12 and 13 to make it work.
You can try something like this in your theme functions.php
function admin_add_script() {
wp_enqueue_script('jquery_script', 'http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js', array(), null);
}
add_action('admin_head-edit.php', 'admin_add_script');
Try adding this to your functions.php:
<?php
function add_jquery_data() {
global $parent_file;
if ( isset( $_GET['action'] ) && $_GET['action'] == 'edit' && isset( $_GET['post'] ) && $parent_file == 'edit.php') {
echo "<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>";
}
}
add_filter('admin_head', 'add_jquery_data');
?>
I hope this helps.
I'm trying to use jquery (bpopup)to load a custom post type post into a popup window. An example of what I'm trying to do is at http://outpost.la —just click on any of the images to see the popup.
I think I ultimately need to write a function to do this, but I'm not sure about how to do that. So far I just have two snippets of code—"button that triggers popup" and "element to pop up"—in my page template. The first snippet is doing what I want: displaying the series of custom post type titles as buttons. But the second snippet which is supposed to display the custom post type content in the popup is showing the titles + content of all of the custom post types.
Screenshot of the Popup w/ buttons in the background:
http://cl.ly/image/1f0G0c2s2J3U
Code:
`
<!-- Button that triggers the popup -->
<?php
$args = array(
'post_type' => 'portfolio_project',
'posts_per_page' => -1 );
$loop = new WP_Query( $args );
$i = 0;
echo'<button class="my-button">';
while ( $loop->have_posts() ) : $loop->the_post();
if ($i % 0 == 0 && $i > 0) {
echo '</button>' . "\n" . '<button class="my-button">';
};
?>
<?php the_title(); ?>
<?php
$i++;
endwhile;
echo '</button>';
?>
<!-- Element to pop up -->
<div id="element_to_pop_up">
<?php
// the query
$the_query = new WP_Query( $args ); ?>
<?php if ( $the_query->have_posts() ) : ?>
<!-- pagination here -->
<!-- the loop -->
<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
<h2><?php the_title(); ?></h2>
<?php endwhile; ?>
<!-- end of the loop -->
<!-- pagination here -->
<?php wp_reset_postdata(); ?>
<?php else: ?>
<p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>
<?php endif; ?>
<!-- end custom post type loop -->
</div>
<!-- END Element to pop up -->
<script>
// Semicolon (;) to ensure closing of earlier scripting
// Encapsulation
// $ is assigned to jQuery
;(function($) {
// DOM Ready
$(function() {
// Binding a click event
// From jQuery v.1.7.0 use .on() instead of .bind()
$('.my-button').bind('click', function(e) {
// Prevents the default action to be triggered.
e.preventDefault();
// Triggering bPopup when click event is fired
$('#element_to_pop_up').bPopup({
appendTo: 'body'
, position: ['auto','0']
, positionStyle: 'fixed'
, scrollBar: 'false'
});
});
});
})(jQuery);
</script>
`
Actually Wordpress uses a different approach for ajax request. You have to understand that first. So, the simple prototype is something like this
// In your functions.php file
add_action( 'wp_ajax_nopriv_ MyAjaxAction', 'MyAjaxFunction' );
add_action( 'wp_ajax_ MyAjaxAction', 'MyAjaxFunction' );
function MyAjaxFunction() {
// do query for your posts
// process it
// echo it
die();
}
In your client side/jQuery code
$(function(){
$('.myButton').on('click', function(e){
e.preventDefault();
// other code
$.ajax({
'url':'/wp-admin/admin-ajax.php', // admin-ajax.php will handle the request
'type':'post',
'data': {
// this is the action hook to call the handler "MyAjaxFunction"
'action': 'MyAjaxAction',
// pass some data to post variblr to use in php/wordpress (optional)
'id':'someId' // you can retrieve this using $_POST['id'];
},
'success':function(data){
// returned data by wordpress
}
});
});
});
This is the proper way to handle ajax request in WordPress, read this article for more help and as a bonus download this book.