PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.3.3
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.3.3
3.3.3 3.3.2 3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 158 releases
notificationx / includes / Abilities / Registrar.php

Registrar.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.3.3, at includes/Abilities/Registrar.php

217 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ability registry for the NotificationX MCP server.
4 *
5 * Collects every {@see AbilityBase} the plugin exposes and hands them to the
6 * MCP tools bridge. The registry is deliberately API-compatible with the
7 * WordPress Abilities API: if that API is present it registers the abilities
8 * there as well, so a future WordPress that ships the Abilities API in core
9 * gets the same tools with zero changes. Pro (or any add-on) can inject its
10 * own abilities through the `nx_register_abilities` filter.
11 *
12 * @package NotificationX\Abilities
13 */
14
15 namespace NotificationX\Abilities;
16
17 use NotificationX\GetInstance;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 /**
24 * @method static Registrar get_instance( $args = null )
25 */
26 class Registrar {
27
28 use GetInstance;
29
30 /**
31 * The ability category id used both here and (when present) in the
32 * WordPress Abilities API.
33 */
34 const CATEGORY = 'notificationx';
35
36 /**
37 * Registered abilities keyed by ability id.
38 *
39 * @var AbilityBase[]
40 */
41 protected $abilities = array();
42
43 /**
44 * Whether {@see boot()} has already run.
45 *
46 * @var bool
47 */
48 protected $booted = false;
49
50 /**
51 * Instantiate and register the core abilities. Called once when the MCP
52 * module is enabled. Registration is intentionally decoupled from the
53 * transport: abilities are always permission-checked individually, so it
54 * is safe to register them whenever the module boots.
55 *
56 * @return void
57 */
58 public function boot() {
59 if ( $this->booted ) {
60 return;
61 }
62 $this->booted = true;
63
64 $abilities = array(
65 // Read.
66 new Read\ListNotifications(),
67 new Read\GetNotification(),
68 new Read\ListTypes(),
69 new Read\ListSources(),
70 new Read\DescribeType(),
71 new Read\GetStatus(),
72 new Read\GetAnalytics(),
73 new Read\GetSettings(),
74 new Read\ListEntries(),
75 new Read\ExportEntries(),
76 // Manage (write).
77 new Manage\CreateNotification(),
78 new Manage\ToggleNotification(),
79 new Manage\UpdateNotification(),
80 new Manage\DuplicateNotification(),
81 new Manage\DeleteNotification(),
82 );
83
84 /**
85 * Filter the abilities exposed over MCP.
86 *
87 * Pro and third-party add-ons append their own AbilityBase instances
88 * here (e.g. "notificationx-pro/...").
89 *
90 * @param AbilityBase[] $abilities
91 */
92 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Prefixed with nx_ per NotificationX convention.
93 $abilities = apply_filters( 'nx_register_abilities', $abilities );
94
95 foreach ( $abilities as $ability ) {
96 $this->register( $ability );
97 }
98
99 // Mirror into the WordPress Abilities API when it exists. The category
100 // must exist before any ability may claim it, and core fires its
101 // `wp_abilities_api_categories_init` action first, so both hooks are
102 // registered together here.
103 if ( function_exists( 'wp_register_ability' ) ) {
104 add_action( 'wp_abilities_api_categories_init', array( $this, 'register_ability_category' ) );
105 add_action( 'wp_abilities_api_init', array( $this, 'register_with_wp_abilities' ) );
106 }
107 }
108
109 /**
110 * Add a single ability to the registry.
111 *
112 * @param AbilityBase $ability Ability instance.
113 * @return void
114 */
115 public function register( $ability ) {
116 if ( $ability instanceof AbilityBase && $ability->get_id() ) {
117 $this->abilities[ $ability->get_id() ] = $ability;
118 }
119 }
120
121 /**
122 * Get one ability by id.
123 *
124 * @param string $id Ability id (with category prefix).
125 * @return AbilityBase|null
126 */
127 public function get( $id ) {
128 return isset( $this->abilities[ $id ] ) ? $this->abilities[ $id ] : null;
129 }
130
131 /**
132 * Look an ability up by its bare MCP tool name (no category prefix).
133 *
134 * @param string $tool_name Tool name, e.g. "list-notifications".
135 * @return AbilityBase|null
136 */
137 public function get_by_tool_name( $tool_name ) {
138 foreach ( $this->abilities as $ability ) {
139 if ( $ability->tool_name() === $tool_name ) {
140 return $ability;
141 }
142 }
143 return null;
144 }
145
146 /**
147 * All registered abilities.
148 *
149 * @return AbilityBase[]
150 */
151 public function get_all() {
152 return $this->abilities;
153 }
154
155 /**
156 * Register our ability category with the WordPress Abilities API.
157 *
158 * Core rejects (and emits a `_doing_it_wrong()` notice for) any ability
159 * whose category is unknown, so this must run on
160 * `wp_abilities_api_categories_init` — the only action on which
161 * `wp_register_ability_category()` accepts a registration.
162 *
163 * @return void
164 */
165 public function register_ability_category() {
166 if ( ! function_exists( 'wp_register_ability_category' ) ) {
167 return;
168 }
169 if ( function_exists( 'wp_has_ability_category' ) && wp_has_ability_category( self::CATEGORY ) ) {
170 return;
171 }
172 wp_register_ability_category(
173 self::CATEGORY,
174 array(
175 'label' => __( 'NotificationX', 'notificationx' ),
176 'description' => __( 'Read and manage NotificationX notifications, form entries, analytics and settings.', 'notificationx' ),
177 )
178 );
179 }
180
181 /**
182 * Bridge our abilities into the WordPress Abilities API when available.
183 *
184 * Bails when the category is missing — that only happens if the module
185 * booted after `wp_abilities_api_categories_init` had already fired, and
186 * registering anyway would fail per ability with a `_doing_it_wrong()`
187 * notice. NotificationX's own registry is unaffected either way.
188 *
189 * @return void
190 */
191 public function register_with_wp_abilities() {
192 if ( function_exists( 'wp_has_ability_category' ) && ! wp_has_ability_category( self::CATEGORY ) ) {
193 return;
194 }
195 foreach ( $this->abilities as $ability ) {
196 if ( function_exists( 'wp_has_ability' ) && wp_has_ability( $ability->get_id() ) ) {
197 continue;
198 }
199 wp_register_ability(
200 $ability->get_id(),
201 array(
202 'label' => $ability->get_label(),
203 'description' => $ability->get_description(),
204 'category' => self::CATEGORY,
205 'input_schema' => $ability->input_schema(),
206 'output_schema' => $ability->output_schema(),
207 'permission_callback' => array( $ability, 'permission_callback' ),
208 'execute_callback' => array( $ability, 'run' ),
209 'meta' => array(
210 'annotations' => $ability->annotations(),
211 ),
212 )
213 );
214 }
215 }
216 }
217