: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @author Vova Feldman (@svovaf)
* @return bool If trial notice added.
function _add_trial_notice() {
if ( ! $this->is_user_admin() ) {
if ( ! $this->is_user_in_admin() ) {
if ( $this->_is_network_active ) {
if ( fs_is_network_admin() ) {
// Network level trial is disabled at the moment.
if ( ! $this->is_delegated_connection() ) {
// Only delegated sites should support trials.
// Check if trial message is already shown.
if ( $this->is_in_trial_promotion() ) {
add_action( 'admin_footer', array( &$this, '_fix_start_trial_menu_item_url' ) );
$this->_menu->add_counter_to_menu_item( 1, 'fs-trial' );
if ( $this->is_premium() && ! WP_FS__DEV_MODE ) {
// Don't show trial if running the premium code, unless running in DEV mode.
if ( ! $this->has_trial_plan() ) {
if ( ! $this->apply_filters( 'show_trial', true ) ) {
// Developer explicitly asked not to show the trial promo.
if ( $this->is_registered() ) {
// Check if trial already utilized.
if ( $this->_site->is_trial_utilized() ) {
if ( $this->is_paying_or_trial() ) {
// Don't show trial if paying or already in trial.
if ( $this->is_activation_mode() || $this->is_pending_activation() ) {
// If not yet opted-in/skipped, or pending activation, don't show trial.
$last_time_trial_promotion_shown = $this->_storage->get( 'trial_promotion_shown', false );
$was_promotion_shown_before = ( false !== $last_time_trial_promotion_shown );
// Show promotion if never shown before and 24 hours after initial activation with FS.
if ( ! $was_promotion_shown_before &&
$this->_storage->install_timestamp > ( time() - $this->apply_filters( 'show_first_trial_after_n_sec', WP_FS__TIME_24_HOURS_IN_SEC ) )
// OR if promotion was shown before, try showing it every 30 days.
if ( $was_promotion_shown_before &&
$this->apply_filters( 'reshow_trial_after_every_n_sec', 30 * WP_FS__TIME_24_HOURS_IN_SEC ) > time() - $last_time_trial_promotion_shown
$trial_period = $this->_trial_days;
$require_payment = $this->_is_trial_require_payment;
$trial_url = $this->get_trial_url();
$plans_string = strtolower( $this->get_text_inline( 'Awesome', 'awesome' ) );
if ( $this->is_registered() ) {
// If opted-in, override trial with up to date data from API.
$trial_plans = FS_Plan_Manager::instance()->get_trial_plans( $this->_plans );
$trial_plans_count = count( $trial_plans );
if ( 0 === $trial_plans_count ) {
// If there's no plans with a trial just exit.
* @var FS_Plugin_Plan $paid_plan
$paid_plan = $trial_plans[0];
$require_payment = $paid_plan->is_require_subscription;
$trial_period = $paid_plan->trial_period;
$total_paid_plans = count( $this->_plans ) - ( FS_Plan_Manager::instance()->has_free_plan( $this->_plans ) ? 1 : 0 );
if ( $total_paid_plans !== $trial_plans_count ) {
// Not all paid plans have a trial - generate a string of those that have it.
for ( $i = 0; $i < $trial_plans_count; $i ++ ) {
$plans_string .= sprintf(
$trial_plans[ $i ]->title
if ( $i < $trial_plans_count - 2 ) {
} else if ( $i == $trial_plans_count - 2 ) {
$plans_string .= ' and ';
$this->get_text_x_inline( 'Hey', 'exclamation', 'hey' ) . '! ' . $this->get_text_inline( 'How do you like %s so far? Test all our %s premium features with a %d-day free trial.', 'trial-x-promotion-message' ),
sprintf( '<b>%s</b>', $this->get_plugin_name() ),
// "No Credit-Card Required" or "No Commitment for N Days".
$cc_string = $require_payment ?
sprintf( $this->get_text_inline( 'No commitment for %s days - cancel anytime!', 'no-commitment-for-x-days' ), $trial_period ) :
$this->get_text_inline( 'No credit card required', 'no-cc-required' ) . '!';
'<a style="margin-left: 10px; vertical-align: super;" href="%s"><button class="button button-primary">%s ➜</button></a>',
$this->get_text_x_inline( 'Start free trial', 'call to action', 'start-free-trial' )
$this->_admin_notices->add_sticky(
$this->apply_filters( 'trial_promotion_message', "{$message} {$cc_string} {$button}" ),
$this->_storage->trial_promotion_shown = WP_FS__SCRIPT_START_TIME;
* Lets users/customers know that the product has an affiliate program.
* @author Leo Fajardo (@leorw)
* @return bool Returns true if the notice has been added.
function _add_affiliate_program_notice() {
if ( ! $this->is_user_admin() ) {
if ( ! $this->is_user_in_admin() ) {
// Check if the notice is already shown.
if ( $this->_admin_notices->has_sticky( 'affiliate_program' ) ) {
// Product has no affiliate program.
! $this->has_affiliate_program() ||
// User has applied for an affiliate account.
! empty( $this->_storage->affiliate_application_data )
if ( ! $this->apply_filters( 'show_affiliate_program_notice', true ) ) {
// Developer explicitly asked not to show the notice about the affiliate program.
if ( $this->is_activation_mode() || $this->is_pending_activation() ) {
// If not yet opted in/skipped, or pending activation, don't show the notice.
$last_time_notice_was_shown = $this->_storage->get( 'affiliate_program_notice_shown', false );
$was_notice_shown_before = ( false !== $last_time_notice_was_shown );
* Do not show the notice if it was already shown before or less than 30 days have passed since the initial
if ( $was_notice_shown_before ||
$this->_storage->install_timestamp > ( time() - ( WP_FS__TIME_24_HOURS_IN_SEC * 30 ) )
if ( ! $this->is_paying() &&
FS_Plugin::AFFILIATE_MODERATION_CUSTOMERS == $this->_plugin->affiliate_moderation
// If the user is not a customer and the affiliate program is only for customers, don't show the notice.
$this->get_text_inline( 'Hey there, did you know that %s has an affiliate program? If you like the %s you can become our ambassador and earn some cash!', 'become-an-ambassador-admin-notice' ),
sprintf( '<strong>%s</strong>', $this->get_plugin_name() ),
$this->get_module_label( true )
// HTML code for the "Learn more..." button.
'<a style="display: block; margin-top: 10px;" href="%s"><button class="button button-primary">%s ➜</button></a>',
$this->_get_admin_page_url( 'affiliation' ),
$this->get_text_inline( 'Learn more', 'learn-more' ) . '...'
$this->_admin_notices->add_sticky(
$this->apply_filters( 'affiliate_program_notice', "{$message} {$button}" ),
$this->_storage->affiliate_program_notice_shown = WP_FS__SCRIPT_START_TIME;
* @author Vova Feldman (@svovaf)
function _enqueue_common_css() {
if ( $this->has_paid_plan() && ! $this->is_paying() ) {
// Add basic CSS for admin-notices and menu-item colors.
fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
* @author Leo Fajardo (@leorw)
function _show_theme_activation_optin_dialog() {
fs_enqueue_local_style( 'fs_connect', '/admin/connect.css' );
add_action( 'admin_footer', array( &$this, '_add_fs_theme_activation_dialog' ) );
* @author Leo Fajardo (@leorw)
function _add_fs_theme_activation_dialog() {
if ( 'themes.php' !== $pagenow ) {
$vars = array( 'id' => $this->_module_id );
fs_require_once_template( 'connect.php', $vars );
------------------------------------------------------------------------------------------------------------------*/
private $_action_links_hooked = false;
private $_action_links = array();
* Hook to plugin action links filter.
* @author Vova Feldman (@svovaf)
private function hook_plugin_action_links() {
$this->_logger->entrance();
$this->_action_links_hooked = true;
$this->_logger->log( 'Adding action links hooks.' );
// Add action link to settings page.
add_filter( 'plugin_action_links_' . $this->_plugin_basename, array(
'_modify_plugin_action_links_hook'
), WP_FS__DEFAULT_PRIORITY, 2 );
add_filter( 'network_admin_plugin_action_links_' . $this->_plugin_basename, array(
'_modify_plugin_action_links_hook'
), WP_FS__DEFAULT_PRIORITY, 2 );
* Add plugin action link.
* @author Vova Feldman (@svovaf)
function add_plugin_action_link( $label, $url, $external = false, $priority = WP_FS__DEFAULT_PRIORITY, $key = false ) {
$this->_logger->entrance();
if ( ! isset( $this->_action_links[ $priority ] ) ) {
$this->_action_links[ $priority ] = array();
$key = preg_replace( "/[^A-Za-z0-9 ]/", '', strtolower( $label ) );
$this->_action_links[ $priority ][] = array(
* Adds Upgrade and Add-Ons links to the main Plugins page link actions collection.
* @author Vova Feldman (@svovaf)
function _add_upgrade_action_link() {
$this->_logger->entrance();
$is_activation_mode = $this->is_activation_mode();
$add_action_links = $this->should_add_submenu_or_action_links( $is_activation_mode );
* The following logic is based on the logic in `add_submenu_items()` method that decides when the "Upgrade"
* and "Add-Ons" menus should be added.
* @author Leo Fajardo (@leorw)
( $is_activation_mode && $this->is_only_premium() )
) && ! WP_FS__DEMO_MODE && ( ! $this->is_whitelabeled() );
$add_addons_link = ( $add_action_links && $this->has_addons() );
if ( ! $add_upgrade_link && ! $add_addons_link ) {
$this->is_pricing_page_visible() &&
$this->is_submenu_item_visible( 'pricing' )
$this->add_plugin_action_link(
$this->get_text_inline( 'Upgrade', 'upgrade' ),
$this->get_upgrade_url(),
$this->is_submenu_item_visible( 'addons' )
$this->add_plugin_action_link(
$this->get_text_inline( 'Add-Ons', 'add-ons' ),
$this->_get_admin_page_url( 'addons' ),
* Adds "Activate License" or "Change License" link to the main Plugins page link actions collection.
* @author Leo Fajardo (@leorw)
function _add_license_action_link() {
$this->_logger->entrance();
if ( ! self::is_ajax() ) {
// Inject license activation dialog UI and client side code.
add_action( 'admin_footer', array( &$this, '_add_license_activation_dialog_box' ) );
$link_text = $this->is_free_plan() ?
$this->get_text_inline( 'Activate License', 'activate-license' ) :
$this->get_text_inline( 'Change License', 'change-license' );
$this->add_plugin_action_link(
( 'activate-license ' . $this->get_unique_affix() )
* @author Leo Fajardo (@leorw)
function _add_premium_version_upgrade_selection_action() {
$this->_logger->entrance();
if ( ! self::is_ajax() ) {
add_action( 'admin_footer', array( &$this, '_add_premium_version_upgrade_selection_dialog_box' ) );
* Adds "Opt In" or "Opt Out" link to the main "Plugins" page link actions collection.
* @author Leo Fajardo (@leorw)
function _add_tracking_links() {
if ( ! current_user_can( 'manage_options' ) ) {
$this->_logger->entrance();
if ( $this->is_only_premium() && $this->is_free_plan() ) {
// Don't add tracking links for premium-only products that were opted-in by relation (add-on or a parent product) before activating any license.
! $this->is_only_premium()
$parent = $this->get_parent_instance();
if ( is_object( $parent ) && $parent->is_anonymous() ) {
if ( fs_is_network_admin() ) {
if ( ! $this->_is_network_active ) {
// Don't add tracking links when browsing the network WP Admin and the plugin is not network active.
} else if ( $this->is_network_delegated_connection() ) {
// Don't add tracking links when browsing the network WP Admin and the activation has been delegated to site admins.
if ( $this->_is_network_active && ! $this->is_delegated_connection() ) {
// Don't add tracking links when browsing the sub-site WP Admin, the plugin is network active, and the connection was not delegated.
if ( fs_request_is_action_secure( $this->get_unique_affix() . '_reconnect' ) ) {
if ( ! $this->is_registered() && $this->is_anonymous() ) {
if ( ( $this->is_plugin() && ! self::is_plugins_page() ) ||
( $this->is_theme() && ! self::is_themes_page() )
// Only show tracking links on the plugins and themes pages.