PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.15
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.15
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 / controllers / FrmAddonsController.php

FrmAddonsController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.15, at classes/controllers/FrmAddonsController.php

1,742 lines 46.4 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 class FrmAddonsController {
7
8 /**
9 * @var string
10 */
11 const SCRIPT_HANDLE = 'frm-addons-page';
12
13 /**
14 * @var array
15 */
16 private static $categories = array();
17
18 /**
19 * @var string
20 */
21 private static $request_addon_url;
22
23 /**
24 * @var string
25 */
26 protected static $plugin;
27
28 /**
29 * @since 6.15
30 */
31 public static function load_admin_hooks() {
32 add_action( 'admin_menu', __CLASS__ . '::menu', 100 );
33 add_filter( 'pre_set_site_transient_update_plugins', __CLASS__ . '::check_update' );
34
35 if ( FrmAppHelper::is_admin_page( 'formidable-addons' ) ) {
36 self::$request_addon_url = 'https://connect.formidableforms.com/add-on-request/';
37
38 add_action( 'admin_enqueue_scripts', __CLASS__ . '::enqueue_assets', 15 );
39 add_filter( 'frm_show_footer_links', '__return_false' );
40 }
41 }
42
43 /**
44 * Enqueues the Add-Ons page scripts and styles.
45 *
46 * @since 6.15
47 *
48 * @return void
49 */
50 public static function enqueue_assets() {
51 $plugin_url = FrmAppHelper::plugin_url();
52 $version = FrmAppHelper::plugin_version();
53 $js_dependencies = array(
54 'wp-i18n',
55 // This prevents a console error "wp.hooks is undefined" in WP versions older than 5.7.
56 'wp-hooks',
57 'formidable_dom',
58 );
59
60 // Enqueue styles that needed.
61 wp_enqueue_style( 'formidable-admin' );
62 wp_enqueue_style( 'formidable-grids' );
63
64 // Register and enqueue Add-Ons page style.
65 wp_register_style( self::SCRIPT_HANDLE, $plugin_url . '/css/admin/addons-page.css', array(), $version );
66 wp_enqueue_style( self::SCRIPT_HANDLE );
67
68 // Register and enqueue Add-Ons page script.
69 wp_register_script( self::SCRIPT_HANDLE, $plugin_url . '/js/addons-page.js', $js_dependencies, $version, true );
70 wp_localize_script( self::SCRIPT_HANDLE, 'frmAddonsVars', self::get_js_variables() );
71 wp_enqueue_script( self::SCRIPT_HANDLE );
72
73 FrmAppHelper::dequeue_extra_global_scripts();
74 }
75
76 /**
77 * Get the Add-Ons page JS variables as an array.
78 *
79 * @since 6.15
80 *
81 * @return array
82 */
83 private static function get_js_variables() {
84 return array(
85 'proIsIncluded' => FrmAppHelper::pro_is_included(),
86 'addonRequestURL' => self::$request_addon_url,
87 );
88 }
89
90 /**
91 * @return void
92 */
93 public static function menu() {
94 if ( ! current_user_can( 'activate_plugins' ) ) {
95 return;
96 }
97
98 $label = __( 'Add-Ons', 'formidable' );
99 $label = '<span style="color:#3FCA89">' . $label . '</span>';
100
101 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Add-Ons', 'formidable' ), $label, 'frm_view_forms', 'formidable-addons', 'FrmAddonsController::list_addons' );
102
103 // remove default created subpage, make the page with highest priority as default.
104 remove_submenu_page( 'formidable', 'formidable' );
105
106 if ( ! FrmAppHelper::pro_is_installed() ) {
107 add_submenu_page(
108 'formidable',
109 'Formidable | ' . __( 'Upgrade', 'formidable' ),
110 '<span class="frm-upgrade-submenu">' . __( 'Upgrade', 'formidable' ) . '</span>',
111 'frm_view_forms',
112 'formidable-pro-upgrade',
113 'FrmAddonsController::upgrade_to_pro'
114 );
115 } elseif ( 'formidable-pro-upgrade' === FrmAppHelper::get_param( 'page' ) ) {
116 wp_safe_redirect( admin_url( 'admin.php?page=formidable' ) );
117 exit;
118 }
119 }
120
121 /**
122 * @return void
123 */
124 public static function list_addons() {
125 FrmAppHelper::include_svg();
126
127 $view_path = FrmAppHelper::plugin_path() . '/classes/views/addons/';
128 $installed_addons = apply_filters( 'frm_installed_addons', array() );
129 $addons = self::get_api_addons();
130 $errors = array();
131 $license_type = '';
132 $request_addon_url = self::$request_addon_url;
133
134 if ( isset( $addons['error'] ) ) {
135 $api = new FrmFormApi();
136 $errors = $api->get_error_from_response( $addons );
137 $license_type = isset( $addons['error']['type'] ) ? $addons['error']['type'] : '';
138 unset( $addons['error'] );
139 }
140
141 $pro = array(
142 'pro' => array(
143 'title' => 'Formidable Forms Pro',
144 'slug' => 'formidable-pro',
145 'released' => '2011-02-05',
146 'docs' => 'knowledgebase/',
147 'categories' => array( 'basic', 'plus', 'business', 'elite' ),
148 'excerpt' => 'Create calculators, surveys, smart forms, and data-driven applications. Build directories, real estate listings, job boards, and much more.',
149 ),
150 );
151 $addons = $pro + $addons;
152 self::prepare_addons( $addons );
153
154 $pricing = FrmAppHelper::admin_upgrade_link( 'addons' );
155
156 self::organize_and_get_categories();
157 $categories = self::$categories;
158
159 include $view_path . 'index.php';
160 }
161
162 /**
163 * Organize and set categories.
164 *
165 * @since 6.15
166 *
167 * @return void
168 */
169 protected static function organize_and_get_categories() {
170 unset( self::$categories['strategy11'] );
171 ksort( self::$categories );
172
173 $bottom_categories = array();
174 $plans = FrmFormsHelper::get_license_types(
175 array(
176 'include_all' => false,
177 'case_lower' => true,
178 )
179 );
180
181 // Extract the elements to move
182 foreach ( $plans as $plan ) {
183 if ( isset( self::$categories[ $plan ] ) ) {
184 $bottom_categories[ $plan ] = self::$categories[ $plan ];
185 unset( self::$categories[ $plan ] );
186 }
187 }
188
189 $special_categories = array();
190 if ( 'elite' !== self::license_type() ) {
191 $special_categories['available-addons'] = array(
192 'name' => __( 'Available', 'formidable' ),
193 // To be assigned via JavaScript.
194 'count' => 0,
195 );
196 }
197
198 $special_categories['active-addons'] = array(
199 'name' => __( 'Active', 'formidable' ),
200 // To be assigned via JavaScript.
201 'count' => 0,
202 );
203
204 $special_categories['all-items'] = array(
205 'name' => __( 'All Add-Ons', 'formidable' ),
206 // To be assigned via JavaScript.
207 'count' => 0,
208 );
209
210 self::$categories = array_merge(
211 $special_categories,
212 self::$categories,
213 $bottom_categories
214 );
215 }
216
217 /**
218 * Organize and set categories.
219 *
220 * @since 6.15
221 *
222 * @param array $addon The addon array that will be modified by reference.
223 * @return void
224 */
225 protected static function set_categories( &$addon ) {
226 if ( ! isset( $addon['categories'] ) ) {
227 return;
228 }
229
230 $addon['category-slugs'] = array();
231
232 foreach ( $addon['categories'] as $category ) {
233 $category = FrmFormsHelper::convert_legacy_package_names( $category );
234 $category_slug = sanitize_title( $category );
235
236 // Add the slug to the new array.
237 $addon['category-slugs'][] = $category_slug;
238
239 if ( ! isset( self::$categories[ $category_slug ] ) ) {
240 self::$categories[ $category_slug ] = array(
241 'name' => $category,
242 'count' => 0,
243 );
244 }
245
246 ++self::$categories[ $category_slug ]['count'];
247 }
248 }
249
250 /**
251 * @return void
252 */
253 public static function license_settings() {
254 $plugins = apply_filters( 'frm_installed_addons', array() );
255 if ( empty( $plugins ) ) {
256 esc_html_e( 'There are no plugins on your site that require a license', 'formidable' );
257
258 return;
259 }
260
261 ksort( $plugins );
262
263 include FrmAppHelper::plugin_path() . '/classes/views/addons/settings.php';
264 }
265
266 /**
267 * @return array
268 */
269 protected static function get_api_addons() {
270 $api = new FrmFormApi();
271 $addons = $api->get_api_info();
272
273 if ( empty( $addons ) ) {
274 $addons = self::fallback_plugin_list();
275 } else {
276 foreach ( $addons as $k => $addon ) {
277 if ( empty( $addon['excerpt'] ) && $k !== 'error' ) {
278 unset( $addons[ $k ] );
279 }
280 }
281 }
282
283 return $addons;
284 }
285
286 /**
287 * Retrieves the count of available addons.
288 *
289 * @since 6.9
290 *
291 * @return int Count of addons.
292 */
293 public static function get_addons_count() {
294 $addons = self::get_api_addons();
295
296 return count( $addons );
297 }
298
299 /**
300 * If the API is unable to connect, show something on the addons page
301 *
302 * @since 3.04.03
303 * @return array
304 */
305 protected static function fallback_plugin_list() {
306 $list = array(
307 'formidable-pro' => array(
308 'title' => 'Formidable Forms Pro',
309 'link' => 'pricing/',
310 'docs' => '',
311 'excerpt' => 'Enhance your basic Formidable forms with a plethora of Pro field types and features. Create advanced forms and data-driven applications in minutes.',
312 ),
313 'mailchimp' => array(
314 'title' => 'Mailchimp Forms',
315 'excerpt' => 'Get on the path to more sales and leads in a matter of minutes. Add leads to a Mailchimp mailing list when they submit forms and update their information along with the entry.',
316 ),
317 'registration' => array(
318 'title' => 'User Registration Forms',
319 'link' => 'downloads/user-registration/',
320 'excerpt' => 'Give new users access to your site as quickly and painlessly as possible. Allow users to register, edit and be able to login to their profiles on your site from the front end in a clean, customized registration form.',
321 ),
322 'paypal' => array(
323 'title' => 'PayPal Standard Forms',
324 'link' => 'downloads/paypal-standard/',
325 'excerpt' => 'Automate your business by collecting instant payments from your clients. Collect information, calculate a total, and send them on to PayPal. Require a payment before publishing content on your site.',
326 ),
327 'stripe' => array(
328 'title' => 'Stripe Forms',
329 'docs' => 'knowledgebase/stripe/',
330 'excerpt' => 'Any Formidable forms on your site can accept credit card payments without users ever leaving your site.',
331 ),
332 'authorize-net' => array(
333 'title' => 'Authorize.net AIM Forms',
334 'link' => 'downloads/authorize-net-aim/',
335 'docs' => 'knowledgebase/authorize-net-aim/',
336 'excerpt' => 'Accept one-time payments directly on your site, using Authorize.net AIM.',
337 ),
338 'woocommerce' => array(
339 'title' => 'WooCommerce Forms',
340 'excerpt' => 'Use a Formidable form on your WooCommerce product pages.',
341 ),
342 'autoresponder' => array(
343 'title' => 'Form Action Automation',
344 'docs' => 'knowledgebase/schedule-autoresponder/',
345 'excerpt' => 'Schedule email notifications, SMS messages, and API actions.',
346 ),
347 'modal' => array(
348 'title' => 'Bootstrap Modal Forms',
349 'link' => 'downloads/bootstrap-modal/',
350 'docs' => 'knowledgebase/bootstrap-modal/',
351 'excerpt' => 'Open a view or form in a Bootstrap popup.',
352 ),
353 'bootstrap' => array(
354 'title' => 'Bootstrap Style Forms',
355 'excerpt' => 'Instantly add Bootstrap styling to all your Formidable forms.',
356 ),
357 'zapier' => array(
358 'title' => 'Zapier Forms',
359 'excerpt' => 'Connect with hundreds of different applications through Zapier. Insert a new row in a Google docs spreadsheet, post on Twitter, or add a new Dropbox file with your form.',
360 ),
361 'signature' => array(
362 'title' => 'Digital Signature Forms',
363 'excerpt' => 'Add a signature field to your form. The user may write their signature with a trackpad/mouse or just type it.',
364 ),
365 'api' => array(
366 'title' => 'Formidable Forms API',
367 'link' => 'downloads/formidable-api/',
368 'excerpt' => 'Send entry results to any other site that has a Rest API. This includes the option of sending entries from one Formidable site to another.',
369 ),
370 'twilio' => array(
371 'title' => 'Twilio SMS Forms',
372 'docs' => 'knowledgebase/twilio-add-on/',
373 'excerpt' => 'Allow users to text their votes for polls created by Formidable Forms, or send SMS notifications when entries are submitted or updated.',
374 ),
375 'views' => array(
376 'title' => 'Formidable Views',
377 'excerpt' => 'Add the power of views to your Formidable Forms to display your form submissions in listings, tables, calendars, and more.',
378 ),
379 'quiz_maker' => array(
380 'title' => 'Quiz Maker',
381 'link' => 'downloads/quiz-maker/',
382 'excerpt' => 'Make quizzes, automatically score them and show user scores.',
383 ),
384 );
385
386 $defaults = array(
387 'released' => '',
388 );
389
390 foreach ( $list as $k => $info ) {
391 $info['slug'] = $k;
392 $list[ $k ] = array_merge( $defaults, $info );
393 }
394 return $list;
395 }
396
397 /**
398 * If Pro is missing but has been authenticated, include a download URL
399 *
400 * @since 3.04.03
401 * @return string
402 */
403 public static function get_pro_download_url() {
404 $license = self::get_pro_license();
405 $api = new FrmFormApi( $license );
406 $downloads = $api->get_api_info();
407 $pro = self::get_pro_from_addons( $downloads );
408
409 return isset( $pro['url'] ) ? $pro['url'] : '';
410 }
411
412 /**
413 * @since 4.08
414 */
415 public static function get_pro_license() {
416 $pro_cred_store = 'frmpro-credentials';
417 $pro_wpmu_store = 'frmpro-wpmu-sitewide';
418 if ( is_multisite() && get_site_option( $pro_wpmu_store ) ) {
419 $creds = get_site_option( $pro_cred_store );
420 } else {
421 $creds = get_option( $pro_cred_store );
422 }
423
424 if ( empty( $creds ) || ! is_array( $creds ) || ! isset( $creds['license'] ) ) {
425 return '';
426 }
427
428 $license = $creds['license'];
429 if ( empty( $license ) ) {
430 return '';
431 }
432
433 if ( strpos( $license, '-' ) ) {
434 // this is a fix for licenses saved in the past
435 $license = strtoupper( $license );
436 }
437 return $license;
438 }
439
440 /**
441 * @since 4.08
442 *
443 * @param array $addons
444 * @return array
445 */
446 protected static function get_pro_from_addons( $addons ) {
447 return isset( $addons['93790'] ) ? $addons['93790'] : array();
448 }
449
450 /**
451 * @since 4.06
452 */
453 public static function license_type() {
454 if ( is_callable( 'FrmProAddonsController::license_type' ) ) {
455 return FrmProAddonsController::license_type();
456 }
457
458 return 'free';
459 }
460
461 /**
462 * @since 4.0.01
463 *
464 * @return bool
465 */
466 public static function is_license_expired() {
467 $version_info = self::get_primary_license_info();
468 if ( ! isset( $version_info['error'] ) ) {
469 return false;
470 }
471
472 $expires = isset( $version_info['error']['expires'] ) ? $version_info['error']['expires'] : 0;
473 if ( empty( $expires ) || $expires > time() ) {
474 return false;
475 }
476
477 $rate_limited = ! empty( $version_info['response_code'] ) && 429 === (int) $version_info['response_code'];
478 if ( $rate_limited ) {
479 // Do not return false positives for rate limited responses.
480 return false;
481 }
482
483 return $version_info['error'];
484 }
485
486 /**
487 * @since 4.08
488 * @since 6.7 This is public.
489 *
490 * @return array|false
491 */
492 public static function get_primary_license_info() {
493 $installed_addons = apply_filters( 'frm_installed_addons', array() );
494 if ( empty( $installed_addons ) || ! isset( $installed_addons['formidable_pro'] ) ) {
495 return false;
496 }
497 $installed_addons = array(
498 'formidable_pro' => $installed_addons['formidable_pro'],
499 );
500
501 return self::fill_update_addon_info( $installed_addons );
502 }
503
504 /**
505 * @since 3.04.03
506 */
507 public static function check_update( $transient ) {
508 if ( ! FrmAppHelper::pro_is_installed() ) {
509 // Don't make any changes if only Lite is installed.
510 return $transient;
511 }
512
513 if ( ! is_object( $transient ) ) {
514 $transient = new stdClass();
515 }
516
517 $installed_addons = apply_filters( 'frm_installed_addons', array() );
518 if ( empty( $installed_addons ) ) {
519 return $transient;
520 }
521
522 $version_info = self::fill_update_addon_info( $installed_addons );
523 $transient->last_checked = time();
524 $wp_plugins = self::get_plugins();
525
526 foreach ( $version_info as $plugin ) {
527 $plugin = (object) $plugin;
528
529 if ( ! isset( $plugin->new_version ) || ! isset( $plugin->package ) ) {
530 continue;
531 }
532
533 $folder = $plugin->plugin;
534 if ( empty( $folder ) ) {
535 continue;
536 }
537
538 if ( ! self::is_installed( $folder ) ) {
539 // don't show an update if the plugin isn't installed
540 continue;
541 }
542
543 $wp_plugin = isset( $wp_plugins[ $folder ] ) ? $wp_plugins[ $folder ] : array();
544 $wp_version = isset( $wp_plugin['Version'] ) ? $wp_plugin['Version'] : '1.0';
545 $plugin->slug = explode( '/', $folder )[0];
546
547 if ( version_compare( $wp_version, $plugin->new_version, '<' ) ) {
548 $transient->response[ $folder ] = $plugin;
549 } else {
550 $transient->no_update[ $folder ] = $plugin;
551 }
552
553 $transient->checked[ $folder ] = $wp_version;
554
555 }//end foreach
556
557 return $transient;
558 }
559
560 /**
561 * Copy of FrmAppHelper::get_plugins.
562 * Because this gets called on "pre_set_site_transient_update_plugins" an old version of FrmAppHelper may be loaded on plugin update.
563 * This means that trying to access FrmAppHelper::get_plugins when upgrading from a Lite version before v5.5 results in a one-off error.
564 *
565 * @since 5.5.2
566 * @return array
567 */
568 protected static function get_plugins() {
569 if ( ! function_exists( 'get_plugins' ) ) {
570 require_once ABSPATH . 'wp-admin/includes/plugin.php';
571 }
572 return get_plugins();
573 }
574
575 /**
576 * Check if a plugin is installed before showing an update for it
577 *
578 * @since 3.05
579 *
580 * @param string $plugin The folder/filename.php for a plugin.
581 *
582 * @return bool - True if installed
583 */
584 protected static function is_installed( $plugin ) {
585 $all_plugins = self::get_plugins();
586 return isset( $all_plugins[ $plugin ] );
587 }
588
589 /**
590 * @since 3.04.03
591 *
592 * @param array $installed_addons
593 *
594 * @return array
595 */
596 protected static function fill_update_addon_info( $installed_addons ) {
597 $checked_licenses = array();
598 $version_info = array();
599
600 foreach ( $installed_addons as $addon ) {
601 if ( $addon->store_url !== 'https://formidableforms.com' ) {
602 // check if this is a third-party addon
603 continue;
604 }
605
606 $new_license = $addon->license;
607 if ( empty( $new_license ) || in_array( $new_license, $checked_licenses ) ) {
608 continue;
609 }
610
611 $checked_licenses[] = $new_license;
612
613 $api = new FrmFormApi( $new_license );
614 if ( empty( $version_info ) ) {
615 $version_info = $api->get_api_info();
616 continue;
617 }
618
619 $plugin = $api->get_addon_for_license( $addon, $version_info );
620 if ( empty( $plugin ) ) {
621 continue;
622 }
623
624 $download_id = isset( $plugin['id'] ) ? $plugin['id'] : 0;
625 if ( ! empty( $download_id ) && ! isset( $version_info[ $download_id ]['package'] ) ) {
626 // if this addon is using its own license, get the update url
627 $addon_info = $api->get_api_info();
628
629 $version_info[ $download_id ] = $addon_info[ $download_id ];
630 if ( isset( $addon_info['error'] ) ) {
631 $version_info[ $download_id ]['error'] = array(
632 'message' => $addon_info['error']['message'],
633 'code' => $addon_info['error']['code'],
634 );
635 }
636 }
637 }//end foreach
638
639 return $version_info;
640 }
641
642 /**
643 * Get the action link for an addon that isn't active.
644 *
645 * @since 3.06.03
646 * @param string $plugin The plugin slug.
647 * @return array
648 */
649 public static function install_link( $plugin ) {
650 $link = array();
651 $addon = self::get_addon( $plugin );
652
653 if ( $addon ) {
654 if ( $addon['status']['type'] === 'installed' && ! empty( $addon['activate_url'] ) ) {
655 $link = array(
656 'url' => $addon['plugin'],
657 'class' => 'frm-activate-addon',
658 );
659 } elseif ( ! empty( $addon['url'] ) ) {
660 $link = array(
661 'url' => $addon['url'],
662 'class' => 'frm-install-addon',
663 );
664 } elseif ( ! empty( $addon['categories'] ) ) {
665 $link = array(
666 'categories' => $addon['categories'],
667 );
668 }
669
670 if ( ! empty( $link ) ) {
671 $link['status'] = $addon['status']['type'];
672 }
673 } elseif ( current_user_can( 'activate_plugins' ) && self::is_installed( 'formidable-' . $plugin . '/formidable-' . $plugin . '.php' ) ) {
674 $link = array(
675 'url' => 'formidable-' . $plugin . '/formidable-' . $plugin . '.php',
676 'class' => 'frm-activate-addon',
677 );
678 }//end if
679
680 return $link;
681 }
682
683 /**
684 * @since 4.09
685 * @param string $plugin The plugin slug.
686 * @return array|false
687 */
688 public static function get_addon( $plugin ) {
689 $addons = self::get_api_addons();
690 self::prepare_addons( $addons );
691 foreach ( $addons as $addon ) {
692 $slug = explode( '/', $addon['plugin'] );
693 if ( $slug[0] === 'formidable-' . $plugin ) {
694 return $addon;
695 }
696 }
697 return false;
698 }
699
700 /**
701 * @since 4.09
702 * @return string
703 */
704 protected static function get_license_type() {
705 $license_type = '';
706 $addons = self::get_api_addons();
707 if ( isset( $addons['error'] ) && isset( $addons['error']['type'] ) ) {
708 $license_type = $addons['error']['type'];
709 }
710 return $license_type;
711 }
712
713 /**
714 * @since 3.04.03
715 *
716 * @param array $addons
717 * @param object $license The FrmAddon object.
718 *
719 * @return array
720 */
721 public static function get_addon_for_license( $addons, $license ) {
722 $download_id = $license->download_id;
723 $plugin = array();
724 if ( empty( $download_id ) && ! empty( $addons ) ) {
725 foreach ( $addons as $addon ) {
726 if ( strtolower( $license->plugin_name ) === strtolower( $addon['title'] ) ) {
727 return $addon;
728 }
729 }
730 } elseif ( isset( $addons[ $download_id ] ) ) {
731 $plugin = $addons[ $download_id ];
732 }
733
734 return $plugin;
735 }
736
737 /**
738 * @return void
739 */
740 protected static function prepare_addons( &$addons ) {
741 $activate_url = '';
742 if ( current_user_can( 'activate_plugins' ) ) {
743 $activate_url = add_query_arg( array( 'action' => 'activate' ), admin_url( 'plugins.php' ) );
744 }
745
746 $loop_addons = $addons;
747 foreach ( $loop_addons as $id => $addon ) {
748 if ( is_numeric( $id ) ) {
749 $slug = str_replace( array( '-wordpress-plugin', '-wordpress' ), '', $addon['slug'] );
750 $file_name = $addon['plugin'];
751 } else {
752 $slug = $id;
753 if ( isset( $addon['file'] ) ) {
754 $base_file = $addon['file'];
755 } else {
756 $base_file = 'formidable-' . $slug;
757 }
758 $file_name = $base_file . '/' . $base_file . '.php';
759 if ( ! isset( $addon['plugin'] ) ) {
760 $addon['plugin'] = $file_name;
761 }
762 }
763
764 $addon['installed'] = self::is_installed( $file_name );
765 if ( $addon['installed'] && 'formidable-views/formidable-views.php' === $file_name ) {
766 $active_views_version = self::get_active_views_version();
767 if ( false !== $active_views_version && $slug !== $active_views_version ) {
768 $addon['installed'] = false;
769 }
770 }
771
772 $addon['activate_url'] = '';
773
774 if ( $addon['installed'] && ! empty( $activate_url ) && ! self::is_plugin_active( $file_name, $slug ) ) {
775 $addon['activate_url'] = add_query_arg(
776 array(
777 '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $file_name ),
778 'plugin' => $file_name,
779 ),
780 $activate_url
781 );
782 }
783
784 if ( ! isset( $addon['docs'] ) ) {
785 $addon['docs'] = 'knowledgebase/formidable-' . $slug . '/';
786 }
787 self::prepare_addon_link( $addon['docs'] );
788
789 if ( ! isset( $addon['link'] ) ) {
790 $addon['link'] = 'downloads/' . $slug . '/';
791 }
792
793 self::prepare_addon_link( $addon['link'] );
794 self::set_addon_status( $addon );
795 self::set_categories( $addon );
796
797 $addons[ $id ] = $addon;
798 }//end foreach
799 }
800
801 /**
802 * @return bool
803 */
804 private static function is_plugin_active( $file_name, $slug ) {
805 if ( 'formidable-views/formidable-views.php' === $file_name ) {
806 return self::get_active_views_version() === $slug;
807 }
808 return is_plugin_active( $file_name );
809 }
810
811 /**
812 * @return false|string either 'visual-views' or 'views', false if one is not found.
813 */
814 private static function get_active_views_version() {
815 if ( ! is_callable( 'FrmViewsAppHelper::plugin_version' ) ) {
816 return false;
817 }
818 $plugin_version = FrmViewsAppHelper::plugin_version();
819 return version_compare( $plugin_version, '5.0', '>=' ) ? 'visual-views' : 'views';
820 }
821
822 /**
823 * @since 3.04.02
824 *
825 * @return void
826 */
827 protected static function prepare_addon_link( &$link ) {
828 $site_url = 'https://formidableforms.com/';
829 if ( strpos( $link, 'http' ) !== 0 ) {
830 $link = $site_url . $link;
831 }
832 $link = FrmAppHelper::make_affiliate_url( $link );
833 $query_args = array(
834 'utm_source' => 'WordPress',
835 'utm_medium' => 'addons',
836 'utm_campaign' => 'liteplugin',
837 );
838 $link = add_query_arg( $query_args, $link );
839 }
840
841 /**
842 * Add the status to the addon array. Status options are:
843 * installed, active, not installed
844 *
845 * @since 3.04.02
846 *
847 * @return void
848 */
849 protected static function set_addon_status( &$addon ) {
850 if ( ! empty( $addon['activate_url'] ) ) {
851 $addon['status'] = array(
852 'type' => 'installed',
853 'label' => __( 'Installed', 'formidable' ),
854 );
855 } elseif ( $addon['installed'] ) {
856 $addon['status'] = array(
857 'type' => 'active',
858 'label' => __( 'Active', 'formidable' ),
859 );
860 } else {
861 $addon['status'] = array(
862 'type' => 'not-installed',
863 'label' => __( 'Not Installed', 'formidable' ),
864 );
865 }
866 }
867
868 /**
869 * @return void
870 */
871 public static function upgrade_to_pro() {
872 FrmAppHelper::include_svg();
873
874 $link_parts = array(
875 'medium' => 'upgrade',
876 'content' => 'button',
877 );
878
879 $features = array(
880 'Display Entries' => array(
881 array(
882 'label' => 'Display form data with virtually limitless views',
883 'link' => array(
884 'content' => 'views',
885 'param' => 'views-display-form-data',
886 ),
887 'lite' => false,
888 ),
889 array(
890 'label' => 'Generate graphs and stats based on your submitted data',
891 'link' => array(
892 'content' => 'graphs',
893 'param' => 'statistics-graphs-wordpress-forms',
894 ),
895 'lite' => false,
896 ),
897 ),
898 'Entry Management' => array(
899 array(
900 'label' => 'Import entries from a CSV',
901 'link' => array(
902 'content' => 'import-entries',
903 'param' => 'importing-exporting-wordpress-forms',
904 ),
905 'lite' => false,
906 ),
907 array(
908 'label' => 'Logged-in users can save drafts and return later',
909 'link' => array(
910 'content' => 'save-drafts',
911 'param' => 'save-drafts-wordpress-form',
912 ),
913 'lite' => false,
914 ),
915 array(
916 'label' => 'Flexibly and powerfully view, edit, and delete entries from anywhere on your site',
917 'link' => array(
918 'content' => 'front-edit',
919 'param' => 'wordpress-front-end-editing',
920 ),
921 'lite' => false,
922 ),
923 array(
924 'label' => 'View form submissions from the back-end',
925 'lite' => true,
926 ),
927 array(
928 'label' => 'Export your entries to a CSV',
929 'lite' => true,
930 ),
931 ),
932 'Form Building' => array(
933 array(
934 'label' => 'Save a calculated value into a field',
935 'link' => array(
936 'content' => 'calculations',
937 'param' => 'field-calculations-wordpress-form',
938 ),
939 'lite' => false,
940 ),
941 array(
942 'label' => 'Allow multiple file uploads',
943 'link' => array(
944 'content' => 'file-uploads',
945 'param' => 'wordpress-multi-file-upload-fields',
946 ),
947 'lite' => false,
948 ),
949 array(
950 'label' => 'Repeat sections of fields',
951 'link' => array(
952 'content' => 'repeaters',
953 'param' => 'repeatable-sections-forms',
954 ),
955 'lite' => false,
956 ),
957 array(
958 'label' => 'Hide and show fields conditionally based on other fields or the user\'s role',
959 'link' => array(
960 'content' => 'conditional-logic',
961 'param' => 'conditional-logic-wordpress-forms',
962 ),
963 'lite' => false,
964 ),
965 array(
966 'label' => 'Confirmation fields',
967 'link' => array(
968 'content' => 'confirmation-fields',
969 'param' => 'confirmation-fields-wordpress-forms',
970 ),
971 'lite' => false,
972 ),
973 array(
974 'label' => 'Multi-paged forms',
975 'link' => array(
976 'content' => 'page-breaks',
977 'param' => 'wordpress-multi-page-forms',
978 ),
979 'lite' => false,
980 ),
981 array(
982 'label' => 'Include section headings, page breaks, rich text, dates, times, scales, star ratings, sliders, toggles, dynamic fields populated from other forms, passwords, and tags in advanced forms.',
983 'lite' => false,
984 ),
985 array(
986 'label' => 'Include text, email, url, paragraph text, radio, checkbox, dropdown fields, hidden fields, user ID fields, and HTML blocks in your form.',
987 'lite' => true,
988 ),
989 array(
990 'label' => 'Drag & Drop Form building',
991 'link' => array(
992 'content' => 'drag-drop',
993 'param' => 'drag-drop-forms',
994 ),
995 'lite' => true,
996 ),
997 array(
998 'label' => 'Create forms from Templates',
999 'link' => array(
1000 'content' => 'form-templates',
1001 'param' => 'wordpress-form-templates',
1002 ),
1003 'lite' => true,
1004 ),
1005 array(
1006 'label' => 'Import and export forms with XML',
1007 'link' => array(
1008 'content' => 'import',
1009 'param' => 'importing-exporting-wordpress-forms',
1010 ),
1011 'lite' => true,
1012 ),
1013 array(
1014 'label' => 'Use input placeholder text in your fields that clear when typing starts.',
1015 'lite' => true,
1016 ),
1017 ),
1018 'Form Actions' => array(
1019 array(
1020 'label' => 'Conditionally send your email notifications based on values in your form',
1021 'link' => array(
1022 'content' => 'conditional-emails',
1023 ),
1024 'lite' => false,
1025 ),
1026 array(
1027 'label' => 'Create and edit WordPress posts or custom posts from the front-end',
1028 'link' => array(
1029 'content' => 'create-posts',
1030 'param' => 'create-posts-pages-wordpress-forms',
1031 ),
1032 'lite' => false,
1033 ),
1034 array(
1035 'label' => 'Send multiple emails and autoresponders',
1036 'link' => array(
1037 'content' => 'multiple-emails',
1038 'param' => 'virtually-unlimited-emails',
1039 ),
1040 'lite' => true,
1041 ),
1042 ),
1043 'Form Appearance' => array(
1044 array(
1045 'label' => 'Create Multiple styles for different forms',
1046 'link' => array(
1047 'content' => 'multiple-styles',
1048 'param' => 'wordpress-visual-form-styler',
1049 ),
1050 'lite' => false,
1051 ),
1052 array(
1053 'label' => 'Customizable layout with CSS classes',
1054 'link' => array(
1055 'content' => 'form-layout',
1056 'param' => 'wordpress-mobile-friendly-forms',
1057 ),
1058 'lite' => true,
1059 ),
1060 array(
1061 'label' => 'Customize the HTML for your forms',
1062 'link' => array(
1063 'content' => 'custom-html',
1064 'param' => 'customizable-html-wordpress-form',
1065 ),
1066 'lite' => true,
1067 ),
1068 array(
1069 'label' => 'Style your form with the Visual Form Styler',
1070 'lite' => true,
1071 ),
1072 ),
1073 );
1074
1075 include FrmAppHelper::plugin_path() . '/classes/views/addons/upgrade_to_pro.php';
1076 }
1077
1078 /**
1079 * @since 5.5.2
1080 *
1081 * @param string $plugin
1082 * @param string $redirect
1083 * @param bool $network_wide
1084 * @param bool $silent
1085 * @return WP_Error|null Null on success, WP_Error on invalid file.
1086 */
1087 protected static function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) {
1088 if ( ! function_exists( 'activate_plugin' ) ) {
1089 require_once ABSPATH . 'wp-admin/includes/plugin.php';
1090 }
1091 return activate_plugin( $plugin, $redirect, $network_wide, $silent );
1092 }
1093
1094 /**
1095 * Deactivate a specified plugin.
1096 *
1097 * @since 6.8
1098 *
1099 * @param string $plugin
1100 * @param bool $silent
1101 * @return void
1102 */
1103 protected static function deactivate_plugin( $plugin, $silent = false ) {
1104 if ( ! function_exists( 'deactivate_plugins' ) ) {
1105 require_once ABSPATH . 'wp-admin/includes/plugin.php';
1106 }
1107 deactivate_plugins( $plugin, $silent );
1108 }
1109
1110 /**
1111 * Uninstall a specified plugin.
1112 *
1113 * @since 6.8
1114 *
1115 * @param string $plugin
1116 * @return true|WP_Error True on success, WP_Error on invalid file.
1117 */
1118 protected static function uninstall_plugin( $plugin ) {
1119 if ( ! current_user_can( 'delete_plugins' ) ) {
1120 return new WP_Error( 'uninstall_failed', __( 'Current user cannot delete plugins.', 'formidable' ) );
1121 }
1122
1123 if ( ! function_exists( 'delete_plugins' ) ) {
1124 require_once ABSPATH . 'wp-admin/includes/plugin.php';
1125 }
1126
1127 self::deactivate_plugin( $plugin, true );
1128 $result = delete_plugins( array( $plugin ) );
1129
1130 if ( is_wp_error( $result ) ) {
1131 return $result;
1132 }
1133
1134 return true;
1135 }
1136
1137 /**
1138 * @since 5.0.10
1139 *
1140 * @return string
1141 */
1142 protected static function get_current_plugin() {
1143 if ( empty( self::$plugin ) ) {
1144 self::$plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'esc_url_raw' );
1145 }
1146 return self::$plugin;
1147 }
1148
1149 /**
1150 * @since 4.08
1151 *
1152 * @return array|void
1153 */
1154 protected static function download_and_activate() {
1155 if ( is_admin() ) {
1156 FrmAppHelper::set_current_screen_and_hook_suffix();
1157 }
1158
1159 self::maybe_show_cred_form();
1160
1161 $installed = self::install_addon();
1162 if ( is_array( $installed ) && isset( $installed['message'] ) ) {
1163 return $installed;
1164 }
1165 self::handle_addon_action( $installed, 'activate' );
1166 }
1167
1168 /**
1169 * @since 3.04.02
1170 *
1171 * @return void
1172 */
1173 protected static function maybe_show_cred_form() {
1174 if ( ! function_exists( 'request_filesystem_credentials' ) ) {
1175 include_once ABSPATH . 'wp-admin/includes/file.php';
1176 }
1177
1178 // Start output bufferring to catch the filesystem form if credentials are needed.
1179 ob_start();
1180
1181 $show_form = false;
1182 $method = '';
1183 $url = add_query_arg( array( 'page' => 'formidable-settings' ), admin_url( 'admin.php' ) );
1184 $url = esc_url_raw( $url );
1185 $creds = request_filesystem_credentials( $url, $method, false, false, null );
1186
1187 if ( false === $creds ) {
1188 $show_form = true;
1189 } elseif ( ! WP_Filesystem( $creds ) ) {
1190 request_filesystem_credentials( $url, $method, true, false, null );
1191 $show_form = true;
1192 }
1193
1194 if ( $show_form ) {
1195 $form = ob_get_clean();
1196 $message = __( 'Sorry, your site requires FTP authentication. Please download plugins from FormidableForms.com and install them manually.', 'formidable' );
1197 $data = $form;
1198 $response = array(
1199 'success' => false,
1200 'message' => $message,
1201 'form' => $form,
1202 );
1203 wp_send_json( $response );
1204 }
1205
1206 ob_end_clean();
1207 }
1208
1209 /**
1210 * Checks if an addon download url is allowed.
1211 *
1212 * @since 6.2
1213 *
1214 * @param string $download_url
1215 *
1216 * @return bool
1217 */
1218 public static function url_is_allowed( $download_url ) {
1219 return FrmAppHelper::validate_url_is_in_s3_bucket( $download_url, 'zip' ) || in_array( $download_url, self::allowed_external_urls(), true );
1220 }
1221
1222 /**
1223 * We do not need any extra credentials if we have gotten this far,
1224 * so let's install the plugin.
1225 *
1226 * @since 3.04.02
1227 */
1228 protected static function install_addon() {
1229 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
1230
1231 $download_url = self::get_current_plugin();
1232
1233 if ( ! self::url_is_allowed( $download_url ) ) {
1234 return array(
1235 'message' => 'Plugin URL is not valid',
1236 'success' => false,
1237 );
1238 }
1239
1240 // Create the plugin upgrader with our custom skin.
1241 $installer = new Plugin_Upgrader( new FrmInstallerSkin() );
1242 $installer->install( $download_url );
1243
1244 // Flush the cache and return the newly installed plugin basename.
1245 wp_cache_flush();
1246
1247 $plugin = $installer->plugin_info();
1248 if ( ! $plugin ) {
1249 return array(
1250 'message' => 'Plugin was not installed. ' . $installer->result,
1251 'success' => false,
1252 );
1253 }
1254 return $plugin;
1255 }
1256
1257 /**
1258 * Handle the AJAX request to activate an add-on.
1259 *
1260 * @since 6.8
1261 *
1262 * @return void
1263 */
1264 public static function ajax_activate_addon() {
1265 self::process_addon_action(
1266 function ( $plugin ) {
1267 return self::handle_addon_action( $plugin, 'activate' );
1268 },
1269 array( 'FrmAddonsController', 'get_addon_activation_response' )
1270 );
1271 }
1272
1273 /**
1274 * @since 3.04.02
1275 *
1276 * @param string $installed The plugin folder name with file name.
1277 */
1278 protected static function maybe_activate_addon( $installed ) {
1279 self::ajax_activate_addon();
1280 }
1281
1282 /**
1283 * Handle the AJAX request to deactivate an add-on.
1284 *
1285 * @since 6.8
1286 *
1287 * @return void
1288 */
1289 public static function ajax_deactivate_addon() {
1290 self::process_addon_action(
1291 function ( $plugin ) {
1292 return self::handle_addon_action( $plugin, 'deactivate' );
1293 }
1294 );
1295 }
1296
1297 /**
1298 * Handle the AJAX request to uninstall an add-on.
1299 *
1300 * @since 6.8
1301 *
1302 * @return void
1303 */
1304 public static function ajax_uninstall_addon() {
1305 self::process_addon_action(
1306 function ( $plugin ) {
1307 return self::handle_addon_action( $plugin, 'uninstall' );
1308 }
1309 );
1310 }
1311
1312 /**
1313 * Process a specific action (activate, deactivate, uninstall) on an add-on.
1314 *
1315 * @since 6.8
1316 *
1317 * @param callable $action_callback The specific add-on action to be executed.
1318 * @param callable|null $response_callback Optional. The response handling callback. Default null.
1319 * @return void
1320 */
1321 private static function process_addon_action( $action_callback, $response_callback = null ) {
1322 self::install_addon_permissions();
1323 FrmAppHelper::set_current_screen_and_hook_suffix();
1324
1325 $plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
1326 call_user_func( $action_callback, $plugin );
1327
1328 if ( is_callable( $response_callback ) ) {
1329 wp_send_json_success( call_user_func( $response_callback ) );
1330 return;
1331 }
1332
1333 wp_send_json_success();
1334 }
1335
1336 /**
1337 * Attempt to perform a specific action (activate, deactivate, uninstall) on an add-on.
1338 *
1339 * @since 6.8
1340 *
1341 * @param string $installed The plugin folder name with file name.
1342 * @param string $action The action type ('activate', 'deactivate', 'uninstall').
1343 * @return array|void
1344 */
1345 protected static function handle_addon_action( $installed, $action ) {
1346 if ( ! $installed || ! $action ) {
1347 return;
1348 }
1349
1350 $result = null;
1351 switch ( $action ) {
1352 case 'activate':
1353 $result = self::activate_plugin( $installed );
1354 break;
1355 case 'deactivate':
1356 self::deactivate_plugin( $installed );
1357 break;
1358 case 'uninstall':
1359 $result = self::uninstall_plugin( $installed );
1360 break;
1361 }
1362
1363 if ( is_wp_error( $result ) ) {
1364 // Ignore the invalid header message that shows with nested plugins.
1365 if ( $result->get_error_code() !== 'no_plugin_header' ) {
1366 if ( wp_doing_ajax() ) {
1367 wp_send_json_error( array( 'error' => $result->get_error_message() ) );
1368 }
1369 return array(
1370 'message' => $result->get_error_message(),
1371 'success' => false,
1372 );
1373 }
1374 }
1375
1376 return $result;
1377 }
1378
1379 /**
1380 * @return array
1381 */
1382 private static function get_addon_activation_response() {
1383 $activating_page = self::get_activating_page();
1384
1385 $message = $activating_page ? __( 'Your plugin has been activated. Would you like to save and reload the page now?', 'formidable' ) : __( 'Your plugin has been activated.', 'formidable' );
1386
1387 $response = array(
1388 'message' => $message,
1389 'saveAndReload' => $activating_page,
1390 );
1391
1392 return $response;
1393 }
1394
1395 /**
1396 * Return a string that reflects the page from which the addon is being activated on,
1397 * if it is from settings or form builder, otherwise return empty string.
1398 *
1399 * @return string
1400 */
1401 private static function get_activating_page() {
1402 $referer = FrmAppHelper::get_server_value( 'HTTP_REFERER' );
1403 if ( false !== strpos( $referer, 'frm_action=settings' ) ) {
1404 return 'settings';
1405 }
1406
1407 if ( false !== strpos( $referer, 'frm_action=edit' ) ) {
1408 return 'form_builder';
1409 }
1410
1411 return '';
1412 }
1413
1414 /**
1415 * Run security checks before installing
1416 *
1417 * @since 3.04.02
1418 *
1419 * @return void
1420 */
1421 protected static function install_addon_permissions() {
1422 check_ajax_referer( 'frm_ajax', 'nonce' );
1423
1424 if ( ! current_user_can( 'activate_plugins' ) || ! self::get_current_plugin() ) {
1425 echo json_encode( true );
1426 wp_die();
1427 }
1428 }
1429
1430 /**
1431 * @since 4.08
1432 *
1433 * @return string
1434 */
1435 public static function connect_link() {
1436 $auth = get_option( 'frm_connect_token' );
1437 if ( empty( $auth ) ) {
1438 $auth = hash( 'sha512', wp_rand() );
1439 update_option( 'frm_connect_token', $auth, 'no' );
1440 }
1441 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title', 'formidable-settings' );
1442 $link = 'https://formidableforms.com/api-connect/';
1443 $args = array(
1444 'v' => 2,
1445 'siteurl' => FrmAppHelper::site_url(),
1446 'url' => get_rest_url(),
1447 'inst' => (int) FrmAppHelper::pro_is_included(),
1448 'return' => $page,
1449 'token' => $auth,
1450 'l' => self::get_pro_license(),
1451 );
1452
1453 return add_query_arg( $args, $link );
1454 }
1455
1456 /**
1457 * Check the auth value for install permission.
1458 *
1459 * @since 4.08
1460 *
1461 * @return bool
1462 */
1463 public static function can_install_addon_api() {
1464 // Verify params present (auth & download link).
1465 $post_auth = FrmAppHelper::get_param( 'token', '', 'request', 'sanitize_text_field' );
1466 $post_url = FrmAppHelper::get_param( 'file_url', '', 'request', 'sanitize_text_field' );
1467
1468 // The download link is not required if already installed.
1469 $is_installed = FrmAppHelper::pro_is_included();
1470 $file_missing = ! $is_installed && empty( $post_url );
1471 if ( ! $post_auth || $file_missing ) {
1472 return false;
1473 }
1474
1475 // Verify auth.
1476 $auth = get_option( 'frm_connect_token' );
1477 if ( empty( $auth ) || ! hash_equals( $auth, $post_auth ) ) {
1478 return false;
1479 }
1480
1481 return true;
1482 }
1483
1484 /**
1485 * Install and/or activate the add-on file.
1486 *
1487 * @since 4.08
1488 *
1489 * @return array
1490 */
1491 public static function install_addon_api() {
1492 self::$plugin = FrmAppHelper::get_param( 'file_url', '', 'request', 'esc_url_raw' );
1493
1494 $error = esc_html__( 'Could not install an upgrade. Please download from formidableforms.com and install manually.', 'formidable' );
1495
1496 // Delete so cannot replay.
1497 delete_option( 'frm_connect_token' );
1498
1499 // It's already installed and active.
1500 $active = self::activate_plugin( 'formidable-pro/formidable-pro.php', false, false, true );
1501 if ( is_wp_error( $active ) ) {
1502 $response = self::maybe_download_and_activate();
1503 if ( is_array( $response ) ) {
1504 // The download failed.
1505 return $response;
1506 }
1507 }
1508
1509 // If empty license, save it now.
1510 if ( empty( self::get_pro_license() ) && function_exists( 'load_formidable_pro' ) ) {
1511 load_formidable_pro();
1512 $license = stripslashes( FrmAppHelper::get_param( 'key', '', 'request', 'sanitize_text_field' ) );
1513 if ( ! $license ) {
1514 return array(
1515 'success' => false,
1516 'error' => 'That site does not have a valid license key.',
1517 );
1518 }
1519
1520 $response = FrmAddon::activate_license_for_plugin( $license, 'formidable_pro' );
1521 if ( ! $response['success'] ) {
1522 // Could not activate license.
1523 return $response;
1524 }
1525 }
1526
1527 return array(
1528 'success' => true,
1529 );
1530 }
1531
1532 /**
1533 * @since 6.8.3
1534 *
1535 * @return array|true
1536 */
1537 private static function maybe_download_and_activate() {
1538 if ( ! self::$plugin ) {
1539 return array(
1540 'success' => false,
1541 'message' => __( 'The plugin download was not found.', 'formidable' ),
1542 );
1543 }
1544
1545 // Download plugin now.
1546 $response = self::download_and_activate();
1547 if ( is_array( $response ) && isset( $response['success'] ) ) {
1548 // The download failed.
1549 return $response;
1550 }
1551
1552 return true;
1553 }
1554
1555 /**
1556 * Render a conditional action button for a specified plugin
1557 *
1558 * @since 4.09
1559 *
1560 * @param string $plugin
1561 * @param array|string $upgrade_link_args
1562 * @return void
1563 */
1564 public static function conditional_action_button( $plugin, $upgrade_link_args ) {
1565 if ( is_callable( 'FrmProAddonsController::conditional_action_button' ) ) {
1566 FrmProAddonsController::conditional_action_button( $plugin, $upgrade_link_args );
1567 return;
1568 }
1569
1570 $addon = self::get_addon( $plugin );
1571 $upgrade_link = FrmAppHelper::admin_upgrade_link( $upgrade_link_args );
1572
1573 if ( ! is_array( $upgrade_link_args ) ) {
1574 // A string $upgrade_link_args is used for the utm-medium value when calling
1575 // FrmAppHelper::admin_upgrade_link above.
1576 // For self::addon_upgrade_link, we'll pass just an empty array with the link key (set below).
1577 $upgrade_link_args = array();
1578 }
1579
1580 $upgrade_link_args['link'] = $upgrade_link;
1581
1582 self::addon_upgrade_link( $addon, $upgrade_link_args );
1583 }
1584
1585 /**
1586 * Render a conditional action button for an add on
1587 *
1588 * @since 4.09.01
1589 *
1590 * @param array $atts {
1591 * Button attributes.
1592 *
1593 * @type array $addon
1594 * @type false|string $license_type
1595 * @type string $plan_required
1596 * @type string $upgrade_link
1597 * }
1598 * @return void
1599 */
1600 public static function show_conditional_action_button( $atts ) {
1601 if ( is_callable( 'FrmProAddonsController::show_conditional_action_button' ) ) {
1602 FrmProAddonsController::show_conditional_action_button( $atts );
1603 return;
1604 }
1605
1606 self::addon_upgrade_link( $atts['addon'], $atts['upgrade_link'] );
1607 }
1608
1609 /**
1610 * @since 4.09.01
1611 *
1612 * @param array|false $addon
1613 * @param array|string $upgrade_link
1614 *
1615 * @return void
1616 */
1617 public static function addon_upgrade_link( $addon, $upgrade_link ) {
1618 $atts = is_array( $upgrade_link ) ? $upgrade_link : array();
1619 $upgrade_link = is_array( $upgrade_link ) ? $upgrade_link['link'] : $upgrade_link;
1620
1621 if ( $addon ) {
1622 $upgrade_link .= '&utm_content=' . $addon['slug'];
1623 }
1624
1625 if ( $addon && isset( $addon['categories'] ) && in_array( 'Solution', $addon['categories'], true ) ) {
1626 // Solutions will go to a separate page.
1627 $upgrade_link = FrmAppHelper::admin_upgrade_link( 'addons', $addon['link'] );
1628 }
1629
1630 $class = ! empty( $atts['class'] ) ? $atts['class'] : '';
1631 if ( strpos( $class, 'frm-button' ) === false ) {
1632 $class .= ' frm-button-secondary frm-button-sm';
1633 }
1634 ?>
1635 <a class="install-now button <?php echo esc_attr( $class ); ?>" href="<?php echo esc_url( $upgrade_link ); ?>" target="_blank" rel="noopener" aria-label="<?php esc_attr_e( 'Upgrade Now', 'formidable' ); ?>">
1636 <?php esc_html_e( 'Upgrade Now', 'formidable' ); ?>
1637 </a>
1638 <?php
1639 }
1640
1641 /**
1642 * @since 3.04.02
1643 *
1644 * @return void
1645 */
1646 public static function ajax_install_addon() {
1647 self::install_addon_permissions();
1648
1649 $result = self::download_and_activate();
1650 if ( isset( $result['success'] ) && ! $result['success'] ) {
1651 echo json_encode( $result );
1652 wp_die();
1653 }
1654
1655 echo json_encode( self::get_addon_activation_response() );
1656 wp_die();
1657 }
1658
1659 /**
1660 * Allowed URLs used for internal source of plugins installation.
1661 *
1662 * @since 6.3.1
1663 *
1664 * @return array
1665 */
1666 private static function allowed_external_urls() {
1667 $allowed_url_list = array(
1668 'https://downloads.wordpress.org/plugin/formidable-gravity-forms-importer.zip',
1669 'https://downloads.wordpress.org/plugin/formidable-import-pirate-forms.zip',
1670 'https://downloads.wordpress.org/plugin/wp-mail-smtp.zip',
1671 );
1672
1673 /**
1674 * List of URLs used in plugin formidable internal installation.
1675 *
1676 * @since 6.3.1
1677 *
1678 * @param array $allowed_url_list List of URLs.
1679 */
1680 $allowed_url_list = apply_filters( 'frm_allowed_external_urls', $allowed_url_list );
1681
1682 if ( ! is_array( $allowed_url_list ) ) {
1683 _doing_it_wrong( __METHOD__, 'Only an array of URLs could be used within this filter.', '6.3.1' );
1684
1685 return array();
1686 }
1687
1688 return $allowed_url_list;
1689 }
1690
1691 /**
1692 * Gets required plan for an addon.
1693 *
1694 * @since 6.4.2
1695 *
1696 * @return string Empty string if no plan is required for active license.
1697 */
1698 public static function get_addon_required_plan( $addon_id ) {
1699 $api = new FrmFormApi();
1700 $addons = $api->get_api_info();
1701
1702 if ( is_array( $addons ) && array_key_exists( $addon_id, $addons ) ) {
1703 $dates = $addons[ $addon_id ];
1704 $requires = FrmFormsHelper::get_plan_required( $dates );
1705 }
1706
1707 if ( ! isset( $requires ) || ! is_string( $requires ) ) {
1708 $requires = '';
1709 }
1710
1711 return $requires;
1712 }
1713
1714 /**
1715 * @since 4.02.05
1716 * @deprecated 6.8.3
1717 *
1718 * @codeCoverageIgnore
1719 *
1720 * @return void
1721 */
1722 public static function connect_pro() {
1723 _deprecated_function( __METHOD__, '6.8.3' );
1724 }
1725
1726 /**
1727 * @since 4.08
1728 * @deprecated 6.11.1
1729 *
1730 * @return bool|int false or the number of days until expiration.
1731 */
1732 public static function is_license_expiring() {
1733 _deprecated_function( __METHOD__, '6.11.1', 'FrmProAddonsController::is_license_expiring' );
1734
1735 if ( is_callable( 'FrmProAddonsController::is_license_expiring' ) ) {
1736 return FrmProAddonsController::is_license_expiring();
1737 }
1738
1739 return false;
1740 }
1741 }
1742