PluginProbe
Gutenberg / 23.2.1
Gutenberg v23.2.1
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 / experimental / dashboard-widgets / dashboard-layout.php

dashboard-layout.php in Gutenberg 23.2.1, at lib/experimental/dashboard-widgets/dashboard-layout.php

153 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Dashboard Layout: server-side defaults.
4 *
5 * Allows plugins and themes to register a default dashboard layout
6 * that surfaces transparently through the `@wordpress/preferences`
7 * store for users who have not customized theirs.
8 *
9 * @package gutenberg
10 */
11
12 /**
13 * Preferences scope under which the dashboard layout is stored.
14 * Mirrors the scope read by the JS surface.
15 */
16 const GUTENBERG_DASHBOARD_LAYOUT_SCOPE = 'core/dashboard';
17
18 /**
19 * Preferences key under `GUTENBERG_DASHBOARD_LAYOUT_SCOPE` that holds
20 * the layout array.
21 */
22 const GUTENBERG_DASHBOARD_LAYOUT_KEY = 'dashboardLayout';
23
24 /**
25 * Identifier of the bundled dashboard surface, formatted as
26 * `<plugin>_<page>` to match the underscore form produced by the
27 * wp-build pipeline (mirrors the `{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}`
28 * pair used in generated page templates).
29 *
30 * Passed as context to `gutenberg_dashboard_default_layout` and used
31 * as the `{name}` segment of the REST default-layout route.
32 */
33 const GUTENBERG_DASHBOARD_NAME = 'gutenberg_dashboard';
34
35 /**
36 * Injects a registered default dashboard layout into the user's
37 * `persisted_preferences` read when the stored layout is empty.
38 *
39 * Hooks into `get_user_metadata` so the default propagates through
40 * the same persistence layer the dashboard's JS surface reads from.
41 * The JS side stays oblivious: a default and a user-saved layout
42 * look identical at the preferences-store boundary.
43 *
44 * @param mixed $value The pre-fetched value, or null to let the
45 * meta API resolve normally.
46 * @param int $user_id User ID.
47 * @param string $meta_key Meta key being read.
48 * @return mixed The original value, or a single-element array
49 * containing the extended persisted preferences.
50 */
51 function gutenberg_inject_dashboard_default_layout( $value, $user_id, $meta_key ) {
52 global $wpdb;
53
54 $expected_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
55 if ( $meta_key !== $expected_key ) {
56 return $value;
57 }
58
59 // Avoid recursion when reading the user meta.
60 remove_filter( 'get_user_metadata', __FUNCTION__, 99 );
61 $base = get_user_meta( $user_id, $meta_key, true );
62 add_filter( 'get_user_metadata', __FUNCTION__, 99, 3 );
63
64 if ( ! is_array( $base ) ) {
65 $base = array();
66 }
67
68 $committed = isset( $base[ GUTENBERG_DASHBOARD_LAYOUT_SCOPE ][ GUTENBERG_DASHBOARD_LAYOUT_KEY ] )
69 ? $base[ GUTENBERG_DASHBOARD_LAYOUT_SCOPE ][ GUTENBERG_DASHBOARD_LAYOUT_KEY ]
70 : array();
71
72 if ( ! empty( $committed ) ) {
73 return $value;
74 }
75
76 /**
77 * Filters the default dashboard layout served to users who have
78 * not customized theirs.
79 *
80 * Each entry should match the dashboard's widget instance shape:
81 * `uuid`, `type`, optional `attributes`, optional `placement`.
82 *
83 * @param array $default_layout Default array of widget instances.
84 * @param string $dashboard_name Identifier of the dashboard surface
85 * receiving the default. Callbacks
86 * targeting a specific dashboard
87 * should switch on this value.
88 */
89 $default = apply_filters( 'gutenberg_dashboard_default_layout', array(), GUTENBERG_DASHBOARD_NAME );
90
91 if ( empty( $default ) || ! is_array( $default ) ) {
92 return $value;
93 }
94
95 if ( ! isset( $base[ GUTENBERG_DASHBOARD_LAYOUT_SCOPE ] ) || ! is_array( $base[ GUTENBERG_DASHBOARD_LAYOUT_SCOPE ] ) ) {
96 $base[ GUTENBERG_DASHBOARD_LAYOUT_SCOPE ] = array();
97 }
98
99 $base[ GUTENBERG_DASHBOARD_LAYOUT_SCOPE ][ GUTENBERG_DASHBOARD_LAYOUT_KEY ] = $default;
100
101 return array( $base );
102 }
103
104 add_filter( 'get_user_metadata', 'gutenberg_inject_dashboard_default_layout', 99, 3 );
105
106 /**
107 * Returns the default layout registered for a dashboard surface.
108 *
109 * Resolves `gutenberg_dashboard_default_layout` for the supplied
110 * dashboard name, returning a fresh evaluation of the filter chain
111 * each call. Used by the JS surface to back a "reset to default"
112 * action without depending on the user-meta hydration path.
113 *
114 * @param WP_REST_Request $request REST request carrying the
115 * dashboard name segment.
116 * @return WP_REST_Response Response wrapping the default layout
117 * array.
118 */
119 function gutenberg_get_dashboard_default_layout( $request ) {
120 $name = $request['name'];
121 $default = apply_filters( 'gutenberg_dashboard_default_layout', array(), $name );
122
123 if ( ! is_array( $default ) ) {
124 $default = array();
125 }
126
127 return rest_ensure_response( array_values( $default ) );
128 }
129
130 /**
131 * Registers the REST route that exposes per-dashboard default layouts.
132 */
133 function gutenberg_register_dashboard_default_layout_route() {
134 register_rest_route(
135 'wp/v2',
136 '/dashboards/(?P<name>[a-z][a-z0-9]*(?:_[a-z0-9]+)+)/default-layout',
137 array(
138 'methods' => WP_REST_Server::READABLE,
139 'callback' => 'gutenberg_get_dashboard_default_layout',
140 'permission_callback' => function () {
141 return current_user_can( 'read' );
142 },
143 'args' => array(
144 'name' => array(
145 'description' => __( 'Dashboard identifier as produced by the build pipeline.', 'gutenberg' ),
146 'type' => 'string',
147 ),
148 ),
149 )
150 );
151 }
152 add_action( 'rest_api_init', 'gutenberg_register_dashboard_default_layout_route' );
153