skip to Main Content

Since 1 week, I’m trying to do writing custom PHP & jQuery code to upload additional variation images to each variation. I wrote some code, but it doesn’t work properly.

With the code below, I am:

  1. not able to delete selected images.
  2. not able to see the images that i upload each variation (on the front-end section)

Any help is highly appreciated.

function custom_allow_multiple_variation_images( $loop, $variation_data, $variation ) {
    $variation_id = $variation->ID;
    $field_name = 'variation_image';
    $attachment_ids = get_post_meta( $variation_id, $field_name, true );

    echo '<div class="upload_variation_image">';
    echo '<h4>Fotoğraf</h4>';
    echo '<input type="hidden" name="' . $field_name . '[' . $loop . ']" id="' . $field_name . '" class="upload_image" value="' . esc_attr( implode( ',', (array) $attachment_ids ) ) . '" />';
    echo '<button class="upload_image_button button">Upload Image</button>';

    if ( $attachment_ids ) {
        $attachment_ids = explode( ',', $attachment_ids );
        foreach ( $attachment_ids as $attachment_id ) {
            $image_src = wp_get_attachment_image_src( $attachment_id, 'thumbnail' );
            if ( $image_src ) {
                echo '<div class="uploaded_image_wrapper">';
                echo '<img src="' . esc_url( $image_src[0] ) . '" alt="Uploaded Image" />';
                echo '<span class="delete_variation_image" data-attachment_id="' . $attachment_id . '">Sil</span>';
                echo '</div>';
            }
        }
    }

    echo '</div>';
}

add_action( 'woocommerce_variation_options', 'custom_allow_multiple_variation_images', 10, 3 );


function custom_save_variation_image( $variation_id ) {
    $field_name = 'variation_image';
    $attachment_ids = isset( $_POST[ $field_name ] ) ? array_map( 'absint', explode( ',', wc_clean( $_POST[ $field_name ][0] ) ) ) : array();

    update_post_meta( $variation_id, $field_name, implode( ',', $attachment_ids ) );
}

add_action( 'woocommerce_save_product_variation', 'custom_save_variation_image', 10, 1 );


add_action( 'woocommerce_save_product_variation', 'custom_save_variation_image', 10, 1 );


function custom_variation_image_scripts() {
    ?>
    <script>
        jQuery(document).ready(function($) {
            
            function custom_add_variation_image($wrapper) {
                var file_frame;
                if (file_frame) {
                    file_frame.open();
                    return;
                }
                file_frame = wp.media.frames.file_frame = wp.media({
                    title: 'Variation Image Select',
                    button: {
                        text: 'Add Additional Image'
                    },
                    multiple: true
                });

                file_frame.on('select', function() {
                    var attachment_ids = [];
                    var selection = file_frame.state().get('selection');
                    selection.map(function(attachment) {
                        attachment = attachment.toJSON();
                        attachment_ids.push(attachment.id);
                    });
                    $wrapper.find('.upload_image').val(attachment_ids.join(','));
                    $wrapper.find('.uploaded_image_wrapper').remove();
                    attachment_ids.forEach(function(attachment_id) {
                        var image_url = wp.media.attachment(attachment_id).get('url');
                        $wrapper.append('<div class="uploaded_image_wrapper"><img src="' + image_url + '" alt="Uploaded Image" /><span class="delete_variation_image" data-attachment_id="' + attachment_id + '">Sil</span></div>');
                    });
                    $wrapper.find('.upload_image').trigger('change'); // Trigger change event when selecting a variation image
                });
                file_frame.open();
            }

           
            function custom_remove_variation_image($wrapper, attachment_id) {
                var attachment_ids = $wrapper.find('.upload_image').val().split(',');
                var index = attachment_ids.indexOf(attachment_id);
                if (index !== -1) {
                    attachment_ids.splice(index, 1);
                    $wrapper.find('.upload_image').val(attachment_ids.join(','));
                }
                $wrapper.find('.uploaded_image_wrapper[data-attachment_id="' + attachment_id + '"]').remove();
                $wrapper.find('.upload_image').trigger('change'); // Trigger change event when removing a variation image
            }

            
            function custom_detect_variation_changes() {
                $('form.cart').on('change', '.variation-control', function() {
                    $('.single_add_to_cart_button').prop('disabled', false);
                });

                // When a variation image changes, enable "Add to Cart" button
                $('form.cart').on('change', '.upload_image', function() {
                    $('.single_add_to_cart_button').prop('disabled', false);
                });
            }

            // Medya yükleyici olaylarını ekle
            $(document).on('click', '.upload_image_button', function(e) {
                e.preventDefault();
                custom_add_variation_image($(this).closest('.upload_variation_image'));
            });

            $(document).on('click', '.delete_variation_image', function() {
                var attachment_id = $(this).data('attachment_id');
                custom_remove_variation_image($(this).closest('.upload_variation_image'), attachment_id);
            });

            
            custom_detect_variation_changes();
        });
    </script>
    <style>
        .uploaded_image_wrapper {
            margin: 10px 0;
            display: inline-block;
        }

        .uploaded_image_wrapper img {
            max-width: 100px;
            height: auto;
            margin-right: 10px;
        }

        .delete_variation_image {
            cursor: pointer;
            color: #a00;
        }
    </style>
    <?php
}

add_action( 'admin_footer', 'custom_variation_image_scripts' );

After @LoicTheAztec answer i can add variation images from variation tab but nothing display on the product page. You can see the image below about my latest situation.enter image description here

2

Answers


  1. As I have already implemented something similar in a custom plugin… Find below a simplified and compact working code version.

    PHP

    add_action( 'woocommerce_variation_options', 'add_additional_variation_image_ids', 10, 3 );
    function add_additional_variation_image_ids( $loop, $variation_data, $variation ) {
        $variation_id     = $variation->ID;
        $variation_object = wc_get_product($variation_id);
    
        $attachment_ids   = $variation_object->get_meta( 'additional_img_ids' ); // Get Attachments Ids
        $attachment_ids   = empty($attachment_ids) ? array( 0 => '' ) : $attachment_ids;
        $count            = count($attachment_ids);
        $placeholder      = esc_url( wc_placeholder_img_src() );
    
        $upload_img_txt   = esc_html__( 'Upload an image', 'woocommerce' );
        $remove_img_txt   = esc_html__( 'Remove this image', 'woocommerce' );
        $add_txt          = esc_html__( 'Add', 'woocommerce' );
        $remove_txt       = esc_html__( 'Remove', 'woocommerce' );
    
        echo '<div class="custom-uploads">
        <h4>' . __( 'Additional images:', 'woocommerce' ) . '</h4>';
    
        // Loop through each existing attachment image ID
        foreach( $attachment_ids as $index => $image_id ) {
            // Add an Image field
            printf('<div class="image-box"><p class="form-row form-row-wide upload_image">
                <a href="#" class="upload_image_button tips %s" data-tip="%s" rel="%s"><img src="%s" />
                <input type="hidden" name="additional_img_ids-%s-%s" class="upload_image_id" value="%s" /></a>
                <p></div>', 
                $image_id ? 'remove' : '', $image_id ? $remove_img_txt : $upload_img_txt, $variation_id,
                $image_id ? esc_url( wp_get_attachment_thumb_url( $image_id ) ) : $placeholder, $loop, $index, $image_id
            );
        }
        // Add the buttons
        printf('<div class="buttons-box"><p>
            <button type="button" class="add-slot" data-loop="%d">%s</button>
            <button type="button" class="remove-slot" data-loop="%d"%s>%s</button>
            <input type="hidden" name="slot-index-%d" value="%s" /><input type="hidden" name="ph-img-%s" value="%s" /></a><p></div>', 
            $loop, $add_txt, $loop, $count == 1 ? ' style="display:none;"' : '', $remove_txt, $loop, $count, $loop, $placeholder
        );
        echo '</div>';
    }
    
    add_action( 'woocommerce_admin_process_variation_object', 'save_additional_variation_image_ids', 10, 2 );
    function save_additional_variation_image_ids( $variation, $i ) 
    {
        if ( isset($_POST["slot-index-{$i}"]) && $_POST["slot-index-{$i}"] > 1 ) {
            $attachment_ids = array(); // Initialize
    
            // Loop through each posted attachment Id for the current variation
            for( $k = 0; $k < $_POST["slot-index-{$i}"]; $k++ ) {
                if ( isset($_POST["additional_img_ids-{$i}-{$k}"]) && ! empty($_POST["additional_img_ids-{$i}-{$k}"]) ) {
                    $attachment_ids[$k] =esc_attr($_POST["additional_img_ids-{$i}-{$k}"]); // Set it in the array
                }
            }
            if( ! empty($attachment_ids) ) {
                $variation->update_meta_data( 'additional_img_ids', $attachment_ids ); // save
            }
        }
    }
    

    JavaScript / jQuery (embedded in a function, can be enqueued from an external file):

    add_action( 'admin_footer', 'additional_variation_image_js' );
    function additional_variation_image_js() {
        global $pagenow, $typenow;
    
    if( in_array( $pagenow, array('post.php', 'post-new.php') ) && $typenow === 'product' ) :
    ?>
    <script>
        jQuery(function($) {
            $('body').on('click', '.add-slot', function(){
                const parent      = $(this).closest('.custom-uploads'),
                    loop          = $(this).data('loop');
                
                var lastImageBox  = $(parent).find('.image-box:last'),
                    hiddenInput   = $('[name=slot-index-'+loop+']'),
                    index         = parseInt(hiddenInput.val()),
                    inputNameUpd  = 'additional_img_ids-'+loop+'-'+index,
                    inputPropsUpd = {'name': inputNameUpd, 'value': null}
                    placeholder   = $('[name=ph-img-'+loop+']').val(),
                    clonedImgBox  = lastImageBox.clone().insertBefore('.buttons-box'); // Insert a clone
    
                clonedImgBox.find('.upload_image_id').prop(inputPropsUpd);
                clonedImgBox.find('img').prop('src', placeholder);
                clonedImgBox.find('a').removeClass('remove');
                hiddenInput.val(index+1);
    
                if ( index == 1 ) {
                    $(this).parent().find('.remove-slot').show();
                }
            }).on('click', '.remove-slot', function(){
                const parent     = $(this).closest('.custom-uploads'),
                    loop         = $(this).data('loop');
                    
                var lastImageBox = $(parent).find('.image-box:last'),
                    hiddenInput  = $('[name=slot-index-'+loop+']'),
                    index        = parseInt(hiddenInput.val());
    
                lastImageBox.remove();
                hiddenInput.val(index-1);
                
                if ( index == 2 ) {
                    $(this).hide();
                }
            });
        });
    </script>
    <?php
    endif;
    }
    

    CSS (embedded in a function, can be enqueued from an external file):

    add_action( 'admin_head', 'additional_variation_image_css', 9999 );
    function additional_variation_image_css() {
        global $pagenow, $typenow;
    
        if( in_array( $pagenow, array('post.php', 'post-new.php') ) && $typenow === 'product' ) :
        ?>
        <style>
            .custom-uploads .image-box,
            .custom-uploads .buttons-box {
                float:left;
                width:76px;
            }
    
            .custom-uploads .upload_image,
            .buttons-box p {
                margin-top:0;
                width:auto;
                float:none;
            }
            .custom-uploads a {
                margin-right:12px;
            }
            .add-slot {
                margin:6px 0;
            }
        </style>
        <?php
        endif;
    }
    

    Code goes in functions.php file of your child theme or in a plugin file. Tested and works.

    You will get something like:

    enter image description here

    So now, additional images can be added or removed from product variations with ease… They are saved for each variation as an array of attachment Ids using a unique custom field.

    Login or Signup to reply.
  2. I inserted the code into the functions.php file but I don’t see any image in the frontend. do I have to write some css code? Thank you.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search