Add and manage Product custom upload field in Woocommerce 3

I am trying to add a file upload along with radio inputs in a custom woocommerce page; where all the products are showing in a list view.

The Custom Page CODE:

        <?php /*
    Template Name: Custom Woo Product List Page
    */ ?>
    <?php get_header();?>


          <div class="inn_page">


                <table id="wh_table" class="table table-hover" width="100%" cellspacing="0">

                <thead>
                  <tr>
                    <th></th>
                    <th>PRODUCT</th>
                    <th>Monogram letter or Message Box</th>
                    <th>PRICE</th>              
                    <th>Product Total Quantity</th>
                    <th></th>
                  </tr>
                  </thead>

                    <tbody>         
                    <?php
                        $args = array( 
                        'post_type' => array('product', 'product_variation'), 
                        'post_status' => array('publish'),
                        'posts_per_page' => -1,
                        'product_cat' => '', 
                        'post__in' => array( 178, 39, 180, 101, 182, 108, 184, 171, 872, 877, 206, 197, 1028, 330, 216, 451, 481, 478, 589 ),
                        'orderby' => 'post__in',
                        //'order'     => 'DESC',
                        'paged'   => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1 );
                        $wp_query = new WP_Query( $args );
                        while ( $wp_query->have_posts() ) : $wp_query->the_post(); 
                        global $product; 
                    ?>

                    <?php if ( $product->is_type( 'variable' ) ) 
                        {   
                            show_variable_products_list();              
                        }
                        else 
                        {
                    ?>

                    <tr class="product-<?php echo esc_attr( $product->id ); ?> variations_form" data-role="product"> 
                    <form action="<?php echo esc_url( $product->add_to_cart_url() ); ?>" class="cart" name="upload_form" id="upload_form" method="post" enctype='multipart/form-data'>

                        <a href="<?php echo get_permalink( $wp_query->post->ID ) ?>" title="<?php echo esc_attr($wp_query->post->post_title ? $wp_query->post->post_title : $wp_query->post->ID); ?>">

                            <td class="image">

                                <?php woocommerce_show_product_sale_flash( $post, $product ); ?>

                                <?php if (has_post_thumbnail( $wp_query->post->ID )) echo get_the_post_thumbnail($wp_query->post->ID, 'wh_catalog'); else echo '<img src="'.woocommerce_placeholder_img_src().'" alt="Placeholder" width="150px" height="150px" />'; ?>
                            </td>

                            <td class="title">
                                <h3><?php the_title(); ?></h3>
                                <?php if ( ($product->get_id() == 178) || ($product->get_id() == 589) ) { ?>
                                    <b>Sterling Silver</b>
                                <?php } ?>                      
                            </td>

                            <td class="note">                           
                                <?php letter_note(); ?>
                                <?php msg_note(); ?>
                                <?php upload_logo(); ?>         
                            </td>

                            <td class="wh-price">
                                <span class="hiddenPrice"><?php echo $product->get_price_html() ?></span>
                                <span class="woocommerce-Price-amount ajaxPrice"><?php echo $product->get_price_html() ?></span>
                            </td>

                        </a>

                            <td class="quantity-field">
                                <?php woocommerce_quantity_input(); ?>
                            </td>

                            <td class="button-row">
                                <input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $product->id ); ?>" />
                                <input type="hidden" name="product_id" value="<?php echo esc_attr( $product->id ); ?>" />
                                <div class="wh-button">
                                <button type="submit" class="single_add_to_cart_button btn btn-primary button wh-btn"><span class="glyphicon glyphicon-tag"></span> ADD TO CART</button>
                                </div>


                            </td>


                    </form>

                    </tr>
                        <?php } ?>

                        <?php endwhile; ?>
                        </tbody>

                </table><!--/.products-->

            <?php wp_reset_query(); ?>              


          </div>



    <?php get_footer();?>

For variations to show in list view as different items/products in funtions.php

        <?php 

        //----------------------------- START PRODUCT LIST VIEW PAGE CODE ----------------------------------

        //-------------------------------------- Variations in Table List  ---------------------------

        function show_variable_products_list(){
            global $product, $post;

            $variations = find_valid_variations();

            asort($variations);

                    foreach ($variations as $key => $value) {
                        if( !$value['variation_is_visible'] ) continue; ?>

                    <?php 
                    $id_variation = $value['variation_id']          
                    ?>
                    <tr class="product-<?php echo esc_attr( $product->id ); ?> variation-<?php echo $value['variation_id']?> variations_form" data-role="product"> 
                      <form class="variations_form cart" method="post" enctype='multipart/form-data' data-product_id="<?php echo absint( $product->id ); ?>" data-product_variations="<?php echo htmlspecialchars( json_encode( $available_variations ) ) ?>">  
                        <td class="image">
                            <?php echo '<img src="'.$value['image_src'].'" alt="'.$product->get_title().'-'.$value['variation_id'].'" width="150px" height="150px" />'; ?>
                        </td>

                        <td class="title">
                            <h3><?php the_title(); ?></h3><br />
                            <b class="var-name"><?php                   
                            foreach($value['attributes'] as $attr_name => $attr_value ) {
                            $attr_name = 'pa_setting';
                            $attr = get_term_by('slug', $attr_value, $attr_name);
                            $attr_value = $attr->name;
                            echo $attr_value, '  ';                 
                            } 
                            ?></b>
                            <?php echo $id_variation ?>
                        </td>

                        <td class="note">
                            <?php letter_note(); ?>
                            <?php msg_note(); ?>
                            <?php upload_logo(); ?>
                        </td>   
                        <td class="wh-price">
                            <span class="hiddenPrice"><?php echo $value['price_html'];?></span>
                            <span class="woocommerce-Price-amount ajaxPrice"><?php echo $value['price_html'];?></span>
                        </td>


                            <?php if( $value['is_in_stock'] ) { ?>


                            <td class="quantity-field">
                                <?php woocommerce_quantity_input(); ?>                      
                            </td>

                            <td class="button-row">
                                <?php
                                if(!empty($value['attributes'])){
                                    foreach ($value['attributes'] as $attr_key => $attr_value) {
                                    ?>
                                    <input type="hidden" name="<?php echo $attr_key?>" value="<?php echo $attr_value?>">
                                    <?php
                                    }
                                }
                                ?>
                                <div class="wh-button">
                                <button type="submit" class="single_add_to_cart_button btn btn-primary button wh-btn"><span class="glyphicon glyphicon-tag"></span> ADD TO CART</button>
                                </div>
                                <input type="hidden" name="variation_id" class="variation_id" value="<?php echo $value['variation_id']?>" />
                                <input type="hidden" name="product_id" value="<?php echo esc_attr( $post->ID ); ?>" />
                                <input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $post->ID ); ?>" />

                            <?php } else { ?>
                                <p class="stock out-of-stock"><?php _e( 'This product is currently out of stock and unavailable.', 'woocommerce' ); ?></p>
                            <?php } ?>

                            </td>
                            </form>

                            </tr>

                    <?php 
                    } 
                    } 

                    ?>


        <?php

        function find_valid_variations() {
            global $product;
        if ( $product->get_id() == 330 ) {


            $variations = $product->get_available_variations();
            //$attributes = $product->get_attributes();
            $new_variants = array();

          /* Show only the variations listed below */
            foreach( $variations as $variation ) {
         if ( $variation["variation_id"] == 971 || $variation["variation_id"] == 958 || $variation["variation_id"] == 945 || $variation["variation_id"] == 422 || $variation["variation_id"] == 412 || $variation["variation_id"] == 386 || $variation["variation_id"] == 358 ) {

                $valid = true; 

                if( $valid )
                    $new_variants[] = $variation;
            }       
            }


        }
        elseif ( $product->get_id() == 216 ) {


            $variations = $product->get_available_variations();
            $new_variants = array();


            foreach( $variations as $variation ) {
         if ( $variation["variation_id"] == 1010 || $variation["variation_id"] == 997 || $variation["variation_id"] == 984 || $variation["variation_id"] == 321 || $variation["variation_id"] == 295 || $variation["variation_id"] == 267 || $variation["variation_id"] == 237 ) {

                $valid = true; 

                if( $valid )
                    $new_variants[] = $variation;
            }       
            }


        }

        else {


            $variations = $product->get_available_variations();
            $attributes = $product->get_attributes();
            $new_variants = array();


            foreach( $variations as $variation ) {

                $valid = true; 
                foreach( $attributes as $slug => $args ) {
                    if( array_key_exists("attribute_$slug", $variation['attributes']) && !empty($variation['attributes']["attribute_$slug"]) ) {
                        // Exists

                    } else {

                        $valid = false; 

                        foreach( explode( '|', $attributes[$slug]['value']) as $attribute ) {
                            $attribute = trim( $attribute );
                            $new_variant = $variation;
                            $new_variant['attributes']["attribute_$slug"] = $attribute;
                            $new_variants[] = $new_variant;

                        }

                    }
                }

                if( $valid )
                    $new_variants[] = $variation;

            }
        } 
            return $new_variants;
        }           

        add_filter( 'woocommerce_variable_add_to_cart', 'show_variable_products_list', 10, 2 );


        ?>

I am able to add the radio values to cart & order but not able to do anything with file upload.

Please take a look:

    add_action("woocommerce_before_add_to_cart_button", "upload_logo", 9);
    function upload_logo(){
        ?>
        <div>
            <p>Want to add Logo? <input type="checkbox" id="showHide"  onclick="myFunction()"><b>Tick</b></p>

    <p id="hiddenInputs" style="display:none">
            <label for="radio_field">
                Where you want the logo?
                <input type="radio" name="radio_field" checked="checked" value="Front Side"> Front Side
                <input type="radio" name="radio_field" value="Back Side"> Back Side
                <input type="radio" name="radio_field" value="Both Side"> Both Side
            </label> <br />

            <label for="file_field">
                Upload logo: <input type="file" name="file_field" value="">
            </label> <br />
    </p>
    </div>


    <script>
    function myFunction() {
        var checkboxToShowInputs = document.getElementById("showHide");
        var showInputs = document.getElementById("hiddenInputs");
        if (checkboxToShowInputs.checked == true){
            showInputs.style.display = "block";
        } else {
           showInputs.style.display = "none";
        }
    }
    </script>

        <?php
    }

    /* Add File custom data to the cart item */

    function file_upload_add_cart_item_data( $cart_item, $product_id ){

        if( isset( $_POST['file_field'] ) ) {
            $cart_item['logo_upload'] = $_POST['file_field'];
        }

        return $cart_item;

    }
    add_filter( 'woocommerce_add_cart_item_data', 'file_upload_add_cart_item_data', 10, 2 );

     /* Add Radio custom data to the cart item */
     // Stores the custom field value in Cart object
    add_action( 'woocommerce_add_cart_item_data', 'save_custom_product_field_data', 10, 2 );
    function save_custom_product_field_data( $cart_item, $product_id ) {
        if( isset( $_REQUEST['radio_field'] ) ) {
            $cart_item[ 'side_radio' ] = $_REQUEST['radio_field'];
            // below statement make sure every add to cart action as unique line item
            $cart_item['unique_key'] = md5( microtime().rand() );
            WC()->session->set( 'my_order_data', $_REQUEST['radio_field'] );
        }
        return $cart_item;
    }


    /* Load File cart data from session */

    function file_upload_get_cart_item_from_session( $cart_item, $values ) {

        if ( isset( $values['logo_upload'] ) ){
            $cart_item['logo_upload'] = $values['logo_upload'];
        }

        return $cart_item;

    }
    add_filter( 'woocommerce_get_cart_item_from_session', 'file_upload_get_cart_item_from_session', 20, 2 );


    /* Load Radio cart data from session */

    function radio_get_cart_item_from_session( $cart_item, $values ) {

        if ( isset( $values['side_radio'] ) ){
            $cart_item['side_radio'] = $values['side_radio'];
        }

        return $cart_item;

    }
    add_filter( 'woocommerce_get_cart_item_from_session', 'radio_get_cart_item_from_session', 20, 2 );


    /* Add File meta to order item */

    function file_upload_add_order_item_meta( $item_id, $values ) {

        if ( ! empty( $values['logo_upload'] ) ) {
            woocommerce_add_order_item_meta( $item_id, 'logo_upload', $values['logo_upload'] );           
        }
    }
    add_action( 'woocommerce_add_order_item_meta', 'file_upload_add_order_item_meta', 10, 2 );

    /* Add Radio meta to order item */

    function radio_add_order_item_meta( $item_id, $values ) {

        if ( ! empty( $values['side_radio'] ) ) {
            woocommerce_add_order_item_meta( $item_id, 'side_radio', $values['side_radio'] );           
        }
    }
    add_action( 'woocommerce_add_order_item_meta', 'radio_add_order_item_meta', 10, 2 );


    /* Get File item data to display in cart */

    function file_upload_get_item_data( $other_data, $cart_item ) {

        if ( ! empty ( $cart_item['logo_upload'] ) ){

            $other_data[] = array(
                'name' => __( 'Logo ', 'woocommerce' ),
                'value' =>  $cart_item['logo_upload']
            );

        }

        return $other_data;

    }
    add_filter( 'woocommerce_get_item_data', 'file_upload_get_item_data', 10, 2 );

    /* Get Radio item data to display in cart */

    function radio_get_item_data( $other_data, $cart_item ) {

        if ( ! empty ( $cart_item['side_radio'] ) ){

            $other_data[] = array(
                'name' => __( 'Side ', 'woocommerce' ),
                'value' =>  $cart_item['side_radio']
            );

        }

        return $other_data;

    }
    add_filter( 'woocommerce_get_item_data', 'radio_get_item_data', 10, 2 );


    /* Show File field in order overview */

    function file_upload_order_item_product( $cart_item, $order_item ){

        if( isset( $order_item['logo_upload'] ) ){
            $cart_item_meta['logo_upload'] = $order_item['logo_upload'];
        }

        return $cart_item;

    }
    add_filter( 'woocommerce_order_item_product', 'file_upload_order_item_product', 10, 2 );


    /* Show Radio field in order overview */

    function radio_order_item_product( $cart_item, $order_item ){

        if( isset( $order_item['side_radio'] ) ){
            $cart_item_meta['side_radio'] = $order_item['side_radio'];
        }

        return $cart_item;

    }
    add_filter( 'woocommerce_order_item_product', 'radio_order_item_product', 10, 2 );


    /* Add the File Upload field to order emails */ 

    function file_upload_email_order_meta_fields( $fields ) { 
        $fields['custom_field'] = __( 'Logo ', 'woocommerce' ); 
        return $fields; 
    } 
    add_filter('woocommerce_email_order_meta_fields', 'file_upload_email_order_meta_fields');

    /* Add the Radio field to order emails */ 

    function radio_email_order_meta_fields( $fields ) { 
        $fields['custom_field'] = __( 'Side ', 'woocommerce' ); 
        return $fields; 
    } 
    add_filter('woocommerce_email_order_meta_fields', 'radio_email_order_meta_fields');

Here's the AJAX PHP

        function ajax_add_to_cart_script() {
      wp_enqueue_script( 'add-to-cart-wh_ajax', plugins_url() . '/wh-page-ajax-add-to-cart/js/add-to-cart-wh.js', array('jquery'), '', true );

    }
    add_action( 'wp_enqueue_scripts', 'ajax_add_to_cart_script',99 );

    add_action( 'wp_ajax_woocommerce_add_to_cart_wh_sh', 'woocommerce_add_to_cart_wh_sh_callback' );
    add_action( 'wp_ajax_nopriv_woocommerce_add_to_cart_wh_sh', 'woocommerce_add_to_cart_wh_sh_callback' );

    function woocommerce_add_to_cart_wh_sh_callback() {

        ob_start();

        $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
        $quantity = empty( $_POST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_POST['quantity'] );
        $variation_id = $_POST['variation_id'];
        $variation  = $_POST['variation'];          
        $letter = $_POST['_letter'];
        $message = $_POST['_message'];              
        $radio = $_POST['radio_field'];     
        //$file = $_POST['file_field'];
        $file = $_FILES['id_proof'];;       
        $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $quantity, $cart_item_data, $letter, $message, $radio, $file );

        if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $letter, $message, $radio, $file ) ) {
            do_action( 'woocommerce_ajax_added_to_cart', $product_id );
            if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) {
                wc_add_to_cart_message( $product_id );
            }

            // Return fragments
            WC_AJAX::get_refreshed_fragments();
        }  else {
            $this->json_headers();

            // If there was an error adding to the cart, redirect to the product page to show any errors
            $data = array(
                'error' => true,
                'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id )
                );
            echo json_encode( $data );
        }
        die();
    }  

And here's the edited js

         /* AJAX Add to Cart Button */
    jQuery(function($) {

        // wc_add_to_cart_params is required to continue, ensure the object exists
        if (typeof wc_add_to_cart_params === 'undefined')
            return false;

        // Ajax add to cart
        $(document).on('click', '.variations_form .wh-btn', function(e) {

            e.preventDefault();

            $variation_form = $(this).closest('.variations_form');
            var var_id = $variation_form.find('input[name=variation_id]').val();
            var product_id = $variation_form.find('input[name=product_id]').val();
            var quantity = $variation_form.find('input[name=quantity]').val();              
            var letter = $variation_form.find('input[name=_wholesale_letter]').val();
            var message = $variation_form.find('input[name=_wholesale_message]').val();
            var rad = $variation_form.find('input[name=radio_field]:checked').val();
            var file = $variation_form.find('input[name=file_field]').val();
            //var file = $variation_form.find('input[name=file_field]').files[0].path;

            //attributes = [];
            $('.ajaxerrors').remove();
            var item = {},
                check = true;

            variations = $variation_form.find('select[name^=attribute]');

            /* Updated code to work with radio button - mantish - WC Variations Radio Buttons - 8manos */
            if (!variations.length) {
                variations = $variation_form.find('[name^=attribute]:checked');
            }

            /* Backup Code for getting input variable */
            if (!variations.length) {
                variations = $variation_form.find('input[name^=attribute]');
            }

            variations.each(function() {

                var $this = $(this),
                    attributeName = $this.attr('name'),
                    attributevalue = $this.val(),
                    index,
                    attributeTaxName;

                $this.removeClass('has-error');

                if (attributevalue.length === 0) {
                    index = attributeName.lastIndexOf('_');
                    attributeTaxName = attributeName.substring(index + 1);

                    $this
                        //.css( 'border', '1px solid red' )
                        .addClass('required has-error')
                        //.addClass( 'barizi-class' )
                        .before('<div class="ajaxerrors"><p>OH No Please select ' + attributeTaxName + '</p></div>')

                    //check = false;
                } else {
                    item[attributeName] = attributevalue;
                }


            });

            if (!check) {
                return false;
            }

            /* Validate for All the input Message field */

            var itemMessages = {},
                checkmsg = true;
            messages = $variation_form.find('input[name=_message');


            messages.each(function() {

                var $this = $(this),
                    attributeName = $this.attr('name'),
                    attributevalue = $this.val(),
                    index,
                    attributeTaxName;

                $this.removeClass('required wh-error');

                if (attributevalue.length === 0) {
                    index = attributeName.lastIndexOf('_');
                    attributeTaxName = attributeName.substring(index + 1);

                    $this
                        .removeClass('wh-input')
                        .addClass('required wh-error')                              
                        .before('<div class="ajaxerrors"><p><span style="font-weight: bold;">REQUIRED!</span> Please Type Some Text or Number.</p></div>')

                    //checkmsg = false;
                } else {
                    itemMessages[attributeName] = attributevalue;
                    $this.addClass('wh-input');
                }


            });

            if (!checkmsg) {
                return false;
            }


            /* Validate One Letter Input Field */
            var itemLetter = {},
                checkltr = true;
            letterOne = $variation_form.find('input[name=_letter]');


            letterOne.each(function() {

                var $this = $(this),
                    attributeName = $this.attr('name'),
                    attributevalue = $this.val(),
                    index,
                    attributeTaxName;

                $this.removeClass('required wh-error');

                if (attributevalue.length === 0) {
                    index = attributeName.lastIndexOf('_');
                    attributeTaxName = attributeName.substring(index + 1);

                    $this
                       /* .css({
                        'border': '2px solid #a94442', 
                        'box-shadow': 'inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483'                            
                        })*/
                        .removeClass('wh-input')
                        .addClass('required wh-error')                          
                        .before('<div class="ajaxerrors"><p><span style="font-weight: bold;">REQUIRED!</span> Please Type 1 Letter or Number.</p></div>')

                    //checkmsg = false;
                } else {
                    itemLetter[attributeName] = attributevalue;
                    $this.addClass('wh-input');
                }


            });

            if (!checkltr) {
                return false;
            }


           //item = JSON.stringify(item);
            //alert(item);
            //return false;

            // AJAX add to cart request

            var $thisbutton = $(this);

            if ($thisbutton.is('.variations_form .wh-btn')) {

                $thisbutton.removeClass('added');
                $thisbutton.addClass('loading');
                $thisbutton.attr("disabled", "disabled");


                var data = {
                    action: 'woocommerce_add_to_cart_wh_sh',
                    product_id: product_id,
                    quantity: quantity,
                    variation_id: var_id,
                    variation: item,                        
                    _letter: letter,
                    _message: message,
                    radio_field: rad,
            file_field: file
                };

                $.each($thisbutton.data(), function(key, value) {
                    data[key] = value;
                });

                // Trigger event
                $('body').trigger('adding_to_cart', [$thisbutton, data]);

                // Ajax action
                $.post(wc_add_to_cart_params.ajax_url.toString().replace('%%endpoint%%', 'add_to_cart'), data, function(response) {

                        if (!response) {
                            return;
                        }

                        var this_page = window.location.toString();

                        this_page = this_page.replace('add-to-cart', 'added-to-cart');

                        if (response.error && response.product_url) {
                            window.location = response.product_url;
                            return;
                        }

                        if (wc_add_to_cart_params.cart_redirect_after_add === 'yes') {

                            window.location = wc_add_to_cart_params.cart_url;
                            return;

                        } else {

                            $thisbutton.removeClass('loading');

                            var fragments = response.fragments;
                            var cart_hash = response.cart_hash;

                            // Block fragments class
                            if (fragments) {
                                $.each(fragments, function(key) {
                                    $(key).addClass('updating');
                                });
                            }

                            // Block widgets and fragments
                            $('.shop_table.cart, .updating, .cart_totals').fadeTo('400', '0.6').block({
                                message: null,
                                overlayCSS: {
                                    opacity: 0.6
                                }
                            });

                            // Changes button classes
                            $thisbutton.addClass('added');

                            // View cart text
                            /*  if ( ! wc_add_to_cart_params.is_cart && $thisbutton.parent().find( '.added_to_cart' ).size() === 0 ) {
                                    $thisbutton.after( ' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
                                        wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>' );
                                }

                            // View cart text
                            if (!wc_add_to_cart_params.is_cart && $variation_form.find('.added_to_cart').length === 0) {
                                $thisbutton.after(' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
                                    wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>');
                            }
                             */

                            // Replace fragments
                            if (fragments) {
                                $.each(fragments, function(key, value) {
                                    $(key).replaceWith(value);
                                });
                            }

                            // Unblock
                            $('.widget_shopping_cart, .updating').stop(true).css('opacity', '1').unblock();

                            // Cart page elements
                            $('.shop_table.cart').load(this_page + ' .shop_table.cart:eq(0) > *', function() {

                                $('.shop_table.cart').stop(true).css('opacity', '1').unblock();

                                $(document.body).trigger('cart_page_refreshed');
                            });

                            $('.cart_totals').load(this_page + ' .cart_totals:eq(0) > *', function() {
                                $('.cart_totals').stop(true).css('opacity', '1').unblock();
                            });

                            // Trigger event so themes can refresh other areas
                            $(document.body).trigger('added_to_cart', [fragments, cart_hash, $thisbutton]);
                        }
                    })
                    .done(function(response) {
                        if ($variation_form.find('.added_to_cart').length === 0) {
                            $thisbutton.after(' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
                                wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>');
                        }

                        $thisbutton.removeAttr("disabled", "disabled");                         
                        $thisbutton.removeClass('failed')

                        var quantity = $variation_form.find('input[name=quantity]').val("1");
                        var letter = $variation_form.find('input[name=_letter]').val("");
                        var message = $variation_form.find('input[name=_message]').val("");
                        var rad = $variation_form.find('input[name=radio_field]').val("Front Side");
                    })
                    .fail(function(response) {
                        setTimeout(function() {
                            $thisbutton.removeClass('loading');
                            $thisbutton.removeAttr("disabled", "disabled");
                        }, 2000);
                        $thisbutton.addClass('failed');
                    })

                return false;

            } else {
                return true;
            }

        });

    });

This page is only accessible to certain users, so it has different input fields, price than the single product page counterpart. Client don't like this page to be refreshed so I had to add AJAX, with the little knowledge I have. Now it's getting more complicated so please help me out.


Solution 1:

Update 2021 - Still works perfectly on last WooCommerce version (5.1.x).

In your actual code, there is many mistakes as:

  • Repetitive hooked functions using the same hook, that need to be merged instead.
  • Deprecated hooked functions.
  • Not useful or not needed hooked functions.
  • Wrong or missing code related to file upload

Here is your revisited code (much more lighter, compact and complete):

// Display additional product fields (+ jQuery code)
add_action( 'woocommerce_before_add_to_cart_button', 'display_additional_product_fields', 9 );
function display_additional_product_fields(){
    // Array of radio button options
    $options = array( __("Front Side"), __("Back Side"), __("Both Sides") );
    // Temporary styles
    ?>
    <style>
    .upload-logo a.button { padding: .3em .75em !important; }
    .upload-logo a.button.on { background-color: #CC0000 !important; color: #FFFFFF !important; }
    .upload-logo p span { display:inline-block; padding:0 8px 0 4px; }
    </style><?php
    // Html output ?>
    <div class="upload-logo">
        <p><strong><?php _e( "Add a Logo option"); ?>: </strong>
            <a href="#" class="button"><?php _e( "Yes" ); ?></a>
            <input type="hidden" name="upload_active" value="">
        </p>
        <div id="hidden-inputs" style="display:none">
            <p><label for="radio_field"><?php

            echo __( "Where you want the logo?" ) . ' <br>';

            // Loop though each $options array
            foreach( $options as $key => $option ) {
                $atts = $key == 0 ? 'name="side_field" checked="checked"' : 'name="side_field"'; ?>
                <input type="radio" <?php echo $atts; ?> value="<?php echo $option; ?>"><span> <?php echo $option . '</span> ';
            }
            ?>
            </label></p>
            <p><label for="file_field"><?php echo __("Upload logo") . ': '; ?>
                <input type='file' name='image' accept='image/*'>
            </label></p>
        </div>
    </div><?php
    // Javascript (jQuery) ?>
    <script type="text/javascript">
    jQuery( function($){
        var a = '.upload-logo',         b = a+' a.button',
            c = a+' #hidden-inputs',    d = a+' input[type=hidden]';

        $(b).click(function(e){
            e.preventDefault();
            if( ! $(this).hasClass('on') ) {
                $(this).addClass('on');
                $(c).show();
                $(d).val('1');
            } else {
                $(this).removeClass('on');
                $(c).hide('fast');
                $(d).val('');
            }
        });
    });
    </script>
    <?php
}

// @ ===> Manage the file upload <=== @
// Add custom fields data as the cart item custom data 
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_fields_data_as_custom_cart_item_data', 10, 2 );
function add_custom_fields_data_as_custom_cart_item_data( $cart_item, $product_id ){
    if( isset($_POST['upload_active']) && $_POST['upload_active'] && isset($_FILES['image']) ) {
        $upload = wp_upload_bits( $_FILES['image']['name'], null, file_get_contents( $_FILES['image']['tmp_name'] ) );

        $filetype = wp_check_filetype( basename( $upload['file'] ), null );

        $upload_dir = wp_upload_dir();

        $upl_base_url = is_ssl() ? str_replace('http://', 'https://', $upload_dir['baseurl']) : $upload_dir['baseurl'];

        $base_name = basename( $upload['file'] );

        $cart_item['custom_file'] = array(
            'guid'      => $upl_base_url .'/'. _wp_relative_upload_path( $upload['file'] ),
            'file_type' => $filetype['type'],
            'file_name' => $base_name,
            'title'     => preg_replace('/\.[^.]+$/', '', $base_name ),
            'side'      => isset( $_POST['side_field'] ) ? sanitize_text_field( $_POST['side_field'] ) : '',
            'key'       => md5( microtime().rand() ),
        );
    }
    return $cart_item;
}

// Display custom cart item data in cart
add_filter( 'woocommerce_get_item_data', 'display_custom_item_data', 10, 2 );
function display_custom_item_data( $cart_item_data, $cart_item ) {
    if ( isset( $cart_item['custom_file']['title'] ) ){
        $cart_item_data[] = array(
            'name' => __( 'Logo', 'woocommerce' ),
            'value' =>  $cart_item['custom_file']['title']
        );
    }

    if ( isset( $cart_item['custom_file']['side'] ) ){
        $cart_item_data[] = array(
            'name' => __( 'Side', 'woocommerce' ),
            'value' =>  $cart_item['custom_file']['side']
        );
    }
    return $cart_item_data;
}

// Save and display Logo data in orders and email notifications (everywhere)
add_action( 'woocommerce_checkout_create_order_line_item', 'custom_field_update_order_item_meta', 20, 4 );
function custom_field_update_order_item_meta( $item, $cart_item_key, $values, $order ) {
    if ( isset( $values['custom_file'] ) ){
        $item->update_meta_data( __('Logo'),  $values['custom_file']['title'] );
        $item->update_meta_data( __('Side'),  $values['custom_file']['side'] );
        $item->update_meta_data( '_logo_file_data',  $values['custom_file'] );
    }
}

// Display a linked button + the link of the logo file in backend
add_action( 'woocommerce_after_order_itemmeta', 'backend_logo_link_after_order_itemmeta', 20, 3 );
function backend_logo_link_after_order_itemmeta( $item_id, $item, $product ) {
    // Only in backend for order line items (avoiding errors)
    if( is_admin() && $item->is_type('line_item') && $item->get_meta('_logo_file_data') ){
        $file_data = $item->get_meta( '_logo_file_data' );
        echo '<p><a href="'.$file_data['guid'].'" target="_blank" class="button">'.__("Open Logo") . '</a></p>';
        echo '<p>Link: <textarea type="text" class="input-text" readonly>'.$file_data['guid'].'</textarea></p>';
    }
}

This code goes in functions.php file of your active child theme (or active theme).

Tested in Woocommerce version 3.4.x and working with normal products (from all types)


Frontend: orders display (and email notifications):

enter image description here

Backend (Admin): Display on orders edit pages:

enter image description here