: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
private function delegate_connection( $all_or_blog_ids = true ) {
$this->_logger->entrance();
$this->_admin_notices->remove_sticky( 'connect_account' );
if ( true === $all_or_blog_ids ) {
$this->_storage->store( 'is_delegated_connection', true, true );
// Specified sites delegation.
foreach ( $all_or_blog_ids as $blog_id ) {
$this->delegate_site_connection( $blog_id );
$this->network_upgrade_mode_completed();
* Delegate specific network site conncetion to the site admin.
* @author Vova Feldman (@svovaf)
private function delegate_site_connection( $blog_id ) {
$this->_storage->store( 'is_delegated_connection', true, $blog_id );
* Check if super-admin delegated the connection of ALL sites to the site admins.
* @author Vova Feldman (@svovaf)
function is_network_delegated_connection() {
if ( ! $this->_is_network_active ) {
return $this->_storage->get( 'is_delegated_connection', false, true );
* @author Leo Fajardo (@leorw)
function is_site_delegated_connection( $blog_id = 0 ) {
if ( ! $this->_is_network_active ) {
$blog_id = get_current_blog_id();
return $this->_storage->get( 'is_delegated_connection', false, $blog_id );
* Check if delegated the connection. When running within the network admin,
* and haven't specified the blog ID, checks if network level delegated. If running
* within a site admin or specified a blog ID, check if delegated the connection for
* the current context site.
* If executed outside the the admin, check if delegated the connection
* for the current context site OR the whole network.
* @author Vova Feldman (@svovaf)
* @param int $blog_id If set, checks if network delegated or blog specific delegated.
function is_delegated_connection( $blog_id = 0 ) {
if ( ! $this->_is_network_active ) {
if ( fs_is_network_admin() && 0 == $blog_id ) {
return $this->is_network_delegated_connection();
$this->is_network_delegated_connection() ||
$this->is_site_delegated_connection( $blog_id )
* Check if the current module is active for the site.
* @author Vova Feldman (@svovaf)
function is_active_for_site( $blog_id ) {
if ( ! is_multisite() ) {
// Not a multisite and this code is executed, means that the plugin is active.
if ( $this->is_theme() ) {
// All themes are site level activated.
if ( $this->_is_network_active ) {
// Plugin was network activated so it's active.
return in_array( $this->_plugin_basename, (array) get_blog_option( $blog_id, 'active_plugins', array() ) );
* @todo Implement pagination when accessing the subsites collection.
* @author Leo Fajardo (@leorw)
* @param int $limit Default to 1,000
* @param int $offset Default to 0
* @return array Active & public sites collection.
static function get_sites( $limit = 1000, $offset = 0 ) {
if ( ! is_multisite() ) {
* For consistency with get_blog_list() which only return active public sites.
* @author Vova Feldman (@svovaf)
* Commented out in order to handle the migration of site options whether the site is public or not.
* @author Leo Fajardo (@leorw)
return get_sites( $args );
* Checks if a given blog is active.
* @author Vova Feldman (@svovaf)
private static function is_site_active( $blog_id ) {
$blog_info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->blogs} WHERE blog_id = %d", $blog_id ) );
if ( ! is_object( $blog_info ) ) {
true == $blog_info->public &&
false == $blog_info->archived &&
false == $blog_info->mature &&
false == $blog_info->spam &&
false == $blog_info->deleted
* Get a mapping between the site addresses to their blog IDs.
* @author Vova Feldman (@svovaf)
* @key string Site address without protocol with a trailing slash.
* @value int Site's blog ID.
private function get_address_to_blog_map() {
$sites = self::get_sites();
// Map site addresses to their blog IDs.
$address_to_blog_map = array();
foreach ( $sites as $site ) {
$blog_id = self::get_site_blog_id( $site );
$address = self::get_unfiltered_site_url( $blog_id, true, true );
$address_to_blog_map[ $address ] = $blog_id;
return $address_to_blog_map;
* Get a mapping between the site addresses to their blog IDs.
* @author Vova Feldman (@svovaf)
* @key int Site's blog ID.
* @value FS_Site Associated install.
function get_blog_install_map() {
$sites = self::get_sites();
// Map site blog ID to its install.
foreach ( $sites as $site ) {
$blog_id = self::get_site_blog_id( $site );
$install = $this->get_install_by_blog_id( $blog_id );
if ( is_object( $install ) ) {
$install_map[ $blog_id ] = $install;
* @author Vova Feldman (@svovaf)
* @param bool|null $is_delegated When `true`, returns only connection delegated blog IDs. When `false`, only non-delegated blog IDs.
private function get_blog_ids( $is_delegated = null ) {
$sites = self::get_sites();
foreach ( $sites as $site ) {
$blog_id = self::get_site_blog_id( $site );
is_null( $is_delegated ) ||
$is_delegated === $this->is_site_delegated_connection( $blog_id )
* @author Vova Feldman (@svovaf)
private function get_non_delegated_blog_ids() {
return $this->get_blog_ids( false );
* Gets a map of module IDs that the given user has opted-in to.
* @author Leo Fajardo (@leorw)
* @param number $fs_user_id
* @value bool Always true.
private static function get_user_opted_in_module_ids_map( $fs_user_id ) {
self::$_static_logger->entrance();
if ( ! is_multisite() ) {
self::get_all_sites( WP_FS__MODULE_TYPE_PLUGIN ),
self::get_all_sites( WP_FS__MODULE_TYPE_THEME )
$sites = self::get_sites();
foreach ( $sites as $site ) {
$blog_id = self::get_site_blog_id( $site );
self::get_all_sites( WP_FS__MODULE_TYPE_PLUGIN, $blog_id ),
self::get_all_sites( WP_FS__MODULE_TYPE_THEME, $blog_id )
$module_ids_map = array();
foreach ( $installs as $install ) {
if ( is_object( $install ) &&
FS_Site::is_valid_id( $install->id ) &&
FS_User::is_valid_id( $install->user_id ) &&
( $install->user_id == $fs_user_id )
$module_ids_map[ $install->plugin_id ] = true;
* @author Leo Fajardo (@leorw)
* 'install' => FS_Site Module's install,
* 'blog_id' => string The associated blog ID.
function find_first_install() {
$sites = self::get_sites();
foreach ( $sites as $site ) {
$blog_id = self::get_site_blog_id( $site );
$install = $this->get_install_by_blog_id( $blog_id );
if ( is_object( $install ) ) {
* Switches the Freemius site level context to a specified blog.
* @author Vova Feldman (@svovaf)
* @param FS_Site $install
* @return bool Since 2.3.1 returns if a switch was made.
function switch_to_blog( $blog_id, FS_Site $install = null, $flush = false ) {
if ( ! is_numeric( $blog_id ) ) {
if ( ! $flush && $blog_id == $this->_context_is_network_or_blog_id ) {
switch_to_blog( $blog_id );
$this->_context_is_network_or_blog_id = $blog_id;
self::$_accounts->set_site_blog_context( $blog_id );
$this->_storage->set_site_blog_context( $blog_id );
$this->_storage->set_network_active( $this->_is_network_active, $this->is_delegated_connection( $blog_id ) );
$this->_site = is_object( $install ) ?
$this->get_install_by_blog_id( $blog_id );
$this->_licenses = false;
$this->is_whitelabeled = null;
if ( is_object( $this->_site ) ) {
// Try to fetch user from install.
$this->_user = self::_get_user_by_id( $this->_site->user_id );
if ( ! is_object( $this->_user ) &&
FS_User::is_valid_id( $this->_storage->prev_user_id )
// Try to fetch previously saved user.
$this->_user = self::_get_user_by_id( $this->_storage->prev_user_id );
if ( ! is_object( $this->_user ) ) {
// Fallback to network's user.
$this->_user = $this->get_network_user();
$all_plugin_licenses = self::get_all_licenses( $this->_module_id );
if ( ! empty( $all_plugin_licenses ) ) {
if ( ! FS_Plugin_License::is_valid_id( $this->_site->license_id ) ) {
foreach ( $all_plugin_licenses as $license ) {
if ( $license->id == $this->_site->license_id ) {
$this->_license = $license;
$this->link_license_2_user( $this->_license->id, $this->_user->id );
$this->_licenses = $this->get_user_licenses( $this->_user->id );
unset( $this->_site_api );
unset( $this->_user_api );
* Restore the blog context to the blog that originally loaded the module.
* @author Vova Feldman (@svovaf)
function restore_current_blog() {
$this->switch_to_blog( $this->_blog_id );
* @author Vova Feldman (@svovaf)
* @param array|WP_Site $site
static function get_site_blog_id( &$site ) {
return ( $site instanceof WP_Site ) ?
( is_object( $site ) && isset( $site->userblog_id ) ?
* @author Vova Feldman (@svovaf)
* @param WP_Site[]|array[] $sites
static function get_sites_blog_ids( $sites ) {
foreach ( $sites as $site ) {
$blog_ids[] = self::get_site_blog_id( $site );
* @author Leo Fajardo (@leorw)
* @param array|WP_Site|null $site
* @param bool $load_registration Since 2.5.1 When set to `true` the method will attempt to return the subsite's registration date, regardless of the `$site` type and value. In most calls, the registration date will be returned anyway, even when the value is `false`. This param is purely for performance optimization.
function get_site_info( $site = null, $load_registration = false ) {
$this->_logger->entrance();