: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
if ( ! defined( 'ABSPATH' ) ) {
* Class FS_Plugin_Info_Dialog
* @author Vova Feldman (@svovaf)
class FS_Plugin_Info_Dialog {
* Collection of plugin installation, update, download, activation, and purchase actions. This is used in
* populating the actions dropdown list when there are at least 2 actions. If there's only 1 action, a button
* @author Leo Fajardo (@leorw)
* Contains plugin status information that is used to determine which actions should be part of the actions
* @author Leo Fajardo (@leorw)
function __construct( Freemius $fs ) {
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $fs->get_slug() . '_info', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
// Remove default plugin information action.
remove_all_actions( 'install_plugins_pre_plugin-information' );
// Override action with custom plugins function for add-ons.
add_action( 'install_plugins_pre_plugin-information', array( &$this, 'install_plugin_information' ) );
// Override request for plugin information for Add-ons.
array( &$this, '_get_addon_info_filter' ),
WP_FS__DEFAULT_PRIORITY, 3 );
* Generate add-on plugin information.
* @author Vova Feldman (@svovaf)
* @param object|null $args
function _get_addon_info_filter( $data, $action = '', $args = null ) {
$this->_logger->entrance();
$parent_plugin_id = fs_request_get( 'parent_plugin_id', $this->_fs->get_id() );
if ( $this->_fs->get_id() != $parent_plugin_id ||
( 'plugin_information' !== $action ) ||
$selected_addon = $this->_fs->get_addon_by_slug( $args->slug, WP_FS__DEV_MODE );
if ( false === $selected_addon ) {
if ( ! isset( $selected_addon->info ) ) {
// Setup some default info.
$selected_addon->info = new stdClass();
$selected_addon->info->selling_point_0 = 'Selling Point 1';
$selected_addon->info->selling_point_1 = 'Selling Point 2';
$selected_addon->info->selling_point_2 = 'Selling Point 3';
$selected_addon->info->description = '<p>Tell your users all about your add-on</p>';
fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
$result = $this->_fs->get_api_plugin_scope()->get( $this->_fs->add_show_pending( "/addons/{$selected_addon->id}/pricing.json?type=visible" ) );
if ( ! isset( $result->error ) ) {
if ( is_array( $plans ) ) {
for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
$pricing = isset( $plans[ $i ]->pricing ) ? $plans[ $i ]->pricing : null;
$features = isset( $plans[ $i ]->features ) ? $plans[ $i ]->features : null;
$plans[ $i ] = new FS_Plugin_Plan( $plans[ $i ] );
if ( 'free' == $plans[ $i ]->name ||
! is_array( $pricing ) ||
if ( is_array( $pricing ) && 0 < count( $pricing ) ) {
$filtered_pricing = array();
foreach ( $pricing as $prices ) {
$prices = new FS_Pricing( $prices );
if ( ! $prices->is_usd() ) {
* @author Leo Fajardo (@leorw)
if ( ( $prices->has_monthly() && $prices->monthly_price > 1.0 ) ||
( $prices->has_annual() && $prices->annual_price > 1.0 ) ||
( $prices->has_lifetime() && $prices->lifetime_price > 1.0 )
$filtered_pricing[] = $prices;
if ( ! empty( $filtered_pricing ) ) {
$plan->pricing = $filtered_pricing;
if ( is_array( $features ) && 0 < count( $features ) ) {
$plan->features = $features;
if ( ! $has_paid_plan && $selected_addon->is_wp_org_compliant ) {
$repo_data = FS_Plugin_Updater::_fetch_plugin_info_from_repository(
'plugin_information', (object) array(
'slug' => $selected_addon->slug,
'active_installs' => true
if ( ! empty( $repo_data ) ) {
$data->wp_org_missing = false;
// Couldn't find plugin on .org.
$selected_addon->is_wp_org_compliant = false;
// Plugin is missing, not on Freemius nor WP.org.
$data->wp_org_missing = true;
$data->fs_missing = ( ! $has_free_plan || $data->wp_org_missing );
$data->has_purchased_license = false;
$data->wp_org_missing = false;
$current_addon_version = false;
if ( $this->_fs->is_addon_activated( $selected_addon->id ) ) {
$fs_addon = $this->_fs->get_addon_instance( $selected_addon->id );
$current_addon_version = $fs_addon->get_plugin_version();
} else if ( $this->_fs->is_addon_installed( $selected_addon->id ) ) {
$addon_plugin_data = get_plugin_data(
( WP_PLUGIN_DIR . '/' . $this->_fs->get_addon_basename( $selected_addon->id ) ),
if ( ! empty( $addon_plugin_data ) ) {
$current_addon_version = $addon_plugin_data['Version'];
// Fetch latest version from Freemius.
$latest = $this->_fs->_fetch_latest_version(
WP_FS__TIME_24_HOURS_IN_SEC,
$blog_id = fs_request_get( 'fs_blog_id' );
$has_valid_blog_id = is_numeric( $blog_id );
if ( $has_valid_blog_id ) {
switch_to_blog( $blog_id );
$data->checkout_link = $this->_fs->checkout_url(
( $has_valid_blog_id ? false : null )
if ( $has_valid_blog_id ) {
* Check if there's a purchased license in case the add-on can only be installed/downloaded as part of a purchased bundle.
* @author Leo Fajardo (@leorw)
if ( is_object( $fs_addon ) ) {
$data->has_purchased_license = $fs_addon->has_active_valid_license();
$account_addons = $this->_fs->get_account_addons();
if ( ! empty( $account_addons ) && in_array( $selected_addon->id, $account_addons ) ) {
$data->has_purchased_license = true;
if ( $has_free_plan || $data->has_purchased_license ) {
$data->download_link = $this->_fs->_get_latest_download_local_url( $selected_addon->id );
empty( $selected_addon->premium_releases_count ) ||
! ( $selected_addon->premium_releases_count > 0 )
// Fetch as much as possible info from local files.
$plugin_local_data = $this->_fs->get_plugin_data();
$data->author = $plugin_local_data['Author'];
if ( ! empty( $selected_addon->info->banner_url ) ) {
'low' => $selected_addon->info->banner_url,
if ( ! empty( $selected_addon->info->screenshots ) ) {
'screenshots' => $selected_addon->info->screenshots,
'plugin' => $selected_addon,
$data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
if ( is_object( $latest ) ) {
$data->version = $latest->version;
$data->last_updated = $latest->created;
$data->requires = $latest->requires_platform_version;
$data->requires_php = $latest->requires_programming_language_version;
$data->tested = $latest->tested_up_to_version;
} else if ( ! empty( $current_addon_version ) ) {
$data->version = $current_addon_version;
$data->version = '1.0.0';
// Add message to developer to deploy the plugin through Freemius.
$data->name = $selected_addon->title;
$view_vars = array( 'plugin' => $selected_addon );
if ( is_object( $latest ) && isset( $latest->readme ) && is_object( $latest->readme ) ) {
$latest_version_readme_data = $latest->readme;
if ( isset( $latest_version_readme_data->sections ) ) {
$data->sections = (array) $latest_version_readme_data->sections;
$data->sections = array();
$data->sections['description'] = fs_get_template( '/plugin-info/description.php', $view_vars );
'plugin' => $selected_addon,
$data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
$data->has_free_plan = $has_free_plan;
$data->has_paid_plan = $has_paid_plan;
$data->is_paid = $has_paid_plan;
$data->is_wp_org_compliant = $selected_addon->is_wp_org_compliant;
$data->premium_slug = $selected_addon->premium_slug;
$data->addon_id = $selected_addon->id;
if ( ! isset( $data->has_purchased_license ) ) {
$data->has_purchased_license = false;
* @author Vova Feldman (@svovaf)
* @param FS_Plugin_Plan $plan
private function get_billing_cycle( FS_Plugin_Plan $plan ) {
if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) {
$pricing = $plan->pricing[0];
if ( isset( $pricing->annual_price ) ) {
$billing_cycle = 'annual';
} else if ( isset( $pricing->monthly_price ) ) {
$billing_cycle = 'monthly';
} else if ( isset( $pricing->lifetime_price ) ) {
$billing_cycle = 'lifetime';
foreach ( $plan->pricing as $pricing ) {
if ( isset( $pricing->annual_price ) ) {
$billing_cycle = 'annual';
} else if ( isset( $pricing->monthly_price ) ) {
$billing_cycle = 'monthly';
} else if ( isset( $pricing->lifetime_price ) ) {
$billing_cycle = 'lifetime';
if ( ! is_null( $billing_cycle ) ) {
* @author Vova Feldman (@svovaf)
* @param FS_Plugin_Plan $plan
* @param FS_Pricing $pricing
* @return float|null|string
private function get_price_tag( FS_Plugin_Plan $plan, FS_Pricing $pricing ) {
if ( isset( $pricing->annual_price ) ) {
$price_tag = $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
} else if ( isset( $pricing->monthly_price ) ) {
$price_tag = $pricing->monthly_price . ' / mo';
} else if ( isset( $pricing->lifetime_price ) ) {
$price_tag = $pricing->lifetime_price;
* @author Leo Fajardo (@leorw)
* @param FS_Plugin_Plan $plan
private function get_actions_dropdown( $api, $plan = null ) {
$this->actions = isset( $this->actions ) ?
$this->get_plugin_actions( $api );
$actions = $this->actions;
$checkout_cta = $this->get_checkout_cta( $api, $plan );
if ( ! empty( $checkout_cta ) ) {
* If there's no license yet, make the checkout button the main CTA. Otherwise, make it the last item in
* @author Leo Fajardo (@leorw)
if ( ! $api->has_purchased_license ) {
array_unshift( $actions, $checkout_cta );
$actions[] = $checkout_cta;
if ( empty( $actions ) ) {
$total_actions = count( $actions );
if ( 1 === $total_actions ) {
<div class="fs-cta fs-dropdown">
<div class="button-group">
// This should NOT be sanitized as the $actions are HTML buttons already.
<div class="button button-primary fs-dropdown-arrow-button">
<span class="fs-dropdown-arrow"></span>
<ul class="fs-dropdown-list" style="display: none">
<?php for ( $i = 1; $i < $total_actions; $i ++ ) : ?>
<li><?php echo str_replace( 'button button-primary', '', $actions[ $i ] ) ?></li>
* @author Vova Feldman (@svovaf)
* @param FS_Plugin_Plan $plan