Changeset 3789014
- Timestamp:
- 11/07/2026 05:31:48 AM (less than one hour ago)
- Location:
- yoohw-advanced-notifications
- Files:
-
- 22 added
- 20 edited
- 1 copied
-
assets/screenshot-1.jpg (added)
-
assets/screenshot-2.jpg (added)
-
assets/screenshot-3.jpg (added)
-
assets/screenshot-4.jpg (added)
-
tags/0.4.0 (copied) (copied from yoohw-advanced-notifications/trunk )
-
tags/0.4.0/assets/admin.css (modified) (1 diff)
-
tags/0.4.0/assets/admin.js (modified) (4 diffs)
-
tags/0.4.0/changelog.txt (added)
-
tags/0.4.0/docs/operator-features.md (modified) (2 diffs)
-
tags/0.4.0/includes/class-customer-email-notify.php (modified) (33 diffs)
-
tags/0.4.0/includes/trait-campaign-audiences.php (modified) (6 diffs)
-
tags/0.4.0/includes/trait-campaign-authoring.php (modified) (9 diffs)
-
tags/0.4.0/includes/trait-campaign-automation-ui.php (added)
-
tags/0.4.0/includes/trait-campaign-automations.php (added)
-
tags/0.4.0/includes/trait-campaign-checkout.php (added)
-
tags/0.4.0/includes/trait-campaign-contact-history.php (added)
-
tags/0.4.0/includes/trait-campaign-entrypoints.php (added)
-
tags/0.4.0/includes/trait-campaign-personalization.php (added)
-
tags/0.4.0/includes/trait-campaign-privacy.php (modified) (5 diffs)
-
tags/0.4.0/includes/trait-campaign-purchase-history.php (added)
-
tags/0.4.0/includes/trait-campaign-subscriptions.php (added)
-
tags/0.4.0/languages/yoohw-advanced-notifications.pot (modified) (14 diffs)
-
tags/0.4.0/readme.txt (modified) (8 diffs)
-
tags/0.4.0/yoohw-advanced-notifications.php (modified) (2 diffs)
-
trunk/assets/admin.css (modified) (1 diff)
-
trunk/assets/admin.js (modified) (4 diffs)
-
trunk/changelog.txt (added)
-
trunk/docs/operator-features.md (modified) (2 diffs)
-
trunk/includes/class-customer-email-notify.php (modified) (33 diffs)
-
trunk/includes/trait-campaign-audiences.php (modified) (6 diffs)
-
trunk/includes/trait-campaign-authoring.php (modified) (9 diffs)
-
trunk/includes/trait-campaign-automation-ui.php (added)
-
trunk/includes/trait-campaign-automations.php (added)
-
trunk/includes/trait-campaign-checkout.php (added)
-
trunk/includes/trait-campaign-contact-history.php (added)
-
trunk/includes/trait-campaign-entrypoints.php (added)
-
trunk/includes/trait-campaign-personalization.php (added)
-
trunk/includes/trait-campaign-privacy.php (modified) (5 diffs)
-
trunk/includes/trait-campaign-purchase-history.php (added)
-
trunk/includes/trait-campaign-subscriptions.php (added)
-
trunk/languages/yoohw-advanced-notifications.pot (modified) (14 diffs)
-
trunk/readme.txt (modified) (8 diffs)
-
trunk/yoohw-advanced-notifications.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
yoohw-advanced-notifications/tags/0.4.0/assets/admin.css
r3771948 r3789014 810 810 811 811 .yoohw-an-workspace .an-preview-device .dashicons { display: block; width: 20px; height: 20px; margin: 0; font-size: 20px; line-height: 20px; } 812 813 /* Automation authoring shares the composer steps, editor and preview layout. */ 814 .an-automation-rule { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 16px 0; border-top: 1px solid #dcdcde; } 815 .an-automation-rule p { margin: 6px 0 0; color: #50575e; } 816 .an-automation-state { display: inline-block; margin-left: 12px; padding: 2px 8px; border: 1px solid #c3c4c7; border-radius: 3px; font-size: 12px; } 817 .an-automation-rule-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } 818 .an-automation-form details { margin-top: 16px; } 819 .an-automation-form .an-field > input[type="number"] { max-width: 240px; } 820 .an-automation-form .an-sample-stale { padding: 12px; border-left: 4px solid #dba617; background: #fcf9e8; } 821 .an-automation-form .an-automation-sample[hidden], .an-automation-form .an-sample-stale[hidden] { display: none !important; } 822 @media (max-width: 782px) { .an-automation-rule { align-items: flex-start; flex-direction: column; gap: 12px; } } -
yoohw-advanced-notifications/tags/0.4.0/assets/admin.js
r3771948 r3789014 27 27 $row.find(':input').prop('disabled', false); 28 28 } 29 revealApplicable('.an-selected-orders', source === 'selected_orders'); 29 30 revealApplicable('#yoohw-advanced-notifications-products-row', product); 30 31 revealApplicable('#yoohw-advanced-notifications-roles-row', registered); 31 32 revealApplicable('#yoohw-advanced-notifications-manual-row', manual); 32 revealApplicable('.an-order-filters', product || source === yoohwAN.customersSource );33 revealApplicable('.an-country-filter', !manual );33 revealApplicable('.an-order-filters', product || source === yoohwAN.customersSource || source === 'selected_orders'); 34 revealApplicable('.an-country-filter', !manual && source !== 'subscribed_emails'); 34 35 $('#yoohw-advanced-notifications-customers-row').toggle(source === yoohwAN.customersSource); 35 36 $('.an-incompatible-help').prop('hidden', !$('.an-inapplicable-selection').length); … … 143 144 144 145 editor.on('keyup change input SetContent NodeChange', updateEmailPreview); 146 editor.on('change input keyup', markAutomationPreviewStale); 145 147 editor.yoohwEmailNotifyPreviewBound = true; 146 148 } … … 209 211 if (panel) { showStep(names.indexOf(panel.dataset.anPanel), false); } 210 212 }, true); 211 showStep(0, false); 213 var initial = names.indexOf($form.attr('data-an-initial-step')); 214 showStep(initial < 0 ? 0 : initial, false); 212 215 } 213 216 … … 282 285 updateEmailPreview(); 283 286 }); 287 288 function markAutomationPreviewStale() { 289 $('.an-automation-form .an-automation-sample').prop('hidden', true); 290 $('.an-automation-form .an-sample-stale').prop('hidden', false); 291 } 292 $(document).on('input change', '.an-automation-form input:not([type="hidden"]), .an-automation-form select, .an-automation-form textarea', function() { 293 if (this.name !== 'test_email' && this.name !== 'name') { markAutomationPreviewStale(); } 294 }); 284 295 $(document).on('submit', 'form', function() { if (window.tinymce) { window.tinymce.triggerSave(); } }); 285 296 $(document).on('change', '#recipient_source, .an-order-filters :input, .an-country-filter :input, #yoohw-advanced-notifications-roles-row :input, #yoohw-advanced-notifications-products-row :input, #yoohw-advanced-notifications-manual-row :input', toggleRecipientFields); -
yoohw-advanced-notifications/tags/0.4.0/docs/operator-features.md
r3771948 r3789014 1 # Tính năng vận hành campaign ( chưa phát hành)1 # Tính năng vận hành campaign (0.4.0) 2 2 3 3 Nền đối chiếu: `74353181835147d8e68d9bca87a3d801c3e772dd` trên local và `origin/main`. Giữ schema recipient 3, Action Scheduler, manifest xác nhận và durable opt-out hiện có. Không thêm service hoặc kênh gửi khác. … … 78 78 79 79 Các selection field dùng SelectWoo có sẵn của WooCommerce (giao diện Select2), bao gồm các bộ lọc và người nhận mẫu; giá trị gốc và validation vẫn giữ nguyên. Hai nút icon Desktop/Mobile điều chỉnh bố cục preview trong cả bước soạn và preview người nhận, có tooltip/nhãn hỗ trợ đọc màn hình và trạng thái lựa chọn rõ ràng; không tạo thao tác gửi. 80 81 ### AN-5: Liên hệ từ Products và Orders (0.4.0) 82 83 - Products có **Email purchasers** tại danh sách và trang sửa. Sản phẩm cha gồm các variation; từng variation có liên kết riêng chỉ chọn người mua variation đó. Orders có bulk action **Email selected orders** trên cả HPOS và lưu trữ cũ; trang chi tiết có **Email this customer**. Các thao tác chỉ lưu bản nháp, chưa tạo job hay gửi email. 84 - Nguồn **Selected orders** giữ tập ID rõ ràng, sửa được trong composer. Mặc định xét mọi trạng thái trong tập đã chọn để hỗ trợ thông báo cho cả đơn đang chờ/hủy; bộ lọc trạng thái có thể thu hẹp. Product customers tiếp tục mặc định Processing/Completed. Guest và tài khoản được gộp theo billing email đã chuẩn hóa, mỗi email nhận một thư cho campaign. Bộ lọc đơn vẫn khớp cùng một đơn; ID mất/quyền không đủ bị từ chối, không mở rộng tập chọn. 85 - Subject, heading và body của campaign mới hỗ trợ `{customer_name}`, `{store_name}`, `{product_name}`, `{order_number}`, `{ordered_products}`, `{order_url}`. `{product_name}` vẫn là nhãn chung của campaign. Thông tin riêng lấy từ **đơn khớp có ID lớn nhất**, gồm toàn bộ tên dòng sản phẩm của đơn đó; preview ghi số đơn đại diện và số đơn khớp. Không lấy đơn mới hơn nằm ngoài phạm vi. Thiếu tên dùng **Customer**; thiếu ngữ cảnh đơn thì các biến đơn rỗng. 86 - `{order_url}` chỉ có khi email tài khoản sở hữu khớp billing email, dùng trang My Account và cần đăng nhập đúng chủ đơn. Guest hoặc email khác tài khoản không có liên kết; không lưu khóa order/guest. Không chèn liên kết vào mẫu mặc định khi thiếu ngữ cảnh. 87 - Live editor hiển thị nội dung template; **Preview Recipients** là preview cá nhân hóa thật, chọn được tối đa 20 người mẫu. Email thử dùng người đủ điều kiện đầu tiên, hoặc Test Customer nếu chưa có người nhận, và luôn gửi tới địa chỉ thử đã nhập. Ba mẫu có hướng dẫn điền thay đổi/ngày hiệu lực/hành động/liên hệ và vẫn sửa tự do. 88 - Lưu/mở lại/duplicate/saved audience giữ tiêu chí ID; phải preview dữ liệu hiện tại khi dùng lại. Xác nhận giữ nguyên context, tên cửa hàng, nội dung và recipient; dispatcher/recovery đọc snapshot, không truy vấn lại đơn để gửi. Campaign đã xác nhận trước AN-5 giữ subject/heading literal và cách thay body cũ. Durable opt-out, outcome unknown, privacy/retention hiện hành tiếp tục có hiệu lực; export bổ sung context của đúng email và erasure xóa context khỏi snapshot/preview/args. 89 90 Kiểm chứng mới: `tests/contextual-campaigns.php` và `tests/contextual-entrypoints.php`, được chạy trong CI regression với database reliability riêng và mail bị chặn. Bằng chứng theo candidate ghi trong PR. Không chứng minh SMTP/inbox thật. 91 92 93 ### AN-6: Đăng ký trực tiếp và lịch sử liên hệ (0.4.0) 94 95 - Chèn shortcode `[yoohw_an_subscribe]` vào trang. Khách nhập email, chủ động chọn đồng ý rồi nhận thư xác nhận. Classic Checkout và Checkout Blocks có checkbox tùy chọn, không chọn sẵn, chỉ gửi yêu cầu xác nhận cho billing email; My Account quản lý đúng email hiện tại của tài khoản. Không suy diễn consent từ đơn hàng/tài khoản. Blocks dùng Additional Checkout Fields API của WooCommerce, không lưu lựa chọn mặc định trên hồ sơ khách. 96 - Link email chỉ mở trang xác nhận; cần bấm **Confirm subscription** để thay đổi trạng thái, tránh scanner email tự đăng ký. Token ngẫu nhiên, chỉ lưu hash, hết hạn sau 24 giờ, dùng một lần. Trước xác nhận, trạng thái có hiệu lực vẫn là unknown hoặc unsubscribed; My Account và tìm kiếm subscriber thể hiện yêu cầu đang chờ. 97 - Đăng ký lại sau unsubscribe cần yêu cầu mới và xác nhận mailbox. Record subscription xác nhận ghi nhận đúng thế hệ suppression trước yêu cầu; unsubscribe mới tạo thế hệ mới nên chặn cả link cũ lẫn quyền xác nhận cũ. Không xóa option suppression legacy hoặc bản ghi bảo vệ hàng loạt. Import không có thẩm quyền xác nhận này và không gỡ opt-out. 98 - Nguồn **Subscribed email addresses** dùng record hiện có, bao gồm guest không tài khoản/đơn hàng; chỉ lấy subscribed còn hiệu lực. Không áp dụng product/order/country/roles/manual criteria của nguồn khác. Draft/saved audience/preview/duplicate/lịch/controls dùng đường hiện có. Worker kiểm tra lại đăng ký trước handoff; unsubscribe hoặc trạng thái unknown sau preview không được gửi trong nguồn này. Campaign đã xác nhận không lấy thêm subscriber mới. 99 - **Subscribers → Contact history by email** tra cứu chính xác email trên bảng recipient hiện có, 50 dòng/trang: campaign, subject/context còn được lưu, due/updated time UTC, outcome và lý do, liên kết mở campaign. Không query đơn live để khôi phục context. Retention chỉ còn outcome sẽ báo nội dung không còn; tombstone erasure chặn toàn bộ lịch sử plaintext. 100 - Anti-abuse dùng nonce/honeypot trên form và quota nguyên tử dưới mutex privacy hiện có: một yêu cầu/email mỗi 10 phút, tối đa 5/client mỗi 30 phút, 100/site mỗi giờ. Client chỉ dùng HMAC của REMOTE_ADDR (không tin X-Forwarded-For, không lưu IP gốc); quota chung NAT có thể giới hạn nhiều khách cùng mạng. Phản hồi công khai không cho biết email đã tồn tại, unsubscribed hay erased. Pending request/counter hết hạn được dọn qua reconciliation hàng giờ; không tự retry confirmation mail khi transport mơ hồ. 101 - Confirmation mail là thư xác minh theo yêu cầu, có thể gửi tới địa chỉ đang unsubscribed để chính chủ đăng ký lại; không dùng đường này cho campaign. Nó dùng WooCommerce template/sender của shop và transport WordPress, không được trình bày như campaign handoff trong contact history. Kiểm thử chặn toàn bộ mail ra ngoài, không xác minh SMTP/inbox thật. 102 - Erasure giữ nguyên protective hash và không cho signup mới phục hồi dữ liệu/subscriber đã erase. Pending request được scrub cùng dữ liệu cá nhân hiện có; export bổ sung nguồn/thời gian yêu cầu, không xuất token. Việc đăng ký lại sau unsubscribe chỉ thay lựa chọn tương lai, không dựng lại history, không replay campaign cũ, không tự thay outcome unknown. 103 104 Bộ kiểm chứng mới: `subscriptions.php`, `checkout-subscription.php`, `contact-history.php` và concurrency cho request/confirm/unsubscribe/erasure. Bằng chứng theo candidate và giới hạn runtime ghi trong PR; không thêm service, bảng CRM hoặc cơ chế tracking mở/nhấp email. 105 106 107 ## Purchase history and Completed-order guides (AN-7) 108 109 Compose and saved audiences support `purchase_frequency` (`first`/`repeat`) and `inactive_days` (1–36500). These criteria scan valid purchases across the whole store, separately from same-order product/category/date/status/country conditions. Identity is normalized billing email, including guest/account orders; different emails are never inferred to be the same customer. Valid purchases are Processing/Completed orders excluding full refunds; a partial refund counts while value remains, and free orders without refunds count. Inactivity uses the latest valid order creation instant and X × 24 hours. Never-buyers and orders with unavailable dates do not qualify. 110 111 Automations supports one fixed guide per rule/order after a new Completed transition. Save disabled, inspect conditions/content/delay, preview or test with an accessible order, then explicitly Enable. Test mail goes only to its entered address and never saves/enables a rule or creates a delivery job. Products/variations and category descendants reuse the existing same-order matching behavior. Each eligible order can receive its own guide even when another order shares the email. 112 113 The event stores an immutable campaign manifest using a deterministic rule/order identity. Repeated events, items and workers reuse the same identity. Delay is an exact UTC offset from capture; queue delays never roll the due time to another day. Edits affect future events only. Disable rotates the enabled generation, durably blocks pending campaigns and cancels their unstarted rows. Re-enable cannot revive them. Work already admitted may finish. History and contact lookup retain the exact triggering order and result. 114 115 Before handoff the rule generation, fresh order, billing email and saved product/category conditions are rechecked. An order must still be Completed and not fully refunded; other states are skipped, partial refunds remain eligible while value remains. Active subscription is required and checked again after email rendering. Unknown never becomes subscribed through purchase. Existing suppression, erasure, claim, rate, recovery and unknown-handoff protections apply. 116 117 Only new events are admitted; there is no historical backfill. Captured manifests interrupted before their history row are registered by existing reconciliation and deactivation. A database/process failure before durable capture cannot be reconstructed without a new transition: the WooCommerce logger records a non-personal capture error. Operators must investigate storage/history and any mail-provider ambiguity before manually changing order status; the plugin never automatically replays an unknown handoff. No external event service or general automation builder is added. 118 119 120 Automation authoring follows the same four-step layout as Compose: **Conditions → Content → Timing → Review**. Content uses the shared WooCommerce live preview, Visual/Code editor and Desktop/Mobile controls. Live preview retains placeholders; Review refreshes the exact order sample through the existing server renderer. Preview/test returns to Review and preserves the unsaved form. Changing content, conditions, timing or sample order hides the old personal preview and asks for a refresh. Saving and enabling remain separate operations; list controls always use the saved configuration. The campaign-history link opens the campaign list so pending guides are discoverable. -
yoohw-advanced-notifications/tags/0.4.0/includes/class-customer-email-notify.php
r3771948 r3789014 10 10 require_once __DIR__ . '/trait-campaign-audiences.php'; 11 11 require_once __DIR__ . '/trait-campaign-privacy.php'; 12 require_once __DIR__ . '/trait-campaign-entrypoints.php'; 13 require_once __DIR__ . '/trait-campaign-personalization.php'; 14 require_once __DIR__ . '/trait-campaign-subscriptions.php'; 15 require_once __DIR__ . '/trait-campaign-checkout.php'; 16 require_once __DIR__ . '/trait-campaign-contact-history.php'; 17 require_once __DIR__ . '/trait-campaign-purchase-history.php'; 18 require_once __DIR__ . '/trait-campaign-automations.php'; 19 require_once __DIR__ . '/trait-campaign-automation-ui.php'; 12 20 13 21 class YOOHW_AN_Customer_Email_Notify { … … 17 25 use YOOHW_AN_Campaign_Audiences; 18 26 use YOOHW_AN_Campaign_Privacy; 27 use YOOHW_AN_Campaign_Entrypoints; 28 use YOOHW_AN_Campaign_Personalization; 29 use YOOHW_AN_Campaign_Subscriptions; 30 use YOOHW_AN_Campaign_Checkout; 31 use YOOHW_AN_Campaign_Contact_History; 32 use YOOHW_AN_Campaign_Purchase_History; 33 use YOOHW_AN_Campaign_Automations; 34 use YOOHW_AN_Campaign_Automation_UI; 19 35 20 36 const ACTION_SEND_SINGLE_EMAIL = 'yoohw_an_send_single_email'; … … 50 66 const SOURCE_REGISTERED_USERS = 'registered_users'; 51 67 const SOURCE_WOOCOMMERCE_CUSTOMERS = 'woocommerce_customers'; 68 const SOURCE_SUBSCRIBED = 'subscribed_emails'; 69 const SOURCE_SELECTED_ORDERS = 'selected_orders'; 52 70 const SOURCE_MANUAL_EMAILS = 'manual_emails'; 53 71 … … 56 74 private $last_mail_error = ''; 57 75 private $mail_handoff_started = false; 76 private $last_automation_outcome = ''; 58 77 private $current_action_id = 0; 59 78 private $recovery_enabled = true; … … 63 82 public function __construct() { 64 83 $this->register_operator_features(); 84 $this->register_contextual_entrypoints(); 85 $this->register_subscriptions(); 86 $this->register_automations(); 65 87 // Register after WooCommerce sorts Marketing at priority 99 to preserve our position. 66 88 add_action( 'admin_menu', [ $this, 'add_submenu' ], 100 ); … … 143 165 public function deactivate() { 144 166 $this->recovery_enabled = false; 167 $this->register_automation_manifests(); 145 168 $this->block_campaigns_on_deactivation(); 146 169 wp_unschedule_hook( self::ACTION_RECONCILE_CAMPAIGNS ); … … 176 199 177 200 public function reconcile_open_campaigns( $campaign_id = '' ) { 201 $this->reconcile_automation_campaigns(); 178 202 $campaigns = $this->get_campaign_history(); 179 203 $campaign_id = sanitize_text_field( $campaign_id ); … … 781 805 782 806 $active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'campaign'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin navigation, filters and notices; no state is changed. 807 808 if ( 'automations' === $active_tab ) { $this->render_automations_page(); return; } 783 809 784 810 if ( 'library' === $active_tab ) { … … 1155 1181 ); 1156 1182 ?> 1157 <p><?php /* translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. */ esc_html_e( ' Body variables: {customer_name} uses the saved recipient name, falling back to email; {product_name} is the shared campaign product label, never a personal purchase. With no product selection it uses the audience label. Subject and heading are literal.', 'yoohw-advanced-notifications' ); ?></p>1183 <p><?php /* translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. */ esc_html_e( 'Variables in subject, heading and body: {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products}, {order_url}. Order variables use the matching order with the highest order ID; preview shows its number and the matching order count. Without order context they are empty; missing names use Customer. {product_name} remains the shared campaign label. Order links require the matching account login; guests have no order link. The live editor shows template text; Preview Recipients and test email use the first eligible recipient.', 'yoohw-advanced-notifications' ); ?></p> 1158 1184 <p><?php esc_html_e( 'An unsubscribe link is added automatically to campaign emails.', 'yoohw-advanced-notifications' ); ?></p> 1159 1185 </div> … … 1296 1322 'campaigns' => [ 'label' => __( 'Campaigns', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'campaigns' ] ) ], 1297 1323 'campaign' => [ 'label' => __( 'Compose', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url() ], 1324 'automations' => [ 'label' => __( 'Automations', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'automations' ] ) ], 1298 1325 'library' => [ 'label' => __( 'Library', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'library' ] ) ], 1299 1326 'subscribers' => [ 'label' => __( 'Subscribers', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'subscribers' ] ) ], … … 2325 2352 ); 2326 2353 2327 $test_message = str_replace( 2328 [ 2329 '{customer_name}', 2330 '{product_name}', 2331 ], 2332 [ 2333 __( 'Test Customer', 'yoohw-advanced-notifications' ), 2334 $payload['products_label'], 2335 ], 2336 $payload['message'] 2337 ); 2354 $test_recipients = $this->get_recipients_by_payload( $payload ); 2355 $personal = $this->render_personalized_email( $payload, $test_recipients[0] ?? [ 'name' => __( 'Test Customer', 'yoohw-advanced-notifications' ), 'email' => $test_email ] ); 2356 $test_message = $personal['message']; 2338 2357 $test_message = $this->append_unsubscribe_footer( $test_message, $test_email, $payload['campaign_id'] ); 2339 2358 2340 2359 $sent = $this->send_woocommerce_email( 2341 2360 $test_email, 2342 '[TEST] ' . $p ayload['subject'],2343 $p ayload['heading'],2361 '[TEST] ' . $personal['subject'], 2362 $personal['heading'], 2344 2363 $test_message, 2345 2364 $payload['from_email'], … … 2488 2507 } 2489 2508 2509 if ( self::SOURCE_SUBSCRIBED === ( $payload['recipient_source'] ?? '' ) || ! empty( $payload['automation'] ) ) { $email_payload['subscription_required'] = true; } 2510 if ( ! empty( $payload['automation'] ) ) { $email_payload['automation'] = $payload['automation']; } 2511 if ( ! empty( $payload['personalization_version'] ) ) { $email_payload['personalization_version'] = absint( $payload['personalization_version'] ); $email_payload['store_name'] = sanitize_text_field( $payload['store_name'] ?? get_bloginfo( 'name' ) ); } 2512 2490 2513 $payload_hash = hash( 'sha256', wp_json_encode( $email_payload ) ); 2491 2514 $payload_key = $this->get_campaign_payload_option_name( $campaign_id, $delivery_id ); … … 2565 2588 $this->campaign_payload_cache[ $payload_key ] = $record; 2566 2589 2567 foreach ( [ 'subject', 'heading', 'message', 'products_label', 'from_email', 'from_name', 'reply_to_email' ] as $field ) {2590 foreach ( [ 'subject', 'heading', 'message', 'products_label', 'from_email', 'from_name', 'reply_to_email', 'personalization_version', 'store_name', 'subscription_required', 'automation' ] as $field ) { 2568 2591 $args[ $field ] = isset( $record['payload'][ $field ] ) ? $record['payload'][ $field ] : ''; 2569 2592 } 2570 2593 2594 if ( ! empty( $args['personalization_version'] ) ) { 2595 $manifest = $this->read_durable_option( $this->campaign_manifest_key( $campaign_id ) ); 2596 $found = false; 2597 foreach ( (array) ( $manifest['recipients'] ?? [] ) as $recipient ) { 2598 if ( strtolower( $recipient['email'] ?? '' ) === strtolower( $args['to'] ?? '' ) && ! empty( $recipient['email'] ) ) { 2599 $args['order_context'] = $this->sanitize_order_context( $recipient['order_context'] ?? [] ); 2600 $found = true; break; 2601 } 2602 } 2603 if ( ! $found ) { return new WP_Error( 'missing_recipient_context', __( 'Confirmed recipient context is unavailable. No email was handed off.', 'yoohw-advanced-notifications' ) ); } 2604 } 2571 2605 return $args; 2572 2606 } … … 2777 2811 } 2778 2812 $options_valid = $this->validate_recipient_source_options( [ 2813 'order_ids' => $this->parse_selected_order_ids( wp_unslash( $_POST['order_ids'] ?? '' ) ), 2779 2814 'recipient_source' => $recipient_source, 'user_roles' => $user_roles, 2780 2815 'manual_emails' => $manual_emails, 'test_mode' => $test_mode, … … 2829 2864 2830 2865 private function generate_campaign_hash( $payload ) { 2831 $hash_payload = [ ' filters' => $payload['filters'] ?? [], 'schedule_policy' => $payload['schedule_policy'] ?? '', 'store_timezone' => $payload['store_timezone'] ?? '',2866 $hash_payload = [ 'order_ids' => $payload['order_ids'] ?? [], 'personalization_version' => $payload['personalization_version'] ?? 0, 'store_name' => $payload['store_name'] ?? '', 'filters' => $payload['filters'] ?? [], 'schedule_policy' => $payload['schedule_policy'] ?? '', 'store_timezone' => $payload['store_timezone'] ?? '', 2832 2867 'recipient_source' => isset( $payload['recipient_source'] ) ? (string) $payload['recipient_source'] : self::SOURCE_PRODUCT_CUSTOMERS, 2833 2868 'product_ids' => isset( $payload['product_ids'] ) ? array_map( 'absint', (array) $payload['product_ids'] ) : [], … … 3075 3110 ); 3076 3111 3077 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone', 'schedule_summary' ] as $field ) { if ( isset( $payload[ $field ] ) ) { $entry[ $field ] = $payload[ $field ]; } }3112 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone', 'schedule_summary', 'order_ids', 'personalization_version', 'store_name', 'automation' ] as $field ) { if ( isset( $payload[ $field ] ) ) { $entry[ $field ] = $payload[ $field ]; } } 3078 3113 $entry['status_counts'] = isset( $existing['status_counts'] ) && is_array( $existing['status_counts'] ) 3079 3114 ? $this->sanitize_count_map( $existing['status_counts'] ) … … 3327 3362 ]; 3328 3363 3329 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone' ] as $field ) { if ( isset( $campaign[ $field ] ) ) { $payload[ $field ] = $campaign[ $field ]; } }3364 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone', 'order_ids', 'personalization_version', 'store_name', 'automation' ] as $field ) { if ( isset( $campaign[ $field ] ) ) { $payload[ $field ] = $campaign[ $field ]; } } 3330 3365 if ( empty( $payload['products_label'] ) ) { 3331 3366 $payload['products_label'] = ! empty( $payload['product_ids'] ) … … 3429 3464 private function sanitize_recipient_context( $recipient ) { 3430 3465 return [ 3466 'order_context' => $this->sanitize_order_context( $recipient['order_context'] ?? [] ), 3431 3467 'user_id' => isset( $recipient['user_id'] ) ? absint( $recipient['user_id'] ) : 0, 3432 3468 'email' => isset( $recipient['email'] ) ? sanitize_email( $recipient['email'] ) : '', … … 3899 3935 3900 3936 private function get_recipient_scheduled_delivery( $payload, $recipient, $roll_forward = true, $reference_time = null ) { 3937 if ( ! empty( $payload['automation']['due'] ) ) { return [ 'timestamp' => (int) $payload['automation']['due'], 'timezone' => 'UTC', 'fallback' => false, 'country' => '', 'state' => '', 'city' => '', 'rolled_forward_days' => 0 ]; } 3901 3938 if ( isset( $payload['schedule_policy'] ) ) { return $this->operator_schedule( $payload, $recipient ); } 3902 3939 $reference_time = null === $reference_time ? time() : absint( $reference_time ); … … 4251 4288 private function get_recipient_sources() { 4252 4289 $sources = [ 4290 self::SOURCE_SUBSCRIBED => __( 'Subscribed email addresses', 'yoohw-advanced-notifications' ), 4291 self::SOURCE_SELECTED_ORDERS => __( 'Selected orders', 'yoohw-advanced-notifications' ), 4253 4292 self::SOURCE_PRODUCT_CUSTOMERS => __( 'Product customers', 'yoohw-advanced-notifications' ), 4254 4293 self::SOURCE_WOOCOMMERCE_CUSTOMERS => __( 'WooCommerce customers', 'yoohw-advanced-notifications' ), … … 4283 4322 4284 4323 private function validate_recipient_source_options( $payload ) { 4324 $selected = $this->validate_selected_orders( $payload ); 4325 if ( is_wp_error( $selected ) ) { return $selected; } 4285 4326 $valid = $this->validate_audience_filters( $payload ); 4286 4327 if ( is_wp_error( $valid ) ) { return $valid; } … … 4351 4392 4352 4393 switch ( $recipient_source ) { 4394 case self::SOURCE_SUBSCRIBED: 4395 return $this->get_subscribed_recipients(); 4396 4397 case self::SOURCE_SELECTED_ORDERS: 4398 return $this->get_order_customer_recipients( null, $payload['filters'] ?? [], $payload['order_ids'] ?? [] ); 4399 4353 4400 case self::SOURCE_REGISTERED_USERS: 4354 4401 return $this->get_registered_user_recipients( [], isset( $payload['user_roles'] ) ? $payload['user_roles'] : [] ); … … 4502 4549 $record = $this->read_durable_option( 'yoohw_an_optout_' . hash( 'sha256', $email ) ); 4503 4550 if ( $this->read_durable_option( 'yoohw_an_erased_' . hash( 'sha256', $email ) ) ) { return true; } 4504 if ( is_array( $record ) && ( ! empty( $record['suppressed'] ) || $email === ( $record['email'] ?? '' ) ) ) { return true; }4551 if ( is_array( $record ) && ( ! empty( $record['suppressed'] ) || $email === ( $record['email'] ?? '' ) ) ) { return ! $this->confirmed_suppression_override( $email ); } 4505 4552 $legacy = $this->normalize_unsubscribed_emails( $this->read_durable_option( self::OPTION_UNSUBSCRIBED_EMAILS ) ); 4506 return isset( $legacy[ $email ] ) ;4553 return isset( $legacy[ $email ] ) && ! $this->confirmed_suppression_override( $email ); 4507 4554 } 4508 4555 … … 4515 4562 } 4516 4563 } 4517 return $this->normalize_unsubscribed_emails( $stored);4564 return array_filter( $this->normalize_unsubscribed_emails( $stored ), function ( $record, $email ) { return ! $this->confirmed_suppression_override( $email ); }, ARRAY_FILTER_USE_BOTH ); 4518 4565 } 4519 4566 … … 4559 4606 try { 4560 4607 $key = 'yoohw_an_optout_' . hash( 'sha256', $email ); 4561 $data = $this->read_durable_option( 'yoohw_an_erased_' . hash( 'sha256', $email ) ) ? [ 'suppressed' => true ] : [ 'email' => $email, 'unsubscribed_at' => time(), ' campaign_id' => sanitize_text_field( $campaign_id ) ];4608 $data = $this->read_durable_option( 'yoohw_an_erased_' . hash( 'sha256', $email ) ) ? [ 'suppressed' => true ] : [ 'email' => $email, 'unsubscribed_at' => time(), 'generation' => wp_generate_uuid4(), 'campaign_id' => sanitize_text_field( $campaign_id ) ]; 4562 4609 $data = $this->scrub_erased_references( $data ); 4563 $this->write_durable_option( $key, $data, true );4610 if ( false === $this->write_durable_option( $key, $data ) ) { return false; } 4564 4611 $saved = $this->read_durable_option( $key ); 4565 return is_array( $saved ) && ( ! empty( $saved['suppressed'] ) || $email === ( $saved['email'] ?? '' ) );4612 return $data === $saved; 4566 4613 } finally { $this->release_campaign_lock( '__privacy__' ); } 4567 4614 } … … 4886 4933 } 4887 4934 try { 4888 $message = str_replace( [ '{customer_name}', '{product_name}' ], [ $args['name'] ?? $to, $args['products_label'] ?? '' ], $args['message'] ); 4935 $automation_check = $this->automation_delivery_check( $args ); 4936 if ( is_wp_error( $automation_check ) ) { 4937 $outcome = 'automation_cancelled' === $automation_check->get_error_code() ? 'cancelled' : ( 'automation_ineligible' === $automation_check->get_error_code() ? 'skipped' : 'failed' ); 4938 $this->finish_delivery( $campaign_id, $delivery_id, $to, $claim, $outcome, $automation_check->get_error_message(), 'failed' === $outcome ? 'configuration' : '' ); return; 4939 } 4940 if ( ! empty( $args['subscription_required'] ) && 'subscribed' !== $this->subscription_record( $to )['status'] ) { 4941 $this->finish_delivery( $campaign_id, $delivery_id, $to, $claim, 'skipped_unsubscribed', __( 'No active subscription before send.', 'yoohw-advanced-notifications' ) ); 4942 return; 4943 } 4944 $personal = $this->render_personalized_email( $args, array_merge( $args, [ 'email' => $to ] ) ); 4945 $message = $personal['message']; 4889 4946 $message = $this->append_unsubscribe_footer( $message, $to, $campaign_id ); 4890 4947 // Read the durable opt-out immediately before entering the sending path. … … 4894 4951 } 4895 4952 $this->mail_handoff_started = false; 4896 $sent = $this->send_woocommerce_email( $to, $args['subject'], $args['heading'], $message, $args['from_email'] ?? '', $args['from_name'] ?? '', $args['reply_to_email'] ?? '' ); 4897 $status = $sent ? 'sent' : ( $this->mail_handoff_started ? 'unknown' : ( $this->is_email_unsubscribed( $to ) ? 'skipped_unsubscribed' : 'failed' ) ); 4953 $sent = $this->send_woocommerce_email( $to, $personal['subject'], $personal['heading'], $message, $args['from_email'] ?? '', $args['from_name'] ?? '', $args['reply_to_email'] ?? '', ! empty( $args['subscription_required'] ), $args['automation'] ?? [] ); 4954 $status = $sent ? 'sent' : ( $this->mail_handoff_started ? 'unknown' : ( ( $this->is_email_unsubscribed( $to ) || ( ! empty( $args['subscription_required'] ) && 'subscribed' !== $this->subscription_record( $to )['status'] ) ) ? 'skipped_unsubscribed' : 'failed' ) ); 4955 if ( ! $sent && ! $this->mail_handoff_started && $this->last_automation_outcome ) { $status = $this->last_automation_outcome; } 4898 4956 $this->finish_delivery( $campaign_id, $delivery_id, $to, $claim, $status, 4899 4957 $sent ? __( 'Mail system accepted the request; inbox delivery is not verified.', 'yoohw-advanced-notifications' ) : ( $this->last_mail_error ?: __( 'Mail transport returned no confirmation. Check the mail provider before sending again.', 'yoohw-advanced-notifications' ) ), … … 4967 5025 } 4968 5026 4969 private function get_order_customer_recipients( $product_ids = null, $filters = [] ) { 5027 private function get_order_customer_recipients( $product_ids = null, $filters = [], $order_ids = null ) { 5028 if ( null !== $order_ids && ! $order_ids ) { return []; } 4970 5029 $all_products = null === $product_ids; 4971 5030 $product_ids = $all_products ? [] : $product_ids; … … 5024 5083 $orders = wc_get_orders( 5025 5084 [ 5085 'post__in' => null === $order_ids ? [] : $order_ids, 5026 5086 'limit' => self::ORDER_QUERY_LIMIT, 5027 5087 'paged' => $page, 5028 'status' => ! empty( $filters['order_statuses'] ) ? $filters['order_statuses'] : [ 'processing', 'completed' ],5088 'status' => ! empty( $filters['order_statuses'] ) ? $filters['order_statuses'] : ( null === $order_ids ? [ 'processing', 'completed' ] : array_keys( wc_get_order_statuses() ) ), 5029 5089 'return' => 'objects', 5030 5090 'orderby' => 'ID', … … 5042 5102 } 5043 5103 5104 if ( null !== $order_ids && ! in_array( (int) $order->get_id(), $order_ids, true ) ) { continue; } 5044 5105 if ( ! $this->order_matches_filters( $order, $filters ) ) { continue; } 5045 5106 $has_product = $all_products; … … 5076 5137 $email = strtolower( sanitize_email( $order->get_billing_email() ) ); 5077 5138 5078 if ( ! is_email( $email ) || isset( $customers[ $email ] ) ) { 5079 continue; 5080 } 5139 if ( ! is_email( $email ) ) { continue; } 5140 if ( isset( $customers[ $email ] ) ) { $customers[ $email ]['order_context']['count']++; continue; } 5081 5141 5082 5142 $name = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ); … … 5086 5146 'email' => $email, 5087 5147 'name' => $name ?: $email, 5148 'order_context' => $this->context_from_order( $order ), 5088 5149 'country' => $this->normalize_country_code( $order->get_billing_country() ), 5089 5150 'state' => $this->normalize_location_part( $order->get_billing_state() ), … … 5235 5296 } 5236 5297 5237 private function send_woocommerce_email( $to, $subject, $heading, $message, $from_email = '', $from_name = '', $reply_to_email = '' ) { 5298 private function send_woocommerce_email( $to, $subject, $heading, $message, $from_email = '', $from_name = '', $reply_to_email = '', $require_subscription = false, $automation = [], $sample_email_hash = '' ) { 5299 $this->last_automation_outcome = ''; 5238 5300 $email_body = $this->build_woocommerce_email_body( $heading, $message ); 5239 5301 5240 5302 if ( false === $email_body ) { 5241 5303 $this->last_mail_error = __( 'WooCommerce mailer is unavailable.', 'yoohw-advanced-notifications' ); 5304 return false; 5305 } 5306 5307 if ( $sample_email_hash && $this->read_durable_option( 'yoohw_an_erased_' . $sample_email_hash ) ) { 5308 $this->last_mail_error = __( 'The sample was erased before test mail handoff.', 'yoohw-advanced-notifications' ); return false; 5309 } 5310 5311 $check = $this->automation_delivery_check( [ 'automation' => $automation, 'to' => $to ] ); 5312 if ( is_wp_error( $check ) ) { 5313 $this->last_automation_outcome = 'automation_cancelled' === $check->get_error_code() ? 'cancelled' : ( 'automation_ineligible' === $check->get_error_code() ? 'skipped' : 'failed' ); 5314 $this->last_mail_error = $check->get_error_message(); return false; 5315 } 5316 5317 if ( $require_subscription && 'subscribed' !== $this->subscription_record( $to )['status'] ) { 5318 $this->last_mail_error = __( 'No active subscription before mail handoff.', 'yoohw-advanced-notifications' ); 5242 5319 return false; 5243 5320 } -
yoohw-advanced-notifications/tags/0.4.0/includes/trait-campaign-audiences.php
r3771948 r3789014 7 7 $raw = wp_unslash( $_POST['audience_filters'] ?? [] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each scalar/list is type checked, sanitized below and strictly validated by validate_audience_filters(). 8 8 $filters = []; 9 $scalar_keys = [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode' ];9 $scalar_keys = [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'purchase_frequency', 'inactive_days' ]; 10 10 $list_keys = [ 'category_ids', 'order_statuses' ]; 11 11 if ( ! is_array( $raw ) || array_diff( array_keys( $raw ), array_merge( $scalar_keys, $list_keys ) ) ) { return [ 'invalid_input' => true ]; } 12 12 foreach ( $scalar_keys as $key ) { if ( isset( $raw[ $key ] ) && ! is_string( $raw[ $key ] ) ) { return [ 'invalid_input' => true ]; } } 13 13 foreach ( $list_keys as $key ) { if ( isset( $raw[ $key ] ) && ( ! is_array( $raw[ $key ] ) || array_filter( $raw[ $key ], static function ( $value ) { return ! is_string( $value ); } ) ) ) { return [ 'invalid_input' => true ]; } } 14 foreach ( [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode' ] as $key ) { $filters[ $key ] = sanitize_text_field( $raw[ $key ] ?? '' ); }14 foreach ( [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'purchase_frequency', 'inactive_days' ] as $key ) { $filters[ $key ] = sanitize_text_field( $raw[ $key ] ?? '' ); } 15 15 foreach ( [ 'category_ids', 'order_statuses' ] as $key ) { $filters[ $key ] = array_map( 'sanitize_text_field', (array) ( $raw[ $key ] ?? [] ) ); } 16 16 return $filters; … … 19 19 private function validate_audience_filters( $p ) { 20 20 $f = $p['filters'] ?? []; 21 $invalid = new WP_Error( 'invalid_filters', __( 'Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country and campaign history; no condition has been ignored.', 'yoohw-advanced-notifications' ) );22 if ( ! is_array( $f ) || array_diff( array_keys( $f ), [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'category_ids', 'order_statuses' ] ) ) { return $invalid; }21 $invalid = new WP_Error( 'invalid_filters', __( 'Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country, purchase history and campaign history; no condition has been ignored.', 'yoohw-advanced-notifications' ) ); 22 if ( ! is_array( $f ) || array_diff( array_keys( $f ), [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'category_ids', 'order_statuses', 'purchase_frequency', 'inactive_days' ] ) ) { return $invalid; } 23 23 foreach ( [ 'category_ids', 'order_statuses' ] as $key ) { if ( isset( $f[ $key ] ) && ! is_array( $f[ $key ] ) ) { return $invalid; } } 24 if ( ! in_array( $f['purchase_frequency'] ?? '', [ '', 'first', 'repeat' ], true ) ) { return $invalid; } 25 if ( isset( $f['inactive_days'] ) && '' !== $f['inactive_days'] && ( ( ! is_string( $f['inactive_days'] ) && ! is_int( $f['inactive_days'] ) ) || ! ctype_digit( (string) $f['inactive_days'] ) || (int) $f['inactive_days'] < 1 || (int) $f['inactive_days'] > 36500 ) ) { return $invalid; } 24 26 $source = $p['recipient_source'] ?? ''; 25 $order_source = in_array( $source, [ self::SOURCE_PRODUCT_CUSTOMERS, self::SOURCE_WOOCOMMERCE_CUSTOMERS ], true ); 27 if ( self::SOURCE_SUBSCRIBED === $source && ( ! empty( $p['product_ids'] ) || ! empty( $p['user_roles'] ) || ! empty( $p['manual_emails'] ) ) ) { return $invalid; } 28 $order_source = in_array( $source, [ self::SOURCE_PRODUCT_CUSTOMERS, self::SOURCE_WOOCOMMERCE_CUSTOMERS, self::SOURCE_SELECTED_ORDERS ], true ); 26 29 foreach ( [ 'date_from', 'date_to', 'last_days', 'category_ids', 'order_statuses' ] as $field ) { if ( ! $order_source && ! empty( $f[ $field ] ) ) { return $invalid; } } 27 if ( self::SOURCE_MANUAL_EMAILS === $source&& ! empty( $f['country'] ) ) { return $invalid; }30 if ( in_array( $source, [ self::SOURCE_MANUAL_EMAILS, self::SOURCE_SUBSCRIBED ], true ) && ! empty( $f['country'] ) ) { return $invalid; } 28 31 foreach ( [ 'date_from', 'date_to' ] as $field ) { 29 32 if ( isset( $f[ $field ] ) && '' !== $f[ $field ] ) { … … 66 69 } 67 70 private function subscription_record( $email ) { 68 if ( $this->is_email_unsubscribed( $email ) ) { return [ 'status' => 'unsubscribed', 'source' => 'suppression' ]; } 69 return $this->read_durable_option( 'yoohw_an_subscription_' . hash( 'sha256', strtolower( $email ) ) ) ?: [ 'status' => 'unknown', 'source' => '', 'recorded_at' => 0 ]; 71 $email = strtolower( $email ); 72 $record = $this->is_email_unsubscribed( $email ) ? [ 'status' => 'unsubscribed', 'source' => 'suppression' ] : ( $this->read_durable_option( 'yoohw_an_subscription_' . hash( 'sha256', $email ) ) ?: [ 'status' => 'unknown', 'source' => '', 'recorded_at' => 0 ] ); 73 $pending = $this->read_durable_option( 'yoohw_an_signup_' . hash( 'sha256', $email ) ); 74 if ( is_array( $pending ) && ( $pending['email'] ?? '' ) === $email && ! empty( $pending['token_hash'] ) && ( $pending['expires'] ?? 0 ) > time() ) { $record['confirmation_pending'] = true; $record['request_source'] = $pending['source']; $record['requested_at'] = $pending['requested_at']; } 75 return $record; 70 76 } 71 77 private function apply_audience_filters( $recipients, $p ) { 72 78 if ( is_wp_error( $this->validate_audience_filters( $p ) ) ) { return []; } 73 79 $f = $p['filters'] ?? []; 80 $recipients = $this->apply_purchase_history_filters( $recipients, $f ); 74 81 $result = []; 75 82 $history = []; … … 129 136 } 130 137 private function render_audience_fields( $p ) { 138 $this->render_selected_orders_field( $p ); 131 139 $f = $p['filters'] ?? []; 132 140 $invalid = is_wp_error( $this->validate_audience_filters( $p ) ); 141 $this->render_purchase_history_fields( $f, $invalid ); 133 142 if ( $invalid ) { echo '<p role="alert">' . esc_html__( 'Saved conditions are invalid or unavailable. They remain selected; correct or explicitly remove them before previewing.', 'yoohw-advanced-notifications' ) . '</p>'; } 134 143 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Audience conditions', 'yoohw-advanced-notifications' ) . '</h2><div class="an-order-filters"><div class="an-form-grid an-form-grid-three">'; 135 144 foreach ( [ 'date_from' => [ 'date', __( 'Order created from (store timezone)', 'yoohw-advanced-notifications' ) ], 'date_to' => [ 'date', __( 'Through date (inclusive)', 'yoohw-advanced-notifications' ) ], 'last_days' => [ 'number', __( 'Or last N × 24 hours', 'yoohw-advanced-notifications' ) ] ] as $key => $field ) { echo '<div class="an-field"><label>' . esc_html( $field[1] ) . ' <input type="' . esc_attr( $invalid ? 'text' : $field[0] ) . '" name="audience_filters[' . esc_attr( $key ) . ']" value="' . esc_attr( $f[ $key ] ?? '' ) . '"></label></div>'; } 136 echo '</div><div class="an-form-grid"><div class="an-field"><label>' . esc_html__( 'Matching order statuses ( defaultprocessing/completed)', 'yoohw-advanced-notifications' ) . '<select multiple name="audience_filters[order_statuses][]">';145 echo '</div><div class="an-form-grid"><div class="an-field"><label>' . esc_html__( 'Matching order statuses (selected orders: all; other sources: processing/completed)', 'yoohw-advanced-notifications' ) . '<select multiple name="audience_filters[order_statuses][]">'; 137 146 foreach ( $this->get_order_status_options() as $key => $label ) { echo '<option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $f['order_statuses'] ?? [], true ), true, false ) . '>' . esc_html( $label ) . '</option>'; } 138 147 $this->render_unavailable_options( $f['order_statuses'] ?? [], array_keys( $this->get_order_status_options() ) ); … … 156 165 $f = array_filter( $p['filters'] ?? [], static function ( $value ) { return '' !== $value && [] !== $value; } ); 157 166 if ( ! $f ) { return; } 158 $labels = [ ' date_from' => __( 'Order created from', 'yoohw-advanced-notifications' ), 'date_to' => __( 'Through date', 'yoohw-advanced-notifications' ), 'last_days' => __( 'Last N days', 'yoohw-advanced-notifications' ), 'country' => __( 'Billing country', 'yoohw-advanced-notifications' ), 'subscription' => __( 'Subscription status', 'yoohw-advanced-notifications' ), 'history_campaign' => __( 'History campaign', 'yoohw-advanced-notifications' ), 'history_mode' => __( 'Handoff condition', 'yoohw-advanced-notifications' ), 'category_ids' => __( 'Categories including descendants', 'yoohw-advanced-notifications' ), 'order_statuses' => __( 'Matching order statuses', 'yoohw-advanced-notifications' ) ];167 $labels = [ 'purchase_frequency' => __( 'Store-wide purchase frequency', 'yoohw-advanced-notifications' ), 'inactive_days' => __( 'Days without a valid store-wide purchase', 'yoohw-advanced-notifications' ), 'date_from' => __( 'Order created from', 'yoohw-advanced-notifications' ), 'date_to' => __( 'Through date', 'yoohw-advanced-notifications' ), 'last_days' => __( 'Last N days', 'yoohw-advanced-notifications' ), 'country' => __( 'Billing country', 'yoohw-advanced-notifications' ), 'subscription' => __( 'Subscription status', 'yoohw-advanced-notifications' ), 'history_campaign' => __( 'History campaign', 'yoohw-advanced-notifications' ), 'history_mode' => __( 'Handoff condition', 'yoohw-advanced-notifications' ), 'category_ids' => __( 'Categories including descendants', 'yoohw-advanced-notifications' ), 'order_statuses' => __( 'Matching order statuses', 'yoohw-advanced-notifications' ) ]; 159 168 echo '<h3>' . esc_html__( 'Saved audience conditions', 'yoohw-advanced-notifications' ) . '</h3><table class="widefat striped">'; 160 169 foreach ( $f as $key => $value ) { 161 170 $values = (array) $value; 171 if ( 'purchase_frequency' === $key ) { $options = [ 'first' => __( 'First-time buyer (one valid order)', 'yoohw-advanced-notifications' ), 'repeat' => __( 'Repeat buyer (at least two valid orders)', 'yoohw-advanced-notifications' ) ]; $values = [ $options[ $value ] ?? $value ]; } 162 172 if ( 'order_statuses' === $key ) { $options = $this->get_order_status_options(); $values = array_map( static function ( $status ) use ( $options ) { return $options[ $status ] ?? $status; }, $values ); } 163 173 if ( 'category_ids' === $key ) { $values = array_map( static function ( $id ) { $term = get_term( (int) $id, 'product_cat' ); return $term && ! is_wp_error( $term ) ? $term->name . ' (#' . $id . ')' : '#' . $id; }, $values ); } … … 177 187 $reason = __( 'Not in the selected source or product purchasers.', 'yoohw-advanced-notifications' ); 178 188 if ( in_array( $email, array_column( $baseline, 'email' ), true ) ) { $reason = __( 'No single order matches all order conditions, or billing country is missing/different.', 'yoohw-advanced-notifications' ); } 179 if ( in_array( $email, array_column( $filtered, 'email' ), true ) ) { $reason = __( 'S ubscription status or known campaign handoff condition does not match.', 'yoohw-advanced-notifications' ); }189 if ( in_array( $email, array_column( $filtered, 'email' ), true ) ) { $reason = __( 'Store-wide purchase history, subscription status or known campaign handoff condition does not match.', 'yoohw-advanced-notifications' ); } 180 190 if ( in_array( $email, array_column( $filtered_common, 'email' ), true ) ) { $reason = __( 'Matched source and all conditions; removed by an explicit exclusion.', 'yoohw-advanced-notifications' ); } 181 191 if ( in_array( $email, array_column( $this->get_recipients_by_payload( $p ), 'email' ), true ) ) { $reason = __( 'Included: matches source and every applicable condition; no exclusion matched.', 'yoohw-advanced-notifications' ); } -
yoohw-advanced-notifications/tags/0.4.0/includes/trait-campaign-authoring.php
r3771948 r3789014 12 12 } 13 13 private function draft_fields() { 14 return [ ' internal_name', 'subject', 'heading', 'message', 'recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'schedule_mode', 'scheduled_at_input', 'filters', 'test_email' ];15 } 16 private function criteria_fields() { return [ ' recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'filters' ]; }14 return [ 'order_ids', 'personalization_version', 'internal_name', 'subject', 'heading', 'message', 'recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'schedule_mode', 'scheduled_at_input', 'filters', 'test_email' ]; 15 } 16 private function criteria_fields() { return [ 'order_ids', 'recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'filters' ]; } 17 17 private function save_draft( $payload, $id = '' ) { 18 18 $id = $id ?: ( $payload['draft_id'] ?? wp_generate_uuid4() ); … … 37 37 $p['exclude_emails_raw'] = sanitize_textarea_field( $post['exclude_emails'] ?? '' ); 38 38 $p['exclusions'] = [ 'product_ids' => array_map( 'absint', (array) ( $post['exclude_product_ids'] ?? [] ) ), 'order_statuses' => array_map( 'sanitize_key', (array) ( $post['exclude_order_statuses'] ?? [] ) ), 'emails' => $this->parse_email_list( $p['exclude_emails_raw'] ) ]; 39 $p['order_ids'] = $this->parse_selected_order_ids( $post['order_ids'] ?? '' ); 40 if ( is_wp_error( $p['order_ids'] ) ) { wp_die( esc_html( $p['order_ids']->get_error_message() ) ); } 41 $p['personalization_version'] = 1; 42 $p['store_name'] = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 39 43 $p['filters'] = $this->filters_from_request(); 40 44 return $p; … … 61 65 $p['internal_name'] = sanitize_text_field( wp_unslash( $_POST['internal_name'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Caller verifies nonce. 62 66 $p['filters'] = $this->filters_from_request(); 67 $p['order_ids'] = $this->parse_selected_order_ids( wp_unslash( $_POST['order_ids'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Caller verifies nonce. 68 if ( is_wp_error( $p['order_ids'] ) ) { return $p['order_ids']; } 69 $p['personalization_version'] = 1; 70 $p['store_name'] = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 71 $valid = $this->validate_selected_orders( $p ); 72 if ( is_wp_error( $valid ) ) { return $valid; } 63 73 $p['schedule_policy'] = 'strict_v1'; 64 74 $p['store_timezone'] = wp_timezone_string(); … … 120 130 if ( ! $drafts ) { echo '<p>' . esc_html__( 'No saved drafts yet.', 'yoohw-advanced-notifications' ) . '</p>'; } 121 131 foreach ( $drafts as $draft ) { 122 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'draft_id' => $draft['draft_id'] ] ) ) . '">' . esc_html( $draft['internal_name'] ?: ( $draft['subject']?: $draft['draft_id'] ) ) . '</a>';132 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'draft_id' => $draft['draft_id'] ] ) ) . '">' . esc_html( ( $draft['internal_name'] ?? '' ) ?: ( ( $draft['subject'] ?? '' ) ?: $draft['draft_id'] ) ) . '</a>'; 123 133 $this->library_button( $draft['draft_id'], 'delete_draft', __( 'Delete draft', 'yoohw-advanced-notifications' ) ); 124 134 echo '</div>'; … … 128 138 if ( ! $audiences ) { echo '<p>' . esc_html__( 'No saved audiences yet.', 'yoohw-advanced-notifications' ) . '</p>'; } 129 139 foreach ( $audiences as $audience ) { 130 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ) . '</a>';140 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ?? $audience['id'] ) . '</a>'; 131 141 $this->library_button( $audience['id'], 'delete_audience', __( 'Delete audience', 'yoohw-advanced-notifications' ) ); 132 142 echo '</div>'; … … 140 150 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Saved audience criteria', 'yoohw-advanced-notifications' ) . '</h2><p>'; 141 151 foreach ( $this->read_durable_options( 'yoohw_an_audience_' ) as $audience ) { 142 echo '<a class="button" href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ) . '</a> ';152 echo '<a class="button" href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ?? $audience['id'] ) . '</a> '; 143 153 } 144 154 echo '<a href="' . esc_url( $this->get_admin_page_url( [ 'tab' => 'library' ] ) ) . '">' . esc_html__( 'Open Library', 'yoohw-advanced-notifications' ) . '</a></p><p class="description">' . esc_html__( 'Opening saved criteria replaces this form. Save your draft first to keep current edits.', 'yoohw-advanced-notifications' ) . '</p><input type="hidden" name="audience_id" value="' . esc_attr( $p['audience_id'] ?? '' ) . '"><div class="an-form-row"><label class="an-field">' . esc_html__( 'Audience name', 'yoohw-advanced-notifications' ) . ' <input name="audience_name" value="' . esc_attr( $p['audience_name'] ?? '' ) . '"></label> <button class="button" formnovalidate name="authoring_operation" value="save_audience">' . esc_html__( 'Save audience criteria', 'yoohw-advanced-notifications' ) . '</button></div></section>'; … … 147 157 echo '<section class="yoohw-advanced-notifications-panel an-template-field"><label for="an-template">' . esc_html__( 'Insert editable content template', 'yoohw-advanced-notifications' ) . '</label><p><select id="an-template"><option value="">—</option>'; 148 158 $templates = [ 149 'update' => [ __( 'Product or documentation update', 'yoohw-advanced-notifications' ), __( 'An update for you', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>We have updated {product_name}. Add the details and documentation link here.</p>', 'yoohw-advanced-notifications' ) ],150 'guide' => [ __( 'After-purchase guide', 'yoohw-advanced-notifications' ), __( 'Getting started', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>Thank you for your purchase . Add setup steps and support detailshere.</p>', 'yoohw-advanced-notifications' ) ],151 'service' => [ __( 'Service or order change', 'yoohw-advanced-notifications' ), __( 'Service update', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>A dd the change, effective date and any action neededhere.</p>', 'yoohw-advanced-notifications' ) ],159 'update' => [ __( 'Product or documentation update', 'yoohw-advanced-notifications' ), __( 'An update for you', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>We have updated {product_name}. Describe what changed, when it applies, and add the documentation link and any action needed. Contact our support team if you need help.</p>', 'yoohw-advanced-notifications' ) ], 160 'guide' => [ __( 'After-purchase guide', 'yoohw-advanced-notifications' ), __( 'Getting started', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>Thank you for your purchase of {ordered_products} (order {order_number}). Add setup or care steps, when to follow them, and a support contact here.</p>', 'yoohw-advanced-notifications' ) ], 161 'service' => [ __( 'Service or order change', 'yoohw-advanced-notifications' ), __( 'Service update', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>An update about order {order_number}: describe the change and the new delivery date or effective time. Explain any action needed and add a support contact here.</p>', 'yoohw-advanced-notifications' ) ], 152 162 ]; 153 163 foreach ( $templates as $key => $template ) { echo '<option value="' . esc_attr( $key ) . '" data-subject="' . esc_attr( $template[1] ) . '" data-body="' . esc_attr( $template[2] ) . '">' . esc_html( $template[0] ) . '</option>'; } … … 217 227 if ( ! empty( $_GET['audience_changed'] ) ) { echo '<p class="notice notice-warning" role="alert">' . esc_html__( 'Audience changed since preview. Review this updated preview and confirm again.', 'yoohw-advanced-notifications' ) . '</p>'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended 218 228 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Recipients and schedule to confirm', 'yoohw-advanced-notifications' ) . '</h2><dl class="an-preview-counts"><div><dt>' . esc_html__( 'Selected', 'yoohw-advanced-notifications' ) . '</dt><dd>' . esc_html( number_format_i18n( $p['recipient_count'] ?? 0 ) ) . '</dd></div><div><dt>' . esc_html__( 'Excluded', 'yoohw-advanced-notifications' ) . '</dt><dd>' . esc_html( number_format_i18n( $p['excluded_count'] ?? 0 ) ) . '</dd></div></dl>'; 219 $reason_labels = [ 'order_conditions' => __( 'Removed by order conditions', 'yoohw-advanced-notifications' ), 'subscription_or_history' => __( 'Removed by subscription or campaign history', 'yoohw-advanced-notifications' ), 'explicit_exclusions_or_suppression' => __( 'Removed by exclusions or suppression', 'yoohw-advanced-notifications' ) ];229 $reason_labels = [ 'order_conditions' => __( 'Removed by order conditions', 'yoohw-advanced-notifications' ), 'subscription_or_history' => __( 'Removed by purchase history, subscription or campaign history', 'yoohw-advanced-notifications' ), 'explicit_exclusions_or_suppression' => __( 'Removed by exclusions or suppression', 'yoohw-advanced-notifications' ) ]; 220 230 echo '<dl class="an-review-facts">'; 221 231 foreach ( $p['audience_audit'] ?? [] as $reason => $count ) { echo '<div><dt>' . esc_html( $reason_labels[ $reason ] ?? $reason ) . '</dt><dd>' . esc_html( number_format_i18n( $count ) ) . '</dd></div>'; } … … 239 249 echo '</select></div><button class="button">' . esc_html__( 'Show sample', 'yoohw-advanced-notifications' ) . '</button></form>'; 240 250 $this->render_preview_device_controls(); 241 $message = str_replace( [ '{customer_name}', '{product_name}' ], [ $sample['name'] ?: $sample['email'], $p['products_label'] ?? '' ], $p['message'] ); 251 $personal = $this->render_personalized_email( $p, $sample ); 252 echo '<p>' . esc_html( $personal['subject'] ) . '</p>'; 253 $this->render_order_context_summary( $sample ); 254 $message = $personal['message']; 242 255 $message = $this->append_unsubscribe_footer( $message, $sample['email'], $p['campaign_id'] ); 243 $html = $this->build_woocommerce_email_body( $p ['heading'], $message );256 $html = $this->build_woocommerce_email_body( $personal['heading'], $message ); 244 257 echo '<iframe class="an-personal-preview" sandbox="" title="' . esc_attr__( 'Personalized email preview', 'yoohw-advanced-notifications' ) . '" srcdoc="' . esc_attr( $html ) . '"></iframe></section>'; 245 258 } -
yoohw-advanced-notifications/tags/0.4.0/includes/trait-campaign-privacy.php
r3771948 r3789014 121 121 echo '<div class="wrap yoohw-an-workspace"><h1>' . esc_html__( 'Email campaigns', 'yoohw-advanced-notifications' ) . '</h1>'; 122 122 $this->render_page_tabs( 'subscribers' ); 123 $this->render_contact_history(); 123 124 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Subscribers and suppression', 'yoohw-advanced-notifications' ) . '</h2><p>' . esc_html__( 'An order, account or pasted email is not opt-in evidence. Unknown remains unknown. Imports never remove an unsubscribe. For subscribed records, enter the actual evidence source; the recorded time is the import time, not an inferred original consent time.', 'yoohw-advanced-notifications' ) . '</p>'; 124 125 $search = strtolower( sanitize_text_field( wp_unslash( $_GET['subscription_search'] ?? '' ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended … … 130 131 foreach ( $this->read_durable_options( 'yoohw_an_subscription_' ) as $record ) { if ( ! empty( $record['email'] ) ) { $records[ $record['email'] ] = $record; } } 131 132 foreach ( $this->get_unsubscribed_emails() as $email => $record ) { $records[ $email ] = array_merge( (array) $record, $records[ $email ] ?? [], [ 'status' => 'unsubscribed' ] ); } 132 if ( is_email( $search ) && ! isset( $records[ $search ] )) { $records[ $search ] = $this->subscription_record( $search ); }133 if ( is_email( $search ) ) { $records[ $search ] = $this->subscription_record( $search ); } 133 134 $count = 0; 134 135 foreach ( $records as $email => $record ) { … … 138 139 $timestamp = $record['recorded_at'] ?? ( $record['unsubscribed_at'] ?? 0 ); 139 140 echo '<tr><td>' . esc_html( $email . ' / ' . $record['status'] ) . '</td><td>' . esc_html( ( $record['source'] ?? 'legacy/unsubscribe' ) . ' / ' . ( $timestamp ? gmdate( 'Y-m-d H:i:s', is_numeric( $timestamp ) ? (int) $timestamp : strtotime( $timestamp ) ) : '—' ) ) . '</td></tr>'; 141 if ( ! empty( $record['confirmation_pending'] ) ) { echo '<tr><td colspan="2">' . esc_html__( 'Confirmation pending; current subscription unchanged.', 'yoohw-advanced-notifications' ) . ' ' . esc_html( $record['request_source'] . ' / ' . gmdate( 'Y-m-d H:i:s', $record['requested_at'] ) ) . '</td></tr>'; } 140 142 } echo '</table><p>' . esc_html__( 'Up to 200 matches. Erased addresses are represented only by protective hashes and are not listed as plaintext.', 'yoohw-advanced-notifications' ) . '</p>'; 141 143 echo '</section><section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Import records', 'yoohw-advanced-notifications' ) . '</h2><p>' . esc_html__( '1. Paste → 2. Preview → 3. Apply and review result', 'yoohw-advanced-notifications' ) . '</p><form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '"><input type="hidden" name="action" value="yoohw_an_data"><input type="hidden" name="operation" value="preview_import">'; wp_nonce_field( 'yoohw_an_data' ); … … 179 181 $fields = []; 180 182 foreach ( $row as $name => $value ) { $fields[] = [ 'name' => $name, 'value' => $value ]; } 183 $manifest = $this->read_durable_option( $this->campaign_manifest_key( $row['campaign_id'] ) ); 184 foreach ( (array) ( $manifest['recipients'] ?? [] ) as $recipient ) { 185 if ( strtolower( $recipient['email'] ?? '' ) === $email && ! empty( $recipient['order_context'] ) ) { $fields[] = [ 'name' => __( 'Saved order context', 'yoohw-advanced-notifications' ), 'value' => wp_json_encode( $this->sanitize_order_context( $recipient['order_context'] ) ) ]; } 186 } 181 187 $data[] = [ 'group_id' => 'yoohw-an', 'group_label' => __( 'Email campaigns', 'yoohw-advanced-notifications' ), 'item_id' => 'yoohw-an-' . $row['campaign_id'] . '-' . $page . '-' . $index, 'data' => $fields ]; 182 188 } 183 189 if ( 1 === (int) $page ) { 184 190 $record = $this->subscription_record( $email ); 191 $pending = $this->read_durable_option( 'yoohw_an_signup_' . $hash ); 192 if ( is_array( $pending ) && ( $pending['email'] ?? '' ) === $email ) { $record['pending_request'] = array_intersect_key( $pending, array_flip( [ 'source', 'requested_at', 'expires', 'consumed_at' ] ) ); } 185 193 $record['suppression_evidence'] = $this->read_durable_option( 'yoohw_an_optout_' . $hash ) ?: ( $this->get_unsubscribed_emails()[ $email ] ?? [] ); 186 194 $record['protective_erasure_hash'] = (bool) $this->read_durable_option( 'yoohw_an_erased_' . $hash ); … … 203 211 if ( is_array( $value ) ) { 204 212 if ( strtolower( $value['email'] ?? $value['to'] ?? '' ) === $email ) { 205 foreach ( [ 'email', 'to', 'name', 'recipient_name', 'country', 'state', 'city', 'timezone', 'user_id' ] as $field ) { if ( isset( $value[ $field ] ) ) { $value[ $field ] = ''; } }213 foreach ( [ 'email', 'to', 'name', 'recipient_name', 'country', 'state', 'city', 'timezone', 'user_id', 'order_context' ] as $field ) { if ( isset( $value[ $field ] ) ) { $value[ $field ] = ''; } } 206 214 } 207 215 $result = []; -
yoohw-advanced-notifications/tags/0.4.0/languages/yoohw-advanced-notifications.pot
r3771948 r3789014 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Advanced Notifications for WooCommerce 0. 3.0\n"5 "Project-Id-Version: Advanced Notifications for WooCommerce 0.4.0\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/yoohw-advanced-notifications\n" 7 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" … … 10 10 "Content-Type: text/plain; charset=UTF-8\n" 11 11 "Content-Transfer-Encoding: 8bit\n" 12 "POT-Creation-Date: 2026-1 0-29T02:04:10+00:00\n"12 "POT-Creation-Date: 2026-11-07T03:47:04+00:00\n" 13 13 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 14 "X-Generator: WP-CLI 2.9.0\n" … … 35 35 msgstr "" 36 36 37 #: includes/class-customer-email-notify.php:1 6137 #: includes/class-customer-email-notify.php:184 38 38 msgid "Plugin deactivated before delivery." 39 39 msgstr "" 40 40 41 #: includes/class-customer-email-notify.php:3 6541 #: includes/class-customer-email-notify.php:389 42 42 msgid "Privacy cleanup is busy. Campaign preparation will resume." 43 43 msgstr "" 44 44 45 #: includes/class-customer-email-notify.php:3 7245 #: includes/class-customer-email-notify.php:396 46 46 msgid "Campaign recipients could not be prepared for background dispatch." 47 47 msgstr "" 48 48 49 #: includes/class-customer-email-notify.php: 37849 #: includes/class-customer-email-notify.php:402 50 50 msgid "Recipient tracking storage is unavailable." 51 51 msgstr "" 52 52 53 #: includes/class-customer-email-notify.php:4 1353 #: includes/class-customer-email-notify.php:437 54 54 msgid "Invalid scheduled date/time. Create a new campaign with a valid time." 55 55 msgstr "" 56 56 57 #: includes/class-customer-email-notify.php:4 7557 #: includes/class-customer-email-notify.php:499 58 58 msgid "Recipient dispatch storage failed." 59 59 msgstr "" 60 60 61 #: includes/class-customer-email-notify.php:7 1261 #: includes/class-customer-email-notify.php:736 62 62 msgid "Recipient preparation reached the limit of 3 queue attempts. Check Scheduled Actions for jobs saved before the interruption. Existing jobs may finish; recovery will not create further jobs for these recipients." 63 63 msgstr "" 64 64 65 #: includes/class-customer-email-notify.php:7 1865 #: includes/class-customer-email-notify.php:742 66 66 msgid "Dispatcher could not be queued. Check Action Scheduler, then use Recover / retry eligible recipients." 67 67 msgstr "" 68 68 69 #: includes/class-customer-email-notify.php:7 2769 #: includes/class-customer-email-notify.php:751 70 70 msgid "Recipient snapshot is incomplete. Recovery uses only saved recipients; it cannot recreate a lost historical audience. Review the stored records before creating a new campaign." 71 71 msgstr "" 72 72 73 #: includes/class-customer-email-notify.php:7 3173 #: includes/class-customer-email-notify.php:755 74 74 msgid "Delivery jobs are overdue. Check WordPress cron and WooCommerce Scheduled Actions. Existing pending jobs are retained; recovery will not create another send while they remain pending." 75 75 msgstr "" 76 76 77 #: includes/class-customer-email-notify.php:7 3577 #: includes/class-customer-email-notify.php:759 78 78 msgid "Some outcomes are unknown. Check the mail provider logs before creating another campaign for those addresses. Recovery never resends unknown outcomes." 79 79 msgstr "" 80 80 81 #: includes/class-customer-email-notify.php:7 3781 #: includes/class-customer-email-notify.php:761 82 82 msgid "Review recipient reasons below. Queue failures retry at least 5 minutes apart, up to 3 queue attempts. Correct configuration failures before recovery. Cancelled recipients require a new campaign." 83 83 msgstr "" 84 84 85 #: includes/class-customer-email-notify.php:7 4285 #: includes/class-customer-email-notify.php:766 86 86 msgid "Paused. Resume to continue remaining recipients." 87 87 msgstr "" 88 88 89 #: includes/class-customer-email-notify.php:763 90 #: includes/class-customer-email-notify.php:764 91 #: includes/class-customer-email-notify.php:848 92 #: includes/class-customer-email-notify.php:1356 93 #: includes/class-customer-email-notify.php:1839 94 #: includes/trait-campaign-authoring.php:112 89 #: includes/class-customer-email-notify.php:787 90 #: includes/class-customer-email-notify.php:788 91 #: includes/class-customer-email-notify.php:874 92 #: includes/class-customer-email-notify.php:1383 93 #: includes/class-customer-email-notify.php:1866 94 #: includes/trait-campaign-authoring.php:122 95 #: includes/trait-campaign-automation-ui.php:64 95 96 #: includes/trait-campaign-privacy.php:121 96 #: includes/trait-campaign-privacy.php:18197 97 #: includes/trait-campaign-privacy.php:187 98 #: includes/trait-campaign-privacy.php:198 98 #: includes/trait-campaign-privacy.php:195 99 #: includes/trait-campaign-privacy.php:206 99 100 msgid "Email campaigns" 100 101 msgstr "" 101 102 102 #: includes/class-customer-email-notify.php:8 54103 #: includes/class-customer-email-notify.php:2 879103 #: includes/class-customer-email-notify.php:880 104 #: includes/class-customer-email-notify.php:2914 104 105 msgid "The email preview expired. Please review the form and try again." 105 106 msgstr "" 106 107 107 #: includes/class-customer-email-notify.php:8 60108 #: includes/class-customer-email-notify.php:886 108 109 msgid "The shared campaign content could not be stored safely, so no email jobs were created. Review the campaign log or server error log before retrying." 109 110 msgstr "" 110 111 111 #: includes/class-customer-email-notify.php:8 66112 #: includes/class-customer-email-notify.php:892 112 113 msgid "Draft restored. You can edit it and preview recipients again." 113 114 msgstr "" 114 115 115 #: includes/class-customer-email-notify.php:8 70116 #: includes/class-customer-email-notify.php:896 116 117 msgid "The draft preview expired, so the form could not be restored." 117 118 msgstr "" 118 119 119 #: includes/class-customer-email-notify.php: 876120 #: includes/class-customer-email-notify.php:902 120 121 msgid "Recipients could not be prepared for background delivery, so no new email jobs were created." 121 122 msgstr "" 122 123 123 124 #. translators: %d: Number of recipients. 124 #: includes/class-customer-email-notify.php: 886125 #: includes/class-customer-email-notify.php:912 125 126 msgid "%d recipient(s) are being prepared in the background. You can leave this page; campaign status will update automatically." 126 127 msgstr "" 127 128 128 129 #. translators: %d: Number of recipients. 129 #: includes/class-customer-email-notify.php:9 01130 #: includes/class-customer-email-notify.php:927 130 131 msgid "Email queued for %d recipient(s). Emails will be sent in the background." 131 132 msgstr "" 132 133 133 134 #. translators: 1: Number of recipients. 2: Scheduled local date and time. 134 #: includes/class-customer-email-notify.php:9 17135 #: includes/class-customer-email-notify.php:943 135 136 msgid "Email scheduled for %1$d recipient(s). Local send time: %2$s. Timezone is derived from each recipient billing country; missing country uses UTC." 136 137 msgstr "" 137 138 138 #: includes/class-customer-email-notify.php:9 19139 #: includes/class-customer-email-notify.php:945 139 140 msgid "the selected time" 140 141 msgstr "" 141 142 142 143 #. translators: %d: Number of recipients. 143 #: includes/class-customer-email-notify.php:9 33144 #: includes/class-customer-email-notify.php:959 144 145 msgid "This campaign was already queued recently for %d recipient(s), so the duplicate submission was blocked." 145 146 msgstr "" 146 147 147 #: includes/class-customer-email-notify.php:9 47148 #: includes/class-customer-email-notify.php:973 148 149 msgid "Test email handed to the mail system. Inbox delivery is not verified." 149 150 msgstr "" 150 151 151 #: includes/class-customer-email-notify.php:9 48152 #: includes/class-customer-email-notify.php:974 152 153 msgid "Test email could not be sent." 153 154 msgstr "" 154 155 155 156 #. translators: %d: Number of recipients. 156 #: includes/class-customer-email-notify.php:9 60157 #: includes/class-customer-email-notify.php:986 157 158 msgid "Email sent to %d recipient(s)." 158 159 msgstr "" 159 160 160 #: includes/class-customer-email-notify.php:9 71161 #: includes/class-customer-email-notify.php:1 581162 #: includes/class-customer-email-notify.php:18 54161 #: includes/class-customer-email-notify.php:997 162 #: includes/class-customer-email-notify.php:1608 163 #: includes/class-customer-email-notify.php:1881 163 164 msgid "Sender" 164 165 msgstr "" 165 166 166 #: includes/class-customer-email-notify.php: 975167 #: includes/class-customer-email-notify.php:1 595168 #: includes/class-customer-email-notify.php:20 27167 #: includes/class-customer-email-notify.php:1001 168 #: includes/class-customer-email-notify.php:1622 169 #: includes/class-customer-email-notify.php:2054 169 170 msgid "Reply-To" 170 171 msgstr "" 171 172 172 173 #. translators: %s: effective no-reply address. 173 #: includes/class-customer-email-notify.php: 982174 #: includes/class-customer-email-notify.php:16 03175 #: includes/class-customer-email-notify.php:20 35174 #: includes/class-customer-email-notify.php:1008 175 #: includes/class-customer-email-notify.php:1630 176 #: includes/class-customer-email-notify.php:2062 176 177 msgid "%s (automatic replies suppressed)" 177 178 msgstr "" 178 179 179 #: includes/class-customer-email-notify.php: 991180 #: includes/class-customer-email-notify.php:1017 180 181 msgid "Edit Settings" 181 182 msgstr "" 182 183 183 #: includes/class-customer-email-notify.php:10 01184 #: includes/class-customer-email-notify.php:1027 184 185 msgid "Compose steps" 185 186 msgstr "" 186 187 187 #: includes/class-customer-email-notify.php:10 02188 #: includes/class-customer-email-notify.php:1028 188 189 msgid "1. Audience" 189 190 msgstr "" 190 191 191 #: includes/class-customer-email-notify.php:1002 192 #: includes/class-customer-email-notify.php:1028 193 #: includes/trait-campaign-automation-ui.php:94 192 194 msgid "2. Content" 193 195 msgstr "" 194 196 195 #: includes/class-customer-email-notify.php:10 02197 #: includes/class-customer-email-notify.php:1028 196 198 msgid "3. Schedule" 197 199 msgstr "" 198 200 199 #: includes/class-customer-email-notify.php:1002 201 #: includes/class-customer-email-notify.php:1028 202 #: includes/trait-campaign-automation-ui.php:94 200 203 msgid "4. Review" 201 204 msgstr "" 202 205 203 #: includes/class-customer-email-notify.php:10 12204 #: includes/class-customer-email-notify.php:14 19205 #: includes/class-customer-email-notify.php:14 31206 #: includes/class-customer-email-notify.php:15 49206 #: includes/class-customer-email-notify.php:1038 207 #: includes/class-customer-email-notify.php:1446 208 #: includes/class-customer-email-notify.php:1458 209 #: includes/class-customer-email-notify.php:1576 207 210 msgid "Audience" 208 211 msgstr "" 209 212 210 #: includes/class-customer-email-notify.php:10 13213 #: includes/class-customer-email-notify.php:1039 211 214 msgid "Choose who should receive this campaign." 212 215 msgstr "" 213 216 214 #: includes/class-customer-email-notify.php:10 17217 #: includes/class-customer-email-notify.php:1043 215 218 msgid "Some selections do not apply to this recipient source. Clear the highlighted selections explicitly or choose a compatible source before previewing." 216 219 msgstr "" 217 220 218 #: includes/class-customer-email-notify.php:10 20219 #: includes/class-customer-email-notify.php: 1974221 #: includes/class-customer-email-notify.php:1046 222 #: includes/class-customer-email-notify.php:2001 220 223 msgid "Recipient source" 221 224 msgstr "" 222 225 223 #: includes/class-customer-email-notify.php:10 28226 #: includes/class-customer-email-notify.php:1054 224 227 msgid "Product selection is only required for product customers." 225 228 msgstr "" 226 229 227 #: includes/class-customer-email-notify.php:10 31228 #: includes/class-customer-email-notify.php: 1979230 #: includes/class-customer-email-notify.php:1057 231 #: includes/class-customer-email-notify.php:2006 229 232 msgid "User roles" 230 233 msgstr "" 231 234 232 #: includes/class-customer-email-notify.php:10 32233 #: includes/class-customer-email-notify.php:4 264235 #: includes/class-customer-email-notify.php:1058 236 #: includes/class-customer-email-notify.php:4303 234 237 msgid "All roles" 235 238 msgstr "" 236 239 237 #: includes/class-customer-email-notify.php:10 37240 #: includes/class-customer-email-notify.php:1063 238 241 msgid "Match any selected role. Leave empty for all registered users, including administrators." 239 242 msgstr "" 240 243 241 #: includes/class-customer-email-notify.php:10 40244 #: includes/class-customer-email-notify.php:1066 242 245 msgid "Recipient email addresses" 243 246 msgstr "" 244 247 245 #: includes/class-customer-email-notify.php:10 42248 #: includes/class-customer-email-notify.php:1068 246 249 msgid "Enter email addresses separated by commas, semicolons, spaces, or line breaks. Duplicates are removed. Invalid addresses must be corrected. Recipient-local scheduling uses UTC for this list; store-time scheduling uses the store timezone." 247 250 msgstr "" 248 251 249 #: includes/class-customer-email-notify.php:10 44252 #: includes/class-customer-email-notify.php:1070 250 253 msgid "Includes billing email addresses from matching orders, including guests (processing/completed by default). Each email address is included once." 251 254 msgstr "" 252 255 253 #: includes/class-customer-email-notify.php:1047 254 #: includes/class-customer-email-notify.php:1985 256 #. translators: %d: Number of hours after the Completed event. 257 #: includes/class-customer-email-notify.php:1073 258 #: includes/class-customer-email-notify.php:2012 259 #: includes/trait-campaign-automation-ui.php:84 255 260 msgid "Products" 256 261 msgstr "" 257 262 258 #: includes/class-customer-email-notify.php:1054 263 #: includes/class-customer-email-notify.php:1080 264 #: includes/class-customer-email-notify.php:1125 265 #: includes/trait-campaign-automation-ui.php:99 266 msgid "Search products or variations" 267 msgstr "" 268 269 #: includes/class-customer-email-notify.php:1085 270 msgid "Include matching purchases of selected products or variations." 271 msgstr "" 272 273 #: includes/class-customer-email-notify.php:1093 274 #: includes/class-customer-email-notify.php:1592 275 #: includes/class-customer-email-notify.php:2031 276 msgid "Exclusions" 277 msgstr "" 278 279 #: includes/class-customer-email-notify.php:1094 280 msgid "Remove matched recipients from the final list." 281 msgstr "" 282 259 283 #: includes/class-customer-email-notify.php:1099 260 msgid "Search products or variations"261 msgstr ""262 263 #: includes/class-customer-email-notify.php:1059264 msgid "Include matching purchases of selected products or variations."265 msgstr ""266 267 #: includes/class-customer-email-notify.php:1067268 #: includes/class-customer-email-notify.php:1565269 #: includes/class-customer-email-notify.php:2004270 msgid "Exclusions"271 msgstr ""272 273 #: includes/class-customer-email-notify.php:1068274 msgid "Remove matched recipients from the final list."275 msgstr ""276 277 #: includes/class-customer-email-notify.php:1073278 284 msgid "Order statuses" 279 285 msgstr "" 280 286 281 #: includes/class-customer-email-notify.php:1 080287 #: includes/class-customer-email-notify.php:1106 282 288 msgid "No order statuses excluded" 283 289 msgstr "" 284 290 285 #: includes/class-customer-email-notify.php:1 088291 #: includes/class-customer-email-notify.php:1114 286 292 msgid "Example: exclude users with refunded orders." 287 293 msgstr "" 288 294 289 #: includes/class-customer-email-notify.php:1 092295 #: includes/class-customer-email-notify.php:1118 290 296 msgid "Product purchasers" 291 297 msgstr "" 292 298 293 #: includes/class-customer-email-notify.php:11 04299 #: includes/class-customer-email-notify.php:1130 294 300 msgid "Exclude people who already bought selected products." 295 301 msgstr "" 296 302 297 #: includes/class-customer-email-notify.php:11 08303 #: includes/class-customer-email-notify.php:1134 298 304 msgid "Manual emails" 299 305 msgstr "" 300 306 301 #: includes/class-customer-email-notify.php:11 14307 #: includes/class-customer-email-notify.php:1140 302 308 msgid "one@example.com, two@example.com" 303 309 msgstr "" 304 310 305 #: includes/class-customer-email-notify.php:11 15311 #: includes/class-customer-email-notify.php:1141 306 312 msgid "Comma, semicolon, space, or line break separated." 307 313 msgstr "" 308 314 309 #: includes/class-customer-email-notify.php:1128 315 #: includes/class-customer-email-notify.php:1154 316 #: includes/trait-campaign-automation-ui.php:106 310 317 msgid "Content" 311 318 msgstr "" 312 319 313 #: includes/class-customer-email-notify.php:11 29320 #: includes/class-customer-email-notify.php:1155 314 321 msgid "Compose the email shown inside the WooCommerce template." 315 322 msgstr "" 316 323 317 #: includes/class-customer-email-notify.php:1135 318 #: includes/class-customer-email-notify.php:1202 319 #: includes/class-customer-email-notify.php:1545 320 #: includes/class-customer-email-notify.php:2044 324 #: includes/class-customer-email-notify.php:1161 325 #: includes/class-customer-email-notify.php:1228 326 #: includes/class-customer-email-notify.php:1572 327 #: includes/class-customer-email-notify.php:2071 328 #: includes/trait-campaign-automation-ui.php:107 329 #: includes/trait-campaign-automation-ui.php:132 330 #: includes/trait-campaign-automation-ui.php:135 321 331 msgid "Subject" 322 332 msgstr "" 323 333 324 #: includes/class-customer-email-notify.php:1140 325 #: includes/class-customer-email-notify.php:5160 326 #: includes/class-customer-email-notify.php:5389 334 #: includes/class-customer-email-notify.php:1166 335 #: includes/class-customer-email-notify.php:5221 336 #: includes/class-customer-email-notify.php:5466 337 #: includes/trait-campaign-automation-ui.php:107 327 338 msgid "Email heading" 328 339 msgstr "" 329 340 330 #: includes/class-customer-email-notify.php:1145 331 #: includes/class-customer-email-notify.php:5147 332 #: includes/class-customer-email-notify.php:5390 341 #: includes/class-customer-email-notify.php:1171 342 #: includes/class-customer-email-notify.php:5208 343 #: includes/class-customer-email-notify.php:5467 344 #: includes/trait-campaign-automation-ui.php:108 333 345 msgid "Message body" 334 346 msgstr "" 335 347 336 348 #. translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. 337 #: includes/class-customer-email-notify.php:11 57338 msgid " Body variables: {customer_name} uses the saved recipient name, falling back to email; {product_name} is the shared campaign product label, never a personal purchase. With no product selection it uses the audience label. Subject and heading are literal."349 #: includes/class-customer-email-notify.php:1183 350 msgid "Variables in subject, heading and body: {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products}, {order_url}. Order variables use the matching order with the highest order ID; preview shows its number and the matching order count. Without order context they are empty; missing names use Customer. {product_name} remains the shared campaign label. Order links require the matching account login; guests have no order link. The live editor shows template text; Preview Recipients and test email use the first eligible recipient." 339 351 msgstr "" 340 352 341 353 #. translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. 342 #: includes/class-customer-email-notify.php:11 58354 #: includes/class-customer-email-notify.php:1184 343 355 msgid "An unsubscribe link is added automatically to campaign emails." 344 356 msgstr "" 345 357 346 #: includes/class-customer-email-notify.php:11 66358 #: includes/class-customer-email-notify.php:1192 347 359 msgid "Test" 348 360 msgstr "" 349 361 350 #: includes/class-customer-email-notify.php:11 67362 #: includes/class-customer-email-notify.php:1193 351 363 msgid "Send a single email without building the campaign queue." 352 364 msgstr "" 353 365 354 #: includes/class-customer-email-notify.php:1 174366 #: includes/class-customer-email-notify.php:1200 355 367 msgid "Enable test mode" 356 368 msgstr "" 357 369 358 #: includes/class-customer-email-notify.php:1 175370 #: includes/class-customer-email-notify.php:1201 359 371 msgid "Only the test recipient will receive this email." 360 372 msgstr "" 361 373 362 #: includes/class-customer-email-notify.php:1180 374 #: includes/class-customer-email-notify.php:1206 375 #: includes/trait-campaign-automation-ui.php:118 363 376 msgid "Test email address" 364 377 msgstr "" 365 378 366 #: includes/class-customer-email-notify.php:1 189367 #: includes/class-customer-email-notify.php:1 278379 #: includes/class-customer-email-notify.php:1215 380 #: includes/class-customer-email-notify.php:1304 368 381 msgid "Send Test Email" 369 382 msgstr "" 370 383 371 #: includes/class-customer-email-notify.php:1191 372 #: includes/class-customer-email-notify.php:1194 384 #: includes/class-customer-email-notify.php:1217 385 #: includes/class-customer-email-notify.php:1220 386 #: includes/trait-campaign-automation-ui.php:128 387 #: includes/trait-campaign-automation-ui.php:129 373 388 msgid "Email preview" 374 389 msgstr "" 375 390 376 #: includes/class-customer-email-notify.php:1195 391 #: includes/class-customer-email-notify.php:1221 392 #: includes/trait-campaign-automation-ui.php:129 377 393 msgid "Rendered with the active WooCommerce email template." 378 394 msgstr "" 379 395 380 #: includes/class-customer-email-notify.php:1197 396 #: includes/class-customer-email-notify.php:1223 397 #: includes/trait-campaign-automation-ui.php:129 381 398 msgid "Live" 382 399 msgstr "" 383 400 384 #: includes/class-customer-email-notify.php:12 03385 #: includes/class-customer-email-notify.php:5 388401 #: includes/class-customer-email-notify.php:1229 402 #: includes/class-customer-email-notify.php:5465 386 403 msgid "Email subject" 387 404 msgstr "" 388 405 389 #: includes/class-customer-email-notify.php:1210 406 #: includes/class-customer-email-notify.php:1236 407 #: includes/trait-campaign-automation-ui.php:132 390 408 msgid "WooCommerce email preview" 391 409 msgstr "" 392 410 393 #: includes/class-customer-email-notify.php:12 19411 #: includes/class-customer-email-notify.php:1245 394 412 msgid "Schedule" 395 413 msgstr "" 396 414 397 #: includes/class-customer-email-notify.php:12 20415 #: includes/class-customer-email-notify.php:1246 398 416 msgid "Choose when the campaign should be sent." 399 417 msgstr "" 400 418 401 #: includes/class-customer-email-notify.php:12 28419 #: includes/class-customer-email-notify.php:1254 402 420 msgid "Send after confirmation" 403 421 msgstr "" 404 422 405 #: includes/class-customer-email-notify.php:12 29423 #: includes/class-customer-email-notify.php:1255 406 424 msgid "Queue emails as soon as the preview is confirmed." 407 425 msgstr "" 408 426 409 #: includes/class-customer-email-notify.php:12 35427 #: includes/class-customer-email-notify.php:1261 410 428 msgid "Schedule for later" 411 429 msgstr "" 412 430 413 #: includes/class-customer-email-notify.php:12 36431 #: includes/class-customer-email-notify.php:1262 414 432 msgid "Legacy schedule restored. Choose an explicit store or local mode for this new campaign." 415 433 msgstr "" 416 434 417 #: includes/class-customer-email-notify.php:12 41435 #: includes/class-customer-email-notify.php:1267 418 436 msgid "One time in store timezone:" 419 437 msgstr "" 420 438 421 #: includes/class-customer-email-notify.php:12 41439 #: includes/class-customer-email-notify.php:1267 422 440 msgid "All recipients share one UTC due time." 423 441 msgstr "" 424 442 425 #: includes/class-customer-email-notify.php:12 42426 #: includes/trait-campaign-authoring.php:2 22443 #: includes/class-customer-email-notify.php:1268 444 #: includes/trait-campaign-authoring.php:232 427 445 msgid "Same local time per recipient (location estimate; UTC fallback)" 428 446 msgstr "" 429 447 430 #: includes/class-customer-email-notify.php:12 42448 #: includes/class-customer-email-notify.php:1268 431 449 msgid "Only unambiguous billing countries use a location estimate. Other countries, missing data and manual lists use UTC." 432 450 msgstr "" 433 451 434 #: includes/class-customer-email-notify.php:12 44452 #: includes/class-customer-email-notify.php:1270 435 453 msgid "Scheduled date/time" 436 454 msgstr "" 437 455 438 #: includes/class-customer-email-notify.php:12 51456 #: includes/class-customer-email-notify.php:1277 439 457 msgid "Store mode uses the displayed store timezone. Local mode uses a billing-location estimate only when unambiguous, otherwise UTC. Past, nonexistent or repeated local times are rejected; choose another time. No automatic next-day rollover." 440 458 msgstr "" 441 459 442 #: includes/class-customer-email-notify.php:12 57460 #: includes/class-customer-email-notify.php:1283 443 461 msgid "Review before confirmation" 444 462 msgstr "" 445 463 446 #: includes/class-customer-email-notify.php:12 58464 #: includes/class-customer-email-notify.php:1284 447 465 msgid "Preview Recipients opens the saved recipient preview with selected and excluded counts, reasons, personalized samples and confirmed due times. No audience estimate is calculated while you edit." 448 466 msgstr "" 449 467 450 #: includes/class-customer-email-notify.php:12 59468 #: includes/class-customer-email-notify.php:1285 451 469 msgid "Review that preview, then confirm there. Changes require another preview. Emails already handed to the mail system cannot be recalled; inbox delivery is not verified." 452 470 msgstr "" 453 471 454 #: includes/class-customer-email-notify.php:12 60472 #: includes/class-customer-email-notify.php:1286 455 473 msgid "Test mode sends only to the test address. Turn it off in Content to preview a campaign audience." 456 474 msgstr "" 457 475 458 #: includes/class-customer-email-notify.php:12 65459 #: includes/class-customer-email-notify.php:12 67476 #: includes/class-customer-email-notify.php:1291 477 #: includes/class-customer-email-notify.php:1293 460 478 msgid "Next step: preview recipients and confirm before sending." 461 479 msgstr "" 462 480 463 #: includes/class-customer-email-notify.php:12 66481 #: includes/class-customer-email-notify.php:1292 464 482 msgid "Test mode sends one email to the test recipient and keeps this draft for further edits." 465 483 msgstr "" 466 484 467 #: includes/class-customer-email-notify.php:12 71468 #: includes/class-customer-email-notify.php:1 277485 #: includes/class-customer-email-notify.php:1297 486 #: includes/class-customer-email-notify.php:1303 469 487 msgid "Preview Recipients" 470 488 msgstr "" 471 489 472 #: includes/class-customer-email-notify.php:1285 490 #: includes/class-customer-email-notify.php:1311 491 #: includes/trait-campaign-automation-ui.php:122 473 492 msgid "Back" 474 493 msgstr "" 475 494 476 #: includes/class-customer-email-notify.php:1286 495 #: includes/class-customer-email-notify.php:1312 496 #: includes/trait-campaign-automation-ui.php:122 477 497 msgid "Continue" 478 498 msgstr "" 479 499 480 #: includes/class-customer-email-notify.php:1 296500 #: includes/class-customer-email-notify.php:1322 481 501 msgid "Campaigns" 482 502 msgstr "" 483 503 484 #: includes/class-customer-email-notify.php:1 297504 #: includes/class-customer-email-notify.php:1323 485 505 msgid "Compose" 486 506 msgstr "" 487 507 488 #: includes/class-customer-email-notify.php:1298 508 #: includes/class-customer-email-notify.php:1324 509 #: includes/trait-campaign-automation-ui.php:80 510 msgid "Automations" 511 msgstr "" 512 513 #: includes/class-customer-email-notify.php:1325 489 514 msgid "Library" 490 515 msgstr "" 491 516 492 #: includes/class-customer-email-notify.php:1 299517 #: includes/class-customer-email-notify.php:1326 493 518 msgid "Subscribers" 494 519 msgstr "" 495 520 496 #: includes/class-customer-email-notify.php:13 00521 #: includes/class-customer-email-notify.php:1327 497 522 msgid "Settings" 498 523 msgstr "" 499 524 500 #: includes/class-customer-email-notify.php:13 44501 #: includes/class-customer-email-notify.php:1 380525 #: includes/class-customer-email-notify.php:1371 526 #: includes/class-customer-email-notify.php:1407 502 527 msgid "Campaign list" 503 528 msgstr "" 504 529 505 530 #. translators: %s: Campaign ID. 506 #: includes/class-customer-email-notify.php:13 49507 #: includes/class-customer-email-notify.php:16 70531 #: includes/class-customer-email-notify.php:1376 532 #: includes/class-customer-email-notify.php:1697 508 533 msgid "Recent campaign log" 509 534 msgstr "" 510 535 511 #: includes/class-customer-email-notify.php:13 60536 #: includes/class-customer-email-notify.php:1387 512 537 msgid "Handed to mail system means the sending request was accepted, not that the email reached an inbox. Queue failures retry automatically up to 3 attempts, at least 5 minutes apart. Known pre-transport failures require correcting the reported data or configuration, then recovery. Unknown outcomes require checking the mail provider before deciding to create a new campaign." 513 538 msgstr "" 514 539 515 #: includes/class-customer-email-notify.php:1 381540 #: includes/class-customer-email-notify.php:1408 516 541 msgid "Recent campaign previews, tests, queues, schedules, and send results are grouped by campaign." 517 542 msgstr "" 518 543 519 544 #. translators: %d: Number of campaigns. 520 #: includes/class-customer-email-notify.php:1 387545 #: includes/class-customer-email-notify.php:1414 521 546 msgid "%d campaign(s) stored" 522 547 msgstr "" 523 548 524 #: includes/class-customer-email-notify.php:1 397549 #: includes/class-customer-email-notify.php:1424 525 550 msgid "No campaign history has been created yet. Preview or send a campaign to start tracking it here." 526 551 msgstr "" 527 552 528 #: includes/class-customer-email-notify.php:14 16529 #: includes/class-customer-email-notify.php:14 28530 #: includes/class-customer-email-notify.php:17 11531 #: includes/class-customer-email-notify.php:17 21553 #: includes/class-customer-email-notify.php:1443 554 #: includes/class-customer-email-notify.php:1455 555 #: includes/class-customer-email-notify.php:1738 556 #: includes/class-customer-email-notify.php:1748 532 557 msgid "Campaign" 533 558 msgstr "" 534 559 535 #: includes/class-customer-email-notify.php:14 17536 #: includes/class-customer-email-notify.php:14 29537 #: includes/class-customer-email-notify.php:17 13538 #: includes/class-customer-email-notify.php:17 23539 #: includes/trait-campaign-privacy.php:14 2560 #: includes/class-customer-email-notify.php:1444 561 #: includes/class-customer-email-notify.php:1456 562 #: includes/class-customer-email-notify.php:1740 563 #: includes/class-customer-email-notify.php:1750 564 #: includes/trait-campaign-privacy.php:144 540 565 msgid "Status" 541 566 msgstr "" 542 567 543 #: includes/class-customer-email-notify.php:14 18544 #: includes/class-customer-email-notify.php:14 30545 #: includes/class-customer-email-notify.php:17 15546 #: includes/class-customer-email-notify.php:17 25568 #: includes/class-customer-email-notify.php:1445 569 #: includes/class-customer-email-notify.php:1457 570 #: includes/class-customer-email-notify.php:1742 571 #: includes/class-customer-email-notify.php:1752 547 572 msgid "Message" 548 573 msgstr "" 549 574 550 #: includes/class-customer-email-notify.php:14 20551 #: includes/class-customer-email-notify.php:14 32552 #: includes/class-customer-email-notify.php:1 577553 #: includes/class-customer-email-notify.php:20 52575 #: includes/class-customer-email-notify.php:1447 576 #: includes/class-customer-email-notify.php:1459 577 #: includes/class-customer-email-notify.php:1604 578 #: includes/class-customer-email-notify.php:2079 554 579 msgid "Delivery" 555 580 msgstr "" 556 581 557 #: includes/class-customer-email-notify.php:14 21558 #: includes/class-customer-email-notify.php:14 33582 #: includes/class-customer-email-notify.php:1448 583 #: includes/class-customer-email-notify.php:1460 559 584 msgid "Activity" 560 585 msgstr "" 561 586 562 #: includes/class-customer-email-notify.php:1422 563 #: includes/class-customer-email-notify.php:1434 587 #: includes/class-customer-email-notify.php:1449 588 #: includes/class-customer-email-notify.php:1461 589 #: includes/trait-campaign-contact-history.php:81 564 590 msgid "Updated" 565 591 msgstr "" 566 592 567 #: includes/class-customer-email-notify.php:14 23568 #: includes/class-customer-email-notify.php:14 35593 #: includes/class-customer-email-notify.php:1450 594 #: includes/class-customer-email-notify.php:1462 569 595 msgid "Actions" 570 596 msgstr "" 571 597 572 #: includes/class-customer-email-notify.php:14 59598 #: includes/class-customer-email-notify.php:1486 573 599 msgid "Test campaign" 574 600 msgstr "" 575 601 576 #: includes/class-customer-email-notify.php:14 63577 #: includes/class-customer-email-notify.php:15 06602 #: includes/class-customer-email-notify.php:1490 603 #: includes/class-customer-email-notify.php:1533 578 604 msgid "View log" 579 605 msgstr "" 580 606 581 #: includes/class-customer-email-notify.php:1 473607 #: includes/class-customer-email-notify.php:1500 582 608 msgid "(No subject)" 583 609 msgstr "" 584 610 585 611 #. translators: %s: Formatted creation date and time. 586 #: includes/class-customer-email-notify.php:1 496612 #: includes/class-customer-email-notify.php:1523 587 613 msgid "Created %s" 588 614 msgstr "" 589 615 590 #: includes/class-customer-email-notify.php:15 30616 #: includes/class-customer-email-notify.php:1557 591 617 msgid "The selected campaign could not be found in stored history." 592 618 msgstr "" 593 619 594 #: includes/class-customer-email-notify.php:15 37620 #: includes/class-customer-email-notify.php:1564 595 621 msgid "Campaign details" 596 622 msgstr "" 597 623 598 #: includes/class-customer-email-notify.php:15 41599 #: includes/class-customer-email-notify.php:19 70624 #: includes/class-customer-email-notify.php:1568 625 #: includes/class-customer-email-notify.php:1997 600 626 msgid "Campaign ID" 601 627 msgstr "" 602 628 603 #: includes/class-customer-email-notify.php:15 61629 #: includes/class-customer-email-notify.php:1588 604 630 msgid "Scope" 605 631 msgstr "" 606 632 607 #: includes/class-customer-email-notify.php:15 71633 #: includes/class-customer-email-notify.php:1598 608 634 msgid "None" 609 635 msgstr "" 610 636 611 #: includes/class-customer-email-notify.php:16 34637 #: includes/class-customer-email-notify.php:1661 612 638 msgid "Recover / retry eligible recipients" 613 639 msgstr "" 614 640 615 641 #. translators: %d: Number of scheduling failures. 616 #: includes/class-customer-email-notify.php:16 44642 #: includes/class-customer-email-notify.php:1671 617 643 msgid "%d eligible recipient(s). Recovery continues preparation and retries queue failures or known pre-transport failures, up to 3 attempts. Unknown outcomes are never retried. Unsubscribes are checked again." 618 644 msgstr "" 619 645 620 #: includes/class-customer-email-notify.php:16 55646 #: includes/class-customer-email-notify.php:1682 621 647 msgid "Historical schedule failures are recorded, but their recipient-level records are no longer complete. Automatic retry is disabled to prevent sending to the wrong or already handled recipients." 622 648 msgstr "" 623 649 624 650 #. translators: %s: Campaign ID. 625 #: includes/class-customer-email-notify.php:16 69651 #: includes/class-customer-email-notify.php:1696 626 652 msgid "Log for campaign %s" 627 653 msgstr "" 628 654 629 #: includes/class-customer-email-notify.php:1 674655 #: includes/class-customer-email-notify.php:1701 630 656 msgid "Latest stored send, queue, schedule, failure, skipped, and unsubscribe events." 631 657 msgstr "" 632 658 633 #: includes/class-customer-email-notify.php:1 678659 #: includes/class-customer-email-notify.php:1705 634 660 msgid "View all logs" 635 661 msgstr "" 636 662 637 #: includes/class-customer-email-notify.php:1 685663 #: includes/class-customer-email-notify.php:1712 638 664 msgid "No log entries found yet." 639 665 msgstr "" 640 666 641 #: includes/class-customer-email-notify.php:17 10642 #: includes/class-customer-email-notify.php:17 20667 #: includes/class-customer-email-notify.php:1737 668 #: includes/class-customer-email-notify.php:1747 643 669 msgid "Time" 644 670 msgstr "" 645 671 646 #: includes/class-customer-email-notify.php:17 12647 #: includes/class-customer-email-notify.php:17 22648 #: includes/class-customer-email-notify.php:2 075672 #: includes/class-customer-email-notify.php:1739 673 #: includes/class-customer-email-notify.php:1749 674 #: includes/class-customer-email-notify.php:2102 649 675 #: includes/trait-campaign-controls.php:179 650 676 msgid "Email" 651 677 msgstr "" 652 678 653 #: includes/class-customer-email-notify.php:17 14654 #: includes/class-customer-email-notify.php:17 24679 #: includes/class-customer-email-notify.php:1741 680 #: includes/class-customer-email-notify.php:1751 655 681 msgid "Action ID" 656 682 msgstr "" 657 683 658 #: includes/class-customer-email-notify.php:17 41684 #: includes/class-customer-email-notify.php:1768 659 685 msgid "unknown" 660 686 msgstr "" 661 687 662 #: includes/class-customer-email-notify.php:1 778688 #: includes/class-customer-email-notify.php:1805 663 689 msgid "The selected campaign could not be found." 664 690 msgstr "" 665 691 666 #: includes/class-customer-email-notify.php:1 779692 #: includes/class-customer-email-notify.php:1806 667 693 msgid "This campaign does not have enough stored email content to reschedule safely. For older campaigns, keep at least one pending scheduled action so Email campaigns can recover the message payload." 668 694 msgstr "" 669 695 670 #: includes/class-customer-email-notify.php:1 780696 #: includes/class-customer-email-notify.php:1807 671 697 msgid "Recipient-level failure records are incomplete, so automatic retry was blocked to prevent duplicate or incorrect delivery." 672 698 msgstr "" 673 699 674 #: includes/class-customer-email-notify.php:1 781700 #: includes/class-customer-email-notify.php:1808 675 701 msgid "The campaign content could not be stored safely, so no retry jobs were created." 676 702 msgstr "" 677 703 678 #: includes/class-customer-email-notify.php:1 782704 #: includes/class-customer-email-notify.php:1809 679 705 msgid "Failed recipients could not be prepared for background retry." 680 706 msgstr "" 681 707 682 #: includes/class-customer-email-notify.php:1 783708 #: includes/class-customer-email-notify.php:1810 683 709 msgid "The background retry dispatcher could not be queued." 684 710 msgstr "" 685 711 686 #: includes/class-customer-email-notify.php:1 784712 #: includes/class-customer-email-notify.php:1811 687 713 msgid "No stuck schedule-failed recipients were found for this campaign." 688 714 msgstr "" 689 715 690 #: includes/class-customer-email-notify.php:1 788716 #: includes/class-customer-email-notify.php:1815 691 717 msgid "The failed schedule retry could not be completed." 692 718 msgstr "" 693 719 694 720 #. translators: 1: Number of emails successfully rescheduled. 2: Number of failed retries. 695 #: includes/class-customer-email-notify.php:18 07721 #: includes/class-customer-email-notify.php:1834 696 722 msgid "Rescheduled %1$d failed email(s). %2$d retry attempt(s) failed." 697 723 msgstr "" 698 724 699 725 #. translators: %d: Number of recipients. 700 #: includes/class-customer-email-notify.php:18 25726 #: includes/class-customer-email-notify.php:1852 701 727 msgid "%d failed recipient(s) are being prepared for retry in the background." 702 728 msgstr "" 703 729 704 #: includes/class-customer-email-notify.php:18 45730 #: includes/class-customer-email-notify.php:1872 705 731 msgid "Email campaigns settings saved." 706 732 msgstr "" 707 733 708 #: includes/class-customer-email-notify.php:18 56734 #: includes/class-customer-email-notify.php:1883 709 735 msgid "From email" 710 736 msgstr "" 711 737 712 #: includes/class-customer-email-notify.php:18 66738 #: includes/class-customer-email-notify.php:1893 713 739 msgid "Used as the sender email for every campaign." 714 740 msgstr "" 715 741 716 #: includes/class-customer-email-notify.php:18 68742 #: includes/class-customer-email-notify.php:1895 717 743 msgid "From name" 718 744 msgstr "" 719 745 720 #: includes/class-customer-email-notify.php:1 877746 #: includes/class-customer-email-notify.php:1904 721 747 msgid "Reply-To email" 722 748 msgstr "" 723 749 724 #: includes/class-customer-email-notify.php:1 887750 #: includes/class-customer-email-notify.php:1914 725 751 msgid "Used when automated-reply suppression is disabled." 726 752 msgstr "" 727 753 728 #: includes/class-customer-email-notify.php:1 889754 #: includes/class-customer-email-notify.php:1916 729 755 msgid "No-reply email" 730 756 msgstr "" 731 757 732 #: includes/class-customer-email-notify.php:1 898758 #: includes/class-customer-email-notify.php:1925 733 759 msgid "Used as Reply-To while suppression is enabled, so non-compliant automatic responders do not reach the support inbox." 734 760 msgstr "" 735 761 736 #: includes/class-customer-email-notify.php:19 00762 #: includes/class-customer-email-notify.php:1927 737 763 msgid "Automated replies" 738 764 msgstr "" 739 765 740 #: includes/class-customer-email-notify.php:19 09766 #: includes/class-customer-email-notify.php:1936 741 767 msgid "Suppress out-of-office and other automatic replies" 742 768 msgstr "" 743 769 744 #: includes/class-customer-email-notify.php:19 12770 #: includes/class-customer-email-notify.php:1939 745 771 msgid "Adds standards-based bulk/automatic message headers while preserving delivery failure notifications." 746 772 msgstr "" 747 773 748 #: includes/class-customer-email-notify.php:19 15774 #: includes/class-customer-email-notify.php:1942 749 775 msgid "Save Settings" 750 776 msgstr "" 751 777 752 #: includes/class-customer-email-notify.php:19 28753 #: includes/class-customer-email-notify.php:19 63778 #: includes/class-customer-email-notify.php:1955 779 #: includes/class-customer-email-notify.php:1990 754 780 msgid "Preview email campaign" 755 781 msgstr "" 756 782 757 #: includes/class-customer-email-notify.php:19 34758 #: includes/class-customer-email-notify.php:21 33783 #: includes/class-customer-email-notify.php:1961 784 #: includes/class-customer-email-notify.php:2160 759 785 msgid "Back to email form" 760 786 msgstr "" 761 787 762 #: includes/class-customer-email-notify.php:19 48763 #: includes/class-customer-email-notify.php:42 53788 #: includes/class-customer-email-notify.php:1975 789 #: includes/class-customer-email-notify.php:4292 764 790 msgid "Product customers" 765 791 msgstr "" 766 792 767 #: includes/class-customer-email-notify.php:19 51768 #: includes/class-customer-email-notify.php:51 15793 #: includes/class-customer-email-notify.php:1978 794 #: includes/class-customer-email-notify.php:5176 769 795 msgid "selected product(s)" 770 796 msgstr "" 771 797 772 #: includes/class-customer-email-notify.php: 1990798 #: includes/class-customer-email-notify.php:2017 773 799 #: includes/trait-campaign-controls.php:172 774 800 msgid "Recipients" … … 776 802 777 803 #. translators: %d: Number of recipients. 778 #: includes/class-customer-email-notify.php: 1995804 #: includes/class-customer-email-notify.php:2022 779 805 msgid "%d recipient" 780 806 msgid_plural "%d recipients" … … 782 808 msgstr[1] "" 783 809 784 #: includes/class-customer-email-notify.php:20 08785 #: includes/trait-campaign-authoring.php:2 18810 #: includes/class-customer-email-notify.php:2035 811 #: includes/trait-campaign-authoring.php:228 786 812 msgid "Excluded" 787 813 msgstr "" 788 814 789 815 #. translators: 1: Number of excluded recipients. 2: Initial number of recipients. 790 #: includes/class-customer-email-notify.php:20 13816 #: includes/class-customer-email-notify.php:2040 791 817 msgid "%1$d removed from %2$d initial recipient(s)." 792 818 msgstr "" 793 819 794 #: includes/class-customer-email-notify.php:20 23820 #: includes/class-customer-email-notify.php:2050 795 821 msgid "From" 796 822 msgstr "" 797 823 798 #: includes/class-customer-email-notify.php:20 48824 #: includes/class-customer-email-notify.php:2075 799 825 msgid "Heading" 800 826 msgstr "" 801 827 802 828 #. translators: %s: Scheduled local date and time. 803 #: includes/class-customer-email-notify.php:20 58829 #: includes/class-customer-email-notify.php:2085 804 830 msgid "Scheduled for %s. See the confirmed mode, timezone and UTC range below." 805 831 msgstr "" 806 832 807 #: includes/class-customer-email-notify.php:20 61833 #: includes/class-customer-email-notify.php:2088 808 834 msgid "Send as soon as possible after confirmation" 809 835 msgstr "" 810 836 811 #: includes/class-customer-email-notify.php:20 70837 #: includes/class-customer-email-notify.php:2097 812 838 msgid "Saved recipient sample and due times" 813 839 msgstr "" 814 840 815 #: includes/class-customer-email-notify.php:2 074841 #: includes/class-customer-email-notify.php:2101 816 842 msgid "Name" 817 843 msgstr "" 818 844 819 #: includes/class-customer-email-notify.php:2 076820 #: includes/trait-campaign-audiences.php:1 43821 #: includes/trait-campaign-audiences.php:1 58845 #: includes/class-customer-email-notify.php:2103 846 #: includes/trait-campaign-audiences.php:152 847 #: includes/trait-campaign-audiences.php:167 822 848 msgid "Billing country" 823 849 msgstr "" 824 850 825 #: includes/class-customer-email-notify.php:2 077851 #: includes/class-customer-email-notify.php:2104 826 852 msgid "Billing state/city" 827 853 msgstr "" 828 854 829 #: includes/class-customer-email-notify.php:2 079855 #: includes/class-customer-email-notify.php:2106 830 856 msgid "Scheduled timezone" 831 857 msgstr "" 832 858 833 #: includes/class-customer-email-notify.php:2 080859 #: includes/class-customer-email-notify.php:2107 834 860 msgid "Scheduled send time" 835 861 msgstr "" 836 862 837 #: includes/class-customer-email-notify.php:2 094863 #: includes/class-customer-email-notify.php:2121 838 864 msgid "UTC fallback" 839 865 msgstr "" 840 866 841 #: includes/class-customer-email-notify.php:21 01867 #: includes/class-customer-email-notify.php:2128 842 868 msgid "Not set" 843 869 msgstr "" 844 870 845 #: includes/class-customer-email-notify.php:21 12871 #: includes/class-customer-email-notify.php:2139 846 872 msgid "Invalid scheduled time" 847 873 msgstr "" 848 874 849 #: includes/class-customer-email-notify.php:21 25875 #: includes/class-customer-email-notify.php:2152 850 876 msgid "Message preview" 851 877 msgstr "" 852 878 853 #: includes/class-customer-email-notify.php:21 41879 #: includes/class-customer-email-notify.php:2168 854 880 msgid "Confirm this saved preview" 855 881 msgstr "" 856 882 857 #: includes/class-customer-email-notify.php:21 42883 #: includes/class-customer-email-notify.php:2169 858 884 msgid "Confirmation creates this campaign with its saved recipients and content. Audience changes require a new preview. Emails already handed to the mail system cannot be recalled; inbox delivery is not verified." 859 885 msgstr "" 860 886 861 887 #. translators: %d: Number of recipients. 862 #: includes/class-customer-email-notify.php:21 49888 #: includes/class-customer-email-notify.php:2176 863 889 msgid "Schedule Email for %d Recipient(s)" 864 890 msgstr "" 865 891 866 892 #. translators: %d: Number of recipients. 867 #: includes/class-customer-email-notify.php:21 50893 #: includes/class-customer-email-notify.php:2177 868 894 msgid "Queue Email for %d Recipient(s)" 869 895 msgstr "" 870 896 871 #: includes/class-customer-email-notify.php:21 58897 #: includes/class-customer-email-notify.php:2185 872 898 msgid "No matching customers were found. Nothing will be queued." 873 899 msgstr "" 874 900 875 #: includes/class-customer-email-notify.php:2 173901 #: includes/class-customer-email-notify.php:2200 876 902 msgid "This unsubscribe link is invalid or expired." 877 903 msgstr "" 878 904 879 #: includes/class-customer-email-notify.php:2 174905 #: includes/class-customer-email-notify.php:2201 880 906 msgid "Invalid unsubscribe link" 881 907 msgstr "" 882 908 883 #: includes/class-customer-email-notify.php:2 180909 #: includes/class-customer-email-notify.php:2207 884 910 msgid "Your unsubscribe could not be saved. Please try this link again." 885 911 msgstr "" 886 912 887 #: includes/class-customer-email-notify.php:2 189913 #: includes/class-customer-email-notify.php:2216 888 914 msgid "You have been unsubscribed." 889 915 msgstr "" 890 916 891 #: includes/class-customer-email-notify.php:2 190917 #: includes/class-customer-email-notify.php:2217 892 918 msgid "This email address will be excluded from future email campaigns." 893 919 msgstr "" 894 920 895 #: includes/class-customer-email-notify.php:2193 896 #: includes/class-customer-email-notify.php:3600 921 #: includes/class-customer-email-notify.php:2220 922 #: includes/class-customer-email-notify.php:3636 923 #: includes/trait-campaign-contact-history.php:66 897 924 #: includes/trait-campaign-controls.php:173 898 #: includes/trait-campaign-privacy.php:12 7899 #: includes/trait-campaign-privacy.php:14 3925 #: includes/trait-campaign-privacy.php:128 926 #: includes/trait-campaign-privacy.php:145 900 927 msgid "Unsubscribed" 901 928 msgstr "" 902 929 903 #: includes/class-customer-email-notify.php:2200 904 #: includes/class-customer-email-notify.php:2253 905 #: includes/class-customer-email-notify.php:2270 906 #: includes/trait-campaign-authoring.php:91 930 #: includes/class-customer-email-notify.php:2227 931 #: includes/class-customer-email-notify.php:2280 932 #: includes/class-customer-email-notify.php:2297 933 #: includes/trait-campaign-authoring.php:101 934 #: includes/trait-campaign-automation-ui.php:16 935 #: includes/trait-campaign-contact-history.php:6 907 936 #: includes/trait-campaign-controls.php:111 937 #: includes/trait-campaign-entrypoints.php:61 938 #: includes/trait-campaign-entrypoints.php:83 908 939 #: includes/trait-campaign-privacy.php:80 940 #: includes/trait-campaign-subscriptions.php:128 909 941 msgid "Permission denied." 910 942 msgstr "" 911 943 912 #: includes/class-customer-email-notify.php:22 15913 #: includes/class-customer-email-notify.php:27 56944 #: includes/class-customer-email-notify.php:2242 945 #: includes/class-customer-email-notify.php:2790 914 946 msgid "Please enter a valid sender email address." 915 947 msgstr "" 916 948 917 #: includes/class-customer-email-notify.php:22 19918 #: includes/class-customer-email-notify.php:27 60949 #: includes/class-customer-email-notify.php:2246 950 #: includes/class-customer-email-notify.php:2794 919 951 msgid "Please enter a sender name." 920 952 msgstr "" 921 953 922 #: includes/class-customer-email-notify.php:22 23923 #: includes/class-customer-email-notify.php:27 64954 #: includes/class-customer-email-notify.php:2250 955 #: includes/class-customer-email-notify.php:2798 924 956 msgid "Please enter a valid Reply-To email address." 925 957 msgstr "" 926 958 927 #: includes/class-customer-email-notify.php:22 27959 #: includes/class-customer-email-notify.php:2254 928 960 msgid "Please enter a valid no-reply email address when automated replies are suppressed." 929 961 msgstr "" 930 962 931 #: includes/class-customer-email-notify.php:23 15963 #: includes/class-customer-email-notify.php:2342 932 964 msgid "Please enter a valid test email address." 933 965 msgstr "" 934 966 935 #: includes/class-customer-email-notify.php:23 33967 #: includes/class-customer-email-notify.php:2355 936 968 msgid "Test Customer" 937 969 msgstr "" 938 970 939 #: includes/class-customer-email-notify.php:24 64971 #: includes/class-customer-email-notify.php:2483 940 972 msgid "Missing campaign payload identity." 941 973 msgstr "" 942 974 943 #: includes/class-customer-email-notify.php:2 487975 #: includes/class-customer-email-notify.php:2506 944 976 msgid "Campaign content or sender details are incomplete." 945 977 msgstr "" 946 978 947 #: includes/class-customer-email-notify.php:25 12979 #: includes/class-customer-email-notify.php:2535 948 980 msgid "Stored campaign content does not match this campaign delivery." 949 981 msgstr "" 950 982 951 #: includes/class-customer-email-notify.php:25 36983 #: includes/class-customer-email-notify.php:2559 952 984 msgid "Invalid shared campaign payload reference." 953 985 msgstr "" 954 986 955 #: includes/class-customer-email-notify.php:25 51987 #: includes/class-customer-email-notify.php:2574 956 988 msgid "Shared campaign content is missing or invalid." 957 989 msgstr "" 958 990 959 #: includes/class-customer-email-notify.php:25 62991 #: includes/class-customer-email-notify.php:2585 960 992 msgid "Shared campaign content failed its integrity check." 961 993 msgstr "" 962 994 963 #: includes/class-customer-email-notify.php:2591 995 #: includes/class-customer-email-notify.php:2603 996 msgid "Confirmed recipient context is unavailable. No email was handed off." 997 msgstr "" 998 999 #: includes/class-customer-email-notify.php:2625 964 1000 msgid "Email job metadata is too large for Action Scheduler. Campaign content must use shared payload storage." 965 1001 msgstr "" 966 1002 967 #: includes/class-customer-email-notify.php:26 021003 #: includes/class-customer-email-notify.php:2636 968 1004 msgid "Scheduled timestamp is not in the future." 969 1005 msgstr "" 970 1006 971 #: includes/class-customer-email-notify.php:26 221007 #: includes/class-customer-email-notify.php:2656 972 1008 msgid "as_schedule_single_action returned an empty action id" 973 1009 msgstr "" 974 1010 975 #: includes/class-customer-email-notify.php:26 331011 #: includes/class-customer-email-notify.php:2667 976 1012 msgid "wp_schedule_single_event returned false" 977 1013 msgstr "" 978 1014 979 #: includes/class-customer-email-notify.php:26 441015 #: includes/class-customer-email-notify.php:2678 980 1016 msgid "Action Scheduler is unavailable." 981 1017 msgstr "" 982 1018 983 #: includes/class-customer-email-notify.php:26 561019 #: includes/class-customer-email-notify.php:2690 984 1020 msgid "as_enqueue_async_action returned an empty action id" 985 1021 msgstr "" 986 1022 987 #: includes/class-customer-email-notify.php:2 6981023 #: includes/class-customer-email-notify.php:2732 988 1024 msgid "The exclusion list contains an invalid email address. Correct it before previewing." 989 1025 msgstr "" 990 1026 991 #: includes/class-customer-email-notify.php:27 021027 #: includes/class-customer-email-notify.php:2736 992 1028 msgid "A selected product is invalid or unavailable. Review the selection." 993 1029 msgstr "" 994 1030 995 #: includes/class-customer-email-notify.php:27 051031 #: includes/class-customer-email-notify.php:2739 996 1032 msgid "An excluded order status is invalid." 997 1033 msgstr "" 998 1034 999 #: includes/class-customer-email-notify.php:27 241000 #: includes/class-customer-email-notify.php:4 2891035 #: includes/class-customer-email-notify.php:2758 1036 #: includes/class-customer-email-notify.php:4330 1001 1037 msgid "Please choose a valid recipient source." 1002 1038 msgstr "" 1003 1039 1004 #: includes/class-customer-email-notify.php:27 281040 #: includes/class-customer-email-notify.php:2762 1005 1041 msgid "Please choose a valid send time option." 1006 1042 msgstr "" 1007 1043 1008 #: includes/class-customer-email-notify.php:27 321044 #: includes/class-customer-email-notify.php:2766 1009 1045 msgid "Selected products apply only to Product customers. Clear the products or choose that recipient source before previewing." 1010 1046 msgstr "" 1011 1047 1012 #: includes/class-customer-email-notify.php:27 351048 #: includes/class-customer-email-notify.php:2769 1013 1049 msgid "Selected roles apply only to registered users. Clear the roles or choose that recipient source before previewing." 1014 1050 msgstr "" 1015 1051 1016 #: includes/class-customer-email-notify.php:27 381052 #: includes/class-customer-email-notify.php:2772 1017 1053 msgid "The pasted email list applies only to Manual email list. Clear the list or choose that recipient source before previewing." 1018 1054 msgstr "" 1019 1055 1020 #: includes/class-customer-email-notify.php:27 471056 #: includes/class-customer-email-notify.php:2781 1021 1057 msgid "Please enter a valid scheduled date/time." 1022 1058 msgstr "" 1023 1059 1024 #: includes/class-customer-email-notify.php:27 521060 #: includes/class-customer-email-notify.php:2786 1025 1061 msgid "Missing required fields." 1026 1062 msgstr "" 1027 1063 1028 #: includes/class-customer-email-notify.php:2 7681064 #: includes/class-customer-email-notify.php:2802 1029 1065 msgid "Please select at least one product." 1030 1066 msgstr "" 1031 1067 1032 #: includes/class-customer-email-notify.php:2 8731068 #: includes/class-customer-email-notify.php:2908 1033 1069 msgid "Missing email preview token." 1034 1070 msgstr "" 1035 1071 1036 1072 #. translators: %s: Formatted number of items. 1037 #: includes/class-customer-email-notify.php:29 461073 #: includes/class-customer-email-notify.php:2981 1038 1074 msgid "%s item" 1039 1075 msgid_plural "%s items" … … 1041 1077 msgstr[1] "" 1042 1078 1043 #: includes/class-customer-email-notify.php:29 561079 #: includes/class-customer-email-notify.php:2991 1044 1080 msgid "First page" 1045 1081 msgstr "" 1046 1082 1047 #: includes/class-customer-email-notify.php:29 571083 #: includes/class-customer-email-notify.php:2992 1048 1084 msgid "Previous page" 1049 1085 msgstr "" 1050 1086 1051 #: includes/class-customer-email-notify.php:29 611087 #: includes/class-customer-email-notify.php:2996 1052 1088 msgid "Current page" 1053 1089 msgstr "" 1054 1090 1055 #: includes/class-customer-email-notify.php: 29731091 #: includes/class-customer-email-notify.php:3008 1056 1092 msgid "of" 1057 1093 msgstr "" 1058 1094 1059 #: includes/class-customer-email-notify.php: 29781095 #: includes/class-customer-email-notify.php:3013 1060 1096 msgid "Next page" 1061 1097 msgstr "" 1062 1098 1063 #: includes/class-customer-email-notify.php: 29791099 #: includes/class-customer-email-notify.php:3014 1064 1100 msgid "Last page" 1065 1101 msgstr "" 1066 1102 1067 #: includes/class-customer-email-notify.php:3 0981103 #: includes/class-customer-email-notify.php:3133 1068 1104 msgid "Recovered campaign content. Only stored recipients and existing jobs can continue. The original audience may be incomplete; review recipient records before creating another campaign." 1069 1105 msgstr "" 1070 1106 1071 #: includes/class-customer-email-notify.php:3 2891107 #: includes/class-customer-email-notify.php:3324 1072 1108 msgid "Missing campaign ID." 1073 1109 msgstr "" 1074 1110 1075 #: includes/class-customer-email-notify.php:33 581111 #: includes/class-customer-email-notify.php:3393 1076 1112 msgid "Missing campaign content needed for rescheduling." 1077 1113 msgstr "" 1078 1114 1079 #: includes/class-customer-email-notify.php:3 5751080 #: includes/class-customer-email-notify.php:3 5761115 #: includes/class-customer-email-notify.php:3611 1116 #: includes/class-customer-email-notify.php:3612 1081 1117 #: includes/trait-campaign-controls.php:173 1082 1118 msgid "Paused" 1083 1119 msgstr "" 1084 1120 1085 #: includes/class-customer-email-notify.php:3 5771121 #: includes/class-customer-email-notify.php:3613 1086 1122 msgid "Waiting for site limit" 1087 1123 msgstr "" 1088 1124 1089 #: includes/class-customer-email-notify.php:3 5781125 #: includes/class-customer-email-notify.php:3614 1090 1126 msgid "Saving recipient snapshot" 1091 1127 msgstr "" 1092 1128 1093 #: includes/class-customer-email-notify.php:3 5791129 #: includes/class-customer-email-notify.php:3615 1094 1130 msgid "Needs attention" 1095 1131 msgstr "" 1096 1132 1097 #: includes/class-customer-email-notify.php:3 5801133 #: includes/class-customer-email-notify.php:3616 1098 1134 msgid "Previewed" 1099 1135 msgstr "" 1100 1136 1101 #: includes/class-customer-email-notify.php:3 5811137 #: includes/class-customer-email-notify.php:3617 1102 1138 msgid "Testing" 1103 1139 msgstr "" 1104 1140 1105 #: includes/class-customer-email-notify.php:3 5821141 #: includes/class-customer-email-notify.php:3618 1106 1142 msgid "Test handed to mail system" 1107 1143 msgstr "" 1108 1144 1109 #: includes/class-customer-email-notify.php:3 5831145 #: includes/class-customer-email-notify.php:3619 1110 1146 msgid "Test failed" 1111 1147 msgstr "" 1112 1148 1113 #: includes/class-customer-email-notify.php:3 5841149 #: includes/class-customer-email-notify.php:3620 1114 1150 msgid "Queueing" 1115 1151 msgstr "" 1116 1152 1117 #: includes/class-customer-email-notify.php:3 5851153 #: includes/class-customer-email-notify.php:3621 1118 1154 msgid "Preparing in background" 1119 1155 msgstr "" 1120 1156 1121 #: includes/class-customer-email-notify.php:3 5861157 #: includes/class-customer-email-notify.php:3622 1122 1158 msgid "Preparing" 1123 1159 msgstr "" 1124 1160 1125 #: includes/class-customer-email-notify.php:3 5871161 #: includes/class-customer-email-notify.php:3623 1126 1162 #: includes/trait-campaign-controls.php:173 1127 1163 msgid "Queued" 1128 1164 msgstr "" 1129 1165 1130 #: includes/class-customer-email-notify.php:3 5881166 #: includes/class-customer-email-notify.php:3624 1131 1167 #: includes/trait-campaign-controls.php:173 1132 1168 msgid "Queue failed" 1133 1169 msgstr "" 1134 1170 1135 #: includes/class-customer-email-notify.php:3 5891171 #: includes/class-customer-email-notify.php:3625 1136 1172 msgid "Scheduling" 1137 1173 msgstr "" 1138 1174 1139 #: includes/class-customer-email-notify.php:3 5901175 #: includes/class-customer-email-notify.php:3626 1140 1176 #: includes/trait-campaign-controls.php:173 1141 1177 msgid "Scheduled" 1142 1178 msgstr "" 1143 1179 1144 #: includes/class-customer-email-notify.php:3 5911180 #: includes/class-customer-email-notify.php:3627 1145 1181 #: includes/trait-campaign-controls.php:173 1146 1182 msgid "Schedule failed" 1147 1183 msgstr "" 1148 1184 1149 #: includes/class-customer-email-notify.php:3 5921150 #: includes/class-customer-email-notify.php:46 271185 #: includes/class-customer-email-notify.php:3628 1186 #: includes/class-customer-email-notify.php:4674 1151 1187 #: includes/trait-campaign-controls.php:140 1152 1188 #: includes/trait-campaign-controls.php:173 … … 1154 1190 msgstr "" 1155 1191 1156 #: includes/class-customer-email-notify.php:3 5931157 #: includes/class-customer-email-notify.php:46 291192 #: includes/class-customer-email-notify.php:3629 1193 #: includes/class-customer-email-notify.php:4676 1158 1194 msgid "Completed" 1159 1195 msgstr "" 1160 1196 1161 #: includes/class-customer-email-notify.php:3 5941197 #: includes/class-customer-email-notify.php:3630 1162 1198 msgid "Completed with issues" 1163 1199 msgstr "" 1164 1200 1165 #: includes/class-customer-email-notify.php:3 5951166 #: includes/trait-campaign-audiences.php:1 521201 #: includes/class-customer-email-notify.php:3631 1202 #: includes/trait-campaign-audiences.php:161 1167 1203 #: includes/trait-campaign-controls.php:138 1168 1204 #: includes/trait-campaign-controls.php:173 … … 1170 1206 msgstr "" 1171 1207 1172 #: includes/class-customer-email-notify.php:3 5961173 #: includes/class-customer-email-notify.php:46 321208 #: includes/class-customer-email-notify.php:3632 1209 #: includes/class-customer-email-notify.php:4679 1174 1210 #: includes/trait-campaign-controls.php:141 1175 1211 #: includes/trait-campaign-controls.php:173 … … 1177 1213 msgstr "" 1178 1214 1179 #: includes/class-customer-email-notify.php:3 5971215 #: includes/class-customer-email-notify.php:3633 1180 1216 msgid "Skipped" 1181 1217 msgstr "" 1182 1218 1183 #: includes/class-customer-email-notify.php:3 5981219 #: includes/class-customer-email-notify.php:3634 1184 1220 msgid "Skipped unsubscribed" 1185 1221 msgstr "" 1186 1222 1187 #: includes/class-customer-email-notify.php:3 5991223 #: includes/class-customer-email-notify.php:3635 1188 1224 msgid "Skipped duplicate" 1189 1225 msgstr "" 1190 1226 1191 #: includes/class-customer-email-notify.php:36 011227 #: includes/class-customer-email-notify.php:3637 1192 1228 msgid "Duplicate blocked" 1193 1229 msgstr "" 1194 1230 1195 #: includes/class-customer-email-notify.php:36 021231 #: includes/class-customer-email-notify.php:3638 1196 1232 msgid "No recipients" 1197 1233 msgstr "" 1198 1234 1199 #: includes/class-customer-email-notify.php:36 031200 #: includes/class-customer-email-notify.php:46 301235 #: includes/class-customer-email-notify.php:3639 1236 #: includes/class-customer-email-notify.php:4677 1201 1237 #: includes/trait-campaign-controls.php:173 1202 1238 msgid "Cancelled" 1203 1239 msgstr "" 1204 1240 1205 #: includes/class-customer-email-notify.php:36 041241 #: includes/class-customer-email-notify.php:3640 1206 1242 msgid "Unresolved" 1207 1243 msgstr "" 1208 1244 1209 #: includes/class-customer-email-notify.php:36 051245 #: includes/class-customer-email-notify.php:3641 1210 1246 msgid "Outcome unknown" 1211 1247 msgstr "" 1212 1248 1213 1249 #. translators: 1: Final number of recipients. 2: Excluded recipients. 3: Initial recipients. 1214 #: includes/class-customer-email-notify.php:36 401250 #: includes/class-customer-email-notify.php:3676 1215 1251 msgid "%1$d recipient(s), %2$d excluded from %3$d" 1216 1252 msgstr "" 1217 1253 1218 1254 #. translators: %d: Number of recipients. 1219 #: includes/class-customer-email-notify.php:36 481255 #: includes/class-customer-email-notify.php:3684 1220 1256 msgid "%d recipient(s)" 1221 1257 msgstr "" 1222 1258 1223 #: includes/class-customer-email-notify.php:36 541259 #: includes/class-customer-email-notify.php:3690 1224 1260 msgid "Recipient location estimate / UTC fallback" 1225 1261 msgstr "" 1226 1262 1227 #: includes/class-customer-email-notify.php:36 561263 #: includes/class-customer-email-notify.php:3692 1228 1264 msgid "Test email only" 1229 1265 msgstr "" 1230 1266 1231 1267 #. translators: %s: Scheduled local date and time. 1232 #: includes/class-customer-email-notify.php:3 6651268 #: includes/class-customer-email-notify.php:3701 1233 1269 msgid "Scheduled: %s by recipient timezone" 1234 1270 msgstr "" 1235 1271 1236 1272 #. translators: %s: Scheduled local date and time. 1237 #: includes/class-customer-email-notify.php:3 6661273 #: includes/class-customer-email-notify.php:3702 1238 1274 msgid "selected time" 1239 1275 msgstr "" 1240 1276 1241 #: includes/class-customer-email-notify.php:3 6701242 #: includes/trait-campaign-authoring.php:2 221277 #: includes/class-customer-email-notify.php:3706 1278 #: includes/trait-campaign-authoring.php:232 1243 1279 msgid "After confirmation" 1244 1280 msgstr "" 1245 1281 1246 #: includes/class-customer-email-notify.php:37 291282 #: includes/class-customer-email-notify.php:3765 1247 1283 msgid "No activity yet" 1248 1284 msgstr "" 1249 1285 1250 #: includes/class-customer-email-notify.php:4254 1286 #: includes/class-customer-email-notify.php:4290 1287 msgid "Subscribed email addresses" 1288 msgstr "" 1289 1290 #: includes/class-customer-email-notify.php:4291 1291 #: includes/trait-campaign-entrypoints.php:72 1292 msgid "Selected orders" 1293 msgstr "" 1294 1295 #: includes/class-customer-email-notify.php:4293 1251 1296 msgid "WooCommerce customers" 1252 1297 msgstr "" 1253 1298 1254 #: includes/class-customer-email-notify.php:42 551299 #: includes/class-customer-email-notify.php:4294 1255 1300 msgid "All registered users" 1256 1301 msgstr "" 1257 1302 1258 #: includes/class-customer-email-notify.php:42 561303 #: includes/class-customer-email-notify.php:4295 1259 1304 msgid "Manual email list" 1260 1305 msgstr "" 1261 1306 1262 #: includes/class-customer-email-notify.php:42711263 1307 #: includes/class-customer-email-notify.php:4310 1308 #: includes/class-customer-email-notify.php:4351 1264 1309 msgid "Please enter a list of valid email addresses." 1265 1310 msgstr "" 1266 1311 1267 #: includes/class-customer-email-notify.php:4 2761312 #: includes/class-customer-email-notify.php:4315 1268 1313 msgid "The recipient list contains an invalid email address. Correct the list before continuing." 1269 1314 msgstr "" 1270 1315 1271 #: includes/class-customer-email-notify.php:4 2941316 #: includes/class-customer-email-notify.php:4335 1272 1317 msgid "Please choose valid user roles." 1273 1318 msgstr "" 1274 1319 1275 #: includes/class-customer-email-notify.php:4 2991320 #: includes/class-customer-email-notify.php:4340 1276 1321 msgid "A selected user role is unavailable. Review the recipient selection before continuing." 1277 1322 msgstr "" 1278 1323 1279 #: includes/class-customer-email-notify.php:43 061324 #: includes/class-customer-email-notify.php:4347 1280 1325 msgid "Please enter at least one recipient email address." 1281 1326 msgstr "" 1282 1327 1283 #: includes/class-customer-email-notify.php:43 311328 #: includes/class-customer-email-notify.php:4372 1284 1329 msgid "Previously unsubscribed email addresses" 1285 1330 msgstr "" 1286 1331 1287 #: includes/class-customer-email-notify.php:46 101332 #: includes/class-customer-email-notify.php:4657 1288 1333 msgid "Do not want to receive these campaign emails?" 1289 1334 msgstr "" 1290 1335 1291 #: includes/class-customer-email-notify.php:4612 1336 #: includes/class-customer-email-notify.php:4659 1337 #: includes/trait-campaign-subscriptions.php:125 1292 1338 msgid "Unsubscribe" 1293 1339 msgstr "" 1294 1340 1295 #: includes/class-customer-email-notify.php:46 261341 #: includes/class-customer-email-notify.php:4673 1296 1342 msgid "Pending payment" 1297 1343 msgstr "" 1298 1344 1299 #: includes/class-customer-email-notify.php:46 281345 #: includes/class-customer-email-notify.php:4675 1300 1346 msgid "On hold" 1301 1347 msgstr "" 1302 1348 1303 #: includes/class-customer-email-notify.php:46 311349 #: includes/class-customer-email-notify.php:4678 1304 1350 msgid "Refunded" 1305 1351 msgstr "" 1306 1352 1307 1353 #. translators: %s: Comma-separated order status labels. 1308 #: includes/class-customer-email-notify.php:4 6931354 #: includes/class-customer-email-notify.php:4740 1309 1355 msgid "Order statuses: %s" 1310 1356 msgstr "" 1311 1357 1312 1358 #. translators: %s: Comma-separated product names. 1313 #: includes/class-customer-email-notify.php:47 021359 #: includes/class-customer-email-notify.php:4749 1314 1360 msgid "Purchased products: %s" 1315 1361 msgstr "" 1316 1362 1317 1363 #. translators: %d: Number of excluded email addresses. 1318 #: includes/class-customer-email-notify.php:47 111364 #: includes/class-customer-email-notify.php:4758 1319 1365 msgid "Manual emails: %d address" 1320 1366 msgid_plural "Manual emails: %d addresses" … … 1322 1368 msgstr[1] "" 1323 1369 1324 #: includes/class-customer-email-notify.php:4 8841370 #: includes/class-customer-email-notify.php:4931 1325 1371 msgid "Missing required email content. Repair campaign data before retrying." 1326 1372 msgstr "" 1327 1373 1328 #: includes/class-customer-email-notify.php:4892 1374 #: includes/class-customer-email-notify.php:4941 1375 msgid "No active subscription before send." 1376 msgstr "" 1377 1378 #: includes/class-customer-email-notify.php:4949 1329 1379 msgid "Recipient unsubscribed before send." 1330 1380 msgstr "" 1331 1381 1332 #: includes/class-customer-email-notify.php:4 8991382 #: includes/class-customer-email-notify.php:4957 1333 1383 msgid "Mail system accepted the request; inbox delivery is not verified." 1334 1384 msgstr "" 1335 1385 1336 #: includes/class-customer-email-notify.php:4 8991386 #: includes/class-customer-email-notify.php:4957 1337 1387 msgid "Mail transport returned no confirmation. Check the mail provider before sending again." 1338 1388 msgstr "" 1339 1389 1340 #: includes/class-customer-email-notify.php:49 191390 #: includes/class-customer-email-notify.php:4977 1341 1391 msgid "Preserved a pre-upgrade delivery claim. Check the mail provider for unknown outcomes." 1342 1392 msgstr "" 1343 1393 1344 1394 #. translators: %d: Product ID. 1345 #: includes/class-customer-email-notify.php:51 311395 #: includes/class-customer-email-notify.php:5192 1346 1396 msgid "Product #%d" 1347 1397 msgstr "" 1348 1398 1349 #: includes/class-customer-email-notify.php:5 1551399 #: includes/class-customer-email-notify.php:5216 1350 1400 msgid "WooCommerce email template is unavailable." 1351 1401 msgstr "" 1352 1402 1353 #: includes/class-customer-email-notify.php:5 2411403 #: includes/class-customer-email-notify.php:5303 1354 1404 msgid "WooCommerce mailer is unavailable." 1355 1405 msgstr "" 1356 1406 1357 #: includes/class-customer-email-notify.php:5246 1407 #: includes/class-customer-email-notify.php:5308 1408 msgid "The sample was erased before test mail handoff." 1409 msgstr "" 1410 1411 #: includes/class-customer-email-notify.php:5318 1412 msgid "No active subscription before mail handoff." 1413 msgstr "" 1414 1415 #: includes/class-customer-email-notify.php:5323 1358 1416 msgid "Recipient unsubscribed before mail handoff." 1359 1417 msgstr "" 1360 1418 1361 1419 #: includes/trait-campaign-audiences.php:21 1362 msgid "Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country and campaign history; no condition has been ignored."1363 msgstr "" 1364 1365 #: includes/trait-campaign-audiences.php:1 271420 msgid "Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country, purchase history and campaign history; no condition has been ignored." 1421 msgstr "" 1422 1423 #: includes/trait-campaign-audiences.php:134 1366 1424 msgid "Unavailable selection; remove or replace:" 1367 1425 msgstr "" 1368 1426 1369 #: includes/trait-campaign-audiences.php:1 331427 #: includes/trait-campaign-audiences.php:142 1370 1428 msgid "Saved conditions are invalid or unavailable. They remain selected; correct or explicitly remove them before previewing." 1371 1429 msgstr "" 1372 1430 1373 #: includes/trait-campaign-audiences.php:1 341431 #: includes/trait-campaign-audiences.php:143 1374 1432 msgid "Audience conditions" 1375 1433 msgstr "" 1376 1434 1377 #: includes/trait-campaign-audiences.php:1 351435 #: includes/trait-campaign-audiences.php:144 1378 1436 msgid "Order created from (store timezone)" 1379 1437 msgstr "" 1380 1438 1381 #: includes/trait-campaign-audiences.php:1 351439 #: includes/trait-campaign-audiences.php:144 1382 1440 msgid "Through date (inclusive)" 1383 1441 msgstr "" 1384 1442 1385 #: includes/trait-campaign-audiences.php:1 351443 #: includes/trait-campaign-audiences.php:144 1386 1444 msgid "Or last N × 24 hours" 1387 1445 msgstr "" 1388 1446 1389 #: includes/trait-campaign-audiences.php:1 361390 msgid "Matching order statuses ( defaultprocessing/completed)"1391 msgstr "" 1392 1393 #: includes/trait-campaign-audiences.php:1 391447 #: includes/trait-campaign-audiences.php:145 1448 msgid "Matching order statuses (selected orders: all; other sources: processing/completed)" 1449 msgstr "" 1450 1451 #: includes/trait-campaign-audiences.php:148 1394 1452 msgid "Categories (includes all descendants)" 1395 1453 msgstr "" 1396 1454 1397 #: includes/trait-campaign-audiences.php:1 461398 #: includes/trait-campaign-audiences.php:1 581455 #: includes/trait-campaign-audiences.php:155 1456 #: includes/trait-campaign-audiences.php:167 1399 1457 msgid "Subscription status" 1400 1458 msgstr "" 1401 1459 1402 #: includes/trait-campaign-audiences.php:1 471460 #: includes/trait-campaign-audiences.php:156 1403 1461 msgid "Any (suppression still applies)" 1404 1462 msgstr "" 1405 1463 1406 #: includes/trait-campaign-audiences.php:147 1407 #: includes/trait-campaign-privacy.php:127 1464 #: includes/trait-campaign-audiences.php:156 1465 #: includes/trait-campaign-contact-history.php:66 1466 #: includes/trait-campaign-privacy.php:128 1467 #: includes/trait-campaign-subscriptions.php:118 1408 1468 msgid "Subscribed" 1409 1469 msgstr "" 1410 1470 1411 #: includes/trait-campaign-audiences.php:1 471471 #: includes/trait-campaign-audiences.php:156 1412 1472 msgid "No confirmation recorded" 1413 1473 msgstr "" 1414 1474 1415 #: includes/trait-campaign-audiences.php:1 471475 #: includes/trait-campaign-audiences.php:156 1416 1476 msgid "Unsubscribed (excluded from sending)" 1417 1477 msgstr "" 1418 1478 1419 #: includes/trait-campaign-audiences.php:1 481479 #: includes/trait-campaign-audiences.php:157 1420 1480 msgid "Campaign history" 1421 1481 msgstr "" 1422 1482 1423 #: includes/trait-campaign-audiences.php:1 511483 #: includes/trait-campaign-audiences.php:160 1424 1484 msgid "History outcome" 1425 1485 msgstr "" 1426 1486 1427 #: includes/trait-campaign-audiences.php:1 521487 #: includes/trait-campaign-audiences.php:161 1428 1488 msgid "Known unsent terminal outcome" 1429 1489 msgstr "" 1430 1490 1431 #: includes/trait-campaign-audiences.php:1 531491 #: includes/trait-campaign-audiences.php:162 1432 1492 msgid "Durable opt-outs always apply. Orders and accounts do not establish opt-in." 1433 1493 msgstr "" 1434 1494 1435 #: includes/trait-campaign-audiences.php:1 531495 #: includes/trait-campaign-audiences.php:162 1436 1496 msgid "How audience conditions match" 1437 1497 msgstr "" 1438 1498 1439 #: includes/trait-campaign-audiences.php:1 531499 #: includes/trait-campaign-audiences.php:162 1440 1500 msgid "Order filters use order creation time in the store timezone and match on one order, including product/variation, status and billing country. Categories include descendants and use current product categories. Registered users use profile billing country; manual lists have no country. Missing data fails the condition. History uses handoff only: unknown, pending and missing history never qualify as known unsent. Existing exclusions and durable opt-outs apply last." 1441 1501 msgstr "" 1442 1502 1443 #: includes/trait-campaign-audiences.php:158 1503 #: includes/trait-campaign-audiences.php:167 1504 msgid "Store-wide purchase frequency" 1505 msgstr "" 1506 1507 #: includes/trait-campaign-audiences.php:167 1508 msgid "Days without a valid store-wide purchase" 1509 msgstr "" 1510 1511 #: includes/trait-campaign-audiences.php:167 1444 1512 msgid "Order created from" 1445 1513 msgstr "" 1446 1514 1447 #: includes/trait-campaign-audiences.php:1 581515 #: includes/trait-campaign-audiences.php:167 1448 1516 msgid "Through date" 1449 1517 msgstr "" 1450 1518 1451 #: includes/trait-campaign-audiences.php:1 581519 #: includes/trait-campaign-audiences.php:167 1452 1520 msgid "Last N days" 1453 1521 msgstr "" 1454 1522 1455 #: includes/trait-campaign-audiences.php:1 581523 #: includes/trait-campaign-audiences.php:167 1456 1524 msgid "History campaign" 1457 1525 msgstr "" 1458 1526 1459 #: includes/trait-campaign-audiences.php:1 581527 #: includes/trait-campaign-audiences.php:167 1460 1528 msgid "Handoff condition" 1461 1529 msgstr "" 1462 1530 1463 #: includes/trait-campaign-audiences.php:1 581531 #: includes/trait-campaign-audiences.php:167 1464 1532 msgid "Categories including descendants" 1465 1533 msgstr "" 1466 1534 1467 #: includes/trait-campaign-audiences.php:1 581535 #: includes/trait-campaign-audiences.php:167 1468 1536 msgid "Matching order statuses" 1469 1537 msgstr "" 1470 1538 1471 #: includes/trait-campaign-audiences.php:159 1539 #: includes/trait-campaign-audiences.php:168 1540 #: includes/trait-campaign-authoring.php:238 1541 msgid "Saved audience conditions" 1542 msgstr "" 1543 1544 #: includes/trait-campaign-audiences.php:171 1545 #: includes/trait-campaign-purchase-history.php:54 1546 msgid "First-time buyer (one valid order)" 1547 msgstr "" 1548 1549 #: includes/trait-campaign-audiences.php:171 1550 #: includes/trait-campaign-purchase-history.php:54 1551 msgid "Repeat buyer (at least two valid orders)" 1552 msgstr "" 1553 1554 #: includes/trait-campaign-audiences.php:181 1555 msgid "Inspect an address against current criteria" 1556 msgstr "" 1557 1558 #: includes/trait-campaign-audiences.php:181 1559 msgid "Inspect" 1560 msgstr "" 1561 1562 #: includes/trait-campaign-audiences.php:187 1563 msgid "Not in the selected source or product purchasers." 1564 msgstr "" 1565 1566 #: includes/trait-campaign-audiences.php:188 1567 msgid "No single order matches all order conditions, or billing country is missing/different." 1568 msgstr "" 1569 1570 #: includes/trait-campaign-audiences.php:189 1571 msgid "Store-wide purchase history, subscription status or known campaign handoff condition does not match." 1572 msgstr "" 1573 1574 #: includes/trait-campaign-audiences.php:190 1575 msgid "Matched source and all conditions; removed by an explicit exclusion." 1576 msgstr "" 1577 1578 #: includes/trait-campaign-audiences.php:191 1579 msgid "Included: matches source and every applicable condition; no exclusion matched." 1580 msgstr "" 1581 1582 #: includes/trait-campaign-audiences.php:192 1583 msgid "Excluded: durable unsubscribe/suppression." 1584 msgstr "" 1585 1586 #: includes/trait-campaign-authoring.php:57 1587 msgid "Enter an audience name." 1588 msgstr "" 1589 1590 #: includes/trait-campaign-authoring.php:60 1591 msgid "Audience could not be saved." 1592 msgstr "" 1593 1594 #: includes/trait-campaign-authoring.php:86 1595 msgid "This draft changed or was deleted. Open it and create a new preview." 1596 msgstr "" 1597 1598 #: includes/trait-campaign-authoring.php:107 1599 msgid "Campaign content unavailable." 1600 msgstr "" 1601 1602 #: includes/trait-campaign-authoring.php:120 1603 msgid "Duplicate as new draft" 1604 msgstr "" 1605 1606 #: includes/trait-campaign-authoring.php:128 1607 msgid "Drafts" 1608 msgstr "" 1609 1610 #: includes/trait-campaign-authoring.php:128 1611 msgid "Drafts do not expire and never create delivery jobs." 1612 msgstr "" 1613 1614 #: includes/trait-campaign-authoring.php:130 1615 msgid "No saved drafts yet." 1616 msgstr "" 1617 1618 #: includes/trait-campaign-authoring.php:133 1619 msgid "Delete draft" 1620 msgstr "" 1621 1622 #: includes/trait-campaign-authoring.php:136 1623 #: includes/trait-campaign-authoring.php:150 1624 msgid "Saved audience criteria" 1625 msgstr "" 1626 1627 #: includes/trait-campaign-authoring.php:136 1628 msgid "Reusable rules, not a frozen recipient list. A new preview is required when reused." 1629 msgstr "" 1630 1631 #: includes/trait-campaign-authoring.php:138 1632 msgid "No saved audiences yet." 1633 msgstr "" 1634 1635 #: includes/trait-campaign-authoring.php:141 1636 msgid "Delete audience" 1637 msgstr "" 1638 1639 #: includes/trait-campaign-authoring.php:147 1640 msgid "Draft name (internal only)" 1641 msgstr "" 1642 1643 #: includes/trait-campaign-authoring.php:147 1644 msgid "Save draft" 1645 msgstr "" 1646 1647 #: includes/trait-campaign-authoring.php:147 1648 msgid "Drafts create no delivery jobs. Changes require a new preview." 1649 msgstr "" 1650 1651 #: includes/trait-campaign-authoring.php:154 1652 msgid "Open Library" 1653 msgstr "" 1654 1655 #: includes/trait-campaign-authoring.php:154 1656 msgid "Opening saved criteria replaces this form. Save your draft first to keep current edits." 1657 msgstr "" 1658 1659 #: includes/trait-campaign-authoring.php:154 1660 msgid "Audience name" 1661 msgstr "" 1662 1663 #: includes/trait-campaign-authoring.php:154 1664 msgid "Save audience criteria" 1665 msgstr "" 1666 1667 #: includes/trait-campaign-authoring.php:157 1668 msgid "Insert editable content template" 1669 msgstr "" 1670 1671 #: includes/trait-campaign-authoring.php:159 1672 msgid "Product or documentation update" 1673 msgstr "" 1674 1675 #: includes/trait-campaign-authoring.php:159 1676 msgid "An update for you" 1677 msgstr "" 1678 1679 #: includes/trait-campaign-authoring.php:159 1680 msgid "<p>Hello {customer_name},</p><p>We have updated {product_name}. Describe what changed, when it applies, and add the documentation link and any action needed. Contact our support team if you need help.</p>" 1681 msgstr "" 1682 1683 #: includes/trait-campaign-authoring.php:160 1684 msgid "After-purchase guide" 1685 msgstr "" 1686 1687 #: includes/trait-campaign-authoring.php:160 1688 msgid "Getting started" 1689 msgstr "" 1690 1691 #: includes/trait-campaign-authoring.php:160 1692 msgid "<p>Hello {customer_name},</p><p>Thank you for your purchase of {ordered_products} (order {order_number}). Add setup or care steps, when to follow them, and a support contact here.</p>" 1693 msgstr "" 1694 1695 #: includes/trait-campaign-authoring.php:161 1696 msgid "Service or order change" 1697 msgstr "" 1698 1699 #: includes/trait-campaign-authoring.php:161 1700 msgid "Service update" 1701 msgstr "" 1702 1703 #: includes/trait-campaign-authoring.php:161 1704 msgid "<p>Hello {customer_name},</p><p>An update about order {order_number}: describe the change and the new delivery date or effective time. Explain any action needed and add a support contact here.</p>" 1705 msgstr "" 1706 1707 #: includes/trait-campaign-authoring.php:197 1708 msgid "At least one recipient has a past, nonexistent or repeated local time. Choose a later, unambiguous time and preview again. No date was shifted." 1709 msgstr "" 1710 1711 #: includes/trait-campaign-authoring.php:220 1712 msgid "Preview width" 1713 msgstr "" 1714 1715 #: includes/trait-campaign-authoring.php:221 1716 msgid "Desktop" 1717 msgstr "" 1718 1719 #: includes/trait-campaign-authoring.php:221 1720 msgid "Mobile" 1721 msgstr "" 1722 1723 #: includes/trait-campaign-authoring.php:227 1724 msgid "Audience changed since preview. Review this updated preview and confirm again." 1725 msgstr "" 1726 1472 1727 #: includes/trait-campaign-authoring.php:228 1473 msgid "Saved audience conditions"1474 msgstr ""1475 1476 #: includes/trait-campaign-audiences.php:1711477 msgid "Inspect an address against current criteria"1478 msgstr ""1479 1480 #: includes/trait-campaign-audiences.php:1711481 msgid "Inspect"1482 msgstr ""1483 1484 #: includes/trait-campaign-audiences.php:1771485 msgid "Not in the selected source or product purchasers."1486 msgstr ""1487 1488 #: includes/trait-campaign-audiences.php:1781489 msgid "No single order matches all order conditions, or billing country is missing/different."1490 msgstr ""1491 1492 #: includes/trait-campaign-audiences.php:1791493 msgid "Subscription status or known campaign handoff condition does not match."1494 msgstr ""1495 1496 #: includes/trait-campaign-audiences.php:1801497 msgid "Matched source and all conditions; removed by an explicit exclusion."1498 msgstr ""1499 1500 #: includes/trait-campaign-audiences.php:1811501 msgid "Included: matches source and every applicable condition; no exclusion matched."1502 msgstr ""1503 1504 #: includes/trait-campaign-audiences.php:1821505 msgid "Excluded: durable unsubscribe/suppression."1506 msgstr ""1507 1508 #: includes/trait-campaign-authoring.php:531509 msgid "Enter an audience name."1510 msgstr ""1511 1512 #: includes/trait-campaign-authoring.php:561513 msgid "Audience could not be saved."1514 msgstr ""1515 1516 #: includes/trait-campaign-authoring.php:761517 msgid "This draft changed or was deleted. Open it and create a new preview."1518 msgstr ""1519 1520 #: includes/trait-campaign-authoring.php:971521 msgid "Campaign content unavailable."1522 msgstr ""1523 1524 #: includes/trait-campaign-authoring.php:1101525 msgid "Duplicate as new draft"1526 msgstr ""1527 1528 #: includes/trait-campaign-authoring.php:1181529 msgid "Drafts"1530 msgstr ""1531 1532 #: includes/trait-campaign-authoring.php:1181533 msgid "Drafts do not expire and never create delivery jobs."1534 msgstr ""1535 1536 #: includes/trait-campaign-authoring.php:1201537 msgid "No saved drafts yet."1538 msgstr ""1539 1540 #: includes/trait-campaign-authoring.php:1231541 msgid "Delete draft"1542 msgstr ""1543 1544 #: includes/trait-campaign-authoring.php:1261545 #: includes/trait-campaign-authoring.php:1401546 msgid "Saved audience criteria"1547 msgstr ""1548 1549 #: includes/trait-campaign-authoring.php:1261550 msgid "Reusable rules, not a frozen recipient list. A new preview is required when reused."1551 msgstr ""1552 1553 #: includes/trait-campaign-authoring.php:1281554 msgid "No saved audiences yet."1555 msgstr ""1556 1557 #: includes/trait-campaign-authoring.php:1311558 msgid "Delete audience"1559 msgstr ""1560 1561 #: includes/trait-campaign-authoring.php:1371562 msgid "Draft name (internal only)"1563 msgstr ""1564 1565 #: includes/trait-campaign-authoring.php:1371566 msgid "Save draft"1567 msgstr ""1568 1569 #: includes/trait-campaign-authoring.php:1371570 msgid "Drafts create no delivery jobs. Changes require a new preview."1571 msgstr ""1572 1573 #: includes/trait-campaign-authoring.php:1441574 msgid "Open Library"1575 msgstr ""1576 1577 #: includes/trait-campaign-authoring.php:1441578 msgid "Opening saved criteria replaces this form. Save your draft first to keep current edits."1579 msgstr ""1580 1581 #: includes/trait-campaign-authoring.php:1441582 msgid "Audience name"1583 msgstr ""1584 1585 #: includes/trait-campaign-authoring.php:1441586 msgid "Save audience criteria"1587 msgstr ""1588 1589 #: includes/trait-campaign-authoring.php:1471590 msgid "Insert editable content template"1591 msgstr ""1592 1593 #: includes/trait-campaign-authoring.php:1491594 msgid "Product or documentation update"1595 msgstr ""1596 1597 #: includes/trait-campaign-authoring.php:1491598 msgid "An update for you"1599 msgstr ""1600 1601 #: includes/trait-campaign-authoring.php:1491602 msgid "<p>Hello {customer_name},</p><p>We have updated {product_name}. Add the details and documentation link here.</p>"1603 msgstr ""1604 1605 #: includes/trait-campaign-authoring.php:1501606 msgid "After-purchase guide"1607 msgstr ""1608 1609 #: includes/trait-campaign-authoring.php:1501610 msgid "Getting started"1611 msgstr ""1612 1613 #: includes/trait-campaign-authoring.php:1501614 msgid "<p>Hello {customer_name},</p><p>Thank you for your purchase. Add setup steps and support details here.</p>"1615 msgstr ""1616 1617 #: includes/trait-campaign-authoring.php:1511618 msgid "Service or order change"1619 msgstr ""1620 1621 #: includes/trait-campaign-authoring.php:1511622 msgid "Service update"1623 msgstr ""1624 1625 #: includes/trait-campaign-authoring.php:1511626 msgid "<p>Hello {customer_name},</p><p>Add the change, effective date and any action needed here.</p>"1627 msgstr ""1628 1629 #: includes/trait-campaign-authoring.php:1871630 msgid "At least one recipient has a past, nonexistent or repeated local time. Choose a later, unambiguous time and preview again. No date was shifted."1631 msgstr ""1632 1633 #: includes/trait-campaign-authoring.php:2101634 msgid "Preview width"1635 msgstr ""1636 1637 #: includes/trait-campaign-authoring.php:2111638 msgid "Desktop"1639 msgstr ""1640 1641 #: includes/trait-campaign-authoring.php:2111642 msgid "Mobile"1643 msgstr ""1644 1645 #: includes/trait-campaign-authoring.php:2171646 msgid "Audience changed since preview. Review this updated preview and confirm again."1647 msgstr ""1648 1649 #: includes/trait-campaign-authoring.php:2181650 1728 msgid "Recipients and schedule to confirm" 1651 1729 msgstr "" 1652 1730 1653 #: includes/trait-campaign-authoring.php:2 181731 #: includes/trait-campaign-authoring.php:228 1654 1732 msgid "Selected" 1655 1733 msgstr "" 1656 1734 1657 #: includes/trait-campaign-authoring.php:2 191735 #: includes/trait-campaign-authoring.php:229 1658 1736 msgid "Removed by order conditions" 1659 1737 msgstr "" 1660 1738 1661 #: includes/trait-campaign-authoring.php:2 191662 msgid "Removed by subscription or campaign history"1663 msgstr "" 1664 1665 #: includes/trait-campaign-authoring.php:2 191739 #: includes/trait-campaign-authoring.php:229 1740 msgid "Removed by purchase history, subscription or campaign history" 1741 msgstr "" 1742 1743 #: includes/trait-campaign-authoring.php:229 1666 1744 msgid "Removed by exclusions or suppression" 1667 1745 msgstr "" 1668 1746 1669 #: includes/trait-campaign-authoring.php:2 221747 #: includes/trait-campaign-authoring.php:232 1670 1748 msgid "One time in store timezone" 1671 1749 msgstr "" 1672 1750 1673 #: includes/trait-campaign-authoring.php:2 221751 #: includes/trait-campaign-authoring.php:232 1674 1752 msgid "Legacy schedule" 1675 1753 msgstr "" 1676 1754 1677 #: includes/trait-campaign-authoring.php:2 231755 #: includes/trait-campaign-authoring.php:233 1678 1756 msgid "Schedule mode / store timezone" 1679 1757 msgstr "" 1680 1758 1681 #: includes/trait-campaign-authoring.php:2 261759 #: includes/trait-campaign-authoring.php:236 1682 1760 msgid "UTC fallback count" 1683 1761 msgstr "" 1684 1762 1685 #: includes/trait-campaign-authoring.php:2 261763 #: includes/trait-campaign-authoring.php:236 1686 1764 msgid "Earliest and latest due (UTC)" 1687 1765 msgstr "" 1688 1766 1689 #: includes/trait-campaign-authoring.php:2 301767 #: includes/trait-campaign-authoring.php:240 1690 1768 msgid "Inspect an address" 1691 1769 msgstr "" 1692 1770 1693 #: includes/trait-campaign-authoring.php:2 371694 #: includes/trait-campaign-authoring.php:2 441771 #: includes/trait-campaign-authoring.php:247 1772 #: includes/trait-campaign-authoring.php:257 1695 1773 msgid "Personalized email preview" 1696 1774 msgstr "" 1697 1775 1698 #: includes/trait-campaign-authoring.php:2 371776 #: includes/trait-campaign-authoring.php:247 1699 1777 msgid "Sample recipient (up to 20)" 1700 1778 msgstr "" 1701 1779 1702 #: includes/trait-campaign-authoring.php:2 391780 #: includes/trait-campaign-authoring.php:249 1703 1781 msgid "Show sample" 1782 msgstr "" 1783 1784 #: includes/trait-campaign-automation-ui.php:17 1785 msgid "Use the automation form." 1786 msgstr "" 1787 1788 #: includes/trait-campaign-automation-ui.php:19 1789 msgid "Choose a valid automation rule." 1790 msgstr "" 1791 1792 #: includes/trait-campaign-automation-ui.php:32 1793 msgid "Choose an available order ID for the sample." 1794 msgstr "" 1795 1796 #: includes/trait-campaign-automation-ui.php:38 1797 msgid "The test email could not be handed off. Check mail settings and try again." 1798 msgstr "" 1799 1800 #: includes/trait-campaign-automation-ui.php:47 1801 msgid "Choose a valid automation action." 1802 msgstr "" 1803 1804 #: includes/trait-campaign-automation-ui.php:66 1805 msgid "This automation rule is unavailable." 1806 msgstr "" 1807 1808 #: includes/trait-campaign-automation-ui.php:67 1809 msgid "Rule saved. New rules stay disabled until you choose Enable. Changes to enabled rules apply to new events only." 1810 msgstr "" 1811 1812 #: includes/trait-campaign-automation-ui.php:67 1813 msgid "Rule enabled for new Completed events. Historical orders were not queued." 1814 msgstr "" 1815 1816 #: includes/trait-campaign-automation-ui.php:67 1817 msgid "Rule disabled. Unstarted emails are cancelled; work already in flight may finish." 1818 msgstr "" 1819 1820 #: includes/trait-campaign-automation-ui.php:67 1821 msgid "Test mail handed to the mail system. No rule was saved or enabled. Inbox delivery is not verified." 1822 msgstr "" 1823 1824 #: includes/trait-campaign-automation-ui.php:67 1825 msgid "Sample refreshed. No rule was saved or enabled and no delivery job was created." 1826 msgstr "" 1827 1828 #: includes/trait-campaign-automation-ui.php:80 1829 msgid "Send a helpful guide after an order is completed. Enable uses the saved configuration." 1830 msgstr "" 1831 1832 #: includes/trait-campaign-automation-ui.php:80 1833 msgid "New rule" 1834 msgstr "" 1835 1836 #: includes/trait-campaign-automation-ui.php:81 1837 msgid "No rules yet. Build your first guide below, then enable it when you are ready." 1838 msgstr "" 1839 1840 #: includes/trait-campaign-automation-ui.php:84 1841 msgid "Enabled" 1842 msgstr "" 1843 1844 #: includes/trait-campaign-automation-ui.php:84 1845 msgid "Disabled" 1846 msgstr "" 1847 1848 #. translators: %d: Number of hours after the Completed event. 1849 #: includes/trait-campaign-automation-ui.php:84 1850 msgid "Completed → wait %d hours → send one guide" 1851 msgstr "" 1852 1853 #. translators: %d: Number of hours after the Completed event. 1854 #: includes/trait-campaign-automation-ui.php:84 1855 msgid "Saved configuration" 1856 msgstr "" 1857 1858 #. translators: %d: Number of hours after the Completed event. 1859 #: includes/trait-campaign-automation-ui.php:84 1860 msgid "All products" 1861 msgstr "" 1862 1863 #. translators: %d: Number of hours after the Completed event. 1864 #: includes/trait-campaign-automation-ui.php:84 1865 msgid "Categories" 1866 msgstr "" 1867 1868 #. translators: %d: Number of hours after the Completed event. 1869 #: includes/trait-campaign-automation-ui.php:84 1870 msgid "All categories" 1871 msgstr "" 1872 1873 #. translators: %d: Number of hours after the Completed event. 1874 #: includes/trait-campaign-automation-ui.php:85 1875 msgid "Edit rule" 1876 msgstr "" 1877 1878 #. translators: %d: Number of hours after the Completed event. 1879 #: includes/trait-campaign-automation-ui.php:85 1880 msgid "Disable and cancel waiting emails" 1881 msgstr "" 1882 1883 #. translators: %d: Number of hours after the Completed event. 1884 #: includes/trait-campaign-automation-ui.php:85 1885 msgid "Enable" 1886 msgstr "" 1887 1888 #: includes/trait-campaign-automation-ui.php:88 1889 msgid "View campaigns and delivery status" 1890 msgstr "" 1891 1892 #: includes/trait-campaign-automation-ui.php:88 1893 msgid "Look up a contact" 1894 msgstr "" 1895 1896 #: includes/trait-campaign-automation-ui.php:92 1897 msgid "Rule name (internal only)" 1898 msgstr "" 1899 1900 #: includes/trait-campaign-automation-ui.php:92 1901 #: includes/trait-campaign-automation-ui.php:119 1902 msgid "Save changes for new events" 1903 msgstr "" 1904 1905 #: includes/trait-campaign-automation-ui.php:92 1906 #: includes/trait-campaign-automation-ui.php:119 1907 msgid "Save rule" 1908 msgstr "" 1909 1910 #: includes/trait-campaign-automation-ui.php:92 1911 msgid "Waiting emails keep their confirmed content, order context and due time." 1912 msgstr "" 1913 1914 #: includes/trait-campaign-automation-ui.php:92 1915 msgid "Save your rule, then explicitly Enable it above. Saving alone never enables a new rule." 1916 msgstr "" 1917 1918 #: includes/trait-campaign-automation-ui.php:93 1919 msgid "Automation steps" 1920 msgstr "" 1921 1922 #: includes/trait-campaign-automation-ui.php:94 1923 msgid "1. Conditions" 1924 msgstr "" 1925 1926 #: includes/trait-campaign-automation-ui.php:94 1927 msgid "3. Timing" 1928 msgstr "" 1929 1930 #: includes/trait-campaign-automation-ui.php:97 1931 msgid "Conditions" 1932 msgstr "" 1933 1934 #: includes/trait-campaign-automation-ui.php:97 1935 msgid "Choose which completed orders should receive this guide." 1936 msgstr "" 1937 1938 #: includes/trait-campaign-automation-ui.php:98 1939 msgid "Trigger: order changes to Completed" 1940 msgstr "" 1941 1942 #: includes/trait-campaign-automation-ui.php:98 1943 msgid "Only new events after Enable are captured. There is no historical backfill. A customer with several qualifying orders can receive one guide for each order." 1944 msgstr "" 1945 1946 #: includes/trait-campaign-automation-ui.php:99 1947 msgid "Products or variations (empty means any)" 1948 msgstr "" 1949 1950 #: includes/trait-campaign-automation-ui.php:100 1951 msgid "Categories including descendants (empty means any)" 1952 msgstr "" 1953 1954 #: includes/trait-campaign-automation-ui.php:102 1955 msgid "Product and category conditions match the same order. Parent products include their variations; a selected variation matches only that variation." 1956 msgstr "" 1957 1958 #: includes/trait-campaign-automation-ui.php:103 1959 msgid "Eligibility and subscription" 1960 msgstr "" 1961 1962 #: includes/trait-campaign-automation-ui.php:103 1963 msgid "An active subscription is required at sending. Unknown is not consent. Unsubscribe and erasure protection always apply. The order must still be Completed, match its saved conditions and keep the same billing email. Cancelled, failed and fully refunded orders are skipped; partial refunds remain eligible while an amount remains." 1964 msgstr "" 1965 1966 #: includes/trait-campaign-automation-ui.php:106 1967 msgid "Write useful setup or care instructions for the purchased items." 1968 msgstr "" 1969 1970 #: includes/trait-campaign-automation-ui.php:107 1971 msgid "A guide for order {order_number}" 1972 msgstr "" 1973 1974 #: includes/trait-campaign-automation-ui.php:107 1975 msgid "Getting started with your purchase" 1976 msgstr "" 1977 1978 #: includes/trait-campaign-automation-ui.php:108 1979 msgid "<p>Hello {customer_name},</p><p>Thank you for purchasing {ordered_products}.</p><p>Before you start, check the setup instructions included with your order. Keep this email handy and contact our store if you need help.</p><p>Order: {order_number}</p>" 1980 msgstr "" 1981 1982 #: includes/trait-campaign-automation-ui.php:109 1983 msgid "An unsubscribe link is added automatically. The live preview shows template text; Review uses the exact sample order." 1984 msgstr "" 1985 1986 #: includes/trait-campaign-automation-ui.php:109 1987 msgid "Personalization variables" 1988 msgstr "" 1989 1990 #: includes/trait-campaign-automation-ui.php:109 1991 msgid "Use {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products} and {order_url} in the subject, heading or body. Order values come from the triggering order and are frozen when captured. Missing names use Customer. Guest order links are empty; account links require the owning account login." 1992 msgstr "" 1993 1994 #: includes/trait-campaign-automation-ui.php:112 1995 msgid "Timing" 1996 msgstr "" 1997 1998 #: includes/trait-campaign-automation-ui.php:112 1999 msgid "Set how long to wait after the order becomes Completed." 2000 msgstr "" 2001 2002 #: includes/trait-campaign-automation-ui.php:113 2003 msgid "Delay after Completed (hours)" 2004 msgstr "" 2005 2006 #: includes/trait-campaign-automation-ui.php:113 2007 msgid "Use 0 to queue immediately, or 24 to wait one day. Sending limits and queue delays can make actual delivery later." 2008 msgstr "" 2009 2010 #: includes/trait-campaign-automation-ui.php:113 2011 msgid "Editing the delay affects new events only. Waiting emails keep their original due time." 2012 msgstr "" 2013 2014 #: includes/trait-campaign-automation-ui.php:116 2015 msgid "Preview and test" 2016 msgstr "" 2017 2018 #: includes/trait-campaign-automation-ui.php:116 2019 msgid "Check the personalized email using an order you can access." 2020 msgstr "" 2021 2022 #: includes/trait-campaign-automation-ui.php:117 2023 msgid "Sample order ID" 2024 msgstr "" 2025 2026 #: includes/trait-campaign-automation-ui.php:117 2027 msgid "Preview guide" 2028 msgstr "" 2029 2030 #: includes/trait-campaign-automation-ui.php:118 2031 msgid "Send test email" 2032 msgstr "" 2033 2034 #: includes/trait-campaign-automation-ui.php:118 2035 msgid "Test mail goes only to this address. Preview and test create no campaign or delivery job, and never save or enable the rule." 2036 msgstr "" 2037 2038 #: includes/trait-campaign-automation-ui.php:119 2039 msgid "Ready to save?" 2040 msgstr "" 2041 2042 #: includes/trait-campaign-automation-ui.php:119 2043 msgid "Save the form, then Enable the saved rule above. If it is already enabled, your changes apply to new events only." 2044 msgstr "" 2045 2046 #: includes/trait-campaign-automation-ui.php:119 2047 msgid "What happens when I disable a rule?" 2048 msgstr "" 2049 2050 #: includes/trait-campaign-automation-ui.php:119 2051 msgid "New events stop and unstarted emails are cancelled. Work already in flight may finish. Re-enabling never restores cancelled mail. History is preserved." 2052 msgstr "" 2053 2054 #: includes/trait-campaign-automation-ui.php:128 2055 #: includes/trait-campaign-automation-ui.php:129 2056 #: includes/trait-campaign-automation-ui.php:135 2057 msgid "Personalized guide preview" 2058 msgstr "" 2059 2060 #: includes/trait-campaign-automation-ui.php:129 2061 msgid "Based on the form at the last refresh." 2062 msgstr "" 2063 2064 #: includes/trait-campaign-automation-ui.php:129 2065 msgid "Sample" 2066 msgstr "" 2067 2068 #: includes/trait-campaign-automation-ui.php:135 2069 msgid "The form has changed. Choose Preview guide to refresh this sample before saving or testing." 2070 msgstr "" 2071 2072 #: includes/trait-campaign-automation-ui.php:135 2073 msgid "Sample recipient" 2074 msgstr "" 2075 2076 #: includes/trait-campaign-automation-ui.php:136 2077 msgid "Choose a sample order and select Preview guide to see its customer name, products and order details here." 2078 msgstr "" 2079 2080 #: includes/trait-campaign-automations.php:16 2081 msgid "Review the rule name, products, categories, delay and required email content." 2082 msgstr "" 2083 2084 #: includes/trait-campaign-automations.php:37 2085 #: includes/trait-campaign-automations.php:48 2086 msgid "Another rule change is in progress. Please try again." 2087 msgstr "" 2088 2089 #: includes/trait-campaign-automations.php:40 2090 msgid "Rule not found. Open Automations again." 2091 msgstr "" 2092 2093 #: includes/trait-campaign-automations.php:44 2094 msgid "The rule could not be saved. Please try again after checking storage." 2095 msgstr "" 2096 2097 #: includes/trait-campaign-automations.php:51 2098 msgid "Rule not found." 2099 msgstr "" 2100 2101 #: includes/trait-campaign-automations.php:56 2102 msgid "The rule change could not be verified. Please check its current state and try again." 2103 msgstr "" 2104 2105 #: includes/trait-campaign-automations.php:60 2106 msgid "The rule is disabled and its previous generation cannot send. Some campaign cancellations still need cleanup; open Campaigns again after checking storage." 2107 msgstr "" 2108 2109 #: includes/trait-campaign-automations.php:77 2110 #: includes/trait-campaign-automations.php:157 2111 msgid "Completed-order guide" 2112 msgstr "" 2113 2114 #: includes/trait-campaign-automations.php:90 2115 msgid "The triggering order has no valid billing email. No guide was queued." 2116 msgstr "" 2117 2118 #: includes/trait-campaign-automations.php:144 2119 msgid "Guide rule disabled or this pending email belongs to an earlier enabled generation." 2120 msgstr "" 2121 2122 #: includes/trait-campaign-automations.php:146 2123 msgid "The triggering order is no longer Completed, has been fully refunded, changed billing email or no longer matches its saved product/category conditions." 2124 msgstr "" 2125 2126 #: includes/trait-campaign-automations.php:148 2127 msgid "The triggering order or rule could not be checked. No guide was handed off." 2128 msgstr "" 2129 2130 #: includes/trait-campaign-automations.php:152 2131 msgid "Choose a valid sample order ID." 2132 msgstr "" 2133 2134 #: includes/trait-campaign-automations.php:154 2135 msgid "Choose an available order that you can access for preview." 2136 msgstr "" 2137 2138 #: includes/trait-campaign-automations.php:155 2139 msgid "This sample is protected by erasure. Its previous personal context cannot be previewed or tested." 2140 msgstr "" 2141 2142 #: includes/trait-campaign-automations.php:159 2143 msgid "This sample order does not currently match the rule. Preview only; it will not trigger a guide in this state." 2144 msgstr "" 2145 2146 #: includes/trait-campaign-automations.php:159 2147 msgid "This sample has no active subscription. A real guide would be skipped unless subscribed at send time." 2148 msgstr "" 2149 2150 #: includes/trait-campaign-automations.php:159 2151 msgid "This sample matches now. Enabling never sends to historical orders; only a new Completed event can trigger a guide." 2152 msgstr "" 2153 2154 #: includes/trait-campaign-automations.php:163 2155 msgid "Enter a valid test email address." 2156 msgstr "" 2157 2158 #: includes/trait-campaign-checkout.php:16 2159 #: includes/trait-campaign-checkout.php:26 2160 msgid "Email me store news and offers. I will confirm my email address before subscribing." 2161 msgstr "" 2162 2163 #: includes/trait-campaign-contact-history.php:7 2164 msgid "Enter one valid email address to look up its contact history." 2165 msgstr "" 2166 2167 #: includes/trait-campaign-contact-history.php:19 2168 #: includes/trait-campaign-contact-history.php:24 2169 #: includes/trait-campaign-contact-history.php:51 2170 msgid "Contact history could not be read. Please try again after checking storage." 2171 msgstr "" 2172 2173 #: includes/trait-campaign-contact-history.php:62 2174 msgid "Contact history by email" 2175 msgstr "" 2176 2177 #: includes/trait-campaign-contact-history.php:62 2178 msgid "Only contacts recorded by Advanced Notifications are shown. A mail-system handoff does not confirm inbox delivery or that an email was read." 2179 msgstr "" 2180 2181 #: includes/trait-campaign-contact-history.php:62 2182 msgid "Email for contact history" 2183 msgstr "" 2184 2185 #: includes/trait-campaign-contact-history.php:62 2186 msgid "Look up contacts" 2187 msgstr "" 2188 2189 #: includes/trait-campaign-contact-history.php:65 2190 msgid "This address is protected by erasure. Its previous contact details are not shown or reconstructed." 2191 msgstr "" 2192 2193 #: includes/trait-campaign-contact-history.php:66 2194 #: includes/trait-campaign-controls.php:143 2195 #: includes/trait-campaign-controls.php:173 2196 #: includes/trait-campaign-privacy.php:128 2197 #: includes/trait-campaign-privacy.php:145 2198 msgid "Unknown" 2199 msgstr "" 2200 2201 #: includes/trait-campaign-contact-history.php:68 2202 msgid "Current subscription" 2203 msgstr "" 2204 2205 #: includes/trait-campaign-contact-history.php:69 2206 msgid "Recorded source" 2207 msgstr "" 2208 2209 #: includes/trait-campaign-contact-history.php:70 2210 msgid "No campaign contacts are currently retained for this email." 2211 msgstr "" 2212 2213 #: includes/trait-campaign-contact-history.php:71 2214 msgid "Campaign / saved context" 2215 msgstr "" 2216 2217 #: includes/trait-campaign-contact-history.php:71 2218 msgid "Recorded times (UTC)" 2219 msgstr "" 2220 2221 #: includes/trait-campaign-contact-history.php:71 2222 msgid "Outcome / reason" 2223 msgstr "" 2224 2225 #: includes/trait-campaign-contact-history.php:79 2226 msgid "Saved matching order" 2227 msgstr "" 2228 2229 #: includes/trait-campaign-contact-history.php:80 2230 msgid "Campaign content is no longer available. Only the retained outcome is shown." 2231 msgstr "" 2232 2233 #: includes/trait-campaign-contact-history.php:81 2234 msgid "Created" 2235 msgstr "" 2236 2237 #: includes/trait-campaign-contact-history.php:81 2238 msgid "Due" 2239 msgstr "" 2240 2241 #: includes/trait-campaign-contact-history.php:87 2242 msgid "Previous contacts" 2243 msgstr "" 2244 2245 #. translators: 1: Current page, 2: Total pages. 2246 #: includes/trait-campaign-contact-history.php:89 2247 msgid "Page %1$d of %2$d" 2248 msgstr "" 2249 2250 #: includes/trait-campaign-contact-history.php:90 2251 msgid "Next contacts" 1704 2252 msgstr "" 1705 2253 … … 1773 2321 msgstr "" 1774 2322 1775 #: includes/trait-campaign-controls.php:1431776 #: includes/trait-campaign-controls.php:1731777 #: includes/trait-campaign-privacy.php:1271778 #: includes/trait-campaign-privacy.php:1431779 msgid "Unknown"1780 msgstr ""1781 1782 2323 #: includes/trait-campaign-controls.php:151 1783 2324 msgid "Handed off does not verify inbox delivery. Unknown outcomes are never retried automatically. Retry only eligible known failures after correcting the reported problem." … … 1892 2433 msgstr "" 1893 2434 2435 #: includes/trait-campaign-entrypoints.php:24 2436 #: includes/trait-campaign-entrypoints.php:32 2437 msgid "Email purchasers" 2438 msgstr "" 2439 2440 #: includes/trait-campaign-entrypoints.php:32 2441 msgid "A parent product includes all its variations. Opening a draft sends no email." 2442 msgstr "" 2443 2444 #: includes/trait-campaign-entrypoints.php:38 2445 msgid "Email purchasers of this variation" 2446 msgstr "" 2447 2448 #: includes/trait-campaign-entrypoints.php:44 2449 msgid "Email this customer" 2450 msgstr "" 2451 2452 #: includes/trait-campaign-entrypoints.php:49 2453 msgid "Email selected orders" 2454 msgstr "" 2455 2456 #: includes/trait-campaign-entrypoints.php:62 2457 msgid "Select at least one available order." 2458 msgstr "" 2459 2460 #: includes/trait-campaign-entrypoints.php:65 2461 #: includes/trait-campaign-entrypoints.php:67 2462 msgid "A selected order is invalid or unavailable." 2463 msgstr "" 2464 2465 #: includes/trait-campaign-entrypoints.php:91 2466 msgid "A selected product is invalid or unavailable." 2467 msgstr "" 2468 2469 #: includes/trait-campaign-entrypoints.php:94 2470 msgid "Invalid draft source." 2471 msgstr "" 2472 2473 #: includes/trait-campaign-personalization.php:6 2474 msgid "Choose valid orders. No order selection has been ignored." 2475 msgstr "" 2476 2477 #: includes/trait-campaign-personalization.php:16 2478 msgid "Clear selected orders or choose Selected orders before previewing." 2479 msgstr "" 2480 2481 #: includes/trait-campaign-personalization.php:18 2482 msgid "Select at least one order." 2483 msgstr "" 2484 2485 #: includes/trait-campaign-personalization.php:21 2486 msgid "A selected order is unavailable or cannot be accessed. Review the selection." 2487 msgstr "" 2488 2489 #: includes/trait-campaign-personalization.php:26 2490 msgid "Selected order IDs (exact scope)" 2491 msgstr "" 2492 2493 #: includes/trait-campaign-personalization.php:26 2494 msgid "Used only with Selected orders. These orders do not expand into other purchases. All selected order statuses are included unless filtered below; invalid emails and suppression are excluded. Product customers includes purchases of the selected parent and its variations; a selected variation matches only that variation." 2495 msgstr "" 2496 2497 #: includes/trait-campaign-personalization.php:47 2498 msgid "Customer" 2499 msgstr "" 2500 2501 #: includes/trait-campaign-personalization.php:60 2502 msgid "Order context: highest matching order ID" 2503 msgstr "" 2504 2505 #: includes/trait-campaign-personalization.php:60 2506 msgid "Matching orders" 2507 msgstr "" 2508 1894 2509 #: includes/trait-campaign-privacy.php:57 1895 2510 msgid "Invalid email; use one plain email address per line." … … 1984 2599 msgstr "" 1985 2600 1986 #: includes/trait-campaign-privacy.php:12 32601 #: includes/trait-campaign-privacy.php:124 1987 2602 msgid "Subscribers and suppression" 1988 2603 msgstr "" 1989 2604 1990 #: includes/trait-campaign-privacy.php:12 32605 #: includes/trait-campaign-privacy.php:124 1991 2606 msgid "An order, account or pasted email is not opt-in evidence. Unknown remains unknown. Imports never remove an unsubscribe. For subscribed records, enter the actual evidence source; the recorded time is the import time, not an inferred original consent time." 1992 2607 msgstr "" 1993 2608 1994 #: includes/trait-campaign-privacy.php:12 52609 #: includes/trait-campaign-privacy.php:126 1995 2610 msgid "Find subscription or suppression" 1996 2611 msgstr "" 1997 2612 1998 #: includes/trait-campaign-privacy.php:12 52613 #: includes/trait-campaign-privacy.php:126 1999 2614 msgid "State" 2000 2615 msgstr "" 2001 2616 2002 #: includes/trait-campaign-privacy.php:12 72617 #: includes/trait-campaign-privacy.php:128 2003 2618 msgid "All states" 2004 2619 msgstr "" 2005 2620 2006 #: includes/trait-campaign-privacy.php:12 82621 #: includes/trait-campaign-privacy.php:129 2007 2622 msgid "Search" 2008 2623 msgstr "" 2009 2624 2010 #: includes/trait-campaign-privacy.php:12 82625 #: includes/trait-campaign-privacy.php:129 2011 2626 msgid "Email / state" 2012 2627 msgstr "" 2013 2628 2014 #: includes/trait-campaign-privacy.php:12 82629 #: includes/trait-campaign-privacy.php:129 2015 2630 msgid "Source / recorded time (UTC)" 2016 2631 msgstr "" 2017 2632 2018 #: includes/trait-campaign-privacy.php:140 2633 #: includes/trait-campaign-privacy.php:141 2634 msgid "Confirmation pending; current subscription unchanged." 2635 msgstr "" 2636 2637 #: includes/trait-campaign-privacy.php:142 2019 2638 msgid "Up to 200 matches. Erased addresses are represented only by protective hashes and are not listed as plaintext." 2020 2639 msgstr "" 2021 2640 2022 #: includes/trait-campaign-privacy.php:14 12641 #: includes/trait-campaign-privacy.php:143 2023 2642 msgid "Import records" 2024 2643 msgstr "" 2025 2644 2026 #: includes/trait-campaign-privacy.php:14 12645 #: includes/trait-campaign-privacy.php:143 2027 2646 msgid "1. Paste → 2. Preview → 3. Apply and review result" 2028 2647 msgstr "" 2029 2648 2030 #: includes/trait-campaign-privacy.php:14 22649 #: includes/trait-campaign-privacy.php:144 2031 2650 msgid "One email per line" 2032 2651 msgstr "" 2033 2652 2034 #: includes/trait-campaign-privacy.php:14 32653 #: includes/trait-campaign-privacy.php:145 2035 2654 msgid "Subscribed (evidence required)" 2036 2655 msgstr "" 2037 2656 2038 #: includes/trait-campaign-privacy.php:14 42657 #: includes/trait-campaign-privacy.php:146 2039 2658 msgid "Evidence/source" 2040 2659 msgstr "" 2041 2660 2042 #: includes/trait-campaign-privacy.php:14 42661 #: includes/trait-campaign-privacy.php:146 2043 2662 msgid "Preview import" 2044 2663 msgstr "" 2045 2664 2046 #: includes/trait-campaign-privacy.php:14 72665 #: includes/trait-campaign-privacy.php:149 2047 2666 msgid "Previewed import" 2048 2667 msgstr "" 2049 2668 2050 #: includes/trait-campaign-privacy.php:14 72669 #: includes/trait-campaign-privacy.php:149 2051 2670 msgid "State / evidence source:" 2052 2671 msgstr "" 2053 2672 2054 #: includes/trait-campaign-privacy.php:14 72673 #: includes/trait-campaign-privacy.php:149 2055 2674 msgid "Apply uses this saved preview. If you edit the input above, preview it again before applying." 2056 2675 msgstr "" 2057 2676 2058 #: includes/trait-campaign-privacy.php:1 482677 #: includes/trait-campaign-privacy.php:150 2059 2678 msgid "Valid / duplicate or already protected / rejected:" 2060 2679 msgstr "" 2061 2680 2062 #: includes/trait-campaign-privacy.php:15 02681 #: includes/trait-campaign-privacy.php:152 2063 2682 msgid "Apply previewed import" 2064 2683 msgstr "" 2065 2684 2066 #: includes/trait-campaign-privacy.php:15 32685 #: includes/trait-campaign-privacy.php:155 2067 2686 msgid "Applied / not applied (protected or storage failure):" 2068 2687 msgstr "" 2069 2688 2070 #: includes/trait-campaign-privacy.php:16 72071 #: includes/trait-campaign-privacy.php:17 02689 #: includes/trait-campaign-privacy.php:169 2690 #: includes/trait-campaign-privacy.php:172 2072 2691 msgid "YoOhw campaign data" 2073 2692 msgstr "" 2074 2693 2075 #: includes/trait-campaign-privacy.php:187 2694 #: includes/trait-campaign-privacy.php:185 2695 msgid "Saved order context" 2696 msgstr "" 2697 2698 #: includes/trait-campaign-privacy.php:195 2076 2699 msgid "Subscription and protection" 2077 2700 msgstr "" 2078 2701 2079 #: includes/trait-campaign-privacy.php: 1982702 #: includes/trait-campaign-privacy.php:206 2080 2703 msgid "Saved list references and legacy logs" 2081 2704 msgstr "" 2082 2705 2083 #: includes/trait-campaign-privacy.php:2 152706 #: includes/trait-campaign-privacy.php:223 2084 2707 msgid "Campaign storage is busy or unavailable. Personal data was not fully erased; run erasure again after checking storage and workers." 2085 2708 msgstr "" 2086 2709 2087 #: includes/trait-campaign-privacy.php:2 272710 #: includes/trait-campaign-privacy.php:235 2088 2711 msgid "A send is in flight. Run erasure again after the worker finishes. A protective hash already blocks future admission." 2089 2712 msgstr "" 2090 2713 2091 #: includes/trait-campaign-privacy.php:2 632714 #: includes/trait-campaign-privacy.php:271 2092 2715 msgid "Personal fields removed. Active campaign shared content is retained until completion; run erasure again if it contains personal text. Minimal recipient/campaign hashes, outcomes and suppression/erasure protection remain to prevent duplicate sends and data reconstruction." 2716 msgstr "" 2717 2718 #: includes/trait-campaign-purchase-history.php:53 2719 msgid "Purchase history across the store" 2720 msgstr "" 2721 2722 #: includes/trait-campaign-purchase-history.php:53 2723 msgid "Purchase frequency" 2724 msgstr "" 2725 2726 #: includes/trait-campaign-purchase-history.php:54 2727 msgid "Any purchase history" 2728 msgstr "" 2729 2730 #: includes/trait-campaign-purchase-history.php:57 2731 msgid "No repeat purchase in the last X days" 2732 msgstr "" 2733 2734 #: includes/trait-campaign-purchase-history.php:57 2735 msgid "These conditions use all valid purchases across the entire store, including orders outside the dates and products selected below. Product/category conditions still match one order; they do not change this into repeat purchases of only that product." 2736 msgstr "" 2737 2738 #: includes/trait-campaign-purchase-history.php:57 2739 msgid "Which purchases count?" 2740 msgstr "" 2741 2742 #: includes/trait-campaign-purchase-history.php:57 2743 msgid "Processing and Completed orders count by normalized billing email, including guest orders and orders before an account existed. Cancelled, Failed, Refunded and fully refunded orders do not count. Partial refunds count while an amount remains; free orders without refunds count. Inactivity uses the latest valid order creation time and X times 24 hours. A customer with no valid purchases never qualifies as inactive. Different emails are not merged." 2093 2744 msgstr "" 2094 2745 … … 2113 2764 msgstr "" 2114 2765 2766 #: includes/trait-campaign-subscriptions.php:42 2767 msgid "Enter a valid email address and try again." 2768 msgstr "" 2769 2770 #: includes/trait-campaign-subscriptions.php:43 2771 #: includes/trait-campaign-subscriptions.php:74 2772 msgid "Subscription storage is busy. Please try again." 2773 msgstr "" 2774 2775 #: includes/trait-campaign-subscriptions.php:57 2776 msgid "The request could not be completed. Please try again later." 2777 msgstr "" 2778 2779 #: includes/trait-campaign-subscriptions.php:61 2780 #: includes/trait-campaign-subscriptions.php:113 2781 msgid "Confirm your email subscription" 2782 msgstr "" 2783 2784 #: includes/trait-campaign-subscriptions.php:62 2785 msgid "Someone requested campaign emails from this store for this address. To subscribe, open the link below and confirm. It expires in 24 hours. If you did not request this, ignore this email; your preference has not changed." 2786 msgstr "" 2787 2788 #: includes/trait-campaign-subscriptions.php:72 2789 msgid "This confirmation is invalid, expired or already used. Submit a new subscription request." 2790 msgstr "" 2791 2792 #: includes/trait-campaign-subscriptions.php:85 2793 msgid "The subscription could not be saved. Submit a new request and try again." 2794 msgstr "" 2795 2796 #: includes/trait-campaign-subscriptions.php:92 2797 msgid "Email address" 2798 msgstr "" 2799 2800 #: includes/trait-campaign-subscriptions.php:92 2801 msgid "I would like to receive campaign emails from this store. I can unsubscribe at any time." 2802 msgstr "" 2803 2804 #: includes/trait-campaign-subscriptions.php:92 2805 msgid "Leave this field empty" 2806 msgstr "" 2807 2808 #: includes/trait-campaign-subscriptions.php:92 2809 msgid "Request subscription" 2810 msgstr "" 2811 2812 #: includes/trait-campaign-subscriptions.php:92 2813 msgid "Check your email to confirm. Submitting this form does not subscribe you." 2814 msgstr "" 2815 2816 #: includes/trait-campaign-subscriptions.php:96 2817 msgid "Use the subscription form." 2818 msgstr "" 2819 2820 #: includes/trait-campaign-subscriptions.php:99 2821 msgid "Choose whether you want to request campaign emails." 2822 msgstr "" 2823 2824 #: includes/trait-campaign-subscriptions.php:103 2825 msgid "If this address is eligible, a confirmation email has been requested. Check your inbox and spam folder. Requests are limited; you can try again later." 2826 msgstr "" 2827 2828 #: includes/trait-campaign-subscriptions.php:103 2829 msgid "Check your email" 2830 msgstr "" 2831 2832 #: includes/trait-campaign-subscriptions.php:112 2833 msgid "Invalid confirmation link." 2834 msgstr "" 2835 2836 #: includes/trait-campaign-subscriptions.php:113 2837 msgid "Confirm that you want campaign emails from this store. This also replaces an earlier unsubscribe for this address. You can unsubscribe again at any time." 2838 msgstr "" 2839 2840 #: includes/trait-campaign-subscriptions.php:113 2841 #: includes/trait-campaign-subscriptions.php:114 2842 msgid "Confirm subscription" 2843 msgstr "" 2844 2845 #: includes/trait-campaign-subscriptions.php:118 2846 msgid "Your email subscription is confirmed. You can unsubscribe from any campaign email." 2847 msgstr "" 2848 2849 #: includes/trait-campaign-subscriptions.php:123 2850 msgid "Email confirmation is pending. Your current preference remains in effect until you confirm." 2851 msgstr "" 2852 2853 #: includes/trait-campaign-subscriptions.php:124 2854 msgid "Campaign email preference" 2855 msgstr "" 2856 2857 #: includes/trait-campaign-subscriptions.php:124 2858 msgid "Preference for your current account email:" 2859 msgstr "" 2860 2861 #: includes/trait-campaign-subscriptions.php:125 2862 msgid "Request subscription by email" 2863 msgstr "" 2864 2865 #: includes/trait-campaign-subscriptions.php:125 2866 msgid "A subscription request requires email confirmation. Unsubscribe applies immediately." 2867 msgstr "" 2868 2869 #: includes/trait-campaign-subscriptions.php:133 2870 msgid "The preference could not be saved. Try again later." 2871 msgstr "" 2872 2115 2873 #: yoohw-advanced-notifications.php:43 2116 2874 msgid "Advanced Notifications for WooCommerce requires WooCommerce to be active." -
yoohw-advanced-notifications/tags/0.4.0/readme.txt
r3771948 r3789014 6 6 Requires PHP: 8.1 7 7 Requires Plugins: woocommerce 8 Stable tag: 0. 3.08 Stable tag: 0.4.0 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 20 20 = Choose and review your audience = 21 21 22 * Select product or variation purchasers, WooCommerce customers with matching orders, registered users or a pasted email list. Order-based sources include guest customers. 22 * Select product or variation purchasers, selected orders, WooCommerce customers with matching orders, registered users, subscribed email addresses or a pasted email list. Order-based sources include guest customers. 23 * Start from Email purchasers on Products or Email selected orders / Email this customer on Orders. These actions create a draft with an explicit scope; preview and confirmation are still required before sending. 23 24 * Filter matching orders by product, category (including child categories), creation date, order status and billing country. These order conditions must match the same order. 24 25 * Filter registered users by role and profile billing country. Only filters supported by the selected source can be used. 25 26 * Select by subscription status or a previous campaign's recorded handoff outcome. Missing or unknown delivery history is not treated as proof that an email was never sent. 26 27 * Apply exclusions, remove duplicate email addresses and respect saved unsubscribes across every recipient source. 28 * Choose first-time buyers (one valid order), repeat buyers (two or more), or customers with no valid purchase in the last X days. History spans the entire store, outside campaign product/date filters. Processing and Completed orders count by normalized billing email; cancelled, failed and fully refunded orders do not. Partial refunds count while value remains; free orders without refunds count. Inactivity uses order creation time and X times 24 hours; customers with no valid purchases are excluded. 27 29 * Save audience criteria for reuse. Each use requires a fresh recipient preview and confirmation. 28 30 * Review selection and exclusion counts and inspect why an email address is included or excluded. … … 35 37 * Use WooCommerce HTML email styling, the rich-text editor and desktop/mobile previews for a sample recipient. 36 38 * Send a test email and continue editing the draft before confirming recipients. 37 * Personalize the message body with {customer_name} and {product_name}. A missing customer name falls back to the email address. The product variable is a campaign-wide label, not a record of each recipient's purchases. Subjects and headings do not expand these variables.39 * New campaigns personalize subject, heading and body with {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products} and {order_url}. Missing names use Customer. {product_name} remains a campaign-wide label; order details come from the matching order with the highest order ID and are empty without order context. Guest order links are empty; account order links require the owning account login. Already-confirmed older campaigns keep their original rendering contract. 38 40 39 41 = Schedule and control sending = … … 46 48 * Recover interrupted work using confirmed recipients and bounded retries for eligible known failures. Unknown handoff outcomes are not automatically retried. 47 49 50 = One guide after Completed = 51 52 * Follow Conditions → Content → Timing → Review in Automations. Compose with a live WooCommerce preview and Desktop/Mobile controls, then refresh the exact order sample in Review. Save a guide with optional products/categories and a delay of 0–8760 hours. Preview an accessible sample order or send a test to your chosen address, then explicitly enable the saved rule. 53 * Only new transitions to Completed are captured. Enabling never scans historical orders. Each rule/order can create at most one email, including repeated transitions and multiple matching items; different orders for the same email can each receive a guide. 54 * An active subscription is required at sending. Unknown is not consent. Orders must still be Completed, have the same valid billing email, match saved product/category conditions and not be fully refunded. Partial refunds remain eligible while value remains. Subscription, suppression and erasure protections are checked before handoff. 55 * Content, triggering-order context and UTC due time are fixed when captured. Editing a rule changes future events. Disabling stops new events and cancels unstarted mail; started work may finish. Re-enabling does not restore cancelled mail. 56 * Use Campaigns & Logs or the contact lookup to inspect the guide, exact order and recorded result. Existing limits, recovery and unknown-outcome protections apply. A working queue is required; delivery may be later than the due time. 57 48 58 = Subscription and privacy tools = 59 60 * Place [yoohw_an_subscribe] on a page for guest signup. Optional, unchecked Classic Checkout and Checkout Blocks fields (Blocks requires WooCommerce 8.9 or later) request a confirmation email; buying or creating an account never establishes consent. 61 * Confirm mailbox ownership using the emailed link and confirmation button within 24 hours. A new verified request can replace an earlier unsubscribe; imports cannot. Erasure protection remains in effect. 62 * View or change the preference for the current email in My Account. Choose Subscribed email addresses in the composer to include subscribers without an account or order. 63 * Look up one email under Subscribers to review its retained campaign outcomes, reasons and campaign links. Handoff does not prove inbox delivery or reading. 49 64 50 65 * Keep subscribed, unsubscribed and unknown states separate, with the recorded source and time where available. … … 60 75 Only this plugin's campaign emails are subject to its send controls and admission limits. WooCommerce transactional emails and unrelated scheduled actions keep their existing behavior. Test emails are outside the campaign admission limits. 61 76 62 This plugin does not include recurring marketing automation, WooCommerce Subscriptions audiences, CRM synchronization or additional messaging channels.77 This plugin does not include multi-step or recurring marketing automation, WooCommerce Subscriptions audiences, CRM synchronization or additional messaging channels. 63 78 64 79 == Installation == … … 97 112 = What data does the plugin store and erase? = 98 113 99 The plugin stores campaign content, confirmed recipients, scheduling and delivery records, drafts, saved audience criteria, subscription evidence and opt-outs in your WordPress database. Emails are sent through the mail transport configured on your site. 114 The plugin stores campaign content, confirmed recipients, scheduling and delivery records, drafts, saved audience criteria, subscription evidence and opt-outs in your WordPress database. Emails are sent through the mail transport configured on your site. Subscription requests store the email, source, request/expiry time and a hashed confirmation token for at most 24 hours. Rate counters store hashes, not raw IP addresses. Confirmation requests are limited per address, client and site. A protected erased address is not re-enrolled or reconstructed by a new request. 100 115 101 116 WordPress Tools > Export Personal Data and Erase Personal Data include this plugin's records for the requested email address, including guests. Erasure retains protective hashes and opt-out evidence to prevent reconstruction or another send. In-flight work or shared content in an active campaign may require another erasure pass after completion; the erasure result reports retained data. … … 107 122 Deactivation cancels pending campaign work and removes the reconciliation event while retaining campaign records and opt-outs. Reactivation does not automatically restart cancelled work. 108 123 109 When upgrading, stop background workers that have already loaded the old plugin code before replacing files. Version 0. 3.0 keeps the existing plugin slug, text domain, settings, campaigns and opt-outs. Do not downgrade directly to 0.2.2, which does not understand the new cancellation and erasure protections. Data from the separate YoOhw Extra Code plugin is not imported automatically.124 When upgrading, stop background workers that have already loaded the old plugin code before replacing files. Version 0.4.0 keeps the existing plugin slug, text domain, settings, campaigns and opt-outs. Do not downgrade directly to 0.2.2, which does not understand the new cancellation and erasure protections. Data from the separate YoOhw Extra Code plugin is not imported automatically. 110 125 111 126 = Can I translate the interface? = … … 115 130 == Changelog == 116 131 117 = 0.3.0 = 118 * Rename the plugin to Advanced Notifications for WooCommerce; keep the existing slug, text domain and stored data. 119 * Add individual campaign controls and shared sending admission limits. 120 * Add durable drafts, duplication, content templates and personalized previews. 121 * Add source-aware saved audiences and explicit timezone scheduling. 122 * Add subscription/suppression administration, privacy callbacks and terminal retention. 123 * Preserve erased data boundaries, known-unsent history and cancellation during concurrent recovery. 124 * Unify campaign forms with the admin color scheme, SelectWoo fields and desktop/mobile preview controls. 125 * Harden confirmed recipient snapshots, duplicate protection, bounded retries and interrupted-work recovery. 132 = 0.4.0 = 133 * Add product and order email entry points that create scoped drafts, with HPOS and posts order storage support. 134 * Personalize new campaign subjects, headings and bodies with frozen customer, store and representative-order context; preserve already-confirmed campaigns. 135 * Add verified subscriptions through a signup shortcode, Classic Checkout, Checkout Blocks and My Account without treating purchase or account creation as consent. 136 * Add per-email contact history lookup with retained outcomes, reasons and campaign links. 137 * Add store-wide first-time, repeat-buyer and purchase-inactivity filters for campaigns and saved audiences. 138 * Add explicitly enabled Completed-order guides with product/category conditions, a fixed delay and one immutable delivery per rule/order. 139 * Recheck rule, order, subscription, suppression and erasure before guide handoff; preserve cancellation, duplicate protection and unknown-outcome boundaries. 140 * Align automation authoring with the four-step composer, live Desktop/Mobile previews and exact-order preview/test; hide stale samples after edits. 141 * Fix Library warnings when optional draft or saved-audience names are missing. 126 142 127 = 0.2.2 = 128 * Align the translation domain with the WordPress.org slug yoohw-advanced-notifications. 129 * Resolve Plugin Check findings for SQL identifiers, input handling, test fixtures and plugin metadata. 130 * Load admin JavaScript and CSS from separate files with WordPress dependencies. 131 132 = 0.2.1 = 133 * Register the languages directory on init and include a POT translation template. 134 * Make remaining delivery messages and status labels translatable. 135 * Add translator notes and translation setup instructions. 136 137 = 0.2.0 = 138 * Add WooCommerce customers and Manual email list recipient sources. 139 * Add multi-role filtering for registered users, including preview and campaign history. 140 * Preserve recipient selections when restoring drafts and retrying failed schedules. 141 * Use native JavaScript trim() for the live preview. 142 143 = 0.1.0 = 144 * Extract standalone customer email campaigns from YoOhw Extra Code. 145 * Remove WooCommerce Subscriptions audiences and exclusions, and Audience sync integration. 146 * Isolate plugin storage/hooks and use the current store's sender defaults. 143 See changelog.txt for the full version history. 147 144 148 145 == Upgrade Notice == 149 146 147 = 0.4.0 = 148 Adds scoped product/order campaigns, verified subscriptions, contact history, purchase-history filters and Completed-order guides. Existing data and confirmed work are retained. New automation rules stay disabled until explicitly enabled; there is no historical backfill. Stop workers using the old code before replacing plugin files. Do not downgrade to an older version without reviewing pending jobs and subscription/privacy compatibility. 149 150 150 = 0.3.0 = 151 151 Campaign controls, reusable drafts, audience filters, scheduling and privacy tools. Existing data is retained. Stop old background workers before upgrading. Do not downgrade to 0.2.2 because it lacks the new cancellation and erasure protections. -
yoohw-advanced-notifications/tags/0.4.0/yoohw-advanced-notifications.php
r3771948 r3789014 4 4 * Plugin URI: https://wordpress.org/plugins/yoohw-advanced-notifications 5 5 * Description: Compose, preview, schedule and track WooCommerce customer email campaigns. 6 * Version: 0. 3.06 * Version: 0.4.0 7 7 * Author: YoOhw Studio 8 8 * Author URI: https://yoohw.com/ … … 20 20 } 21 21 22 define( 'YOOHW_AN_VERSION', '0. 3.0' );22 define( 'YOOHW_AN_VERSION', '0.4.0' ); 23 23 24 24 function yoohw_an_load_textdomain() { -
yoohw-advanced-notifications/trunk/assets/admin.css
r3771948 r3789014 810 810 811 811 .yoohw-an-workspace .an-preview-device .dashicons { display: block; width: 20px; height: 20px; margin: 0; font-size: 20px; line-height: 20px; } 812 813 /* Automation authoring shares the composer steps, editor and preview layout. */ 814 .an-automation-rule { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 16px 0; border-top: 1px solid #dcdcde; } 815 .an-automation-rule p { margin: 6px 0 0; color: #50575e; } 816 .an-automation-state { display: inline-block; margin-left: 12px; padding: 2px 8px; border: 1px solid #c3c4c7; border-radius: 3px; font-size: 12px; } 817 .an-automation-rule-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } 818 .an-automation-form details { margin-top: 16px; } 819 .an-automation-form .an-field > input[type="number"] { max-width: 240px; } 820 .an-automation-form .an-sample-stale { padding: 12px; border-left: 4px solid #dba617; background: #fcf9e8; } 821 .an-automation-form .an-automation-sample[hidden], .an-automation-form .an-sample-stale[hidden] { display: none !important; } 822 @media (max-width: 782px) { .an-automation-rule { align-items: flex-start; flex-direction: column; gap: 12px; } } -
yoohw-advanced-notifications/trunk/assets/admin.js
r3771948 r3789014 27 27 $row.find(':input').prop('disabled', false); 28 28 } 29 revealApplicable('.an-selected-orders', source === 'selected_orders'); 29 30 revealApplicable('#yoohw-advanced-notifications-products-row', product); 30 31 revealApplicable('#yoohw-advanced-notifications-roles-row', registered); 31 32 revealApplicable('#yoohw-advanced-notifications-manual-row', manual); 32 revealApplicable('.an-order-filters', product || source === yoohwAN.customersSource );33 revealApplicable('.an-country-filter', !manual );33 revealApplicable('.an-order-filters', product || source === yoohwAN.customersSource || source === 'selected_orders'); 34 revealApplicable('.an-country-filter', !manual && source !== 'subscribed_emails'); 34 35 $('#yoohw-advanced-notifications-customers-row').toggle(source === yoohwAN.customersSource); 35 36 $('.an-incompatible-help').prop('hidden', !$('.an-inapplicable-selection').length); … … 143 144 144 145 editor.on('keyup change input SetContent NodeChange', updateEmailPreview); 146 editor.on('change input keyup', markAutomationPreviewStale); 145 147 editor.yoohwEmailNotifyPreviewBound = true; 146 148 } … … 209 211 if (panel) { showStep(names.indexOf(panel.dataset.anPanel), false); } 210 212 }, true); 211 showStep(0, false); 213 var initial = names.indexOf($form.attr('data-an-initial-step')); 214 showStep(initial < 0 ? 0 : initial, false); 212 215 } 213 216 … … 282 285 updateEmailPreview(); 283 286 }); 287 288 function markAutomationPreviewStale() { 289 $('.an-automation-form .an-automation-sample').prop('hidden', true); 290 $('.an-automation-form .an-sample-stale').prop('hidden', false); 291 } 292 $(document).on('input change', '.an-automation-form input:not([type="hidden"]), .an-automation-form select, .an-automation-form textarea', function() { 293 if (this.name !== 'test_email' && this.name !== 'name') { markAutomationPreviewStale(); } 294 }); 284 295 $(document).on('submit', 'form', function() { if (window.tinymce) { window.tinymce.triggerSave(); } }); 285 296 $(document).on('change', '#recipient_source, .an-order-filters :input, .an-country-filter :input, #yoohw-advanced-notifications-roles-row :input, #yoohw-advanced-notifications-products-row :input, #yoohw-advanced-notifications-manual-row :input', toggleRecipientFields); -
yoohw-advanced-notifications/trunk/docs/operator-features.md
r3771948 r3789014 1 # Tính năng vận hành campaign ( chưa phát hành)1 # Tính năng vận hành campaign (0.4.0) 2 2 3 3 Nền đối chiếu: `74353181835147d8e68d9bca87a3d801c3e772dd` trên local và `origin/main`. Giữ schema recipient 3, Action Scheduler, manifest xác nhận và durable opt-out hiện có. Không thêm service hoặc kênh gửi khác. … … 78 78 79 79 Các selection field dùng SelectWoo có sẵn của WooCommerce (giao diện Select2), bao gồm các bộ lọc và người nhận mẫu; giá trị gốc và validation vẫn giữ nguyên. Hai nút icon Desktop/Mobile điều chỉnh bố cục preview trong cả bước soạn và preview người nhận, có tooltip/nhãn hỗ trợ đọc màn hình và trạng thái lựa chọn rõ ràng; không tạo thao tác gửi. 80 81 ### AN-5: Liên hệ từ Products và Orders (0.4.0) 82 83 - Products có **Email purchasers** tại danh sách và trang sửa. Sản phẩm cha gồm các variation; từng variation có liên kết riêng chỉ chọn người mua variation đó. Orders có bulk action **Email selected orders** trên cả HPOS và lưu trữ cũ; trang chi tiết có **Email this customer**. Các thao tác chỉ lưu bản nháp, chưa tạo job hay gửi email. 84 - Nguồn **Selected orders** giữ tập ID rõ ràng, sửa được trong composer. Mặc định xét mọi trạng thái trong tập đã chọn để hỗ trợ thông báo cho cả đơn đang chờ/hủy; bộ lọc trạng thái có thể thu hẹp. Product customers tiếp tục mặc định Processing/Completed. Guest và tài khoản được gộp theo billing email đã chuẩn hóa, mỗi email nhận một thư cho campaign. Bộ lọc đơn vẫn khớp cùng một đơn; ID mất/quyền không đủ bị từ chối, không mở rộng tập chọn. 85 - Subject, heading và body của campaign mới hỗ trợ `{customer_name}`, `{store_name}`, `{product_name}`, `{order_number}`, `{ordered_products}`, `{order_url}`. `{product_name}` vẫn là nhãn chung của campaign. Thông tin riêng lấy từ **đơn khớp có ID lớn nhất**, gồm toàn bộ tên dòng sản phẩm của đơn đó; preview ghi số đơn đại diện và số đơn khớp. Không lấy đơn mới hơn nằm ngoài phạm vi. Thiếu tên dùng **Customer**; thiếu ngữ cảnh đơn thì các biến đơn rỗng. 86 - `{order_url}` chỉ có khi email tài khoản sở hữu khớp billing email, dùng trang My Account và cần đăng nhập đúng chủ đơn. Guest hoặc email khác tài khoản không có liên kết; không lưu khóa order/guest. Không chèn liên kết vào mẫu mặc định khi thiếu ngữ cảnh. 87 - Live editor hiển thị nội dung template; **Preview Recipients** là preview cá nhân hóa thật, chọn được tối đa 20 người mẫu. Email thử dùng người đủ điều kiện đầu tiên, hoặc Test Customer nếu chưa có người nhận, và luôn gửi tới địa chỉ thử đã nhập. Ba mẫu có hướng dẫn điền thay đổi/ngày hiệu lực/hành động/liên hệ và vẫn sửa tự do. 88 - Lưu/mở lại/duplicate/saved audience giữ tiêu chí ID; phải preview dữ liệu hiện tại khi dùng lại. Xác nhận giữ nguyên context, tên cửa hàng, nội dung và recipient; dispatcher/recovery đọc snapshot, không truy vấn lại đơn để gửi. Campaign đã xác nhận trước AN-5 giữ subject/heading literal và cách thay body cũ. Durable opt-out, outcome unknown, privacy/retention hiện hành tiếp tục có hiệu lực; export bổ sung context của đúng email và erasure xóa context khỏi snapshot/preview/args. 89 90 Kiểm chứng mới: `tests/contextual-campaigns.php` và `tests/contextual-entrypoints.php`, được chạy trong CI regression với database reliability riêng và mail bị chặn. Bằng chứng theo candidate ghi trong PR. Không chứng minh SMTP/inbox thật. 91 92 93 ### AN-6: Đăng ký trực tiếp và lịch sử liên hệ (0.4.0) 94 95 - Chèn shortcode `[yoohw_an_subscribe]` vào trang. Khách nhập email, chủ động chọn đồng ý rồi nhận thư xác nhận. Classic Checkout và Checkout Blocks có checkbox tùy chọn, không chọn sẵn, chỉ gửi yêu cầu xác nhận cho billing email; My Account quản lý đúng email hiện tại của tài khoản. Không suy diễn consent từ đơn hàng/tài khoản. Blocks dùng Additional Checkout Fields API của WooCommerce, không lưu lựa chọn mặc định trên hồ sơ khách. 96 - Link email chỉ mở trang xác nhận; cần bấm **Confirm subscription** để thay đổi trạng thái, tránh scanner email tự đăng ký. Token ngẫu nhiên, chỉ lưu hash, hết hạn sau 24 giờ, dùng một lần. Trước xác nhận, trạng thái có hiệu lực vẫn là unknown hoặc unsubscribed; My Account và tìm kiếm subscriber thể hiện yêu cầu đang chờ. 97 - Đăng ký lại sau unsubscribe cần yêu cầu mới và xác nhận mailbox. Record subscription xác nhận ghi nhận đúng thế hệ suppression trước yêu cầu; unsubscribe mới tạo thế hệ mới nên chặn cả link cũ lẫn quyền xác nhận cũ. Không xóa option suppression legacy hoặc bản ghi bảo vệ hàng loạt. Import không có thẩm quyền xác nhận này và không gỡ opt-out. 98 - Nguồn **Subscribed email addresses** dùng record hiện có, bao gồm guest không tài khoản/đơn hàng; chỉ lấy subscribed còn hiệu lực. Không áp dụng product/order/country/roles/manual criteria của nguồn khác. Draft/saved audience/preview/duplicate/lịch/controls dùng đường hiện có. Worker kiểm tra lại đăng ký trước handoff; unsubscribe hoặc trạng thái unknown sau preview không được gửi trong nguồn này. Campaign đã xác nhận không lấy thêm subscriber mới. 99 - **Subscribers → Contact history by email** tra cứu chính xác email trên bảng recipient hiện có, 50 dòng/trang: campaign, subject/context còn được lưu, due/updated time UTC, outcome và lý do, liên kết mở campaign. Không query đơn live để khôi phục context. Retention chỉ còn outcome sẽ báo nội dung không còn; tombstone erasure chặn toàn bộ lịch sử plaintext. 100 - Anti-abuse dùng nonce/honeypot trên form và quota nguyên tử dưới mutex privacy hiện có: một yêu cầu/email mỗi 10 phút, tối đa 5/client mỗi 30 phút, 100/site mỗi giờ. Client chỉ dùng HMAC của REMOTE_ADDR (không tin X-Forwarded-For, không lưu IP gốc); quota chung NAT có thể giới hạn nhiều khách cùng mạng. Phản hồi công khai không cho biết email đã tồn tại, unsubscribed hay erased. Pending request/counter hết hạn được dọn qua reconciliation hàng giờ; không tự retry confirmation mail khi transport mơ hồ. 101 - Confirmation mail là thư xác minh theo yêu cầu, có thể gửi tới địa chỉ đang unsubscribed để chính chủ đăng ký lại; không dùng đường này cho campaign. Nó dùng WooCommerce template/sender của shop và transport WordPress, không được trình bày như campaign handoff trong contact history. Kiểm thử chặn toàn bộ mail ra ngoài, không xác minh SMTP/inbox thật. 102 - Erasure giữ nguyên protective hash và không cho signup mới phục hồi dữ liệu/subscriber đã erase. Pending request được scrub cùng dữ liệu cá nhân hiện có; export bổ sung nguồn/thời gian yêu cầu, không xuất token. Việc đăng ký lại sau unsubscribe chỉ thay lựa chọn tương lai, không dựng lại history, không replay campaign cũ, không tự thay outcome unknown. 103 104 Bộ kiểm chứng mới: `subscriptions.php`, `checkout-subscription.php`, `contact-history.php` và concurrency cho request/confirm/unsubscribe/erasure. Bằng chứng theo candidate và giới hạn runtime ghi trong PR; không thêm service, bảng CRM hoặc cơ chế tracking mở/nhấp email. 105 106 107 ## Purchase history and Completed-order guides (AN-7) 108 109 Compose and saved audiences support `purchase_frequency` (`first`/`repeat`) and `inactive_days` (1–36500). These criteria scan valid purchases across the whole store, separately from same-order product/category/date/status/country conditions. Identity is normalized billing email, including guest/account orders; different emails are never inferred to be the same customer. Valid purchases are Processing/Completed orders excluding full refunds; a partial refund counts while value remains, and free orders without refunds count. Inactivity uses the latest valid order creation instant and X × 24 hours. Never-buyers and orders with unavailable dates do not qualify. 110 111 Automations supports one fixed guide per rule/order after a new Completed transition. Save disabled, inspect conditions/content/delay, preview or test with an accessible order, then explicitly Enable. Test mail goes only to its entered address and never saves/enables a rule or creates a delivery job. Products/variations and category descendants reuse the existing same-order matching behavior. Each eligible order can receive its own guide even when another order shares the email. 112 113 The event stores an immutable campaign manifest using a deterministic rule/order identity. Repeated events, items and workers reuse the same identity. Delay is an exact UTC offset from capture; queue delays never roll the due time to another day. Edits affect future events only. Disable rotates the enabled generation, durably blocks pending campaigns and cancels their unstarted rows. Re-enable cannot revive them. Work already admitted may finish. History and contact lookup retain the exact triggering order and result. 114 115 Before handoff the rule generation, fresh order, billing email and saved product/category conditions are rechecked. An order must still be Completed and not fully refunded; other states are skipped, partial refunds remain eligible while value remains. Active subscription is required and checked again after email rendering. Unknown never becomes subscribed through purchase. Existing suppression, erasure, claim, rate, recovery and unknown-handoff protections apply. 116 117 Only new events are admitted; there is no historical backfill. Captured manifests interrupted before their history row are registered by existing reconciliation and deactivation. A database/process failure before durable capture cannot be reconstructed without a new transition: the WooCommerce logger records a non-personal capture error. Operators must investigate storage/history and any mail-provider ambiguity before manually changing order status; the plugin never automatically replays an unknown handoff. No external event service or general automation builder is added. 118 119 120 Automation authoring follows the same four-step layout as Compose: **Conditions → Content → Timing → Review**. Content uses the shared WooCommerce live preview, Visual/Code editor and Desktop/Mobile controls. Live preview retains placeholders; Review refreshes the exact order sample through the existing server renderer. Preview/test returns to Review and preserves the unsaved form. Changing content, conditions, timing or sample order hides the old personal preview and asks for a refresh. Saving and enabling remain separate operations; list controls always use the saved configuration. The campaign-history link opens the campaign list so pending guides are discoverable. -
yoohw-advanced-notifications/trunk/includes/class-customer-email-notify.php
r3771948 r3789014 10 10 require_once __DIR__ . '/trait-campaign-audiences.php'; 11 11 require_once __DIR__ . '/trait-campaign-privacy.php'; 12 require_once __DIR__ . '/trait-campaign-entrypoints.php'; 13 require_once __DIR__ . '/trait-campaign-personalization.php'; 14 require_once __DIR__ . '/trait-campaign-subscriptions.php'; 15 require_once __DIR__ . '/trait-campaign-checkout.php'; 16 require_once __DIR__ . '/trait-campaign-contact-history.php'; 17 require_once __DIR__ . '/trait-campaign-purchase-history.php'; 18 require_once __DIR__ . '/trait-campaign-automations.php'; 19 require_once __DIR__ . '/trait-campaign-automation-ui.php'; 12 20 13 21 class YOOHW_AN_Customer_Email_Notify { … … 17 25 use YOOHW_AN_Campaign_Audiences; 18 26 use YOOHW_AN_Campaign_Privacy; 27 use YOOHW_AN_Campaign_Entrypoints; 28 use YOOHW_AN_Campaign_Personalization; 29 use YOOHW_AN_Campaign_Subscriptions; 30 use YOOHW_AN_Campaign_Checkout; 31 use YOOHW_AN_Campaign_Contact_History; 32 use YOOHW_AN_Campaign_Purchase_History; 33 use YOOHW_AN_Campaign_Automations; 34 use YOOHW_AN_Campaign_Automation_UI; 19 35 20 36 const ACTION_SEND_SINGLE_EMAIL = 'yoohw_an_send_single_email'; … … 50 66 const SOURCE_REGISTERED_USERS = 'registered_users'; 51 67 const SOURCE_WOOCOMMERCE_CUSTOMERS = 'woocommerce_customers'; 68 const SOURCE_SUBSCRIBED = 'subscribed_emails'; 69 const SOURCE_SELECTED_ORDERS = 'selected_orders'; 52 70 const SOURCE_MANUAL_EMAILS = 'manual_emails'; 53 71 … … 56 74 private $last_mail_error = ''; 57 75 private $mail_handoff_started = false; 76 private $last_automation_outcome = ''; 58 77 private $current_action_id = 0; 59 78 private $recovery_enabled = true; … … 63 82 public function __construct() { 64 83 $this->register_operator_features(); 84 $this->register_contextual_entrypoints(); 85 $this->register_subscriptions(); 86 $this->register_automations(); 65 87 // Register after WooCommerce sorts Marketing at priority 99 to preserve our position. 66 88 add_action( 'admin_menu', [ $this, 'add_submenu' ], 100 ); … … 143 165 public function deactivate() { 144 166 $this->recovery_enabled = false; 167 $this->register_automation_manifests(); 145 168 $this->block_campaigns_on_deactivation(); 146 169 wp_unschedule_hook( self::ACTION_RECONCILE_CAMPAIGNS ); … … 176 199 177 200 public function reconcile_open_campaigns( $campaign_id = '' ) { 201 $this->reconcile_automation_campaigns(); 178 202 $campaigns = $this->get_campaign_history(); 179 203 $campaign_id = sanitize_text_field( $campaign_id ); … … 781 805 782 806 $active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'campaign'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin navigation, filters and notices; no state is changed. 807 808 if ( 'automations' === $active_tab ) { $this->render_automations_page(); return; } 783 809 784 810 if ( 'library' === $active_tab ) { … … 1155 1181 ); 1156 1182 ?> 1157 <p><?php /* translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. */ esc_html_e( ' Body variables: {customer_name} uses the saved recipient name, falling back to email; {product_name} is the shared campaign product label, never a personal purchase. With no product selection it uses the audience label. Subject and heading are literal.', 'yoohw-advanced-notifications' ); ?></p>1183 <p><?php /* translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. */ esc_html_e( 'Variables in subject, heading and body: {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products}, {order_url}. Order variables use the matching order with the highest order ID; preview shows its number and the matching order count. Without order context they are empty; missing names use Customer. {product_name} remains the shared campaign label. Order links require the matching account login; guests have no order link. The live editor shows template text; Preview Recipients and test email use the first eligible recipient.', 'yoohw-advanced-notifications' ); ?></p> 1158 1184 <p><?php esc_html_e( 'An unsubscribe link is added automatically to campaign emails.', 'yoohw-advanced-notifications' ); ?></p> 1159 1185 </div> … … 1296 1322 'campaigns' => [ 'label' => __( 'Campaigns', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'campaigns' ] ) ], 1297 1323 'campaign' => [ 'label' => __( 'Compose', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url() ], 1324 'automations' => [ 'label' => __( 'Automations', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'automations' ] ) ], 1298 1325 'library' => [ 'label' => __( 'Library', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'library' ] ) ], 1299 1326 'subscribers' => [ 'label' => __( 'Subscribers', 'yoohw-advanced-notifications' ), 'url' => $this->get_admin_page_url( [ 'tab' => 'subscribers' ] ) ], … … 2325 2352 ); 2326 2353 2327 $test_message = str_replace( 2328 [ 2329 '{customer_name}', 2330 '{product_name}', 2331 ], 2332 [ 2333 __( 'Test Customer', 'yoohw-advanced-notifications' ), 2334 $payload['products_label'], 2335 ], 2336 $payload['message'] 2337 ); 2354 $test_recipients = $this->get_recipients_by_payload( $payload ); 2355 $personal = $this->render_personalized_email( $payload, $test_recipients[0] ?? [ 'name' => __( 'Test Customer', 'yoohw-advanced-notifications' ), 'email' => $test_email ] ); 2356 $test_message = $personal['message']; 2338 2357 $test_message = $this->append_unsubscribe_footer( $test_message, $test_email, $payload['campaign_id'] ); 2339 2358 2340 2359 $sent = $this->send_woocommerce_email( 2341 2360 $test_email, 2342 '[TEST] ' . $p ayload['subject'],2343 $p ayload['heading'],2361 '[TEST] ' . $personal['subject'], 2362 $personal['heading'], 2344 2363 $test_message, 2345 2364 $payload['from_email'], … … 2488 2507 } 2489 2508 2509 if ( self::SOURCE_SUBSCRIBED === ( $payload['recipient_source'] ?? '' ) || ! empty( $payload['automation'] ) ) { $email_payload['subscription_required'] = true; } 2510 if ( ! empty( $payload['automation'] ) ) { $email_payload['automation'] = $payload['automation']; } 2511 if ( ! empty( $payload['personalization_version'] ) ) { $email_payload['personalization_version'] = absint( $payload['personalization_version'] ); $email_payload['store_name'] = sanitize_text_field( $payload['store_name'] ?? get_bloginfo( 'name' ) ); } 2512 2490 2513 $payload_hash = hash( 'sha256', wp_json_encode( $email_payload ) ); 2491 2514 $payload_key = $this->get_campaign_payload_option_name( $campaign_id, $delivery_id ); … … 2565 2588 $this->campaign_payload_cache[ $payload_key ] = $record; 2566 2589 2567 foreach ( [ 'subject', 'heading', 'message', 'products_label', 'from_email', 'from_name', 'reply_to_email' ] as $field ) {2590 foreach ( [ 'subject', 'heading', 'message', 'products_label', 'from_email', 'from_name', 'reply_to_email', 'personalization_version', 'store_name', 'subscription_required', 'automation' ] as $field ) { 2568 2591 $args[ $field ] = isset( $record['payload'][ $field ] ) ? $record['payload'][ $field ] : ''; 2569 2592 } 2570 2593 2594 if ( ! empty( $args['personalization_version'] ) ) { 2595 $manifest = $this->read_durable_option( $this->campaign_manifest_key( $campaign_id ) ); 2596 $found = false; 2597 foreach ( (array) ( $manifest['recipients'] ?? [] ) as $recipient ) { 2598 if ( strtolower( $recipient['email'] ?? '' ) === strtolower( $args['to'] ?? '' ) && ! empty( $recipient['email'] ) ) { 2599 $args['order_context'] = $this->sanitize_order_context( $recipient['order_context'] ?? [] ); 2600 $found = true; break; 2601 } 2602 } 2603 if ( ! $found ) { return new WP_Error( 'missing_recipient_context', __( 'Confirmed recipient context is unavailable. No email was handed off.', 'yoohw-advanced-notifications' ) ); } 2604 } 2571 2605 return $args; 2572 2606 } … … 2777 2811 } 2778 2812 $options_valid = $this->validate_recipient_source_options( [ 2813 'order_ids' => $this->parse_selected_order_ids( wp_unslash( $_POST['order_ids'] ?? '' ) ), 2779 2814 'recipient_source' => $recipient_source, 'user_roles' => $user_roles, 2780 2815 'manual_emails' => $manual_emails, 'test_mode' => $test_mode, … … 2829 2864 2830 2865 private function generate_campaign_hash( $payload ) { 2831 $hash_payload = [ ' filters' => $payload['filters'] ?? [], 'schedule_policy' => $payload['schedule_policy'] ?? '', 'store_timezone' => $payload['store_timezone'] ?? '',2866 $hash_payload = [ 'order_ids' => $payload['order_ids'] ?? [], 'personalization_version' => $payload['personalization_version'] ?? 0, 'store_name' => $payload['store_name'] ?? '', 'filters' => $payload['filters'] ?? [], 'schedule_policy' => $payload['schedule_policy'] ?? '', 'store_timezone' => $payload['store_timezone'] ?? '', 2832 2867 'recipient_source' => isset( $payload['recipient_source'] ) ? (string) $payload['recipient_source'] : self::SOURCE_PRODUCT_CUSTOMERS, 2833 2868 'product_ids' => isset( $payload['product_ids'] ) ? array_map( 'absint', (array) $payload['product_ids'] ) : [], … … 3075 3110 ); 3076 3111 3077 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone', 'schedule_summary' ] as $field ) { if ( isset( $payload[ $field ] ) ) { $entry[ $field ] = $payload[ $field ]; } }3112 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone', 'schedule_summary', 'order_ids', 'personalization_version', 'store_name', 'automation' ] as $field ) { if ( isset( $payload[ $field ] ) ) { $entry[ $field ] = $payload[ $field ]; } } 3078 3113 $entry['status_counts'] = isset( $existing['status_counts'] ) && is_array( $existing['status_counts'] ) 3079 3114 ? $this->sanitize_count_map( $existing['status_counts'] ) … … 3327 3362 ]; 3328 3363 3329 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone' ] as $field ) { if ( isset( $campaign[ $field ] ) ) { $payload[ $field ] = $campaign[ $field ]; } }3364 foreach ( [ 'internal_name', 'filters', 'schedule_policy', 'store_timezone', 'order_ids', 'personalization_version', 'store_name', 'automation' ] as $field ) { if ( isset( $campaign[ $field ] ) ) { $payload[ $field ] = $campaign[ $field ]; } } 3330 3365 if ( empty( $payload['products_label'] ) ) { 3331 3366 $payload['products_label'] = ! empty( $payload['product_ids'] ) … … 3429 3464 private function sanitize_recipient_context( $recipient ) { 3430 3465 return [ 3466 'order_context' => $this->sanitize_order_context( $recipient['order_context'] ?? [] ), 3431 3467 'user_id' => isset( $recipient['user_id'] ) ? absint( $recipient['user_id'] ) : 0, 3432 3468 'email' => isset( $recipient['email'] ) ? sanitize_email( $recipient['email'] ) : '', … … 3899 3935 3900 3936 private function get_recipient_scheduled_delivery( $payload, $recipient, $roll_forward = true, $reference_time = null ) { 3937 if ( ! empty( $payload['automation']['due'] ) ) { return [ 'timestamp' => (int) $payload['automation']['due'], 'timezone' => 'UTC', 'fallback' => false, 'country' => '', 'state' => '', 'city' => '', 'rolled_forward_days' => 0 ]; } 3901 3938 if ( isset( $payload['schedule_policy'] ) ) { return $this->operator_schedule( $payload, $recipient ); } 3902 3939 $reference_time = null === $reference_time ? time() : absint( $reference_time ); … … 4251 4288 private function get_recipient_sources() { 4252 4289 $sources = [ 4290 self::SOURCE_SUBSCRIBED => __( 'Subscribed email addresses', 'yoohw-advanced-notifications' ), 4291 self::SOURCE_SELECTED_ORDERS => __( 'Selected orders', 'yoohw-advanced-notifications' ), 4253 4292 self::SOURCE_PRODUCT_CUSTOMERS => __( 'Product customers', 'yoohw-advanced-notifications' ), 4254 4293 self::SOURCE_WOOCOMMERCE_CUSTOMERS => __( 'WooCommerce customers', 'yoohw-advanced-notifications' ), … … 4283 4322 4284 4323 private function validate_recipient_source_options( $payload ) { 4324 $selected = $this->validate_selected_orders( $payload ); 4325 if ( is_wp_error( $selected ) ) { return $selected; } 4285 4326 $valid = $this->validate_audience_filters( $payload ); 4286 4327 if ( is_wp_error( $valid ) ) { return $valid; } … … 4351 4392 4352 4393 switch ( $recipient_source ) { 4394 case self::SOURCE_SUBSCRIBED: 4395 return $this->get_subscribed_recipients(); 4396 4397 case self::SOURCE_SELECTED_ORDERS: 4398 return $this->get_order_customer_recipients( null, $payload['filters'] ?? [], $payload['order_ids'] ?? [] ); 4399 4353 4400 case self::SOURCE_REGISTERED_USERS: 4354 4401 return $this->get_registered_user_recipients( [], isset( $payload['user_roles'] ) ? $payload['user_roles'] : [] ); … … 4502 4549 $record = $this->read_durable_option( 'yoohw_an_optout_' . hash( 'sha256', $email ) ); 4503 4550 if ( $this->read_durable_option( 'yoohw_an_erased_' . hash( 'sha256', $email ) ) ) { return true; } 4504 if ( is_array( $record ) && ( ! empty( $record['suppressed'] ) || $email === ( $record['email'] ?? '' ) ) ) { return true; }4551 if ( is_array( $record ) && ( ! empty( $record['suppressed'] ) || $email === ( $record['email'] ?? '' ) ) ) { return ! $this->confirmed_suppression_override( $email ); } 4505 4552 $legacy = $this->normalize_unsubscribed_emails( $this->read_durable_option( self::OPTION_UNSUBSCRIBED_EMAILS ) ); 4506 return isset( $legacy[ $email ] ) ;4553 return isset( $legacy[ $email ] ) && ! $this->confirmed_suppression_override( $email ); 4507 4554 } 4508 4555 … … 4515 4562 } 4516 4563 } 4517 return $this->normalize_unsubscribed_emails( $stored);4564 return array_filter( $this->normalize_unsubscribed_emails( $stored ), function ( $record, $email ) { return ! $this->confirmed_suppression_override( $email ); }, ARRAY_FILTER_USE_BOTH ); 4518 4565 } 4519 4566 … … 4559 4606 try { 4560 4607 $key = 'yoohw_an_optout_' . hash( 'sha256', $email ); 4561 $data = $this->read_durable_option( 'yoohw_an_erased_' . hash( 'sha256', $email ) ) ? [ 'suppressed' => true ] : [ 'email' => $email, 'unsubscribed_at' => time(), ' campaign_id' => sanitize_text_field( $campaign_id ) ];4608 $data = $this->read_durable_option( 'yoohw_an_erased_' . hash( 'sha256', $email ) ) ? [ 'suppressed' => true ] : [ 'email' => $email, 'unsubscribed_at' => time(), 'generation' => wp_generate_uuid4(), 'campaign_id' => sanitize_text_field( $campaign_id ) ]; 4562 4609 $data = $this->scrub_erased_references( $data ); 4563 $this->write_durable_option( $key, $data, true );4610 if ( false === $this->write_durable_option( $key, $data ) ) { return false; } 4564 4611 $saved = $this->read_durable_option( $key ); 4565 return is_array( $saved ) && ( ! empty( $saved['suppressed'] ) || $email === ( $saved['email'] ?? '' ) );4612 return $data === $saved; 4566 4613 } finally { $this->release_campaign_lock( '__privacy__' ); } 4567 4614 } … … 4886 4933 } 4887 4934 try { 4888 $message = str_replace( [ '{customer_name}', '{product_name}' ], [ $args['name'] ?? $to, $args['products_label'] ?? '' ], $args['message'] ); 4935 $automation_check = $this->automation_delivery_check( $args ); 4936 if ( is_wp_error( $automation_check ) ) { 4937 $outcome = 'automation_cancelled' === $automation_check->get_error_code() ? 'cancelled' : ( 'automation_ineligible' === $automation_check->get_error_code() ? 'skipped' : 'failed' ); 4938 $this->finish_delivery( $campaign_id, $delivery_id, $to, $claim, $outcome, $automation_check->get_error_message(), 'failed' === $outcome ? 'configuration' : '' ); return; 4939 } 4940 if ( ! empty( $args['subscription_required'] ) && 'subscribed' !== $this->subscription_record( $to )['status'] ) { 4941 $this->finish_delivery( $campaign_id, $delivery_id, $to, $claim, 'skipped_unsubscribed', __( 'No active subscription before send.', 'yoohw-advanced-notifications' ) ); 4942 return; 4943 } 4944 $personal = $this->render_personalized_email( $args, array_merge( $args, [ 'email' => $to ] ) ); 4945 $message = $personal['message']; 4889 4946 $message = $this->append_unsubscribe_footer( $message, $to, $campaign_id ); 4890 4947 // Read the durable opt-out immediately before entering the sending path. … … 4894 4951 } 4895 4952 $this->mail_handoff_started = false; 4896 $sent = $this->send_woocommerce_email( $to, $args['subject'], $args['heading'], $message, $args['from_email'] ?? '', $args['from_name'] ?? '', $args['reply_to_email'] ?? '' ); 4897 $status = $sent ? 'sent' : ( $this->mail_handoff_started ? 'unknown' : ( $this->is_email_unsubscribed( $to ) ? 'skipped_unsubscribed' : 'failed' ) ); 4953 $sent = $this->send_woocommerce_email( $to, $personal['subject'], $personal['heading'], $message, $args['from_email'] ?? '', $args['from_name'] ?? '', $args['reply_to_email'] ?? '', ! empty( $args['subscription_required'] ), $args['automation'] ?? [] ); 4954 $status = $sent ? 'sent' : ( $this->mail_handoff_started ? 'unknown' : ( ( $this->is_email_unsubscribed( $to ) || ( ! empty( $args['subscription_required'] ) && 'subscribed' !== $this->subscription_record( $to )['status'] ) ) ? 'skipped_unsubscribed' : 'failed' ) ); 4955 if ( ! $sent && ! $this->mail_handoff_started && $this->last_automation_outcome ) { $status = $this->last_automation_outcome; } 4898 4956 $this->finish_delivery( $campaign_id, $delivery_id, $to, $claim, $status, 4899 4957 $sent ? __( 'Mail system accepted the request; inbox delivery is not verified.', 'yoohw-advanced-notifications' ) : ( $this->last_mail_error ?: __( 'Mail transport returned no confirmation. Check the mail provider before sending again.', 'yoohw-advanced-notifications' ) ), … … 4967 5025 } 4968 5026 4969 private function get_order_customer_recipients( $product_ids = null, $filters = [] ) { 5027 private function get_order_customer_recipients( $product_ids = null, $filters = [], $order_ids = null ) { 5028 if ( null !== $order_ids && ! $order_ids ) { return []; } 4970 5029 $all_products = null === $product_ids; 4971 5030 $product_ids = $all_products ? [] : $product_ids; … … 5024 5083 $orders = wc_get_orders( 5025 5084 [ 5085 'post__in' => null === $order_ids ? [] : $order_ids, 5026 5086 'limit' => self::ORDER_QUERY_LIMIT, 5027 5087 'paged' => $page, 5028 'status' => ! empty( $filters['order_statuses'] ) ? $filters['order_statuses'] : [ 'processing', 'completed' ],5088 'status' => ! empty( $filters['order_statuses'] ) ? $filters['order_statuses'] : ( null === $order_ids ? [ 'processing', 'completed' ] : array_keys( wc_get_order_statuses() ) ), 5029 5089 'return' => 'objects', 5030 5090 'orderby' => 'ID', … … 5042 5102 } 5043 5103 5104 if ( null !== $order_ids && ! in_array( (int) $order->get_id(), $order_ids, true ) ) { continue; } 5044 5105 if ( ! $this->order_matches_filters( $order, $filters ) ) { continue; } 5045 5106 $has_product = $all_products; … … 5076 5137 $email = strtolower( sanitize_email( $order->get_billing_email() ) ); 5077 5138 5078 if ( ! is_email( $email ) || isset( $customers[ $email ] ) ) { 5079 continue; 5080 } 5139 if ( ! is_email( $email ) ) { continue; } 5140 if ( isset( $customers[ $email ] ) ) { $customers[ $email ]['order_context']['count']++; continue; } 5081 5141 5082 5142 $name = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ); … … 5086 5146 'email' => $email, 5087 5147 'name' => $name ?: $email, 5148 'order_context' => $this->context_from_order( $order ), 5088 5149 'country' => $this->normalize_country_code( $order->get_billing_country() ), 5089 5150 'state' => $this->normalize_location_part( $order->get_billing_state() ), … … 5235 5296 } 5236 5297 5237 private function send_woocommerce_email( $to, $subject, $heading, $message, $from_email = '', $from_name = '', $reply_to_email = '' ) { 5298 private function send_woocommerce_email( $to, $subject, $heading, $message, $from_email = '', $from_name = '', $reply_to_email = '', $require_subscription = false, $automation = [], $sample_email_hash = '' ) { 5299 $this->last_automation_outcome = ''; 5238 5300 $email_body = $this->build_woocommerce_email_body( $heading, $message ); 5239 5301 5240 5302 if ( false === $email_body ) { 5241 5303 $this->last_mail_error = __( 'WooCommerce mailer is unavailable.', 'yoohw-advanced-notifications' ); 5304 return false; 5305 } 5306 5307 if ( $sample_email_hash && $this->read_durable_option( 'yoohw_an_erased_' . $sample_email_hash ) ) { 5308 $this->last_mail_error = __( 'The sample was erased before test mail handoff.', 'yoohw-advanced-notifications' ); return false; 5309 } 5310 5311 $check = $this->automation_delivery_check( [ 'automation' => $automation, 'to' => $to ] ); 5312 if ( is_wp_error( $check ) ) { 5313 $this->last_automation_outcome = 'automation_cancelled' === $check->get_error_code() ? 'cancelled' : ( 'automation_ineligible' === $check->get_error_code() ? 'skipped' : 'failed' ); 5314 $this->last_mail_error = $check->get_error_message(); return false; 5315 } 5316 5317 if ( $require_subscription && 'subscribed' !== $this->subscription_record( $to )['status'] ) { 5318 $this->last_mail_error = __( 'No active subscription before mail handoff.', 'yoohw-advanced-notifications' ); 5242 5319 return false; 5243 5320 } -
yoohw-advanced-notifications/trunk/includes/trait-campaign-audiences.php
r3771948 r3789014 7 7 $raw = wp_unslash( $_POST['audience_filters'] ?? [] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each scalar/list is type checked, sanitized below and strictly validated by validate_audience_filters(). 8 8 $filters = []; 9 $scalar_keys = [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode' ];9 $scalar_keys = [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'purchase_frequency', 'inactive_days' ]; 10 10 $list_keys = [ 'category_ids', 'order_statuses' ]; 11 11 if ( ! is_array( $raw ) || array_diff( array_keys( $raw ), array_merge( $scalar_keys, $list_keys ) ) ) { return [ 'invalid_input' => true ]; } 12 12 foreach ( $scalar_keys as $key ) { if ( isset( $raw[ $key ] ) && ! is_string( $raw[ $key ] ) ) { return [ 'invalid_input' => true ]; } } 13 13 foreach ( $list_keys as $key ) { if ( isset( $raw[ $key ] ) && ( ! is_array( $raw[ $key ] ) || array_filter( $raw[ $key ], static function ( $value ) { return ! is_string( $value ); } ) ) ) { return [ 'invalid_input' => true ]; } } 14 foreach ( [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode' ] as $key ) { $filters[ $key ] = sanitize_text_field( $raw[ $key ] ?? '' ); }14 foreach ( [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'purchase_frequency', 'inactive_days' ] as $key ) { $filters[ $key ] = sanitize_text_field( $raw[ $key ] ?? '' ); } 15 15 foreach ( [ 'category_ids', 'order_statuses' ] as $key ) { $filters[ $key ] = array_map( 'sanitize_text_field', (array) ( $raw[ $key ] ?? [] ) ); } 16 16 return $filters; … … 19 19 private function validate_audience_filters( $p ) { 20 20 $f = $p['filters'] ?? []; 21 $invalid = new WP_Error( 'invalid_filters', __( 'Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country and campaign history; no condition has been ignored.', 'yoohw-advanced-notifications' ) );22 if ( ! is_array( $f ) || array_diff( array_keys( $f ), [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'category_ids', 'order_statuses' ] ) ) { return $invalid; }21 $invalid = new WP_Error( 'invalid_filters', __( 'Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country, purchase history and campaign history; no condition has been ignored.', 'yoohw-advanced-notifications' ) ); 22 if ( ! is_array( $f ) || array_diff( array_keys( $f ), [ 'date_from', 'date_to', 'last_days', 'country', 'subscription', 'history_campaign', 'history_mode', 'category_ids', 'order_statuses', 'purchase_frequency', 'inactive_days' ] ) ) { return $invalid; } 23 23 foreach ( [ 'category_ids', 'order_statuses' ] as $key ) { if ( isset( $f[ $key ] ) && ! is_array( $f[ $key ] ) ) { return $invalid; } } 24 if ( ! in_array( $f['purchase_frequency'] ?? '', [ '', 'first', 'repeat' ], true ) ) { return $invalid; } 25 if ( isset( $f['inactive_days'] ) && '' !== $f['inactive_days'] && ( ( ! is_string( $f['inactive_days'] ) && ! is_int( $f['inactive_days'] ) ) || ! ctype_digit( (string) $f['inactive_days'] ) || (int) $f['inactive_days'] < 1 || (int) $f['inactive_days'] > 36500 ) ) { return $invalid; } 24 26 $source = $p['recipient_source'] ?? ''; 25 $order_source = in_array( $source, [ self::SOURCE_PRODUCT_CUSTOMERS, self::SOURCE_WOOCOMMERCE_CUSTOMERS ], true ); 27 if ( self::SOURCE_SUBSCRIBED === $source && ( ! empty( $p['product_ids'] ) || ! empty( $p['user_roles'] ) || ! empty( $p['manual_emails'] ) ) ) { return $invalid; } 28 $order_source = in_array( $source, [ self::SOURCE_PRODUCT_CUSTOMERS, self::SOURCE_WOOCOMMERCE_CUSTOMERS, self::SOURCE_SELECTED_ORDERS ], true ); 26 29 foreach ( [ 'date_from', 'date_to', 'last_days', 'category_ids', 'order_statuses' ] as $field ) { if ( ! $order_source && ! empty( $f[ $field ] ) ) { return $invalid; } } 27 if ( self::SOURCE_MANUAL_EMAILS === $source&& ! empty( $f['country'] ) ) { return $invalid; }30 if ( in_array( $source, [ self::SOURCE_MANUAL_EMAILS, self::SOURCE_SUBSCRIBED ], true ) && ! empty( $f['country'] ) ) { return $invalid; } 28 31 foreach ( [ 'date_from', 'date_to' ] as $field ) { 29 32 if ( isset( $f[ $field ] ) && '' !== $f[ $field ] ) { … … 66 69 } 67 70 private function subscription_record( $email ) { 68 if ( $this->is_email_unsubscribed( $email ) ) { return [ 'status' => 'unsubscribed', 'source' => 'suppression' ]; } 69 return $this->read_durable_option( 'yoohw_an_subscription_' . hash( 'sha256', strtolower( $email ) ) ) ?: [ 'status' => 'unknown', 'source' => '', 'recorded_at' => 0 ]; 71 $email = strtolower( $email ); 72 $record = $this->is_email_unsubscribed( $email ) ? [ 'status' => 'unsubscribed', 'source' => 'suppression' ] : ( $this->read_durable_option( 'yoohw_an_subscription_' . hash( 'sha256', $email ) ) ?: [ 'status' => 'unknown', 'source' => '', 'recorded_at' => 0 ] ); 73 $pending = $this->read_durable_option( 'yoohw_an_signup_' . hash( 'sha256', $email ) ); 74 if ( is_array( $pending ) && ( $pending['email'] ?? '' ) === $email && ! empty( $pending['token_hash'] ) && ( $pending['expires'] ?? 0 ) > time() ) { $record['confirmation_pending'] = true; $record['request_source'] = $pending['source']; $record['requested_at'] = $pending['requested_at']; } 75 return $record; 70 76 } 71 77 private function apply_audience_filters( $recipients, $p ) { 72 78 if ( is_wp_error( $this->validate_audience_filters( $p ) ) ) { return []; } 73 79 $f = $p['filters'] ?? []; 80 $recipients = $this->apply_purchase_history_filters( $recipients, $f ); 74 81 $result = []; 75 82 $history = []; … … 129 136 } 130 137 private function render_audience_fields( $p ) { 138 $this->render_selected_orders_field( $p ); 131 139 $f = $p['filters'] ?? []; 132 140 $invalid = is_wp_error( $this->validate_audience_filters( $p ) ); 141 $this->render_purchase_history_fields( $f, $invalid ); 133 142 if ( $invalid ) { echo '<p role="alert">' . esc_html__( 'Saved conditions are invalid or unavailable. They remain selected; correct or explicitly remove them before previewing.', 'yoohw-advanced-notifications' ) . '</p>'; } 134 143 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Audience conditions', 'yoohw-advanced-notifications' ) . '</h2><div class="an-order-filters"><div class="an-form-grid an-form-grid-three">'; 135 144 foreach ( [ 'date_from' => [ 'date', __( 'Order created from (store timezone)', 'yoohw-advanced-notifications' ) ], 'date_to' => [ 'date', __( 'Through date (inclusive)', 'yoohw-advanced-notifications' ) ], 'last_days' => [ 'number', __( 'Or last N × 24 hours', 'yoohw-advanced-notifications' ) ] ] as $key => $field ) { echo '<div class="an-field"><label>' . esc_html( $field[1] ) . ' <input type="' . esc_attr( $invalid ? 'text' : $field[0] ) . '" name="audience_filters[' . esc_attr( $key ) . ']" value="' . esc_attr( $f[ $key ] ?? '' ) . '"></label></div>'; } 136 echo '</div><div class="an-form-grid"><div class="an-field"><label>' . esc_html__( 'Matching order statuses ( defaultprocessing/completed)', 'yoohw-advanced-notifications' ) . '<select multiple name="audience_filters[order_statuses][]">';145 echo '</div><div class="an-form-grid"><div class="an-field"><label>' . esc_html__( 'Matching order statuses (selected orders: all; other sources: processing/completed)', 'yoohw-advanced-notifications' ) . '<select multiple name="audience_filters[order_statuses][]">'; 137 146 foreach ( $this->get_order_status_options() as $key => $label ) { echo '<option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $f['order_statuses'] ?? [], true ), true, false ) . '>' . esc_html( $label ) . '</option>'; } 138 147 $this->render_unavailable_options( $f['order_statuses'] ?? [], array_keys( $this->get_order_status_options() ) ); … … 156 165 $f = array_filter( $p['filters'] ?? [], static function ( $value ) { return '' !== $value && [] !== $value; } ); 157 166 if ( ! $f ) { return; } 158 $labels = [ ' date_from' => __( 'Order created from', 'yoohw-advanced-notifications' ), 'date_to' => __( 'Through date', 'yoohw-advanced-notifications' ), 'last_days' => __( 'Last N days', 'yoohw-advanced-notifications' ), 'country' => __( 'Billing country', 'yoohw-advanced-notifications' ), 'subscription' => __( 'Subscription status', 'yoohw-advanced-notifications' ), 'history_campaign' => __( 'History campaign', 'yoohw-advanced-notifications' ), 'history_mode' => __( 'Handoff condition', 'yoohw-advanced-notifications' ), 'category_ids' => __( 'Categories including descendants', 'yoohw-advanced-notifications' ), 'order_statuses' => __( 'Matching order statuses', 'yoohw-advanced-notifications' ) ];167 $labels = [ 'purchase_frequency' => __( 'Store-wide purchase frequency', 'yoohw-advanced-notifications' ), 'inactive_days' => __( 'Days without a valid store-wide purchase', 'yoohw-advanced-notifications' ), 'date_from' => __( 'Order created from', 'yoohw-advanced-notifications' ), 'date_to' => __( 'Through date', 'yoohw-advanced-notifications' ), 'last_days' => __( 'Last N days', 'yoohw-advanced-notifications' ), 'country' => __( 'Billing country', 'yoohw-advanced-notifications' ), 'subscription' => __( 'Subscription status', 'yoohw-advanced-notifications' ), 'history_campaign' => __( 'History campaign', 'yoohw-advanced-notifications' ), 'history_mode' => __( 'Handoff condition', 'yoohw-advanced-notifications' ), 'category_ids' => __( 'Categories including descendants', 'yoohw-advanced-notifications' ), 'order_statuses' => __( 'Matching order statuses', 'yoohw-advanced-notifications' ) ]; 159 168 echo '<h3>' . esc_html__( 'Saved audience conditions', 'yoohw-advanced-notifications' ) . '</h3><table class="widefat striped">'; 160 169 foreach ( $f as $key => $value ) { 161 170 $values = (array) $value; 171 if ( 'purchase_frequency' === $key ) { $options = [ 'first' => __( 'First-time buyer (one valid order)', 'yoohw-advanced-notifications' ), 'repeat' => __( 'Repeat buyer (at least two valid orders)', 'yoohw-advanced-notifications' ) ]; $values = [ $options[ $value ] ?? $value ]; } 162 172 if ( 'order_statuses' === $key ) { $options = $this->get_order_status_options(); $values = array_map( static function ( $status ) use ( $options ) { return $options[ $status ] ?? $status; }, $values ); } 163 173 if ( 'category_ids' === $key ) { $values = array_map( static function ( $id ) { $term = get_term( (int) $id, 'product_cat' ); return $term && ! is_wp_error( $term ) ? $term->name . ' (#' . $id . ')' : '#' . $id; }, $values ); } … … 177 187 $reason = __( 'Not in the selected source or product purchasers.', 'yoohw-advanced-notifications' ); 178 188 if ( in_array( $email, array_column( $baseline, 'email' ), true ) ) { $reason = __( 'No single order matches all order conditions, or billing country is missing/different.', 'yoohw-advanced-notifications' ); } 179 if ( in_array( $email, array_column( $filtered, 'email' ), true ) ) { $reason = __( 'S ubscription status or known campaign handoff condition does not match.', 'yoohw-advanced-notifications' ); }189 if ( in_array( $email, array_column( $filtered, 'email' ), true ) ) { $reason = __( 'Store-wide purchase history, subscription status or known campaign handoff condition does not match.', 'yoohw-advanced-notifications' ); } 180 190 if ( in_array( $email, array_column( $filtered_common, 'email' ), true ) ) { $reason = __( 'Matched source and all conditions; removed by an explicit exclusion.', 'yoohw-advanced-notifications' ); } 181 191 if ( in_array( $email, array_column( $this->get_recipients_by_payload( $p ), 'email' ), true ) ) { $reason = __( 'Included: matches source and every applicable condition; no exclusion matched.', 'yoohw-advanced-notifications' ); } -
yoohw-advanced-notifications/trunk/includes/trait-campaign-authoring.php
r3771948 r3789014 12 12 } 13 13 private function draft_fields() { 14 return [ ' internal_name', 'subject', 'heading', 'message', 'recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'schedule_mode', 'scheduled_at_input', 'filters', 'test_email' ];15 } 16 private function criteria_fields() { return [ ' recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'filters' ]; }14 return [ 'order_ids', 'personalization_version', 'internal_name', 'subject', 'heading', 'message', 'recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'schedule_mode', 'scheduled_at_input', 'filters', 'test_email' ]; 15 } 16 private function criteria_fields() { return [ 'order_ids', 'recipient_source', 'product_ids', 'user_roles', 'manual_emails', 'manual_emails_raw', 'exclusions', 'exclude_emails_raw', 'filters' ]; } 17 17 private function save_draft( $payload, $id = '' ) { 18 18 $id = $id ?: ( $payload['draft_id'] ?? wp_generate_uuid4() ); … … 37 37 $p['exclude_emails_raw'] = sanitize_textarea_field( $post['exclude_emails'] ?? '' ); 38 38 $p['exclusions'] = [ 'product_ids' => array_map( 'absint', (array) ( $post['exclude_product_ids'] ?? [] ) ), 'order_statuses' => array_map( 'sanitize_key', (array) ( $post['exclude_order_statuses'] ?? [] ) ), 'emails' => $this->parse_email_list( $p['exclude_emails_raw'] ) ]; 39 $p['order_ids'] = $this->parse_selected_order_ids( $post['order_ids'] ?? '' ); 40 if ( is_wp_error( $p['order_ids'] ) ) { wp_die( esc_html( $p['order_ids']->get_error_message() ) ); } 41 $p['personalization_version'] = 1; 42 $p['store_name'] = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 39 43 $p['filters'] = $this->filters_from_request(); 40 44 return $p; … … 61 65 $p['internal_name'] = sanitize_text_field( wp_unslash( $_POST['internal_name'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Caller verifies nonce. 62 66 $p['filters'] = $this->filters_from_request(); 67 $p['order_ids'] = $this->parse_selected_order_ids( wp_unslash( $_POST['order_ids'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Caller verifies nonce. 68 if ( is_wp_error( $p['order_ids'] ) ) { return $p['order_ids']; } 69 $p['personalization_version'] = 1; 70 $p['store_name'] = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); 71 $valid = $this->validate_selected_orders( $p ); 72 if ( is_wp_error( $valid ) ) { return $valid; } 63 73 $p['schedule_policy'] = 'strict_v1'; 64 74 $p['store_timezone'] = wp_timezone_string(); … … 120 130 if ( ! $drafts ) { echo '<p>' . esc_html__( 'No saved drafts yet.', 'yoohw-advanced-notifications' ) . '</p>'; } 121 131 foreach ( $drafts as $draft ) { 122 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'draft_id' => $draft['draft_id'] ] ) ) . '">' . esc_html( $draft['internal_name'] ?: ( $draft['subject']?: $draft['draft_id'] ) ) . '</a>';132 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'draft_id' => $draft['draft_id'] ] ) ) . '">' . esc_html( ( $draft['internal_name'] ?? '' ) ?: ( ( $draft['subject'] ?? '' ) ?: $draft['draft_id'] ) ) . '</a>'; 123 133 $this->library_button( $draft['draft_id'], 'delete_draft', __( 'Delete draft', 'yoohw-advanced-notifications' ) ); 124 134 echo '</div>'; … … 128 138 if ( ! $audiences ) { echo '<p>' . esc_html__( 'No saved audiences yet.', 'yoohw-advanced-notifications' ) . '</p>'; } 129 139 foreach ( $audiences as $audience ) { 130 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ) . '</a>';140 echo '<div class="an-library-item"><a href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ?? $audience['id'] ) . '</a>'; 131 141 $this->library_button( $audience['id'], 'delete_audience', __( 'Delete audience', 'yoohw-advanced-notifications' ) ); 132 142 echo '</div>'; … … 140 150 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Saved audience criteria', 'yoohw-advanced-notifications' ) . '</h2><p>'; 141 151 foreach ( $this->read_durable_options( 'yoohw_an_audience_' ) as $audience ) { 142 echo '<a class="button" href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ) . '</a> ';152 echo '<a class="button" href="' . esc_url( $this->get_admin_page_url( [ 'audience_id' => $audience['id'] ] ) ) . '">' . esc_html( $audience['name'] ?? $audience['id'] ) . '</a> '; 143 153 } 144 154 echo '<a href="' . esc_url( $this->get_admin_page_url( [ 'tab' => 'library' ] ) ) . '">' . esc_html__( 'Open Library', 'yoohw-advanced-notifications' ) . '</a></p><p class="description">' . esc_html__( 'Opening saved criteria replaces this form. Save your draft first to keep current edits.', 'yoohw-advanced-notifications' ) . '</p><input type="hidden" name="audience_id" value="' . esc_attr( $p['audience_id'] ?? '' ) . '"><div class="an-form-row"><label class="an-field">' . esc_html__( 'Audience name', 'yoohw-advanced-notifications' ) . ' <input name="audience_name" value="' . esc_attr( $p['audience_name'] ?? '' ) . '"></label> <button class="button" formnovalidate name="authoring_operation" value="save_audience">' . esc_html__( 'Save audience criteria', 'yoohw-advanced-notifications' ) . '</button></div></section>'; … … 147 157 echo '<section class="yoohw-advanced-notifications-panel an-template-field"><label for="an-template">' . esc_html__( 'Insert editable content template', 'yoohw-advanced-notifications' ) . '</label><p><select id="an-template"><option value="">—</option>'; 148 158 $templates = [ 149 'update' => [ __( 'Product or documentation update', 'yoohw-advanced-notifications' ), __( 'An update for you', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>We have updated {product_name}. Add the details and documentation link here.</p>', 'yoohw-advanced-notifications' ) ],150 'guide' => [ __( 'After-purchase guide', 'yoohw-advanced-notifications' ), __( 'Getting started', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>Thank you for your purchase . Add setup steps and support detailshere.</p>', 'yoohw-advanced-notifications' ) ],151 'service' => [ __( 'Service or order change', 'yoohw-advanced-notifications' ), __( 'Service update', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>A dd the change, effective date and any action neededhere.</p>', 'yoohw-advanced-notifications' ) ],159 'update' => [ __( 'Product or documentation update', 'yoohw-advanced-notifications' ), __( 'An update for you', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>We have updated {product_name}. Describe what changed, when it applies, and add the documentation link and any action needed. Contact our support team if you need help.</p>', 'yoohw-advanced-notifications' ) ], 160 'guide' => [ __( 'After-purchase guide', 'yoohw-advanced-notifications' ), __( 'Getting started', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>Thank you for your purchase of {ordered_products} (order {order_number}). Add setup or care steps, when to follow them, and a support contact here.</p>', 'yoohw-advanced-notifications' ) ], 161 'service' => [ __( 'Service or order change', 'yoohw-advanced-notifications' ), __( 'Service update', 'yoohw-advanced-notifications' ), __( '<p>Hello {customer_name},</p><p>An update about order {order_number}: describe the change and the new delivery date or effective time. Explain any action needed and add a support contact here.</p>', 'yoohw-advanced-notifications' ) ], 152 162 ]; 153 163 foreach ( $templates as $key => $template ) { echo '<option value="' . esc_attr( $key ) . '" data-subject="' . esc_attr( $template[1] ) . '" data-body="' . esc_attr( $template[2] ) . '">' . esc_html( $template[0] ) . '</option>'; } … … 217 227 if ( ! empty( $_GET['audience_changed'] ) ) { echo '<p class="notice notice-warning" role="alert">' . esc_html__( 'Audience changed since preview. Review this updated preview and confirm again.', 'yoohw-advanced-notifications' ) . '</p>'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended 218 228 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Recipients and schedule to confirm', 'yoohw-advanced-notifications' ) . '</h2><dl class="an-preview-counts"><div><dt>' . esc_html__( 'Selected', 'yoohw-advanced-notifications' ) . '</dt><dd>' . esc_html( number_format_i18n( $p['recipient_count'] ?? 0 ) ) . '</dd></div><div><dt>' . esc_html__( 'Excluded', 'yoohw-advanced-notifications' ) . '</dt><dd>' . esc_html( number_format_i18n( $p['excluded_count'] ?? 0 ) ) . '</dd></div></dl>'; 219 $reason_labels = [ 'order_conditions' => __( 'Removed by order conditions', 'yoohw-advanced-notifications' ), 'subscription_or_history' => __( 'Removed by subscription or campaign history', 'yoohw-advanced-notifications' ), 'explicit_exclusions_or_suppression' => __( 'Removed by exclusions or suppression', 'yoohw-advanced-notifications' ) ];229 $reason_labels = [ 'order_conditions' => __( 'Removed by order conditions', 'yoohw-advanced-notifications' ), 'subscription_or_history' => __( 'Removed by purchase history, subscription or campaign history', 'yoohw-advanced-notifications' ), 'explicit_exclusions_or_suppression' => __( 'Removed by exclusions or suppression', 'yoohw-advanced-notifications' ) ]; 220 230 echo '<dl class="an-review-facts">'; 221 231 foreach ( $p['audience_audit'] ?? [] as $reason => $count ) { echo '<div><dt>' . esc_html( $reason_labels[ $reason ] ?? $reason ) . '</dt><dd>' . esc_html( number_format_i18n( $count ) ) . '</dd></div>'; } … … 239 249 echo '</select></div><button class="button">' . esc_html__( 'Show sample', 'yoohw-advanced-notifications' ) . '</button></form>'; 240 250 $this->render_preview_device_controls(); 241 $message = str_replace( [ '{customer_name}', '{product_name}' ], [ $sample['name'] ?: $sample['email'], $p['products_label'] ?? '' ], $p['message'] ); 251 $personal = $this->render_personalized_email( $p, $sample ); 252 echo '<p>' . esc_html( $personal['subject'] ) . '</p>'; 253 $this->render_order_context_summary( $sample ); 254 $message = $personal['message']; 242 255 $message = $this->append_unsubscribe_footer( $message, $sample['email'], $p['campaign_id'] ); 243 $html = $this->build_woocommerce_email_body( $p ['heading'], $message );256 $html = $this->build_woocommerce_email_body( $personal['heading'], $message ); 244 257 echo '<iframe class="an-personal-preview" sandbox="" title="' . esc_attr__( 'Personalized email preview', 'yoohw-advanced-notifications' ) . '" srcdoc="' . esc_attr( $html ) . '"></iframe></section>'; 245 258 } -
yoohw-advanced-notifications/trunk/includes/trait-campaign-privacy.php
r3771948 r3789014 121 121 echo '<div class="wrap yoohw-an-workspace"><h1>' . esc_html__( 'Email campaigns', 'yoohw-advanced-notifications' ) . '</h1>'; 122 122 $this->render_page_tabs( 'subscribers' ); 123 $this->render_contact_history(); 123 124 echo '<section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Subscribers and suppression', 'yoohw-advanced-notifications' ) . '</h2><p>' . esc_html__( 'An order, account or pasted email is not opt-in evidence. Unknown remains unknown. Imports never remove an unsubscribe. For subscribed records, enter the actual evidence source; the recorded time is the import time, not an inferred original consent time.', 'yoohw-advanced-notifications' ) . '</p>'; 124 125 $search = strtolower( sanitize_text_field( wp_unslash( $_GET['subscription_search'] ?? '' ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended … … 130 131 foreach ( $this->read_durable_options( 'yoohw_an_subscription_' ) as $record ) { if ( ! empty( $record['email'] ) ) { $records[ $record['email'] ] = $record; } } 131 132 foreach ( $this->get_unsubscribed_emails() as $email => $record ) { $records[ $email ] = array_merge( (array) $record, $records[ $email ] ?? [], [ 'status' => 'unsubscribed' ] ); } 132 if ( is_email( $search ) && ! isset( $records[ $search ] )) { $records[ $search ] = $this->subscription_record( $search ); }133 if ( is_email( $search ) ) { $records[ $search ] = $this->subscription_record( $search ); } 133 134 $count = 0; 134 135 foreach ( $records as $email => $record ) { … … 138 139 $timestamp = $record['recorded_at'] ?? ( $record['unsubscribed_at'] ?? 0 ); 139 140 echo '<tr><td>' . esc_html( $email . ' / ' . $record['status'] ) . '</td><td>' . esc_html( ( $record['source'] ?? 'legacy/unsubscribe' ) . ' / ' . ( $timestamp ? gmdate( 'Y-m-d H:i:s', is_numeric( $timestamp ) ? (int) $timestamp : strtotime( $timestamp ) ) : '—' ) ) . '</td></tr>'; 141 if ( ! empty( $record['confirmation_pending'] ) ) { echo '<tr><td colspan="2">' . esc_html__( 'Confirmation pending; current subscription unchanged.', 'yoohw-advanced-notifications' ) . ' ' . esc_html( $record['request_source'] . ' / ' . gmdate( 'Y-m-d H:i:s', $record['requested_at'] ) ) . '</td></tr>'; } 140 142 } echo '</table><p>' . esc_html__( 'Up to 200 matches. Erased addresses are represented only by protective hashes and are not listed as plaintext.', 'yoohw-advanced-notifications' ) . '</p>'; 141 143 echo '</section><section class="yoohw-advanced-notifications-panel"><h2>' . esc_html__( 'Import records', 'yoohw-advanced-notifications' ) . '</h2><p>' . esc_html__( '1. Paste → 2. Preview → 3. Apply and review result', 'yoohw-advanced-notifications' ) . '</p><form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '"><input type="hidden" name="action" value="yoohw_an_data"><input type="hidden" name="operation" value="preview_import">'; wp_nonce_field( 'yoohw_an_data' ); … … 179 181 $fields = []; 180 182 foreach ( $row as $name => $value ) { $fields[] = [ 'name' => $name, 'value' => $value ]; } 183 $manifest = $this->read_durable_option( $this->campaign_manifest_key( $row['campaign_id'] ) ); 184 foreach ( (array) ( $manifest['recipients'] ?? [] ) as $recipient ) { 185 if ( strtolower( $recipient['email'] ?? '' ) === $email && ! empty( $recipient['order_context'] ) ) { $fields[] = [ 'name' => __( 'Saved order context', 'yoohw-advanced-notifications' ), 'value' => wp_json_encode( $this->sanitize_order_context( $recipient['order_context'] ) ) ]; } 186 } 181 187 $data[] = [ 'group_id' => 'yoohw-an', 'group_label' => __( 'Email campaigns', 'yoohw-advanced-notifications' ), 'item_id' => 'yoohw-an-' . $row['campaign_id'] . '-' . $page . '-' . $index, 'data' => $fields ]; 182 188 } 183 189 if ( 1 === (int) $page ) { 184 190 $record = $this->subscription_record( $email ); 191 $pending = $this->read_durable_option( 'yoohw_an_signup_' . $hash ); 192 if ( is_array( $pending ) && ( $pending['email'] ?? '' ) === $email ) { $record['pending_request'] = array_intersect_key( $pending, array_flip( [ 'source', 'requested_at', 'expires', 'consumed_at' ] ) ); } 185 193 $record['suppression_evidence'] = $this->read_durable_option( 'yoohw_an_optout_' . $hash ) ?: ( $this->get_unsubscribed_emails()[ $email ] ?? [] ); 186 194 $record['protective_erasure_hash'] = (bool) $this->read_durable_option( 'yoohw_an_erased_' . $hash ); … … 203 211 if ( is_array( $value ) ) { 204 212 if ( strtolower( $value['email'] ?? $value['to'] ?? '' ) === $email ) { 205 foreach ( [ 'email', 'to', 'name', 'recipient_name', 'country', 'state', 'city', 'timezone', 'user_id' ] as $field ) { if ( isset( $value[ $field ] ) ) { $value[ $field ] = ''; } }213 foreach ( [ 'email', 'to', 'name', 'recipient_name', 'country', 'state', 'city', 'timezone', 'user_id', 'order_context' ] as $field ) { if ( isset( $value[ $field ] ) ) { $value[ $field ] = ''; } } 206 214 } 207 215 $result = []; -
yoohw-advanced-notifications/trunk/languages/yoohw-advanced-notifications.pot
r3771948 r3789014 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Advanced Notifications for WooCommerce 0. 3.0\n"5 "Project-Id-Version: Advanced Notifications for WooCommerce 0.4.0\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/yoohw-advanced-notifications\n" 7 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" … … 10 10 "Content-Type: text/plain; charset=UTF-8\n" 11 11 "Content-Transfer-Encoding: 8bit\n" 12 "POT-Creation-Date: 2026-1 0-29T02:04:10+00:00\n"12 "POT-Creation-Date: 2026-11-07T03:47:04+00:00\n" 13 13 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 14 "X-Generator: WP-CLI 2.9.0\n" … … 35 35 msgstr "" 36 36 37 #: includes/class-customer-email-notify.php:1 6137 #: includes/class-customer-email-notify.php:184 38 38 msgid "Plugin deactivated before delivery." 39 39 msgstr "" 40 40 41 #: includes/class-customer-email-notify.php:3 6541 #: includes/class-customer-email-notify.php:389 42 42 msgid "Privacy cleanup is busy. Campaign preparation will resume." 43 43 msgstr "" 44 44 45 #: includes/class-customer-email-notify.php:3 7245 #: includes/class-customer-email-notify.php:396 46 46 msgid "Campaign recipients could not be prepared for background dispatch." 47 47 msgstr "" 48 48 49 #: includes/class-customer-email-notify.php: 37849 #: includes/class-customer-email-notify.php:402 50 50 msgid "Recipient tracking storage is unavailable." 51 51 msgstr "" 52 52 53 #: includes/class-customer-email-notify.php:4 1353 #: includes/class-customer-email-notify.php:437 54 54 msgid "Invalid scheduled date/time. Create a new campaign with a valid time." 55 55 msgstr "" 56 56 57 #: includes/class-customer-email-notify.php:4 7557 #: includes/class-customer-email-notify.php:499 58 58 msgid "Recipient dispatch storage failed." 59 59 msgstr "" 60 60 61 #: includes/class-customer-email-notify.php:7 1261 #: includes/class-customer-email-notify.php:736 62 62 msgid "Recipient preparation reached the limit of 3 queue attempts. Check Scheduled Actions for jobs saved before the interruption. Existing jobs may finish; recovery will not create further jobs for these recipients." 63 63 msgstr "" 64 64 65 #: includes/class-customer-email-notify.php:7 1865 #: includes/class-customer-email-notify.php:742 66 66 msgid "Dispatcher could not be queued. Check Action Scheduler, then use Recover / retry eligible recipients." 67 67 msgstr "" 68 68 69 #: includes/class-customer-email-notify.php:7 2769 #: includes/class-customer-email-notify.php:751 70 70 msgid "Recipient snapshot is incomplete. Recovery uses only saved recipients; it cannot recreate a lost historical audience. Review the stored records before creating a new campaign." 71 71 msgstr "" 72 72 73 #: includes/class-customer-email-notify.php:7 3173 #: includes/class-customer-email-notify.php:755 74 74 msgid "Delivery jobs are overdue. Check WordPress cron and WooCommerce Scheduled Actions. Existing pending jobs are retained; recovery will not create another send while they remain pending." 75 75 msgstr "" 76 76 77 #: includes/class-customer-email-notify.php:7 3577 #: includes/class-customer-email-notify.php:759 78 78 msgid "Some outcomes are unknown. Check the mail provider logs before creating another campaign for those addresses. Recovery never resends unknown outcomes." 79 79 msgstr "" 80 80 81 #: includes/class-customer-email-notify.php:7 3781 #: includes/class-customer-email-notify.php:761 82 82 msgid "Review recipient reasons below. Queue failures retry at least 5 minutes apart, up to 3 queue attempts. Correct configuration failures before recovery. Cancelled recipients require a new campaign." 83 83 msgstr "" 84 84 85 #: includes/class-customer-email-notify.php:7 4285 #: includes/class-customer-email-notify.php:766 86 86 msgid "Paused. Resume to continue remaining recipients." 87 87 msgstr "" 88 88 89 #: includes/class-customer-email-notify.php:763 90 #: includes/class-customer-email-notify.php:764 91 #: includes/class-customer-email-notify.php:848 92 #: includes/class-customer-email-notify.php:1356 93 #: includes/class-customer-email-notify.php:1839 94 #: includes/trait-campaign-authoring.php:112 89 #: includes/class-customer-email-notify.php:787 90 #: includes/class-customer-email-notify.php:788 91 #: includes/class-customer-email-notify.php:874 92 #: includes/class-customer-email-notify.php:1383 93 #: includes/class-customer-email-notify.php:1866 94 #: includes/trait-campaign-authoring.php:122 95 #: includes/trait-campaign-automation-ui.php:64 95 96 #: includes/trait-campaign-privacy.php:121 96 #: includes/trait-campaign-privacy.php:18197 97 #: includes/trait-campaign-privacy.php:187 98 #: includes/trait-campaign-privacy.php:198 98 #: includes/trait-campaign-privacy.php:195 99 #: includes/trait-campaign-privacy.php:206 99 100 msgid "Email campaigns" 100 101 msgstr "" 101 102 102 #: includes/class-customer-email-notify.php:8 54103 #: includes/class-customer-email-notify.php:2 879103 #: includes/class-customer-email-notify.php:880 104 #: includes/class-customer-email-notify.php:2914 104 105 msgid "The email preview expired. Please review the form and try again." 105 106 msgstr "" 106 107 107 #: includes/class-customer-email-notify.php:8 60108 #: includes/class-customer-email-notify.php:886 108 109 msgid "The shared campaign content could not be stored safely, so no email jobs were created. Review the campaign log or server error log before retrying." 109 110 msgstr "" 110 111 111 #: includes/class-customer-email-notify.php:8 66112 #: includes/class-customer-email-notify.php:892 112 113 msgid "Draft restored. You can edit it and preview recipients again." 113 114 msgstr "" 114 115 115 #: includes/class-customer-email-notify.php:8 70116 #: includes/class-customer-email-notify.php:896 116 117 msgid "The draft preview expired, so the form could not be restored." 117 118 msgstr "" 118 119 119 #: includes/class-customer-email-notify.php: 876120 #: includes/class-customer-email-notify.php:902 120 121 msgid "Recipients could not be prepared for background delivery, so no new email jobs were created." 121 122 msgstr "" 122 123 123 124 #. translators: %d: Number of recipients. 124 #: includes/class-customer-email-notify.php: 886125 #: includes/class-customer-email-notify.php:912 125 126 msgid "%d recipient(s) are being prepared in the background. You can leave this page; campaign status will update automatically." 126 127 msgstr "" 127 128 128 129 #. translators: %d: Number of recipients. 129 #: includes/class-customer-email-notify.php:9 01130 #: includes/class-customer-email-notify.php:927 130 131 msgid "Email queued for %d recipient(s). Emails will be sent in the background." 131 132 msgstr "" 132 133 133 134 #. translators: 1: Number of recipients. 2: Scheduled local date and time. 134 #: includes/class-customer-email-notify.php:9 17135 #: includes/class-customer-email-notify.php:943 135 136 msgid "Email scheduled for %1$d recipient(s). Local send time: %2$s. Timezone is derived from each recipient billing country; missing country uses UTC." 136 137 msgstr "" 137 138 138 #: includes/class-customer-email-notify.php:9 19139 #: includes/class-customer-email-notify.php:945 139 140 msgid "the selected time" 140 141 msgstr "" 141 142 142 143 #. translators: %d: Number of recipients. 143 #: includes/class-customer-email-notify.php:9 33144 #: includes/class-customer-email-notify.php:959 144 145 msgid "This campaign was already queued recently for %d recipient(s), so the duplicate submission was blocked." 145 146 msgstr "" 146 147 147 #: includes/class-customer-email-notify.php:9 47148 #: includes/class-customer-email-notify.php:973 148 149 msgid "Test email handed to the mail system. Inbox delivery is not verified." 149 150 msgstr "" 150 151 151 #: includes/class-customer-email-notify.php:9 48152 #: includes/class-customer-email-notify.php:974 152 153 msgid "Test email could not be sent." 153 154 msgstr "" 154 155 155 156 #. translators: %d: Number of recipients. 156 #: includes/class-customer-email-notify.php:9 60157 #: includes/class-customer-email-notify.php:986 157 158 msgid "Email sent to %d recipient(s)." 158 159 msgstr "" 159 160 160 #: includes/class-customer-email-notify.php:9 71161 #: includes/class-customer-email-notify.php:1 581162 #: includes/class-customer-email-notify.php:18 54161 #: includes/class-customer-email-notify.php:997 162 #: includes/class-customer-email-notify.php:1608 163 #: includes/class-customer-email-notify.php:1881 163 164 msgid "Sender" 164 165 msgstr "" 165 166 166 #: includes/class-customer-email-notify.php: 975167 #: includes/class-customer-email-notify.php:1 595168 #: includes/class-customer-email-notify.php:20 27167 #: includes/class-customer-email-notify.php:1001 168 #: includes/class-customer-email-notify.php:1622 169 #: includes/class-customer-email-notify.php:2054 169 170 msgid "Reply-To" 170 171 msgstr "" 171 172 172 173 #. translators: %s: effective no-reply address. 173 #: includes/class-customer-email-notify.php: 982174 #: includes/class-customer-email-notify.php:16 03175 #: includes/class-customer-email-notify.php:20 35174 #: includes/class-customer-email-notify.php:1008 175 #: includes/class-customer-email-notify.php:1630 176 #: includes/class-customer-email-notify.php:2062 176 177 msgid "%s (automatic replies suppressed)" 177 178 msgstr "" 178 179 179 #: includes/class-customer-email-notify.php: 991180 #: includes/class-customer-email-notify.php:1017 180 181 msgid "Edit Settings" 181 182 msgstr "" 182 183 183 #: includes/class-customer-email-notify.php:10 01184 #: includes/class-customer-email-notify.php:1027 184 185 msgid "Compose steps" 185 186 msgstr "" 186 187 187 #: includes/class-customer-email-notify.php:10 02188 #: includes/class-customer-email-notify.php:1028 188 189 msgid "1. Audience" 189 190 msgstr "" 190 191 191 #: includes/class-customer-email-notify.php:1002 192 #: includes/class-customer-email-notify.php:1028 193 #: includes/trait-campaign-automation-ui.php:94 192 194 msgid "2. Content" 193 195 msgstr "" 194 196 195 #: includes/class-customer-email-notify.php:10 02197 #: includes/class-customer-email-notify.php:1028 196 198 msgid "3. Schedule" 197 199 msgstr "" 198 200 199 #: includes/class-customer-email-notify.php:1002 201 #: includes/class-customer-email-notify.php:1028 202 #: includes/trait-campaign-automation-ui.php:94 200 203 msgid "4. Review" 201 204 msgstr "" 202 205 203 #: includes/class-customer-email-notify.php:10 12204 #: includes/class-customer-email-notify.php:14 19205 #: includes/class-customer-email-notify.php:14 31206 #: includes/class-customer-email-notify.php:15 49206 #: includes/class-customer-email-notify.php:1038 207 #: includes/class-customer-email-notify.php:1446 208 #: includes/class-customer-email-notify.php:1458 209 #: includes/class-customer-email-notify.php:1576 207 210 msgid "Audience" 208 211 msgstr "" 209 212 210 #: includes/class-customer-email-notify.php:10 13213 #: includes/class-customer-email-notify.php:1039 211 214 msgid "Choose who should receive this campaign." 212 215 msgstr "" 213 216 214 #: includes/class-customer-email-notify.php:10 17217 #: includes/class-customer-email-notify.php:1043 215 218 msgid "Some selections do not apply to this recipient source. Clear the highlighted selections explicitly or choose a compatible source before previewing." 216 219 msgstr "" 217 220 218 #: includes/class-customer-email-notify.php:10 20219 #: includes/class-customer-email-notify.php: 1974221 #: includes/class-customer-email-notify.php:1046 222 #: includes/class-customer-email-notify.php:2001 220 223 msgid "Recipient source" 221 224 msgstr "" 222 225 223 #: includes/class-customer-email-notify.php:10 28226 #: includes/class-customer-email-notify.php:1054 224 227 msgid "Product selection is only required for product customers." 225 228 msgstr "" 226 229 227 #: includes/class-customer-email-notify.php:10 31228 #: includes/class-customer-email-notify.php: 1979230 #: includes/class-customer-email-notify.php:1057 231 #: includes/class-customer-email-notify.php:2006 229 232 msgid "User roles" 230 233 msgstr "" 231 234 232 #: includes/class-customer-email-notify.php:10 32233 #: includes/class-customer-email-notify.php:4 264235 #: includes/class-customer-email-notify.php:1058 236 #: includes/class-customer-email-notify.php:4303 234 237 msgid "All roles" 235 238 msgstr "" 236 239 237 #: includes/class-customer-email-notify.php:10 37240 #: includes/class-customer-email-notify.php:1063 238 241 msgid "Match any selected role. Leave empty for all registered users, including administrators." 239 242 msgstr "" 240 243 241 #: includes/class-customer-email-notify.php:10 40244 #: includes/class-customer-email-notify.php:1066 242 245 msgid "Recipient email addresses" 243 246 msgstr "" 244 247 245 #: includes/class-customer-email-notify.php:10 42248 #: includes/class-customer-email-notify.php:1068 246 249 msgid "Enter email addresses separated by commas, semicolons, spaces, or line breaks. Duplicates are removed. Invalid addresses must be corrected. Recipient-local scheduling uses UTC for this list; store-time scheduling uses the store timezone." 247 250 msgstr "" 248 251 249 #: includes/class-customer-email-notify.php:10 44252 #: includes/class-customer-email-notify.php:1070 250 253 msgid "Includes billing email addresses from matching orders, including guests (processing/completed by default). Each email address is included once." 251 254 msgstr "" 252 255 253 #: includes/class-customer-email-notify.php:1047 254 #: includes/class-customer-email-notify.php:1985 256 #. translators: %d: Number of hours after the Completed event. 257 #: includes/class-customer-email-notify.php:1073 258 #: includes/class-customer-email-notify.php:2012 259 #: includes/trait-campaign-automation-ui.php:84 255 260 msgid "Products" 256 261 msgstr "" 257 262 258 #: includes/class-customer-email-notify.php:1054 263 #: includes/class-customer-email-notify.php:1080 264 #: includes/class-customer-email-notify.php:1125 265 #: includes/trait-campaign-automation-ui.php:99 266 msgid "Search products or variations" 267 msgstr "" 268 269 #: includes/class-customer-email-notify.php:1085 270 msgid "Include matching purchases of selected products or variations." 271 msgstr "" 272 273 #: includes/class-customer-email-notify.php:1093 274 #: includes/class-customer-email-notify.php:1592 275 #: includes/class-customer-email-notify.php:2031 276 msgid "Exclusions" 277 msgstr "" 278 279 #: includes/class-customer-email-notify.php:1094 280 msgid "Remove matched recipients from the final list." 281 msgstr "" 282 259 283 #: includes/class-customer-email-notify.php:1099 260 msgid "Search products or variations"261 msgstr ""262 263 #: includes/class-customer-email-notify.php:1059264 msgid "Include matching purchases of selected products or variations."265 msgstr ""266 267 #: includes/class-customer-email-notify.php:1067268 #: includes/class-customer-email-notify.php:1565269 #: includes/class-customer-email-notify.php:2004270 msgid "Exclusions"271 msgstr ""272 273 #: includes/class-customer-email-notify.php:1068274 msgid "Remove matched recipients from the final list."275 msgstr ""276 277 #: includes/class-customer-email-notify.php:1073278 284 msgid "Order statuses" 279 285 msgstr "" 280 286 281 #: includes/class-customer-email-notify.php:1 080287 #: includes/class-customer-email-notify.php:1106 282 288 msgid "No order statuses excluded" 283 289 msgstr "" 284 290 285 #: includes/class-customer-email-notify.php:1 088291 #: includes/class-customer-email-notify.php:1114 286 292 msgid "Example: exclude users with refunded orders." 287 293 msgstr "" 288 294 289 #: includes/class-customer-email-notify.php:1 092295 #: includes/class-customer-email-notify.php:1118 290 296 msgid "Product purchasers" 291 297 msgstr "" 292 298 293 #: includes/class-customer-email-notify.php:11 04299 #: includes/class-customer-email-notify.php:1130 294 300 msgid "Exclude people who already bought selected products." 295 301 msgstr "" 296 302 297 #: includes/class-customer-email-notify.php:11 08303 #: includes/class-customer-email-notify.php:1134 298 304 msgid "Manual emails" 299 305 msgstr "" 300 306 301 #: includes/class-customer-email-notify.php:11 14307 #: includes/class-customer-email-notify.php:1140 302 308 msgid "one@example.com, two@example.com" 303 309 msgstr "" 304 310 305 #: includes/class-customer-email-notify.php:11 15311 #: includes/class-customer-email-notify.php:1141 306 312 msgid "Comma, semicolon, space, or line break separated." 307 313 msgstr "" 308 314 309 #: includes/class-customer-email-notify.php:1128 315 #: includes/class-customer-email-notify.php:1154 316 #: includes/trait-campaign-automation-ui.php:106 310 317 msgid "Content" 311 318 msgstr "" 312 319 313 #: includes/class-customer-email-notify.php:11 29320 #: includes/class-customer-email-notify.php:1155 314 321 msgid "Compose the email shown inside the WooCommerce template." 315 322 msgstr "" 316 323 317 #: includes/class-customer-email-notify.php:1135 318 #: includes/class-customer-email-notify.php:1202 319 #: includes/class-customer-email-notify.php:1545 320 #: includes/class-customer-email-notify.php:2044 324 #: includes/class-customer-email-notify.php:1161 325 #: includes/class-customer-email-notify.php:1228 326 #: includes/class-customer-email-notify.php:1572 327 #: includes/class-customer-email-notify.php:2071 328 #: includes/trait-campaign-automation-ui.php:107 329 #: includes/trait-campaign-automation-ui.php:132 330 #: includes/trait-campaign-automation-ui.php:135 321 331 msgid "Subject" 322 332 msgstr "" 323 333 324 #: includes/class-customer-email-notify.php:1140 325 #: includes/class-customer-email-notify.php:5160 326 #: includes/class-customer-email-notify.php:5389 334 #: includes/class-customer-email-notify.php:1166 335 #: includes/class-customer-email-notify.php:5221 336 #: includes/class-customer-email-notify.php:5466 337 #: includes/trait-campaign-automation-ui.php:107 327 338 msgid "Email heading" 328 339 msgstr "" 329 340 330 #: includes/class-customer-email-notify.php:1145 331 #: includes/class-customer-email-notify.php:5147 332 #: includes/class-customer-email-notify.php:5390 341 #: includes/class-customer-email-notify.php:1171 342 #: includes/class-customer-email-notify.php:5208 343 #: includes/class-customer-email-notify.php:5467 344 #: includes/trait-campaign-automation-ui.php:108 333 345 msgid "Message body" 334 346 msgstr "" 335 347 336 348 #. translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. 337 #: includes/class-customer-email-notify.php:11 57338 msgid " Body variables: {customer_name} uses the saved recipient name, falling back to email; {product_name} is the shared campaign product label, never a personal purchase. With no product selection it uses the audience label. Subject and heading are literal."349 #: includes/class-customer-email-notify.php:1183 350 msgid "Variables in subject, heading and body: {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products}, {order_url}. Order variables use the matching order with the highest order ID; preview shows its number and the matching order count. Without order context they are empty; missing names use Customer. {product_name} remains the shared campaign label. Order links require the matching account login; guests have no order link. The live editor shows template text; Preview Recipients and test email use the first eligible recipient." 339 351 msgstr "" 340 352 341 353 #. translators: Keep {customer_name} and {product_name} unchanged. They are email placeholders. 342 #: includes/class-customer-email-notify.php:11 58354 #: includes/class-customer-email-notify.php:1184 343 355 msgid "An unsubscribe link is added automatically to campaign emails." 344 356 msgstr "" 345 357 346 #: includes/class-customer-email-notify.php:11 66358 #: includes/class-customer-email-notify.php:1192 347 359 msgid "Test" 348 360 msgstr "" 349 361 350 #: includes/class-customer-email-notify.php:11 67362 #: includes/class-customer-email-notify.php:1193 351 363 msgid "Send a single email without building the campaign queue." 352 364 msgstr "" 353 365 354 #: includes/class-customer-email-notify.php:1 174366 #: includes/class-customer-email-notify.php:1200 355 367 msgid "Enable test mode" 356 368 msgstr "" 357 369 358 #: includes/class-customer-email-notify.php:1 175370 #: includes/class-customer-email-notify.php:1201 359 371 msgid "Only the test recipient will receive this email." 360 372 msgstr "" 361 373 362 #: includes/class-customer-email-notify.php:1180 374 #: includes/class-customer-email-notify.php:1206 375 #: includes/trait-campaign-automation-ui.php:118 363 376 msgid "Test email address" 364 377 msgstr "" 365 378 366 #: includes/class-customer-email-notify.php:1 189367 #: includes/class-customer-email-notify.php:1 278379 #: includes/class-customer-email-notify.php:1215 380 #: includes/class-customer-email-notify.php:1304 368 381 msgid "Send Test Email" 369 382 msgstr "" 370 383 371 #: includes/class-customer-email-notify.php:1191 372 #: includes/class-customer-email-notify.php:1194 384 #: includes/class-customer-email-notify.php:1217 385 #: includes/class-customer-email-notify.php:1220 386 #: includes/trait-campaign-automation-ui.php:128 387 #: includes/trait-campaign-automation-ui.php:129 373 388 msgid "Email preview" 374 389 msgstr "" 375 390 376 #: includes/class-customer-email-notify.php:1195 391 #: includes/class-customer-email-notify.php:1221 392 #: includes/trait-campaign-automation-ui.php:129 377 393 msgid "Rendered with the active WooCommerce email template." 378 394 msgstr "" 379 395 380 #: includes/class-customer-email-notify.php:1197 396 #: includes/class-customer-email-notify.php:1223 397 #: includes/trait-campaign-automation-ui.php:129 381 398 msgid "Live" 382 399 msgstr "" 383 400 384 #: includes/class-customer-email-notify.php:12 03385 #: includes/class-customer-email-notify.php:5 388401 #: includes/class-customer-email-notify.php:1229 402 #: includes/class-customer-email-notify.php:5465 386 403 msgid "Email subject" 387 404 msgstr "" 388 405 389 #: includes/class-customer-email-notify.php:1210 406 #: includes/class-customer-email-notify.php:1236 407 #: includes/trait-campaign-automation-ui.php:132 390 408 msgid "WooCommerce email preview" 391 409 msgstr "" 392 410 393 #: includes/class-customer-email-notify.php:12 19411 #: includes/class-customer-email-notify.php:1245 394 412 msgid "Schedule" 395 413 msgstr "" 396 414 397 #: includes/class-customer-email-notify.php:12 20415 #: includes/class-customer-email-notify.php:1246 398 416 msgid "Choose when the campaign should be sent." 399 417 msgstr "" 400 418 401 #: includes/class-customer-email-notify.php:12 28419 #: includes/class-customer-email-notify.php:1254 402 420 msgid "Send after confirmation" 403 421 msgstr "" 404 422 405 #: includes/class-customer-email-notify.php:12 29423 #: includes/class-customer-email-notify.php:1255 406 424 msgid "Queue emails as soon as the preview is confirmed." 407 425 msgstr "" 408 426 409 #: includes/class-customer-email-notify.php:12 35427 #: includes/class-customer-email-notify.php:1261 410 428 msgid "Schedule for later" 411 429 msgstr "" 412 430 413 #: includes/class-customer-email-notify.php:12 36431 #: includes/class-customer-email-notify.php:1262 414 432 msgid "Legacy schedule restored. Choose an explicit store or local mode for this new campaign." 415 433 msgstr "" 416 434 417 #: includes/class-customer-email-notify.php:12 41435 #: includes/class-customer-email-notify.php:1267 418 436 msgid "One time in store timezone:" 419 437 msgstr "" 420 438 421 #: includes/class-customer-email-notify.php:12 41439 #: includes/class-customer-email-notify.php:1267 422 440 msgid "All recipients share one UTC due time." 423 441 msgstr "" 424 442 425 #: includes/class-customer-email-notify.php:12 42426 #: includes/trait-campaign-authoring.php:2 22443 #: includes/class-customer-email-notify.php:1268 444 #: includes/trait-campaign-authoring.php:232 427 445 msgid "Same local time per recipient (location estimate; UTC fallback)" 428 446 msgstr "" 429 447 430 #: includes/class-customer-email-notify.php:12 42448 #: includes/class-customer-email-notify.php:1268 431 449 msgid "Only unambiguous billing countries use a location estimate. Other countries, missing data and manual lists use UTC." 432 450 msgstr "" 433 451 434 #: includes/class-customer-email-notify.php:12 44452 #: includes/class-customer-email-notify.php:1270 435 453 msgid "Scheduled date/time" 436 454 msgstr "" 437 455 438 #: includes/class-customer-email-notify.php:12 51456 #: includes/class-customer-email-notify.php:1277 439 457 msgid "Store mode uses the displayed store timezone. Local mode uses a billing-location estimate only when unambiguous, otherwise UTC. Past, nonexistent or repeated local times are rejected; choose another time. No automatic next-day rollover." 440 458 msgstr "" 441 459 442 #: includes/class-customer-email-notify.php:12 57460 #: includes/class-customer-email-notify.php:1283 443 461 msgid "Review before confirmation" 444 462 msgstr "" 445 463 446 #: includes/class-customer-email-notify.php:12 58464 #: includes/class-customer-email-notify.php:1284 447 465 msgid "Preview Recipients opens the saved recipient preview with selected and excluded counts, reasons, personalized samples and confirmed due times. No audience estimate is calculated while you edit." 448 466 msgstr "" 449 467 450 #: includes/class-customer-email-notify.php:12 59468 #: includes/class-customer-email-notify.php:1285 451 469 msgid "Review that preview, then confirm there. Changes require another preview. Emails already handed to the mail system cannot be recalled; inbox delivery is not verified." 452 470 msgstr "" 453 471 454 #: includes/class-customer-email-notify.php:12 60472 #: includes/class-customer-email-notify.php:1286 455 473 msgid "Test mode sends only to the test address. Turn it off in Content to preview a campaign audience." 456 474 msgstr "" 457 475 458 #: includes/class-customer-email-notify.php:12 65459 #: includes/class-customer-email-notify.php:12 67476 #: includes/class-customer-email-notify.php:1291 477 #: includes/class-customer-email-notify.php:1293 460 478 msgid "Next step: preview recipients and confirm before sending." 461 479 msgstr "" 462 480 463 #: includes/class-customer-email-notify.php:12 66481 #: includes/class-customer-email-notify.php:1292 464 482 msgid "Test mode sends one email to the test recipient and keeps this draft for further edits." 465 483 msgstr "" 466 484 467 #: includes/class-customer-email-notify.php:12 71468 #: includes/class-customer-email-notify.php:1 277485 #: includes/class-customer-email-notify.php:1297 486 #: includes/class-customer-email-notify.php:1303 469 487 msgid "Preview Recipients" 470 488 msgstr "" 471 489 472 #: includes/class-customer-email-notify.php:1285 490 #: includes/class-customer-email-notify.php:1311 491 #: includes/trait-campaign-automation-ui.php:122 473 492 msgid "Back" 474 493 msgstr "" 475 494 476 #: includes/class-customer-email-notify.php:1286 495 #: includes/class-customer-email-notify.php:1312 496 #: includes/trait-campaign-automation-ui.php:122 477 497 msgid "Continue" 478 498 msgstr "" 479 499 480 #: includes/class-customer-email-notify.php:1 296500 #: includes/class-customer-email-notify.php:1322 481 501 msgid "Campaigns" 482 502 msgstr "" 483 503 484 #: includes/class-customer-email-notify.php:1 297504 #: includes/class-customer-email-notify.php:1323 485 505 msgid "Compose" 486 506 msgstr "" 487 507 488 #: includes/class-customer-email-notify.php:1298 508 #: includes/class-customer-email-notify.php:1324 509 #: includes/trait-campaign-automation-ui.php:80 510 msgid "Automations" 511 msgstr "" 512 513 #: includes/class-customer-email-notify.php:1325 489 514 msgid "Library" 490 515 msgstr "" 491 516 492 #: includes/class-customer-email-notify.php:1 299517 #: includes/class-customer-email-notify.php:1326 493 518 msgid "Subscribers" 494 519 msgstr "" 495 520 496 #: includes/class-customer-email-notify.php:13 00521 #: includes/class-customer-email-notify.php:1327 497 522 msgid "Settings" 498 523 msgstr "" 499 524 500 #: includes/class-customer-email-notify.php:13 44501 #: includes/class-customer-email-notify.php:1 380525 #: includes/class-customer-email-notify.php:1371 526 #: includes/class-customer-email-notify.php:1407 502 527 msgid "Campaign list" 503 528 msgstr "" 504 529 505 530 #. translators: %s: Campaign ID. 506 #: includes/class-customer-email-notify.php:13 49507 #: includes/class-customer-email-notify.php:16 70531 #: includes/class-customer-email-notify.php:1376 532 #: includes/class-customer-email-notify.php:1697 508 533 msgid "Recent campaign log" 509 534 msgstr "" 510 535 511 #: includes/class-customer-email-notify.php:13 60536 #: includes/class-customer-email-notify.php:1387 512 537 msgid "Handed to mail system means the sending request was accepted, not that the email reached an inbox. Queue failures retry automatically up to 3 attempts, at least 5 minutes apart. Known pre-transport failures require correcting the reported data or configuration, then recovery. Unknown outcomes require checking the mail provider before deciding to create a new campaign." 513 538 msgstr "" 514 539 515 #: includes/class-customer-email-notify.php:1 381540 #: includes/class-customer-email-notify.php:1408 516 541 msgid "Recent campaign previews, tests, queues, schedules, and send results are grouped by campaign." 517 542 msgstr "" 518 543 519 544 #. translators: %d: Number of campaigns. 520 #: includes/class-customer-email-notify.php:1 387545 #: includes/class-customer-email-notify.php:1414 521 546 msgid "%d campaign(s) stored" 522 547 msgstr "" 523 548 524 #: includes/class-customer-email-notify.php:1 397549 #: includes/class-customer-email-notify.php:1424 525 550 msgid "No campaign history has been created yet. Preview or send a campaign to start tracking it here." 526 551 msgstr "" 527 552 528 #: includes/class-customer-email-notify.php:14 16529 #: includes/class-customer-email-notify.php:14 28530 #: includes/class-customer-email-notify.php:17 11531 #: includes/class-customer-email-notify.php:17 21553 #: includes/class-customer-email-notify.php:1443 554 #: includes/class-customer-email-notify.php:1455 555 #: includes/class-customer-email-notify.php:1738 556 #: includes/class-customer-email-notify.php:1748 532 557 msgid "Campaign" 533 558 msgstr "" 534 559 535 #: includes/class-customer-email-notify.php:14 17536 #: includes/class-customer-email-notify.php:14 29537 #: includes/class-customer-email-notify.php:17 13538 #: includes/class-customer-email-notify.php:17 23539 #: includes/trait-campaign-privacy.php:14 2560 #: includes/class-customer-email-notify.php:1444 561 #: includes/class-customer-email-notify.php:1456 562 #: includes/class-customer-email-notify.php:1740 563 #: includes/class-customer-email-notify.php:1750 564 #: includes/trait-campaign-privacy.php:144 540 565 msgid "Status" 541 566 msgstr "" 542 567 543 #: includes/class-customer-email-notify.php:14 18544 #: includes/class-customer-email-notify.php:14 30545 #: includes/class-customer-email-notify.php:17 15546 #: includes/class-customer-email-notify.php:17 25568 #: includes/class-customer-email-notify.php:1445 569 #: includes/class-customer-email-notify.php:1457 570 #: includes/class-customer-email-notify.php:1742 571 #: includes/class-customer-email-notify.php:1752 547 572 msgid "Message" 548 573 msgstr "" 549 574 550 #: includes/class-customer-email-notify.php:14 20551 #: includes/class-customer-email-notify.php:14 32552 #: includes/class-customer-email-notify.php:1 577553 #: includes/class-customer-email-notify.php:20 52575 #: includes/class-customer-email-notify.php:1447 576 #: includes/class-customer-email-notify.php:1459 577 #: includes/class-customer-email-notify.php:1604 578 #: includes/class-customer-email-notify.php:2079 554 579 msgid "Delivery" 555 580 msgstr "" 556 581 557 #: includes/class-customer-email-notify.php:14 21558 #: includes/class-customer-email-notify.php:14 33582 #: includes/class-customer-email-notify.php:1448 583 #: includes/class-customer-email-notify.php:1460 559 584 msgid "Activity" 560 585 msgstr "" 561 586 562 #: includes/class-customer-email-notify.php:1422 563 #: includes/class-customer-email-notify.php:1434 587 #: includes/class-customer-email-notify.php:1449 588 #: includes/class-customer-email-notify.php:1461 589 #: includes/trait-campaign-contact-history.php:81 564 590 msgid "Updated" 565 591 msgstr "" 566 592 567 #: includes/class-customer-email-notify.php:14 23568 #: includes/class-customer-email-notify.php:14 35593 #: includes/class-customer-email-notify.php:1450 594 #: includes/class-customer-email-notify.php:1462 569 595 msgid "Actions" 570 596 msgstr "" 571 597 572 #: includes/class-customer-email-notify.php:14 59598 #: includes/class-customer-email-notify.php:1486 573 599 msgid "Test campaign" 574 600 msgstr "" 575 601 576 #: includes/class-customer-email-notify.php:14 63577 #: includes/class-customer-email-notify.php:15 06602 #: includes/class-customer-email-notify.php:1490 603 #: includes/class-customer-email-notify.php:1533 578 604 msgid "View log" 579 605 msgstr "" 580 606 581 #: includes/class-customer-email-notify.php:1 473607 #: includes/class-customer-email-notify.php:1500 582 608 msgid "(No subject)" 583 609 msgstr "" 584 610 585 611 #. translators: %s: Formatted creation date and time. 586 #: includes/class-customer-email-notify.php:1 496612 #: includes/class-customer-email-notify.php:1523 587 613 msgid "Created %s" 588 614 msgstr "" 589 615 590 #: includes/class-customer-email-notify.php:15 30616 #: includes/class-customer-email-notify.php:1557 591 617 msgid "The selected campaign could not be found in stored history." 592 618 msgstr "" 593 619 594 #: includes/class-customer-email-notify.php:15 37620 #: includes/class-customer-email-notify.php:1564 595 621 msgid "Campaign details" 596 622 msgstr "" 597 623 598 #: includes/class-customer-email-notify.php:15 41599 #: includes/class-customer-email-notify.php:19 70624 #: includes/class-customer-email-notify.php:1568 625 #: includes/class-customer-email-notify.php:1997 600 626 msgid "Campaign ID" 601 627 msgstr "" 602 628 603 #: includes/class-customer-email-notify.php:15 61629 #: includes/class-customer-email-notify.php:1588 604 630 msgid "Scope" 605 631 msgstr "" 606 632 607 #: includes/class-customer-email-notify.php:15 71633 #: includes/class-customer-email-notify.php:1598 608 634 msgid "None" 609 635 msgstr "" 610 636 611 #: includes/class-customer-email-notify.php:16 34637 #: includes/class-customer-email-notify.php:1661 612 638 msgid "Recover / retry eligible recipients" 613 639 msgstr "" 614 640 615 641 #. translators: %d: Number of scheduling failures. 616 #: includes/class-customer-email-notify.php:16 44642 #: includes/class-customer-email-notify.php:1671 617 643 msgid "%d eligible recipient(s). Recovery continues preparation and retries queue failures or known pre-transport failures, up to 3 attempts. Unknown outcomes are never retried. Unsubscribes are checked again." 618 644 msgstr "" 619 645 620 #: includes/class-customer-email-notify.php:16 55646 #: includes/class-customer-email-notify.php:1682 621 647 msgid "Historical schedule failures are recorded, but their recipient-level records are no longer complete. Automatic retry is disabled to prevent sending to the wrong or already handled recipients." 622 648 msgstr "" 623 649 624 650 #. translators: %s: Campaign ID. 625 #: includes/class-customer-email-notify.php:16 69651 #: includes/class-customer-email-notify.php:1696 626 652 msgid "Log for campaign %s" 627 653 msgstr "" 628 654 629 #: includes/class-customer-email-notify.php:1 674655 #: includes/class-customer-email-notify.php:1701 630 656 msgid "Latest stored send, queue, schedule, failure, skipped, and unsubscribe events." 631 657 msgstr "" 632 658 633 #: includes/class-customer-email-notify.php:1 678659 #: includes/class-customer-email-notify.php:1705 634 660 msgid "View all logs" 635 661 msgstr "" 636 662 637 #: includes/class-customer-email-notify.php:1 685663 #: includes/class-customer-email-notify.php:1712 638 664 msgid "No log entries found yet." 639 665 msgstr "" 640 666 641 #: includes/class-customer-email-notify.php:17 10642 #: includes/class-customer-email-notify.php:17 20667 #: includes/class-customer-email-notify.php:1737 668 #: includes/class-customer-email-notify.php:1747 643 669 msgid "Time" 644 670 msgstr "" 645 671 646 #: includes/class-customer-email-notify.php:17 12647 #: includes/class-customer-email-notify.php:17 22648 #: includes/class-customer-email-notify.php:2 075672 #: includes/class-customer-email-notify.php:1739 673 #: includes/class-customer-email-notify.php:1749 674 #: includes/class-customer-email-notify.php:2102 649 675 #: includes/trait-campaign-controls.php:179 650 676 msgid "Email" 651 677 msgstr "" 652 678 653 #: includes/class-customer-email-notify.php:17 14654 #: includes/class-customer-email-notify.php:17 24679 #: includes/class-customer-email-notify.php:1741 680 #: includes/class-customer-email-notify.php:1751 655 681 msgid "Action ID" 656 682 msgstr "" 657 683 658 #: includes/class-customer-email-notify.php:17 41684 #: includes/class-customer-email-notify.php:1768 659 685 msgid "unknown" 660 686 msgstr "" 661 687 662 #: includes/class-customer-email-notify.php:1 778688 #: includes/class-customer-email-notify.php:1805 663 689 msgid "The selected campaign could not be found." 664 690 msgstr "" 665 691 666 #: includes/class-customer-email-notify.php:1 779692 #: includes/class-customer-email-notify.php:1806 667 693 msgid "This campaign does not have enough stored email content to reschedule safely. For older campaigns, keep at least one pending scheduled action so Email campaigns can recover the message payload." 668 694 msgstr "" 669 695 670 #: includes/class-customer-email-notify.php:1 780696 #: includes/class-customer-email-notify.php:1807 671 697 msgid "Recipient-level failure records are incomplete, so automatic retry was blocked to prevent duplicate or incorrect delivery." 672 698 msgstr "" 673 699 674 #: includes/class-customer-email-notify.php:1 781700 #: includes/class-customer-email-notify.php:1808 675 701 msgid "The campaign content could not be stored safely, so no retry jobs were created." 676 702 msgstr "" 677 703 678 #: includes/class-customer-email-notify.php:1 782704 #: includes/class-customer-email-notify.php:1809 679 705 msgid "Failed recipients could not be prepared for background retry." 680 706 msgstr "" 681 707 682 #: includes/class-customer-email-notify.php:1 783708 #: includes/class-customer-email-notify.php:1810 683 709 msgid "The background retry dispatcher could not be queued." 684 710 msgstr "" 685 711 686 #: includes/class-customer-email-notify.php:1 784712 #: includes/class-customer-email-notify.php:1811 687 713 msgid "No stuck schedule-failed recipients were found for this campaign." 688 714 msgstr "" 689 715 690 #: includes/class-customer-email-notify.php:1 788716 #: includes/class-customer-email-notify.php:1815 691 717 msgid "The failed schedule retry could not be completed." 692 718 msgstr "" 693 719 694 720 #. translators: 1: Number of emails successfully rescheduled. 2: Number of failed retries. 695 #: includes/class-customer-email-notify.php:18 07721 #: includes/class-customer-email-notify.php:1834 696 722 msgid "Rescheduled %1$d failed email(s). %2$d retry attempt(s) failed." 697 723 msgstr "" 698 724 699 725 #. translators: %d: Number of recipients. 700 #: includes/class-customer-email-notify.php:18 25726 #: includes/class-customer-email-notify.php:1852 701 727 msgid "%d failed recipient(s) are being prepared for retry in the background." 702 728 msgstr "" 703 729 704 #: includes/class-customer-email-notify.php:18 45730 #: includes/class-customer-email-notify.php:1872 705 731 msgid "Email campaigns settings saved." 706 732 msgstr "" 707 733 708 #: includes/class-customer-email-notify.php:18 56734 #: includes/class-customer-email-notify.php:1883 709 735 msgid "From email" 710 736 msgstr "" 711 737 712 #: includes/class-customer-email-notify.php:18 66738 #: includes/class-customer-email-notify.php:1893 713 739 msgid "Used as the sender email for every campaign." 714 740 msgstr "" 715 741 716 #: includes/class-customer-email-notify.php:18 68742 #: includes/class-customer-email-notify.php:1895 717 743 msgid "From name" 718 744 msgstr "" 719 745 720 #: includes/class-customer-email-notify.php:1 877746 #: includes/class-customer-email-notify.php:1904 721 747 msgid "Reply-To email" 722 748 msgstr "" 723 749 724 #: includes/class-customer-email-notify.php:1 887750 #: includes/class-customer-email-notify.php:1914 725 751 msgid "Used when automated-reply suppression is disabled." 726 752 msgstr "" 727 753 728 #: includes/class-customer-email-notify.php:1 889754 #: includes/class-customer-email-notify.php:1916 729 755 msgid "No-reply email" 730 756 msgstr "" 731 757 732 #: includes/class-customer-email-notify.php:1 898758 #: includes/class-customer-email-notify.php:1925 733 759 msgid "Used as Reply-To while suppression is enabled, so non-compliant automatic responders do not reach the support inbox." 734 760 msgstr "" 735 761 736 #: includes/class-customer-email-notify.php:19 00762 #: includes/class-customer-email-notify.php:1927 737 763 msgid "Automated replies" 738 764 msgstr "" 739 765 740 #: includes/class-customer-email-notify.php:19 09766 #: includes/class-customer-email-notify.php:1936 741 767 msgid "Suppress out-of-office and other automatic replies" 742 768 msgstr "" 743 769 744 #: includes/class-customer-email-notify.php:19 12770 #: includes/class-customer-email-notify.php:1939 745 771 msgid "Adds standards-based bulk/automatic message headers while preserving delivery failure notifications." 746 772 msgstr "" 747 773 748 #: includes/class-customer-email-notify.php:19 15774 #: includes/class-customer-email-notify.php:1942 749 775 msgid "Save Settings" 750 776 msgstr "" 751 777 752 #: includes/class-customer-email-notify.php:19 28753 #: includes/class-customer-email-notify.php:19 63778 #: includes/class-customer-email-notify.php:1955 779 #: includes/class-customer-email-notify.php:1990 754 780 msgid "Preview email campaign" 755 781 msgstr "" 756 782 757 #: includes/class-customer-email-notify.php:19 34758 #: includes/class-customer-email-notify.php:21 33783 #: includes/class-customer-email-notify.php:1961 784 #: includes/class-customer-email-notify.php:2160 759 785 msgid "Back to email form" 760 786 msgstr "" 761 787 762 #: includes/class-customer-email-notify.php:19 48763 #: includes/class-customer-email-notify.php:42 53788 #: includes/class-customer-email-notify.php:1975 789 #: includes/class-customer-email-notify.php:4292 764 790 msgid "Product customers" 765 791 msgstr "" 766 792 767 #: includes/class-customer-email-notify.php:19 51768 #: includes/class-customer-email-notify.php:51 15793 #: includes/class-customer-email-notify.php:1978 794 #: includes/class-customer-email-notify.php:5176 769 795 msgid "selected product(s)" 770 796 msgstr "" 771 797 772 #: includes/class-customer-email-notify.php: 1990798 #: includes/class-customer-email-notify.php:2017 773 799 #: includes/trait-campaign-controls.php:172 774 800 msgid "Recipients" … … 776 802 777 803 #. translators: %d: Number of recipients. 778 #: includes/class-customer-email-notify.php: 1995804 #: includes/class-customer-email-notify.php:2022 779 805 msgid "%d recipient" 780 806 msgid_plural "%d recipients" … … 782 808 msgstr[1] "" 783 809 784 #: includes/class-customer-email-notify.php:20 08785 #: includes/trait-campaign-authoring.php:2 18810 #: includes/class-customer-email-notify.php:2035 811 #: includes/trait-campaign-authoring.php:228 786 812 msgid "Excluded" 787 813 msgstr "" 788 814 789 815 #. translators: 1: Number of excluded recipients. 2: Initial number of recipients. 790 #: includes/class-customer-email-notify.php:20 13816 #: includes/class-customer-email-notify.php:2040 791 817 msgid "%1$d removed from %2$d initial recipient(s)." 792 818 msgstr "" 793 819 794 #: includes/class-customer-email-notify.php:20 23820 #: includes/class-customer-email-notify.php:2050 795 821 msgid "From" 796 822 msgstr "" 797 823 798 #: includes/class-customer-email-notify.php:20 48824 #: includes/class-customer-email-notify.php:2075 799 825 msgid "Heading" 800 826 msgstr "" 801 827 802 828 #. translators: %s: Scheduled local date and time. 803 #: includes/class-customer-email-notify.php:20 58829 #: includes/class-customer-email-notify.php:2085 804 830 msgid "Scheduled for %s. See the confirmed mode, timezone and UTC range below." 805 831 msgstr "" 806 832 807 #: includes/class-customer-email-notify.php:20 61833 #: includes/class-customer-email-notify.php:2088 808 834 msgid "Send as soon as possible after confirmation" 809 835 msgstr "" 810 836 811 #: includes/class-customer-email-notify.php:20 70837 #: includes/class-customer-email-notify.php:2097 812 838 msgid "Saved recipient sample and due times" 813 839 msgstr "" 814 840 815 #: includes/class-customer-email-notify.php:2 074841 #: includes/class-customer-email-notify.php:2101 816 842 msgid "Name" 817 843 msgstr "" 818 844 819 #: includes/class-customer-email-notify.php:2 076820 #: includes/trait-campaign-audiences.php:1 43821 #: includes/trait-campaign-audiences.php:1 58845 #: includes/class-customer-email-notify.php:2103 846 #: includes/trait-campaign-audiences.php:152 847 #: includes/trait-campaign-audiences.php:167 822 848 msgid "Billing country" 823 849 msgstr "" 824 850 825 #: includes/class-customer-email-notify.php:2 077851 #: includes/class-customer-email-notify.php:2104 826 852 msgid "Billing state/city" 827 853 msgstr "" 828 854 829 #: includes/class-customer-email-notify.php:2 079855 #: includes/class-customer-email-notify.php:2106 830 856 msgid "Scheduled timezone" 831 857 msgstr "" 832 858 833 #: includes/class-customer-email-notify.php:2 080859 #: includes/class-customer-email-notify.php:2107 834 860 msgid "Scheduled send time" 835 861 msgstr "" 836 862 837 #: includes/class-customer-email-notify.php:2 094863 #: includes/class-customer-email-notify.php:2121 838 864 msgid "UTC fallback" 839 865 msgstr "" 840 866 841 #: includes/class-customer-email-notify.php:21 01867 #: includes/class-customer-email-notify.php:2128 842 868 msgid "Not set" 843 869 msgstr "" 844 870 845 #: includes/class-customer-email-notify.php:21 12871 #: includes/class-customer-email-notify.php:2139 846 872 msgid "Invalid scheduled time" 847 873 msgstr "" 848 874 849 #: includes/class-customer-email-notify.php:21 25875 #: includes/class-customer-email-notify.php:2152 850 876 msgid "Message preview" 851 877 msgstr "" 852 878 853 #: includes/class-customer-email-notify.php:21 41879 #: includes/class-customer-email-notify.php:2168 854 880 msgid "Confirm this saved preview" 855 881 msgstr "" 856 882 857 #: includes/class-customer-email-notify.php:21 42883 #: includes/class-customer-email-notify.php:2169 858 884 msgid "Confirmation creates this campaign with its saved recipients and content. Audience changes require a new preview. Emails already handed to the mail system cannot be recalled; inbox delivery is not verified." 859 885 msgstr "" 860 886 861 887 #. translators: %d: Number of recipients. 862 #: includes/class-customer-email-notify.php:21 49888 #: includes/class-customer-email-notify.php:2176 863 889 msgid "Schedule Email for %d Recipient(s)" 864 890 msgstr "" 865 891 866 892 #. translators: %d: Number of recipients. 867 #: includes/class-customer-email-notify.php:21 50893 #: includes/class-customer-email-notify.php:2177 868 894 msgid "Queue Email for %d Recipient(s)" 869 895 msgstr "" 870 896 871 #: includes/class-customer-email-notify.php:21 58897 #: includes/class-customer-email-notify.php:2185 872 898 msgid "No matching customers were found. Nothing will be queued." 873 899 msgstr "" 874 900 875 #: includes/class-customer-email-notify.php:2 173901 #: includes/class-customer-email-notify.php:2200 876 902 msgid "This unsubscribe link is invalid or expired." 877 903 msgstr "" 878 904 879 #: includes/class-customer-email-notify.php:2 174905 #: includes/class-customer-email-notify.php:2201 880 906 msgid "Invalid unsubscribe link" 881 907 msgstr "" 882 908 883 #: includes/class-customer-email-notify.php:2 180909 #: includes/class-customer-email-notify.php:2207 884 910 msgid "Your unsubscribe could not be saved. Please try this link again." 885 911 msgstr "" 886 912 887 #: includes/class-customer-email-notify.php:2 189913 #: includes/class-customer-email-notify.php:2216 888 914 msgid "You have been unsubscribed." 889 915 msgstr "" 890 916 891 #: includes/class-customer-email-notify.php:2 190917 #: includes/class-customer-email-notify.php:2217 892 918 msgid "This email address will be excluded from future email campaigns." 893 919 msgstr "" 894 920 895 #: includes/class-customer-email-notify.php:2193 896 #: includes/class-customer-email-notify.php:3600 921 #: includes/class-customer-email-notify.php:2220 922 #: includes/class-customer-email-notify.php:3636 923 #: includes/trait-campaign-contact-history.php:66 897 924 #: includes/trait-campaign-controls.php:173 898 #: includes/trait-campaign-privacy.php:12 7899 #: includes/trait-campaign-privacy.php:14 3925 #: includes/trait-campaign-privacy.php:128 926 #: includes/trait-campaign-privacy.php:145 900 927 msgid "Unsubscribed" 901 928 msgstr "" 902 929 903 #: includes/class-customer-email-notify.php:2200 904 #: includes/class-customer-email-notify.php:2253 905 #: includes/class-customer-email-notify.php:2270 906 #: includes/trait-campaign-authoring.php:91 930 #: includes/class-customer-email-notify.php:2227 931 #: includes/class-customer-email-notify.php:2280 932 #: includes/class-customer-email-notify.php:2297 933 #: includes/trait-campaign-authoring.php:101 934 #: includes/trait-campaign-automation-ui.php:16 935 #: includes/trait-campaign-contact-history.php:6 907 936 #: includes/trait-campaign-controls.php:111 937 #: includes/trait-campaign-entrypoints.php:61 938 #: includes/trait-campaign-entrypoints.php:83 908 939 #: includes/trait-campaign-privacy.php:80 940 #: includes/trait-campaign-subscriptions.php:128 909 941 msgid "Permission denied." 910 942 msgstr "" 911 943 912 #: includes/class-customer-email-notify.php:22 15913 #: includes/class-customer-email-notify.php:27 56944 #: includes/class-customer-email-notify.php:2242 945 #: includes/class-customer-email-notify.php:2790 914 946 msgid "Please enter a valid sender email address." 915 947 msgstr "" 916 948 917 #: includes/class-customer-email-notify.php:22 19918 #: includes/class-customer-email-notify.php:27 60949 #: includes/class-customer-email-notify.php:2246 950 #: includes/class-customer-email-notify.php:2794 919 951 msgid "Please enter a sender name." 920 952 msgstr "" 921 953 922 #: includes/class-customer-email-notify.php:22 23923 #: includes/class-customer-email-notify.php:27 64954 #: includes/class-customer-email-notify.php:2250 955 #: includes/class-customer-email-notify.php:2798 924 956 msgid "Please enter a valid Reply-To email address." 925 957 msgstr "" 926 958 927 #: includes/class-customer-email-notify.php:22 27959 #: includes/class-customer-email-notify.php:2254 928 960 msgid "Please enter a valid no-reply email address when automated replies are suppressed." 929 961 msgstr "" 930 962 931 #: includes/class-customer-email-notify.php:23 15963 #: includes/class-customer-email-notify.php:2342 932 964 msgid "Please enter a valid test email address." 933 965 msgstr "" 934 966 935 #: includes/class-customer-email-notify.php:23 33967 #: includes/class-customer-email-notify.php:2355 936 968 msgid "Test Customer" 937 969 msgstr "" 938 970 939 #: includes/class-customer-email-notify.php:24 64971 #: includes/class-customer-email-notify.php:2483 940 972 msgid "Missing campaign payload identity." 941 973 msgstr "" 942 974 943 #: includes/class-customer-email-notify.php:2 487975 #: includes/class-customer-email-notify.php:2506 944 976 msgid "Campaign content or sender details are incomplete." 945 977 msgstr "" 946 978 947 #: includes/class-customer-email-notify.php:25 12979 #: includes/class-customer-email-notify.php:2535 948 980 msgid "Stored campaign content does not match this campaign delivery." 949 981 msgstr "" 950 982 951 #: includes/class-customer-email-notify.php:25 36983 #: includes/class-customer-email-notify.php:2559 952 984 msgid "Invalid shared campaign payload reference." 953 985 msgstr "" 954 986 955 #: includes/class-customer-email-notify.php:25 51987 #: includes/class-customer-email-notify.php:2574 956 988 msgid "Shared campaign content is missing or invalid." 957 989 msgstr "" 958 990 959 #: includes/class-customer-email-notify.php:25 62991 #: includes/class-customer-email-notify.php:2585 960 992 msgid "Shared campaign content failed its integrity check." 961 993 msgstr "" 962 994 963 #: includes/class-customer-email-notify.php:2591 995 #: includes/class-customer-email-notify.php:2603 996 msgid "Confirmed recipient context is unavailable. No email was handed off." 997 msgstr "" 998 999 #: includes/class-customer-email-notify.php:2625 964 1000 msgid "Email job metadata is too large for Action Scheduler. Campaign content must use shared payload storage." 965 1001 msgstr "" 966 1002 967 #: includes/class-customer-email-notify.php:26 021003 #: includes/class-customer-email-notify.php:2636 968 1004 msgid "Scheduled timestamp is not in the future." 969 1005 msgstr "" 970 1006 971 #: includes/class-customer-email-notify.php:26 221007 #: includes/class-customer-email-notify.php:2656 972 1008 msgid "as_schedule_single_action returned an empty action id" 973 1009 msgstr "" 974 1010 975 #: includes/class-customer-email-notify.php:26 331011 #: includes/class-customer-email-notify.php:2667 976 1012 msgid "wp_schedule_single_event returned false" 977 1013 msgstr "" 978 1014 979 #: includes/class-customer-email-notify.php:26 441015 #: includes/class-customer-email-notify.php:2678 980 1016 msgid "Action Scheduler is unavailable." 981 1017 msgstr "" 982 1018 983 #: includes/class-customer-email-notify.php:26 561019 #: includes/class-customer-email-notify.php:2690 984 1020 msgid "as_enqueue_async_action returned an empty action id" 985 1021 msgstr "" 986 1022 987 #: includes/class-customer-email-notify.php:2 6981023 #: includes/class-customer-email-notify.php:2732 988 1024 msgid "The exclusion list contains an invalid email address. Correct it before previewing." 989 1025 msgstr "" 990 1026 991 #: includes/class-customer-email-notify.php:27 021027 #: includes/class-customer-email-notify.php:2736 992 1028 msgid "A selected product is invalid or unavailable. Review the selection." 993 1029 msgstr "" 994 1030 995 #: includes/class-customer-email-notify.php:27 051031 #: includes/class-customer-email-notify.php:2739 996 1032 msgid "An excluded order status is invalid." 997 1033 msgstr "" 998 1034 999 #: includes/class-customer-email-notify.php:27 241000 #: includes/class-customer-email-notify.php:4 2891035 #: includes/class-customer-email-notify.php:2758 1036 #: includes/class-customer-email-notify.php:4330 1001 1037 msgid "Please choose a valid recipient source." 1002 1038 msgstr "" 1003 1039 1004 #: includes/class-customer-email-notify.php:27 281040 #: includes/class-customer-email-notify.php:2762 1005 1041 msgid "Please choose a valid send time option." 1006 1042 msgstr "" 1007 1043 1008 #: includes/class-customer-email-notify.php:27 321044 #: includes/class-customer-email-notify.php:2766 1009 1045 msgid "Selected products apply only to Product customers. Clear the products or choose that recipient source before previewing." 1010 1046 msgstr "" 1011 1047 1012 #: includes/class-customer-email-notify.php:27 351048 #: includes/class-customer-email-notify.php:2769 1013 1049 msgid "Selected roles apply only to registered users. Clear the roles or choose that recipient source before previewing." 1014 1050 msgstr "" 1015 1051 1016 #: includes/class-customer-email-notify.php:27 381052 #: includes/class-customer-email-notify.php:2772 1017 1053 msgid "The pasted email list applies only to Manual email list. Clear the list or choose that recipient source before previewing." 1018 1054 msgstr "" 1019 1055 1020 #: includes/class-customer-email-notify.php:27 471056 #: includes/class-customer-email-notify.php:2781 1021 1057 msgid "Please enter a valid scheduled date/time." 1022 1058 msgstr "" 1023 1059 1024 #: includes/class-customer-email-notify.php:27 521060 #: includes/class-customer-email-notify.php:2786 1025 1061 msgid "Missing required fields." 1026 1062 msgstr "" 1027 1063 1028 #: includes/class-customer-email-notify.php:2 7681064 #: includes/class-customer-email-notify.php:2802 1029 1065 msgid "Please select at least one product." 1030 1066 msgstr "" 1031 1067 1032 #: includes/class-customer-email-notify.php:2 8731068 #: includes/class-customer-email-notify.php:2908 1033 1069 msgid "Missing email preview token." 1034 1070 msgstr "" 1035 1071 1036 1072 #. translators: %s: Formatted number of items. 1037 #: includes/class-customer-email-notify.php:29 461073 #: includes/class-customer-email-notify.php:2981 1038 1074 msgid "%s item" 1039 1075 msgid_plural "%s items" … … 1041 1077 msgstr[1] "" 1042 1078 1043 #: includes/class-customer-email-notify.php:29 561079 #: includes/class-customer-email-notify.php:2991 1044 1080 msgid "First page" 1045 1081 msgstr "" 1046 1082 1047 #: includes/class-customer-email-notify.php:29 571083 #: includes/class-customer-email-notify.php:2992 1048 1084 msgid "Previous page" 1049 1085 msgstr "" 1050 1086 1051 #: includes/class-customer-email-notify.php:29 611087 #: includes/class-customer-email-notify.php:2996 1052 1088 msgid "Current page" 1053 1089 msgstr "" 1054 1090 1055 #: includes/class-customer-email-notify.php: 29731091 #: includes/class-customer-email-notify.php:3008 1056 1092 msgid "of" 1057 1093 msgstr "" 1058 1094 1059 #: includes/class-customer-email-notify.php: 29781095 #: includes/class-customer-email-notify.php:3013 1060 1096 msgid "Next page" 1061 1097 msgstr "" 1062 1098 1063 #: includes/class-customer-email-notify.php: 29791099 #: includes/class-customer-email-notify.php:3014 1064 1100 msgid "Last page" 1065 1101 msgstr "" 1066 1102 1067 #: includes/class-customer-email-notify.php:3 0981103 #: includes/class-customer-email-notify.php:3133 1068 1104 msgid "Recovered campaign content. Only stored recipients and existing jobs can continue. The original audience may be incomplete; review recipient records before creating another campaign." 1069 1105 msgstr "" 1070 1106 1071 #: includes/class-customer-email-notify.php:3 2891107 #: includes/class-customer-email-notify.php:3324 1072 1108 msgid "Missing campaign ID." 1073 1109 msgstr "" 1074 1110 1075 #: includes/class-customer-email-notify.php:33 581111 #: includes/class-customer-email-notify.php:3393 1076 1112 msgid "Missing campaign content needed for rescheduling." 1077 1113 msgstr "" 1078 1114 1079 #: includes/class-customer-email-notify.php:3 5751080 #: includes/class-customer-email-notify.php:3 5761115 #: includes/class-customer-email-notify.php:3611 1116 #: includes/class-customer-email-notify.php:3612 1081 1117 #: includes/trait-campaign-controls.php:173 1082 1118 msgid "Paused" 1083 1119 msgstr "" 1084 1120 1085 #: includes/class-customer-email-notify.php:3 5771121 #: includes/class-customer-email-notify.php:3613 1086 1122 msgid "Waiting for site limit" 1087 1123 msgstr "" 1088 1124 1089 #: includes/class-customer-email-notify.php:3 5781125 #: includes/class-customer-email-notify.php:3614 1090 1126 msgid "Saving recipient snapshot" 1091 1127 msgstr "" 1092 1128 1093 #: includes/class-customer-email-notify.php:3 5791129 #: includes/class-customer-email-notify.php:3615 1094 1130 msgid "Needs attention" 1095 1131 msgstr "" 1096 1132 1097 #: includes/class-customer-email-notify.php:3 5801133 #: includes/class-customer-email-notify.php:3616 1098 1134 msgid "Previewed" 1099 1135 msgstr "" 1100 1136 1101 #: includes/class-customer-email-notify.php:3 5811137 #: includes/class-customer-email-notify.php:3617 1102 1138 msgid "Testing" 1103 1139 msgstr "" 1104 1140 1105 #: includes/class-customer-email-notify.php:3 5821141 #: includes/class-customer-email-notify.php:3618 1106 1142 msgid "Test handed to mail system" 1107 1143 msgstr "" 1108 1144 1109 #: includes/class-customer-email-notify.php:3 5831145 #: includes/class-customer-email-notify.php:3619 1110 1146 msgid "Test failed" 1111 1147 msgstr "" 1112 1148 1113 #: includes/class-customer-email-notify.php:3 5841149 #: includes/class-customer-email-notify.php:3620 1114 1150 msgid "Queueing" 1115 1151 msgstr "" 1116 1152 1117 #: includes/class-customer-email-notify.php:3 5851153 #: includes/class-customer-email-notify.php:3621 1118 1154 msgid "Preparing in background" 1119 1155 msgstr "" 1120 1156 1121 #: includes/class-customer-email-notify.php:3 5861157 #: includes/class-customer-email-notify.php:3622 1122 1158 msgid "Preparing" 1123 1159 msgstr "" 1124 1160 1125 #: includes/class-customer-email-notify.php:3 5871161 #: includes/class-customer-email-notify.php:3623 1126 1162 #: includes/trait-campaign-controls.php:173 1127 1163 msgid "Queued" 1128 1164 msgstr "" 1129 1165 1130 #: includes/class-customer-email-notify.php:3 5881166 #: includes/class-customer-email-notify.php:3624 1131 1167 #: includes/trait-campaign-controls.php:173 1132 1168 msgid "Queue failed" 1133 1169 msgstr "" 1134 1170 1135 #: includes/class-customer-email-notify.php:3 5891171 #: includes/class-customer-email-notify.php:3625 1136 1172 msgid "Scheduling" 1137 1173 msgstr "" 1138 1174 1139 #: includes/class-customer-email-notify.php:3 5901175 #: includes/class-customer-email-notify.php:3626 1140 1176 #: includes/trait-campaign-controls.php:173 1141 1177 msgid "Scheduled" 1142 1178 msgstr "" 1143 1179 1144 #: includes/class-customer-email-notify.php:3 5911180 #: includes/class-customer-email-notify.php:3627 1145 1181 #: includes/trait-campaign-controls.php:173 1146 1182 msgid "Schedule failed" 1147 1183 msgstr "" 1148 1184 1149 #: includes/class-customer-email-notify.php:3 5921150 #: includes/class-customer-email-notify.php:46 271185 #: includes/class-customer-email-notify.php:3628 1186 #: includes/class-customer-email-notify.php:4674 1151 1187 #: includes/trait-campaign-controls.php:140 1152 1188 #: includes/trait-campaign-controls.php:173 … … 1154 1190 msgstr "" 1155 1191 1156 #: includes/class-customer-email-notify.php:3 5931157 #: includes/class-customer-email-notify.php:46 291192 #: includes/class-customer-email-notify.php:3629 1193 #: includes/class-customer-email-notify.php:4676 1158 1194 msgid "Completed" 1159 1195 msgstr "" 1160 1196 1161 #: includes/class-customer-email-notify.php:3 5941197 #: includes/class-customer-email-notify.php:3630 1162 1198 msgid "Completed with issues" 1163 1199 msgstr "" 1164 1200 1165 #: includes/class-customer-email-notify.php:3 5951166 #: includes/trait-campaign-audiences.php:1 521201 #: includes/class-customer-email-notify.php:3631 1202 #: includes/trait-campaign-audiences.php:161 1167 1203 #: includes/trait-campaign-controls.php:138 1168 1204 #: includes/trait-campaign-controls.php:173 … … 1170 1206 msgstr "" 1171 1207 1172 #: includes/class-customer-email-notify.php:3 5961173 #: includes/class-customer-email-notify.php:46 321208 #: includes/class-customer-email-notify.php:3632 1209 #: includes/class-customer-email-notify.php:4679 1174 1210 #: includes/trait-campaign-controls.php:141 1175 1211 #: includes/trait-campaign-controls.php:173 … … 1177 1213 msgstr "" 1178 1214 1179 #: includes/class-customer-email-notify.php:3 5971215 #: includes/class-customer-email-notify.php:3633 1180 1216 msgid "Skipped" 1181 1217 msgstr "" 1182 1218 1183 #: includes/class-customer-email-notify.php:3 5981219 #: includes/class-customer-email-notify.php:3634 1184 1220 msgid "Skipped unsubscribed" 1185 1221 msgstr "" 1186 1222 1187 #: includes/class-customer-email-notify.php:3 5991223 #: includes/class-customer-email-notify.php:3635 1188 1224 msgid "Skipped duplicate" 1189 1225 msgstr "" 1190 1226 1191 #: includes/class-customer-email-notify.php:36 011227 #: includes/class-customer-email-notify.php:3637 1192 1228 msgid "Duplicate blocked" 1193 1229 msgstr "" 1194 1230 1195 #: includes/class-customer-email-notify.php:36 021231 #: includes/class-customer-email-notify.php:3638 1196 1232 msgid "No recipients" 1197 1233 msgstr "" 1198 1234 1199 #: includes/class-customer-email-notify.php:36 031200 #: includes/class-customer-email-notify.php:46 301235 #: includes/class-customer-email-notify.php:3639 1236 #: includes/class-customer-email-notify.php:4677 1201 1237 #: includes/trait-campaign-controls.php:173 1202 1238 msgid "Cancelled" 1203 1239 msgstr "" 1204 1240 1205 #: includes/class-customer-email-notify.php:36 041241 #: includes/class-customer-email-notify.php:3640 1206 1242 msgid "Unresolved" 1207 1243 msgstr "" 1208 1244 1209 #: includes/class-customer-email-notify.php:36 051245 #: includes/class-customer-email-notify.php:3641 1210 1246 msgid "Outcome unknown" 1211 1247 msgstr "" 1212 1248 1213 1249 #. translators: 1: Final number of recipients. 2: Excluded recipients. 3: Initial recipients. 1214 #: includes/class-customer-email-notify.php:36 401250 #: includes/class-customer-email-notify.php:3676 1215 1251 msgid "%1$d recipient(s), %2$d excluded from %3$d" 1216 1252 msgstr "" 1217 1253 1218 1254 #. translators: %d: Number of recipients. 1219 #: includes/class-customer-email-notify.php:36 481255 #: includes/class-customer-email-notify.php:3684 1220 1256 msgid "%d recipient(s)" 1221 1257 msgstr "" 1222 1258 1223 #: includes/class-customer-email-notify.php:36 541259 #: includes/class-customer-email-notify.php:3690 1224 1260 msgid "Recipient location estimate / UTC fallback" 1225 1261 msgstr "" 1226 1262 1227 #: includes/class-customer-email-notify.php:36 561263 #: includes/class-customer-email-notify.php:3692 1228 1264 msgid "Test email only" 1229 1265 msgstr "" 1230 1266 1231 1267 #. translators: %s: Scheduled local date and time. 1232 #: includes/class-customer-email-notify.php:3 6651268 #: includes/class-customer-email-notify.php:3701 1233 1269 msgid "Scheduled: %s by recipient timezone" 1234 1270 msgstr "" 1235 1271 1236 1272 #. translators: %s: Scheduled local date and time. 1237 #: includes/class-customer-email-notify.php:3 6661273 #: includes/class-customer-email-notify.php:3702 1238 1274 msgid "selected time" 1239 1275 msgstr "" 1240 1276 1241 #: includes/class-customer-email-notify.php:3 6701242 #: includes/trait-campaign-authoring.php:2 221277 #: includes/class-customer-email-notify.php:3706 1278 #: includes/trait-campaign-authoring.php:232 1243 1279 msgid "After confirmation" 1244 1280 msgstr "" 1245 1281 1246 #: includes/class-customer-email-notify.php:37 291282 #: includes/class-customer-email-notify.php:3765 1247 1283 msgid "No activity yet" 1248 1284 msgstr "" 1249 1285 1250 #: includes/class-customer-email-notify.php:4254 1286 #: includes/class-customer-email-notify.php:4290 1287 msgid "Subscribed email addresses" 1288 msgstr "" 1289 1290 #: includes/class-customer-email-notify.php:4291 1291 #: includes/trait-campaign-entrypoints.php:72 1292 msgid "Selected orders" 1293 msgstr "" 1294 1295 #: includes/class-customer-email-notify.php:4293 1251 1296 msgid "WooCommerce customers" 1252 1297 msgstr "" 1253 1298 1254 #: includes/class-customer-email-notify.php:42 551299 #: includes/class-customer-email-notify.php:4294 1255 1300 msgid "All registered users" 1256 1301 msgstr "" 1257 1302 1258 #: includes/class-customer-email-notify.php:42 561303 #: includes/class-customer-email-notify.php:4295 1259 1304 msgid "Manual email list" 1260 1305 msgstr "" 1261 1306 1262 #: includes/class-customer-email-notify.php:42711263 1307 #: includes/class-customer-email-notify.php:4310 1308 #: includes/class-customer-email-notify.php:4351 1264 1309 msgid "Please enter a list of valid email addresses." 1265 1310 msgstr "" 1266 1311 1267 #: includes/class-customer-email-notify.php:4 2761312 #: includes/class-customer-email-notify.php:4315 1268 1313 msgid "The recipient list contains an invalid email address. Correct the list before continuing." 1269 1314 msgstr "" 1270 1315 1271 #: includes/class-customer-email-notify.php:4 2941316 #: includes/class-customer-email-notify.php:4335 1272 1317 msgid "Please choose valid user roles." 1273 1318 msgstr "" 1274 1319 1275 #: includes/class-customer-email-notify.php:4 2991320 #: includes/class-customer-email-notify.php:4340 1276 1321 msgid "A selected user role is unavailable. Review the recipient selection before continuing." 1277 1322 msgstr "" 1278 1323 1279 #: includes/class-customer-email-notify.php:43 061324 #: includes/class-customer-email-notify.php:4347 1280 1325 msgid "Please enter at least one recipient email address." 1281 1326 msgstr "" 1282 1327 1283 #: includes/class-customer-email-notify.php:43 311328 #: includes/class-customer-email-notify.php:4372 1284 1329 msgid "Previously unsubscribed email addresses" 1285 1330 msgstr "" 1286 1331 1287 #: includes/class-customer-email-notify.php:46 101332 #: includes/class-customer-email-notify.php:4657 1288 1333 msgid "Do not want to receive these campaign emails?" 1289 1334 msgstr "" 1290 1335 1291 #: includes/class-customer-email-notify.php:4612 1336 #: includes/class-customer-email-notify.php:4659 1337 #: includes/trait-campaign-subscriptions.php:125 1292 1338 msgid "Unsubscribe" 1293 1339 msgstr "" 1294 1340 1295 #: includes/class-customer-email-notify.php:46 261341 #: includes/class-customer-email-notify.php:4673 1296 1342 msgid "Pending payment" 1297 1343 msgstr "" 1298 1344 1299 #: includes/class-customer-email-notify.php:46 281345 #: includes/class-customer-email-notify.php:4675 1300 1346 msgid "On hold" 1301 1347 msgstr "" 1302 1348 1303 #: includes/class-customer-email-notify.php:46 311349 #: includes/class-customer-email-notify.php:4678 1304 1350 msgid "Refunded" 1305 1351 msgstr "" 1306 1352 1307 1353 #. translators: %s: Comma-separated order status labels. 1308 #: includes/class-customer-email-notify.php:4 6931354 #: includes/class-customer-email-notify.php:4740 1309 1355 msgid "Order statuses: %s" 1310 1356 msgstr "" 1311 1357 1312 1358 #. translators: %s: Comma-separated product names. 1313 #: includes/class-customer-email-notify.php:47 021359 #: includes/class-customer-email-notify.php:4749 1314 1360 msgid "Purchased products: %s" 1315 1361 msgstr "" 1316 1362 1317 1363 #. translators: %d: Number of excluded email addresses. 1318 #: includes/class-customer-email-notify.php:47 111364 #: includes/class-customer-email-notify.php:4758 1319 1365 msgid "Manual emails: %d address" 1320 1366 msgid_plural "Manual emails: %d addresses" … … 1322 1368 msgstr[1] "" 1323 1369 1324 #: includes/class-customer-email-notify.php:4 8841370 #: includes/class-customer-email-notify.php:4931 1325 1371 msgid "Missing required email content. Repair campaign data before retrying." 1326 1372 msgstr "" 1327 1373 1328 #: includes/class-customer-email-notify.php:4892 1374 #: includes/class-customer-email-notify.php:4941 1375 msgid "No active subscription before send." 1376 msgstr "" 1377 1378 #: includes/class-customer-email-notify.php:4949 1329 1379 msgid "Recipient unsubscribed before send." 1330 1380 msgstr "" 1331 1381 1332 #: includes/class-customer-email-notify.php:4 8991382 #: includes/class-customer-email-notify.php:4957 1333 1383 msgid "Mail system accepted the request; inbox delivery is not verified." 1334 1384 msgstr "" 1335 1385 1336 #: includes/class-customer-email-notify.php:4 8991386 #: includes/class-customer-email-notify.php:4957 1337 1387 msgid "Mail transport returned no confirmation. Check the mail provider before sending again." 1338 1388 msgstr "" 1339 1389 1340 #: includes/class-customer-email-notify.php:49 191390 #: includes/class-customer-email-notify.php:4977 1341 1391 msgid "Preserved a pre-upgrade delivery claim. Check the mail provider for unknown outcomes." 1342 1392 msgstr "" 1343 1393 1344 1394 #. translators: %d: Product ID. 1345 #: includes/class-customer-email-notify.php:51 311395 #: includes/class-customer-email-notify.php:5192 1346 1396 msgid "Product #%d" 1347 1397 msgstr "" 1348 1398 1349 #: includes/class-customer-email-notify.php:5 1551399 #: includes/class-customer-email-notify.php:5216 1350 1400 msgid "WooCommerce email template is unavailable." 1351 1401 msgstr "" 1352 1402 1353 #: includes/class-customer-email-notify.php:5 2411403 #: includes/class-customer-email-notify.php:5303 1354 1404 msgid "WooCommerce mailer is unavailable." 1355 1405 msgstr "" 1356 1406 1357 #: includes/class-customer-email-notify.php:5246 1407 #: includes/class-customer-email-notify.php:5308 1408 msgid "The sample was erased before test mail handoff." 1409 msgstr "" 1410 1411 #: includes/class-customer-email-notify.php:5318 1412 msgid "No active subscription before mail handoff." 1413 msgstr "" 1414 1415 #: includes/class-customer-email-notify.php:5323 1358 1416 msgid "Recipient unsubscribed before mail handoff." 1359 1417 msgstr "" 1360 1418 1361 1419 #: includes/trait-campaign-audiences.php:21 1362 msgid "Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country and campaign history; no condition has been ignored."1363 msgstr "" 1364 1365 #: includes/trait-campaign-audiences.php:1 271420 msgid "Invalid or inapplicable audience conditions. Review source, dates, statuses, category, country, purchase history and campaign history; no condition has been ignored." 1421 msgstr "" 1422 1423 #: includes/trait-campaign-audiences.php:134 1366 1424 msgid "Unavailable selection; remove or replace:" 1367 1425 msgstr "" 1368 1426 1369 #: includes/trait-campaign-audiences.php:1 331427 #: includes/trait-campaign-audiences.php:142 1370 1428 msgid "Saved conditions are invalid or unavailable. They remain selected; correct or explicitly remove them before previewing." 1371 1429 msgstr "" 1372 1430 1373 #: includes/trait-campaign-audiences.php:1 341431 #: includes/trait-campaign-audiences.php:143 1374 1432 msgid "Audience conditions" 1375 1433 msgstr "" 1376 1434 1377 #: includes/trait-campaign-audiences.php:1 351435 #: includes/trait-campaign-audiences.php:144 1378 1436 msgid "Order created from (store timezone)" 1379 1437 msgstr "" 1380 1438 1381 #: includes/trait-campaign-audiences.php:1 351439 #: includes/trait-campaign-audiences.php:144 1382 1440 msgid "Through date (inclusive)" 1383 1441 msgstr "" 1384 1442 1385 #: includes/trait-campaign-audiences.php:1 351443 #: includes/trait-campaign-audiences.php:144 1386 1444 msgid "Or last N × 24 hours" 1387 1445 msgstr "" 1388 1446 1389 #: includes/trait-campaign-audiences.php:1 361390 msgid "Matching order statuses ( defaultprocessing/completed)"1391 msgstr "" 1392 1393 #: includes/trait-campaign-audiences.php:1 391447 #: includes/trait-campaign-audiences.php:145 1448 msgid "Matching order statuses (selected orders: all; other sources: processing/completed)" 1449 msgstr "" 1450 1451 #: includes/trait-campaign-audiences.php:148 1394 1452 msgid "Categories (includes all descendants)" 1395 1453 msgstr "" 1396 1454 1397 #: includes/trait-campaign-audiences.php:1 461398 #: includes/trait-campaign-audiences.php:1 581455 #: includes/trait-campaign-audiences.php:155 1456 #: includes/trait-campaign-audiences.php:167 1399 1457 msgid "Subscription status" 1400 1458 msgstr "" 1401 1459 1402 #: includes/trait-campaign-audiences.php:1 471460 #: includes/trait-campaign-audiences.php:156 1403 1461 msgid "Any (suppression still applies)" 1404 1462 msgstr "" 1405 1463 1406 #: includes/trait-campaign-audiences.php:147 1407 #: includes/trait-campaign-privacy.php:127 1464 #: includes/trait-campaign-audiences.php:156 1465 #: includes/trait-campaign-contact-history.php:66 1466 #: includes/trait-campaign-privacy.php:128 1467 #: includes/trait-campaign-subscriptions.php:118 1408 1468 msgid "Subscribed" 1409 1469 msgstr "" 1410 1470 1411 #: includes/trait-campaign-audiences.php:1 471471 #: includes/trait-campaign-audiences.php:156 1412 1472 msgid "No confirmation recorded" 1413 1473 msgstr "" 1414 1474 1415 #: includes/trait-campaign-audiences.php:1 471475 #: includes/trait-campaign-audiences.php:156 1416 1476 msgid "Unsubscribed (excluded from sending)" 1417 1477 msgstr "" 1418 1478 1419 #: includes/trait-campaign-audiences.php:1 481479 #: includes/trait-campaign-audiences.php:157 1420 1480 msgid "Campaign history" 1421 1481 msgstr "" 1422 1482 1423 #: includes/trait-campaign-audiences.php:1 511483 #: includes/trait-campaign-audiences.php:160 1424 1484 msgid "History outcome" 1425 1485 msgstr "" 1426 1486 1427 #: includes/trait-campaign-audiences.php:1 521487 #: includes/trait-campaign-audiences.php:161 1428 1488 msgid "Known unsent terminal outcome" 1429 1489 msgstr "" 1430 1490 1431 #: includes/trait-campaign-audiences.php:1 531491 #: includes/trait-campaign-audiences.php:162 1432 1492 msgid "Durable opt-outs always apply. Orders and accounts do not establish opt-in." 1433 1493 msgstr "" 1434 1494 1435 #: includes/trait-campaign-audiences.php:1 531495 #: includes/trait-campaign-audiences.php:162 1436 1496 msgid "How audience conditions match" 1437 1497 msgstr "" 1438 1498 1439 #: includes/trait-campaign-audiences.php:1 531499 #: includes/trait-campaign-audiences.php:162 1440 1500 msgid "Order filters use order creation time in the store timezone and match on one order, including product/variation, status and billing country. Categories include descendants and use current product categories. Registered users use profile billing country; manual lists have no country. Missing data fails the condition. History uses handoff only: unknown, pending and missing history never qualify as known unsent. Existing exclusions and durable opt-outs apply last." 1441 1501 msgstr "" 1442 1502 1443 #: includes/trait-campaign-audiences.php:158 1503 #: includes/trait-campaign-audiences.php:167 1504 msgid "Store-wide purchase frequency" 1505 msgstr "" 1506 1507 #: includes/trait-campaign-audiences.php:167 1508 msgid "Days without a valid store-wide purchase" 1509 msgstr "" 1510 1511 #: includes/trait-campaign-audiences.php:167 1444 1512 msgid "Order created from" 1445 1513 msgstr "" 1446 1514 1447 #: includes/trait-campaign-audiences.php:1 581515 #: includes/trait-campaign-audiences.php:167 1448 1516 msgid "Through date" 1449 1517 msgstr "" 1450 1518 1451 #: includes/trait-campaign-audiences.php:1 581519 #: includes/trait-campaign-audiences.php:167 1452 1520 msgid "Last N days" 1453 1521 msgstr "" 1454 1522 1455 #: includes/trait-campaign-audiences.php:1 581523 #: includes/trait-campaign-audiences.php:167 1456 1524 msgid "History campaign" 1457 1525 msgstr "" 1458 1526 1459 #: includes/trait-campaign-audiences.php:1 581527 #: includes/trait-campaign-audiences.php:167 1460 1528 msgid "Handoff condition" 1461 1529 msgstr "" 1462 1530 1463 #: includes/trait-campaign-audiences.php:1 581531 #: includes/trait-campaign-audiences.php:167 1464 1532 msgid "Categories including descendants" 1465 1533 msgstr "" 1466 1534 1467 #: includes/trait-campaign-audiences.php:1 581535 #: includes/trait-campaign-audiences.php:167 1468 1536 msgid "Matching order statuses" 1469 1537 msgstr "" 1470 1538 1471 #: includes/trait-campaign-audiences.php:159 1539 #: includes/trait-campaign-audiences.php:168 1540 #: includes/trait-campaign-authoring.php:238 1541 msgid "Saved audience conditions" 1542 msgstr "" 1543 1544 #: includes/trait-campaign-audiences.php:171 1545 #: includes/trait-campaign-purchase-history.php:54 1546 msgid "First-time buyer (one valid order)" 1547 msgstr "" 1548 1549 #: includes/trait-campaign-audiences.php:171 1550 #: includes/trait-campaign-purchase-history.php:54 1551 msgid "Repeat buyer (at least two valid orders)" 1552 msgstr "" 1553 1554 #: includes/trait-campaign-audiences.php:181 1555 msgid "Inspect an address against current criteria" 1556 msgstr "" 1557 1558 #: includes/trait-campaign-audiences.php:181 1559 msgid "Inspect" 1560 msgstr "" 1561 1562 #: includes/trait-campaign-audiences.php:187 1563 msgid "Not in the selected source or product purchasers." 1564 msgstr "" 1565 1566 #: includes/trait-campaign-audiences.php:188 1567 msgid "No single order matches all order conditions, or billing country is missing/different." 1568 msgstr "" 1569 1570 #: includes/trait-campaign-audiences.php:189 1571 msgid "Store-wide purchase history, subscription status or known campaign handoff condition does not match." 1572 msgstr "" 1573 1574 #: includes/trait-campaign-audiences.php:190 1575 msgid "Matched source and all conditions; removed by an explicit exclusion." 1576 msgstr "" 1577 1578 #: includes/trait-campaign-audiences.php:191 1579 msgid "Included: matches source and every applicable condition; no exclusion matched." 1580 msgstr "" 1581 1582 #: includes/trait-campaign-audiences.php:192 1583 msgid "Excluded: durable unsubscribe/suppression." 1584 msgstr "" 1585 1586 #: includes/trait-campaign-authoring.php:57 1587 msgid "Enter an audience name." 1588 msgstr "" 1589 1590 #: includes/trait-campaign-authoring.php:60 1591 msgid "Audience could not be saved." 1592 msgstr "" 1593 1594 #: includes/trait-campaign-authoring.php:86 1595 msgid "This draft changed or was deleted. Open it and create a new preview." 1596 msgstr "" 1597 1598 #: includes/trait-campaign-authoring.php:107 1599 msgid "Campaign content unavailable." 1600 msgstr "" 1601 1602 #: includes/trait-campaign-authoring.php:120 1603 msgid "Duplicate as new draft" 1604 msgstr "" 1605 1606 #: includes/trait-campaign-authoring.php:128 1607 msgid "Drafts" 1608 msgstr "" 1609 1610 #: includes/trait-campaign-authoring.php:128 1611 msgid "Drafts do not expire and never create delivery jobs." 1612 msgstr "" 1613 1614 #: includes/trait-campaign-authoring.php:130 1615 msgid "No saved drafts yet." 1616 msgstr "" 1617 1618 #: includes/trait-campaign-authoring.php:133 1619 msgid "Delete draft" 1620 msgstr "" 1621 1622 #: includes/trait-campaign-authoring.php:136 1623 #: includes/trait-campaign-authoring.php:150 1624 msgid "Saved audience criteria" 1625 msgstr "" 1626 1627 #: includes/trait-campaign-authoring.php:136 1628 msgid "Reusable rules, not a frozen recipient list. A new preview is required when reused." 1629 msgstr "" 1630 1631 #: includes/trait-campaign-authoring.php:138 1632 msgid "No saved audiences yet." 1633 msgstr "" 1634 1635 #: includes/trait-campaign-authoring.php:141 1636 msgid "Delete audience" 1637 msgstr "" 1638 1639 #: includes/trait-campaign-authoring.php:147 1640 msgid "Draft name (internal only)" 1641 msgstr "" 1642 1643 #: includes/trait-campaign-authoring.php:147 1644 msgid "Save draft" 1645 msgstr "" 1646 1647 #: includes/trait-campaign-authoring.php:147 1648 msgid "Drafts create no delivery jobs. Changes require a new preview." 1649 msgstr "" 1650 1651 #: includes/trait-campaign-authoring.php:154 1652 msgid "Open Library" 1653 msgstr "" 1654 1655 #: includes/trait-campaign-authoring.php:154 1656 msgid "Opening saved criteria replaces this form. Save your draft first to keep current edits." 1657 msgstr "" 1658 1659 #: includes/trait-campaign-authoring.php:154 1660 msgid "Audience name" 1661 msgstr "" 1662 1663 #: includes/trait-campaign-authoring.php:154 1664 msgid "Save audience criteria" 1665 msgstr "" 1666 1667 #: includes/trait-campaign-authoring.php:157 1668 msgid "Insert editable content template" 1669 msgstr "" 1670 1671 #: includes/trait-campaign-authoring.php:159 1672 msgid "Product or documentation update" 1673 msgstr "" 1674 1675 #: includes/trait-campaign-authoring.php:159 1676 msgid "An update for you" 1677 msgstr "" 1678 1679 #: includes/trait-campaign-authoring.php:159 1680 msgid "<p>Hello {customer_name},</p><p>We have updated {product_name}. Describe what changed, when it applies, and add the documentation link and any action needed. Contact our support team if you need help.</p>" 1681 msgstr "" 1682 1683 #: includes/trait-campaign-authoring.php:160 1684 msgid "After-purchase guide" 1685 msgstr "" 1686 1687 #: includes/trait-campaign-authoring.php:160 1688 msgid "Getting started" 1689 msgstr "" 1690 1691 #: includes/trait-campaign-authoring.php:160 1692 msgid "<p>Hello {customer_name},</p><p>Thank you for your purchase of {ordered_products} (order {order_number}). Add setup or care steps, when to follow them, and a support contact here.</p>" 1693 msgstr "" 1694 1695 #: includes/trait-campaign-authoring.php:161 1696 msgid "Service or order change" 1697 msgstr "" 1698 1699 #: includes/trait-campaign-authoring.php:161 1700 msgid "Service update" 1701 msgstr "" 1702 1703 #: includes/trait-campaign-authoring.php:161 1704 msgid "<p>Hello {customer_name},</p><p>An update about order {order_number}: describe the change and the new delivery date or effective time. Explain any action needed and add a support contact here.</p>" 1705 msgstr "" 1706 1707 #: includes/trait-campaign-authoring.php:197 1708 msgid "At least one recipient has a past, nonexistent or repeated local time. Choose a later, unambiguous time and preview again. No date was shifted." 1709 msgstr "" 1710 1711 #: includes/trait-campaign-authoring.php:220 1712 msgid "Preview width" 1713 msgstr "" 1714 1715 #: includes/trait-campaign-authoring.php:221 1716 msgid "Desktop" 1717 msgstr "" 1718 1719 #: includes/trait-campaign-authoring.php:221 1720 msgid "Mobile" 1721 msgstr "" 1722 1723 #: includes/trait-campaign-authoring.php:227 1724 msgid "Audience changed since preview. Review this updated preview and confirm again." 1725 msgstr "" 1726 1472 1727 #: includes/trait-campaign-authoring.php:228 1473 msgid "Saved audience conditions"1474 msgstr ""1475 1476 #: includes/trait-campaign-audiences.php:1711477 msgid "Inspect an address against current criteria"1478 msgstr ""1479 1480 #: includes/trait-campaign-audiences.php:1711481 msgid "Inspect"1482 msgstr ""1483 1484 #: includes/trait-campaign-audiences.php:1771485 msgid "Not in the selected source or product purchasers."1486 msgstr ""1487 1488 #: includes/trait-campaign-audiences.php:1781489 msgid "No single order matches all order conditions, or billing country is missing/different."1490 msgstr ""1491 1492 #: includes/trait-campaign-audiences.php:1791493 msgid "Subscription status or known campaign handoff condition does not match."1494 msgstr ""1495 1496 #: includes/trait-campaign-audiences.php:1801497 msgid "Matched source and all conditions; removed by an explicit exclusion."1498 msgstr ""1499 1500 #: includes/trait-campaign-audiences.php:1811501 msgid "Included: matches source and every applicable condition; no exclusion matched."1502 msgstr ""1503 1504 #: includes/trait-campaign-audiences.php:1821505 msgid "Excluded: durable unsubscribe/suppression."1506 msgstr ""1507 1508 #: includes/trait-campaign-authoring.php:531509 msgid "Enter an audience name."1510 msgstr ""1511 1512 #: includes/trait-campaign-authoring.php:561513 msgid "Audience could not be saved."1514 msgstr ""1515 1516 #: includes/trait-campaign-authoring.php:761517 msgid "This draft changed or was deleted. Open it and create a new preview."1518 msgstr ""1519 1520 #: includes/trait-campaign-authoring.php:971521 msgid "Campaign content unavailable."1522 msgstr ""1523 1524 #: includes/trait-campaign-authoring.php:1101525 msgid "Duplicate as new draft"1526 msgstr ""1527 1528 #: includes/trait-campaign-authoring.php:1181529 msgid "Drafts"1530 msgstr ""1531 1532 #: includes/trait-campaign-authoring.php:1181533 msgid "Drafts do not expire and never create delivery jobs."1534 msgstr ""1535 1536 #: includes/trait-campaign-authoring.php:1201537 msgid "No saved drafts yet."1538 msgstr ""1539 1540 #: includes/trait-campaign-authoring.php:1231541 msgid "Delete draft"1542 msgstr ""1543 1544 #: includes/trait-campaign-authoring.php:1261545 #: includes/trait-campaign-authoring.php:1401546 msgid "Saved audience criteria"1547 msgstr ""1548 1549 #: includes/trait-campaign-authoring.php:1261550 msgid "Reusable rules, not a frozen recipient list. A new preview is required when reused."1551 msgstr ""1552 1553 #: includes/trait-campaign-authoring.php:1281554 msgid "No saved audiences yet."1555 msgstr ""1556 1557 #: includes/trait-campaign-authoring.php:1311558 msgid "Delete audience"1559 msgstr ""1560 1561 #: includes/trait-campaign-authoring.php:1371562 msgid "Draft name (internal only)"1563 msgstr ""1564 1565 #: includes/trait-campaign-authoring.php:1371566 msgid "Save draft"1567 msgstr ""1568 1569 #: includes/trait-campaign-authoring.php:1371570 msgid "Drafts create no delivery jobs. Changes require a new preview."1571 msgstr ""1572 1573 #: includes/trait-campaign-authoring.php:1441574 msgid "Open Library"1575 msgstr ""1576 1577 #: includes/trait-campaign-authoring.php:1441578 msgid "Opening saved criteria replaces this form. Save your draft first to keep current edits."1579 msgstr ""1580 1581 #: includes/trait-campaign-authoring.php:1441582 msgid "Audience name"1583 msgstr ""1584 1585 #: includes/trait-campaign-authoring.php:1441586 msgid "Save audience criteria"1587 msgstr ""1588 1589 #: includes/trait-campaign-authoring.php:1471590 msgid "Insert editable content template"1591 msgstr ""1592 1593 #: includes/trait-campaign-authoring.php:1491594 msgid "Product or documentation update"1595 msgstr ""1596 1597 #: includes/trait-campaign-authoring.php:1491598 msgid "An update for you"1599 msgstr ""1600 1601 #: includes/trait-campaign-authoring.php:1491602 msgid "<p>Hello {customer_name},</p><p>We have updated {product_name}. Add the details and documentation link here.</p>"1603 msgstr ""1604 1605 #: includes/trait-campaign-authoring.php:1501606 msgid "After-purchase guide"1607 msgstr ""1608 1609 #: includes/trait-campaign-authoring.php:1501610 msgid "Getting started"1611 msgstr ""1612 1613 #: includes/trait-campaign-authoring.php:1501614 msgid "<p>Hello {customer_name},</p><p>Thank you for your purchase. Add setup steps and support details here.</p>"1615 msgstr ""1616 1617 #: includes/trait-campaign-authoring.php:1511618 msgid "Service or order change"1619 msgstr ""1620 1621 #: includes/trait-campaign-authoring.php:1511622 msgid "Service update"1623 msgstr ""1624 1625 #: includes/trait-campaign-authoring.php:1511626 msgid "<p>Hello {customer_name},</p><p>Add the change, effective date and any action needed here.</p>"1627 msgstr ""1628 1629 #: includes/trait-campaign-authoring.php:1871630 msgid "At least one recipient has a past, nonexistent or repeated local time. Choose a later, unambiguous time and preview again. No date was shifted."1631 msgstr ""1632 1633 #: includes/trait-campaign-authoring.php:2101634 msgid "Preview width"1635 msgstr ""1636 1637 #: includes/trait-campaign-authoring.php:2111638 msgid "Desktop"1639 msgstr ""1640 1641 #: includes/trait-campaign-authoring.php:2111642 msgid "Mobile"1643 msgstr ""1644 1645 #: includes/trait-campaign-authoring.php:2171646 msgid "Audience changed since preview. Review this updated preview and confirm again."1647 msgstr ""1648 1649 #: includes/trait-campaign-authoring.php:2181650 1728 msgid "Recipients and schedule to confirm" 1651 1729 msgstr "" 1652 1730 1653 #: includes/trait-campaign-authoring.php:2 181731 #: includes/trait-campaign-authoring.php:228 1654 1732 msgid "Selected" 1655 1733 msgstr "" 1656 1734 1657 #: includes/trait-campaign-authoring.php:2 191735 #: includes/trait-campaign-authoring.php:229 1658 1736 msgid "Removed by order conditions" 1659 1737 msgstr "" 1660 1738 1661 #: includes/trait-campaign-authoring.php:2 191662 msgid "Removed by subscription or campaign history"1663 msgstr "" 1664 1665 #: includes/trait-campaign-authoring.php:2 191739 #: includes/trait-campaign-authoring.php:229 1740 msgid "Removed by purchase history, subscription or campaign history" 1741 msgstr "" 1742 1743 #: includes/trait-campaign-authoring.php:229 1666 1744 msgid "Removed by exclusions or suppression" 1667 1745 msgstr "" 1668 1746 1669 #: includes/trait-campaign-authoring.php:2 221747 #: includes/trait-campaign-authoring.php:232 1670 1748 msgid "One time in store timezone" 1671 1749 msgstr "" 1672 1750 1673 #: includes/trait-campaign-authoring.php:2 221751 #: includes/trait-campaign-authoring.php:232 1674 1752 msgid "Legacy schedule" 1675 1753 msgstr "" 1676 1754 1677 #: includes/trait-campaign-authoring.php:2 231755 #: includes/trait-campaign-authoring.php:233 1678 1756 msgid "Schedule mode / store timezone" 1679 1757 msgstr "" 1680 1758 1681 #: includes/trait-campaign-authoring.php:2 261759 #: includes/trait-campaign-authoring.php:236 1682 1760 msgid "UTC fallback count" 1683 1761 msgstr "" 1684 1762 1685 #: includes/trait-campaign-authoring.php:2 261763 #: includes/trait-campaign-authoring.php:236 1686 1764 msgid "Earliest and latest due (UTC)" 1687 1765 msgstr "" 1688 1766 1689 #: includes/trait-campaign-authoring.php:2 301767 #: includes/trait-campaign-authoring.php:240 1690 1768 msgid "Inspect an address" 1691 1769 msgstr "" 1692 1770 1693 #: includes/trait-campaign-authoring.php:2 371694 #: includes/trait-campaign-authoring.php:2 441771 #: includes/trait-campaign-authoring.php:247 1772 #: includes/trait-campaign-authoring.php:257 1695 1773 msgid "Personalized email preview" 1696 1774 msgstr "" 1697 1775 1698 #: includes/trait-campaign-authoring.php:2 371776 #: includes/trait-campaign-authoring.php:247 1699 1777 msgid "Sample recipient (up to 20)" 1700 1778 msgstr "" 1701 1779 1702 #: includes/trait-campaign-authoring.php:2 391780 #: includes/trait-campaign-authoring.php:249 1703 1781 msgid "Show sample" 1782 msgstr "" 1783 1784 #: includes/trait-campaign-automation-ui.php:17 1785 msgid "Use the automation form." 1786 msgstr "" 1787 1788 #: includes/trait-campaign-automation-ui.php:19 1789 msgid "Choose a valid automation rule." 1790 msgstr "" 1791 1792 #: includes/trait-campaign-automation-ui.php:32 1793 msgid "Choose an available order ID for the sample." 1794 msgstr "" 1795 1796 #: includes/trait-campaign-automation-ui.php:38 1797 msgid "The test email could not be handed off. Check mail settings and try again." 1798 msgstr "" 1799 1800 #: includes/trait-campaign-automation-ui.php:47 1801 msgid "Choose a valid automation action." 1802 msgstr "" 1803 1804 #: includes/trait-campaign-automation-ui.php:66 1805 msgid "This automation rule is unavailable." 1806 msgstr "" 1807 1808 #: includes/trait-campaign-automation-ui.php:67 1809 msgid "Rule saved. New rules stay disabled until you choose Enable. Changes to enabled rules apply to new events only." 1810 msgstr "" 1811 1812 #: includes/trait-campaign-automation-ui.php:67 1813 msgid "Rule enabled for new Completed events. Historical orders were not queued." 1814 msgstr "" 1815 1816 #: includes/trait-campaign-automation-ui.php:67 1817 msgid "Rule disabled. Unstarted emails are cancelled; work already in flight may finish." 1818 msgstr "" 1819 1820 #: includes/trait-campaign-automation-ui.php:67 1821 msgid "Test mail handed to the mail system. No rule was saved or enabled. Inbox delivery is not verified." 1822 msgstr "" 1823 1824 #: includes/trait-campaign-automation-ui.php:67 1825 msgid "Sample refreshed. No rule was saved or enabled and no delivery job was created." 1826 msgstr "" 1827 1828 #: includes/trait-campaign-automation-ui.php:80 1829 msgid "Send a helpful guide after an order is completed. Enable uses the saved configuration." 1830 msgstr "" 1831 1832 #: includes/trait-campaign-automation-ui.php:80 1833 msgid "New rule" 1834 msgstr "" 1835 1836 #: includes/trait-campaign-automation-ui.php:81 1837 msgid "No rules yet. Build your first guide below, then enable it when you are ready." 1838 msgstr "" 1839 1840 #: includes/trait-campaign-automation-ui.php:84 1841 msgid "Enabled" 1842 msgstr "" 1843 1844 #: includes/trait-campaign-automation-ui.php:84 1845 msgid "Disabled" 1846 msgstr "" 1847 1848 #. translators: %d: Number of hours after the Completed event. 1849 #: includes/trait-campaign-automation-ui.php:84 1850 msgid "Completed → wait %d hours → send one guide" 1851 msgstr "" 1852 1853 #. translators: %d: Number of hours after the Completed event. 1854 #: includes/trait-campaign-automation-ui.php:84 1855 msgid "Saved configuration" 1856 msgstr "" 1857 1858 #. translators: %d: Number of hours after the Completed event. 1859 #: includes/trait-campaign-automation-ui.php:84 1860 msgid "All products" 1861 msgstr "" 1862 1863 #. translators: %d: Number of hours after the Completed event. 1864 #: includes/trait-campaign-automation-ui.php:84 1865 msgid "Categories" 1866 msgstr "" 1867 1868 #. translators: %d: Number of hours after the Completed event. 1869 #: includes/trait-campaign-automation-ui.php:84 1870 msgid "All categories" 1871 msgstr "" 1872 1873 #. translators: %d: Number of hours after the Completed event. 1874 #: includes/trait-campaign-automation-ui.php:85 1875 msgid "Edit rule" 1876 msgstr "" 1877 1878 #. translators: %d: Number of hours after the Completed event. 1879 #: includes/trait-campaign-automation-ui.php:85 1880 msgid "Disable and cancel waiting emails" 1881 msgstr "" 1882 1883 #. translators: %d: Number of hours after the Completed event. 1884 #: includes/trait-campaign-automation-ui.php:85 1885 msgid "Enable" 1886 msgstr "" 1887 1888 #: includes/trait-campaign-automation-ui.php:88 1889 msgid "View campaigns and delivery status" 1890 msgstr "" 1891 1892 #: includes/trait-campaign-automation-ui.php:88 1893 msgid "Look up a contact" 1894 msgstr "" 1895 1896 #: includes/trait-campaign-automation-ui.php:92 1897 msgid "Rule name (internal only)" 1898 msgstr "" 1899 1900 #: includes/trait-campaign-automation-ui.php:92 1901 #: includes/trait-campaign-automation-ui.php:119 1902 msgid "Save changes for new events" 1903 msgstr "" 1904 1905 #: includes/trait-campaign-automation-ui.php:92 1906 #: includes/trait-campaign-automation-ui.php:119 1907 msgid "Save rule" 1908 msgstr "" 1909 1910 #: includes/trait-campaign-automation-ui.php:92 1911 msgid "Waiting emails keep their confirmed content, order context and due time." 1912 msgstr "" 1913 1914 #: includes/trait-campaign-automation-ui.php:92 1915 msgid "Save your rule, then explicitly Enable it above. Saving alone never enables a new rule." 1916 msgstr "" 1917 1918 #: includes/trait-campaign-automation-ui.php:93 1919 msgid "Automation steps" 1920 msgstr "" 1921 1922 #: includes/trait-campaign-automation-ui.php:94 1923 msgid "1. Conditions" 1924 msgstr "" 1925 1926 #: includes/trait-campaign-automation-ui.php:94 1927 msgid "3. Timing" 1928 msgstr "" 1929 1930 #: includes/trait-campaign-automation-ui.php:97 1931 msgid "Conditions" 1932 msgstr "" 1933 1934 #: includes/trait-campaign-automation-ui.php:97 1935 msgid "Choose which completed orders should receive this guide." 1936 msgstr "" 1937 1938 #: includes/trait-campaign-automation-ui.php:98 1939 msgid "Trigger: order changes to Completed" 1940 msgstr "" 1941 1942 #: includes/trait-campaign-automation-ui.php:98 1943 msgid "Only new events after Enable are captured. There is no historical backfill. A customer with several qualifying orders can receive one guide for each order." 1944 msgstr "" 1945 1946 #: includes/trait-campaign-automation-ui.php:99 1947 msgid "Products or variations (empty means any)" 1948 msgstr "" 1949 1950 #: includes/trait-campaign-automation-ui.php:100 1951 msgid "Categories including descendants (empty means any)" 1952 msgstr "" 1953 1954 #: includes/trait-campaign-automation-ui.php:102 1955 msgid "Product and category conditions match the same order. Parent products include their variations; a selected variation matches only that variation." 1956 msgstr "" 1957 1958 #: includes/trait-campaign-automation-ui.php:103 1959 msgid "Eligibility and subscription" 1960 msgstr "" 1961 1962 #: includes/trait-campaign-automation-ui.php:103 1963 msgid "An active subscription is required at sending. Unknown is not consent. Unsubscribe and erasure protection always apply. The order must still be Completed, match its saved conditions and keep the same billing email. Cancelled, failed and fully refunded orders are skipped; partial refunds remain eligible while an amount remains." 1964 msgstr "" 1965 1966 #: includes/trait-campaign-automation-ui.php:106 1967 msgid "Write useful setup or care instructions for the purchased items." 1968 msgstr "" 1969 1970 #: includes/trait-campaign-automation-ui.php:107 1971 msgid "A guide for order {order_number}" 1972 msgstr "" 1973 1974 #: includes/trait-campaign-automation-ui.php:107 1975 msgid "Getting started with your purchase" 1976 msgstr "" 1977 1978 #: includes/trait-campaign-automation-ui.php:108 1979 msgid "<p>Hello {customer_name},</p><p>Thank you for purchasing {ordered_products}.</p><p>Before you start, check the setup instructions included with your order. Keep this email handy and contact our store if you need help.</p><p>Order: {order_number}</p>" 1980 msgstr "" 1981 1982 #: includes/trait-campaign-automation-ui.php:109 1983 msgid "An unsubscribe link is added automatically. The live preview shows template text; Review uses the exact sample order." 1984 msgstr "" 1985 1986 #: includes/trait-campaign-automation-ui.php:109 1987 msgid "Personalization variables" 1988 msgstr "" 1989 1990 #: includes/trait-campaign-automation-ui.php:109 1991 msgid "Use {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products} and {order_url} in the subject, heading or body. Order values come from the triggering order and are frozen when captured. Missing names use Customer. Guest order links are empty; account links require the owning account login." 1992 msgstr "" 1993 1994 #: includes/trait-campaign-automation-ui.php:112 1995 msgid "Timing" 1996 msgstr "" 1997 1998 #: includes/trait-campaign-automation-ui.php:112 1999 msgid "Set how long to wait after the order becomes Completed." 2000 msgstr "" 2001 2002 #: includes/trait-campaign-automation-ui.php:113 2003 msgid "Delay after Completed (hours)" 2004 msgstr "" 2005 2006 #: includes/trait-campaign-automation-ui.php:113 2007 msgid "Use 0 to queue immediately, or 24 to wait one day. Sending limits and queue delays can make actual delivery later." 2008 msgstr "" 2009 2010 #: includes/trait-campaign-automation-ui.php:113 2011 msgid "Editing the delay affects new events only. Waiting emails keep their original due time." 2012 msgstr "" 2013 2014 #: includes/trait-campaign-automation-ui.php:116 2015 msgid "Preview and test" 2016 msgstr "" 2017 2018 #: includes/trait-campaign-automation-ui.php:116 2019 msgid "Check the personalized email using an order you can access." 2020 msgstr "" 2021 2022 #: includes/trait-campaign-automation-ui.php:117 2023 msgid "Sample order ID" 2024 msgstr "" 2025 2026 #: includes/trait-campaign-automation-ui.php:117 2027 msgid "Preview guide" 2028 msgstr "" 2029 2030 #: includes/trait-campaign-automation-ui.php:118 2031 msgid "Send test email" 2032 msgstr "" 2033 2034 #: includes/trait-campaign-automation-ui.php:118 2035 msgid "Test mail goes only to this address. Preview and test create no campaign or delivery job, and never save or enable the rule." 2036 msgstr "" 2037 2038 #: includes/trait-campaign-automation-ui.php:119 2039 msgid "Ready to save?" 2040 msgstr "" 2041 2042 #: includes/trait-campaign-automation-ui.php:119 2043 msgid "Save the form, then Enable the saved rule above. If it is already enabled, your changes apply to new events only." 2044 msgstr "" 2045 2046 #: includes/trait-campaign-automation-ui.php:119 2047 msgid "What happens when I disable a rule?" 2048 msgstr "" 2049 2050 #: includes/trait-campaign-automation-ui.php:119 2051 msgid "New events stop and unstarted emails are cancelled. Work already in flight may finish. Re-enabling never restores cancelled mail. History is preserved." 2052 msgstr "" 2053 2054 #: includes/trait-campaign-automation-ui.php:128 2055 #: includes/trait-campaign-automation-ui.php:129 2056 #: includes/trait-campaign-automation-ui.php:135 2057 msgid "Personalized guide preview" 2058 msgstr "" 2059 2060 #: includes/trait-campaign-automation-ui.php:129 2061 msgid "Based on the form at the last refresh." 2062 msgstr "" 2063 2064 #: includes/trait-campaign-automation-ui.php:129 2065 msgid "Sample" 2066 msgstr "" 2067 2068 #: includes/trait-campaign-automation-ui.php:135 2069 msgid "The form has changed. Choose Preview guide to refresh this sample before saving or testing." 2070 msgstr "" 2071 2072 #: includes/trait-campaign-automation-ui.php:135 2073 msgid "Sample recipient" 2074 msgstr "" 2075 2076 #: includes/trait-campaign-automation-ui.php:136 2077 msgid "Choose a sample order and select Preview guide to see its customer name, products and order details here." 2078 msgstr "" 2079 2080 #: includes/trait-campaign-automations.php:16 2081 msgid "Review the rule name, products, categories, delay and required email content." 2082 msgstr "" 2083 2084 #: includes/trait-campaign-automations.php:37 2085 #: includes/trait-campaign-automations.php:48 2086 msgid "Another rule change is in progress. Please try again." 2087 msgstr "" 2088 2089 #: includes/trait-campaign-automations.php:40 2090 msgid "Rule not found. Open Automations again." 2091 msgstr "" 2092 2093 #: includes/trait-campaign-automations.php:44 2094 msgid "The rule could not be saved. Please try again after checking storage." 2095 msgstr "" 2096 2097 #: includes/trait-campaign-automations.php:51 2098 msgid "Rule not found." 2099 msgstr "" 2100 2101 #: includes/trait-campaign-automations.php:56 2102 msgid "The rule change could not be verified. Please check its current state and try again." 2103 msgstr "" 2104 2105 #: includes/trait-campaign-automations.php:60 2106 msgid "The rule is disabled and its previous generation cannot send. Some campaign cancellations still need cleanup; open Campaigns again after checking storage." 2107 msgstr "" 2108 2109 #: includes/trait-campaign-automations.php:77 2110 #: includes/trait-campaign-automations.php:157 2111 msgid "Completed-order guide" 2112 msgstr "" 2113 2114 #: includes/trait-campaign-automations.php:90 2115 msgid "The triggering order has no valid billing email. No guide was queued." 2116 msgstr "" 2117 2118 #: includes/trait-campaign-automations.php:144 2119 msgid "Guide rule disabled or this pending email belongs to an earlier enabled generation." 2120 msgstr "" 2121 2122 #: includes/trait-campaign-automations.php:146 2123 msgid "The triggering order is no longer Completed, has been fully refunded, changed billing email or no longer matches its saved product/category conditions." 2124 msgstr "" 2125 2126 #: includes/trait-campaign-automations.php:148 2127 msgid "The triggering order or rule could not be checked. No guide was handed off." 2128 msgstr "" 2129 2130 #: includes/trait-campaign-automations.php:152 2131 msgid "Choose a valid sample order ID." 2132 msgstr "" 2133 2134 #: includes/trait-campaign-automations.php:154 2135 msgid "Choose an available order that you can access for preview." 2136 msgstr "" 2137 2138 #: includes/trait-campaign-automations.php:155 2139 msgid "This sample is protected by erasure. Its previous personal context cannot be previewed or tested." 2140 msgstr "" 2141 2142 #: includes/trait-campaign-automations.php:159 2143 msgid "This sample order does not currently match the rule. Preview only; it will not trigger a guide in this state." 2144 msgstr "" 2145 2146 #: includes/trait-campaign-automations.php:159 2147 msgid "This sample has no active subscription. A real guide would be skipped unless subscribed at send time." 2148 msgstr "" 2149 2150 #: includes/trait-campaign-automations.php:159 2151 msgid "This sample matches now. Enabling never sends to historical orders; only a new Completed event can trigger a guide." 2152 msgstr "" 2153 2154 #: includes/trait-campaign-automations.php:163 2155 msgid "Enter a valid test email address." 2156 msgstr "" 2157 2158 #: includes/trait-campaign-checkout.php:16 2159 #: includes/trait-campaign-checkout.php:26 2160 msgid "Email me store news and offers. I will confirm my email address before subscribing." 2161 msgstr "" 2162 2163 #: includes/trait-campaign-contact-history.php:7 2164 msgid "Enter one valid email address to look up its contact history." 2165 msgstr "" 2166 2167 #: includes/trait-campaign-contact-history.php:19 2168 #: includes/trait-campaign-contact-history.php:24 2169 #: includes/trait-campaign-contact-history.php:51 2170 msgid "Contact history could not be read. Please try again after checking storage." 2171 msgstr "" 2172 2173 #: includes/trait-campaign-contact-history.php:62 2174 msgid "Contact history by email" 2175 msgstr "" 2176 2177 #: includes/trait-campaign-contact-history.php:62 2178 msgid "Only contacts recorded by Advanced Notifications are shown. A mail-system handoff does not confirm inbox delivery or that an email was read." 2179 msgstr "" 2180 2181 #: includes/trait-campaign-contact-history.php:62 2182 msgid "Email for contact history" 2183 msgstr "" 2184 2185 #: includes/trait-campaign-contact-history.php:62 2186 msgid "Look up contacts" 2187 msgstr "" 2188 2189 #: includes/trait-campaign-contact-history.php:65 2190 msgid "This address is protected by erasure. Its previous contact details are not shown or reconstructed." 2191 msgstr "" 2192 2193 #: includes/trait-campaign-contact-history.php:66 2194 #: includes/trait-campaign-controls.php:143 2195 #: includes/trait-campaign-controls.php:173 2196 #: includes/trait-campaign-privacy.php:128 2197 #: includes/trait-campaign-privacy.php:145 2198 msgid "Unknown" 2199 msgstr "" 2200 2201 #: includes/trait-campaign-contact-history.php:68 2202 msgid "Current subscription" 2203 msgstr "" 2204 2205 #: includes/trait-campaign-contact-history.php:69 2206 msgid "Recorded source" 2207 msgstr "" 2208 2209 #: includes/trait-campaign-contact-history.php:70 2210 msgid "No campaign contacts are currently retained for this email." 2211 msgstr "" 2212 2213 #: includes/trait-campaign-contact-history.php:71 2214 msgid "Campaign / saved context" 2215 msgstr "" 2216 2217 #: includes/trait-campaign-contact-history.php:71 2218 msgid "Recorded times (UTC)" 2219 msgstr "" 2220 2221 #: includes/trait-campaign-contact-history.php:71 2222 msgid "Outcome / reason" 2223 msgstr "" 2224 2225 #: includes/trait-campaign-contact-history.php:79 2226 msgid "Saved matching order" 2227 msgstr "" 2228 2229 #: includes/trait-campaign-contact-history.php:80 2230 msgid "Campaign content is no longer available. Only the retained outcome is shown." 2231 msgstr "" 2232 2233 #: includes/trait-campaign-contact-history.php:81 2234 msgid "Created" 2235 msgstr "" 2236 2237 #: includes/trait-campaign-contact-history.php:81 2238 msgid "Due" 2239 msgstr "" 2240 2241 #: includes/trait-campaign-contact-history.php:87 2242 msgid "Previous contacts" 2243 msgstr "" 2244 2245 #. translators: 1: Current page, 2: Total pages. 2246 #: includes/trait-campaign-contact-history.php:89 2247 msgid "Page %1$d of %2$d" 2248 msgstr "" 2249 2250 #: includes/trait-campaign-contact-history.php:90 2251 msgid "Next contacts" 1704 2252 msgstr "" 1705 2253 … … 1773 2321 msgstr "" 1774 2322 1775 #: includes/trait-campaign-controls.php:1431776 #: includes/trait-campaign-controls.php:1731777 #: includes/trait-campaign-privacy.php:1271778 #: includes/trait-campaign-privacy.php:1431779 msgid "Unknown"1780 msgstr ""1781 1782 2323 #: includes/trait-campaign-controls.php:151 1783 2324 msgid "Handed off does not verify inbox delivery. Unknown outcomes are never retried automatically. Retry only eligible known failures after correcting the reported problem." … … 1892 2433 msgstr "" 1893 2434 2435 #: includes/trait-campaign-entrypoints.php:24 2436 #: includes/trait-campaign-entrypoints.php:32 2437 msgid "Email purchasers" 2438 msgstr "" 2439 2440 #: includes/trait-campaign-entrypoints.php:32 2441 msgid "A parent product includes all its variations. Opening a draft sends no email." 2442 msgstr "" 2443 2444 #: includes/trait-campaign-entrypoints.php:38 2445 msgid "Email purchasers of this variation" 2446 msgstr "" 2447 2448 #: includes/trait-campaign-entrypoints.php:44 2449 msgid "Email this customer" 2450 msgstr "" 2451 2452 #: includes/trait-campaign-entrypoints.php:49 2453 msgid "Email selected orders" 2454 msgstr "" 2455 2456 #: includes/trait-campaign-entrypoints.php:62 2457 msgid "Select at least one available order." 2458 msgstr "" 2459 2460 #: includes/trait-campaign-entrypoints.php:65 2461 #: includes/trait-campaign-entrypoints.php:67 2462 msgid "A selected order is invalid or unavailable." 2463 msgstr "" 2464 2465 #: includes/trait-campaign-entrypoints.php:91 2466 msgid "A selected product is invalid or unavailable." 2467 msgstr "" 2468 2469 #: includes/trait-campaign-entrypoints.php:94 2470 msgid "Invalid draft source." 2471 msgstr "" 2472 2473 #: includes/trait-campaign-personalization.php:6 2474 msgid "Choose valid orders. No order selection has been ignored." 2475 msgstr "" 2476 2477 #: includes/trait-campaign-personalization.php:16 2478 msgid "Clear selected orders or choose Selected orders before previewing." 2479 msgstr "" 2480 2481 #: includes/trait-campaign-personalization.php:18 2482 msgid "Select at least one order." 2483 msgstr "" 2484 2485 #: includes/trait-campaign-personalization.php:21 2486 msgid "A selected order is unavailable or cannot be accessed. Review the selection." 2487 msgstr "" 2488 2489 #: includes/trait-campaign-personalization.php:26 2490 msgid "Selected order IDs (exact scope)" 2491 msgstr "" 2492 2493 #: includes/trait-campaign-personalization.php:26 2494 msgid "Used only with Selected orders. These orders do not expand into other purchases. All selected order statuses are included unless filtered below; invalid emails and suppression are excluded. Product customers includes purchases of the selected parent and its variations; a selected variation matches only that variation." 2495 msgstr "" 2496 2497 #: includes/trait-campaign-personalization.php:47 2498 msgid "Customer" 2499 msgstr "" 2500 2501 #: includes/trait-campaign-personalization.php:60 2502 msgid "Order context: highest matching order ID" 2503 msgstr "" 2504 2505 #: includes/trait-campaign-personalization.php:60 2506 msgid "Matching orders" 2507 msgstr "" 2508 1894 2509 #: includes/trait-campaign-privacy.php:57 1895 2510 msgid "Invalid email; use one plain email address per line." … … 1984 2599 msgstr "" 1985 2600 1986 #: includes/trait-campaign-privacy.php:12 32601 #: includes/trait-campaign-privacy.php:124 1987 2602 msgid "Subscribers and suppression" 1988 2603 msgstr "" 1989 2604 1990 #: includes/trait-campaign-privacy.php:12 32605 #: includes/trait-campaign-privacy.php:124 1991 2606 msgid "An order, account or pasted email is not opt-in evidence. Unknown remains unknown. Imports never remove an unsubscribe. For subscribed records, enter the actual evidence source; the recorded time is the import time, not an inferred original consent time." 1992 2607 msgstr "" 1993 2608 1994 #: includes/trait-campaign-privacy.php:12 52609 #: includes/trait-campaign-privacy.php:126 1995 2610 msgid "Find subscription or suppression" 1996 2611 msgstr "" 1997 2612 1998 #: includes/trait-campaign-privacy.php:12 52613 #: includes/trait-campaign-privacy.php:126 1999 2614 msgid "State" 2000 2615 msgstr "" 2001 2616 2002 #: includes/trait-campaign-privacy.php:12 72617 #: includes/trait-campaign-privacy.php:128 2003 2618 msgid "All states" 2004 2619 msgstr "" 2005 2620 2006 #: includes/trait-campaign-privacy.php:12 82621 #: includes/trait-campaign-privacy.php:129 2007 2622 msgid "Search" 2008 2623 msgstr "" 2009 2624 2010 #: includes/trait-campaign-privacy.php:12 82625 #: includes/trait-campaign-privacy.php:129 2011 2626 msgid "Email / state" 2012 2627 msgstr "" 2013 2628 2014 #: includes/trait-campaign-privacy.php:12 82629 #: includes/trait-campaign-privacy.php:129 2015 2630 msgid "Source / recorded time (UTC)" 2016 2631 msgstr "" 2017 2632 2018 #: includes/trait-campaign-privacy.php:140 2633 #: includes/trait-campaign-privacy.php:141 2634 msgid "Confirmation pending; current subscription unchanged." 2635 msgstr "" 2636 2637 #: includes/trait-campaign-privacy.php:142 2019 2638 msgid "Up to 200 matches. Erased addresses are represented only by protective hashes and are not listed as plaintext." 2020 2639 msgstr "" 2021 2640 2022 #: includes/trait-campaign-privacy.php:14 12641 #: includes/trait-campaign-privacy.php:143 2023 2642 msgid "Import records" 2024 2643 msgstr "" 2025 2644 2026 #: includes/trait-campaign-privacy.php:14 12645 #: includes/trait-campaign-privacy.php:143 2027 2646 msgid "1. Paste → 2. Preview → 3. Apply and review result" 2028 2647 msgstr "" 2029 2648 2030 #: includes/trait-campaign-privacy.php:14 22649 #: includes/trait-campaign-privacy.php:144 2031 2650 msgid "One email per line" 2032 2651 msgstr "" 2033 2652 2034 #: includes/trait-campaign-privacy.php:14 32653 #: includes/trait-campaign-privacy.php:145 2035 2654 msgid "Subscribed (evidence required)" 2036 2655 msgstr "" 2037 2656 2038 #: includes/trait-campaign-privacy.php:14 42657 #: includes/trait-campaign-privacy.php:146 2039 2658 msgid "Evidence/source" 2040 2659 msgstr "" 2041 2660 2042 #: includes/trait-campaign-privacy.php:14 42661 #: includes/trait-campaign-privacy.php:146 2043 2662 msgid "Preview import" 2044 2663 msgstr "" 2045 2664 2046 #: includes/trait-campaign-privacy.php:14 72665 #: includes/trait-campaign-privacy.php:149 2047 2666 msgid "Previewed import" 2048 2667 msgstr "" 2049 2668 2050 #: includes/trait-campaign-privacy.php:14 72669 #: includes/trait-campaign-privacy.php:149 2051 2670 msgid "State / evidence source:" 2052 2671 msgstr "" 2053 2672 2054 #: includes/trait-campaign-privacy.php:14 72673 #: includes/trait-campaign-privacy.php:149 2055 2674 msgid "Apply uses this saved preview. If you edit the input above, preview it again before applying." 2056 2675 msgstr "" 2057 2676 2058 #: includes/trait-campaign-privacy.php:1 482677 #: includes/trait-campaign-privacy.php:150 2059 2678 msgid "Valid / duplicate or already protected / rejected:" 2060 2679 msgstr "" 2061 2680 2062 #: includes/trait-campaign-privacy.php:15 02681 #: includes/trait-campaign-privacy.php:152 2063 2682 msgid "Apply previewed import" 2064 2683 msgstr "" 2065 2684 2066 #: includes/trait-campaign-privacy.php:15 32685 #: includes/trait-campaign-privacy.php:155 2067 2686 msgid "Applied / not applied (protected or storage failure):" 2068 2687 msgstr "" 2069 2688 2070 #: includes/trait-campaign-privacy.php:16 72071 #: includes/trait-campaign-privacy.php:17 02689 #: includes/trait-campaign-privacy.php:169 2690 #: includes/trait-campaign-privacy.php:172 2072 2691 msgid "YoOhw campaign data" 2073 2692 msgstr "" 2074 2693 2075 #: includes/trait-campaign-privacy.php:187 2694 #: includes/trait-campaign-privacy.php:185 2695 msgid "Saved order context" 2696 msgstr "" 2697 2698 #: includes/trait-campaign-privacy.php:195 2076 2699 msgid "Subscription and protection" 2077 2700 msgstr "" 2078 2701 2079 #: includes/trait-campaign-privacy.php: 1982702 #: includes/trait-campaign-privacy.php:206 2080 2703 msgid "Saved list references and legacy logs" 2081 2704 msgstr "" 2082 2705 2083 #: includes/trait-campaign-privacy.php:2 152706 #: includes/trait-campaign-privacy.php:223 2084 2707 msgid "Campaign storage is busy or unavailable. Personal data was not fully erased; run erasure again after checking storage and workers." 2085 2708 msgstr "" 2086 2709 2087 #: includes/trait-campaign-privacy.php:2 272710 #: includes/trait-campaign-privacy.php:235 2088 2711 msgid "A send is in flight. Run erasure again after the worker finishes. A protective hash already blocks future admission." 2089 2712 msgstr "" 2090 2713 2091 #: includes/trait-campaign-privacy.php:2 632714 #: includes/trait-campaign-privacy.php:271 2092 2715 msgid "Personal fields removed. Active campaign shared content is retained until completion; run erasure again if it contains personal text. Minimal recipient/campaign hashes, outcomes and suppression/erasure protection remain to prevent duplicate sends and data reconstruction." 2716 msgstr "" 2717 2718 #: includes/trait-campaign-purchase-history.php:53 2719 msgid "Purchase history across the store" 2720 msgstr "" 2721 2722 #: includes/trait-campaign-purchase-history.php:53 2723 msgid "Purchase frequency" 2724 msgstr "" 2725 2726 #: includes/trait-campaign-purchase-history.php:54 2727 msgid "Any purchase history" 2728 msgstr "" 2729 2730 #: includes/trait-campaign-purchase-history.php:57 2731 msgid "No repeat purchase in the last X days" 2732 msgstr "" 2733 2734 #: includes/trait-campaign-purchase-history.php:57 2735 msgid "These conditions use all valid purchases across the entire store, including orders outside the dates and products selected below. Product/category conditions still match one order; they do not change this into repeat purchases of only that product." 2736 msgstr "" 2737 2738 #: includes/trait-campaign-purchase-history.php:57 2739 msgid "Which purchases count?" 2740 msgstr "" 2741 2742 #: includes/trait-campaign-purchase-history.php:57 2743 msgid "Processing and Completed orders count by normalized billing email, including guest orders and orders before an account existed. Cancelled, Failed, Refunded and fully refunded orders do not count. Partial refunds count while an amount remains; free orders without refunds count. Inactivity uses the latest valid order creation time and X times 24 hours. A customer with no valid purchases never qualifies as inactive. Different emails are not merged." 2093 2744 msgstr "" 2094 2745 … … 2113 2764 msgstr "" 2114 2765 2766 #: includes/trait-campaign-subscriptions.php:42 2767 msgid "Enter a valid email address and try again." 2768 msgstr "" 2769 2770 #: includes/trait-campaign-subscriptions.php:43 2771 #: includes/trait-campaign-subscriptions.php:74 2772 msgid "Subscription storage is busy. Please try again." 2773 msgstr "" 2774 2775 #: includes/trait-campaign-subscriptions.php:57 2776 msgid "The request could not be completed. Please try again later." 2777 msgstr "" 2778 2779 #: includes/trait-campaign-subscriptions.php:61 2780 #: includes/trait-campaign-subscriptions.php:113 2781 msgid "Confirm your email subscription" 2782 msgstr "" 2783 2784 #: includes/trait-campaign-subscriptions.php:62 2785 msgid "Someone requested campaign emails from this store for this address. To subscribe, open the link below and confirm. It expires in 24 hours. If you did not request this, ignore this email; your preference has not changed." 2786 msgstr "" 2787 2788 #: includes/trait-campaign-subscriptions.php:72 2789 msgid "This confirmation is invalid, expired or already used. Submit a new subscription request." 2790 msgstr "" 2791 2792 #: includes/trait-campaign-subscriptions.php:85 2793 msgid "The subscription could not be saved. Submit a new request and try again." 2794 msgstr "" 2795 2796 #: includes/trait-campaign-subscriptions.php:92 2797 msgid "Email address" 2798 msgstr "" 2799 2800 #: includes/trait-campaign-subscriptions.php:92 2801 msgid "I would like to receive campaign emails from this store. I can unsubscribe at any time." 2802 msgstr "" 2803 2804 #: includes/trait-campaign-subscriptions.php:92 2805 msgid "Leave this field empty" 2806 msgstr "" 2807 2808 #: includes/trait-campaign-subscriptions.php:92 2809 msgid "Request subscription" 2810 msgstr "" 2811 2812 #: includes/trait-campaign-subscriptions.php:92 2813 msgid "Check your email to confirm. Submitting this form does not subscribe you." 2814 msgstr "" 2815 2816 #: includes/trait-campaign-subscriptions.php:96 2817 msgid "Use the subscription form." 2818 msgstr "" 2819 2820 #: includes/trait-campaign-subscriptions.php:99 2821 msgid "Choose whether you want to request campaign emails." 2822 msgstr "" 2823 2824 #: includes/trait-campaign-subscriptions.php:103 2825 msgid "If this address is eligible, a confirmation email has been requested. Check your inbox and spam folder. Requests are limited; you can try again later." 2826 msgstr "" 2827 2828 #: includes/trait-campaign-subscriptions.php:103 2829 msgid "Check your email" 2830 msgstr "" 2831 2832 #: includes/trait-campaign-subscriptions.php:112 2833 msgid "Invalid confirmation link." 2834 msgstr "" 2835 2836 #: includes/trait-campaign-subscriptions.php:113 2837 msgid "Confirm that you want campaign emails from this store. This also replaces an earlier unsubscribe for this address. You can unsubscribe again at any time." 2838 msgstr "" 2839 2840 #: includes/trait-campaign-subscriptions.php:113 2841 #: includes/trait-campaign-subscriptions.php:114 2842 msgid "Confirm subscription" 2843 msgstr "" 2844 2845 #: includes/trait-campaign-subscriptions.php:118 2846 msgid "Your email subscription is confirmed. You can unsubscribe from any campaign email." 2847 msgstr "" 2848 2849 #: includes/trait-campaign-subscriptions.php:123 2850 msgid "Email confirmation is pending. Your current preference remains in effect until you confirm." 2851 msgstr "" 2852 2853 #: includes/trait-campaign-subscriptions.php:124 2854 msgid "Campaign email preference" 2855 msgstr "" 2856 2857 #: includes/trait-campaign-subscriptions.php:124 2858 msgid "Preference for your current account email:" 2859 msgstr "" 2860 2861 #: includes/trait-campaign-subscriptions.php:125 2862 msgid "Request subscription by email" 2863 msgstr "" 2864 2865 #: includes/trait-campaign-subscriptions.php:125 2866 msgid "A subscription request requires email confirmation. Unsubscribe applies immediately." 2867 msgstr "" 2868 2869 #: includes/trait-campaign-subscriptions.php:133 2870 msgid "The preference could not be saved. Try again later." 2871 msgstr "" 2872 2115 2873 #: yoohw-advanced-notifications.php:43 2116 2874 msgid "Advanced Notifications for WooCommerce requires WooCommerce to be active." -
yoohw-advanced-notifications/trunk/readme.txt
r3771948 r3789014 6 6 Requires PHP: 8.1 7 7 Requires Plugins: woocommerce 8 Stable tag: 0. 3.08 Stable tag: 0.4.0 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 20 20 = Choose and review your audience = 21 21 22 * Select product or variation purchasers, WooCommerce customers with matching orders, registered users or a pasted email list. Order-based sources include guest customers. 22 * Select product or variation purchasers, selected orders, WooCommerce customers with matching orders, registered users, subscribed email addresses or a pasted email list. Order-based sources include guest customers. 23 * Start from Email purchasers on Products or Email selected orders / Email this customer on Orders. These actions create a draft with an explicit scope; preview and confirmation are still required before sending. 23 24 * Filter matching orders by product, category (including child categories), creation date, order status and billing country. These order conditions must match the same order. 24 25 * Filter registered users by role and profile billing country. Only filters supported by the selected source can be used. 25 26 * Select by subscription status or a previous campaign's recorded handoff outcome. Missing or unknown delivery history is not treated as proof that an email was never sent. 26 27 * Apply exclusions, remove duplicate email addresses and respect saved unsubscribes across every recipient source. 28 * Choose first-time buyers (one valid order), repeat buyers (two or more), or customers with no valid purchase in the last X days. History spans the entire store, outside campaign product/date filters. Processing and Completed orders count by normalized billing email; cancelled, failed and fully refunded orders do not. Partial refunds count while value remains; free orders without refunds count. Inactivity uses order creation time and X times 24 hours; customers with no valid purchases are excluded. 27 29 * Save audience criteria for reuse. Each use requires a fresh recipient preview and confirmation. 28 30 * Review selection and exclusion counts and inspect why an email address is included or excluded. … … 35 37 * Use WooCommerce HTML email styling, the rich-text editor and desktop/mobile previews for a sample recipient. 36 38 * Send a test email and continue editing the draft before confirming recipients. 37 * Personalize the message body with {customer_name} and {product_name}. A missing customer name falls back to the email address. The product variable is a campaign-wide label, not a record of each recipient's purchases. Subjects and headings do not expand these variables.39 * New campaigns personalize subject, heading and body with {customer_name}, {store_name}, {product_name}, {order_number}, {ordered_products} and {order_url}. Missing names use Customer. {product_name} remains a campaign-wide label; order details come from the matching order with the highest order ID and are empty without order context. Guest order links are empty; account order links require the owning account login. Already-confirmed older campaigns keep their original rendering contract. 38 40 39 41 = Schedule and control sending = … … 46 48 * Recover interrupted work using confirmed recipients and bounded retries for eligible known failures. Unknown handoff outcomes are not automatically retried. 47 49 50 = One guide after Completed = 51 52 * Follow Conditions → Content → Timing → Review in Automations. Compose with a live WooCommerce preview and Desktop/Mobile controls, then refresh the exact order sample in Review. Save a guide with optional products/categories and a delay of 0–8760 hours. Preview an accessible sample order or send a test to your chosen address, then explicitly enable the saved rule. 53 * Only new transitions to Completed are captured. Enabling never scans historical orders. Each rule/order can create at most one email, including repeated transitions and multiple matching items; different orders for the same email can each receive a guide. 54 * An active subscription is required at sending. Unknown is not consent. Orders must still be Completed, have the same valid billing email, match saved product/category conditions and not be fully refunded. Partial refunds remain eligible while value remains. Subscription, suppression and erasure protections are checked before handoff. 55 * Content, triggering-order context and UTC due time are fixed when captured. Editing a rule changes future events. Disabling stops new events and cancels unstarted mail; started work may finish. Re-enabling does not restore cancelled mail. 56 * Use Campaigns & Logs or the contact lookup to inspect the guide, exact order and recorded result. Existing limits, recovery and unknown-outcome protections apply. A working queue is required; delivery may be later than the due time. 57 48 58 = Subscription and privacy tools = 59 60 * Place [yoohw_an_subscribe] on a page for guest signup. Optional, unchecked Classic Checkout and Checkout Blocks fields (Blocks requires WooCommerce 8.9 or later) request a confirmation email; buying or creating an account never establishes consent. 61 * Confirm mailbox ownership using the emailed link and confirmation button within 24 hours. A new verified request can replace an earlier unsubscribe; imports cannot. Erasure protection remains in effect. 62 * View or change the preference for the current email in My Account. Choose Subscribed email addresses in the composer to include subscribers without an account or order. 63 * Look up one email under Subscribers to review its retained campaign outcomes, reasons and campaign links. Handoff does not prove inbox delivery or reading. 49 64 50 65 * Keep subscribed, unsubscribed and unknown states separate, with the recorded source and time where available. … … 60 75 Only this plugin's campaign emails are subject to its send controls and admission limits. WooCommerce transactional emails and unrelated scheduled actions keep their existing behavior. Test emails are outside the campaign admission limits. 61 76 62 This plugin does not include recurring marketing automation, WooCommerce Subscriptions audiences, CRM synchronization or additional messaging channels.77 This plugin does not include multi-step or recurring marketing automation, WooCommerce Subscriptions audiences, CRM synchronization or additional messaging channels. 63 78 64 79 == Installation == … … 97 112 = What data does the plugin store and erase? = 98 113 99 The plugin stores campaign content, confirmed recipients, scheduling and delivery records, drafts, saved audience criteria, subscription evidence and opt-outs in your WordPress database. Emails are sent through the mail transport configured on your site. 114 The plugin stores campaign content, confirmed recipients, scheduling and delivery records, drafts, saved audience criteria, subscription evidence and opt-outs in your WordPress database. Emails are sent through the mail transport configured on your site. Subscription requests store the email, source, request/expiry time and a hashed confirmation token for at most 24 hours. Rate counters store hashes, not raw IP addresses. Confirmation requests are limited per address, client and site. A protected erased address is not re-enrolled or reconstructed by a new request. 100 115 101 116 WordPress Tools > Export Personal Data and Erase Personal Data include this plugin's records for the requested email address, including guests. Erasure retains protective hashes and opt-out evidence to prevent reconstruction or another send. In-flight work or shared content in an active campaign may require another erasure pass after completion; the erasure result reports retained data. … … 107 122 Deactivation cancels pending campaign work and removes the reconciliation event while retaining campaign records and opt-outs. Reactivation does not automatically restart cancelled work. 108 123 109 When upgrading, stop background workers that have already loaded the old plugin code before replacing files. Version 0. 3.0 keeps the existing plugin slug, text domain, settings, campaigns and opt-outs. Do not downgrade directly to 0.2.2, which does not understand the new cancellation and erasure protections. Data from the separate YoOhw Extra Code plugin is not imported automatically.124 When upgrading, stop background workers that have already loaded the old plugin code before replacing files. Version 0.4.0 keeps the existing plugin slug, text domain, settings, campaigns and opt-outs. Do not downgrade directly to 0.2.2, which does not understand the new cancellation and erasure protections. Data from the separate YoOhw Extra Code plugin is not imported automatically. 110 125 111 126 = Can I translate the interface? = … … 115 130 == Changelog == 116 131 117 = 0.3.0 = 118 * Rename the plugin to Advanced Notifications for WooCommerce; keep the existing slug, text domain and stored data. 119 * Add individual campaign controls and shared sending admission limits. 120 * Add durable drafts, duplication, content templates and personalized previews. 121 * Add source-aware saved audiences and explicit timezone scheduling. 122 * Add subscription/suppression administration, privacy callbacks and terminal retention. 123 * Preserve erased data boundaries, known-unsent history and cancellation during concurrent recovery. 124 * Unify campaign forms with the admin color scheme, SelectWoo fields and desktop/mobile preview controls. 125 * Harden confirmed recipient snapshots, duplicate protection, bounded retries and interrupted-work recovery. 132 = 0.4.0 = 133 * Add product and order email entry points that create scoped drafts, with HPOS and posts order storage support. 134 * Personalize new campaign subjects, headings and bodies with frozen customer, store and representative-order context; preserve already-confirmed campaigns. 135 * Add verified subscriptions through a signup shortcode, Classic Checkout, Checkout Blocks and My Account without treating purchase or account creation as consent. 136 * Add per-email contact history lookup with retained outcomes, reasons and campaign links. 137 * Add store-wide first-time, repeat-buyer and purchase-inactivity filters for campaigns and saved audiences. 138 * Add explicitly enabled Completed-order guides with product/category conditions, a fixed delay and one immutable delivery per rule/order. 139 * Recheck rule, order, subscription, suppression and erasure before guide handoff; preserve cancellation, duplicate protection and unknown-outcome boundaries. 140 * Align automation authoring with the four-step composer, live Desktop/Mobile previews and exact-order preview/test; hide stale samples after edits. 141 * Fix Library warnings when optional draft or saved-audience names are missing. 126 142 127 = 0.2.2 = 128 * Align the translation domain with the WordPress.org slug yoohw-advanced-notifications. 129 * Resolve Plugin Check findings for SQL identifiers, input handling, test fixtures and plugin metadata. 130 * Load admin JavaScript and CSS from separate files with WordPress dependencies. 131 132 = 0.2.1 = 133 * Register the languages directory on init and include a POT translation template. 134 * Make remaining delivery messages and status labels translatable. 135 * Add translator notes and translation setup instructions. 136 137 = 0.2.0 = 138 * Add WooCommerce customers and Manual email list recipient sources. 139 * Add multi-role filtering for registered users, including preview and campaign history. 140 * Preserve recipient selections when restoring drafts and retrying failed schedules. 141 * Use native JavaScript trim() for the live preview. 142 143 = 0.1.0 = 144 * Extract standalone customer email campaigns from YoOhw Extra Code. 145 * Remove WooCommerce Subscriptions audiences and exclusions, and Audience sync integration. 146 * Isolate plugin storage/hooks and use the current store's sender defaults. 143 See changelog.txt for the full version history. 147 144 148 145 == Upgrade Notice == 149 146 147 = 0.4.0 = 148 Adds scoped product/order campaigns, verified subscriptions, contact history, purchase-history filters and Completed-order guides. Existing data and confirmed work are retained. New automation rules stay disabled until explicitly enabled; there is no historical backfill. Stop workers using the old code before replacing plugin files. Do not downgrade to an older version without reviewing pending jobs and subscription/privacy compatibility. 149 150 150 = 0.3.0 = 151 151 Campaign controls, reusable drafts, audience filters, scheduling and privacy tools. Existing data is retained. Stop old background workers before upgrading. Do not downgrade to 0.2.2 because it lacks the new cancellation and erasure protections. -
yoohw-advanced-notifications/trunk/yoohw-advanced-notifications.php
r3771948 r3789014 4 4 * Plugin URI: https://wordpress.org/plugins/yoohw-advanced-notifications 5 5 * Description: Compose, preview, schedule and track WooCommerce customer email campaigns. 6 * Version: 0. 3.06 * Version: 0.4.0 7 7 * Author: YoOhw Studio 8 8 * Author URI: https://yoohw.com/ … … 20 20 } 21 21 22 define( 'YOOHW_AN_VERSION', '0. 3.0' );22 define( 'YOOHW_AN_VERSION', '0.4.0' ); 23 23 24 24 function yoohw_an_load_textdomain() {
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)