@wordpress/block-library 9.19.0 → 9.20.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 (119) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/archives/edit.js +2 -2
  3. package/build/archives/edit.js.map +1 -1
  4. package/build/audio/edit.js +66 -33
  5. package/build/audio/edit.js.map +1 -1
  6. package/build/avatar/index.js +8 -3
  7. package/build/avatar/index.js.map +1 -1
  8. package/build/button/edit.js +43 -16
  9. package/build/button/edit.js.map +1 -1
  10. package/build/comment-template/hooks.js +6 -0
  11. package/build/comment-template/hooks.js.map +1 -1
  12. package/build/cover/index.js +8 -1
  13. package/build/cover/index.js.map +1 -1
  14. package/build/image/constants.js +2 -1
  15. package/build/image/constants.js.map +1 -1
  16. package/build/image/image.js +85 -72
  17. package/build/image/image.js.map +1 -1
  18. package/build/latest-posts/edit.js +2 -1
  19. package/build/latest-posts/edit.js.map +1 -1
  20. package/build/navigation/use-template-part-area-label.js +7 -6
  21. package/build/navigation/use-template-part-area-label.js.map +1 -1
  22. package/build/post-author/edit.js +1 -1
  23. package/build/post-author/edit.js.map +1 -1
  24. package/build/post-author/index.js +8 -1
  25. package/build/post-author/index.js.map +1 -1
  26. package/build/post-author-name/edit.js +2 -2
  27. package/build/post-author-name/edit.js.map +1 -1
  28. package/build/query/edit/inspector-controls/index.js +2 -0
  29. package/build/query/edit/inspector-controls/index.js.map +1 -1
  30. package/build/query/edit/inspector-controls/order-control.js +3 -2
  31. package/build/query/edit/inspector-controls/order-control.js.map +1 -1
  32. package/build/query/utils.js +45 -0
  33. package/build/query/utils.js.map +1 -1
  34. package/build/query-total/index.js +2 -2
  35. package/build/query-total/index.js.map +1 -1
  36. package/build/site-logo/index.js +8 -1
  37. package/build/site-logo/index.js.map +1 -1
  38. package/build/social-links/index.js +1 -0
  39. package/build/social-links/index.js.map +1 -1
  40. package/build/table-of-contents/hooks.js +6 -3
  41. package/build/table-of-contents/hooks.js.map +1 -1
  42. package/build/template-part/edit/advanced-controls.js +1 -1
  43. package/build/template-part/edit/advanced-controls.js.map +1 -1
  44. package/build/template-part/edit/utils/hooks.js +1 -1
  45. package/build/template-part/edit/utils/hooks.js.map +1 -1
  46. package/build-module/archives/edit.js +2 -2
  47. package/build-module/archives/edit.js.map +1 -1
  48. package/build-module/audio/edit.js +68 -35
  49. package/build-module/audio/edit.js.map +1 -1
  50. package/build-module/avatar/index.js +8 -3
  51. package/build-module/avatar/index.js.map +1 -1
  52. package/build-module/button/edit.js +44 -17
  53. package/build-module/button/edit.js.map +1 -1
  54. package/build-module/comment-template/hooks.js +6 -0
  55. package/build-module/comment-template/hooks.js.map +1 -1
  56. package/build-module/cover/index.js +8 -1
  57. package/build-module/cover/index.js.map +1 -1
  58. package/build-module/image/constants.js +1 -0
  59. package/build-module/image/constants.js.map +1 -1
  60. package/build-module/image/image.js +88 -75
  61. package/build-module/image/image.js.map +1 -1
  62. package/build-module/latest-posts/edit.js +2 -1
  63. package/build-module/latest-posts/edit.js.map +1 -1
  64. package/build-module/navigation/use-template-part-area-label.js +7 -6
  65. package/build-module/navigation/use-template-part-area-label.js.map +1 -1
  66. package/build-module/post-author/edit.js +1 -1
  67. package/build-module/post-author/edit.js.map +1 -1
  68. package/build-module/post-author/index.js +8 -1
  69. package/build-module/post-author/index.js.map +1 -1
  70. package/build-module/post-author-name/edit.js +2 -2
  71. package/build-module/post-author-name/edit.js.map +1 -1
  72. package/build-module/query/edit/inspector-controls/index.js +3 -1
  73. package/build-module/query/edit/inspector-controls/index.js.map +1 -1
  74. package/build-module/query/edit/inspector-controls/order-control.js +3 -2
  75. package/build-module/query/edit/inspector-controls/order-control.js.map +1 -1
  76. package/build-module/query/utils.js +44 -0
  77. package/build-module/query/utils.js.map +1 -1
  78. package/build-module/query-total/index.js +2 -2
  79. package/build-module/query-total/index.js.map +1 -1
  80. package/build-module/site-logo/index.js +8 -1
  81. package/build-module/site-logo/index.js.map +1 -1
  82. package/build-module/social-links/index.js +1 -0
  83. package/build-module/social-links/index.js.map +1 -1
  84. package/build-module/table-of-contents/hooks.js +6 -3
  85. package/build-module/table-of-contents/hooks.js.map +1 -1
  86. package/build-module/template-part/edit/advanced-controls.js +1 -1
  87. package/build-module/template-part/edit/advanced-controls.js.map +1 -1
  88. package/build-module/template-part/edit/utils/hooks.js +1 -1
  89. package/build-module/template-part/edit/utils/hooks.js.map +1 -1
  90. package/build-style/editor-rtl.css +0 -9
  91. package/build-style/editor.css +0 -9
  92. package/build-style/image/editor-rtl.css +0 -9
  93. package/build-style/image/editor.css +0 -9
  94. package/package.json +35 -35
  95. package/src/archives/edit.js +2 -2
  96. package/src/audio/edit.js +84 -33
  97. package/src/avatar/block.json +8 -3
  98. package/src/button/edit.js +69 -24
  99. package/src/comment-template/hooks.js +14 -6
  100. package/src/cover/block.json +8 -1
  101. package/src/image/constants.js +1 -0
  102. package/src/image/editor.scss +0 -13
  103. package/src/image/image.js +115 -122
  104. package/src/latest-posts/edit.js +1 -0
  105. package/src/navigation/use-template-part-area-label.js +6 -6
  106. package/src/post-author/block.json +8 -1
  107. package/src/post-author/edit.js +1 -1
  108. package/src/post-author-name/edit.js +4 -4
  109. package/src/query/edit/inspector-controls/index.js +3 -1
  110. package/src/query/edit/inspector-controls/order-control.js +9 -3
  111. package/src/query/utils.js +58 -0
  112. package/src/query-total/block.json +2 -2
  113. package/src/query-total/index.php +2 -2
  114. package/src/site-logo/block.json +8 -1
  115. package/src/site-title/index.php +1 -1
  116. package/src/social-links/block.json +1 -0
  117. package/src/table-of-contents/hooks.js +5 -2
  118. package/src/template-part/edit/advanced-controls.js +1 -1
  119. package/src/template-part/edit/utils/hooks.js +1 -1
@@ -19,7 +19,11 @@ import {
19
19
  DropdownMenu,
20
20
  Popover,
21
21
  } from '@wordpress/components';
22
- import { useViewportMatch } from '@wordpress/compose';
22
+ import {
23
+ useMergeRefs,
24
+ useResizeObserver,
25
+ useViewportMatch,
26
+ } from '@wordpress/compose';
23
27
  import { useSelect, useDispatch } from '@wordpress/data';
24
28
  import {
25
29
  BlockControls,
@@ -34,7 +38,7 @@ import {
34
38
  privateApis as blockEditorPrivateApis,
35
39
  BlockSettingsMenuControls,
36
40
  } from '@wordpress/block-editor';
37
- import { useEffect, useMemo, useState, useRef } from '@wordpress/element';
41
+ import { useCallback, useEffect, useMemo, useState } from '@wordpress/element';
38
42
  import { __, _x, sprintf, isRTL } from '@wordpress/i18n';
39
43
  import { getFilename } from '@wordpress/url';
40
44
  import { getBlockBindingsSource, switchToBlockType } from '@wordpress/blocks';
@@ -54,7 +58,7 @@ import { Caption } from '../utils/caption';
54
58
  * Module constants
55
59
  */
56
60
  import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
57
- import { MIN_SIZE, ALLOWED_MEDIA_TYPES } from './constants';
61
+ import { MIN_SIZE, ALLOWED_MEDIA_TYPES, SIZED_LAYOUTS } from './constants';
58
62
  import { evalAspectRatio } from './utils';
59
63
 
60
64
  const { DimensionsTool, ResolutionTool } = unlock( blockEditorPrivateApis );
@@ -280,12 +284,22 @@ export default function Image( {
280
284
  lightbox,
281
285
  metadata,
282
286
  } = attributes;
283
-
284
- // The only supported unit is px, so we can parseInt to strip the px here.
285
- const numericWidth = width ? parseInt( width, 10 ) : undefined;
286
- const numericHeight = height ? parseInt( height, 10 ) : undefined;
287
-
288
- const imageRef = useRef();
287
+ const [ imageElement, setImageElement ] = useState();
288
+ const [ resizeDelta, setResizeDelta ] = useState( null );
289
+ const [ pixelSize, setPixelSize ] = useState( {} );
290
+ const [ offsetTop, setOffsetTop ] = useState( 0 );
291
+ const setResizeObserved = useResizeObserver( ( [ entry ] ) => {
292
+ if ( ! resizeDelta ) {
293
+ const [ box ] = entry.borderBoxSize;
294
+ setPixelSize( { width: box.inlineSize, height: box.blockSize } );
295
+ }
296
+ // This is usually 0 unless the image height is less than the line-height.
297
+ setOffsetTop( entry.target.offsetTop );
298
+ } );
299
+ const effectResizeableBoxPlacement = useCallback( () => {
300
+ setOffsetTop( imageElement?.offsetTop ?? 0 );
301
+ }, [ imageElement ] );
302
+ const setRefs = useMergeRefs( [ setImageElement, setResizeObserved ] );
289
303
  const { allowResize = true } = context;
290
304
  const { getBlock, getSettings } = useSelect( blockEditorStore );
291
305
 
@@ -369,34 +383,18 @@ export default function Image( {
369
383
  .catch( () => {} );
370
384
  }, [ id, url, isSingleSelected, externalBlob ] );
371
385
 
372
- // Get naturalWidth and naturalHeight from image ref, and fall back to loaded natural
386
+ // Get naturalWidth and naturalHeight from image, and fall back to loaded natural
373
387
  // width and height. This resolves an issue in Safari where the loaded natural
374
388
  // width and height is otherwise lost when switching between alignments.
375
389
  // See: https://github.com/WordPress/gutenberg/pull/37210.
376
390
  const { naturalWidth, naturalHeight } = useMemo( () => {
377
391
  return {
378
392
  naturalWidth:
379
- imageRef.current?.naturalWidth ||
380
- loadedNaturalWidth ||
381
- undefined,
393
+ imageElement?.naturalWidth || loadedNaturalWidth || undefined,
382
394
  naturalHeight:
383
- imageRef.current?.naturalHeight ||
384
- loadedNaturalHeight ||
385
- undefined,
395
+ imageElement?.naturalHeight || loadedNaturalHeight || undefined,
386
396
  };
387
- }, [
388
- loadedNaturalWidth,
389
- loadedNaturalHeight,
390
- imageRef.current?.complete,
391
- ] );
392
-
393
- function onResizeStart() {
394
- toggleSelection( false );
395
- }
396
-
397
- function onResizeStop() {
398
- toggleSelection( true );
399
- }
397
+ }, [ loadedNaturalWidth, loadedNaturalHeight, imageElement?.complete ] );
400
398
 
401
399
  function onImageError() {
402
400
  setHasImageErrored( true );
@@ -541,49 +539,49 @@ export default function Image( {
541
539
 
542
540
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();
543
541
 
544
- const dimensionsControl = (
545
- <DimensionsTool
546
- value={ { width, height, scale, aspectRatio } }
547
- onChange={ ( {
548
- width: newWidth,
549
- height: newHeight,
550
- scale: newScale,
551
- aspectRatio: newAspectRatio,
552
- } ) => {
553
- // Rebuilding the object forces setting `undefined`
554
- // for values that are removed since setAttributes
555
- // doesn't do anything with keys that aren't set.
556
- setAttributes( {
557
- // CSS includes `height: auto`, but we need
558
- // `width: auto` to fix the aspect ratio when
559
- // only height is set due to the width and
560
- // height attributes set via the server.
561
- width: ! newWidth && newHeight ? 'auto' : newWidth,
542
+ const dimensionsControl =
543
+ isResizable &&
544
+ ( SIZED_LAYOUTS.includes( parentLayoutType ) ? (
545
+ <DimensionsTool
546
+ value={ { aspectRatio } }
547
+ onChange={ ( { aspectRatio: newAspectRatio } ) => {
548
+ setAttributes( {
549
+ aspectRatio: newAspectRatio,
550
+ scale: 'cover',
551
+ } );
552
+ } }
553
+ defaultAspectRatio="auto"
554
+ tools={ [ 'aspectRatio' ] }
555
+ />
556
+ ) : (
557
+ <DimensionsTool
558
+ value={ { width, height, scale, aspectRatio } }
559
+ onChange={ ( {
560
+ width: newWidth,
562
561
  height: newHeight,
563
562
  scale: newScale,
564
563
  aspectRatio: newAspectRatio,
565
- } );
566
- } }
567
- defaultScale="cover"
568
- defaultAspectRatio="auto"
569
- scaleOptions={ scaleOptions }
570
- unitsOptions={ dimensionsUnitsOptions }
571
- />
572
- );
573
-
574
- const aspectRatioControl = (
575
- <DimensionsTool
576
- value={ { aspectRatio } }
577
- onChange={ ( { aspectRatio: newAspectRatio } ) => {
578
- setAttributes( {
579
- aspectRatio: newAspectRatio,
580
- scale: 'cover',
581
- } );
582
- } }
583
- defaultAspectRatio="auto"
584
- tools={ [ 'aspectRatio' ] }
585
- />
586
- );
564
+ } ) => {
565
+ // Rebuilding the object forces setting `undefined`
566
+ // for values that are removed since setAttributes
567
+ // doesn't do anything with keys that aren't set.
568
+ setAttributes( {
569
+ // CSS includes `height: auto`, but we need
570
+ // `width: auto` to fix the aspect ratio when
571
+ // only height is set due to the width and
572
+ // height attributes set via the server.
573
+ width: ! newWidth && newHeight ? 'auto' : newWidth,
574
+ height: newHeight,
575
+ scale: newScale,
576
+ aspectRatio: newAspectRatio,
577
+ } );
578
+ } }
579
+ defaultScale="cover"
580
+ defaultAspectRatio="auto"
581
+ scaleOptions={ scaleOptions }
582
+ unitsOptions={ dimensionsUnitsOptions }
583
+ />
584
+ ) );
587
585
 
588
586
  const resetAll = () => {
589
587
  setAttributes( {
@@ -603,10 +601,7 @@ export default function Image( {
603
601
  resetAll={ resetAll }
604
602
  dropdownMenuProps={ dropdownMenuProps }
605
603
  >
606
- { isResizable &&
607
- ( parentLayoutType === 'grid'
608
- ? aspectRatioControl
609
- : dimensionsControl ) }
604
+ { dimensionsControl }
610
605
  </ToolsPanel>
611
606
  </InspectorControls>
612
607
  );
@@ -835,10 +830,7 @@ export default function Image( {
835
830
  />
836
831
  </ToolsPanelItem>
837
832
  ) }
838
- { isResizable &&
839
- ( parentLayoutType === 'grid'
840
- ? aspectRatioControl
841
- : dimensionsControl ) }
833
+ { dimensionsControl }
842
834
  { !! imageSizeOptions.length && (
843
835
  <ResolutionTool
844
836
  value={ sizeSlug }
@@ -926,17 +918,19 @@ export default function Image( {
926
918
  alt={ defaultedAlt }
927
919
  onError={ onImageError }
928
920
  onLoad={ onImageLoad }
929
- ref={ imageRef }
921
+ ref={ setRefs }
930
922
  className={ borderProps.className }
923
+ width={ naturalWidth }
924
+ height={ naturalHeight }
931
925
  style={ {
932
- width:
933
- ( width && height ) || aspectRatio
934
- ? '100%'
935
- : undefined,
936
- height:
937
- ( width && height ) || aspectRatio
938
- ? '100%'
939
- : undefined,
926
+ aspectRatio,
927
+ ...( resizeDelta
928
+ ? {
929
+ width: pixelSize.width + resizeDelta.width,
930
+ height:
931
+ pixelSize.height + resizeDelta.height,
932
+ }
933
+ : { width, height } ),
940
934
  objectFit: scale,
941
935
  ...borderProps.style,
942
936
  ...shadowProps.style,
@@ -953,8 +947,7 @@ export default function Image( {
953
947
  <ImageEditor
954
948
  id={ id }
955
949
  url={ url }
956
- width={ numericWidth }
957
- height={ numericHeight }
950
+ { ...pixelSize }
958
951
  naturalHeight={ naturalHeight }
959
952
  naturalWidth={ naturalWidth }
960
953
  onSaveImage={ ( imageAttributes ) =>
@@ -967,26 +960,21 @@ export default function Image( {
967
960
  />
968
961
  </ImageWrapper>
969
962
  );
970
- } else if ( ! isResizable || parentLayoutType === 'grid' ) {
971
- img = (
972
- <div style={ { width, height, aspectRatio } }>
973
- <ImageWrapper href={ href }>{ img }</ImageWrapper>
974
- </div>
975
- );
976
963
  } else {
964
+ img = <ImageWrapper href={ href }>{ img }</ImageWrapper>;
965
+ }
966
+
967
+ let resizableBox;
968
+ if (
969
+ isResizable &&
970
+ isSingleSelected &&
971
+ ! isEditingImage &&
972
+ ! SIZED_LAYOUTS.includes( parentLayoutType )
973
+ ) {
977
974
  const numericRatio = aspectRatio && evalAspectRatio( aspectRatio );
978
- const customRatio = numericWidth / numericHeight;
975
+ const customRatio = pixelSize.width / pixelSize.height;
979
976
  const naturalRatio = naturalWidth / naturalHeight;
980
977
  const ratio = numericRatio || customRatio || naturalRatio || 1;
981
- const currentWidth =
982
- ! numericWidth && numericHeight
983
- ? numericHeight * ratio
984
- : numericWidth;
985
- const currentHeight =
986
- ! numericHeight && numericWidth
987
- ? numericWidth / ratio
988
- : numericHeight;
989
-
990
978
  const minWidth =
991
979
  naturalWidth < naturalHeight ? MIN_SIZE : MIN_SIZE * ratio;
992
980
  const minHeight =
@@ -1032,21 +1020,17 @@ export default function Image( {
1032
1020
  }
1033
1021
  }
1034
1022
  /* eslint-enable no-lonely-if */
1035
- img = (
1023
+ resizableBox = (
1036
1024
  <ResizableBox
1025
+ ref={ effectResizeableBoxPlacement }
1037
1026
  style={ {
1038
- display: 'block',
1039
- objectFit: scale,
1040
- aspectRatio:
1041
- ! width && ! height && aspectRatio
1042
- ? aspectRatio
1043
- : undefined,
1044
- } }
1045
- size={ {
1046
- width: currentWidth ?? 'auto',
1047
- height: currentHeight ?? 'auto',
1027
+ position: 'absolute',
1028
+ // To match the vertical-align: bottom of the img (from style.scss)
1029
+ // syncs the top with the img. This matters when the img height is
1030
+ // less than the line-height.
1031
+ inset: `${ offsetTop }px 0 0 0`,
1048
1032
  } }
1049
- showHandle={ isSingleSelected }
1033
+ size={ pixelSize }
1050
1034
  minWidth={ minWidth }
1051
1035
  maxWidth={ maxResizeWidth }
1052
1036
  minHeight={ minHeight }
@@ -1058,9 +1042,19 @@ export default function Image( {
1058
1042
  bottom: true,
1059
1043
  left: showLeftHandle,
1060
1044
  } }
1061
- onResizeStart={ onResizeStart }
1062
- onResizeStop={ ( event, direction, elt ) => {
1063
- onResizeStop();
1045
+ onResizeStart={ () => {
1046
+ toggleSelection( false );
1047
+ } }
1048
+ onResize={ ( event, direction, elt, delta ) => {
1049
+ setResizeDelta( delta );
1050
+ } }
1051
+ onResizeStop={ ( event, direction, elt, delta ) => {
1052
+ toggleSelection( true );
1053
+ setResizeDelta( null );
1054
+ setPixelSize( ( current ) => ( {
1055
+ width: current.width + delta.width,
1056
+ height: current.height + delta.height,
1057
+ } ) );
1064
1058
 
1065
1059
  // Clear hardcoded width if the resized width is close to the max-content width.
1066
1060
  if (
@@ -1091,9 +1085,7 @@ export default function Image( {
1091
1085
  } );
1092
1086
  } }
1093
1087
  resizeRatio={ align === 'center' ? 2 : 1 }
1094
- >
1095
- <ImageWrapper href={ href }>{ img }</ImageWrapper>
1096
- </ResizableBox>
1088
+ />
1097
1089
  );
1098
1090
  }
1099
1091
 
@@ -1139,6 +1131,7 @@ export default function Image( {
1139
1131
  { controls }
1140
1132
  { featuredImageControl }
1141
1133
  { img }
1134
+ { resizableBox }
1142
1135
 
1143
1136
  <Caption
1144
1137
  attributes={ attributes }
@@ -126,6 +126,7 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
126
126
  orderby: orderBy,
127
127
  per_page: postsToShow,
128
128
  _embed: 'wp:featuredmedia',
129
+ ignore_sticky: true,
129
130
  } ).filter( ( [ , value ] ) => typeof value !== 'undefined' )
130
131
  );
131
132
 
@@ -36,24 +36,24 @@ export default function useTemplatePartAreaLabel( clientId ) {
36
36
  return;
37
37
  }
38
38
 
39
+ const { getCurrentTheme, getEditedEntityRecord } =
40
+ select( coreStore );
41
+
42
+ const currentTheme = getCurrentTheme();
39
43
  const defaultTemplatePartAreas =
40
- select( coreStore ).getEntityRecord( 'root', '__unstableBase' )
41
- ?.default_template_part_areas || [];
44
+ currentTheme?.default_template_part_areas || [];
42
45
 
43
46
  const definedAreas = defaultTemplatePartAreas.map( ( item ) => ( {
44
47
  ...item,
45
48
  icon: getTemplatePartIcon( item.icon ),
46
49
  } ) );
47
50
 
48
- const { getCurrentTheme, getEditedEntityRecord } =
49
- select( coreStore );
50
-
51
51
  for ( const templatePartClientId of parentTemplatePartClientIds ) {
52
52
  const templatePartBlock = getBlock( templatePartClientId );
53
53
 
54
54
  // The 'area' usually isn't stored on the block, but instead
55
55
  // on the entity.
56
- const { theme = getCurrentTheme()?.stylesheet, slug } =
56
+ const { theme = currentTheme?.stylesheet, slug } =
57
57
  templatePartBlock.attributes;
58
58
  const templatePartEntityId = createTemplatePartId(
59
59
  theme,
@@ -58,7 +58,6 @@
58
58
  "color": {
59
59
  "gradients": true,
60
60
  "link": true,
61
- "__experimentalDuotone": ".wp-block-post-author__avatar img",
62
61
  "__experimentalDefaultControls": {
63
62
  "background": true,
64
63
  "text": true
@@ -78,6 +77,14 @@
78
77
  "width": true,
79
78
  "style": true
80
79
  }
80
+ },
81
+ "filter": {
82
+ "duotone": true
83
+ }
84
+ },
85
+ "selectors": {
86
+ "filter": {
87
+ "duotone": ".wp-block-post-author .wp-block-post-author__avatar img"
81
88
  }
82
89
  },
83
90
  "editorStyle": "wp-block-post-author-editor",
@@ -99,7 +99,7 @@ function PostAuthorEdit( {
99
99
  const showAuthorControl =
100
100
  !! postId && ! isDescendentOfQueryLoop && authorOptions.length > 0;
101
101
 
102
- if ( ! supportsAuthor ) {
102
+ if ( ! supportsAuthor && postType !== undefined ) {
103
103
  return (
104
104
  <div { ...blockProps }>
105
105
  { sprintf(
@@ -132,15 +132,15 @@ function PostAuthorNameEdit( {
132
132
  </ToolsPanel>
133
133
  </InspectorControls>
134
134
  <div { ...blockProps }>
135
- { supportsAuthor
136
- ? displayAuthor
137
- : sprintf(
135
+ { ! supportsAuthor && postType !== undefined
136
+ ? sprintf(
138
137
  // translators: %s: Name of the post type e.g: "post".
139
138
  __(
140
139
  'This post type (%s) does not support the author.'
141
140
  ),
142
141
  postType
143
- ) }
142
+ )
143
+ : displayAuthor }
144
144
  </div>
145
145
  </>
146
146
  );
@@ -35,6 +35,7 @@ import {
35
35
  useAllowedControls,
36
36
  isControlAllowed,
37
37
  useTaxonomies,
38
+ useOrderByOptions,
38
39
  } from '../../utils';
39
40
  import { useToolsPanelDropdownMenuProps } from '../../../utils/hooks';
40
41
 
@@ -111,6 +112,7 @@ export default function QueryInspectorControls( props ) {
111
112
  return onChangeDebounced.cancel;
112
113
  }, [ querySearch, onChangeDebounced ] );
113
114
 
115
+ const orderByOptions = useOrderByOptions( postType );
114
116
  const showInheritControl =
115
117
  ! isSingular && isControlAllowed( allowedControls, 'inherit' );
116
118
  const showPostTypeControl =
@@ -329,7 +331,7 @@ export default function QueryInspectorControls( props ) {
329
331
  isShownByDefault
330
332
  >
331
333
  <OrderControl
332
- { ...{ order, orderBy } }
334
+ { ...{ order, orderBy, orderByOptions } }
333
335
  onChange={ setQuery }
334
336
  />
335
337
  </ToolsPanelItem>
@@ -4,7 +4,7 @@
4
4
  import { SelectControl } from '@wordpress/components';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
- const orderOptions = [
7
+ const defaultOrderByOptions = [
8
8
  {
9
9
  label: __( 'Newest to oldest' ),
10
10
  value: 'date/desc',
@@ -24,14 +24,20 @@ const orderOptions = [
24
24
  value: 'title/desc',
25
25
  },
26
26
  ];
27
- function OrderControl( { order, orderBy, onChange } ) {
27
+
28
+ function OrderControl( {
29
+ order,
30
+ orderBy,
31
+ orderByOptions = defaultOrderByOptions,
32
+ onChange,
33
+ } ) {
28
34
  return (
29
35
  <SelectControl
30
36
  __nextHasNoMarginBottom
31
37
  __next40pxDefaultSize
32
38
  label={ __( 'Order by' ) }
33
39
  value={ `${ orderBy }/${ order }` }
34
- options={ orderOptions }
40
+ options={ orderByOptions }
35
41
  onChange={ ( value ) => {
36
42
  const [ newOrderBy, newOrder ] = value.split( '/' );
37
43
  onChange( { order: newOrder, orderBy: newOrderBy } );
@@ -6,6 +6,7 @@ import { useMemo } from '@wordpress/element';
6
6
  import { store as coreStore } from '@wordpress/core-data';
7
7
  import { store as blockEditorStore } from '@wordpress/block-editor';
8
8
  import { decodeEntities } from '@wordpress/html-entities';
9
+ import { __ } from '@wordpress/i18n';
9
10
  import {
10
11
  cloneBlock,
11
12
  getBlockSupport,
@@ -13,6 +14,7 @@ import {
13
14
  } from '@wordpress/blocks';
14
15
 
15
16
  /** @typedef {import('@wordpress/blocks').WPBlockVariation} WPBlockVariation */
17
+ /** @typedef {import('@wordpress/components/build-types/query-controls/types').OrderByOption} OrderByOption */
16
18
 
17
19
  /**
18
20
  * @typedef IHasNameAndId
@@ -186,6 +188,62 @@ export function useIsPostTypeHierarchical( postType ) {
186
188
  );
187
189
  }
188
190
 
191
+ /**
192
+ * List of avaiable options to order by.
193
+ *
194
+ * @param {string} postType The post type to check.
195
+ * @return {OrderByOption[]} List of order options.
196
+ */
197
+ export function useOrderByOptions( postType ) {
198
+ const supportsCustomOrder = useSelect(
199
+ ( select ) => {
200
+ const type = select( coreStore ).getPostType( postType );
201
+ return !! type?.supports?.[ 'page-attributes' ];
202
+ },
203
+ [ postType ]
204
+ );
205
+
206
+ return useMemo( () => {
207
+ const orderByOptions = [
208
+ {
209
+ label: __( 'Newest to oldest' ),
210
+ value: 'date/desc',
211
+ },
212
+ {
213
+ label: __( 'Oldest to newest' ),
214
+ value: 'date/asc',
215
+ },
216
+ {
217
+ /* translators: Label for ordering posts by title in ascending order. */
218
+ label: __( 'A → Z' ),
219
+ value: 'title/asc',
220
+ },
221
+ {
222
+ /* translators: Label for ordering posts by title in descending order. */
223
+ label: __( 'Z → A' ),
224
+ value: 'title/desc',
225
+ },
226
+ ];
227
+
228
+ if ( supportsCustomOrder ) {
229
+ orderByOptions.push(
230
+ {
231
+ /* translators: Label for ordering posts by ascending menu order. */
232
+ label: __( 'Ascending by order' ),
233
+ value: 'menu_order/asc',
234
+ },
235
+ {
236
+ /* translators: Label for ordering posts by descending menu order. */
237
+ label: __( 'Descending by order' ),
238
+ value: 'menu_order/desc',
239
+ }
240
+ );
241
+ }
242
+
243
+ return orderByOptions;
244
+ }, [ supportsCustomOrder ] );
245
+ }
246
+
189
247
  /**
190
248
  * Hook that returns the query properties' names defined by the active
191
249
  * block variation, to determine which block's filters to show.
@@ -23,9 +23,9 @@
23
23
  },
24
24
  "color": {
25
25
  "gradients": true,
26
- "text": true,
27
26
  "__experimentalDefaultControls": {
28
- "background": true
27
+ "background": true,
28
+ "text": true
29
29
  }
30
30
  },
31
31
  "typography": {
@@ -23,7 +23,7 @@ function render_block_core_query_total( $attributes, $content, $block ) {
23
23
  $wrapper_attributes = get_block_wrapper_attributes();
24
24
  if ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ) {
25
25
  $query_to_use = $wp_query;
26
- $current_page = max( 1, get_query_var( 'paged', 1 ) );
26
+ $current_page = max( 1, (int) get_query_var( 'paged', 1 ) );
27
27
  } else {
28
28
  $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page';
29
29
  $current_page = isset( $_GET[ $page_key ] ) ? (int) $_GET[ $page_key ] : 1;
@@ -31,7 +31,7 @@ function render_block_core_query_total( $attributes, $content, $block ) {
31
31
  }
32
32
 
33
33
  $max_rows = $query_to_use->found_posts;
34
- $posts_per_page = $query_to_use->get( 'posts_per_page' );
34
+ $posts_per_page = (int) $query_to_use->get( 'posts_per_page' );
35
35
 
36
36
  // Calculate the range of posts being displayed.
37
37
  $start = ( $current_page - 1 ) * $posts_per_page + 1;
@@ -36,7 +36,6 @@
36
36
  "align": true,
37
37
  "alignWide": false,
38
38
  "color": {
39
- "__experimentalDuotone": "img, .components-placeholder__illustration, .components-placeholder::before",
40
39
  "text": false,
41
40
  "background": false
42
41
  },
@@ -50,6 +49,9 @@
50
49
  },
51
50
  "interactivity": {
52
51
  "clientNavigation": true
52
+ },
53
+ "filter": {
54
+ "duotone": true
53
55
  }
54
56
  },
55
57
  "styles": [
@@ -60,6 +62,11 @@
60
62
  },
61
63
  { "name": "rounded", "label": "Rounded" }
62
64
  ],
65
+ "selectors": {
66
+ "filter": {
67
+ "duotone": ".wp-block-site-logo img, .wp-block-site-logo .components-placeholder__illustration, .wp-block-site-logo .components-placeholder::before"
68
+ }
69
+ },
63
70
  "editorStyle": "wp-block-site-logo-editor",
64
71
  "style": "wp-block-site-logo"
65
72
  }
@@ -31,7 +31,7 @@ function render_block_core_site_title( $attributes ) {
31
31
  }
32
32
 
33
33
  if ( $attributes['isLink'] ) {
34
- $aria_current = is_home() || ( is_front_page() && 'page' === get_option( 'show_on_front' ) ) ? ' aria-current="page"' : '';
34
+ $aria_current = ! is_paged() && ( is_front_page() || is_home() && ( (int) get_option( 'page_for_posts' ) !== get_queried_object_id() ) ) ? ' aria-current="page"' : '';
35
35
  $link_target = ! empty( $attributes['linkTarget'] ) ? $attributes['linkTarget'] : '_self';
36
36
 
37
37
  $site_title = sprintf(
@@ -50,6 +50,7 @@
50
50
  "supports": {
51
51
  "align": [ "left", "center", "right" ],
52
52
  "anchor": true,
53
+ "html": false,
53
54
  "__experimentalExposeControlsToChildren": true,
54
55
  "layout": {
55
56
  "allowSwitching": false,