Checkbox in WooCommerce product loop that add an option on Ajax add to cart

In WooCommerce, I have added a checkbox in single product pages and also on the products loops, where the user can check that they want to request a certificate.

My code below works fine on single product pages. However, in the products loops, the value of the check box is always taken, even if the checkbox is unchecked. It should only be taken if the checkbox is checked.

Here is my code:

function add_name_on_certificate_field() {
echo '<table class="certificate" cellspacing="0">
      <tbody>
          <tr>
             <td class="value">
              Certificate: <input type="checkbox" name="name_on_certificate" value="certificate" "/>                      
             </td>
         </tr>                               
      </tbody>
  </table>';}

add_action( 'woocommerce_before_add_to_cart_button', 'add_name_on_certificate_field'); 


 function save_name_on_certificate_field( $cart_item_data, $product_id ) {
    if( isset( $_REQUEST['name_on_certificate'] ) ) {
       $cart_item_data[ 'name_on_certificate' ] = $_REQUEST['name_on_certificate'];
       $cart_item_data['unique_key'] = md5( microtime().rand() );
    }
  return $cart_item_data;
}
add_action( 'woocommerce_add_cart_item_data', 'save_name_on_certificate_field', 10, 2 ); code here


function render_meta_on_cart_and_checkout2( $cart_data, $cart_item = null ) {
    $custom_items = array();
    if( !empty( $cart_data ) ) {
        $custom_items = $cart_data;
    }
    if( isset( $cart_item['name_on_certificate'] ) ) {
       $custom_items[] = array( "name" => 'Certificate', "value" => 
        $cart_item['name_on_certificate']);
    }
    return $custom_items;
 }
 add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart_and_checkout2', 10, 2 );

  function certificate_order_meta_handler( $item_id, $values, $cart_item_key ) {
      if( isset( $values['name_on_certificate'] ) ) {
       wc_add_order_item_meta( $item_id, "name_on_certificate", $values['name_on_certificate']);
      }
  }
  add_action( 'woocommerce_add_order_item_meta', 'certificate_order_meta_handler', 1, 3 );


 function add_custom_fields_on_product_listing2() {
      global $product;
      echo '</a><div class="sark-custom-fields-wrapper">
          <input type="checkbox" id="name_on_certificate-'. $product->id .'" value="certificate-required" /> </div>';
}
 add_action( "woocommerce_after_shop_loop_item", 'add_custom_fields_on_product_listing2', 1 );


function inject_custom_field_script2() { ?>
     <script type="text/javascript">       
       jQuery(document).on("adding_to_cart", function( e, btn, data ){
        data["name_on_certificate"] = jQuery("#name_on_certificate-" + btn.attr( "data-product_id" )).val();
     return true;
    });
  
  </script>
 <?php }
add_action( "woocommerce_after_main_content", 'inject_custom_field_script2', 1 );

For info, there is already a text field, where you can set the size of the product that works fine.

Any help will be appreciated.

Answer

I have revisited your code, renaming functions, changing an obsolete hook, adding some missing things and making multiple changes.

Now only when the checkbox is checked and when the related product is added to cart (on single product pages or in product loops via Ajax add to cart), an option is added as custom cart item data, displayed on cart, checkout, orders and emails.

The code:

// Products Loop: Display the checkbox field on products that have Ajax add to cart enabled
add_action( "woocommerce_after_shop_loop_item", 'product_loop_display_certificate_field' );
function product_loop_display_certificate_field() {
    global $product;

    if ( $product->supports( 'ajax_add_to_cart' ) && $product->is_purchasable() && $product->is_in_stock() ) {
        echo '</a><div class="sark-custom-fields-wrapper"><input type="checkbox" id="name_on_certificate-' .
        $product->get_id() . '" value="required" /></div>';
    }
}

// Products Loop: Handle Ajax add to cart for the checkbox
add_action( "init", 'certificate_field_loop_jquery_script', 1 );
function certificate_field_loop_jquery_script() {
    wc_enqueue_js("jQuery( function($){
        $(document.body).on('adding_to_cart', function( e, btn, data ){
            var checkbox = $('#name_on_certificate-'+data.product_id);
            if( checkbox.is(':checked') ) {
                data['name_on_certificate'] = checkbox.val();
                return data['name_on_certificate'];
            }
        });
    });");
}

// Single products: Display the checkbox field
add_action( 'woocommerce_before_add_to_cart_button', 'single_product_display_certificate_field');
function single_product_display_certificate_field() {
    echo '<table class="certificate" cellspacing="0"><tbody><tr>
        <td class="value">' . __("Certificate:", "woocommerce") .
        ' <input type="checkbox" name="name_on_certificate" value="required" "/>
        </td>
    </tr></tbody></table>';
}

// Add checked checkbox value as custom cart item data
add_action( 'woocommerce_add_cart_item_data', 'add_cart_item_certificate_field_value', 10, 2 );
function add_cart_item_certificate_field_value( $cart_item_data, $product_id ) {
    if( isset( $_REQUEST['name_on_certificate'] ) ) {
       $cart_item_data[ 'name_on_certificate' ] = $_REQUEST['name_on_certificate'];
       $cart_item_data['unique_key'] = md5( microtime().rand() );
    }
    return $cart_item_data;
}

// Display required certificate in minicart, cart and checkou
add_filter( 'woocommerce_get_item_data', 'display_cart_item_certificate_field_value', 10, 2 );
function display_cart_item_certificate_field_value( $cart_data, $cart_item ) {
    if( isset( $cart_item['name_on_certificate'] ) ) {
        $cart_data[] = array( "name" => 'Certificate', "value" => $cart_item['name_on_certificate']);
    }
    return $cart_data;
}

// Save required certificate as custon order item data and display it on orders and emails
add_action( 'woocommerce_checkout_create_order_line_item', 'add_order_item_certificate_field_value', 10, 4 );
function add_order_item_certificate_field_value( $item, $cart_item_key, $values, $order ) {
    if( isset( $values['name_on_certificate'] ) ) {
        $item->update_meta_data( 'name_on_certificate', esc_attr($values['name_on_certificate']) );
    }
}

// Change required certificate displayed meta key label to something readable
add_filter('woocommerce_order_item_display_meta_key', 'filter_order_item_displayed_meta_key', 20, 3 );
function filter_order_item_displayed_meta_key( $displayed_key, $meta, $item ) {
    // Change displayed meta key label for specific order item meta key
    if( $item->get_type() === 'line_item' && $meta->key === 'name_on_certificate' ) {
        $displayed_key = __("Certificate", "woocommerce");
    }
    return $displayed_key;
}

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

Leave a Reply

Your email address will not be published. Required fields are marked *