Here we are talking about selling products (especially pastry or food) in bulk unit / unit / or kg.
All measurements are known weight and quantity,Therefore we must be able to estimate which product in kg will have how many units.
So I created an example of products just to test in woocommerce,
I managed to realize my idea to estimate minimum qty of pieces (or any unit) per kg using a useful piece of code found here.
(1) I put it in a Snippet.
After that I started reading and trying to understand and follow the logic behind the code.
(2) Add some fonctions. just duplicated a few lines.. some copy / paste..
(3) Try to put the same functions in product page (in progress no solution found)
Update 09/12/2019
Code revised no more internal error
// Backend: Add and display a custom field for simple and variable products
add_action( 'woocommerce_product_options_general_product_data', 'add_custom_price_field_to_general_product_data' );
function add_custom_price_field_to_general_product_data() {
global $product_object;
echo '<div class="options_group hide_if_external">';
woocommerce_wp_text_input(array(
'id' => '_min_unit_price',
'label' => __('Min Unit price', 'woocommerce') . ' (' . get_woocommerce_currency_symbol() . ')',
'description' => __('Enter the minimum unit price here.', 'woocommerce'),
'desc_tip' => 'true',
'value' => str_replace('.', ',', $product_object->get_meta('_min_unit_price') ),
'data_type' => 'price'
));
// My custom field "Min price unit prefix"
woocommerce_wp_text_input(array(
'id' => '_min_unit_prefix',
'label' => __('Min Unit prefix', 'woocommerce'),
'description' => __(' Enter prefix unit price here.', 'woocommerce'),
'desc_tip' => 'true',
'value' => str_replace('.', ',', $product_object->get_meta('_min_unit_prefix') ),
'data_type' => 'texte'
));
// My custom field "Estimated quantity"
woocommerce_wp_text_input(array(
'id' => '_estimated_quantity',
'label' => __('Estimated Quantity', 'woocommerce'),
'description' => __('Enter the quantity here.', 'woocommerce'),
'desc_tip' => 'true',
'value' => str_replace('.', ',', $product_object->get_meta('_estimated_quantity') ),
'data_type' => 'price'
));
echo '</div>';
}
// Backend: Save the custom field value for simple and variable products
add_action( 'woocommerce_admin_process_product_object', 'save_product_custom_price_field', 10, 1 );
function save_product_custom_price_field( $product ) {
if ( isset($_POST['_min_unit_price']) ) {
$product->update_meta_data( '_min_unit_price', wc_clean( wp_unslash( str_replace( ',', '.', $_POST['_min_unit_price'] ) ) ) );
}
if ( isset($_POST['_min_unit_prefix']) ) {
$product->update_meta_data( '_min_unit_prefix', wc_clean( wp_unslash( str_replace( ',', '.', $_POST['_min_unit_prefix'] ) ) ) );
}
if ( isset($_POST['_estimated_quantity']) ) {
$product->update_meta_data( '_estimated_quantity', wc_clean( wp_unslash( str_replace( ',', '.', $_POST['_estimated_quantity'] ) ) ) );
}
}
// Frontend variable products: Display the min price with "From" prefix label
add_filter( 'woocommerce_variable_price_html', 'custom_min_unit_variable_price_html', 10, 2 );
function custom_min_unit_variable_price_html( $price, $product ) {
if( $min_unit_price = $product->get_meta('_min_unit_price') ){
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $min_unit_price ) ) );
$price .= $product->get_meta('_min_unit_prefix');
}
return $price;
}
// Frontend simple products: Display the min price with "From" prefix label
add_filter( 'woocommerce_get_price_html', 'custom_min_unit_product_price_html', 10, 2 );
function custom_min_unit_product_price_html( $price, $product ) {
if( $product->is_type('simple') && $min_unit_price = $product->get_meta('_min_unit_price') ){
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $min_unit_price ) ) );
$price .= $product->get_meta('_min_unit_prefix');
}
return $price;
}
// Display the cart item weight in cart and checkout pages
add_filter( 'woocommerce_get_item_data', 'display_custom_item_data', 10, 2 );
function display_custom_item_data( $cart_item_data, $cart_item ) {
if ( $cart_item['data']->get_weight() > 0 ){
$cart_item_data[] = array(
'name' => __( 'Weight subtotal', 'woocommerce' ),
'value' => ( $cart_item['quantity'] * $cart_item['data']->get_weight() ) . ' ' . get_option('woocommerce_weight_unit')
);
}
// Display the cart item "estimated quantity" in cart and checkout pages
if ( $cart_item['data']->get_meta('_estimated_quantity') ){
$cart_item_data[] = array(
'name' => __( 'Estimated quantity ', 'woocommerce' ),
'value' => ( $cart_item['quantity'] * $cart_item['data']->get_meta('_estimated_quantity') )
);
}
return $cart_item_data;
}
// Save and Display the order item weight (everywhere)
add_action( 'woocommerce_checkout_create_order_line_item', 'display_order_item_data', 20, 4 );
function display_order_item_data( $item, $cart_item_key, $values, $order ) {
if ( $values['data']->get_weight() > 0 ){
$item->update_meta_data( __( 'Weight subtotal', 'woocommerce' ), ( $item['quantity'] * $values['data']->get_weight() ) . ' ' . get_option('woocommerce_weight_unit') );
}
}
Now, I need help to understand how
Estimated quantity: <? Php echo get_post_meta (get_the_ID (), '_estimated_quantity', true); ?>
can Update in real time with the quantity of add_to_cart.
the formula must be extremely simple in jQuery or javascript ?
_estimated_quantity * quantity.
That all I need now. To show to costumer how much they can get piece of cakes (or any others things) in 1 or xx kg
So I put a 15 or xx (approximate value) in backend.
I hope it makes sense for you.
For information I use clean install wordpress + elementor + elementor hello theme + woocommerce.
update 09/12/2019
I corrected the last php error.
I would like to thank Snuwerd for his support and considerable help without him I will not have the courage to throw myself into the world of php code I learned a lot.
Thank you again
Welcome to Stack Overflow!
To answer your questions:
"Verify that the code is valid"
The code looks quite good (especially if this is really your first time messing with PHP)
"and (code) does not create problems in future woocommerce updates."
This question is really hard to answer.
"Now I am trying to put these two lines of information in the product page. via shortcode? or php again ?"
Probably with more filters/actions, like you have done in the current code. And if that doesn't seem possible, maybe by altering/overriding some template(s). Shortcodes don't necessarily make much sense, unless you want to insert the data into content area's in the backend when adding/editing products.
"Also improve the code"
This doesn't seem necessary.
"and add a prefix to Estimated Quantity."
Can you elaborate on what you mean by this?
ps. I am probably off to bed soon, so I'll check again tomorrow.
Update
I send qty and product_id to the server with AJAX and then the server gives back qty * _estimated_quantity;
To get qty from the box on your screen and to set the right value in Estimated quantity, I need you to make a screenshot of their code. Open the page in Google Chrome, right click > inspect element on the quantity box and then make a screenshot of the code in the Elements tab. Also do the same for the Estimated quantity box (that has 15 in it in the screenshot).
I also assume your website is located on the root of your domain. So on www.example.com and not on www.example.com/wordpress/ (The Ajax call needs the right location).
You can add this PHP to your functions.php
<?php
add_action("wp_ajax_product_get_estimated_quantity", "product_get_estimated_quantity"); // calls our function if user is logged in
add_action("wp_ajax_nopriv_product_get_estimated_quantity", "product_get_estimated_quantity"); // calls our function if user is not logged in, we do not do any security checks on which user etc though, but I don't think it's relevant in our case.
function product_get_estimated_quantity () {
error_log('Snuwerd: Ajax call for estimated quantity is being called correctly.');
$product_id = $_REQUEST["product_id"];
if (!is_numeric($product_id)) { // check if really a number, for security purposes
die();
}
$qty = $_REQUEST["qty"];
if (!is_numeric($qty)) { // check if really a number, for security purposes
die();
}
// No need to get product object, can get metadata directly with get_post_meta
// // get estimated_quantity per kg by product_id
// $args = array(
// 'include' => array( $product_id ),
// );
// $products = wc_get_products( $args );
// foreach ($products as $product) {
// }
// echo $product->get_id();
$estimated_quantity_per_kg = get_post_meta( $product_id, '_estimated_quantity', true);
// $estimated_quantity_per_kg = 15; // this line is only for my local testing, since my products dont have _estimated_quantity meta
echo ((int) $estimated_quantity_per_kg) * ((int) $qty);
error_log('Snuwerd: Ajax call for estimated quantity returned to single-product page.');
die();
}
?>
And add this javascript/jquery anywhere you can (assuming that you know how to, its also easy to find out with google (How to add javascript to Wordpress)).
console.log('Snuwerd: Code planted in document.ready');
jQuery(document).ready(function($) {
console.log('Snuwerd: JS code is being loaded.');
if( $('body.single-product').length) { // if on a single product page
console.log('Snuwerd: We are on the single product page');
$( document ).on( 'change', '.quantity input[type=number]', function() { // selector for the qty box is probably already correct
var qty = $( this ).val();
// var product_id = $(this).closest('.product').attr('id');
// product_id = product_id.split('-');
// product_id = product_id[1];
var product_id = get_current_post_id();
console.log('Snuwerd: quantity changed. Sending ajax call with qty'+qty+' and product_id'+product_id);
jQuery.ajax({
type : "post",
dataType : "json",
url : '/wp-admin/admin-ajax.php', // only works if Wordpress is installed in root of your domain. if you installed in www.example.com/wordpress/, then add /wordpress/ before this
data : {action: "product_get_estimated_quantity", product_id : product_id, qty: qty},
success: function(response) {
console.log('Snuwerd: Ajax call returned succesfully');
// right click -> inspect element to find the right selector for estimated quantity (the 15 from your photoshop)
response = parseInt(response);
console.log('Snuwerd: Ajax call returned succesfully with value '+response);
$('#snuwerd > div').html('Estimated quantity: ' + response);
}
});
return false;
});
}
function get_current_post_id() {
var page_body = $('body');
var id = 0;
if(page_body) {
var classList = page_body.attr('class').split(/\s+/);
$.each(classList, function(index, item) {
if (item.indexOf('postid') >= 0) {
var item_arr = item.split('-');
id = item_arr[item_arr.length -1];
return false;
}
});
}
return id;
}
});
In case you want to know how I added the javascript, i made a file in child-theme-directory/js/child.js.
Then added the Jquery to it. And then I added this to functions.php:
function theme_enqueue_child_scripts() {
error_log('Snuwerd: js script being added in theme_enqueue_child_scripts.');
$file = '/js/child.js';
$cache_buster = date("YmdHis", filemtime( get_stylesheet_directory() . $file )); // no uri
wp_enqueue_script( 'child', get_stylesheet_directory_uri() . $file, array( 'jquery' ), $cache_buster, true ); // true = footer
}
add_action( 'wp_enqueue_scripts', 'theme_enqueue_child_scripts' );
Update
I added the selector for the Estimated quantity field in the javascript, and the quantity selector was already correct, so please re-copy the javascript.
I looked at the screenshot where you add in JS and PHP, but the way you add PHP is not good enough for this PHP. Where you add PHP in the screenshot, it only counts for that page and it needs to be sidewide. The Ajax call will not be able to access PHP that is added to a specific page. If Elementor doesn't have a side wide place to add PHP and if you don't want to change the functions.php of your theme, then maybe you can use this plugin: https://wordpress.org/plugins/my-custom-functions/ . Also, don't forget to actually add the PHP I provided, I didn't see it in your JS/PHP screenshot.
Update
I added some debug messages to find out what parts work. Can you enter the PHP code that is meant for functions.php into your site again and also the JS code.
After this open your product page in Google Chrome and press ctrl+shift+i to open developer tools window. Now change the quantity by pressing the arrows in the number box on the page. There should be a few messages in the Console tab in the developer tools window. Can you paste a screenshot of the console here?
If nothing appears in this console, please check that you're not having cache problems > go to Network Tab in developer tools window and check the disable cache checkbox and then refresh the page and try again.
Next, also check the PHP error log, if you don't know how to check it, please learn about PHP error logging here: https://www.loggly.com/ultimate-guide/php-logging-basics/
In the error log search for Snuwerd and show those lines to me as well.
Related
Have been trying to solve this for a couple days and decided to just break down and ask for some insight. I'm basing what I have off of these two solutions:
Change items tax rate in WooCommerce checkout based on radio buttons
Add a dynamic fee based on a select field in WooCommerce Checkout
I'm trying to use a drop down/select to change the tax class on the checkout page of WooCommerce.
I've left a lot alone from the two above examples but am still not getting the results expected. I also need to store & place the delivery location in the admin area & emails but need to get this tax class change issue sorted first.
Below is what I have right now. It seems like it should be working but alas, no joy.
// Add a custom select fields for packing option fee
add_action( 'woocommerce_after_order_notes', 'checkout_shipping_form_packing_addition', 20 );
function checkout_shipping_form_packing_addition( ) {
$domain = 'woocommerce';
echo '<tr class="packing-select"><th>' . __('Pickup Location', $domain) . '</th><td>';
$chosen = WC()->session->get('chosen_packing');
// Add a custom checkbox field
woocommerce_form_field( 'chosen_packing', array(
'type' => 'select',
'class' => array( 'form-row-wide packing' ),
'options' => array(
'' => __("Please select a location...", $domain),
'BELGIUM - LOC' => sprintf( __("BELGIUM - LOC", $domain) ),
'BROOTEN - LOC' => sprintf( __("BROOTEN - LOC", $domain) ),
'OWATONNA - LOC' => sprintf( __("OWATONNA - LOC", $domain) ),
),
'required' => true,
), $chosen );
echo '</td></tr>';
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_shipping_packing_script' );
function checkout_shipping_packing_script() {
// Only checkout page
if ( is_checkout() && ! is_wc_endpoint_url() ) :
WC()->session->__unset('chosen_packing');
?>
<script type="text/javascript">
jQuery( function($){
$('form.checkout').on('change', 'select#chosen_packing', function(){
var p = $(this).val();
console.log(p);
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'woo_get_ajax_data',
'packing': p,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log('response: '+result); // just for testing | TO BE REMOVED
},
error: function(error){
console.log(error); // just for testing | TO BE REMOVED
}
});
});
});
</script>
<?php
endif;
}
// Php Ajax (Receiving request and saving to WC session)
add_action( 'wp_ajax_woo_get_ajax_data', 'woo_get_ajax_data' );
add_action( 'wp_ajax_nopriv_woo_get_ajax_data', 'woo_get_ajax_data' );
function woo_get_ajax_data() {
if ( isset($_POST['packing']) ){
$packing = sanitize_key( $_POST['packing'] );
WC()->session->set('chosen_packing', $packing );
echo json_encode( $packing );
}
die(); // Alway at the end (to avoid server error 500)
}
// Add a custom dynamic packaging fee
add_action( 'woocommerce_before_calculate_totals', 'change_tax_class_conditionally', 1000 );
function change_tax_class_conditionally( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$domain = "woocommerce";
$packing_fee = WC()->session->get( 'chosen_packing' ); // Dynamic packing fee
if ( $packing_fee === 'BELGIUM - LOC' ) {
//$label = __("Bag packing fee", $domain);
$tax_class = '5 Percent';
}
if ( $packing_fee === 'BROOTEN - LOC' ) {
//$label = __("Bag packing fee", $domain);
$tax_class = '0 Percent';
}
if ( $packing_fee === 'CHER-MAKE - LOC' ) {
//$label = __("Bag packing fee", $domain);
$tax_class = 'Reduced Rates';
}
// Loop through cart items
foreach( $cart->get_cart() as $cart_item ){
if( $choice === $field_value ) {
$cart_item['data']->set_tax_class($tax_class);
}
}
}
// Field validation, as this packing field is required
add_action('woocommerce_checkout_process', 'packing_field_checkout_process');
function packing_field_checkout_process() {
// Check if set, if its not set add an error.
if ( isset($_POST['chosen_packing']) && empty($_POST['chosen_packing']) )
wc_add_notice( __( "Please choose a packing option...", "woocommerce" ), 'error' );
}
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.
I am creating a custom wordpress theme and what i want is that; there is a download link, what i want is that users can download only 5 times when the user clicks that link only for 5 times, if the user tries to click the link for the 6th time it automatically hides. I dont have any idea how to do this, also didn't find any relevant solution on google.
here below is my testing code:
<script type="text/javascript">
function myFunction() {
$(document).ready(function(){
$(".gotocls").click(function(){
alert("Hello! I am an alert box!!");
});
});
}
</script>
<a class="dkpdf-button gotocls" onclick="myFunction()" href="downlaod/image.com" target="_blank"><span class="dkpdf-button-icon"><i class="fa fa-file-pdf-o"></i></span> <?php echo $pdfbutton_text;?></a>
i think this might be done with ajax, but i dont have much knowledge of ajax
you don't need onClick in this code I add document.getElementsByClassName('gotocls')[0].style.display = 'none'; when i equals 5 .
$(document).ready(function(){
var i = 0
$(".gotocls").click(function(){
i++
if(i == 5)
document.getElementsByClassName('gotocls')[0].style.display = 'none';
alert("Hello! I am an alert box!!" + i);
});
});
</script>
<a class="dkpdf-button gotocls" id="myLink" href="downlaod/image.com" target="_blank"><span class="dkpdf-button-icon"><i class="fa fa-file-pdf-o"></i></span> <?php echo $pdfbutton_text;?></a>
If you only want to hide the download link in the current session, then simple javascript should do your job.
<script type="text/javascript">
var counter = 0;
function myFunction() {
if(counter === 5){
document.getElementsByClassName('gotocls')[0].style.display = 'none';
}
counter = counter +1;
}
</script>
However when the user refreshes the site, then the download link will be visible again. If you want to store information permanently then you have to use a database.
I wrote the code needed real quick with no tests but it should give you a starting point at least, in your PHP:
/**
* Enqueue a JS file using WP proper action and functions
* 'my-custom-script' can be any name of your fantasy, prepend it with your vendor name and you are good to go
* 'url_to_js_file' MUST be a full URL to your .JS file containing the ajax you need
*/
function our_custom_scripts() {
wp_register_script( 'my-custom-script', 'url_to_js_file.js', array( 'jquery' ), false, true );
wp_localize_script( 'my-custom-script', 'myJsVarName', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ), // Used to make ajax call in WP
) );
wp_enqueue_script( 'my-custom-script' );
}
// Load script
add_action( 'wp_enqueue_scripts', 'our_custom_scripts' );
/**
* What the ajax call will actually trigger thanks to WP AJAX handle
*/
function my_ajax_action() {
/** #var wpdb $wpdb */
global $wpdb;
$clickedLink = $_POST["clicked_link"];
$userId = get_current_user_id();
/*
* Query for the pressed link, that's up to you on how to store data in the database, im going with an easy one
* saving the full link (i would really NOT recommend this :D, its just to show)
*/
$sql = "SELECT * FROM {$wpdb->prefix}my_table_name WHERE link = %s";
$res = $wpdb->get_row( $wpdb->prepare( $sql, array( $clickedLink ) ) );
if ( $canClick = $res["num_pressed"] < 5 ) {
$wpdb->update(
$wpdb->prefix . "my_table_name",
array(
'num_pressed' => ( $res["num_pressed"] + 1 ),
'string_col' => 'val2', //example string col
'int_col' => 3, //example int col
),
array( "user_id" => $userId ), // Where condition
array( "%d", "%s", "%d" ), // updated values format. %s are for strings, %d for integers
array( "%d" ) );// Where condition format
wp_send_json_success();
} else {
wp_send_json_error();
}
}
add_action( 'wp_ajax_my_ajax_action', array( $this, 'my_ajax_action' ) );
add_action( 'wp_ajax_nopriv_my_ajax_action', array( $this, 'my_ajax_action' ) );
Then in your .js file add this:
$(document).ready(function () {
$(".gotocls").click(function (evt) {
var $pressedLink = $(this);
evt.preventDefault(); // Stop doing w/e the browser was trying to do
$.ajax({
url: myJsVarName.ajaxurl,
type: 'POST',
data: {
action: 'my_ajax_action',
clicked_link: $pressedLink.attr("href")
},
timeout: 5000
dataType: 'json',
success: function (response) {
console.log('Your response content', response);
if (response.success) {
window.location.href = $pressedLink.attr("href"); // Proceed with click
}
},
error: function (jqXHR, textStatus, errorThrown) {
}
});
});
});
})(jQuery);
This should cover the PHP and the JS side of your stuff. The rest is up to you, stackoverflow is not a coding factory, it's a community for advices :D
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)
I am trying to implement "redeem coupon" functionality in a Woocommerce store, I have already found useful tutorial, but I can't make it work properly.
This is the tutorial.
What I've already done:
Created new page template with this code:
<div class="redeem-coupon">
<form id="ajax-coupon-redeem">
<p>
<input type="text" name="coupon" id="coupon"/>
<input type="submit" name="redeem-coupon" value="Redeem Offer" />
</p>
<p class="result"></p>
</form><!-- #ajax-coupon-redeem -->
Added this to my theme's functions.php file:
add_action( 'wp_ajax_spyr_coupon_redeem_handler', 'spyr_coupon_redeem_handler' );
add_action( 'wp_ajax_nopriv_spyr_coupon_redeem_handler', 'spyr_coupon_redeem_handler' );
Added this to my theme's functions.php file:
function spyr_coupon_redeem_handler() {
// Get the value of the coupon code
$code = $_REQUEST['coupon_code'];
// Check coupon code to make sure is not empty
if( empty( $code ) || !isset( $code ) ) {
// Build our response
$response = array(
'result' => 'error',
'message' => 'Code text field can not be empty.'
);
header( 'Content-Type: application/json' );
echo json_encode( $response );
// Always exit when doing ajax
exit();
}
// Create an instance of WC_Coupon with our code
$coupon = new WC_Coupon( $code );
// Check coupon to make determine if its valid or not
if( ! $coupon->id && ! isset( $coupon->id ) ) {
// Build our response
$response = array(
'result' => 'error',
'message' => 'Invalid code entered. Please try again.'
);
header( 'Content-Type: application/json' );
echo json_encode( $response );
// Always exit when doing ajax
exit();
} else {
// Coupon must be valid so we must
// populate the cart with the attached products
foreach( $coupon->product_ids as $prod_id ) {
WC()->cart->add_to_cart( $prod_id );
}
// Build our response
$response = array(
'result' => 'success',
'href' => WC()->cart->get_cart_url()
);
header( 'Content-Type: application/json' );
echo json_encode( $response );
// Always exit when doing ajax
exit();
}
}
Created "kody.js":
jQuery( document ).ready( function() {
jQuery( '#ajax-coupon-redeem input[type="submit"]').click( function( ev ) {
// Get the coupon code
var code = jQuery( 'input#coupon').val();
// We are going to send this for processing
data = {
action: 'spyr_coupon_redeem_handler',
coupon_code: code
}
// Send it over to WordPress.
jQuery.post( woocommerce_params.ajax_url, data, function( returned_data ) {
if( returned_data.result == 'error' ) {
jQuery( 'p.result' ).html( returned_data.message );
} else {
// Hijack the browser and redirect user to cart page
window.location.href = returned_data.href;
}
})
// Prevent the form from submitting
ev.preventDefault();
});
});
Called the script from functions.php with this code:
function my_scripts_method() {
wp_register_script('kody',
get_template_directory_uri() . '/js/kody.js',
array('jquery'),
'1.0' );
enqueue the script
wp_enqueue_script('kody');
}
add_action('wp_enqueue_scripts', 'my_scripts_method');
And here's the weird thing: it's sort of working. I've setup a page where I can enter the coupon code, I paste the code, click "Redeem" and it adds products related to the coupon to the cart. It doesn't, however apply pre-defined discounts.
The "redeem coupon" page is also only half-working. It should display error messages when someone leaves the field empty or enters an incorrect code - and it only does the former. Entering incorrect code results in redirection to cart.
My knowledge on Ajax and JS is very limited, I tried to find some other tutorials, but without any luck.
Is something wrong with the code? It's from 2014, so something might have change in Wordpress engine, causing troubles.
Thank you in advance for any reply!
Regards
Problems solved, if anyone encounters similar issues with the tutorial provided, here's what you have to do:
To apply discount, add following code:
global $woocommerce;
WC()->cart->add_discount( $code );
Just below these lines:
// Coupon must be valid so we must
// populate the cart with the attached products
foreach( $coupon->product_ids as $prod_id ) {
WC()->cart->add_to_cart( $prod_id );
To display invalid code message change this:
// Check coupon to make determine if its valid or not
if( ! $coupon->id && ! isset( $coupon->id ) ) {
To this:
// Check coupon to make determine if its valid or not
if( ! $coupon->id && ! isset( $coupon_id ) ) {
Everything is working now.
(Also changed the title to make it easier to others to find this post in the future.)