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 |