@wordpress/block-library 8.21.0 → 8.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/avatar/index.js +5 -1
  3. package/build/avatar/index.js.map +1 -1
  4. package/build/block/edit-title.native.js +11 -3
  5. package/build/block/edit-title.native.js.map +1 -1
  6. package/build/block/edit.js +3 -3
  7. package/build/block/edit.js.map +1 -1
  8. package/build/column/edit.js +2 -1
  9. package/build/column/edit.js.map +1 -1
  10. package/build/column/edit.native.js +2 -1
  11. package/build/column/edit.native.js.map +1 -1
  12. package/build/columns/edit.native.js +2 -1
  13. package/build/columns/edit.native.js.map +1 -1
  14. package/build/cover/controls.native.js +2 -1
  15. package/build/cover/controls.native.js.map +1 -1
  16. package/build/cover/edit/index.js +2 -1
  17. package/build/cover/edit/index.js.map +1 -1
  18. package/build/cover/edit/inspector-controls.js +2 -1
  19. package/build/cover/edit/inspector-controls.js.map +1 -1
  20. package/build/file/view.js +1 -1
  21. package/build/file/view.js.map +1 -1
  22. package/build/form/edit.js +2 -2
  23. package/build/form/edit.js.map +1 -1
  24. package/build/form/index.js +25 -5
  25. package/build/form/index.js.map +1 -1
  26. package/build/form/variations.js +1 -1
  27. package/build/form/variations.js.map +1 -1
  28. package/build/form-input/index.js +2 -2
  29. package/build/form-input/index.js.map +1 -1
  30. package/build/form-input/variations.js +7 -7
  31. package/build/form-input/variations.js.map +1 -1
  32. package/build/form-submission-notification/index.js +1 -1
  33. package/build/form-submission-notification/index.js.map +1 -1
  34. package/build/form-submission-notification/variations.js +4 -4
  35. package/build/form-submission-notification/variations.js.map +1 -1
  36. package/build/form-submit-button/index.js +2 -2
  37. package/build/form-submit-button/index.js.map +1 -1
  38. package/build/group/edit.js +2 -11
  39. package/build/group/edit.js.map +1 -1
  40. package/build/html/preview.js +2 -4
  41. package/build/html/preview.js.map +1 -1
  42. package/build/image/image.js +11 -5
  43. package/build/image/image.js.map +1 -1
  44. package/build/image/view.js +10 -20
  45. package/build/image/view.js.map +1 -1
  46. package/build/missing/edit.native.js +46 -8
  47. package/build/missing/edit.native.js.map +1 -1
  48. package/build/paragraph/edit.js +1 -1
  49. package/build/paragraph/edit.js.map +1 -1
  50. package/build/post-featured-image/dimension-controls.js +2 -2
  51. package/build/post-featured-image/dimension-controls.js.map +1 -1
  52. package/build/post-terms/edit.js +2 -2
  53. package/build/post-terms/edit.js.map +1 -1
  54. package/build/query/edit/enhanced-pagination-modal.js +27 -13
  55. package/build/query/edit/enhanced-pagination-modal.js.map +1 -1
  56. package/build/query/edit/inspector-controls/enhanced-pagination-control.js +15 -12
  57. package/build/query/edit/inspector-controls/enhanced-pagination-control.js.map +1 -1
  58. package/build/query/utils.js +29 -8
  59. package/build/query/utils.js.map +1 -1
  60. package/build/query/view.js +4 -2
  61. package/build/query/view.js.map +1 -1
  62. package/build/search/edit.js +1 -2
  63. package/build/search/edit.js.map +1 -1
  64. package/build/social-link/edit.native.js +7 -19
  65. package/build/social-link/edit.native.js.map +1 -1
  66. package/build/spacer/controls.js +3 -3
  67. package/build/spacer/controls.js.map +1 -1
  68. package/build/spacer/controls.native.js +2 -1
  69. package/build/spacer/controls.native.js.map +1 -1
  70. package/build/spacer/edit.js +1 -1
  71. package/build/spacer/edit.js.map +1 -1
  72. package/build/spacer/edit.native.js +5 -1
  73. package/build/spacer/edit.native.js.map +1 -1
  74. package/build/tag-cloud/edit.js +2 -1
  75. package/build/tag-cloud/edit.js.map +1 -1
  76. package/build/template-part/edit/inner-blocks.js +2 -2
  77. package/build/template-part/edit/inner-blocks.js.map +1 -1
  78. package/build/term-description/index.js +0 -1
  79. package/build/term-description/index.js.map +1 -1
  80. package/build-module/avatar/index.js +5 -1
  81. package/build-module/avatar/index.js.map +1 -1
  82. package/build-module/block/edit-title.native.js +12 -4
  83. package/build-module/block/edit-title.native.js.map +1 -1
  84. package/build-module/block/edit.js +3 -3
  85. package/build-module/block/edit.js.map +1 -1
  86. package/build-module/column/edit.js +3 -2
  87. package/build-module/column/edit.js.map +1 -1
  88. package/build-module/column/edit.native.js +3 -2
  89. package/build-module/column/edit.native.js.map +1 -1
  90. package/build-module/columns/edit.native.js +3 -2
  91. package/build-module/columns/edit.native.js.map +1 -1
  92. package/build-module/cover/controls.native.js +3 -2
  93. package/build-module/cover/controls.native.js.map +1 -1
  94. package/build-module/cover/edit/index.js +3 -2
  95. package/build-module/cover/edit/index.js.map +1 -1
  96. package/build-module/cover/edit/inspector-controls.js +3 -2
  97. package/build-module/cover/edit/inspector-controls.js.map +1 -1
  98. package/build-module/file/view.js +2 -2
  99. package/build-module/file/view.js.map +1 -1
  100. package/build-module/form/edit.js +2 -2
  101. package/build-module/form/edit.js.map +1 -1
  102. package/build-module/form/index.js +29 -5
  103. package/build-module/form/index.js.map +1 -1
  104. package/build-module/form/variations.js +1 -1
  105. package/build-module/form/variations.js.map +1 -1
  106. package/build-module/form-input/index.js +2 -2
  107. package/build-module/form-input/index.js.map +1 -1
  108. package/build-module/form-input/variations.js +7 -7
  109. package/build-module/form-input/variations.js.map +1 -1
  110. package/build-module/form-submission-notification/index.js +1 -1
  111. package/build-module/form-submission-notification/index.js.map +1 -1
  112. package/build-module/form-submission-notification/variations.js +4 -4
  113. package/build-module/form-submission-notification/variations.js.map +1 -1
  114. package/build-module/form-submit-button/index.js +2 -2
  115. package/build-module/form-submit-button/index.js.map +1 -1
  116. package/build-module/group/edit.js +3 -12
  117. package/build-module/group/edit.js.map +1 -1
  118. package/build-module/html/preview.js +2 -4
  119. package/build-module/html/preview.js.map +1 -1
  120. package/build-module/image/image.js +12 -6
  121. package/build-module/image/image.js.map +1 -1
  122. package/build-module/image/view.js +10 -20
  123. package/build-module/image/view.js.map +1 -1
  124. package/build-module/missing/edit.native.js +47 -9
  125. package/build-module/missing/edit.native.js.map +1 -1
  126. package/build-module/paragraph/edit.js +2 -2
  127. package/build-module/paragraph/edit.js.map +1 -1
  128. package/build-module/post-featured-image/dimension-controls.js +3 -3
  129. package/build-module/post-featured-image/dimension-controls.js.map +1 -1
  130. package/build-module/post-terms/edit.js +2 -2
  131. package/build-module/post-terms/edit.js.map +1 -1
  132. package/build-module/query/edit/enhanced-pagination-modal.js +28 -14
  133. package/build-module/query/edit/enhanced-pagination-modal.js.map +1 -1
  134. package/build-module/query/edit/inspector-controls/enhanced-pagination-control.js +17 -14
  135. package/build-module/query/edit/inspector-controls/enhanced-pagination-control.js.map +1 -1
  136. package/build-module/query/utils.js +27 -5
  137. package/build-module/query/utils.js.map +1 -1
  138. package/build-module/query/view.js +4 -2
  139. package/build-module/query/view.js.map +1 -1
  140. package/build-module/search/edit.js +2 -3
  141. package/build-module/search/edit.js.map +1 -1
  142. package/build-module/social-link/edit.native.js +8 -20
  143. package/build-module/social-link/edit.native.js.map +1 -1
  144. package/build-module/spacer/controls.js +4 -4
  145. package/build-module/spacer/controls.js.map +1 -1
  146. package/build-module/spacer/controls.native.js +3 -2
  147. package/build-module/spacer/controls.native.js.map +1 -1
  148. package/build-module/spacer/edit.js +2 -2
  149. package/build-module/spacer/edit.js.map +1 -1
  150. package/build-module/spacer/edit.native.js +6 -2
  151. package/build-module/spacer/edit.native.js.map +1 -1
  152. package/build-module/tag-cloud/edit.js +3 -2
  153. package/build-module/tag-cloud/edit.js.map +1 -1
  154. package/build-module/template-part/edit/inner-blocks.js +3 -3
  155. package/build-module/template-part/edit/inner-blocks.js.map +1 -1
  156. package/build-module/term-description/index.js +0 -1
  157. package/build-module/term-description/index.js.map +1 -1
  158. package/build-style/file/style-rtl.css +0 -5
  159. package/build-style/file/style.css +0 -5
  160. package/build-style/navigation/style-rtl.css +5 -0
  161. package/build-style/navigation/style.css +5 -0
  162. package/build-style/style-rtl.css +5 -5
  163. package/build-style/style.css +5 -5
  164. package/package.json +32 -32
  165. package/src/avatar/block.json +5 -1
  166. package/src/block/edit-title.native.js +16 -13
  167. package/src/block/edit.js +1 -1
  168. package/src/calendar/index.php +2 -6
  169. package/src/column/edit.js +3 -8
  170. package/src/column/edit.native.js +3 -8
  171. package/src/columns/edit.native.js +3 -8
  172. package/src/comment-author-avatar/index.php +1 -1
  173. package/src/cover/controls.native.js +3 -8
  174. package/src/cover/edit/index.js +3 -2
  175. package/src/cover/edit/inspector-controls.js +3 -8
  176. package/src/file/index.php +2 -1
  177. package/src/file/style.scss +0 -6
  178. package/src/file/view.js +2 -2
  179. package/src/form/edit.js +3 -1
  180. package/src/form/index.js +38 -1
  181. package/src/form/variations.js +1 -1
  182. package/src/form-input/block.json +2 -2
  183. package/src/form-input/variations.js +7 -7
  184. package/src/form-submission-notification/block.json +1 -1
  185. package/src/form-submission-notification/variations.js +4 -4
  186. package/src/form-submit-button/block.json +2 -2
  187. package/src/freeform/test/__snapshots__/index.native.js.snap +7 -0
  188. package/src/freeform/test/index.native.js +57 -0
  189. package/src/group/edit.js +2 -7
  190. package/src/html/preview.js +9 -4
  191. package/src/image/image.js +17 -6
  192. package/src/image/index.php +5 -6
  193. package/src/image/view.js +13 -19
  194. package/src/missing/edit.native.js +43 -6
  195. package/src/navigation/index.php +1 -1
  196. package/src/navigation/style.scss +6 -1
  197. package/src/paragraph/edit.js +2 -2
  198. package/src/post-featured-image/dimension-controls.js +3 -3
  199. package/src/post-terms/edit.js +2 -2
  200. package/src/query/edit/enhanced-pagination-modal.js +37 -21
  201. package/src/query/edit/inspector-controls/enhanced-pagination-control.js +18 -22
  202. package/src/query/index.php +97 -8
  203. package/src/query/utils.js +29 -8
  204. package/src/query/view.js +11 -2
  205. package/src/query-pagination-next/index.php +1 -1
  206. package/src/query-pagination-previous/index.php +1 -1
  207. package/src/search/edit.js +5 -3
  208. package/src/social-link/edit.native.js +12 -26
  209. package/src/social-link/editor.native.scss +0 -9
  210. package/src/social-link/index.php +2 -2
  211. package/src/spacer/controls.js +9 -12
  212. package/src/spacer/controls.native.js +3 -8
  213. package/src/spacer/edit.js +2 -2
  214. package/src/spacer/edit.native.js +6 -5
  215. package/src/tag-cloud/edit.js +3 -7
  216. package/src/template-part/edit/inner-blocks.js +3 -3
  217. package/src/term-description/block.json +0 -1
@@ -235,6 +235,7 @@ function block_core_image_render_lightbox( $block_content, $block ) {
235
235
  $button =
236
236
  $img[0]
237
237
  . '<button
238
+ class="lightbox-trigger"
238
239
  type="button"
239
240
  aria-haspopup="dialog"
240
241
  aria-label="' . esc_attr( $aria_label ) . '"
@@ -243,11 +244,8 @@ function block_core_image_render_lightbox( $block_content, $block ) {
243
244
  data-wp-style--top="context.core.image.imageButtonTop"
244
245
  style="background: #000"
245
246
  >
246
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
247
- <path d="M9 5H5V9" stroke="#FFFFFF" stroke-width="1.5"/>
248
- <path d="M15 19L19 19L19 15" stroke="#FFFFFF" stroke-width="1.5"/>
249
- <path d="M15 5H19V9" stroke="#FFFFFF" stroke-width="1.5"/>
250
- <path d="M9 19L5 19L5 15" stroke="#FFFFFF" stroke-width="1.5"/>
247
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false">
248
+ <Path stroke="#FFFFFF" d="M6 4a2 2 0 0 0-2 2v3h1.5V6a.5.5 0 0 1 .5-.5h3V4H6Zm3 14.5H6a.5.5 0 0 1-.5-.5v-3H4v3a2 2 0 0 0 2 2h3v-1.5Zm6 1.5v-1.5h3a.5.5 0 0 0 .5-.5v-3H20v3a2 2 0 0 1-2 2h-3Zm3-16a2 2 0 0 1 2 2v3h-1.5V6a.5.5 0 0 0-.5-.5h-3V4h3Z" />
251
249
  </svg>
252
250
  </button>';
253
251
 
@@ -322,12 +320,13 @@ function block_core_image_render_lightbox( $block_content, $block ) {
322
320
  data-wp-on--touchmove="actions.core.image.handleTouchMove"
323
321
  data-wp-on--touchend="actions.core.image.handleTouchEnd"
324
322
  data-wp-on--click="actions.core.image.hideLightbox"
323
+ tabindex="-1"
325
324
  >
326
325
  <button type="button" aria-label="$close_button_label" style="fill: $close_button_color" class="close-button" data-wp-on--click="actions.core.image.hideLightbox">
327
326
  $close_button_icon
328
327
  </button>
329
328
  <div class="lightbox-image-container">$initial_image_content</div>
330
- <div class="lightbox-image-container">$enlarged_image_content</div>
329
+ <div class="lightbox-image-container">$enlarged_image_content</div>
331
330
  <div class="scrim" style="background-color: $background_color" aria-hidden="true"></div>
332
331
  </div>
333
332
  HTML;
package/src/image/view.js CHANGED
@@ -135,7 +135,7 @@ store(
135
135
  false
136
136
  );
137
137
  },
138
- hideLightbox: async ( { context, event } ) => {
138
+ hideLightbox: async ( { context } ) => {
139
139
  context.core.image.hideAnimationEnabled = true;
140
140
  if ( context.core.image.lightboxEnabled ) {
141
141
  // We want to wait until the close animation is completed
@@ -149,19 +149,15 @@ store(
149
149
  'scroll',
150
150
  scrollCallback
151
151
  );
152
+ // If we don't delay before changing the focus,
153
+ // the focus ring will appear on Firefox before
154
+ // the image has finished animating, which looks broken.
155
+ context.core.image.lightboxTriggerRef.focus( {
156
+ preventScroll: true,
157
+ } );
152
158
  }, 450 );
153
159
 
154
160
  context.core.image.lightboxEnabled = false;
155
-
156
- // We want to avoid drawing attention to the button
157
- // after the lightbox closes for mouse and touch users.
158
- // Note that the `event.pointerType` property returns
159
- // as an empty string if a keyboard fired the event.
160
- if ( event.pointerType === '' ) {
161
- context.core.image.lastFocusedElement.focus( {
162
- preventScroll: true,
163
- } );
164
- }
165
161
  }
166
162
  },
167
163
  handleKeydown: ( { context, actions, event } ) => {
@@ -266,6 +262,10 @@ store(
266
262
  image: {
267
263
  initOriginImage: ( { context, ref } ) => {
268
264
  context.core.image.imageRef = ref;
265
+ context.core.image.lightboxTriggerRef =
266
+ ref.parentElement.querySelector(
267
+ '.lightbox-trigger'
268
+ );
269
269
  if ( ref.complete ) {
270
270
  context.core.image.imageLoaded = true;
271
271
  context.core.image.imageCurrentSrc = ref.currentSrc;
@@ -282,14 +282,8 @@ store(
282
282
  focusableElements.length - 1
283
283
  ];
284
284
 
285
- // We want to avoid drawing unnecessary attention to the close
286
- // button for mouse and touch users. Note that even if opening
287
- // the lightbox via keyboard, the event fired is of type
288
- // `pointerEvent`, so we need to rely on the `event.pointerType`
289
- // property, which returns an empty string for keyboard events.
290
- if ( context.core.image.pointerType === '' ) {
291
- ref.querySelector( '.close-button' ).focus();
292
- }
285
+ // Move focus to the dialog when opening it.
286
+ ref.focus();
293
287
  }
294
288
  },
295
289
  setButtonStyles: ( { context, ref } ) => {
@@ -14,7 +14,7 @@ import {
14
14
  import { Icon } from '@wordpress/components';
15
15
  import { compose, withPreferredColorScheme } from '@wordpress/compose';
16
16
  import { coreBlocks } from '@wordpress/block-library';
17
- import { normalizeIconObject } from '@wordpress/blocks';
17
+ import { normalizeIconObject, rawHandler, serialize } from '@wordpress/blocks';
18
18
  import { Component } from '@wordpress/element';
19
19
  import { __, _x, sprintf } from '@wordpress/i18n';
20
20
  import { help, plugins } from '@wordpress/icons';
@@ -24,6 +24,7 @@ import {
24
24
  UnsupportedBlockDetails,
25
25
  store as blockEditorStore,
26
26
  } from '@wordpress/block-editor';
27
+ import { store as noticesStore } from '@wordpress/notices';
27
28
 
28
29
  /**
29
30
  * Internal dependencies
@@ -34,6 +35,8 @@ import styles from './style.scss';
34
35
  const UBE_INCOMPATIBLE_BLOCKS = [ 'core/block' ];
35
36
  const I18N_BLOCK_SCHEMA_TITLE = 'block title';
36
37
 
38
+ const EMPTY_ARRAY = [];
39
+
37
40
  export class UnsupportedBlockEdit extends Component {
38
41
  constructor( props ) {
39
42
  super( props );
@@ -119,16 +122,39 @@ export class UnsupportedBlockEdit extends Component {
119
122
  }
120
123
 
121
124
  renderSheet( blockTitle, blockName ) {
122
- const { clientId } = this.props;
125
+ const { block, clientId, createSuccessNotice, replaceBlocks } =
126
+ this.props;
123
127
  const { showHelp } = this.state;
128
+
124
129
  /* translators: Missing block alert title. %s: The localized block name */
125
130
  const titleFormat = __( "'%s' is not fully-supported" );
126
131
  const title = sprintf( titleFormat, blockTitle );
127
- const description = applyFilters(
132
+ let description = applyFilters(
128
133
  'native.missing_block_detail',
129
134
  __( 'We are working hard to add more blocks with each release.' ),
130
135
  blockName
131
136
  );
137
+ let customActions = EMPTY_ARRAY;
138
+
139
+ // For Classic blocks, we offer the alternative to convert the content to blocks.
140
+ if ( blockName === 'core/freeform' ) {
141
+ description +=
142
+ ' ' +
143
+ __( 'Alternatively, you can convert the content to blocks.' );
144
+ /* translators: displayed right after the classic block is converted to blocks. %s: The localized classic block name */
145
+ const successNotice = __( "'%s' block converted to blocks" );
146
+ customActions = [
147
+ {
148
+ label: __( 'Convert to blocks' ),
149
+ onPress: () => {
150
+ createSuccessNotice(
151
+ sprintf( successNotice, blockTitle )
152
+ );
153
+ replaceBlocks( block );
154
+ },
155
+ },
156
+ ];
157
+ }
132
158
 
133
159
  return (
134
160
  <UnsupportedBlockDetails
@@ -138,6 +164,7 @@ export class UnsupportedBlockEdit extends Component {
138
164
  customBlockTitle={ blockTitle }
139
165
  title={ title }
140
166
  description={ description }
167
+ customActions={ customActions }
141
168
  />
142
169
  );
143
170
  }
@@ -202,8 +229,9 @@ export class UnsupportedBlockEdit extends Component {
202
229
  }
203
230
 
204
231
  export default compose( [
205
- withSelect( ( select, { attributes } ) => {
206
- const { capabilities } = select( blockEditorStore ).getSettings();
232
+ withSelect( ( select, { attributes, clientId } ) => {
233
+ const { getBlock, getSettings } = select( blockEditorStore );
234
+ const { capabilities } = getSettings();
207
235
  return {
208
236
  isUnsupportedBlockEditorSupported:
209
237
  capabilities?.unsupportedBlockEditor === true,
@@ -211,14 +239,23 @@ export default compose( [
211
239
  capabilities?.canEnableUnsupportedBlockEditor === true,
212
240
  isEditableInUnsupportedBlockEditor:
213
241
  ! UBE_INCOMPATIBLE_BLOCKS.includes( attributes.originalName ),
242
+ block: getBlock( clientId ),
214
243
  };
215
244
  } ),
216
245
  withDispatch( ( dispatch, ownProps ) => {
217
- const { selectBlock } = dispatch( blockEditorStore );
246
+ const { selectBlock, replaceBlocks } = dispatch( blockEditorStore );
247
+ const { createSuccessNotice } = dispatch( noticesStore );
218
248
  return {
219
249
  selectBlock() {
220
250
  selectBlock( ownProps.clientId );
221
251
  },
252
+ replaceBlocks( block ) {
253
+ replaceBlocks(
254
+ ownProps.clientId,
255
+ rawHandler( { HTML: serialize( block ) } )
256
+ );
257
+ },
258
+ createSuccessNotice,
222
259
  };
223
260
  } ),
224
261
  withPreferredColorScheme,
@@ -744,7 +744,7 @@ function render_block_core_navigation( $attributes, $content, $block ) {
744
744
  }
745
745
 
746
746
  $responsive_container_markup = sprintf(
747
- '<button aria-haspopup="true" %3$s class="%6$s" %10$s>%8$s</button>
747
+ '<button aria-haspopup="dialog" %3$s class="%6$s" %10$s>%8$s</button>
748
748
  <div class="%5$s" style="%7$s" id="%1$s" %11$s>
749
749
  <div class="wp-block-navigation__responsive-close" tabindex="-1">
750
750
  <div class="wp-block-navigation__responsive-dialog" %12$s>
@@ -317,7 +317,9 @@ button.wp-block-navigation-item__content {
317
317
  // When set to open on click, a button element is used.
318
318
  // We pad it to include the arrow icon in the clickable area.
319
319
  // The padding can be blanket for click, since you can't set click and hide the icon.
320
+ // This is only applied to the submenu in the page list block.
320
321
  .wp-block-navigation-item.open-on-click .wp-block-navigation-submenu__toggle {
322
+ padding-left: 0; // Remove the browser default padding.
321
323
  padding-right: 0.6em + 0.25em; // Same size as icon plus margin.
322
324
 
323
325
  + .wp-block-navigation__submenu-icon {
@@ -325,7 +327,10 @@ button.wp-block-navigation-item__content {
325
327
  pointer-events: none; // Make the icon inert to allow click on the button.
326
328
  }
327
329
  }
328
-
330
+ // Remove the browser default padding on the button element used in the navigation link submenu.
331
+ .wp-block-navigation-item.open-on-click button.wp-block-navigation-item__content:not(.wp-block-navigation-submenu__toggle) {
332
+ padding: 0;
333
+ }
329
334
 
330
335
  /**
331
336
  * Margins
@@ -18,7 +18,7 @@ import {
18
18
  InspectorControls,
19
19
  RichText,
20
20
  useBlockProps,
21
- useSetting,
21
+ useSettings,
22
22
  } from '@wordpress/block-editor';
23
23
  import { createBlock } from '@wordpress/blocks';
24
24
  import { formatLtr } from '@wordpress/icons';
@@ -58,7 +58,7 @@ function ParagraphBlock( {
58
58
  clientId,
59
59
  } ) {
60
60
  const { align, content, direction, dropCap, placeholder } = attributes;
61
- const isDropCapFeatureEnabled = useSetting( 'typography.dropCap' );
61
+ const [ isDropCapFeatureEnabled ] = useSettings( 'typography.dropCap' );
62
62
  const blockProps = useBlockProps( {
63
63
  ref: useOnEnter( { clientId, content } ),
64
64
  className: classnames( {
@@ -10,7 +10,7 @@ import {
10
10
  __experimentalUseCustomUnits as useCustomUnits,
11
11
  __experimentalToolsPanelItem as ToolsPanelItem,
12
12
  } from '@wordpress/components';
13
- import { InspectorControls, useSetting } from '@wordpress/block-editor';
13
+ import { InspectorControls, useSettings } from '@wordpress/block-editor';
14
14
 
15
15
  const SCALE_OPTIONS = (
16
16
  <>
@@ -53,9 +53,9 @@ const DimensionControls = ( {
53
53
  setAttributes,
54
54
  imageSizeOptions = [],
55
55
  } ) => {
56
- const defaultUnits = [ 'px', '%', 'vw', 'em', 'rem' ];
56
+ const [ availableUnits ] = useSettings( 'spacing.units' );
57
57
  const units = useCustomUnits( {
58
- availableUnits: useSetting( 'spacing.units' ) || defaultUnits,
58
+ availableUnits: availableUnits || [ 'px', '%', 'vw', 'em', 'rem' ],
59
59
  } );
60
60
  const onDimensionChange = ( dimension, nextValue ) => {
61
61
  const parsedValue = parseFloat( nextValue );
@@ -93,7 +93,7 @@ export default function PostTermsEdit( {
93
93
  </InspectorControls>
94
94
  <div { ...blockProps }>
95
95
  { isLoading && hasPost && <Spinner /> }
96
- { ! isLoading && hasPostTerms && ( isSelected || prefix ) && (
96
+ { ! isLoading && ( isSelected || prefix ) && (
97
97
  <RichText
98
98
  allowedFormats={ ALLOWED_FORMATS }
99
99
  className="wp-block-post-terms__prefix"
@@ -137,7 +137,7 @@ export default function PostTermsEdit( {
137
137
  ! hasPostTerms &&
138
138
  ( selectedTerm?.labels?.no_terms ||
139
139
  __( 'Term items not found.' ) ) }
140
- { ! isLoading && hasPostTerms && ( isSelected || suffix ) && (
140
+ { ! isLoading && ( isSelected || suffix ) && (
141
141
  <RichText
142
142
  allowedFormats={ ALLOWED_FORMATS }
143
143
  className="wp-block-post-terms__suffix"
@@ -12,11 +12,7 @@ import { useState, useEffect } from '@wordpress/element';
12
12
  /**
13
13
  * Internal dependencies
14
14
  */
15
- import { useContainsThirdPartyBlocks } from '../utils';
16
-
17
- const disableEnhancedPaginationDescription = __(
18
- 'Plugin blocks are not supported yet. For the enhanced pagination to work, remove the plugin block, then re-enable "Enhanced pagination" in the Query Block settings.'
19
- );
15
+ import { useUnsupportedBlocks } from '../utils';
20
16
 
21
17
  const modalDescriptionId =
22
18
  'wp-block-query-enhanced-pagination-modal__description';
@@ -27,35 +23,55 @@ export default function EnhancedPaginationModal( {
27
23
  setAttributes,
28
24
  } ) {
29
25
  const [ isOpen, setOpen ] = useState( false );
30
-
31
- const containsThirdPartyBlocks = useContainsThirdPartyBlocks( clientId );
26
+ const { hasBlocksFromPlugins, hasPostContentBlock, hasUnsupportedBlocks } =
27
+ useUnsupportedBlocks( clientId );
32
28
 
33
29
  useEffect( () => {
34
- setOpen( containsThirdPartyBlocks && enhancedPagination );
35
- }, [ containsThirdPartyBlocks, enhancedPagination, setOpen ] );
30
+ if ( enhancedPagination && hasUnsupportedBlocks ) {
31
+ setAttributes( { enhancedPagination: false } );
32
+ setOpen( true );
33
+ }
34
+ }, [ enhancedPagination, hasUnsupportedBlocks, setAttributes ] );
35
+
36
+ const closeModal = () => {
37
+ setOpen( false );
38
+ };
39
+
40
+ let notice = __(
41
+ 'If you still want to prevent full page reloads, remove that block, then disable "Force page reload" again in the Query Block settings.'
42
+ );
43
+ if ( hasBlocksFromPlugins ) {
44
+ notice =
45
+ __(
46
+ 'Currently, avoiding full page reloads is not possible when blocks from plugins are present inside the Query block.'
47
+ ) +
48
+ ' ' +
49
+ notice;
50
+ } else if ( hasPostContentBlock ) {
51
+ notice =
52
+ __(
53
+ 'Currently, avoiding full page reloads is not possible when a Content block is present inside the Query block.'
54
+ ) +
55
+ ' ' +
56
+ notice;
57
+ }
36
58
 
37
59
  return (
38
60
  isOpen && (
39
61
  <Modal
40
- title={ __( 'Enhanced pagination will be disabled' ) }
62
+ title={ __( 'Query block: Force page reload enabled' ) }
41
63
  className="wp-block-query__enhanced-pagination-modal"
42
64
  aria={ {
43
65
  describedby: modalDescriptionId,
44
66
  } }
67
+ role="alertdialog"
68
+ focusOnMount="firstElement"
45
69
  isDismissible={ false }
46
- shouldCloseOnEsc={ false }
47
- shouldCloseOnClickOutside={ false }
70
+ onRequestClose={ closeModal }
48
71
  >
49
72
  <VStack alignment="right" spacing={ 5 }>
50
- <span id={ modalDescriptionId }>
51
- { disableEnhancedPaginationDescription }
52
- </span>
53
- <Button
54
- variant="primary"
55
- onClick={ () => {
56
- setAttributes( { enhancedPagination: false } );
57
- } }
58
- >
73
+ <span id={ modalDescriptionId }>{ notice }</span>
74
+ <Button variant="primary" onClick={ closeModal }>
59
75
  { __( 'OK' ) }
60
76
  </Button>
61
77
  </VStack>
@@ -1,49 +1,45 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { ToggleControl, Notice } from '@wordpress/components';
4
+ import { ToggleControl } from '@wordpress/components';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
7
  /**
8
8
  * Internal dependencies
9
9
  */
10
- import { useContainsThirdPartyBlocks } from '../../utils';
10
+ import { useUnsupportedBlocks } from '../../utils';
11
11
 
12
12
  export default function EnhancedPaginationControl( {
13
13
  enhancedPagination,
14
14
  setAttributes,
15
15
  clientId,
16
16
  } ) {
17
- const enhancedPaginationNotice = __(
18
- "Enhanced pagination doesn't support plugin blocks yet. If you want to enable it, you have to remove all plugin blocks from the Query Loop."
19
- );
17
+ const { hasUnsupportedBlocks } = useUnsupportedBlocks( clientId );
20
18
 
21
- const containsThirdPartyBlocks = useContainsThirdPartyBlocks( clientId );
19
+ let help = __( 'Browsing between pages requires a full page reload.' );
20
+ if ( enhancedPagination ) {
21
+ help = __(
22
+ "Browsing between pages won't require a full page reload, unless non-compatible blocks are detected."
23
+ );
24
+ } else if ( hasUnsupportedBlocks ) {
25
+ help = __(
26
+ "Force page reload can't be disabled because there are non-compatible blocks inside the Query block."
27
+ );
28
+ }
22
29
 
23
30
  return (
24
31
  <>
25
32
  <ToggleControl
26
- label={ __( 'Enhanced pagination' ) }
27
- help={ __(
28
- 'Browsing between pages won’t require a full page reload.'
29
- ) }
30
- checked={ !! enhancedPagination }
31
- disabled={ containsThirdPartyBlocks }
33
+ label={ __( 'Force page reload' ) }
34
+ help={ help }
35
+ checked={ ! enhancedPagination }
36
+ disabled={ hasUnsupportedBlocks }
32
37
  onChange={ ( value ) => {
33
38
  setAttributes( {
34
- enhancedPagination: !! value,
39
+ enhancedPagination: ! value,
35
40
  } );
36
41
  } }
37
42
  />
38
- { containsThirdPartyBlocks && (
39
- <Notice
40
- status="warning"
41
- isDismissible={ false }
42
- className="wp-block-query__enhanced-pagination-notice"
43
- >
44
- { enhancedPaginationNotice }
45
- </Notice>
46
- ) }
47
43
  </>
48
44
  );
49
45
  }
@@ -10,14 +10,14 @@
10
10
  *
11
11
  * @since 6.4.0
12
12
  *
13
- * @param array $attributes Block attributes.
14
- * @param string $content Block default content.
15
- * @param string $block Block instance.
13
+ * @param array $attributes Block attributes.
14
+ * @param string $content Block default content.
15
+ * @param WP_Block $block The block instance.
16
16
  *
17
17
  * @return string Returns the modified output of the query block.
18
18
  */
19
19
  function render_block_core_query( $attributes, $content, $block ) {
20
- if ( $attributes['enhancedPagination'] ) {
20
+ if ( $attributes['enhancedPagination'] && isset( $attributes['queryId'] ) ) {
21
21
  $p = new WP_HTML_Tag_Processor( $content );
22
22
  if ( $p->next_tag() ) {
23
23
  // Add the necessary directives.
@@ -67,11 +67,14 @@ function render_block_core_query( $attributes, $content, $block ) {
67
67
  if ( ! wp_script_is( $view_asset ) ) {
68
68
  $script_handles = $block->block_type->view_script_handles;
69
69
  // If the script is not needed, and it is still in the `view_script_handles`, remove it.
70
- if ( ! $attributes['enhancedPagination'] && in_array( $view_asset, $script_handles, true ) ) {
70
+ if (
71
+ ( ! $attributes['enhancedPagination'] || ! isset( $attributes['queryId'] ) )
72
+ && in_array( $view_asset, $script_handles, true )
73
+ ) {
71
74
  $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_asset ) );
72
75
  }
73
76
  // If the script is needed, but it was previously removed, add it again.
74
- if ( $attributes['enhancedPagination'] && ! in_array( $view_asset, $script_handles, true ) ) {
77
+ if ( $attributes['enhancedPagination'] && isset( $attributes['queryId'] ) && ! in_array( $view_asset, $script_handles, true ) ) {
75
78
  $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_asset ) );
76
79
  }
77
80
  }
@@ -80,11 +83,14 @@ function render_block_core_query( $attributes, $content, $block ) {
80
83
  if ( ! wp_style_is( $style_asset ) ) {
81
84
  $style_handles = $block->block_type->style_handles;
82
85
  // If the styles are not needed, and they are still in the `style_handles`, remove them.
83
- if ( ! $attributes['enhancedPagination'] && in_array( $style_asset, $style_handles, true ) ) {
86
+ if (
87
+ ( ! $attributes['enhancedPagination'] || ! isset( $attributes['queryId'] ) )
88
+ && in_array( $style_asset, $style_handles, true )
89
+ ) {
84
90
  $block->block_type->style_handles = array_diff( $style_handles, array( $style_asset ) );
85
91
  }
86
92
  // If the styles are needed, but they were previously removed, add them again.
87
- if ( $attributes['enhancedPagination'] && ! in_array( $style_asset, $style_handles, true ) ) {
93
+ if ( $attributes['enhancedPagination'] && isset( $attributes['queryId'] ) && ! in_array( $style_asset, $style_handles, true ) ) {
88
94
  $block->block_type->style_handles = array_merge( $style_handles, array( $style_asset ) );
89
95
  }
90
96
  }
@@ -123,3 +129,86 @@ function register_block_core_query() {
123
129
  );
124
130
  }
125
131
  add_action( 'init', 'register_block_core_query' );
132
+
133
+ /**
134
+ * Traverse the tree of blocks looking for any plugin block (i.e., a block from
135
+ * an installed plugin) inside a Query block with the enhanced pagination
136
+ * enabled. If at least one is found, the enhanced pagination is effectively
137
+ * disabled to prevent any potential incompatibilities.
138
+ *
139
+ * @since 6.4.0
140
+ *
141
+ * @param array $parsed_block The block being rendered.
142
+ * @return string Returns the parsed block, unmodified.
143
+ */
144
+ function block_core_query_disable_enhanced_pagination( $parsed_block ) {
145
+ static $enhanced_query_stack = array();
146
+ static $dirty_enhanced_queries = array();
147
+ static $render_query_callback = null;
148
+
149
+ $block_name = $parsed_block['blockName'];
150
+
151
+ if (
152
+ 'core/query' === $block_name &&
153
+ isset( $parsed_block['attrs']['enhancedPagination'] ) &&
154
+ true === $parsed_block['attrs']['enhancedPagination'] &&
155
+ isset( $parsed_block['attrs']['queryId'] )
156
+ ) {
157
+ $enhanced_query_stack[] = $parsed_block['attrs']['queryId'];
158
+
159
+ if ( ! isset( $render_query_callback ) ) {
160
+ /**
161
+ * Filter that disables the enhanced pagination feature during block
162
+ * rendering when a plugin block has been found inside. It does so
163
+ * by adding an attribute called `data-wp-navigation-disabled` which
164
+ * is later handled by the front-end logic.
165
+ *
166
+ * @param string $content The block content.
167
+ * @param array $block The full block, including name and attributes.
168
+ * @return string Returns the modified output of the query block.
169
+ */
170
+ $render_query_callback = static function ( $content, $block ) use ( &$enhanced_query_stack, &$dirty_enhanced_queries, &$render_query_callback ) {
171
+ $has_enhanced_pagination =
172
+ isset( $block['attrs']['enhancedPagination'] ) &&
173
+ true === $block['attrs']['enhancedPagination'] &&
174
+ isset( $block['attrs']['queryId'] );
175
+
176
+ if ( ! $has_enhanced_pagination ) {
177
+ return $content;
178
+ }
179
+
180
+ if ( isset( $dirty_enhanced_queries[ $block['attrs']['queryId'] ] ) ) {
181
+ $p = new WP_HTML_Tag_Processor( $content );
182
+ if ( $p->next_tag() ) {
183
+ $p->set_attribute( 'data-wp-navigation-disabled', 'true' );
184
+ }
185
+ $content = $p->get_updated_html();
186
+ $dirty_enhanced_queries[ $block['attrs']['queryId'] ] = null;
187
+ }
188
+
189
+ array_pop( $enhanced_query_stack );
190
+
191
+ if ( empty( $enhanced_query_stack ) ) {
192
+ remove_filter( 'render_block_core/query', $render_query_callback );
193
+ $render_query_callback = null;
194
+ }
195
+
196
+ return $content;
197
+ };
198
+
199
+ add_filter( 'render_block_core/query', $render_query_callback, 10, 2 );
200
+ }
201
+ } elseif (
202
+ ! empty( $enhanced_query_stack ) &&
203
+ isset( $block_name ) &&
204
+ ( ! str_starts_with( $block_name, 'core/' ) || 'core/post-content' === $block_name )
205
+ ) {
206
+ foreach ( $enhanced_query_stack as $query_id ) {
207
+ $dirty_enhanced_queries[ $query_id ] = true;
208
+ }
209
+ }
210
+
211
+ return $parsed_block;
212
+ }
213
+
214
+ add_filter( 'render_block_data', 'block_core_query_disable_enhanced_pagination', 10, 1 );
@@ -346,22 +346,43 @@ export const usePatterns = ( clientId, name ) => {
346
346
  };
347
347
 
348
348
  /**
349
- * Hook that returns whether the Query Loop with the given `clientId` contains
350
- * any third-party block.
349
+ * The object returned by useUnsupportedBlocks with info about the type of
350
+ * unsupported blocks present inside the Query block.
351
+ *
352
+ * @typedef {Object} UnsupportedBlocksInfo
353
+ * @property {boolean} hasBlocksFromPlugins True if blocks from plugins are present.
354
+ * @property {boolean} hasPostContentBlock True if a 'core/post-content' block is present.
355
+ * @property {boolean} hasUnsupportedBlocks True if there are any unsupported blocks.
356
+ */
357
+
358
+ /**
359
+ * Hook that returns an object with information about the unsupported blocks
360
+ * present inside a Query Loop with the given `clientId`. The returned object
361
+ * contains props that are true when a certain type of unsupported block is
362
+ * present.
351
363
  *
352
364
  * @param {string} clientId The block's client ID.
353
- * @return {boolean} True if it contains third-party blocks.
365
+ * @return {UnsupportedBlocksInfo} The object containing the information.
354
366
  */
355
- export const useContainsThirdPartyBlocks = ( clientId ) => {
367
+ export const useUnsupportedBlocks = ( clientId ) => {
356
368
  return useSelect(
357
369
  ( select ) => {
358
370
  const { getClientIdsOfDescendants, getBlockName } =
359
371
  select( blockEditorStore );
360
-
361
- return getClientIdsOfDescendants( clientId ).some(
362
- ( descendantClientId ) =>
363
- ! getBlockName( descendantClientId ).startsWith( 'core/' )
372
+ const blocks = {};
373
+ getClientIdsOfDescendants( clientId ).forEach(
374
+ ( descendantClientId ) => {
375
+ const blockName = getBlockName( descendantClientId );
376
+ if ( ! blockName.startsWith( 'core/' ) ) {
377
+ blocks.hasBlocksFromPlugins = true;
378
+ } else if ( blockName === 'core/post-content' ) {
379
+ blocks.hasPostContentBlock = true;
380
+ }
381
+ }
364
382
  );
383
+ blocks.hasUnsupportedBlocks =
384
+ blocks.hasBlocksFromPlugins || blocks.hasPostContentBlock;
385
+ return blocks;
365
386
  },
366
387
  [ clientId ]
367
388
  );