In woocommerce, what determines the order_item_id? - unique

I've got a webshop running with woocommerce. The webshop has products with variations. When I add the same product with the same variation, I want it to generate a new order_item_id, in stead of combining the two under the same order_item_id.
I can't seem to find the bit of code that is responsible for generating the order_item_id.
Could anyone tell me where this bit of code is located?
My goal is to make each product unique in stead of stacking items that are the same.
-EDIT
Ok, so I've narrowed it down to class-wc-cart.php
On line 782 the product ID is generated with the following code:
public function generate_cart_id( $product_id, $variation_id = '', $variation = '', $cart_item_data = array() ) {
$id_parts = array( $product_id );
if ( $variation_id ) $id_parts[] = $variation_id;
if ( is_array( $variation ) ) {
$variation_key = '';
foreach ( $variation as $key => $value ) {
$variation_key .= trim( $key ) . trim( $value );
}
$id_parts[] = $variation_key;
}
if ( is_array( $cart_item_data ) && ! empty( $cart_item_data ) ) {
$cart_item_data_key = '';
foreach ( $cart_item_data as $key => $value ) {
if ( is_array( $value ) ) $value = http_build_query( $value );
$cart_item_data_key .= trim($key) . trim($value);
}
$id_parts[] = $cart_item_data_key;
}
return md5( implode( '_', $id_parts ) );
}
Now all that is left is to edit in a unique ID via a timestamp or something.
Will keep you guys posted.

Solved it.
Open class-wc-cart.php, and add a timestamp, or anything else that is unique to $id_parts.
Just like in the following code:
public function generate_cart_id( $product_id, $variation_id = '', $variation = '', $cart_item_data = array() ) {
$id_parts = array( $product_id );
if ( $variation_id ) $id_parts[] = $variation_id.time();
if ( is_array( $variation ) ) {
$variation_key = '';
foreach ( $variation as $key => $value ) {
$variation_key .= trim( $key ) . trim( $value );
}
$id_parts[] = $variation_key.time();
}
if ( is_array( $cart_item_data ) && ! empty( $cart_item_data ) ) {
$cart_item_data_key = '';
foreach ( $cart_item_data as $key => $value ) {
if ( is_array( $value ) ) $value = http_build_query( $value );
$cart_item_data_key .= trim($key) . trim($value);
}
$id_parts[] = $cart_item_data_key.time();
}
return md5( implode( '_', $id_parts ) );
}

Related

Collect "where" clause array with "join" using wpdb prepare safely

I need to secure a big SQL statement has a lot of conditions in its WHERE clause so I made an array for WHERE clause using $wpdb->prepare properly BUT an error happened while join this array together as a string in the final statement.
Here is some of my code .. Is that secure enough or it may cause an SQL injection?
P.S. I try to make another $wpdb->prepare in the last get_row function but the join function made quotes before and after WHERE clause so the statement generates an error.
foreach( $args as $field => $field_value ) {
if( ! is_null( $field_value ) ) {
switch( $field ) {
case 'id': {
if( is_numeric( $field_value ) && ( intval( $field_value ) > 0 ) ) {
$where[] = $wpdb->prepare( 'tbl_names.id = %d', $field_value );
}
} break;
case 'name': {
$where[] = $wpdb->prepare( 'tbl_names.name = %s', $field_value );
} break;
}
}
}
// NOT Working
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$tbl_names} tbl_names WHERE %s", join( ' AND ', $where ) ), ARRAY_A );
// Working Good .. BUT Is it Safe??
return $wpdb->get_row( ( "SELECT * FROM {$tbl_names} tbl_names WHERE " . join( ' AND ', $where ) ), ARRAY_A );
Unfortunately, I think this will be the only answer for a while.
$count = 0;
$query = "SELECT * FROM {$tbl_names} tbl_names";
foreach( $args as $field => $field_value ) {
if( ! is_null( $field_value ) ) {
$count++;
$query .= ( 1 == $count ) ? ' WHERE ' : ' AND ';
switch( $field ) {
case 'id': {
$query .= $wpdb->prepare( 'tbl_names.id = %d', $field_value );
} break;
case 'name': {
$query .= $wpdb->prepare( 'tbl_names.name = %s', $field_value );
} break;
}
}
}
return $wpdb->get_row( $query, ARRAY_A );

WP custom field value

I try to format some products price using a custom field (unit_price). My value is 3.2 (3,2) but the code doesn't recognize comma or dot and it shows only 3
Is there any way I could achieve showing the full value?
Any help is appreciated.
function cw_change_product_html( $price_html, $product )
{
$unit_price = get_post_meta( $product->id, 'unit_price', true );
if ( ! empty( $unit_price ) ) {
$price_html = '<span class="amount">' . wc_price( $unit_price ) . ' per kg</span>';
}
return $price_html;
}
add_filter( 'woocommerce_get_price_html', 'cw_change_product_html', 10, 2 );
function cw_change_product_price_cart( $price, $cart_item, $cart_item_key )
{
$unit_price = get_post_meta( $cart_item['product_id'], 'unit_price', true );
if ( ! empty( $unit_price ) )
{
$price = wc_price( $unit_price ) . ' per kg';
}
return $price;}
add_filter( 'woocommerce_cart_item_price', 'cw_change_product_price_cart', 10, 3 );`
Please try dumping the output(just for better understanding the variable) from $unit_price = get_post_meta( $product->id, 'unit_price', true ); as
var_dump($unit_price);
This will return string. Then all you have to convert string into float
$unit_price= floatval($unit_price);
Then you can use wc_price( $unit_price ).
Check documentation http://woocommerce.wp-a2z.org/oik_api/wc_price/ as $price is float value

Contact Form 7 check quantity of fields

In wordpress I'm using Contact Form 7. I want to create a order form. But the order quantity has to have a minimum of 2 products. When people order less then two products they have to get a message that it's not possible.
There are a total of 6 different products people can order. Each product can ben orderd as many as they like.
Any ideas how I can make this work?
I found a way. I've created a new filter for the Contact Form
Code below:
add_filter( 'wpcf7_validate_number*', 'custom_number_confirmation_validation_filter', 20, 2 );
function custom_number_confirmation_validation_filter( $result, $tag ) {
$tag = new WPCF7_Shortcode( $tag );
$var1 = isset( $_POST['your_number1'] ) ? trim( $_POST['your_number1'] ) : '';
$var2 = isset( $_POST['your_number2'] ) ? trim( $_POST['your_number2'] ) : '';
$var3 = isset( $_POST['your_number3'] ) ? trim( $_POST['your_number3'] ) : '';
$var4 = isset( $_POST['your_number4'] ) ? trim( $_POST['your_number4'] ) : '';
$var5 = isset( $_POST['your_number5'] ) ? trim( $_POST['your_number5'] ) : '';
$var6 = isset( $_POST['your_number6'] ) ? trim( $_POST['your_number6'] ) : '';
$varNumber = '2';
if ( $var1 + $var2 + $var3 + $var4 + $var5 + $var6 < $varNumber) {
$result->invalidate( $tag, "Order a minimum of 2!" );
}
return $result;}
Replace your_number# with the name of the field in Contact Form 7

Select dropdown option not selecting on mobile phone (iphone 4s)

When you select another option than default on a mobile phone, the native mobile phone selection list appears. When you then select another option, the price changes however the selected weight does not appear in the selection box.
Open for example this page on the mobile phone.
<select class="variation-selector" id="<?php echo esc_attr( sanitize_title( $name ) ); ?>" name="attribute_<?php echo sanitize_title( $name ); ?>">
<option value="" disabled="disabled"><?php echo __( 'Choose an option', 'woocommerce' ) ?>…</option>
<?php
if ( is_array( $options ) ) {
if ( isset( $_REQUEST[ 'attribute_' . sanitize_title( $name ) ] ) ) {
$selected_value = $_REQUEST[ 'attribute_' . sanitize_title( $name ) ];
} elseif ( isset( $selected_attributes[ sanitize_title( $name ) ] ) ) {
$selected_value = $selected_attributes[ sanitize_title( $name ) ];
} else {
$selected_value = '';
}
// Get terms if this is a taxonomy - ordered
if ( taxonomy_exists( $name ) ) {
$orderby = wc_attribute_orderby( $name );
switch ( $orderby ) {
case 'name' :
$args = array( 'orderby' => 'name', 'hide_empty' => false, 'menu_order' => false );
break;
case 'id' :
$args = array( 'orderby' => 'id', 'order' => 'ASC', 'menu_order' => false, 'hide_empty' => false );
break;
case 'menu_order' :
$args = array( 'menu_order' => 'ASC', 'hide_empty' => false );
break;
}
$terms = get_terms( $name, $args );
foreach ( $terms as $term ) {
if ( ! in_array( $term->slug, $options ) )
continue;
echo '<option value="' . esc_attr( $term->slug ) . '" ' . selected( sanitize_title( $selected_value ), sanitize_title( $term->slug ), false ) . '>' . apply_filters( 'woocommerce_variation_option_name', $term->name ) . '</option>';
}
} else {
foreach ( $options as $option ) {
echo '<option value="' . esc_attr( sanitize_title( $option ) ) . '" ' . selected( sanitize_title( $selected_value ), sanitize_title( $option ), false ) . '>' . esc_html( apply_filters( 'woocommerce_variation_option_name', $option ) ) . '</option>';
}
}
}
?>
</select>
Edit:
The above code outputs:
<select class="variation-selector selecter-element" id="pa_gewicht" name="attribute_pa_gewicht">
<option value="" disabled="disabled">Kies een optie…</option>
<option value="175-g" selected="selected">175 g</option>
<option value="350-g">350 g</option>
</select>
<div class="selecter closed">
<span class="selecter-selected">175 g</span>
<div class="selecter-options" style="display: none;">
<span class="selecter-item disabled first" data-value="">Kies een optie…</span>
<span class="selecter-item selected" data-value="175-g">175 g</span>
<span class="selecter-item last" data-value="350-g">350 g</span>
</div>
</div>
As you can see it duplicates it. Found out this is cause by a line in my javascript, namely:
$j(".orderby, .variations td.value select").selecter();
Which in turn uses the jquery.fs.selecter.min.js

A duplicate key is inserted instead of updated in a SQL INSERT / UPDATE query

I have the below function in Wordpress.
However, the meta key product_price is duplicated each time a post is updated.
Like this image
Is there any way to prevent this?
function do_my_stuff($post_ID) {
global $post,$wpdb;
$tablename="wp_cart66_products";
if($post->post_type == "post" && strlen( get_post_meta($post_ID, 'price', true))>0 )
{
$id = $wpdb->get_var("SELECT id FROM ".$tablename." WHERE id=".$post_ID);
$cny = get_post_meta($post->ID, 'price', true);
/*Shipping rate */
if( $cny < 50 )
$shipping = 14.97;
else if( $cny >= 50 && $cny < 200 )
$shipping = 22.59;
else if( $cny >= 200 && $cny < 250 )
$shipping = 24.59;
else if( $cny >= 250 && $cny < 300 )
$shipping = 26.60;
else if( $cny >= 300 )
$shipping = 29.27;
/*Exchange rate CNY to EURO */
$cny_to_euro = 0.124;
$euro = $cny * $cny_to_euro ;
$price = $euro + $shipping;
$price = number_format($price,2);
$data=array(
'id'=>$post_ID,
'item_number'=>get_post_meta($post->ID, 'scode', true),
'name'=>$post->post_title,
'price'=>$price,
'options_1'=>get_post_meta($post->ID, 'variations', true),
'shipped'=>'1',
);
$where = array("id" => $post_ID);
// Possible format values: %s as string; %d as decimal number; and %f as float.
$format=array( '%d', '%s', '%s', '%s', '%s', '%d');
$where_format = array( '%d' );
if($id>0){
// update
$wpdb->update( $tablename,$data, $where, $format, $where_format);
}else{
// insert
$wpdb->insert( $tablename,$data,$format);
}
AddMetaPrice ( $post_ID ) ;
}
return $post_ID;
}
function AddMetaPrice ( $post_ID )
{
// init
global $post,$wpdb;
// We add the wordpress post ID and price to a meta tag
$metaKey = "product_price" ;
$tableName = "wp_cart66_products" ;
$metaQuery = "SELECT price FROM $tableName WHERE id='$post_ID'" ;
$metaValue = $wpdb->get_var( $metaQuery ) ;
$tableName = "wp_postmeta" ;
// Do we have this post already?
if ( $id > 0 )
{
// this already exists. we only need to update
// $metaQuery = "UPDATE $tableName SET meta_value='$metaValue' WHERE meta_key='$metaKey' AND post_id='$id'" ; // we use wordpress's method instead
$data = array ( "meta_value" => $metaValue ) ;
$where = array ( "meta_key" => $metaKey, "post_id" => $post_ID ) ;
$wpdb->update( $tableName, $data, $where ) ;
}
else
{
// this is not created, we need to create it now (insert)
// $metaQuery = "INSERT INTO $tableName (post_id, meta_key, meta_value) VALUES ('$id', '$metaKey', '$metaValue')" ; // we use wordpress's method instead
$data = array ( "post_id" => $post_ID, "meta_key" => $metaKey, "meta_value" => $metaValue ) ;
$wpdb->insert( $tableName, $data ) ;
}
}
add_action('publish_post', 'do_my_stuff');
I've read here that a ON DUPLICATE KEY statement exists. But i'm not sure if it can be implemented in the above code.
Try replacing that piece of code:
if ( $metaValue !== NULL )
{
update_post_meta($post_ID, $metaKey, $metaValue); // use built-in function instead
}
where it was:
// Do we have this post already?
if ( $id > 0 )
{
// this already exists. we only need to update
// $metaQuery = "UPDATE $tableName SET meta_value='$metaValue' WHERE meta_key='$metaKey' AND post_id='$id'" ; // we use wordpress's method instead
$data = array ( "meta_value" => $metaValue ) ;
$where = array ( "meta_key" => $metaKey, "post_id" => $post_ID ) ;
$wpdb->update( $tableName, $data, $where ) ;
}