Skip to content

Commit 1b2882b

Browse files
Mamadukaramonjd
andauthored
Post Author: Optimize and improve user control queries (WordPress#70510)
* Post Author: Optimize and improve user control queries * Fix queries for low-capability users * Ensure the current author is included in the list Co-authored-by: Mamaduka <mamaduka@git.wordpress.org> Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
1 parent 1f78151 commit 1b2882b

File tree

1 file changed

+91
-40
lines changed
  • packages/block-library/src/post-author

1 file changed

+91
-40
lines changed

packages/block-library/src/post-author/edit.js

Lines changed: 91 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,93 @@ import {
2020
__experimentalToolsPanel as ToolsPanel,
2121
__experimentalToolsPanelItem as ToolsPanelItem,
2222
} from '@wordpress/components';
23+
import { debounce } from '@wordpress/compose';
24+
import { useMemo, useState } from '@wordpress/element';
2325
import { useSelect, useDispatch } from '@wordpress/data';
2426
import { __, sprintf } from '@wordpress/i18n';
27+
import { decodeEntities } from '@wordpress/html-entities';
2528
import { store as coreStore } from '@wordpress/core-data';
2629

2730
/**
2831
* Internal dependencies
2932
*/
3033
import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
3134

32-
const minimumUsersForCombobox = 25;
33-
3435
const AUTHORS_QUERY = {
3536
who: 'authors',
3637
per_page: 100,
38+
_fields: 'id,name',
39+
context: 'view',
3740
};
3841

42+
function AuthorCombobox( { value, onChange } ) {
43+
const [ filterValue, setFilterValue ] = useState( '' );
44+
const { authors, isLoading } = useSelect(
45+
( select ) => {
46+
const { getUsers, isResolving } = select( coreStore );
47+
48+
const query = { ...AUTHORS_QUERY };
49+
if ( filterValue ) {
50+
query.search = filterValue;
51+
query.search_columns = [ 'name' ];
52+
}
53+
54+
return {
55+
authors: getUsers( query ),
56+
isLoading: isResolving( 'getUsers', [ query ] ),
57+
};
58+
},
59+
[ filterValue ]
60+
);
61+
62+
const authorOptions = useMemo( () => {
63+
const fetchedAuthors = ( authors ?? [] ).map( ( author ) => {
64+
return {
65+
value: author.id,
66+
label: decodeEntities( author.name ),
67+
};
68+
} );
69+
70+
// Ensure the current author is included in the list.
71+
const foundAuthor = fetchedAuthors.findIndex(
72+
( fetchedAuthor ) => value?.id === fetchedAuthor.value
73+
);
74+
75+
let currentAuthor = [];
76+
if ( foundAuthor < 0 && value ) {
77+
currentAuthor = [
78+
{
79+
value: value.id,
80+
label: decodeEntities( value.name ),
81+
},
82+
];
83+
} else if ( foundAuthor < 0 && ! value ) {
84+
currentAuthor = [
85+
{
86+
value: 0,
87+
label: __( '(No author)' ),
88+
},
89+
];
90+
}
91+
92+
return [ ...currentAuthor, ...fetchedAuthors ];
93+
}, [ authors, value ] );
94+
95+
return (
96+
<ComboboxControl
97+
__next40pxDefaultSize
98+
__nextHasNoMarginBottom
99+
label={ __( 'Author' ) }
100+
options={ authorOptions }
101+
value={ value?.id }
102+
onFilterValueChange={ debounce( setFilterValue, 300 ) }
103+
onChange={ onChange }
104+
allowReset={ false }
105+
isLoading={ isLoading }
106+
/>
107+
);
108+
}
109+
39110
function PostAuthorEdit( {
40111
isSelected,
41112
context: { postType, postId, queryId },
@@ -45,22 +116,28 @@ function PostAuthorEdit( {
45116
const isDescendentOfQueryLoop = Number.isFinite( queryId );
46117
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
47118

48-
const { authorId, authorDetails, authors, supportsAuthor } = useSelect(
119+
const { authorDetails, canAssignAuthor, supportsAuthor } = useSelect(
49120
( select ) => {
50-
const { getEditedEntityRecord, getUser, getUsers, getPostType } =
121+
const { getEditedEntityRecord, getUser, getPostType } =
51122
select( coreStore );
52-
const _authorId = getEditedEntityRecord(
123+
const currentPost = getEditedEntityRecord(
53124
'postType',
54125
postType,
55126
postId
56-
)?.author;
127+
);
128+
const authorId = currentPost?.author;
57129

58130
return {
59-
authorId: _authorId,
60-
authorDetails: _authorId ? getUser( _authorId ) : null,
61-
authors: getUsers( AUTHORS_QUERY ),
131+
authorDetails: authorId
132+
? getUser( authorId, { context: 'view' } )
133+
: null,
62134
supportsAuthor:
63135
getPostType( postType )?.supports?.author ?? false,
136+
canAssignAuthor: currentPost?._links?.[
137+
'wp:action-assign-author'
138+
]
139+
? true
140+
: false,
64141
};
65142
},
66143
[ postType, postId ]
@@ -94,24 +171,14 @@ function PostAuthorEdit( {
94171
} ),
95172
} );
96173

97-
const authorOptions = authors?.length
98-
? authors.map( ( { id, name } ) => {
99-
return {
100-
value: id,
101-
label: name,
102-
};
103-
} )
104-
: [];
105-
106174
const handleSelect = ( nextAuthorId ) => {
107175
editEntityRecord( 'postType', postType, postId, {
108176
author: nextAuthorId,
109177
} );
110178
};
111179

112-
const showCombobox = authorOptions.length >= minimumUsersForCombobox;
113180
const showAuthorControl =
114-
!! postId && ! isDescendentOfQueryLoop && authorOptions.length > 0;
181+
!! postId && ! isDescendentOfQueryLoop && canAssignAuthor;
115182

116183
if ( ! supportsAuthor && postType !== undefined ) {
117184
return (
@@ -142,26 +209,10 @@ function PostAuthorEdit( {
142209
>
143210
{ showAuthorControl && (
144211
<div style={ { gridColumn: '1 / -1' } }>
145-
{ ( showCombobox && (
146-
<ComboboxControl
147-
__next40pxDefaultSize
148-
__nextHasNoMarginBottom
149-
label={ __( 'Author' ) }
150-
options={ authorOptions }
151-
value={ authorId }
152-
onChange={ handleSelect }
153-
allowReset={ false }
154-
/>
155-
) ) || (
156-
<SelectControl
157-
__next40pxDefaultSize
158-
__nextHasNoMarginBottom
159-
label={ __( 'Author' ) }
160-
value={ authorId }
161-
options={ authorOptions }
162-
onChange={ handleSelect }
163-
/>
164-
) }
212+
<AuthorCombobox
213+
value={ authorDetails }
214+
onChange={ handleSelect }
215+
/>
165216
</div>
166217
) }
167218
<ToolsPanelItem

0 commit comments

Comments
 (0)