PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.8.3
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.8.3
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / FrmAddon.php

FrmAddon.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.8.3, at classes/models/FrmAddon.php

885 lines 25.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 /** @phpstan-consistent-constructor */
7 class FrmAddon {
8 public $store_url = 'https://formidableforms.com';
9 public $download_id;
10 public $plugin_file;
11 public $plugin_folder;
12 public $plugin_name;
13 public $plugin_slug;
14 public $option_name;
15 public $version;
16 public $author = 'Strategy11';
17 public $is_parent_licence = false;
18 public $needs_license = true;
19 private $is_expired_addon = false;
20 public $license;
21 protected $get_beta = false;
22
23 /**
24 * This is used to decide whether the license checks should continue.
25 * The point is to avoid license issues when a site url changes.
26 *
27 * @since 6.8.3
28 *
29 * @var array
30 */
31 private $save_response = array();
32
33 /**
34 * This is used to flag other add ons not to send a request.
35 * We only want to send a single API request per page load.
36 *
37 * @since 6.8.3
38 *
39 * @var string
40 */
41 private $transient_lock_key = 'frm_activate_request_lock';
42
43 /**
44 * @since 6.8.3
45 *
46 * @var bool
47 */
48 protected $should_clear_cache = true;
49
50 public function __construct() {
51
52 if ( empty( $this->plugin_slug ) ) {
53 $this->plugin_slug = preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->plugin_name ) ) );
54 }
55 if ( empty( $this->option_name ) ) {
56 $this->option_name = 'edd_' . $this->plugin_slug . '_license_';
57 }
58
59 $this->plugin_folder = plugin_basename( $this->plugin_file );
60 $this->license = $this->get_license();
61
62 add_filter( 'frm_installed_addons', array( &$this, 'insert_installed_addon' ) );
63 $this->edd_plugin_updater();
64 }
65
66 public static function load_hooks() {
67 add_filter( 'frm_include_addon_page', '__return_true' );
68 new static();
69 }
70
71 public function insert_installed_addon( $plugins ) {
72 $plugins[ $this->plugin_slug ] = $this;
73
74 return $plugins;
75 }
76
77 public static function get_addon( $plugin_slug ) {
78 $plugins = apply_filters( 'frm_installed_addons', array() );
79 $plugin = false;
80 if ( isset( $plugins[ $plugin_slug ] ) ) {
81 $plugin = $plugins[ $plugin_slug ];
82 }
83
84 return $plugin;
85 }
86
87 public function edd_plugin_updater() {
88
89 $this->is_license_revoked();
90 $license = $this->license;
91
92 add_action( 'after_plugin_row_' . plugin_basename( $this->plugin_file ), array( $this, 'maybe_show_license_message' ), 10, 2 );
93
94 if ( ! empty( $license ) ) {
95
96 if ( 'formidable/formidable.php' !== $this->plugin_folder ) {
97 add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
98 }
99
100 add_filter( 'site_transient_update_plugins', array( &$this, 'clear_expired_download' ) );
101 }
102 }
103
104 /**
105 * Updates information on the "View version x.x details" page with custom data.
106 *
107 * @uses api_request()
108 *
109 * @param mixed $_data
110 * @param string $_action
111 * @param object $_args
112 *
113 * @return object $_data
114 */
115 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
116
117 if ( $_action != 'plugin_information' ) {
118 return $_data;
119 }
120
121 $slug = basename( $this->plugin_file, '.php' );
122 $slug2 = str_replace( '/' . $slug . '.php', '', $this->plugin_folder );
123 if ( empty( $_args->slug ) || ( $_args->slug != $slug && $_args->slug !== $slug2 ) ) {
124 return $_data;
125 }
126
127 $item_id = $this->download_id;
128 if ( empty( $item_id ) ) {
129 $_data = array(
130 'name' => $this->plugin_name,
131 'excerpt' => '',
132 'changelog' => 'See the full changelog at <a href="' . esc_url( $this->store_url . '/changelog/' ) . '"></a>',
133 'banners' => array(
134 'high' => '',
135 'low' => 'https://ps.w.org/formidable/assets/banner-1544x500.png',
136 ),
137 );
138 } else {
139 $api = new FrmFormApi( $this->license );
140 $plugins = $api->get_api_info();
141 $_data = $plugins[ $item_id ];
142 }
143
144 $_data['sections'] = array(
145 'description' => $_data['excerpt'],
146 'changelog' => $_data['changelog'],
147 );
148 $_data['author'] = '<a href="' . esc_url( $this->store_url ) . '">' . esc_html( $this->author ) . '</a>';
149 $_data['homepage'] = $this->store_url;
150
151 return (object) $_data;
152 }
153
154 public function get_license() {
155 $license = $this->maybe_get_pro_license();
156 if ( ! empty( $license ) ) {
157 return $license;
158 }
159
160 $license = trim( get_option( $this->option_name . 'key' ) );
161 if ( empty( $license ) ) {
162 $license = $this->activate_defined_license();
163 }
164
165 return $license;
166 }
167
168 /**
169 * @since 3.04.03
170 */
171 protected function maybe_get_pro_license() {
172 // prevent a loop if $this is the pro plugin
173 $get_license = FrmAppHelper::pro_is_installed() && is_callable( 'FrmProAppHelper::get_updater' ) && $this->plugin_name != 'Formidable Pro';
174
175 if ( ! $get_license ) {
176 return false;
177 }
178
179 $api = new FrmFormApi();
180 $api->get_pro_updater();
181 $license = $api->get_license();
182 if ( empty( $license ) ) {
183 return false;
184 }
185
186 $this->get_api_info( $license );
187 if ( ! $this->is_parent_licence ) {
188 $license = false;
189 }
190
191 return $license;
192 }
193
194 /**
195 * Activate the license in wp-config.php
196 *
197 * @since 2.04
198 */
199 public function activate_defined_license() {
200 $license = $this->get_defined_license();
201 if ( ! empty( $license ) && ! $this->is_active() && ! $this->checked_recently( '1 day' ) ) {
202 $response = $this->activate_license( $license );
203 if ( ! $response['success'] ) {
204 $license = '';
205 }
206 }
207
208 return $license;
209 }
210
211 /**
212 * Check the wp-config.php for the license key
213 *
214 * @since 2.04
215 */
216 public function get_defined_license() {
217 $consant_name = 'FRM_' . strtoupper( $this->plugin_slug ) . '_LICENSE';
218
219 return defined( $consant_name ) ? constant( $consant_name ) : false;
220 }
221
222 public function set_license( $license ) {
223 update_option( $this->option_name . 'key', $license );
224 }
225
226 public function is_active() {
227 return get_option( $this->option_name . 'active' );
228 }
229
230 /**
231 * @since 3.04.03
232 *
233 * @param array|string $error
234 */
235 public function maybe_clear_license( $error ) {
236 if ( is_array( $error ) && $error['code'] === 'disabled' && $error['license'] === $this->license ) {
237 $this->clear_license();
238 }
239 }
240
241 public function clear_license() {
242 delete_option( $this->option_name . 'active' );
243 delete_option( $this->option_name . 'key' );
244
245 if ( $this->should_clear_cache ) {
246 delete_site_option( $this->transient_key() );
247 delete_option( $this->transient_key() );
248 $this->delete_cache();
249 $this->should_clear_cache = true;
250 }
251 }
252
253 /**
254 * Don't save an invalid license.
255 *
256 * @since 6.8.3
257 *
258 * @param bool $is_valid If license activation was successful.
259 *
260 * @return void
261 */
262 protected function maybe_set_active( $is_valid ) {
263 update_option( $this->option_name . 'active', $is_valid );
264 if ( $is_valid ) {
265 $this->set_active( $is_valid );
266 return;
267 }
268
269 // Don't save the license if it's invalid.
270 $this->should_clear_cache = false;
271 $this->clear_license();
272 delete_option( $this->option_name . 'key' );
273 $this->license = '';
274 }
275
276 public function set_active( $is_active ) {
277 $this->delete_cache();
278 FrmAppHelper::save_combined_js();
279 $this->update_pro_capabilities();
280 }
281
282 /**
283 * Updates roles capabilities after pro license is active.
284 *
285 * @since 5.0
286 */
287 protected function update_pro_capabilities() {
288 global $wp_roles;
289
290 if ( ! function_exists( 'get_editable_roles' ) ) {
291 require_once ABSPATH . 'wp-admin/includes/user.php';
292 }
293
294 $caps = FrmAppHelper::frm_capabilities( 'pro_only' );
295 $roles = get_editable_roles();
296 $settings = new FrmSettings();
297 foreach ( $caps as $cap => $cap_desc ) {
298 $cap_roles = (array) ( isset( $settings->$cap ) ? $settings->$cap : 'administrator' );
299
300 // Make sure administrators always have permissions.
301 if ( ! in_array( 'administrator', $cap_roles ) ) {
302 array_push( $cap_roles, 'administrator' );
303 }
304
305 foreach ( $roles as $role => $details ) {
306 if ( in_array( $role, $cap_roles ) ) {
307 $wp_roles->add_cap( $role, $cap );
308 } else {
309 $wp_roles->remove_cap( $role, $cap );
310 }
311 }
312 }
313 }
314
315 /**
316 * @since 3.04.03
317 */
318 protected function delete_cache() {
319 delete_transient( 'frm_api_licence' );
320
321 // Cleanup option that has been removed.
322 delete_option( $this->option_name . 'last_activate' );
323
324 $api = new FrmFormApi( $this->license );
325 $api->reset_cached();
326
327 $api = new FrmFormTemplateApi( $this->license );
328 $api->reset_cached();
329
330 $api = new FrmApplicationApi( $this->license );
331 $api->reset_cached();
332 }
333
334 /**
335 * The Pro version includes the show_license_message function.
336 * We need an extra check before we allow it to show a message.
337 *
338 * @since 3.04.03
339 */
340 public function maybe_show_license_message( $file, $plugin ) {
341 if ( $this->is_expired_addon || isset( $plugin['package'] ) ) {
342 // let's not show a ton of duplicate messages
343 return;
344 }
345
346 $this->show_license_message( $file, $plugin );
347 }
348
349 public function show_license_message( $file, $plugin ) {
350 $message = '';
351 if ( empty( $this->license ) ) {
352 /* translators: %1$s: Plugin name, %2$s: Start link HTML, %3$s: end link HTML */
353 $message = sprintf( esc_html__( 'Your %1$s license key is missing. Please add it on the %2$slicenses page%3$s.', 'formidable' ), esc_html( $this->plugin_name ), '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-settings' ) ) . '">', '</a>' );
354 } else {
355 $api = new FrmFormApi( $this->license );
356 $errors = $api->error_for_license();
357 if ( ! empty( $errors ) ) {
358 $message = reset( $errors );
359 }
360 }
361
362 if ( empty( $message ) ) {
363 return;
364 }
365
366 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
367 $id = sanitize_title( $plugin['Name'] ) . '-next';
368
369 echo '<tr class="plugin-update-tr active" id="' . esc_attr( $id ) . '"><td colspan="' . esc_attr( $wp_list_table->get_column_count() ) . '" class="plugin-update colspanchange"><div class="update-message notice error inline notice-error notice-alt"><p>';
370 echo FrmAppHelper::kses( $message, 'a' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
371 echo '<script type="text/javascript">var d = document.getElementById("' . esc_attr( $id ) . '").previousSibling;if ( d !== null ){ d.className = d.className + " update"; }</script>';
372 echo '</p></div></td></tr>';
373 }
374
375 public function clear_expired_download( $transient ) {
376 if ( ! is_object( $transient ) ) {
377 return $transient;
378 }
379
380 if ( $this->is_current_version( $transient ) ) {
381 // Make sure it doesn't show there is an update if plugin is up-to-date.
382 if ( isset( $transient->response[ $this->plugin_folder ] ) ) {
383 unset( $transient->response[ $this->plugin_folder ] );
384 }
385 } elseif ( isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) ) {
386 $this->prepare_update_details( $transient->response[ $this->plugin_folder ] );
387
388 // if the transient has expired, clear the update and trigger it again
389 if ( $transient->response[ $this->plugin_folder ] === false ) {
390 if ( ! $this->has_been_cleared() ) {
391 $this->cleared_plugins();
392 $this->manually_queue_update();
393 }
394 unset( $transient->response[ $this->plugin_folder ] );
395 }
396 }
397
398 return $transient;
399 }
400
401 /**
402 * Check if the plugin information is correct to allow an update
403 *
404 * @since 3.04.03
405 *
406 * @param object $transient The current plugin info saved for update.
407 */
408 private function prepare_update_details( &$transient ) {
409 $version_info = $transient;
410 $has_beta_url = isset( $version_info->beta ) && ! empty( $version_info->beta );
411 if ( $this->get_beta && ! $has_beta_url ) {
412 $version_info = (object) $this->get_api_info( $this->license );
413 }
414
415 if ( isset( $version_info->new_version ) && ! empty( $version_info->new_version ) ) {
416 $this->clear_old_plugin_version( $version_info );
417 if ( $version_info === false ) {
418 // Was cleared with timeout.
419 $transient = false;
420 } else {
421 $this->maybe_use_beta_url( $version_info );
422
423 if ( version_compare( $version_info->new_version, $this->version, '>' ) ) {
424 $transient = $version_info;
425 }
426 }
427 }
428 }
429
430 /**
431 * Get the API info for this plugin
432 *
433 * @since 3.04.03
434 */
435 protected function get_api_info( $license ) {
436 $api = new FrmFormApi( $license );
437 $addon = $api->get_addon_for_license( $this );
438
439 // if there is no download url, this license does not apply to the addon
440 if ( isset( $addon['package'] ) ) {
441 $this->is_parent_licence = true;
442 } elseif ( isset( $addon['error'] ) ) {
443 // if the license is expired, we must assume all add-ons were packaged
444 $this->is_parent_licence = true;
445 $this->is_expired_addon = true;
446 }
447
448 return $addon;
449 }
450
451 /**
452 * Make sure transients don't stick around on sites that
453 * don't save the transient expiration
454 *
455 * @since 2.05.05
456 */
457 private function clear_old_plugin_version( &$version_info ) {
458 $timeout = ( isset( $version_info->timeout ) && ! empty( $version_info->timeout ) ) ? $version_info->timeout : 0;
459 if ( ! empty( $timeout ) && time() > $timeout ) {
460 // Cache is expired.
461 $version_info = false;
462 $api = new FrmFormApi( $this->license );
463 $api->reset_cached();
464 }
465 }
466
467 /**
468 * The beta url is always included if the download has a beta.
469 * Check if the beta should be downloaded.
470 *
471 * @since 3.04.03
472 */
473 private function maybe_use_beta_url( &$version_info ) {
474 if ( $this->get_beta && isset( $version_info->beta ) && ! empty( $version_info->beta ) ) {
475 $version_info->new_version = $version_info->beta['version'];
476 $version_info->package = $version_info->beta['package'];
477 if ( isset( $version_info->plugin ) && ! empty( $version_info->plugin ) ) {
478 $version_info->plugin = $version_info->beta['plugin'];
479 }
480 }
481 }
482
483 private function is_current_version( $transient ) {
484 if ( empty( $transient->checked ) || ! isset( $transient->checked[ $this->plugin_folder ] ) ) {
485 return false;
486 }
487
488 $response = ! isset( $transient->response ) || empty( $transient->response );
489 if ( $response ) {
490 return true;
491 }
492
493 return isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) && $transient->checked[ $this->plugin_folder ] === $transient->response[ $this->plugin_folder ]->new_version;
494 }
495
496 private function has_been_cleared() {
497 $last_cleared = get_option( 'frm_last_cleared' );
498
499 return ( $last_cleared && $last_cleared > gmdate( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) ) );
500 }
501
502 private function cleared_plugins() {
503 update_option( 'frm_last_cleared', gmdate( 'Y-m-d H:i:s' ) );
504 }
505
506 private function is_license_revoked() {
507 if ( empty( $this->license ) || empty( $this->plugin_slug ) || isset( $_POST['license'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
508 return;
509 }
510
511 if ( $this->get_defined_license() ) {
512 // Don't check if the license is defined in wp-config.php since we can't remove it.
513 return;
514 }
515
516 // Only check weekly.
517 if ( $this->checked_recently( '7 days', 'valid' ) || $this->is_running() ) {
518 return;
519 }
520
521 $response = $this->get_license_status();
522 if ( 'revoked' === $response['status'] || 'blocked' === $response['status'] || 'disabled' === $response['status'] || 'missing' === $response['status'] ) {
523 $this->clear_license();
524 }
525 }
526
527 /**
528 * Has this been checked too recently?
529 *
530 * @param string $time ie. '1 day'.
531 * @param string $required_status Return false if the last check does not match. ie 'valid'.
532 *
533 * @return bool
534 */
535 private function checked_recently( $time, $required_status = '' ) {
536 $last_checked = $this->last_checked();
537 $is_429 = isset( $last_checked['response_code'] ) && 429 === $last_checked['response_code'];
538 if ( $is_429 ) {
539 // If the last check was a a rate limit, we'll need to check again sooner.
540 $time = '5 minutes';
541 $required_status = '';
542 }
543
544 if ( $required_status && ( ! isset( $last_checked['status'] ) || $last_checked['status'] !== $required_status ) ) {
545 // If the last check was invalid, we don't need to check again.
546 return true;
547 }
548
549 $checked_time = isset( $last_checked['time'] ) ? $last_checked['time'] : false;
550 $time_ago = gmdate( 'Y-m-d H:i:s', strtotime( '-' . $time ) );
551 return $checked_time && $checked_time > $time_ago;
552 }
553
554 /**
555 * @since 6.8.3 Switched to an array to store extra response info.
556 *
557 * @return array
558 */
559 private function last_checked() {
560 if ( is_multisite() ) {
561 $last_checked = get_site_option( $this->transient_key() );
562 } else {
563 $last_checked = get_option( $this->transient_key() );
564 }
565 if ( $last_checked && ! is_array( $last_checked ) ) {
566 // Get string into array for existing values.
567 $last_checked = array( 'time' => $last_checked );
568 }
569 return $last_checked ? (array) $last_checked : array();
570 }
571
572 /**
573 * @return void
574 */
575 private function update_last_checked() {
576 $this->save_response['time'] = gmdate( 'Y-m-d H:i:s' );
577 if ( is_multisite() ) {
578 update_site_option( $this->transient_key(), $this->save_response );
579 } else {
580 update_option( $this->transient_key(), $this->save_response );
581 }
582 }
583
584 /**
585 * Use a new cache after the license is changed, or Formidable is updated.
586 */
587 private function transient_key() {
588 return 'frm_' . md5( sanitize_key( $this->license . '_' . $this->plugin_slug ) );
589 }
590
591 public static function activate() {
592 FrmAppHelper::permission_check( 'frm_change_settings' );
593 check_ajax_referer( 'frm_ajax', 'nonce' );
594
595 $license = stripslashes( FrmAppHelper::get_param( 'license', '', 'post', 'sanitize_text_field' ) );
596 if ( empty( $license ) ) {
597 wp_send_json(
598 array(
599 'message' => __( 'Oops! You forgot to enter your license number.', 'formidable' ),
600 'success' => false,
601 )
602 );
603 }
604
605 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
606 $response = self::activate_license_for_plugin( $license, $plugin_slug );
607
608 wp_send_json( $response );
609 }
610
611 /**
612 * @since 4.08
613 */
614 public static function activate_license_for_plugin( $license, $plugin_slug ) {
615 $this_plugin = self::get_addon( $plugin_slug );
616 return $this_plugin->activate_license( $license );
617 }
618
619 private function activate_license( $license ) {
620 $this->set_license( $license );
621 $this->license = $license;
622
623 $this->die_if_not_allowed();
624
625 $response = $this->get_license_status();
626 $response['message'] = '';
627 $response['success'] = false;
628
629 if ( $response['error'] ) {
630 $response['message'] = $response['status'];
631 } else {
632 $messages = $this->get_messages();
633 if ( is_string( $response['status'] ) && isset( $messages[ $response['status'] ] ) ) {
634 $response['message'] = $messages[ $response['status'] ];
635 } else {
636 $response['message'] = FrmAppHelper::kses( $response['status'], array( 'a' ) );
637 }
638
639 $is_valid = false;
640 if ( 'valid' === $response['status'] ) {
641 $is_valid = 'valid';
642 $response['success'] = true;
643 }
644 $this->maybe_set_active( $is_valid );
645 }
646
647 $this->update_last_checked();
648
649 return $response;
650 }
651
652 /**
653 * Prevent this check from happening more than once per minute with the same license.
654 *
655 * @return void
656 */
657 private function die_if_not_allowed() {
658 if ( ! $this->checked_recently( '2 minutes' ) ) {
659 return;
660 }
661
662 // Don't check more than once per minute.
663 wp_send_json(
664 array(
665 'message' => __( 'Please wait two minutes before trying again.', 'formidable' ),
666 'success' => false,
667 )
668 );
669 }
670
671 private function get_license_status() {
672 $this->set_running();
673
674 $response = array(
675 'status' => 'missing',
676 'error' => true,
677 );
678 if ( empty( $this->license ) ) {
679 $response['error'] = false;
680
681 return $response;
682 }
683
684 try {
685 $response['error'] = false;
686 $license_data = $this->send_mothership_request( 'activate_license' );
687
688 // $license_data->license will be either "valid" or "invalid"
689 if ( is_array( $license_data ) ) {
690 if ( ! empty( $license_data['license'] ) && in_array( $license_data['license'], array( 'valid', 'invalid' ), true ) ) {
691 $response['status'] = $license_data['license'];
692 $this->save_status['status'] = $license_data['license'];
693 }
694 } else {
695 $response['status'] = $license_data;
696 }
697 } catch ( Exception $e ) {
698 $response['status'] = $e->getMessage();
699 }
700
701 $this->update_last_checked();
702 $this->done_running();
703 return $response;
704 }
705
706 private function get_messages() {
707 return array(
708 'valid' => __( 'Your license has been activated. Enjoy!', 'formidable' ),
709 'invalid' => __( 'That license key is invalid', 'formidable' ),
710 'expired' => __( 'That license is expired', 'formidable' ),
711 'revoked' => __( 'That license has been refunded', 'formidable' ),
712 'no_activations_left' => __( 'That license has been used on too many sites', 'formidable' ),
713 'invalid_item_id' => __( 'Oops! That is the wrong license key for this plugin.', 'formidable' ),
714 'missing' => __( 'That license key is invalid', 'formidable' ),
715 );
716 }
717
718 /**
719 * @since 4.03
720 */
721 public static function reset_cache() {
722 FrmAppHelper::permission_check( 'frm_change_settings' );
723 check_ajax_referer( 'frm_ajax', 'nonce' );
724
725 $this_plugin = self::set_license_from_post();
726 $this_plugin->delete_cache();
727
728 $response = array(
729 'success' => true,
730 'message' => __( 'Cache cleared', 'formidable' ),
731 );
732
733 wp_send_json( $response );
734 }
735
736 public static function deactivate() {
737 FrmAppHelper::permission_check( 'frm_change_settings' );
738 check_ajax_referer( 'frm_ajax', 'nonce' );
739
740 $this_plugin = self::set_license_from_post();
741
742 $response = array(
743 'success' => false,
744 'message' => '',
745 );
746 try {
747 // $license_data->license will be either "deactivated" or "failed"
748 $license_data = $this_plugin->send_mothership_request( 'deactivate_license' );
749 if ( is_array( $license_data ) && 'deactivated' === $license_data['license'] ) {
750 $response['success'] = true;
751 $response['message'] = __( 'That license was removed successfully', 'formidable' );
752 } else {
753 $response['message'] = __( 'There was an error deactivating your license.', 'formidable' );
754 }
755 } catch ( Exception $e ) {
756 $response['message'] = $e->getMessage();
757 }
758
759 $this_plugin->clear_license();
760
761 wp_send_json( $response );
762 }
763
764 /**
765 * @since 4.03
766 */
767 private static function set_license_from_post() {
768 $plugin_slug = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
769 $this_plugin = self::get_addon( $plugin_slug );
770 $license = $this_plugin->get_license();
771 $this_plugin->license = $license;
772 return $this_plugin;
773 }
774
775 /**
776 * @return string
777 */
778 public function send_mothership_request( $action ) {
779 $api_params = array(
780 'edd_action' => $action,
781 'license' => $this->license,
782 'url' => home_url(),
783 );
784 if ( is_numeric( $this->download_id ) ) {
785 $api_params['item_id'] = absint( $this->download_id );
786 } else {
787 $api_params['item_name'] = rawurlencode( $this->plugin_name );
788 }
789
790 $arg_array = array(
791 'body' => $api_params,
792 'timeout' => 25,
793 'user-agent' => $this->plugin_slug . '/' . $this->version . '; ' . get_bloginfo( 'url' ),
794 );
795
796 $resp = wp_remote_post(
797 $this->store_url . '?l=' . urlencode( base64_encode( $this->license ) ),
798 $arg_array
799 );
800 $body = wp_remote_retrieve_body( $resp );
801
802 $this->save_status = array( 'response_code' => wp_remote_retrieve_response_code( $resp ) );
803
804 $message = __( 'Your License Key was invalid', 'formidable' );
805 if ( is_wp_error( $resp ) ) {
806 $link = FrmAppHelper::admin_upgrade_link( 'api', 'knowledgebase/why-cant-i-activate-formidable-pro/' );
807 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
808 $message = sprintf( __( 'You had an error communicating with the Formidable API. %1$sClick here%2$s for more information.', 'formidable' ), '<a href="' . esc_url( $link ) . '" target="_blank">', '</a>' );
809 $message .= ' ' . $resp->get_error_message();
810 } elseif ( 'error' === $body || is_wp_error( $body ) ) {
811 $message = __( 'You had an HTTP error connecting to the Formidable API', 'formidable' );
812 } else {
813 $json_res = json_decode( $body, true );
814 if ( null !== $json_res ) {
815 if ( is_array( $json_res ) && isset( $json_res['error'] ) ) {
816 $message = $json_res['error'];
817 } else {
818 $message = $json_res;
819 }
820 } elseif ( ! empty( $resp['response'] ) && ! empty( $resp['response']['code'] ) ) {
821 $resp['body'] = wp_strip_all_tags( $resp['body'] );
822
823 $message = sprintf(
824 /* translators: %1$s: Error code, %2$s: Error message */
825 esc_html__( 'There was a %1$s error: %2$s', 'formidable' ),
826 esc_html( $resp['response']['code'] ),
827 $resp['response']['message'] . ' ' . $resp['body']
828 );
829 }
830 }//end if
831
832 return $message;
833 }
834
835 public function manually_queue_update() {
836 $updates = new stdClass();
837 $updates->last_checked = 0;
838 $updates->response = array();
839 $updates->translations = array();
840 $updates->no_update = array();
841 $updates->checked = array();
842 set_site_transient( 'update_plugins', $updates );
843 }
844
845 /**
846 * Set the transient key for the lock. It should be unique to the license.
847 *
848 * @since 6.8.3
849 *
850 * @return bool
851 */
852 protected function lock_key() {
853 return $this->transient_lock_key . '_' . $this->license;
854 }
855
856 /**
857 * Prevent multiple requests from running at the same time.
858 *
859 * @since 6.8.3
860 *
861 * @return bool
862 */
863 protected function is_running() {
864 return get_transient( $this->lock_key() );
865 }
866
867 /**
868 * @since 6.8.3
869 *
870 * @return void
871 */
872 protected function set_running() {
873 set_transient( $this->lock_key(), true, 2 * MINUTE_IN_SECONDS );
874 }
875
876 /**
877 * @since 6.8.3
878 *
879 * @return void
880 */
881 protected function done_running() {
882 delete_transient( $this->lock_key() );
883 }
884 }
885