PluginProbe
Gutenberg / 23.4.0
Gutenberg v23.4.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / lib / compat / wordpress-7.1 / view-config-api.php

view-config-api.php in Gutenberg 23.4.0, at lib/compat/wordpress-7.1/view-config-api.php

738 lines 19.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Entity view configuration API.
4 *
5 * Builds the default view configuration for an entity and exposes it through
6 * the dynamic `get_entity_view_config_{$kind}_{$name}` filter so core and third
7 * parties can provide the configuration for a specific entity.
8 *
9 * @package gutenberg
10 */
11
12 /**
13 * Returns the view configuration for the given entity.
14 *
15 * Builds the default configuration shared by all entities and then exposes it
16 * through the dynamic `get_entity_view_config_{$kind}_{$name}` filter so that core
17 * and third parties can provide the configuration for a specific entity.
18 *
19 * @param string $kind The entity kind (e.g. `postType`).
20 * @param string $name The entity name (e.g. `page`).
21 * @return array {
22 * The view configuration for the entity.
23 *
24 * @type array $default_view Default view configuration.
25 * @type array $default_layouts Default layouts configuration.
26 * @type array $view_list List of available views.
27 * @type array $form Form configuration.
28 * }
29 */
30 function gutenberg_get_entity_view_config( $kind, $name ) {
31 $default_view = array(
32 'type' => 'table',
33 'filters' => array(),
34 'perPage' => 20,
35 'sort' => array(
36 'field' => 'title',
37 'direction' => 'asc',
38 ),
39 'titleField' => 'title',
40 'fields' => array( 'author', 'status' ),
41 );
42 $default_layouts = array(
43 'table' => array(),
44 'grid' => array(),
45 'list' => array(),
46 );
47 $all_items_title = __( 'All items', 'gutenberg' );
48 if ( 'postType' === $kind ) {
49 $post_type_object = get_post_type_object( $name );
50 if ( $post_type_object && ! empty( $post_type_object->labels->all_items ) ) {
51 $all_items_title = $post_type_object->labels->all_items;
52 }
53 }
54 $view_list = array(
55 array(
56 'title' => $all_items_title,
57 'slug' => 'all',
58 ),
59 );
60
61 $config = array(
62 'default_view' => $default_view,
63 'default_layouts' => $default_layouts,
64 'view_list' => $view_list,
65 'form' => array(),
66 );
67
68 /**
69 * Filters the view configuration for a given entity.
70 *
71 * The dynamic portions of the hook name, `$kind` and `$name`, refer to the
72 * entity kind (e.g. `postType`) and the entity name (e.g. `page`).
73 *
74 * @param array $config {
75 * The view configuration for the entity.
76 *
77 * @type array $default_view Default view configuration.
78 * @type array $default_layouts Default layouts configuration.
79 * @type array $view_list List of available views.
80 * @type array $form Form configuration.
81 * }
82 * @param array $entity {
83 * The entity the configuration is built for.
84 *
85 * @type string $kind The entity kind.
86 * @type string $name The entity name.
87 * }
88 */
89 $filtered_config = apply_filters(
90 "get_entity_view_config_{$kind}_{$name}",
91 $config,
92 array(
93 'kind' => $kind,
94 'name' => $name,
95 )
96 );
97
98 if ( ! is_array( $filtered_config ) ) {
99 return $config;
100 }
101
102 // Backfill any dropped keys with their defaults, then discard any keys the
103 // filter introduced that are not part of the documented configuration shape.
104 $filtered_config = array_merge( $config, $filtered_config );
105 return array_intersect_key( $filtered_config, $config );
106 }
107
108 /**
109 * Provides the view configuration for the `page` post type.
110 *
111 * @param array $config {
112 * The view configuration for the entity.
113 * }
114 * @return array The filtered view configuration.
115 */
116 function _gutenberg_get_entity_view_config_post_type_page( $config ) {
117 $config['default_layouts'] = array(
118 'table' => array(
119 'layout' => array(
120 'styles' => array(
121 'author' => array(
122 'align' => 'start',
123 ),
124 ),
125 ),
126 ),
127 'grid' => array(),
128 'list' => array(),
129 );
130
131 $config['default_view'] = array(
132 'type' => 'list',
133 'filters' => array(),
134 'perPage' => 20,
135 'sort' => array(
136 'field' => 'title',
137 'direction' => 'asc',
138 ),
139 'showLevels' => true,
140 'titleField' => 'title',
141 'mediaField' => 'featured_media',
142 'fields' => array( 'author', 'status' ),
143 );
144
145 $config['view_list'] = array(
146 // Reuse the base "all items" view, whose title is derived from the post
147 // type's `all_items` label in gutenberg_get_entity_view_config().
148 $config['view_list'][0],
149 array(
150 'title' => __( 'Published', 'gutenberg' ),
151 'slug' => 'published',
152 'view' => array(
153 'filters' => array(
154 array(
155 'field' => 'status',
156 'operator' => 'isAny',
157 'value' => 'publish',
158 'isLocked' => true,
159 ),
160 ),
161 ),
162 ),
163 array(
164 'title' => __( 'Scheduled', 'gutenberg' ),
165 'slug' => 'future',
166 'view' => array(
167 'filters' => array(
168 array(
169 'field' => 'status',
170 'operator' => 'isAny',
171 'value' => 'future',
172 'isLocked' => true,
173 ),
174 ),
175 ),
176 ),
177 array(
178 'title' => __( 'Drafts', 'gutenberg' ),
179 'slug' => 'drafts',
180 'view' => array(
181 'filters' => array(
182 array(
183 'field' => 'status',
184 'operator' => 'isAny',
185 'value' => 'draft',
186 'isLocked' => true,
187 ),
188 ),
189 ),
190 ),
191 array(
192 'title' => __( 'Pending', 'gutenberg' ),
193 'slug' => 'pending',
194 'view' => array(
195 'filters' => array(
196 array(
197 'field' => 'status',
198 'operator' => 'isAny',
199 'value' => 'pending',
200 'isLocked' => true,
201 ),
202 ),
203 ),
204 ),
205 array(
206 'title' => __( 'Private', 'gutenberg' ),
207 'slug' => 'private',
208 'view' => array(
209 'filters' => array(
210 array(
211 'field' => 'status',
212 'operator' => 'isAny',
213 'value' => 'private',
214 'isLocked' => true,
215 ),
216 ),
217 ),
218 ),
219 array(
220 'title' => __( 'Trash', 'gutenberg' ),
221 'slug' => 'trash',
222 'view' => array(
223 'type' => 'table',
224 'layout' => $config['default_layouts']['table']['layout'],
225 'filters' => array(
226 array(
227 'field' => 'status',
228 'operator' => 'isAny',
229 'value' => 'trash',
230 'isLocked' => true,
231 ),
232 ),
233 ),
234 ),
235 );
236
237 $config['form'] = array(
238 'layout' => array( 'type' => 'panel' ),
239 'fields' => array(
240 array(
241 'id' => 'featured_media',
242 'layout' => array(
243 'type' => 'regular',
244 'labelPosition' => 'none',
245 ),
246 ),
247 array(
248 'id' => 'post-content-info',
249 'layout' => array(
250 'type' => 'regular',
251 'labelPosition' => 'none',
252 ),
253 ),
254 array(
255 'id' => 'excerpt',
256 'layout' => array(
257 'type' => 'panel',
258 'labelPosition' => 'top',
259 ),
260 ),
261 array(
262 'id' => 'status',
263 'label' => __( 'Status', 'gutenberg' ),
264 'children' => array(
265 array(
266 'id' => 'status',
267 'layout' => array(
268 'type' => 'regular',
269 'labelPosition' => 'none',
270 ),
271 ),
272 'scheduled_date',
273 'password',
274 'sticky',
275 ),
276 ),
277 'date',
278 'slug',
279 'author',
280 'template',
281 array(
282 'id' => 'discussion',
283 'label' => __( 'Discussion', 'gutenberg' ),
284 'children' => array(
285 array(
286 'id' => 'comment_status',
287 'layout' => array(
288 'type' => 'regular',
289 'labelPosition' => 'none',
290 ),
291 ),
292 'ping_status',
293 ),
294 ),
295 'parent',
296 'format',
297 ),
298 );
299
300 return $config;
301 }
302 if ( has_filter( 'get_entity_view_config_postType_page', '_wp_get_entity_view_config_post_type_page' ) ) {
303 remove_filter( 'get_entity_view_config_postType_page', '_wp_get_entity_view_config_post_type_page' );
304 }
305 add_filter( 'get_entity_view_config_postType_page', '_gutenberg_get_entity_view_config_post_type_page', 10, 1 );
306
307 /**
308 * Provides the view configuration for the `post` post type.
309 *
310 * @param array $config {
311 * The view configuration for the entity.
312 * }
313 * @return array The filtered view configuration.
314 */
315 function _gutenberg_get_entity_view_config_post_type_post( $config ) {
316 $config['form'] = array(
317 'layout' => array( 'type' => 'panel' ),
318 'fields' => array(
319 array(
320 'id' => 'featured_media',
321 'layout' => array(
322 'type' => 'regular',
323 'labelPosition' => 'none',
324 ),
325 ),
326 array(
327 'id' => 'post-content-info',
328 'layout' => array(
329 'type' => 'regular',
330 'labelPosition' => 'none',
331 ),
332 ),
333 array(
334 'id' => 'excerpt',
335 'layout' => array(
336 'type' => 'panel',
337 'labelPosition' => 'top',
338 ),
339 ),
340 array(
341 'id' => 'status',
342 'label' => __( 'Status', 'gutenberg' ),
343 'children' => array(
344 array(
345 'id' => 'status',
346 'layout' => array(
347 'type' => 'regular',
348 'labelPosition' => 'none',
349 ),
350 ),
351 'scheduled_date',
352 'password',
353 'sticky',
354 ),
355 ),
356 'date',
357 'slug',
358 'author',
359 'template',
360 array(
361 'id' => 'discussion',
362 'label' => __( 'Discussion', 'gutenberg' ),
363 'children' => array(
364 array(
365 'id' => 'comment_status',
366 'layout' => array(
367 'type' => 'regular',
368 'labelPosition' => 'none',
369 ),
370 ),
371 'ping_status',
372 ),
373 ),
374 'parent',
375 'format',
376 ),
377 );
378
379 return $config;
380 }
381 if ( has_filter( 'get_entity_view_config_postType_post', '_wp_get_entity_view_config_post_type_post' ) ) {
382 remove_filter( 'get_entity_view_config_postType_post', '_wp_get_entity_view_config_post_type_post' );
383 }
384 add_filter( 'get_entity_view_config_postType_post', '_gutenberg_get_entity_view_config_post_type_post', 10, 1 );
385
386 /**
387 * Provides the view configuration for the `wp_block` post type.
388 *
389 * @param array $config {
390 * The view configuration for the entity.
391 * }
392 * @return array The filtered view configuration.
393 */
394 function _gutenberg_get_entity_view_config_post_type_wp_block( $config ) {
395 $config['default_layouts'] = array(
396 'table' => array(
397 'layout' => array(
398 'styles' => array(
399 'author' => array(
400 'width' => '1%',
401 ),
402 ),
403 ),
404 ),
405 'grid' => array(
406 'layout' => array(
407 'badgeFields' => array( 'sync-status' ),
408 ),
409 ),
410 );
411
412 $config['default_view'] = array(
413 'type' => 'grid',
414 'perPage' => 20,
415 'titleField' => 'title',
416 'mediaField' => 'preview',
417 'fields' => array( 'sync-status' ),
418 'filters' => array(),
419 'layout' => $config['default_layouts']['grid']['layout'],
420 );
421
422 $view_list = array(
423 array(
424 'title' => __( 'All patterns', 'gutenberg' ),
425 'slug' => 'all-patterns',
426 ),
427 array(
428 'title' => __( 'My patterns', 'gutenberg' ),
429 'slug' => 'my-patterns',
430 ),
431 );
432
433 // Gather categories from the block pattern categories registry.
434 $registry = WP_Block_Pattern_Categories_Registry::get_instance();
435 $categories = array();
436
437 foreach ( $registry->get_all_registered() as $category ) {
438 $categories[ $category['name'] ] = $category['label'];
439 }
440
441 // Ensure "Uncategorized" is always included for patterns
442 // that have no category assigned.
443 $categories['uncategorized'] ??= __( 'Uncategorized', 'gutenberg' );
444
445 // Also gather user-created pattern categories (wp_pattern_category taxonomy).
446 $user_terms = get_terms(
447 array(
448 'taxonomy' => 'wp_pattern_category',
449 'hide_empty' => false,
450 )
451 );
452
453 if ( ! is_wp_error( $user_terms ) ) {
454 foreach ( $user_terms as $term ) {
455 $categories[ $term->slug ] = $term->name;
456 }
457 }
458
459 // Sort categories alphabetically by label.
460 asort( $categories, SORT_NATURAL | SORT_FLAG_CASE );
461
462 foreach ( $categories as $category_name => $label ) {
463 $view_list[] = array(
464 'title' => $label,
465 'slug' => $category_name,
466 );
467 }
468
469 $config['view_list'] = $view_list;
470
471 return $config;
472 }
473 if ( has_filter( 'get_entity_view_config_postType_wp_block', '_wp_get_entity_view_config_post_type_wp_block' ) ) {
474 remove_filter( 'get_entity_view_config_postType_wp_block', '_wp_get_entity_view_config_post_type_wp_block' );
475 }
476 add_filter( 'get_entity_view_config_postType_wp_block', '_gutenberg_get_entity_view_config_post_type_wp_block', 10, 1 );
477
478 /**
479 * Provides the view configuration for the `wp_template_part` post type.
480 *
481 * @param array $config {
482 * The view configuration for the entity.
483 * }
484 * @return array The filtered view configuration.
485 */
486 function _gutenberg_get_entity_view_config_post_type_wp_template_part( $config ) {
487 $config['default_layouts'] = array(
488 'table' => array(
489 'layout' => array(
490 'styles' => array(
491 'author' => array(
492 'width' => '1%',
493 ),
494 ),
495 ),
496 ),
497 'grid' => array(
498 'layout' => array(),
499 ),
500 );
501
502 $config['default_view'] = array(
503 'type' => 'grid',
504 'perPage' => 20,
505 'titleField' => 'title',
506 'mediaField' => 'preview',
507 'fields' => array( 'author' ),
508 'filters' => array(),
509 'layout' => $config['default_layouts']['grid']['layout'],
510 );
511
512 $view_list = array(
513 array(
514 'title' => __( 'All template parts', 'gutenberg' ),
515 'slug' => 'all-parts',
516 ),
517 );
518
519 $areas = get_allowed_block_template_part_areas();
520
521 // Ensure default areas appear in a consistent order.
522 $preferred_order = array( 'header', 'footer', 'sidebar', 'navigation-overlay', 'uncategorized' );
523 $ordered_areas = array();
524 $remaining_areas = array();
525 foreach ( $areas as $area ) {
526 $position = array_search( $area['area'], $preferred_order, true );
527 if ( false !== $position ) {
528 $ordered_areas[ $position ] = $area;
529 } else {
530 $remaining_areas[] = $area;
531 }
532 }
533 ksort( $ordered_areas );
534 $areas = array_merge( array_values( $ordered_areas ), $remaining_areas );
535
536 foreach ( $areas as $area ) {
537 $view_list[] = array(
538 'title' => $area['label'],
539 'slug' => $area['area'],
540 'view' => array(
541 'filters' => array(
542 array(
543 'field' => 'area',
544 'operator' => 'is',
545 'value' => $area['area'],
546 'isLocked' => true,
547 ),
548 ),
549 ),
550 );
551 }
552
553 $config['view_list'] = $view_list;
554
555 return $config;
556 }
557 if ( has_filter( 'get_entity_view_config_postType_wp_template_part', '_wp_get_entity_view_config_post_type_wp_template_part' ) ) {
558 remove_filter( 'get_entity_view_config_postType_wp_template_part', '_wp_get_entity_view_config_post_type_wp_template_part' );
559 }
560 add_filter( 'get_entity_view_config_postType_wp_template_part', '_gutenberg_get_entity_view_config_post_type_wp_template_part', 10, 1 );
561
562 /**
563 * Provides the view configuration for the `wp_template` post type.
564 *
565 * @param array $config {
566 * The view configuration for the entity.
567 * }
568 * @return array The filtered view configuration.
569 */
570 function _gutenberg_get_entity_view_config_post_type_wp_template( $config ) {
571 $config['default_view'] = array(
572 'type' => 'grid',
573 'perPage' => 20,
574 'sort' => array(
575 'field' => 'title',
576 'direction' => 'asc',
577 ),
578 'titleField' => 'title',
579 'descriptionField' => 'description',
580 'mediaField' => 'preview',
581 'fields' => array( 'author', 'active', 'slug', 'theme' ),
582 'filters' => array(),
583 'showMedia' => true,
584 );
585
586 $config['default_layouts'] = array(
587 'table' => array( 'showMedia' => false ),
588 'grid' => array( 'showMedia' => true ),
589 'list' => array( 'showMedia' => false ),
590 );
591
592 $view_list = array(
593 array(
594 'title' => __( 'All templates', 'gutenberg' ),
595 'slug' => 'all',
596 ),
597 );
598
599 $templates = get_block_templates( array(), 'wp_template' );
600
601 // Collect unique authors, tracking whether they come from a registered
602 // source (theme, plugin, site) so we can sort those before user ones.
603 $seen_authors = array();
604 $registered_authors = array();
605 $user_authors = array();
606 foreach ( $templates as $template ) {
607 /*
608 * Determine the original source of the template ('theme', 'plugin',
609 * 'site', or 'user').
610 */
611 $original_source = 'user';
612 if ( 'wp_template' === $template->type || 'wp_template_part' === $template->type ) {
613 if ( $template->has_theme_file &&
614 ( 'theme' === $template->origin || (
615 empty( $template->origin ) && in_array(
616 $template->source,
617 array(
618 'theme',
619 'custom',
620 ),
621 true
622 ) )
623 )
624 ) {
625 /*
626 * Added by theme.
627 * Template originally provided by a theme, but customized by a user.
628 * Templates originally didn't have the 'origin' field so identify
629 * older customized templates by checking for no origin and a 'theme'
630 * or 'custom' source.
631 */
632 $original_source = 'theme';
633 } elseif ( 'plugin' === $template->origin ) {
634 // Added by plugin.
635 $original_source = 'plugin';
636 } elseif ( empty( $template->has_theme_file ) && 'custom' === $template->source && empty( $template->author ) ) {
637 /*
638 * Added by site.
639 * Template was created from scratch, but has no author. Author support
640 * was only added to templates in WordPress 5.9. Fallback to showing the
641 * site logo and title.
642 */
643 $original_source = 'site';
644 }
645 }
646
647 // Determine a human readable text for the author of the template.
648 $author_text = '';
649 switch ( $original_source ) {
650 case 'theme':
651 $theme_name = wp_get_theme( $template->theme )->get( 'Name' );
652 $author_text = empty( $theme_name ) ? $template->theme : $theme_name;
653 break;
654 case 'plugin':
655 if ( ! function_exists( 'get_plugins' ) ) {
656 require_once ABSPATH . 'wp-admin/includes/plugin.php';
657 }
658 $plugin_name = '';
659 if ( isset( $template->plugin ) ) {
660 $plugins = wp_get_active_and_valid_plugins();
661
662 foreach ( $plugins as $plugin_file ) {
663 $plugin_basename = plugin_basename( $plugin_file );
664 list( $plugin_slug, ) = explode( '/', $plugin_basename );
665
666 if ( $plugin_slug === $template->plugin ) {
667 $plugin_data = get_plugin_data( $plugin_file );
668
669 if ( ! empty( $plugin_data['Name'] ) ) {
670 $plugin_name = $plugin_data['Name'];
671 }
672
673 break;
674 }
675 }
676 }
677
678 /*
679 * Fall back to the theme name if the plugin is not defined. That's needed to keep backwards
680 * compatibility with templates that were registered before the plugin attribute was added.
681 */
682 if ( '' === $plugin_name ) {
683 $plugins = get_plugins();
684 $plugin_basename = plugin_basename( sanitize_text_field( $template->theme . '.php' ) );
685 if ( isset( $plugins[ $plugin_basename ] ) && isset( $plugins[ $plugin_basename ]['Name'] ) ) {
686 $plugin_name = $plugins[ $plugin_basename ]['Name'];
687 } else {
688 $plugin_name = $template->plugin ?? $template->theme;
689 }
690 }
691 $author_text = $plugin_name;
692 break;
693 case 'site':
694 $author_text = get_bloginfo( 'name' );
695 break;
696 case 'user':
697 $author = get_user_by( 'id', $template->author );
698 if ( ! $author ) {
699 $author_text = __( 'Unknown author', 'gutenberg' );
700 } else {
701 $author_text = $author->get( 'display_name' );
702 }
703 break;
704 }
705
706 if ( ! empty( $author_text ) && ! isset( $seen_authors[ $author_text ] ) ) {
707 $seen_authors[ $author_text ] = true;
708 $entry = array(
709 'title' => $author_text,
710 'slug' => $author_text,
711 'view' => array(
712 'filters' => array(
713 array(
714 'field' => 'author',
715 'operator' => 'is',
716 'value' => $author_text,
717 'isLocked' => true,
718 ),
719 ),
720 ),
721 );
722 if ( 'user' === $original_source ) {
723 $user_authors[] = $entry;
724 } else {
725 $registered_authors[] = $entry;
726 }
727 }
728 }
729
730 $config['view_list'] = array_merge( $view_list, $registered_authors, $user_authors );
731
732 return $config;
733 }
734 if ( has_filter( 'get_entity_view_config_postType_wp_template', '_wp_get_entity_view_config_post_type_wp_template' ) ) {
735 remove_filter( 'get_entity_view_config_postType_wp_template', '_wp_get_entity_view_config_post_type_wp_template' );
736 }
737 add_filter( 'get_entity_view_config_postType_wp_template', '_gutenberg_get_entity_view_config_post_type_wp_template', 10, 1 );
738