Thêm Form tuỳ chỉnh tính giá sản phẩm trong Woocommerce WordPress

Đa số các product trong Woocommerce sẽ set cứng giá hoặc thêm variable để tùy chỉnh giá của sản phẩm. Nhưng trong trường hợp mình có một sản phẩm giá sẽ được tính theo chu vi hoặc diện tích. Với các field cho phép người dùng nhập chiều dài , chiều rộng vào thì sao.

Trong bài viết này sẽ hướng dẫn các bạn Custom Form tính giá cho sản phẩm trong Woocommerce WordPress.

Để demo cho bài viết này, mình có tham khảo giá của Sàn gỗ Savi bên site này, Sàn gỗ Savi 160.000 đ/m2.

Thêm Form tính giá sản phẩm trong Woocommerce WordPress
Thêm Form tính giá sản phẩm trong Woocommerce WordPress

Trong demo này mình dùng theme Storefront của woo luôn nhé.

Bây giờ tiến hành custom thôi nào:

B1: Add Woo Advanced custom field

B1: Add Woo Advanced custom field
B1: Add Woo Advanced custom field

Chỗ này mình muốn add 1 option để có thể enable/disable custom form hiển thị ở front-end.

//Add woo custom field
add_action( 'woocommerce_product_options_advanced', 'ntc_add_custom_field_product_dashboard_advanced_tab' );
function ntc_add_custom_field_product_dashboard_advanced_tab() {
	global $post;

	$custom_price_form_product_option = get_post_meta( $post->ID, '_custom_price_form_of_product', true );
	echo '<div class="options_group ">';
	// Checkbox Field
	woocommerce_wp_checkbox( array(
		'id'          => '_custom_price_form_of_product',
		'description' => __( 'Show custom price form of product', 'woocommerce' ),
		'label'       => __( 'Show custom price form of product', 'woocommerce' ),
		'value'       => $custom_price_form_product_option,
	) );
	echo '</div>';
}

B2: Save data của custom field vừa tạo ở B1 nhé

//Save data
add_action( 'woocommerce_process_product_meta', 'ntc_save_custom_product_fields' );
function ntc_save_custom_product_fields( $post_id ) {
	$_custom_price_form_of_product = isset( $_POST['_custom_price_form_of_product'] ) ? 'yes' : 'no';
	//=========
	update_post_meta( $post_id, '_custom_price_form_of_product', esc_attr( $_custom_price_form_of_product ) );
}

B3: Giờ thì show form ra Front-End nào

Ở bước này, mình có kiểm tra điều kiện là nếu là single product và form được cho phép hiển thị thì nó sẽ xuất hiện ở front-end, trước button add to cart.

//show to frontend
add_action( 'woocommerce_before_add_to_cart_button', 'ntc_show_custom_input_field_to_single_product', 0 );
function ntc_show_custom_input_field_to_single_product() {
	global $post;

	$custom_price_form_product_option = get_post_meta( $post->ID, '_custom_price_form_of_product', true );
	$product                          = wc_get_product( $post->ID );
	
	//Check is product and form is enable -> show on single product
	if ( is_product() && $custom_price_form_product_option == 'yes' ) { ?>
        <table id="ntc_price_calculator">
			<tbody>
                <tr class="price-table-row length-input">
                    <td>
                        <label for="length_value">Chiều dài</label>
                    </td>
                    <td style="text-align:right;">
                        <div class="input-wrap">
                            <input type="number" name="length_value" id="length_value" class="amount_needed" autocomplete="off" required>
                        </div>
                    </td>
                </tr>
                <tr class="price-table-row width-input">
                    <td>
                        <label for="width_value">Chiều rộng</label>
                    </td>
                    <td style="text-align:right;">
                        <div class="input-wrap">
                            <input type="number" name="width_value" id="width_value" class="amount_needed" autocomplete="off" required>
                        </div>
                    </td>
                </tr>

                <tr class="price-table-row total-row">
                    <td>Thành tiền</td>
                    <td style="text-align:right;"><span class="standard-total" data-product-price="<?php echo $product->get_price(); ?>">0</span></td>
                </tr>
			</tbody>
		</table>
		<?php
		// custom js form
		echo "<script>
			jQuery(document).ready(function() {
			    jQuery('#length_value, #width_value').on('change', function (e) {
			        let length = jQuery('#length_value').val(),
			        width = jQuery('#width_value').val(),
			        product_price = jQuery('.standard-total[data-product-price]').data('product-price');
			        length =length? parseFloat(length):0;
			        width =width? parseFloat(width):0;
			        product_price = parseFloat(product_price);
			        let total = length*width*product_price;
			        jQuery('.standard-total[data-product-price]').html((length*width)+'m<sup>2</sup> -- '+total.toLocaleString('vi-VN') +'₫');
			        console.log(length, width,product_price,total.toLocaleString('vi-VN'));
			    })
			});
			</script>";
	}
}

Ngoài ra trong đoạn code trên, mình có add thêm đoạn js để tính toán và hiển thị giá ở trên form đó luôn. Bạn có thể add đoạn js này vào 1 file riêng và enqueue vào nhé.

B4: Ở bước này thì chúng ta tính toán một chút và add data vào cart nhé.

// Set custom field and  calculated price as custom cart data in the cart item
add_filter( 'woocommerce_add_cart_item_data', 'ntc_save_custom_data_in_cart_object', 30, 3 );
function ntc_save_custom_data_in_cart_object( $cart_item_data, $product_id, $variation_id ) {
	if ( ! isset( $_POST['length_value'] ) || ! isset( $_POST['width_value'] ) ) {
		return $cart_item_data;
	}
	$length_value  = isset( $_POST['length_value'] ) ? floatval( $_POST['length_value'] ) : 0;
	$width_value   = isset( $_POST['width_value'] ) ? floatval( $_POST['width_value'] ) : 0;
	$lVal          = floatval( $length_value < 0 ? $length_value * - 1 : $length_value );
	$wVal          = floatval( $width_value < 0 ? $width_value * - 1 : $width_value );
	$product       = wc_get_product( $product_id );
	$product_price = floatval( $product->get_price() );

	$price_total = $lVal * $wVal * $product_price;

	$cart_item_data['custom_data']['price']  = $price_total;
	$cart_item_data['custom_data']['length'] = $length_value . ' (m)';
	$cart_item_data['custom_data']['width']  = $width_value . ' (m)';

	return $cart_item_data;
}

B5: Set new price cho product -> hiển thị ở page cart và page checkout


// Set the new calculated price of the cart item -- https://prnt.sc/rfpz1w
add_action( 'woocommerce_before_calculate_totals', 'ntc_calculate_product_fee', 99, 1 );
function ntc_calculate_product_fee( $cart ) {
	if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
		return;
	}
	if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
		return;
	}
	foreach ( $cart->get_cart() as $cart_item ) {
		if ( isset( $cart_item['custom_data']['price'] ) ) {
			// Get the new calculated price
			$new_price = (float) $cart_item['custom_data']['price'];
			// Set the new calculated price
			$cart_item['data']->set_price( $new_price );
		}
	}
}

//Show price in cart item - https://prnt.sc/rfpumh
add_filter( 'woocommerce_cart_item_product', 'ntc_woo_filter_cart_item_product', 20, 3 );
function ntc_woo_filter_cart_item_product( $cart_data, $cart_item, $cart_item_key ) {
	if ( isset( $cart_item['custom_data']['price'] ) ) {
		// Get the new calculated price
		$new_price = (float) $cart_item['custom_data']['price'];
		// Set the new calculated price
		$cart_data->set_price( $new_price );
	}

	return $cart_data;
}

B6: Hiển thị custom text ở page cart và page checkout

Custom text ở đây là chiều dài và chiều rộng của sản phẩm được add vào form ở trên.

// Display Custom text in cart and checkout pages
add_filter( 'woocommerce_get_item_data', 'ntc_render_meta_on_cart_and_checkout', 99, 2 );
function ntc_render_meta_on_cart_and_checkout( $cart_data, $cart_item = null ) {
	if ( isset( $cart_item['custom_data']['length'] ) ) {
		$cart_data[] = array( "name" => "Length", "value" => $cart_item["custom_data"]["length"] );
	}
	if ( isset( $cart_item['custom_data']['width'] ) ) {
		$cart_data[] = array( "name" => "Width", "value" => $cart_item["custom_data"]["width"] );
	}

	return $cart_data;
}

B7: Add custom text vào phần order để hiển thị trong backend và email các thứ nhé.

B7: Add custom text vào phần order để hiển thị trong backend và email các thứ nhé.
B7: Add custom text vào phần order để hiển thị trong backend và email các thứ nhé.
// Save the custom text as order item data (displaying it in order and notifications)
add_action( 'woocommerce_add_order_item_meta', 'ntc_order_meta_handler', 99, 3 );
function ntc_order_meta_handler( $item_id, $values, $cart_item_key ) {
	if ( isset( $values['custom_data']['length'] ) ) {
		wc_add_order_item_meta( $item_id, "Length", $values["custom_data"]["length"] );
	}
	if ( isset( $values['custom_data']['width'] ) ) {
		wc_add_order_item_meta( $item_id, "Width", $values["custom_data"]["width"] );
	}
}

Các bạn có thể test sản phẩm demo ở đây nhé https://ccgr.tk/product/san-go-savi-sv6034-thuong-hieu-san-go-viet-nam-cao-cap/

Code on Gist https://gist.github.com/trongcong/c3ce527ffe691288e3c28d5117dd17e7

Vậy là xong các bước để thêm form tính giá sản phẩm trong Woocommerce WordPress rồi đấy.

Oh My Zsh: Nâng cao trải nghiệm terminal với giao diện đẹp và các plugin tăng hiệu suất! Git cherry-pick là gì? Cách sử dụng và ví dụ Git Rebase: Gộp nhiều commit thành một để tối ưu hóa lịch sử commit 11 tính năng JavaScript mới tuyệt vời trong ES13 (ES2022) CSS diệu kỳ: Các thuộc tính CSS mà bạn có thể chưa biết Auto deploy projects với GitHub Actions – sử dụng ssh-action WordPress Gutenberg Block Server Side Render Add, Upload image trong Gutenberg Block Development Tạo Block Controls – Block Toolbar và Settings Sidebar trong WordPress Gutenberg Làm quen với các components thường dùng khi tạo Gutenberg Block

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.