PluginProbe ʕ •ᴥ•ʔ
Hustle – Email Marketing, Lead Generation, Optins, Popups / 7.8.14
Hustle – Email Marketing, Lead Generation, Optins, Popups v7.8.14
7.8.14 7.8.14.1 7.8.13 7.8.13.1 trunk 3.0 3.1 3.1.1 3.1.2 3.1.3 3.1.4 4.3.2 4.4.4 4.4.5 4.4.5.1 4.4.5.4 4.6 4.6.1.1 4.6.1.4 4.7.0.2 4.7.0.3 4.7.0.7 4.7.0.9 4.7.1.0 4.7.1.1 4.8.0.0 5.0.0 5.0.1 5.0.1.1 5.0.1.2 5.1 5.1.1 5.1.2 5.1.3 5.1.3.1 5.1.3.2 5.1.4 5.1.5 6.0 6.0.1 6.0.2 6.0.3 6.0.4.2 6.0.5 6.0.6.1 6.0.7 6.0.8.1 6.0.9 7.0.0.1 7.0.2 7.0.3 7.0.4 7.1.0 7.1.1 7.2.0 7.2.1 7.3.0 7.3.1 7.3.3 7.3.5 7.3.6 7.3.7 7.4.0 7.4.1 7.4.11 7.4.13 7.4.13.1 7.4.2 7.4.3 7.4.4 7.4.5 7.4.5.1 7.4.5.2 7.4.6 7.4.7 7.5.0 7.6.0 7.6.1 7.6.3 7.6.4 7.6.6 7.7.0 7.7.1 7.8.0 7.8.1 7.8.10 7.8.10.1 7.8.10.2 7.8.11 7.8.12 7.8.12.1 7.8.2 7.8.3 7.8.4 7.8.5 7.8.6 7.8.7 7.8.8 7.8.9 7.8.9.1 7.8.9.2 7.8.9.3
wordpress-popup / inc / metas / class-hustle-meta-base-settings.php
wordpress-popup / inc / metas Last commit date
default-design 5 months ago popup 5 months ago slidein 3 years ago sshare 5 months ago class-hustle-meta-base-content.php 3 years ago class-hustle-meta-base-design.php 3 years ago class-hustle-meta-base-display.php 6 years ago class-hustle-meta-base-emails.php 4 months ago class-hustle-meta-base-integrations.php 3 years ago class-hustle-meta-base-settings.php 3 years ago class-hustle-meta-base-visibility.php 5 months ago
class-hustle-meta-base-settings.php
608 lines
1 <?php
2 /**
3 * File for Hustle_Meta_Base_Content class.
4 *
5 * @package Hustle
6 * @since 4.2.0
7 */
8
9 /**
10 * Hustle_Meta_Base_Settings is the base class for the "settings" meta of modules.
11 * It's extended by popup, slidein, and embed modules.
12 * This class should handle what's related to the "settings" meta.
13 */
14 class Hustle_Meta_Base_Settings extends Hustle_Meta {
15
16 /**
17 * Returns the defaults for merging purposes.
18 * Avoid overwritting the triggers when the saved value is an empty array.
19 *
20 * @since 4.4.1
21 *
22 * @return array
23 */
24 protected function get_defaults_for_merge() {
25 $defaults = $this->get_defaults();
26
27 // Avoid overwritting the saved form elements when the default fields aren't present.
28 if ( ! empty( $this->data['triggers'] ) && isset( $defaults['triggers']['trigger'] ) && is_array( $this->data['triggers']['trigger'] ) ) {
29 unset( $defaults['triggers']['trigger'] );
30 }
31 // Avoid overwritting the empty after_close_trigger saved by the user.
32 if ( isset( $this->data['after_close_trigger'] ) ) {
33 unset( $defaults['after_close_trigger'] );
34 }
35 return $defaults;
36 }
37
38 /**
39 * Retrieves the base defaults for the 'settings' meta.
40 * Extended by embeds, popups, and slideins.
41 *
42 * @since 4.0.2
43 * @return array
44 */
45 public function get_defaults() {
46 return array(
47 'auto_close_success_message' => '0',
48 'triggers' => array(
49 'trigger' => array( 'time' ),
50 'on_time_delay' => '3',
51 'on_time_unit' => 'seconds',
52 'on_scroll' => 'scrolled',
53 'on_scroll_page_percent' => 20,
54 'on_scroll_css_selector' => '',
55 'enable_on_click_element' => '1',
56 'on_click_element' => '',
57 'enable_on_click_shortcode' => '1',
58 'on_exit_intent_per_session' => '1',
59 'on_exit_intent_delayed_time' => '0',
60 'on_exit_intent_delayed_unit' => 'seconds',
61 'on_adblock_delay' => '0',
62 'on_adblock_delay_unit' => 'seconds',
63 ),
64 'animation_in' => 'no_animation',
65 'animation_out' => 'no_animation',
66 'after_close_trigger' => array( 'click_close_icon' ),
67 'after_close' => 'keep_show',
68 'expiration' => 365,
69 'expiration_unit' => 'days',
70 'after_optin_expiration' => 365,
71 'after_optin_expiration_unit' => 'days',
72 'after_cta_expiration' => 365,
73 'after_cta2_expiration' => 365,
74 'after_cta_expiration_unit' => 'days',
75 'after_cta2_expiration_unit' => 'days',
76 'on_submit' => 'nothing', // close | default |nothing | redirect.
77 'on_submit_delay' => '5',
78 'on_submit_delay_unit' => 'seconds',
79 'close_cta' => '0',
80 'close_cta_time' => '0',
81 'close_cta_unit' => 'seconds',
82 'hide_after_cta' => 'keep_show', // keep_show | no_show_on_post | no_show_all.
83 'hide_after_cta2' => 'keep_show', // keep_show | no_show_on_post | no_show_all.
84 'hide_after_subscription' => 'keep_show', // keep_show | no_show_on_post | no_show_all.
85
86 'is_schedule' => '0',
87
88 'schedule' => array(
89 'not_schedule_start' => '1',
90 'start_date' => date( 'm/d/Y', strtotime( 'tomorrow' ) ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
91 'start_hour' => '12',
92 'start_minute' => '00',
93 'start_meridiem_offset' => 'am',
94
95 'not_schedule_end' => '1',
96 'end_date' => date( 'm/d/Y', strtotime( '+7 days' ) ), // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
97 'end_hour' => '11',
98 'end_minute' => '59',
99 'end_meridiem_offset' => 'pm',
100
101 'active_days' => 'all', // all | week_days.
102 'week_days' => array(),
103
104 'is_active_all_day' => '1',
105 'day_start_hour' => '00',
106 'day_start_minute' => '00',
107 'day_start_meridiem_offset' => 'am',
108
109 'day_end_hour' => '11',
110 'day_end_minute' => '59',
111 'day_end_meridiem_offset' => 'pm',
112
113 'time_to_use' => 'server', // server | custom.
114 'custom_timezone' => 'UTC',
115 ),
116 );
117 }
118
119 // ****************************************
120 // SCHEDULE.
121 // ****************************************
122 /**
123 * Whether this module will be shown any time in the future.
124 * Used in dashboard to display a notice if it won't.
125 *
126 * @since 4.2.0
127 * @return bool
128 */
129 public function will_be_shown_again() {
130
131 $is_scheduled = $this->is_currently_scheduled();
132
133 if ( ! $is_scheduled ) {
134 $flags = $this->module->get_schedule_flags();
135
136 // The module isn't shown now and won't be checked to show later on.
137 if ( '0' === $flags['check_schedule_at'] ) {
138 return false;
139 }
140 }
141
142 return true;
143 }
144
145 /**
146 * Returns whether the "schedule" setting allows this module to be displayed
147 *
148 * @since 4.2.0
149 * @return boolean
150 */
151 public function is_currently_scheduled() {
152
153 $schedule_flags = $this->module->get_schedule_flags();
154
155 $is_active = '1' === $schedule_flags['is_currently_scheduled'];
156 $check_schedule_at = $schedule_flags['check_schedule_at'];
157 $current_time = time();
158 $skip_cache = false;
159
160 /**
161 * Whether to use cached flags to check schedule settings.
162 * Useful for debugging.
163 *
164 * @since 4.2.0
165 *
166 * @param bool $skip_cache Set to true if you want the schedule to be checked on each run.
167 * @param Hustle_Module_Model $module
168 */
169 $skip_cache = apply_filters( 'hustle_skip_schedule_cache', $skip_cache, $this->module );
170
171 // Run the check if the flag isn't set to "don't check again"
172 // and the time the "schedule" should be checked again already passed.
173 if ( $skip_cache || ( '0' !== $check_schedule_at && $current_time > $check_schedule_at ) ) {
174 $is_active = $this->check_schedule();
175 }
176
177 /**
178 * Filter whether the schedule allows this module to be displayed.
179 *
180 * @since 4.2.0
181 *
182 * @param bool $is_currently_scheduled Whether the module should be shown.
183 * @param Hustle_Module_Model $module This module's instance.
184 */
185 return apply_filters( 'hustle_module_is_currently_scheduled', $is_active, $this->module );
186 }
187
188 /**
189 * Returns the "schedule" check and saves the "schedule" flags for future use
190 *
191 * @since 4.2.0
192 * @return bool
193 */
194 private function check_schedule() {
195
196 $flags = $this->get_schedule_flags();
197
198 /**
199 * Filter the schedule flags.
200 * Change their values before it's stored and before it's used
201 * to define whether the module should be shown in frontend.
202 *
203 * @since 4.2.0
204 *
205 * @param array $flags Schedule flags.
206 * [
207 * is_currently_scheduled => 1|0, // As strings. 1 to display the module, 0 otherwise.
208 * check_schedule_at => timestamp|0 // As strings. Next time the schedule will be checked. 0 to skip check.
209 * ]
210 * @param Hustle_Meta_Base_Settings $this
211 */
212 $flags = apply_filters( 'hustle_get_schedule_flags', $flags, $this );
213
214 // Store the flags for future use.
215 $this->module->set_schedule_flags( $flags );
216
217 return ( '1' === $flags['is_currently_scheduled'] );
218 }
219
220 /**
221 * Returns the 'schedule flags' to be stored.
222 *
223 * @since 4.2.0
224 * @return array
225 */
226 private function get_schedule_flags() {
227
228 $settings = $this->to_array();
229
230 // Schedule is deactivated. Show it right away.
231 if ( '1' !== $settings['is_schedule'] ) {
232
233 // Skip schedule check in next runs.
234 return array(
235 'is_currently_scheduled' => '1',
236 'check_schedule_at' => '0',
237 );
238 }
239
240 $schedule = $settings['schedule'];
241
242 $start_strtotime_str = "{$schedule['start_date']} {$schedule['start_hour']}:{$schedule['start_minute']} {$schedule['start_meridiem_offset']}";
243 $schedule['start_timestamp'] = $this->get_time_with_timezone( $start_strtotime_str );
244
245 $end_strtotime_str = "{$schedule['end_date']} {$schedule['end_hour']}:{$schedule['end_minute']} {$schedule['end_meridiem_offset']}";
246 $schedule['end_timestamp'] = $this->get_time_with_timezone( $end_strtotime_str );
247
248 $is_within_date_range = $this->check_schedule_date_range( $schedule );
249
250 // We're not within the active date ranges. Return the flags to be set.
251 if ( true !== $is_within_date_range ) {
252 return $is_within_date_range;
253 }
254
255 $check_daily_range = $this->check_schedule_daily_range( $schedule );
256
257 // There's no daily range.
258 if ( false === $check_daily_range ) {
259
260 // Run the next check at the end of the date range, if set.
261 $end_timestamp = '1' !== $schedule['not_schedule_end'] ? $schedule['end_timestamp'] : '0';
262 return array(
263 'is_currently_scheduled' => '1',
264 'check_schedule_at' => $end_timestamp,
265 );
266 }
267
268 return $check_daily_range;
269 }
270
271 /**
272 * Checks whether we're within the date range.
273 *
274 * @since 4.2.0
275 * @param array $schedule Stored 'schedule' settings.
276 * @return array|true Array if the module isn't active. True otherwise.
277 */
278 private function check_schedule_date_range( $schedule ) {
279
280 $current_time = time();
281
282 // End is scheduled.
283 if ( '1' !== $schedule['not_schedule_end'] ) {
284
285 $end_timestamp = $schedule['end_timestamp'];
286
287 // End moment already passed.
288 if ( $current_time > $end_timestamp ) {
289
290 // Skip schedule check in the future.
291 return array(
292 'is_currently_scheduled' => '0',
293 'check_schedule_at' => '0',
294 );
295 }
296 }
297
298 // Start is scheduled.
299 if ( '1' !== $schedule['not_schedule_start'] ) {
300
301 $start_timestamp = $schedule['start_timestamp'];
302
303 // Start moment hasn't passed yet.
304 if ( $current_time < $start_timestamp ) {
305
306 // Run the schedule check again then.
307 return array(
308 'is_currently_scheduled' => '0',
309 'check_schedule_at' => $start_timestamp,
310 );
311 }
312 }
313
314 return true;
315 }
316
317 /**
318 * Check out the daily time range.
319 *
320 * @since 4.2.0
321 * @param array $schedule Stored 'schedule' settings.
322 * @return array|false Array if there's a 'next check' scheduled. False otherwise.
323 */
324 private function check_schedule_daily_range( $schedule ) {
325
326 $check_day = 'all' !== $schedule['active_days'] && ! empty( $schedule['week_days'] );
327 $check_hour = '1' !== $schedule['is_active_all_day'];
328
329 // The module is displayed all day every day.
330 if ( ! $check_day && ! $check_hour ) {
331 return false;
332 }
333
334 // Get today's week day as a number between 0 (Sun) and 6 (Mon).
335 $current_time = time();
336 $todays_day = $this->get_time_with_timezone( 'now', 'w' );
337 $week_days = $schedule['week_days'];
338
339 if ( $check_day ) {
340
341 // Not displaying today.
342 if ( ! in_array( $todays_day, $week_days, true ) ) {
343
344 // Run the check again the next day it should be shown.
345 $next_check = $this->get_schedule_next_week_day_timestamp( $todays_day, $week_days );
346 return array(
347 'is_currently_scheduled' => '0',
348 'check_schedule_at' => $next_check,
349 );
350 } else {
351 // Run the check again the next day it should be hidden.
352 $next_check = $this->get_schedule_next_week_day_timestamp( $todays_day, array_diff( array( 1, 2, 3, 4, 5, 6, 7 ), $week_days ) );
353 $is_currently_scheduled = '1';
354 }
355 }
356
357 if ( $check_hour ) {
358
359 $end_strtotime_str = "{$schedule['day_end_hour']}:{$schedule['day_end_minute']} {$schedule['day_end_meridiem_offset']}";
360 $end_timestamp = $this->get_time_with_timezone( $end_strtotime_str );
361
362 $start_strtotime_str = "{$schedule['day_start_hour']}:{$schedule['day_start_minute']} {$schedule['day_start_meridiem_offset']}";
363 $start_timestamp = $this->get_time_with_timezone( $start_strtotime_str );
364
365 // If start time is greater that end time swap them.
366 $swaptime = $start_timestamp > $end_timestamp ? true : false;
367 if ( $swaptime ) {
368 // swap start time and end time.
369 list( $start_strtotime_str, $end_strtotime_str ) = array( $end_strtotime_str, $start_strtotime_str );
370 list( $start_timestamp, $end_timestamp ) = array( $end_timestamp, $start_timestamp );
371 }
372 // End time already passed.
373 if ( $current_time > $end_timestamp ) {
374
375 // Run the check again the next day it should be shown.
376 if ( $check_day ) {
377 $next_check = $this->get_schedule_next_week_day_timestamp( $todays_day, $week_days );
378 } else {
379 $next_check = $this->get_time_with_timezone( 'tomorrow ' . $start_strtotime_str );
380 }
381 return array(
382 'is_currently_scheduled' => $swaptime ? '1' : '0',
383 'check_schedule_at' => $next_check,
384 );
385 }
386
387 // Start time hasn't passed.
388 if ( $current_time < $start_timestamp ) {
389
390 // Run the check again at the time it should be shown again.
391 $next_check = $this->get_time_with_timezone( $start_strtotime_str );
392
393 return array(
394 'is_currently_scheduled' => $swaptime ? '1' : '0',
395 'check_schedule_at' => $next_check,
396 );
397 }
398
399 // Start time already passed and end time hasn't passed.
400 return array(
401 'is_currently_scheduled' => $swaptime ? '0' : '1',
402 'check_schedule_at' => $end_timestamp,
403 );
404 } elseif ( $is_currently_scheduled ) {
405 // Run the check again the next day it should be hidden.
406 return array(
407 'is_currently_scheduled' => $is_currently_scheduled,
408 'check_schedule_at' => $next_check,
409 );
410 }
411
412 return false;
413 }
414
415 /**
416 * Get the next day of the week when the module should be displayed.
417 *
418 * @since 4.2.0
419 * @param string $todays_day Today's week day as a 'w' format for date().
420 * @param array $week_days Selected weeks days for the module to be shown.
421 * @return string timestamp
422 */
423 private function get_schedule_next_week_day_timestamp( $todays_day, $week_days ) {
424
425 // Get the following week day to be displayed.
426 $next_day = false;
427 foreach ( $week_days as $day ) {
428
429 // Get the following one this week.
430 if ( intval( $day ) > intval( $todays_day ) ) {
431 $next_day = $day;
432 $strtotime_str = "Sunday last week +{$next_day} days";
433 break;
434 }
435 }
436
437 // If the next day to display isn't ahead this week, get the first selected week day.
438 if ( false === $next_day ) {
439 $next_day = $week_days[0];
440 $strtotime_str = "Sunday this week +{$next_day} days";
441 }
442
443 // Run the check again the next day it should be shown.
444 $next_check = $this->get_time_with_timezone( $strtotime_str );
445
446 return $next_check;
447 }
448
449 /**
450 * Returns the given date string as Unix timestamp according to the selected wp timezone.
451 *
452 * @since 4.2.0
453 * @param string $str Time as a human readable string.
454 * @param string $format Optional. Date format.
455 * @return string Timestamp.
456 */
457 private function get_time_with_timezone( $str = 'now', $format = 'U' ) {
458
459 $settings = $this->to_array(); // We can probably make this a property of this class.
460
461 // Using WP's selected timezone.
462 if ( 'server' === $settings['schedule']['time_to_use'] ) {
463 $timezone_string = $this->get_wp_timezone();
464
465 } else {
466 $selected_timezone = $settings['schedule']['custom_timezone'];
467 $timezone_string = $this->format_datetimezone_compatible_string( $selected_timezone );
468 }
469
470 $timezone_object = new DateTimeZone( $timezone_string );
471 // return if the passed date is wrong.
472 try {
473 $date_time_instance = new DateTime( $str, $timezone_object );
474 } catch ( Exception $e ) {
475 return '';
476 }
477 return $date_time_instance->format( $format );
478 }
479
480 /**
481 * Gets the timezone set up in WordPress settings.
482 * This timezone string is valid for the DateTimeZone constructor.
483 *
484 * @since 4.2.0
485 *
486 * @return string
487 */
488 private function get_wp_timezone() {
489
490 // Available since WP 5.3.0.
491 if ( function_exists( 'wp_timezone_string' ) ) {
492 return wp_timezone_string();
493 }
494
495 /**
496 * Copied from @see https://developer.wordpress.org/reference/functions/wp_timezone_string/
497 * This is intended for WP versions previous to 5.3.0
498 */
499 $timezone_string = get_option( 'timezone_string' );
500
501 if ( $timezone_string ) {
502 return $timezone_string;
503 }
504
505 $offset_str = get_option( 'gmt_offset' );
506 $tz_offset = $this->format_timezone_utc_offset( $offset_str );
507
508 return $tz_offset;
509 }
510
511 /**
512 * Formats a timezone string so it's compatible with DateTimeZone.
513 *
514 * @since 4.2.0
515 * @param string $timezone_string Timezone string to format.
516 * @return string
517 */
518 private function format_datetimezone_compatible_string( $timezone_string ) {
519
520 if ( '0' === $timezone_string ) {
521 $timezone_string = 'UTC';
522 }
523
524 if ( false === stripos( $timezone_string, 'UTC' ) ) {
525 return $timezone_string;
526 }
527
528 $offset_str = str_replace( 'UTC', '', $timezone_string );
529 $tz_offset = $this->format_timezone_utc_offset( $offset_str );
530
531 return $tz_offset;
532 }
533
534 /**
535 * Formats the utc offset so it's compatible with the DateTimezone constructor.
536 *
537 * @since 4.3.0
538 * @param string $offset_str UTC offset string.
539 * @return string
540 */
541 private function format_timezone_utc_offset( $offset_str ) {
542
543 $offset = (float) $offset_str;
544 $hours = (int) $offset;
545 $minutes = ( $offset - $hours );
546
547 $sign = ( $offset < 0 ) ? '-' : '+';
548 $abs_hour = abs( $hours );
549 $abs_mins = abs( $minutes * 60 );
550 $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
551
552 return $tz_offset;
553 }
554
555 /**
556 * Check this module schedule has finished or not
557 * Return true if schedule finished false otherwise
558 *
559 * @since 4.4.6
560 * @return boolean
561 */
562 public function is_schedule_finished() {
563 $settings = $this->to_array();
564 $schedule = $settings['schedule'];
565
566 // If schedule is not enabled.
567 if ( '0' === $settings['is_schedule'] ) {
568 return false;
569 }
570
571 // If `Never end the schedule` option is enabled.
572 if ( '1' === $schedule['not_schedule_end'] ) {
573 return false;
574 }
575
576 $end_time_string = "{$schedule['end_date']} {$schedule['end_hour']}:{$schedule['end_minute']} {$schedule['end_meridiem_offset']}";
577 $end_timestamp = $this->get_time_with_timezone( $end_time_string );
578
579 // If time of today is already passed, then return true.
580 return ( time() > $end_timestamp );
581 }
582
583 /**
584 * Return true if schedule is between start and end date
585 *
586 * @since 4.4.6
587 * @return boolean
588 */
589 public function is_between_start_and_end_date() {
590 $settings = $this->to_array();
591 $schedule = $settings['schedule'];
592
593 // If schedule is not enabled.
594 if ( '0' === $settings['is_schedule'] ) {
595 return false;
596 }
597
598 $start_time_string = "{$schedule['start_date']} {$schedule['start_hour']}:{$schedule['start_minute']} {$schedule['start_meridiem_offset']}";
599 $start_timestamp = $this->get_time_with_timezone( $start_time_string );
600
601 $end_time_string = "{$schedule['end_date']} {$schedule['end_hour']}:{$schedule['end_minute']} {$schedule['end_meridiem_offset']}";
602 $end_timestamp = $this->get_time_with_timezone( $end_time_string );
603
604 // If time has been started but not finished, then return true.
605 return ( time() >= $start_timestamp && time() <= $end_timestamp );
606 }
607 }
608