`
* grid scaffold. `$wrapper_attrs` are merged with the block's wrapper
* attributes via `get_block_wrapper_attributes()`.
*
* Trust contract: callers are responsible for ensuring `$inner` and
* `$before_list` contain only safe, escaped HTML — typically composed
* from the section helpers below, never from raw schema/request input.
*
* @param array $wrapper_attrs Attributes for the outer ``.
* @param string $list_class Class attribute for the inner `
`.
* @param string $inner Markup placed inside the `
` (template + SSR rows + empty state).
* @param string $before_list Markup placed between `` and `
',
get_block_wrapper_attributes( $wrapper_attrs ),
$before_list,
esc_attr( $list_class ),
$inner
);
}
/**
* Wrap `$row_inner_markup` in a `` element that
* iAPI uses to render new rows. `$row_inner_markup` is the inner HTML
* for the `
` — everything between `
` and `
`.
*
* Trust contract: caller is responsible for ensuring `$row_inner_markup`
* contains only safe, escaped HTML.
*
* @param string $row_inner_markup Inner markup for the `
`.
* @return string
*/
public static function render_each_template( string $row_inner_markup ): string {
return sprintf(
'
%2$s
',
esc_attr( self::ROW_CLASS ),
$row_inner_markup
);
}
/**
* Wrap `$row_inner_markup` in an SSR `
` element
* seeded with the per-row iAPI context derived from `$item`. iAPI's
* hydration treats this as a no-op diff against the `` if
* the inner markup matches.
*
* Trust contract: caller is responsible for ensuring `$row_inner_markup`
* contains only safe, escaped HTML.
*
* @param array $item Schema-shape item.
* @param string $row_inner_markup Inner markup for the `
`.
* @return string
*/
public static function render_each_child( array $item, string $row_inner_markup ): string {
$context = array( 'listItem' => $item );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_interactivity_data_wp_context() returns a safely-encoded attribute pair; $row_inner_markup is composed of escaped fragments from the section helpers below.
return sprintf(
'
%3$s
',
esc_attr( self::ROW_CLASS ),
wp_interactivity_data_wp_context( $context ),
$row_inner_markup
);
}
/**
* Render the image + title + price triplet for the template-mode row
* (no static attrs; bindings only). Identical between consumer blocks.
*
* @return string
*/
public static function render_template_common_row(): string {
ob_start();
?>
` that the block toggles on once `state.isEmpty`
* flips. `$start_hidden = true` makes SSR ship with `hidden` so the
* message doesn't flash for shoppers whose list is being populated
* client-side. `$start_hidden = false` is for blocks (e.g. Wishlist)
* where the message should show on first paint when the list is empty.
*
* @param string $message Visible empty-state message.
* @param string $css_class Class attribute for the `
`.
* @param bool $start_hidden Whether the `
` should be `hidden` on first paint.
* @return string
*/
public static function render_empty_state( string $message, string $css_class, bool $start_hidden = true ): string {
return sprintf(
'
%3$s
',
esc_attr( $css_class ),
$start_hidden ? ' hidden' : '',
esc_html( $message )
);
}
/**
* Render the iAPI store-notices region used by the row-level error
* banners. Mirrors `AddToCartWithOptions::render_interactivity_notices_region()`
* — keep in sync if the shape changes.
*
* @param string $wrapper_class Class attribute for the outer `
`.
* @return string
*/
public static function render_interactivity_notices_region( string $wrapper_class ): string {
ob_start();
?>
';
}
/**
* Markup for the empty-star icon. Mirrors `starEmpty` from
* `@wordpress/icons`, inlined here so SSR first paint matches what JS
* renders after hydration. `currentColor` lets the surrounding button
* drive the fill.
*
* @return string
*/
public static function get_star_empty_svg(): string {
return '';
}
/**
* Markup for the filled-star icon. Mirrors `starFilled` from
* `@wordpress/icons`, inlined here so SSR first paint matches what JS
* renders after hydration. `currentColor` lets the surrounding button
* drive the fill.
*
* @return string
*/
public static function get_star_filled_svg(): string {
return '';
}
/**
* Build a comma-separated variation label like "Color: Blue, Size: M".
*
* @param array $item Schema-shape item.
* @return string
*/
public static function get_variation_label( array $item ): string {
$variation = $item['variation'] ?? array();
if ( ! is_array( $variation ) || empty( $variation ) ) {
return '';
}
$parts = array();
foreach ( $variation as $entry ) {
if ( ! is_array( $entry ) ) {
continue;
}
$attribute = isset( $entry['attribute'] ) ? html_entity_decode( (string) $entry['attribute'], ENT_QUOTES, 'UTF-8' ) : '';
$value = isset( $entry['value'] ) ? html_entity_decode( (string) $entry['value'], ENT_QUOTES, 'UTF-8' ) : '';
if ( '' === $attribute && '' === $value ) {
continue;
}
$parts[] = $attribute . ': ' . $value;
}
return implode( ', ', $parts );
}
}