phpwordpresswoocommercecustom-fieldsproduct-variations

WooCommerce product variation price based on custom fields


I have variable products to which i added custom fields like this :

function ab_preorder_variation_fields( $loop, $variation_data, $variation ) {

    echo '<div class="options_group form-row form-row-full">';
    // Is Preordable
    woocommerce_wp_checkbox(
        array(
            'id'            => '_ab_preorder_checkbox[' . $variation->ID . ']',
            'wrapper_class' => 'show_if_simple',
            'label'         => __(' Disponible à la précommande', 'woocommerce' ),
            'description'   => __( 'Disponible à la précommande', 'woocommerce' ),
            'desc_tip'    => true,
            'value' => get_post_meta( $variation->ID, '_ab_preorder_checkbox', true )
        )
    );
    
    // Custom Preorder Price
    woocommerce_wp_text_input(
        array(
            'id'                => '_ab_preorder_custom_price[' . $variation->ID . ']',
            'label'             => __( 'Prix à la précommande', 'woocommerce' ),
            'placeholder'       => '',
            'desc_tip'          => true,
            'description'       => __( "Prix à la précommande", 'woocommerce' ),
            'type'              => 'number',
            'custom_attributes' => array(
                    'step'  => 'any',
                    'min'   => '0'
                ),
            'value' => get_post_meta( $variation->ID, '_ab_preorder_custom_price', true )
        )
    );
    // Date de livraison estimée
    woocommerce_wp_text_input(
        array(
            'id'          => '_ab_preorder_estimated_date[' . $variation->ID . ']',
            'label'       => __( 'Date de livraison estimé', 'woocommerce' ),
            'placeholder' => '24/09/2021',
            'desc_tip'    => true,
            'description' => __( "Date de livraison estimé", "woocommerce" ),
            'value' => get_post_meta( $variation->ID, '_ab_preorder_estimated_date', true )
        )
    );


    echo '</div>';

}
add_action( 'woocommerce_product_after_variable_attributes', 'ab_preorder_variation_fields', 10, 3 ); // After all Variation fields
function ab_preorder_variation_fields_saving( $post_id ){

    // Is Preordable
    $woocommerce_text_field = $_POST['_ab_preorder_checkbox'][ $post_id ];
    update_post_meta( $post_id, '_ab_preorder_checkbox', esc_attr( $woocommerce_text_field ) );
    
    // Custom Preorder Price
    $woocommerce_text_field = $_POST['_ab_preorder_custom_price'][ $post_id ];
    update_post_meta( $post_id, '_ab_preorder_custom_price', esc_attr( $woocommerce_text_field ) );
    
    // Date de livraison estimée
    $woocommerce_text_field = $_POST['_ab_preorder_estimated_date'][ $post_id ];
    update_post_meta( $post_id, '_ab_preorder_estimated_date', esc_attr( $woocommerce_text_field ) );

}

Here's the result in WP Admin : enter image description here

Here's what i want to do : When a customer chooses a variation, i want to : if the variation stock quantity is 0 and _ab_preorder_checkbox checkbox is checked, i want to set the product price at 100.

I tried with the code below but it doesn't work :/

function action_woocommerce_before_calculate_totals( $cart_object) { 
    $cart_items = $cart_object->cart_contents;

      if ( ! empty( $cart_items ) ) {
        $price = 100;
        foreach ( $cart_items as $key => $value ) {
            if($value['data']['_ab_preorder_checkbox']=="yes")
            $value['data']->set_price( $price );
          
        }
      }

}; 
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 2 ); 

Can anyone please help me out with that ?

Regards,


Solution

  • As woocommerce will not allow to purchase products with zero stock, you will need to set "Allow backorders" option for the related products.

    I have revisited your code a bit (specifically your 2nd function).

    The hook woocommerce_before_calculate_totals is not convenient in your case. Is better to set the backorder custom price on the product instead.

    The following will set the backorder price on the variation when the checkbox is enabled and will display it on the related variation with the delivery estimated date:

    // Admin Variation custom fields
    add_action( 'woocommerce_product_after_variable_attributes', 'ab_preorder_variation_fields', 10, 3 );
    function ab_preorder_variation_fields( $loop, $variation_data, $variation ) {
    
        echo '<div class="options_group form-row form-row-full">';
        
        // Is Preordable
        woocommerce_wp_checkbox(
            array(
                'id'            => '_ab_preorder_checkbox['.$loop.']',
                'wrapper_class' => 'show_if_simple',
                'label'         => __(' Disponible à la précommande', 'woocommerce' ),
                'description'   => __( 'Disponible à la précommande', 'woocommerce' ),
                'desc_tip'    => true,
                'value' => get_post_meta( $variation->ID, '_ab_preorder_checkbox', true )
            )
        );
    
        // Custom Preorder Price
        woocommerce_wp_text_input(
            array(
                'id'                => '_ab_preorder_custom_price['.$loop.']',
                'label'             => __( 'Prix à la précommande', 'woocommerce' ),
                'placeholder'       => '',
                'desc_tip'          => true,
                'description'       => __( "Prix à la précommande", 'woocommerce' ),
                'type'              => 'number',
                'custom_attributes' => array(
                        'step'  => 'any',
                        'min'   => '0'
                    ),
                'value' => get_post_meta( $variation->ID, '_ab_preorder_custom_price', true )
            )
        );
    
        // Date de livraison estimée
        woocommerce_wp_text_input(
            array(
                'id'          => '_ab_preorder_estimated_date['.$loop.']',
                'label'       => __( 'Date de livraison estimé', 'woocommerce' ),
                'desc_tip'    => true,
                'description' => __( "Date de livraison estimé", "woocommerce" ),
                'type'        => 'date',
                'value' => get_post_meta( $variation->ID, '_ab_preorder_estimated_date', true )
            )
        );
    
        echo '</div>';
    }
    
    // Save admin Variations custom fields values
    add_action( 'woocommerce_admin_process_variation_object', 'ab_preorder_variation_fields_saving', 10, 2 );
    function ab_preorder_variation_fields_saving( $variation, $loop ) {
        if( isset($_POST['_ab_preorder_checkbox'][$loop]) ) {
            $variation->update_meta_data( '_ab_preorder_checkbox', esc_attr($_POST['_ab_preorder_checkbox'][$loop]) );
        }
    
        if( isset($_POST['_ab_preorder_custom_price'][$loop]) ) {
            $variation->update_meta_data( '_ab_preorder_custom_price', esc_attr($_POST['_ab_preorder_custom_price'][$loop]) );
        }
    
        if( isset($_POST['_ab_preorder_estimated_date'][$loop]) ) {
            $variation->update_meta_data( '_ab_preorder_estimated_date', esc_attr($_POST['_ab_preorder_estimated_date'][$loop]) );
        }
    }
    
    // Set the variation backorder price
    add_filter('woocommerce_product_variation_get_regular_price', 'custom_price', 99, 2 );
    add_filter('woocommerce_product_variation_get_price', 'custom_price', 99, 2 );
    function custom_price( $price, $product ) {
        if ( $product->get_stock_quantity() == 0 && $product->get_meta('_ab_preorder_checkbox') === 'yes' ) {
            $backorder_price = $product->get_meta('_ab_preorder_custom_price');
            
            if( $backorder_price > 0 ) {
                $price = (float) $backorder_price;
            }
        }
        return $price;
    }
    
    // Display prefixed backorder price and estimated delivery on single product pages
    add_filter( 'woocommerce_available_variation', 'ab_available_variation_custom_field', 10, 3 );
    function ab_available_variation_custom_field( $variation_data, $product, $variation ) {
        if ( $variation->get_stock_quantity() == 0 && $variation->get_meta('_ab_preorder_checkbox') === 'yes' ) {
            if ( $estimated_delivery_date = $variation->get_meta('_ab_preorder_estimated_date') ) {
                // Display estimated delivery date
                $variation_data['availability_html'] .= sprintf( '<p class="stock date-precommande">%s : %s</p>',
                __("Date de livraison estimée (précommande)", "woocommerce"), $estimated_delivery_date );
            }
            
            // Displayed prefixed formatted price
            $variation_data['price_html'] = '<span class="price-prefix">'.__("Prix à la précommande", "") .'<span> : ' . wc_price( $variation_data['display_price'] );
        }
        return $variation_data;
    }
    
    // Display on estimated delivery date on cart and checkout
    add_filter( 'woocommerce_get_item_data', 'display_acf_on_cart_and_checkout', 10, 2 );
    function display_acf_on_cart_and_checkout( $cart_data, $cart_item ) {
        if ( $cart_item['variation_id'] > 0 && $cart_item['data']->get_stock_quantity() == 0
        && $cart_item['data']->get_meta('_ab_preorder_checkbox') === 'yes' ) {
            if ( $estimated_delivery_date = $cart_item['data']->get_meta('_ab_preorder_estimated_date') ) {
                $custom_items[] = array( "name" => __("Date de livraison estimée", "woocommerce"),  "value" => $estimated_delivery_date );
            }
        }
        return $custom_items;
    }
    

    Code goes in functions.php file of the active child theme (or active theme). Tested and works.