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

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