PluginProbe ʕ •ᴥ•ʔ
AlphaListing / trunk
AlphaListing vtrunk
trunk 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0
alphalisting / scripts / components / PostParent.js
alphalisting / scripts / components Last commit date
utils 1 month ago AZInspectorControls.js 1 month ago DisplayOptions.js 1 month ago Extensions.js 1 month ago ItemSelection.js 1 month ago PostParent.js 1 month ago
PostParent.js
128 lines
1 /**
2 * External dependencies
3 */
4 import {
5 get,
6 unescape as unescapeString,
7 debounce,
8 flatMap,
9 repeat,
10 find,
11 } from 'lodash';
12
13 /**
14 * WordPress dependencies
15 */
16 import { __ } from '@wordpress/i18n';
17 import { ComboboxControl } from '@wordpress/components';
18 import { useState, useMemo } from '@wordpress/element';
19 import { useSelect } from '@wordpress/data';
20 import { buildTermsTree } from './utils/terms';
21
22 function getTitle( post ) {
23 return post?.title?.rendered
24 ? post.title.rendered
25 : `#${ post.id } (${ __( 'no title' ) })`;
26 }
27
28 export function PostParent( { pageId, postTypeSlug, onChange } ) {
29 const [ fieldValue, setFieldValue ] = useState( '' );
30 const isSearching = fieldValue;
31 const { parentPost, parentPostId, items, postType } = useSelect(
32 ( select ) => {
33 const { getPostType, getEntityRecords, getEntityRecord } = select( 'core' );
34 const pType = getPostType( postTypeSlug );
35 const isHierarchical = get( pType, [ 'hierarchical' ], false );
36 const query = {
37 per_page: 100,
38 orderby: 'menu_order',
39 order: 'asc',
40 _fields: 'id,title,parent',
41 };
42
43 // Perform a search when the field is changed.
44 if ( isSearching ) {
45 query.search = fieldValue;
46 }
47
48 return {
49 parentPostId: pageId,
50 parentPost: pageId
51 ? getEntityRecord( 'postType', postTypeSlug, pageId )
52 : null,
53 items: isHierarchical
54 ? getEntityRecords( 'postType', postTypeSlug, query )
55 : [],
56 postType: pType,
57 };
58 },
59 [ fieldValue, pageId, postTypeSlug ]
60 );
61
62 const isHierarchical = get( postType, [ 'hierarchical' ], false );
63 const pageItems = items || [];
64 const getOptionsFromTree = ( tree, level = 0 ) => {
65 return flatMap( tree, ( treeNode ) => [
66 {
67 value: treeNode.id,
68 label: repeat( '', level ) + unescapeString( treeNode.name ),
69 },
70 ...getOptionsFromTree( treeNode.children || [], level + 1 ),
71 ] );
72 };
73
74 const parentOptions = useMemo( () => {
75 let tree = pageItems.map( ( item ) => ( {
76 id: item.id,
77 parent: item.parent,
78 name: getTitle( item ),
79 } ) );
80
81 // Only build a hierarchical tree when not searching.
82 if ( ! isSearching ) {
83 tree = buildTermsTree( tree );
84 }
85
86 const opts = getOptionsFromTree( tree );
87
88 // Ensure the current parent is in the options list.
89 const optsHasParent = find(
90 opts,
91 ( item ) => item.value === parentPostId
92 );
93 if ( parentPost && ! optsHasParent ) {
94 opts.unshift( {
95 value: parentPostId,
96 label: getTitle( parentPost ),
97 } );
98 }
99 return opts;
100 }, [ pageItems, parentPost, parentPostId, isSearching ] );
101
102 if ( ! isHierarchical ) {
103 return null;
104 }
105 /**
106 * Handle user input.
107 *
108 * @param {string} inputValue The current value of the input field.
109 */
110 const handleKeydown = ( inputValue ) => {
111 setFieldValue( inputValue );
112 };
113
114 return (
115 <ComboboxControl
116 label={ __( 'Parent post', 'alphalisting' ) }
117 value={ parentPostId }
118 options={ parentOptions }
119 onFilterValueChange={ debounce( handleKeydown, 300 ) }
120 onChange={ onChange }
121 __next40pxDefaultSize
122 __nextHasNoMarginBottom
123 />
124 );
125 }
126
127 export default PostParent;
128