PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.9
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.9
4.0.9 4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 All 150 releases
← All changes | vendor/codeinwp/themeisle-sdk/src/Modules/Announcements.php +389 -222 3.10.10 → 4.0.9 View file →
@@ -9,10 +9,12 @@
9 9 * @copyright Copyright (c) 2017, Marius Cristea
10 10 * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
11 11 * @since 3.3.0
12 12 */
13 +
13 14 namespace ThemeisleSDK\Modules;
14 15
16 +use DateTime;
15 17 use ThemeisleSDK\Common\Abstract_Module;
16 18 use ThemeisleSDK\Loader;
17 19 use ThemeisleSDK\Product;
18 20
@@ -20,36 +22,31 @@
20 22 * Announcement module for the ThemeIsle SDK.
21 23 */
22 24 class Announcements extends Abstract_Module {
23 25
26 + const SALE_DURATION_BLACK_FRIDAY = '+7 days'; // DateTime modifier. (Include Cyber Monday)
27 + const MINIMUM_INSTALL_AGE = 3 * DAY_IN_SECONDS;
28 +
24 29 /**
25 - * Holds the timeline for the announcements.
30 + * Mark if the notice was already loaded.
26 31 *
27 - * @var array
32 + * @var boolean
28 33 */
29 - private static $timeline = array(
30 - 'black_friday' => array(
31 - 'start' => '2024-11-25 00:00:00',
32 - 'end' => '2024-12-03 23:59:59',
33 - 'rendered' => false,
34 - ),
35 - );
34 + private static $notice_loaded = false;
36 35
37 36 /**
38 - * Holds the option prefix for the announcements.
37 + * Mark if the plugin meta link was already loaded.
39 38 *
40 - * This is used to store the dismiss date for each announcement.
41 - *
42 - * @var string
39 + * @var boolean
43 40 */
44 - public $option_prefix = 'themeisle_sdk_announcement_';
41 + private static $meta_link_loaded = false;
45 42
46 43 /**
47 - * Holds the time for the current request.
44 + * The product to be used.
48 45 *
49 46 * @var string
50 47 */
51 - public $time = '';
48 + private static $current_product = '';
52 49
53 50 /**
54 51 * Check if the module can be loaded.
55 52 *
@@ -72,17 +69,19 @@
72 69 *
73 70 * @return void
74 71 */
75 72 public function load( $product ) {
76 - if ( ! current_user_can( 'install_plugins' ) ) {
77 - return;
78 - }
73 + $this->product = $product;
79 74
80 - $this->product = $product;
75 + add_filter(
76 + 'themeisle_sdk_is_black_friday_sale',
77 + function( $is_black_friday ) {
78 + return $this->is_black_friday_sale( $this->get_current_date() );
79 + }
80 + );
81 81
82 - add_action( 'admin_init', array( $this, 'load_announcements' ) );
83 - add_filter( 'themeisle_sdk_active_announcements', array( $this, 'get_active_announcements' ) );
84 - add_filter( 'themeisle_sdk_announcements', array( $this, 'get_announcements_for_plugins' ) );
82 + add_action( 'admin_menu', array( $this, 'load_announcements' ), 9 );
83 + add_action( 'wp_ajax_themeisle_sdk_dismiss_black_friday_notice', array( $this, 'disable_notification_ajax' ) );
85 84 }
86 85
87 86 /**
88 87 * Load all valid announcements.
@@ -89,291 +88,459 @@
89 88 *
90 89 * @return void
91 90 */
92 91 public function load_announcements() {
93 - $active = $this->get_active_announcements();
92 + $current_date = $this->get_current_date();
93 + if ( ! $this->is_black_friday_sale( $current_date ) ) {
94 + return;
95 + }
94 96
95 - if ( empty( $active ) ) {
97 + if ( self::MINIMUM_INSTALL_AGE > ( $current_date->getTimestamp() - $this->product->get_install_time() ) ) {
96 98 return;
97 99 }
98 100
99 - foreach ( $active as $announcement ) {
101 + add_action( 'admin_notices', array( $this, 'black_friday_notice_render' ) );
100 102
101 - $method = $announcement . '_notice_render';
103 + add_action(
104 + 'themeisle_internal_page',
105 + function( $plugin, $page_slug ) {
106 + self::$current_product = $plugin;
107 + },
108 + 10,
109 + 2
110 + );
102 111
103 - if ( method_exists( $this, $method ) ) {
104 - add_action( 'admin_notices', array( $this, $method ) );
105 - }
106 - }
112 + add_filter( 'plugin_row_meta', array( $this, 'add_plugin_meta_links' ), 10, 2 );
113 + add_filter( $this->product->get_key() . '_about_us_metadata', array( $this, 'override_about_us_metadata' ), 100 );
114 + }
107 115
108 - // Load the ajax handler.
109 - add_action( 'wp_ajax_themeisle_sdk_dismiss_announcement', array( $this, 'disable_notification_ajax' ) );
116 + /**
117 + * Get the remaining time for the event in a human-readable format.
118 + *
119 + * @param DateTime $end_date The end date for event.
120 + *
121 + * @return string Remaining time for the event.
122 + */
123 + public function get_remaining_time_for_event( $end_date ) {
124 + return human_time_diff( $this->get_current_date()->getTimestamp(), $end_date->getTimestamp() );
110 125 }
111 126
112 127 /**
113 - * Get all active announcements.
128 + * Check if the announcement can be shown.
114 129 *
115 - * @return array List of active announcements.
130 + * @param DateTime $current_date The announcement to check.
131 + * @param int $user_id The user id to show the notice.
132 + *
133 + * @return bool
116 134 */
117 - public function get_active_announcements() {
118 - $active = array();
135 + public function can_show_notice( $current_date, $user_id ) {
136 + $current_year = $current_date->format( 'Y' );
137 + $user_notice_dismiss_timestamp = get_user_meta( $user_id, 'themeisle_sdk_dismissed_notice_black_friday', true );
119 138
120 - foreach ( self::$timeline as $announcement_slug => $dates ) {
121 - if ( $this->is_active( $dates ) && $this->can_show( $announcement_slug, $dates ) ) {
122 - $active[] = $announcement_slug;
123 - }
139 + if ( empty( $user_notice_dismiss_timestamp ) ) {
140 + return true;
124 141 }
125 142
126 - return $active;
143 + $dismissed_year = wp_date( 'Y', $user_notice_dismiss_timestamp );
144 +
145 + return $current_year !== $dismissed_year;
127 146 }
128 147
129 148 /**
130 - * Get all announcements along with plugin specific data.
149 + * Calculate the start date for Black Friday based on the year of the given date.
131 150 *
132 - * @return array List of announcements.
151 + * Black Friday is the day after the Thanksgiving and the sale starts on the Monday of that week.
152 + *
153 + * @param DateTime $date The current date object, used to determine the year.
154 + * @return DateTime The start date of Black Friday for the given year.
133 155 */
134 - public function get_announcements_for_plugins() {
156 + public function get_start_date( $date ) {
157 + $year = $date->format( 'Y' );
158 + $black_friday = new DateTime( "last friday of november {$year}" );
135 159
136 - $announcements = array();
160 + $sale_start = clone $black_friday;
161 + $sale_start->modify( 'monday this week' );
162 + $sale_start->setTime( 0, 0 );
137 163
138 - foreach ( self::$timeline as $announcement => $dates ) {
139 - $announcements[ $announcement ] = $dates;
164 + return $sale_start;
165 + }
140 166
141 - if ( false !== strpos( $announcement, 'black_friday' ) ) {
142 - $announcements[ $announcement ]['active'] = $this->is_active( $dates );
143 -
144 - // Dashboard banners URLs.
145 - $announcements[ $announcement ]['feedzy_dashboard_url'] = tsdk_utmify( 'https://themeisle.com/plugins/feedzy-rss-feeds/blackfriday/', 'bfcm24', 'dashboard' );
146 - $announcements[ $announcement ]['neve_dashboard_url'] = tsdk_utmify( 'https://themeisle.com/themes/neve/blackfriday/', 'bfcm24', 'dashboard' );
147 - $announcements[ $announcement ]['otter_dashboard_url'] = tsdk_utmify( 'https://themeisle.com/plugins/otter-blocks/blackfriday/', 'bfcm24', 'dashboard' );
148 -
149 - // Customizer banners URLs.
150 - $announcements[ $announcement ]['hestia_customizer_url'] = tsdk_utmify( 'https://themeisle.com/black-friday/', 'bfcm24', 'hestiacustomizer' );
151 - $announcements[ $announcement ]['neve_customizer_url'] = tsdk_utmify( 'https://themeisle.com/black-friday/', 'bfcm24', 'nevecustomizer' );
152 -
153 - // Banners urgency text.
154 - $remaining_time = $this->get_remaining_time_for_event( $dates['end'] );
155 - $announcements[ $announcement ]['remaining_time'] = $remaining_time;
156 - $announcements[ $announcement ]['urgency_text'] = ! empty( $remaining_time ) ? 'Hurry up! Only ' . $remaining_time . ' left.' : '';
157 - }
158 - }
159 -
160 - return apply_filters( 'themeisle_sdk_announcements_data', $announcements );
167 + /**
168 + * Calculate the event end date.
169 + *
170 + * @param DateTime $start_date The start date.
171 + * @return DateTime The end date.
172 + */
173 + public function get_end_date( $start_date ) {
174 + $black_friday_end = clone $start_date;
175 + $black_friday_end->modify( self::SALE_DURATION_BLACK_FRIDAY );
176 + $black_friday_end->setTime( 23, 59, 59 );
177 + return $black_friday_end;
161 178 }
162 179
163 180 /**
164 - * Get the announcement data.
181 + * Check if the current date falls within the Black Friday sale period.
165 182 *
166 - * @param string $announcement The announcement to get the data for.
167 - *
168 - * @return array
183 + * @param DateTime $current_date The date to check.
184 + * @return bool True if the date is within the Black Friday sale period, false otherwise.
169 185 */
170 - public function get_announcement_data( $announcement ) {
171 - return ! empty( $announcement ) && is_string( $announcement ) && isset( self::$timeline[ $announcement ] ) ? self::$timeline[ $announcement ] : array();
186 + public function is_black_friday_sale( $current_date ) {
187 + $black_friday_start_date = $this->get_start_date( $current_date );
188 + $black_friday_end = $this->get_end_date( $black_friday_start_date );
189 + return $black_friday_start_date <= $current_date && $current_date <= $black_friday_end;
172 190 }
173 191
174 192 /**
175 - * Check if the announcement has an active timeline.
193 + * Get the notice data.
176 194 *
177 - * @param array $dates The announcement to check.
178 - *
179 - * @return bool
195 + * @return array The notice data.
180 196 */
181 - public function is_active( $dates ) {
197 + public function get_notice_data() {
198 + $time_left_label = $this->get_remaining_time_for_event( $this->get_end_date( $this->get_start_date( $this->get_current_date() ) ) );
199 + $time_left_label = sprintf( Loader::$labels['announcements']['time_left'], $time_left_label );
182 200
183 - if ( empty( $this->time ) ) {
184 - $this->time = current_time( 'Y-m-d' );
201 + $utm_location = 'globalnotice';
202 + if ( ! empty( $this->product ) ) {
203 + $utm_location = $this->product->get_friendly_name();
185 204 }
186 205
187 - $start = isset( $dates['start'] ) ? $dates['start'] : null;
188 - $end = isset( $dates['end'] ) ? $dates['end'] : null;
206 + $sale_title = Loader::$labels['announcements']['black_friday'];
207 + $sale_url = tsdk_translate_link( tsdk_utmify( 'https://themeisle.com/blackfriday/', 'bfcm26', $utm_location ) );
189 208
190 - if ( $start && $end ) {
191 - return $start <= $this->time && $this->time <= $end;
192 - } elseif ( $start ) {
193 - return $this->time >= $start;
194 - } elseif ( $end ) {
195 - return $this->time <= $end;
196 - }
209 + $current_year = $this->get_current_date()->format( 'Y' );
210 + $sale_message = sprintf( Loader::$labels['announcements']['max_savings'], $current_year );
197 211
198 - return false;
212 + return array(
213 + 'title' => $sale_title,
214 + 'sale_url' => $sale_url,
215 + 'message' => $sale_message,
216 + 'time_left' => $time_left_label,
217 + );
199 218 }
200 219
201 220 /**
202 - * Get the remaining time for the event in a human readable format.
221 + * Render the Black Friday notice.
203 222 *
204 - * @param string $end_date The end date for event.
205 - * @return string Remaining time for the event.
223 + * @return void
206 224 */
207 - public function get_remaining_time_for_event( $end_date ) {
208 - if ( empty( $end_date ) || ! is_string( $end_date ) ) {
209 - return '';
225 + public function black_friday_notice_render() {
226 +
227 + // Prevent the notice from being rendered twice.
228 + if ( self::$notice_loaded ) {
229 + return;
210 230 }
231 + self::$notice_loaded = true;
211 232
212 - try {
213 - $end_date = new \DateTime( $end_date, new \DateTimeZone( 'GMT' ) );
214 - $current_date = new \DateTime( 'now', new \DateTimeZone( 'GMT' ) );
215 - $diff = $end_date->diff( $current_date );
233 + $current_user_id = get_current_user_id();
216 234
217 - if ( $diff->days > 0 ) {
218 - return $diff->days === 1 ? $diff->format( '%a day' ) : $diff->format( '%a days' );
235 + if ( ! $this->can_show_notice( $this->get_current_date(), $current_user_id ) ) {
236 + return;
237 + }
238 +
239 + $all_configs = apply_filters( 'themeisle_sdk_blackfriday_data', array( 'default' => $this->get_notice_data() ) );
240 +
241 + if ( empty( $all_configs ) || ! is_array( $all_configs ) ) {
242 + return;
243 + }
244 +
245 + $data = isset( $all_configs['default'] ) ? $all_configs['default'] : $this->get_notice_data();
246 + $products = Loader::get_products();
247 + $current_time = $this->get_current_date()->getTimestamp();
248 + $can_show = false;
249 +
250 + // Check if we have products that are eligible to show the notice with the default data. If the product provide its own config, use it.
251 + foreach ( $products as $product ) {
252 + $slug = $product->get_slug();
253 +
254 + if ( self::MINIMUM_INSTALL_AGE < ( $current_time - $product->get_install_time() ) ) {
255 + $can_show = true;
256 +
257 + if ( isset( $all_configs[ $slug ] ) && ! empty( $all_configs[ $slug ] ) && is_array( $all_configs[ $slug ] ) ) {
258 + $data = $all_configs[ $slug ];
259 +
260 + if ( self::$current_product === $slug ) {
261 + $data = $all_configs[ $slug ];
262 + break;
263 + }
264 + }
219 265 }
266 + }
220 267
221 - if ( $diff->h > 0 ) {
222 - return $diff->h === 1 ? $diff->format( '%h hour' ) : $diff->format( '%h hours' );
268 + if ( ! $can_show ) {
269 + return;
270 + }
271 +
272 + $displayed_on_internal_page = 0 < did_action( 'themeisle_internal_page' );
273 +
274 + $title = ! empty( $data['title'] ) ? $data['title'] : Loader::$labels['announcements']['black_friday'];
275 + $time_left_label = ! empty( $data['time_left'] ) ? $data['time_left'] : '';
276 + $message = ! empty( $data['message'] ) ? $data['message'] : '';
277 + $logo_url = ! empty( $data['logo_url'] ) ? $data['logo_url'] : $this->get_sdk_uri() . 'assets/images/themeisle-logo.png';
278 + $cta_label = ! empty( $data['cta_label'] ) ? $data['cta_label'] : Loader::$labels['announcements']['notice_link_label'];
279 + $sale_url = ! empty( $data['sale_url'] ) ? $data['sale_url'] : '';
280 + $hide_other_notices = ! empty( $data['hide_other_notices'] ) ? $data['hide_other_notices'] : $displayed_on_internal_page;
281 + $dismiss_notice_url = wp_nonce_url(
282 + add_query_arg(
283 + array( 'action' => 'themeisle_sdk_dismiss_black_friday_notice' ),
284 + admin_url( 'admin-ajax.php' )
285 + ),
286 + 'dismiss_themeisle_event_notice'
287 + );
288 +
289 + if ( empty( $sale_url ) ) {
290 + return;
291 + }
292 +
293 + if ( ! current_user_can( 'install_plugins' ) ) {
294 + $sale_url = remove_query_arg( 'lkey', $sale_url );
295 + }
296 +
297 + ?>
298 + <style>
299 + .themeisle-sale {
300 + border-left-color: #0466CB;
223 301 }
224 -
225 - if ( $diff->i > 0 ) {
226 - return $diff->i === 1 ? $diff->format( '%i minute' ) : $diff->format( '%i minutes' );
302 + .themeisle-sale :is(.themeisle-sale-title, p) {
303 + margin: 0;
227 304 }
305 + .themeisle-sale-container {
306 + display: flex;
307 + align-items: center;
308 + padding: 0.5rem 0;
309 + gap: 0.5rem;
310 + padding-right: 10px;
311 + }
312 + .themeisle-sale-content {
313 + display: flex;
314 + flex-direction: column;
315 + gap: 0.2rem;
316 + }
317 + .themeisle-sale a {
318 + text-decoration: none;
319 + }
320 + .themeisle-sale p a {
321 + margin-left: 1rem;
322 + padding: 7px 12px;
323 + border-radius: 4px;
324 + background: #0466CB;
325 + color: white;
326 + font-weight: 700;
327 + }
328 + .themeisle-sale-dismiss {
329 + padding-top: 5px;
330 + }
331 + .themeisle-sale-dismiss span {
332 + color: #787c82;
333 + font-size: 16px;
334 + }
335 + .notice.themeisle-sale {
336 + padding: 0;
337 + }
338 + .themeisle-sale-logo {
339 + display: flex;
340 + justify-content: center;
341 + align-items: center;
342 + margin-left: 5px;
343 + }
344 + .themeisle-sale-time-left {
345 + margin-left: 5px;
346 + padding: 3px 5px;
347 + border-radius: 4px;
348 + background-color: #dfdfdf;
349 + font-weight: 600;
350 + font-size: x-small;
351 + line-height: 1;
352 + }
353 + .themeisle-sale-title {
354 + font-size: 14px;
355 + display: flex;
356 + align-items: center;
357 + }
358 + .themeisle-sale-action {
359 + flex-grow: 1;
360 + display: flex;
361 + justify-content: flex-end;
362 + }
363 + <?php if ( $hide_other_notices ) : ?>
364 + .notice:not(.themeisle-sale) {
365 + display: none;
366 + }
367 + <?php endif; ?>
368 + </style>
369 + <div class="themeisle-sale notice notice-info" data-event-slug="black_friday">
370 + <div class="themeisle-sale-container">
371 + <div class="themeisle-sale-logo">
372 + <img
373 + width="45"
374 + src="<?php echo esc_url( $logo_url ); ?>"
375 + />
376 + </div>
377 + <div class="themeisle-sale-content">
378 + <h4 class="themeisle-sale-title">
379 + <?php echo esc_html( $title ); ?>
380 + <span class="themeisle-sale-time-left">
381 + <?php echo esc_html( $time_left_label ); ?>
382 + </span>
383 + </h4>
384 + <p>
385 + <?php echo wp_kses_post( $message ); ?>
386 + </p>
387 + </div>
388 + <div class="themeisle-sale-action">
389 + <a
390 + href="<?php echo esc_url( $sale_url ); ?>"
391 + target="_blank"
392 + class="button button-primary themeisle-sale-button"
393 + >
394 + <?php echo esc_html( $cta_label ); ?>
395 + </a>
396 + </div>
397 + <a href="<?php echo esc_url( $dismiss_notice_url ); ?>" class="themeisle-sale-dismiss">
398 + <span class="dashicons dashicons-dismiss"></span>
399 + </a>
400 + </div>
401 + </div>
402 + <script>
403 + // Note: Some plugins use React and the content is ready after the `DOMContentLoaded` event. Use this function to reposition the notice after components have rendered.
404 + window.tsdk_reposition_notice = function() {
405 + const bannerRoot = document.getElementById('tsdk_banner');
406 + const saleNotice = document.querySelector('.themeisle-sale');
407 + if ( ! bannerRoot || ! saleNotice ) {
408 + return;
409 + }
228 410
229 - return $diff->s === 1 ? $diff->format( '%s second' ) : $diff->format( '%s seconds' );
230 - } catch ( \Exception $e ) {
231 - if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
232 - error_log( $e->getMessage() ); // phpcs:ignore
233 - }
234 - }
411 + bannerRoot.appendChild(saleNotice);
412 + };
235 413
236 - return '';
414 + document.addEventListener( 'DOMContentLoaded', function() {
415 + window.tsdk_reposition_notice();
416 + } );
417 + </script>
418 + <?php
237 419 }
238 420
239 421 /**
240 - * Check if the announcement can be shown.
422 + * Disable the notification via ajax.
241 423 *
242 - * @param string $announcement_slug The announcement to check.
243 - * @param array $dates The announcement to check.
244 - *
245 - * @return bool
424 + * @return void
246 425 */
247 - public function can_show( $announcement_slug, $dates ) {
248 - $dismiss_date = get_option( $this->option_prefix . $announcement_slug, false );
426 + public function disable_notification_ajax() {
427 + check_ajax_referer( 'dismiss_themeisle_event_notice' );
249 428
250 - if ( false === $dismiss_date ) {
251 - return true;
252 - }
429 + update_user_meta( get_current_user_id(), 'themeisle_sdk_dismissed_notice_black_friday', $this->get_current_date()->getTimestamp() );
253 430
254 - // If the start date is after the dismiss date, show the notice.
255 - $start = isset( $dates['start'] ) ? $dates['start'] : null;
256 - if ( $start && $dismiss_date < $start ) {
257 - return true;
431 + $return_page_url = wp_get_referer();
432 + if ( empty( $return_page_url ) ) {
433 + $return_page_url = admin_url();
258 434 }
259 435
260 - return false;
436 + wp_safe_redirect( $return_page_url );
437 + exit;
261 438 }
262 439
263 440 /**
264 - * Disable the notification via ajax.
441 + * Add the plugin meta links.
265 442 *
266 - * @return void
443 + * @param array<string, string> $links The plugin meta links.
444 + * @param string $plugin_file The plugin file.
445 + * @return array<string, string> The plugin meta links.
267 446 */
268 - public function disable_notification_ajax() {
269 - if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'dismiss_themeisle_event_notice' ) ) {
270 - wp_die( 'Invalid nonce! Refresh the page and try again.' );
447 + public function add_plugin_meta_links( $links, $plugin_file ) {
448 + if ( self::$meta_link_loaded ) {
449 + return $links;
271 450 }
272 451
273 - if ( ! isset( $_POST['announcement'] ) || ! is_string( $_POST['announcement'] ) ) {
274 - wp_die( 'Invalid announcement! Refresh the page and try again.' );
452 + if ( $plugin_file !== plugin_basename( $this->product->get_basefile() ) ) {
453 + return $links;
275 454 }
276 455
277 - $announcement = sanitize_key( $_POST['announcement'] );
456 + $configs = apply_filters( 'themeisle_sdk_blackfriday_data', array( 'default' => $this->get_notice_data() ) );
278 457
279 - update_option( $this->option_prefix . $announcement, current_time( 'Y-m-d' ) );
280 - wp_die( 'success' );
458 + if ( empty( $configs ) || ! is_array( $configs ) ) {
459 + return $links;
460 + }
461 +
462 + $current_slug = $this->product->get_slug();
463 + $data = isset( $configs[ $current_slug ] ) && ! empty( $configs[ $current_slug ] ) && is_array( $configs[ $current_slug ] ) ? $configs[ $current_slug ] : array();
464 +
465 + $plugin_meta_message = '';
466 + $plugin_meta_url = '';
467 +
468 + if ( isset( $data['plugin_meta_targets'] ) && ! empty( $data['plugin_meta_targets'] ) && ! in_array( $current_slug, $data['plugin_meta_targets'] ) ) {
469 + return $links; // The current configuration is for another plugins.
470 + }
471 +
472 + $plugin_meta_message = ! empty( $data['plugin_meta_message'] ) ? $data['plugin_meta_message'] : '';
473 + $plugin_meta_url = ! empty( $data['sale_url'] ) ? $data['sale_url'] : '';
474 +
475 + if ( empty( $plugin_meta_url ) || empty( $plugin_meta_message ) ) {
476 +
477 + // Check if a configuration is in another plugin.
478 + $products = Loader::get_products();
479 + foreach ( $products as $product ) {
480 + $slug = $product->get_slug();
481 +
482 + if ( $slug === $current_slug || ! isset( $configs[ $slug ] ) || empty( $configs[ $slug ] ) || ! is_array( $configs[ $slug ] ) ) {
483 + continue;
484 + }
485 +
486 + if ( ! empty( $configs[ $slug ]['plugin_meta_targets'] ) && in_array( $current_slug, $configs[ $slug ]['plugin_meta_targets'] ) ) {
487 + $plugin_meta_message = ! empty( $configs[ $slug ]['plugin_meta_message'] ) ? $configs[ $slug ]['plugin_meta_message'] : '';
488 + $plugin_meta_url = ! empty( $configs[ $slug ]['sale_url'] ) ? $configs[ $slug ]['sale_url'] : '';
489 + break;
490 + }
491 + }
492 + }
493 +
494 + if ( empty( $plugin_meta_url ) || empty( $plugin_meta_message ) ) {
495 + return $links;
496 + }
497 +
498 + $links[] = sprintf( '<a class="themeisle-sale-plugin-meta-link" style="color: red;" href="%s" target="_blank">%s</a>', esc_url( $plugin_meta_url ), esc_html( $plugin_meta_message ) );
499 +
500 + self::$meta_link_loaded = true;
501 +
502 + return $links;
281 503 }
282 504
283 505 /**
284 - * Render the Black Friday notice.
506 + * Override the About Us upgrade menu during Black Friday.
285 507 *
286 - * @return void
508 + * Registered dynamically during admin_menu when sale is active.
509 + * Only applies if About_Us module is loaded for the product.
510 + *
511 + * @param array<string, mixed> $about_data About Us metadata.
512 + *
513 + * @return array<string, mixed>
287 514 */
288 - public function black_friday_notice_render() {
515 + public function override_about_us_metadata( $about_data ) {
516 + if ( ! $this->is_black_friday_sale( $this->get_current_date() ) ) {
517 + return $about_data;
518 + }
289 519
290 - // Prevent the notice from being rendered twice.
291 - if ( self::$timeline['black_friday']['rendered'] ) {
292 - return;
520 + if ( empty( $about_data ) || ! is_array( $about_data ) ) {
521 + return $about_data;
293 522 }
294 - self::$timeline['black_friday']['rendered'] = true;
295 523
296 - $product_names = array();
524 + if ( empty( $about_data['has_upgrade_menu'] ) || true !== $about_data['has_upgrade_menu'] ) {
525 + return $about_data;
526 + }
297 527
298 - foreach ( Loader::get_products() as $product ) {
299 - $slug = $product->get_slug();
528 + $configs = apply_filters( 'themeisle_sdk_blackfriday_data', array( 'default' => $this->get_notice_data() ) );
300 529
301 - // Do not add if the contains the string 'pro'.
302 - if ( strpos( $slug, 'pro' ) !== false ) {
303 - continue;
304 - }
305 -
306 - $product_names[] = $product->get_name();
530 + $current_slug = $this->product->get_slug();
531 + if ( ! isset( $configs[ $current_slug ] ) || empty( $configs[ $current_slug ] ) || ! is_array( $configs[ $current_slug ] ) ) {
532 + return $about_data;
307 533 }
308 534
309 - // Randomize the products and get only 4.
310 - shuffle( $product_names );
311 - $product_names = array_slice( $product_names, 0, 4 );
535 + $config = $configs[ $current_slug ];
312 536
313 - ?>
314 - <style>
315 - .themeisle-sale {
316 - display: flex;
317 - }
318 - </style>
319 - <div class="themeisle-sale notice notice-info is-dismissible" data-announcement="black_friday">
320 - <img src="<?php echo esc_url_raw( $this->get_sdk_uri() . 'assets/images/themeisle-logo.svg' ); ?>" />
321 - <p>
322 - <strong>Themeisle Black Friday Sale is Live!</strong> - Enjoy Maximum Savings on <?php echo esc_html( implode( ', ', $product_names ) ); ?>.
323 - <a href="<?php echo esc_url_raw( tsdk_utmify( 'https://themeisle.com/blackfriday/', 'bfcm24', 'globalnotice' ) ); ?>" target="_blank">Learn more</a>
324 - <span class="themeisle-sale-error"></span>
325 - </p>
326 - </div>
327 - <script type="text/javascript" data-origin="themeisle-sdk">
328 - window.document.addEventListener('DOMContentLoaded', () => {
329 - const observer = new MutationObserver((mutationsList, observer) => {
330 - for(let mutation of mutationsList) {
331 - if (mutation.type === 'childList') {
332 - const container = document.querySelector('.themeisle-sale.notice');
333 - const button = container?.querySelector('button');
334 - if ( button ) {
335 - button.addEventListener('click', e => {
336 - e.preventDefault();
337 - fetch('<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>', {
338 - method: 'POST',
339 - headers: {
340 - 'Content-Type': 'application/x-www-form-urlencoded'
341 - },
342 - body: new URLSearchParams({
343 - action: 'themeisle_sdk_dismiss_announcement',
344 - nonce: '<?php echo esc_attr( wp_create_nonce( 'dismiss_themeisle_event_notice' ) ); ?>',
345 - announcement: container.dataset.announcement
346 - })
347 - })
348 - .then(response => response.text())
349 - .then(response => {
350 - if (!response?.includes('success')) {
351 - document.querySelector('.themeisle-sale-error').innerHTML = response;
352 - return;
353 - }
537 + if ( empty( $config['upgrade_menu_text'] ) || empty( $config['sale_url'] ) ) {
538 + return $about_data;
539 + }
354 540
355 - document.querySelectorAll('.themeisle-sale.notice').forEach(el => {
356 - el.classList.add('hidden');
357 - setTimeout(() => {
358 - el.remove();
359 - }, 800);
360 - });
361 - })
362 - .catch(error => {
363 - console.error('Error:', error);
364 - document.querySelector('.themeisle-sale-error').innerHTML = error;
365 - });
366 - });
367 - observer.disconnect();
368 - break;
369 - }
370 - }
371 - }
372 - });
541 + $about_data['upgrade_text'] = $config['upgrade_menu_text'];
542 + $about_data['upgrade_link'] = $config['sale_url'];
373 543
374 - observer.observe(document.body, { childList: true, subtree: true });
375 - });
376 - </script>
377 - <?php
544 + return $about_data;
378 545 }
379 546 }