Skip to content

Commit b56680f

Browse files
committed
Tweak conditions
1 parent 0b3cfdb commit b56680f

File tree

4 files changed

+89
-42
lines changed

4 files changed

+89
-42
lines changed

packages/block-library/src/navigation-link/edit.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,13 @@ export default function NavigationLinkEdit( {
265265
const { getBlocks } = useSelect( blockEditorStore );
266266

267267
// URL binding logic
268-
const { clearBinding, createBinding } = useEntityBinding( {
269-
clientId,
270-
attributes,
271-
} );
268+
const { clearBinding, createBinding, isBoundEntityAvailable } =
269+
useEntityBinding( {
270+
clientId,
271+
attributes,
272+
} );
272273

273-
const [ isInvalid, isDraft, isDeleted ] = useIsInvalidLink(
274+
const [ isInvalid, isDraft ] = useIsInvalidLink(
274275
kind,
275276
type,
276277
id,
@@ -319,10 +320,16 @@ export default function NavigationLinkEdit( {
319320
transformToSubmenu,
320321
] );
321322

322-
// Auto-clear URL and open Link UI when entity is deleted and block is selected
323+
// Auto-clear URL and open Link UI when entity is not available and block is selected
323324
// Keep binding so invalid state remains until user selects a new entity
324325
useEffect( () => {
325-
if ( isSelected && isDeleted && id && metadata?.bindings?.url && url ) {
326+
if (
327+
isSelected &&
328+
! isBoundEntityAvailable &&
329+
id &&
330+
metadata?.bindings?.url &&
331+
url
332+
) {
326333
// Mark this change as not persistent to avoid creating undo levels
327334
// for automatic cleanup of broken bindings
328335
__unstableMarkNextChangeAsNotPersistent();
@@ -336,7 +343,7 @@ export default function NavigationLinkEdit( {
336343
}
337344
}, [
338345
isSelected,
339-
isDeleted,
346+
isBoundEntityAvailable,
340347
id,
341348
metadata?.bindings?.url,
342349
url,
@@ -492,7 +499,6 @@ export default function NavigationLinkEdit( {
492499
attributes={ attributes }
493500
setAttributes={ setAttributes }
494501
clientId={ clientId }
495-
isDeleted={ isDeleted }
496502
/>
497503
</InspectorControls>
498504
<div { ...blockProps }>
@@ -573,7 +579,6 @@ export default function NavigationLinkEdit( {
573579
ref={ linkUIref }
574580
clientId={ clientId }
575581
link={ attributes }
576-
isDeleted={ isDeleted }
577582
onClose={ () => {
578583
setIsLinkOpen( false );
579584
// If there is no link then remove the auto-inserted block.

packages/block-library/src/navigation-link/link-ui/index.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { useInstanceId } from '@wordpress/compose';
2626
*/
2727
import { LinkUIPageCreator } from './page-creator';
2828
import LinkUIBlockInserter from './block-inserter';
29+
import { useEntityBinding } from '../shared/use-entity-binding';
2930

3031
/**
3132
* Given the Link block's type attribute, return the query params to give to
@@ -66,7 +67,8 @@ export function getSuggestionsQuery( type, kind ) {
6667
}
6768

6869
function UnforwardedLinkUI( props, ref ) {
69-
const { label, url, opensInNewTab, type, kind, id, metadata } = props.link;
70+
const { label, url, opensInNewTab, type, kind, id } = props.link;
71+
const { clientId } = props;
7072
const postType = type || 'page';
7173

7274
const [ addingBlock, setAddingBlock ] = useState( false );
@@ -78,15 +80,15 @@ function UnforwardedLinkUI( props, ref ) {
7880
name: postType,
7981
} );
8082

81-
// Check if there's a URL binding with the new binding sources
82-
// Only enable handleEntities when there's actually a binding present
83-
// Disable handleEntities if entity is deleted so user can edit the link
84-
const { isDeleted = false } = props;
85-
const hasUrlBinding =
86-
( metadata?.bindings?.url?.source === 'core/post-data' ||
87-
metadata?.bindings?.url?.source === 'core/term-data' ) &&
88-
!! id &&
89-
! isDeleted;
83+
// Use the entity binding hook to get binding status
84+
const { isBindingActive } = useEntityBinding( {
85+
clientId,
86+
attributes: props.link,
87+
} );
88+
89+
// Only enable handleEntities when binding is active (exists AND entity available)
90+
// This allows editing when entity is missing even though binding exists
91+
const hasUrlBinding = isBindingActive;
9092

9193
// Memoize link value to avoid overriding the LinkControl's internal state.
9294
// This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/50976#issuecomment-1568226407.

packages/block-library/src/navigation-link/shared/controls.js

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,8 @@ function getEntityTypeName( type, kind ) {
6767
* @param {Object} props.attributes - Block attributes
6868
* @param {Function} props.setAttributes - Function to update block attributes
6969
* @param {string} props.clientId - Block client ID
70-
* @param {boolean} props.isDeleted - Whether the linked entity is deleted
7170
*/
72-
export function Controls( {
73-
attributes,
74-
setAttributes,
75-
clientId,
76-
isDeleted = false,
77-
} ) {
71+
export function Controls( { attributes, setAttributes, clientId } ) {
7872
const { label, url, description, rel, opensInNewTab } = attributes;
7973
const lastURLRef = useRef( url );
8074
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
@@ -93,15 +87,16 @@ export function Controls( {
9387
}, [ url ] );
9488

9589
// Use the entity binding hook internally
96-
const { hasUrlBinding, clearBinding } = useEntityBinding( {
90+
const {
91+
hasUrlBinding,
92+
isBoundEntityAvailable,
93+
isBindingActive,
94+
clearBinding,
95+
} = useEntityBinding( {
9796
clientId,
9897
attributes,
9998
} );
10099

101-
// When entity is deleted, keep binding active for UI (locked state)
102-
// User must unlock to edit
103-
const isBindingActive = hasUrlBinding;
104-
105100
// Get direct store dispatch to bypass setBoundAttributes wrapper
106101
const { updateBlockAttributes } = useDispatch( blockEditorStore );
107102

@@ -176,7 +171,7 @@ export function Controls( {
176171
id={ inputId }
177172
label={ __( 'Link' ) }
178173
value={ ( () => {
179-
if ( isDeleted && hasUrlBinding ) {
174+
if ( ! isBoundEntityAvailable && hasUrlBinding ) {
180175
return '';
181176
}
182177
return inputValue ? safeDecodeURI( inputValue ) : '';
@@ -185,16 +180,18 @@ export function Controls( {
185180
type="url"
186181
disabled={ isBindingActive }
187182
aria-invalid={
188-
isDeleted && hasUrlBinding ? 'true' : undefined
183+
! isBoundEntityAvailable && hasUrlBinding
184+
? 'true'
185+
: undefined
189186
}
190187
aria-describedby={ helpTextId }
191188
className={
192-
isDeleted && hasUrlBinding
189+
! isBoundEntityAvailable && hasUrlBinding
193190
? 'navigation-link-control__input-with-error-suffix'
194191
: undefined
195192
}
196193
onClick={
197-
isDeleted && hasUrlBinding
194+
! isBoundEntityAvailable && hasUrlBinding
198195
? () => {
199196
unsyncBoundLink();
200197
shouldFocusURLInputRef.current = true;
@@ -236,7 +233,7 @@ export function Controls( {
236233
} );
237234
} }
238235
help={
239-
isDeleted && hasUrlBinding ? (
236+
! isBoundEntityAvailable && hasUrlBinding ? (
240237
<MissingEntityHelpText
241238
id={ helpTextId }
242239
type={ attributes.type }
@@ -252,7 +249,7 @@ export function Controls( {
252249
)
253250
}
254251
suffix={
255-
isBindingActive && (
252+
hasUrlBinding && (
256253
<Button
257254
icon={ unlinkIcon }
258255
onClick={ () => {
@@ -266,7 +263,7 @@ export function Controls( {
266263
label={ __( 'Unsync and edit' ) }
267264
__next40pxDefaultSize
268265
className={
269-
isDeleted && hasUrlBinding
266+
! isBoundEntityAvailable && hasUrlBinding
270267
? 'navigation-link-control__error-suffix-button'
271268
: undefined
272269
}

packages/block-library/src/navigation-link/shared/use-entity-binding.js

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
* WordPress dependencies
33
*/
44
import { useCallback } from '@wordpress/element';
5-
import { useBlockBindingsUtils } from '@wordpress/block-editor';
5+
import {
6+
useBlockBindingsUtils,
7+
useBlockEditingMode,
8+
} from '@wordpress/block-editor';
9+
import { useSelect } from '@wordpress/data';
10+
import { store as coreStore } from '@wordpress/core-data';
611

712
/**
813
* Builds entity binding configuration for navigation link URLs.
@@ -57,14 +62,46 @@ export function buildNavigationLinkEntityBinding( kind ) {
5762
*/
5863
export function useEntityBinding( { clientId, attributes } ) {
5964
const { updateBlockBindings } = useBlockBindingsUtils( clientId );
60-
const { metadata, id, kind } = attributes;
65+
const { metadata, id, kind, type } = attributes;
66+
const blockEditingMode = useBlockEditingMode();
6167

6268
const hasUrlBinding = !! metadata?.bindings?.url && !! id;
6369
const expectedSource =
6470
kind === 'post-type' ? 'core/post-data' : 'core/term-data';
6571
const hasCorrectBinding =
6672
hasUrlBinding && metadata?.bindings?.url?.source === expectedSource;
6773

74+
// Check if the bound entity is available (not deleted)
75+
const isBoundEntityAvailable = useSelect(
76+
( select ) => {
77+
const isPostType =
78+
kind === 'post-type' || type === 'post' || type === 'page';
79+
80+
if ( ! isPostType || ! hasCorrectBinding || ! id ) {
81+
return true; // Assume available if not a post type or no binding
82+
}
83+
84+
// Skip check in disabled contexts to avoid unnecessary requests
85+
if ( blockEditingMode === 'disabled' ) {
86+
return true; // Assume available in disabled contexts
87+
}
88+
89+
const { getEntityRecord, hasFinishedResolution } =
90+
select( coreStore );
91+
const entityRecord = getEntityRecord( 'postType', type, id );
92+
const hasResolved = hasFinishedResolution( 'getEntityRecord', [
93+
'postType',
94+
type,
95+
id,
96+
] );
97+
98+
// If resolution has finished and entityRecord is undefined, the entity was deleted
99+
// Return true if entity exists, false if deleted
100+
return hasResolved ? entityRecord !== undefined : true;
101+
},
102+
[ kind, type, id, hasCorrectBinding, blockEditingMode ]
103+
);
104+
68105
const clearBinding = useCallback( () => {
69106
if ( hasUrlBinding ) {
70107
updateBlockBindings( { url: undefined } );
@@ -94,11 +131,17 @@ export function useEntityBinding( { clientId, attributes } ) {
94131
// Don't create binding if validation fails
95132
}
96133
},
97-
[ updateBlockBindings, kind, id ]
134+
[ updateBlockBindings, kind ]
98135
);
99136

137+
// A binding is "active" only when it exists AND the entity is available
138+
// This determines when the input should be disabled/locked
139+
const isBindingActive = hasCorrectBinding && isBoundEntityAvailable;
140+
100141
return {
101142
hasUrlBinding: hasCorrectBinding,
143+
isBoundEntityAvailable,
144+
isBindingActive,
102145
clearBinding,
103146
createBinding,
104147
};

0 commit comments

Comments
 (0)