: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$this->do_action( 'after_account_connection', $this->_user, $first_install );
// Map site addresses to their blog IDs.
$address_to_blog_map = $this->get_address_to_blog_map();
$blog_2_install_map = array();
foreach ( $installs as $install ) {
$address = trailingslashit( fs_strip_url_protocol( $install->url ) );
$blog_id = $address_to_blog_map[ $address ];
$this->_store_site( true, $blog_id, $install );
if ( is_null( $first_blog_id ) ) {
$first_blog_id = $blog_id;
$blog_2_install_map[ $blog_id ] = $install;
if ( ! FS_User::is_valid_id( $this->_storage->network_user_id ) ||
! is_object( self::_get_user_by_id( $this->_storage->network_user_id ) )
$this->_storage->network_user_id = $this->_user->id;
if ( ! FS_Site::is_valid_id( $this->_storage->network_install_blog_id ) ) {
$this->_storage->network_install_blog_id = $first_blog_id;
if ( count( $installs ) === count( $address_to_blog_map ) ) {
// Super admin opted in for all sites in the network.
$this->_storage->is_network_connected = true;
$this->_store_licenses( false );
self::$_accounts->store();
// Don't sync the installs data on network upgrade
if ( ! $this->network_upgrade_mode_completed() ) {
$this->send_installs_update();
$current_blog = get_current_blog_id();
foreach ( $blog_2_install_map as $blog_id => $install ) {
$this->switch_to_blog( $blog_id );
$this->do_action( 'after_account_connection', $this->_user, $install );
// Switch install context back to the first install.
( $this->_site->id != $first_install->id )
$this->do_action( 'after_network_account_connection', $this->_user, $blog_2_install_map );
* Tries to activate parent account based on add-on's info.
* @author Vova Feldman (@svovaf)
* @param Freemius $parent_fs
private function activate_parent_account( Freemius $parent_fs ) {
if ( ! $this->is_addon() ) {
// This is not an add-on.
if ( $parent_fs->is_registered() ) {
// Activate parent with add-on's user credentials.
$parent_install = $this->get_api_user_scope()->call(
"/plugins/{$parent_fs->_plugin->id}/installs.json",
$parent_fs->get_install_data_for_api( array(
'uid' => $parent_fs->get_anonymous_id(),
if ( isset( $parent_install->error ) ) {
$this->_admin_notices->add(
sprintf( $this->get_text_inline( 'Couldn\'t activate %s.', 'could-not-activate-x' ), $this->get_plugin_name() ) . ' ' .
$this->get_text_inline( 'Please contact us with the following message:', 'contact-us-with-error-message' ) . ' ' . '<b>' . $parent_install->error->message . '</b>',
$this->get_text_x_inline( 'Oops', 'exclamation', 'oops' ) . '...',
$parent_fs->_admin_notices->remove_sticky( 'connect_account' );
if ( $parent_fs->is_pending_activation() ) {
$parent_fs->clear_pending_activation_mode();
// Get user information based on parent's plugin.
$user = $this->get_user();
// First of all, set site info - otherwise we won't
// be able to invoke API calls.
$parent_fs->_site = new FS_Site( $parent_install );
$parent_fs->_user = $user;
$parent_fs->_sync_plans();
$parent_fs->update_license_required_permissions_if_anonymous();
$parent_fs->_set_account( $user, $parent_fs->_site );
#----------------------------------------------------------------------------------
#----------------------------------------------------------------------------------
private $_menu_items = array();
* @author Vova Feldman (@svovaf)
function get_menu_items() {
return $this->_menu_items;
* @author Vova Feldman (@svovaf)
function get_menu_slug() {
return $this->_menu->get_slug();
* @author Vova Feldman (@svovaf)
function _prepare_admin_menu() {
// if ( ! $this->is_on() ) {
if ( is_object( $this->_site ) && ! $this->is_registered() ) {
* When running from a site admin with a network activated module and the connection
* was NOT delegated and the user still haven't skipped or opted-in, then hide the
* @author Vova Feldman (@svovaf)
$should_hide_site_admin_settings = (
$this->_is_network_active &&
! fs_is_network_admin() &&
! $this->is_delegated_connection() &&
! $this->is_anonymous() &&
$should_hide_site_admin_settings = $this->apply_filters( 'should_hide_site_admin_settings_on_network_activation_mode', $should_hide_site_admin_settings );
if ( ( false === $this->has_api_connectivity() && ! $this->is_enable_anonymous() ) ||
$should_hide_site_admin_settings
$this->_menu->remove_menu_item( $should_hide_site_admin_settings );
$this->do_action( fs_is_network_admin() ?
'before_network_admin_menu_init' :
$this->add_menu_action();
$this->add_network_menu_when_missing();
$this->add_submenu_items();
* Admin dashboard menu items modifications.
* NOTE: admin_menu action executed before admin_init.
* @author Vova Feldman (@svovaf)
private function add_menu_action() {
if ( $this->is_activation_mode() ) {
if ( $this->show_opt_in_on_setting_page() ) {
$this->override_plugin_menu_with_activation();
* Handle theme opt-in when the opt-in form shows as a dialog box in the themes page.
if ( fs_request_is_action( $this->get_unique_affix() . '_activate_existing' ) ) {
add_action( 'load-themes.php', array( &$this, '_install_with_current_user' ) );
} else if ( fs_request_is_action( $this->get_unique_affix() . '_activate_new' ) ||
fs_request_get_bool( 'pending_activation' )
add_action( 'load-themes.php', array( &$this, '_install_with_new_user' ) );
if ( ! $this->is_registered() ) {
// If not registered try to install user.
if ( fs_request_is_action( $this->get_unique_affix() . '_activate_new' ) ) {
$this->_install_with_new_user();
fs_request_is_action( 'sync_user' ) &&
( ! $this->has_settings_menu() || $this->show_opt_in_on_themes_page() )
$this->_handle_account_user_sync();
* @author Vova Feldman (@svovaf)
function _redirect_on_clicked_menu_link() {
$this->_logger->entrance();
$page = fs_request_get('page');
$page = is_string($page) ? strtolower($page) : '';
$this->_logger->log( 'page = ' . $page );
foreach ( $this->_menu_items as $priority => $items ) {
foreach ( $items as $item ) {
if ( isset( $item['url'] ) ) {
if ( $page === $this->_menu->get_slug( strtolower( $item['menu_slug'] ) ) ) {
$this->_logger->log( 'Redirecting to ' . $item['url'] );
fs_redirect( $item['url'] );
* Remove plugin's all admin menu items & pages, and replace with activation page.
* @author Vova Feldman (@svovaf)
private function override_plugin_menu_with_activation() {
$this->_logger->entrance();
if ( ! $this->has_settings_menu() ) {
// Add the opt-in page without a menu item.
$hook = FS_Admin_Menu_Manager::add_subpage(
$this->get_plugin_name(),
$this->get_plugin_name(),
array( &$this, '_connect_page_render' )
} else if ( $this->_menu->is_top_level() ) {
if ( $this->_menu->is_override_exact() ) {
// Make sure the current page is matching the activation page.
if ( ! $this->is_matching_url( $this->get_activation_url() ) ) {
$hook = $this->_menu->override_menu_item( array( &$this, '_connect_page_render' ) );
// Create new menu item just for the opt-in.
$hook = FS_Admin_Menu_Manager::add_page(
$this->get_plugin_name(),
$this->get_plugin_name(),
$this->_menu->get_slug(),
array( &$this, '_connect_page_render' )
$menus = array( $this->_menu->get_parent_slug() );
if ( $this->_menu->is_override_exact() ) {
// Make sure the current page is matching the activation page.
if ( ! $this->is_matching_url( $this->get_activation_url() ) ) {
foreach ( $menus as $parent_slug ) {
$hook = $this->_menu->override_submenu_action(
$this->_menu->get_raw_slug(),
array( &$this, '_connect_page_render' )
// Found plugin's submenu item.
if ( $this->is_activation_page() ) {
// Clean admin page from distracting content.
self::_clean_admin_content_section();
if ( fs_request_is_action( $this->get_unique_affix() . '_activate_existing' ) ) {
$this->_install_with_current_user();
} else if ( fs_request_is_action( $this->get_unique_affix() . '_activate_new' ) ) {
$this->_install_with_new_user();
* If a plugin was network activated and connected but don't have a network
* level settings, then add an artificial menu item for the Account and other
* @author Vova Feldman (@svovaf)
private function add_network_menu_when_missing() {
$this->_logger->entrance();
if ( ! $this->_is_network_active ) {
// Plugin wasn't activated on the network level.
if ( ! fs_is_network_admin() ) {
// The context is not the network admin.
if ( $this->_menu->has_network_menu() ) {
// Plugin already has a network level menu.
if ( $this->is_network_activation_mode() ) {
* Do not add during activation mode, otherwise, there will be duplicate menus while the opt-in
* @author Leo Fajardo (@leorw)
if ( ! WP_FS__SHOW_NETWORK_EVEN_WHEN_DELEGATED ) {
if ( $this->is_network_delegated_connection() ) {
// Super-admin delegated the connection to the site admins.
if ( ! $this->_menu->has_menu() || $this->_menu->is_top_level() ) {
if ( $this->_menu->has_menu() ||
$this->is_activation_mode()
$this->_dynamically_added_top_level_page_hook_name = $this->_menu->add_page_and_update(
$this->get_plugin_name(),
$this->get_plugin_name(),
$this->_menu->has_menu() ? $this->_menu->get_slug() : $this->_slug
$this->_menu->add_subpage_and_update(
$this->_menu->get_parent_slug(),
$this->get_plugin_name(),
$this->get_plugin_name(),
* @author Leo Fajardo (@leorw)
function get_top_level_menu_capability() {
$top_level_menu_slug = $this->get_top_level_menu_slug();
foreach ( $menu as $menu_info ) {
* The second element in the menu info array is the capability/role that has access to the menu and the
* third element is the menu slug.
if ( $menu_info[2] === $top_level_menu_slug ) {
* @author Vova Feldman (@svovaf)
private function get_top_level_menu_slug() {
return ( $this->is_addon() ?
$this->get_parent_instance()->_menu->get_top_level_menu_slug() :
$this->_menu->get_top_level_menu_slug() );
* @author Vova Feldman (@svovaf)
function get_pricing_cta_label() {
$label = $this->get_text_inline( 'Upgrade', 'upgrade' );
if ( $this->is_in_trial_promotion() &&
! $this->is_paying_or_trial()
// If running a trial promotion, modify the pricing to load the trial.
$label = $this->get_text_inline( 'Start Trial', 'start-trial' );
} else if ( $this->is_paying() ) {
$label = $this->get_text_inline( 'Pricing', 'pricing' );
* @author Vova Feldman (@svovaf)
function is_pricing_page_visible() {
// Has at least one paid plan.
$this->has_paid_plan() &&
// Didn't ask to hide the pricing page.
$this->is_page_visible( 'pricing' ) &&
// Don't have a valid active license or has more than one plan.
( ! $this->is_paying() || ! $this->is_single_plan( true ) )
* @author Leo Fajardo (@leorw)
* @param bool $is_activation_mode
private function should_add_submenu_or_action_links( $is_activation_mode ) {
if ( $this->is_addon() ) {