Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
4.35% covered (danger)
4.35%
1 / 23
25.00% covered (danger)
25.00%
1 / 4
CRAP
n/a
0 / 0
Automattic\Jetpack\PremiumAnalytics\register_widget_types
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
30
Automattic\Jetpack\PremiumAnalytics\bootstrap_widget_types
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
Automattic\Jetpack\PremiumAnalytics\get_registered_widget_types
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
Automattic\Jetpack\PremiumAnalytics\get_available_widget_types
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Widget Types: registry hydration plus the availability filter hooks.
4 *
5 * Copies the wp-build manifest (`jpa_get_registered_widget_modules()`) into the
6 * in-memory Widget_Type_Registry, so the plugin queries the registry instead
7 * of re-parsing the manifest.
8 *
9 * This is the problem-agnostic "core" layer (a PA-namespaced copy of the
10 * experimental Gutenberg API): it exposes the hooks a consumer uses to scope
11 * widget types, but never decides availability itself.
12 *
13 *   - REGISTRABLE_WIDGET_TYPES_FILTER (registry-time): drop candidates before
14 *     they register, gone everywhere. For hard availability.
15 *   - WIDGET_TYPES_FILTER (runtime): scope the registered set on read. For
16 *     request-dependent or soft state (e.g. shown locked).
17 *
18 * @package automattic/jetpack-premium-analytics
19 */
20
21namespace Automattic\Jetpack\PremiumAnalytics;
22
23require_once __DIR__ . '/class-widget-type.php';
24require_once __DIR__ . '/class-widget-type-registry.php';
25
26/**
27 * Registry-time filter over the manifest candidates, before they are registered.
28 */
29const REGISTRABLE_WIDGET_TYPES_FILTER = 'jetpack_premium_analytics_registrable_widget_types';
30
31/**
32 * Runtime filter over the registered widget types map, read for the client.
33 */
34const WIDGET_TYPES_FILTER = 'jetpack_premium_analytics_widget_types';
35
36/**
37 * Hydrates the widget type registry from the build manifest.
38 *
39 * Each manifest widget is copied into the registry, gated by
40 * REGISTRABLE_WIDGET_TYPES_FILTER so a consumer can drop a candidate first.
41 *
42 * @return void
43 */
44function register_widget_types() {
45    if ( ! function_exists( 'jpa_get_registered_widget_modules' ) ) {
46        return;
47    }
48
49    $registry = Widget_Type_Registry::get_instance();
50
51    // @phan-suppress-next-line PhanUndeclaredFunction -- Generated by wp-build into build/widgets.php, outside Phan's analysis scope. The function_exists() guard above protects the call at runtime.
52    $jetpack_widget_modules = jpa_get_registered_widget_modules();
53
54    /**
55     * Filters the widget type candidates before they are registered.
56     *
57     * A dropped candidate is never registered, so it is gone from the REST list,
58     * the import map, and any registry reader. Use for hard availability; for
59     * soft state that must stay visible (e.g. shown locked), filter on read via
60     * WIDGET_TYPES_FILTER.
61     *
62     * @param array $jetpack_widget_modules Manifest candidates, each with a `name`.
63     */
64    $jetpack_widget_modules = apply_filters( REGISTRABLE_WIDGET_TYPES_FILTER, $jetpack_widget_modules );
65
66    foreach ( $jetpack_widget_modules as $widget ) {
67        if ( empty( $widget['name'] ) || $registry->is_registered( $widget['name'] ) ) {
68            continue;
69        }
70
71        $registry->register(
72            $widget['name'],
73            array(
74                'render_module' => $widget['render_module'] ?? null,
75                'widget_module' => $widget['widget_module'] ?? null,
76                'presentation'  => $widget['presentation'] ?? null,
77            )
78        );
79    }
80}
81
82/**
83 * Hydrates the registry now if init has run, otherwise on init.
84 *
85 * Call after the availability filters are hooked, so the registry-time
86 * filter applies during hydration.
87 *
88 * @return void
89 */
90function bootstrap_widget_types() {
91    if ( did_action( 'init' ) ) {
92        register_widget_types();
93    } else {
94        add_action( 'init', __NAMESPACE__ . '\\register_widget_types' );
95    }
96}
97
98/**
99 * Returns the raw registry. For the client-facing set use
100 * get_available_widget_types().
101 *
102 * @return Widget_Type[] Map of `$name => $widget_type`.
103 */
104function get_registered_widget_types() {
105    return Widget_Type_Registry::get_instance()->get_all_registered();
106}
107
108/**
109 * Returns the registered widget types scoped through WIDGET_TYPES_FILTER.
110 *
111 * Use this, not get_registered_widget_types(), wherever widget types reach the
112 * client, so the REST list and import map share one policy.
113 *
114 * @return Widget_Type[] Map of `$name => Widget_Type`.
115 */
116function get_available_widget_types() {
117    /**
118     * Filters the widget types available to the dashboard this request.
119     *
120     * Removing an entry drops it from the REST list and the import map. The type
121     * stays registered, so use this (not the registry-time filter) when a
122     * consumer must still see it, e.g. to show it locked.
123     *
124     * @param Widget_Type[] $widget_types Map of `$name => Widget_Type`.
125     */
126    return apply_filters( WIDGET_TYPES_FILTER, get_registered_widget_types() );
127}