diff --git a/.phpstan/stubs/includes/entities/class-fs-entity.php b/.phpstan/stubs/includes/entities/class-fs-entity.php new file mode 100644 index 00000000..a453a619 --- /dev/null +++ b/.phpstan/stubs/includes/entities/class-fs-entity.php @@ -0,0 +1,93 @@ + + */ + function fs_get_object_public_vars($object) { + return []; + } + + class FS_Entity { + + /** + * @var int + */ + public $id; + + /** + * @var string + */ + public $updated; + + /** + * @var string + */ + public $created; + + /** + * FS_Entity constructor. + * @param mixed $entity + */ + function __construct($entity = false) { + // Implementation here + } + + /** + * @return string + */ + static function get_type() { + // Implementation here + return ''; + } + + /** + * @param mixed $entity1 + * @param mixed $entity2 + * @return bool + */ + static function equals($entity1, $entity2) { + // Implementation here + return false; + } + + /** + * @var bool + */ + private $_is_updated = false; + + /** + * @param string $key + * @param bool $val + * @return bool + */ + function update($key, $val = false) { + return false; + } + + /** + * @return bool + */ + function is_updated() { + // Implementation here + return $this->_is_updated; + } + + /** + * @param int $id + * @return bool + */ + static function is_valid_id($id) { + // Implementation here + return false; + } + + /** + * @return string + */ + public static function get_class_name() { + // Implementation here + return ''; + } + } diff --git a/.phpstan/stubs/includes/fs-plugin-info-dialog.php b/.phpstan/stubs/includes/fs-plugin-info-dialog.php new file mode 100644 index 00000000..5e5d134c --- /dev/null +++ b/.phpstan/stubs/includes/fs-plugin-info-dialog.php @@ -0,0 +1,129 @@ + + */ + public $pricing; + + /** + * @var array + */ + public $features; + + /** + * FS_Plugin_Plan constructor. + * @param object|bool $plan + */ + public function __construct($plan = false) {} + + /** + * @return string + */ + public static function get_type() {} + + /** + * @return bool + */ + public function is_free() {} + + /** + * @return bool + */ + public function has_technical_support() {} + + /** + * @return bool + */ + public function has_trial() {} + } diff --git a/includes/class-freemius.php b/includes/class-freemius.php index 4512b47a..119f0731 100755 --- a/includes/class-freemius.php +++ b/includes/class-freemius.php @@ -987,10 +987,13 @@ private static function migrate_install_plan_to_plan_id( FS_Storage $storage, $b $module_type = $storage->get_module_type(); $module_slug = $storage->get_module_slug(); + /** + * @var FS_Site[] $installs + */ $installs = self::get_all_sites( $module_type, $blog_id ); $install = isset( $installs[ $module_slug ] ) ? $installs[ $module_slug ] : null; - if ( ! is_object( $install ) ) { + if ( is_null( $install ) ) { return; } @@ -1571,8 +1574,8 @@ private function register_constructor_hooks() { ); $this->add_filter( 'after_code_type_change', array( &$this, '_after_code_type_change' ) ); - add_action( 'admin_init', array( &$this, '_add_trial_notice' ) ); // @phpstan-ignore-line - add_action( 'admin_init', array( &$this, '_add_affiliate_program_notice' ) ); // @phpstan-ignore-line + add_action( 'admin_init', array( &$this, '_add_trial_notice' ) ); + add_action( 'admin_init', array( &$this, '_add_affiliate_program_notice' ) ); add_action( 'admin_enqueue_scripts', array( &$this, '_enqueue_common_css' ) ); /** @@ -1872,7 +1875,7 @@ private function unregister_uninstall_hook() { */ private function clear_module_main_file_cache( $store_prev_path = true ) { if ( ! isset( $this->_storage->plugin_main_file ) || - empty( $this->_storage->plugin_main_file->path ) + empty( $this->_storage->plugin_main_file->path ) ) { return; } @@ -1888,6 +1891,9 @@ private function clear_module_main_file_cache( $store_prev_path = true ) { */ unset( $this->_storage->plugin_main_file->path ); } else { + /** + * @var stdClass $plugin_main_file + */ $plugin_main_file = clone $this->_storage->plugin_main_file; // Store cached path (2nd layer cache). @@ -2745,7 +2751,7 @@ function cancel_subscription_or_trial_ajax_action() { $this->check_ajax_referer( 'cancel_subscription_or_trial' ); - $result = $this->cancel_subscription_or_trial( fs_request_get( 'plugin_id', $this->get_id() ), false ); + $result = $this->cancel_subscription_or_trial( fs_request_get( 'plugin_id', $this->get_id() ) ); if ( $this->is_api_error( $result ) ) { $this->shoot_ajax_failure( $result->error->message ); @@ -5960,9 +5966,6 @@ function is_org_repo_compliant() { private function get_cron_data( $name ) { $this->_logger->entrance( $name ); - /** - * @var object $cron_data - */ return $this->_storage->get( "{$name}_cron", null ); } @@ -7688,7 +7691,7 @@ private function maybe_network_activate_addon_license( $license = null ) { } } - if ( ! empty( $site_ids ) ) { + if ( 0 < count( $site_ids ) ) { $this->activate_license_on_many_sites( $user, $license->secret_key, $site_ids ); } } @@ -8183,7 +8186,7 @@ function _deactivate_plugin_hook() { unset( $this->_storage->sticky_optin_added_ms ); } - if ( ! empty( $storage_keys_for_removal ) ) { + if ( count( $storage_keys_for_removal ) > 0 ) { $sites = self::get_sites(); foreach ( $sites as $site ) { @@ -8593,7 +8596,6 @@ function skip_connection( $network_or_blog_ids = false ) { * @since 2.0.0 * * @param int|null $blog_id - * @param bool $send_skip */ private function skip_site_connection( $blog_id = null ) { $this->_logger->entrance(); @@ -8627,7 +8629,7 @@ private function update_plugin_version_event() { * @author Vova Feldman (@svovaf) * @since 2.0.0 * - * @param array [string]array $plugins + * @param array $plugins * * @return string */ @@ -9042,7 +9044,7 @@ private function get_install_data_for_api( * @author Vova Feldman (@svovaf) * @since 2.0.0 * - * @param string[] string $override + * @param string[] $override * @param bool $only_diff * @param bool $is_keepalive * @param bool $include_plugins Since 1.1.8 by default include plugin changes. @@ -9229,7 +9231,7 @@ private function get_installs_data_for_api( * * @param array $site * @param FS_Site $install - * @param string[] string $override + * @param string[] $override * * @return array */ @@ -9351,7 +9353,7 @@ function send_clone_resolution_update( $resolution_type, $clone_context_install * @author Vova Feldman (@svovaf) * @since 1.0.9 * - * @param string[] string $override + * @param string[] $override * @param bool $flush * @param bool $is_two_way_sync @since 2.5.0 If true and there's a successful API request, the install sync cron will be cleared. * @@ -9424,11 +9426,11 @@ private function send_install_update( $override = array(), $flush = false, $is_t * @author Vova Feldman (@svovaf) * @since 2.0.0 * - * @param string[] string $override + * @param string[] $override * @param bool $flush * @param bool $is_two_way_sync @since 2.5.0 If true and there's a successful API request, the install sync cron will be cleared. * - * @return false|object|string + * @return object */ private function send_installs_update( $override = array(), $flush = false, $is_two_way_sync = false ) { $this->_logger->entrance(); @@ -9444,7 +9446,7 @@ private function send_installs_update( $override = array(), $flush = false, $is_ $installs_data = $this->get_installs_data_for_api( $override, ! $flush, $should_send_keepalive ); if ( empty( $installs_data ) ) { - return false; + return; } if ( $is_two_way_sync ) { @@ -9511,7 +9513,7 @@ private function maybe_sync_install_user() { * @author Vova Feldman (@svovaf) * @since 1.0.9 * - * @param string[] string $override + * @param string[] $override * @param bool $flush */ function sync_install( $override = array(), $flush = false ) { @@ -9540,19 +9542,13 @@ function sync_install( $override = array(), $flush = false ) { * @author Vova Feldman (@svovaf) * @since 1.0.9 * - * @param string[] string $override + * @param string[] $override * @param bool $flush */ private function sync_installs( $override = array(), $flush = false ) { $this->_logger->entrance(); $result = $this->send_installs_update( $override, $flush, true ); - - if ( false === $result ) { - // No sync required. - return; - } - if ( ! $this->is_api_result_object( $result, 'installs' ) ) { // Failed to sync, don't update locally. return; @@ -9675,7 +9671,7 @@ function _uninstall_plugin_event( $check_user = true ) { $params = array(); $uninstall_reason = null; - if ( isset( $this->_storage->uninstall_reason ) ) { + if ( isset( $this->_storage->uninstall_reason ) && is_object( $this->_storage->uninstall_reason ) ) { $uninstall_reason = $this->_storage->uninstall_reason; $params['reason_id'] = $uninstall_reason->id; $params['reason_info'] = $uninstall_reason->info; @@ -9683,8 +9679,8 @@ function _uninstall_plugin_event( $check_user = true ) { if ( ! $this->is_registered() ) { // Send anonymous uninstall event only if user submitted a feedback. - if ( isset( $uninstall_reason ) ) { - if ( isset( $uninstall_reason->is_anonymous ) && ! $uninstall_reason->is_anonymous ) { + if ( $uninstall_reason !== null ) { + if ( ! empty( $uninstall_reason->is_anonymous ) ) { $this->opt_in( false, false, false, false, true ); } else { $params['uid'] = $this->get_anonymous_id(); @@ -13562,13 +13558,11 @@ function is_migration() { * @param array $sites * @param int $blog_id * - * @return array { - * @var bool $success - * @var string $error - * @var string $next_page - * } + * @return array * - * @uses Freemius::activate_license() + * @property bool $success + * @property string $error + * @property string $next_page */ function activate_migrated_license( $license_key, @@ -13665,11 +13659,11 @@ function should_use_external_pricing() { * @param bool|null $is_diagnostic_tracking_allowed Since 2.5.0.2 to allow license activation with minimal data footprint. * * - * @return array { - * @var bool $success - * @var string $error - * @var string $next_page - * } + * @return array + * + * @property bool $success + * @property string $error + * @property string $next_page */ private function activate_license( $license_key, @@ -13757,7 +13751,7 @@ private function activate_license( $result = $fs->activate_license_on_many_installs( $user, $license_key, $blog_2_install_map ); } - if ( true === $result && ! empty( $site_ids ) ) { + if ( true === $result && ! count( $site_ids ) > 0 ) { $result = $fs->activate_license_on_many_sites( $user, $license_key, $site_ids ); } } else { @@ -13976,6 +13970,7 @@ private function get_parent_and_addons_installs_info() { ) ); + $installed_addons_ids_map = array_flip( $installed_addons_ids ); foreach ( $addons_ids as $addon_id ) { $is_installed = isset( $installed_addons_ids_map[ $addon_id ] ); @@ -14011,7 +14006,8 @@ function _network_activate_ajax_action() { $this : $this->get_addon_instance( $plugin_id ); - $error = false; + $error = false; + $next_page = ''; $sites = fs_request_get( 'sites', array(), 'post' ); if ( is_array( $sites ) && ! empty( $sites ) ) { @@ -14027,10 +14023,7 @@ function _network_activate_ajax_action() { $total_sites = count( $sites ); $total_sites_to_delegate = count( $sites_by_action['delegate'] ); - - $next_page = ''; - - $has_any_install = fs_request_get_bool( 'has_any_install' ); + $has_any_install = fs_request_get_bool( 'has_any_install' ); if ( $total_sites === $total_sites_to_delegate && ! $this->is_network_upgrade_mode() && @@ -16379,6 +16372,11 @@ private static function _encrypt( $str ) { return $fn( $str ); } + /** + * @param $str + * + * @return mixed|null + */ static function _decrypt( $str ) { if ( is_null( $str ) ) { return null; @@ -16980,7 +16978,6 @@ function get_opt_in_params( $override_with = array(), $network_level_or_blog_id * @param bool $redirect * * @return string|object - * @use WP_Error */ function opt_in( $email = false, @@ -17149,12 +17146,14 @@ function opt_in( * @link https://themes.trac.wordpress.org/ticket/46134#comment:9 * @link https://themes.trac.wordpress.org/ticket/46134#comment:12 * @link https://themes.trac.wordpress.org/ticket/46134#comment:14 + * + * @var stdClass $decoded The decoded object is expected to be UserPlugin entity, but since we do not have this Entity in the SDK, we made this a StdClass */ $decoded = is_string( $response['body'] ) ? json_decode( $response['body'] ) : null; - if ( empty( $decoded ) ) { + if ( ! is_object( $decoded ) ) { return false; } @@ -19615,7 +19614,7 @@ function has_filter( $tag, $function_to_check = false ) { * @author Vova Feldman (@svovaf) * @since 1.1.6 * - * @param string[] string $key_value + * @param string[] $key_value * * @uses fs_override_i18n() */ @@ -19642,9 +19641,9 @@ private function _store_site( $store = true, $network_level_or_blog_id = null, F $site = $this->_site; } - if ( !isset( $site ) || !is_object($site) || empty( $site->id ) ) { + // @phpstan-ignore-next-line Variable $site in isset() always exists and is not nullable + if ( !isset( $site ) || !is_object( $site ) || empty( $site->id ) ) { $this->_logger->error( "Empty install ID, can't store site." ); - return; } @@ -19776,10 +19775,8 @@ private function _store_licenses( $store = true, $module_id = false, $licenses = } } - if ( ! empty( $new_user_licenses_map ) ) { - // Add new licenses. - $all_licenses[ $module_id ] = array_merge( array_values( $new_user_licenses_map ), $all_licenses[ $module_id ] ); - } + // Add new licenses. + $all_licenses[ $module_id ] = array_merge( array_values( $new_user_licenses_map ), $all_licenses[ $module_id ] ); $licenses = $all_licenses[ $module_id ]; } @@ -20093,7 +20090,11 @@ private function _handle_account_user_sync() { $api = $this->get_api_user_scope(); - // Get user's information. + /** + * Get user's information. + * + * @var FS_User $user + */ $user = $api->get( '/', true ); if ( isset( $user->id ) ) { @@ -21022,14 +21023,16 @@ private function _sync_plugin_license( // Find the current context install. $site = null; - foreach ( $result->installs as $install ) { - if ( $install->id == $this->_site->id ) { - $site = new FS_Site( $install ); - } else { - $address = trailingslashit( fs_strip_url_protocol( $install->url ) ); - $blog_id = $address_to_blog_map[ $address ]; + if ( is_object( $result ) && is_array( $result->installs ) ) { + foreach ( $result->installs as $install ) { + if ( $install->id == $this->_site->id ) { + $site = new FS_Site( $install ); + } else { + $address = trailingslashit( fs_strip_url_protocol( $install->url ) ); + $blog_id = $address_to_blog_map[ $address ]; - $this->_store_site( true, $blog_id, new FS_Site( $install ) ); + $this->_store_site( true, $blog_id, new FS_Site( $install ) ); + } } } } @@ -22576,8 +22579,8 @@ private function complete_change_owner() { * @author Leo Fajardo (@leorw) * @since 2.3.2 * - * @param number $user_id - * @param array[string]number $install_ids_by_slug_map + * @param number $user_id + * @param array $install_ids_by_slug_map * */ private function complete_ownership_change_by_license( $user_id, $install_ids_by_slug_map ) { @@ -25778,9 +25781,6 @@ function _maybe_show_gdpr_admin_notice() { return; } - /** - * @var $current_wp_user WP_User - */ $current_wp_user = self::_get_current_wp_user(); /** diff --git a/includes/class-fs-plugin-updater.php b/includes/class-fs-plugin-updater.php index dc233da4..aae43de1 100755 --- a/includes/class-fs-plugin-updater.php +++ b/includes/class-fs-plugin-updater.php @@ -534,9 +534,8 @@ function pre_set_site_transient_update_plugins_filter( $transient_data ) { return $transient_data; } - if ( empty( $transient_data ) || - defined( 'WP_FS__UNINSTALL_MODE' ) - ) { + // @phpstan-ignore-next-line + if ( empty( $transient_data ) || defined( 'WP_FS__UNINSTALL_MODE' ) ) { return $transient_data; } @@ -871,7 +870,7 @@ function delete_update_data() { * @param string $action * @param object $args * - * @return bool|mixed + * @return bool|object The plugin information or false on failure. */ static function _fetch_plugin_info_from_repository( $action, $args ) { $url = $http_url = 'http://api.wordpress.org/plugins/info/1.2/'; @@ -1093,7 +1092,7 @@ function plugins_api_filter( $data, $action = '', $args = null ) { false ); - if ( ! empty( $addon_plugin_data ) ) { + if ( ! empty( $addon_plugin_data['Version'] ) ) { $addon_version = $addon_plugin_data['Version']; } } @@ -1112,12 +1111,16 @@ function plugins_api_filter( $data, $action = '', $args = null ) { if ( ! $plugin_in_repo ) { $data = $args; - // Fetch as much as possible info from local files. + /** + * Fetch as much as possible info from local files. + * + * @var stdClass $data + */ $plugin_local_data = $this->_fs->get_plugin_data(); $data->name = $plugin_local_data['Name']; $data->author = $plugin_local_data['Author']; $data->sections = array( - 'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.', + 'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.' ); // @todo Store extra plugin info on Freemius or parse readme.txt markup. @@ -1132,7 +1135,12 @@ function plugins_api_filter( $data, $action = '', $args = null ) { $addon_version : $this->_fs->get_plugin_version(); - // Get plugin's newest update. + /** + * Get plugin's newest update. + * + * @var FS_Plugin_Tag $new_version + * @var object $data + */ $new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false, $plugin_version ); if ( ! is_object( $new_version ) || empty( $new_version->version ) ) { @@ -1443,7 +1451,6 @@ function install_and_activate_plugin( $plugin_id = false ) { // Pass through the error from WP_Filesystem if one was raised. if ( $wp_filesystem instanceof WP_Filesystem_Base && - is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) { $error_message = $wp_filesystem->errors->get_error_message(); diff --git a/includes/class-fs-storage.php b/includes/class-fs-storage.php index 1028b113..e0bee32c 100644 --- a/includes/class-fs-storage.php +++ b/includes/class-fs-storage.php @@ -21,6 +21,14 @@ * @property bool|null $is_diagnostic_tracking_allowed * @property object $sync_cron * @property bool|int $install_timestamp + * @property bool $is_whitelabeled + * @property mixed $beta_data + * @property bool $expired_license_notice_shown + * @property bool $has_trial_plan + * @property bool $trial_promotion_shown + * @property bool $affiliate_program_notice_shown + * @property bool $is_pending_activation + * @property bool $pending_license_key */ class FS_Storage { /** @@ -32,6 +40,196 @@ class FS_Storage { */ private $_storage; + /** + * @var int Timestamp of the last load. + */ + public $last_load_timestamp; + + /** + * @var bool Indicates if the network is activated. + */ + public $is_network_activated; + + /** + * @var string Last version of the SDK. + */ + public $sdk_last_version; + + /** + * @var string Current version of the SDK. + */ + public $sdk_version; + + /** + * @var bool Indicates if the SDK upgrade mode is active. + */ + public $sdk_upgrade_mode; + + /** + * @var bool Indicates if the SDK downgrade mode is active. + */ + public $sdk_downgrade_mode; + + /** + * @var string Last version of the plugin. + */ + public $plugin_last_version; + + /** + * @var string Current version of the plugin. + */ + public $plugin_version; + + /** + * @var bool Indicates if the plugin upgrade mode is active. + */ + public $plugin_upgrade_mode; + + /** + * @var bool Indicates if the plugin downgrade mode is active. + */ + public $plugin_downgrade_mode; + + /** + * @var bool Indicates if the plugin is a new install. + */ + public $is_plugin_new_install; + + /** + * @var bool Indicates if the user is anonymous. + */ + public $is_anonymous; + + /** + * @var bool Indicates if the user is anonymous in multisite. + */ + public $is_anonymous_ms; + + /** + * @var bool Indicates if the network is connected. + */ + public $is_network_connected; + + /** + * @var int Network user ID. + */ + public $network_user_id; + + /** + * @var bool Indicates if the plugin was loaded. + */ + public $was_plugin_loaded; + + /** + * @var bool Handle GDPR admin notice. + */ + public $handle_gdpr_admin_notice; + + /** + * @var object Main file of the plugin. + */ + public $plugin_main_file; + + /** + * @var bool Indicates if license activation is required. + */ + public $require_license_activation; + + /** + * @var bool Connectivity test status. + */ + public $connectivity_test; + + /** + * @var bool Indicates if the previous state was premium. + */ + public $prev_is_premium; + + /** + * @var int Activation timestamp. + */ + public $activation_timestamp; + + /** + * @var bool Indicates if sticky opt-in was added. + */ + public $sticky_optin_added; + + /** + * @var bool Indicates if sticky opt-in was added in multisite. + */ + public $sticky_optin_added_ms; + + /** + * @var string Previous theme. + */ + public $previous_theme; + + /** + * @var int Clone ID. + */ + public $clone_id; + + /** + * @var string Last license key. + */ + public $last_license_key; + + /** + * @var int Last license user ID. + */ + public $last_license_user_id; + + /** + * @var string Last license user key. + */ + public $last_license_user_key; + + /** + * @var array Subscriptions. + */ + public $subscriptions; + + /** + * @var bool License migration status. + */ + public $license_migration; + + /** + * @var array Affiliate application data. + */ + public $affiliate_application_data; + + /** + * @var int Previous user ID. + */ + public $prev_user_id; + + /** + * @var bool Indicates if the user was recovered from install. + */ + public $user_was_recovered_from_install; + + /** + * @var int Number of user recovery attempts from install. + */ + public $user_recovery_from_install_attempts; + + /** + * @var int Timestamp of the last user recovery attempt from install. + */ + public $user_recovery_from_install_last_attempt_timestamp; + + /** + * @var object Reason for uninstall. + */ + public $uninstall_reason; + + /** + * @var array Pending sites information. + */ + public $pending_sites_info; + /** * @var FS_Key_Value_Storage Network level storage. */ diff --git a/includes/entities/class-fs-entity.php b/includes/entities/class-fs-entity.php index ce281f45..7558ff3e 100755 --- a/includes/entities/class-fs-entity.php +++ b/includes/entities/class-fs-entity.php @@ -88,8 +88,8 @@ static function equals( $entity1, $entity2 ) { * @author Vova Feldman (@svovaf) * @since 1.0.9 * - * @param string|array[string]mixed $key - * @param string|bool $val + * @param string|array $key + * @param string|bool $val * * @return bool */ @@ -156,4 +156,4 @@ static function is_valid_id($id){ public static function get_class_name() { return get_called_class(); } - } \ No newline at end of file + } diff --git a/includes/fs-core-functions.php b/includes/fs-core-functions.php index 09bb0b48..83b36e82 100755 --- a/includes/fs-core-functions.php +++ b/includes/fs-core-functions.php @@ -1389,8 +1389,8 @@ function fs_esc_html_echo_inline( $text, $key = '', $slug = 'freemius' ) { * @author Vova Feldman (@svovaf) * @since 1.1.6 * - * @param array[string]string $key_value - * @param string $slug + * @param array $key_value + * @param string $slug * * @global $fs_text_overrides */ diff --git a/includes/fs-essential-functions.php b/includes/fs-essential-functions.php index 84ffcbe0..ffd98e41 100644 --- a/includes/fs-essential-functions.php +++ b/includes/fs-essential-functions.php @@ -250,6 +250,9 @@ function fs_update_sdk_newest_version( $sdk_relative_path, $plugin_file = false global $fs_active_plugins; + /** + * @var stdClass $newest_sdk + */ $newest_sdk = $fs_active_plugins->plugins[ $sdk_relative_path ]; if ( ! is_string( $plugin_file ) ) { @@ -415,4 +418,4 @@ function fs_fallback_to_newest_active_sdk() { fs_update_sdk_newest_version( $newest_sdk_path, $newest_sdk_data->plugin_path ); } } - } \ No newline at end of file + } diff --git a/includes/fs-plugin-info-dialog.php b/includes/fs-plugin-info-dialog.php index 69bb6ce4..04df244f 100755 --- a/includes/fs-plugin-info-dialog.php +++ b/includes/fs-plugin-info-dialog.php @@ -78,9 +78,9 @@ function __construct( Freemius $fs ) { * @author Vova Feldman (@svovaf) * @since 1.0.6 * - * @param array $data - * @param string $action - * @param object|null $args + * @param object|array $data + * @param string $action + * @param object|null $args * * @return array|null */ @@ -188,6 +188,9 @@ function _get_addon_info_filter( $data, $action = '', $args = null ) { $latest = null; + /** + * @var stdClass $data + */ if ( ! $has_paid_plan && $selected_addon->is_wp_org_compliant ) { $repo_data = FS_Plugin_Updater::_fetch_plugin_info_from_repository( 'plugin_information', (object) array( @@ -201,8 +204,7 @@ function _get_addon_info_filter( $data, $action = '', $args = null ) { ) ) ); - if ( ! empty( $repo_data ) ) { - $data = $repo_data; + if ( ! is_object( $repo_data ) ) { $data->wp_org_missing = false; } else { // Couldn't find plugin on .org. @@ -229,7 +231,7 @@ function _get_addon_info_filter( $data, $action = '', $args = null ) { false ); - if ( ! empty( $addon_plugin_data ) ) { + if ( ! empty( $addon_plugin_data['Version'] ) ) { $current_addon_version = $addon_plugin_data['Version']; } } @@ -493,12 +495,12 @@ private function get_actions_dropdown( $api, $plan = null ) { * @author Vova Feldman (@svovaf) * @since 1.1.7 * - * @param object $api - * @param FS_Plugin_Plan $plan + * @param object $api + * @param bool|FS_Plugin_Plan $plan * * @return string */ - private function get_checkout_cta( $api, $plan = null ) { + private function get_checkout_cta( $api, $plan = false ) { if ( empty( $api->checkout_link ) || ! isset( $api->plans ) || ! is_array( $api->plans ) || @@ -535,6 +537,9 @@ private function get_checkout_cta( $api, $plan = null ) { restore_current_blog(); } + /** + * @var stdClass $api + */ return '' . esc_html( ! $plan->has_trial() ? ( @@ -763,6 +768,9 @@ private function get_plugin_actions( $api ) { $download_latest_action = ''; + /** + * @var stdClass $api + */ if ( ! empty( $api->download_link ) && ( $can_download_free_version || $can_download_premium_version ) @@ -1092,6 +1100,7 @@ function install_plugin_information() { /** * @var FS_Plugin_Plan $plan + * @var stdClass $api */ ?> pricing[0] ?> @@ -1310,6 +1319,11 @@ class="fs-annual-discount">

slug ) ?>

    + version ) ) { ?>
  • slug ); ?> diff --git a/includes/managers/class-fs-admin-menu-manager.php b/includes/managers/class-fs-admin-menu-manager.php index f4d3f0b8..e01a5709 100644 --- a/includes/managers/class-fs-admin-menu-manager.php +++ b/includes/managers/class-fs-admin-menu-manager.php @@ -154,7 +154,7 @@ private function get_bool_option( &$options, $key, $default = false ) { * @param bool $is_addon */ function init( $menu, $is_addon = false ) { - $this->_menu_exists = ( isset( $menu['slug'] ) && ! empty( $menu['slug'] ) ); + $this->_menu_exists = ( ! empty( $menu['slug'] ) ); $this->_network_menu_exists = ( ! empty( $menu['network'] ) && true === $menu['network'] ); $this->_menu_slug = ( $this->_menu_exists ? $menu['slug'] : $this->_module_unique_affix ); @@ -168,7 +168,7 @@ function init( $menu, $is_addon = false ) { // @deprecated $this->_parent_type = 'page'; - if ( isset( $menu ) ) { + if ( is_array( $menu ) ) { if ( ! $is_addon ) { $this->_default_submenu_items = array( 'contact' => $this->get_bool_option( $menu, 'contact', true ), @@ -318,13 +318,14 @@ function is_submenu_item_visible( $id, $default = true, $ignore_menu_existence = return false; } - return fs_apply_filter( - $this->_module_unique_affix, - 'is_submenu_visible', - $this->get_bool_option( $this->_default_submenu_items, $id, $default ), - $id - ); - } + // @phpstan-ignore-next-line + return fs_apply_filter( + $this->_module_unique_affix, + 'is_submenu_visible', + $this->get_bool_option( $this->_default_submenu_items, $id, $default ), + $id + ); + } /** * Calculates admin settings menu slug. @@ -1003,4 +1004,4 @@ function add_subpage_and_update( $function ); } - } \ No newline at end of file + } diff --git a/includes/managers/class-fs-cache-manager.php b/includes/managers/class-fs-cache-manager.php index 7f2d850c..d1fbb377 100755 --- a/includes/managers/class-fs-cache-manager.php +++ b/includes/managers/class-fs-cache-manager.php @@ -160,6 +160,9 @@ function has_valid( $key, $expiration = null ) { function get( $key, $default = null ) { $this->_logger->entrance( 'key = ' . $key ); + /** + * @var stdClass $cache_entry + */ $cache_entry = $this->_options->get_option( $key, false ); if ( is_object( $cache_entry ) && @@ -184,6 +187,9 @@ function get( $key, $default = null ) { function get_valid( $key, $default = null ) { $this->_logger->entrance( 'key = ' . $key ); + /** + * @var stdClass $cache_entry + */ $cache_entry = $this->_options->get_option( $key, false ); if ( is_object( $cache_entry ) && @@ -271,6 +277,9 @@ function purge( $key ) { function update_expiration( $key, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) { $this->_logger->entrance( 'key = ' . $key ); + /** + * @var stdClass $cache_entry + */ $cache_entry = $this->_options->get_option( $key, false ); if ( ! is_object( $cache_entry ) || @@ -323,4 +332,4 @@ function migrate_to_network() { } #endregion - } \ No newline at end of file + } diff --git a/includes/managers/class-fs-debug-manager.php b/includes/managers/class-fs-debug-manager.php index 5364712d..72ff7aa9 100644 --- a/includes/managers/class-fs-debug-manager.php +++ b/includes/managers/class-fs-debug-manager.php @@ -9,6 +9,11 @@ class FS_DebugManager { + /** + * @var mixed + */ + private static $_accounts; + /** * @author Vova Feldman (@svovaf) * Moved from Freemius diff --git a/includes/managers/class-fs-permission-manager.php b/includes/managers/class-fs-permission-manager.php index 4fff146a..bbf632ec 100644 --- a/includes/managers/class-fs-permission-manager.php +++ b/includes/managers/class-fs-permission-manager.php @@ -638,7 +638,7 @@ function render_permissions_group( array $permissions_group ) { fs_require_template( 'connect/permissions-group.php', $permissions_group ); } - function require_permissions_js() { + function require_permissions_js( $params ) { fs_require_once_template( 'js/permissions.php', $params ); } diff --git a/includes/managers/class-fs-plugin-manager.php b/includes/managers/class-fs-plugin-manager.php index a3ae55b1..78d9e990 100755 --- a/includes/managers/class-fs-plugin-manager.php +++ b/includes/managers/class-fs-plugin-manager.php @@ -106,11 +106,7 @@ function load() { } foreach ( $all_modules as $modules ) { - /** - * @since 1.2.2 - * - * @var $modules FS_Plugin[] - */ + foreach ( $modules as $module ) { $found_module = false; @@ -230,4 +226,4 @@ function get() { return $plugin; } - } \ No newline at end of file + } diff --git a/phpstan.neon b/phpstan.neon index 02b7cc4b..314e3ab1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 0 + level: 2 paths: - config.php - start.php @@ -8,7 +8,15 @@ parameters: - templates/ bootstrapFiles: - .phpstan/exceptions.php + stubFiles: + - .phpstan/stubs/includes/fs-plugin-info-dialog.php + - .phpstan/stubs/includes/entities/class-fs-entity.php ignoreErrors: - - message: '#will always evaluate to true#' - path: includes/class-fs-plugin-updater.php \ No newline at end of file + messages: + - '#Action callback returns bool but should not return anything.#' + path: includes/class-freemius.php + - + message: '#Variable \$VARS might not be defined#' + paths: + - templates/* diff --git a/start.php b/start.php index bc8db040..17da5023 100644 --- a/start.php +++ b/start.php @@ -102,11 +102,17 @@ function_exists( 'wp_is_json_request' ) && $fs_active_plugins = new stdClass(); } + /** + * @var stdClass $fs_active_plugins + */ if ( ! isset( $fs_active_plugins->plugins ) ) { $fs_active_plugins->plugins = array(); } } + /** + * @var stdClass $fs_active_plugins + */ if ( empty( $fs_active_plugins->abspath ) ) { /** * Store the WP install absolute path reference to identify environment change @@ -229,6 +235,9 @@ function_exists( 'wp_is_json_request' ) && $is_newest_sdk_plugin_active = is_plugin_active( $fs_newest_sdk->plugin_path ); } else { $current_theme = wp_get_theme(); + /** + * @var stdClass $fs_newest_sdk + */ $is_newest_sdk_plugin_active = ( $current_theme->stylesheet === $fs_newest_sdk->plugin_path ); $current_theme_parent = $current_theme->parent(); diff --git a/templates/account.php b/templates/account.php index 89120022..edc199eb 100755 --- a/templates/account.php +++ b/templates/account.php @@ -96,14 +96,13 @@ ) ); } + $payments = []; $show_billing = ( ! $is_whitelabeled && ! $fs->apply_filters( 'hide_billing_and_payments_info', false ) ); if ( $show_billing ) { - $payments = $fs->_fetch_payments(); - - $show_billing = ( is_array( $payments ) && 0 < count( $payments ) ); + $payments = $fs->_fetch_payments(); + $show_billing = ( 0 < count( $payments ) ); } - $has_tabs = $fs->_add_tabs_before_content(); // Aliases. @@ -137,8 +136,7 @@ $show_plan_row = true; $show_license_row = is_object( $license ); - - $site_view_params = array(); + $site_view_params = array(); if ( fs_is_network_admin() ) { $sites = Freemius::get_sites(); @@ -157,7 +155,7 @@ $site_view_params[] = $view_params; - if ( empty( $install ) ) { + if ( ! is_object( $install ) ) { continue; } @@ -186,6 +184,7 @@ $bundle_subscription = null; $is_bundle_first_payment_pending = false; + $bundle_plan_title = ''; if ( $show_plan_row && @@ -870,8 +869,8 @@ class="fs-tag fs-can_use_premium_code() ? 'success' : 'warn' ?>" $VARS['id'], 'payments' => $payments ); - fs_require_once_template( 'account/billing.php', $view_params ); + $view_params = array( 'id' => $VARS['id'], 'payments' => $payments ); + fs_require_once_template( 'account/billing.php', $view_params ); fs_require_once_template( 'account/payments.php', $view_params ); } ?> diff --git a/templates/account/partials/addon.php b/templates/account/partials/addon.php index af9b94c2..f7fa1c62 100644 --- a/templates/account/partials/addon.php +++ b/templates/account/partials/addon.php @@ -67,6 +67,10 @@ $show_upgrade = false; $is_whitelabeled = $VARS['is_whitelabeled']; + $version = ''; + $plan_name = ''; + $plan_title = ''; + if ( is_object( $fs_addon ) ) { $is_paying = $fs_addon->is_paying(); $user = $fs_addon->get_user(); @@ -158,11 +162,11 @@ - + - + diff --git a/templates/account/partials/site.php b/templates/account/partials/site.php index 0be1440a..5e90522d 100644 --- a/templates/account/partials/site.php +++ b/templates/account/partials/site.php @@ -323,13 +323,13 @@ class="dashicons dashicons-arrow-right-alt2"> $downgrade_confirmation_message = sprintf( $downgrade_x_confirm_text, ( $fs->is_only_premium() ? $cancelling_subscription_text : $downgrading_plan_text ), - $plan->title, + $plan_title, $human_readable_license_expiration ); $after_downgrade_message = ! $license->is_block_features ? - sprintf( $after_downgrade_non_blocking_text, $plan->title, $fs->get_module_label( true ) ) : - sprintf( $after_downgrade_blocking_text, $plan->title ); + sprintf( $after_downgrade_non_blocking_text, $plan_title, $fs->get_module_label( true ) ) : + sprintf( $after_downgrade_blocking_text, $plan_title ); ?>
    diff --git a/templates/add-ons.php b/templates/add-ons.php index 77329799..eccd83ab 100755 --- a/templates/add-ons.php +++ b/templates/add-ons.php @@ -141,11 +141,9 @@ continue; } - $has_paid_plan = true; - $has_trial = $has_trial || ( is_numeric( $plan->trial_period ) && ( $plan->trial_period > 0 ) ); - - $min_price = 999999; + $has_trial = isset( $plan->trial_period ) && is_numeric( $plan->trial_period ) && $plan->trial_period > 0; + $min_price = 999999; foreach ( $plan->pricing as $pricing ) { $pricing = new FS_Pricing( $pricing ); diff --git a/templates/debug.php b/templates/debug.php index b45a6ff5..92c3ddb2 100644 --- a/templates/debug.php +++ b/templates/debug.php @@ -355,22 +355,22 @@ function stopCountdownManually() { } ?> id ); + $fs = null; + $has_api_connectivity = false; + if ( $is_active ) { + $fs = freemius( $data->id ); $active_modules_by_id[ $data->id ] = true; } ?> has_api_connectivity(); - - if ( true === $has_api_connectivity && $fs->is_on() ) { - echo ' style="background: #E6FFE6; font-weight: bold"'; - } else { - echo ' style="background: #ffd0d0; font-weight: bold"'; - } - } ?>> + $has_api_connectivity = $fs->has_api_connectivity(); + if ( true === $has_api_connectivity && $fs->is_on() ) { + echo ' style="background: #E6FFE6; font-weight: bold"'; + } else { + echo ' style="background: #ffd0d0; font-weight: bold"'; + } + } ?>> id ?> version ?> diff --git a/templates/forms/affiliation.php b/templates/forms/affiliation.php index 428691ab..6f5d3867 100644 --- a/templates/forms/affiliation.php +++ b/templates/forms/affiliation.php @@ -121,28 +121,29 @@ ?>

    - is_suspended() ) { - $message_text = fs_text_inline( 'Your affiliation account was temporarily suspended.', 'affiliate-account-suspended', $slug ); - $message_container_class = 'notice notice-warning'; - } else if ( $affiliate->is_rejected() ) { - $message_text = fs_text_inline( "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days.", 'affiliate-application-rejected', $slug ); - $message_container_class = 'error'; - } else if ( $affiliate->is_blocked() ) { - $message_text = fs_text_inline( 'Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support.', 'affiliate-account-blocked', $slug ); - $message_container_class = 'error'; - } - ?> -
    -

    -
    - + is_suspended() ) { + $message_text = fs_text_inline( 'Your affiliation account was temporarily suspended.', 'affiliate-account-suspended', $slug ); + $message_container_class = 'notice notice-warning'; + } else if ( $affiliate->is_rejected() ) { + $message_text = fs_text_inline( "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days.", 'affiliate-application-rejected', $slug ); + $message_container_class = 'error'; + } else if ( $affiliate->is_blocked() ) { + $message_text = fs_text_inline( 'Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support.', 'affiliate-account-blocked', $slug ); + $message_container_class = 'error'; + } + ?> +
    +

    +
    +
    diff --git a/templates/plugin-info/features.php b/templates/plugin-info/features.php index 62256fda..6e91160e 100644 --- a/templates/plugin-info/features.php +++ b/templates/plugin-info/features.php @@ -21,13 +21,15 @@ $features_plan_map = array(); foreach ( $plans as $plan ) { + /** + * @var FS_Plugin_Plan $plan + */ if (!empty($plan->features) && is_array($plan->features)) { foreach ( $plan->features as $feature ) { - if ( ! isset( $features_plan_map[ $feature->id ] ) ) { - $features_plan_map[ $feature->id ] = array( 'feature' => $feature, 'plans' => array() ); - } - - $features_plan_map[ $feature->id ]['plans'][ $plan->id ] = $feature; + if ( ! isset( $features_plan_map[ $feature->id ] ) ) { + $features_plan_map[ $feature->id ] = array( 'feature' => $feature, 'plans' => array() ); + } + $features_plan_map[ $feature->id ]['plans'][ $plan->id ] = $feature; } } @@ -111,4 +113,4 @@ -
    \ No newline at end of file +