programmatically serve different images for shop and category pages in woocommerce

Viewed 37

Hi – is it possible to serve a different image, than the predefined woocommerce thumbnails for the shop and category pages in a programmatical manner? For instance a different image that shows a product detail? Without digging into the code, my guess is to add to the product-image, another field labeled product-detail-image. In this field i can choose, from the media library, the detail image for a given product. Then assign a custom-size in functions.php and finally fetch the image in the appropriate place with something like this:

$product->get_image('detail_img_size');

Thanks for any hint.

1 Answers

It is possible with the following steps:

  1. add an additional image meta box, source (applause for this):

     //in functions.php or plugin
     add_action( 'add_meta_boxes', 'detail_image_add_metabox' );
     function detail_image_add_metabox () {
         add_meta_box( 'listingimagediv', __( 'Detail-Bild', 'text-domain' ), 'detail_image_metabox', 'product', 'side', 'low');//post, page, product
     }
    
     function detail_image_metabox ( $post ) {
         global $content_width, $_wp_additional_image_sizes;
    
         $image_id = get_post_meta( $post->ID, '_detail_image_id', true );
    
         $old_content_width = $content_width;
         $content_width = 254;
    
         if ( $image_id && get_post( $image_id ) ) {
    
             if ( ! isset( $_wp_additional_image_sizes['post-thumbnail'] ) ) {
                 $thumbnail_html = wp_get_attachment_image( $image_id, array( $content_width, $content_width ) );
             } else {
                 $thumbnail_html = wp_get_attachment_image( $image_id, 'post-thumbnail' );
             }
    
             if ( ! empty( $thumbnail_html ) ) {
                 $content = $thumbnail_html;
                 $content .= '<p class="hide-if-no-js"><a href="javascript:;" id="remove_listing_image_button" >' . esc_html__( 'Entferne das Detail-Bild', 'text-domain' ) . '</a></p>';
                 $content .= '<input type="hidden" id="upload_listing_image" name="_product_detail_image" value="' . esc_attr( $image_id ) . '" />';
             }
    
             $content_width = $old_content_width;
         } else {
    
             $content = '<img src="" style="width:' . esc_attr( $content_width ) . 'px;height:auto;border:0;display:none;" />';
             $content .= '<p class="hide-if-no-js"><a title="' . esc_attr__( 'wähle das Detail-Bild', 'text-domain' ) . '" href="javascript:;" id="upload_listing_image_button" id="set-listing-image" data-uploader_title="' . esc_attr__( 'Wähle ein Detail-Bild', 'text-domain' ) . '" data-uploader_button_text="' . esc_attr__( 'wähle das Detail-Bild', 'text-domain' ) . '">' . esc_html__( 'wähle das Detail-Bild', 'text-domain' ) . '</a></p>';
             $content .= '<input type="hidden" id="upload_listing_image" name="_product_detail_image" value="" />';
    
         }
         echo $content;
     }
    
     add_action( 'save_post_product', 'detail_image_save', 10, 1 );
     function detail_image_save ( $post_id ) {
         //check if the image is set and not empty
         if( isset( $_POST['_product_detail_image'] ) && !empty($_POST['_product_detail_image']) ) {
             $image_id = (int) $_POST['_product_detail_image'];
             echo $image_id;
             update_post_meta( $post_id, '_detail_image_id', $image_id );
         } else {
             //else delete the post meta
             delete_post_meta($post_id, '_detail_image_id');
         }
     }
    

This creates an image meta box on the product edit screen.

  1. add a script that communicates with the media library:

     jQuery(document).ready(function($) {
    
         // Uploading files
         var file_frame;
    
         jQuery.fn.upload_listing_image = function( button ) {
             var button_id = button.attr('id');
             var field_id = button_id.replace( '_button', '' );
    
             // If the media frame already exists, reopen it.
             if ( file_frame ) {
               file_frame.open();
               return;
             }
    
             // Create the media frame.
             file_frame = wp.media.frames.file_frame = wp.media({
               title: jQuery( this ).data( 'uploader_title' ),
               button: {
                 text: jQuery( this ).data( 'uploader_button_text' ),
               },
               multiple: false
             });
    
             // When an image is selected, run a callback.
             file_frame.on( 'select', function() {
               var attachment = file_frame.state().get('selection').first().toJSON();
               jQuery("#"+field_id).val(attachment.id);
               jQuery("#listingimagediv img").attr('src',attachment.url);
               jQuery( '#listingimagediv img' ).show();
               jQuery( '#' + button_id ).attr( 'id', 'remove_listing_image_button' );
               jQuery( '#remove_listing_image_button' ).text( 'enterne das Detail-Bild' );
             });
    
             // Finally, open the modal
             file_frame.open();
         };
    
         jQuery('#listingimagediv').on( 'click', '#upload_listing_image_button', function( event ) {
             event.preventDefault();
             jQuery.fn.upload_listing_image( jQuery(this) );
         });
    
         jQuery('#listingimagediv').on( 'click', '#remove_listing_image_button', function( event ) {
             event.preventDefault();
             jQuery( '#upload_listing_image' ).val( '' );
             jQuery( '#listingimagediv img' ).attr( 'src', '' );
             jQuery( '#listingimagediv img' ).hide();
             jQuery( this ).attr( 'id', 'upload_listing_image_button' );
             jQuery( '#upload_listing_image_button' ).text( 'wähle das Detail-Bild' );
         });
    
     });
    
  2. enqueue the script in functions.php or plugin:

     //load script only for product admin
     function load_admin_metabox_script() {
    
     $current_screen = get_current_screen();
    
     if ( $current_screen->post_type === 'product' )  {
         wp_enqueue_script( 'zcustom_js', get_template_directory_uri() . '/js/image_meta_box.js', array( 'jquery' ));
     }
    
     }
     add_action( 'admin_enqueue_scripts', 'load_admin_metabox_script' );
    
  3. assign images to the loop running for the shop and category pages:

     //in functions.php or plugin
     remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
     add_action( 'woocommerce_before_shop_loop_item_title', 'custom_loop_product_detail_thumbnail', 10 );
     function custom_loop_product_detail_thumbnail() {
         global $product;
         $id = $product->get_id();
         $size = 'woocommerce_thumbnail';
         $detail_img_id = get_post_meta( $id , '_detail_image_id', true );
         //check if image id is available and not empty
         if (isset($detail_img_id) && !empty($detail_img_id)){
             $detail_img = wp_get_attachment_image( $detail_img_id, $size );
             echo $detail_img;
             //else fallback to the original product image
         } else {
             $image_size = apply_filters( 'single_product_archive_thumbnail_size', $size );
             echo $product ? $product->get_image( $image_size ) : '';
         }
     }
    

The same is applicable for the product widget. Just alter the template content-widget-product.php by overriding it in your child theme.

    <!-- get detail images-->
    <?php $id = $product->get_id();
          //i use a custom size
          $size = 'my_small_size';
          $detail_img_id = get_post_meta( $id , '_detail_image_id', true );
          if (isset($detail_img_id) && !empty($detail_img_id)){
                $detail_img = wp_get_attachment_image( $detail_img_id, $size );
                echo $detail_img;
            } else {
                //if detail images are not available use the original product image
                echo $product->get_image('my_small_size'); // PHPCS:Ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            }
    ?>

This method allows to use a different set of product images for the shop and category pages. It may enhance the visibility of important product features and adds visual variety, at least it does it for my project.

Related