Skip to content
3 changes: 3 additions & 0 deletions classes/controllers/FrmHooksController.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ public static function load_admin_hooks() {
// Cronjob.
add_action( 'admin_init', 'FrmCronController::schedule_events' );

// Cross sell.
add_action( 'admin_menu', 'FrmSalesApi::menu', 1000 );

// Deactivation feedback.
add_action( 'admin_enqueue_scripts', 'FrmDeactivationFeedbackController::enqueue_assets' );
add_action( 'admin_footer', 'FrmDeactivationFeedbackController::footer_html' );
Expand Down
136 changes: 136 additions & 0 deletions classes/models/FrmSalesApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ class FrmSalesApi extends FrmFormApi {
*/
private static $best_sale;

/**
* @since x.x
*
* @var string|null
*/
private static $cross_sell_text;

/**
* @since x.x
*
* @var string|null
*/
private static $cross_sell_link;

public function __construct() {
$this->set_cache_key();

Expand Down Expand Up @@ -70,7 +84,94 @@ private function set_sales() {

foreach ( $api as $sale ) {
$this->add_sale( $sale );

if ( is_array( $sale ) && isset( $sale['cross_sell_text'] ) ) {
$this->set_cross_sell( $sale );
}
}
}

/**
* Check for a special array in the sales API array.
* Normally cross_sell_text and cross_sell_link are not set.
* But one array, that isn't actually a sale, contains cross sell data.
* This should be near the end of the array.
*
* @since x.x
*
* @param array $data
* @return void
*/
private function set_cross_sell( $data ) {
if ( ! self::cross_sell_is_valid( $data ) ) {
return;
}

$cross_sell_text = $data['cross_sell_text'];
$cross_sell_links = $data['cross_sell_link'];
$index = self::determine_cross_sell_index( $cross_sell_text );

self::$cross_sell_text = sanitize_text_field( $cross_sell_text[ $index ] );
self::$cross_sell_link = esc_url_raw( $cross_sell_links[ $index ] );
}
Comment thread
Crabcyborg marked this conversation as resolved.

/**
* Check that both cross_sell_text and cross_sell_link are set and are arrays of the same size.
*
* @since x.x
*
* @param array $data
* @return bool
*/
private function cross_sell_is_valid( $data ) {
if ( empty( $data['cross_sell_text'] ) || empty( $data['cross_sell_link'] ) ) {
return false;
}

if ( ! is_array( $data['cross_sell_text'] ) || ! is_array( $data['cross_sell_link'] ) ) {
return false;
}

return count( $data['cross_sell_link'] ) === count( $data['cross_sell_text'] );
}

/**
* Determine which cross sell text to use.
* These are shown in order for 30 days before moving on to the next one.
*
* @since x.x
*
* @param array $cross_sell_text
* @return int
*/
private static function determine_cross_sell_index( $cross_sell_text ) {
$option_name = 'frm_cross_sell_settings';
$cross_sell_settings = get_option( $option_name );

if ( ! is_array( $cross_sell_settings ) ) {
$cross_sell_settings = array(
reset( $cross_sell_text ) => time(),
);
update_option( $option_name, $cross_sell_settings );
return 0;
}

foreach ( $cross_sell_text as $index => $current_text ) {
if ( ! isset( $cross_sell_settings[ $current_text ] ) ) {
$cross_sell_settings[ $current_text ] = time();
update_option( $option_name, $cross_sell_settings );
return $index;
}

$time_elapsed = time() - $cross_sell_settings[ $current_text ];
if ( $time_elapsed < DAY_IN_SECONDS * 30 ) {
return $index;
}
}

// If all options are expired, reset the option.
delete_option( $option_name );
return 0;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
Crabcyborg marked this conversation as resolved.

/**
Expand Down Expand Up @@ -383,4 +484,39 @@ private static function is_banner_dismissed( $key ) {
$dismissed_sales = get_user_option( 'frm_dismissed_sales', get_current_user_id() );
return is_array( $dismissed_sales ) && in_array( $key, $dismissed_sales, true );
}

public static function menu() {
if ( false === self::$sales ) {
new self();
}

if ( ! self::$cross_sell_text || ! self::$cross_sell_link ) {
return;
}

add_submenu_page(
'formidable',
esc_html( self::$cross_sell_text ) . ' | Formidable',
esc_html( self::$cross_sell_text ),
'activate_plugins',
'frm-sales-api-cross-sell',
function () {
// There is no page. The redirect logic is handled below, before this callback is triggered.
}
);

add_action(
'admin_init',
function () {
if ( ! current_user_can( 'activate_plugins' ) ) {
return;
}

if ( 'frm-sales-api-cross-sell' === FrmAppHelper::simple_get( 'page' ) && ! empty( self::$cross_sell_link ) ) {
wp_redirect( self::$cross_sell_link );
exit;
}
}
);
}
Comment thread
Crabcyborg marked this conversation as resolved.
}