| @@ -33,14 +33,16 @@ | ||
| 33 | 33 | public static function load_admin_hooks() { |
| 34 | 34 | add_action( 'admin_menu', self::class . '::menu', 100 ); |
| 35 | 35 | add_filter( 'pre_set_site_transient_update_plugins', self::class . '::check_update' ); |
| 36 | 36 | |
| 37 | - if ( FrmAppHelper::is_admin_page( 'formidable-addons' ) ) { | |
| 38 | - self::$request_addon_url = 'https://connect.formidableforms.com/add-on-request/'; | |
| 37 | + if ( ! FrmAppHelper::is_admin_page( 'formidable-addons' ) ) { | |
| 38 | + return; | |
| 39 | + } | |
| 39 | 40 | |
| 40 | - add_action( 'admin_enqueue_scripts', self::class . '::enqueue_assets', 15 ); | |
| 41 | - add_filter( 'frm_show_footer_links', '__return_false' ); | |
| 42 | - } | |
| 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' ); | |
| 43 | 45 | } |
| 44 | 46 | |
| 45 | 47 | /** |
| 46 | 48 | * Enqueues the Add-Ons page scripts and styles. |
| @@ -102,9 +104,9 @@ | ||
| 102 | 104 | $label = '<span style="color:#3FCA89">' . esc_html( $label ) . '</span>'; |
| 103 | 105 | |
| 104 | 106 | add_submenu_page( 'formidable', 'Formidable | ' . __( 'Add-Ons', 'formidable' ), $label, 'frm_view_forms', 'formidable-addons', 'FrmAddonsController::list_addons' ); |
| 105 | 107 | |
| 106 | - // 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. | |
| 107 | 109 | remove_submenu_page( 'formidable', 'formidable' ); |
| 108 | 110 | |
| 109 | 111 | if ( ! FrmAppHelper::pro_is_installed() ) { |
| 110 | 112 | $cta_text = FrmSalesApi::get_best_sale_value( 'menu_cta_text' ); |
| @@ -154,9 +156,10 @@ | ||
| 154 | 156 | 'pro' => array( |
| 155 | 157 | 'title' => 'Formidable Forms Pro', |
| 156 | 158 | 'slug' => 'formidable-pro', |
| 157 | 159 | 'released' => '2011-02-05', |
| 158 | - 'docs' => 'knowledgebase/', | |
| 160 | + 'docs' => 'knowledgebase/what-is-the-difference-between-the-lite-free-and-pro-version/', | |
| 161 | + 'docs_label' => __( 'Why Upgrade', 'formidable' ), | |
| 159 | 162 | 'categories' => array( 'basic', 'plus', 'business', 'elite' ), |
| 160 | 163 | 'excerpt' => 'Create calculators, surveys, smart forms, and data-driven applications. Build directories, real estate listings, job boards, and much more.', |
| 161 | 164 | ), |
| 162 | 165 | ); |
| @@ -191,12 +194,14 @@ | ||
| 191 | 194 | ); |
| 192 | 195 | |
| 193 | 196 | // Extract the elements to move |
| 194 | 197 | foreach ( $plans as $plan ) { |
| 195 | - if ( isset( self::$categories[ $plan ] ) ) { | |
| 196 | - $bottom_categories[ $plan ] = self::$categories[ $plan ]; | |
| 197 | - unset( self::$categories[ $plan ] ); | |
| 198 | + if ( ! isset( self::$categories[ $plan ] ) ) { | |
| 199 | + continue; | |
| 198 | 200 | } |
| 201 | + | |
| 202 | + $bottom_categories[ $plan ] = self::$categories[ $plan ]; | |
| 203 | + unset( self::$categories[ $plan ] ); | |
| 199 | 204 | } |
| 200 | 205 | |
| 201 | 206 | $special_categories = array(); |
| 202 | 207 | |
| @@ -266,11 +271,10 @@ | ||
| 266 | 271 | */ |
| 267 | 272 | public static function license_settings() { |
| 268 | 273 | $plugins = apply_filters( 'frm_installed_addons', array() ); |
| 269 | 274 | |
| 270 | - if ( empty( $plugins ) ) { | |
| 275 | + if ( ! $plugins ) { | |
| 271 | 276 | esc_html_e( 'There are no plugins on your site that require a license', 'formidable' ); |
| 272 | - | |
| 273 | 277 | return; |
| 274 | 278 | } |
| 275 | 279 | |
| 276 | 280 | ksort( $plugins ); |
| @@ -284,15 +288,15 @@ | ||
| 284 | 288 | protected static function get_api_addons() { |
| 285 | 289 | $api = new FrmFormApi(); |
| 286 | 290 | $addons = $api->get_api_info(); |
| 287 | 291 | |
| 288 | - if ( empty( $addons ) ) { | |
| 289 | - $addons = self::fallback_plugin_list(); | |
| 290 | - } else { | |
| 291 | - foreach ( $addons as $k => $addon ) { | |
| 292 | - if ( empty( $addon['excerpt'] ) && $k !== 'error' ) { | |
| 293 | - unset( $addons[ $k ] ); | |
| 294 | - } | |
| 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 ] ); | |
| 295 | 299 | } |
| 296 | 300 | } |
| 297 | 301 | |
| 298 | 302 | return $addons; |
| @@ -305,11 +309,9 @@ | ||
| 305 | 309 | * |
| 306 | 310 | * @return int Count of addons. |
| 307 | 311 | */ |
| 308 | 312 | public static function get_addons_count() { |
| 309 | - $addons = self::get_api_addons(); | |
| 310 | - | |
| 311 | - return count( $addons ); | |
| 313 | + return count( self::get_api_addons() ); | |
| 312 | 314 | } |
| 313 | 315 | |
| 314 | 316 | /** |
| 315 | 317 | * If the API is unable to connect, show something on the addons page |
| @@ -327,19 +329,19 @@ | ||
| 327 | 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.', |
| 328 | 330 | ), |
| 329 | 331 | 'mailchimp' => array( |
| 330 | 332 | 'title' => 'Mailchimp Forms', |
| 331 | - '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 | |
| 332 | 334 | ), |
| 333 | 335 | 'registration' => array( |
| 334 | 336 | 'title' => 'User Registration Forms', |
| 335 | 337 | 'link' => 'downloads/user-registration/', |
| 336 | - '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 | |
| 337 | 339 | ), |
| 338 | 340 | 'paypal' => array( |
| 339 | 341 | 'title' => 'PayPal Standard Forms', |
| 340 | 342 | 'link' => 'downloads/paypal-standard/', |
| 341 | - '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 | |
| 342 | 344 | ), |
| 343 | 345 | 'stripe' => array( |
| 344 | 346 | 'title' => 'Stripe Forms', |
| 345 | 347 | 'docs' => 'knowledgebase/stripe/', |
| @@ -371,9 +373,9 @@ | ||
| 371 | 373 | 'excerpt' => 'Instantly add Bootstrap styling to all your Formidable forms.', |
| 372 | 374 | ), |
| 373 | 375 | 'zapier' => array( |
| 374 | 376 | 'title' => 'Zapier Forms', |
| 375 | - '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 | |
| 376 | 378 | ), |
| 377 | 379 | 'signature' => array( |
| 378 | 380 | 'title' => 'Digital Signature Forms', |
| 379 | 381 | 'excerpt' => 'Add a signature field to your form. The user may write their signature with a trackpad/mouse or just type it.', |
| @@ -406,8 +408,9 @@ | ||
| 406 | 408 | foreach ( $list as $k => $info ) { |
| 407 | 409 | $info['slug'] = $k; |
| 408 | 410 | $list[ $k ] = array_merge( $defaults, $info ); |
| 409 | 411 | } |
| 412 | + | |
| 410 | 413 | return $list; |
| 411 | 414 | } |
| 412 | 415 | |
| 413 | 416 | /** |
| @@ -417,10 +420,9 @@ | ||
| 417 | 420 | * |
| 418 | 421 | * @return string |
| 419 | 422 | */ |
| 420 | 423 | public static function get_pro_download_url() { |
| 421 | - $license = self::get_pro_license(); | |
| 422 | - $api = new FrmFormApi( $license ); | |
| 424 | + $api = new FrmFormApi( self::get_pro_license() ); | |
| 423 | 425 | $downloads = $api->get_api_info(); |
| 424 | 426 | $pro = self::get_pro_from_addons( $downloads ); |
| 425 | 427 | |
| 426 | 428 | return $pro['url'] ?? ''; |
| @@ -446,16 +448,17 @@ | ||
| 446 | 448 | } |
| 447 | 449 | |
| 448 | 450 | $license = $creds['license']; |
| 449 | 451 | |
| 450 | - if ( empty( $license ) ) { | |
| 452 | + if ( ! $license ) { | |
| 451 | 453 | return ''; |
| 452 | 454 | } |
| 453 | 455 | |
| 454 | - if ( strpos( $license, '-' ) ) { | |
| 455 | - // this is a fix for licenses saved in the past | |
| 456 | - $license = strtoupper( $license ); | |
| 456 | + if ( str_contains( $license, '-' ) ) { | |
| 457 | + // This is a fix for licenses saved in the past | |
| 458 | + return strtoupper( $license ); | |
| 457 | 459 | } |
| 460 | + | |
| 458 | 461 | return $license; |
| 459 | 462 | } |
| 460 | 463 | |
| 461 | 464 | /** |
| @@ -470,14 +473,17 @@ | ||
| 470 | 473 | } |
| 471 | 474 | |
| 472 | 475 | /** |
| 473 | 476 | * @since 4.06 |
| 477 | + * @since 6.31 Added the $force_type param. | |
| 474 | 478 | * |
| 479 | + * @param bool $force_type Whether to resolve grandfathered licenses to their real license type. | |
| 480 | + * | |
| 475 | 481 | * @return string |
| 476 | 482 | */ |
| 477 | - public static function license_type() { | |
| 483 | + public static function license_type( $force_type = false ) { | |
| 478 | 484 | if ( is_callable( 'FrmProAddonsController::license_type' ) ) { |
| 479 | - return FrmProAddonsController::license_type(); | |
| 485 | + return FrmProAddonsController::license_type( $force_type ); | |
| 480 | 486 | } |
| 481 | 487 | |
| 482 | 488 | return 'free'; |
| 483 | 489 | } |
| @@ -482,8 +488,122 @@ | ||
| 482 | 488 | return 'free'; |
| 483 | 489 | } |
| 484 | 490 | |
| 485 | 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 | + /** | |
| 486 | 606 | * @since 4.0.01 |
| 487 | 607 | * |
| 488 | 608 | * @return bool |
| 489 | 609 | */ |
| @@ -495,9 +615,9 @@ | ||
| 495 | 615 | } |
| 496 | 616 | |
| 497 | 617 | $expires = $version_info['error']['expires'] ?? 0; |
| 498 | 618 | |
| 499 | - if ( empty( $expires ) || $expires > time() ) { | |
| 619 | + if ( ! $expires || $expires > time() ) { | |
| 500 | 620 | return false; |
| 501 | 621 | } |
| 502 | 622 | |
| 503 | 623 | $rate_limited = ! empty( $version_info['response_code'] ) && 429 === (int) $version_info['response_code']; |
| @@ -518,9 +638,9 @@ | ||
| 518 | 638 | */ |
| 519 | 639 | public static function get_primary_license_info() { |
| 520 | 640 | $installed_addons = apply_filters( 'frm_installed_addons', array() ); |
| 521 | 641 | |
| 522 | - if ( empty( $installed_addons ) || ! isset( $installed_addons['formidable_pro'] ) ) { | |
| 642 | + if ( ! $installed_addons || ! isset( $installed_addons['formidable_pro'] ) ) { | |
| 523 | 643 | return false; |
| 524 | 644 | } |
| 525 | 645 | |
| 526 | 646 | $installed_addons = array( |
| @@ -548,9 +668,9 @@ | ||
| 548 | 668 | } |
| 549 | 669 | |
| 550 | 670 | $installed_addons = apply_filters( 'frm_installed_addons', array() ); |
| 551 | 671 | |
| 552 | - if ( empty( $installed_addons ) ) { | |
| 672 | + if ( ! $installed_addons ) { | |
| 553 | 673 | return $transient; |
| 554 | 674 | } |
| 555 | 675 | |
| 556 | 676 | $version_info = self::fill_update_addon_info( $installed_addons ); |
| @@ -565,14 +685,14 @@ | ||
| 565 | 685 | } |
| 566 | 686 | |
| 567 | 687 | $folder = $plugin->plugin; |
| 568 | 688 | |
| 569 | - if ( empty( $folder ) ) { | |
| 689 | + if ( ! $folder ) { | |
| 570 | 690 | continue; |
| 571 | 691 | } |
| 572 | 692 | |
| 573 | 693 | if ( ! self::is_installed( $folder ) ) { |
| 574 | - // don't show an update if the plugin isn't installed | |
| 694 | + // Don't show an update if the plugin isn't installed | |
| 575 | 695 | continue; |
| 576 | 696 | } |
| 577 | 697 | |
| 578 | 698 | $wp_plugin = $wp_plugins[ $folder ] ?? array(); |
| @@ -585,9 +705,8 @@ | ||
| 585 | 705 | $transient->no_update[ $folder ] = $plugin; |
| 586 | 706 | } |
| 587 | 707 | |
| 588 | 708 | $transient->checked[ $folder ] = $wp_version; |
| 589 | - | |
| 590 | 709 | }//end foreach |
| 591 | 710 | |
| 592 | 711 | return $transient; |
| 593 | 712 | } |
| @@ -634,23 +753,22 @@ | ||
| 634 | 753 | $version_info = array(); |
| 635 | 754 | |
| 636 | 755 | foreach ( $installed_addons as $addon ) { |
| 637 | 756 | if ( $addon->store_url !== 'https://formidableforms.com' ) { |
| 638 | - // check if this is a third-party addon | |
| 757 | + // Check if this is a third-party addon | |
| 639 | 758 | continue; |
| 640 | 759 | } |
| 641 | 760 | |
| 642 | 761 | $new_license = $addon->license; |
| 643 | 762 | |
| 644 | - if ( empty( $new_license ) || in_array( $new_license, $checked_licenses ) ) { | |
| 763 | + if ( ! $new_license || in_array( $new_license, $checked_licenses, true ) ) { | |
| 645 | 764 | continue; |
| 646 | 765 | } |
| 647 | 766 | |
| 648 | 767 | $checked_licenses[] = $new_license; |
| 768 | + $api = new FrmFormApi( $new_license ); | |
| 649 | 769 | |
| 650 | - $api = new FrmFormApi( $new_license ); | |
| 651 | - | |
| 652 | - if ( empty( $version_info ) ) { | |
| 770 | + if ( ! $version_info ) { | |
| 653 | 771 | $version_info = $api->get_api_info(); |
| 654 | 772 | continue; |
| 655 | 773 | } |
| 656 | 774 | |
| @@ -655,26 +773,28 @@ | ||
| 655 | 773 | } |
| 656 | 774 | |
| 657 | 775 | $plugin = $api->get_addon_for_license( $addon, $version_info ); |
| 658 | 776 | |
| 659 | - if ( empty( $plugin ) ) { | |
| 777 | + if ( ! $plugin ) { | |
| 660 | 778 | continue; |
| 661 | 779 | } |
| 662 | 780 | |
| 663 | 781 | $download_id = $plugin['id'] ?? 0; |
| 664 | 782 | |
| 665 | - if ( ! empty( $download_id ) && ! isset( $version_info[ $download_id ]['package'] ) ) { | |
| 666 | - // if this addon is using its own license, get the update url | |
| 667 | - $addon_info = $api->get_api_info(); | |
| 783 | + if ( ! $download_id || isset( $version_info[ $download_id ]['package'] ) ) { | |
| 784 | + continue; | |
| 785 | + } | |
| 668 | 786 | |
| 669 | - $version_info[ $download_id ] = $addon_info[ $download_id ]; | |
| 787 | + // If this addon is using its own license, get the update url | |
| 788 | + $addon_info = $api->get_api_info(); | |
| 670 | 789 | |
| 671 | - if ( isset( $addon_info['error'] ) ) { | |
| 672 | - $version_info[ $download_id ]['error'] = array( | |
| 673 | - 'message' => $addon_info['error']['message'], | |
| 674 | - 'code' => $addon_info['error']['code'], | |
| 675 | - ); | |
| 676 | - } | |
| 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 | + ); | |
| 677 | 797 | } |
| 678 | 798 | }//end foreach |
| 679 | 799 | |
| 680 | 800 | return $version_info; |
| @@ -709,9 +829,9 @@ | ||
| 709 | 829 | 'categories' => $addon['categories'], |
| 710 | 830 | ); |
| 711 | 831 | } |
| 712 | 832 | |
| 713 | - if ( ! empty( $link ) ) { | |
| 833 | + if ( $link ) { | |
| 714 | 834 | $link['status'] = $addon['status']['type']; |
| 715 | 835 | } |
| 716 | 836 | } elseif ( current_user_can( 'activate_plugins' ) && self::is_installed( 'formidable-' . $plugin . '/formidable-' . $plugin . '.php' ) ) { |
| 717 | 837 | $link = array( |
| @@ -723,8 +843,47 @@ | ||
| 723 | 843 | return $link; |
| 724 | 844 | } |
| 725 | 845 | |
| 726 | 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 | + /** | |
| 727 | 886 | * @since 4.09 |
| 728 | 887 | * |
| 729 | 888 | * @param string $plugin The plugin slug. |
| 730 | 889 | * |
| @@ -740,8 +899,9 @@ | ||
| 740 | 899 | if ( $slug[0] === 'formidable-' . $plugin ) { |
| 741 | 900 | return $addon; |
| 742 | 901 | } |
| 743 | 902 | } |
| 903 | + | |
| 744 | 904 | return false; |
| 745 | 905 | } |
| 746 | 906 | |
| 747 | 907 | /** |
| @@ -753,10 +913,11 @@ | ||
| 753 | 913 | $license_type = ''; |
| 754 | 914 | $addons = self::get_api_addons(); |
| 755 | 915 | |
| 756 | 916 | if ( isset( $addons['error'] ) && isset( $addons['error']['type'] ) ) { |
| 757 | - $license_type = $addons['error']['type']; | |
| 917 | + return $addons['error']['type']; | |
| 758 | 918 | } |
| 919 | + | |
| 759 | 920 | return $license_type; |
| 760 | 921 | } |
| 761 | 922 | |
| 762 | 923 | /** |
| @@ -770,11 +931,11 @@ | ||
| 770 | 931 | public static function get_addon_for_license( $addons, $license ) { |
| 771 | 932 | $download_id = $license->download_id; |
| 772 | 933 | $plugin = array(); |
| 773 | 934 | |
| 774 | - if ( empty( $download_id ) && ! empty( $addons ) ) { | |
| 935 | + if ( ! $download_id && $addons ) { | |
| 775 | 936 | foreach ( $addons as $addon ) { |
| 776 | - if ( strtolower( $license->plugin_name ) === strtolower( $addon['title'] ) ) { | |
| 937 | + if ( 0 === strcasecmp( $license->plugin_name, $addon['title'] ) ) { | |
| 777 | 938 | return $addon; |
| 778 | 939 | } |
| 779 | 940 | } |
| 780 | 941 | } elseif ( isset( $addons[ $download_id ] ) ) { |
| @@ -789,8 +950,11 @@ | ||
| 789 | 950 | * |
| 790 | 951 | * @return void |
| 791 | 952 | */ |
| 792 | 953 | protected static function prepare_addons( &$addons ) { |
| 954 | + // Reset categories to prevent count accumulation across multiple calls. | |
| 955 | + self::$categories = array(); | |
| 956 | + | |
| 793 | 957 | $activate_url = ''; |
| 794 | 958 | |
| 795 | 959 | if ( current_user_can( 'activate_plugins' ) ) { |
| 796 | 960 | $activate_url = add_query_arg( array( 'action' => 'activate' ), admin_url( 'plugins.php' ) ); |
| @@ -802,16 +966,10 @@ | ||
| 802 | 966 | if ( is_numeric( $id ) ) { |
| 803 | 967 | $slug = str_replace( array( '-wordpress-plugin', '-wordpress' ), '', $addon['slug'] ); |
| 804 | 968 | $file_name = $addon['plugin']; |
| 805 | 969 | } else { |
| 806 | - $slug = $id; | |
| 807 | - | |
| 808 | - if ( isset( $addon['file'] ) ) { | |
| 809 | - $base_file = $addon['file']; | |
| 810 | - } else { | |
| 811 | - $base_file = 'formidable-' . $slug; | |
| 812 | - } | |
| 813 | - | |
| 970 | + $slug = $id; | |
| 971 | + $base_file = $addon['file'] ?? 'formidable-' . $slug; | |
| 814 | 972 | $file_name = $base_file . '/' . $base_file . '.php'; |
| 815 | 973 | |
| 816 | 974 | if ( ! isset( $addon['plugin'] ) ) { |
| 817 | 975 | $addon['plugin'] = $file_name; |
| @@ -819,8 +977,13 @@ | ||
| 819 | 977 | } |
| 820 | 978 | |
| 821 | 979 | $addon['installed'] = self::is_installed( $file_name ); |
| 822 | 980 | |
| 981 | + if ( 'highrise' === $slug && ! $addon['installed'] ) { | |
| 982 | + unset( $addons[ $id ] ); | |
| 983 | + continue; | |
| 984 | + } | |
| 985 | + | |
| 823 | 986 | if ( $addon['installed'] && 'formidable-views/formidable-views.php' === $file_name ) { |
| 824 | 987 | $active_views_version = self::get_active_views_version(); |
| 825 | 988 | |
| 826 | 989 | if ( false !== $active_views_version && $slug !== $active_views_version ) { |
| @@ -829,9 +992,9 @@ | ||
| 829 | 992 | } |
| 830 | 993 | |
| 831 | 994 | $addon['activate_url'] = ''; |
| 832 | 995 | |
| 833 | - 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 ) ) { | |
| 834 | 997 | $addon['activate_url'] = add_query_arg( |
| 835 | 998 | array( |
| 836 | 999 | '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $file_name ), |
| 837 | 1000 | 'plugin' => $file_name, |
| @@ -891,13 +1054,13 @@ | ||
| 891 | 1054 | */ |
| 892 | 1055 | protected static function prepare_addon_link( &$link ) { |
| 893 | 1056 | $site_url = 'https://formidableforms.com/'; |
| 894 | 1057 | |
| 895 | - if ( strpos( $link, 'http' ) !== 0 ) { | |
| 1058 | + if ( ! str_starts_with( $link, 'http' ) ) { | |
| 896 | 1059 | $link = $site_url . $link; |
| 897 | 1060 | } |
| 898 | 1061 | |
| 899 | - $link = FrmAppHelper::make_affiliate_url( $link ); | |
| 1062 | + $link = FrmAppHelper::make_affiliate_url( $link ); | |
| 900 | 1063 | |
| 901 | 1064 | $utm = array( |
| 902 | 1065 | 'campaign' => 'addons', |
| 903 | 1066 | ); |
| @@ -987,13 +1150,9 @@ | ||
| 987 | 1150 | |
| 988 | 1151 | self::deactivate_plugin( $plugin, true ); |
| 989 | 1152 | $result = delete_plugins( array( $plugin ) ); |
| 990 | 1153 | |
| 991 | - if ( is_wp_error( $result ) ) { | |
| 992 | - return $result; | |
| 993 | - } | |
| 994 | - | |
| 995 | - return true; | |
| 1154 | + return is_wp_error( $result ) ? $result : true; | |
| 996 | 1155 | } |
| 997 | 1156 | |
| 998 | 1157 | /** |
| 999 | 1158 | * @since 5.0.10 |
| @@ -1000,9 +1159,9 @@ | ||
| 1000 | 1159 | * |
| 1001 | 1160 | * @return string |
| 1002 | 1161 | */ |
| 1003 | 1162 | protected static function get_current_plugin() { |
| 1004 | - if ( empty( self::$plugin ) ) { | |
| 1163 | + if ( ! self::$plugin ) { | |
| 1005 | 1164 | self::$plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'esc_url_raw' ); |
| 1006 | 1165 | } |
| 1007 | 1166 | return self::$plugin; |
| 1008 | 1167 | } |
| @@ -1009,9 +1168,9 @@ | ||
| 1009 | 1168 | |
| 1010 | 1169 | /** |
| 1011 | 1170 | * @since 4.08 |
| 1012 | 1171 | * |
| 1013 | - * @return array|void | |
| 1172 | + * @return mixed[]|null | |
| 1014 | 1173 | */ |
| 1015 | 1174 | protected static function download_and_activate() { |
| 1016 | 1175 | if ( is_admin() ) { |
| 1017 | 1176 | FrmAppHelper::set_current_screen_and_hook_suffix(); |
| @@ -1024,8 +1183,9 @@ | ||
| 1024 | 1183 | if ( is_array( $installed ) && isset( $installed['message'] ) ) { |
| 1025 | 1184 | return $installed; |
| 1026 | 1185 | } |
| 1027 | 1186 | self::handle_addon_action( $installed, 'activate' ); |
| 1187 | + return null; | |
| 1028 | 1188 | } |
| 1029 | 1189 | |
| 1030 | 1190 | /** |
| 1031 | 1191 | * @since 3.04.02 |
| @@ -1055,9 +1215,8 @@ | ||
| 1055 | 1215 | |
| 1056 | 1216 | if ( $show_form ) { |
| 1057 | 1217 | $form = ob_get_clean(); |
| 1058 | 1218 | $message = __( 'Sorry, your site requires FTP authentication. Please download plugins from FormidableForms.com and install them manually.', 'formidable' ); |
| 1059 | - $data = $form; | |
| 1060 | 1219 | $response = array( |
| 1061 | 1220 | 'success' => false, |
| 1062 | 1221 | 'message' => $message, |
| 1063 | 1222 | 'form' => $form, |
| @@ -1102,9 +1261,9 @@ | ||
| 1102 | 1261 | } |
| 1103 | 1262 | |
| 1104 | 1263 | // Create the plugin upgrader with our custom skin. |
| 1105 | 1264 | $installer = new Plugin_Upgrader( new FrmInstallerSkin() ); |
| 1106 | - $installer->install( $download_url ); | |
| 1265 | + $installer->install( $download_url, array( 'overwrite_package' => true ) ); | |
| 1107 | 1266 | |
| 1108 | 1267 | // Flush the cache and return the newly installed plugin basename. |
| 1109 | 1268 | wp_cache_flush(); |
| 1110 | 1269 | |
| @@ -1115,8 +1274,9 @@ | ||
| 1115 | 1274 | 'message' => 'Plugin was not installed. ' . $installer->result, |
| 1116 | 1275 | 'success' => false, |
| 1117 | 1276 | ); |
| 1118 | 1277 | } |
| 1278 | + | |
| 1119 | 1279 | return $plugin; |
| 1120 | 1280 | } |
| 1121 | 1281 | |
| 1122 | 1282 | /** |
| @@ -1206,13 +1366,13 @@ | ||
| 1206 | 1366 | * |
| 1207 | 1367 | * @param string $installed The plugin folder name with file name. |
| 1208 | 1368 | * @param string $action The action type ('activate', 'deactivate', 'uninstall'). |
| 1209 | 1369 | * |
| 1210 | - * @return array|void | |
| 1370 | + * @return mixed[]|null | |
| 1211 | 1371 | */ |
| 1212 | 1372 | protected static function handle_addon_action( $installed, $action ) { |
| 1213 | 1373 | if ( ! $installed || ! $action ) { |
| 1214 | - return; | |
| 1374 | + return null; | |
| 1215 | 1375 | } |
| 1216 | 1376 | |
| 1217 | 1377 | $result = null; |
| 1218 | 1378 | switch ( $action ) { |
| @@ -1232,8 +1392,9 @@ | ||
| 1232 | 1392 | if ( $result->get_error_code() !== 'no_plugin_header' ) { |
| 1233 | 1393 | if ( wp_doing_ajax() ) { |
| 1234 | 1394 | wp_send_json_error( array( 'error' => $result->get_error_message() ) ); |
| 1235 | 1395 | } |
| 1396 | + | |
| 1236 | 1397 | return array( |
| 1237 | 1398 | 'message' => $result->get_error_message(), |
| 1238 | 1399 | 'success' => false, |
| 1239 | 1400 | ); |
| @@ -1247,17 +1408,14 @@ | ||
| 1247 | 1408 | * @return array |
| 1248 | 1409 | */ |
| 1249 | 1410 | private static function get_addon_activation_response() { |
| 1250 | 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 | |
| 1251 | 1413 | |
| 1252 | - $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' ); | |
| 1253 | - | |
| 1254 | - $response = array( | |
| 1414 | + return array( | |
| 1255 | 1415 | 'message' => $message, |
| 1256 | 1416 | 'saveAndReload' => $activating_page, |
| 1257 | 1417 | ); |
| 1258 | - | |
| 1259 | - return $response; | |
| 1260 | 1418 | } |
| 1261 | 1419 | |
| 1262 | 1420 | /** |
| 1263 | 1421 | * Return a string that reflects the page from which the addon is being activated on, |
| @@ -1267,17 +1425,13 @@ | ||
| 1267 | 1425 | */ |
| 1268 | 1426 | private static function get_activating_page() { |
| 1269 | 1427 | $referer = FrmAppHelper::get_server_value( 'HTTP_REFERER' ); |
| 1270 | 1428 | |
| 1271 | - if ( false !== strpos( $referer, 'frm_action=settings' ) ) { | |
| 1429 | + if ( str_contains( $referer, 'frm_action=settings' ) ) { | |
| 1272 | 1430 | return 'settings'; |
| 1273 | 1431 | } |
| 1274 | 1432 | |
| 1275 | - if ( false !== strpos( $referer, 'frm_action=edit' ) ) { | |
| 1276 | - return 'form_builder'; | |
| 1277 | - } | |
| 1278 | - | |
| 1279 | - return ''; | |
| 1433 | + return str_contains( $referer, 'frm_action=edit' ) ? 'form_builder' : ''; | |
| 1280 | 1434 | } |
| 1281 | 1435 | |
| 1282 | 1436 | /** |
| 1283 | 1437 | * Run security checks before installing |
| @@ -1288,12 +1442,14 @@ | ||
| 1288 | 1442 | */ |
| 1289 | 1443 | protected static function install_addon_permissions() { |
| 1290 | 1444 | check_ajax_referer( 'frm_ajax', 'nonce' ); |
| 1291 | 1445 | |
| 1292 | - if ( ! current_user_can( 'activate_plugins' ) || ! self::get_current_plugin() ) { | |
| 1293 | - echo json_encode( true ); | |
| 1294 | - wp_die(); | |
| 1446 | + if ( current_user_can( 'activate_plugins' ) && self::get_current_plugin() ) { | |
| 1447 | + return; | |
| 1295 | 1448 | } |
| 1449 | + | |
| 1450 | + echo json_encode( true ); | |
| 1451 | + wp_die(); | |
| 1296 | 1452 | } |
| 1297 | 1453 | |
| 1298 | 1454 | /** |
| 1299 | 1455 | * @since 4.08 |
| @@ -1302,11 +1458,11 @@ | ||
| 1302 | 1458 | */ |
| 1303 | 1459 | public static function connect_link() { |
| 1304 | 1460 | $auth = get_option( 'frm_connect_token' ); |
| 1305 | 1461 | |
| 1306 | - if ( empty( $auth ) ) { | |
| 1462 | + if ( ! $auth ) { | |
| 1307 | 1463 | $auth = hash( 'sha512', wp_rand() ); |
| 1308 | - update_option( 'frm_connect_token', $auth, 'no' ); | |
| 1464 | + update_option( 'frm_connect_token', $auth, false ); | |
| 1309 | 1465 | } |
| 1310 | 1466 | |
| 1311 | 1467 | $page = FrmAppHelper::simple_get( 'page', 'sanitize_title', 'formidable-settings' ); |
| 1312 | 1468 | $link = 'https://formidableforms.com/api-connect/'; |
| @@ -1336,9 +1492,9 @@ | ||
| 1336 | 1492 | $post_url = FrmAppHelper::get_param( 'file_url', '', 'request', 'sanitize_text_field' ); |
| 1337 | 1493 | |
| 1338 | 1494 | // The download link is not required if already installed. |
| 1339 | 1495 | $is_installed = FrmAppHelper::pro_is_included(); |
| 1340 | - $file_missing = ! $is_installed && empty( $post_url ); | |
| 1496 | + $file_missing = ! $is_installed && ! $post_url; | |
| 1341 | 1497 | |
| 1342 | 1498 | if ( ! $post_auth || $file_missing ) { |
| 1343 | 1499 | return false; |
| 1344 | 1500 | } |
| @@ -1344,14 +1500,9 @@ | ||
| 1344 | 1500 | } |
| 1345 | 1501 | |
| 1346 | 1502 | // Verify auth. |
| 1347 | 1503 | $auth = get_option( 'frm_connect_token' ); |
| 1348 | - | |
| 1349 | - if ( empty( $auth ) || ! hash_equals( $auth, $post_auth ) ) { | |
| 1350 | - return false; | |
| 1351 | - } | |
| 1352 | - | |
| 1353 | - return true; | |
| 1504 | + return $auth && hash_equals( $auth, $post_auth ); | |
| 1354 | 1505 | } |
| 1355 | 1506 | |
| 1356 | 1507 | /** |
| 1357 | 1508 | * Install and/or activate the add-on file. |
| @@ -1378,9 +1529,9 @@ | ||
| 1378 | 1529 | } |
| 1379 | 1530 | } |
| 1380 | 1531 | |
| 1381 | 1532 | // If empty license, save it now. |
| 1382 | - if ( empty( self::get_pro_license() ) && function_exists( 'load_formidable_pro' ) ) { | |
| 1533 | + if ( ! self::get_pro_license() && function_exists( 'load_formidable_pro' ) ) { | |
| 1383 | 1534 | load_formidable_pro(); |
| 1384 | 1535 | $license = stripslashes( FrmAppHelper::get_param( 'key', '', 'request', 'sanitize_text_field' ) ); |
| 1385 | 1536 | |
| 1386 | 1537 | if ( ! $license ) { |
| @@ -1506,16 +1657,18 @@ | ||
| 1506 | 1657 | } |
| 1507 | 1658 | |
| 1508 | 1659 | $class = ! empty( $atts['class'] ) ? $atts['class'] : ''; |
| 1509 | 1660 | |
| 1510 | - if ( strpos( $class, 'frm-button' ) === false ) { | |
| 1661 | + if ( ! str_contains( $class, 'frm-button' ) ) { | |
| 1511 | 1662 | $class .= ' frm-button-secondary frm-button-sm'; |
| 1512 | 1663 | } |
| 1664 | + // phpcs:disable Generic.WhiteSpace.ScopeIndent | |
| 1513 | 1665 | ?> |
| 1514 | - <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 ?> | |
| 1515 | 1667 | <?php echo esc_html( $text ); ?> |
| 1516 | 1668 | </a> |
| 1517 | 1669 | <?php |
| 1670 | + // phpcs:enable Generic.WhiteSpace.ScopeIndent | |
| 1518 | 1671 | } |
| 1519 | 1672 | |
| 1520 | 1673 | /** |
| 1521 | 1674 | * @since 3.04.02 |
| @@ -1560,9 +1713,8 @@ | ||
| 1560 | 1713 | $allowed_url_list = apply_filters( 'frm_allowed_external_urls', $allowed_url_list ); |
| 1561 | 1714 | |
| 1562 | 1715 | if ( ! is_array( $allowed_url_list ) ) { |
| 1563 | 1716 | _doing_it_wrong( __METHOD__, 'Only an array of URLs could be used within this filter.', '6.3.1' ); |
| 1564 | - | |
| 1565 | 1717 | return array(); |
| 1566 | 1718 | } |
| 1567 | 1719 | |
| 1568 | 1720 | return $allowed_url_list; |
| @@ -1586,9 +1738,9 @@ | ||
| 1586 | 1738 | $requires = FrmFormsHelper::get_plan_required( $dates ); |
| 1587 | 1739 | } |
| 1588 | 1740 | |
| 1589 | 1741 | if ( ! isset( $requires ) || ! is_string( $requires ) ) { |
| 1590 | - $requires = ''; | |
| 1742 | + return ''; | |
| 1591 | 1743 | } |
| 1592 | 1744 | |
| 1593 | 1745 | return $requires; |
| 1594 | 1746 | } |