I am using Dokan to develop a multi Vendor store for a client, I have added two custom product fields but on will not save values (the product info) Screen shot.
''' add_action( 'dokan_new_product_added','save_add_product_meta', 10, 2 );
add_action( 'dokan_product_updated', 'save_add_product_meta', 10, 2 );
function save_add_product_meta($product_id, $postdata){
if ( ! dokan_is_user_seller( get_current_user_id() ) ) {
return;
}
if ( ! empty( $postdata['new_field'] ) ) {
update_post_meta( $product_id, 'new_field', $postdata['new_field'] );
}
if ( ! empty( $postdata['new_field_1'] ) ) {
update_post_meta( $product_id, 'new_field_1', $postdata['new_field_1'] );
}
}
'''
Related
I need to modify the stock levels for inventory per product using a custom field.
These are the code snippets i have tried and modified.
The goal is to manually modify the inventory levels even when they're in stock so orders cannot be placed when stock is low and the add to cart button is removed.
add_action( 'woocommerce_process_product_meta', 'custom_product_inventory_settings' );
function custom_product_inventory_settings( $post_id ) {
// if ( isset( $_POST['_custom'] ) ) :
$product = wc_get_product( $post_id );
$stock_threshold = get_post_meta( $product->get_id(), '_custom', true );
if ( ! empty( $stock_threshold ) ) {
$new_stock_quantity = $product->get_stock_quantity() - $stock_threshold;
update_post_meta( $post_id, '_stock', $new_stock_quantity );
wc_delete_product_transients( $post_id );
}
// endif;
}
// Save custom field
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
function action_woocommerce_admin_process_product_object( $product ) {
// if ( isset( $_POST['_out_of_stock_threshold'] ) ) {
$product->update_meta_data( 'custom_field', sanitize_text_field( $_POST['custom_field'] ) );
$stock_threshold = get_post_meta( $product->get_id(), 'custom_field', true );
if ( ! empty( $stock_threshold ) ) {
$new_stock_quantity = $product->get_stock_quantity() - $stock_threshold;
// update_post_meta( $post_id, '_stock', $new_stock_quantity );
$product->update_meta_data( 'custom_field', sanitize_text_field( $_POST['custom_field'] ) );
update_post_meta( $post_id, '_stock', $new_stock_quantity );
$post_id = $product->get_id();
wc_delete_product_transients( $post_id );
}
}
Maybe i need to use a different hook like woocommerce_get_availability or something else?
Not sure what your problem is, or what is happening when you run the code, but at first glance you are using a variable before declaring it:
update_post_meta( $post_id, '_stock', $new_stock_quantity );
$post_id = $product->get_id();
Also, is the custom field you are using really supposed to be called custom_field?
I'm working on a giftcard product whereof I need the customer to be able to set the price as long as it is 100 or more. Problem is, I'm not sure how to create the value check.
The customer should then be able to add to cart as normal and to checkout as usual.
I've included a remove_action for the product price (which for some reason does not work) if the product is assigned to the giftcard category.
The field input has been created and the data should be carried over to the cart and checkout and into the order -- but it does not work for some reason.
The next step is to set the product price into whatever the customer submits as the giftcard value (as long as it is 100 or more) and to display that as the product price on cart and checkout.
If anyone can review and help me out, that would be awesome.
add_action( 'woocommerce_before_add_to_cart_form', 'giftcard_price_field' );
function giftcard_price_field() {
global $product;
if( has_term('giftcard', 'product_cat', $product->get_id() ) ) {
// if the product is assigned to the giftcard category, remove the product price
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
// add a new input field for the price, allowing the customer to set the price
echo '<div class="giftcard-product-price">
<label for="giftcard-product-price">Giftcard value: </label>
<input type="text" id="giftcard-product-price" name="giftcard-product-price" placeholder="Giftcard value" maxlength="1000">
</div>';
}
}
add_filter( 'woocommerce_add_cart_item_data', 'giftcard_price_field_cart_data', 10, 3 );
function giftcard_price_field_cart_data( $cart_item_data, $product_id, $variation_id ) {
if( ! empty ( $_POST[ 'giftcard-product-price' ] ) ) {
// need to check that the value is NOT below 100 and if so, create a wc_notice warning
$cart_item_data['giftcard-product-price'] = sanitize_text_field( $_POST['giftcard-product-price']);
}
return $cart_item_data;
}
add_filter( 'woocommerce_get_item_data', 'giftcard_price_field_display_data', 10, 2 );
function giftcard_price_field_display_data( $item_data, $cart_item ) {
if( ! empty ( $cart_item[ 'giftcard-product-price' ] ) ) {
$item_data[] = array (
'key' => 'Giftcard value',
'value' => $cart_item['giftcard-product-price'],
'display' => '',
);
}
return $item_data;
}
add_action( 'woocommerce_checkout_create_order_line_item', 'giftcard_price_field_order_data', 10, 4 );
function giftcard_price_field_order_data( $item, $cart_item_key, $values, $order ) {
if( ! empty ( $values[ 'giftcard-product-price' ] ) ) {
$item->add_meta_data( 'Giftcard value', $values['giftcard-product-price'] );
}
}
Add a new field 'giftcard_product_price' on single product page if has_term()
Removes the original product price on the single product page
Various validations have been added and are possible
The price of the product (giftcard) is adjusted to the price entered by the customer
function giftcard_price_field() {
global $product;
// Instanceof
if ( $product instanceof WC_Product ) {
// Set category(ies)
$cats = array ( 'giftcard' );
// True
if ( has_term( $cats, 'product_cat', $product->get_id() ) ) {
// add a new input field for the price, allowing the customer to set the price
echo '<div class="giftcard-product-price">
<label for="giftcard-product-price">Giftcard value: </label>
<input type="text" id="giftcard_product_price" name="giftcard_product_price" placeholder="Giftcard value" maxlength="1000">
</div>';
}
}
}
add_action( 'woocommerce_before_add_to_cart_button', 'giftcard_price_field', 10, 0 );
// Remove price
function action_woocommerce_single_product_summary() {
global $product;
// Instanceof
if ( $product instanceof WC_Product ) {
// Set category(ies)
$cats = array ( 'giftcard' );
// True
if ( has_term( $cats, 'product_cat', $product->get_id() ) ) {
remove_action('woocommerce_single_product_summary','woocommerce_template_single_price', 10 );
}
}
}
add_action( 'woocommerce_single_product_summary', 'action_woocommerce_single_product_summary', 5 );
// Validate
function filter_woocommerce_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id = null, $variations = null ) {
// Isset
if ( isset ( $_POST['giftcard_product_price'] ) ) {
$giftcard_product_price = $_POST['giftcard_product_price'];
// Error = empty, not numeric or less than 100
if ( empty ( $giftcard_product_price ) ) {
wc_add_notice( __( 'Field is empty', 'woocommerce' ), 'error' );
$passed = false;
} elseif ( ! is_numeric ( $giftcard_product_price ) ) {
wc_add_notice( __( 'NOT a number or a numeric string', 'woocommerce' ), 'error' );
$passed = false;
} elseif ( $giftcard_product_price < 100 ) {
wc_add_notice( __( 'Less than 100', 'woocommerce' ), 'error' );
$passed = false;
}
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'filter_woocommerce_add_to_cart_validation', 10, 5 );
function filter_add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
if ( isset ( $_POST['giftcard_product_price'] ) ) {
$cart_item_data['giftcard_product_price'] = sanitize_text_field( $_POST['giftcard_product_price'] );
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'filter_add_cart_item_data', 10, 3 );
// Set price
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
if ( isset ( $cart_item['giftcard_product_price'] ) ) {
$cart_item['data']->set_price( $cart_item['giftcard_product_price'] );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
I have successfully added this code to my functions.php, and it works - to great relief.
Here is a URL of it in action: https://www.bagnboxman.co.uk/?add-to-cart=207,7488,39439,939,393,395,396,411,1012,503
I would dearly love to redirect to the cart contents on loading this, so that a customer does not see a green wall of text "you have successfully added xyz to your cart"
Is this possible? How would I do this?
This is the code in question:
// adds support for multi add to cart for 3rd party cart plugin
function woocommerce_maybe_add_multiple_products_to_cart() {
// Make sure WC is installed, and add-to-cart qauery arg exists, and contains at least one comma.
if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) {
return;
}
// Remove WooCommerce's hook, as it's useless (doesn't handle multiple products).
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 );
$product_ids = explode( ',', $_REQUEST['add-to-cart'] );
$count = count( $product_ids );
$number = 0;
foreach ( $product_ids as $product_id ) {
if ( ++$number === $count ) {
// Ok, final item, let's send it back to woocommerce's add_to_cart_action method for handling.
$_REQUEST['add-to-cart'] = $product_id;
return WC_Form_Handler::add_to_cart_action();
}
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_id ) );
$was_added_to_cart = false;
$adding_to_cart = wc_get_product( $product_id );
if ( ! $adding_to_cart ) {
continue;
}
// only works for simple atm
if ( $adding_to_cart->is_type( 'simple' ) ) {
// quantity applies to all products atm
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && false !== WC()->cart->add_to_cart( $product_id, $quantity ) ) {
wc_add_to_cart_message( array( $product_id => $quantity ), true );
}
}
}
}
add_action( 'wp_loaded', 'woocommerce_maybe_add_multiple_products_to_cart', 15 );
To make this as simple and as easy as possible, I'm trying to add this checkbox on the top row next to the product type selector where you would normally find Virtual and Download.
The idea is to have the checkbox there so that no matter the product type, it is always available.
This is what I've tried:
add_action( 'woocommerce_product_type_options', 'remove_related_products_checkbox' );
function remove_related_products_checkbox() {
woocommerce_wp_checkbox( array(
'id' => '_remove_related_products',
'class' => '',
'label' => 'Remove Related Products?'
) );
}
add_action( 'save_post_product', 'related_products_checkbox_save' );
function remove_related_products_checkbox_save( $product_id ) {
global $pagenow, $typenow;
if ( 'post.php' !== $pagenow || 'product' !== $typenow ) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( isset( $_POST['_remove_related_products'] ) ) {
update_post_meta( $product_id, '_remove_related_products', $_POST['_remove_related_products'] );
} else
delete_post_meta( $product_id, '_remove_related_products' );
}
add_action( 'woocommerce_after_single_product_summary', 'remove_related_products_checkbox_display', 1 );
function remove_related_products_checkbox_display() {
global $product;
if ( ! empty ( get_post_meta( $product->get_id(), '_remove_related_products', true ) ) ) {
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );
}
}
But it doesn't work… Any advice please?
Your code is a bit outdated since WooCommerce 3 and there are some mistakes.
Try the following instead:
add_filter( 'product_type_options', 'hide_related_products_option' );
function hide_related_products_option( $fields ) {
$fields['hide_related'] = array(
'id' => '_hide_related',
'wrapper_class' => '',
'label' => __('Remove Related Products'),
'description' => __( 'Remove/Hide related products.', 'woocommerce' ),
'default' => 'no'
);
return $fields;
}
add_action( 'woocommerce_admin_process_product_object', 'hide_related_products_option_save' );
function hide_related_products_option_save( $product ) {
$product->update_meta_data( '_hide_related', isset( $_POST['_hide_related'] ) ? 'yes' : 'no' );
}
add_action( 'woocommerce_after_single_product_summary', 'remove_related_products_checkbox_display', 1 );
function remove_related_products_checkbox_display() {
global $product;
if ( $product->get_meta('_hide_related') === 'yes' ) {
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );
}
}
Code goes in function.php file of your active child theme (active theme). Tested and works.
Related: Add checkbox to product type option in Woocommerce backend product edit pages
In order to hide the Related Products section you can display a checkbox to disable related products. You just need to add the following snippet to your functions.php.
add_action( 'woocommerce_product_options_general_product_data', 'codeithub_add_related_checkbox_products' );
function codeithub_add_related_checkbox_products() {
woocommerce_wp_checkbox( array(
'id' => 'hide_related',
'class' => '',
'label' => 'Hide Related Products'
)
);
}
add_action( 'save_post_product', 'codeithub_save_related_checkbox_products' );
function codeithub_save_related_checkbox_products( $product_id ) {
global $pagenow, $typenow;
if ( 'post.php' !== $pagenow || 'product' !== $typenow ) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( isset( $_POST['hide_related'] ) ) {
update_post_meta( $product_id, 'hide_related', $_POST['hide_related'] );
} else delete_post_meta( $product_id, 'hide_related' );
}
add_action( 'woocommerce_after_single_product_summary', 'codeithub_hide_related_checkbox_products', 1 );
function codeithub_hide_related_checkbox_products() {
global $product;
if ( ! empty ( get_post_meta( $product->get_id(), 'hide_related', true ) ) ) {
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );
}
}
The goal here is to have a text field on the product page.
The customer fills it in and adds to cart. The text is added to the product and included in the cart and on the checkout and on the order.
The field works and the validation works fine, but the text is not included / transferred to the cart, checkout and order.
Here's the code:
add_action( 'woocommerce_before_add_to_cart_button', 'product_add_on', 9 );
function product_add_on() {
$value = isset( $_POST['_custom_text_add_on'] ) ? sanitize_text_field( $_POST['_custom_text_add_on'] ) : '';
echo '<div><label>Custom Text Add-On <abbr class="required" title="required">*</abbr></label><p><input name="_custom_text_add_on" value="' . $value . '"></p></div>';
}
add_filter( 'woocommerce_add_to_cart_validation', 'product_add_on_validation', 10, 3 );
function product_add_on_validation( $passed, $product_id, $qty ){
if( isset( $_POST['_custom_text_add_on'] ) && sanitize_text_field( $_POST['_custom_text_add_on'] ) == '' ) {
wc_add_notice( 'Custom Text Add-On is a required field', 'error' );
$passed = false;
}
return $passed;
}
add_filter( 'woocommerce_add_cart_item_data', 'product_add_on_cart_item_data', 10, 2 );
function product_add_on_cart_item_data( $cart_item, $product_id ){
if( isset( $_POST['_custom_text_add_on'] ) ) {
$cart_item['custom_text_add_on'] = sanitize_text_field( $_POST['custom_text_add_on'] );
}
return $cart_item;
}
add_filter( 'woocommerce_get_item_data', 'product_add_on_display_cart', 10, 2 );
function product_add_on_display_cart( $_data, $cart_item ) {
if ( isset( $cart_item['custom_text_add_on'] ) ){
$data[] = array(
'name' => 'Custom Text Add-On',
'value' => sanitize_text_field( $cart_item['custom_text_add_on'] )
);
}
return $data;
}
add_action( 'woocommerce_add_order_item_meta', 'product_add_on_order_item_meta', 10, 2 );
function product_add_on_order_item_meta( $item_id, $values ) {
if ( ! empty( $values['custom_text_add_on'] ) ) {
wc_add_order_item_meta( $item_id, 'Custom Text Add-On', $values['custom_text_add_on'], true );
}
}
add_filter( 'woocommerce_order_item_product', 'product_add_on_display_order', 10, 2 );
function product_add_on_display_order( $cart_item, $order_item ){
if( isset( $order_item['custom_text_add_on'] ) ){
$cart_item_meta['custom_text_add_on'] = $order_item['custom_text_add_on'];
}
return $cart_item;
}
add_filter( 'woocommerce_email_order_meta_fields', 'product_add_on_display_emails' );
function product_add_on_display_emails( $fields ) {
$fields['custom_text_add_on'] = 'Custom Text Add-On';
return $fields;
}
I have copied the code and done a quick test and could found that you are missing underscore _ for the field name in two functions. You were using $_POST['custom_text_add_on'] instead of $_POST['_custom_text_add_on'] in the product_add_on_cart_item_data function. That was just a mistake.
add_filter( 'woocommerce_add_cart_item_data', 'product_add_on_cart_item_data', 10, 2 );
function product_add_on_cart_item_data( $cart_item, $product_id ){
if( isset( $_POST['_custom_text_add_on'] ) ) {
$cart_item['custom_text_add_on'] = sanitize_text_field( $_POST['_custom_text_add_on'] );
}
return $cart_item;
}
Hope you got the issue resolved