Skip to content

Fatal error on first opt-in when plugin has no paid plans (count() on bool _plans) #879

Open

Description

@hammad-wpbrigade

🐞 bug report

Behavior:

  • What is the issue? (*)
    On a fresh first opt-in for a free-only plugin ('has_paid_plans' => false), two problems occur:
  1. Warning: Undefined property: stdClass::$plan_id in .../freemius/includes/entities/class-fs-site.php on line 123
    FS_Site::__construct() reads $site->plan_id without checking the property exists.

  2. Fatal error: Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, bool given in .../freemius/includes/class-freemius.php:19847
    _store_plans() calls count( $this->_plans ) while $this->_plans is still its initial value false.

Reproduction: activate a free-only Freemius plugin on a clean WordPress install (PHP 8+) and complete the opt-in for the first time.

  • What is the expected behavior?
    Opt-in completes without warnings or fatal errors when the plugin has no paid plans / the install object has no plan_id.

Versions: (*)

  • Freemius SDK Version: 2.13.1 (code path also present in 2.13.4 / current develop)
  • WordPress Version: 6.9
  • PHP Version: 8.2

Plugin / Theme: (*)

  • Name: [redacted]
  • Slug: [redacted]
  • Freemius ID: [redacted]

Additional Information:

Image

Activity

  1. hammad-wpbrigade commented on Jul 29, 2026

    @hammad-wpbrigade
    Author
  2. Tobias-Conrad commented on Oct 7, 2026

    @Tobias-Conrad

    Both symptoms in this report are still present on master (2.13.4) and on 2.13.5, and they share one root cause: $this->_plans defaults to false and _set_account() only assigns it when a plan list is passed, so on a fresh first opt-in without paid plans _store_plans() still calls count( $this->_plans ) on false (fatal on PHP 8), and FS_Site::__construct() reads $site->plan_id which the payload can omit (warning).

    Opened a minimal fix for both with the class's existing ! is_array( $this->_plans ) convention: #888

    Reproduced on a clean WordPress, PHP 8.2 first opt-in before the change; both diagnostics gone after. php -l clean.

  3. patzman-one-two-three commented on Oct 8, 2026

    @patzman-one-two-three

    Also reproducible on SDK 2.13.4 (PHP 8.2) for a plugin with paid plans: if the plans request inside setup_network_account() → _sync_plans() fails (timeout/network/API error), $this->_plans stays false and the subsequent _set_account() → _store_account() → _store_plans() throws TypeError: count(): Argument #1 ($value) must be of type Countable|array, bool given (class-freemius.php, _store_plans). With a successful plans response the flow completes normally.

    A guard such as if ( ! is_array( $this->_plans ) ) { $this->_plans = array(); } at the start of _store_plans() (or initialising the property to array()) prevents the fatal error. We currently ship the unmodified SDK and would appreciate an upstream fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions