Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 3ae7314

Browse files
authored
Featured Product block: Allow custom background image selecton (#322)
* Add media icon to toolbar, save selected media ID and src as attributes * Use the selected image instead of the product image, if set * Unset the selected image when a new product is selected
1 parent 07b0d70 commit 3ae7314

File tree

4 files changed

+104
-10
lines changed

4 files changed

+104
-10
lines changed

assets/js/blocks/featured-product/block.js

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import {
77
AlignmentToolbar,
88
BlockControls,
99
InspectorControls,
10+
MediaUpload,
11+
MediaUploadCheck,
1012
PanelColorSettings,
1113
RichText,
1214
withColors,
1315
} from '@wordpress/editor';
1416
import {
1517
Button,
18+
IconButton,
1619
PanelBody,
1720
Placeholder,
1821
RangeControl,
@@ -24,23 +27,41 @@ import {
2427
import classnames from 'classnames';
2528
import { Component, Fragment } from '@wordpress/element';
2629
import { compose } from '@wordpress/compose';
27-
import { debounce } from 'lodash';
30+
import { debounce, isObject } from 'lodash';
2831
import PropTypes from 'prop-types';
2932

3033
/**
3134
* Internal dependencies
3235
*/
3336
import ProductControl from '../../components/product-control';
37+
import {
38+
getImageSrcFromProduct,
39+
getImageIdFromProduct,
40+
} from '../../utils/products';
3441

35-
// Copied from core/cover, updated for product.
36-
function backgroundImageStyles( { images = [] } ) {
37-
if ( images.length ) {
38-
const url = images[ 0 ].src;
42+
/**
43+
* Generate a style object given either a product object or URL to an image.
44+
*
45+
* @param {object|string} url A product object as returned from the API, or an image URL.
46+
* @return {object} A style object with a backgroundImage set (if a valid image is provided).
47+
*/
48+
function backgroundImageStyles( url ) {
49+
// If `url` is an object, it's actually a product.
50+
if ( isObject( url ) ) {
51+
url = getImageSrcFromProduct( url );
52+
}
53+
if ( url ) {
3954
return { backgroundImage: `url(${ url })` };
4055
}
4156
return {};
4257
}
4358

59+
/**
60+
* Convert the selected ratio to the correct background class.
61+
*
62+
* @param {number} ratio Selected opacity from 0 to 100.
63+
* @return {string} The class name, if applicable (not used for ratio 0 or 50).
64+
*/
4465
function dimRatioToClass( ratio ) {
4566
return ratio === 0 || ratio === 50 ?
4667
null :
@@ -107,7 +128,7 @@ class FeaturedProduct extends Component {
107128
selected={ attributes.productId || 0 }
108129
onChange={ ( value = [] ) => {
109130
const id = value[ 0 ] ? value[ 0 ].id : 0;
110-
setAttributes( { productId: id } );
131+
setAttributes( { productId: id, mediaId: 0, mediaSrc: '' } );
111132
} }
112133
/>
113134
</PanelBody>
@@ -173,7 +194,7 @@ class FeaturedProduct extends Component {
173194
selected={ attributes.productId || 0 }
174195
onChange={ ( value = [] ) => {
175196
const id = value[ 0 ] ? value[ 0 ].id : 0;
176-
setAttributes( { productId: id } );
197+
setAttributes( { productId: id, mediaId: 0, mediaSrc: '' } );
177198
} }
178199
/>
179200
<Button isDefault onClick={ onDone }>
@@ -205,8 +226,11 @@ class FeaturedProduct extends Component {
205226
dimRatioToClass( dimRatio ),
206227
contentAlign !== 'center' && `has-${ contentAlign }-content`
207228
);
229+
const mediaId = attributes.mediaId || getImageIdFromProduct( product );
208230

209-
const style = !! product ? backgroundImageStyles( product ) : {};
231+
const style = !! product ?
232+
backgroundImageStyles( attributes.mediaSrc || product ) :
233+
{};
210234
if ( overlayColor.color ) {
211235
style.backgroundColor = overlayColor.color;
212236
}
@@ -230,6 +254,25 @@ class FeaturedProduct extends Component {
230254
},
231255
] }
232256
/>
257+
<MediaUploadCheck>
258+
<Toolbar>
259+
<MediaUpload
260+
onSelect={ ( media ) => {
261+
setAttributes( { mediaId: media.id, mediaSrc: media.url } );
262+
} }
263+
allowedTypes={ [ 'image' ] }
264+
value={ mediaId }
265+
render={ ( { open } ) => (
266+
<IconButton
267+
className="components-toolbar__control"
268+
label={ __( 'Edit media' ) }
269+
icon="format-image"
270+
onClick={ open }
271+
/>
272+
) }
273+
/>
274+
</Toolbar>
275+
</MediaUploadCheck>
233276
</BlockControls>
234277
{ ! attributes.editMode && this.getInspectorControls() }
235278
{ editMode ? (

assets/js/blocks/featured-product/index.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ registerBlockType( 'woocommerce/featured-product', {
5050
default: true,
5151
},
5252

53+
/**
54+
* ID for a custom image, overriding the product's featured image.
55+
*/
56+
mediaId: {
57+
type: 'number',
58+
default: 0,
59+
},
60+
61+
/**
62+
* URL for a custom image, overriding the product's featured image.
63+
*/
64+
mediaSrc: {
65+
type: 'string',
66+
default: '',
67+
},
68+
5369
/**
5470
* The overlay color, from the color list.
5571
*/

assets/js/utils/products.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Get the src of the first image attached to a product (the featured image).
3+
*
4+
* @param {array} images The array of images, destructured from the product object.
5+
* @return {string} The full URL to the image.
6+
*/
7+
export function getImageSrcFromProduct( { images = [] } ) {
8+
if ( images.length ) {
9+
return images[ 0 ].src || '';
10+
}
11+
return '';
12+
}
13+
14+
/**
15+
* Get the ID of the first image attached to a product (the featured image).
16+
*
17+
* @param {array} images The array of images, destructured from the product object.
18+
* @return {number} The ID of the image.
19+
*/
20+
export function getImageIdFromProduct( { images = [] } ) {
21+
if ( images.length ) {
22+
return images[ 0 ].id || 0;
23+
}
24+
return 0;
25+
}

includes/blocks/class-wc-block-featured-product.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class WC_Block_Featured_Product {
3030
'contentAlign' => 'center',
3131
'dimRatio' => 50,
3232
'linkText' => false,
33+
'mediaId' => 0,
34+
'mediaSrc' => '',
3335
'showDesc' => true,
3436
'showPrice' => true,
3537
);
@@ -98,8 +100,16 @@ public static function render( $attributes, $content ) {
98100
* @return string
99101
*/
100102
public static function get_styles( $attributes, $product ) {
101-
$image = self::get_image( $product, ( 'none' !== $attributes['align'] ) ? 'large' : 'full' );
102-
$style = sprintf( 'background-image:url(%s);', esc_url( $image ) );
103+
$image_size = ( 'none' !== $attributes['align'] ) ? 'full' : 'large';
104+
if ( $attributes['mediaId'] ) {
105+
$image = wp_get_attachment_image_url( $attributes['mediaId'], $image_size );
106+
} else {
107+
$image = self::get_image( $product, $image_size );
108+
}
109+
110+
if ( ! empty( $image ) ) {
111+
$style = sprintf( 'background-image:url(%s);', esc_url( $image ) );
112+
}
103113

104114
if ( isset( $attributes['customOverlayColor'] ) ) {
105115
$style .= sprintf( 'background-color:%s;', esc_attr( $attributes['customOverlayColor'] ) );

0 commit comments

Comments
 (0)