Changeset 3380746
- Timestamp:
- 10/19/2025 09:33:20 AM (4 months ago)
- Location:
- taboola-push-notification/trunk
- Files:
-
- 3 edited
-
assets/js/admin/metabox.js (modified) (4 diffs)
-
assets/js/admin/settings-page.js (modified) (1 diff)
-
taboola-web-push.php (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
taboola-push-notification/trunk/assets/js/admin/metabox.js
r3379652 r3380746 104 104 var executionTime = null; 105 105 if (isScheduled && scheduleDateTime) { 106 executionTime = new Date(scheduleDateTime).getTime();106 executionTime = Math.floor(new Date(scheduleDateTime).getTime() / 1000); 107 107 } 108 108 … … 119 119 }; 120 120 121 122 121 $(this).prop("disabled", true).text(taboola_metabox.sending_text); 123 122 … … 129 128 130 129 if (response.success) { 131 resultDiv.html('<div style="padding: 10px; background: #d4edda; border: 1px solid #28a745; border-radius: 4px; color: #155724;"><strong>Success!</strong> ' + (response.data || taboola_metabox.success_text) + '</div>');130 resultDiv.html('<div style="padding: 10px; background: #d4edda; border: 1px solid #28a745; border-radius: 4px; color: #155724;"><strong>Success!</strong> ' + (response.data.message || taboola_metabox.success_text) + '</div>'); 132 131 133 132 // Clear form fields … … 139 138 }, 3000); 140 139 } else { 141 resultDiv.html('<div style="padding: 10px; background: #fee; border: 1px solid #dc3545; border-radius: 4px; color: #721c24;"><strong>Error:</strong> ' + (response.data || "Failed to send notification") + '</div>');140 resultDiv.html('<div style="padding: 10px; background: #fee; border: 1px solid #dc3545; border-radius: 4px; color: #721c24;"><strong>Error:</strong> ' + (response.data.message || "Failed to send notification") + '</div>'); 142 141 } 143 142 }).always(function() { -
taboola-push-notification/trunk/assets/js/admin/settings-page.js
r3379652 r3380746 210 210 if (!includedSegments && !excludedSegments) { 211 211 } 212 213 212 214 213 // Send AJAX request -
taboola-push-notification/trunk/taboola-web-push.php
r3379652 r3380746 144 144 } 145 145 146 // Prepare payload and endpoint (USE SAME ENDPOINT FOR BOTH IMMEDIATE AND SCHEDULED)146 // Prepare payload and endpoint - USE DIFFERENT ENDPOINTS FOR IMMEDIATE VS SCHEDULED 147 147 $is_scheduled = !empty($execution_time) && $execution_time > 0; 148 $epsilon_url = $this->getEpsilonBaseUrl() . '/epsilon/push'; 148 $epsilon_base = $this->getEpsilonBaseUrl(); 149 $epsilon_url = $is_scheduled ? $epsilon_base . '/epsilon/push/scheduled' : $epsilon_base . '/epsilon/push'; 149 150 150 151 // Create push events array - one event per app ID … … 207 208 // Only add executionTime if this is actually a scheduled notification 208 209 if ($is_scheduled) { 209 $push_event['executionTime'] = $execution_time; 210 // Epsilon scheduled endpoint expects milliseconds, not seconds 211 $push_event['executionTime'] = $execution_time * 1000; 210 212 } 211 213 … … 593 595 add_action('wp_ajax_taboola_fetch_segments', array($this, 'handle_fetch_segments_ajax')); 594 596 595 // Add service worker endpoint596 add_action('init', array($this, 'add_service_worker_endpoint'));597 598 599 600 597 // Add meta box for post edit screen (OneSignal style) 601 598 add_action('add_meta_boxes', array($this, 'add_push_notification_meta_box')); … … 653 650 } 654 651 652 /** 653 * Display the main admin dashboard page 654 */ 655 public function admin_page() { 656 // Check user capabilities 657 if (!current_user_can('manage_options')) { 658 wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'taboola-push-notification')); 659 } 660 661 // Include the admin page template 662 include TABOOLA_WEB_PUSH_PLUGIN_PATH . 'includes/admin-page.php'; 663 } 664 665 /** 666 * Display the settings page 667 */ 668 public function settings_page() { 669 // Check user capabilities 670 if (!current_user_can('manage_options')) { 671 wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'taboola-push-notification')); 672 } 673 674 // Include the settings page template 675 include TABOOLA_WEB_PUSH_PLUGIN_PATH . 'includes/settings-page.php'; 676 } 677 655 678 public function enqueue_scripts() { 656 679 // Enqueue main JavaScript … … 675 698 'ajax_url' => admin_url('admin-ajax.php'), 676 699 'nonce' => wp_create_nonce('taboola_push_nonce'), 677 'service_worker_url' => TABOOLA_WEB_PUSH_PLUGIN_URL . 'taboola-sw.js',678 700 'plugin_url' => TABOOLA_WEB_PUSH_PLUGIN_URL, 679 701 'debug_mode' => defined('WP_DEBUG') && WP_DEBUG … … 797 819 } 798 820 799 800 /**801 * Enqueue theme styles using wp_add_inline_style()802 */803 private function enqueue_theme_styles() {804 $theme = self::get_theme_variables();805 806 // Build CSS string807 $theme_css = ':root {808 --taboola-primary: ' . esc_attr($theme['primary']) . ';809 --taboola-secondary: ' . esc_attr($theme['secondary']) . ';810 --taboola-accent: ' . esc_attr($theme['accent']) . ';811 --taboola-text: ' . esc_attr($theme['text']) . ';812 }813 814 .taboola-client-auth, .taboola-send-form, .taboola-push-server-response,815 .taboola-dashboard-stats .taboola-stat-box, .taboola-quick-actions,816 .taboola-service-worker-status, .taboola-recent-activity, .taboola-getting-started,817 .taboola-help, .taboola-settings-form, .taboola-subscribers-table, .taboola-sidebar-box {818 background: linear-gradient(135deg, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0.9) 100%) !important;819 backdrop-filter: blur(10px);820 border-left: 4px solid transparent !important;821 border-image: var(--taboola-primary) 1 !important;822 position: relative;823 overflow: hidden;824 }825 826 .taboola-client-auth::before, .taboola-send-form::before, .taboola-push-server-response::before,827 .taboola-dashboard-stats .taboola-stat-box::before, .taboola-quick-actions::before,828 .taboola-service-worker-status::before, .taboola-recent-activity::before,829 .taboola-getting-started::before, .taboola-help::before, .taboola-settings-form::before,830 .taboola-subscribers-table::before, .taboola-sidebar-box::before {831 content: "";832 position: absolute;833 top: 0;834 left: 0;835 right: 0;836 bottom: 0;837 background: var(--taboola-secondary);838 opacity: 0.03;839 z-index: -1;840 }841 842 .taboola-client-auth h2, .taboola-send-form h2, .taboola-push-server-response h2,843 .taboola-dashboard-stats h3, .taboola-quick-actions h2, .taboola-service-worker-status h3,844 .taboola-recent-activity h3, .taboola-getting-started h2, .taboola-help h3,845 .taboola-settings-form h2, .taboola-subscribers-table h2, .taboola-sidebar-box h3 {846 background: var(--taboola-primary);847 -webkit-background-clip: text;848 -webkit-text-fill-color: transparent;849 background-clip: text;850 font-weight: bold;851 }852 853 .taboola-client-auth .button-secondary, .taboola-send-form .button-primary {854 background: var(--taboola-primary) !important;855 border: none !important;856 color: white !important;857 transition: all 0.3s ease;858 }859 860 .taboola-client-auth .button-secondary:hover, .taboola-send-form .button-primary:hover {861 transform: translateY(-2px);862 box-shadow: 0 8px 25px rgba(0,0,0,0.2);863 }';864 865 wp_add_inline_style('taboola-admin', $theme_css);866 }867 868 /**869 * Add shared segments JavaScript functions to admin footer870 * NOTE: Now handled by properly enqueued segments.js file871 */872 public function admin_footer_segments_script() {873 // This method is deprecated - segments are now loaded via wp_enqueue_script874 // Keeping this method for compatibility but it no longer outputs inline scripts875 }876 // Load segments for a specific app and update button state877 public function add_service_worker_endpoint() {878 // Handle service worker request - no nonce needed for static file serving879 // phpcs:ignore WordPress.Security.NonceVerification.Recommended880 if (isset($_GET['taboola-sw']) || (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === '/taboola-sw.js')) {881 $this->serve_service_worker();882 }883 }884 885 private function serve_service_worker() {886 // Set proper headers for service worker887 header('Content-Type: application/javascript');888 header('Service-Worker-Allowed: /');889 890 // Output service worker content directly (no sanitization for JavaScript)891 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- This is JavaScript content served as a file892 echo $this->get_service_worker_content();893 exit;894 }895 896 private function get_service_worker_content() {897 $sw_file = TABOOLA_WEB_PUSH_PLUGIN_PATH . 'taboola-sw.js';898 if (file_exists($sw_file)) {899 $content = file_get_contents($sw_file);900 901 // Replace hardcoded paths with dynamic URLs902 $plugin_url = TABOOLA_WEB_PUSH_PLUGIN_URL;903 $icon_url = $plugin_url . 'assets/images/taboola-icon-192x192.png';904 905 // Replace the hardcoded paths in the service worker906 $content = str_replace(907 '/wp-content/plugins/taboola-push-notification/assets/images/taboola-icon-192x192.png',908 $icon_url,909 $content910 );911 912 return $content;913 }914 915 // Fallback service worker content916 return "// Service worker content";917 }918 919 public function handle_subscription() {920 check_ajax_referer('taboola_push_nonce', 'nonce');921 922 $endpoint = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'endpoint', FILTER_UNSAFE_RAW) ?? ''));923 $p256dh = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'p256dh', FILTER_UNSAFE_RAW) ?? ''));924 $auth = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'auth', FILTER_UNSAFE_RAW) ?? ''));925 926 $subscriptions = get_option('taboola_push_subscriptions', array());927 928 $subscription = array(929 'endpoint' => $endpoint,930 'p256dh' => $p256dh,931 'auth' => $auth,932 'date' => current_time('mysql'),933 'user_agent' => sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'] ?? ''))934 );935 936 $subscriptions[] = $subscription;937 update_option('taboola_push_subscriptions', $subscriptions);938 939 wp_send_json_success(array('message' => 'Subscription saved successfully'));940 }941 942 public function handle_send_notification() {943 check_ajax_referer('taboola_push_nonce', 'nonce');944 945 // Get notification data (using same approach as working meta box)946 $app_id = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'app_id', FILTER_UNSAFE_RAW) ?? ''));947 $title = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'title', FILTER_UNSAFE_RAW) ?? ''));948 $message = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'message', FILTER_UNSAFE_RAW) ?? ''));949 $url = esc_url_raw(wp_unslash(filter_input(INPUT_POST, 'url', FILTER_SANITIZE_URL) ?? ''));950 $icon = esc_url_raw(wp_unslash(filter_input(INPUT_POST, 'icon', FILTER_SANITIZE_URL) ?? ''));951 952 if (empty($app_id) || empty($title) || empty($message) || empty($url)) {953 wp_send_json_error(array('message' => 'Please fill in all required fields.'));954 return;955 }956 957 // Get segments data if provided (nonce already verified above)958 $segments_data = $this->extract_segments_data();959 960 // Get execution time if provided and valid (exact same logic as meta box)961 $execution_time = null;962 $execution_time_raw = filter_input(INPUT_POST, 'execution_time', FILTER_UNSAFE_RAW);963 if ($execution_time_raw && !empty($execution_time_raw) && $execution_time_raw !== 'null') {964 $execution_time = intval($execution_time_raw);965 // Only use if it's a valid future timestamp966 if ($execution_time <= time()) {967 $execution_time = null;968 } else {969 }970 }971 972 // Send notification using the exact same method as meta box973 $result = $this->send_to_push_server($title, $message, $url, $icon, null, $app_id, $segments_data, $execution_time);974 975 if ($result) {976 // Clear the saved manual notification fields on successful send977 delete_option('taboola_push_manual_title');978 delete_option('taboola_push_manual_message');979 delete_option('taboola_push_manual_url');980 delete_option('taboola_push_manual_icon');981 delete_option('taboola_push_manual_url_selector');982 983 wp_send_json_success(array('message' => 'Notification sent successfully to Taboola Push Notification Server!'));984 } else {985 // Get the last error from the API client for debugging (same as before)986 $api_client = TaboolaApiClient::getInstance();987 $last_error = $api_client->getLastError();988 989 $debug_info = array(990 'message' => 'Failed to send notification. Check your Taboola Push Notification Server credentials.',991 'debug' => array(992 'app_id' => $app_id,993 'execution_time' => $execution_time,994 'is_scheduled' => !empty($execution_time),995 'segments_count' => count($segments_data),996 'last_api_error' => $last_error,997 )998 );999 wp_send_json_error($debug_info);1000 }1001 }1002 1003 public function handle_check_notification() {1004 // Check for test notifications in transient1005 $notification = get_transient('taboola_test_notification');1006 1007 if ($notification) {1008 // Clear the notification after retrieving it1009 delete_transient('taboola_test_notification');1010 1011 wp_send_json_success(array(1012 'has_notification' => true,1013 'notification' => $notification1014 ));1015 } else {1016 wp_send_json_success(array(1017 'has_notification' => false1018 ));1019 }1020 }1021 1022 1023 public function admin_page() {1024 include TABOOLA_WEB_PUSH_PLUGIN_PATH . 'includes/admin-page.php';1025 }1026 1027 1028 public function settings_page() {1029 include TABOOLA_WEB_PUSH_PLUGIN_PATH . 'includes/settings-page.php';1030 }1031 1032 1033 1034 public function activate() {1035 // Plugin activation tasks1036 if (!get_option('taboola_push_subscriptions')) {1037 add_option('taboola_push_subscriptions', array());1038 }1039 }1040 1041 public function deactivate() {1042 // Plugin deactivation tasks - cleanup if needed1043 }1044 1045 public function enqueue_admin_styles($hook) {1046 if (strpos($hook, 'taboola') !== false) {1047 wp_enqueue_style(1048 'taboola-admin-style',1049 TABOOLA_WEB_PUSH_PLUGIN_URL . 'assets/css/taboola-admin.css',1050 array(),1051 TABOOLA_WEB_PUSH_VERSION1052 );1053 }1054 }1055 821 1056 822 /** … … 1115 881 1116 882 /** 1117 * Output theme CSS variables for all plugin pages 1118 * Now uses wp_add_inline_style() via admin_print_styles hook 883 * Output theme styles directly for non-admin pages 1119 884 */ 1120 885 public static function output_theme_styles() { 1121 // This method is kept for backward compatibility but now does nothing 1122 // Theme styles are properly enqueued via enqueue_theme_styles() 1123 } 1124 /** 1125 * Add push notification meta box to post edit screen 1126 */ 886 $theme = self::get_theme_variables(); 887 888 // Build CSS string 889 $theme_css = ':root { 890 --taboola-primary: ' . esc_attr($theme['primary']) . '; 891 --taboola-secondary: ' . esc_attr($theme['secondary']) . '; 892 --taboola-accent: ' . esc_attr($theme['accent']) . '; 893 --taboola-text: ' . esc_attr($theme['text']) . '; 894 }'; 895 896 // Output inline style tag 897 echo '<style type="text/css">' . $theme_css . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 898 } 899 900 /** 901 * Enqueue theme styles using wp_add_inline_style() 902 */ 903 private function enqueue_theme_styles() { 904 $theme = self::get_theme_variables(); 905 906 // Build CSS string 907 $theme_css = ':root { 908 --taboola-primary: ' . esc_attr($theme['primary']) . '; 909 --taboola-secondary: ' . esc_attr($theme['secondary']) . '; 910 --taboola-accent: ' . esc_attr($theme['accent']) . '; 911 --taboola-text: ' . esc_attr($theme['text']) . '; 912 } 913 914 .taboola-client-auth, .taboola-send-form, .taboola-push-server-response, 915 .taboola-dashboard-stats .taboola-stat-box, .taboola-quick-actions, 916 .taboola-service-worker-status, .taboola-recent-activity, .taboola-getting-started, 917 .taboola-help, .taboola-settings-form, .taboola-subscribers-table, .taboola-sidebar-box { 918 background: linear-gradient(135deg, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0.9) 100%) !important; 919 backdrop-filter: blur(10px); 920 border-left: 4px solid transparent !important; 921 border-image: var(--taboola-primary) 1 !important; 922 position: relative; 923 overflow: hidden; 924 } 925 926 .taboola-client-auth::before, .taboola-send-form::before, .taboola-push-server-response::before, 927 .taboola-dashboard-stats .taboola-stat-box::before, .taboola-quick-actions::before, 928 .taboola-service-worker-status::before, .taboola-recent-activity::before, 929 .taboola-getting-started::before, .taboola-help::before, .taboola-settings-form::before, 930 .taboola-subscribers-table::before, .taboola-sidebar-box::before { 931 content: ""; 932 position: absolute; 933 top: 0; 934 left: 0; 935 right: 0; 936 bottom: 0; 937 background: var(--taboola-secondary); 938 opacity: 0.03; 939 z-index: -1; 940 } 941 942 .taboola-client-auth h2, .taboola-send-form h2, .taboola-push-server-response h2, 943 .taboola-dashboard-stats h3, .taboola-quick-actions h2, .taboola-service-worker-status h3, 944 .taboola-recent-activity h3, .taboola-getting-started h2, .taboola-help h3, 945 .taboola-settings-form h2, .taboola-subscribers-table h2, .taboola-sidebar-box h3 { 946 background: var(--taboola-primary); 947 -webkit-background-clip: text; 948 -webkit-text-fill-color: transparent; 949 background-clip: text; 950 font-weight: bold; 951 } 952 953 .taboola-client-auth .button-secondary, .taboola-send-form .button-primary { 954 background: var(--taboola-primary) !important; 955 border: none !important; 956 color: white !important; 957 transition: all 0.3s ease; 958 } 959 960 .taboola-client-auth .button-secondary:hover, .taboola-send-form .button-primary:hover { 961 transform: translateY(-2px); 962 box-shadow: 0 8px 25px rgba(0,0,0,0.2); 963 }'; 964 965 wp_add_inline_style('taboola-admin', $theme_css); 966 } 967 968 /** 969 * Add shared segments JavaScript functions to admin footer 970 * NOTE: Now handled by properly enqueued segments.js file 971 */ 972 public function admin_footer_segments_script() { 973 // This method is deprecated - segments are now loaded via wp_enqueue_script 974 // Keeping this method for compatibility but it no longer outputs inline scripts 975 } 976 // Load segments for a specific app and update button state 977 1127 978 public function add_push_notification_meta_box() { 1128 979 add_meta_box( … … 1504 1355 $app_ids = $app_manager->getAppIds($app_id, $post_id); 1505 1356 1506 1507 1357 // Send notification using the API client 1508 1358 $result = $api_client->sendPushNotification($title, $message, $url, $icon, $app_ids, $segments_data, $execution_time); 1509 1359 1510 1511 1360 return $result; 1512 1361 } 1513 1362 1363 1364 /** 1365 * AJAX handler for sending notification from settings page 1366 */ 1367 public function handle_send_notification() { 1368 // Verify nonce 1369 $nonce_raw = filter_input(INPUT_POST, 'nonce', FILTER_UNSAFE_RAW); 1370 if (!wp_verify_nonce(sanitize_text_field(wp_unslash($nonce_raw ?? '')), 'taboola_push_nonce')) { 1371 wp_send_json_error('Security check failed'); 1372 return; 1373 } 1374 1375 // Check permissions 1376 if (!current_user_can('manage_options')) { 1377 wp_send_json_error('Insufficient permissions'); 1378 return; 1379 } 1380 1381 // Get notification data 1382 $title = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'title', FILTER_UNSAFE_RAW) ?? '')); 1383 $message = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'message', FILTER_UNSAFE_RAW) ?? '')); 1384 $url = sanitize_url(filter_input(INPUT_POST, 'url', FILTER_SANITIZE_URL) ?? ''); 1385 $icon = sanitize_url(filter_input(INPUT_POST, 'icon', FILTER_SANITIZE_URL) ?? ''); 1386 $app_id = sanitize_text_field(wp_unslash(filter_input(INPUT_POST, 'app_id', FILTER_UNSAFE_RAW) ?? 'all')); 1387 1388 // Validate required fields 1389 if (empty($title) || empty($message)) { 1390 wp_send_json_error('Title and message are required'); 1391 return; 1392 } 1393 1394 // Get segments data if provided 1395 $segments_data = $this->extract_segments_data(); 1396 1397 // Get execution time if provided (this comes in seconds from settings-page.js) 1398 $execution_time = null; 1399 $execution_time_raw = filter_input(INPUT_POST, 'execution_time', FILTER_UNSAFE_RAW); 1400 if ($execution_time_raw && !empty($execution_time_raw) && $execution_time_raw !== 'null') { 1401 $execution_time = intval($execution_time_raw); 1402 // Only use if it's a valid future timestamp 1403 if ($execution_time <= time()) { 1404 wp_send_json_error('Scheduled time must be in the future'); 1405 return; 1406 } 1407 } 1408 1409 // Send notification using the Push Server function 1410 $result = $this->send_to_push_server($title, $message, $url, $icon, null, $app_id, $segments_data, $execution_time); 1411 1412 if ($result) { 1413 wp_send_json_success(array('message' => 'Notification sent successfully to Taboola Push Notification Server!')); 1414 } else { 1415 wp_send_json_error(array('message' => 'Failed to send notification. Check your Taboola Push Notification Server credentials.')); 1416 } 1417 } 1514 1418 1515 1419 /** … … 1575 1479 1576 1480 if ($result) { 1577 wp_send_json_success( 'Notification sent successfully to Taboola Push Notification Server!');1481 wp_send_json_success(array('message' => 'Notification sent successfully to Taboola Push Notification Server!')); 1578 1482 } else { 1579 wp_send_json_error( 'Failed to send notification. Check your Taboola Push Notification Server credentials.');1483 wp_send_json_error(array('message' => 'Failed to send notification. Check your Taboola Push Notification Server credentials.')); 1580 1484 } 1581 1485 }
Note: See TracChangeset
for help on using the changeset viewer.