oont-contents/plugins/webappick-product-feed-for-woocommerce/libs/WebAppick/AppServices/Promotions.php
2025-03-31 21:42:48 +02:00

387 lines
No EOL
13 KiB
PHP

<?php
/**
* Webappick Promotion handler
* @version 1.0.0
* @package CTXFeed
* @subpackage AppServices
*/
namespace CTXFeed\AppServices;
if ( ! defined( 'ABSPATH' ) ) {
die();
}
/**
* Class Promotions
* Source Format
*
$promos = [
(object) [
// required; offer start
'start' => '2019-11-20 00:00:01',
// required; offer end
'end' => '2019-12-04 23:59:00',
// required; some unique hash for offer, use for hiding the offer when user click to close.
'hash' => '9df37798-bd35-421b-b6f2-fbc095686efc',
// Optional; Allow closing default is 0, set to 1 to allow user hide it
'dismissible' => 1, // 0
// required; main content required, will be filtered with wp_kses_post()
'content' => '<p>Biggest Sale of the year on this</p><h3>Black Friday & Cyber Monday</h3><p>Claim your discount on till 4th December</p>',
// optional; wrapper padding
wrapperPadding => ''
// optional; image source url or data url
'backgroundImage' => '',
// optional;
'backgroundRepeat' => '',
// optional;
'backgroundSize' => '',
// optional; background color to apply with the background image
'backgroundColor' => '#000',
// optional; text color will be inherited by the content
'color' => '#fff',
// optional; can be empty
'logo' => [
// required; image source url or data url
'src' => '',
// required;
'alt' => 'Woo Feed Pro',
],
// optional; can be empty
'button' => [
// required
'label' => 'Save 30%',
// required
'url' => '#?utm_campaign=black_friday_&_cyber_monday&utm_medium=banner&utm_source=wp_dashboard',
// optional;
'backgroundColor' => '#F71560',
// optional;
'color' => '#FFF',
// optional;
'after' => '<span style="font-size: 12px; font-weight: 700; margin-top: 12px; display: block;">Coupon: BFCM2019</span>', // html content filtered with wp_kses_post()
],
],
];
*
*/
class Promotions {
/**
* CTXFeed\AppServices\Client
*
* @var Client
*/
protected $client;
/**
* URL for Promotions source json file
* @var string
*/
private $promotionSrc;
/**
* Promotions
* @var bool|object[]
*/
private $promotions = false;
/**
* List of hidden promotions for current user
* @var array
*/
private $hiddenPromotions;
/**
* Current User Id
* @var int
*/
private $currentUser = 0;
/**
* Promotions constructor.
* @param Client $client The Client.
* @param string $data_source Data Source URL
* @return void
*/
public function __construct( Client $client, $data_source = null ) {
$this->client = $client;
if ( ! is_null( $data_source ) ) $this->promotionSrc = esc_url( $data_source );
}
/**
* Set JSON Source File URL For getting promotion data
* @param string $URL Set Data Source URL.
*
* @return Promotions
*/
public function set_source( $URL ) {
$this->promotionSrc = esc_url( $URL );
return $this;
}
/**
* Init Promotions
* @return void
*/
public function init() {
if ( is_null( $this->promotionSrc ) ) {
_doing_it_wrong( __METHOD__, esc_html__( 'Promotion Source URL Not Set. see Promotions::set_source( $URL )', 'woo-feed' ), '1.0.0' );
}
add_action( 'admin_init', [ $this, '__init_internal' ], 10 );
}
/**
* Set environment variables and init internal hooks
* @return void
*/
public function __init_internal() {
$this->currentUser = get_current_user_id();
$this->hiddenPromotions = (array) get_user_option( $this->client->getSlug() . '_hidden_promos', $this->currentUser );
$this->promotions = $this->__get_promos();
// only run if there is active promotions.
if ( count( $this->promotions ) ) {
add_action( 'admin_notices', [ $this, '__show_promos' ], 10 );
add_action( 'wp_ajax_webappick_dismiss_promo', [ $this, '__webappick_dismiss_promo' ], 10 );
add_action( 'admin_print_styles', [ $this, '__get_promo_styles' ], 99 );
add_action( 'admin_enqueue_scripts', [ $this, '__enqueue_deps' ], 10 );
add_action( 'admin_print_footer_scripts', [ $this, '__get_promo_scripts' ], 10 );
}
}
/**
* Render Promotions
* @return void
*/
public function __show_promos() {
foreach ( $this->promotions as $promotion ) {
$wrapperStyles = '';
$buttonStyles = '';
$is_dismissible = ! isset( $promotion->dismissible ) || isset( $promotion->dismissible ) && 0 == $promotion->dismissible ? false : true;
$has_columns = isset( $promotion->button, $promotion->logo );
if ( isset( $promotion->color ) ) {
$wrapperStyles .= 'color: ' . $promotion->color . ';';
}
if ( isset( $promotion->wrapperPadding ) ) {
$wrapperStyles .= 'padding: ' . $promotion->wrapperPadding . ';';
}
if ( isset( $promotion->backgroundColor ) ) {
$wrapperStyles .= 'background-color: ' . $promotion->backgroundColor . ';';
}
if ( isset( $promotion->backgroundImage ) ) {
$wrapperStyles .= 'background-image: url("' . esc_url( $promotion->backgroundImage ) . '");';
}
if ( isset( $promotion->backgroundRepeat ) ) {
$wrapperStyles .= 'background-repeat: ' . $promotion->backgroundRepeat . ';';
}
if ( isset( $promotion->backgroundSize ) ) {
$wrapperStyles .= 'background-size: ' . $promotion->backgroundSize . ';';
}
if ( property_exists( $promotion, 'button' ) ) {
if ( isset( $promotion->button->backgroundColor ) ) {
$buttonStyles .= 'background-color: ' . $promotion->button->backgroundColor . ';border-color: ' . $promotion->button->backgroundColor . ';';
}
if ( isset( $promotion->button->color ) ) {
$buttonStyles .= 'color: ' . $promotion->button->color . ';';
}
}
$noticeClasses = 'notice notice-success wapk-promo';
if ( $is_dismissible ) {
$noticeClasses .= ' is-dismissible';
}
?>
<div class="<?php echo esc_attr( $noticeClasses ); ?> " id="<?php echo esc_attr( $promotion->hash ); ?>" data-nonce="<?php echo esc_attr( wp_create_nonce( 'wapk-dismiss-promo' ) ); ?>" style="<?php echo esc_attr( $wrapperStyles ); ?>">
<div class="wapk-promo-wrap<?php if ( ! $has_columns ) echo ' no-column'; ?>">
<?php if ( isset( $promotion->logo ) && ! empty( $promotion->logo ) ) { ?>
<div class="wapk-logo wapk-column">
<img src="<?php echo esc_url( $promotion->logo->src ); ?>" alt="<?php echo esc_attr( $promotion->logo->alt ); ?>">
</div>
<?php } ?>
<div class="wapk-details<?php if ( $has_columns ) echo ' wapk-column'; ?>">
<?php echo wp_kses_post( $promotion->content ); ?>
</div>
<?php if ( isset( $promotion->button ) && ! empty( $promotion->button ) ) { ?>
<div class="wapk-btn-container wapk-column">
<a href="<?php echo esc_url( $promotion->button->url ); ?>" class="button wapk-promo-btn" style="<?php echo esc_attr( $buttonStyles ); ?>" target="_blank"><?php echo wp_kses_post( $promotion->button->label ); ?></a>
<?php
if ( isset( $promotion->button->after ) && ! empty( $promotion->button->after ) ) {
echo wp_kses_post( $promotion->button->after );
}
?>
</div>
<?php } ?>
<?php if ( isset( $promotion->button ) && ! empty( $promotion->button ) ) { ?>
<?php } ?>
</div>
</div>
<?php
}
}
/**
* Get Promotion Data
* Cache First then fetch source url for json data.
* @return array
*/
private function __get_promos() {
$promos = get_transient( $this->client->getSlug() . '_cached_promos' );
if ( empty( $promos ) ) {
// get promotions data from json source.
$response = wp_safe_remote_get( $this->promotionSrc, array( 'timeout' => 15 ) ); // phpcs:ignore
$promos = wp_remote_retrieve_body( $response );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
$promos = '[]';
}
// cache data.
set_transient( $this->client->getSlug() . '_cached_promos', $promos, 12 * HOUR_IN_SECONDS );
}
// decode to array.
$promos = json_decode( $promos );
// filter promotions by date.
$promos = array_filter( $promos, [ $this, '__is_promo_active' ] );
if ( ! empty( $promos ) ) {
// filter promotions by list of hidden promotions by the user.
$promos = array_filter( $promos, [ $this, '__is_promo_hidden' ] );
}
return $promos;
}
/**
* Check if promotion is active by date.
* must have start and end property
* @param object $promo { the promo object.
* Single Promo Object
* @type string $content string. required
* @type string $start valid timestamp. required
* @type string $end valid timestamp. required
* }
*
* @return bool
*/
public function __is_promo_active( $promo ) {
$ct = current_time( 'timestamp' ); // phpcs:ignore
return ( ! empty( $promo->content ) && strtotime( $promo->start ) < $ct && $ct < strtotime( $promo->end ) );
}
/**
* Check if promo is hidden by current user
* @param object $promo { the promo object.
* Single Promo Object
* @type string $hash valid unique hash for a promo
* }
*
* @return bool true if promo is hidden by user
*/
public function __is_promo_hidden( $promo ) {
return ! in_array( $promo->hash, $this->hiddenPromotions );
}
/**
* Js Dependencies
* @return void
*/
public function __enqueue_deps(){
wp_enqueue_script( 'wp-util' );
wp_enqueue_script( 'jquery' );
}
/**
* Script for hiding promo on user click
* @return void
*/
public function __get_promo_scripts() {
?>
<!--suppress ES6ConvertVarToLetConst -->
<script>
(function($){
$('body').on('click', '.wapk-promo .notice-dismiss', function (e) {
e.preventDefault();
var $parent = $(this).closest( '.wapk-promo' );
wp.ajax.post('webappick_dismiss_promo', {
dismissed: true,
hash: $parent.attr( 'id' ),
_wpnonce: $parent.data( 'nonce' ),
});
});
})(jQuery);
</script>
<?php
}
/**
* Global Promo Styles
* @return void
*/
public function __get_promo_styles() {
?>
<!--suppress CssUnusedSymbol -->
<style>
.wapk-promo { border: none; padding: 15px 0; }
.wapk-promo-wrap { display: flex; justify-content: center; align-items: center; text-align: center; color: inherit; max-width: 1820px; margin: 0 auto; }
.wapk-promo-wrap.no-column{ display: block; }
.wapk-column.wapk-logo { flex: 0 0 25%; }
.wapk-column.wapk-logo img { height: 48px; width: auto; }
.wapk-details {display: block;}
.wapk-details h3 { color: inherit; font-size: 30px; margin: 12px 0; }
.wapk-details p { color: inherit; font-size: 15px; }
.wapk-column.wapk-details { flex: 0 0 50%; }
.wapk-column.wapk-btn-container { flex: 0 0 25%; }
.wapk-promo-wrap .wapk-promo-btn { position: relative; padding: 15px; border-radius: 30px; font-size: 15px; font-weight: 700; display: block; color: inherit; text-decoration: none; max-width: 200px; margin: 0 auto; line-height: normal; height: auto; box-shadow: 1px 2px 0 rgba(0, 0, 0, 0.1); }
.wapk-promo-wrap .wapk-promo-btn:focus,
.wapk-promo-wrap .wapk-promo-btn:hover,
.wapk-promo-wrap .wapk-promo-btn:active { box-shadow: inset 3px 4px 6px 0 rgba(1, 9, 12, 0.25); }
.wapk-promo-wrap .wapk-promo-btn:active { top: 1px; }
@media screen and (max-width: 1200px) {
.wapk-promo-wrap { display: block; overflow: hidden; }
.wapk-column .wapk-logo { width: 100%; margin: 0 auto; }
.wapk-column .wapk-details { width: 68%; float: left; margin-right: 4%; margin-top: 32px; }
.wapk-column.wapk-btn-container { width: 28%; float: right; margin-top: 42px; }
}
@media screen and (max-width: 782px) {
.wapk-promo-wrap .wapk-details { float: none; width: 100%; }
.wapk-btn-container { float: none; width: 100%; margin-top: 32px; }
.wapk-column.wapk-btn-container { width: 100%; float: right; margin-top: 42px; }
}
</style>
<?php
}
/**
* Ajax Callback handler for hiding promo
* @return void
*/
public function __webappick_dismiss_promo() {
if (
isset( $_REQUEST['dismissed'], $_REQUEST['hash'], $_REQUEST['_wpnonce'] ) &&
'true' == $_REQUEST['dismissed'] && ! empty( $_REQUEST['hash'] ) &&
wp_verify_nonce( sanitize_text_field( $_REQUEST['_wpnonce'] ), 'wapk-dismiss-promo' )
) {
$this->hiddenPromotions = array_merge( $this->hiddenPromotions, [ sanitize_text_field( $_REQUEST['hash'] ) ] );
update_user_option( $this->currentUser, $this->client->getSlug() . '_hidden_promos', $this->hiddenPromotions );
wp_send_json_success( esc_html__( 'Promo hidden', 'woo-feed' ) );
}
wp_send_json_error( esc_html__( 'Invalid Request', 'woo-feed' ) );
die();
}
/**
* @noinspection PhpUnused
* Clear Hidden Promotion preference for User
* @return bool
*/
public function clear_hidden_promos() {
if ( ! did_action( 'admin_init' ) ) {
_doing_it_wrong( __METHOD__, esc_html__( 'Method must be invoked inside admin_init action', 'woo-feed' ), '1.0.0' );
}
$this->currentUser = get_current_user_id();
return delete_user_option( $this->currentUser, $this->client->getSlug() . '_hidden_promos' );
}
/**
* Clear Cached Promotion data
* @return bool
*/
public function clear_cache() {
return delete_transient( $this->client->getSlug() . '_cached_promos' );
}
}
// End of file Promotions.php.