Reputation: 366
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
Upvotes: 0
Views: 1026
Reputation: 459
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.
Upvotes: 1