Automattic\WooCommerce\Blocks\BlockTypes

ProductFilterChips{}finalWC 1.0└─ AbstractBlock

Product Filter: Chips Block.

No Hooks.

Usage

$ProductFilterChips = new ProductFilterChips();
// use class methods

Methods

  1. protected enqueue_data( array $attributes = array() )
  2. private get_item_swatch_style( array $item )
  3. private static has_visual_swatches( array $items )
  4. protected render( $attributes, $content, $block )

ProductFilterChips{} code WC 10.9.4

<?php
final class ProductFilterChips extends AbstractBlock {

	use EnableBlockJsonAssetsTrait;

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

	/**
	 * 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.
	 * @return void
	 */
	protected function enqueue_data( array $attributes = array() ) {
		parent::enqueue_data( $attributes );

		if ( is_admin() ) {
			$this->asset_data_registry->add( 'globalStylesColors', wp_get_global_styles( array( 'color' ) ) );
		}
	}

	/**
	 * Render the block.
	 *
	 * @param array     $attributes Block attributes.
	 * @param string    $content    Block content.
	 * @param \WP_Block $block      Block instance.
	 * @return string Rendered block type output.
	 */
	protected function render( $attributes, $content, $block ) {
		if ( empty( $block->context['woocommerce/selectableItems'] ) ) {
			return '';
		}

		$block_context   = $block->context['woocommerce/selectableItems'];
		$items           = is_array( $block_context['items'] ?? null ) ? $block_context['items'] : array();
		$store_namespace = $block_context['storeNamespace'] ?? 'woocommerce/product-filters';
		$display_limit   = 'woocommerce/product-filters' === $store_namespace ? 15 : 30;
		$classes         = '';
		$style           = '';

		$tags = new \WP_HTML_Tag_Processor( $content );
		if ( $tags->next_tag( array( 'class_name' => 'wc-block-product-filter-chips' ) ) ) {
			$classes = $tags->get_attribute( 'class' );
			$style   = $tags->get_attribute( 'style' );
		}

		$wrapper_attributes = array(
			'data-wp-interactive'  => 'woocommerce/product-filter-chips',
			'data-wp-init--colors' => 'callbacks.initColors',
			'data-wp-context'      => (string) wp_json_encode(
				array(
					'storeNamespace' => $store_namespace,
					'displayLimit'   => $display_limit,
					'isExpanded'     => false,
				),
				JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
			),
			'class'                => esc_attr( $classes ),
		);

		if ( ! empty( $style ) ) {
			// Styles generated by Supports API doesn't include semicolon at the end.
			$wrapper_attributes['style'] = esc_attr( $style ) . ';';
		}

		$attribute_id       = $block->context['woocommerce/attributeId'] ?? '';
		$has_external_label = is_string( $attribute_id ) && '' !== $attribute_id;

		if ( $has_external_label ) {
			$wrapper_attributes['role']            = 'single' === $block_context['selectionMode'] ? 'radiogroup' : 'group';
			$wrapper_attributes['aria-labelledby'] = esc_attr( $attribute_id . '_label' );
		}

		$first_items             = array_slice( $items, 0, $display_limit, true );
		$overflow_items          = array_slice( $items, $display_limit );
		$overflow_selected_items = array_filter( $overflow_items, fn( $item ) => is_array( $item ) && ! empty( $item['selected'] ) );
		$visible_items           = array_merge( $first_items, $overflow_selected_items );
		$hidden_count            = count( $items ) - count( $visible_items );

		$first_item          = reset( $items );
		$show_counts         = is_array( $first_item ) && array_key_exists( 'count', $first_item );
		$has_visual_swatches = self::has_visual_swatches( $items );
		$button_role         = 'single' === $block_context['selectionMode'] ? 'radio' : 'checkbox';

		if ( $has_visual_swatches && is_string( $classes ) && ! str_contains( $classes, 'is-style-swatch' ) ) {
			$classes                    .= ' is-style-swatch';
			$wrapper_attributes['class'] = esc_attr( $classes );
		}

		ob_start();
		?>
		<div <?php echo get_block_wrapper_attributes( $wrapper_attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
			<fieldset class="wc-block-product-filter-chips__fieldset">
				<?php if ( ! empty( $block_context['groupLabel'] ) && ! $has_external_label ) : ?>
					<legend class="screen-reader-text"><?php echo esc_html( $block_context['groupLabel'] ); ?></legend>
				<?php endif; ?>
				<div class="wc-block-product-filter-chips__items">
					<?php
					foreach ( $visible_items as $item ) :
						?>
						<button
							class="wc-block-product-filter-chips__item"
							type="button"
							role="<?php echo esc_attr( $button_role ); ?>"
							id="<?php echo esc_attr( $item['id'] ); ?>"
							<?php if ( ! empty( $item['ariaLabel'] ) ) : ?>
								aria-label="<?php echo esc_attr( $item['ariaLabel'] ); ?>"
							<?php endif; ?>
							<?php if ( $has_visual_swatches ) : ?>
								title="<?php echo esc_attr( $item['label'] ); ?>"
							<?php endif; ?>
							value="<?php echo esc_attr( $item['value'] ); ?>"
							aria-checked="<?php echo ! empty( $item['selected'] ) ? 'true' : 'false'; ?>"
							<?php disabled( ! empty( $item['disabled'] ) ); ?>
							data-wp-each-child
							<?php echo wp_interactivity_data_wp_context( array( 'item' => $item ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
							data-wp-bind--aria-checked="context.item.selected"
							data-wp-bind--disabled="context.item.disabled"
							data-wp-bind--hidden="context.item.hidden"
							data-wp-on--click="actions.toggle"
						>
							<span class="wc-block-product-filter-chips__label">
								<?php if ( $has_visual_swatches ) : ?>
									<?php
									$swatch_style = $this->get_item_swatch_style( $item );
									$has_visual   = '' !== $swatch_style;
									?>
									<span
										class="wc-block-product-filter-chips__swatch<?php echo ! $has_visual ? ' wc-block-product-filter-chips__swatch--no-color' : ''; ?>"
										<?php if ( $has_visual ) : ?>
											style="<?php echo esc_attr( $swatch_style ); ?>"
										<?php endif; ?>
										aria-hidden="true"
									></span>
								<?php endif; ?>
								<span class="wc-block-product-filter-chips__text">
									<?php echo esc_html( $item['label'] ); ?>
								</span>
								<?php if ( isset( $item['count'] ) ) : ?>
									<span class="wc-block-product-filter-chips__count">
										(<span data-wp-text="context.item.count"><?php echo esc_html( $item['count'] ); ?></span>)
									</span>
								<?php endif; ?>
							</span>
						</button>
					<?php endforeach; ?>
					<template
						data-wp-each--item="state.items"
						data-wp-each-key="context.item.id"
					>
						<button
							class="wc-block-product-filter-chips__item"
							type="button"
							role="<?php echo esc_attr( $button_role ); ?>"
							data-wp-bind--id="context.item.id"
							data-wp-bind--aria-label="context.item.ariaLabel"
							<?php if ( $has_visual_swatches ) : ?>
								data-wp-bind--title="context.item.label"
							<?php endif; ?>
							data-wp-bind--value="context.item.value"
							data-wp-bind--aria-checked="context.item.selected"
							data-wp-bind--disabled="context.item.disabled"
							data-wp-bind--hidden="context.item.hidden"
							data-wp-on--click="actions.toggle"
						>
							<span class="wc-block-product-filter-chips__label">
								<?php if ( $has_visual_swatches ) : ?>
									<span
										class="wc-block-product-filter-chips__swatch"
										data-wp-class--wc-block-product-filter-chips__swatch--no-color="woocommerce/product-filter-chips::state.swatchHidden"
										data-wp-bind--style="woocommerce/product-filter-chips::state.swatchStyle"
										aria-hidden="true"
									></span>
								<?php endif; ?>
								<span
									class="wc-block-product-filter-chips__text"
									data-wp-text="context.item.label"
								></span>
								<?php if ( $show_counts ) : ?>
									<span class="wc-block-product-filter-chips__count">
										(<span data-wp-text="context.item.count"></span>)
									</span>
								<?php endif; ?>
							</span>
						</button>
					</template>
				</div>
				<?php if ( $hidden_count > 0 ) : ?>
					<button
						type="button"
						class="wc-block-product-filter-chips__show-more"
						data-wp-on--click="actions.showAll"
						data-wp-bind--hidden="context.isExpanded"
					>
						<?php
						/* translators: %d: number of hidden items */
						echo esc_html( sprintf( __( '+%d more', 'woocommerce' ), $hidden_count ) );
						?>
					</button>
				<?php endif; ?>
			</fieldset>
		</div>
		<?php
		return ob_get_clean();
	}

	/**
	 * Check whether any item has visual swatch data.
	 *
	 * @param array $items Selectable items.
	 * @return bool
	 */
	private static function has_visual_swatches( array $items ): bool {
		foreach ( $items as $item ) {
			if ( is_array( $item ) && array_key_exists( 'visual', $item ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Build inline swatch style from item visual data.
	 *
	 * @param array $item Selectable item data.
	 * @return string
	 */
	private function get_item_swatch_style( array $item ): string {
		$visual = isset( $item['visual'] ) && is_array( $item['visual'] ) ? $item['visual'] : array();

		return VisualAttributeTermMeta::get_swatch_style( $visual );
	}
}