PluginProbe
Texty – SMS Notification for WordPress, WooCommerce, Dokan and more / 2.0.0
Texty – SMS Notification for WordPress, WooCommerce, Dokan and more v2.0.0
2.0.2 trunk 0.2 1.0 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 2.0.0 2.0.1
texty / includes / Api / Notifications.php

Notifications.php in Texty – SMS Notification for WordPress, WooCommerce, Dokan and more 2.0.0, at includes/Api/Notifications.php

311 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Texty\Api;
4
5 use Texty\Notifications as TextyNotifications;
6 use WP_Error;
7 use WP_REST_Server;
8 use WP_Rest_Response;
9 use WP_REST_Request;
10
11 class Notifications extends Base {
12
13 /**
14 * Initialize
15 *
16 * @return void
17 */
18 public function __construct() {
19 $this->namespace = 'texty/v1';
20 $this->rest_base = 'notifications';
21 }
22
23 /**
24 * Registers the routes for the objects of the controller.
25 *
26 * @return void
27 */
28 public function register_routes() {
29 register_rest_route(
30 $this->namespace,
31 '/' . $this->rest_base,
32 [
33 [
34 'methods' => WP_REST_Server::READABLE,
35 'callback' => [ $this, 'get_items' ],
36 'permission_callback' => [ $this, 'admin_permissions_check' ],
37 'args' => [],
38 ],
39 [
40 'methods' => WP_REST_Server::EDITABLE,
41 'callback' => [ $this, 'update_items' ],
42 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
43 'permission_callback' => [ $this, 'admin_permissions_check' ],
44 ],
45 'schema' => [ $this, 'get_item_schema' ],
46 ]
47 );
48
49 register_rest_route(
50 $this->namespace,
51 '/' . $this->rest_base . '/schema',
52 [
53 [
54 'methods' => WP_REST_Server::READABLE,
55 'callback' => [ $this, 'get_schema' ],
56 'permission_callback' => [ $this, 'admin_permissions_check' ],
57 'args' => [
58 'group' => [
59 'description' => __( 'Notification group key.', 'texty' ),
60 'type' => 'string',
61 'required' => true,
62 ],
63 ],
64 ],
65 ]
66 );
67 }
68
69 /**
70 * Build a plugin-ui Settings schema (and values) for one notification group.
71 *
72 * One `page` → one `section` → a `collapsible_switch` field per notification,
73 * with its recipients / message / variables attached as children via
74 * `field_group_id`. The frontend renders this verbatim — no schema building
75 * lives on the client.
76 *
77 * @since TEXTY_VERSION
78 *
79 * @param WP_REST_Request $request Request object.
80 *
81 * @return WP_REST_Response|WP_Error
82 */
83 public function get_schema( $request ) {
84 $group_id = sanitize_key( (string) $request->get_param( 'group' ) );
85 $groups = texty()->notifications()->get_groups();
86
87 if ( '' === $group_id || ! isset( $groups[ $group_id ] ) ) {
88 return new WP_Error(
89 'texty_invalid_group',
90 __( 'Invalid notification group.', 'texty' ),
91 [ 'status' => 400 ]
92 );
93 }
94
95 $group = $groups[ $group_id ];
96 $roles = $this->get_roles();
97 $section_id = $group_id . '_section';
98
99 $schema = [
100 [
101 // Heading (icon + title + description) is rendered by the frontend,
102 // since plugin-ui's built-in heading has no icon slot. Suppress its
103 // heading; label/description/icon are still sent for the frontend.
104 'id' => $group_id,
105 'type' => 'page',
106 'label' => $group['title'],
107 'description' => isset( $group['description'] ) ? $group['description'] : '',
108 'icon' => $this->group_icon( $group_id ),
109 'hide_heading' => true,
110 'priority' => 10,
111 ],
112 [
113 // No header — the section is just the card wrapper for the rows;
114 // title + description live on the page heading above.
115 'id' => $section_id,
116 'type' => 'section',
117 'label' => '',
118 'page_id' => $group_id,
119 'priority' => 10,
120 ],
121 ];
122
123 $values = [];
124
125 foreach ( texty()->notifications()->all() as $class ) {
126 $obj = new $class();
127
128 if ( $obj->get_group() !== $group_id ) {
129 continue;
130 }
131
132 $id = $obj->get_id();
133 $message = (string) $obj->get_message_raw();
134
135 $schema[] = [
136 'id' => $id,
137 'type' => 'field',
138 'variant' => 'collapsible_switch',
139 'section_id' => $section_id,
140 'title' => $obj->get_title(),
141 'description' => $message,
142 'collapsed' => true,
143 ];
144 $values[ $id ] = (bool) $obj->enabled();
145
146 if ( $obj->get_type() === 'role' ) {
147 $recipients = $obj->get_recipients_raw();
148
149 $schema[] = [
150 'id' => $id . '_recipients',
151 'type' => 'field',
152 'variant' => 'multicheck',
153 'field_group_id' => $id,
154 'title' => __( 'Recipients', 'texty' ),
155 'options' => $roles,
156 ];
157 $values[ $id . '_recipients' ] = is_array( $recipients ) ? array_values( $recipients ) : [];
158 }
159
160 $schema[] = [
161 'id' => $id . '_message',
162 'type' => 'field',
163 'variant' => 'textarea',
164 'field_group_id' => $id,
165 'title' => __( 'Message Content', 'texty' ),
166 'rows' => 4,
167 ];
168 $values[ $id . '_message' ] = $message;
169
170 $replacements = array_merge(
171 array_keys( $obj->replacement_keys() ),
172 array_keys( $obj->global_replacement_keys() )
173 );
174
175 if ( ! empty( $replacements ) ) {
176 $tokens = array_map(
177 function ( $token ) {
178 return '{' . $token . '}';
179 },
180 $replacements
181 );
182
183 $schema[] = [
184 'id' => $id . '_vars',
185 'type' => 'field',
186 'variant' => 'info',
187 'field_group_id' => $id,
188 'title' => __( 'Available variables', 'texty' ),
189 'description' => implode( ', ', $tokens ),
190 ];
191 }
192 }
193
194 return rest_ensure_response(
195 [
196 'schema' => $schema,
197 'values' => $values,
198 ]
199 );
200 }
201
202 /**
203 * Map a notification group to a plugin-ui (lucide) icon name.
204 *
205 * @since TEXTY_VERSION
206 *
207 * @param string $group_id Group key.
208 *
209 * @return string
210 */
211 private function group_icon( $group_id ) {
212 $icons = [
213 'wp' => 'Globe',
214 'wc' => 'ShoppingCart',
215 'dokan' => 'Store',
216 ];
217
218 return isset( $icons[ $group_id ] ) ? $icons[ $group_id ] : 'Bell';
219 }
220
221 /**
222 * Retrieves a list of items.
223 *
224 * @param WP_Rest_Request $request
225 *
226 * @return WP_Rest_Response|WP_Error
227 */
228 public function get_items( $request ) {
229 if ( isset( $request['context'] ) && $request['context'] === 'edit' ) {
230 $notifications = texty()->notifications()->all();
231
232 $response = [
233 'groups' => texty()->notifications()->get_groups(),
234 'roles' => $this->get_roles(),
235 'notifications' => array_map( function ( $notifier ) { // phpcs:ignore
236 $obj = new $notifier();
237
238 return [
239 'id' => $obj->get_id(),
240 'enabled' => $obj->enabled(),
241 'title' => $obj->get_title(),
242 'type' => $obj->get_type(),
243 'message' => $obj->get_message_raw(),
244 'route' => 'sms',
245 'group' => $obj->get_group(),
246 'recipients' => $obj->get_recipients_raw(),
247 'replacements' => array_merge(
248 array_keys( $obj->replacement_keys() ),
249 array_keys( $obj->global_replacement_keys() )
250 ),
251 ];
252 }, $notifications ), // phpcs:ignore
253 ];
254 } else {
255 $response = texty()->notifications()->settings();
256 }
257
258 return rest_ensure_response( $response );
259 }
260
261 /**
262 * Updates item from the collection.
263 *
264 * @param WP_REST_Request $request
265 *
266 * @return WP_Error|WP_REST_Response
267 */
268 public function update_items( $request ) {
269 // Merge over the stored option so a partial (single-group) save does not
270 // wipe the notifications that weren't included in this request.
271 $settings = get_option( TextyNotifications::OPTION_KEY, [] );
272 if ( ! is_array( $settings ) ) {
273 $settings = [];
274 }
275
276 $notifications = texty()->notifications()->all();
277
278 foreach ( $notifications as $class ) {
279 $obj = new $class();
280
281 if ( $request->has_param( $obj->get_id() ) ) {
282 $settings[ $obj->get_id() ] = $request->get_param( $obj->get_id() );
283 }
284 }
285
286 update_option( TextyNotifications::OPTION_KEY, $settings, false );
287
288 $request->set_param( 'context', 'edit' );
289
290 return $this->get_items( $request );
291 }
292
293 /**
294 * Get user roles
295 *
296 * @return array
297 */
298 public function get_roles() {
299 $roles = [];
300
301 foreach ( wp_roles()->get_names() as $value => $label ) {
302 $roles[] = [
303 'label' => $label,
304 'value' => $value,
305 ];
306 }
307
308 return $roles;
309 }
310 }
311