*/ class Pro_Upgrade { use Date; public $slug; protected $data = array(); /** * Construct method */ const SYNC_HOOK = 'pxlbsadminify_sheet_promo_data_remote_sync'; const DATA_OPTION = 'pxlbsadminify_sheet_promo_data'; public function __construct() { $this->slug = Helper::slug_cleanup(); add_action( self::SYNC_HOOK, array($this, 'sync_remote_data') ); $this->maybe_schedule_sync(); $this->set_data(); add_action( 'admin_footer', array($this, 'display_popup') ); add_action( 'wp_dashboard_setup', array($this, 'dashboard_widget') ); add_action( 'wp_network_dashboard_setup', array($this, 'dashboard_widget') ); } /** * Fetch campaigns only when the admin allowed Freemius opt-in on activation. * Required by WordPress.org guideline 7: no external calls without consent. */ public static function is_opted_in() { $fs = jltwp_adminify(); return $fs->is_registered() && $fs->is_tracking_allowed(); } /** * Schedule the daily sync when opted in, tear it down (and drop stored data) otherwise. */ public function maybe_schedule_sync() { $scheduled = wp_next_scheduled( self::SYNC_HOOK ); if ( self::is_opted_in() ) { if ( !$scheduled ) { // First fetch now (once, right after opt-in); cron handles the daily refresh. wp_schedule_event( time() + DAY_IN_SECONDS, 'daily', self::SYNC_HOOK ); $this->sync_remote_data(); } } elseif ( $scheduled ) { wp_clear_scheduled_hook( self::SYNC_HOOK ); delete_option( self::DATA_OPTION ); } } /** * Fetch campaign from pixarlabs.com/api/plugin/update/{slug} and store it. */ public function sync_remote_data() { if ( !self::is_opted_in() ) { return; } $response = wp_safe_remote_get( Helper::api_endpoint() . 'api/plugin/update/' . rawurlencode( $this->slug ), array( 'timeout' => 10, 'headers' => array( 'Accept' => 'application/json', ), ) ); // Network/server failure: keep the last known campaign. if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) { return; } $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( !is_array( $data ) ) { return; } // API answers {success:false} when no campaign exists for this slug. if ( empty( $data['product_slug'] ) || $this->slug !== $data['product_slug'] ) { delete_option( self::DATA_OPTION ); return; } update_option( self::DATA_OPTION, self::sanitize_remote_data( $data ), false ); } /** * Whitelist + sanitize remote fields (trust boundary). * * @param array $data Raw API response. */ public static function sanitize_remote_data( $data ) { $data = wp_parse_args( $data, array_fill_keys( array( 'image_url', 'start_date', 'end_date', 'button_text', 'button_url', 'btn_color', 'notice', 'show_for_premium', 'is_live' ), '' ) ); $clean = array( 'product_slug' => sanitize_key( $data['product_slug'] ), 'image_url' => esc_url_raw( $data['image_url'] ), 'start_date' => self::normalize_date( $data['start_date'] ), 'end_date' => self::normalize_date( $data['end_date'] ), 'button_text' => sanitize_text_field( $data['button_text'] ), 'button_url' => esc_url_raw( $data['button_url'] ), 'btn_color' => self::sanitize_color( $data['btn_color'] ), 'notice' => wp_kses_post( $data['notice'] ), 'show_for_premium' => wp_validate_boolean( $data['show_for_premium'] ), 'is_live' => wp_validate_boolean( $data['is_live'] ), ); // Drop empty values so Helper::get_merged_data() defaults (color, button text/url) apply. return array_filter( $clean, static function ( $value ) { return '' !== $value; } ); } /** * Backend color picker sends hex or rgb()/rgba(). * * @param string $color . */ public static function sanitize_color( $color ) { $color = trim( (string) $color ); if ( sanitize_hex_color( $color ) ) { return $color; } return ( preg_match( '/^rgba?\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*(,\\s*(0|1|0?\\.\\d+)\\s*)?\\)$/', $color ) ? $color : '' ); } /** * API sends "d/m/Y h:i a"; convert to 'Y-m-d H:i:s' so PHP/JS parsers agree. * * @param string $value . */ public static function normalize_date( $value ) { $value = trim( (string) $value ); foreach ( array('d/m/Y h:i a', 'd/m/Y H:i', 'd/m/Y') as $format ) { $dt = \DateTime::createFromFormat( $format, $value ); if ( $dt instanceof \DateTime ) { return $dt->format( 'Y-m-d H:i:s' ); } } return ''; } /** * Set merged data * * @return void * @author Jewel Theme */ public function set_data() { $this->data = Helper::get_merged_data( self::get_data() ); } /** * Get stored campaign data; is_live is forced off outside start/end window. * * @author Jewel Theme */ public static function get_data() { $data = get_option( self::DATA_OPTION ); if ( !is_array( $data ) || empty( $data ) ) { return array(); } $now = current_time( 'mysql' ); if ( !empty( $data['start_date'] ) && $now < $data['start_date'] || !empty( $data['end_date'] ) && $now > $data['end_date'] ) { $data['is_live'] = false; } return $data; } /** * Premium users only see a campaign flagged "Show For Premium" in the backend. */ public function is_hidden_for_user() { return jltwp_adminify()->can_use_premium_code() && !wp_validate_boolean( $this->get_content( 'show_for_premium' ) ); } /** * Register promo dashboard widget while a campaign is live (hideable via Screen Options). */ public function dashboard_widget() { if ( !current_user_can( 'manage_options' ) || !wp_validate_boolean( $this->get_content( 'is_live' ) ) || $this->is_hidden_for_user() ) { return; } wp_add_dashboard_widget( 'pxlbsadminify_dashboard_widget', esc_html__( 'Adminify Deals', 'adminify' ), array($this, 'dashboard_widget_render') ); } /** * Render promo dashboard widget. */ public function dashboard_widget_render() { ?>
<?php 
        esc_attr_e( 'Adminify promotion', 'adminify' );
        ?> get_content( 'end_date' ) ? strtotime( $this->get_content( 'end_date' ) ) - current_time( 'timestamp' ) : 0 ); if ( $seconds_left > 0 ) { // Reuses the upgrade popup countdown styles (dev/scss/common/_popup.scss), overlaid on the banner bottom. ?>
00
:
00
:
00
:
00
get_content( 'notice' ) ) { ?>

get_content( 'notice' ) ); ?>

get_content( 'button_text' ) ); ?>
*/ public function get_content( $key ) { if ( empty( $this->data ) ) { return; } return $this->data[$key]; } /** * Display popup contents * * @author Jewel Theme */ public function display_popup() { if ( $this->is_hidden_for_user() ) { return ''; } if ( empty( $this->get_content( 'is_live' ) ) ) { $image_url = PXLBSADMINIFY_ASSETS_IMAGE . 'promo-image.png'; $notice = 'Use "SPECIAL40" to Get Flat 40% OFF'; $btn_url = 'https://wpadminify.com/pricing'; $btn_text = 'GET THE DEAL'; } else { $image_url = $this->get_content( 'image_url' ); $notice = $this->get_content( 'notice' ); $btn_url = $this->get_content( 'button_url' ); $btn_text = $this->get_content( 'button_text' ); } ?> */ public function counter_date() { $endDate = $this->get_content( 'end_date' ); $is_active = $this->date_is_current_or_next( $endDate ); if ( $is_active ) { return $endDate; } return $this->date_increment( $this->current_time(), 3 ); } }