Load Template-Part with Ajax in Wordpress - javascript

Hi I am trying to add a feature to my store that when someone clicks on a product instead of being redirected to the product page, the product page loads with ajax in the home page like in this website (click on one of the products): http://www.itsjustyes.com. This is my jquery:
jQuery(document).ready(function($){
$('.info_btn').on('click',function(){
var theId = $(this).attr('id');
var div = $('#product-container')
$.post('wp-admin/admin-ajax.php',{
action:'my_get_posts',post_id: theId
}, function(data){
console.log(data);
div.html(data);
})
return false;
});
});
This is my code in functions.php:
//Ajax call to product
function my_get_posts_return()
{
global $post;
$post_id = intval(isset($_POST['post_id']) ? $_POST['post_id'] : 0);
if ($post_id > 0) {
$the_query = new WP_query(array('p' => $post_id));
if ($the_query->have_posts()) {
while ($the_query->have_posts()) : $the_query->the_post();
wc_get_template_part( 'content', 'single-product' );
endwhile;
} else {
echo "There were no posts found";
}
}
wp_die();
}
add_action('wp_ajax_my_get_posts', 'my_get_posts_return');
add_action('wp_ajax_nopriv_my_get_posts', 'my_get_posts_return');
I keep getting that there were no posts found in the loop which is weird cause I know I am sending the right post id. By the way, if I try to get the individual parts of the product page with get_the_title( $post_id ) I get it just fine. It's only when I try to load the template part with the loop that I get this problem. Any idea what I am doing wrong??

Your WP_Query was not finding the correct post type.
$the_query = new WP_query(array('p' => $post_id));
The query above didn't return any post at all. By default, wordpress will assume that you're querying the post_type = 'posts' which is why you cannot find the product post.
Therefore, you need to specify what post_type you're looking for. With WooCommerce product, you can use:
$the_query = new WP_query(array('p' => $post_id, 'post_type' => 'product'));
P.S. It's a good practice to use wp_localize_script function to register your ajaxurl, rather than hard coded in your javascript. You can follow this post for more detail.
Hope this helps.

Related

Update InnerHTML (Echo PHP) Value on Button Click [duplicate]

This question already has answers here:
What is the difference between client-side and server-side programming?
(3 answers)
Closed 9 months ago.
I am still in beginner's level of WordPress and PHP. I already doing my research in stackoverflow but because of my low-level understanding, I can't find the solution for the problem I have.
I use WordPress as CMS for my website. I use PHP echo for showing the average rating value of a user review plugin. It shows fine. But after a visitor insert his/her own rating and click submit button, the average rating value didn't update until the page is refreshed. How to automatically update the average rating value after the submit button clicked without having to refresh the page?
<script type="text/javascript">
var userRating = <?php echo rmp_get_avg_rating( $postID ); ?> ;
document.getElementById("div-rating").innerHTML = userRating;
</script>
This is the submit button class created by the plugin to trigger User Submission.
rmp-rating-widget__submit-btn rmp-btn js-submit-rating-btn rmp-rating-widget__submit-btn--visible
This is the PHP function I need to echo.
public function load_results() {
if ( wp_doing_ajax() ) {
// array with vote count, ratings and errors
$data = array(
'voteCount' => false,
'avgRating' => false,
'errorMsg' => '',
);
$post_id = intval( $_POST['postID'] );
$nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : false;
// security check
if( ! $post_id ) {
$data['errorMsg'] = esc_html__( 'You cannot rate a web page without an id!', 'rate-my-post' );
echo json_encode( $data );
die();
}
$nonce_check = $this->has_valid_nonce( $nonce );
if( ! $nonce_check['valid'] ) {
$data['errorMsg'] = $nonce_check['error'];
echo json_encode( $data );
die();
}
$vote_count = rmp_get_vote_count( $post_id );
$sum_of_ratings = rmp_get_sum_of_ratings( $post_id );
$average_rating = rmp_calculate_average_rating( $sum_of_ratings, $vote_count );
if ( $average_rating ) { // post has been rated
$data['voteCount'] = $vote_count;
$data['avgRating'] = $average_rating;
} else { // no ratings so far
$data['voteCount'] = 0;
$data['avgRating'] = 0;
}
echo json_encode( $data );
};
die();
}
Thank you for your help.
Without refreshing the webpage, you can take the data on the server by using XMLHttpRequest object on client side. You can find a lot of implementations ( such as
XMLHttpRequest, Fetch API) which help you for communicating with the server from client side without refreshing page.
If you want to use a different technology ( Socket.io ), web sockets can meet your needs on this problem.

(populate dropdown in contact form 7 getting this error - Warning: array_keys() expects parameter 1 to be array, null given in

Ok where to start, I will try and explain as much as I can.
I am using wordpress with contact form 7 and I am trying to populate 3 dropdown items on the contact form, I found some code that I was able to use with no problem but the problem with this was that it was getting the information from a excel file, the file is now to big and will not run on my website anymore so I would like to get the information from my database now.
I have made a table in my database "vehicle_information" with 3 columns "vehicle_type", "vehicle_make", vehicle_model"
I have code in my functions.php and code in my footer to be able to use the cf7 shortcodes.
Code from funtions.php
function ajax_cf7_populate_values() {
//MySQLi information
$db_host = '***';
$db_username = '***';
$db_password = '***';
$vehicles_makes_models = array();
//connect to mysqli database (Host/Username/Password)
$connection = mysqli_connect($db_host, $db_username, $db_password) or die('Error ' . mysqli_error());
//select MySQLi dabatase table
$vehicles_makes_models = mysqli_select_db($connection, 'vehicle_information') or die('Error ' . mysqli_error());
$sql = mysqli_query($connection, 'SELECT * FROM vehicle_type');
while($row = mysqli_fetch_array($sql)) {
$vehicles_makes_models[$row[0]][$row[1]][] = $row[2]; }
}
// setup the initial array that will be returned to the the client side script as a JSON object.
$return_array = array(
'vehicles' => array_keys($vehicles_makes_models),
'makes' => array(),
'models' => array(),
'current_vehicle' => false,
'current_make' => false
);
// collect the posted values from the submitted form
$vehicle = key_exists('vehicle', $_POST) ? $_POST['vehicle'] : false;
$make = key_exists('make', $_POST) ? $_POST['make'] : false;
$model = key_exists('model', $_POST) ? $_POST['model'] : false;
// populate the $return_array with the necessary values
if ($vehicle) {
$return_array['current_vehicle'] = $vehicle;
$return_array['makes'] = array_keys($vehicles_makes_models[$vehicle]);
if ($make) {
$return_array['current_make'] = $make;
$return_array['models'] = $vehicles_makes_models[$vehicle][$make];
if ($model) {
$return_array['current_model'] = $model;
}
}
}
// encode the $return_array as a JSON object and echo it
echo json_encode($return_array);
wp_die();
// These action hooks are needed to tell WordPress that the cf7_populate_values() function needs to be called
// if a script is POSTing the action : 'cf7_populate_values'
add_action( 'wp_ajax_cf7_populate_values', 'ajax_cf7_populate_values' );
add_action( 'wp_ajax_nopriv_cf7_populate_values', 'ajax_cf7_populate_values' );
Code from my footer
<script>
(function($) {
// create references to the 3 dropdown fields for later use.
var $vehicles_dd = $('[name="vehicles"]');
var $makes_dd = $('[name="makes"]');
var $models_dd = $('[name="models"]');
// run the populate_fields function, and additionally run it every time a value changes
populate_fields();
$('select').change(function() {
populate_fields();
});
function populate_fields() {
var data = {
// action needs to match the action hook part after wp_ajax_nopriv_ and wp_ajax_ in the server side script.
'action' : 'cf7_populate_values',
// pass all the currently selected values to the server side script.
'vehicle' : $vehicles_dd.val(),
'make' : $makes_dd.val(),
'model' : $models_dd.val()
};
// call the server side script, and on completion, update all dropdown lists with the received values.
$.post('<?php echo admin_url( 'admin-ajax.php' ) ?>', data, function(response) {
all_values = response;
$vehicles_dd.html('').append($('<option>').text(' -- choose vehicle -- '));
$makes_dd.html('').append($('<option>').text(' -- choose make -- '));
$models_dd.html('').append($('<option>').text(' -- choose model -- '));
$.each(all_values.vehicles, function() {
$option = $("<option>").text(this).val(this);
if (all_values.current_vehicle == this) {
$option.attr('selected','selected');
}
$vehicles_dd.append($option);
});
$.each(all_values.makes, function() {
$option = $("<option>").text(this).val(this);
if (all_values.current_make == this) {
$option.attr('selected','selected');
}
$makes_dd.append($option);
});
$.each(all_values.models, function() {
$option = $("<option>").text(this).val(this);
if (all_values.current_model == this) {
$option.attr('selected','selected');
}
$models_dd.append($option);
});
},'json');
}
})( jQuery );
The problem is I am still learning and this is the first time I have had to use this funtion.
and I am getting an error on my website
Warning: array_keys() expects parameter 1 to be array, null given in /customers/4/0/0/motobid.co.uk/httpd.www/wp-content/themes/storevilla-child/functions.php on line 38 {"vehicles":null,"makes":[],"models":[],"current_vehicle":false,"current_make":false}
any help would be very greatful.
Just like to say code was supplied by BDMW.
Where you use the method array_keys(), instead of:
$return_array['makes'] = array_keys($vehicles_makes_models[$vehicle]);
Try this:
$return_array['makes'] = ! empty($vehicles_makes_models[$vehicle]) ? array_keys($vehicles_makes_models[$vehicle]) : [];
From what I've read, the array_keys() has been an issue depending on php versions. Hope this helps!

Update Woocommerce product gallery with Ajax

I'm trying to do a dynamic product gallery based on colours in woocommerce product page. When I click on one colour, example on red, i should see Red Gallery's photos.
To do this i replaced all woocommerce gallery block with a new one created by ajax ( who have same classes of old gallery).
The loading of new photos work fine and I get gallery photos based on colour.
But when ajax load new gallery the slider don't work, I think because the woocommere js, who create the slider, is read only on page load.
I think I should reload some Woocommerce JS Function to recreate slider with his functions, but I don't know how.
This is the php file, which one I create a new gallery, called from ajax:
global $product;
$current_id = "";
if(isset($_POST['prodid']) && $_POST['prodid'] != "" ) {
$current_id = $_POST['prodid'];
$product = new WC_Product($current_id);
}
$columns = apply_filters( 'woocommerce_product_thumbnails_columns', 4 );
$post_thumbnail_id = $product->get_image_id();
$wrapper_classes = apply_filters( 'woocommerce_single_product_image_gallery_classes', array(
'woocommerce-product-gallery',
'woocommerce-product-gallery--' . ( $product->get_image_id() ? 'with-images' : 'without-images' ),
'woocommerce-product-gallery--columns-' . absint( $columns ),
'images',
) );
?>
<figure class="woocommerce-product-gallery__wrapper">
<?php
if ( $product->get_image_id() ) {
$html = wc_get_gallery_image_html( $post_thumbnail_id, true );
} else {
$html = '<div class="woocommerce-product-gallery__image--placeholder">';
$html .= sprintf( '<img src="%s" alt="%s" class="wp-post-image" />', esc_url( wc_placeholder_img_src( 'woocommerce_single' ) ), esc_html__( 'Awaiting product image', 'woocommerce' ) );
$html .= '</div>';
}
echo apply_filters( 'woocommerce_single_product_image_thumbnail_html', $html, $post_thumbnail_id ); // phpcs:disable WordPress.XSS.EscapeOutput.OutputNotEscaped
do_action( 'woocommerce_product_thumbnails' );
?>
</figure>
This is the ajax function called on box colour click
function changeGallery(selected_gallery, productID) {
jQuery(function($) {
var select_color = selected_gallery;
var xhttp;
$.ajax({
url : 'https://mysite.it/wp-admin/admin-ajax.php', // AJAX handler
data : { action : 'load_gallery', gallery : select_color, prodid : productID },
type : 'POST',
beforeSend: function() {
},
success : function( result ){
if( result ) {
$('.woocommerce-product-gallery').html(result);
//Reload here some woocommerce JS functions?
}
}
});
});
}
The way to solve issues like this is to look at the WooCommerce source code to see how the plugin initialises the gallery to begin with. Based on this, I think you need to do something like:
jQuery( '.woocommerce-product-gallery' ).each( function() {
jQuery( this ).wc_product_gallery();
} );
See Github: single-product.js for reference.
I had same problem. The dafoxuk answer is correct, you need to reinitialize ProductGallery class on the .woocomorce-product-gallery. The problem was that this element already has a flexslider entity attached to it. To solve this, just remove that element (.woocomorce-product-gallery) and create a new identical one. (Flexslider doesn't have a way to detach itself from the element as far as I know)

My AJAX function works correctly, but sometimes I get a JSON object undefined

i am building the next interface:
as you can see, this interface has two links shown as buttons, one to add products and the other one to rest products.
when i click in the link "addProduct" then it calculates the new total which is shown in the following interface:
The code involved in this operation, involves 2 files:
JQuery Ajax File:
$.ajax({
async:true,
type:"POST",
url: "masProducto.php",
datatype:"JSON",
data: {
tecantidad: tecantidad.val(),
valorId:id
},
success:function (jsonStr) {
var cantidad=jsonStr.cantidad;
var fila=$("#ticket_"+jsonStr.id);
var tetotal=fila.find(".precioTotal");
var teprecio=parseFloat(fila.find("input[type=hidden]").val());
var teCosteTotal=$("#importeTotal");
teCosteTotal.text(jsonStr.total+"€");
tetotal.text(teprecio*cantidad+"€");
var resumenTotal=$("#resumenTicket td:nth-child(3)");
resumenTotal.text(jsonStr.total+"€");
var resumenNumProductos=$("#resumenTicket td:nth-child(1)");
resumenNumProductos.text(jsonStr.numTotalProductos+" Items en la cesta");
},
error:function(err){
alert(err);
},
timeout:4000
});
The file masProducto.php where the JSON object is built:
<?php
include 'functions.php';
include('./ShoppingCart.php');
include('./Item.php');
sec_session_start(); //Nuestra manera personalizada segura de iniciar sesión php.
if (!isset($_SESSION['cesta'])){
header('Location: ./login.php?error=1');
}
else {
$cesta=new ShoppingCart();
$cesta=unserialize($_SESSION['cesta']);
}
header('Content-Type: application/json');
$listaItems=$cesta->getItems();
$numEltos=$cesta->count();
$tecantidad=$_POST['tecantidad'];
$id=$_POST['valorId'];
foreach ($listaItems as $celda){
if($id===$celda['item']->getId()){
$cesta->updateItem($celda['item'],$tecantidad);
}
}
$_SESSION['cesta']=serialize($cesta);
if(isset($id)){
$data = array(
"cantidad" => $tecantidad,
"id" => $id,
"total" => $cesta->calcularTotal(),
"numTotalProductos" => $numEltos
);
echo json_encode($data);
}
?>
I am using PHP OOP, and i use to objects for my shopping basket which are the "Soppingcart" and "Item".
My problem is that this code works right, but when i click fast to the plus (or rest button), it gives me back an undefined object.
I would apreciate if some could help me, because i dont even know how to look for the solution for this problem.
for more details you can enter in this website www.galeonweb.es/Index.php, where if you loggin with "test#example.com" and password "123456" you can see what is my problem better.
Thank you in advance
First off this line is pretty bad practice
if (!isset($_SESSION['cesta'])){
header('Location: ./login.php?error=1');
}
You should rather have something like
if (!isset($_SESSION['cesta'])){
echo json_encode(array(code => 2, message => 'Session invalid'));
}
And redirect the user to the login page from jQuery.
You would then need to modify the rest accordingly
if(isset($id)){
$data = array(
"code" => 0,
"message" => "Success",
"data" => array(
"cantidad" => $tecantidad,
"id" => $id,
"total" => $cesta->calcularTotal(),
"numTotalProductos" => $numEltos
)
);
echo json_encode($data);
}
I would also add the following to that
else {
echo json_encode(array('code' => 1, 'message' => 'Item not found' ));
}
Furthermore rather than test if an id is passed at the very end I would do
if(isset($id)){
$found = false;
foreach ($listaItems as $celda){
if($id===$celda['item']->getId()){
$cesta->updateItem($celda['item'],$tecantidad);
$found = true;
}
}
}
else
{
echo json_encode(array(code => 1, message => 'Fatal error, id not set'));
}
And replace
if(isset($id)){
$data = array(
With
if($found === true){
$data = array(
You'll of course have to adapt your javascript accordingly to parse the response.
Those changes should give you a better idea of what is going wrong. But, as I said in my comment, using a debug tool like Firebug will also go a long way.
Have you tried non async?
$.ajax({
async:false,
type:"POST",
url: "masProducto.php",
datatype:"JSON",
...

Codeigniter, jQuery and Ajax - Preventing Page Refresh on Displaying New Database Content Dynamically

I'm trying to achieve something relatively straightforward - allow users to make comments on a view page, update the database and display the new content dynamically on the page without the whole page refreshing.
My efforts so far have been unsuccessful - there may be several issues with what I'm doing!
On the view page I have tried this (to send 2 variables to a CI controller function):
<script type="text/javascript">
function ajax(id, user_id) {
jQuery('#dynamicdiv').load('/controller/function/' + id + '/' + user_id);
}
</script>
<div id='dynamicdiv'>
</div>
I have a textarea to collect the user comment, in the controller function should I be able to call this as post data in order to write it to the database? If so, I would still need to send two other variables ($id and $user_id) to the ajax function.
<?php $atts = array (
'class' => "alignright button",
'onClick' => "ajax('$id,$user_id')",
); ?>
<?php echo anchor(current_url(), 'Post my Comment', $atts); ?>
and in the controller, which involves a different function (view) than the page I want the user to stay on:
$data = $this->model->database_query($id, $user_id);
echo $data; // from reading other posts it seems I would process the data within this function, to have it displayed on the page the user is viewing?
Any help appreciated!
Don't forget to block you default anchor behaviour (for example by adding return false; to your onclick parameter).
<?php $atts = array (
'class' => "alignright button",
'onClick' => "ajax('$id,$user_id'); return false;",
); ?>
you can make the ajax request as follows:
function ajax(id, user_id) {
$.ajax({
url: base_url + controller_name + '/' + action_name,
type: 'GET',
data: { id: id, user_id: user_id },
dataType: 'json',
success: function (data) {
// append the returned result to your #dynamicdiv
}
});
}
and in the controller:
$id = $this->input->get('id');
$user_id = $this->input->get('user_id');
$data = $this->model->database_query($id, $user_id);
echo json_encode($data);
Hope this helps

Categories