- WordPress core y plugins - Tema Twenty Twenty-Four configurado - Plugin allow-unfiltered-html.php simplificado - .gitignore configurado para excluir wp-config.php y uploads 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1068 lines
34 KiB
PHP
Executable File
1068 lines
34 KiB
PHP
Executable File
<?php
|
|
|
|
/**
|
|
* Contains logic for frontend display of campaigns
|
|
*
|
|
* @class TU_Frontend_Handler
|
|
*/
|
|
class TU_Frontend_Handler {
|
|
|
|
/**
|
|
* @var WP_Post the current campaign that's being displayed. ONLY available during the ajax-call for Lazy-load
|
|
*/
|
|
public $campaign;
|
|
|
|
/**
|
|
* @var WP_Post[] the list of campaigns for which the display settings apply for the current request (ONLY AVAILABLE DURING THE MAIN REQUEST)
|
|
*/
|
|
protected $campaigns;
|
|
|
|
/**
|
|
* called on template_redirect hook
|
|
*
|
|
* it should handle all redirections if a current page is a promotion page and the special offer conditions are not met
|
|
*
|
|
* for fixed date campaigns:
|
|
* redirect to pre-offer before the campaign starts
|
|
* redirect to expired after the campaign ended
|
|
*
|
|
* for rolling date campaigns:
|
|
* redirect to pre-offer before the campaign start or if the campaign will be shown again (is not currently in the rolling date interval)
|
|
* redirect to expired after the campaign has ended
|
|
*
|
|
* for evergreen campaigns:
|
|
* redirect to pre-offer before the triggers are met
|
|
* redirect to expired if the campaign has expired for the current user
|
|
*
|
|
* Also, this is the point where email addresses passed in as URL parameters are stored and timestamped
|
|
*
|
|
*/
|
|
public function hook_template_redirect() {
|
|
|
|
if ( current_user_can( 'edit_posts' ) || TU_Product::has_access() ) {
|
|
return false;
|
|
}
|
|
|
|
$is_shop = function_exists( 'is_shop' ) && is_shop();
|
|
if ( ! $is_shop && ( ! is_singular() || ! $this->should_display_campaign() ) ) {
|
|
return;
|
|
}
|
|
|
|
$the_id = $is_shop ? get_option( 'woocommerce_shop_page_id' ) : get_the_ID();
|
|
|
|
if ( function_exists( 'thrive_ab' ) ) {
|
|
$post = get_post( $the_id );
|
|
$is_top_variation = thrive_ab()->maybe_variation( $post );
|
|
$the_id = $is_top_variation ? $post->post_parent : $the_id;
|
|
}
|
|
$campaigns = tve_ult_get_campaigns_for_promotion_page( $the_id );
|
|
$redirect_campaigns = tve_ult_get_campaigns_with_redirect( $the_id );
|
|
|
|
/**
|
|
* get all campaigns that have the current page set as a promotion (special offer) page
|
|
*/
|
|
if ( empty( $the_id ) || ( ! $campaigns && ! $redirect_campaigns ) ) {
|
|
return;
|
|
}
|
|
|
|
$campaigns_logic = array();
|
|
|
|
//support + sign in emails
|
|
if ( isset( $_GET['tu_em'] ) ) {
|
|
$_GET['tu_em'] = str_replace( ' ', '+', $_GET['tu_em'] );
|
|
}
|
|
|
|
/* Lockdown campaigns */
|
|
foreach ( $campaigns as $campaign ) {
|
|
/* @var TU_Schedule_Abstract $schedule */
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
$campaigns_logic[ $campaign->ID ] = true;
|
|
|
|
if ( $schedule->should_redirect_pre_access() ) {
|
|
$permalink = isset( $campaign->lockdown_settings['preaccess']['id'] ) ? get_post_permalink( $campaign->lockdown_settings['preaccess']['id'] ) : $campaign->lockdown_settings['preaccess']['value'];
|
|
$campaigns_logic[ $campaign->ID ] = $permalink;
|
|
continue;
|
|
}
|
|
|
|
/** if the campaign is evergreen save the email in the db if not exists */
|
|
if ( $campaign->type === TVE_Ult_Const::CAMPAIGN_TYPE_EVERGREEN ) {
|
|
|
|
/* @var $schedule TU_Schedule_Evergreen */
|
|
|
|
//if we have the email in the url
|
|
unset( $email_param );
|
|
if ( isset( $_GET['tu_em'] ) && filter_var( $_GET['tu_em'], FILTER_VALIDATE_EMAIL ) && isset( $_GET['tu_id'] ) && $_GET['tu_id'] == $campaign->ID ) {
|
|
$email_param = $params['lockdown']['email'] = $_GET['tu_em'];
|
|
}
|
|
|
|
if ( isset( $_COOKIE[ $schedule->cookie_name() ] ) ) {
|
|
$cookie = $schedule->get_cookie_data();
|
|
$cookie = $cookie['cookie'];
|
|
$params['start_date'] = $cookie['start_date'];
|
|
|
|
$has_email = $schedule->verify_cookie();
|
|
if ( $has_email ) {
|
|
$params['lockdown']['email'] = $cookie['lockdown']['email'];
|
|
$params['lockdown']['cookie_id'] = $cookie['lockdown']['log_id'];
|
|
}
|
|
/**
|
|
* If a visitor changes the email from the link and tries to access the special offer page, also save that email address with the same start date as the first one
|
|
*/
|
|
if ( isset( $email_param ) && ( ! $has_email || $email_param !== $params['lockdown']['email'] ) ) {
|
|
$params['lockdown']['email'] = $email_param; // make sure the new email address is timestampped with the same date
|
|
}
|
|
}
|
|
|
|
$email_log = empty( $params['lockdown']['email'] ) ? null : tve_ult_get_email_log( $campaign->ID, $params['lockdown']['email'] );
|
|
$is_webhook = $campaign->settings['trigger']['type'] === TVE_Ult_Const::TRIGGER_TYPE_WEBHOOK;
|
|
|
|
if ( isset( $params['lockdown']['email'] ) && ( ( $is_webhook && ! empty( $email_log ) ) || ! $is_webhook ) ) {
|
|
$schedule->set_cookie_and_save_log( $params );
|
|
} elseif ( isset( $_GET['tu_id'] ) && $_GET['tu_id'] == $campaign->ID ) {
|
|
$permalink = isset( $campaign->lockdown_settings['expired']['id'] ) ? get_post_permalink( $campaign->lockdown_settings['expired']['id'] ) : $campaign->lockdown_settings['expired']['value'];
|
|
$campaigns_logic[ $campaign->ID ] = $permalink;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( $schedule->should_redirect_expired() ) {
|
|
$permalink = isset( $campaign->lockdown_settings['expired']['id'] ) ? get_post_permalink( $campaign->lockdown_settings['expired']['id'] ) : $campaign->lockdown_settings['expired']['value'];
|
|
$campaigns_logic[ $campaign->ID ] = $permalink;
|
|
continue;
|
|
}
|
|
|
|
/**
|
|
* we've found the 1st campaign applicable
|
|
* in this case we should let the logic be
|
|
*/
|
|
if ( isset( $campaigns_logic[ $campaign->ID ] ) && $campaigns_logic[ $campaign->ID ] === true ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Redirect campaigns */
|
|
foreach ( $redirect_campaigns as $campaign ) {
|
|
/* @var TU_Schedule_Abstract $schedule */
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
$campaigns_logic[ $campaign->ID ] = true;
|
|
|
|
if ( isset( $_COOKIE[ $schedule->get_redirect_cookie_key() ] ) ) {
|
|
$cookie = $schedule->get_cookie_redirect_data();
|
|
$cookie = $cookie['cookie'];
|
|
|
|
if ( isset( $campaign->settings['redirect_url'] ) && $schedule->is_past( $cookie['end_date'] ) ) {
|
|
$campaigns_logic[ $campaign->ID ] = get_permalink( $campaign->settings['redirect_url'] );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* we've found the 1st campaign applicable
|
|
* in this case we should let the logic be
|
|
*/
|
|
if ( isset( $campaigns_logic[ $campaign->ID ] ) && $campaigns_logic[ $campaign->ID ] === true ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* at this moment we should have at least 1 campaign with 1 redirect because:
|
|
* - if there is no campaign there is another if above
|
|
* - if there is an applicable campaign there is an if in loop
|
|
*/
|
|
wp_redirect( array_shift( $campaigns_logic ) );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* its logic has been moved on wp_print_footer_script action
|
|
*
|
|
* @see $this->hook_print_footer_scripts()
|
|
*/
|
|
public function hook_enqueue_scripts() {
|
|
/**
|
|
* this function initializes $this->campaigns
|
|
* and we need them here because they are needed to be loaded for widget logic
|
|
*/
|
|
$this->get_available_campaigns();
|
|
|
|
tve_ult_enqueue_style( 'tve-ult-main-frame-css', TVE_Ult_Const::plugin_url( 'tcb-bridge/assets/css/placeholders.css' ) );
|
|
|
|
/**
|
|
* check if shop or single
|
|
*/
|
|
$is_shop = function_exists( 'is_shop' ) && is_shop();
|
|
$the_id = $is_shop ? get_option( 'woocommerce_shop_page_id' ) : get_the_ID();
|
|
|
|
/**
|
|
* check if we should enqueue tooltip assets
|
|
*/
|
|
if ( ! empty( $the_id ) && tve_ult_get_campaigns_for_promotion_page( $the_id ) ) {
|
|
$tooltip_url = defined( 'TVE_DEBUG' ) && TVE_DEBUG ? 'js/tooltip.js' : 'js/dist/tooltip.min.js';
|
|
$velocity_url = defined( 'TVE_DEBUG' ) && TVE_DEBUG ? 'js/velocity.js' : 'js/dist/velocity.min.js';
|
|
|
|
wp_script_is( 'tve-ult-velocity' ) || wp_enqueue_script( 'tve-ult-velocity', TVE_Ult_Const::plugin_url( $velocity_url ), array( 'jquery' ), TVE_Ult_Const::PLUGIN_VERSION, true );
|
|
wp_script_is( 'tve-ult-tooltip' ) || wp_enqueue_script( 'tve-ult-tooltip', TVE_Ult_Const::plugin_url( $tooltip_url ), array( 'jquery' ), TVE_Ult_Const::PLUGIN_VERSION, true );
|
|
wp_style_is( 'tve-ult-styles' ) || wp_enqueue_style( 'tve-ult-styles', TVE_Ult_Const::plugin_url( 'css/styles.css' ), array(), TVE_Ult_Const::PLUGIN_VERSION );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* called on wp_print_footer_scripts WP hook
|
|
* it iterates through the campaigns and selects the ones that are viable for display
|
|
* the conditions for display are:
|
|
* 1) the Display settings for the campaign match
|
|
* 2) the schedule for the matched campaign applies
|
|
*
|
|
* we cannot verify point (2) at this point, because of caching plugins - point (2) will be verified in the ajax - load phase
|
|
*
|
|
* if a campaign can be displayed, than we enqueue the scripts and data required on frontend, in order to make the AJAX call that will display the campaign design
|
|
*
|
|
* we have the following possible triggers for a campaign:
|
|
* a) time-based
|
|
* b) user-based
|
|
* c) event-based (e.g. a Conversion event for a campaign triggers the start of another campaign)
|
|
*/
|
|
public function hook_print_footer_scripts() {
|
|
if ( ! $this->should_display_campaign() ) {
|
|
return;
|
|
}
|
|
|
|
$available_campaigns = $this->get_available_campaigns();
|
|
$shortcode_campaigns = TU_Shortcodes::get_campaigns();
|
|
|
|
/**
|
|
* campaign IDs that should only display ribbons and widgets - campaigns that have been matched by display settings
|
|
*/
|
|
$matched_display_settings_ids = array_map( 'tve_ult_campaign_id', $available_campaigns );
|
|
|
|
$campaigns_by_id = array_unique( array_merge( $matched_display_settings_ids, $shortcode_campaigns ) );
|
|
|
|
$scripts = array();
|
|
|
|
if ( ! $campaigns_by_id ) {
|
|
$scripts[] = TVE_Ult_Const::plugin_url( 'js/dist/no-campaign.min.js' );
|
|
} else {
|
|
$scripts[] = TVE_Ult_Const::plugin_url( 'js/dist/frontend.min.js' );
|
|
}
|
|
|
|
/**
|
|
* localize data required by scripts
|
|
*/
|
|
$this->localize_data( 'TVE_Ult_Data', $this->get_localization( $campaigns_by_id, $matched_display_settings_ids ) );
|
|
|
|
/**
|
|
* print required scripts
|
|
*/
|
|
foreach ( $scripts as $script ) {
|
|
$this->print_script( $script );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prints the json data in HTML
|
|
*
|
|
* @param string $name
|
|
* @param mixed $data
|
|
*/
|
|
public function localize_data( $name, $data ) {
|
|
$output = "var $name = " . wp_json_encode( $data ) . ';';
|
|
|
|
echo "<script type='text/javascript'>\n";
|
|
echo "/* <![CDATA[ */\n";
|
|
echo "$output\n";
|
|
echo "/* ]]> */\n";
|
|
echo "</script>\n";
|
|
}
|
|
|
|
/**
|
|
* Prints the script in HTML
|
|
*
|
|
* @param $src
|
|
*/
|
|
public function print_script( $src ) {
|
|
|
|
if ( defined( 'TVE_DEBUG' ) && TVE_DEBUG ) {
|
|
$src = preg_replace( '#\.min\.js$#', '.js', $src );
|
|
}
|
|
|
|
$src .= '?v=' . TVE_Ult_Const::PLUGIN_VERSION;
|
|
|
|
?>
|
|
<script type="text/javascript" src="<?php echo $src ?>"></script><?php
|
|
}
|
|
|
|
/**
|
|
* fetch a campaign list that matches the current page based on the selected display settings
|
|
*
|
|
* we do this here, as this is dependent on the current request, and the schedule checking will be done via ajax, in order to circumvent caching plugins
|
|
*
|
|
* @return WP_Post[]
|
|
*/
|
|
protected function get_available_campaigns() {
|
|
|
|
/**
|
|
* cache the campaigns during the current request
|
|
*/
|
|
if ( $this->campaigns !== null ) {
|
|
return $this->campaigns;
|
|
}
|
|
|
|
$filtered = array();
|
|
|
|
$all_campaigns = tve_ult_get_campaigns( array(
|
|
'get_designs' => false, // do not get the designs at this point, avoid extra db queries
|
|
'get_events' => false,
|
|
'get_settings' => false,
|
|
'get_logs' => false,
|
|
'only_running' => true,
|
|
) );
|
|
|
|
foreach ( $all_campaigns as $campaign ) {
|
|
|
|
/**
|
|
* if the schedule for the campaign applies (e.g. the current time is in the required interval, or a cookie exists)
|
|
* we continue checking if the display settings apply
|
|
*
|
|
*/
|
|
if ( ! isset( $manager ) ) {
|
|
require_once TVE_Ult_Const::plugin_path( 'inc/classes/display_settings/class-thrive-display-settings-manager.php' );
|
|
$manager = new Thrive_Ult_Display_Settings_Manager();
|
|
$manager->load_dependencies();
|
|
}
|
|
|
|
$saved_ptions = new Thrive_Ult_Campaign_Options( $campaign->ID );
|
|
$saved_ptions->initOptions();
|
|
|
|
$available = $saved_ptions->displayCampaign();
|
|
|
|
/**
|
|
* a campaign is available if it has display settings and also has designs other than shortcodes
|
|
*/
|
|
if ( $available ) {
|
|
$campaign->designs = tve_ult_get_designs( $campaign->ID, array( 'edit_links' => false ) );
|
|
$other_than_shortcode = false;
|
|
foreach ( $campaign->designs as $design ) {
|
|
if ( $design['post_type'] !== TVE_Ult_Const::DESIGN_TYPE_SHORTCODE ) {
|
|
$other_than_shortcode = true;
|
|
break;
|
|
}
|
|
}
|
|
$available = $other_than_shortcode;
|
|
}
|
|
|
|
if ( $available ) {
|
|
$filtered [] = $campaign;
|
|
}
|
|
}
|
|
|
|
$this->campaigns = $filtered;
|
|
|
|
return $filtered;
|
|
}
|
|
|
|
/**
|
|
* some general restrictions on pages where we are sure that no campaigns will be displayed
|
|
* e.g. on the TCB editor page, when previewing a lightbox / thrive leads form etc
|
|
*
|
|
* @return bool whether or not the current request can display a campaign
|
|
*
|
|
*/
|
|
public function should_display_campaign() {
|
|
|
|
if ( is_editor_page_raw() || is_singular( array( TVE_Ult_Const::POST_TYPE_NAME_FOR_CAMPAIGN ) ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( function_exists( 'tve_leads_is_preview_page' ) && tve_leads_is_preview_page() ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Allow short-circuiting the TU campaign logic
|
|
*
|
|
* hook to this filter and return false if a campaign should not be displayed for the current request
|
|
*
|
|
* @param bool $can_display
|
|
*
|
|
* @since 0.0.1
|
|
*
|
|
*/
|
|
$can_display = apply_filters( 'thrive_ult_can_display_campaign', true );
|
|
|
|
return $can_display;
|
|
}
|
|
|
|
/**
|
|
* gets the non-shortcode or mixed campaigns
|
|
*
|
|
* @param array $campaigns
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_nonshortcode_campaigns( $campaigns ) {
|
|
$nonshortcode_campaigns = array();
|
|
foreach ( $campaigns as $campaign ) {
|
|
$other_than_shortcode = false;
|
|
foreach ( $campaign->designs as $design ) {
|
|
if ( $design['post_type'] !== TVE_Ult_Const::DESIGN_TYPE_SHORTCODE ) {
|
|
$other_than_shortcode = true;
|
|
}
|
|
continue;
|
|
}
|
|
if ( $other_than_shortcode ) {
|
|
$nonshortcode_campaigns[] = $campaign->ID;
|
|
}
|
|
}
|
|
|
|
return $nonshortcode_campaigns;
|
|
}
|
|
|
|
/**
|
|
* Prints the json response that is required by frontend.js file
|
|
*
|
|
* @se insert_response()
|
|
*
|
|
* @param array $current
|
|
* @param array $params
|
|
*
|
|
* @return array|void
|
|
*/
|
|
public function ajax_load( $current = array(), $params = array() ) {
|
|
|
|
if ( empty( $params ) ) {
|
|
$params = $_REQUEST;
|
|
}
|
|
|
|
$this->check_evergreen_triggers();
|
|
|
|
if ( empty( $params['campaign_ids'] ) || ! is_array( $params['campaign_ids'] ) ) {
|
|
return empty( $params['hard_ajax'] ) ? array() : wp_die();
|
|
}
|
|
|
|
$matched_display_settings_ids = ! empty( $params['matched_display_settings'] ) ? $params['matched_display_settings'] : array();
|
|
|
|
$applicable_campaigns = $this->get_applicable_campaigns( $_REQUEST['campaign_ids'] );
|
|
$nonshortcode_campaigns = $this->get_nonshortcode_campaigns( $applicable_campaigns );
|
|
|
|
if ( empty( $applicable_campaigns ) ) {
|
|
return empty( $params['hard_ajax'] ) ? array() : wp_die();
|
|
}
|
|
|
|
add_filter( 'option_tve_leads_ajax_load', '__return_false' );
|
|
|
|
/**
|
|
* "enqueue" the default scripts and css needed
|
|
*/
|
|
tve_ult_enqueue_default_scripts();
|
|
|
|
$response = array(
|
|
'resources' => array(
|
|
'css' => array(),
|
|
'js' => array(),
|
|
),
|
|
'body_end' => '',
|
|
);
|
|
|
|
$shortcode_campaigns = $this->param( 'shortcode_campaign_ids', array() );
|
|
$shortcode_campaigns = array_map( 'intval', $shortcode_campaigns );
|
|
/* TODO: why is this the first campaign ?! */
|
|
$main_campaign_id = reset( $nonshortcode_campaigns );
|
|
|
|
foreach ( $applicable_campaigns as $campaign ) {
|
|
$is_shortcode = in_array( $campaign->ID, $shortcode_campaigns );
|
|
$is_main = $campaign->ID === $main_campaign_id;
|
|
|
|
/* TODO: we should rewrite this, this is only a hotfix */
|
|
$is_main = $is_main && in_array( $campaign->ID, $matched_display_settings_ids );
|
|
if ( $main_campaign_id && $is_main ) {
|
|
$response[ $campaign->ID ] = $this->prepare_campaign_response( $campaign );
|
|
} elseif ( $is_shortcode ) {
|
|
$response[ $campaign->ID ] = $this->prepare_campaign_response( $campaign, true );
|
|
}
|
|
}
|
|
|
|
$outer_html = apply_filters( 'tve_ult_body_end_html', '' );
|
|
|
|
$response['resources']['css'] = $this->get_outer_css( 'tve' );
|
|
$response['resources']['js'] = $this->get_outer_scripts( 'tve' );
|
|
|
|
/** print footer javascript */
|
|
ob_start();
|
|
tve_print_footer_events();
|
|
echo $outer_html;
|
|
$response['body_end'] = ob_get_contents();
|
|
ob_end_clean();
|
|
|
|
$response = apply_filters( 'tve_ultimatum_ajax_load_forms', $response );
|
|
|
|
return empty( $params['hard_ajax'] ) ? $response : wp_send_json( $response );
|
|
}
|
|
|
|
/**
|
|
* Foreach campaign we need to have its response: html designs, assets, etc
|
|
*
|
|
* @param $campaign
|
|
* @param $is_shortcode
|
|
*
|
|
* @return array|void
|
|
*/
|
|
public function prepare_campaign_response( $campaign, $is_shortcode = false ) {
|
|
/**
|
|
* Registers an impression for the campaign
|
|
*/
|
|
if ( ! isset( $_COOKIE[ TVE_Ult_Const::COOKIE_IMPRESSION . $campaign->ID ] ) ) {
|
|
|
|
$email_log = tve_ult_get_email_log( $campaign->ID, $this->param( 'tu_em' ) );
|
|
|
|
/**
|
|
* Action filter - register an impression for a campaign
|
|
*
|
|
* @param WP_Post $campaign
|
|
*
|
|
* @since 0.1
|
|
*
|
|
*/
|
|
if ( ! tve_dash_is_crawler() && ( empty( $email_log ) || empty( $email_log['has_impression'] ) ) ) {
|
|
|
|
do_action( 'tve_ult_action_impression', $campaign );
|
|
|
|
if ( ! empty( $email_log ) ) {
|
|
$email_log['has_impression'] = 1;
|
|
tve_ult_save_email_log( $email_log );
|
|
}
|
|
}
|
|
/*
|
|
* expiration dates for cookies:
|
|
* - for evergreen campaigns: the number of days entered in the "Don't show this campaign until" field
|
|
* - for others: 1 year
|
|
* also modifies the global $_COOKIE variable - so that it's available later in the same request if required
|
|
*/
|
|
$expiry = tve_ult_current_time( 'timestamp' ) + YEAR_IN_SECONDS;
|
|
if ( $campaign->type === TVE_Ult_Const::CAMPAIGN_TYPE_EVERGREEN && ! empty( $campaign->settings ) && ! empty( $campaign->settings['end'] ) && is_numeric( $campaign->settings['end'] ) ) {
|
|
$cookie = $campaign->settings['end'] + $campaign->settings['duration'];
|
|
$expiry = tve_ult_current_time( 'timestamp' ) + $cookie * DAY_IN_SECONDS;
|
|
}
|
|
$now = tve_ult_current_time( 'Y-m-d H:i:s' );
|
|
setcookie( TVE_Ult_Const::COOKIE_IMPRESSION . $campaign->ID, $now, $expiry, '/' );
|
|
$_COOKIE[ TVE_Ult_Const::COOKIE_IMPRESSION . $campaign->ID ] = $now;
|
|
}
|
|
|
|
$this->campaign = $campaign;
|
|
/** @var TU_Schedule_Abstract $schedule */
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
$event = new TU_Event( $campaign );
|
|
$designs = $event->get_designs();
|
|
|
|
/**
|
|
* $html will containing a key-value pair for the designs
|
|
* design_id => html code
|
|
*/
|
|
$html = array();
|
|
$design_ids = [];
|
|
$display_positions = [];
|
|
|
|
foreach ( $designs as $design ) {
|
|
if ( ! $is_shortcode || ( $is_shortcode && $design['post_type'] === TVE_Ult_Const::DESIGN_TYPE_SHORTCODE ) ) {
|
|
tve_ult_enqueue_design_scripts( $design );
|
|
|
|
if ( $design['post_type'] === TVE_Ult_Const::DESIGN_TYPE_SHORTCODE ) {
|
|
|
|
/**
|
|
* The shortcode will contain design attribute id only for the main state
|
|
* but the TU_Event returns the exact state that need to be displayed
|
|
* so we need to display a state on main placeholder
|
|
*
|
|
* @see TU_Shortcode_Countdown->placeholder() and TU_Shortcodes how the placeholders are rendered
|
|
*/
|
|
$key = $design['post_type'] . '-';
|
|
$key .= $design['parent_id'] ? $design['parent_id'] : $design['id'];
|
|
} else {
|
|
$key = $design['post_type'];
|
|
}
|
|
|
|
$html[ $key ] = tve_ult_get_design_html( $design );
|
|
$display_positions[ $key ] = isset( $design['tcb_fields']['display_position'] ) ? $design['tcb_fields']['display_position'] : '';
|
|
|
|
$design_ids[] = $design[ TVE_Ult_Const::DESIGN_QUERY_KEY_NAME ];
|
|
}
|
|
}
|
|
if ( ! empty( $design_ids ) ) {
|
|
$end_date = $schedule->get_end_date();
|
|
$response = array(
|
|
'html' => $html,
|
|
'display_position' => $display_positions,
|
|
'designs' => $design_ids,
|
|
'resources' => isset( $GLOBALS['tve_ult_res'] ) ? $GLOBALS['tve_ult_res'] : array(),
|
|
'timer_components' => tve_ult_get_date_components( $end_date ),
|
|
);
|
|
/* for evergreen campaigns we need to also send the exact second at which the campaign started */
|
|
if ( $schedule instanceof TU_Schedule_Evergreen ) {
|
|
$response['timer_components']['sec'] = date( 's', strtotime( $end_date ) );
|
|
if ( $schedule->use_gmt() ) {
|
|
$response['timer_components']['timezone'] = tve_ult_get_timezone_format( tve_ult_gmt_offset_from_tzstring( $schedule->get()['gmt_offset'] ) );
|
|
}
|
|
}
|
|
} else {
|
|
$response = array();
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Check the wp_scripts() and returns the registered scripts based on $filter
|
|
*
|
|
* @param string $filter
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_outer_scripts( $filter ) {
|
|
$scripts = array();
|
|
|
|
$wp_scripts = wp_scripts();
|
|
|
|
foreach ( $wp_scripts->queue as $handle ) {
|
|
if ( ! isset( $wp_scripts->registered[ $handle ] ) || strpos( $handle, $filter ) === false ) {
|
|
continue;
|
|
}
|
|
|
|
$obj = $wp_scripts->registered[ $handle ];
|
|
|
|
if ( null === $obj->ver ) {
|
|
$ver = '';
|
|
} else {
|
|
$ver = $obj->ver ? $obj->ver : $wp_scripts->default_version;
|
|
}
|
|
|
|
if ( ! $obj->src ) {
|
|
continue;
|
|
}
|
|
|
|
$src = $obj->src;
|
|
|
|
if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $wp_scripts->content_url && 0 === strpos( $src, $wp_scripts->content_url ) ) ) {
|
|
$src = $wp_scripts->base_url . $src;
|
|
}
|
|
|
|
if ( ! empty( $ver ) ) {
|
|
$src = add_query_arg( 'ver', $ver, $src );
|
|
}
|
|
|
|
/** This filter is documented in wp-includes/class.wp-scripts.php */
|
|
$src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
|
|
|
|
if ( ! $src ) {
|
|
continue;
|
|
}
|
|
|
|
$scripts[ $handle ] = $src;
|
|
}
|
|
|
|
return $scripts;
|
|
}
|
|
|
|
/**
|
|
* Check the wp_styles() and returns the registered styles based on $filter
|
|
*
|
|
* @param string $filter
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_outer_css( $filter ) {
|
|
$css = array();
|
|
|
|
$wp_styles = wp_styles();
|
|
|
|
foreach ( $wp_styles->queue as $handle ) {
|
|
if ( ! isset( $wp_styles->registered[ $handle ] ) && strpos( $handle, $filter ) !== false ) {
|
|
continue;
|
|
}
|
|
|
|
$obj = $wp_styles->registered[ $handle ];
|
|
if ( null === $obj->ver ) {
|
|
$ver = '';
|
|
} else {
|
|
$ver = $obj->ver ? $obj->ver : $wp_styles->default_version;
|
|
}
|
|
|
|
$css[ $handle ] = $wp_styles->_css_href( $obj->src, $ver, $handle );
|
|
}
|
|
|
|
return $css;
|
|
}
|
|
|
|
/**
|
|
* check for a Conversion event that has the trigger set as visit to page
|
|
* it should loop the $_COOKIE variable and for each campaign that's registered in the cookie,
|
|
*
|
|
* Also, check for any evergreen campaigns that should be started during this request (e.g. first page visit, visit to a specific page)
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function ajax_conversion_event_check() {
|
|
$post_id = $this->param( 'post_id' );
|
|
|
|
$this->check_evergreen_triggers();
|
|
|
|
foreach ( $_COOKIE as $key => $value ) {
|
|
/**
|
|
* we might have evergreen|other campaign started which are not visible on this request
|
|
* evergreen campaign has COOKIE_NAME and the others have COOKIE_IMPRESSION
|
|
*/
|
|
$cookie_impression = strpos( $key, TVE_Ult_Const::COOKIE_IMPRESSION ) !== false;
|
|
$cookie_evergreen = strpos( $key, TVE_Ult_Const::COOKIE_NAME ) !== false;
|
|
|
|
if ( ! $cookie_impression && ! $cookie_evergreen ) {
|
|
continue;
|
|
}
|
|
|
|
/**
|
|
* find on which cookie determines the campaign id
|
|
*/
|
|
$cookie_name = $cookie_impression ? TVE_Ult_Const::COOKIE_IMPRESSION : TVE_Ult_Const::COOKIE_NAME;
|
|
|
|
$campaign_id = (int) str_replace( $cookie_name, '', $key );
|
|
$campaign = tve_ult_get_campaign( $campaign_id, array(
|
|
'get_settings' => true,
|
|
'get_events' => true,
|
|
) );
|
|
if ( empty( $campaign ) ) {
|
|
continue;
|
|
}
|
|
|
|
/** do the conversion if the campaign conversion event match the post_id */
|
|
$campaign->tu_schedule_instance->check_specific_events( $campaign, $post_id );
|
|
}
|
|
|
|
return 'conversion checked';
|
|
}
|
|
|
|
/**
|
|
* @param array $campaign_ids usually displayable campaigns
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_applicable_campaigns( $campaign_ids ) {
|
|
|
|
/**
|
|
* campaigns will come by default ordered, we can take the first one for which the schedule applies
|
|
*/
|
|
$campaign_ids = array_map( 'intval', $campaign_ids );
|
|
$post_id = $this->param( 'post_id' );
|
|
$applicable_campaigns = array();
|
|
|
|
$campaigns = tve_ult_get_campaigns( array(
|
|
'get_designs' => true,
|
|
'get_events' => true,
|
|
'get_settings' => true,
|
|
'get_logs' => false,
|
|
'lockdown' => true,
|
|
'only_running' => true,
|
|
) );
|
|
|
|
$campaigns_by_id = array_combine( array_map( 'tve_ult_campaign_id', $campaigns ), $campaigns );
|
|
|
|
$singular = $this->param( 'is_singular' );
|
|
$is_singular = ! empty( $singular );
|
|
|
|
/**
|
|
* first loop - check for any possible conversion events and end any campaigns that have had a conversion
|
|
*/
|
|
$campaign_conversions = array();
|
|
foreach ( $campaigns as $campaign ) {
|
|
/** @var TU_Schedule_Abstract $schedule */
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
/** check if a non displayable campaign has a conversion event with specific trigger that needs to do_conversion() */
|
|
|
|
if ( $is_singular ) {
|
|
/** the real post_id is received only in singular requests */
|
|
$campaign_conversions[ $campaign->ID ] = $schedule->check_specific_events( $campaign, $post_id );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* second loop: check if we need to display a specific campaign, as a result of a conversion event
|
|
* $campaign_ids are sorted in the order of priority, so it's ok to take on the one with the highest priority
|
|
*/
|
|
foreach ( $campaign_ids as $campaign_id ) {
|
|
|
|
if ( ! isset( $campaigns_by_id[ $campaign_id ] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$campaign = $campaigns_by_id[ $campaign_id ];
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
if ( isset( $_COOKIE[ $schedule->cookie_force_display() ] ) && ! isset( $_COOKIE[ $schedule->cookie_end_name() ] ) ) {
|
|
$applicable_campaigns[] = $campaign;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* lastly, check for "regular" campaign triggers - intervals, first visits to site etc
|
|
*/
|
|
foreach ( $campaign_ids as $campaign_id ) {
|
|
|
|
if ( ! isset( $campaigns_by_id[ $campaign_id ] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$campaign = $campaigns_by_id[ $campaign_id ];
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
/** if the campaign has a conversion event then it cannot be applied */
|
|
if ( empty( $campaign_conversions[ $campaign_id ] ) && $schedule->applies() ) {
|
|
$applicable_campaigns[] = $campaign;
|
|
}
|
|
}
|
|
|
|
return $applicable_campaigns;
|
|
}
|
|
|
|
/**
|
|
* get the first campaign which has a schedule that matches
|
|
*
|
|
* @param array $campaign_ids usually displayable campaigns
|
|
*
|
|
* @return bool|WP_Post
|
|
*/
|
|
public function get_applicable_campaign( $campaign_ids ) {
|
|
/**
|
|
* campaigns will come by default ordered, we can take the first one for which the schedule applies
|
|
*/
|
|
$campaign_ids = array_map( 'intval', $campaign_ids );
|
|
$post_id = $this->param( 'post_id' );
|
|
|
|
$campaigns = tve_ult_get_campaigns( array(
|
|
'get_designs' => false,
|
|
'get_events' => true,
|
|
'get_settings' => true,
|
|
'get_logs' => false,
|
|
'lockdown' => true,
|
|
'only_running' => true,
|
|
) );
|
|
|
|
$campaigns_by_id = array_combine( array_map( 'tve_ult_campaign_id', $campaigns ), $campaigns );
|
|
|
|
$singular = $this->param( 'is_singular' );
|
|
$is_singular = ! empty( $singular );
|
|
|
|
/**
|
|
* first loop - check for any possible conversion events and end any campaigns that have had a conversion
|
|
*/
|
|
$campaign_conversions = array();
|
|
foreach ( $campaigns as $campaign ) {
|
|
/** @var TU_Schedule_Abstract $schedule */
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
/** check if a non displayable campaign has a conversion event with specific trigger that needs to do_conversion() */
|
|
|
|
if ( $is_singular ) {
|
|
/** the real post_id is received only in singular requests */
|
|
$campaign_conversions[ $campaign->ID ] = $schedule->check_specific_events( $campaign, $post_id );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* second loop: check if we need to display a specific campaign, as a result of a conversion event
|
|
* $campaign_ids are sorted in the order of priority, so it's ok to take on the one with the highest priority
|
|
*/
|
|
foreach ( $campaign_ids as $campaign_id ) {
|
|
$campaign = $campaigns_by_id[ $campaign_id ];
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
if ( isset( $_COOKIE[ $schedule->cookie_force_display() ] ) && ! isset( $_COOKIE[ $schedule->cookie_end_name() ] ) ) {
|
|
return $campaign;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* lastly, check for "regular" campaign triggers - intervals, first visits to site etc
|
|
*/
|
|
foreach ( $campaign_ids as $campaign_id ) {
|
|
$campaign = $campaigns_by_id[ $campaign_id ];
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
/** if the campaign has a conversion event then it cannot be applied */
|
|
if ( empty( $campaign_conversions[ $campaign_id ] ) && $schedule->applies() ) {
|
|
return $campaign;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* helper function
|
|
*
|
|
* @return string admin-ajax action user for ajax-loading campaign designs on frontend
|
|
*/
|
|
public function ajax_load_action() {
|
|
return 'tve_ult_ajax_load';
|
|
}
|
|
|
|
/**
|
|
* helper function
|
|
*
|
|
* @return string admin-ajax action user for checking if any conversion event applies to the current page
|
|
*/
|
|
public function conversion_events_action() {
|
|
return 'tve_ult_conversion_event';
|
|
}
|
|
|
|
/**
|
|
* prepares the localization of frontend javascript
|
|
*
|
|
* @param array $campaigns a list of campaigns that matches the display settings for the current request
|
|
* @param array $matched_display_settings_ids campaigns campaigns that have matched the display settings for the current page
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_localization( $campaigns, $matched_display_settings_ids ) {
|
|
|
|
$post_id = null;
|
|
|
|
if ( function_exists( 'is_shop' ) && is_shop() ) {
|
|
$post_id = get_option( 'woocommerce_shop_page_id' );
|
|
} else {
|
|
$post_id = get_the_ID();
|
|
}
|
|
|
|
$campaign_ids = array();
|
|
|
|
/**
|
|
* we need to localize emails from cookies so that we know if there are logs in db to register impression or not
|
|
* Flow:
|
|
* 1. localize emails
|
|
* 2. do tu request for designs with localized email
|
|
* 3. check for emails based on localized email
|
|
* 4. update log
|
|
*
|
|
* @see ajax_load
|
|
* @see prepare_campaign_response
|
|
*/
|
|
$cookie_email = '';
|
|
|
|
$redirects = array();
|
|
foreach ( $campaigns as $campaign ) {
|
|
$campaign_id = $campaign instanceof WP_Post ? $campaign->ID : $campaign;
|
|
$campaign_ids [] = $campaign_id;
|
|
|
|
$campaign_cookie_name = TVE_Ult_Const::COOKIE_NAME . $campaign_id;
|
|
|
|
if ( empty( $cookie_email ) && isset( $_COOKIE[ $campaign_cookie_name ] ) ) {
|
|
$cookie_value = thrive_safe_unserialize( stripcslashes( $_COOKIE[ $campaign_cookie_name ] ) );
|
|
$cookie_email = ! empty( $cookie_value['lockdown'] ) ?
|
|
! empty( $cookie_value['lockdown']['email'] ) ? $cookie_value['lockdown']['email'] : ''
|
|
: '';
|
|
}
|
|
|
|
$campaign_data = $campaign instanceof WP_Post ? $campaign : tve_ult_get_campaign( $campaign );
|
|
|
|
/**
|
|
* Get evergreen redirects
|
|
*/
|
|
if ( $campaign_data->type === 'evergreen'
|
|
&& ! empty( $campaign_data->lockdown_settings )
|
|
&& ! empty( $campaign_data->lockdown_settings['expired'] )
|
|
&& isset( $campaign_data->lockdown_settings['expired']['id'] )
|
|
) {
|
|
$redirects[ $campaign_id ] = [
|
|
'redirect_url' => get_permalink( $campaign_data->lockdown_settings['expired']['id'] ),
|
|
'promotion_page' => array_column($campaign_data->lockdown_settings['promotion'], 'id'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get evergreen redirects
|
|
*/
|
|
if ( $campaign_data->type === 'evergreen'
|
|
&& ! empty( $campaign_data->settings )
|
|
&& ! empty( $campaign_data->settings['redirect'] )
|
|
&& isset( $campaign_data->settings['redirect_url'] )
|
|
) {
|
|
$redirects[ $campaign_id ] = [
|
|
'redirect_url' => get_permalink( $campaign_data->settings['redirect_url'] ),
|
|
'promotion_page' => [ $campaign_data->settings['trigger']['ids'] ],
|
|
];
|
|
}
|
|
}
|
|
|
|
$frontend_data = array(
|
|
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
|
'ajax_load_action' => $this->ajax_load_action(),
|
|
'conversion_events_action' => $this->conversion_events_action(),
|
|
// at this point, campaign_ids should be ordered. In the ajax call, it's sufficient to just display the first one that matches
|
|
'shortcode_campaign_ids' => TU_Shortcodes::get_campaigns(),
|
|
'matched_display_settings' => $matched_display_settings_ids,
|
|
'campaign_ids' => $campaign_ids,
|
|
'post_id' => $post_id,
|
|
'is_singular' => is_singular(),
|
|
'tu_em' => $this->param( 'tu_em', $cookie_email ),
|
|
'evergreen_redirects' => $redirects,
|
|
);
|
|
|
|
/**
|
|
* Allows inserting custom data into the frontend javascript localization object
|
|
*
|
|
* @param array $frontend_data
|
|
*
|
|
* @since 0.0.1
|
|
*
|
|
*/
|
|
return apply_filters( 'thrive_ult_js_localize', $frontend_data );
|
|
}
|
|
|
|
/**
|
|
* getter. Returns the list of available campaigns
|
|
*
|
|
* @return WP_Post[]
|
|
*/
|
|
public function get_campaigns() {
|
|
return $this->campaigns;
|
|
}
|
|
|
|
protected function param( $key, $default = null ) {
|
|
return isset( $_POST[ $key ] ) ? $_POST[ $key ] : ( isset( $_REQUEST[ $key ] ) ? $_REQUEST[ $key ] : $default );
|
|
}
|
|
|
|
/**
|
|
* Check for any campaigns that might have the current request as a trigger ( applies to evergreen campaigns ) and set the start cookie.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function check_evergreen_triggers() {
|
|
/**
|
|
* This only applies to evergreen campaigns - only fetch evergreen campaigns
|
|
*/
|
|
$evergreen_campaigns = tve_ult_get_campaigns( array(
|
|
'only_running' => true,
|
|
'get_designs' => false,
|
|
'get_events' => false,
|
|
'campaign_type' => TVE_Ult_Const::CAMPAIGN_TYPE_EVERGREEN,
|
|
'get_settings' => true,
|
|
) );
|
|
foreach ( $evergreen_campaigns as $campaign ) {
|
|
//this will trigger any campaigns for which the current request acts as a trigger
|
|
/** @var TU_Schedule_Evergreen $schedule */
|
|
$schedule = $campaign->tu_schedule_instance;
|
|
|
|
if ( isset( $_COOKIE[ $schedule->cookie_name() ] ) && $has_email = $schedule->verify_cookie() ) {
|
|
$cookie = $schedule->get_cookie_data();
|
|
$cookie = $cookie['cookie'];
|
|
$email = $cookie['lockdown']['email'];
|
|
if ( is_email( $email ) ) {
|
|
$data = $schedule->set_cookie_data( $cookie );
|
|
unset( $_COOKIE[ $schedule->cookie_name( $campaign->ID ) ] );
|
|
$schedule->setCookie( $data['value'], $data['expire'] );
|
|
}
|
|
}
|
|
|
|
$schedule->applies();
|
|
}
|
|
}
|
|
}
|