ProductGalleryPager.php
<?php
namespace Automattic\WooCommerce\Blocks\BlockTypes;
use Automattic\WooCommerce\Blocks\Utils\ProductGalleryUtils;
/**
* ProductGalleryPager class.
*/
class ProductGalleryPager extends AbstractBlock {
/**
* Block name.
*
* @var string
*/
protected $block_name = 'product-gallery-pager';
/**
* It isn't necessary register block assets because it is a server side block.
*/
protected function register_block_type_assets() {
return null;
}
/**
* Get the frontend style handle for this block type.
*
* @return null
*/
protected function get_block_type_style() {
return null;
}
/**
* Register the context
*
* @return string[]
*/
protected function get_block_type_uses_context() {
return [ 'productGalleryClientId', 'pagerDisplayMode', 'thumbnailsNumberOfThumbnails', 'postId' ];
}
/**
* Include and render the block.
*
* @param array $attributes Block attributes. Default empty array.
* @param string $content Block content. Default empty string.
* @param WP_Block $block Block instance.
* @return string Rendered block type output.
*/
protected function render( $attributes, $content, $block ) {
$pager_display_mode = $block->context['pagerDisplayMode'] ?? '';
if ( 'off' === $pager_display_mode ) {
return null;
}
$number_of_thumbnails = $block->context['thumbnailsNumberOfThumbnails'] ?? 0;
$classname = $attributes['className'] ?? '';
$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => trim( $classname ) ) );
$post_id = $block->context['postId'] ?? '';
$product = wc_get_product( $post_id );
if ( $product ) {
$product_gallery_images_ids = ProductGalleryUtils::get_product_gallery_image_ids( $product );
$number_of_available_images = count( $product_gallery_images_ids );
$number_of_thumbnails = $number_of_thumbnails < $number_of_available_images ? $number_of_thumbnails : $number_of_available_images;
if ( $number_of_thumbnails > 1 ) {
$html = $this->render_pager( $product_gallery_images_ids, $pager_display_mode, $number_of_thumbnails );
return sprintf(
'<div %1$s data-wc-interactive=\'%3$s\'>
%2$s
</div>',
$wrapper_attributes,
$html,
wp_json_encode( array( 'namespace' => 'woocommerce/product-gallery' ) )
);
}
return '';
}
}
/**
* Renders the pager for the product gallery.
*
* @param array $product_gallery_images_ids An array of image IDs for the product gallery.
* @param string $pager_display_mode The display mode for the pager.
* @param int $number_of_thumbnails The number of thumbnails to display in the pager.
* @return string|null The rendered pager HTML, or null if the pager should not be displayed.
*/
private function render_pager( $product_gallery_images_ids, $pager_display_mode, $number_of_thumbnails ) {
if ( $number_of_thumbnails < 2 || 'off' === $pager_display_mode ) {
return null;
}
return $this->render_pager_pages( $product_gallery_images_ids, $number_of_thumbnails, $pager_display_mode );
}
/**
* Renders the pager pages for the product gallery.
*
* @param array $product_gallery_images_ids An array of image IDs for the product gallery.
* @param int $number_of_thumbnails The number of thumbnails to display in the pager.
* @param string $pager_display_mode The display mode for the pager. Defaults to 'dots'.
* @return string The rendered pager pages HTML.
*/
private function render_pager_pages( $product_gallery_images_ids, $number_of_thumbnails, $pager_display_mode = 'dots' ) {
$html = '';
foreach ( $product_gallery_images_ids as $key => $product_gallery_image_id ) {
if ( $key >= $number_of_thumbnails ) {
break;
}
$is_first_pager_item = 0 === $key;
$pager_item = sprintf(
'<li class="wc-block-product-gallery-pager__pager-item %2$s"><button aria-pressed="%3$s" data-wc-bind--aria-pressed="state.pagerButtonPressed">%1$s</button></li>',
'dots' === $pager_display_mode ? $this->get_dot_icon( $is_first_pager_item ) : $key + 1,
$is_first_pager_item ? 'wc-block-product-gallery-pager__pager-item--is-active' : '',
$is_first_pager_item ? 'true' : 'false'
);
$p = new \WP_HTML_Tag_Processor( $pager_item );
if ( $p->next_tag() ) {
$p->set_attribute(
'data-wc-context',
wp_json_encode(
array( 'imageId' => strval( $product_gallery_image_id ) ),
)
);
$p->set_attribute(
'data-wc-on--click',
'actions.selectImage'
);
$p->set_attribute(
'data-wc-class--wc-block-product-gallery-pager__pager-item--is-active',
'state.isSelected'
);
$html .= $p->get_updated_html();
}
}
return sprintf(
'<ul class="wc-block-product-gallery-pager__pager">
%1$s
</ul>',
$html
);
}
/**
* Generates an SVG dot icon with the specified opacity.
*
* @param bool $is_active Whether the dot icon should be in active state. Defaults to false.
* @return string The SVG dot icon HTML.
*/
private function get_dot_icon( $is_active = false ) {
$initial_opacity = $is_active ? '1' : '0.2';
return sprintf(
'<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="6" cy="6" r="6" fill="black" fill-opacity="%1$s" data-wc-bind--fill-opacity="state.pagerDotFillOpacity" />
</svg>',
$initial_opacity
);
}
}