mirror of
https://github.com/woocommerce/woocommerce.git
synced 2025-02-09 02:24:15 +08:00
Product Gallery Thumbnails: remove settings from container block (#54799)
* Remove thumbnails settings from container block * Migrate Thumbnails from context usage to local attributes * Cleanup types * Adjust frontend * Fix the frontend gallery * Fix types * Fix types * Remove provide context * Remove occurrances of productGalleryClientId * Update block references and block manifest * Rename thumbnailsNumberOfThumbnails to numberOfThumbnails * Remove attribute from gallery template * Remove thumbnails editor styles * Simplify Thumbnails edit file * Remove thumbnails position manipulation from parent * Remove utils manipulating positions * WIP: Simplify styles * Some stylingimprovements * Update block manifest * Bring back some of the old styles * Fix styles * Remove Thumbnails position attribute and corresponding code * Remove leftover exports * Continue adjusting styles * Fix frontend by attaching new classes * Remove unnecessary variables and fix merge * Add changelog * Fix lint * Remove tests related to positioning settings * Fix E2E * Update blocks references and manifest * Fix test * Address code review * Update blocks manifest * Fix typo * Limit the number of thumbnails if there's not enough images * Fix PHP error * Fix lint
This commit is contained in:
parent
c9ee77c785
commit
67348ccaf3
@ -152,6 +152,61 @@ Displays an on-sale badge if the product is on-sale.
|
||||
- **Supports:**
|
||||
- **Attributes:** isDescendentOfQueryLoop, isDescendentOfSingleProductTemplate, productId
|
||||
|
||||
## Product Summary - woocommerce/product-summary
|
||||
|
||||
Display a short description about a product.
|
||||
|
||||
- **Name:** woocommerce/product-summary
|
||||
- **Category:**
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:**
|
||||
- **Attributes:** isDescendantOfAllProducts, isDescendentOfQueryLoop, isDescendentOfSingleProductBlock, isDescendentOfSingleProductTemplate, linkText, productId, showDescriptionIfEmpty, showLink, summaryLength
|
||||
|
||||
## Accordion Group - woocommerce/accordion-group
|
||||
|
||||
A group of headers and associated expandable content.
|
||||
|
||||
- **Name:** woocommerce/accordion-group
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** align (full, wide), background (backgroundImage, backgroundSize), color (background, gradient, text), interactivity, layout, shadow, spacing (blockGap, margin, padding), ~~html~~
|
||||
- **Attributes:** allowedBlocks, autoclose, iconPosition
|
||||
|
||||
## Accordion Header - woocommerce/accordion-header
|
||||
|
||||
Accordion header.
|
||||
|
||||
- **Name:** woocommerce/accordion-header
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:** woocommerce/accordion-item
|
||||
- **Supports:** anchor, border, color (background, gradient, text), interactivity, layout, shadow, spacing (margin, padding), typography (fontSize, textAlign), ~~align~~
|
||||
- **Attributes:** icon, iconPosition, level, levelOptions, openByDefault, textAlignment, title
|
||||
|
||||
## Accordion - woocommerce/accordion-item
|
||||
|
||||
A single accordion that displays a header and expandable content.
|
||||
|
||||
- **Name:** woocommerce/accordion-item
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:** woocommerce/accordion-group
|
||||
- **Supports:** align (full, wide), color (background, gradient, text), interactivity, layout, shadow, spacing (blockGap, margin)
|
||||
- **Attributes:** openByDefault
|
||||
|
||||
## Accordion Panel - woocommerce/accordion-panel
|
||||
|
||||
Accordion Panel
|
||||
|
||||
- **Name:** woocommerce/accordion-panel
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:** woocommerce/accordion-item
|
||||
- **Supports:** border, color (background, gradient, text), interactivity, layout, shadow, spacing (blockGap, margin, padding), typography (fontSize, lineHeight)
|
||||
- **Attributes:** allowedBlocks, isSelected, openByDefault, templateLock
|
||||
|
||||
## Active Filters Controls - woocommerce/active-filters
|
||||
|
||||
Display the currently active filters.
|
||||
@ -163,6 +218,61 @@ Display the currently active filters.
|
||||
- **Supports:** color (text, ~~background~~), ~~html~~, ~~inserter~~, ~~lock~~, ~~multiple~~
|
||||
- **Attributes:** displayStyle, headingLevel
|
||||
|
||||
## Add to Cart with Options (Experimental) - woocommerce/add-to-cart-with-options
|
||||
|
||||
Create an "Add To Cart" composition by using blocks
|
||||
|
||||
- **Name:** woocommerce/add-to-cart-with-options
|
||||
- **Category:** woocommerce-product-elements
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** interactivity
|
||||
- **Attributes:** isDescendentOfSingleProductBlock
|
||||
|
||||
## Grouped Product Selector (Experimental) - woocommerce/add-to-cart-with-options-grouped-product-selector
|
||||
|
||||
Display a group of products that can be added to the cart.
|
||||
|
||||
- **Name:** woocommerce/add-to-cart-with-options-grouped-product-selector
|
||||
- **Category:** woocommerce-product-elements
|
||||
- **Ancestor:** woocommerce/add-to-cart-with-options
|
||||
- **Parent:**
|
||||
- **Supports:**
|
||||
- **Attributes:**
|
||||
|
||||
## Grouped Product Selector Item Template (Experimental) - woocommerce/add-to-cart-with-options-grouped-product-selector-item
|
||||
|
||||
A list item template that represents a child product within the Grouped Product Selector block.
|
||||
|
||||
- **Name:** woocommerce/add-to-cart-with-options-grouped-product-selector-item
|
||||
- **Category:** woocommerce-product-elements
|
||||
- **Ancestor:** woocommerce/add-to-cart-with-options-grouped-product-selector
|
||||
- **Parent:**
|
||||
- **Supports:** ~~inserter~~
|
||||
- **Attributes:**
|
||||
|
||||
## Quantity Selector (Experimental) - woocommerce/add-to-cart-with-options-quantity-selector
|
||||
|
||||
Display an input field to select the number of products to add to cart.
|
||||
|
||||
- **Name:** woocommerce/add-to-cart-with-options-quantity-selector
|
||||
- **Category:** woocommerce-product-elements
|
||||
- **Ancestor:** woocommerce/add-to-cart-with-options
|
||||
- **Parent:**
|
||||
- **Supports:**
|
||||
- **Attributes:** quantitySelectorStyle
|
||||
|
||||
## Variation Selector (Experimental) - woocommerce/add-to-cart-with-options-variation-selector
|
||||
|
||||
Display a dropdown to select a variation to add to cart.
|
||||
|
||||
- **Name:** woocommerce/add-to-cart-with-options-variation-selector
|
||||
- **Category:** woocommerce-product-elements
|
||||
- **Ancestor:** woocommerce/add-to-cart-with-options
|
||||
- **Parent:**
|
||||
- **Supports:**
|
||||
- **Attributes:**
|
||||
|
||||
## Filter by Attribute Controls - woocommerce/attribute-filter
|
||||
|
||||
Enable customers to filter the product grid by selecting one or more attributes, such as color.
|
||||
@ -414,7 +524,7 @@ Enable customers to change the sorting order of the products.
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** color (text, ~~background~~), typography (fontSize)
|
||||
- **Attributes:** fontSize
|
||||
- **Attributes:** fontSize, useLabel
|
||||
|
||||
## Checkout - woocommerce/checkout
|
||||
|
||||
@ -524,7 +634,7 @@ Shows cart items.
|
||||
- **Ancestor:**
|
||||
- **Parent:** woocommerce/checkout-order-summary-block
|
||||
- **Supports:** ~~align~~, ~~html~~, ~~lock~~, ~~multiple~~, ~~reusable~~
|
||||
- **Attributes:** className, lock
|
||||
- **Attributes:** className, disableProductDescriptions, lock
|
||||
|
||||
## Coupon Form - woocommerce/checkout-order-summary-coupon-form-block
|
||||
|
||||
@ -699,8 +809,8 @@ Renders classic WooCommerce shortcodes.
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** color (text, ~~background~~), ~~inserter~~
|
||||
- **Attributes:** color, storeOnly
|
||||
- **Supports:** color (background, text), ~~inserter~~
|
||||
- **Attributes:** color, comingSoonPatternId, storeOnly
|
||||
|
||||
## Customer account - woocommerce/customer-account
|
||||
|
||||
@ -946,7 +1056,7 @@ Display the order confirmation billing section.
|
||||
|
||||
## Account Creation - woocommerce/order-confirmation-create-account
|
||||
|
||||
Allow customers to create an account after their purchase. Configure this feature in your store settings.
|
||||
Allow customers to create an account after their purchase.
|
||||
|
||||
- **Name:** woocommerce/order-confirmation-create-account
|
||||
- **Category:** woocommerce
|
||||
@ -1120,6 +1230,17 @@ The contents of this block will display when there are no products found.
|
||||
- **Supports:** align, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~
|
||||
- **Attributes:**
|
||||
|
||||
## Blockified Product Details - woocommerce/blockified-product-details
|
||||
|
||||
Display a product's description, attributes, and reviews
|
||||
|
||||
- **Name:** woocommerce/blockified-product-details
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:**
|
||||
- **Attributes:**
|
||||
|
||||
## Add to Cart with Options - woocommerce/add-to-cart-form
|
||||
|
||||
Display a button so the customer can add a product to their cart. Options will also be displayed depending on product type. e.g. quantity, variation.
|
||||
@ -1139,7 +1260,7 @@ Let shoppers filter products displayed on the page.
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** align, color (background, button, heading, text, ~~enableContrastChecker~~), inserter, interactivity, multiple, typography (fontSize)
|
||||
- **Supports:** align, color (background, button, heading, text, ~~enableContrastChecker~~), inserter, interactivity, layout (default, ~~allowEditing~~), multiple, spacing (blockGap), typography (fontSize)
|
||||
- **Attributes:** overlayButtonType, overlayIcon, overlayIconSize
|
||||
|
||||
## Active (Experimental) - woocommerce/product-filter-active
|
||||
@ -1150,8 +1271,8 @@ Display the currently active filters.
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:** woocommerce/product-filters
|
||||
- **Parent:**
|
||||
- **Supports:** color (text, ~~background~~), interactivity
|
||||
- **Attributes:** displayStyle
|
||||
- **Supports:** interactivity, spacing (margin, padding, ~~blockGap~~)
|
||||
- **Attributes:**
|
||||
|
||||
## Attribute (Experimental) - woocommerce/product-filter-attribute
|
||||
|
||||
@ -1162,7 +1283,7 @@ Enable customers to filter the product grid by selecting one or more attributes,
|
||||
- **Ancestor:** woocommerce/product-filters
|
||||
- **Parent:**
|
||||
- **Supports:** color (text, ~~background~~), interactivity, spacing (blockGap, margin, padding), typography (fontSize, lineHeight)
|
||||
- **Attributes:** attributeId, clearButton, displayStyle, hideEmpty, isPreview, queryType, selectType, showCounts, sortOrder
|
||||
- **Attributes:** attributeId, displayStyle, hideEmpty, isPreview, queryType, selectType, showCounts, sortOrder
|
||||
|
||||
## List - woocommerce/product-filter-checkbox-list
|
||||
|
||||
@ -1192,32 +1313,10 @@ Allows shoppers to reset this filter.
|
||||
|
||||
- **Name:** woocommerce/product-filter-clear-button
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:** woocommerce/product-filter
|
||||
- **Ancestor:** woocommerce/product-filter,woocommerce/product-filter-attribute,woocommerce/product-filter-price,woocommerce/product-filter-rating,woocommerce/product-filter-status,woocommerce/product-filter-active
|
||||
- **Parent:**
|
||||
- **Supports:** interactivity, ~~inserter~~
|
||||
- **Attributes:**
|
||||
|
||||
## Product Filters Overlay (Experimental) - woocommerce/product-filters-overlay
|
||||
|
||||
Display product filters in an overlay on top of a page.
|
||||
|
||||
- **Name:** woocommerce/product-filters-overlay
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** align, color (background, text), dimensions (), layout (allowCustomContentAndWideSize), spacing (blockGap, padding), typography (), ~~inserter~~, ~~multiple~~
|
||||
- **Attributes:** overlayPosition, overlayStyle, style
|
||||
|
||||
## Overlay Navigation (Experimental) - woocommerce/product-filters-overlay-navigation
|
||||
|
||||
Display overlay navigation controls.
|
||||
|
||||
- **Name:** woocommerce/product-filters-overlay-navigation
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:** woocommerce/product-filters-overlay,woocommerce/product-filters
|
||||
- **Parent:**
|
||||
- **Supports:** align (center, left, right), color (background, text), inserter, interactivity, layout (default, ~~allowEditing~~), position (sticky), spacing (blockGap, margin, padding), typography (fontSize, lineHeight)
|
||||
- **Attributes:** align, buttonStyle, iconSize, navigationStyle, overlayIcon, overlayMode, style, triggerType
|
||||
- **Supports:** inserter, interactivity
|
||||
- **Attributes:** clearType
|
||||
|
||||
## Price (Experimental) - woocommerce/product-filter-price
|
||||
|
||||
@ -1238,8 +1337,8 @@ A slider helps shopper choose a price range.
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:** woocommerce/product-filter-price
|
||||
- **Parent:**
|
||||
- **Supports:** ~~html~~
|
||||
- **Attributes:** inlineInput, showInputFields
|
||||
- **Supports:** color (~~background~~, ~~enableContrastChecker~~, ~~text~~), ~~html~~
|
||||
- **Attributes:** customSlider, customSliderHandle, customSliderHandleBorder, inlineInput, showInputFields, slider, sliderHandle, sliderHandleBorder
|
||||
|
||||
## Rating (Experimental) - woocommerce/product-filter-rating
|
||||
|
||||
@ -1252,6 +1351,17 @@ Enable customers to filter the product collection by rating.
|
||||
- **Supports:** color (text, ~~background~~), interactivity
|
||||
- **Attributes:** className, isPreview, minRating, showCounts
|
||||
|
||||
## Chips - woocommerce/product-filter-removable-chips
|
||||
|
||||
Display removable active filters as chips.
|
||||
|
||||
- **Name:** woocommerce/product-filter-removable-chips
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:** woocommerce/product-filter-active
|
||||
- **Parent:**
|
||||
- **Supports:** layout (default, ~~allowInheriting~~, ~~allowJustification~~, ~~allowSwitching~~, ~~allowVerticalAlignment~~)
|
||||
- **Attributes:** chipBackground, chipBorder, chipText, customChipBackground, customChipBorder, customChipText
|
||||
|
||||
## Status (Experimental) - woocommerce/product-filter-status
|
||||
|
||||
Let shoppers filter products by choosing stock status.
|
||||
@ -1261,7 +1371,7 @@ Let shoppers filter products by choosing stock status.
|
||||
- **Ancestor:** woocommerce/product-filters
|
||||
- **Parent:**
|
||||
- **Supports:** color (text, ~~background~~), interactivity, spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~
|
||||
- **Attributes:** clearButton, displayStyle, hideEmpty, isPreview, showCounts
|
||||
- **Attributes:** displayStyle, hideEmpty, isPreview, showCounts
|
||||
|
||||
## Product Gallery (Beta) - woocommerce/product-gallery
|
||||
|
||||
@ -1269,10 +1379,10 @@ Showcase your products relevant images and media.
|
||||
|
||||
- **Name:** woocommerce/product-gallery
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Ancestor:** woocommerce/single-product
|
||||
- **Parent:**
|
||||
- **Supports:** align, interactivity, ~~multiple~~
|
||||
- **Attributes:** cropImages, fullScreenOnClick, hoverZoom, mode, nextPreviousButtonsPosition, pagerDisplayMode, productGalleryClientId, thumbnailsNumberOfThumbnails, thumbnailsPosition
|
||||
- **Supports:** align, interactivity
|
||||
- **Attributes:** cropImages, fullScreenOnClick, hoverZoom
|
||||
|
||||
## Large Image - woocommerce/product-gallery-large-image
|
||||
|
||||
@ -1298,13 +1408,13 @@ Display next and previous buttons.
|
||||
|
||||
## Pager - woocommerce/product-gallery-pager
|
||||
|
||||
Display the gallery pager.
|
||||
Display the gallery pager in format "current image/total images".
|
||||
|
||||
- **Name:** woocommerce/product-gallery-pager
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:** woocommerce/product-gallery
|
||||
- **Parent:**
|
||||
- **Supports:**
|
||||
- **Supports:** color (background, text), spacing (margin, padding), typography (fontSize, lineHeight, textAlign)
|
||||
- **Attributes:**
|
||||
|
||||
## Thumbnails - woocommerce/product-gallery-thumbnails
|
||||
@ -1316,7 +1426,7 @@ Display the Thumbnails of a product.
|
||||
- **Ancestor:** woocommerce/product-gallery
|
||||
- **Parent:**
|
||||
- **Supports:** spacing (margin)
|
||||
- **Attributes:**
|
||||
- **Attributes:** numberOfThumbnails
|
||||
|
||||
## Newest Products - woocommerce/product-new
|
||||
|
||||
@ -1403,7 +1513,7 @@ Enable customers to filter the product grid by rating.
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** color, ~~html~~, ~~inserter~~, ~~lock~~, ~~multiple~~
|
||||
- **Supports:** color (background, button, text), ~~html~~, ~~inserter~~, ~~lock~~, ~~multiple~~
|
||||
- **Attributes:** className, displayStyle, isPreview, selectType, showCounts, showFilterButton
|
||||
|
||||
## Single Product - woocommerce/single-product
|
||||
@ -1425,7 +1535,7 @@ Enable customers to filter the product grid by stock status.
|
||||
- **Category:** woocommerce
|
||||
- **Ancestor:**
|
||||
- **Parent:**
|
||||
- **Supports:** color, ~~html~~, ~~inserter~~, ~~lock~~, ~~multiple~~
|
||||
- **Supports:** color (background, button, text), ~~html~~, ~~inserter~~, ~~lock~~, ~~multiple~~
|
||||
- **Attributes:** className, displayStyle, headingLevel, isPreview, selectType, showCounts, showFilterButton
|
||||
|
||||
## Store Notices - woocommerce/store-notices
|
||||
|
@ -79,7 +79,7 @@
|
||||
"post_title": "Blocks reference",
|
||||
"menu_title": "Blocks Reference",
|
||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/building-a-woo-store/block-references.md",
|
||||
"hash": "fee3ebe3c18bb39f0a8e9e1f43fe8153b4b5664913cd50b6e3c078ede151601b",
|
||||
"hash": "0200411990f2cf1bdb9b0240380779d6777d2e60a7d1920fec1181d6b4281e0e",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/building-a-woo-store/block-references.md",
|
||||
"id": "1fbe91d7fa4fafaf35f0297e4cee1e7958756aed"
|
||||
},
|
||||
@ -451,7 +451,7 @@
|
||||
"menu_title": "Free shipping customizations",
|
||||
"tags": "code-snippets",
|
||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/free_shipping_customization.md",
|
||||
"hash": "3cf4bf7ecf4ea4138591ee6fead8268f48619e28ecb2c3b10a8cf7f6ad68ed09",
|
||||
"hash": "0f5793a00b7e2db6d0862ff4130951ebdd1845bd77237d8e94dc4e63f4fe70e9",
|
||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/free_shipping_customization.md",
|
||||
"id": "cac6f1ccd661588e9a5fa7405643e9c6d4da388e"
|
||||
},
|
||||
@ -1915,5 +1915,5 @@
|
||||
"categories": []
|
||||
}
|
||||
],
|
||||
"hash": "010c87899f8432c25051b7e14b4262763197d04ffa0dc581be95945454acacb3"
|
||||
"hash": "541fa48f03c824c6b66c26ea761ad690aba0eda3084e9e28b0a8a5d26f5ffbc7"
|
||||
}
|
@ -9,30 +9,14 @@ import { __ } from '@wordpress/i18n';
|
||||
* Internal dependencies
|
||||
*/
|
||||
import type { ProductGallerySettingsProps } from '../types';
|
||||
import { ProductGalleryThumbnailsBlockSettings } from '../inner-blocks/product-gallery-thumbnails/block-settings';
|
||||
|
||||
export const ProductGalleryBlockSettings = ( {
|
||||
attributes,
|
||||
setAttributes,
|
||||
context,
|
||||
}: ProductGallerySettingsProps ) => {
|
||||
const { cropImages, hoverZoom, fullScreenOnClick } = attributes;
|
||||
const {
|
||||
productGalleryClientId,
|
||||
thumbnailsNumberOfThumbnails,
|
||||
thumbnailsPosition,
|
||||
} = context;
|
||||
return (
|
||||
<InspectorControls>
|
||||
<PanelBody title={ __( 'Gallery Navigation', 'woocommerce' ) }>
|
||||
<ProductGalleryThumbnailsBlockSettings
|
||||
context={ {
|
||||
productGalleryClientId,
|
||||
thumbnailsNumberOfThumbnails,
|
||||
thumbnailsPosition,
|
||||
} }
|
||||
/>
|
||||
</PanelBody>
|
||||
<PanelBody title={ __( 'Media Settings', 'woocommerce' ) }>
|
||||
<ToggleControl
|
||||
label={ __( 'Crop images to fit', 'woocommerce' ) }
|
||||
|
@ -14,27 +14,12 @@
|
||||
"textdomain": "woocommerce",
|
||||
"usesContext": [ "postId" ],
|
||||
"providesContext": {
|
||||
"thumbnailsPosition": "thumbnailsPosition",
|
||||
"thumbnailsNumberOfThumbnails": "thumbnailsNumberOfThumbnails",
|
||||
"productGalleryClientId": "productGalleryClientId",
|
||||
"hoverZoom": "hoverZoom",
|
||||
"fullScreenOnClick": "fullScreenOnClick",
|
||||
"cropImages": "cropImages"
|
||||
},
|
||||
"ancestor": [ "woocommerce/single-product" ],
|
||||
"attributes": {
|
||||
"thumbnailsPosition": {
|
||||
"type": "string",
|
||||
"default": "left"
|
||||
},
|
||||
"thumbnailsNumberOfThumbnails": {
|
||||
"type": "number",
|
||||
"default": 3
|
||||
},
|
||||
"productGalleryClientId": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"cropImages": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
|
@ -8,14 +8,12 @@ import {
|
||||
useInnerBlocksProps,
|
||||
} from '@wordpress/block-editor';
|
||||
import { BlockEditProps, InnerBlockTemplate } from '@wordpress/blocks';
|
||||
import { useEffect } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ProductGalleryBlockSettings } from './block-settings/index';
|
||||
import type { ProductGalleryAttributes } from './types';
|
||||
import { moveInnerBlocksToPosition } from './utils';
|
||||
import type { ProductGalleryBlockAttributes } from './types';
|
||||
|
||||
const TEMPLATE: InnerBlockTemplate[] = [
|
||||
[
|
||||
@ -88,33 +86,17 @@ const TEMPLATE: InnerBlockTemplate[] = [
|
||||
];
|
||||
|
||||
export const Edit = ( {
|
||||
clientId,
|
||||
attributes,
|
||||
setAttributes,
|
||||
}: BlockEditProps< ProductGalleryAttributes > ) => {
|
||||
}: BlockEditProps< ProductGalleryBlockAttributes > ) => {
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
useEffect( () => {
|
||||
setAttributes( {
|
||||
...attributes,
|
||||
productGalleryClientId: clientId,
|
||||
} );
|
||||
// Move the Thumbnails block to the correct above or below the Large Image based on the thumbnailsPosition attribute.
|
||||
moveInnerBlocksToPosition( attributes, clientId );
|
||||
}, [ setAttributes, attributes, clientId ] );
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InspectorControls>
|
||||
<ProductGalleryBlockSettings
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
context={ {
|
||||
productGalleryClientId: clientId,
|
||||
thumbnailsPosition: attributes.thumbnailsPosition,
|
||||
thumbnailsNumberOfThumbnails:
|
||||
attributes.thumbnailsNumberOfThumbnails,
|
||||
} }
|
||||
/>
|
||||
</InspectorControls>
|
||||
<InnerBlocks
|
||||
|
@ -6,13 +6,8 @@
|
||||
"title": "Next/Previous Buttons",
|
||||
"description": "Display next and previous buttons.",
|
||||
"category": "woocommerce",
|
||||
"keywords": [
|
||||
"WooCommerce"
|
||||
],
|
||||
"usesContext": [
|
||||
"productGalleryClientId",
|
||||
"postId"
|
||||
],
|
||||
"keywords": [ "WooCommerce" ],
|
||||
"usesContext": [ "postId" ],
|
||||
"textdomain": "woocommerce",
|
||||
"supports": {
|
||||
"layout": {
|
||||
@ -26,7 +21,5 @@
|
||||
"allowInheriting": false
|
||||
}
|
||||
},
|
||||
"ancestor": [
|
||||
"woocommerce/product-gallery-large-image"
|
||||
]
|
||||
}
|
||||
"ancestor": [ "woocommerce/product-gallery-large-image" ]
|
||||
}
|
||||
|
@ -1,109 +1,38 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { store as blockEditorStore } from '@wordpress/block-editor';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
thumbnailsPositionLeft,
|
||||
thumbnailsPositionBottom,
|
||||
thumbnailsPositionRight,
|
||||
} from '@woocommerce/icons';
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import {
|
||||
Icon,
|
||||
RangeControl,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore - Ignoring because `__experimentalToggleGroupControlOption` is not yet in the type definitions.
|
||||
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
||||
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore - Ignoring because `__experimentalToggleGroupControl` is not yet in the type definitions.
|
||||
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
|
||||
__experimentalToggleGroupControl as ToggleGroupControl,
|
||||
} from '@wordpress/components';
|
||||
import { RangeControl } from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ThumbnailsPosition } from '../constants';
|
||||
import type { ProductGalleryThumbnailsSettingsProps } from '../../../types';
|
||||
|
||||
const positionHelp: Record< ThumbnailsPosition, string > = {
|
||||
[ ThumbnailsPosition.LEFT ]: __(
|
||||
'A strip of small images will appear to the left of the main gallery image.',
|
||||
'woocommerce'
|
||||
),
|
||||
[ ThumbnailsPosition.BOTTOM ]: __(
|
||||
'A strip of small images will appear below the main gallery image.',
|
||||
'woocommerce'
|
||||
),
|
||||
[ ThumbnailsPosition.RIGHT ]: __(
|
||||
'A strip of small images will appear to the right of the main gallery image.',
|
||||
'woocommerce'
|
||||
),
|
||||
};
|
||||
import type { ProductGalleryThumbnailsSettingsProps } from '../types';
|
||||
|
||||
export const ProductGalleryThumbnailsBlockSettings = ( {
|
||||
context,
|
||||
attributes,
|
||||
setAttributes,
|
||||
}: ProductGalleryThumbnailsSettingsProps ) => {
|
||||
const maxNumberOfThumbnails = 8;
|
||||
const minNumberOfThumbnails = 3;
|
||||
const { productGalleryClientId } = context;
|
||||
const { updateBlockAttributes } = useDispatch( blockEditorStore );
|
||||
const { numberOfThumbnails } = attributes;
|
||||
|
||||
return (
|
||||
<>
|
||||
<ToggleGroupControl
|
||||
className="wc-block-editor-product-gallery-thumbnails__position-toggle"
|
||||
isBlock
|
||||
label={ __( 'Thumbnails', 'woocommerce' ) }
|
||||
value={ context.thumbnailsPosition }
|
||||
help={
|
||||
positionHelp[
|
||||
context.thumbnailsPosition as ThumbnailsPosition
|
||||
]
|
||||
}
|
||||
onChange={ ( value: string ) =>
|
||||
updateBlockAttributes( productGalleryClientId, {
|
||||
thumbnailsPosition: value,
|
||||
} )
|
||||
}
|
||||
>
|
||||
<ToggleGroupControlOption
|
||||
value={ ThumbnailsPosition.LEFT }
|
||||
label={
|
||||
<Icon size={ 32 } icon={ thumbnailsPositionLeft } />
|
||||
}
|
||||
/>
|
||||
<ToggleGroupControlOption
|
||||
value={ ThumbnailsPosition.BOTTOM }
|
||||
label={
|
||||
<Icon size={ 32 } icon={ thumbnailsPositionBottom } />
|
||||
}
|
||||
/>
|
||||
<ToggleGroupControlOption
|
||||
value={ ThumbnailsPosition.RIGHT }
|
||||
label={
|
||||
<Icon size={ 32 } icon={ thumbnailsPositionRight } />
|
||||
}
|
||||
/>
|
||||
</ToggleGroupControl>
|
||||
<RangeControl
|
||||
label={ __( 'Number of Thumbnails', 'woocommerce' ) }
|
||||
value={ context.thumbnailsNumberOfThumbnails }
|
||||
onChange={ ( value: number ) =>
|
||||
updateBlockAttributes( productGalleryClientId, {
|
||||
thumbnailsNumberOfThumbnails: Math.round( value ),
|
||||
} )
|
||||
}
|
||||
help={ __(
|
||||
'Choose how many thumbnails (3-8) will display. If more images exist, a “View all” button will display.',
|
||||
'woocommerce'
|
||||
) }
|
||||
max={ maxNumberOfThumbnails }
|
||||
min={ minNumberOfThumbnails }
|
||||
step={ 1 }
|
||||
/>
|
||||
</>
|
||||
<RangeControl
|
||||
label={ __( 'Number of Thumbnails', 'woocommerce' ) }
|
||||
value={ numberOfThumbnails }
|
||||
onChange={ ( value: number ) =>
|
||||
setAttributes( {
|
||||
numberOfThumbnails: Math.round( value ),
|
||||
} )
|
||||
}
|
||||
help={ __(
|
||||
'Choose how many thumbnails (3-8) will display. If more images exist, a “View all” button will display.',
|
||||
'woocommerce'
|
||||
) }
|
||||
max={ maxNumberOfThumbnails }
|
||||
min={ minNumberOfThumbnails }
|
||||
step={ 1 }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -6,20 +6,16 @@
|
||||
"title": "Thumbnails",
|
||||
"description": "Display the Thumbnails of a product.",
|
||||
"category": "woocommerce",
|
||||
"keywords": [
|
||||
"WooCommerce"
|
||||
],
|
||||
"usesContext": [
|
||||
"postId",
|
||||
"thumbnailsPosition",
|
||||
"thumbnailsNumberOfThumbnails",
|
||||
"productGalleryClientId",
|
||||
"cropImages"
|
||||
],
|
||||
"keywords": [ "WooCommerce" ],
|
||||
"usesContext": [ "postId", "cropImages" ],
|
||||
"textdomain": "woocommerce",
|
||||
"ancestor": [
|
||||
"woocommerce/product-gallery"
|
||||
],
|
||||
"ancestor": [ "woocommerce/product-gallery" ],
|
||||
"attributes": {
|
||||
"numberOfThumbnails": {
|
||||
"type": "number",
|
||||
"default": 3
|
||||
}
|
||||
},
|
||||
"supports": {
|
||||
"spacing": {
|
||||
"margin": true,
|
||||
@ -28,4 +24,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
export enum ThumbnailsPosition {
|
||||
LEFT = 'left',
|
||||
BOTTOM = 'bottom',
|
||||
RIGHT = 'right',
|
||||
}
|
@ -2,66 +2,50 @@
|
||||
* External dependencies
|
||||
*/
|
||||
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
|
||||
import { Disabled, PanelBody } from '@wordpress/components';
|
||||
import { PanelBody } from '@wordpress/components';
|
||||
import { WC_BLOCKS_IMAGE_URL } from '@woocommerce/block-settings';
|
||||
import clsx from 'clsx';
|
||||
import type { BlockEditProps } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './editor.scss';
|
||||
import { ProductGalleryThumbnailsBlockSettings } from './block-settings';
|
||||
import type { ProductGalleryContext } from '../../types';
|
||||
import type { ProductGalleryThumbnailsBlockAttributes } from './types';
|
||||
|
||||
interface EditProps {
|
||||
context: ProductGalleryContext;
|
||||
}
|
||||
|
||||
export const Edit = ( { context }: EditProps ) => {
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
setAttributes,
|
||||
}: BlockEditProps< ProductGalleryThumbnailsBlockAttributes > ) => {
|
||||
const blockProps = useBlockProps( {
|
||||
className: clsx(
|
||||
'wc-block-product-gallery-thumbnails',
|
||||
`wc-block-product-gallery-thumbnails--number-of-thumbnails-${ context.thumbnailsNumberOfThumbnails }`,
|
||||
`wc-block-product-gallery-thumbnails--position-${ context.thumbnailsPosition }`
|
||||
),
|
||||
className: `wc-block-product-gallery-thumbnails wc-block-product-gallery-thumbnails--number-of-thumbnails-${ attributes.numberOfThumbnails }`,
|
||||
} );
|
||||
|
||||
const Placeholder = () => {
|
||||
return (
|
||||
<div className="wc-block-editor-product-gallery-thumbnails">
|
||||
{ [
|
||||
...Array( context.thumbnailsNumberOfThumbnails ).keys(),
|
||||
].map( ( index ) => {
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InspectorControls>
|
||||
<PanelBody>
|
||||
<ProductGalleryThumbnailsBlockSettings
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
/>
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
{ [ ...Array( attributes.numberOfThumbnails ).keys() ].map(
|
||||
( index ) => {
|
||||
return (
|
||||
<div
|
||||
className="wc-block-product-gallery-thumbnails__thumbnail"
|
||||
key={ index }
|
||||
>
|
||||
<img
|
||||
className="wc-block-product-gallery-thumbnails__image"
|
||||
src={ `${ WC_BLOCKS_IMAGE_URL }block-placeholders/product-image-gallery.svg` }
|
||||
alt="Placeholder"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} ) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div { ...blockProps }>
|
||||
<InspectorControls>
|
||||
<PanelBody>
|
||||
<ProductGalleryThumbnailsBlockSettings
|
||||
context={ context }
|
||||
/>
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
<Disabled>
|
||||
<Placeholder />
|
||||
</Disabled>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,30 +0,0 @@
|
||||
$thumbnails: ".wc-block-editor-product-gallery-thumbnails";
|
||||
$thumbnails-gap: 15px;
|
||||
|
||||
#{$thumbnails} {
|
||||
display: flex;
|
||||
|
||||
.wc-block-product-gallery-thumbnails--position-bottom & {
|
||||
flex-direction: row;
|
||||
gap: 0 15px;
|
||||
}
|
||||
|
||||
.wc-block-product-gallery-thumbnails:not(.wc-block-product-gallery-thumbnails--position-bottom) & {
|
||||
flex-direction: column;
|
||||
gap: 15px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 3 through 8 {
|
||||
// Calculate the total width occupied by the gaps between thumbnails.
|
||||
$gap-width: $thumbnails-gap * ($i - 1);
|
||||
|
||||
// Calculate the border width, which is multiplied by 2 to account for both sides of each thumbnail.
|
||||
$border-width: ($i * 1px * 2);
|
||||
|
||||
$additional-space: $i * 1px;
|
||||
|
||||
.wc-block-product-gallery-thumbnails--number-of-thumbnails-#{$i}:not(.wc-block-product-gallery-thumbnails--position-bottom) {
|
||||
flex-basis: calc((100% - #{$gap-width} - #{$border-width} - #{$additional-space}) / #{$i});
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
export type ProductGalleryThumbnailsBlockAttributes = {
|
||||
numberOfThumbnails: number;
|
||||
};
|
||||
|
||||
export type ProductGalleryThumbnailsSettingsProps = {
|
||||
attributes: ProductGalleryThumbnailsBlockAttributes;
|
||||
setAttributes: (
|
||||
attributes: Partial< ProductGalleryThumbnailsBlockAttributes >
|
||||
) => void;
|
||||
};
|
@ -1,17 +1,9 @@
|
||||
$admin-bar-height: 32px;
|
||||
$gallery: ".wc-block-product-gallery";
|
||||
$large-image: "#{$gallery}-large-image";
|
||||
$thumbnails: "#{$gallery}-thumbnails";
|
||||
$next-previous: "#{$large-image}-next-previous";
|
||||
$next-previous-left-off: "#{$next-previous}-left--off";
|
||||
$next-previous-right-off: "#{$next-previous}-right--off";
|
||||
$outside-image-offset: 30px;
|
||||
$outside-image-max-width: calc(100% - (2 * $outside-image-offset));
|
||||
$thumbnails-gap: 15px;
|
||||
$default-number-of-thumbnails: 3;
|
||||
$thumbnails-border-width: 1px;
|
||||
$dialog-padding: 20px;
|
||||
|
||||
// Large Image
|
||||
#{$large-image} {
|
||||
.wc-block-product-gallery-large-image {
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
position: relative;
|
||||
@ -84,8 +76,7 @@ $default-number-of-thumbnails: 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Next/Previous Buttons
|
||||
#{$next-previous} {
|
||||
.wc-block-product-gallery-large-image-next-previous {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
flex-direction: row;
|
||||
@ -125,12 +116,6 @@ $default-number-of-thumbnails: 3;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// Next/Previous Buttons Off Setting
|
||||
#{$next-previous-left-off},
|
||||
#{$next-previous-right-off} {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Next/Previous Buttons Inside the Image Settings
|
||||
.wc-block-product-gallery-large-image-next-previous-left--inside-image {
|
||||
margin-left: 15px;
|
||||
@ -157,100 +142,45 @@ $default-number-of-thumbnails: 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Thumbnails
|
||||
#{$thumbnails} {
|
||||
.wc-block-product-gallery-thumbnails {
|
||||
display: flex;
|
||||
gap: $thumbnails-gap;
|
||||
|
||||
img {
|
||||
&__image {
|
||||
cursor: pointer;
|
||||
height: auto;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#{$gallery}[data-thumbnails-position='bottom'] & {
|
||||
flex-direction: row;
|
||||
gap: 0 15px;
|
||||
}
|
||||
|
||||
#{$gallery}:not([data-thumbnails-position='bottom']) & {
|
||||
flex-direction: column;
|
||||
gap: 15px 0;
|
||||
|
||||
// Calculate the total width occupied by the gaps between thumbnails.
|
||||
$gap-width: $thumbnails-gap * ($default-number-of-thumbnails - 1);
|
||||
|
||||
// Calculate the border width, which is multiplied by 2 to account for both sides of each thumbnail.
|
||||
$border-width: #{$default-number-of-thumbnails * 1px * 2};
|
||||
|
||||
// Calculate the width of each thumbnail by accounting for the gap, border, and additional space.
|
||||
flex-basis: calc((100% - #{$gap-width} - #{$border-width} - 4px) / #{$default-number-of-thumbnails});
|
||||
}
|
||||
|
||||
@for $i from 3 through 8 {
|
||||
#{$gallery}[data-thumbnails-number-of-thumbnails='#{$i}']:not([data-thumbnails-position='bottom']) & {
|
||||
// Calculate the total width occupied by the gaps between thumbnails.
|
||||
$gap-width: $thumbnails-gap * ($i - 1);
|
||||
|
||||
// Calculate the border width, which is multiplied by 2 to account for both sides of each thumbnail.
|
||||
$border-width: $i * 1px * 2;
|
||||
|
||||
flex-basis: calc((100% - #{$gap-width} - #{$border-width}) / $i);
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-product-gallery-thumbnails__thumbnail {
|
||||
border: 1px solid rgba($color: #000, $alpha: 0.1);
|
||||
height: auto;
|
||||
width: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
aspect-ratio: 1 / 1;
|
||||
position: relative;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
&__thumbnail {
|
||||
border: $thumbnails-border-width solid rgba($color: #000, $alpha: 0.1);
|
||||
display: flex;
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
|
||||
img {
|
||||
aspect-ratio: 1 / 1;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
display: block;
|
||||
padding-top: 100%;
|
||||
}
|
||||
|
||||
@for $i from 3 through 8 {
|
||||
#{$gallery}[data-thumbnails-number-of-thumbnails='#{$i}'][data-thumbnails-position="bottom"] & {
|
||||
// Calculate the total width occupied by the gaps between thumbnails.
|
||||
$gap-width: $thumbnails-gap * ($i - 1);
|
||||
|
||||
// Calculate the border width, which is multiplied by 2 to account for both sides of each thumbnail.
|
||||
$border-width: $i * 1px * 2;
|
||||
|
||||
$thumbnail-width: calc((100% - #{$gap-width} - #{$border-width}) / $i);
|
||||
|
||||
flex: 0 0 $thumbnail-width;
|
||||
}
|
||||
}
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.wc-block-product-gallery-thumbnails__thumbnail__overlay {
|
||||
&__thumbnail__overlay {
|
||||
container-type: inline-size;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 1.5;
|
||||
|
||||
|
||||
.wc-block-product-gallery-thumbnails__thumbnail__remaining-thumbnails-count {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
@ -260,11 +190,6 @@ $default-number-of-thumbnails: 3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.wc-block-product-gallery-thumbnails__thumbnail__remaining-thumbnails-count,
|
||||
.wc-block-product-gallery-thumbnails__thumbnail__view-all {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@container (width < 70px) {
|
||||
.wc-block-product-gallery-thumbnails__thumbnail__view-all {
|
||||
display: none;
|
||||
@ -301,7 +226,34 @@ $default-number-of-thumbnails: 3;
|
||||
}
|
||||
}
|
||||
|
||||
$dialog-padding: 20px;
|
||||
// Automattically react to the Group container settings.
|
||||
.is-nowrap .wc-block-product-gallery-thumbnails,
|
||||
.is-horizontal.is-nowrap .wc-block-product-gallery-thumbnails {
|
||||
flex-direction: column;
|
||||
|
||||
@for $i from 3 through 8 {
|
||||
&.wc-block-product-gallery-thumbnails--number-of-thumbnails-#{$i} {
|
||||
$gap-width: $thumbnails-gap * ($i - 1);
|
||||
$border-width: $i * $thumbnails-border-width * 2;
|
||||
|
||||
flex-basis: calc((100% - #{$gap-width} - #{$border-width}) / $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-vertical .wc-block-product-gallery-thumbnails,
|
||||
.is-horizontal .wc-block-product-gallery-thumbnails {
|
||||
flex-direction: row;
|
||||
|
||||
@for $i from 3 through 8 {
|
||||
&.wc-block-product-gallery-thumbnails--number-of-thumbnails-#{$i} {
|
||||
$gap-width: $thumbnails-gap * ($i - 1);
|
||||
$border-width: $i * $thumbnails-border-width * 2;
|
||||
|
||||
flex: 0 0 calc((100% - #{$gap-width} - #{$border-width}) / $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.wc-block-product-gallery-dialog-open {
|
||||
overflow: hidden;
|
||||
|
@ -1,60 +1,12 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ThumbnailsPosition } from './inner-blocks/product-gallery-thumbnails/constants';
|
||||
|
||||
export interface ProductGalleryBlockAttributes {
|
||||
cropImages?: boolean;
|
||||
hoverZoom?: boolean;
|
||||
fullScreenOnClick?: boolean;
|
||||
}
|
||||
|
||||
export interface ProductGalleryThumbnailsBlockAttributes {
|
||||
thumbnailsPosition: ThumbnailsPosition;
|
||||
thumbnailsNumberOfThumbnails: number;
|
||||
productGalleryClientId: string;
|
||||
}
|
||||
|
||||
export interface ProductGalleryBlockEditProps {
|
||||
clientId: string;
|
||||
attributes: ProductGalleryThumbnailsBlockAttributes;
|
||||
setAttributes: (
|
||||
newAttributes: ProductGalleryThumbnailsBlockAttributes
|
||||
) => void;
|
||||
cropImages: boolean;
|
||||
hoverZoom: boolean;
|
||||
fullScreenOnClick: boolean;
|
||||
}
|
||||
|
||||
export interface ProductGallerySettingsProps {
|
||||
attributes: ProductGalleryBlockAttributes;
|
||||
setAttributes: ( attributes: ProductGalleryBlockAttributes ) => void;
|
||||
context: ProductGalleryContext;
|
||||
setAttributes: (
|
||||
attributes: Partial< ProductGalleryBlockAttributes >
|
||||
) => void;
|
||||
}
|
||||
|
||||
export interface ProductGalleryThumbnailsSettingsProps {
|
||||
context: ProductGalleryThumbnailsContext;
|
||||
}
|
||||
|
||||
export type ProductGalleryContext = {
|
||||
thumbnailsPosition: ThumbnailsPosition;
|
||||
thumbnailsNumberOfThumbnails: number;
|
||||
productGalleryClientId: string;
|
||||
};
|
||||
|
||||
export type ProductGalleryPagerContext = Pick<
|
||||
ProductGalleryContext,
|
||||
'productGalleryClientId'
|
||||
>;
|
||||
|
||||
export type ProductGalleryLargeImageNextPreviousContext = Pick<
|
||||
ProductGalleryContext,
|
||||
'productGalleryClientId'
|
||||
>;
|
||||
|
||||
export type ProductGalleryThumbnailsContext = Pick<
|
||||
ProductGalleryContext,
|
||||
| 'productGalleryClientId'
|
||||
| 'thumbnailsPosition'
|
||||
| 'thumbnailsNumberOfThumbnails'
|
||||
>;
|
||||
|
||||
export type ProductGalleryAttributes = ProductGalleryThumbnailsBlockAttributes &
|
||||
ProductGalleryBlockAttributes;
|
||||
|
@ -1,178 +0,0 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { BlockAttributes } from '@wordpress/blocks';
|
||||
import { select, dispatch } from '@wordpress/data';
|
||||
import { findBlock } from '@woocommerce/utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ThumbnailsPosition } from './inner-blocks/product-gallery-thumbnails/constants';
|
||||
|
||||
/**
|
||||
* Generates layout attributes based on the position of thumbnails.
|
||||
*
|
||||
* @param {string} thumbnailsPosition - The position of thumbnails ('bottom' or other values).
|
||||
* @return {{type: string, orientation?: string, flexWrap?: string}} - An object representing layout attributes.
|
||||
*/
|
||||
export const getGroupLayoutAttributes = (
|
||||
thumbnailsPosition: string
|
||||
): { type: string; orientation?: string; flexWrap?: string } => {
|
||||
switch ( thumbnailsPosition ) {
|
||||
case 'bottom':
|
||||
// Stack
|
||||
return { type: 'flex', orientation: 'vertical' };
|
||||
case 'off':
|
||||
// Stack
|
||||
return { type: 'flex', orientation: 'vertical' };
|
||||
default:
|
||||
// Row
|
||||
return { type: 'flex', flexWrap: 'nowrap' };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates block attributes based on provided attributes.
|
||||
*
|
||||
* @param {BlockAttributes} attributesToUpdate - The new attributes to set on the block.
|
||||
* @param {BlockAttributes | undefined} block - The block object to update.
|
||||
*/
|
||||
export const updateBlockAttributes = (
|
||||
attributesToUpdate: BlockAttributes,
|
||||
block: BlockAttributes | undefined
|
||||
): void => {
|
||||
if ( block !== undefined ) {
|
||||
const updatedBlock = {
|
||||
...block,
|
||||
attributes: {
|
||||
...block.attributes,
|
||||
...attributesToUpdate,
|
||||
},
|
||||
};
|
||||
|
||||
dispatch( 'core/block-editor' ).updateBlock(
|
||||
block.clientId,
|
||||
updatedBlock
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the layout of group block based on the thumbnails' position.
|
||||
*
|
||||
* @param {ThumbnailsPosition} thumbnailsPosition - The position of thumbnails.
|
||||
* @param {string} clientId - The client ID of the block to update.
|
||||
*/
|
||||
const setGroupBlockLayoutByThumbnailsPosition = (
|
||||
thumbnailsPosition: ThumbnailsPosition,
|
||||
clientId: string
|
||||
): void => {
|
||||
const block = select( 'core/block-editor' ).getBlock( clientId );
|
||||
block?.innerBlocks.forEach( ( innerBlock ) => {
|
||||
if (
|
||||
innerBlock.name === 'core/group' &&
|
||||
innerBlock.attributes.metadata.name === 'Gallery Area'
|
||||
) {
|
||||
updateBlockAttributes(
|
||||
{
|
||||
layout: getGroupLayoutAttributes( thumbnailsPosition ),
|
||||
},
|
||||
innerBlock
|
||||
);
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves inner blocks to a position based on provided attributes.
|
||||
*
|
||||
* @param {BlockAttributes} attributes - The attributes of the parent block.
|
||||
* @param {string} clientId - The clientId of the parent block.
|
||||
*/
|
||||
export const moveInnerBlocksToPosition = (
|
||||
attributes: BlockAttributes,
|
||||
clientId: string
|
||||
): void => {
|
||||
const { getBlock, getBlockRootClientId, getBlockIndex } =
|
||||
select( 'core/block-editor' );
|
||||
const productGalleryBlock = getBlock( clientId );
|
||||
|
||||
if ( productGalleryBlock?.name === 'woocommerce/product-gallery' ) {
|
||||
const { moveBlockToPosition } = dispatch( 'core/block-editor' );
|
||||
const previousLayout = productGalleryBlock.innerBlocks.length
|
||||
? productGalleryBlock.innerBlocks[ 0 ].attributes.layout
|
||||
: null;
|
||||
|
||||
const thumbnailsBlock = findBlock( {
|
||||
blocks: [ productGalleryBlock ],
|
||||
findCondition( block ) {
|
||||
return block.name === 'woocommerce/product-gallery-thumbnails';
|
||||
},
|
||||
} );
|
||||
const largeImageParentBlock = findBlock( {
|
||||
blocks: [ productGalleryBlock ],
|
||||
findCondition( block ) {
|
||||
return Boolean(
|
||||
block.innerBlocks?.find(
|
||||
( innerBlock ) =>
|
||||
innerBlock.name ===
|
||||
'woocommerce/product-gallery-large-image'
|
||||
)
|
||||
);
|
||||
},
|
||||
} );
|
||||
const largeImageParentBlockIndex = getBlockIndex(
|
||||
largeImageParentBlock?.clientId || ''
|
||||
);
|
||||
const thumbnailsBlockIndex = getBlockIndex(
|
||||
thumbnailsBlock?.clientId || ''
|
||||
);
|
||||
|
||||
if (
|
||||
largeImageParentBlock &&
|
||||
thumbnailsBlock &&
|
||||
largeImageParentBlockIndex !== -1 &&
|
||||
thumbnailsBlockIndex !== -1
|
||||
) {
|
||||
const { thumbnailsPosition } = attributes;
|
||||
setGroupBlockLayoutByThumbnailsPosition(
|
||||
thumbnailsPosition,
|
||||
clientId
|
||||
);
|
||||
|
||||
setGroupBlockLayoutByThumbnailsPosition(
|
||||
thumbnailsPosition,
|
||||
productGalleryBlock.innerBlocks[ 0 ].clientId
|
||||
);
|
||||
|
||||
if ( previousLayout ) {
|
||||
const orientation =
|
||||
getGroupLayoutAttributes( thumbnailsPosition ).orientation;
|
||||
updateBlockAttributes(
|
||||
{
|
||||
layout: { ...previousLayout, orientation },
|
||||
},
|
||||
productGalleryBlock.innerBlocks[ 0 ]
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
( ( thumbnailsPosition === 'bottom' ||
|
||||
thumbnailsPosition === 'right' ) &&
|
||||
thumbnailsBlockIndex < largeImageParentBlockIndex ) ||
|
||||
( thumbnailsPosition === 'left' &&
|
||||
thumbnailsBlockIndex > largeImageParentBlockIndex )
|
||||
) {
|
||||
moveBlockToPosition(
|
||||
thumbnailsBlock.clientId,
|
||||
getBlockRootClientId( thumbnailsBlock.clientId ) ||
|
||||
undefined,
|
||||
getBlockRootClientId( largeImageParentBlock.clientId ) ||
|
||||
undefined,
|
||||
largeImageParentBlockIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -31,9 +31,6 @@ export { default as removeCart } from './library/remove-cart';
|
||||
export { default as sparkles } from './library/sparkles';
|
||||
export { default as stacks } from './library/stacks';
|
||||
export { default as thumbUp } from './library/thumb-up';
|
||||
export { default as thumbnailsPositionBottom } from './library/thumbnails-position-bottom';
|
||||
export { default as thumbnailsPositionLeft } from './library/thumbnails-position-left';
|
||||
export { default as thumbnailsPositionRight } from './library/thumbnails-position-right';
|
||||
export { default as toggle } from './library/toggle';
|
||||
export { default as totals } from './library/totals';
|
||||
export { default as woo } from './library/woo';
|
||||
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { SVG } from '@wordpress/primitives';
|
||||
|
||||
const thumbnailsPositionBottom = (
|
||||
<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||
<path
|
||||
d="M19 3H5C3.9 3 3 3.9 3 5V12C3 13.1 3.9 14 5 14H19C20.1 14 21 13.1 21 12V5C21 3.9 20.1 3 19 3ZM5 4.5H19C19.3 4.5 19.5 4.7 19.5 5V8.4L16.5 5.5C16.2 5.2 15.7 5.2 15.5 5.5L11.9 9L9 7C8.7 6.8 8.4 6.8 8.2 7L4.6 9.6V5C4.5 4.7 4.7 4.5 5 4.5ZM19 12.5H5C4.7 12.5 4.5 12.3 4.5 12V11.6L8.6 8.6L11.6 10.5C11.9 10.7 12.3 10.7 12.5 10.4L16 7L19.5 10.4V12C19.5 12.3 19.3 12.5 19 12.5Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<rect
|
||||
x="6.25"
|
||||
y="15.75"
|
||||
width="4.5"
|
||||
height="4.5"
|
||||
rx="1.25"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
<rect
|
||||
x="13.25"
|
||||
y="15.75"
|
||||
width="4.5"
|
||||
height="4.5"
|
||||
rx="1.25"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
</SVG>
|
||||
);
|
||||
|
||||
export default thumbnailsPositionBottom;
|
@ -1,45 +0,0 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { SVG } from '@wordpress/primitives';
|
||||
|
||||
const thumbnailsPositionLeft = (
|
||||
<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 24" fill="none">
|
||||
<g clipPath="url(#clip0_420_11645)">
|
||||
<path
|
||||
d="M22.5 3H10.5C9.4 3 8.5 3.9 8.5 5V19C8.5 20.1 9.4 21 10.5 21H22.5C23.6 21 24.5 20.1 24.5 19V5C24.5 3.9 23.6 3 22.5 3ZM10.5 4.5H22.5C22.8 4.5 23 4.7 23 5V13.4L21 10.5C20.7 10.2 20.2 10.2 20 10.5L16.4 14L13.5 12C13.2 11.8 12.9 11.8 12.7 12L10.1 14.6V5C10 4.7 10.2 4.5 10.5 4.5ZM22.5 19.5H10.5C10.2 19.5 10 19.3 10 19V16.6L13.1 13.6L16.1 15.5C16.4 15.7 16.8 15.7 17 15.4L20.5 12L23 15.4V19C23 19.3 22.8 19.5 22.5 19.5Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<rect
|
||||
x="1.25"
|
||||
y="3.75"
|
||||
width="4.5"
|
||||
height="4.5"
|
||||
rx="1.25"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
<rect
|
||||
x="1.25"
|
||||
y="10.75"
|
||||
width="4.5"
|
||||
height="4.5"
|
||||
rx="1.25"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_420_11645">
|
||||
<rect
|
||||
width="24"
|
||||
height="24"
|
||||
fill="white"
|
||||
transform="translate(0.5)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</SVG>
|
||||
);
|
||||
|
||||
export default thumbnailsPositionLeft;
|
@ -1,45 +0,0 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { SVG } from '@wordpress/primitives';
|
||||
|
||||
const thumbnailsPositionRight = (
|
||||
<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 24" fill="none">
|
||||
<g clipPath="url(#clip0_420_11656)">
|
||||
<path
|
||||
d="M14.5 3H2.5C1.4 3 0.5 3.9 0.5 5V19C0.5 20.1 1.4 21 2.5 21H14.5C15.6 21 16.5 20.1 16.5 19V5C16.5 3.9 15.6 3 14.5 3ZM2.5 4.5H14.5C14.8 4.5 15 4.7 15 5V13.4L13 10.5C12.7 10.2 12.2 10.2 12 10.5L8.4 14L5.5 12C5.2 11.8 4.9 11.8 4.7 12L2.1 14.6V5C2 4.7 2.2 4.5 2.5 4.5ZM14.5 19.5H2.5C2.2 19.5 2 19.3 2 19V16.6L5.1 13.6L8.1 15.5C8.4 15.7 8.8 15.7 9 15.4L12.5 12L15 15.4V19C15 19.3 14.8 19.5 14.5 19.5Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<rect
|
||||
x="19.25"
|
||||
y="3.75"
|
||||
width="4.5"
|
||||
height="4.5"
|
||||
rx="1.25"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
<rect
|
||||
x="19.25"
|
||||
y="10.75"
|
||||
width="4.5"
|
||||
height="4.5"
|
||||
rx="1.25"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_420_11656">
|
||||
<rect
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
transform="translate(0.5)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</SVG>
|
||||
);
|
||||
|
||||
export default thumbnailsPositionRight;
|
@ -72,74 +72,14 @@ test.describe( 'Product Gallery Thumbnails block', () => {
|
||||
} );
|
||||
|
||||
test.describe( 'settings', () => {
|
||||
for ( const position of [ 'left', 'bottom', 'right' ] ) {
|
||||
test( `positions thumbnails to the ${ position }`, async ( {
|
||||
page,
|
||||
editor,
|
||||
} ) => {
|
||||
const layoutClass = {
|
||||
left: 'left-of',
|
||||
bottom: 'below',
|
||||
right: 'right-of',
|
||||
}[ position ];
|
||||
|
||||
await test.step( 'in editor', async () => {
|
||||
const productGalleryBlock = editor.canvas.locator(
|
||||
'[data-type="woocommerce/product-gallery"]'
|
||||
);
|
||||
|
||||
await editor.selectBlocks( productGalleryBlock );
|
||||
await editor.openDocumentSettingsSidebar();
|
||||
await page
|
||||
.getByLabel( 'Editor settings' )
|
||||
.locator( `button[data-value="${ position }"]` )
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
productGalleryBlock.locator(
|
||||
`[data-type="woocommerce/product-gallery-thumbnails"]:${ layoutClass }(
|
||||
[data-type="woocommerce/product-gallery-large-image"]
|
||||
)`
|
||||
)
|
||||
).toBeVisible();
|
||||
|
||||
await editor.saveSiteEditorEntities( {
|
||||
isOnlyCurrentEntityDirty: true,
|
||||
} );
|
||||
} );
|
||||
|
||||
await test.step( 'in frontend', async () => {
|
||||
await page.goto( '/product/v-neck-t-shirt/' );
|
||||
const productGalleryBlock = page.locator(
|
||||
'[data-block-name="woocommerce/product-gallery"]'
|
||||
);
|
||||
|
||||
await expect(
|
||||
productGalleryBlock.locator(
|
||||
'[data-block-name="woocommerce/product-gallery-thumbnails"]'
|
||||
)
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
productGalleryBlock.locator(
|
||||
`[data-block-name="woocommerce/product-gallery-thumbnails"]:${ layoutClass }(
|
||||
[data-block-name="woocommerce/product-gallery-large-image"]
|
||||
)`
|
||||
)
|
||||
).toBeVisible();
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
test( 'rounds the number of thumbnails to integer', async ( {
|
||||
page,
|
||||
editor,
|
||||
} ) => {
|
||||
const productGalleryBlock = editor.canvas.locator(
|
||||
'[data-type="woocommerce/product-gallery"]'
|
||||
);
|
||||
const thumbnailsBlock =
|
||||
editor.canvas.getByLabel( 'Block: Thumbnails' );
|
||||
|
||||
await editor.selectBlocks( productGalleryBlock );
|
||||
await editor.selectBlocks( thumbnailsBlock );
|
||||
|
||||
await editor.openDocumentSettingsSidebar();
|
||||
const numberOfThumbnailInput = page
|
||||
@ -151,7 +91,7 @@ test.describe( 'Product Gallery Thumbnails block', () => {
|
||||
await numberOfThumbnailInput.fill( '4.2' );
|
||||
await page.keyboard.press( 'Enter' );
|
||||
|
||||
const numberOfThumbnailsOnScreen = productGalleryBlock.locator(
|
||||
const numberOfThumbnailsOnScreen = thumbnailsBlock.locator(
|
||||
'.wc-block-product-gallery-thumbnails__thumbnail'
|
||||
);
|
||||
|
||||
|
4
plugins/woocommerce/changelog/add-54512
Normal file
4
plugins/woocommerce/changelog/add-54512
Normal file
@ -0,0 +1,4 @@
|
||||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Product Gallery (Beta): Remove Thumbnails position settings and rely on Core's layour blocks
|
@ -115,7 +115,6 @@ class ProductGallery extends AbstractBlock {
|
||||
$classname_single_image = 'is-single-product-gallery-image';
|
||||
}
|
||||
|
||||
$number_of_thumbnails = $block->attributes['thumbnailsNumberOfThumbnails'] ?? 0;
|
||||
$classname = StyleAttributesUtils::get_classes_by_attributes( $attributes, array( 'extra_classes' ) );
|
||||
$product_gallery_first_image = ProductGalleryUtils::get_product_gallery_image_ids( $product, 1 );
|
||||
$product_gallery_first_image_id = reset( $product_gallery_first_image );
|
||||
@ -131,7 +130,7 @@ class ProductGallery extends AbstractBlock {
|
||||
array(
|
||||
'selectedImageNumber' => 1,
|
||||
'isDialogOpen' => false,
|
||||
'visibleImagesIds' => ProductGalleryUtils::get_product_gallery_image_ids( $product, $number_of_thumbnails, true ),
|
||||
'visibleImagesIds' => ProductGalleryUtils::get_product_gallery_image_ids( $product, null, true ),
|
||||
'dialogVisibleImagesIds' => ProductGalleryUtils::get_product_gallery_image_ids( $product, null, false ),
|
||||
'productId' => $product_id,
|
||||
'elementThatTriggeredDialogOpening' => null,
|
||||
|
@ -29,15 +29,6 @@ class ProductGalleryLargeImageNextPrevious extends AbstractBlock {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the context
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_block_type_uses_context() {
|
||||
return [ 'productGalleryClientId' ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Include and render the block.
|
||||
*
|
||||
|
@ -39,7 +39,7 @@ class ProductGalleryThumbnails extends AbstractBlock {
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_block_type_uses_context() {
|
||||
return [ 'productGalleryClientId', 'postId', 'thumbnailsNumberOfThumbnails', 'thumbnailsPosition', 'mode', 'cropImages' ];
|
||||
return [ 'postId', 'mode', 'cropImages' ];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,7 +120,7 @@ class ProductGalleryThumbnails extends AbstractBlock {
|
||||
* @return string Rendered block type output.
|
||||
*/
|
||||
protected function render( $attributes, $content, $block ) {
|
||||
if ( ! isset( $block->context ) || ! isset( $block->context['thumbnailsPosition'] ) || '' === $block->context['thumbnailsPosition'] ) {
|
||||
if ( ! isset( $block->context ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -146,57 +146,66 @@ class ProductGalleryThumbnails extends AbstractBlock {
|
||||
$crop_images = $block->context['cropImages'] ?? false;
|
||||
$product_gallery_images = ProductGalleryUtils::get_product_gallery_images( $post_id, 'full', array(), 'wc-block-product-gallery-thumbnails__thumbnail', $crop_images );
|
||||
|
||||
if ( $product_gallery_images && count( $product_gallery_images ) > 1 ) {
|
||||
$html = '';
|
||||
$number_of_thumbnails = isset( $block->context['thumbnailsNumberOfThumbnails'] ) && is_numeric( $block->context['thumbnailsNumberOfThumbnails'] ) ? $block->context['thumbnailsNumberOfThumbnails'] : 3;
|
||||
$thumbnails_count = 1;
|
||||
if ( ! $product_gallery_images || count( $product_gallery_images ) <= 1 ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach ( $product_gallery_images as $product_gallery_image_html ) {
|
||||
// Limit the number of thumbnails only in the standard mode (and not in dialog).
|
||||
if ( $this->limit_thumbnails( $thumbnails_count, $number_of_thumbnails ) ) {
|
||||
break;
|
||||
}
|
||||
$html = '';
|
||||
$default_number_of_thumbnails = 3;
|
||||
$number_of_thumbnails = isset( $attributes['numberOfThumbnails'] ) && is_numeric( $attributes['numberOfThumbnails'] ) ? $attributes['numberOfThumbnails'] : $default_number_of_thumbnails;
|
||||
$number_of_images = count( $product_gallery_images );
|
||||
// If the number of thumbnails is greater than the number of images, set the number of thumbnails to the number of images.
|
||||
// But not less than than 3 (default number of thumbnails).
|
||||
$thumbnails_layout = max( min( $number_of_images, $number_of_thumbnails ), $default_number_of_thumbnails );
|
||||
$number_of_thumbnails_class = 'wc-block-product-gallery-thumbnails--number-of-thumbnails-' . $thumbnails_layout;
|
||||
$thumbnails_count = 1;
|
||||
|
||||
$remaining_thumbnails_count = count( $product_gallery_images ) - $number_of_thumbnails;
|
||||
|
||||
// Display view all if this is the last visible thumbnail and there are more images.
|
||||
if ( $this->should_display_view_all( $thumbnails_count, $product_gallery_images, $number_of_thumbnails ) ) {
|
||||
$product_gallery_image_html = $this->inject_view_all( $product_gallery_image_html, $this->generate_view_all_html( $remaining_thumbnails_count ) );
|
||||
}
|
||||
|
||||
$processor = new \WP_HTML_Tag_Processor( $product_gallery_image_html );
|
||||
|
||||
if ( $processor->next_tag( 'img' ) ) {
|
||||
$processor->set_attribute( 'data-wc-on--keydown', 'actions.onThumbnailKeyDown' );
|
||||
$processor->set_attribute( 'tabindex', '0' );
|
||||
$processor->set_attribute(
|
||||
'data-wc-on--click',
|
||||
'actions.selectImage'
|
||||
);
|
||||
|
||||
$html .= $processor->get_updated_html();
|
||||
} else {
|
||||
$html .= $product_gallery_image_html;
|
||||
}
|
||||
|
||||
++$thumbnails_count;
|
||||
foreach ( $product_gallery_images as $product_gallery_image_html ) {
|
||||
// Limit the number of thumbnails only in the standard mode (and not in dialog).
|
||||
if ( $this->limit_thumbnails( $thumbnails_count, $number_of_thumbnails ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$allowed_html = wp_kses_allowed_html( 'post' );
|
||||
$allowed_html['img']['tabindex'] = true;
|
||||
$remaining_thumbnails_count = $number_of_images - $number_of_thumbnails;
|
||||
|
||||
return sprintf(
|
||||
'<div class="wc-block-product-gallery-thumbnails wp-block-woocommerce-product-gallery-thumbnails %1$s" style="%2$s" data-wc-interactive=\'%4$s\'>
|
||||
%3$s
|
||||
</div>',
|
||||
esc_attr( $classes_and_styles['classes'] ),
|
||||
esc_attr( $classes_and_styles['styles'] ),
|
||||
wp_kses(
|
||||
$html,
|
||||
$allowed_html
|
||||
),
|
||||
wp_json_encode( array( 'namespace' => 'woocommerce/product-gallery' ), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP )
|
||||
);
|
||||
// Display view all if this is the last visible thumbnail and there are more images.
|
||||
if ( $this->should_display_view_all( $thumbnails_count, $product_gallery_images, $number_of_thumbnails ) ) {
|
||||
$product_gallery_image_html = $this->inject_view_all( $product_gallery_image_html, $this->generate_view_all_html( $remaining_thumbnails_count ) );
|
||||
}
|
||||
|
||||
$processor = new \WP_HTML_Tag_Processor( $product_gallery_image_html );
|
||||
|
||||
if ( $processor->next_tag( 'img' ) ) {
|
||||
$processor->add_class( 'wc-block-product-gallery-thumbnails__image' );
|
||||
$processor->set_attribute( 'data-wc-on--keydown', 'actions.onThumbnailKeyDown' );
|
||||
$processor->set_attribute( 'tabindex', '0' );
|
||||
$processor->set_attribute(
|
||||
'data-wc-on--click',
|
||||
'actions.selectImage'
|
||||
);
|
||||
|
||||
$html .= $processor->get_updated_html();
|
||||
} else {
|
||||
$html .= $product_gallery_image_html;
|
||||
}
|
||||
|
||||
++$thumbnails_count;
|
||||
}
|
||||
|
||||
$allowed_html = wp_kses_allowed_html( 'post' );
|
||||
$allowed_html['img']['tabindex'] = true;
|
||||
|
||||
return sprintf(
|
||||
'<div class="wc-block-product-gallery-thumbnails wp-block-woocommerce-product-gallery-thumbnails %1$s" style="%2$s" data-wc-interactive=\'%4$s\'>
|
||||
%3$s
|
||||
</div>',
|
||||
esc_attr( $classes_and_styles['classes'] . ' ' . $number_of_thumbnails_class ),
|
||||
esc_attr( $classes_and_styles['styles'] ),
|
||||
wp_kses(
|
||||
$html,
|
||||
$allowed_html
|
||||
),
|
||||
wp_json_encode( array( 'namespace' => 'woocommerce/product-gallery' ), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user