0

I'm trying to add a custom field on the checkout form if a certain product category is in the basket and then on submission, check that field has been completed and add the result to the order details.

I have the form field working correctly but not the other actions and it is because the variable $course_in_cart is not being passed to the other actions. All actions work correctly if I remove the $course_in_cart test but it needs to be conditional and this is where I'm failing.

The first action checks if there is a courses category product in the cart, write sthe html and sets the variable to true.

// Set course in cart to false
$course_in_cart = false;

add_action( 'woocommerce_after_checkout_billing_form', 'digitalessence_check_course_category_in_cart' );
function digitalessence_check_course_category_in_cart($checkout) {
    global $course_in_cart;
    // Loop through all products in cart and if there is a course.
        foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
            // If Cart has a course category, set $cat_in_cart to true
            if ( has_term( 'courses', 'product_cat', $cart_item['product_id'] ) ) {
                $course_in_cart = true;
                break;
            }
    }
    // If there is a course in the cart, write HTML form field
    if ( $course_in_cart) {
           echo '<div id="ebike-question">';
           echo '  <div class="woocommerce-additional-fields__field-wrapper">';
             woocommerce_form_field( 'E-Bike__Present', array(
        'type'          => 'text',
        'class'         => array('E-Bike__Present'),
        'placeholder'   => __('Are you bringing an e-bike on the course?'),
        'required'  => true,
        'label'     => __('E-Bike', 'woocommerce'),
        ), $checkout->get_value( 'E-Bike__Present' ));
            echo '</div>';
           echo '  <div class="ebike-question-end-div"></div>';
           echo '</div>';      
    }
    }

The next action I want to perform is to check the status of $course_in_cart and if it is true, add a required field notice. This is where I fall down as it is alsways showing as false.

add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
// Check if set, if its not set add an error.
function my_custom_checkout_field_process() {
    global $course_in_cart;
    if ( $course_in_cart) {
        if ( ! $_POST['E-Bike__Present'] )
        wc_add_notice( __( '<strong>For our legs, we need to know if you are bringing an e-bike!</strong>' ), 'error' );
        }
    else {
        wc_add_notice( __( '<strong>course in cart variable is showing as false</strong>' ), 'error' );
        
    }
}

I stripped everything right back to basics to ensure that passing variables from one function to another would work.

<?php
$course_in_cart = false;
declareVariable();
displayVariable();

function declareVariable() {
  global $course_in_cart;
  $course_in_cart = true;
}
function displayVariable() {
    global $course_in_cart;
    //echo $course_in_cart; // outputs 1
    if ( $course_in_cart) {
        echo "Its working. The variable is showing as: " . $course_in_cart;
    }
}
?>

And it does. I get "Its working. The variable is showing as: 1" in the browser.

Any and all help appreciated. I have searched other questions and haven't found any similar so hope this isn't a duplicate. Please berate me if it is! And I hope I've given enough information. If not...

Thank you.

1 Answer 1

0

You shouldn't be trying to pass the variable between actions. Variables do not persist across requests, and the first time you define it is when the checkout loaded, and the second time is after the checkout is submitted, which is a separate request entirely. To pass a value between requests you would need to store the value in the database, or in a cookie.

That's the wrong approach, though. You don't actually want the variable. What you want to know in each action is "is there a course in the cart?". There's no reason to only perform the check once and then try to pass the result around. Just perform the same check in both places:

/**
 * Check if the cart contains a product in the Courses category.
 */
function digitalessence_is_course_in_cart() {
    $course_in_cart = false;
    
    foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
        if ( has_term( 'courses', 'product_cat', $cart_item['product_id'] ) ) {
            $course_in_cart = true;
            break;
        }
    }

    return $course_in_cart;
}

/**
 * Add a form field if the cart contains a product in the Courses category.
 */
function digitalessence_checkout_billing_form( $checkout ) {
    $course_in_cart = digitalessence_is_course_in_cart();

    if ( $course_in_cart ) {
        // Output form field.
    }
}
add_action( 'woocommerce_after_checkout_billing_form', 'digitalessence_checkout_billing_form' );

/**
 * Validate the form field added if the cart contains a product in the Courses category.
 */
function digitalessence_checkout_validation( $data, $errors ) {
    $course_in_cart = digitalessence_is_course_in_cart();

    if ( $course_in_cart ) {
        // Validate form field.
        // $errors->add( 'ebike', 'For our legs, we need to know if you are bringing an e-bike!' );
    }
}
add_action( 'woocommerce_after_checkout_validation', 'digitalessence_checkout_validation', 10, 2 );

Note that I've changed your last function to use the woocommerce_after_checkout_validation hook. If you want to validate a checkout field, this is the hook to use. If the validation fails add an error to the WP_Error object that's passed as the second argument. My code includes an example commented out.

1
  • Thank you Jacob. Clear & concise with example code that even a simple bear like me can follow & understand. I will head off and read up on WP_Error and use that instead. Appreciate your time and effort in helping me. Sep 11, 2020 at 13:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.