PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.28
Booktics – Appointment Booking Calendar for Service Businesses v1.0.28
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.2 1.0.3 All 31 releases
← All changes | core/extensions/controllers/module-controller.php +398 -248 1.0.1 → 1.0.28 View file →
@@ -1,248 +1,398 @@
1 -<?php
2 -
3 -namespace Booktics\Extensions\Controllers;
4 -
5 -use Booktics\Abstracts\Base_Rest_Controller;
6 -use Arraytics\ToolsSdk\Extension as ExtensionManager;
7 -use WP_HTTP_Response;
8 -use WP_REST_Request;
9 -
10 -/**
11 - * Module Controller
12 - *
13 - * @package Booktics/Module
14 - */
15 -class Module_Controller extends Base_Rest_Controller {
16 - /**
17 - * The namespace of this controller's route.
18 - *
19 - * @since 1.0.0
20 - * @var string
21 - */
22 - protected $namespace = 'booktics/v1';
23 -
24 - /**
25 - * The base of this controller's route.
26 - *
27 - * @since 1.0.0
28 - * @var string
29 - */
30 - protected $rest_base = 'module';
31 -
32 - /**
33 - * Extension manager instance
34 - *
35 - * @var ExtensionManager
36 - */
37 - protected $extensions;
38 -
39 - /**
40 - * Initialize the class and set its properties.
41 - */
42 - public function __construct() {
43 - $this->extensions = new ExtensionManager('booktics_available_modules', booktics_modules_list());
44 - }
45 -
46 - /**
47 - * Register the routes for the objects of the controller.
48 - *
49 - * @since 1.0.0
50 - *
51 - * @return void
52 - */
53 - public function register_routes(): void {
54 - register_rest_route($this->namespace, '/' . $this->rest_base, [
55 - [
56 - 'methods' => \WP_REST_Server::READABLE,
57 - 'callback' => [$this, 'get_items'],
58 - 'permission_callback' => [$this, 'get_items_permissions_check'],
59 - 'args' => [
60 - 'type' => [
61 - 'description' => __('Type of extensions to retrieve (module, addon, plugin, all).', 'booktics'),
62 - 'type' => 'string',
63 - 'enum' => ['module', 'addon', 'plugin', 'all'],
64 - 'default' => 'all',
65 - ],
66 - ],
67 - ],
68 - [
69 - 'methods' => \WP_REST_Server::EDITABLE,
70 - 'callback' => [$this, 'update_item'],
71 - 'permission_callback' => [$this, 'update_item_permissions_check'],
72 - ],
73 - ]);
74 - }
75 -
76 - /**
77 - * Check if a given request has permission to get items.
78 - *
79 - * @since 1.0.0
80 - *
81 - * @param WP_REST_Request $request Full data about the request.
82 - * @return bool True if the request has read access, false otherwise.
83 - */
84 - public function get_items_permissions_check($request) {
85 - return current_user_can('manage_options');
86 - }
87 -
88 - /**
89 - * Check if a given request has permission to update items.
90 - *
91 - * @since 1.0.0
92 - *
93 - * @param WP_REST_Request $request Full data about the request.
94 - * @return bool True if the request has update access, false otherwise.
95 - */
96 - public function update_item_permissions_check($request) {
97 - return current_user_can('manage_options');
98 - }
99 -
100 - /**
101 - * Get all extensions
102 - *
103 - * @since 1.0.0
104 - *
105 - * @param WP_REST_Request $request Full data about the request.
106 - * @return WP_HTTP_Response Response object on success, or WP_Error object on failure.
107 - */
108 - public function get_items($request) {
109 - $type = !empty($request['type']) ? $request['type'] : 'all';
110 -
111 - $types = [
112 - 'module' => $this->extensions->get_modules(),
113 - 'addon' => $this->extensions->get_addons(),
114 - 'plugin' => $this->extensions->get_plugins(),
115 - 'all' => $this->extensions->get()
116 - ];
117 -
118 - if (!isset($types[$type])) {
119 - return $this->error(
120 - __('Invalid extension type', 'booktics'),
121 - 400,
122 - 'invalid_extension_type'
123 - );
124 - }
125 -
126 - foreach ($types[$type] as $data) {
127 - $modules_list[] = $data;
128 - }
129 -
130 - return $this->response($modules_list);
131 - }
132 -
133 - /**
134 - * Update extension status
135 - *
136 - * @since 1.0.0
137 - *
138 - * @param WP_REST_Request $request Full data about the request.
139 - * @return WP_HTTP_Response Response object on success, or WP_Error object on failure.
140 - */
141 - public function update_item($request) {
142 - $params = json_decode($request->get_body(), true);
143 -
144 - $name = isset($params['name']) ? sanitize_text_field($params['name']) : '';
145 - $status = isset($params['status']) ? sanitize_text_field($params['status']) : '';
146 -
147 - $valid_statuses = ['off', 'on', 'install', 'activate', 'deactivate'];
148 -
149 - if (empty($name)) {
150 - return $this->error(
151 - __('Please enter extension name', 'booktics'),
152 - 422,
153 - 'extension_name_error'
154 - );
155 - }
156 -
157 - if (empty($status)) {
158 - return $this->error(
159 - /* translators: %s: extension name */
160 - sprintf(__('Please provide status for extension %s', 'booktics'), $name),
161 - 422,
162 - 'extension_status_error'
163 - );
164 - }
165 -
166 - if (!in_array($status, $valid_statuses, true)) {
167 - return $this->error(
168 - /* translators: %s: extension status */
169 - sprintf(__('Invalid status %s provided', 'booktics'), $status),
170 - 422,
171 - 'invalid_status'
172 - );
173 - }
174 -
175 - $extension = $this->extensions->find($name);
176 -
177 - if (!$extension) {
178 - return $this->error(
179 - /* translators: %s: extension name */
180 - sprintf(__('Extension %s not found', 'booktics'), $name),
181 - 404,
182 - 'extension_not_found'
183 - );
184 - }
185 -
186 - $result = $this->extensions->update($name, $status);
187 -
188 - if (false === $result) {
189 - return $this->error(
190 - /* translators: %s: extension name */
191 - sprintf(__('Could not %s the extension', 'booktics'), $status),
192 - 500,
193 - 'operation_failed'
194 - );
195 - }
196 -
197 - $this->update_relevant_settings($name, $status);
198 -
199 - return $this->response([
200 - 'name' => $name,
201 - 'status' => $status,
202 - ],
203 - /* translators: %s: extension name */
204 - sprintf(__('Extension %s successfully', 'booktics'), $status)
205 - );
206 - }
207 -
208 - /**
209 - * Update relevant settings based on extension status
210 - *
211 - * @since 1.0.0
212 - *
213 - * @param string $extension_name Extension name.
214 - * @param string $extension_status Extension status.
215 - * @return void
216 - */
217 - public function update_relevant_settings($extension_name, $extension_status) {
218 - $is_enabled = $extension_status === 'on';
219 -
220 - switch ($extension_name) {
221 - case 'stripe':
222 - booktics_update_option('stripe_addon_install_status', $is_enabled ? 1 : 0);
223 - booktics_update_option('enable_stripe', $is_enabled);
224 - break;
225 -
226 - case 'paypal':
227 - booktics_update_option('paypal_connected', $is_enabled);
228 - booktics_update_option('enable_paypal', $is_enabled);
229 - break;
230 -
231 - case 'google-calendar':
232 - booktics_update_option('google_redirect_url', booktics_get_auth_redirect_uri('google-auth'));
233 - booktics_update_option('google_calendar_connected', $is_enabled);
234 - booktics_update_option('enable_google_calendar', $is_enabled);
235 - break;
236 -
237 - case 'outlook-calendar':
238 - booktics_update_option('enable_outlook_calendar', $is_enabled);
239 - break;
240 -
241 - case 'fluentcrm':
242 - booktics_update_option('enable_fluentcrm', $is_enabled);
243 - break;
244 - }
245 - }
246 -}
247 -
248 -
1 +<?php
2 +
3 +namespace Booktics\Extensions\Controllers;
4 +
5 +use Booktics\Abstracts\Base_Rest_Controller;
6 +use Arraytics\ToolsSdk\Extension as ExtensionManager;
7 +use Arraytics\ToolsSdk\PluginManager;
8 +use WP_HTTP_Response;
9 +use WP_REST_Request;
10 +
11 +/**
12 + * Module Controller
13 + *
14 + * @package Booktics/Module
15 + */
16 +class Module_Controller extends Base_Rest_Controller {
17 + /**
18 + * The namespace of this controller's route.
19 + *
20 + * @since 1.0.0
21 + * @var string
22 + */
23 + protected $namespace = 'booktics/v1';
24 +
25 + /**
26 + * The base of this controller's route.
27 + *
28 + * @since 1.0.0
29 + * @var string
30 + */
31 + protected $rest_base = 'module';
32 +
33 + /**
34 + * Extension manager instance
35 + *
36 + * @var ExtensionManager
37 + */
38 + protected $extensions;
39 +
40 + /**
41 + * Initialize the class and set its properties.
42 + */
43 + public function __construct() {
44 + $this->extensions = new ExtensionManager('booktics_available_modules', booktics_modules_list());
45 + $this->plugin_manager = new PluginManager();
46 + }
47 +
48 + /**
49 + * Register the routes for the objects of the controller.
50 + *
51 + * @since 1.0.0
52 + *
53 + * @return void
54 + */
55 + public function register_routes(): void {
56 + register_rest_route($this->namespace, '/' . $this->rest_base, [
57 + [
58 + 'methods' => \WP_REST_Server::READABLE,
59 + 'callback' => [$this, 'get_items'],
60 + 'permission_callback' => [$this, 'get_items_permissions_check'],
61 + 'args' => [
62 + 'type' => [
63 + 'description' => __('Type of extensions to retrieve (module, addon, plugin, all).', 'booktics'),
64 + 'type' => 'string',
65 + 'enum' => ['module', 'addon', 'plugin', 'all'],
66 + 'default' => 'all',
67 + ],
68 + ],
69 + ],
70 + [
71 + 'methods' => \WP_REST_Server::EDITABLE,
72 + 'callback' => [$this, 'update_item'],
73 + 'permission_callback' => [$this, 'update_item_permissions_check'],
74 + ],
75 + ]);
76 + }
77 +
78 + /**
79 + * Check if a given request has permission to get items.
80 + *
81 + * @since 1.0.0
82 + *
83 + * @param WP_REST_Request $request Full data about the request.
84 + * @return bool True if the request has read access, false otherwise.
85 + */
86 + public function get_items_permissions_check($request) {
87 + return current_user_can('manage_options');
88 + }
89 +
90 + /**
91 + * Check if a given request has permission to update items.
92 + *
93 + * @since 1.0.0
94 + *
95 + * @param WP_REST_Request $request Full data about the request.
96 + * @return bool True if the request has update access, false otherwise.
97 + */
98 + public function update_item_permissions_check($request) {
99 + return current_user_can('manage_options');
100 + }
101 +
102 + /**
103 + * Get all extensions
104 + *
105 + * @since 1.0.0
106 + *
107 + * @param WP_REST_Request $request Full data about the request.
108 + * @return WP_HTTP_Response Response object on success, or WP_Error object on failure.
109 + */
110 + public function get_items($request) {
111 + $type = ! empty( $request['type'] ) ? sanitize_key( $request['type'] ) : 'all';
112 +
113 + $types = [
114 + 'module' => $this->extensions->get_modules(),
115 + 'addon' => $this->extensions->get_addons(),
116 + 'plugin' => $this->extensions->get_plugins(),
117 + 'all' => $this->extensions->get()
118 + ];
119 +
120 + if (!isset($types[$type])) {
121 + return $this->error(
122 + __('Invalid extension type', 'booktics'),
123 + 400,
124 + 'invalid_extension_type'
125 + );
126 + }
127 +
128 + foreach ($types[$type] as $data) {
129 + if ( isset( $data['slug'] ) && 'woocommerce' === $data['slug'] ) {
130 + $data = $this->enrich_woocommerce( $data );
131 + }
132 +
133 + $modules_list[] = $data;
134 + }
135 +
136 + return $this->response($modules_list);
137 + }
138 +
139 + /**
140 + * Attach WooCommerce install state to the module card payload.
141 + *
142 + * The Modules screen does not load the settings REST payload, so the card
143 + * has no other way to know whether WooCommerce is installed. With this it
144 + * can offer the same Install/Activate action the settings panel does.
145 + *
146 + * @param array $data WooCommerce module row.
147 + * @return array
148 + */
149 + protected function enrich_woocommerce( array $data ): array {
150 + if ( ! function_exists( 'get_plugins' ) ) {
151 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
152 + }
153 +
154 + $active = class_exists( 'WooCommerce' );
155 + $installed = $active || array_key_exists( 'woocommerce/woocommerce.php', get_plugins() );
156 +
157 + $data['woocommerce_install_status'] = $active ? 1 : 0;
158 +
159 + // Installed but switched off gets a real one-click activation; not
160 + // installed at all is sent to WordPress' own plugin install screen.
161 + // Built with add_query_arg, not wp_nonce_url: the latter esc_html's its
162 + // output (& -> &#038;), which survives an HTML href but breaks once the
163 + // URL is carried through JSON and assigned to window.location.
164 + $data['woocommerce_activate_url'] = ( $installed && ! $active )
165 + ? add_query_arg(
166 + array(
167 + 'action' => 'activate',
168 + 'plugin' => 'woocommerce/woocommerce.php',
169 + '_wpnonce' => wp_create_nonce( 'activate-plugin_woocommerce/woocommerce.php' ),
170 + ),
171 + admin_url( 'plugins.php' )
172 + )
173 + : '';
174 + $data['woocommerce_install_url'] = admin_url( 'plugin-install.php?tab=plugin-information&plugin=woocommerce&TB_iframe=true' );
175 +
176 + return $data;
177 + }
178 +
179 + /**
180 + * Update extension status
181 + *
182 + * @since 1.0.0
183 + *
184 + * @param WP_REST_Request $request Full data about the request.
185 + * @return WP_HTTP_Response Response object on success, or WP_Error object on failure.
186 + */
187 + public function update_item($request) {
188 + $params = json_decode( $request->get_body(), true);
189 +
190 + $name = isset($params['name']) ? sanitize_text_field($params['name']) : '';
191 + $status = isset($params['status']) ? sanitize_text_field($params['status']) : '';
192 +
193 + $valid_statuses = ['off', 'on', 'install', 'activate', 'deactivate', 'upgrade'];
194 +
195 + if (empty($name)) {
196 + return $this->error(
197 + __('Please enter extension name', 'booktics'),
198 + 422,
199 + 'extension_name_error'
200 + );
201 + }
202 +
203 + if (empty($status)) {
204 + return $this->error(
205 + /* translators: %s: extension name */
206 + sprintf(__('Please provide status for extension %s', 'booktics'), $name),
207 + 422,
208 + 'extension_status_error'
209 + );
210 + }
211 +
212 + if (!in_array($status, $valid_statuses, true)) {
213 + return $this->error(
214 + /* translators: %s: extension status */
215 + sprintf(__('Invalid status %s provided', 'booktics'), $status),
216 + 422,
217 + 'invalid_status'
218 + );
219 + }
220 +
221 + // WooCommerce is a module in this list, but Install/Activate act on the
222 + // WooCommerce *plugin*, not the module toggle. Handle it up front so the
223 + // Modules card can bring WooCommerce up in place, without bouncing the
224 + // admin to wp-admin/plugins.php.
225 + if ( 'woocommerce' === $name && in_array( $status, array( 'install', 'activate' ), true ) ) {
226 + if ( 'install' === $status && ! $this->plugin_manager::is_installed( 'woocommerce' ) ) {
227 + $installed = $this->plugin_manager->install_plugin( 'woocommerce' );
228 +
229 + if ( is_wp_error( $installed ) ) {
230 + return $this->error( $installed->get_error_message(), 500, 'operation_failed' );
231 + }
232 +
233 + if ( false === $installed ) {
234 + return $this->error( __( 'Could not install WooCommerce.', 'booktics' ), 500, 'operation_failed' );
235 + }
236 + }
237 +
238 + $activated = $this->plugin_manager->activate_plugin( 'woocommerce' );
239 +
240 + if ( is_wp_error( $activated ) ) {
241 + return $this->error( $activated->get_error_message(), 500, 'operation_failed' );
242 + }
243 +
244 + if ( false === $activated ) {
245 + return $this->error( __( 'Could not activate WooCommerce.', 'booktics' ), 500, 'operation_failed' );
246 + }
247 +
248 + return $this->response(
249 + array( 'name' => $name, 'status' => 'activate' ),
250 + __( 'WooCommerce activated successfully', 'booktics' )
251 + );
252 + }
253 +
254 + $extension = $this->extensions->find($name);
255 +
256 + if (!$extension) {
257 + return $this->error(
258 + /* translators: %s: extension name */
259 + sprintf(__('Extension %s not found', 'booktics'), $name),
260 + 404,
261 + 'extension_not_found'
262 + );
263 + }
264 +
265 + if ( in_array( $extension['type'], array( 'module', 'integration' ), true ) ) {
266 + $result = $this->extensions->update($name, $status);
267 +
268 + if (false === $result) {
269 + return $this->error(
270 + /* translators: %s: extension name */
271 + sprintf(__('Could not turn %s the module', 'booktics'), $status),
272 + 500,
273 + 'operation_failed'
274 + );
275 + }
276 +
277 + $this->update_relevant_settings($name, $status);
278 +
279 + /**
280 + * Fires after a module has been turned on or off.
281 + *
282 + * Lets a module react to being enabled without polling, e.g. to
283 + * reset a throttle so its first sync runs immediately.
284 + *
285 + * @param string $name Module slug.
286 + * @param string $status New status.
287 + */
288 + do_action( 'booktics_module_status_updated', $name, $status );
289 +
290 + return $this->response( [
291 + 'name' => $name,
292 + 'status' => $status
293 + ],
294 + /* translators: %s: extension name */
295 + sprintf( __('Module turned %s successfully', 'booktics'), $status) );
296 + }
297 +
298 + // When updating plugin status using tools-sdk change actual plugin status
299 + if ( 'plugin' === $extension['type'] ) {
300 + switch ( $status ) {
301 + case 'install':
302 + $result = $this->plugin_manager->install_plugin($name);
303 + break;
304 + case 'activate':
305 + $result = $this->plugin_manager->activate_plugin($name);
306 + break;
307 + case 'deactivate':
308 + $result = $this->plugin_manager->deactivate_plugin($name);
309 + break;
310 + case 'upgrade':
311 + return $this->response( [ 'redirect_url' => $extension['upgrade_link'] ] );
312 + break;
313 + }
314 +
315 + if ( false === $result ) {
316 + return $this->error(
317 + /* translators: %s: extension name */
318 + sprintf(__('Could not %s the extension', 'booktics'), $status),
319 + 500,
320 + 'operation_failed'
321 + );
322 + }
323 + }
324 +
325 + return $this->response([
326 + 'name' => $name,
327 + 'status' => $status,
328 + ],
329 + /* translators: %s: extension name */
330 + sprintf(__('Extension %s successfully', 'booktics'), $status)
331 + );
332 + }
333 +
334 + /**
335 + * Update relevant settings based on extension status
336 + *
337 + * @since 1.0.0
338 + *
339 + * @param string $extension_name Extension name.
340 + * @param string $extension_status Extension status.
341 + * @return void
342 + */
343 + public function update_relevant_settings($extension_name, $extension_status) {
344 + $is_enabled = $extension_status === 'on';
345 +
346 + switch ($extension_name) {
347 + case 'stripe':
348 + booktics_update_option('stripe_addon_install_status', $is_enabled ? 1 : 0);
349 + booktics_update_option('enable_stripe', $is_enabled);
350 + break;
351 +
352 + case 'paypal':
353 + booktics_update_option('paypal_connected', $is_enabled);
354 + booktics_update_option('enable_paypal', $is_enabled);
355 + break;
356 +
357 + case 'woocommerce':
358 + // The booking frontend gates the gateway on this setting, so a
359 + // module toggled from the Modules screen must flip it too;
360 + // otherwise the module boots but no customer can select it.
361 + booktics_update_option('enable_woocommerce_payment', $is_enabled);
362 + break;
363 +
364 + case 'google-calendar':
365 + booktics_update_option('google_redirect_url', booktics_get_auth_redirect_uri('google-auth'));
366 + booktics_update_option('google_calendar_connected', false);
367 + booktics_update_option('enable_google_calendar', $is_enabled);
368 + break;
369 +
370 + case 'outlook-calendar':
371 + booktics_update_option('microsoft_redirect_url', booktics_get_auth_redirect_uri('microsoft-auth'));
372 + booktics_update_option('enable_outlook_calendar', $is_enabled);
373 + break;
374 +
375 + case 'fluentcrm':
376 + booktics_update_option('enable_fluentcrm', $is_enabled);
377 + break;
378 +
379 + case 'pabbly':
380 + booktics_update_option('enable_pabbly', $is_enabled);
381 + break;
382 +
383 + case 'zapier':
384 + booktics_update_option('enable_zapier', $is_enabled);
385 + break;
386 +
387 + case 'zoho':
388 + booktics_update_option('enable_zoho', $is_enabled);
389 + break;
390 +
391 + case 'mailpoet':
392 + booktics_update_option('enable_mailpoet', $is_enabled);
393 + break;
394 + }
395 + }
396 +}
397 +
398 +