PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-premium-analytics / src / class-dashboard-section.php

class-dashboard-section.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at jetpack_vendor/automattic/jetpack-premium-analytics/src/class-dashboard-section.php

285 lines 7.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Dashboard Sections API: Dashboard_Section class.
4 *
5 * @package automattic/jetpack-premium-analytics
6 */
7
8 namespace Automattic\Jetpack\PremiumAnalytics;
9
10 /**
11 * Represents a dashboard section.
12 *
13 * The server-owned model behind a top-level dashboard tab.
14 */
15 final class Dashboard_Section {
16
17 /**
18 * Date-filter surface offering the rolling date-range picker (today, last 7
19 * days, a custom range, …) plus the comparison control. The default.
20 *
21 * @since 0.2.0
22 * @var string
23 */
24 const DATE_FILTER_RANGE = 'range';
25
26 /**
27 * Date-filter surface offering all time plus one entry per calendar year,
28 * for sections whose data is read as whole history rather than as a
29 * rolling window.
30 *
31 * @since 0.2.0
32 * @var string
33 */
34 const DATE_FILTER_YEAR = 'year';
35
36 /**
37 * Date-filter surfaces a section may declare.
38 *
39 * @since 0.2.0
40 * @var string[]
41 */
42 const DATE_FILTERS = array( self::DATE_FILTER_RANGE, self::DATE_FILTER_YEAR );
43
44 /**
45 * Dashboard identifier.
46 *
47 * @var string
48 */
49 public $dashboard_name;
50
51 /**
52 * Section identifier.
53 *
54 * @var string
55 */
56 public $id;
57
58 /**
59 * URL-facing section slug, derived from the identifier.
60 *
61 * @var string
62 */
63 public $slug;
64
65 /**
66 * Display label, naming the section's tab.
67 *
68 * @var string
69 */
70 public $label;
71
72 /**
73 * Section heading, deliberately distinct from the tab label: the tab reads
74 * `Traffic` where the heading reads `Site traffic`. Null falls back to the label.
75 *
76 * @since 0.3.0
77 * @var string|null
78 */
79 public $title = null;
80
81 /**
82 * Sort order.
83 *
84 * @var int
85 */
86 public $order = 10;
87
88 /**
89 * Which shape the section's date filter takes, as one of self::DATE_FILTERS.
90 *
91 * Shape only. Where it renders and what it supports are
92 * self::$date_filter_options.
93 *
94 * @since 0.2.0
95 * @var string
96 */
97 public $date_filter = self::DATE_FILTER_RANGE;
98
99 /**
100 * What the section's date filter supports, and where it renders.
101 *
102 * - `with_date_comparison`: false drops the comparison param from every widget fetch in the
103 * section, not just the chrome.
104 * - `with_header_date_control`: false hands the control to the section's widgets, which may
105 * save the range onto the widget instance rather than the URL.
106 *
107 * @since 0.3.0
108 * @since 0.5.0 Added `with_header_date_control`.
109 * @var array
110 */
111 public $date_filter_options = array(
112 'with_date_comparison' => true,
113 'with_header_date_control' => true,
114 );
115
116 /**
117 * Whether the section's data only reaches WordPress.com through the analytics
118 * full sync, so its numbers are incomplete until that sync has finished once.
119 *
120 * @since 0.4.0
121 * @var bool
122 */
123 public $requires_sync = false;
124
125 /**
126 * Availability flag or callback.
127 *
128 * @var bool|callable
129 */
130 private $is_available = true;
131
132 /**
133 * Default layout array or callback.
134 *
135 * @var array|callable
136 */
137 private $default_layout = array();
138
139 /**
140 * Constructor.
141 *
142 * @param string $dashboard_name Dashboard identifier.
143 * @param string $id Section identifier.
144 * @param array $args Optional. Section arguments.
145 */
146 public function __construct( $dashboard_name, $id, $args = array() ) {
147 $this->dashboard_name = $dashboard_name;
148 $this->id = $id;
149 $this->slug = self::derive_slug( $id );
150 $this->label = $id;
151
152 $this->set_props( $args );
153 }
154
155 /**
156 * Derives the URL-facing slug from a namespaced section identifier.
157 *
158 * @param string $id Section identifier, e.g. `analytics/traffic`.
159 * @return string The segment after the namespace, e.g. `traffic`.
160 */
161 private static function derive_slug( $id ) {
162 $separator = strpos( (string) $id, '/' );
163
164 return false === $separator ? (string) $id : substr( $id, $separator + 1 );
165 }
166
167 /**
168 * Returns whether this section should be exposed.
169 *
170 * @return bool
171 */
172 public function is_available() {
173 if ( is_callable( $this->is_available ) ) {
174 return (bool) call_user_func( $this->is_available, $this );
175 }
176
177 return (bool) $this->is_available;
178 }
179
180 /**
181 * Returns the section's default widget layout, run through the default-layout filter.
182 *
183 * @return array Array of widget instances.
184 */
185 public function get_default_layout() {
186 $layout = is_callable( $this->default_layout )
187 ? call_user_func( $this->default_layout, $this )
188 : $this->default_layout;
189 $layout = is_array( $layout ) ? array_values( $layout ) : array();
190
191 /**
192 * Filters a dashboard section's default widget layout.
193 *
194 * Each entry matches the dashboard's widget instance shape: `uuid`, `type`, optional
195 * `attributes`, optional `placement`. Runs for every section, so a callback adding an
196 * instance to one switches on `$section_id`.
197 *
198 * @since 0.8.0 Runs from the section, with its declared layout and its
199 * namespaced id; it received an empty array and any alias before.
200 *
201 * @param array $layout The section's declared default widget instances.
202 * @param string $section_id Namespaced section identifier, e.g. `analytics/traffic`.
203 * @param Dashboard_Section $section The section.
204 */
205 $layout = apply_filters( DASHBOARD_DEFAULT_LAYOUT_FILTER, $layout, $this->id, $this );
206
207 return is_array( $layout ) ? array_values( $layout ) : array();
208 }
209
210 /**
211 * Returns the public REST representation.
212 *
213 * @return array
214 */
215 public function to_array() {
216 return array(
217 'id' => $this->id,
218 'slug' => $this->slug,
219 'label' => $this->label,
220 'title' => $this->title,
221 'order' => (int) $this->order,
222 'date_filter' => $this->date_filter,
223 'date_filter_options' => $this->date_filter_options,
224 'requires_sync' => $this->requires_sync,
225 'default_layout' => $this->get_default_layout(),
226 );
227 }
228
229 /**
230 * Hydrates section properties from the args array.
231 *
232 * @param array $args Section arguments.
233 * @return void
234 */
235 private function set_props( $args ) {
236 if ( ! is_array( $args ) ) {
237 return;
238 }
239
240 if ( isset( $args['label'] ) ) {
241 $this->label = (string) $args['label'];
242 }
243
244 // An empty string is a registrant saying "none", not a heading: kept as-is it
245 // would defeat the label fallback and render an `<h2>` with no accessible name.
246 if ( isset( $args['title'] ) ) {
247 $title = (string) $args['title'];
248 $this->title = '' === $title ? null : $title;
249 }
250
251 if ( isset( $args['order'] ) ) {
252 $this->order = (int) $args['order'];
253 }
254
255 // An unrecognized surface keeps the default rather than reaching the
256 // dashboard, where the frontend has no filter to render for it.
257 if ( isset( $args['date_filter'] ) && in_array( $args['date_filter'], self::DATE_FILTERS, true ) ) {
258 $this->date_filter = (string) $args['date_filter'];
259 }
260
261 // Merged over the defaults so a partial array keeps the rest, and narrowed
262 // to the known options, which is all the dashboard renders.
263 if ( isset( $args['date_filter_options'] ) && is_array( $args['date_filter_options'] ) ) {
264 $options = array_merge( $this->date_filter_options, $args['date_filter_options'] );
265
266 $this->date_filter_options = array(
267 'with_date_comparison' => (bool) $options['with_date_comparison'],
268 'with_header_date_control' => (bool) $options['with_header_date_control'],
269 );
270 }
271
272 if ( isset( $args['requires_sync'] ) ) {
273 $this->requires_sync = (bool) $args['requires_sync'];
274 }
275
276 if ( array_key_exists( 'is_available', $args ) ) {
277 $this->is_available = $args['is_available'];
278 }
279
280 if ( array_key_exists( 'default_layout', $args ) ) {
281 $this->default_layout = $args['default_layout'];
282 }
283 }
284 }
285