PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.29
Booktics – Appointment Booking Calendar for Service Businesses v1.0.29
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
booktics / core / extensions / controllers / module-controller.php

module-controller.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.29, at core/extensions/controllers/module-controller.php

399 lines 13.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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
399