: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
if ( ! defined( 'ABSPATH' ) ) {
class Freemius extends Freemius_Abstract {
public $version = WP_FS__SDK_VERSION;
private $_plugin_basename;
private $_premium_plugin_basename;
private $_free_plugin_basename;
private $_plugin_dir_path;
private $_plugin_dir_name;
private $_plugin_main_file_path;
* @var bool If false, don't turn Freemius on.
* @var bool If false, don't turn Freemius on.
* @var bool If false, issues with connectivity to Freemius API.
private $_has_api_connection;
* @since 2.0.0 Default to true since we need the property during the instance construction, prior to the dynamic_init() execution.
* @var bool Hints the SDK if plugin can support anonymous mode (if skip connect is visible).
private $_enable_anonymous = true;
* @var bool Hints the SDK if plugin should run in anonymous mode (only adds feedback form).
private $_anonymous_mode;
* @var bool Hints the SDK if plugin have any free plans.
private $_is_premium_only;
* @var bool Hints the SDK if plugin have premium code version at all.
private $_has_premium_version;
* @var bool Hints the SDK if plugin should ignore pending mode by simulating a skip.
private $_ignore_pending_mode;
* @var bool Hints the SDK if the plugin has any paid plans.
private $_has_paid_plans;
* @var int Hints the SDK if the plugin offers a trial period. If negative, no trial, if zero - has a trial but
* without a specified period, if positive - the number of trial days.
private $_trial_days = - 1;
* @var bool Hints the SDK if the trial requires a payment method or not.
private $_is_trial_require_payment = false;
* @var bool Hints the SDK if the plugin is WordPress.org compliant.
private $_is_org_compliant;
* @var bool Hints the SDK if the plugin is has add-ons.
* @var string Navigation type: 'menu' or 'tabs'.
const NAVIGATION_MENU = 'menu';
const NAVIGATION_TABS = 'tabs';
private $_plugin = false;
private $_parent_plugin = false;
private $_parent = false;
* @var FS_Plugin_License[]
private $_licenses = false;
* @var FS_Admin_Menu_Manager
private static $_global_admin_notices;
private static $_static_logger;
private static $_accounts;
private static $_instances = array();
private $affiliate = null;
private $plugin_affiliate_terms = null;
private $custom_affiliate_terms = null;
private $_is_multisite_integrated;
* @var bool True if the current request is for a network admin screen and the plugin is network active.
private $_is_network_active;
* @var int|null The original blog ID the plugin was loaded with.
private $_blog_id = null;
* @var int|null The current execution context. When true, run on network context. When int, run on the specified blog context.
private $_context_is_network_or_blog_id = null;
private $_dynamically_added_top_level_page_hook_name = '';
* @author Leo Fajardo (@leorw)
private $is_whitelabeled;
* @author Leo Fajardo (@leorw)
private $_is_bundle_license_auto_activation_enabled = false;
#region Uninstall Reasons IDs
const REASON_NO_LONGER_NEEDED = 1;
const REASON_FOUND_A_BETTER_PLUGIN = 2;
const REASON_NEEDED_FOR_A_SHORT_PERIOD = 3;
const REASON_BROKE_MY_SITE = 4;
const REASON_SUDDENLY_STOPPED_WORKING = 5;
const REASON_CANT_PAY_ANYMORE = 6;
const REASON_DIDNT_WORK = 8;
const REASON_DONT_LIKE_TO_SHARE_MY_INFORMATION = 9;
const REASON_COULDNT_MAKE_IT_WORK = 10;
const REASON_GREAT_BUT_NEED_SPECIFIC_FEATURE = 11;
const REASON_NOT_WORKING = 12;
const REASON_NOT_WHAT_I_WAS_LOOKING_FOR = 13;
const REASON_DIDNT_WORK_AS_EXPECTED = 14;
const REASON_TEMPORARY_DEACTIVATION = 15;
* @author Leo Fajardo (@leorw)
private $_use_external_pricing = null;
* @author Leo Fajardo (@leorw)
private $_pricing_js_path = null;
const VERSION_MAX_CHARS = 16;
const LANGUAGE_MAX_CHARS = 8;
------------------------------------------------------------------------------------------------------------------*/
* Main singleton instance.
* @author Vova Feldman (@svovaf)
* @param number $module_id
* @param string|bool $slug
* @param bool $is_init Since 1.2.1 Is initiation sequence.
private function __construct( $module_id, $slug = false, $is_init = false ) {
if ( $is_init && is_numeric( $module_id ) && is_string( $slug ) ) {
$main_file = $this->store_id_slug_type_path_map( $module_id, $slug );
$this->_module_id = $module_id;
$this->_slug = $this->get_slug();
$this->_module_type = $this->get_module_type();
$this->_blog_id = is_multisite() ? get_current_blog_id() : null;
$this->_storage = FS_Storage::instance( $this->_module_type, $this->_slug );
// If not set or 24 hours have already passed from the last time it's set, set the last load timestamp to the current time.
! isset( $this->_storage->last_load_timestamp ) ||
$this->_storage->last_load_timestamp < ( time() - ( WP_FS__TIME_24_HOURS_IN_SEC ) )
$this->_storage->last_load_timestamp = time();
$this->_cache = FS_Cache_Manager::get_manager( WP_FS___OPTION_PREFIX . "cache_{$module_id}" );
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $this->get_unique_affix(), WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
$this->_plugin_main_file_path = $this->_find_caller_plugin_file( $is_init, $main_file );
$this->_plugin_dir_path = plugin_dir_path( $this->_plugin_main_file_path );
$this->_plugin_basename = $this->get_plugin_basename();
$this->_free_plugin_basename = str_replace( '-premium/', '/', $this->_plugin_basename );
$this->_is_multisite_integrated = (
defined( "WP_FS__PRODUCT_{$module_id}_MULTISITE" ) &&
( true === constant( "WP_FS__PRODUCT_{$module_id}_MULTISITE" ) )
$this->_is_network_active = (
$this->_is_multisite_integrated &&
// Themes are always network activated, but the ACTUAL activation is per site.
is_plugin_active_for_network( $this->_plugin_basename ) ||
// Plugin network level activation or uninstall.
( fs_is_network_admin() && is_plugin_inactive( $this->_plugin_basename ) )
$this->_storage->set_network_active(
$this->_is_network_active,
$this->is_delegated_connection()
if ( ! isset( $this->_storage->is_network_activated ) ) {
$this->_storage->is_network_activated = $this->_is_network_active;
if ( $this->_storage->is_network_activated != $this->_is_network_active ) {
// Update last activation level.
$this->_storage->is_network_activated = $this->_is_network_active;
$this->maybe_adjust_storage();
* If the install_timestamp exists on the site level but doesn't exist on the
* network level storage, it means that we need to process the storage with migration.
* The code in this `if` scope will only be executed once and only for the first site that will execute it because once we migrate the storage data, install_timestamp will be already set in the network level storage.
* @author Vova Feldman (@svovaf)
if ( false === $this->_storage->get( 'install_timestamp', false, true ) &&
false !== $this->_storage->get( 'install_timestamp', false, false )
// Initiate storage migration.
$this->_storage->migrate_to_network();
// Migrate module cache to network level storage.
$this->_cache->migrate_to_network();