PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.27
Booktics – Appointment Booking Calendar for Service Businesses v1.0.27
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 +209 -56 1.0.0 → 1.0.27 View file →
@@ -3,10 +3,11 @@
3 3 namespace Booktics\Extensions\Controllers;
4 4
5 5 use Booktics\Abstracts\Base_Rest_Controller;
6 6 use Arraytics\ToolsSdk\Extension as ExtensionManager;
7 +use Arraytics\ToolsSdk\PluginManager;
8 +use WP_HTTP_Response;
7 9 use WP_REST_Request;
8 -use Booktics\Extensions\Extension_Icon;
9 10
10 11 /**
11 12 * Module Controller
12 13 *
@@ -39,47 +40,10 @@
39 40 /**
40 41 * Initialize the class and set its properties.
41 42 */
42 43 public function __construct() {
43 - $available_modules = [
44 - 'stripe-addon' => [
45 - 'name' => 'stripe-addon',
46 - 'slug' => 'stripe-addon',
47 - 'type' => 'module',
48 - 'upgrade' => true,
49 - 'upgrade_link' => 'https://themewinter.com/purchase-history',
50 - 'status' => 'off',
51 - 'is_pro' => false,
52 - 'title' => __( 'Stripe Addon', 'booktics' ),
53 - 'description' => __( 'It allows you to use stripe payment.', 'booktics' ),
54 - 'icon' => Extension_Icon::get( 'booktics-stripe-addon' ),
55 - 'notice' => '',
56 - 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-stripe-addon',
57 - 'settings_link' => '',
58 - 'doc_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-stripe-addon',
59 - 'download_link' => 'https://products.arraytics.com/booktics-addons/booktics-stripe-addon-1.0.0.zip',
60 - ],
61 - 'google-calendar' => [
62 - 'name' => 'google-calendar',
63 - 'slug' => 'google-calendar',
64 - 'type' => 'module',
65 - 'upgrade' => true,
66 - 'upgrade_link' => 'https://themewinter.com/purchase-history',
67 - 'status' => 'off',
68 - 'is_pro' => false,
69 - 'title' => __( 'Google Calendar', 'booktics' ),
70 - 'description' => __( 'It allows you to use google calendar.', 'booktics' ),
71 - 'icon' => Extension_Icon::get( 'booktics-google-calendar' ),
72 - 'notice' => '',
73 - 'demo_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-google-calendar',
74 - 'settings_link' => '',
75 - 'doc_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/integration/booktics-google-calendar',
76 - 'download_link' => 'https://products.arraytics.com/booktics-addons/booktics-google-calendar-1.0.0.zip',
77 - ],
78 - ];
79 - $available_modules = apply_filters('booktics_available_modules', $available_modules);
80 -
81 - $this->extensions = new ExtensionManager('booktics_extension_settings', $available_modules);
44 + $this->extensions = new ExtensionManager('booktics_available_modules', booktics_modules_list());
45 + $this->plugin_manager = new PluginManager();
82 46 }
83 47
84 48 /**
85 49 * Register the routes for the objects of the controller.
@@ -143,10 +107,10 @@
143 107 * @param WP_REST_Request $request Full data about the request.
144 108 * @return WP_HTTP_Response Response object on success, or WP_Error object on failure.
145 109 */
146 110 public function get_items($request) {
147 - $type = !empty($request['type']) ? $request['type'] : 'all';
148 -
111 + $type = ! empty( $request['type'] ) ? sanitize_key( $request['type'] ) : 'all';
112 +
149 113 $types = [
150 114 'module' => $this->extensions->get_modules(),
151 115 'addon' => $this->extensions->get_addons(),
152 116 'plugin' => $this->extensions->get_plugins(),
@@ -161,8 +125,12 @@
161 125 );
162 126 }
163 127
164 128 foreach ($types[$type] as $data) {
129 + if ( isset( $data['slug'] ) && 'woocommerce' === $data['slug'] ) {
130 + $data = $this->enrich_woocommerce( $data );
131 + }
132 +
165 133 $modules_list[] = $data;
166 134 }
167 135
168 136 return $this->response($modules_list);
@@ -168,8 +136,48 @@
168 136 return $this->response($modules_list);
169 137 }
170 138
171 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 (& -> &), 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 + /**
172 180 * Update extension status
173 181 *
174 182 * @since 1.0.0
175 183 *
@@ -176,15 +184,15 @@
176 184 * @param WP_REST_Request $request Full data about the request.
177 185 * @return WP_HTTP_Response Response object on success, or WP_Error object on failure.
178 186 */
179 187 public function update_item($request) {
180 - $params = json_decode($request->get_body(), true);
181 -
188 + $params = json_decode( $request->get_body(), true);
189 +
182 190 $name = isset($params['name']) ? sanitize_text_field($params['name']) : '';
183 191 $status = isset($params['status']) ? sanitize_text_field($params['status']) : '';
184 -
185 - $valid_statuses = ['off', 'on', 'install', 'activate', 'deactivate'];
186 192
193 + $valid_statuses = ['off', 'on', 'install', 'activate', 'deactivate', 'upgrade'];
194 +
187 195 if (empty($name)) {
188 196 return $this->error(
189 197 __('Please enter extension name', 'booktics'),
190 198 422,
@@ -209,10 +217,43 @@
209 217 'invalid_status'
210 218 );
211 219 }
212 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 +
213 254 $extension = $this->extensions->find($name);
214 -
255 +
215 256 if (!$extension) {
216 257 return $this->error(
217 258 /* translators: %s: extension name */
218 259 sprintf(__('Extension %s not found', 'booktics'), $name),
@@ -220,26 +261,138 @@
220 261 'extension_not_found'
221 262 );
222 263 }
223 264
224 - $result = $this->extensions->update($name, $status);
265 + if ( in_array( $extension['type'], array( 'module', 'integration' ), true ) ) {
266 + $result = $this->extensions->update($name, $status);
225 267
226 - if (false === $result) {
227 - return $this->error(
228 - /* translators: %s: extension name */
229 - sprintf(__('Could not %s the extension', 'booktics'), $status),
230 - 500,
231 - 'operation_failed'
232 - );
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) );
233 296 }
234 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 +
235 325 return $this->response([
236 326 'name' => $name,
237 327 'status' => $status,
238 328 ],
239 - /* translators: %s: extension name */
329 + /* translators: %s: extension name */
240 330 sprintf(__('Extension %s successfully', 'booktics'), $status)
241 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 + }
242 395 }
243 396 }
244 397
245 398