PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 2.7.0
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v2.7.0
2.7.0 2.6.0 trunk 1.1.0 1.1.4 1.2.1 1.2.2 1.2.3 1.2.5 1.2.9 1.3.1 1.3.2 1.5.0 1.5.1 1.5.4 1.5.7 1.5.8 1.5.9 1.6.2 1.6.5 1.6.8 1.7.2 1.7.4 1.7.5 1.7.9 All 43 releases
sellkit / includes / admin / class-promotion-banner.php

class-promotion-banner.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 2.7.0, at includes/admin/class-promotion-banner.php

368 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles global admin promotion banner.
4 *
5 * @package Sellkit\Admin\Promotion_Banner
6 *
7 * @since 2.4.0
8 */
9
10 defined( 'ABSPATH' ) || die();
11
12 /**
13 * Global admin promotion banner.
14 *
15 * @since 2.4.0
16 *
17 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
18 */
19 class Sellkit_Admin_Promotion_Banner {
20
21 /**
22 * Cache of active banners for current request.
23 *
24 * @since 2.4.0
25 *
26 * @var array|null
27 */
28 private $active_banners = null;
29
30 /**
31 * Constructor.
32 *
33 * @since 2.4.0
34 */
35 public function __construct() {
36 add_action( 'all_admin_notices', [ $this, 'render' ] );
37 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
38 add_action( 'wp_ajax_sellkit_dismiss_admin_promotion', [ $this, 'ajax_dismiss' ] );
39 }
40
41 /**
42 * Get promotion banners config.
43 *
44 * Each banner item is an associative array with the following keys:
45 * - id (string) Unique identifier for the banner. Required.
46 * - heading (string) Main heading text.
47 * - description (string) Secondary description text.
48 * - mainImageURL (string) Absolute URL to the main image shown on the left.
49 * - backgroundImage (string) Optional absolute URL used as background for the banner container.
50 * - couponCode (string) Coupon code text.
51 * - ctaText (string) Call-to-action button label.
52 * - ctaUrl (string) Call-to-action button URL.
53 * - ctaSubText (string) Small meta text shown under the main copy (e.g. expiry info).
54 * - isDismissible (bool) Whether the banner can be dismissed. Defaults to true.
55 * - startsAt (string) Empty string or ISO-8601 datetime string (UTC) when the banner becomes visible.
56 * - expiresAt (string) Empty string or ISO-8601 datetime string (UTC) when the banner expires.
57 * - sellkitAdminOnly (bool) Whether to show the banner only on SellKit admin pages. Defaults to false.
58 *
59 * @since 2.4.0
60 *
61 * @return array
62 */
63 private function get_banners() {
64 return [
65 [
66 'id' => 'sellkit-bf2025-promotion',
67 'heading' => '50% OFF Lifetime Plan',
68 'description' => 'UNLIMITED WEBSITES',
69 'mainImageURL' => sellkit()->plugin_url() . 'assets/img/promotions/black-friday-2025.png',
70 'backgroundImage' => '',
71 'couponCode' => '2025BF50',
72 'ctaText' => 'SHOP SALE',
73 'ctaSubText' => 'ENDS 2 DEC 23:59 (GMT +3)',
74 'ctaUrl' => 'https://getsellkit.com/pricing/?utm_campaign=BF2025Deal&utm_source=WPDashboard',
75 'isDismissible' => true,
76 'startsAt' => '2025-11-27T00:00:00+03:00',
77 'expiresAt' => '2025-12-02T23:59:00+03:00',
78 'sellkitAdminOnly' => true,
79 ],
80 ];
81 }
82
83 /**
84 * Validate that a promotion ID exists in the banners configuration.
85 *
86 * @since 2.4.0
87 *
88 * @param string $promotion_id Promotion identifier.
89 *
90 * @return bool
91 */
92 private function is_valid_promotion_id( $promotion_id ) {
93 if ( empty( $promotion_id ) ) {
94 return false;
95 }
96
97 foreach ( $this->get_banners() as $banner ) {
98 if ( ! empty( $banner['id'] ) && $promotion_id === $banner['id'] ) {
99 return true;
100 }
101 }
102
103 return false;
104 }
105
106 /**
107 * Check if the current admin page is a SellKit admin page.
108 *
109 * @since 2.4.0
110 *
111 * @return bool
112 */
113 private function is_sellkit_admin_page() {
114 // phpcs:ignore WordPress.Security.NonceVerification -- Reading query param for page routing, not form processing.
115 $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
116
117 return ! empty( $page ) && strpos( $page, 'sellkit' ) !== false;
118 }
119
120 /**
121 * Get active banners for the current user and time.
122 *
123 * @since 2.4.0
124 *
125 * @SuppressWarnings(PHPMD.NPathComplexity)
126 *
127 * @return array
128 */
129 private function get_active_banners() {
130 if ( null !== $this->active_banners ) {
131 return $this->active_banners;
132 }
133
134 $banners = $this->get_banners();
135
136 if ( empty( $banners ) || ! is_array( $banners ) ) {
137 $this->active_banners = [];
138
139 return $this->active_banners;
140 }
141
142 $now = current_time( 'timestamp' );
143 $is_sellkit_admin_page = $this->is_sellkit_admin_page();
144 $filtered = [];
145
146 foreach ( $banners as $banner ) {
147 if ( empty( $banner ) || empty( $banner['id'] ) ) {
148 continue;
149 }
150
151 $dismissed = get_user_meta(
152 get_current_user_id(),
153 'sellkit_admin_promotion_dismissed_' . $banner['id'],
154 true
155 );
156
157 if ( $dismissed ) {
158 continue;
159 }
160
161 if ( ! empty( $banner['startsAt'] ) ) {
162 $starts_at = strtotime( $banner['startsAt'] );
163
164 if ( $starts_at && $now < $starts_at ) {
165 continue;
166 }
167 }
168
169 if ( ! empty( $banner['expiresAt'] ) ) {
170 $expires_at = strtotime( $banner['expiresAt'] );
171
172 if ( $expires_at && $now > $expires_at ) {
173 continue;
174 }
175 }
176
177 if ( ! empty( $banner['sellkitAdminOnly'] ) && ! $is_sellkit_admin_page ) {
178 continue;
179 }
180
181 $filtered[] = $banner;
182 }
183
184 $this->active_banners = $filtered;
185
186 return $this->active_banners;
187 }
188
189 /**
190 * Render global admin promotion banner.
191 *
192 * @since 2.4.0
193 *
194 * @SuppressWarnings(PHPMD.NPathComplexity)
195 *
196 * @return void
197 */
198 public function render() {
199 if ( ! is_admin() || is_network_admin() ) {
200 return;
201 }
202
203 if ( ! current_user_can( 'manage_options' ) ) {
204 return;
205 }
206
207 $banners = $this->get_active_banners();
208
209 if ( empty( $banners ) ) {
210 return;
211 }
212
213 foreach ( $banners as $banner ) {
214 $promotion_id = $banner['id'];
215 $nonce = wp_create_nonce( 'sellkit_dismiss_admin_promotion' );
216 $image_url = isset( $banner['mainImageURL'] ) ? $banner['mainImageURL'] : '';
217 $bg_image = isset( $banner['backgroundImage'] ) ? $banner['backgroundImage'] : '';
218 $heading = isset( $banner['heading'] ) ? $banner['heading'] : '';
219 $description = isset( $banner['description'] ) ? $banner['description'] : '';
220 $coupon_code = isset( $banner['couponCode'] ) ? $banner['couponCode'] : '';
221 $cta_text = isset( $banner['ctaText'] ) ? $banner['ctaText'] : '';
222 $cta_url = isset( $banner['ctaUrl'] ) ? $banner['ctaUrl'] : '';
223 $cta_subtext = isset( $banner['ctaSubText'] ) ? $banner['ctaSubText'] : '';
224 $has_code = ! empty( $coupon_code );
225 $has_cta = ! empty( $cta_text ) && ! empty( $cta_url );
226 $bg_style = '';
227
228 if ( ! empty( $bg_image ) ) {
229 $bg_style = 'background-image:url(' . esc_url( $bg_image ) . ');';
230 }
231
232 $this->render_banner_template(
233 [
234 'promotion_id' => $promotion_id,
235 'nonce' => $nonce,
236 'image_url' => $image_url,
237 'heading' => $heading,
238 'description' => $description,
239 'coupon_code' => $coupon_code,
240 'cta_text' => $cta_text,
241 'cta_url' => $cta_url,
242 'cta_subtext' => $cta_subtext,
243 'has_code' => $has_code,
244 'has_cta' => $has_cta,
245 'bg_style' => $bg_style,
246 'is_dismissible' => ! empty( $banner['isDismissible'] ),
247 ]
248 );
249 }
250 }
251
252 /**
253 * Enqueue styles and scripts for promotion banners.
254 *
255 * @since 2.4.0
256 *
257 * @return void
258 */
259 public function enqueue_assets() {
260 if ( ! is_admin() || is_network_admin() ) {
261 return;
262 }
263
264 if ( ! current_user_can( 'manage_options' ) ) {
265 return;
266 }
267
268 if ( empty( $this->get_active_banners() ) ) {
269 return;
270 }
271
272 wp_enqueue_style(
273 'sellkit-promotion-banner-font',
274 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;700;800&display=swap',
275 [],
276 '1.0.0'
277 );
278
279 wp_enqueue_style(
280 'sellkit-admin-promotion-banner',
281 sellkit()->plugin_url() . 'assets/dist/css/promotion-banner.css',
282 [ 'sellkit-promotion-banner-font' ],
283 sellkit()->version()
284 );
285
286 wp_enqueue_script(
287 'sellkit-admin-promotion-banner',
288 sellkit()->plugin_url() . 'assets/dist/js/promotion-banner.js',
289 [ 'jquery' ],
290 sellkit()->version(),
291 true
292 );
293
294 wp_localize_script(
295 'sellkit-admin-promotion-banner',
296 'sellkitPromotionBanner',
297 [
298 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
299 ]
300 );
301 }
302
303 /**
304 * Render a single promotion banner using a template.
305 *
306 * @since 2.4.0
307 *
308 * @param array $context Banner context data.
309 *
310 * @return void
311 */
312 private function render_banner_template( array $context ) {
313 $template = __DIR__ . '/views/promotion-banner.php';
314
315 if ( ! file_exists( $template ) ) {
316 return;
317 }
318
319 $promotion_id = $context['promotion_id'];
320 $nonce = $context['nonce'];
321 $image_url = $context['image_url'];
322 $heading = $context['heading'];
323 $description = $context['description'];
324 $coupon_code = $context['coupon_code'];
325 $cta_text = $context['cta_text'];
326 $cta_url = $context['cta_url'];
327 $cta_subtext = $context['cta_subtext'];
328 $has_code = $context['has_code'];
329 $has_cta = $context['has_cta'];
330 $bg_style = $context['bg_style'];
331 $is_dismissible = $context['is_dismissible'];
332
333 include $template;
334 }
335
336 /**
337 * Handle AJAX dismissal of the admin promotion banner.
338 *
339 * @since 2.4.0
340 *
341 * @return void
342 */
343 public function ajax_dismiss() {
344 check_ajax_referer( 'sellkit_dismiss_admin_promotion', 'nonce' );
345
346 if ( ! current_user_can( 'manage_options' ) ) {
347 wp_send_json_error();
348 }
349
350 $promotion_id = isset( $_POST['promotionId'] ) ? sanitize_text_field( wp_unslash( $_POST['promotionId'] ) ) : '';
351
352 if ( empty( $promotion_id ) || ! $this->is_valid_promotion_id( $promotion_id ) ) {
353 wp_send_json_error();
354 }
355
356 update_user_meta(
357 get_current_user_id(),
358 'sellkit_admin_promotion_dismissed_' . $promotion_id,
359 1
360 );
361
362 wp_send_json_success();
363 }
364 }
365
366 new Sellkit_Admin_Promotion_Banner();
367
368