: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$this->is_activation_mode() &&
// If not yet registered and running the premium code base, a license activation link will already be shown.
if ( $this->is_registered() && $this->is_tracking_allowed() ) {
if ( ! $this->is_premium() && ! $this->is_enable_anonymous() ) {
// If opted in and tracking is allowed, don't allow to opt out if not premium and anonymous mode is disabled.
if ( $this->add_ajax_action( 'toggle_permission_tracking', array( &$this, '_toggle_permission_tracking_callback' ) ) ) {
if ( $this->is_registered( true ) ) {
if ( $this->is_registered() && $this->is_tracking_allowed() ) {
$link_text_id = $this->get_text_inline( 'Opt Out', 'opt-out' );
$link_text_id = $this->get_text_inline( 'Opt In', 'opt-in' );
} else if ( $this->is_anonymous() || $this->is_activation_mode() ) {
* Show opt-in link only if skipped or in activation mode.
$link_text_id = $this->get_text_inline( 'Opt In', 'opt-in' );
$params = ! $this->is_anonymous() ?
'nonce' => wp_create_nonce( $this->get_unique_affix() . '_reconnect' ),
'fs_action' => ( $this->get_unique_affix() . '_reconnect' ),
$url = $this->get_activation_url( $params );
add_action( 'admin_footer', array( &$this, '_add_optout_dialog' ) );
if ( ! empty( $link_text_id ) && $this->is_plugin() && self::is_plugins_page() ) {
$this->add_plugin_action_link(
"opt-in-or-opt-out {$this->_slug}"
* Get the URL of the page that should be loaded right after the plugin activation.
* @author Vova Feldman (@svovaf)
function get_after_plugin_activation_redirect_url() {
if ( ! $this->is_addon() || ! $this->has_free_plan() ) {
$first_time_path = $this->_menu->get_first_time_path(
fs_is_network_admin() && $this->_is_network_active
if ( $this->is_activation_mode() ) {
$url = $this->get_activation_url();
} else if ( ! empty( $first_time_path ) ) {
if ( ! empty( $this->_dynamically_added_top_level_page_hook_name ) ) {
if ( $this->is_network_registered() ) {
} else if ( $this->is_pending_activation() || $this->is_network_anonymous() ) {
$this->maybe_set_slug_and_network_menu_exists_flag();
$url = $this->_get_admin_page_url( $page );
if ( $this->is_parent_plugin_installed() ) {
$plugin_fs = self::get_parent_instance();
if ( is_object( $plugin_fs ) ) {
if ( ! $plugin_fs->is_registered() ) {
// Forward to parent plugin connect when parent not registered.
$url = $plugin_fs->get_activation_url();
// Forward to account page.
$url = $plugin_fs->_get_admin_page_url( 'account' );
* Forward page to activation page.
* @author Vova Feldman (@svovaf)
function _redirect_on_activation_hook() {
if ( $this->apply_filters( 'redirect_on_activation', true ) ) {
$url = $this->get_after_plugin_activation_redirect_url();
if ( is_string( $url ) ) {
* Modify plugin's page action links collection.
* @author Vova Feldman (@svovaf)
function _modify_plugin_action_links_hook( $links, $file ) {
$this->_logger->entrance();
$passed_deactivate = false;
$before_deactivate = array();
$after_deactivate = array();
foreach ( $links as $key => $link ) {
if ( 'deactivate' === $key ) {
$deactivate_link = $link;
$passed_deactivate = true;
if ( ! $passed_deactivate ) {
$before_deactivate[ $key ] = $link;
$after_deactivate[ $key ] = $link;
ksort( $this->_action_links );
foreach ( $this->_action_links as $new_links ) {
foreach ( $new_links as $link ) {
$before_deactivate[ $link['key'] ] = '<a href="' . $link['href'] . '"' . ( $link['external'] ? ' target="_blank" rel="noopener"' : '' ) . '>' . $link['label'] . '</a>';
if ( ! empty( $deactivate_link ) ) {
* This HTML element is used to identify the correct plugin when attaching an event to its Deactivate link.
* @since 1.2.1.6 Always show the deactivation feedback form since we added automatic free version deactivation upon premium code activation.
$deactivate_link .= '<i class="fs-module-id" data-module-id="' . $this->_module_id . '"></i>';
// Append deactivation link.
$before_deactivate['deactivate'] = $deactivate_link;
return array_merge( $before_deactivate, $after_deactivate );
* @author Vova Feldman (@svovaf)
function add_admin_message( $message, $title = '', $type = 'success' ) {
$this->_admin_notices->add( $message, $title, $type );
* Adds sticky admin message.
* @author Vova Feldman (@svovaf)
function add_sticky_admin_message( $message, $id, $title = '', $type = 'success' ) {
$this->_admin_notices->add_sticky( $message, $id, $title, $type );
* Check if the paid version of the module is installed.
* @author Vova Feldman (@svovaf)
private function is_premium_version_installed() {
$premium_plugin_basename = $this->premium_plugin_basename();
if ( $this->is_theme() ) {
return $this->can_activate_theme( $this->get_premium_slug() );
return file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_plugin_basename ) );
* Helper function that returns the final steps for the upgrade completion.
* If the module is already running the premium code, returns an empty string.
* @author Vova Feldman (@svovaf)
* @param string $plan_title
private function get_complete_upgrade_instructions( $plan_title = '' ) {
$this->_logger->entrance();
$activate_license_string = $this->get_license_network_activation_notice();
if ( ! $this->has_premium_version() || $this->is_premium() ) {
return '' . $activate_license_string;
if ( empty( $plan_title ) ) {
$plan_title = $this->get_plan_title();
if ( $this->is_premium_version_installed() ) {
* If the premium version is already installed, instead of showing the installation instructions,
* tell the current user to activate it.
* @author Leo Fajardo (@leorw)
$premium_theme_slug_or_plugin_basename = $this->is_theme() ?
$this->get_premium_slug() :
$this->premium_plugin_basename();
/* translators: %1$s: Product title; %2$s: Plan title */
$this->get_text_inline( ' The paid version of %1$s is already installed. Please activate it to start benefiting the %2$s features. %3$s', 'activate-premium-version' ),
sprintf( '<em>%s</em>', esc_html( $this->get_plugin_title() ) ),
'<a style="margin-left: 10px;" href="%s"><button class="button button-primary">%s</button></a>',
wp_nonce_url( 'themes.php?action=activate&stylesheet=' . $premium_theme_slug_or_plugin_basename, 'switch-theme_' . $premium_theme_slug_or_plugin_basename ) :
wp_nonce_url( 'plugins.php?action=activate&plugin=' . $premium_theme_slug_or_plugin_basename, 'activate-plugin_' . $premium_theme_slug_or_plugin_basename ) ),
/* translators: %s: Plan title */
$this->get_text_inline( 'Activate %s features', 'activate-x-features' ),
// @since 1.2.1.5 The free version is auto deactivated.
$deactivation_step = version_compare( $this->version, '1.2.1.5', '<' ) ?
( '<li>' . $this->esc_html_inline( 'Deactivate the free version', 'deactivate-free-version' ) . '.</li>' ) :
' %s: <ol><li>%s.</li>%s<li>%s (<a href="%s" target="_blank" rel="noopener">%s</a>).</li></ol>',
$this->get_text_inline( 'Please follow these steps to complete the upgrade', 'follow-steps-to-complete-upgrade' ),
( empty( $activate_license_string ) ? '' : $activate_license_string . '</li><li>' ) .
$this->get_latest_download_link( sprintf(
/* translators: %s: Plan title */
$this->get_text_inline( 'Download the latest %s version', 'download-latest-x-version' ),
$this->get_text_inline( 'Upload and activate the downloaded version', 'upload-and-activate' ),
$this->apply_filters( 'upload_and_install_video_url', '//bit.ly/wp-' . $this->_module_type . '-upload' ),
$this->get_text_inline( 'How to upload and activate?', 'howto-upload-activate' )
* @author Leo Fajardo (@leorw)
* @param string $message_before_the_instructions
* @param string $message_id
* @param string $plan_title
private function add_complete_upgrade_instructions_notice(
$message_before_the_instructions,
$this->_admin_notices->add_sticky(
$message_before_the_instructions .
$this->get_complete_upgrade_instructions( $plan_title ),
$this->get_text_x_inline( 'Yee-haw', 'interjection expressing joy or exuberance', 'yee-haw' ) . '!'
* @author Leo Fajardo (@leorw)
* @param bool $is_upgrade
private function add_after_plan_activation_or_upgrade_instructions_notice( $is_upgrade = true ) {
$this->add_complete_upgrade_instructions_notice(
$this->get_text_inline( 'Your plan was successfully upgraded.', 'plan-upgraded-message' ) :
$this->get_text_inline( 'Your plan was successfully activated.', 'plan-activated-message' ),
* @author Leo Fajardo (@leorw)
private static function enrich_request_for_debug( &$url, &$request ) {
if ( WP_FS__DEBUG_SDK || isset( $_COOKIE['XDEBUG_SESSION'] ) ) {
$url = add_query_arg( 'XDEBUG_SESSION_START', rand( 0, 9999999 ), $url );
$url = add_query_arg( 'XDEBUG_SESSION', 'PHPSTORM', $url );
$request['cookies'] = array(
new WP_Http_Cookie( array(
'name' => 'XDEBUG_SESSION',
* @author Leo Fajardo (@leorw)
* @param int $success_cache_expiration
* @param int $failure_cache_expiration
* @param bool $maybe_enrich_request_for_debug
static function safe_remote_post(
$success_cache_expiration = 0,
$failure_cache_expiration = 0,
$maybe_enrich_request_for_debug = true
$should_cache = ($success_cache_expiration + $failure_cache_expiration > 0);
$cache_key = $should_cache ? md5( fs_strip_url_protocol($url) . json_encode( $request ) ) : false;
$response = (!WP_FS__DEBUG_SDK && ( false !== $cache_key )) ?
get_transient( $cache_key ) :
if ( false === $response ) {
if ( $maybe_enrich_request_for_debug ) {
self::enrich_request_for_debug( $url, $request );
if ( ! isset( $request['method'] ) ) {
$request['method'] = 'POST';
$response = FS_Api::remote_request( $url, $request );
'https://' === substr( $url, 0, 8 ) &&
FS_Api::is_ssl_error_response( $response )
// Failed due to old version of cURL or Open SSL (SSLv3 is not supported by CloudFlare).
$url = 'http://' . substr( $url, 8 );
$request['timeout'] = 15;
$response = FS_Api::remote_request( $url, $request );
if ( false !== $cache_key ) {
( ( $response instanceof WP_Error ) ?
$failure_cache_expiration :
$success_cache_expiration )
* This method is used to enrich the after upgrade notice instructions when the upgraded
* license cannot be activated network wide (license quota isn't large enough).
* @author Vova Feldman (@svovaf)
private function get_license_network_activation_notice() {
if ( ! $this->_is_network_active ) {
// Module isn't network level activated.
if ( ! fs_is_network_admin() ) {
// Not network level admin.
if ( get_blog_count() == 1 ) {
// There's only a single site in the network so if there's a context license it was already activated.
if ( ! is_object( $this->_license ) ) {
if ( $this->_license->is_single_site() && 0 < $this->_license->activated ) {
// License was already utilized (this is not 100% the case if all the network is localhost sites and the license can be utilized on unlimited localhost sites).
if ( $this->can_activate_license_on_network( $this->_license ) ) {
// License can be activated on all the network, so probably, the license is already activate on all the network (that's how the after upgrade sync works).
$this->get_text_inline( '%sClick here%s to choose the sites where you\'d like to activate the license on.', 'network-choose-sites-for-license' ),
'<a href="' . $this->get_account_url( false, array( 'activate_license' => 'true' ) ) . '">',
* @author Vova Feldman (@svovaf)
function get_text( $key ) {
return fs_text( $key, $this->_slug );
* @author Vova Feldman (@svovaf)
* @param string $text Translatable string.
* @param string $key String key for overrides.
function get_text_inline( $text, $key = '' ) {
return _fs_text_inline( $text, $key, $this->_slug );
* @author Vova Feldman (@svovaf)