WooCommerce Code Reference

ProductImage.php

Source code

<?php
namespace Automattic\WooCommerce\Blocks\BlockTypes;

use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;

/**
 * ProductImage class.
 */
class ProductImage extends AbstractBlock {

	/**
	 * Block name.
	 *
	 * @var string
	 */
	protected $block_name = 'product-image';

	/**
	 * API version name.
	 *
	 * @var string
	 */
	protected $api_version = '2';

	/**
	 * Get block supports. Shared with the frontend.
	 * IMPORTANT: If you change anything here, make sure to update the JS file too.
	 *
	 * @return array
	 */
	protected function get_block_type_supports() {
		return array(
			'__experimentalBorder'   =>
			array(
				'radius'                          => true,
				'__experimentalSkipSerialization' => true,
			),
			'typography'             =>
			array(
				'fontSize'                        => true,
				'__experimentalSkipSerialization' => true,
			),
			'spacing'                =>
			array(
				'margin'                          => true,
				'__experimentalSkipSerialization' => true,
			),
			'__experimentalSelector' => '.wc-block-components-product-image',
		);
	}

	/**
	 * It is necessary to register and enqueues assets during the render phase because we want to load assets only if the block has the content.
	 */
	protected function register_block_type_assets() {
		return null;
	}

	/**
	 * Register the context.
	 */
	protected function get_block_type_uses_context() {
		return [ 'query', 'queryId', 'postId' ];
	}

	/**
	 * Get the block's attributes.
	 *
	 * @param array $attributes Block attributes. Default empty array.
	 * @return array  Block attributes merged with defaults.
	 */
	private function parse_attributes( $attributes ) {
		// These should match what's set in JS `registerBlockType`.
		$defaults = array(
			'showProductLink'         => true,
			'showSaleBadge'           => true,
			'saleBadgeAlign'          => 'right',
			'imageSizing'             => 'single',
			'productId'               => 'number',
			'isDescendentOfQueryLoop' => 'false',
			'scale'                   => 'cover',
		);

		return wp_parse_args( $attributes, $defaults );
	}

	/**
	 * Render on Sale Badge.
	 *
	 * @param \WC_Product $product Product object.
	 * @param array       $attributes Attributes.
	 * @return string
	 */
	private function render_on_sale_badge( $product, $attributes ) {
		if ( ! $product->is_on_sale() || false === $attributes['showSaleBadge'] ) {
			return '';
		}

		$font_size = StyleAttributesUtils::get_font_size_class_and_style( $attributes );

		$on_sale_badge = sprintf(
			'
		<div class="wc-block-components-product-sale-badge wc-block-components-product-sale-badge--align-%s wc-block-grid__product-onsale %s" style="%s">
			<span aria-hidden="true">%s</span>
			<span class="screen-reader-text">Product on sale</span>
		</div>
	',
			esc_attr( $attributes['saleBadgeAlign'] ),
			isset( $font_size['class'] ) ? esc_attr( $font_size['class'] ) : '',
			isset( $font_size['style'] ) ? esc_attr( $font_size['style'] ) : '',
			esc_html__( 'Sale', 'woocommerce' )
		);
		return $on_sale_badge;
	}

	/**
	 * Render anchor.
	 *
	 * @param \WC_Product $product       Product object.
	 * @param string      $on_sale_badge Return value from $render_image.
	 * @param string      $product_image Return value from $render_on_sale_badge.
	 * @param array       $attributes    Attributes.
	 * @return string
	 */
	private function render_anchor( $product, $on_sale_badge, $product_image, $attributes ) {
		$product_permalink = $product->get_permalink();

		$pointer_events = false === $attributes['showProductLink'] ? 'pointer-events: none;' : '';

		return sprintf(
			'<a href="%1$s" style="%2$s">%3$s %4$s</a>',
			$product_permalink,
			$pointer_events,
			$on_sale_badge,
			$product_image
		);
	}



	/**
	 * Render Image.
	 *
	 * @param \WC_Product $product Product object.
	 * @param array       $attributes Parsed attributes.
	 * @return string
	 */
	private function render_image( $product, $attributes ) {
		$image_size = 'single' === $attributes['imageSizing'] ? 'woocommerce_single' : 'woocommerce_thumbnail';

		$image_style = 'max-width:none;';
		if ( ! empty( $attributes['height'] ) ) {
			$image_style .= sprintf( 'height:%s;', $attributes['height'] );
		}
		if ( ! empty( $attributes['width'] ) ) {
			$image_style .= sprintf( 'width:%s;', $attributes['width'] );
		}
		if ( ! empty( $attributes['scale'] ) ) {
			$image_style .= sprintf( 'object-fit:%s;', $attributes['scale'] );
		}
		if ( ! empty( $attributes['aspectRatio'] ) ) {
			$image_style .= sprintf( 'aspect-ratio:%s;', $attributes['aspectRatio'] );
		}

		return $product->get_image(
			$image_size,
			array(
				'alt'         => $product->get_title(),
				'data-testid' => 'product-image',
				'style'       => $image_style,
			)
		);
	}

	/**
	 * Extra data passed through from server to client for block.
	 *
	 * @param array $attributes  Any attributes that currently are available from the block.
	 *                           Note, this will be empty in the editor context when the block is
	 *                           not in the post content on editor load.
	 */
	protected function enqueue_data( array $attributes = [] ) {
		$this->asset_data_registry->add( 'isBlockThemeEnabled', wc_current_theme_is_fse_theme() );
	}


	/**
	 * 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 ) {
		if ( ! empty( $content ) ) {
			parent::register_block_type_assets();
			$this->register_chunk_translations( [ $this->block_name ] );
			return $content;
		}
		$parsed_attributes = $this->parse_attributes( $attributes );

		$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );

		$post_id = isset( $block->context['postId'] ) ? $block->context['postId'] : '';
		$product = wc_get_product( $post_id );

		if ( $product ) {
			return sprintf(
				'<div class="wc-block-components-product-image wc-block-grid__product-image %1$s" style="%2$s">
					%3$s
				</div>',
				esc_attr( $classes_and_styles['classes'] ),
				esc_attr( $classes_and_styles['styles'] ),
				$this->render_anchor(
					$product,
					$this->render_on_sale_badge( $product, $parsed_attributes ),
					$this->render_image( $product, $parsed_attributes ),
					$parsed_attributes
				)
			);

		}
	}
}