← All changes
|
includes/extensions/Fomo_Notifications/Fomo_Notifications.php
+551
-94
51.1.44
→
51.1.86
View file →
| @@ -182,32 +182,79 @@ | ||
| 182 | 182 | * @return void |
| 183 | 183 | */ |
| 184 | 184 | public function register_post_meta(): void |
| 185 | 185 | { |
| 186 | - $meta_fields = [ | |
| 186 | + // Simple string fields | |
| 187 | + $string_fields = [ | |
| 187 | 188 | '_kng_fomo_status', |
| 188 | 189 | '_kng_fomo_type', |
| 189 | 190 | '_kng_fomo_source', |
| 191 | + ]; | |
| 192 | + | |
| 193 | + foreach ($string_fields as $meta_key) { | |
| 194 | + register_post_meta(self::POST_TYPE, $meta_key, [ | |
| 195 | + 'type' => 'string', | |
| 196 | + 'single' => true, | |
| 197 | + 'show_in_rest' => false, | |
| 198 | + 'sanitize_callback' => 'sanitize_text_field', | |
| 199 | + ]); | |
| 200 | + } | |
| 201 | + | |
| 202 | + // JSON fields — sanitize_text_field would break JSON, so use a custom callback | |
| 203 | + $json_fields = [ | |
| 190 | 204 | '_kng_fomo_source_config', |
| 191 | 205 | '_kng_fomo_design', |
| 192 | 206 | '_kng_fomo_content', |
| 193 | 207 | '_kng_fomo_display', |
| 194 | 208 | '_kng_fomo_customize', |
| 209 | + ]; | |
| 210 | + | |
| 211 | + foreach ($json_fields as $meta_key) { | |
| 212 | + register_post_meta(self::POST_TYPE, $meta_key, [ | |
| 213 | + 'type' => 'string', | |
| 214 | + 'single' => true, | |
| 215 | + 'show_in_rest' => false, | |
| 216 | + 'sanitize_callback' => [$this, 'sanitize_json_meta'], | |
| 217 | + ]); | |
| 218 | + } | |
| 219 | + | |
| 220 | + // Numeric fields | |
| 221 | + $numeric_fields = [ | |
| 195 | 222 | '_kng_fomo_views', |
| 196 | 223 | '_kng_fomo_clicks', |
| 197 | 224 | ]; |
| 198 | 225 | |
| 199 | - foreach ($meta_fields as $meta_key) { | |
| 226 | + foreach ($numeric_fields as $meta_key) { | |
| 200 | 227 | register_post_meta(self::POST_TYPE, $meta_key, [ |
| 201 | 228 | 'type' => 'string', |
| 202 | 229 | 'single' => true, |
| 203 | 230 | 'show_in_rest' => false, |
| 204 | - 'sanitize_callback' => 'sanitize_text_field', | |
| 231 | + 'sanitize_callback' => 'absint', | |
| 205 | 232 | ]); |
| 206 | 233 | } |
| 207 | 234 | } |
| 208 | 235 | |
| 209 | 236 | /** |
| 237 | + * Sanitize JSON meta value | |
| 238 | + * | |
| 239 | + * @param mixed $value The value to sanitize | |
| 240 | + * @return string | |
| 241 | + */ | |
| 242 | + public function sanitize_json_meta($value): string | |
| 243 | + { | |
| 244 | + if (is_string($value)) { | |
| 245 | + $decoded = json_decode($value, true); | |
| 246 | + if (json_last_error() === JSON_ERROR_NONE) { | |
| 247 | + return wp_json_encode($decoded); | |
| 248 | + } | |
| 249 | + } | |
| 250 | + if (is_array($value)) { | |
| 251 | + return wp_json_encode($value); | |
| 252 | + } | |
| 253 | + return '{}'; | |
| 254 | + } | |
| 255 | + | |
| 256 | + /** | |
| 210 | 257 | * Maybe create stats table (runs once) |
| 211 | 258 | * |
| 212 | 259 | * @return void |
| 213 | 260 | */ |
| @@ -315,8 +362,19 @@ | ||
| 315 | 362 | 'listUrl' => admin_url('admin.php?page=king-addons-fomo&view=list'), |
| 316 | 363 | 'hasPro' => self::hasPro(), |
| 317 | 364 | 'freeLimit' => self::FREE_LIMIT, |
| 318 | 365 | 'upgradeUrl' => 'https://kingaddons.com/pricing/?utm_source=kng-fomo-notifications&utm_medium=plugin', |
| 366 | + 'typeDefaults' => [ | |
| 367 | + 'notification_bar' => self::get_type_defaults('notification_bar'), | |
| 368 | + 'woocommerce_sales' => self::get_type_defaults('woocommerce_sales'), | |
| 369 | + 'wordpress_comments' => self::get_type_defaults('wordpress_comments'), | |
| 370 | + 'wporg_downloads' => self::get_type_defaults('wporg_downloads'), | |
| 371 | + 'reviews' => self::get_type_defaults('reviews'), | |
| 372 | + 'email_subscription' => self::get_type_defaults('email_subscription'), | |
| 373 | + 'donations' => self::get_type_defaults('donations'), | |
| 374 | + 'flashing_tab' => self::get_type_defaults('flashing_tab'), | |
| 375 | + 'custom_csv' => self::get_type_defaults('custom_csv'), | |
| 376 | + ], | |
| 319 | 377 | 'i18n' => [ |
| 320 | 378 | 'confirmDelete' => __('Are you sure you want to delete this notification?', 'king-addons'), |
| 321 | 379 | 'saved' => __('Notification saved successfully!', 'king-addons'), |
| 322 | 380 | 'deleted' => __('Notification deleted.', 'king-addons'), |
| @@ -340,9 +398,10 @@ | ||
| 340 | 398 | */ |
| 341 | 399 | public function enqueue_frontend_assets(): void |
| 342 | 400 | { |
| 343 | 401 | // Check if there are active notifications for current page |
| 344 | - if (!$this->has_active_notifications()) { | |
| 402 | + $notifications = $this->get_active_notifications_for_page(); | |
| 403 | + if (empty($notifications)) { | |
| 345 | 404 | return; |
| 346 | 405 | } |
| 347 | 406 | |
| 348 | 407 | wp_enqueue_style( |
| @@ -354,16 +413,33 @@ | ||
| 354 | 413 | |
| 355 | 414 | wp_enqueue_script( |
| 356 | 415 | 'kng-fomo-frontend', |
| 357 | 416 | $this->url . 'assets/frontend.js', |
| 358 | - ['jquery'], | |
| 417 | + [], | |
| 359 | 418 | self::VERSION, |
| 360 | 419 | true |
| 361 | 420 | ); |
| 362 | 421 | |
| 363 | - wp_localize_script('kng-fomo-frontend', 'kngFomoFrontend', [ | |
| 422 | + // Prepare notifications data for JS | |
| 423 | + $notifications_data = []; | |
| 424 | + $settings = $this->get_settings(); | |
| 425 | + foreach ($notifications as $notification) { | |
| 426 | + $notifications_data[] = $this->prepare_notification_for_frontend($notification); | |
| 427 | + } | |
| 428 | + | |
| 429 | + wp_localize_script('kng-fomo-frontend', 'kngFomoData', [ | |
| 364 | 430 | 'ajaxUrl' => admin_url('admin-ajax.php'), |
| 365 | 431 | 'nonce' => wp_create_nonce('kng_fomo_frontend'), |
| 432 | + 'notifications' => $notifications_data, | |
| 433 | + 'settings' => [ | |
| 434 | + 'position' => 'bottom-left', | |
| 435 | + 'delayBefore' => 5, | |
| 436 | + 'displayFor' => 5, | |
| 437 | + 'delayBetween' => 5, | |
| 438 | + 'sessionLimit' => 0, | |
| 439 | + 'soundVolume' => (int)($settings['sound_volume'] ?? 50), | |
| 440 | + 'loop' => true, | |
| 441 | + ], | |
| 366 | 442 | ]); |
| 367 | 443 | } |
| 368 | 444 | |
| 369 | 445 | /** |
| @@ -394,12 +470,12 @@ | ||
| 394 | 470 | $notification_count = count($notifications); |
| 395 | 471 | $at_limit = !$has_pro && $notification_count >= self::FREE_LIMIT; |
| 396 | 472 | $settings = $this->get_settings(); |
| 397 | 473 | $notification = null; |
| 398 | - $is_edit = $view === 'edit'; | |
| 474 | + $is_edit = ($view === 'edit' || ($view === 'wizard' && isset($_GET['edit']))); | |
| 399 | 475 | |
| 400 | - if ($is_edit && isset($_GET['id'])) { | |
| 401 | - $notification = $this->get_notification((int)$_GET['id']); | |
| 476 | + if ($is_edit && isset($_GET['edit'])) { | |
| 477 | + $notification = $this->get_notification((int)$_GET['edit']); | |
| 402 | 478 | } |
| 403 | 479 | |
| 404 | 480 | include $template_path; |
| 405 | 481 | } |
| @@ -473,9 +549,9 @@ | ||
| 473 | 549 | return [ |
| 474 | 550 | 'id' => $post->ID, |
| 475 | 551 | 'title' => $post->post_title, |
| 476 | 552 | 'status' => get_post_meta($post->ID, '_kng_fomo_status', true) ?: 'disabled', |
| 477 | - 'type' => get_post_meta($post->ID, '_kng_fomo_type', true) ?: 'notification-bar', | |
| 553 | + 'type' => get_post_meta($post->ID, '_kng_fomo_type', true) ?: 'notification_bar', | |
| 478 | 554 | 'source' => get_post_meta($post->ID, '_kng_fomo_source', true) ?: 'manual', |
| 479 | 555 | 'source_config' => json_decode(get_post_meta($post->ID, '_kng_fomo_source_config', true) ?: '{}', true), |
| 480 | 556 | 'design' => json_decode(get_post_meta($post->ID, '_kng_fomo_design', true) ?: '{}', true), |
| 481 | 557 | 'content' => json_decode(get_post_meta($post->ID, '_kng_fomo_content', true) ?: '{}', true), |
| @@ -500,23 +576,21 @@ | ||
| 500 | 576 | 'enabled' => true, |
| 501 | 577 | 'tracking_enabled' => true, |
| 502 | 578 | 'track_for' => 'everyone', |
| 503 | 579 | 'exclude_bots' => true, |
| 504 | - 'cache_ttl' => 3600, | |
| 580 | + 'cache_ttl' => 300, | |
| 581 | + 'anonymize_names' => false, | |
| 582 | + 'sound_volume' => 50, | |
| 505 | 583 | 'modules' => [ |
| 506 | - 'notification-bar' => true, | |
| 507 | - 'woocommerce-sales' => true, | |
| 508 | - 'wordpress-comments' => true, | |
| 509 | - 'wporg-downloads' => true, | |
| 510 | - 'wporg-reviews' => false, | |
| 511 | - 'google-reviews' => false, | |
| 512 | - 'email-subscription' => false, | |
| 513 | - 'elearning' => false, | |
| 584 | + 'notification_bar' => true, | |
| 585 | + 'woocommerce_sales' => true, | |
| 586 | + 'wordpress_comments' => true, | |
| 587 | + 'wporg_downloads' => true, | |
| 588 | + 'reviews' => false, | |
| 589 | + 'email_subscription' => false, | |
| 514 | 590 | 'donations' => false, |
| 515 | - 'discount-alert' => false, | |
| 516 | - 'flashing-tab' => false, | |
| 517 | - 'custom-csv' => false, | |
| 518 | - 'page-analytics' => false, | |
| 591 | + 'flashing_tab' => false, | |
| 592 | + 'custom_csv' => false, | |
| 519 | 593 | ], |
| 520 | 594 | ]; |
| 521 | 595 | |
| 522 | 596 | $saved = get_option('kng_fomo_settings', []); |
| @@ -534,24 +608,8 @@ | ||
| 534 | 608 | return update_option('kng_fomo_settings', $settings); |
| 535 | 609 | } |
| 536 | 610 | |
| 537 | 611 | /** |
| 538 | - * Check if there are active notifications for current page | |
| 539 | - * | |
| 540 | - * @return bool | |
| 541 | - */ | |
| 542 | - private function has_active_notifications(): bool | |
| 543 | - { | |
| 544 | - $settings = $this->get_settings(); | |
| 545 | - if (empty($settings['enabled'])) { | |
| 546 | - return false; | |
| 547 | - } | |
| 548 | - | |
| 549 | - $notifications = $this->get_active_notifications_for_page(); | |
| 550 | - return !empty($notifications); | |
| 551 | - } | |
| 552 | - | |
| 553 | - /** | |
| 554 | 612 | * Get active notifications that should display on current page |
| 555 | 613 | * |
| 556 | 614 | * @return array |
| 557 | 615 | */ |
| @@ -588,9 +646,9 @@ | ||
| 588 | 646 | if (!$this->check_device_visibility($visibility)) { |
| 589 | 647 | return false; |
| 590 | 648 | } |
| 591 | 649 | |
| 592 | - // Check show_on rules | |
| 650 | + // Legacy show_on rules | |
| 593 | 651 | $show_on = $display['show_on'] ?? 'everywhere'; |
| 594 | 652 | if ($show_on === 'include' && !empty($display['include_pages'])) { |
| 595 | 653 | if (!$this->is_current_page_in_list($display['include_pages'])) { |
| 596 | 654 | return false; |
| @@ -600,13 +658,49 @@ | ||
| 600 | 658 | return false; |
| 601 | 659 | } |
| 602 | 660 | } |
| 603 | 661 | |
| 604 | - // Check display_for (audience) | |
| 605 | - $display_for = $display['display_for'] ?? 'everyone'; | |
| 606 | - if ($display_for === 'guests' && is_user_logged_in()) { | |
| 662 | + // Wizard page rules: pages + page_rules | |
| 663 | + $pages_mode = $display['pages'] ?? 'all'; | |
| 664 | + if ($pages_mode === 'specific') { | |
| 665 | + $page_rules = $display['page_rules'] ?? []; | |
| 666 | + if (is_array($page_rules) && !empty($page_rules)) { | |
| 667 | + $has_include = false; | |
| 668 | + $include_matched = false; | |
| 669 | + | |
| 670 | + foreach ($page_rules as $rule) { | |
| 671 | + if (!is_array($rule)) { | |
| 672 | + continue; | |
| 673 | + } | |
| 674 | + | |
| 675 | + $type = sanitize_text_field((string)($rule['type'] ?? 'include')); | |
| 676 | + $matched = $this->match_page_rule($rule); | |
| 677 | + | |
| 678 | + if ($type === 'exclude' && $matched) { | |
| 679 | + return false; | |
| 680 | + } | |
| 681 | + | |
| 682 | + if ($type === 'include') { | |
| 683 | + $has_include = true; | |
| 684 | + if ($matched) { | |
| 685 | + $include_matched = true; | |
| 686 | + } | |
| 687 | + } | |
| 688 | + } | |
| 689 | + | |
| 690 | + if ($has_include && !$include_matched) { | |
| 691 | + return false; | |
| 692 | + } | |
| 693 | + } | |
| 694 | + } | |
| 695 | + | |
| 696 | + // Check display_for / audience (supports both legacy and wizard keys) | |
| 697 | + $display_for = $display['display_for'] ?? ($display['audience'] ?? 'everyone'); | |
| 698 | + | |
| 699 | + if (($display_for === 'guests' || $display_for === 'logged_out') && is_user_logged_in()) { | |
| 607 | 700 | return false; |
| 608 | 701 | } |
| 702 | + | |
| 609 | 703 | if ($display_for === 'logged_in' && !is_user_logged_in()) { |
| 610 | 704 | return false; |
| 611 | 705 | } |
| 612 | 706 | |
| @@ -613,8 +707,53 @@ | ||
| 613 | 707 | return true; |
| 614 | 708 | } |
| 615 | 709 | |
| 616 | 710 | /** |
| 711 | + * Match a single wizard page rule against current request | |
| 712 | + * | |
| 713 | + * @param array $rule Page rule | |
| 714 | + * @return bool | |
| 715 | + */ | |
| 716 | + private function match_page_rule(array $rule): bool | |
| 717 | + { | |
| 718 | + $condition = sanitize_text_field((string)($rule['condition'] ?? 'url_contains')); | |
| 719 | + $value = trim((string)($rule['value'] ?? '')); | |
| 720 | + | |
| 721 | + if ($value === '') { | |
| 722 | + return false; | |
| 723 | + } | |
| 724 | + | |
| 725 | + if ($condition === 'page' || $condition === 'post') { | |
| 726 | + if (is_numeric($value)) { | |
| 727 | + return ((int)get_queried_object_id()) === (int)$value; | |
| 728 | + } | |
| 729 | + return false; | |
| 730 | + } | |
| 731 | + | |
| 732 | + $request_uri = isset($_SERVER['REQUEST_URI']) ? wp_unslash((string)$_SERVER['REQUEST_URI']) : ''; | |
| 733 | + $current_url = strtolower(home_url($request_uri)); | |
| 734 | + $needle = strtolower($value); | |
| 735 | + | |
| 736 | + if ($condition === 'url_is') { | |
| 737 | + // Exact full URL | |
| 738 | + if ($current_url === $needle) { | |
| 739 | + return true; | |
| 740 | + } | |
| 741 | + | |
| 742 | + // Exact path (with or without leading slash) | |
| 743 | + $current_path = strtolower((string)wp_parse_url($current_url, PHP_URL_PATH)); | |
| 744 | + $needle_path = strtolower((string)wp_parse_url($needle, PHP_URL_PATH)); | |
| 745 | + if ($needle_path === '' && strpos($needle, '/') === false) { | |
| 746 | + $needle_path = '/' . ltrim($needle, '/'); | |
| 747 | + } | |
| 748 | + return $needle_path !== '' && $current_path === $needle_path; | |
| 749 | + } | |
| 750 | + | |
| 751 | + // Default: url_contains | |
| 752 | + return strpos($current_url, $needle) !== false; | |
| 753 | + } | |
| 754 | + | |
| 755 | + /** | |
| 617 | 756 | * Check device visibility based on screen width |
| 618 | 757 | * |
| 619 | 758 | * @param array $visibility Visibility settings |
| 620 | 759 | * @return bool |
| @@ -643,20 +782,16 @@ | ||
| 643 | 782 | * @return void |
| 644 | 783 | */ |
| 645 | 784 | public function render_notifications(): void |
| 646 | 785 | { |
| 786 | + // Notifications data is passed via wp_localize_script in enqueue_frontend_assets(). | |
| 787 | + // This method only outputs the container div for popup notifications. | |
| 647 | 788 | $notifications = $this->get_active_notifications_for_page(); |
| 648 | 789 | if (empty($notifications)) { |
| 649 | 790 | return; |
| 650 | 791 | } |
| 651 | 792 | |
| 652 | - // Prepare notifications data for JS | |
| 653 | - $notifications_data = []; | |
| 654 | - foreach ($notifications as $notification) { | |
| 655 | - $notifications_data[] = $this->prepare_notification_for_frontend($notification); | |
| 656 | - } | |
| 657 | - | |
| 658 | - echo '<div id="kng-fomo-container" data-notifications="' . esc_attr(wp_json_encode($notifications_data)) . '"></div>'; | |
| 793 | + echo '<div id="kng-fomo-container"></div>'; | |
| 659 | 794 | } |
| 660 | 795 | |
| 661 | 796 | /** |
| 662 | 797 | * Prepare notification data for frontend rendering |
| @@ -666,19 +801,244 @@ | ||
| 666 | 801 | */ |
| 667 | 802 | private function prepare_notification_for_frontend(array $notification): array |
| 668 | 803 | { |
| 669 | 804 | $content = $this->get_notification_content($notification); |
| 805 | + $design = $notification['design']; | |
| 806 | + $customize = $notification['customize']; | |
| 807 | + $display = $notification['display']; | |
| 670 | 808 | |
| 809 | + // Ensure loop is always set (default true for cycling) | |
| 810 | + if (!isset($display['loop'])) { | |
| 811 | + $display['loop'] = true; | |
| 812 | + } | |
| 813 | + | |
| 671 | 814 | return [ |
| 672 | 815 | 'id' => $notification['id'], |
| 673 | 816 | 'type' => $notification['type'], |
| 674 | - 'design' => $notification['design'], | |
| 817 | + 'design' => $design, | |
| 675 | 818 | 'content' => $content, |
| 676 | - 'customize' => $notification['customize'], | |
| 819 | + 'customize' => $customize, | |
| 820 | + 'display' => $display, | |
| 821 | + // Flat fields for frontend.js convenience | |
| 822 | + 'title' => $content['title'] ?? '', | |
| 823 | + 'message' => $content['message'] ?? '', | |
| 824 | + 'image' => $content['image'] ?? '', | |
| 825 | + 'image_style' => $content['image_type'] ?? 'product', | |
| 826 | + 'time_text' => $content['time_text'] ?? '', | |
| 827 | + 'cta_text' => $content['cta_text'] ?? '', | |
| 828 | + 'cta_url' => $content['cta_url'] ?? '', | |
| 829 | + 'click_url' => ($customize['click_action'] ?? 'link') === 'link' ? ($content['cta_url'] ?? '') : '', | |
| 830 | + 'click_target' => '_self', | |
| 831 | + 'bg_color' => $design['bg_color'] ?? '#ffffff', | |
| 832 | + 'text_color' => $design['text_color'] ?? '#1d1d1f', | |
| 833 | + 'accent_color' => $design['accent_color'] ?? '#0071e3', | |
| 834 | + 'animation' => $design['animation'] ?? 'slide', | |
| 835 | + 'display_time' => (($display['duration'] ?? 5) * 1000), | |
| 836 | + 'sound' => !empty($customize['sound']) ? 'pop' : false, | |
| 837 | + 'device' => 'all', | |
| 838 | + 'bar_position' => $design['position'] ?? 'top', | |
| 839 | + 'page_rules' => $display['page_rules'] ?? null, | |
| 840 | + // Items for dynamic notifications (WooCommerce, comments, etc.) | |
| 841 | + 'items' => $content['items'] ?? [], | |
| 677 | 842 | ]; |
| 678 | 843 | } |
| 679 | 844 | |
| 680 | 845 | /** |
| 846 | + * Get default content templates and source config for a notification type. | |
| 847 | + * | |
| 848 | + * These are used when the user hasn't provided custom templates, and as | |
| 849 | + * fallback data when real sources return empty. | |
| 850 | + * | |
| 851 | + * @param string $type Notification type | |
| 852 | + * @return array { content_defaults: array, source_config_defaults: array, fallback_items: array } | |
| 853 | + */ | |
| 854 | + public static function get_type_defaults(string $type): array | |
| 855 | + { | |
| 856 | + $defaults = [ | |
| 857 | + 'notification_bar' => [ | |
| 858 | + 'content_defaults' => [ | |
| 859 | + 'title' => '', | |
| 860 | + 'message' => '', | |
| 861 | + ], | |
| 862 | + 'source_config_defaults' => [], | |
| 863 | + 'fallback_items' => [], | |
| 864 | + ], | |
| 865 | + 'woocommerce_sales' => [ | |
| 866 | + 'content_defaults' => [ | |
| 867 | + 'title' => '{{name}}', | |
| 868 | + 'message' => 'just purchased {{product}}', | |
| 869 | + ], | |
| 870 | + 'source_config_defaults' => [ | |
| 871 | + 'order_status' => 'any', | |
| 872 | + 'time_range' => '7d', | |
| 873 | + 'limit' => 10, | |
| 874 | + ], | |
| 875 | + 'fallback_items' => [ | |
| 876 | + [ | |
| 877 | + 'username' => 'Sarah', | |
| 878 | + 'product' => 'Premium Bundle', | |
| 879 | + 'product_url' => '#', | |
| 880 | + 'product_image' => '', | |
| 881 | + 'location' => 'New York, US', | |
| 882 | + 'time' => time() - 180, | |
| 883 | + 'time_ago' => '3 mins ago', | |
| 884 | + ], | |
| 885 | + [ | |
| 886 | + 'username' => 'Michael', | |
| 887 | + 'product' => 'Starter Pack', | |
| 888 | + 'product_url' => '#', | |
| 889 | + 'product_image' => '', | |
| 890 | + 'location' => 'London, UK', | |
| 891 | + 'time' => time() - 720, | |
| 892 | + 'time_ago' => '12 mins ago', | |
| 893 | + ], | |
| 894 | + [ | |
| 895 | + 'username' => 'Emma', | |
| 896 | + 'product' => 'Annual Plan', | |
| 897 | + 'product_url' => '#', | |
| 898 | + 'product_image' => '', | |
| 899 | + 'location' => 'Toronto, CA', | |
| 900 | + 'time' => time() - 1800, | |
| 901 | + 'time_ago' => '30 mins ago', | |
| 902 | + ], | |
| 903 | + [ | |
| 904 | + 'username' => 'James', | |
| 905 | + 'product' => 'Pro License', | |
| 906 | + 'product_url' => '#', | |
| 907 | + 'product_image' => '', | |
| 908 | + 'location' => 'Sydney, AU', | |
| 909 | + 'time' => time() - 3600, | |
| 910 | + 'time_ago' => '1 hour ago', | |
| 911 | + ], | |
| 912 | + [ | |
| 913 | + 'username' => 'Lisa', | |
| 914 | + 'product' => 'Business Suite', | |
| 915 | + 'product_url' => '#', | |
| 916 | + 'product_image' => '', | |
| 917 | + 'location' => 'Berlin, DE', | |
| 918 | + 'time' => time() - 7200, | |
| 919 | + 'time_ago' => '2 hours ago', | |
| 920 | + ], | |
| 921 | + ], | |
| 922 | + ], | |
| 923 | + 'wordpress_comments' => [ | |
| 924 | + 'content_defaults' => [ | |
| 925 | + 'title' => '{{name}}', | |
| 926 | + 'message' => 'commented on {{product}}', | |
| 927 | + ], | |
| 928 | + 'source_config_defaults' => [ | |
| 929 | + 'post_types' => ['post'], | |
| 930 | + 'comments_count' => 10, | |
| 931 | + ], | |
| 932 | + 'fallback_items' => [ | |
| 933 | + [ | |
| 934 | + 'username' => 'Alex', | |
| 935 | + 'content' => 'Great article! Very helpful.', | |
| 936 | + 'post_title' => 'Getting Started Guide', | |
| 937 | + 'post_url' => '#', | |
| 938 | + 'avatar' => '', | |
| 939 | + 'time' => time() - 300, | |
| 940 | + 'time_ago' => '5 mins ago', | |
| 941 | + ], | |
| 942 | + [ | |
| 943 | + 'username' => 'Maria', | |
| 944 | + 'content' => 'Thanks for sharing this!', | |
| 945 | + 'post_title' => 'Tips & Tricks', | |
| 946 | + 'post_url' => '#', | |
| 947 | + 'avatar' => '', | |
| 948 | + 'time' => time() - 900, | |
| 949 | + 'time_ago' => '15 mins ago', | |
| 950 | + ], | |
| 951 | + [ | |
| 952 | + 'username' => 'David', | |
| 953 | + 'content' => 'Exactly what I was looking for.', | |
| 954 | + 'post_title' => 'Complete Tutorial', | |
| 955 | + 'post_url' => '#', | |
| 956 | + 'avatar' => '', | |
| 957 | + 'time' => time() - 2700, | |
| 958 | + 'time_ago' => '45 mins ago', | |
| 959 | + ], | |
| 960 | + ], | |
| 961 | + ], | |
| 962 | + 'wporg_downloads' => [ | |
| 963 | + 'content_defaults' => [ | |
| 964 | + 'title' => '{{name}}', | |
| 965 | + 'message' => '{{active_installs}} active installs', | |
| 966 | + ], | |
| 967 | + 'source_config_defaults' => [ | |
| 968 | + 'wporg_slug' => '', | |
| 969 | + 'wporg_type' => 'plugin', | |
| 970 | + 'data_type' => 'downloads', | |
| 971 | + ], | |
| 972 | + 'fallback_items' => [], | |
| 973 | + ], | |
| 974 | + 'reviews' => [ | |
| 975 | + 'content_defaults' => [ | |
| 976 | + 'title' => '{{name}}', | |
| 977 | + 'message' => 'left a review on {{product}}', | |
| 978 | + ], | |
| 979 | + 'source_config_defaults' => [], | |
| 980 | + 'fallback_items' => [ | |
| 981 | + [ | |
| 982 | + 'username' => 'John', | |
| 983 | + 'product' => 'Premium Plugin', | |
| 984 | + 'post_title' => 'Premium Plugin', | |
| 985 | + 'product_url' => '#', | |
| 986 | + 'avatar' => '', | |
| 987 | + 'time' => time() - 600, | |
| 988 | + 'time_ago' => '10 mins ago', | |
| 989 | + ], | |
| 990 | + ], | |
| 991 | + ], | |
| 992 | + 'email_subscription' => [ | |
| 993 | + 'content_defaults' => [ | |
| 994 | + 'title' => '{{name}}', | |
| 995 | + 'message' => 'just subscribed to the newsletter', | |
| 996 | + ], | |
| 997 | + 'source_config_defaults' => [], | |
| 998 | + 'fallback_items' => [ | |
| 999 | + [ | |
| 1000 | + 'username' => 'Subscriber', | |
| 1001 | + 'email' => '[email protected]', | |
| 1002 | + 'avatar' => '', | |
| 1003 | + 'time' => time() - 120, | |
| 1004 | + 'time_ago' => '2 mins ago', | |
| 1005 | + ], | |
| 1006 | + ], | |
| 1007 | + ], | |
| 1008 | + 'donations' => [ | |
| 1009 | + 'content_defaults' => [ | |
| 1010 | + 'title' => '{{name}}', | |
| 1011 | + 'message' => 'just donated', | |
| 1012 | + ], | |
| 1013 | + 'source_config_defaults' => [], | |
| 1014 | + 'fallback_items' => [ | |
| 1015 | + [ | |
| 1016 | + 'username' => 'Donor', | |
| 1017 | + 'product' => '$25', | |
| 1018 | + 'time' => time() - 240, | |
| 1019 | + 'time_ago' => '4 mins ago', | |
| 1020 | + ], | |
| 1021 | + ], | |
| 1022 | + ], | |
| 1023 | + 'custom_csv' => [ | |
| 1024 | + 'content_defaults' => [ | |
| 1025 | + 'title' => '{{name}}', | |
| 1026 | + 'message' => '{{content}}', | |
| 1027 | + ], | |
| 1028 | + 'source_config_defaults' => [], | |
| 1029 | + 'fallback_items' => [], | |
| 1030 | + ], | |
| 1031 | + ]; | |
| 1032 | + | |
| 1033 | + return $defaults[$type] ?? [ | |
| 1034 | + 'content_defaults' => ['title' => '', 'message' => ''], | |
| 1035 | + 'source_config_defaults' => [], | |
| 1036 | + 'fallback_items' => [], | |
| 1037 | + ]; | |
| 1038 | + } | |
| 1039 | + | |
| 1040 | + /** | |
| 681 | 1041 | * Get notification content with dynamic data |
| 682 | 1042 | * |
| 683 | 1043 | * @param array $notification Notification data |
| 684 | 1044 | * @return array |
| @@ -686,19 +1046,46 @@ | ||
| 686 | 1046 | private function get_notification_content(array $notification): array |
| 687 | 1047 | { |
| 688 | 1048 | $content = $notification['content']; |
| 689 | 1049 | $source = $notification['source']; |
| 1050 | + $type = $notification['type']; | |
| 690 | 1051 | $source_config = $notification['source_config']; |
| 691 | 1052 | |
| 692 | - // For dynamic sources, fetch data | |
| 693 | - if ($source === 'woocommerce') { | |
| 694 | - $content['items'] = $this->get_woocommerce_data($source_config); | |
| 695 | - } elseif ($source === 'comments') { | |
| 696 | - $content['items'] = $this->get_comments_data($source_config); | |
| 697 | - } elseif ($source === 'wporg') { | |
| 698 | - $content['items'] = $this->get_wporg_data($source_config); | |
| 1053 | + // Overlay type-specific content defaults when user hasn't provided templates. | |
| 1054 | + $type_defaults = self::get_type_defaults($type); | |
| 1055 | + $cd = $type_defaults['content_defaults']; | |
| 1056 | + | |
| 1057 | + // If title doesn't contain a {{placeholder}}, overlay the type default | |
| 1058 | + if (!empty($cd['title']) && (empty($content['title']) || strpos($content['title'], '{{') === false)) { | |
| 1059 | + $content['title'] = $cd['title']; | |
| 699 | 1060 | } |
| 1061 | + if (!empty($cd['message']) && (empty($content['message']) || strpos($content['message'], '{{') === false)) { | |
| 1062 | + $content['message'] = $cd['message']; | |
| 1063 | + } | |
| 700 | 1064 | |
| 1065 | + // For dynamic sources, fetch real data. | |
| 1066 | + // The wizard sets source = type, so we match both legacy and current values. | |
| 1067 | + $items = []; | |
| 1068 | + if ($source === 'woocommerce' || $source === 'woocommerce_sales' || $type === 'woocommerce_sales') { | |
| 1069 | + $items = $this->get_woocommerce_data($source_config); | |
| 1070 | + } elseif ($source === 'comments' || $source === 'wordpress_comments' || $type === 'wordpress_comments') { | |
| 1071 | + $items = $this->get_comments_data($source_config); | |
| 1072 | + } elseif ($source === 'wporg' || $source === 'wporg_downloads' || $type === 'wporg_downloads') { | |
| 1073 | + $items = $this->get_wporg_data($source_config); | |
| 1074 | + } | |
| 1075 | + | |
| 1076 | + // Fallback: use demo/sample items when real source returned nothing | |
| 1077 | + if (empty($items) && !empty($type_defaults['fallback_items'])) { | |
| 1078 | + $items = $type_defaults['fallback_items']; | |
| 1079 | + // Mark as demo data so frontend can optionally indicate it | |
| 1080 | + foreach ($items as &$item) { | |
| 1081 | + $item['_demo'] = true; | |
| 1082 | + } | |
| 1083 | + unset($item); | |
| 1084 | + } | |
| 1085 | + | |
| 1086 | + $content['items'] = $items; | |
| 1087 | + | |
| 701 | 1088 | return $content; |
| 702 | 1089 | } |
| 703 | 1090 | |
| 704 | 1091 | /** |
| @@ -712,14 +1099,35 @@ | ||
| 712 | 1099 | if (!class_exists('WooCommerce')) { |
| 713 | 1100 | return []; |
| 714 | 1101 | } |
| 715 | 1102 | |
| 716 | - $limit = $config['limit'] ?? 10; | |
| 717 | - $days = $config['days'] ?? 7; | |
| 1103 | + $limit = (int)($config['limit'] ?? 10); | |
| 718 | 1104 | |
| 1105 | + $days = isset($config['days']) ? (int)$config['days'] : 0; | |
| 1106 | + if ($days <= 0 && !empty($config['time_range'])) { | |
| 1107 | + $time_range = sanitize_text_field((string)$config['time_range']); | |
| 1108 | + $days_map = [ | |
| 1109 | + '24h' => 1, | |
| 1110 | + '7d' => 7, | |
| 1111 | + '30d' => 30, | |
| 1112 | + ]; | |
| 1113 | + $days = $days_map[$time_range] ?? 7; | |
| 1114 | + } | |
| 1115 | + if ($days <= 0) { | |
| 1116 | + $days = 7; | |
| 1117 | + } | |
| 1118 | + | |
| 1119 | + $order_status = sanitize_text_field((string)($config['order_status'] ?? 'any')); | |
| 1120 | + $status = ['wc-completed', 'wc-processing']; | |
| 1121 | + if ($order_status === 'completed') { | |
| 1122 | + $status = ['wc-completed']; | |
| 1123 | + } elseif ($order_status === 'processing') { | |
| 1124 | + $status = ['wc-processing']; | |
| 1125 | + } | |
| 1126 | + | |
| 719 | 1127 | $args = [ |
| 720 | 1128 | 'limit' => $limit, |
| 721 | - 'status' => ['wc-completed', 'wc-processing'], | |
| 1129 | + 'status' => $status, | |
| 722 | 1130 | 'date_created' => '>' . (time() - ($days * DAY_IN_SECONDS)), |
| 723 | 1131 | 'orderby' => 'date', |
| 724 | 1132 | 'order' => 'DESC', |
| 725 | 1133 | ]; |
| @@ -759,10 +1167,18 @@ | ||
| 759 | 1167 | * @return array |
| 760 | 1168 | */ |
| 761 | 1169 | private function get_comments_data(array $config): array |
| 762 | 1170 | { |
| 763 | - $limit = $config['limit'] ?? 10; | |
| 1171 | + $limit = (int)($config['limit'] ?? ($config['comments_count'] ?? 10)); | |
| 1172 | + if ($limit <= 0) { | |
| 1173 | + $limit = 10; | |
| 1174 | + } | |
| 764 | 1175 | $post_scope = $config['post_scope'] ?? 'all'; |
| 1176 | + $post_types = $config['post_types'] ?? []; | |
| 1177 | + if (!is_array($post_types)) { | |
| 1178 | + $post_types = [$post_types]; | |
| 1179 | + } | |
| 1180 | + $post_types = array_values(array_filter(array_map('sanitize_text_field', $post_types))); | |
| 765 | 1181 | |
| 766 | 1182 | $args = [ |
| 767 | 1183 | 'number' => $limit, |
| 768 | 1184 | 'status' => 'approve', |
| @@ -769,8 +1185,12 @@ | ||
| 769 | 1185 | 'orderby' => 'comment_date', |
| 770 | 1186 | 'order' => 'DESC', |
| 771 | 1187 | ]; |
| 772 | 1188 | |
| 1189 | + if (!empty($post_types)) { | |
| 1190 | + $args['post_type'] = $post_types; | |
| 1191 | + } | |
| 1192 | + | |
| 773 | 1193 | if ($post_scope !== 'all' && is_numeric($post_scope)) { |
| 774 | 1194 | $args['post_id'] = (int)$post_scope; |
| 775 | 1195 | } |
| 776 | 1196 | |
| @@ -799,11 +1219,11 @@ | ||
| 799 | 1219 | * @return array |
| 800 | 1220 | */ |
| 801 | 1221 | private function get_wporg_data(array $config): array |
| 802 | 1222 | { |
| 803 | - $slug = $config['slug'] ?? ''; | |
| 804 | - $type = $config['product_type'] ?? 'plugin'; | |
| 805 | - $data_type = $config['data_type'] ?? 'downloads'; | |
| 1223 | + $slug = sanitize_text_field((string)($config['slug'] ?? ($config['wporg_slug'] ?? ''))); | |
| 1224 | + $type = sanitize_text_field((string)($config['product_type'] ?? ($config['wporg_type'] ?? 'plugin'))); | |
| 1225 | + $data_type = sanitize_text_field((string)($config['data_type'] ?? 'downloads')); | |
| 806 | 1226 | |
| 807 | 1227 | if (empty($slug)) { |
| 808 | 1228 | return []; |
| 809 | 1229 | } |
| @@ -859,10 +1279,15 @@ | ||
| 859 | 1279 | } |
| 860 | 1280 | |
| 861 | 1281 | $id = isset($_POST['id']) ? (int)$_POST['id'] : 0; |
| 862 | 1282 | $title = isset($_POST['title']) ? sanitize_text_field($_POST['title']) : ''; |
| 1283 | + // Use separate 'name' field for post_title if provided, otherwise fall back to 'title' | |
| 1284 | + $name = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : ''; | |
| 1285 | + if (!empty($name)) { | |
| 1286 | + $title = $name; | |
| 1287 | + } | |
| 863 | 1288 | $status = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : 'disabled'; |
| 864 | - $type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : 'notification-bar'; | |
| 1289 | + $type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : 'notification_bar'; | |
| 865 | 1290 | $source = isset($_POST['source']) ? sanitize_text_field($_POST['source']) : 'manual'; |
| 866 | 1291 | $source_config = isset($_POST['source_config']) ? $_POST['source_config'] : '{}'; |
| 867 | 1292 | $design = isset($_POST['design']) ? $_POST['design'] : '{}'; |
| 868 | 1293 | $content = isset($_POST['content']) ? $_POST['content'] : '{}'; |
| @@ -943,12 +1368,10 @@ | ||
| 943 | 1368 | 'display' => json_decode(get_post_meta($id, '_kng_fomo_display', true) ?: '{}', true), |
| 944 | 1369 | 'customize' => json_decode(get_post_meta($id, '_kng_fomo_customize', true) ?: '{}', true), |
| 945 | 1370 | ]; |
| 946 | 1371 | |
| 947 | - // Ensure content.title has the post title | |
| 948 | - if (empty($data['content']['title'])) { | |
| 949 | - $data['content']['title'] = $post->post_title; | |
| 950 | - } | |
| 1372 | + // Provide the notification name separately from content.title | |
| 1373 | + $data['name'] = $post->post_title; | |
| 951 | 1374 | |
| 952 | 1375 | wp_send_json_success($data); |
| 953 | 1376 | } |
| 954 | 1377 | |
| @@ -1069,22 +1492,32 @@ | ||
| 1069 | 1492 | if (!current_user_can('manage_options')) { |
| 1070 | 1493 | wp_send_json_error(['message' => __('Permission denied.', 'king-addons')]); |
| 1071 | 1494 | } |
| 1072 | 1495 | |
| 1073 | - $settings = isset($_POST['settings']) ? $_POST['settings'] : []; | |
| 1496 | + $raw_settings = isset($_POST['settings']) ? $_POST['settings'] : []; | |
| 1074 | 1497 | |
| 1498 | + // If settings were sent as JSON string, decode them | |
| 1499 | + if (is_string($raw_settings)) { | |
| 1500 | + $raw_settings = json_decode(stripslashes($raw_settings), true); | |
| 1501 | + if (!is_array($raw_settings)) { | |
| 1502 | + $raw_settings = []; | |
| 1503 | + } | |
| 1504 | + } | |
| 1505 | + | |
| 1075 | 1506 | // Sanitize |
| 1076 | 1507 | $sanitized = [ |
| 1077 | - 'enabled' => !empty($settings['enabled']), | |
| 1078 | - 'tracking_enabled' => !empty($settings['tracking_enabled']), | |
| 1079 | - 'track_for' => sanitize_text_field($settings['track_for'] ?? 'everyone'), | |
| 1080 | - 'exclude_bots' => !empty($settings['exclude_bots']), | |
| 1081 | - 'cache_ttl' => (int)($settings['cache_ttl'] ?? 3600), | |
| 1508 | + 'enabled' => !empty($raw_settings['enabled']), | |
| 1509 | + 'tracking_enabled' => !empty($raw_settings['tracking_enabled']), | |
| 1510 | + 'track_for' => sanitize_text_field($raw_settings['track_for'] ?? 'everyone'), | |
| 1511 | + 'exclude_bots' => !empty($raw_settings['exclude_bots']), | |
| 1512 | + 'cache_ttl' => (int)($raw_settings['cache_ttl'] ?? 300), | |
| 1513 | + 'anonymize_names' => !empty($raw_settings['anonymize_names']), | |
| 1514 | + 'sound_volume' => (int)($raw_settings['sound_volume'] ?? 50), | |
| 1082 | 1515 | 'modules' => [], |
| 1083 | 1516 | ]; |
| 1084 | 1517 | |
| 1085 | - if (!empty($settings['modules']) && is_array($settings['modules'])) { | |
| 1086 | - foreach ($settings['modules'] as $module => $enabled) { | |
| 1518 | + if (!empty($raw_settings['modules']) && is_array($raw_settings['modules'])) { | |
| 1519 | + foreach ($raw_settings['modules'] as $module => $enabled) { | |
| 1087 | 1520 | $sanitized['modules'][sanitize_key($module)] = !empty($enabled); |
| 1088 | 1521 | } |
| 1089 | 1522 | } |
| 1090 | 1523 | |
| @@ -1099,8 +1532,11 @@ | ||
| 1099 | 1532 | * @return void |
| 1100 | 1533 | */ |
| 1101 | 1534 | public function ajax_track_event(): void |
| 1102 | 1535 | { |
| 1536 | + // Verify nonce | |
| 1537 | + check_ajax_referer('kng_fomo_frontend', 'nonce'); | |
| 1538 | + | |
| 1103 | 1539 | // Rate limiting |
| 1104 | 1540 | $ip = $_SERVER['REMOTE_ADDR'] ?? ''; |
| 1105 | 1541 | $rate_key = 'kng_fomo_rate_' . md5($ip); |
| 1106 | 1542 | $rate = get_transient($rate_key); |
| @@ -1203,8 +1639,11 @@ | ||
| 1203 | 1639 | global $wpdb; |
| 1204 | 1640 | $table = $wpdb->prefix . self::STATS_TABLE; |
| 1205 | 1641 | |
| 1206 | 1642 | $period = isset($_POST['period']) ? sanitize_text_field($_POST['period']) : '7days'; |
| 1643 | + if (empty($period) && isset($_POST['range'])) { | |
| 1644 | + $period = sanitize_text_field($_POST['range']); | |
| 1645 | + } | |
| 1207 | 1646 | $notification_id = isset($_POST['notification_id']) ? (int)$_POST['notification_id'] : 0; |
| 1208 | 1647 | |
| 1209 | 1648 | // Calculate date range |
| 1210 | 1649 | $end_date = current_time('Y-m-d'); |
| @@ -1209,16 +1648,19 @@ | ||
| 1209 | 1648 | // Calculate date range |
| 1210 | 1649 | $end_date = current_time('Y-m-d'); |
| 1211 | 1650 | switch ($period) { |
| 1212 | 1651 | case '30days': |
| 1213 | - $start_date = date('Y-m-d', strtotime('-30 days')); | |
| 1652 | + $start_date = wp_date('Y-m-d', strtotime('-30 days')); | |
| 1214 | 1653 | break; |
| 1215 | 1654 | case '90days': |
| 1216 | - $start_date = date('Y-m-d', strtotime('-90 days')); | |
| 1655 | + $start_date = wp_date('Y-m-d', strtotime('-90 days')); | |
| 1217 | 1656 | break; |
| 1657 | + case 'year': | |
| 1658 | + $start_date = wp_date('Y-01-01'); | |
| 1659 | + break; | |
| 1218 | 1660 | case '7days': |
| 1219 | 1661 | default: |
| 1220 | - $start_date = date('Y-m-d', strtotime('-7 days')); | |
| 1662 | + $start_date = wp_date('Y-m-d', strtotime('-7 days')); | |
| 1221 | 1663 | break; |
| 1222 | 1664 | } |
| 1223 | 1665 | |
| 1224 | 1666 | // Build query |
| @@ -1252,9 +1694,9 @@ | ||
| 1252 | 1694 | 'clicks' => [], |
| 1253 | 1695 | ]; |
| 1254 | 1696 | |
| 1255 | 1697 | foreach ($daily as $row) { |
| 1256 | - $chart_data['labels'][] = date('M j', strtotime($row->stat_date)); | |
| 1698 | + $chart_data['labels'][] = wp_date('M j', strtotime($row->stat_date)); | |
| 1257 | 1699 | $chart_data['views'][] = (int)$row->views; |
| 1258 | 1700 | $chart_data['clicks'][] = (int)$row->clicks; |
| 1259 | 1701 | } |
| 1260 | 1702 | |
| @@ -1307,20 +1749,38 @@ | ||
| 1307 | 1749 | wp_send_json_error(['message' => __('Permission denied.', 'king-addons')]); |
| 1308 | 1750 | } |
| 1309 | 1751 | |
| 1310 | 1752 | $id = isset($_POST['id']) ? (int)$_POST['id'] : 0; |
| 1311 | - $notification = $this->get_notification($id); | |
| 1312 | 1753 | |
| 1313 | - if (!$notification) { | |
| 1314 | - wp_send_json_error(['message' => __('Notification not found.', 'king-addons')]); | |
| 1754 | + // Export single notification | |
| 1755 | + if ($id) { | |
| 1756 | + $notification = $this->get_notification($id); | |
| 1757 | + | |
| 1758 | + if (!$notification) { | |
| 1759 | + wp_send_json_error(['message' => __('Notification not found.', 'king-addons')]); | |
| 1760 | + } | |
| 1761 | + | |
| 1762 | + // Remove stats and IDs for export | |
| 1763 | + unset($notification['id'], $notification['views'], $notification['clicks'], $notification['ctr']); | |
| 1764 | + | |
| 1765 | + wp_send_json_success([ | |
| 1766 | + 'data' => $notification, | |
| 1767 | + 'filename' => 'fomo-notification-' . sanitize_title($notification['title']) . '.json', | |
| 1768 | + ]); | |
| 1769 | + return; | |
| 1315 | 1770 | } |
| 1316 | 1771 | |
| 1317 | - // Remove stats and IDs for export | |
| 1318 | - unset($notification['id'], $notification['views'], $notification['clicks'], $notification['ctr']); | |
| 1772 | + // Export all notifications | |
| 1773 | + $all = $this->get_all_notifications(); | |
| 1774 | + $export = []; | |
| 1775 | + foreach ($all as $notification) { | |
| 1776 | + unset($notification['id'], $notification['views'], $notification['clicks'], $notification['ctr']); | |
| 1777 | + $export[] = $notification; | |
| 1778 | + } | |
| 1319 | 1779 | |
| 1320 | 1780 | wp_send_json_success([ |
| 1321 | - 'data' => $notification, | |
| 1322 | - 'filename' => 'fomo-notification-' . sanitize_title($notification['title']) . '.json', | |
| 1781 | + 'data' => $export, | |
| 1782 | + 'filename' => 'fomo-notifications-export.json', | |
| 1323 | 1783 | ]); |
| 1324 | 1784 | } |
| 1325 | 1785 | |
| 1326 | 1786 | /** |
| @@ -1365,9 +1825,9 @@ | ||
| 1365 | 1825 | } |
| 1366 | 1826 | |
| 1367 | 1827 | // Save meta |
| 1368 | 1828 | update_post_meta($post_id, '_kng_fomo_status', 'disabled'); |
| 1369 | - update_post_meta($post_id, '_kng_fomo_type', $notification['type'] ?? 'notification-bar'); | |
| 1829 | + update_post_meta($post_id, '_kng_fomo_type', $notification['type'] ?? 'notification_bar'); | |
| 1370 | 1830 | update_post_meta($post_id, '_kng_fomo_source', $notification['source'] ?? 'manual'); |
| 1371 | 1831 | update_post_meta($post_id, '_kng_fomo_source_config', wp_json_encode($notification['source_config'] ?? [])); |
| 1372 | 1832 | update_post_meta($post_id, '_kng_fomo_design', wp_json_encode($notification['design'] ?? [])); |
| 1373 | 1833 | update_post_meta($post_id, '_kng_fomo_content', wp_json_encode($notification['content'] ?? [])); |
| @@ -1436,7 +1896,4 @@ | ||
| 1436 | 1896 | |
| 1437 | 1897 | wp_send_json_success(['message' => __('Cache cleared successfully.', 'king-addons')]); |
| 1438 | 1898 | } |
| 1439 | 1899 | } |
| 1440 | - | |
| 1441 | -// Initialize the extension | |
| 1442 | -Fomo_Notifications::instance(); | |