PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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
← All changes | classes/controllers/FrmAddonsController.php +347 -113 6.25 → trunk View file →
@@ -26,19 +26,23 @@
26 26 protected static $plugin;
27 27
28 28 /**
29 29 * @since 6.15
30 + *
31 + * @return void
30 32 */
31 33 public static function load_admin_hooks() {
32 34 add_action( 'admin_menu', self::class . '::menu', 100 );
33 35 add_filter( 'pre_set_site_transient_update_plugins', self::class . '::check_update' );
34 36
35 - if ( FrmAppHelper::is_admin_page( 'formidable-addons' ) ) {
36 - self::$request_addon_url = 'https://connect.formidableforms.com/add-on-request/';
37 + if ( ! FrmAppHelper::is_admin_page( 'formidable-addons' ) ) {
38 + return;
39 + }
37 40
38 - add_action( 'admin_enqueue_scripts', self::class . '::enqueue_assets', 15 );
39 - add_filter( 'frm_show_footer_links', '__return_false' );
40 - }
41 + self::$request_addon_url = 'https://connect.formidableforms.com/add-on-request/';
42 +
43 + add_action( 'admin_enqueue_scripts', self::class . '::enqueue_assets', 15 );
44 + add_filter( 'frm_show_footer_links', '__return_false' );
41 45 }
42 46
43 47 /**
44 48 * Enqueues the Add-Ons page scripts and styles.
@@ -100,13 +104,14 @@
100 104 $label = '<span style="color:#3FCA89">' . esc_html( $label ) . '</span>';
101 105
102 106 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Add-Ons', 'formidable' ), $label, 'frm_view_forms', 'formidable-addons', 'FrmAddonsController::list_addons' );
103 107
104 - // remove default created subpage, make the page with highest priority as default.
108 + // Remove default created subpage, make the page with highest priority as default.
105 109 remove_submenu_page( 'formidable', 'formidable' );
106 110
107 111 if ( ! FrmAppHelper::pro_is_installed() ) {
108 112 $cta_text = FrmSalesApi::get_best_sale_value( 'menu_cta_text' );
113 +
109 114 if ( ! $cta_text ) {
110 115 $cta_text = __( 'Upgrade', 'formidable' );
111 116 }
112 117
@@ -151,9 +156,10 @@
151 156 'pro' => array(
152 157 'title' => 'Formidable Forms Pro',
153 158 'slug' => 'formidable-pro',
154 159 'released' => '2011-02-05',
155 - 'docs' => 'knowledgebase/',
160 + 'docs' => 'knowledgebase/what-is-the-difference-between-the-lite-free-and-pro-version/',
161 + 'docs_label' => __( 'Why Upgrade', 'formidable' ),
156 162 'categories' => array( 'basic', 'plus', 'business', 'elite' ),
157 163 'excerpt' => 'Create calculators, surveys, smart forms, and data-driven applications. Build directories, real estate listings, job boards, and much more.',
158 164 ),
159 165 );
@@ -188,15 +194,18 @@
188 194 );
189 195
190 196 // Extract the elements to move
191 197 foreach ( $plans as $plan ) {
192 - if ( isset( self::$categories[ $plan ] ) ) {
193 - $bottom_categories[ $plan ] = self::$categories[ $plan ];
194 - unset( self::$categories[ $plan ] );
198 + if ( ! isset( self::$categories[ $plan ] ) ) {
199 + continue;
195 200 }
201 +
202 + $bottom_categories[ $plan ] = self::$categories[ $plan ];
203 + unset( self::$categories[ $plan ] );
196 204 }
197 205
198 206 $special_categories = array();
207 +
199 208 if ( 'elite' !== self::license_type() ) {
200 209 $special_categories['available-addons'] = array(
201 210 'name' => __( 'Available', 'formidable' ),
202 211 // To be assigned via JavaScript.
@@ -228,8 +237,9 @@
228 237 *
229 238 * @since 6.15
230 239 *
231 240 * @param array $addon The addon array that will be modified by reference.
241 + *
232 242 * @return void
233 243 */
234 244 protected static function set_categories( &$addon ) {
235 245 if ( ! isset( $addon['categories'] ) ) {
@@ -260,11 +270,11 @@
260 270 * @return void
261 271 */
262 272 public static function license_settings() {
263 273 $plugins = apply_filters( 'frm_installed_addons', array() );
264 - if ( empty( $plugins ) ) {
274 +
275 + if ( ! $plugins ) {
265 276 esc_html_e( 'There are no plugins on your site that require a license', 'formidable' );
266 -
267 277 return;
268 278 }
269 279
270 280 ksort( $plugins );
@@ -278,15 +288,15 @@
278 288 protected static function get_api_addons() {
279 289 $api = new FrmFormApi();
280 290 $addons = $api->get_api_info();
281 291
282 - if ( empty( $addons ) ) {
283 - $addons = self::fallback_plugin_list();
284 - } else {
285 - foreach ( $addons as $k => $addon ) {
286 - if ( empty( $addon['excerpt'] ) && $k !== 'error' ) {
287 - unset( $addons[ $k ] );
288 - }
292 + if ( ! $addons ) {
293 + return self::fallback_plugin_list();
294 + }
295 +
296 + foreach ( $addons as $k => $addon ) {
297 + if ( empty( $addon['excerpt'] ) && $k !== 'error' ) {
298 + unset( $addons[ $k ] );
289 299 }
290 300 }
291 301
292 302 return $addons;
@@ -299,11 +309,9 @@
299 309 *
300 310 * @return int Count of addons.
301 311 */
302 312 public static function get_addons_count() {
303 - $addons = self::get_api_addons();
304 -
305 - return count( $addons );
313 + return count( self::get_api_addons() );
306 314 }
307 315
308 316 /**
309 317 * If the API is unable to connect, show something on the addons page
@@ -308,8 +316,9 @@
308 316 /**
309 317 * If the API is unable to connect, show something on the addons page
310 318 *
311 319 * @since 3.04.03
320 + *
312 321 * @return array
313 322 */
314 323 protected static function fallback_plugin_list() {
315 324 $list = array(
@@ -320,19 +329,19 @@
320 329 'excerpt' => 'Enhance your basic Formidable forms with a plethora of Pro field types and features. Create advanced forms and data-driven applications in minutes.',
321 330 ),
322 331 'mailchimp' => array(
323 332 'title' => 'Mailchimp Forms',
324 - '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.',
333 + '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.', // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
325 334 ),
326 335 'registration' => array(
327 336 'title' => 'User Registration Forms',
328 337 'link' => 'downloads/user-registration/',
329 - '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.',
338 + '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.', // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
330 339 ),
331 340 'paypal' => array(
332 341 'title' => 'PayPal Standard Forms',
333 342 'link' => 'downloads/paypal-standard/',
334 - '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.',
343 + '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.', // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
335 344 ),
336 345 'stripe' => array(
337 346 'title' => 'Stripe Forms',
338 347 'docs' => 'knowledgebase/stripe/',
@@ -364,9 +373,9 @@
364 373 'excerpt' => 'Instantly add Bootstrap styling to all your Formidable forms.',
365 374 ),
366 375 'zapier' => array(
367 376 'title' => 'Zapier Forms',
368 - '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.',
377 + '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.', // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
369 378 ),
370 379 'signature' => array(
371 380 'title' => 'Digital Signature Forms',
372 381 'excerpt' => 'Add a signature field to your form. The user may write their signature with a trackpad/mouse or just type it.',
@@ -399,8 +408,9 @@
399 408 foreach ( $list as $k => $info ) {
400 409 $info['slug'] = $k;
401 410 $list[ $k ] = array_merge( $defaults, $info );
402 411 }
412 +
403 413 return $list;
404 414 }
405 415
406 416 /**
@@ -406,13 +416,13 @@
406 416 /**
407 417 * If Pro is missing but has been authenticated, include a download URL
408 418 *
409 419 * @since 3.04.03
420 + *
410 421 * @return string
411 422 */
412 423 public static function get_pro_download_url() {
413 - $license = self::get_pro_license();
414 - $api = new FrmFormApi( $license );
424 + $api = new FrmFormApi( self::get_pro_license() );
415 425 $downloads = $api->get_api_info();
416 426 $pro = self::get_pro_from_addons( $downloads );
417 427
418 428 return $pro['url'] ?? '';
@@ -419,12 +429,15 @@
419 429 }
420 430
421 431 /**
422 432 * @since 4.08
433 + *
434 + * @return string
423 435 */
424 436 public static function get_pro_license() {
425 437 $pro_cred_store = 'frmpro-credentials';
426 438 $pro_wpmu_store = 'frmpro-wpmu-sitewide';
439 +
427 440 if ( is_multisite() && get_site_option( $pro_wpmu_store ) ) {
428 441 $creds = get_site_option( $pro_cred_store );
429 442 } else {
430 443 $creds = get_option( $pro_cred_store );
@@ -434,16 +447,18 @@
434 447 return '';
435 448 }
436 449
437 450 $license = $creds['license'];
438 - if ( empty( $license ) ) {
451 +
452 + if ( ! $license ) {
439 453 return '';
440 454 }
441 455
442 - if ( strpos( $license, '-' ) ) {
443 - // this is a fix for licenses saved in the past
444 - $license = strtoupper( $license );
456 + if ( str_contains( $license, '-' ) ) {
457 + // This is a fix for licenses saved in the past
458 + return strtoupper( $license );
445 459 }
460 +
446 461 return $license;
447 462 }
448 463
449 464 /**
@@ -449,8 +464,9 @@
449 464 /**
450 465 * @since 4.08
451 466 *
452 467 * @param array $addons
468 + *
453 469 * @return array
454 470 */
455 471 protected static function get_pro_from_addons( $addons ) {
456 472 return $addons['93790'] ?? array();
@@ -457,12 +473,17 @@
457 473 }
458 474
459 475 /**
460 476 * @since 4.06
477 + * @since 6.31 Added the $force_type param.
478 + *
479 + * @param bool $force_type Whether to resolve grandfathered licenses to their real license type.
480 + *
481 + * @return string
461 482 */
462 - public static function license_type() {
483 + public static function license_type( $force_type = false ) {
463 484 if ( is_callable( 'FrmProAddonsController::license_type' ) ) {
464 - return FrmProAddonsController::license_type();
485 + return FrmProAddonsController::license_type( $force_type );
465 486 }
466 487
467 488 return 'free';
468 489 }
@@ -467,8 +488,122 @@
467 488 return 'free';
468 489 }
469 490
470 491 /**
492 + * Determine the license status for payment fee decisions.
493 + *
494 + * Mirrors determine_status_from_license_details in the Stripe Connect service,
495 + * including its 2016-04-26 grandfathered cutoff. Square and PayPal Commerce use a
496 + * later cutoff, so read their fees through payment_fees_apply instead.
497 + *
498 + * @since 6.31
499 + *
500 + * @return string 'active', 'expired', or 'free'.
501 + */
502 + public static function get_payment_license_status() {
503 + $version_info = self::get_primary_license_info();
504 +
505 + if ( ! $version_info ) {
506 + return 'free';
507 + }
508 +
509 + $error = $version_info['error'] ?? array();
510 +
511 + if ( is_array( $error ) && 'expired' === ( $error['code'] ?? '' ) ) {
512 + return 'expired';
513 + }
514 +
515 + if ( self::is_grandfathered_license() ) {
516 + $expires = self::get_grandfathered_expiration( $version_info );
517 +
518 + if ( $expires && gmdate( 'Y-m-d', $expires ) < '2016-04-26' ) {
519 + return 'free';
520 + }
521 + }
522 +
523 + if ( in_array( self::license_type( true ), array( 'elite', 'business' ), true ) ) {
524 + return 'active';
525 + }
526 +
527 + return 'free';
528 + }
529 +
530 + /**
531 + * Check if a connect service charges its per-transaction fee for this license.
532 + *
533 + * Square and PayPal Commerce launched long after lifetime licenses stopped being
534 + * sold, so their services charge every grandfathered license. Stripe's predates
535 + * them and exempts most of them, which get_payment_license_status mirrors.
536 + *
537 + * @since 6.34
538 + *
539 + * @param string $service The connect service: 'stripe', 'square', or 'paypal'.
540 + *
541 + * @return bool
542 + */
543 + public static function payment_fees_apply( $service ) {
544 + if ( 'active' !== self::get_payment_license_status() ) {
545 + return true;
546 + }
547 +
548 + if ( in_array( $service, array( 'square', 'paypal' ), true ) ) {
549 + return self::is_grandfathered_license();
550 + }
551 +
552 + return false;
553 + }
554 +
555 + /**
556 + * Check if the primary license is grandfathered.
557 + *
558 + * The API reports this on the Pro add-on itself, the same place
559 + * FrmProAddonsController::license_type reads it from. Older responses put it
560 + * in the top level error instead, so check both.
561 + *
562 + * @since 6.34
563 + *
564 + * @return bool
565 + */
566 + public static function is_grandfathered_license() {
567 + $version_info = self::get_primary_license_info();
568 +
569 + if ( ! $version_info ) {
570 + return false;
571 + }
572 +
573 + $error = $version_info['error'] ?? array();
574 +
575 + if ( is_array( $error ) && 'grandfathered' === ( $error['code'] ?? '' ) ) {
576 + return true;
577 + }
578 +
579 + $pro = self::get_pro_from_addons( $version_info );
580 +
581 + return 'grandfathered' === ( $pro['code'] ?? '' );
582 + }
583 +
584 + /**
585 + * Get the expiration timestamp reported alongside a grandfathered license.
586 + *
587 + * @since 6.34
588 + *
589 + * @param array $version_info The license info from get_primary_license_info.
590 + *
591 + * @return int
592 + */
593 + private static function get_grandfathered_expiration( $version_info ) {
594 + $error = $version_info['error'] ?? array();
595 +
596 + if ( is_array( $error ) && ! empty( $error['expires'] ) ) {
597 + return (int) $error['expires'];
598 + }
599 +
600 + $pro = self::get_pro_from_addons( $version_info );
601 +
602 + return (int) ( $pro['expires'] ?? 0 );
603 + }
604 +
605 + /**
471 606 * @since 4.0.01
472 607 *
473 608 * @return bool
474 609 */
@@ -473,18 +608,21 @@
473 608 * @return bool
474 609 */
475 610 public static function is_license_expired() {
476 611 $version_info = self::get_primary_license_info();
612 +
477 613 if ( ! isset( $version_info['error'] ) ) {
478 614 return false;
479 615 }
480 616
481 617 $expires = $version_info['error']['expires'] ?? 0;
482 - if ( empty( $expires ) || $expires > time() ) {
618 +
619 + if ( ! $expires || $expires > time() ) {
483 620 return false;
484 621 }
485 622
486 623 $rate_limited = ! empty( $version_info['response_code'] ) && 429 === (int) $version_info['response_code'];
624 +
487 625 if ( $rate_limited ) {
488 626 // Do not return false positives for rate limited responses.
489 627 return false;
490 628 }
@@ -499,11 +637,13 @@
499 637 * @return array|false
500 638 */
501 639 public static function get_primary_license_info() {
502 640 $installed_addons = apply_filters( 'frm_installed_addons', array() );
503 - if ( empty( $installed_addons ) || ! isset( $installed_addons['formidable_pro'] ) ) {
641 +
642 + if ( ! $installed_addons || ! isset( $installed_addons['formidable_pro'] ) ) {
504 643 return false;
505 644 }
645 +
506 646 $installed_addons = array(
507 647 'formidable_pro' => $installed_addons['formidable_pro'],
508 648 );
509 649
@@ -511,8 +651,12 @@
511 651 }
512 652
513 653 /**
514 654 * @since 3.04.03
655 + *
656 + * @param mixed $transient
657 + *
658 + * @return object
515 659 */
516 660 public static function check_update( $transient ) {
517 661 if ( ! FrmAppHelper::pro_is_installed() ) {
518 662 // Don't make any changes if only Lite is installed.
@@ -523,9 +667,10 @@
523 667 $transient = new stdClass();
524 668 }
525 669
526 670 $installed_addons = apply_filters( 'frm_installed_addons', array() );
527 - if ( empty( $installed_addons ) ) {
671 +
672 + if ( ! $installed_addons ) {
528 673 return $transient;
529 674 }
530 675
531 676 $version_info = self::fill_update_addon_info( $installed_addons );
@@ -539,14 +684,15 @@
539 684 continue;
540 685 }
541 686
542 687 $folder = $plugin->plugin;
543 - if ( empty( $folder ) ) {
688 +
689 + if ( ! $folder ) {
544 690 continue;
545 691 }
546 692
547 693 if ( ! self::is_installed( $folder ) ) {
548 - // don't show an update if the plugin isn't installed
694 + // Don't show an update if the plugin isn't installed
549 695 continue;
550 696 }
551 697
552 698 $wp_plugin = $wp_plugins[ $folder ] ?? array();
@@ -559,9 +705,8 @@
559 705 $transient->no_update[ $folder ] = $plugin;
560 706 }
561 707
562 708 $transient->checked[ $folder ] = $wp_version;
563 -
564 709 }//end foreach
565 710
566 711 return $transient;
567 712 }
@@ -571,8 +716,9 @@
571 716 * Because this gets called on "pre_set_site_transient_update_plugins" an old version of FrmAppHelper may be loaded on plugin update.
572 717 * This means that trying to access FrmAppHelper::get_plugins when upgrading from a Lite version before v5.5 results in a one-off error.
573 718 *
574 719 * @since 5.5.2
720 + *
575 721 * @return array
576 722 */
577 723 protected static function get_plugins() {
578 724 if ( ! function_exists( 'get_plugins' ) ) {
@@ -607,43 +753,49 @@
607 753 $version_info = array();
608 754
609 755 foreach ( $installed_addons as $addon ) {
610 756 if ( $addon->store_url !== 'https://formidableforms.com' ) {
611 - // check if this is a third-party addon
757 + // Check if this is a third-party addon
612 758 continue;
613 759 }
614 760
615 761 $new_license = $addon->license;
616 - if ( empty( $new_license ) || in_array( $new_license, $checked_licenses ) ) {
762 +
763 + if ( ! $new_license || in_array( $new_license, $checked_licenses, true ) ) {
617 764 continue;
618 765 }
619 766
620 767 $checked_licenses[] = $new_license;
768 + $api = new FrmFormApi( $new_license );
621 769
622 - $api = new FrmFormApi( $new_license );
623 - if ( empty( $version_info ) ) {
770 + if ( ! $version_info ) {
624 771 $version_info = $api->get_api_info();
625 772 continue;
626 773 }
627 774
628 775 $plugin = $api->get_addon_for_license( $addon, $version_info );
629 - if ( empty( $plugin ) ) {
776 +
777 + if ( ! $plugin ) {
630 778 continue;
631 779 }
632 780
633 781 $download_id = $plugin['id'] ?? 0;
634 - if ( ! empty( $download_id ) && ! isset( $version_info[ $download_id ]['package'] ) ) {
635 - // if this addon is using its own license, get the update url
636 - $addon_info = $api->get_api_info();
637 782
638 - $version_info[ $download_id ] = $addon_info[ $download_id ];
639 - if ( isset( $addon_info['error'] ) ) {
640 - $version_info[ $download_id ]['error'] = array(
641 - 'message' => $addon_info['error']['message'],
642 - 'code' => $addon_info['error']['code'],
643 - );
644 - }
783 + if ( ! $download_id || isset( $version_info[ $download_id ]['package'] ) ) {
784 + continue;
645 785 }
786 +
787 + // If this addon is using its own license, get the update url
788 + $addon_info = $api->get_api_info();
789 +
790 + $version_info[ $download_id ] = $addon_info[ $download_id ];
791 +
792 + if ( isset( $addon_info['error'] ) ) {
793 + $version_info[ $download_id ]['error'] = array(
794 + 'message' => $addon_info['error']['message'],
795 + 'code' => $addon_info['error']['code'],
796 + );
797 + }
646 798 }//end foreach
647 799
648 800 return $version_info;
649 801 }
@@ -651,9 +803,11 @@
651 803 /**
652 804 * Get the action link for an addon that isn't active.
653 805 *
654 806 * @since 3.06.03
807 + *
655 808 * @param string $plugin The plugin slug.
809 + *
656 810 * @return array
657 811 */
658 812 public static function install_link( $plugin ) {
659 813 $link = array();
@@ -675,9 +829,9 @@
675 829 'categories' => $addon['categories'],
676 830 );
677 831 }
678 832
679 - if ( ! empty( $link ) ) {
833 + if ( $link ) {
680 834 $link['status'] = $addon['status']['type'];
681 835 }
682 836 } elseif ( current_user_can( 'activate_plugins' ) && self::is_installed( 'formidable-' . $plugin . '/formidable-' . $plugin . '.php' ) ) {
683 837 $link = array(
@@ -689,34 +843,81 @@
689 843 return $link;
690 844 }
691 845
692 846 /**
847 + * Get the JSON-encoded install data for a plugin update.
848 + *
849 + * @since 6.29
850 + *
851 + * @param string $addon_slug The addon slug (e.g. 'pro', 'dates').
852 + *
853 + * @return string JSON-encoded install data, or empty string if no URL is available.
854 + */
855 + public static function get_update_install_data( $addon_slug ) {
856 + $upgrading = self::install_link( $addon_slug );
857 +
858 + if ( isset( $upgrading['class'] ) && 'frm-install-addon' === $upgrading['class'] ) {
859 + return (string) json_encode( $upgrading );
860 + }
861 +
862 + if ( 'pro' === $addon_slug ) {
863 + $download_url = self::get_pro_download_url();
864 + $plugin_file = 'formidable-pro/formidable-pro.php';
865 + } else {
866 + $addon_data = self::get_addon( $addon_slug );
867 + $download_url = $addon_data && ! empty( $addon_data['url'] ) ? $addon_data['url'] : '';
868 + $plugin_file = $addon_data && ! empty( $addon_data['plugin'] ) ? $addon_data['plugin'] : 'formidable-' . $addon_slug . '/formidable-' . $addon_slug . '.php';
869 + }
870 +
871 + if ( ! $download_url ) {
872 + $update_plugins = get_site_transient( 'update_plugins' );
873 + $plugin_update = $update_plugins->response[ $plugin_file ] ?? null;
874 + $download_url = $plugin_update && ! empty( $plugin_update->package ) ? $plugin_update->package : '';
875 + }
876 +
877 + return $download_url ? (string) json_encode(
878 + array(
879 + 'url' => $download_url,
880 + 'class' => 'frm-install-addon',
881 + )
882 + ) : '';
883 + }
884 +
885 + /**
693 886 * @since 4.09
887 + *
694 888 * @param string $plugin The plugin slug.
889 + *
695 890 * @return array|false
696 891 */
697 892 public static function get_addon( $plugin ) {
698 893 $addons = self::get_api_addons();
699 894 self::prepare_addons( $addons );
895 +
700 896 foreach ( $addons as $addon ) {
701 897 $slug = explode( '/', $addon['plugin'] );
898 +
702 899 if ( $slug[0] === 'formidable-' . $plugin ) {
703 900 return $addon;
704 901 }
705 902 }
903 +
706 904 return false;
707 905 }
708 906
709 907 /**
710 908 * @since 4.09
909 + *
711 910 * @return string
712 911 */
713 912 protected static function get_license_type() {
714 913 $license_type = '';
715 914 $addons = self::get_api_addons();
915 +
716 916 if ( isset( $addons['error'] ) && isset( $addons['error']['type'] ) ) {
717 - $license_type = $addons['error']['type'];
917 + return $addons['error']['type'];
718 918 }
919 +
719 920 return $license_type;
720 921 }
721 922
722 923 /**
@@ -729,11 +930,12 @@
729 930 */
730 931 public static function get_addon_for_license( $addons, $license ) {
731 932 $download_id = $license->download_id;
732 933 $plugin = array();
733 - if ( empty( $download_id ) && ! empty( $addons ) ) {
934 +
935 + if ( ! $download_id && $addons ) {
734 936 foreach ( $addons as $addon ) {
735 - if ( strtolower( $license->plugin_name ) === strtolower( $addon['title'] ) ) {
937 + if ( 0 === strcasecmp( $license->plugin_name, $addon['title'] ) ) {
736 938 return $addon;
737 939 }
738 940 }
739 941 } elseif ( isset( $addons[ $download_id ] ) ) {
@@ -743,29 +945,33 @@
743 945 return $plugin;
744 946 }
745 947
746 948 /**
949 + * @param array $addons
950 + *
747 951 * @return void
748 952 */
749 953 protected static function prepare_addons( &$addons ) {
954 + // Reset categories to prevent count accumulation across multiple calls.
955 + self::$categories = array();
956 +
750 957 $activate_url = '';
958 +
751 959 if ( current_user_can( 'activate_plugins' ) ) {
752 960 $activate_url = add_query_arg( array( 'action' => 'activate' ), admin_url( 'plugins.php' ) );
753 961 }
754 962
755 963 $loop_addons = $addons;
964 +
756 965 foreach ( $loop_addons as $id => $addon ) {
757 966 if ( is_numeric( $id ) ) {
758 967 $slug = str_replace( array( '-wordpress-plugin', '-wordpress' ), '', $addon['slug'] );
759 968 $file_name = $addon['plugin'];
760 969 } else {
761 - $slug = $id;
762 - if ( isset( $addon['file'] ) ) {
763 - $base_file = $addon['file'];
764 - } else {
765 - $base_file = 'formidable-' . $slug;
766 - }
970 + $slug = $id;
971 + $base_file = $addon['file'] ?? 'formidable-' . $slug;
767 972 $file_name = $base_file . '/' . $base_file . '.php';
973 +
768 974 if ( ! isset( $addon['plugin'] ) ) {
769 975 $addon['plugin'] = $file_name;
770 976 }
771 977 }
@@ -770,10 +976,17 @@
770 976 }
771 977 }
772 978
773 979 $addon['installed'] = self::is_installed( $file_name );
980 +
981 + if ( 'highrise' === $slug && ! $addon['installed'] ) {
982 + unset( $addons[ $id ] );
983 + continue;
984 + }
985 +
774 986 if ( $addon['installed'] && 'formidable-views/formidable-views.php' === $file_name ) {
775 987 $active_views_version = self::get_active_views_version();
988 +
776 989 if ( false !== $active_views_version && $slug !== $active_views_version ) {
777 990 $addon['installed'] = false;
778 991 }
779 992 }
@@ -779,9 +992,9 @@
779 992 }
780 993
781 994 $addon['activate_url'] = '';
782 995
783 - if ( $addon['installed'] && ! empty( $activate_url ) && ! self::is_plugin_active( $file_name, $slug ) ) {
996 + if ( $addon['installed'] && $activate_url && ! self::is_plugin_active( $file_name, $slug ) ) {
784 997 $addon['activate_url'] = add_query_arg(
785 998 array(
786 999 '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $file_name ),
787 1000 'plugin' => $file_name,
@@ -807,8 +1020,11 @@
807 1020 }//end foreach
808 1021 }
809 1022
810 1023 /**
1024 + * @param string $file_name
1025 + * @param string $slug
1026 + *
811 1027 * @return bool
812 1028 */
813 1029 private static function is_plugin_active( $file_name, $slug ) {
814 1030 if ( 'formidable-views/formidable-views.php' === $file_name ) {
@@ -823,8 +1039,9 @@
823 1039 private static function get_active_views_version() {
824 1040 if ( ! is_callable( 'FrmViewsAppHelper::plugin_version' ) ) {
825 1041 return false;
826 1042 }
1043 +
827 1044 $plugin_version = FrmViewsAppHelper::plugin_version();
828 1045 return version_compare( $plugin_version, '5.0', '>=' ) ? 'visual-views' : 'views';
829 1046 }
830 1047
@@ -830,22 +1047,25 @@
830 1047
831 1048 /**
832 1049 * @since 3.04.02
833 1050 *
1051 + * @param string $link
1052 + *
834 1053 * @return void
835 1054 */
836 1055 protected static function prepare_addon_link( &$link ) {
837 1056 $site_url = 'https://formidableforms.com/';
838 - if ( strpos( $link, 'http' ) !== 0 ) {
1057 +
1058 + if ( ! str_starts_with( $link, 'http' ) ) {
839 1059 $link = $site_url . $link;
840 1060 }
841 - $link = FrmAppHelper::make_affiliate_url( $link );
842 - $query_args = array(
843 - 'utm_source' => 'WordPress',
844 - 'utm_medium' => 'addons',
845 - 'utm_campaign' => 'liteplugin',
1061 +
1062 + $link = FrmAppHelper::make_affiliate_url( $link );
1063 +
1064 + $utm = array(
1065 + 'campaign' => 'addons',
846 1066 );
847 - $link = add_query_arg( $query_args, $link );
1067 + $link = FrmAppHelper::maybe_add_missing_utm( $link, $utm );
848 1068 }
849 1069
850 1070 /**
851 1071 * Add the status to the addon array. Status options are:
@@ -852,8 +1072,10 @@
852 1072 * installed, active, not installed
853 1073 *
854 1074 * @since 3.04.02
855 1075 *
1076 + * @param array $addon
1077 + *
856 1078 * @return void
857 1079 */
858 1080 protected static function set_addon_status( &$addon ) {
859 1081 if ( ! empty( $addon['activate_url'] ) ) {
@@ -880,8 +1102,9 @@
880 1102 * @param string $plugin
881 1103 * @param string $redirect
882 1104 * @param bool $network_wide
883 1105 * @param bool $silent
1106 + *
884 1107 * @return WP_Error|null Null on success, WP_Error on invalid file.
885 1108 */
886 1109 protected static function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) {
887 1110 if ( ! function_exists( 'activate_plugin' ) ) {
@@ -896,8 +1119,9 @@
896 1119 * @since 6.8
897 1120 *
898 1121 * @param string $plugin
899 1122 * @param bool $silent
1123 + *
900 1124 * @return void
901 1125 */
902 1126 protected static function deactivate_plugin( $plugin, $silent = false ) {
903 1127 if ( ! function_exists( 'deactivate_plugins' ) ) {
@@ -911,8 +1135,9 @@
911 1135 *
912 1136 * @since 6.8
913 1137 *
914 1138 * @param string $plugin
1139 + *
915 1140 * @return true|WP_Error True on success, WP_Error on invalid file.
916 1141 */
917 1142 protected static function uninstall_plugin( $plugin ) {
918 1143 if ( ! current_user_can( 'delete_plugins' ) ) {
@@ -925,13 +1150,9 @@
925 1150
926 1151 self::deactivate_plugin( $plugin, true );
927 1152 $result = delete_plugins( array( $plugin ) );
928 1153
929 - if ( is_wp_error( $result ) ) {
930 - return $result;
931 - }
932 -
933 - return true;
1154 + return is_wp_error( $result ) ? $result : true;
934 1155 }
935 1156
936 1157 /**
937 1158 * @since 5.0.10
@@ -938,9 +1159,9 @@
938 1159 *
939 1160 * @return string
940 1161 */
941 1162 protected static function get_current_plugin() {
942 - if ( empty( self::$plugin ) ) {
1163 + if ( ! self::$plugin ) {
943 1164 self::$plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'esc_url_raw' );
944 1165 }
945 1166 return self::$plugin;
946 1167 }
@@ -947,9 +1168,9 @@
947 1168
948 1169 /**
949 1170 * @since 4.08
950 1171 *
951 - * @return array|void
1172 + * @return mixed[]|null
952 1173 */
953 1174 protected static function download_and_activate() {
954 1175 if ( is_admin() ) {
955 1176 FrmAppHelper::set_current_screen_and_hook_suffix();
@@ -957,12 +1178,14 @@
957 1178
958 1179 self::maybe_show_cred_form();
959 1180
960 1181 $installed = self::install_addon();
1182 +
961 1183 if ( is_array( $installed ) && isset( $installed['message'] ) ) {
962 1184 return $installed;
963 1185 }
964 1186 self::handle_addon_action( $installed, 'activate' );
1187 + return null;
965 1188 }
966 1189
967 1190 /**
968 1191 * @since 3.04.02
@@ -992,9 +1215,8 @@
992 1215
993 1216 if ( $show_form ) {
994 1217 $form = ob_get_clean();
995 1218 $message = __( 'Sorry, your site requires FTP authentication. Please download plugins from FormidableForms.com and install them manually.', 'formidable' );
996 - $data = $form;
997 1219 $response = array(
998 1220 'success' => false,
999 1221 'message' => $message,
1000 1222 'form' => $form,
@@ -1022,8 +1244,10 @@
1022 1244 * We do not need any extra credentials if we have gotten this far,
1023 1245 * so let's install the plugin.
1024 1246 *
1025 1247 * @since 3.04.02
1248 + *
1249 + * @return array|string
1026 1250 */
1027 1251 protected static function install_addon() {
1028 1252 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
1029 1253
@@ -1037,14 +1261,15 @@
1037 1261 }
1038 1262
1039 1263 // Create the plugin upgrader with our custom skin.
1040 1264 $installer = new Plugin_Upgrader( new FrmInstallerSkin() );
1041 - $installer->install( $download_url );
1265 + $installer->install( $download_url, array( 'overwrite_package' => true ) );
1042 1266
1043 1267 // Flush the cache and return the newly installed plugin basename.
1044 1268 wp_cache_flush();
1045 1269
1046 1270 $plugin = $installer->plugin_info();
1271 +
1047 1272 if ( ! $plugin ) {
1048 1273 return array(
1049 1274 'message' => 'Plugin was not installed. ' . $installer->result,
1050 1275 'success' => false,
@@ -1049,8 +1274,9 @@
1049 1274 'message' => 'Plugin was not installed. ' . $installer->result,
1050 1275 'success' => false,
1051 1276 );
1052 1277 }
1278 +
1053 1279 return $plugin;
1054 1280 }
1055 1281
1056 1282 /**
@@ -1114,8 +1340,9 @@
1114 1340 * @since 6.8
1115 1341 *
1116 1342 * @param callable $action_callback The specific add-on action to be executed.
1117 1343 * @param callable|null $response_callback Optional. The response handling callback. Default null.
1344 + *
1118 1345 * @return void
1119 1346 */
1120 1347 private static function process_addon_action( $action_callback, $response_callback = null ) {
1121 1348 self::install_addon_permissions();
@@ -1138,13 +1365,14 @@
1138 1365 * @since 6.8
1139 1366 *
1140 1367 * @param string $installed The plugin folder name with file name.
1141 1368 * @param string $action The action type ('activate', 'deactivate', 'uninstall').
1142 - * @return array|void
1369 + *
1370 + * @return mixed[]|null
1143 1371 */
1144 1372 protected static function handle_addon_action( $installed, $action ) {
1145 1373 if ( ! $installed || ! $action ) {
1146 - return;
1374 + return null;
1147 1375 }
1148 1376
1149 1377 $result = null;
1150 1378 switch ( $action ) {
@@ -1164,8 +1392,9 @@
1164 1392 if ( $result->get_error_code() !== 'no_plugin_header' ) {
1165 1393 if ( wp_doing_ajax() ) {
1166 1394 wp_send_json_error( array( 'error' => $result->get_error_message() ) );
1167 1395 }
1396 +
1168 1397 return array(
1169 1398 'message' => $result->get_error_message(),
1170 1399 'success' => false,
1171 1400 );
@@ -1179,17 +1408,14 @@
1179 1408 * @return array
1180 1409 */
1181 1410 private static function get_addon_activation_response() {
1182 1411 $activating_page = self::get_activating_page();
1412 + $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' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
1183 1413
1184 - $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' );
1185 -
1186 - $response = array(
1414 + return array(
1187 1415 'message' => $message,
1188 1416 'saveAndReload' => $activating_page,
1189 1417 );
1190 -
1191 - return $response;
1192 1418 }
1193 1419
1194 1420 /**
1195 1421 * Return a string that reflects the page from which the addon is being activated on,
@@ -1198,17 +1424,14 @@
1198 1424 * @return string
1199 1425 */
1200 1426 private static function get_activating_page() {
1201 1427 $referer = FrmAppHelper::get_server_value( 'HTTP_REFERER' );
1202 - if ( false !== strpos( $referer, 'frm_action=settings' ) ) {
1428 +
1429 + if ( str_contains( $referer, 'frm_action=settings' ) ) {
1203 1430 return 'settings';
1204 1431 }
1205 1432
1206 - if ( false !== strpos( $referer, 'frm_action=edit' ) ) {
1207 - return 'form_builder';
1208 - }
1209 -
1210 - return '';
1433 + return str_contains( $referer, 'frm_action=edit' ) ? 'form_builder' : '';
1211 1434 }
1212 1435
1213 1436 /**
1214 1437 * Run security checks before installing
@@ -1219,12 +1442,14 @@
1219 1442 */
1220 1443 protected static function install_addon_permissions() {
1221 1444 check_ajax_referer( 'frm_ajax', 'nonce' );
1222 1445
1223 - if ( ! current_user_can( 'activate_plugins' ) || ! self::get_current_plugin() ) {
1224 - echo json_encode( true );
1225 - wp_die();
1446 + if ( current_user_can( 'activate_plugins' ) && self::get_current_plugin() ) {
1447 + return;
1226 1448 }
1449 +
1450 + echo json_encode( true );
1451 + wp_die();
1227 1452 }
1228 1453
1229 1454 /**
1230 1455 * @since 4.08
@@ -1232,12 +1457,14 @@
1232 1457 * @return string
1233 1458 */
1234 1459 public static function connect_link() {
1235 1460 $auth = get_option( 'frm_connect_token' );
1236 - if ( empty( $auth ) ) {
1461 +
1462 + if ( ! $auth ) {
1237 1463 $auth = hash( 'sha512', wp_rand() );
1238 - update_option( 'frm_connect_token', $auth, 'no' );
1464 + update_option( 'frm_connect_token', $auth, false );
1239 1465 }
1466 +
1240 1467 $page = FrmAppHelper::simple_get( 'page', 'sanitize_title', 'formidable-settings' );
1241 1468 $link = 'https://formidableforms.com/api-connect/';
1242 1469 $args = array(
1243 1470 'v' => 2,
@@ -1265,9 +1492,10 @@
1265 1492 $post_url = FrmAppHelper::get_param( 'file_url', '', 'request', 'sanitize_text_field' );
1266 1493
1267 1494 // The download link is not required if already installed.
1268 1495 $is_installed = FrmAppHelper::pro_is_included();
1269 - $file_missing = ! $is_installed && empty( $post_url );
1496 + $file_missing = ! $is_installed && ! $post_url;
1497 +
1270 1498 if ( ! $post_auth || $file_missing ) {
1271 1499 return false;
1272 1500 }
1273 1501
@@ -1272,13 +1500,9 @@
1272 1500 }
1273 1501
1274 1502 // Verify auth.
1275 1503 $auth = get_option( 'frm_connect_token' );
1276 - if ( empty( $auth ) || ! hash_equals( $auth, $post_auth ) ) {
1277 - return false;
1278 - }
1279 -
1280 - return true;
1504 + return $auth && hash_equals( $auth, $post_auth );
1281 1505 }
1282 1506
1283 1507 /**
1284 1508 * Install and/or activate the add-on file.
@@ -1289,17 +1513,17 @@
1289 1513 */
1290 1514 public static function install_addon_api() {
1291 1515 self::$plugin = FrmAppHelper::get_param( 'file_url', '', 'request', 'esc_url_raw' );
1292 1516
1293 - $error = esc_html__( 'Could not install an upgrade. Please download from formidableforms.com and install manually.', 'formidable' );
1294 -
1295 1517 // Delete so cannot replay.
1296 1518 delete_option( 'frm_connect_token' );
1297 1519
1298 1520 // It's already installed and active.
1299 1521 $active = self::activate_plugin( 'formidable-pro/formidable-pro.php', false, false, true );
1522 +
1300 1523 if ( is_wp_error( $active ) ) {
1301 1524 $response = self::maybe_download_and_activate();
1525 +
1302 1526 if ( is_array( $response ) ) {
1303 1527 // The download failed.
1304 1528 return $response;
1305 1529 }
@@ -1305,11 +1529,12 @@
1305 1529 }
1306 1530 }
1307 1531
1308 1532 // If empty license, save it now.
1309 - if ( empty( self::get_pro_license() ) && function_exists( 'load_formidable_pro' ) ) {
1533 + if ( ! self::get_pro_license() && function_exists( 'load_formidable_pro' ) ) {
1310 1534 load_formidable_pro();
1311 1535 $license = stripslashes( FrmAppHelper::get_param( 'key', '', 'request', 'sanitize_text_field' ) );
1536 +
1312 1537 if ( ! $license ) {
1313 1538 return array(
1314 1539 'success' => false,
1315 1540 'error' => 'That site does not have a valid license key.',
@@ -1316,8 +1541,9 @@
1316 1541 );
1317 1542 }
1318 1543
1319 1544 $response = FrmAddon::activate_license_for_plugin( $license, 'formidable_pro' );
1545 +
1320 1546 if ( ! $response['success'] ) {
1321 1547 // Could not activate license.
1322 1548 return $response;
1323 1549 }
@@ -1342,8 +1568,9 @@
1342 1568 }
1343 1569
1344 1570 // Download plugin now.
1345 1571 $response = self::download_and_activate();
1572 +
1346 1573 if ( is_array( $response ) && isset( $response['success'] ) ) {
1347 1574 // The download failed.
1348 1575 return $response;
1349 1576 }
@@ -1357,8 +1584,9 @@
1357 1584 * @since 4.09
1358 1585 *
1359 1586 * @param string $plugin
1360 1587 * @param array|string $upgrade_link_args
1588 + *
1361 1589 * @return void
1362 1590 */
1363 1591 public static function conditional_action_button( $plugin, $upgrade_link_args ) {
1364 1592 if ( is_callable( 'FrmProAddonsController::conditional_action_button' ) ) {
@@ -1393,8 +1621,9 @@
1393 1621 * @type false|string $license_type
1394 1622 * @type string $plan_required
1395 1623 * @type string $upgrade_link
1396 1624 * }
1625 + *
1397 1626 * @return void
1398 1627 */
1399 1628 public static function show_conditional_action_button( $atts ) {
1400 1629 if ( is_callable( 'FrmProAddonsController::show_conditional_action_button' ) ) {
@@ -1427,16 +1656,19 @@
1427 1656 $upgrade_link = FrmAppHelper::admin_upgrade_link( 'addons', $addon['link'] );
1428 1657 }
1429 1658
1430 1659 $class = ! empty( $atts['class'] ) ? $atts['class'] : '';
1431 - if ( strpos( $class, 'frm-button' ) === false ) {
1660 +
1661 + if ( ! str_contains( $class, 'frm-button' ) ) {
1432 1662 $class .= ' frm-button-secondary frm-button-sm';
1433 1663 }
1664 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
1434 1665 ?>
1435 - <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' ); ?>">
1666 + <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' ); ?>"><?php // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
1436 1667 <?php echo esc_html( $text ); ?>
1437 1668 </a>
1438 1669 <?php
1670 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
1439 1671 }
1440 1672
1441 1673 /**
1442 1674 * @since 3.04.02
@@ -1446,8 +1678,9 @@
1446 1678 public static function ajax_install_addon() {
1447 1679 self::install_addon_permissions();
1448 1680
1449 1681 $result = self::download_and_activate();
1682 +
1450 1683 if ( isset( $result['success'] ) && ! $result['success'] ) {
1451 1684 echo json_encode( $result );
1452 1685 wp_die();
1453 1686 }
@@ -1480,9 +1713,8 @@
1480 1713 $allowed_url_list = apply_filters( 'frm_allowed_external_urls', $allowed_url_list );
1481 1714
1482 1715 if ( ! is_array( $allowed_url_list ) ) {
1483 1716 _doing_it_wrong( __METHOD__, 'Only an array of URLs could be used within this filter.', '6.3.1' );
1484 -
1485 1717 return array();
1486 1718 }
1487 1719
1488 1720 return $allowed_url_list;
@@ -1492,8 +1724,10 @@
1492 1724 * Gets required plan for an addon.
1493 1725 *
1494 1726 * @since 6.4.2
1495 1727 *
1728 + * @param int|string $addon_id
1729 + *
1496 1730 * @return string Empty string if no plan is required for active license.
1497 1731 */
1498 1732 public static function get_addon_required_plan( $addon_id ) {
1499 1733 $api = new FrmFormApi();
@@ -1504,9 +1738,9 @@
1504 1738 $requires = FrmFormsHelper::get_plan_required( $dates );
1505 1739 }
1506 1740
1507 1741 if ( ! isset( $requires ) || ! is_string( $requires ) ) {
1508 - $requires = '';
1742 + return '';
1509 1743 }
1510 1744
1511 1745 return $requires;
1512 1746 }