1 |
|
2 |
|
3 |
|
4 | import { times, unescape } from 'lodash';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | import { PanelBody, Placeholder, Spinner, ToggleControl } from '@wordpress/components';
|
10 | import { compose, withInstanceId } from '@wordpress/compose';
|
11 | import { withSelect } from '@wordpress/data';
|
12 | import { InspectorControls } from '@wordpress/block-editor';
|
13 | import { Component, Fragment } from '@wordpress/element';
|
14 | import { __ } from '@wordpress/i18n';
|
15 |
|
16 | class CategoriesEdit extends Component {
|
17 | constructor() {
|
18 | super( ...arguments );
|
19 |
|
20 | this.toggleDisplayAsDropdown = this.toggleDisplayAsDropdown.bind( this );
|
21 | this.toggleShowPostCounts = this.toggleShowPostCounts.bind( this );
|
22 | this.toggleShowHierarchy = this.toggleShowHierarchy.bind( this );
|
23 | }
|
24 |
|
25 | toggleDisplayAsDropdown() {
|
26 | const { attributes, setAttributes } = this.props;
|
27 | const { displayAsDropdown } = attributes;
|
28 |
|
29 | setAttributes( { displayAsDropdown: ! displayAsDropdown } );
|
30 | }
|
31 |
|
32 | toggleShowPostCounts() {
|
33 | const { attributes, setAttributes } = this.props;
|
34 | const { showPostCounts } = attributes;
|
35 |
|
36 | setAttributes( { showPostCounts: ! showPostCounts } );
|
37 | }
|
38 |
|
39 | toggleShowHierarchy() {
|
40 | const { attributes, setAttributes } = this.props;
|
41 | const { showHierarchy } = attributes;
|
42 |
|
43 | setAttributes( { showHierarchy: ! showHierarchy } );
|
44 | }
|
45 |
|
46 | getCategories( parentId = null ) {
|
47 | const categories = this.props.categories;
|
48 | if ( ! categories || ! categories.length ) {
|
49 | return [];
|
50 | }
|
51 |
|
52 | if ( parentId === null ) {
|
53 | return categories;
|
54 | }
|
55 |
|
56 | return categories.filter( ( category ) => category.parent === parentId );
|
57 | }
|
58 |
|
59 | getCategoryListClassName( level ) {
|
60 | return `wp-block-categories__list wp-block-categories__list-level-${ level }`;
|
61 | }
|
62 |
|
63 | renderCategoryName( category ) {
|
64 | if ( ! category.name ) {
|
65 | return __( '(Untitled)' );
|
66 | }
|
67 |
|
68 | return unescape( category.name ).trim();
|
69 | }
|
70 |
|
71 | renderCategoryList() {
|
72 | const { showHierarchy } = this.props.attributes;
|
73 | const parentId = showHierarchy ? 0 : null;
|
74 | const categories = this.getCategories( parentId );
|
75 |
|
76 | return (
|
77 | <ul className={ this.getCategoryListClassName( 0 ) }>
|
78 | { categories.map( ( category ) => this.renderCategoryListItem( category, 0 ) ) }
|
79 | </ul>
|
80 | );
|
81 | }
|
82 |
|
83 | renderCategoryListItem( category, level ) {
|
84 | const { showHierarchy, showPostCounts } = this.props.attributes;
|
85 | const childCategories = this.getCategories( category.id );
|
86 |
|
87 | return (
|
88 | <li key={ category.id }>
|
89 | <a href={ category.link } target="_blank" rel="noreferrer noopener">{ this.renderCategoryName( category ) }</a>
|
90 | { showPostCounts &&
|
91 | <span className="wp-block-categories__post-count">
|
92 | { ' ' }({ category.count })
|
93 | </span>
|
94 | }
|
95 |
|
96 | {
|
97 | showHierarchy &&
|
98 | !! childCategories.length && (
|
99 | <ul className={ this.getCategoryListClassName( level + 1 ) }>
|
100 | { childCategories.map( ( childCategory ) => this.renderCategoryListItem( childCategory, level + 1 ) ) }
|
101 | </ul>
|
102 | )
|
103 | }
|
104 | </li>
|
105 | );
|
106 | }
|
107 |
|
108 | renderCategoryDropdown() {
|
109 | const { instanceId } = this.props;
|
110 | const { showHierarchy } = this.props.attributes;
|
111 | const parentId = showHierarchy ? 0 : null;
|
112 | const categories = this.getCategories( parentId );
|
113 | const selectId = `blocks-category-select-${ instanceId }`;
|
114 | return (
|
115 | <Fragment>
|
116 | <label htmlFor={ selectId } className="screen-reader-text">
|
117 | { __( 'Categories' ) }
|
118 | </label>
|
119 | <select id={ selectId } className="wp-block-categories__dropdown">
|
120 | { categories.map( ( category ) => this.renderCategoryDropdownItem( category, 0 ) ) }
|
121 | </select>
|
122 | </Fragment>
|
123 | );
|
124 | }
|
125 |
|
126 | renderCategoryDropdownItem( category, level ) {
|
127 | const { showHierarchy, showPostCounts } = this.props.attributes;
|
128 | const childCategories = this.getCategories( category.id );
|
129 |
|
130 | return [
|
131 | <option key={ category.id }>
|
132 | { times( level * 3, () => '\xa0' ) }
|
133 | { this.renderCategoryName( category ) }
|
134 | {
|
135 | !! showPostCounts ?
|
136 | ` (${ category.count })` :
|
137 | ''
|
138 | }
|
139 | </option>,
|
140 | showHierarchy &&
|
141 | !! childCategories.length && (
|
142 | childCategories.map( ( childCategory ) => this.renderCategoryDropdownItem( childCategory, level + 1 ) )
|
143 | ),
|
144 | ];
|
145 | }
|
146 |
|
147 | render() {
|
148 | const { attributes, isRequesting } = this.props;
|
149 | const { displayAsDropdown, showHierarchy, showPostCounts } = attributes;
|
150 |
|
151 | const inspectorControls = (
|
152 | <InspectorControls>
|
153 | <PanelBody title={ __( 'Categories Settings' ) }>
|
154 | <ToggleControl
|
155 | label={ __( 'Display as Dropdown' ) }
|
156 | checked={ displayAsDropdown }
|
157 | onChange={ this.toggleDisplayAsDropdown }
|
158 | />
|
159 | <ToggleControl
|
160 | label={ __( 'Show Hierarchy' ) }
|
161 | checked={ showHierarchy }
|
162 | onChange={ this.toggleShowHierarchy }
|
163 | />
|
164 | <ToggleControl
|
165 | label={ __( 'Show Post Counts' ) }
|
166 | checked={ showPostCounts }
|
167 | onChange={ this.toggleShowPostCounts }
|
168 | />
|
169 | </PanelBody>
|
170 | </InspectorControls>
|
171 | );
|
172 |
|
173 | if ( isRequesting ) {
|
174 | return (
|
175 | <Fragment>
|
176 | { inspectorControls }
|
177 | <Placeholder
|
178 | icon="admin-post"
|
179 | label={ __( 'Categories' ) }
|
180 | >
|
181 | <Spinner />
|
182 | </Placeholder>
|
183 | </Fragment>
|
184 | );
|
185 | }
|
186 |
|
187 | return (
|
188 | <Fragment>
|
189 | { inspectorControls }
|
190 | <div className={ this.props.className }>
|
191 | {
|
192 | displayAsDropdown ?
|
193 | this.renderCategoryDropdown() :
|
194 | this.renderCategoryList()
|
195 | }
|
196 | </div>
|
197 | </Fragment>
|
198 | );
|
199 | }
|
200 | }
|
201 | export default compose(
|
202 | withSelect( ( select ) => {
|
203 | const { getEntityRecords } = select( 'core' );
|
204 | const { isResolving } = select( 'core/data' );
|
205 | const query = { per_page: -1, hide_empty: true };
|
206 |
|
207 | return {
|
208 | categories: getEntityRecords( 'taxonomy', 'category', query ),
|
209 | isRequesting: isResolving( 'core', 'getEntityRecords', [ 'taxonomy', 'category', query ] ),
|
210 | };
|
211 | } ),
|
212 | withInstanceId
|
213 | )( CategoriesEdit );
|