SavedForLater
extends AbstractBlock
in package
Saved for Later block.
Renders the shopper's "Saved for Later" list, wired to the shopper-lists
Store API endpoints via the shared woocommerce/shopper-lists iAPI store.
PHP prefetches the list so the first paint is already populated; JS then
takes over for adds, removes, and Move-to-cart.
The row markup (image, name, price, remove badge, variation overlay) is
shared with other shopper-list blocks via ShopperListRenderer. This
class composes those fragments and adds the bits that are unique to
Saved for Later: auto-injection via the Block Hooks API, the
hasShownItems empty-state gating, the per-row quantity span, and the
Move-to-cart action button.
Table of Contents
- LIST_SLUG = 'saved-for-later'
- The list slug this block renders. Constant — when additional list types ship as their own blocks (e.g. Wishlist), each one will hardcode its own slug.
- $asset_api : Api
- Instance of the asset API.
- $asset_data_registry : AssetDataRegistry
- Instance of the asset data registry.
- $block_name : string
- Block name.
- $enqueued_assets : bool
- Tracks if assets have been enqueued.
- $integration_registry : IntegrationRegistry
- Instance of the integration registry.
- $namespace : string
- Block namespace.
- __construct() : mixed
- Constructor.
- enqueue_editor_assets() : mixed
- Enqueue assets used for rendering the block in editor context.
- register_hooked_block() : array<string|int, mixed>
- Auto-inject this block after `woocommerce/cart`, scoped to the cart page.
- render_callback() : string
- The default render_callback for all blocks. This will ensure assets are enqueued just in time, then render the block (if applicable).
- set_hooked_block_attributes() : array<string|int, mixed>|null
- Seed a default heading inner block on the auto-injected block.
- enqueue_data() : mixed
- Data passed through from server to client for block.
- enqueue_scripts() : mixed
- Register/enqueue scripts used for this block on the frontend, during render.
- get_block_type() : string
- Get the block type.
- get_block_type_attributes() : array<string|int, mixed>
- Get block attributes.
- get_block_type_editor_script() : array<string|int, mixed>|string
- Get the editor script data for this block type.
- get_block_type_editor_style() : null
- Disable the editor style handle for this block type.
- get_block_type_render_callback() : callable|null
- Get the render callback for this block type.
- get_block_type_script() : null
- Get the frontend script handle for this block type.
- get_block_type_style() : null
- Get the frontend style handle for this block type.
- get_block_type_supports() : string
- Get the supports array for this block type.
- get_block_type_uses_context() : array<string|int, mixed>
- Get block usesContext.
- get_chunks_paths() : array<string|int, string>
- Generate an array of chunks paths for loading translation.
- get_full_block_name() : string
- Get the full block name, including namespace.
- get_routes_from_namespace() : array<string|int, mixed>
- Get routes from a REST API namespace.
- initialize() : void
- Initialize this block type.
- is_block_editor() : mixed
- Are we currently on the admin block editor screen?
- parse_render_callback_attributes() : array<string|int, mixed>
- Parses block attributes from the render_callback.
- register_block_type() : array<string|int, string>
- Registers the block type with WordPress.
- register_block_type_assets() : mixed
- Register script and style assets for the block type before it is registered.
- register_chunk_translations() : mixed
- Injects Chunk Translations into the page so translations work for lazy loaded components.
- render() : string
- Render the block.
- get_move_to_cart_label() : string
- Visible label for the move-to-cart action button, used by both the iAPI `<template>` and the SSR per-row markup.
- get_quantity_label_template() : string
- Sprintf template for the per-row quantity label. Used both by PHP SSR (`render_ssr_quantity()`) and by the JS-side getter (via `wp_interactivity_config`) so both paths produce the same string after `%d` interpolation.
- get_remove_label_template() : string
- Sprintf template for the per-row remove button's aria-label. Same dual use as the quantity template.
- prefetch_items() : array<int, array<string, mixed>>
- Prefetch the saved-for-later items via `rest_do_request()`. Logged-out users short-circuit to an empty list — the route requires authentication and we don't want to fire an API call that's only going to 401.
- render_empty_markup() : string
- Render the empty-state markup. Always present in the DOM so JS can toggle it on once the last item is removed. Initially hidden: SSR never shows the message, since `state.isEmpty` requires the JS-side `hasShownItems` context flag to flip first.
- render_header_markup() : string
- Wrap the inner-block content (heading + any future siblings) in an element whose visibility mirrors the empty-state gating: hidden when the shopper has never seen items in this session, revealed once `context.hasShownItems` flips to `true`. Returns an empty string when there's no content to wrap (e.g. merchant deleted the heading and saved), so we don't emit an empty `<div>`.
- render_item_markup() : string
- Render a single SSR item. Composes the shared image / name / price markup with the SFL-specific quantity span and Move-to-cart button.
- render_items_markup() : string
- Render the SSR markup for each item. JS will reconcile these via `data-wp-each-child` after hydration.
- render_ssr_move_to_cart() : string
- SSR-mode markup for the Move-to-cart action button. SFL-specific.
- render_ssr_quantity() : string
- SSR-mode markup for the quantity span. SFL-specific.
- render_template_markup() : string
- The `<template data-wp-each>` describing how each item is rendered on the client. Pre-rendered children sit alongside as `data-wp-each-child` elements so first paint is populated. Composes the shared row markup with Saved for Later's quantity span and Move-to-cart action button.
- render_template_move_to_cart() : string
- Template-mode markup for the Move-to-cart action button. SFL-specific.
- render_template_quantity() : string
- Template-mode markup for the quantity span. SFL-specific — Wishlist has no quantity column.
Constants
LIST_SLUG
The list slug this block renders. Constant — when additional list types ship as their own blocks (e.g. Wishlist), each one will hardcode its own slug.
private
mixed
LIST_SLUG
= 'saved-for-later'
Properties
$asset_api
Instance of the asset API.
protected
Api
$asset_api
$asset_data_registry
Instance of the asset data registry.
protected
AssetDataRegistry
$asset_data_registry
$block_name
Block name.
protected
string
$block_name
= 'saved-for-later'
$enqueued_assets
Tracks if assets have been enqueued.
protected
bool
$enqueued_assets
= false
$integration_registry
Instance of the integration registry.
protected
IntegrationRegistry
$integration_registry
$namespace
Block namespace.
protected
string
$namespace
= 'woocommerce'
Methods
__construct()
Constructor.
public
__construct(Api $asset_api, AssetDataRegistry $asset_data_registry, IntegrationRegistry $integration_registry[, string $block_name = '' ]) : mixed
Parameters
- $asset_api : Api
-
Instance of the asset API.
- $asset_data_registry : AssetDataRegistry
-
Instance of the asset data registry.
- $integration_registry : IntegrationRegistry
-
Instance of the integration registry.
- $block_name : string = ''
-
Optionally set block name during construct.
Return values
mixed —enqueue_editor_assets()
Enqueue assets used for rendering the block in editor context.
public
enqueue_editor_assets() : mixed
This is needed if a block is not yet within the post content--render and enqueue_assets may not have ran.
Return values
mixed —register_hooked_block()
Auto-inject this block after `woocommerce/cart`, scoped to the cart page.
public
register_hooked_block(array<string|int, mixed> $hooked_block_types, string $relative_position, string $anchor_block_type, array<string|int, mixed>|WP_Post|WP_Block_Template|null $context) : array<string|int, mixed>
Parameters
- $hooked_block_types : array<string|int, mixed>
-
Block names hooked at this position.
- $relative_position : string
-
Position of the insertion point.
- $anchor_block_type : string
-
Anchor block name.
- $context : array<string|int, mixed>|WP_Post|WP_Block_Template|null
-
Where the block is being embedded.
Return values
array<string|int, mixed> —render_callback()
The default render_callback for all blocks. This will ensure assets are enqueued just in time, then render the block (if applicable).
public
render_callback([array<string|int, mixed>|WP_Block $attributes = [] ][, string $content = '' ][, WP_Block|null $block = null ]) : string
Parameters
- $attributes : array<string|int, mixed>|WP_Block = []
-
Block attributes, or an instance of a WP_Block. Defaults to an empty array.
- $content : string = ''
-
Block content. Default empty string.
- $block : WP_Block|null = null
-
Block instance.
Return values
string — Rendered block type output.set_hooked_block_attributes()
Seed a default heading inner block on the auto-injected block.
public
set_hooked_block_attributes(array<string|int, mixed>|null $parsed_hooked_block, string $hooked_block_type, string $relative_position, array<string|int, mixed> $parsed_anchor_block) : array<string|int, mixed>|null
Parameters
- $parsed_hooked_block : array<string|int, mixed>|null
-
The parsed hooked block array, or null to suppress insertion.
- $hooked_block_type : string
-
The hooked block type name.
- $relative_position : string
-
Position of the insertion point.
- $parsed_anchor_block : array<string|int, mixed>
-
The anchor block, in parsed block array format.
Return values
array<string|int, mixed>|null —enqueue_data()
Data passed through from server to client for block.
protected
enqueue_data([array<string|int, mixed> $attributes = [] ]) : mixed
Parameters
- $attributes : array<string|int, mixed> = []
-
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 values
mixed —enqueue_scripts()
Register/enqueue scripts used for this block on the frontend, during render.
protected
enqueue_scripts([array<string|int, mixed> $attributes = [] ]) : mixed
Parameters
- $attributes : array<string|int, mixed> = []
-
Any attributes that currently are available from the block.
Return values
mixed —get_block_type()
Get the block type.
protected
get_block_type() : string
Tags
Return values
string —get_block_type_attributes()
Get block attributes.
protected
get_block_type_attributes() : array<string|int, mixed>
Return values
array<string|int, mixed> —get_block_type_editor_script()
Get the editor script data for this block type.
protected
get_block_type_editor_script([string $key = null ]) : array<string|int, mixed>|string
Parameters
- $key : string = null
-
Data to get, or default to everything.
Tags
Return values
array<string|int, mixed>|string —get_block_type_editor_style()
Disable the editor style handle for this block type.
protected
get_block_type_editor_style() : null
Return values
null —get_block_type_render_callback()
Get the render callback for this block type.
protected
get_block_type_render_callback() : callable|null
Dynamic blocks should return a callback, for example, return [ $this, 'render' ];
Tags
Return values
callable|null —get_block_type_script()
Get the frontend script handle for this block type.
protected
get_block_type_script([string|null $key = null ]) : null
Scripts are loaded via viewScriptModule in block.json.
Parameters
- $key : string|null = null
-
The key of the script to get.
Return values
null —get_block_type_style()
Get the frontend style handle for this block type.
protected
get_block_type_style() : null
Returning null lets WP use the style array from block.json, which
lists this block's own stylesheet plus the atomic
product-image / product-price / product-button stylesheets we
borrow class names from. We can't render those atomic blocks as
inner blocks (they rely on WP_Query / $post loop context, which
this block doesn't have — it hydrates from a Store API call), so
declaring them as style dependencies is the only way to get WP
to enqueue their CSS whenever Saved for Later renders.
Return values
null —get_block_type_supports()
Get the supports array for this block type.
protected
get_block_type_supports() : string
Tags
Return values
string —get_block_type_uses_context()
Get block usesContext.
protected
get_block_type_uses_context() : array<string|int, mixed>
Return values
array<string|int, mixed> —get_chunks_paths()
Generate an array of chunks paths for loading translation.
protected
get_chunks_paths(string $chunks_folder) : array<string|int, string>
Parameters
- $chunks_folder : string
-
The folder to iterate over.
Return values
array<string|int, string> — $chunks list of chunks to load.get_full_block_name()
Get the full block name, including namespace.
protected
get_full_block_name() : string
Return values
string —get_routes_from_namespace()
Get routes from a REST API namespace.
protected
get_routes_from_namespace(string $namespace) : array<string|int, mixed>
Parameters
- $namespace : string
-
Namespace to retrieve.
Return values
array<string|int, mixed> —initialize()
Initialize this block type.
protected
initialize() : void
Return values
void —is_block_editor()
Are we currently on the admin block editor screen?
protected
is_block_editor() : mixed
Return values
mixed —parse_render_callback_attributes()
Parses block attributes from the render_callback.
protected
parse_render_callback_attributes(array<string|int, mixed>|WP_Block $attributes) : array<string|int, mixed>
Parameters
- $attributes : array<string|int, mixed>|WP_Block
-
Block attributes, or an instance of a WP_Block. Defaults to an empty array.
Return values
array<string|int, mixed> —register_block_type()
Registers the block type with WordPress.
protected
register_block_type() : array<string|int, string>
Return values
array<string|int, string> — Chunks paths.register_block_type_assets()
Register script and style assets for the block type before it is registered.
protected
register_block_type_assets() : mixed
This registers the scripts; it does not enqueue them.
Return values
mixed —register_chunk_translations()
Injects Chunk Translations into the page so translations work for lazy loaded components.
protected
register_chunk_translations(array<string|int, string> $chunks) : mixed
The chunk names are defined when creating lazy loaded components using webpackChunkName.
Parameters
- $chunks : array<string|int, string>
-
Array of chunk names.
Return values
mixed —render()
Render the block.
protected
render(array<string|int, mixed> $attributes, string $content, WP_Block $block) : string
Parameters
- $attributes : array<string|int, mixed>
-
Block attributes.
- $content : string
-
Block content.
- $block : WP_Block
-
Block instance.
Return values
string — Rendered block type output.get_move_to_cart_label()
Visible label for the move-to-cart action button, used by both the iAPI `<template>` and the SSR per-row markup.
private
get_move_to_cart_label() : string
Return values
string —get_quantity_label_template()
Sprintf template for the per-row quantity label. Used both by PHP SSR (`render_ssr_quantity()`) and by the JS-side getter (via `wp_interactivity_config`) so both paths produce the same string after `%d` interpolation.
private
get_quantity_label_template() : string
Return values
string —get_remove_label_template()
Sprintf template for the per-row remove button's aria-label. Same dual use as the quantity template.
private
get_remove_label_template() : string
Return values
string —prefetch_items()
Prefetch the saved-for-later items via `rest_do_request()`. Logged-out users short-circuit to an empty list — the route requires authentication and we don't want to fire an API call that's only going to 401.
private
prefetch_items() : array<int, array<string, mixed>>
Return values
array<int, array<string, mixed>> — Items in the schema response shape.render_empty_markup()
Render the empty-state markup. Always present in the DOM so JS can toggle it on once the last item is removed. Initially hidden: SSR never shows the message, since `state.isEmpty` requires the JS-side `hasShownItems` context flag to flip first.
private
render_empty_markup() : string
Return values
string —render_header_markup()
Wrap the inner-block content (heading + any future siblings) in an element whose visibility mirrors the empty-state gating: hidden when the shopper has never seen items in this session, revealed once `context.hasShownItems` flips to `true`. Returns an empty string when there's no content to wrap (e.g. merchant deleted the heading and saved), so we don't emit an empty `<div>`.
private
render_header_markup(string $content, bool $is_empty) : string
Parameters
- $content : string
-
Rendered inner-block content (typically the heading HTML).
- $is_empty : bool
-
Whether the saved-for-later list is empty on initial paint.
Return values
string —render_item_markup()
Render a single SSR item. Composes the shared image / name / price markup with the SFL-specific quantity span and Move-to-cart button.
private
render_item_markup(array<string, mixed> $item) : string
Parameters
- $item : array<string, mixed>
-
Schema-shape item.
Return values
string —render_items_markup()
Render the SSR markup for each item. JS will reconcile these via `data-wp-each-child` after hydration.
private
render_items_markup(array<int, array<string, mixed>> $items) : string
Parameters
- $items : array<int, array<string, mixed>>
-
Schema-shape items.
Return values
string —render_ssr_move_to_cart()
SSR-mode markup for the Move-to-cart action button. SFL-specific.
private
render_ssr_move_to_cart(array<string, mixed> $item) : string
Always emits the wrapper so iAPI can toggle hidden after hydration
without swapping the row out. Starts hidden when the row isn't
purchasable.
Parameters
- $item : array<string, mixed>
-
Schema-shape item.
Return values
string —render_ssr_quantity()
SSR-mode markup for the quantity span. SFL-specific.
private
render_ssr_quantity(array<string, mixed> $item) : string
Parameters
- $item : array<string, mixed>
-
Schema-shape item.
Return values
string —render_template_markup()
The `<template data-wp-each>` describing how each item is rendered on the client. Pre-rendered children sit alongside as `data-wp-each-child` elements so first paint is populated. Composes the shared row markup with Saved for Later's quantity span and Move-to-cart action button.
private
render_template_markup() : string
Return values
string —render_template_move_to_cart()
Template-mode markup for the Move-to-cart action button. SFL-specific.
private
render_template_move_to_cart() : string
Return values
string —render_template_quantity()
Template-mode markup for the quantity span. SFL-specific — Wishlist has no quantity column.
private
render_template_quantity() : string
