PluginProbe
Gutenberg / 23.7.2
Gutenberg v23.7.2
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.7.2, at lib/experimental/dashboard-widgets/dashboard-layout.php

153 lines 5.1 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 dashboard's JS layer.
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, formatted as `<plugin>_<page>`
26 * to match the underscore form produced by the wp-build pipeline
27 * (mirrors the `{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}` pair used in
28 * 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 layer 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 * @global wpdb $wpdb WordPress database abstraction object.
45 *
46 * @param mixed $value The pre-fetched value, or null to let the
47 * meta API resolve normally.
48 * @param int $user_id User ID.
49 * @param string $meta_key Meta key being read.
50 * @return mixed The original value, or a single-element array
51 * containing the extended persisted preferences.
52 */
53 function gutenberg_inject_dashboard_default_layout( $value, $user_id, $meta_key ) {
54 global $wpdb;
55
56 $expected_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
57 if ( $meta_key !== $expected_key ) {
58 return $value;
59 }
60
61 // Avoid recursion when reading the user meta.
62 remove_filter( 'get_user_metadata', __FUNCTION__, 99 );
63 $base = get_user_meta( $user_id, $meta_key, true );
64 add_filter( 'get_user_metadata', __FUNCTION__, 99, 3 );
65
66 if ( ! is_array( $base ) ) {
67 $base = array();
68 }
69
70 $committed = $base[ GUTENBERG_DASHBOARD_LAYOUT_SCOPE ][ GUTENBERG_DASHBOARD_LAYOUT_KEY ] ?? 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
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.
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 dashboard's JS layer to back a "reset to
112 * default" 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