: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$this->sync_install( array(), true );
$this->maybe_sync_install_user();
#endregion Async Install Sync ------------------------------------------------------------------
* Show a notice that activation is currently pending.
* @todo Add some sort of mechanism to allow users to update the email address they would like to opt-in with when $is_suspicious_email is true.
* @author Vova Feldman (@svovaf)
* @param bool|string $email_address
* @param bool $is_pending_trial Since 1.2.1.5
* @param bool $is_suspicious_email Since 2.5.0 Set to true when there's an indication that email address the user opted in with is fake/dummy/placeholder.
* @param bool $has_upgrade_context Since 2.5.3
* @param bool $support_email_address Since 2.5.3
function _add_pending_activation_notice(
$is_pending_trial = false,
$is_suspicious_email = false,
$has_upgrade_context = false,
$support_email_address = false
if ( ! is_string( $email_address ) ) {
$current_user = self::_get_current_wp_user();
$email_address = $current_user->user_email;
$formatted_message_args = array(
"<b>{$this->get_plugin_name()}</b>",
"<b>{$email_address}</b>",
if ( ! $has_upgrade_context || ! fs_is_network_admin() ) {
/* translators: %3$s: action (e.g.: "start the trial" or "complete the opt-in") */
$formatted_message = $this->get_text_inline( 'You should receive a confirmation email for %1$s to your mailbox at %2$s. Please make sure you click the button in that email to %3$s.', 'pending-activation-message' );
$formatted_message_args[] = $is_pending_trial ?
$this->get_text_inline( 'start the trial', 'start-the-trial' ) :
$this->get_text_inline( 'complete the opt-in', 'complete-the-opt-in' );
$notice_title = $this->get_text_inline( 'Thanks!', 'thanks' );
/* translators: %3$s: What the user is expected to receive via email (e.g.: "the installation instructions" or "a license key") */
$formatted_message = $this->get_text_inline( 'You should receive %3$s for %1$s to your mailbox at %2$s in the next 5 minutes.' );
if ( $this->has_release_on_freemius() ) {
$formatted_message_args[] = $this->get_text_x_inline(
'the installation instructions',
'Part of the message telling the user what they should receive via email.',
'the-installation-instructions-phrase'
$formatted_message_args[] = $this->get_text_x_inline(
'Part of the message telling the user what they should receive via email.',
$formatted_message .= ( ' ' . sprintf(
/* translators: %s: activation link (e.g.: <a>Click here</a>) */
$this->get_text_inline( '%s to activate the license once you get it.', 'license-activation-link-message' ),
'<b><a href="%s">%s</a></b>',
$this->get_activation_url( array(
'fs_action' => 'reset_pending_activation_mode',
'require_license' => 'true',
'fs_unique_affix' => $this->get_unique_affix(),
$this->get_text_x_inline( 'Click here', 'Part of an activation link message.', 'click-here' )
$formatted_message_args[] = ( ! empty( $support_email_address ) ) ?
( "<b>{$support_email_address}</b>" ) :
$this->get_text_x_inline(
"the product's support email address",
'Part of the message that tells the user to check their spam folder for a specific email.',
'product-support-email-address-phrase'
$formatted_message .= ( ' ' . $this->get_text_inline( 'If you didn\'t get the email, try checking your spam folder or search for emails from %4$s.', 'check-spam-folder-message' ) );
$notice_title = $this->get_text_inline( 'Thanks for upgrading.', 'after-upgrade-thank-you-message' );
$this->_admin_notices->add_sticky(
vsprintf( $formatted_message, $formatted_message_args ),
* Check if currently in plugin activation.
* @author Vova Feldman (@svovaf)
function is_plugin_activation() {
$result = get_transient( "fs_{$this->_module_type}_{$this->_slug}_activated" );
* NOTE: admin_menu action executed before admin_init.
* @author Vova Feldman (@svovaf)
function _admin_init_action() {
$is_migration = $this->is_migration();
* Automatically redirect to connect/activation page after plugin activation.
* @since 1.1.7 Do NOT redirect to opt-in when running in network admin mode.
if ( $this->is_plugin_activation() ) {
delete_transient( "fs_{$this->_module_type}_{$this->_slug}_activated" );
if ( isset( $_GET['activate-multi'] ) ) {
* Don't redirect if activating multiple plugins at once (bulk activation).
self::is_deactivation_snoozed() &&
// Either running the free code base.
// Or if has a free version.
! $this->is_only_premium() ||
// If premium only, don't redirect if license is activated.
( $this->is_registered() && ! $this->can_use_premium_code() )
* Don't redirect if activating during the deactivation snooze period (aka troubleshooting), unless activating a paid product version that the admin didn't enter its license key yet.
} else if ( ! $is_migration ) {
$this->_redirect_on_activation_hook();
if ( fs_request_is_action( $this->get_unique_affix() . '_skip_activation' ) ) {
check_admin_referer( $this->get_unique_affix() . '_skip_activation' );
$this->skip_connection( fs_is_network_admin() );
fs_redirect( $this->get_after_activation_url( 'after_skip_url' ) );
if ( $this->is_network_activation_mode() &&
fs_request_is_action( $this->get_unique_affix() . '_delegate_activation' )
check_admin_referer( $this->get_unique_affix() . '_delegate_activation' );
$this->delegate_connection();
fs_redirect( $this->get_after_activation_url( 'after_delegation_url' ) );
$this->_add_upgrade_action_link();
if ( ! ( ! $this->_is_network_active && fs_is_network_admin() ) &&
( true === $this->_storage->require_license_activation ) ||
// Not registered nor anonymous.
( ! $this->is_registered() && ! $this->is_anonymous() ) ||
// OR, network level and in network upgrade mode.
( fs_is_network_admin() && $this->_is_network_active && $this->is_network_upgrade_mode() )
if ( ! $this->is_pending_activation() ) {
if ( ! $this->is_activation_page() ) {
* If a user visits any other admin page before activating the premium-only theme with a valid
* license, reactivate the previous theme.
* @author Leo Fajardo (@leorw)
if ( $this->is_theme() &&
! $this->has_settings_menu() &&
! isset( $_REQUEST['fs_action'] ) &&
$this->can_activate_previous_theme()
if ( $this->is_only_premium() ) {
$this->activate_previous_theme();
if ( true === $this->_storage->require_license_activation ) {
$this->_storage->require_license_activation = false;
if ( ! fs_is_network_admin() &&
$this->is_network_activation_mode() &&
! $this->is_delegated_connection()
if ( $this->is_plugin_new_install() || $this->is_only_premium() ) {
if ( ! $this->_anonymous_mode &&
( ! $this->is_addon() || ! $this->_parent->is_anonymous() ) ) {
// Show notice for new plugin installations.
$this->_admin_notices->add(
$this->get_text_inline( 'You are just one step away - %s', 'you-are-step-away' ),
sprintf( '<b><a href="%s">%s</a></b>',
$this->get_activation_url( array(), ! $this->is_delegated_connection() ),
sprintf( $this->get_text_x_inline( 'Complete "%s" Activation Now',
'%s - plugin name. As complete "PluginX" activation now', 'activate-x-now' ), $this->get_plugin_name() )
if ( $this->should_add_sticky_optin_notice() ) {
$this->add_sticky_optin_admin_notice();
if ( $this->has_filter( 'optin_pointer_element' ) ) {
// Don't show admin nag if plugin update.
wp_enqueue_script( 'wp-pointer' );
wp_enqueue_style( 'wp-pointer' );
$this->_enqueue_connect_essentials();
add_action( 'admin_print_footer_scripts', array(
'_add_connect_pointer_script'
if ( $this->show_opt_in_on_themes_page() &&
$this->is_activation_page()
$this->_show_theme_activation_optin_dialog();
* @author Vova Feldman (@svovaf)
private function should_add_sticky_optin_notice() {
if ( $this->is_addon() && $this->_parent->is_anonymous() ) {
if ( fs_is_network_admin() ) {
if ( ! $this->_is_network_active ) {
if ( ! $this->is_network_activation_mode() ) {
return ! isset( $this->_storage->sticky_optin_added_ms );
if ( ! $this->is_activation_mode() ) {
// If running from a blog admin and delegated the connection.
return ! isset( $this->_storage->sticky_optin_added );
* @author Leo Fajardo (@leorw)
private function add_sticky_optin_admin_notice() {
if ( ! $this->_is_network_active || ! fs_is_network_admin() ) {
$this->_storage->sticky_optin_added = true;
$this->_storage->sticky_optin_added_ms = true;
// Show notice for new plugin installations.
$this->_admin_notices->add_sticky(
$this->get_text_inline( 'We made a few tweaks to the %s, %s', 'few-plugin-tweaks' ),
sprintf( '<b><a href="%s">%s</a></b>',
$this->get_activation_url(),
sprintf( $this->get_text_inline( 'Opt in to make "%s" better!', 'optin-x-now' ), $this->get_plugin_name() )
* Enqueue connect requires scripts and styles.
* @author Vova Feldman (@svovaf)
function _enqueue_connect_essentials() {
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'json2' );
fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
* Add connect / opt-in pointer.
* @author Vova Feldman (@svovaf)
function _add_connect_pointer_script() {
$vars = array( 'id' => $this->_module_id );
$pointer_content = fs_get_template( 'connect.php', $vars );
<script type="text/javascript">// <![CDATA[
jQuery(document).ready(function ($) {
if ('undefined' !== typeof(jQuery().pointer)) {
var element = <?php echo $this->apply_filters( 'optin_pointer_element', '$("#non_existing_element");' ) ?>;
if (element.length > 0) {
var optin = $(element).pointer($.extend(true, {}, {
content : <?php echo json_encode( $pointer_content ) ?>,
// Don't show pointer buttons.
}, <?php echo $this->apply_filters( 'optin_pointer_options_json', '{}' ) ?>));
echo $this->apply_filters( 'optin_pointer_execute', "
// Tag the opt-in pointer with custom class.
$('.wp-pointer #fs_connect')
.parents('.wp-pointer.wp-pointer-top')
.addClass('fs-opt-in-pointer');
", 'element', 'optin' ) ?>
* Return current page's URL.
* @author Vova Feldman (@svovaf)
static function current_page_url() {
if ( isset( $_SERVER["HTTPS"] ) ) {
if ( $_SERVER["HTTPS"] == "on" ) {
if ( $_SERVER["SERVER_PORT"] != "80" ) {
$url .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
$url .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
* Check if the current page is the plugin's main admin settings page.
* @author Vova Feldman (@svovaf)
function _is_plugin_page() {
return fs_is_plugin_page( $this->_menu->get_raw_slug() ) ||
fs_is_plugin_page( $this->_slug );
------------------------------------------------------------------------------------------------------------------*/
* Delete site install from Database.
* @author Vova Feldman (@svovaf)
* @param int|null $blog_id Since 2.0.0
* @return false|int The install ID if deleted. Otherwise, FALSE (when install not exist).
function _delete_site( $store = true, $blog_id = null ) {
return self::_delete_site_by_slug( $this->_slug, $this->_module_type, $store, $blog_id );
* Delete site install from Database.
* @author Vova Feldman (@svovaf)
* @param string $module_type
* @param int|null $blog_id Since 2.0.0
* @return false|int The install ID if deleted. Otherwise, FALSE (when install not exist).
static function _delete_site_by_slug( $slug, $module_type, $store = true, $blog_id = null ) {
$sites = self::get_all_sites( $module_type, $blog_id );
if ( isset( $sites[ $slug ] ) ) {
if ( is_object( $sites[ $slug ] ) ) {
$install_id = $sites[ $slug ]->id;
unset( $sites[ $slug ] );
self::set_account_option_by_module( $module_type, 'sites', $sites, $store, $blog_id );
* @author Vova Feldman (@svovaf)
* @return false|int The user ID if deleted. Otherwise, FALSE (when install not exist).
private static function delete_user( $user_id, $store = true ) {
$users = self::get_all_users();
if ( ! is_array( $users ) || ! isset( $users[ $user_id ] ) ) {
unset( $users[ $user_id ] );
self::$_accounts->set_option( 'users', $users, $store );