6850

Conditional custom checkout fields based on product category in Woocommerce

<h3>Question</h3>

I am using woocommerce for a site for a nonprofit that sells tickets to classes and tickets to events. When someone is signing up for a class then need to list their emergency contact information and agree to a liability release. When they are buying a ticket to an event the nonprofit doesn't need the emergency contact info or the liability release. So... they want those fields to appear on the woocommerce checkout only on the condition that the person is checking out with a ticket for a class. Make sense?

I figured out how to add the custom fields and the custom liability releases a few months ago when they first added the classes to the website. I created a "class" product category in woocommerce and a function to test for any products in the shopping cart that are in that category, so I can conditionally show the fields.

All of these functions are in my functions.php file and I right now I am running the conditional statement to check for the "class" category in each of the functions. I need help learning how to check for the "class" category once, then run the functions that display the fields, validated the fields, add the data to the database and generate the new order emails. Make sense?

Here's what I have currently:

// Add fields for Emergency Contact & Medical Information to the checkout page add_action('woocommerce_after_order_notes', 'customise_checkout_field'); function customise_checkout_field($checkout) { // Check to see if there is a class in the cart // function is at the end $class_in_cart = is_conditional_product_in_cart( 'class' ); // There is a class in the cart so show additional fields if ( $class_in_cart === true ) { echo '<div id="customise_checkout_field"><h3>' . __('Emergency Contact & Medical Information') . '</h3>'; woocommerce_form_field('emergency_contact', array( 'type' => 'text', 'class' => array( 'emergency-contact form-row-wide' ) , 'label' => __('Emergency Contact') , 'placeholder' => __('Please enter first & last name') , 'required' => true, ) , $checkout->get_value('emergency_contact')); woocommerce_form_field('emergency_contact_relationship', array( 'type' => 'text', 'class' => array( 'emergency-contact-relationship form-row-wide' ) , 'label' => __('What is your relationship with this person?') , 'placeholder' => __('Example: Mother') , 'required' => true, ) , $checkout->get_value('emergency_contact_relationship')); woocommerce_form_field('emergency_contact_phone', array( 'type' => 'text', 'class' => array( 'emergency-contact-phone form-row-wide' ) , 'label' => __('What is their phone number?') , 'placeholder' => __('(555) 555-5555') , 'required' => true, ) , $checkout->get_value('emergency_contact_phone')); woocommerce_form_field('medical_medicine', array( 'type' => 'textarea', 'class' => array( 'medical-medicine form-row-wide' ) , 'label' => __('Do you have any medical conditions and are you taking any medications we need to be aware of?') , 'placeholder' => __('If not please write in "none"') , 'required' => true, ) , $checkout->get_value('medical_medicine')); echo '</div>'; } } // Process emergency contact fields add_action('woocommerce_checkout_process', 'custom_checkout_fields_process'); function custom_checkout_fields_process() { // Check to see if there is a class in the cart $class_in_cart = is_conditional_product_in_cart( 'class' ); // There is a class in the cart so show additional fields if ( $class_in_cart === true ) { // if the field is set, if not then show an error message. if (!$_POST['emergency_contact']) wc_add_notice(__('Please list an emergency contact.') , 'error'); if (!$_POST['emergency_contact_relationship']) wc_add_notice(__('Please indicate your relationship with your emergency contact.') , 'error'); if (!$_POST['emergency_contact_phone']) wc_add_notice(__('Please list a phone number for your emergency contact.') , 'error'); if (!$_POST['medical_medicine']) wc_add_notice(__('Please list any medications or write in "none".') , 'error'); } } // Add emergency contact information to the database add_action('woocommerce_checkout_update_order_meta', 'custom_checkout_fields_update_order_meta'); function custom_checkout_fields_update_order_meta($order_id) { // Check to see if there is a class in the cart $class_in_cart = is_conditional_product_in_cart( 'class' ); // There is a class in the cart so show additional fields if ( $class_in_cart === true ) { if (!empty($_POST['emergency_contact'])) { update_post_meta($order_id, 'emergency_contact', sanitize_text_field($_POST['emergency_contact'])); } if (!empty($_POST['emergency_contact_relationship'])) { update_post_meta($order_id, 'emergency_contact_relationship', sanitize_text_field($_POST['emergency_contact_relationship'])); } if (!empty($_POST['emergency_contact_phone'])) { update_post_meta($order_id, 'emergency_contact_phone', sanitize_text_field($_POST['emergency_contact_phone'])); } if (!empty($_POST['medical_medicine'])) { update_post_meta($order_id, 'medical_medicine', sanitize_text_field($_POST['medical_medicine'])); } } } // Add the emergency contact fields to order email add_filter( 'woocommerce_email_order_meta_keys', 'my_custom_checkout_field_order_meta_keys' ); function my_custom_checkout_field_order_meta_keys( $keys ) { // Check to see if there is a class in the cart $class_in_cart = is_conditional_product_in_cart( 'class' ); // There is a class in the cart so show additional fields if ( $class_in_cart === true ) { echo '<h2>Emergency Contact & Medical Information:</h2>'; $keys['Emergency Contact'] = 'emergency_contact'; $keys['Emergency Contact Relationship'] = 'emergency_contact_relationship'; $keys['Emergency Contact Phone'] = 'emergency_contact_phone'; $keys['Medical Conditions & Medications'] = 'medical_medicine'; return $keys; } // end class in cart condition } /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ // Add custom checkboxes to woocommerce checkout page for Photo Release, Mailing List & Release of Liability // add_action( 'woocommerce_after_order_notes', 'custom_checkout_fields' ); add_action( 'woocommerce_review_order_before_submit', 'custom_checkout_fields' ); function custom_checkout_fields() { echo '<div id="custom_checkout_fields"> <h3>Mailing Lists</h3>

Mailing List boilerplate'; woocommerce_form_field( 'mailing_consent', array( 'type' => 'checkbox', 'class' => array('input-checkbox'), 'label' => __('Please add me to Nonprofit\'s electronic and paper mailing lists.'), 'required' => false, 'clear' => true, 'default' => 1 //This will pre-select the checkbox ), WC()->checkout->get_value( 'mailing_consent' ) ); // Check to see if there is a class in the cart $class_in_cart = is_conditional_product_in_cart( 'class' ); // There is a class in the cart so show additional fields if ( $class_in_cart === true ) { echo '<h3>Photo Release</h3>

Photo Release Boilerplate

'; woocommerce_form_field( 'photo_consent', array( 'type' => 'checkbox', 'class' => array('input-checkbox'), 'label' => __('I agree to the Photo Release as outlined above.'), 'required' => false, 'clear' => true, 'default' => 1 //This will pre-select the checkbox ), WC()->checkout->get_value( 'photo_consent' ) ); echo '<h3>Release of Liability</h3>

Release of Liability Boilerplate

'; woocommerce_form_field( 'liability_release', array( 'type' => 'checkbox', 'class' => array('input-checkbox'), 'label' => __('I agree to the Photo Release as outlined above.'), 'required' => true, 'clear' => true, 'default' => 1 //This will pre-select the checkbox ), WC()->checkout->get_value( 'liability_release' ) ); } // end class in cart condition echo '</div>'; } // Show notice if customer doesn't check the Release of Liability checkbox add_action( 'woocommerce_checkout_process', 'liability_release_not_given' ); function liability_release_not_given() { // Check to see if there is a class in the cart $class_in_cart = is_conditional_product_in_cart( 'class' ); // There is a class in the cart so show additional fields if ( $class_in_cart === true ) { if ( ! (int) isset( $_POST['liability_release'] ) ) { wc_add_notice( __( 'You must agree to the Release of Liability to register for this class. Please contact us with any questions.' ), 'error' ); } } // end class in cart condition } // Save the custom checkout field in the order meta, when checkbox has been checked add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 1 ); function custom_checkout_field_update_order_meta( $order_id ) { if ( ! empty( $_POST['mailing_consent'] ) ) update_post_meta( $order_id, 'mailing_consent', $_POST['mailing_consent'] ); if ( ! empty( $_POST['photo_consent'] ) ) update_post_meta( $order_id, 'photo_consent', $_POST['photo_consent'] ); if ( ! empty( $_POST['liability_release'] ) ) update_post_meta( $order_id, 'liability_release', $_POST['liability_release'] ); } /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ // Display custom field results on the order edit page (backend) // for various liability fields add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 ); function display_custom_field_on_order_edit_pages( $order ){ $mailing_consent = get_post_meta( $order->get_id(), 'mailing_consent', true ); if( $mailing_consent == 1 ) echo '

' . $order->billing_first_name . ' ' . $order->billing_last_name . ' agreed to the be added to Nonprofit\'s mailing lists.

'; $photo_consent = get_post_meta( $order->get_id(), 'photo_consent', true ); if( $photo_consent == 1 ) echo '

' . $order->billing_first_name . ' ' . $order->billing_last_name . ' agreed to the Photo Release.

'; $liability_release = get_post_meta( $order->get_id(), 'liability_release', true ); if( $liability_release == 1 ) echo '

' . $order->billing_first_name . ' ' . $order->billing_last_name . ' agreed to the Release of Liability.

'; } /** * Check if Class is In cart * * https://wordimpress.com/create-conditional-checkout-fields-woocommerce/ * https://businessbloomer.com/woocommerce-check-product-category-cart/ * * @param $product_id * * @return bool */ function is_conditional_product_in_cart( $category_name ) { //Check to see if user has a class in their cart global $woocommerce; //flag no class in cart $class_in_cart = false; foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) { $_product = $values['data']; // if ( $_product->cat === $category_id ) { // //class is in cart! //$class_in_cart = true; if (has_term ( $category_name, 'product_cat', $_product->get_id() ) ) { //class is in cart! $class_in_cart = true; } } return $class_in_cart; }

As you can probably tell I pieced this together from various sources on the web and I realize it is a bit of a mess. Currently the conditional statement:

// Check to see if there is a class in the cart $class_in_cart = is_conditional_product_in_cart( 'class' ); // There is a class in the cart so show additional fields if ( $class_in_cart === true ) {

Is repeated for each function. I know this isn't efficient but I'm not sure how to fix it. What I would like to do is this:

<ol><li>Test for products that are in the "class" category</li> <li>If "class" then run all the functions to display and process emergency contact fields and photo release and release of liability fields</li> <li>Display "join mailing list" agreement regardless of whether or not there is a "class" in the cart and process that field no matter what. </li> </ol>

I tried just wrapping everything in another function but that broke the code. Maybe it would be best to move this into a plugin?

Thanks for any ideas and help you can give.


<h3>Answer1:</h3>

First the conditional function code that you are using is really old, outdated and will not work when cart items are product variations <em>(so for variable products)</em>. Here below is the compact and working conditional function…
It can work with any product category term ID, slug, name or an array of values:

function is_product_cat_in_cart( $categories ) { foreach ( WC()->cart->get_cart() as $cart_item ) { if (has_term ( $categories, 'product_cat', $cart_item['product_id'] ) ) return true; } return false; }

Now the rest of your code has a lot of mistakes or little errors.

It also use outdated or deprecated hooks like:

<ul><li>woocommerce_checkout_update_order_meta replaced by a much appropriated hook.</li> <li>woocommerce_email_order_meta_keys is deprecated since a lot of time.</li> </ul>

You can also merge some code together in the same hooked functions.

You don't need the conditional function everywhere. It's just needed for checkout fields conditional display.

Here is your revisited code <em>(for woocommerce version 3 and above)</em>:

// Add fields for Emergency Contact & Medical Information to the checkout page add_action('woocommerce_after_order_notes', 'customise_checkout_field', 20, 1 ); function customise_checkout_field( $checkout ){ $domain = 'woocommerce'; // There is a class in the cart so show additional fields if ( is_product_cat_in_cart( 'class' ) ): echo '<div id="customise_checkout_field"> <h3>' . __( 'Emergency Contact & Medical Information', $domain ) . '</h3>'; woocommerce_form_field( 'emergency_contact', array( 'type' => 'text', 'class' => array( 'emergency-contact form-row-wide' ), 'label' => __( 'Emergency Contact', $domain ) , 'placeholder' => __( 'Please enter first & last name', $domain ), 'required' => true, ), $checkout->get_value('emergency_contact') ); woocommerce_form_field( 'emergency_contact_relationship', array( 'type' => 'text', 'class' => array( 'emergency-contact-relationship form-row-wide' ), 'label' => __( 'What is your relationship with this person?', $domain ), 'placeholder' => __( 'Example: Mother', $domain ) , 'required' => true, ), $checkout->get_value('emergency_contact_relationship') ); woocommerce_form_field( 'emergency_contact_phone', array( 'type' => 'text', 'class' => array( 'emergency-contact-phone form-row-wide' ), 'label' => __( 'What is their phone number?', $domain ), 'placeholder' => __( '(555) 555-5555', $domain ), 'required' => true, ), $checkout->get_value('emergency_contact_phone') ); woocommerce_form_field( 'medical_medicine', array( 'type' => 'textarea', 'class' => array( 'medical-medicine form-row-wide' ) , 'label' => __( 'Do you have any medical conditions and are you taking any medications we need to be aware of?', $domain ), 'placeholder' => __( 'If not please write in "none"', $domain ), 'required' => true, ) , $checkout->get_value('medical_medicine') ); echo '</div>'; endif; } // Add custom checkboxes to woocommerce checkout page for Photo Release, Mailing List & Release of Liability add_action( 'woocommerce_review_order_before_submit', 'custom_checkout_fields' ); function custom_checkout_fields() { $checkout = WC()->checkout; $domain = 'woocommerce'; echo '<div id="custom_checkout_fields"> <h3>'.__( 'Mailing Lists', $domain ).'</h3>

'.__( 'Mailing List boilerplate', $domain ).'

'; woocommerce_form_field( 'mailing_consent', array( 'type' => 'checkbox', 'class' => array('input-checkbox'), 'label' => __( 'Please add me to Nonprofit\'s electronic and paper mailing lists.', $domain ), 'required' => false, 'clear' => true, 'default' => 1 //This will pre-select the checkbox ), $checkout->get_value( 'mailing_consent' ) ); // There is a class in the cart so show additional fields if ( is_product_cat_in_cart( 'class' ) ): echo '<h3>'.__( 'Photo Release', $domain ).'</h3>

'.__( 'Photo Release Boilerplate', $domain ).'

'; woocommerce_form_field( 'photo_consent', array( 'type' => 'checkbox', 'class' => array('input-checkbox'), 'label' => __( 'I agree to the Photo Release as outlined above.', $domain ), 'required' => false, 'clear' => true, 'default' => 1 //This will pre-select the checkbox ), $checkout->get_value( 'photo_consent' ) ); echo '<h3>'.__( 'Release of Liability', $domain ).'</h3>

'.__( 'Release of Liability Boilerplate', $domain ).'

'; woocommerce_form_field( 'liability_release', array( 'type' => 'checkbox', 'class' => array('input-checkbox'), 'label' => __( 'I agree to the Photo Release as outlined above.', $domain ), 'required' => true, 'clear' => true, 'default' => 1 //This will pre-select the checkbox ), $checkout->get_value( 'liability_release' ) ); endif; echo '</div>'; } // Custom checkout fields validation add_action('woocommerce_checkout_process', 'custom_checkout_fields_process'); function custom_checkout_fields_process() { $domain = 'woocommerce'; if ( isset($_POST['emergency_contact']) && empty($_POST['emergency_contact']) ) wc_add_notice( __( 'Please list an emergency contact.', $domain ) , 'error' ); if ( isset($_POST['emergency_contact_relationship']) && empty($_POST['emergency_contact']) ) wc_add_notice( __( 'Please indicate your relationship with your emergency contact.', $domain ), 'error' ); if ( isset($_POST['emergency_contact_phone']) && empty($_POST['emergency_contact']) ) wc_add_notice( __( 'Please list a phone number for your emergency contact.', $domain ), 'error' ); if ( isset($_POST['medical_medicine']) && empty($_POST['emergency_contact']) ) wc_add_notice( __( 'Please list any medications or write in "none".', $domain ), 'error' ); // Other checkout fields if ( ! isset( $_POST['liability_release'] ) && ! $_POST['liability_release'] && isset($_POST['photo_consent']) ) wc_add_notice( __( 'You must agree to the Release of Liability to register for this class. Please contact us with any questions.', $domain ), 'error' ); } // Save custom checkout fields in the order meta data add_action( 'woocommerce_checkout_create_order', 'custom_checkout_fields_in_order_meta_data', 20, 2 ); function custom_checkout_fields_in_order_meta_data( $order, $data ) { if ( isset($_POST['emergency_contact']) && ! empty($_POST['emergency_contact']) ) $order->update_meta_data( 'emergency_contact', sanitize_text_field($_POST['emergency_contact']) ); if ( isset($_POST['emergency_contact_relationship']) && ! empty($_POST['emergency_contact_relationship']) ) $order->update_meta_data( 'emergency_contact_relationship', sanitize_text_field($_POST['emergency_contact_relationship']) ); if ( isset($_POST['emergency_contact_phone']) && ! empty($_POST['emergency_contact_phone']) ) $order->update_meta_data( 'emergency_contact_phone', sanitize_text_field($_POST['emergency_contact_phone']) ); if ( isset($_POST['medical_medicine']) && ! empty($_POST['medical_medicine']) ) $order->update_meta_data( 'medical_medicine', sanitize_text_field($_POST['medical_medicine']) ); if ( isset($_POST['mailing_consent']) && ! empty($_POST['mailing_consent']) ) $order->update_meta_data( 'mailing_consent', '1' ); if ( isset( $_POST['photo_consent']) && ! empty($_POST['photo_consent']) ) $order->update_meta_data( 'photo_consent', '1' ); if ( isset( $_POST['liability_release']) && ! empty($_POST['liability_release']) ) $order->update_meta_data( 'liability_release', '1' ); } // Add the emergency contact fields to email notifications add_filter( 'woocommerce_email_order_meta_fields', 'custom_checkout_field_email_order_meta', 20, 3 ); function custom_checkout_field_email_order_meta( $fields, $sent_to_admin, $order ) { $domain = 'woocommerce'; if( ! $order->get_meta( 'emergency_contact' ) ) return $fields; // Exit if not set in the order echo '<h2>'.__( 'Emergency Contact & Medical Information', $domain ).'</h2>'; $fields[] = array( 'label' => __( 'Emergency contact', $domain ), 'value' => $order->get_meta( 'emergency_contact' ) ); $fields[] = array( 'label' => __( 'Emergency Contact Relationship', $domain ), 'value' => $order->get_meta( 'emergency_contact_relationship' ) ); $fields[] = array( 'label' => __( 'Emergency Contact Phone', $domain ), 'value' => $order->get_meta( 'emergency_contact_phone' ) ); $fields[] = array( 'label' => __( 'Medical Conditions & Medications', $domain ), 'value' => $order->get_meta( 'medical_medicine' ) ); return $fields; } // Display some custom checkout fields in Order edit pages add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 20, 1 ); function display_custom_field_on_order_edit_pages( $order ){ $domain = 'woocommerce'; $billing_name = $order->get_billing_first_name().' '.$order->get_billing_last_name(); if( $order->get_meta('mailing_consent') ) echo '

' . $billing_name . __( ' agreed to the be added to Nonprofit\'s mailing lists.', $domain ).'

'; if( $order->get_meta('photo_consent') ) echo '

' . $billing_name . __( ' agreed to the Photo Release.', $domain ).'

'; if( $order->get_meta('liability_release') ) echo '

' . $billing_name . __( ' agreed to the Release of Liability.', $domain ).'

'; }

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

Conclusion: If some code doesn't work in function.php file, it will not work better in a plugin. But if you want you can add it in a plugin, if you prefer.

来源:https://stackoverflow.com/questions/50766359/conditional-custom-checkout-fields-based-on-product-category-in-woocommerce

Recommend

  • Error 193 %1 is not a valid Win32 application
  • Trouble with the libPng.dylib from freetype 2.5.3
  • Are there any alternatives to ICRA for self-regulated content labeling of websites?
  • Zoom to the closest level that still shows all markers, including the blue MyLocation marker
  • A glow around a circular image with CSS on hover
  • Showing one marker at a time - Google Maps API v3
  • Targeting Flash Player 10.3 in Adobe Flash CS5
  • Render Box Dynamically in Shiny
  • Admin-on-rest, Edit Page - Incorrect Element Error
  • Jsoncpp FastWriter right trim
  • How to get mouseover event from android emulator
  • TeamCity: Scripting elements jsp:declaration, jsp:expression, jsp:scriptlet are disallowed here
  • Using MS Dynamics NAV with PHP [closed]
  • Adding in new XML root node
  • rvest: extract tables with url's instead of text
  • Is it possible to read static text dynamically from property files in velocity template?
  • Caching of Google Cloud Endpoints?
  • implementing euclidean distance based formula using numpy
  • Quartz clustering load balancing algorithm internal implementation in Jdbcjobstore
  • Conflict. The container name “/gitlab-runner” is already in use by container
  • Applescript: Check if computer is playing any sound
  • Convert a Treeview to JSON using C#
  • C++ method declaration including a macro
  • How do I set context and followup event in one intent?
  • MySQL - Filter records which date is biggest
  • Unable to connect to Azure MySQL Database through Azure Function - C#
  • Tensorflow crash using tf.train.Saver() with GPU
  • Validating my form with Jquery
  • Julia 1.0 UndefVarError - Scope of Variable
  • Error handeling in antlr 3.0
  • DataTables move rows between tables
  • Why does Rails 3 think xE2x80x89 means â x80 x89
  • WPF custom control and direct content support