: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
require_once WP_FS__DIR_INCLUDES . '/class-fs-user-lock.php';
$lock = FS_User_Lock::instance();
* Try to acquire a 60-sec lock based on the WP user and thread/process ID.
if ( ! $lock->try_lock( 60 ) ) {
* @var $current_wp_user WP_User
$current_wp_user = self::_get_current_wp_user();
* @var FS_User $current_fs_user
$current_fs_user = Freemius::_get_user_by_email( $current_wp_user->user_email );
$ten_years_in_sec = 10 * 365 * WP_FS__TIME_24_HOURS_IN_SEC;
if ( ! is_object( $current_fs_user ) ) {
$lock->lock( $ten_years_in_sec );
$gdpr = FS_GDPR_Manager::instance();
if ( $gdpr->is_opt_in_notice_shown() ) {
$lock->lock( 30 * WP_FS__TIME_24_HOURS_IN_SEC );
if ( ! $gdpr->should_show_opt_in_notice() ) {
$lock->lock( $ten_years_in_sec );
$last_time_notice_shown = $gdpr->last_time_notice_was_shown();
$was_notice_shown_before = ( false !== $last_time_notice_shown );
if ( $was_notice_shown_before &&
30 * WP_FS__TIME_24_HOURS_IN_SEC > time() - $last_time_notice_shown
// If the notice was shown before, show it again after 30 days from the last time it was shown.
* Find all plugin IDs that were installed by the current admin.
$plugin_ids_map = self::get_user_opted_in_module_ids_map( $current_fs_user->id );
if ( empty( $plugin_ids_map )) {
$lock->lock( $ten_years_in_sec );
$user_plugins = $this->fetch_user_marketing_flag_status_by_plugins(
array_keys( $plugin_ids_map )
if ( empty( $user_plugins ) ) {
is_array($user_plugins) ?
// Lock for 24-hours on errors.
WP_FS__TIME_24_HOURS_IN_SEC
$has_unset_marketing_optin = false;
foreach ( $user_plugins as $user_plugin ) {
if ( true == $user_plugin->is_marketing_allowed ) {
unset( $plugin_ids_map[ $user_plugin->plugin_id ] );
if ( ! $has_unset_marketing_optin && is_null( $user_plugin->is_marketing_allowed ) ) {
$has_unset_marketing_optin = true;
if ( empty( $plugin_ids_map ) ||
( $was_notice_shown_before && ! $has_unset_marketing_optin )
$lock->lock( $ten_years_in_sec );
array_values( self::maybe_get_entities_account_option( 'plugins', array() ) ),
array_values( self::maybe_get_entities_account_option( 'themes', array() ) )
foreach ( $modules as $module ) {
if ( ! FS_Plugin::is_valid_id( $module->parent_plugin_id ) && isset( $plugin_ids_map[ $module->id ] ) ) {
$plugin_ids_map[ $module->id ] = $module;
if ( 1 === count( $plugin_ids_map ) ) {
$module = reset( $plugin_ids_map );
$plugin_title = $module->title;
$gdpr->add_opt_in_sticky_notice(
$this->get_gdpr_admin_notice_string( $plugin_ids_map ),
$this->add_gdpr_optin_ajax_handler_and_style();
$gdpr->notice_was_just_shown();
$lock->lock( 30 * WP_FS__TIME_24_HOURS_IN_SEC );
* Prevents the GDPR opt-in admin notice from being added if the user has already chosen to allow or not allow
* @author Leo Fajardo (@leorw)
private function disable_opt_in_notice_and_lock_user() {
FS_GDPR_Manager::instance()->disable_opt_in_notice();
require_once WP_FS__DIR_INCLUDES . '/class-fs-user-lock.php';
FS_User_Lock::instance()->lock( 10 * 365 * WP_FS__TIME_24_HOURS_IN_SEC );
* @author Leo Fajardo (@leorw)
static function _add_api_connectivity_notice_handler_js() {
fs_require_once_template( 'api-connectivity-message-js.php' );
* @author Leo Fajardo (@leorw)
function _add_gdpr_optin_js() {
$vars = array( 'id' => $this->_module_id );
fs_require_once_template( 'gdpr-optin-js.php', $vars );
* @author Leo Fajardo (@leorw)
function enqueue_gdpr_optin_notice_style() {
fs_enqueue_local_style( 'fs_gdpr_optin_notice', '/admin/gdpr-optin-notice.css' );
* @author Leo Fajardo (@leorw)
function _maybe_add_gdpr_optin_ajax_handler() {
$this->add_ajax_action( 'fetch_is_marketing_required_flag_value', array( &$this, '_fetch_is_marketing_required_flag_value_ajax_action' ) );
if ( FS_GDPR_Manager::instance()->is_opt_in_notice_shown() ) {
$this->add_gdpr_optin_ajax_handler_and_style();
* @author Leo Fajardo (@leorw)
function _fetch_is_marketing_required_flag_value_ajax_action() {
$this->_logger->entrance();
$this->check_ajax_referer( 'fetch_is_marketing_required_flag_value' );
$license_key = fs_request_get_raw( 'license_key' );
if ( empty($license_key) ) {
self::shoot_ajax_failure( $this->get_text_inline( 'License key is empty.', 'empty-license-key' ) );
$user_plugins = $this->fetch_user_marketing_flag_status_by_plugins(
array( $this->_module_id )
if ( ! is_array( $user_plugins ) ||
!isset($user_plugins[0]->plugin_id) ||
$user_plugins[0]->plugin_id != $this->_module_id
* If faced an error or if the module ID do not match to the current module, ask for GDPR opt-in.
* @author Vova Feldman (@svovaf)
self::shoot_ajax_success( array(
'is_marketing_allowed' => null,
'license_owner_id' => null
self::shoot_ajax_success( array(
'is_marketing_allowed' => $user_plugins[0]->is_marketing_allowed,
'license_owner_id' => ( isset( $user_plugins[0]->license_owner_id ) ? $user_plugins[0]->license_owner_id : null )
* @author Leo Fajardo (@leorw)
* @param number[] $install_ids
* An array of objects containing the installs' licenses owners data.
* @property number $id User ID.
* @property string $email User email (can be masked email).
private function fetch_installs_licenses_owners_data( $install_ids ) {
$this->_logger->entrance();
$response = $this->get_api_user_scope()->get(
'/licenses_owners.json?install_ids=' . implode( ',', $install_ids )
$license_owners = array();
if ( $this->is_api_result_object( $response, 'owners' ) ) {
$license_owners = $response->owners;
* @author Leo Fajardo (@leorw)
private function add_gdpr_optin_ajax_handler_and_style() {
// Add GDPR action AJAX callback.
$this->add_ajax_action( 'gdpr_optin_action', array( &$this, '_gdpr_optin_ajax_action' ) );
add_action( 'admin_footer', array( &$this, '_add_gdpr_optin_js' ) );
add_action( 'admin_enqueue_scripts', array( &$this, 'enqueue_gdpr_optin_notice_style' ) );
* @author Leo Fajardo (@leorw)
function _gdpr_optin_ajax_action() {
$this->_logger->entrance();
$this->check_ajax_referer( 'gdpr_optin_action' );
if ( ! fs_request_has( 'is_marketing_allowed' ) || ! fs_request_has( 'plugin_ids' ) ) {
self::shoot_ajax_failure();
$current_wp_user = self::_get_current_wp_user();
$plugin_ids = fs_request_get( 'plugin_ids', array() );
if ( ! is_array( $plugin_ids ) || empty( $plugin_ids ) ) {
self::shoot_ajax_failure();
array_values( self::maybe_get_entities_account_option( 'plugins', array() ) ),
array_values( self::maybe_get_entities_account_option( 'themes', array() ) )
foreach ( $modules as $key => $module ) {
if ( ! in_array( $module->id, $plugin_ids ) ) {
unset( $modules[ $key ] );
if ( empty( $modules ) ) {
self::shoot_ajax_failure();
$user_api = $this->get_api_user_scope_by_user( Freemius::_get_user_by_email( $current_wp_user->user_email ) );
foreach ( $modules as $module ) {
$user_api->call( "?plugin_id={$module->id}", 'put', array(
'is_marketing_allowed' => ( true == fs_request_get_bool( 'is_marketing_allowed' ) )
FS_GDPR_Manager::instance()->remove_opt_in_notice();
require_once WP_FS__DIR_INCLUDES . '/class-fs-user-lock.php';
FS_User_Lock::instance()->lock( 10 * 365 * WP_FS__TIME_24_HOURS_IN_SEC );
self::shoot_ajax_success();
* Checks if the GDPR admin notice should be handled. By default, this logic is off, unless the integrator adds the special 'handle_gdpr_admin_notice' filter.
* @author Vova Feldman (@svovaf)
private function should_handle_gdpr_admin_notice() {
return $this->apply_filters(
'handle_gdpr_admin_notice',
#----------------------------------------------------------------------------------
#----------------------------------------------------------------------------------
* Check if current user purchased any other plugins before.
* @author Vova Feldman (@svovaf)
function has_purchased_before() {
// TODO: Implement has_purchased_before() method.
throw new Exception( 'not implemented' );
* Check if current user classified as an agency.
* @author Vova Feldman (@svovaf)
// TODO: Implement is_agency() method.
throw new Exception( 'not implemented' );
* Check if current user classified as a developer.
* @author Vova Feldman (@svovaf)
function is_developer() {
// TODO: Implement is_developer() method.
throw new Exception( 'not implemented' );
* Check if current user classified as a business.
* @author Vova Feldman (@svovaf)
// TODO: Implement is_business() method.
throw new Exception( 'not implemented' );
#----------------------------------------------------------------------------------
#----------------------------------------------------------------------------------
* If running with a secret key, assume it's the developer and show pending plans as well.
* @author Vova Feldman (@svovaf)
function add_show_pending( $path ) {
if ( ! $this->has_secret_key() ) {
return $path . ( false !== strpos( $path, '?' ) ? '&' : '?' ) . 'show_pending=true';