Duplicated pic in thumbnail gallery in Woocommerce

2019-03-02 01:56发布

问题:

I'm building a Woocommerce site.

In the Shop grid overview, I'm showing the Featured Image of each product (see link). This Featured image will be cropped to maintain the same image ratio in the Shop Grid.

In the Single Product page, I managed to hide the Featured Image, and make the first of the thumbnails appear in big (see link).

I did so with the following code:

<div class="images">

    <?php

            $imgid = $product->get_gallery_attachment_ids();

    ?>

    <a href="<?php echo wp_get_attachment_url( $imgid[0] ); ?>"
       class="woocommerce-main-image zoom first" 
       rel="lightbox[product-gallery]">
            <img src="<?php echo wp_get_attachment_url( $imgid[0] ); ?>" alt="">
    </a>

    <?php do_action( 'woocommerce_product_thumbnails' ); ?>

</div>

<script>
    jQuery('.thumbnails.columns-3 a:first-child').hide()
</script>

The first part will find the first image in the gallery array and show it in big size (class woocommerce-main-image zoom first) while linking to the lightbox.

Then I call the thumbnails, and I hide the first one using jQuery to avoid a duplicate (first big size image and first thumb are the same).

The problem now is that in the Lightbox, the first image will appear duplicated, as it exists two times in the array, the first one I call in big, and the one from the thumbs array.

Any tips on how to not show the image twice in the lightbox?

Someone mentioned that I should filter the following function, but as of now I don't know how to do that.

public function get_gallery_attachment_ids() {
    return apply_filters( 'woocommerce_product_gallery_attachment_ids', array_filter( (array) explode( ',', $this->product_image_gallery ) ), $this );
}

回答1:

I think that using Multiple Post Thumbnails is the easiest solution. It is exactly for displaying different featured images in different locations.

Option #1: Multiple Post Thumbnails

You would install the plugin and then add the following to your theme's functions.php. It isn't 100% tested so there may be a stray typo or something. Full documentation is here.

// register the new thumbnail
function so_31835142_register_extra_thumbnail() {
    if (class_exists('MultiPostThumbnails')) {
        new MultiPostThumbnails(
            array(
                'label' => __('Product Loop Image', 'your-theme'),
                'id' => 'product-loop-image',
                'post_type' => 'product'
            )
        );
    }
}
add_action( 'after_setup_theme', 'so_31835142_register_extra_thumbnail' );

// remove the existing loop thumbnail
function so_31835142_swap_loop_product_thumbnail(){
    if (class_exists('MultiPostThumbnails')) {
        remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
        add_action( 'woocommerce_before_shop_loop_item_title', 'so_31835142_loop_product_thumbnail', 10 );
    }
}
add_action( 'woocommerce_before_shop_loop_item, 'so_31835142_swap_loop_product_thumbnail' );

// Display the Secondary Thumbnail
function so_31835142_loop_product_thumbnail(){
    global $product;
    $thumbnail = MultiPostThumbnails::get_post_thumbnail(
        'product',
        'product-loop-image',
        $product->id,
        'shop_catalog'
    );

    if ( $thumbnail ) {
        return $thumbnail;
    } elseif ( wc_placeholder_img_src() ) {
        return wc_placeholder_img( $size );
    }
}

Then to use it, you'd set "Product Loop Image" the same way you traditionally set the "featured image". And this new image would be used in the loop.

Option #2: Template Overrides

But as an alternative, if you insist, you can write a custom single-product/product-image.php template and put it in your theme's woocommerce templates folder.

In this alternative we will only show images from the image gallery on the single product page, $product->get_gallery_attachment_ids(), and we will use a basic PHP loop and counter system to display the images differently depending on where they are in the loop. IE. the first image will display as the post thumbnail used to display and the remaining items will display as thumbs.

This section I have tested, so it should (in theory) be good to go.

<?php
/**
 * Single Product Image
 *
 * @author      WooThemes
 * @package     WooCommerce/Templates
 * @version     2.0.14
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

global $post, $woocommerce, $product;

?>
<div class="images">

<?php
$attachment_ids = $product->get_gallery_attachment_ids();

if ( $attachment_ids ) {
    $loop       = 0;
    $columns    = apply_filters( 'woocommerce_product_thumbnails_columns', 3 );
    $attachment_count = count( $attachment_ids );

    foreach ( $attachment_ids as $attachment_id ) {

        // here's your first image
        if( $loop === 0 ){

            $image_title    = esc_attr( get_the_title( $attachment_id ) );
            $image_caption  = get_post( $attachment_id )->post_excerpt;
            $image_link     = wp_get_attachment_url( $attachment_id );
            $image          = wp_get_attachment_image( $attachment_id, apply_filters( 'single_product_large_thumbnail_size', 'shop_single' ), null, array(
                'title' => $image_title,
                'alt'   => $image_title
            ) );

            if ( $attachment_count > 0 ) {
                $gallery = '[product-gallery]';
            } else {
                $gallery = '';
            }

            echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<a href="%s" itemprop="image" class="woocommerce-main-image zoom" title="%s" data-rel="prettyPhoto' . $gallery . '">%s</a>', $image_link, $image_caption, $image ), $post->ID );

        // resume the thumbnails for the rest
        } else {

            // open the thumbnails div
            if( $loop === 1 ) { ?> 
                <div class="thumbnails <?php echo 'columns-' . $columns; ?>">
            <?php }

                $classes = array( 'zoom' );

                if ( $loop == 0 || $loop % $columns == 0 )
                    $classes[] = 'first';

                if ( ( $loop + 1 ) % $columns == 0 )
                    $classes[] = 'last';

                $image_link = wp_get_attachment_url( $attachment_id );

                if ( ! $image_link )
                    continue;

                $image_title    = esc_attr( get_the_title( $attachment_id ) );
                $image_caption  = esc_attr( get_post_field( 'post_excerpt', $attachment_id ) );

                $image       = wp_get_attachment_image( $attachment_id, apply_filters( 'single_product_small_thumbnail_size', 'shop_thumbnail' ), 0, $attr = array(
                    'title' => $image_title,
                    'alt'   => $image_title
                    ) );

                $image_class = esc_attr( implode( ' ', $classes ) );

                echo apply_filters( 'woocommerce_single_product_image_thumbnail_html', sprintf( '<a href="%s" class="%s" title="%s" data-rel="prettyPhoto[product-gallery]"  data-id="'. $attachment_id. '">%s</a>', $image_link, $image_class, $image_caption, $image ), $attachment_id, $post->ID, $image_class );

            // close the thumbnails div
            if( $loop === $attachment_count ) { ?> 
                </div>
            <?php }

        }

        $loop++;
    }

    ?>
    <?php
} else {

    echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<img src="%s" alt="%s" />', wc_placeholder_img_src(), __( 'Placeholder', 'woocommerce' ) ), $post->ID );

}
?>

</div>