Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gallery block: add gap support / block spacing #38164

Merged
merged 22 commits into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
92d75ab
Try using a custom gallery specific var to calculate image sizes base…
Mar 10, 2022
895e799
Add style via same portal as layout styles instead of inline with block
Jan 24, 2022
e3ed7e8
Add doc comment to new render callback
Jan 24, 2022
f8416a4
Switch to using the block id as the selector for custom gap property
Jan 25, 2022
d65734d
Set default block gap in frontend
Jan 25, 2022
2775050
Fix issue with block deprecations failing
Jan 25, 2022
8083ed8
Fix linting issue
Jan 25, 2022
f0332b3
Only add gap styles on web
Jan 25, 2022
1ad43d7
Only run useContext on web
Jan 27, 2022
d62f967
Move the gap styles to a separate component so easier to load for web…
Jan 28, 2022
7e3ce19
Don't display empty placeholder div if Gallery block has images
Jan 28, 2022
d17bb19
Return null from GapStyle if no gap or style element set
Jan 28, 2022
d5a0a8d
Adding the `block_core_gallery_render` render callback to the registe…
ramonjd Feb 11, 2022
8391b9c
Remove the margins on non-cropped images as not needed with move to gap
Feb 20, 2022
10b5865
Add margin reset back
Feb 22, 2022
045de4f
Add back the block margins that are being reset by the
Feb 22, 2022
f90a2e0
Make sure deprecated styles are not applied to new gallery blocks
Feb 22, 2022
3be7cbb
Remove 0 margin setting from editor css and increase specificity of d…
Feb 22, 2022
1bd5330
Reduce specificity of layout margin reset
Feb 22, 2022
c5d6b47
Revert "Reduce specificity of layout margin reset"
Mar 10, 2022
9b39cf3
Change the gap fallback setting from 0.5em to the previous default of…
Mar 13, 2022
c0be8b4
Revert "Change the gap fallback setting from 0.5em to the previous de…
Mar 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ Display multiple images in a rich gallery. ([Source](https://github.com/WordPres

- **Name:** core/gallery
- **Category:** media
- **Supports:** align, anchor, ~~html~~
- **Supports:** align, anchor, spacing (blockGap), units (em, px, rem, vh, vw), ~~html~~
- **Attributes:** allowResize, caption, columns, fixedHeight, ids, imageCrop, images, linkTarget, linkTo, shortCodeTransforms, sizeSlug

## Group
Expand Down
17 changes: 16 additions & 1 deletion packages/block-library/src/gallery/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,22 @@
"supports": {
"anchor": true,
"align": true,
"html": false
"html": false,
"units": [ "px", "em", "rem", "vh", "vw" ],
"spacing": {
"blockGap": true,
"__experimentalDefaultControls": {
"blockGap": true
}
},
"__experimentalLayout": {
"allowSwitching": false,
"allowInheriting": false,
"allowEditing": false,
"default": {
"type": "flex"
}
}
},
"editorStyle": "wp-block-gallery-editor",
"style": "wp-block-gallery"
Expand Down
4 changes: 2 additions & 2 deletions packages/block-library/src/gallery/deprecated.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Deprecated gallery styles pre refactoring to use nested image blocks.
// https://github.com/WordPress/gutenberg/pull/25940.
.wp-block-gallery,
.blocks-gallery-grid {
.wp-block-gallery:not(.has-nested-images),
.blocks-gallery-grid:not(.has-nested-images) {
display: flex;
flex-wrap: wrap;
list-style-type: none;
Expand Down
7 changes: 7 additions & 0 deletions packages/block-library/src/gallery/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import useImageSizes from './use-image-sizes';
import useShortCodeTransform from './use-short-code-transform';
import useGetNewImages from './use-get-new-images';
import useGetMedia from './use-get-media';
import GapStyles from './gap-styles';

const MAX_COLUMNS = 8;
const linkOptions = [
Expand Down Expand Up @@ -548,6 +549,12 @@ function GalleryEdit( props ) {
/>
</BlockControls>
{ noticeUI }
{ Platform.isWeb && (
<GapStyles
blockGap={ attributes.style?.spacing?.blockGap }
clientId={ clientId }
/>
) }
<Gallery
{ ...props }
images={ images }
Expand Down
1 change: 0 additions & 1 deletion packages/block-library/src/gallery/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ figure.wp-block-gallery {
// See https://github.com/WordPress/gutenberg/pull/10358

display: block;
margin: 0;
&.has-nested-images {
.components-drop-zone {
display: none;
Expand Down
15 changes: 8 additions & 7 deletions packages/block-library/src/gallery/gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,14 @@ export const Gallery = ( props ) => {
) }
>
{ children }

<View
className="blocks-gallery-media-placeholder-wrapper"
onClick={ removeCaptionFocus }
>
{ mediaPlaceholder }
</View>
{ isSelected && ! children && (
<View
className="blocks-gallery-media-placeholder-wrapper"
onClick={ removeCaptionFocus }
>
{ mediaPlaceholder }
</View>
) }
<RichTextVisibilityHelper
isHidden={ ! isSelected && RichText.isEmpty( caption ) }
captionFocused={ captionFocused }
Expand Down
21 changes: 21 additions & 0 deletions packages/block-library/src/gallery/gap-styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* WordPress dependencies
*/
import { BlockList } from '@wordpress/block-editor';
import { useContext, createPortal } from '@wordpress/element';

export default function GapStyles( { blockGap, clientId } ) {
const styleElement = useContext( BlockList.__unstableElementContext );

const gap = blockGap
? `#block-${ clientId } { --wp--style--unstable-gallery-gap: ${ blockGap } }`
: `#block-${ clientId } { --wp--style--unstable-gallery-gap: var( --wp--style--block-gap, 0.5em ) }`;

const GapStyle = () => {
return <style>{ gap }</style>;
};

return gap && styleElement
? createPortal( <GapStyle />, styleElement )
: null;
}
43 changes: 42 additions & 1 deletion packages/block-library/src/gallery/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,53 @@ function block_core_gallery_data_id_backcompatibility( $parsed_block ) {

add_filter( 'render_block_data', 'block_core_gallery_data_id_backcompatibility' );

/**
* Adds a style tag for the --wp--style--unstable-gallery-gap var.
*
* The Gallery block needs to recalculate Image block width based on
* the current gap setting in order to maintain the number of flex columns
* so a css var is added to allow this.
*
* @param array $attributes Attributes of the block being rendered.
* @param string $content Content of the block being rendered.
* @return string The content of the block being rendered.
*/
function block_core_gallery_render( $attributes, $content ) {
$gap = _wp_array_get( $attributes, array( 'style', 'spacing', 'blockGap' ) );
// Skip if gap value contains unsupported characters.
// Regex for CSS value borrowed from `safecss_filter_attr`, and used here
// because we only want to match against the value, not the CSS attribute.
$gap = preg_match( '%[\\\(&=}]|/\*%', $gap ) ? null : $gap;
$id = uniqid();
$class = 'wp-block-gallery-' . $id;
Comment on lines +52 to +53
Copy link
Member

@westonruter westonruter Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed this. This should rather have been:

$class     = wp_unique_id( 'wp-block-gallery-' );

See #38889 and #38891

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've applied this change in #39983.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this fix @westonruter

$content = preg_replace(
'/' . preg_quote( 'class="', '/' ) . '/',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why we have this preg_quote here as it doesn't do anything. We generally never need to RegExp-quote a static string literal, especially if the string value doesn't have the delimiter we're escaping in it, as this one does.

Note too that this PCRE pattern isn't doing anything that simple string substitution doesn't do already - why did we use a preg_replace() here instead of str_replace()?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too sure why it was used originally but I believe the implementation here was duplicated from layout.php as it matches the logic used here: https://github.com/WordPress/gutenberg/blob/trunk/lib/block-supports/layout.php#L318, which doesn't appear to have been updated from when the Layout block support was initially introduced back in: #29335, unless I'm missing something.

It sound like str_replace() would work too and be simpler to read. If we update it here it'd be good to update it in the Layout support too for consistency. And of course I'm hopeful for us to be able to switch over to WP_HTML_Walker at some point 😀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it was definitely a case of copy pasta from layout, so @youknowriad is potentially the one that knows the reason for the use of preg_replace if there was one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like $content = str_replace( 'wp-block-gallery', "wp-block-gallery $class", $content ); seems to work in this instance. There are several nested <figure class="..., hence the use of the classname.

Doing a dodgy microtime speed test with 10 galleries on a page, the difference appears negligible on my machine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing a dodgy microtime speed test with 10 galleries on a page, the difference appears negligible on my machine.

My question was definitely geared towards "this looks obviously wrong so I'm confident that I'm misunderstanding the intent of the code and its implementation" more than "this could potentially be slower than another micro-optimized approach."

Thanks for the clarification y'all. In the meantime, would someone be willing to simplify so this doesn't confuse even more folks? To be clear, I'm not commenting on the method of HTML modification, just on the superfluous use of preg_ functions which emulate str_ varieties.

Well, it may be the case that str_replace() won't only replace a single instance. If that's important we might need to stick with preg_ but we absolutely don't need preg_quote() because it's being passed a literal with no quotable characters.

$content = preg_replace( '/class="/', 'class="' . $class . ' ', $content, 1 );

And of course I'm hopeful for us to be able to switch over to #42485 at some point 😀

Yes indeed

$w = new WP_HTML_Walker( $html );
$w->next_tag( [ 'class_name' => "wp-block-gallery-{$id}" ] );
$w->add_class( $class );
$content = (string) $w;

'class="' . $class . ' ',
$content,
1
);
$gap_value = $gap ? $gap : 'var( --wp--style--block-gap, 0.5em )';
andrewserong marked this conversation as resolved.
Show resolved Hide resolved
$style = '.' . $class . '{ --wp--style--unstable-gallery-gap: ' . $gap_value . '}';
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
// Ideally styles should be loaded in the head, but blocks may be parsed
// after that, so loading in the footer for now.
// See https://core.trac.wordpress.org/ticket/53494.
add_action(
'wp_footer',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are issues with adding this to the footer, but this is the same temporary approach as taken by the layout support here, and can hopefully be sorted as part of the new style engine implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's becoming more a more clear that we should look at having a function to do this for us (inject block support style tag) and reuse in layout, duotone and here. (the wp_footer becomes just an implementation detail of it)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note here that a function has been introduced on a separate branch to use the right hook (header or footer, depending on the theme), I guess it should be used here.

function () use ( $style ) {
echo '<style> ' . $style . '</style>';
}
);
return $content;
}
/**
* Registers the `core/gallery` block on server.
*/
function register_block_core_gallery() {
register_block_type_from_metadata(
__DIR__ . '/gallery'
__DIR__ . '/gallery',
array(
'render_callback' => 'block_core_gallery_render',
)
);
}

Expand Down
55 changes: 11 additions & 44 deletions packages/block-library/src/gallery/style.scss
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
// Import styles for rendering the static content of deprecated gallery versions.
@import "./deprecated.scss";

// The following is a temporary override until flex layout supports
// an align items setting of normal.
figure.wp-block-gallery.has-nested-images {
align-items: normal;
}
// Styles for current version of gallery block.
.wp-block-gallery.has-nested-images {
display: flex;
flex-wrap: wrap;
// Need bogus :not(#individual-image) to override long :not()
// specificity chain on default image block on front end.
figure.wp-block-image:not(#individual-image) {
// Add space between thumbnails, and unset right most thumbnails later.
margin: 0 var(--gallery-block--gutter-size, #{$grid-unit-20}) var(--gallery-block--gutter-size, #{$grid-unit-20}) 0;

&:last-of-type:not(#individual-image) {
margin-right: 0;
}

width: calc(50% - (var(--gallery-block--gutter-size, #{$grid-unit-20}) / 2));

&:nth-of-type(even) {
margin-right: 0;
}
width: calc(50% - (var(--wp--style--unstable-gallery-gap, #{$grid-unit-20}) / 2));
margin: 0;
}

figure.wp-block-image {
display: flex;
flex-grow: 1;
justify-content: center;
position: relative;
margin-top: auto;
margin-bottom: auto;
flex-direction: column;
max-width: 100%;

Expand Down Expand Up @@ -96,17 +87,9 @@

// Non cropped images.
&:not(.is-cropped) {

figure.wp-block-image:not(#individual-image) {
margin-top: 0;
margin-bottom: auto;
img {
margin-bottom: var(--gallery-block--gutter-size, #{$grid-unit-20});
}

figcaption {
bottom: var(--gallery-block--gutter-size, #{$grid-unit-20});
}
}
}

Expand All @@ -128,43 +111,27 @@
}

&.columns-1 figure.wp-block-image:not(#individual-image) {
margin-right: 0;
width: 100%;
}

// Beyond mobile viewports, we allow up to 8 columns.
@include break-small {
@for $i from 3 through 8 {
&.columns-#{ $i } figure.wp-block-image:not(#individual-image) {
margin-right: var(--gallery-block--gutter-size, #{$grid-unit-20});
width: calc(#{math.div(100%, $i)} - (var(--gallery-block--gutter-size, #{$grid-unit-20}) * #{math.div($i - 1, $i)}));

}
width: calc(#{math.div(100%, $i)} - (var(--wp--style--unstable-gallery-gap, #{$grid-unit-20}) * #{math.div($i - 1, $i)}));

// Prevent collapsing margin while sibling is being dragged.
&.columns-#{$i} figure.wp-block-image:not(#individual-image).is-dragging ~ figure.wp-block-image:not(#individual-image) {
margin-right: var(--gallery-block--gutter-size, #{$grid-unit-20});
}
}
// Unset the right margin on every rightmost gallery item to ensure center balance.
@for $column-count from 1 through 8 {
&.columns-#{$column-count} figure.wp-block-image:not(#individual-image):nth-of-type(#{ $column-count }n) {
margin-right: 0;
}
}
// If number of columns not explicitly set default to 3 columns if 3 or more images.
&.columns-default {
figure.wp-block-image:not(#individual-image) {
margin-right: var(--gallery-block--gutter-size, #{$grid-unit-20});
width: calc(33.33% - (var(--gallery-block--gutter-size, 16px) * #{math.div(2, 3)}));
}
figure.wp-block-image:not(#individual-image):nth-of-type(3n+3) {
margin-right: 0;

width: calc(33.33% - (var(--wp--style--unstable-gallery-gap, 16px) * #{math.div(2, 3)}));
}
// If only 2 child images use 2 columns.
figure.wp-block-image:not(#individual-image):first-child:nth-last-child(2),
figure.wp-block-image:not(#individual-image):first-child:nth-last-child(2) ~ figure.wp-block-image:not(#individual-image) {
width: calc(50% - (var(--gallery-block--gutter-size, 16px) * 0.5));
width: calc(50% - (var(--wp--style--unstable-gallery-gap, 16px) * 0.5));
}
// For a single image set to 100%.
figure.wp-block-image:not(#individual-image):first-child:nth-last-child(1) {
Expand Down