Changeset 3758167
- Timestamp:
- 10/21/2026 10:43:36 AM (9 days ago)
- Location:
- traceify/trunk
- Files:
-
- 2 added
- 15 edited
-
admin/class-trcfy-admin.php (modified) (17 diffs)
-
admin/views/settings-page.php (modified) (21 diffs)
-
assets/css/public.css (modified) (2 diffs)
-
assets/js/public.js (modified) (1 diff)
-
includes/class-trcfy-core.php (modified) (1 diff)
-
includes/class-trcfy-delivery-estimator.php (modified) (2 diffs)
-
includes/class-trcfy-email-notifier.php (modified) (3 diffs)
-
includes/class-trcfy-installer.php (modified) (3 diffs)
-
includes/class-trcfy-order-status.php (added)
-
includes/class-trcfy-order-tracker.php (modified) (3 diffs)
-
includes/class-trcfy-shipment-tracking.php (added)
-
includes/class-trcfy-whatsapp.php (modified) (4 diffs)
-
public/class-trcfy-public.php (modified) (3 diffs)
-
public/views/tracking-page.php (modified) (15 diffs)
-
readme.txt (modified) (7 diffs)
-
templates/email-notification.php (modified) (6 diffs)
-
traceify-for-woocommerce.php (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
traceify/trunk/admin/class-trcfy-admin.php
r3716662 r3758167 28 28 add_action( 'add_meta_boxes', array( $this, 'add_order_meta_box' ) ); 29 29 30 // Order detail page — Estimated Delivery override meta box. 31 // `woocommerce_process_shop_order_meta` fires for both HPOS and legacy order screens. 32 add_action( 'add_meta_boxes', array( $this, 'add_edd_meta_box' ) ); 33 add_action( 'woocommerce_process_shop_order_meta', array( $this, 'save_edd_override' ), 20, 2 ); 34 30 35 // Settings link on plugins page. 31 36 add_filter( 'plugin_action_links_' . TRCFY_BASENAME, array( $this, 'add_plugin_action_links' ) ); … … 37 42 // Show a red dot badge on the menu item until the user visits settings. 38 43 $show_badge = ( '1' !== get_option( 'trcfy_settings_visited', '0' ) ); 39 $menu_label = __( 'Traceify', 'traceify ' );44 $menu_label = __( 'Traceify', 'traceify-for-woocommerce' ); 40 45 if ( $show_badge ) { 41 46 $menu_label .= ' <span class="trcfy-menu-badge"></span>'; … … 44 49 add_submenu_page( 45 50 'woocommerce', 46 __( 'Traceify Settings', 'traceify ' ),51 __( 'Traceify Settings', 'traceify-for-woocommerce' ), 47 52 $menu_label, 48 53 'manage_woocommerce', … … 69 74 public function render_settings_page() { 70 75 if ( ! current_user_can( 'manage_woocommerce' ) ) { 71 wp_die( esc_html__( 'You do not have permission to access this page.', 'traceify ' ) );76 wp_die( esc_html__( 'You do not have permission to access this page.', 'traceify-for-woocommerce' ) ); 72 77 } 73 78 require_once TRCFY_PATH . 'admin/views/settings-page.php'; … … 97 102 'trcfy_edd_max_ship_days', 98 103 'trcfy_edd_exclude_weekends', 104 // Shipment tracking. 105 'trcfy_shipment_enabled', 106 'trcfy_shipment_auto_shipped', 107 'trcfy_custom_courier_name', 108 'trcfy_custom_courier_url', 99 109 // Email notifications. 100 110 'trcfy_email_enabled', … … 130 140 'trcfy_edd_enabled' => array( $this, 'sanitize_checkbox' ), 131 141 'trcfy_edd_exclude_weekends' => array( $this, 'sanitize_checkbox' ), 142 // Shipment tracking. 143 'trcfy_shipment_enabled' => array( $this, 'sanitize_checkbox' ), 144 'trcfy_shipment_auto_shipped' => array( $this, 'sanitize_checkbox' ), 145 'trcfy_custom_courier_url' => array( 'TRCFY_Shipment_Tracking', 'sanitize_url_template' ), 132 146 // Email toggles. 133 147 'trcfy_email_enabled' => array( $this, 'sanitize_checkbox' ), … … 164 178 $this->get_badge_inline_css() 165 179 ); 180 } 181 182 // Order-screen meta box styles (tiny; only on order edit screens). 183 $screen = get_current_screen(); 184 if ( $screen && ( 'shop_order' === $screen->post_type || 'woocommerce_page_wc-orders' === $screen->id ) ) { 185 wp_add_inline_style( 'wp-admin', '.trcfy-edd-input{width:100%;margin-bottom:8px}' ); 166 186 } 167 187 … … 221 241 if ( 'order_status' === $key ) { 222 242 $new['trcfy_whatsapp'] = '<span class="trcfy-col-icon" title="' . 223 esc_attr__( 'WhatsApp', 'traceify ' ) . '">💬</span>';243 esc_attr__( 'WhatsApp', 'traceify-for-woocommerce' ) . '">💬</span>'; 224 244 } 225 245 } … … 242 262 $wa_number = get_option( 'trcfy_wa_number', '' ); 243 263 if ( ! $wa_number ) { 244 echo '<span title="' . esc_attr__( 'Set your WhatsApp number in WooCommerce → Order Tracker.', 'traceify' ) . '">—</span>';264 echo '<span title="' . esc_attr__( 'Set your WhatsApp number in WooCommerce → Traceify.', 'traceify-for-woocommerce' ) . '">—</span>'; 245 265 return; 246 266 } … … 254 274 '<a href="%s" target="_blank" rel="noopener noreferrer" class="trcfy-wa-btn" title="%s %s">📲</a>', 255 275 esc_url( $wa_link ), 256 esc_attr__( 'Send WhatsApp to', 'traceify ' ),276 esc_attr__( 'Send WhatsApp to', 'traceify-for-woocommerce' ), 257 277 esc_attr( $customer_phone ) 258 278 ); 259 279 } else { 260 echo '<span title="' . esc_attr__( 'No billing phone on this order.', 'traceify ' ) . '">—</span>';280 echo '<span title="' . esc_attr__( 'No billing phone on this order.', 'traceify-for-woocommerce' ) . '">—</span>'; 261 281 } 262 282 } … … 269 289 add_meta_box( 270 290 'trcfy-whatsapp-box', 271 __( 'WhatsApp Update', 'traceify ' ),291 __( 'WhatsApp Update', 'traceify-for-woocommerce' ), 272 292 array( $this, 'render_order_meta_box' ), 273 293 $screen, … … 303 323 printf( 304 324 /* translators: %s = link to settings */ 305 esc_html__( 'Add your WhatsApp number in %s to enable this feature.', 'traceify ' ),325 esc_html__( 'Add your WhatsApp number in %s to enable this feature.', 'traceify-for-woocommerce' ), 306 326 '<a href="' . esc_url( admin_url( 'admin.php?page=traceify-for-woocommerce' ) ) . '">' . 307 esc_html__( 'Traceify Settings', 'traceify ' ) .327 esc_html__( 'Traceify Settings', 'traceify-for-woocommerce' ) . 308 328 '</a>' 309 329 ); … … 311 331 </p> 312 332 <?php elseif ( ! $customer_phone ) : ?> 313 <p class="trcfy-notice"><?php esc_html_e( 'No billing phone number on this order.', 'traceify ' ); ?></p>333 <p class="trcfy-notice"><?php esc_html_e( 'No billing phone number on this order.', 'traceify-for-woocommerce' ); ?></p> 314 334 <?php else : ?> 315 <p class="trcfy-label"><?php esc_html_e( 'Customer Phone:', 'traceify ' ); ?>335 <p class="trcfy-label"><?php esc_html_e( 'Customer Phone:', 'traceify-for-woocommerce' ); ?> 316 336 <strong><?php echo esc_html( $customer_phone ); ?></strong> 317 337 </p> 318 <p class="trcfy-label"><?php esc_html_e( 'Preview message:', 'traceify ' ); ?></p>338 <p class="trcfy-label"><?php esc_html_e( 'Preview message:', 'traceify-for-woocommerce' ); ?></p> 319 339 <p class="trcfy-preview"><?php echo esc_html( $message ); ?></p> 320 340 <a href="<?php echo esc_url( $wa_link ); ?>" … … 322 342 rel="noopener noreferrer" 323 343 class="button button-primary trcfy-send-btn"> 324 📲 <?php esc_html_e( 'Send WhatsApp Update', 'traceify ' ); ?>344 📲 <?php esc_html_e( 'Send WhatsApp Update', 'traceify-for-woocommerce' ); ?> 325 345 </a> 326 346 <p class="trcfy-help"> 327 <?php esc_html_e( 'Opens WhatsApp on your device with the message pre-filled.', 'traceify ' ); ?>347 <?php esc_html_e( 'Opens WhatsApp on your device with the message pre-filled.', 'traceify-for-woocommerce' ); ?> 328 348 </p> 329 349 <?php endif; ?> … … 339 359 add_meta_box( 340 360 'trcfy-edd-box', 341 __( 'Estimated Delivery', 'traceify ' ),361 __( 'Estimated Delivery', 'traceify-for-woocommerce' ), 342 362 array( $this, 'render_edd_meta_box' ), 343 363 $screen, … … 357 377 } 358 378 359 $min = esc_attr( $order->get_meta( '_trcfy_edd_min' ));360 $max = esc_attr( $order->get_meta( '_trcfy_edd_max' ));379 $min = $order->get_meta( '_trcfy_edd_min' ); 380 $max = $order->get_meta( '_trcfy_edd_max' ); 361 381 wp_nonce_field( 'trcfy_edd_override', 'trcfy_edd_override_nonce' ); 362 382 ?> 363 383 <div class="trcfy-meta-box"> 364 <p class="trcfy-label"><?php esc_html_e( 'Min delivery date:', 'traceify ' ); ?></p>365 <input type="date" name="trcfy_edd_min" value="<?php echo esc_attr( $min ); ?>" style="width:100%;margin-bottom:8px;">366 <p class="trcfy-label"><?php esc_html_e( 'Max delivery date:', 'traceify ' ); ?></p>367 <input type="date" name="trcfy_edd_max" value="<?php echo esc_attr( $max ); ?>" style="width:100%;margin-bottom:8px;">368 <p class="trcfy-help"><?php esc_html_e( 'Override the auto-calculated dates shown to the customer on the tracking page.', 'traceify ' ); ?></p>384 <p class="trcfy-label"><?php esc_html_e( 'Min delivery date:', 'traceify-for-woocommerce' ); ?></p> 385 <input type="date" name="trcfy_edd_min" class="trcfy-edd-input" value="<?php echo esc_attr( $min ); ?>"> 386 <p class="trcfy-label"><?php esc_html_e( 'Max delivery date:', 'traceify-for-woocommerce' ); ?></p> 387 <input type="date" name="trcfy_edd_max" class="trcfy-edd-input" value="<?php echo esc_attr( $max ); ?>"> 388 <p class="trcfy-help"><?php esc_html_e( 'Override the auto-calculated dates shown to the customer on the tracking page.', 'traceify-for-woocommerce' ); ?></p> 369 389 </div> 370 390 <?php … … 378 398 } 379 399 380 public function save_edd_override_hpos( $and_taxes, $order ) {381 if ( $order instanceof WC_Order ) {382 TRCFY_Delivery_Estimator::save_admin_override( $order->get_id(), $order );383 }384 }385 386 400 // ── Plugin action links ─────────────────────────────────────────────── 387 401 388 402 public function add_plugin_action_links( $links ) { 389 403 $settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=traceify-for-woocommerce' ) ) . '">' 390 . esc_html__( 'Settings', 'traceify ' ) . '</a>';404 . esc_html__( 'Settings', 'traceify-for-woocommerce' ) . '</a>'; 391 405 array_unshift( $links, $settings_link ); 392 406 return $links; -
traceify/trunk/admin/views/settings-page.php
r3716662 r3758167 15 15 'whatsapp' => array( 'label' => 'WhatsApp', 'group' => 'MESSAGING', 'desc' => 'WhatsApp number and message templates.', 'icon' => '<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413z"/><path d="M12 0C5.373 0 0 5.373 0 12c0 2.124.558 4.122 1.533 5.854L0 24l6.335-1.51A11.945 11.945 0 0012 24c6.627 0 12-5.373 12-12S18.627 0 12 0zm0 21.818a9.818 9.818 0 01-5.006-1.368l-.36-.213-3.76.896.951-3.657-.234-.376A9.817 9.817 0 012.182 12C2.182 6.582 6.582 2.182 12 2.182c5.418 0 9.818 4.4 9.818 9.818 0 5.418-4.4 9.818-9.818 9.818z"/>' ), 16 16 'tracking' => array( 'label' => 'Tracking Page', 'group' => 'TRACKING', 'desc' => 'Configure the customer-facing tracking page.', 'icon' => '<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>' ), 17 'shipment' => array( 'label' => 'Shipment Tracking', 'group' => 'TRACKING', 'desc' => 'Courier and tracking number for each order.', 'icon' => '<path d="M20 8h-3V4H3c-1.1 0-2 .9-2 2v11h2c0 1.66 1.34 3 3 3s3-1.34 3-3h6c0 1.66 1.34 3 3 3s3-1.34 3-3h2v-5l-3-4zM6 18.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm13.5-9l1.96 2.5H17V9.5h2.5zm-1.5 9c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/>' ), 17 18 'delivery' => array( 'label' => 'Estimated Delivery', 'group' => 'TRACKING', 'desc' => 'Auto-calculate delivery date ranges.', 'icon' => '<path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V10h14v10zm0-12H5V6h14v2zM9 14H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm-8 4H7v-2h2v2zm4 4h-2v-2h2v2zm4 0h-2v-2h2v2z"/>' ), 18 19 'emails' => array( 'label' => 'Email Notifications', 'group' => 'NOTIFICATIONS', 'desc' => 'Branded email alerts on order status changes.', 'icon' => '<path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>' ), … … 70 71 <div id="trcfy-saved-notice" style="display:none;align-items:center;gap:8px;background:#D1FAE5;border:1px solid #A7F3D0;color:#065F46;padding:10px 20px;font-size:13px;font-weight:500;"> 71 72 <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg> 72 <?php esc_html_e( 'Settings saved.', 'traceify ' ); ?>73 <?php esc_html_e( 'Settings saved.', 'traceify-for-woocommerce' ); ?> 73 74 </div> 74 75 … … 80 81 </div> 81 82 <button type="submit" form="trcfy-settings-form" class="trcfy-save-btn"> 82 <?php esc_html_e( 'Save changes', 'traceify ' ); ?>83 <?php esc_html_e( 'Save changes', 'traceify-for-woocommerce' ); ?> 83 84 </button> 84 85 </div> … … 94 95 <div class="trcfy-card-header"> 95 96 <div class="trcfy-card-dot"></div> 96 <h3><?php esc_html_e( 'BRANDING', 'traceify ' ); ?></h3>97 </div> 98 <div class="trcfy-row"> 99 <div class="trcfy-row-label"> 100 <strong><?php esc_html_e( 'Store name', 'traceify ' ); ?></strong>101 <span><?php esc_html_e( 'Used in WhatsApp and email message templates.', 'traceify ' ); ?></span>97 <h3><?php esc_html_e( 'BRANDING', 'traceify-for-woocommerce' ); ?></h3> 98 </div> 99 <div class="trcfy-row"> 100 <div class="trcfy-row-label"> 101 <strong><?php esc_html_e( 'Store name', 'traceify-for-woocommerce' ); ?></strong> 102 <span><?php esc_html_e( 'Used in WhatsApp and email message templates.', 'traceify-for-woocommerce' ); ?></span> 102 103 </div> 103 104 <div class="trcfy-row-control"> … … 108 109 <div class="trcfy-row"> 109 110 <div class="trcfy-row-label"> 110 <strong><?php esc_html_e( 'Brand color', 'traceify ' ); ?></strong>111 <span><?php esc_html_e( 'Applied to the tracking page timeline, buttons and focus states.', 'traceify ' ); ?></span>111 <strong><?php esc_html_e( 'Brand color', 'traceify-for-woocommerce' ); ?></strong> 112 <span><?php esc_html_e( 'Applied to the tracking page timeline, buttons and focus states.', 'traceify-for-woocommerce' ); ?></span> 112 113 </div> 113 114 <div class="trcfy-row-control"> … … 126 127 <div class="trcfy-row"> 127 128 <div class="trcfy-row-label"> 128 <strong><?php esc_html_e( 'Logo URL', 'traceify ' ); ?></strong>129 <span><?php esc_html_e( 'Shown at the top of the customer tracking page. Optional.', 'traceify ' ); ?></span>129 <strong><?php esc_html_e( 'Logo URL', 'traceify-for-woocommerce' ); ?></strong> 130 <span><?php esc_html_e( 'Shown at the top of the customer tracking page. Optional.', 'traceify-for-woocommerce' ); ?></span> 130 131 </div> 131 132 <div class="trcfy-row-control"> … … 143 144 <div class="trcfy-card-header"> 144 145 <div class="trcfy-card-dot" style="background:#25D366"></div> 145 <h3><?php esc_html_e( 'CONFIGURATION', 'traceify ' ); ?></h3>146 <h3><?php esc_html_e( 'CONFIGURATION', 'traceify-for-woocommerce' ); ?></h3> 146 147 </div> 147 148 <div class="trcfy-info"> 148 <?php esc_html_e( 'Uses WhatsApp\'s free wa.me link — no API or monthly fee. Clicking opens WhatsApp on your device with the message pre-filled.', 'traceify ' ); ?>149 </div> 150 <div class="trcfy-row"> 151 <div class="trcfy-row-label"> 152 <strong><?php esc_html_e( 'Business number', 'traceify ' ); ?></strong>153 <span><?php esc_html_e( 'Country code + digits only. e.g. 8801712345678', 'traceify ' ); ?></span>149 <?php esc_html_e( 'Uses WhatsApp\'s free wa.me link — no API or monthly fee. Clicking opens WhatsApp on your device with the message pre-filled.', 'traceify-for-woocommerce' ); ?> 150 </div> 151 <div class="trcfy-row"> 152 <div class="trcfy-row-label"> 153 <strong><?php esc_html_e( 'Business number', 'traceify-for-woocommerce' ); ?></strong> 154 <span><?php esc_html_e( 'Country code + digits only. e.g. 8801712345678', 'traceify-for-woocommerce' ); ?></span> 154 155 </div> 155 156 <div class="trcfy-row-control"> … … 161 162 <div class="trcfy-row"> 162 163 <div class="trcfy-row-label"> 163 <strong><?php esc_html_e( 'Customer contact button', 'traceify ' ); ?></strong>164 <span><?php esc_html_e( 'Show a "Chat on WhatsApp" button on the tracking page.', 'traceify ' ); ?></span>164 <strong><?php esc_html_e( 'Customer contact button', 'traceify-for-woocommerce' ); ?></strong> 165 <span><?php esc_html_e( 'Show a "Chat on WhatsApp" button on the tracking page.', 'traceify-for-woocommerce' ); ?></span> 165 166 </div> 166 167 <div class="trcfy-row-control"> … … 174 175 <div class="trcfy-row"> 175 176 <div class="trcfy-row-label"> 176 <strong><?php esc_html_e( 'Button label', 'traceify ' ); ?></strong>177 <span><?php esc_html_e( 'Text shown on the customer-facing WhatsApp button.', 'traceify ' ); ?></span>177 <strong><?php esc_html_e( 'Button label', 'traceify-for-woocommerce' ); ?></strong> 178 <span><?php esc_html_e( 'Text shown on the customer-facing WhatsApp button.', 'traceify-for-woocommerce' ); ?></span> 178 179 </div> 179 180 <div class="trcfy-row-control"> 180 181 <input type="text" name="trcfy_wa_customer_btn_label" class="trcfy-input trcfy-input-wide" 181 value="<?php echo esc_attr( get_option( 'trcfy_wa_customer_btn_label', __( 'Chat with us on WhatsApp', 'traceify ' ) ) ); ?>">182 value="<?php echo esc_attr( get_option( 'trcfy_wa_customer_btn_label', __( 'Chat with us on WhatsApp', 'traceify-for-woocommerce' ) ) ); ?>"> 182 183 </div> 183 184 </div> … … 187 188 <div class="trcfy-card-header"> 188 189 <div class="trcfy-card-dot" style="background:#25D366"></div> 189 <h3><?php esc_html_e( 'MESSAGE TEMPLATES', 'traceify ' ); ?></h3>190 <h3><?php esc_html_e( 'MESSAGE TEMPLATES', 'traceify-for-woocommerce' ); ?></h3> 190 191 </div> 191 192 <div class="trcfy-placeholder"> 192 <?php esc_html_e( 'Placeholders:', 'traceify ' ); ?>193 {customer_name} {order_number} {order_status} {order_total} {store_name} {tracking_url} 193 <?php esc_html_e( 'Placeholders:', 'traceify-for-woocommerce' ); ?> 194 {customer_name} {order_number} {order_status} {order_total} {store_name} {tracking_url} {tracking_number} {tracking_link} {courier_name} 194 195 </div> 195 196 <?php 196 197 $trcfy_wa_statuses = array( 197 'pending' => __( 'Pending Payment', 'traceify ' ),198 'processing' => __( 'Processing', 'traceify ' ),199 'on-hold' => __( 'On Hold', 'traceify ' ),200 'shipped' => __( 'Shipped', 'traceify ' ),201 'completed' => __( 'Completed / Delivered', 'traceify ' ),202 'cancelled' => __( 'Cancelled', 'traceify ' ),198 'pending' => __( 'Pending Payment', 'traceify-for-woocommerce' ), 199 'processing' => __( 'Processing', 'traceify-for-woocommerce' ), 200 'on-hold' => __( 'On Hold', 'traceify-for-woocommerce' ), 201 'shipped' => __( 'Shipped', 'traceify-for-woocommerce' ), 202 'completed' => __( 'Completed / Delivered', 'traceify-for-woocommerce' ), 203 'cancelled' => __( 'Cancelled', 'traceify-for-woocommerce' ), 203 204 ); 204 205 foreach ( $trcfy_wa_statuses as $trcfy_s_key => $trcfy_s_label ) : … … 224 225 <div class="trcfy-card-header"> 225 226 <div class="trcfy-card-dot" style="background:#0EA5E9"></div> 226 <h3><?php esc_html_e( 'PAGE SETUP', 'traceify ' ); ?></h3>227 </div> 228 <div class="trcfy-row"> 229 <div class="trcfy-row-label"> 230 <strong><?php esc_html_e( 'Tracking page', 'traceify ' ); ?></strong>231 <span><?php esc_html_e( 'The page containing the [traceify_tracker] shortcode.', 'traceify ' ); ?></span>227 <h3><?php esc_html_e( 'PAGE SETUP', 'traceify-for-woocommerce' ); ?></h3> 228 </div> 229 <div class="trcfy-row"> 230 <div class="trcfy-row-label"> 231 <strong><?php esc_html_e( 'Tracking page', 'traceify-for-woocommerce' ); ?></strong> 232 <span><?php esc_html_e( 'The page containing the [traceify_tracker] shortcode.', 'traceify-for-woocommerce' ); ?></span> 232 233 </div> 233 234 <div class="trcfy-row-control" style="gap:10px;display:flex;align-items:center;"> 234 235 <select name="trcfy_tracking_page_id" class="trcfy-select"> 235 <option value=""><?php esc_html_e( '— Select —', 'traceify ' ); ?></option>236 <option value=""><?php esc_html_e( '— Select —', 'traceify-for-woocommerce' ); ?></option> 236 237 <?php foreach ( $trcfy_pages as $trcfy_p ) : ?> 237 238 <option value="<?php echo absint( $trcfy_p->ID ); ?>" … … 245 246 rel="noopener noreferrer" 246 247 style="font-size:12px;color:#7C3AED;text-decoration:none;"> 247 <?php esc_html_e( 'View ↗', 'traceify ' ); ?>248 <?php esc_html_e( 'View ↗', 'traceify-for-woocommerce' ); ?> 248 249 </a> 249 250 <?php endif; ?> … … 252 253 <div class="trcfy-row"> 253 254 <div class="trcfy-row-label"> 254 <strong><?php esc_html_e( 'Shortcode', 'traceify ' ); ?></strong>255 <span><?php esc_html_e( 'Add to any page or post to embed the tracking form.', 'traceify ' ); ?></span>256 </div> 257 <div class="trcfy-row-control"> 258 <div class="trcfy-shortcode-pill" title="<?php esc_attr_e( 'Click to copy', 'traceify ' ); ?>">255 <strong><?php esc_html_e( 'Shortcode', 'traceify-for-woocommerce' ); ?></strong> 256 <span><?php esc_html_e( 'Add to any page or post to embed the tracking form.', 'traceify-for-woocommerce' ); ?></span> 257 </div> 258 <div class="trcfy-row-control"> 259 <div class="trcfy-shortcode-pill" title="<?php esc_attr_e( 'Click to copy', 'traceify-for-woocommerce' ); ?>"> 259 260 <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg> 260 261 <code>[traceify_tracker]</code> 261 <span class="trcfy-copied">✓ <?php esc_html_e( 'Copied', 'traceify ' ); ?></span>262 <span class="trcfy-copied">✓ <?php esc_html_e( 'Copied', 'traceify-for-woocommerce' ); ?></span> 262 263 </div> 264 </div> 265 </div> 266 </div> 267 </div> 268 269 <!-- ══ SHIPMENT TRACKING ══ --> 270 <div class="trcfy-section-body<?php echo ( 'shipment' === $trcfy_active ) ? ' active' : ''; ?>" id="section-shipment"> 271 <div class="trcfy-card"> 272 <div class="trcfy-card-header"> 273 <div class="trcfy-card-dot" style="background:#3B82F6"></div> 274 <h3><?php esc_html_e( 'SHIPMENT TRACKING', 'traceify-for-woocommerce' ); ?></h3> 275 </div> 276 <div class="trcfy-row"> 277 <div class="trcfy-row-label"> 278 <strong><?php esc_html_e( 'Enable shipment tracking', 'traceify-for-woocommerce' ); ?></strong> 279 <span><?php esc_html_e( 'Adds a courier + tracking number box to every order and shows it to customers.', 'traceify-for-woocommerce' ); ?></span> 280 </div> 281 <div class="trcfy-row-control"> 282 <label class="trcfy-toggle"> 283 <input type="checkbox" name="trcfy_shipment_enabled" value="yes" 284 <?php checked( 'yes', get_option( 'trcfy_shipment_enabled', 'yes' ) ); ?>> 285 <span class="trcfy-toggle-track"></span> 286 </label> 287 </div> 288 </div> 289 <div class="trcfy-row"> 290 <div class="trcfy-row-label"> 291 <strong><?php esc_html_e( 'Auto-mark as Shipped', 'traceify-for-woocommerce' ); ?></strong> 292 <span><?php esc_html_e( 'When a tracking number is first added to a Processing order, change its status to Shipped.', 'traceify-for-woocommerce' ); ?></span> 293 </div> 294 <div class="trcfy-row-control"> 295 <label class="trcfy-toggle"> 296 <input type="checkbox" name="trcfy_shipment_auto_shipped" value="yes" 297 <?php checked( 'yes', get_option( 'trcfy_shipment_auto_shipped', 'no' ) ); ?>> 298 <span class="trcfy-toggle-track"></span> 299 </label> 300 </div> 301 </div> 302 </div> 303 <div class="trcfy-card"> 304 <div class="trcfy-card-header"> 305 <div class="trcfy-card-dot" style="background:#8B5CF6"></div> 306 <h3><?php esc_html_e( 'CUSTOM COURIER', 'traceify-for-woocommerce' ); ?></h3> 307 </div> 308 <div class="trcfy-placeholder"> 309 <?php esc_html_e( 'Use {tracking_number} in the URL where the number goes, e.g. https://example.com/track?id={tracking_number}', 'traceify-for-woocommerce' ); ?> 310 </div> 311 <div class="trcfy-row"> 312 <div class="trcfy-row-label"> 313 <strong><?php esc_html_e( 'Courier name', 'traceify-for-woocommerce' ); ?></strong> 314 </div> 315 <div class="trcfy-row-control"> 316 <input type="text" name="trcfy_custom_courier_name" class="trcfy-input trcfy-input-wide" 317 value="<?php echo esc_attr( get_option( 'trcfy_custom_courier_name', '' ) ); ?>" 318 placeholder="<?php esc_attr_e( 'e.g. Pathao', 'traceify-for-woocommerce' ); ?>"> 319 </div> 320 </div> 321 <div class="trcfy-row"> 322 <div class="trcfy-row-label"> 323 <strong><?php esc_html_e( 'Tracking URL', 'traceify-for-woocommerce' ); ?></strong> 324 <span><?php esc_html_e( 'Must start with https://', 'traceify-for-woocommerce' ); ?></span> 325 </div> 326 <div class="trcfy-row-control"> 327 <input type="text" name="trcfy_custom_courier_url" class="trcfy-input trcfy-input-wide" 328 value="<?php echo esc_attr( get_option( 'trcfy_custom_courier_url', '' ) ); ?>" 329 placeholder="https://"> 263 330 </div> 264 331 </div> … … 271 338 <div class="trcfy-card-header"> 272 339 <div class="trcfy-card-dot" style="background:#F59E0B"></div> 273 <h3><?php esc_html_e( 'DELIVERY ESTIMATE', 'traceify ' ); ?></h3>274 </div> 275 <div class="trcfy-row"> 276 <div class="trcfy-row-label"> 277 <strong><?php esc_html_e( 'Enable estimated delivery', 'traceify ' ); ?></strong>278 <span><?php esc_html_e( 'Auto-calculate and show delivery date range on the tracking page.', 'traceify ' ); ?></span>340 <h3><?php esc_html_e( 'DELIVERY ESTIMATE', 'traceify-for-woocommerce' ); ?></h3> 341 </div> 342 <div class="trcfy-row"> 343 <div class="trcfy-row-label"> 344 <strong><?php esc_html_e( 'Enable estimated delivery', 'traceify-for-woocommerce' ); ?></strong> 345 <span><?php esc_html_e( 'Auto-calculate and show delivery date range on the tracking page.', 'traceify-for-woocommerce' ); ?></span> 279 346 </div> 280 347 <div class="trcfy-row-control"> … … 288 355 <div class="trcfy-row"> 289 356 <div class="trcfy-row-label"> 290 <strong><?php esc_html_e( 'Processing time', 'traceify ' ); ?></strong>291 <span><?php esc_html_e( 'Days to prepare the order before dispatch.', 'traceify ' ); ?></span>357 <strong><?php esc_html_e( 'Processing time', 'traceify-for-woocommerce' ); ?></strong> 358 <span><?php esc_html_e( 'Days to prepare the order before dispatch.', 'traceify-for-woocommerce' ); ?></span> 292 359 </div> 293 360 <div class="trcfy-row-control"> … … 295 362 min="0" max="30" 296 363 value="<?php echo absint( get_option( 'trcfy_edd_processing_days', 1 ) ); ?>"> 297 <span style="font-size:12px;color:#94A3B8;margin-left:8px;"><?php esc_html_e( 'days', 'traceify ' ); ?></span>298 </div> 299 </div> 300 <div class="trcfy-row"> 301 <div class="trcfy-row-label"> 302 <strong><?php esc_html_e( 'Shipping days range', 'traceify ' ); ?></strong>303 <span><?php esc_html_e( 'Min and max days in transit after dispatch.', 'traceify ' ); ?></span>364 <span style="font-size:12px;color:#94A3B8;margin-left:8px;"><?php esc_html_e( 'days', 'traceify-for-woocommerce' ); ?></span> 365 </div> 366 </div> 367 <div class="trcfy-row"> 368 <div class="trcfy-row-label"> 369 <strong><?php esc_html_e( 'Shipping days range', 'traceify-for-woocommerce' ); ?></strong> 370 <span><?php esc_html_e( 'Min and max days in transit after dispatch.', 'traceify-for-woocommerce' ); ?></span> 304 371 </div> 305 372 <div class="trcfy-row-control" style="gap:8px;display:flex;align-items:center;"> … … 307 374 min="1" max="60" 308 375 value="<?php echo absint( get_option( 'trcfy_edd_min_ship_days', 2 ) ); ?>"> 309 <span style="font-size:12px;color:#94A3B8;"><?php esc_html_e( 'to', 'traceify ' ); ?></span>376 <span style="font-size:12px;color:#94A3B8;"><?php esc_html_e( 'to', 'traceify-for-woocommerce' ); ?></span> 310 377 <input type="number" name="trcfy_edd_max_ship_days" class="trcfy-number-input" 311 378 min="1" max="60" 312 379 value="<?php echo absint( get_option( 'trcfy_edd_max_ship_days', 5 ) ); ?>"> 313 <span style="font-size:12px;color:#94A3B8;"><?php esc_html_e( 'days', 'traceify ' ); ?></span>314 </div> 315 </div> 316 <div class="trcfy-row"> 317 <div class="trcfy-row-label"> 318 <strong><?php esc_html_e( 'Exclude weekends', 'traceify ' ); ?></strong>319 <span><?php esc_html_e( 'Skip Saturday and Sunday when counting delivery days.', 'traceify ' ); ?></span>380 <span style="font-size:12px;color:#94A3B8;"><?php esc_html_e( 'days', 'traceify-for-woocommerce' ); ?></span> 381 </div> 382 </div> 383 <div class="trcfy-row"> 384 <div class="trcfy-row-label"> 385 <strong><?php esc_html_e( 'Exclude weekends', 'traceify-for-woocommerce' ); ?></strong> 386 <span><?php esc_html_e( 'Skip Saturday and Sunday when counting delivery days.', 'traceify-for-woocommerce' ); ?></span> 320 387 </div> 321 388 <div class="trcfy-row-control"> … … 335 402 <div class="trcfy-card-header"> 336 403 <div class="trcfy-card-dot" style="background:#EC4899"></div> 337 <h3><?php esc_html_e( 'EMAIL SETTINGS', 'traceify ' ); ?></h3>404 <h3><?php esc_html_e( 'EMAIL SETTINGS', 'traceify-for-woocommerce' ); ?></h3> 338 405 </div> 339 406 <div class="trcfy-info"> 340 <?php esc_html_e( '"Shipped" is ON by default — WooCommerce has no built-in shipped email. Other statuses are OFF to avoid duplicating WC\'s default emails.', 'traceify ' ); ?>341 </div> 342 <div class="trcfy-row"> 343 <div class="trcfy-row-label"> 344 <strong><?php esc_html_e( 'Enable email notifications', 'traceify ' ); ?></strong>345 <span><?php esc_html_e( 'Master toggle for all Traceify branded emails.', 'traceify ' ); ?></span>407 <?php esc_html_e( '"Shipped" is ON by default — WooCommerce has no built-in shipped email. Other statuses are OFF to avoid duplicating WC\'s default emails.', 'traceify-for-woocommerce' ); ?> 408 </div> 409 <div class="trcfy-row"> 410 <div class="trcfy-row-label"> 411 <strong><?php esc_html_e( 'Enable email notifications', 'traceify-for-woocommerce' ); ?></strong> 412 <span><?php esc_html_e( 'Master toggle for all Traceify branded emails.', 'traceify-for-woocommerce' ); ?></span> 346 413 </div> 347 414 <div class="trcfy-row-control"> … … 357 424 <?php 358 425 $trcfy_email_statuses = array( 359 'shipped' => array( 'label' => 'Shipped', 'on' => 'yes', 'note' => __( 'Recommended ON — no WC default.', 'traceify ' ) ),360 'processing' => array( 'label' => 'Processing', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify ' ) ),361 'completed' => array( 'label' => 'Completed', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify ' ) ),362 'on-hold' => array( 'label' => 'On Hold', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify ' ) ),363 'cancelled' => array( 'label' => 'Cancelled', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify ' ) ),426 'shipped' => array( 'label' => 'Shipped', 'on' => 'yes', 'note' => __( 'Recommended ON — no WC default.', 'traceify-for-woocommerce' ) ), 427 'processing' => array( 'label' => 'Processing', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify-for-woocommerce' ) ), 428 'completed' => array( 'label' => 'Completed', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify-for-woocommerce' ) ), 429 'on-hold' => array( 'label' => 'On Hold', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify-for-woocommerce' ) ), 430 'cancelled' => array( 'label' => 'Cancelled', 'on' => 'no', 'note' => __( 'WC already sends this.', 'traceify-for-woocommerce' ) ), 364 431 ); 365 432 $trcfy_default_subjects = TRCFY_Email_Notifier::default_subjects(); … … 378 445 </div> 379 446 <span class="trcfy-tag <?php echo ( 'yes' === $trcfy_is_enabled ) ? 'trcfy-tag-on' : 'trcfy-tag-off'; ?>"> 380 <?php echo ( 'yes' === $trcfy_is_enabled ) ? esc_html__( 'ON', 'traceify ' ) : esc_html__( 'OFF', 'traceify' ); ?>447 <?php echo ( 'yes' === $trcfy_is_enabled ) ? esc_html__( 'ON', 'traceify-for-woocommerce' ) : esc_html__( 'OFF', 'traceify-for-woocommerce' ); ?> 381 448 </span> 382 449 </div> 383 450 <div class="trcfy-row"> 384 451 <div class="trcfy-row-label"> 385 <strong><?php esc_html_e( 'Send email', 'traceify ' ); ?></strong>452 <strong><?php esc_html_e( 'Send email', 'traceify-for-woocommerce' ); ?></strong> 386 453 <span><?php echo esc_html( $trcfy_s_info['note'] ); ?></span> 387 454 </div> … … 396 463 <div class="trcfy-row trcfy-row-full"> 397 464 <div class="trcfy-row-label"> 398 <strong><?php esc_html_e( 'Email subject', 'traceify ' ); ?></strong>465 <strong><?php esc_html_e( 'Email subject', 'traceify-for-woocommerce' ); ?></strong> 399 466 </div> 400 467 <div class="trcfy-row-control"> -
traceify/trunk/assets/css/public.css
r3716662 r3758167 1 /* WC Order Tracker— Public Styles */1 /* Traceify — Public Styles */ 2 2 :root { 3 3 --trcfy-brand: #7C3AED; … … 330 330 .trcfy-edd-date { font-size: 17px; font-weight: 700; color: var(--trcfy-text); } 331 331 .trcfy-edd-remaining { font-size: 12px; color: var(--trcfy-brand); font-weight: 500; } 332 333 /* ── Shipment tracking ── */ 334 .trcfy-ship-card { border-left: 4px solid var(--trcfy-brand); padding: 16px 20px; } 335 .trcfy-ship-card .trcfy-edd-inner { flex-wrap: wrap; } 336 .trcfy-ship-number { word-break: break-all; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; } 337 .trcfy-ship-btn { margin-left: auto; text-decoration: none; } 338 @media (max-width: 520px) { 339 .trcfy-ship-btn { margin-left: 0; width: 100%; text-align: center; justify-content: center; } 340 } -
traceify/trunk/assets/js/public.js
r3716662 r3758167 1 /* WC Order Tracker— Frontend JS (vanilla, no dependencies) */1 /* Traceify — Frontend JS (vanilla, no dependencies) */ 2 2 (function () { 3 3 'use strict'; -
traceify/trunk/includes/class-trcfy-core.php
r3716662 r3758167 14 14 public function init() { 15 15 // Init new feature classes (always, not just admin). 16 TRCFY_Order_Status::init(); 17 TRCFY_Shipment_Tracking::init(); 16 18 TRCFY_Delivery_Estimator::init(); 17 19 TRCFY_Email_Notifier::init(); -
traceify/trunk/includes/class-trcfy-delivery-estimator.php
r3716662 r3758167 156 156 if ( $diff > 0 ) { 157 157 /* translators: %d = number of days */ 158 $days_remaining = sprintf( _n( '%d day remaining', '%d days remaining', $diff, 'traceify ' ), $diff );158 $days_remaining = sprintf( _n( '%d day remaining', '%d days remaining', $diff, 'traceify-for-woocommerce' ), $diff ); 159 159 } elseif ( 0 === $diff ) { 160 $days_remaining = __( 'Expected today!', 'traceify ' );160 $days_remaining = __( 'Expected today!', 'traceify-for-woocommerce' ); 161 161 } else { 162 $days_remaining = __( 'Expected to have arrived', 'traceify ' );162 $days_remaining = __( 'Expected to have arrived', 'traceify-for-woocommerce' ); 163 163 } 164 164 } … … 188 188 } 189 189 190 if ( isset( $_POST['trcfy_edd_min'] ) ) { 191 $min = sanitize_text_field( wp_unslash( $_POST['trcfy_edd_min'] ) ); 192 $order->update_meta_data( '_trcfy_edd_min', $min ); 193 } 194 if ( isset( $_POST['trcfy_edd_max'] ) ) { 195 $max = sanitize_text_field( wp_unslash( $_POST['trcfy_edd_max'] ) ); 196 $order->update_meta_data( '_trcfy_edd_max', $max ); 197 } 198 $order->save(); 190 // Accept only empty or a valid Y-m-d date; anything else is ignored. 191 $changed = false; 192 foreach ( array( 'min', 'max' ) as $bound ) { 193 $field = 'trcfy_edd_' . $bound; 194 if ( ! isset( $_POST[ $field ] ) ) { 195 continue; 196 } 197 $value = sanitize_text_field( wp_unslash( $_POST[ $field ] ) ); 198 if ( '' !== $value && ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $value ) ) { 199 continue; 200 } 201 $order->update_meta_data( '_trcfy_edd_' . $bound, $value ); 202 $changed = true; 203 } 204 if ( $changed ) { 205 $order->save(); 206 } 199 207 } 200 208 } -
traceify/trunk/includes/class-trcfy-email-notifier.php
r3716662 r3758167 89 89 private static function get_subject( WC_Order $order, $status ) { 90 90 $defaults = array( 91 'processing' => __( 'Your order #{order_number} is being processed', 'traceify ' ),92 'on-hold' => __( 'Your order #{order_number} is on hold', 'traceify ' ),93 'shipped' => __( 'Great news! Your order #{order_number} has been shipped 🚚', 'traceify ' ),94 'completed' => __( 'Your order #{order_number} has been delivered ✅', 'traceify ' ),95 'cancelled' => __( 'Your order #{order_number} has been cancelled', 'traceify ' ),91 'processing' => __( 'Your order #{order_number} is being processed', 'traceify-for-woocommerce' ), 92 'on-hold' => __( 'Your order #{order_number} is on hold', 'traceify-for-woocommerce' ), 93 'shipped' => __( 'Great news! Your order #{order_number} has been shipped 🚚', 'traceify-for-woocommerce' ), 94 'completed' => __( 'Your order #{order_number} has been delivered ✅', 'traceify-for-woocommerce' ), 95 'cancelled' => __( 'Your order #{order_number} has been cancelled', 'traceify-for-woocommerce' ), 96 96 ); 97 97 $template = get_option( 98 98 'trcfy_email_subject_' . $status, 99 isset( $defaults[ $status ] ) ? $defaults[ $status ] : __( 'Your order has been updated', 'traceify ' )99 isset( $defaults[ $status ] ) ? $defaults[ $status ] : __( 'Your order has been updated', 'traceify-for-woocommerce' ) 100 100 ); 101 101 return TRCFY_WhatsApp::replace_placeholders( $template, $order ); … … 135 135 $edd = TRCFY_Delivery_Estimator::get_formatted( $order ); 136 136 if ( $edd ) { 137 $edd_line = '<p style="background:#F0FDF4;border-left:4px solid #22C55E;padding:10px 14px;border-radius:0 6px 6px 0;margin:20px 0;font-size:14px;color:#166534;">📅 <strong>' . esc_html__( 'Estimated Delivery:', 'traceify ' ) . '</strong> ' . esc_html( $edd ) . '</p>';137 $edd_line = '<p style="background:#F0FDF4;border-left:4px solid #22C55E;padding:10px 14px;border-radius:0 6px 6px 0;margin:20px 0;font-size:14px;color:#166534;">📅 <strong>' . esc_html__( 'Estimated Delivery:', 'traceify-for-woocommerce' ) . '</strong> ' . esc_html( $edd ) . '</p>'; 138 138 } 139 } 140 141 // Shipment tracking line. 142 $shipment_line = ''; 143 $shipment = TRCFY_Shipment_Tracking::get_data( $order ); 144 if ( $shipment['available'] ) { 145 $shipment_line = '<p style="background:#F5F3FF;border-left:4px solid ' . esc_attr( $brand_color ) . ';padding:10px 14px;border-radius:0 6px 6px 0;margin:20px 0;font-size:14px;color:#374151;">🚚 <strong>' 146 . esc_html( $shipment['courier'] ? $shipment['courier'] : __( 'Tracking number', 'traceify-for-woocommerce' ) ) . ':</strong> ' 147 . esc_html( $shipment['number'] ); 148 if ( $shipment['url'] ) { 149 $shipment_line .= ' <a href="' . esc_url( $shipment['url'] ) . '" target="_blank" rel="noopener noreferrer" style="color:' . esc_attr( $brand_color ) . ';font-weight:600;">' . esc_html__( 'Track shipment', 'traceify-for-woocommerce' ) . ' →</a>'; 150 } 151 $shipment_line .= '</p>'; 139 152 } 140 153 … … 167 180 public static function default_subjects() { 168 181 return array( 169 'processing' => __( 'Your order #{order_number} is being processed', 'traceify ' ),170 'on-hold' => __( 'Your order #{order_number} is on hold', 'traceify ' ),171 'shipped' => __( 'Great news! Your order #{order_number} has been shipped 🚚', 'traceify ' ),172 'completed' => __( 'Your order #{order_number} has been delivered ✅', 'traceify ' ),173 'cancelled' => __( 'Your order #{order_number} has been cancelled', 'traceify ' ),182 'processing' => __( 'Your order #{order_number} is being processed', 'traceify-for-woocommerce' ), 183 'on-hold' => __( 'Your order #{order_number} is on hold', 'traceify-for-woocommerce' ), 184 'shipped' => __( 'Great news! Your order #{order_number} has been shipped 🚚', 'traceify-for-woocommerce' ), 185 'completed' => __( 'Your order #{order_number} has been delivered ✅', 'traceify-for-woocommerce' ), 186 'cancelled' => __( 'Your order #{order_number} has been cancelled', 'traceify-for-woocommerce' ), 174 187 ); 175 188 } -
traceify/trunk/includes/class-trcfy-installer.php
r3716662 r3758167 31 31 32 32 $page_id = wp_insert_post( array( 33 'post_title' => __( 'Track Your Order', 'traceify ' ),33 'post_title' => __( 'Track Your Order', 'traceify-for-woocommerce' ), 34 34 'post_content' => '<!-- wp:shortcode -->[traceify_tracker]<!-- /wp:shortcode -->', 35 35 'post_status' => 'publish', … … 59 59 'trcfy_wa_number' => '', 60 60 'trcfy_wa_show_customer_btn' => 'yes', 61 'trcfy_wa_customer_btn_label'=> __( 'Chat with us on WhatsApp', 'traceify ' ),62 'trcfy_wa_msg_pending' => __( 'Hi {customer_name}, we received your order #{order_number}. We\'ll start processing it shortly. Thank you for shopping with {store_name}! 🛍️', 'traceify ' ),63 'trcfy_wa_msg_processing' => __( 'Hi {customer_name}, great news! Your order #{order_number} is now being processed and will be dispatched soon. — {store_name}', 'traceify ' ),64 'trcfy_wa_msg_on-hold' => __( 'Hi {customer_name}, your order #{order_number} is on hold. Please contact us for more details. — {store_name}', 'traceify ' ),65 'trcfy_wa_msg_shipped' => __( 'Hi {customer_name}, your order #{order_number} has been shipped and is on its way! 🚚 — {store_name}', 'traceify ' ),66 'trcfy_wa_msg_completed' => __( 'Hi {customer_name}, your order #{order_number} has been delivered. We hope you love it! 💜 — {store_name}', 'traceify ' ),67 'trcfy_wa_msg_cancelled' => __( 'Hi {customer_name}, your order #{order_number} has been cancelled. Contact us if this was a mistake. — {store_name}', 'traceify ' ),61 'trcfy_wa_customer_btn_label'=> __( 'Chat with us on WhatsApp', 'traceify-for-woocommerce' ), 62 'trcfy_wa_msg_pending' => __( 'Hi {customer_name}, we received your order #{order_number}. We\'ll start processing it shortly. Thank you for shopping with {store_name}! 🛍️', 'traceify-for-woocommerce' ), 63 'trcfy_wa_msg_processing' => __( 'Hi {customer_name}, great news! Your order #{order_number} is now being processed and will be dispatched soon. — {store_name}', 'traceify-for-woocommerce' ), 64 'trcfy_wa_msg_on-hold' => __( 'Hi {customer_name}, your order #{order_number} is on hold. Please contact us for more details. — {store_name}', 'traceify-for-woocommerce' ), 65 'trcfy_wa_msg_shipped' => __( 'Hi {customer_name}, your order #{order_number} has been shipped and is on its way! 🚚 — {store_name}', 'traceify-for-woocommerce' ), 66 'trcfy_wa_msg_completed' => __( 'Hi {customer_name}, your order #{order_number} has been delivered. We hope you love it! 💜 — {store_name}', 'traceify-for-woocommerce' ), 67 'trcfy_wa_msg_cancelled' => __( 'Hi {customer_name}, your order #{order_number} has been cancelled. Contact us if this was a mistake. — {store_name}', 'traceify-for-woocommerce' ), 68 68 // Estimated Delivery Date. 69 69 'trcfy_edd_enabled' => 'yes', … … 72 72 'trcfy_edd_max_ship_days' => '5', 73 73 'trcfy_edd_exclude_weekends' => 'yes', 74 // Shipment tracking. 75 'trcfy_shipment_enabled' => 'yes', 76 'trcfy_shipment_auto_shipped' => 'no', 77 'trcfy_custom_courier_name' => '', 78 'trcfy_custom_courier_url' => '', 74 79 // Email notifications. 75 80 'trcfy_email_enabled' => 'yes', -
traceify/trunk/includes/class-trcfy-order-tracker.php
r3716662 r3758167 55 55 56 56 $steps = array( 57 array( 'key' => 'placed', 'label' => __( 'Order Placed', 'traceify ' ), 'icon' => '🛍️' ),58 array( 'key' => 'processing', 'label' => __( 'Processing', 'traceify ' ), 'icon' => '⚙️' ),59 array( 'key' => 'shipped', 'label' => __( 'Shipped', 'traceify ' ), 'icon' => '🚚' ),60 array( 'key' => 'delivered', 'label' => __( 'Delivered', 'traceify ' ), 'icon' => '✅' ),57 array( 'key' => 'placed', 'label' => __( 'Order Placed', 'traceify-for-woocommerce' ), 'icon' => '🛍️' ), 58 array( 'key' => 'processing', 'label' => __( 'Processing', 'traceify-for-woocommerce' ), 'icon' => '⚙️' ), 59 array( 'key' => 'shipped', 'label' => __( 'Shipped', 'traceify-for-woocommerce' ), 'icon' => '🚚' ), 60 array( 'key' => 'delivered', 'label' => __( 'Delivered', 'traceify-for-woocommerce' ), 'icon' => '✅' ), 61 61 ); 62 62 … … 100 100 private static function get_special_status_timeline( $status ) { 101 101 $labels = array( 102 'cancelled' => array( 'label' => __( 'Order Cancelled', 'traceify ' ), 'icon' => '❌' ),103 'refunded' => array( 'label' => __( 'Order Refunded', 'traceify ' ), 'icon' => '↩️' ),104 'failed' => array( 'label' => __( 'Payment Failed', 'traceify ' ), 'icon' => '⚠️' ),102 'cancelled' => array( 'label' => __( 'Order Cancelled', 'traceify-for-woocommerce' ), 'icon' => '❌' ), 103 'refunded' => array( 'label' => __( 'Order Refunded', 'traceify-for-woocommerce' ), 'icon' => '↩️' ), 104 'failed' => array( 'label' => __( 'Payment Failed', 'traceify-for-woocommerce' ), 'icon' => '⚠️' ), 105 105 ); 106 106 $info = $labels[ $status ]; … … 152 152 'timeline' => self::get_timeline( $order ), 153 153 'edd' => TRCFY_Delivery_Estimator::get_data( $order ), 154 'shipment' => TRCFY_Shipment_Tracking::get_data( $order ), 154 155 ); 155 156 } -
traceify/trunk/includes/class-trcfy-whatsapp.php
r3716662 r3758167 78 78 $message = sprintf( 79 79 /* translators: %s = order number */ 80 __( 'Hi, I have a question about my order #%s', 'traceify ' ),80 __( 'Hi, I have a question about my order #%s', 'traceify-for-woocommerce' ), 81 81 $order->get_order_number() 82 82 ); 83 83 } else { 84 $message = __( 'Hi, I need help with my order.', 'traceify ' );84 $message = __( 'Hi, I need help with my order.', 'traceify-for-woocommerce' ); 85 85 } 86 86 … … 93 93 * Supported tags: {customer_name} {order_number} {order_status} 94 94 * {order_total} {store_name} {tracking_url} 95 * {tracking_number} {tracking_link} {courier_name} 95 96 * 96 97 * @param string $template … … 102 103 $tracking_url = $tracking_page_id ? get_permalink( $tracking_page_id ) : site_url(); 103 104 105 $shipment = TRCFY_Shipment_Tracking::get_data( $order ); 106 104 107 $search = array( 108 '{tracking_number}', 109 '{tracking_link}', 110 '{courier_name}', 105 111 '{customer_name}', 106 112 '{order_number}', … … 111 117 ); 112 118 $replace = array( 119 sanitize_text_field( $shipment['number'] ), 120 $shipment['url'], 121 sanitize_text_field( $shipment['courier'] ), 113 122 sanitize_text_field( $order->get_billing_first_name() ), 114 123 sanitize_text_field( $order->get_order_number() ), -
traceify/trunk/public/class-trcfy-public.php
r3716662 r3758167 23 23 24 24 // Only load on the tracking page (or wherever the shortcode is used). 25 if ( ! is_page( $tracking_page_id) && ! $this->current_page_has_shortcode() ) {25 if ( ! ( $tracking_page_id && is_page( $tracking_page_id ) ) && ! $this->current_page_has_shortcode() ) { 26 26 return; 27 27 } … … 70 70 $submitted = false; 71 71 72 // Process form submission (GET method, WooCommerce-style). 73 if ( isset( $_GET['trcfy_order_id'], $_GET['trcfy_billing_email'], $_GET['trcfy_nonce'] ) ) { 72 // Process lookup (GET, WooCommerce-style). This is a read-only lookup that 73 // requires order number + matching billing email, so no nonce is used — 74 // a nonce here would break on cached pages and adds no protection. 75 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only lookup, verified by order number + billing email. 76 if ( isset( $_GET['trcfy_order_id'], $_GET['trcfy_billing_email'] ) ) { 74 77 $submitted = true; 75 78 76 if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['trcfy_nonce'] ) ), 'trcfy_track_order' ) ) { 77 $error = __( 'Security check failed. Please try again.', 'traceify' ); 78 } else { 79 $order_id = sanitize_text_field( wp_unslash( $_GET['trcfy_order_id'] ) ); 80 $email = sanitize_email( wp_unslash( $_GET['trcfy_billing_email'] ) ); 81 $order = TRCFY_Order_Tracker::get_order( $order_id, $email ); 79 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 80 $order_id = sanitize_text_field( wp_unslash( $_GET['trcfy_order_id'] ) ); 81 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 82 $email = sanitize_email( wp_unslash( $_GET['trcfy_billing_email'] ) ); 83 $order = TRCFY_Order_Tracker::get_order( $order_id, $email ); 82 84 83 if ( ! $order ) { 84 $error = __( 'No order found. Please check your order number and billing email and try again.', 'traceify' ); 85 } 85 if ( ! $order ) { 86 $error = __( 'No order found. Please check your order number and billing email and try again.', 'traceify-for-woocommerce' ); 86 87 } 87 88 } … … 92 93 'error' => $error, 93 94 'submitted' => $submitted, 94 'nonce' => wp_create_nonce( 'trcfy_track_order' ),95 95 'logo_url' => esc_url( get_option( 'trcfy_brand_logo_url', '' ) ), 96 96 'store_name' => esc_html( get_option( 'trcfy_store_name', get_bloginfo( 'name' ) ) ), 97 97 'wa_number' => get_option( 'trcfy_wa_number', '' ), 98 98 'show_wa_btn'=> 'yes' === get_option( 'trcfy_wa_show_customer_btn', 'yes' ), 99 'wa_btn_label'=> esc_html( get_option( 'trcfy_wa_customer_btn_label', __( 'Chat with us on WhatsApp', 'traceify ' ) ) ),99 'wa_btn_label'=> esc_html( get_option( 'trcfy_wa_customer_btn_label', __( 'Chat with us on WhatsApp', 'traceify-for-woocommerce' ) ) ), 100 100 ); 101 101 -
traceify/trunk/public/views/tracking-page.php
r3716662 r3758167 6 6 * Receives $data array from TRCFY_Public::render_shortcode(). 7 7 * All dynamic values are already sanitized — escape on output only. 8 * Nonce verification for the tracking form is handled in render_shortcode() 9 * before this template is loaded; $_GET access here is read-only prefill. 8 * $_GET access here is read-only prefill of the lookup form. 10 9 */ 11 10 if ( ! defined( 'ABSPATH' ) ) { exit; } … … 21 20 <?php endif; ?> 22 21 <h2 class="trcfy-title"> 23 <?php esc_html_e( 'Track Your Order', 'traceify ' ); ?>22 <?php esc_html_e( 'Track Your Order', 'traceify-for-woocommerce' ); ?> 24 23 </h2> 25 24 </div> … … 36 35 37 36 <p class="trcfy-search-intro"> 38 <?php esc_html_e( 'Enter your order number and billing email address to check your order status.', 'traceify ' ); ?>37 <?php esc_html_e( 'Enter your order number and billing email address to check your order status.', 'traceify-for-woocommerce' ); ?> 39 38 </p> 40 39 41 40 <form method="GET" action="" class="trcfy-form" id="trcfy-tracking-form" novalidate> 42 <input type="hidden" name="trcfy_nonce" value="<?php echo esc_attr( $data['nonce'] ); ?>">43 41 44 42 <div class="trcfy-field"> 45 43 <label for="trcfy_order_id" class="trcfy-label"> 46 <?php esc_html_e( 'Order Number', 'traceify ' ); ?>44 <?php esc_html_e( 'Order Number', 'traceify-for-woocommerce' ); ?> 47 45 <span class="trcfy-required" aria-hidden="true">*</span> 48 46 </label> 49 47 <?php 50 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified in render_shortcode(); this is prefill only.48 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only prefill of the lookup form. 51 49 $trcfy_prefill_order_id = isset( $_GET['trcfy_order_id'] ) ? sanitize_text_field( wp_unslash( $_GET['trcfy_order_id'] ) ) : ''; 52 50 ?> … … 56 54 class="trcfy-input" 57 55 inputmode="numeric" 58 placeholder="<?php esc_attr_e( 'e.g. 1234', 'traceify ' ); ?>"56 placeholder="<?php esc_attr_e( 'e.g. 1234', 'traceify-for-woocommerce' ); ?>" 59 57 value="<?php echo esc_attr( $trcfy_prefill_order_id ); ?>" 60 58 required … … 64 62 <div class="trcfy-field"> 65 63 <label for="trcfy_billing_email" class="trcfy-label"> 66 <?php esc_html_e( 'Billing Email Address', 'traceify ' ); ?>64 <?php esc_html_e( 'Billing Email Address', 'traceify-for-woocommerce' ); ?> 67 65 <span class="trcfy-required" aria-hidden="true">*</span> 68 66 </label> 69 67 <?php 70 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified in render_shortcode(); this is prefill only.68 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only prefill of the lookup form. 71 69 $trcfy_prefill_email = isset( $_GET['trcfy_billing_email'] ) ? sanitize_email( wp_unslash( $_GET['trcfy_billing_email'] ) ) : ''; 72 70 ?> … … 75 73 name="trcfy_billing_email" 76 74 class="trcfy-input" 77 placeholder="<?php esc_attr_e( 'you@example.com', 'traceify ' ); ?>"75 placeholder="<?php esc_attr_e( 'you@example.com', 'traceify-for-woocommerce' ); ?>" 78 76 value="<?php echo esc_attr( $trcfy_prefill_email ); ?>" 79 77 required … … 83 81 <button type="submit" class="trcfy-btn trcfy-btn-primary"> 84 82 <span class="trcfy-btn-icon">🔍</span> 85 <?php esc_html_e( 'Track Order', 'traceify ' ); ?>83 <?php esc_html_e( 'Track Order', 'traceify-for-woocommerce' ); ?> 86 84 </button> 87 85 </form> … … 100 98 <div class="trcfy-order-meta"> 101 99 <div> 102 <span class="trcfy-meta-label"><?php esc_html_e( 'Order', 'traceify ' ); ?></span>100 <span class="trcfy-meta-label"><?php esc_html_e( 'Order', 'traceify-for-woocommerce' ); ?></span> 103 101 <span class="trcfy-meta-value">#<?php echo esc_html( $trcfy_d['order_number'] ); ?></span> 104 102 </div> 105 103 <div> 106 <span class="trcfy-meta-label"><?php esc_html_e( 'Placed on', 'traceify ' ); ?></span>104 <span class="trcfy-meta-label"><?php esc_html_e( 'Placed on', 'traceify-for-woocommerce' ); ?></span> 107 105 <span class="trcfy-meta-value"><?php echo esc_html( $trcfy_d['date_created'] ); ?></span> 108 106 </div> 109 107 <div> 110 <span class="trcfy-meta-label"><?php esc_html_e( 'Status', 'traceify ' ); ?></span>108 <span class="trcfy-meta-label"><?php esc_html_e( 'Status', 'traceify-for-woocommerce' ); ?></span> 111 109 <span class="trcfy-status-badge trcfy-status-<?php echo esc_attr( $trcfy_status ); ?>"> 112 110 <?php echo esc_html( $trcfy_d['status_label'] ); ?> … … 162 160 <span class="trcfy-edd-icon" aria-hidden="true">📅</span> 163 161 <div class="trcfy-edd-content"> 164 <span class="trcfy-edd-label"><?php esc_html_e( 'Estimated Delivery', 'traceify ' ); ?></span>162 <span class="trcfy-edd-label"><?php esc_html_e( 'Estimated Delivery', 'traceify-for-woocommerce' ); ?></span> 165 163 <span class="trcfy-edd-date"><?php echo esc_html( $trcfy_d['edd']['formatted'] ); ?></span> 166 164 <?php if ( $trcfy_d['edd']['days_remaining'] ) : ?> … … 172 170 <?php endif; ?> 173 171 172 <!-- ── Shipment tracking ── --> 173 <?php if ( ! $trcfy_is_special && ! empty( $trcfy_d['shipment']['available'] ) ) : ?> 174 <div class="trcfy-card trcfy-ship-card"> 175 <div class="trcfy-edd-inner"> 176 <span class="trcfy-edd-icon" aria-hidden="true">🚚</span> 177 <div class="trcfy-edd-content"> 178 <span class="trcfy-edd-label"> 179 <?php 180 echo esc_html( 181 $trcfy_d['shipment']['courier'] 182 ? sprintf( 183 /* translators: %s = courier name */ 184 __( 'Shipped with %s', 'traceify-for-woocommerce' ), 185 $trcfy_d['shipment']['courier'] 186 ) 187 : __( 'Tracking number', 'traceify-for-woocommerce' ) 188 ); 189 ?> 190 </span> 191 <span class="trcfy-edd-date trcfy-ship-number"><?php echo esc_html( $trcfy_d['shipment']['number'] ); ?></span> 192 </div> 193 <?php if ( $trcfy_d['shipment']['url'] ) : ?> 194 <a href="<?php echo esc_url( $trcfy_d['shipment']['url'] ); ?>" 195 target="_blank" rel="noopener noreferrer" 196 class="trcfy-btn trcfy-btn-primary trcfy-ship-btn"> 197 <?php esc_html_e( 'Track shipment', 'traceify-for-woocommerce' ); ?> ↗ 198 </a> 199 <?php endif; ?> 200 </div> 201 </div> 202 <?php endif; ?> 203 174 204 <!-- ── Order items ── --> 175 205 <div class="trcfy-card trcfy-items-card"> 176 <h3 class="trcfy-card-title"><?php esc_html_e( 'Order Summary', 'traceify ' ); ?></h3>206 <h3 class="trcfy-card-title"><?php esc_html_e( 'Order Summary', 'traceify-for-woocommerce' ); ?></h3> 177 207 <div class="trcfy-items-list"> 178 208 <?php foreach ( $trcfy_d['items'] as $trcfy_item ) : ?> … … 191 221 printf( 192 222 /* translators: %d = quantity */ 193 esc_html__( 'Qty: %d', 'traceify ' ),223 esc_html__( 'Qty: %d', 'traceify-for-woocommerce' ), 194 224 absint( $trcfy_item['qty'] ) 195 225 ); … … 204 234 <?php if ( $trcfy_d['shipping_method'] ) : ?> 205 235 <div class="trcfy-total-row"> 206 <span><?php esc_html_e( 'Shipping', 'traceify ' ); ?></span>236 <span><?php esc_html_e( 'Shipping', 'traceify-for-woocommerce' ); ?></span> 207 237 <span><?php echo esc_html( $trcfy_d['shipping_method'] ); ?></span> 208 238 </div> 209 239 <?php endif; ?> 210 240 <div class="trcfy-total-row trcfy-total-grand"> 211 <span><?php esc_html_e( 'Total', 'traceify ' ); ?></span>241 <span><?php esc_html_e( 'Total', 'traceify-for-woocommerce' ); ?></span> 212 242 <span><?php echo wp_kses_post( $trcfy_d['total'] ); ?></span> 213 243 </div> … … 218 248 <?php if ( ! empty( $trcfy_d['notes'] ) ) : ?> 219 249 <div class="trcfy-card trcfy-notes-card"> 220 <h3 class="trcfy-card-title"><?php esc_html_e( 'Order Updates', 'traceify ' ); ?></h3>250 <h3 class="trcfy-card-title"><?php esc_html_e( 'Order Updates', 'traceify-for-woocommerce' ); ?></h3> 221 251 <?php foreach ( $trcfy_d['notes'] as $trcfy_note ) : ?> 222 252 <div class="trcfy-note"> … … 231 261 <?php if ( $trcfy_d['shipping_address'] ) : ?> 232 262 <div class="trcfy-card trcfy-address-card"> 233 <h3 class="trcfy-card-title"><?php esc_html_e( 'Shipping To', 'traceify ' ); ?></h3>263 <h3 class="trcfy-card-title"><?php esc_html_e( 'Shipping To', 'traceify-for-woocommerce' ); ?></h3> 234 264 <address class="trcfy-address"><?php echo wp_kses_post( $trcfy_d['shipping_address'] ); ?></address> 235 265 </div> … … 251 281 <!-- ── Track another ── --> 252 282 <div class="trcfy-track-another"> 253 <a href="<?php echo esc_url( remove_query_arg( array( 'trcfy_order_id', 'trcfy_billing_email' , 'trcfy_nonce') ) ); ?>"283 <a href="<?php echo esc_url( remove_query_arg( array( 'trcfy_order_id', 'trcfy_billing_email' ) ) ); ?>" 254 284 class="trcfy-link"> 255 ← <?php esc_html_e( 'Track another order', 'traceify ' ); ?>285 ← <?php esc_html_e( 'Track another order', 'traceify-for-woocommerce' ); ?> 256 286 </a> 257 287 </div> -
traceify/trunk/readme.txt
r3716662 r3758167 1 1 === Traceify – Order Tracking for WooCommerce === 2 2 Contributors: webtendhq,devhasib 3 Tags: woocommerce, order tracking, whatsapp, estimated delivery, order status3 Tags: woocommerce, order tracking, shipment tracking, whatsapp, estimated delivery 4 4 Requires at least: 6.0 5 5 Tested up to: 7.1 6 6 Requires PHP: 7.4 7 Stable tag: 1.0. 07 Stable tag: 1.0.1 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Branded order tracking page for WooCommerce with WhatsApp updates, estimated delivery dates, and email notifications — no API or monthly fee.11 Branded order tracking for WooCommerce with courier links, WhatsApp updates, delivery dates and email alerts — no API or monthly fee. 12 12 13 13 == Description == 14 14 15 15 **Traceify** gives your WooCommerce store a professional, branded order-tracking experience — and the tools to proactively keep customers updated via WhatsApp and email. 16 17 📖 **[Documentation](https://webtend.net/docs/traceify-doc.html)** 18 16 19 17 20 = Customer-Facing Features = … … 20 23 * **Visual progress timeline** — Order Placed → Processing → Shipped → Delivered 21 24 * **Estimated Delivery Date** — auto-calculated date range shown prominently on the tracking page 25 * **Shipment tracking** — courier name, tracking number and a "Track shipment" button that opens the courier's site 22 26 * **Order summary** — items with images, quantities, totals, and shipping address 23 27 * **Customer order notes** — shows notes you have added to the order … … 28 32 * **WhatsApp column** on the WooCommerce orders list — one click to send a status update to any customer 29 33 * **WhatsApp meta box** on every order detail page — preview the message then send 34 * **Shipment Tracking meta box** — pick a courier and enter the tracking number on any order 30 35 * **Estimated Delivery Date meta box** — manually override the auto-calculated delivery date per order 31 36 * **Branded HTML email notifications** — send beautiful order-status emails on status change 32 37 * **Per-status message templates** for both WhatsApp and email 33 * **Template placeholders**: `{customer_name}` `{order_number}` `{order_status}` `{order_total}` `{store_name}` `{tracking_url}` 38 * **Template placeholders**: `{customer_name}` `{order_number}` `{order_status}` `{order_total}` `{store_name}` `{tracking_url}` `{tracking_number}` `{tracking_link}` `{courier_name}` 39 40 = Shipment Tracking = 41 42 Add a courier and tracking number to any order. Built-in couriers: DHL, FedEx, UPS, USPS and Steadfast. Add your own courier (for example Pathao or RedX) under Traceify → Shipment Tracking with a URL such as `https://example.com/track?id={tracking_number}`. The tracking number and link appear on the customer's tracking page, in Traceify emails and in WhatsApp messages. Optionally mark the order as Shipped automatically when a tracking number is first added. 34 43 35 44 = Estimated Delivery Date = … … 50 59 * **WhatsApp** — business number, show/hide customer contact button, per-status message templates 51 60 * **Tracking Page** — page assignment, shortcode reference 61 * **Shipment Tracking** — enable/disable, auto-mark as Shipped, custom courier name and tracking URL 52 62 * **Delivery EDD** — processing days, min/max shipping days, weekend exclusion toggle 53 63 * **Email Notifications** — master toggle, per-status on/off, custom subject lines … … 86 96 No. By default, only the "Shipped" status email is enabled — WooCommerce has no built-in email for that status. Processing, Completed, Cancelled, and On Hold emails are off by default. 87 97 98 = Can I add a courier that is not in the list? = 99 100 Yes. Go to Traceify → Shipment Tracking → Custom Courier and enter a name and a tracking URL containing `{tracking_number}`. Developers can also use the `trcfy_couriers` filter. 101 102 = Where does the "Shipped" status come from? = 103 104 WooCommerce has no Shipped status. Traceify registers one (`wc-shipped`) only if no other plugin has already done so. 105 88 106 = Is customer data secure? = 89 107 90 Yes. Order lookup requires both the order number and the billing email address, preventing order enumeration. All inputs are sanitized , all outputs are escaped, and forms arenonce-protected.108 Yes. Order lookup requires both the order number and the billing email address, preventing order enumeration. All inputs are sanitized and all outputs are escaped. Admin settings and order actions are capability-checked and nonce-protected. 91 109 92 110 == Screenshots == … … 104 122 == Changelog == 105 123 124 = 1.0.1 = 125 * New: Shipment tracking — courier + tracking number per order with a "Track shipment" link. 126 * New: Built-in couriers (DHL, FedEx, UPS, USPS, Steadfast) plus a custom courier with your own tracking URL. 127 * New: Tracking details on the customer tracking page and in branded emails. 128 * New: WhatsApp placeholders `{tracking_number}`, `{tracking_link}` and `{courier_name}`. 129 * New: Optional "Auto-mark as Shipped" when a tracking number is first added. 130 * New: `trcfy_couriers` filter to add or change couriers in code. 131 132 133 106 134 = 1.0.0 — 2026-09-05 = 107 135 * Initial release. … … 116 144 == Upgrade Notice == 117 145 146 = 1.0.1 = 147 Adds shipment tracking (courier + tracking number). Review Traceify → Shipment Tracking after updating. 148 149 118 150 = 1.0.0 = 119 151 Initial release. -
traceify/trunk/templates/email-notification.php
r3716662 r3758167 48 48 printf( 49 49 /* translators: %s = order number */ 50 esc_html__( 'Order #%s Update', 'traceify ' ),50 esc_html__( 'Order #%s Update', 'traceify-for-woocommerce' ), 51 51 esc_html( $order->get_order_number() ) 52 52 ); … … 57 57 printf( 58 58 /* translators: %s = customer first name */ 59 esc_html__( 'Hi %s, here\'s the latest on your order.', 'traceify ' ),59 esc_html__( 'Hi %s, here\'s the latest on your order.', 'traceify-for-woocommerce' ), 60 60 esc_html( $order->get_billing_first_name() ) 61 61 ); … … 85 85 <?php endif; ?> 86 86 87 <!-- Shipment tracking block --> 88 <?php if ( ! empty( $shipment_line ) ) : ?> 89 <tr> 90 <td style="padding:0 40px;"> 91 <?php echo wp_kses_post( $shipment_line ); ?> 92 </td> 93 </tr> 94 <?php endif; ?> 95 87 96 <!-- Order items --> 88 97 <tr> 89 98 <td style="padding:24px 40px 0;"> 90 99 <p style="font-size:13px;font-weight:600;color:#6B7280;text-transform:uppercase;letter-spacing:0.06em;margin:0 0 10px;"> 91 <?php esc_html_e( 'Order Summary', 'traceify ' ); ?>100 <?php esc_html_e( 'Order Summary', 'traceify-for-woocommerce' ); ?> 92 101 </p> 93 102 <table width="100%" cellpadding="0" cellspacing="0"> 94 103 <thead> 95 104 <tr> 96 <th style="font-size:12px;color:#9CA3AF;font-weight:500;text-align:left;padding-bottom:6px;"><?php esc_html_e( 'Product', 'traceify ' ); ?></th>97 <th style="font-size:12px;color:#9CA3AF;font-weight:500;text-align:right;padding-bottom:6px;"><?php esc_html_e( 'Qty', 'traceify ' ); ?></th>98 <th style="font-size:12px;color:#9CA3AF;font-weight:500;text-align:right;padding-bottom:6px;"><?php esc_html_e( 'Price', 'traceify ' ); ?></th>105 <th style="font-size:12px;color:#9CA3AF;font-weight:500;text-align:left;padding-bottom:6px;"><?php esc_html_e( 'Product', 'traceify-for-woocommerce' ); ?></th> 106 <th style="font-size:12px;color:#9CA3AF;font-weight:500;text-align:right;padding-bottom:6px;"><?php esc_html_e( 'Qty', 'traceify-for-woocommerce' ); ?></th> 107 <th style="font-size:12px;color:#9CA3AF;font-weight:500;text-align:right;padding-bottom:6px;"><?php esc_html_e( 'Price', 'traceify-for-woocommerce' ); ?></th> 99 108 </tr> 100 109 </thead> … … 104 113 <tfoot> 105 114 <tr> 106 <td colspan="2" style="padding-top:10px;font-size:15px;font-weight:700;color:#111827;"><?php esc_html_e( 'Total', 'traceify ' ); ?></td>115 <td colspan="2" style="padding-top:10px;font-size:15px;font-weight:700;color:#111827;"><?php esc_html_e( 'Total', 'traceify-for-woocommerce' ); ?></td> 107 116 <td style="padding-top:10px;font-size:15px;font-weight:700;color:#111827;text-align:right;"><?php echo wp_kses_post( $order->get_formatted_order_total() ); ?></td> 108 117 </tr> … … 118 127 <a href="<?php echo esc_url( $tracking_url . '?trcfy_order_id=' . $order->get_order_number() ); ?>" 119 128 style="display:inline-block;background:<?php echo esc_attr( $brand_color ); ?>;color:#ffffff;text-decoration:none;font-size:15px;font-weight:600;padding:13px 28px;border-radius:8px;"> 120 <?php esc_html_e( 'Track Your Order →', 'traceify ' ); ?>129 <?php esc_html_e( 'Track Your Order →', 'traceify-for-woocommerce' ); ?> 121 130 </a> 122 131 </td> … … 131 140 printf( 132 141 /* translators: %s = store name */ 133 esc_html__( 'You received this email because you placed an order at %s.', 'traceify ' ),142 esc_html__( 'You received this email because you placed an order at %s.', 'traceify-for-woocommerce' ), 134 143 esc_html( $store_name ) 135 144 ); -
traceify/trunk/traceify-for-woocommerce.php
r3716672 r3758167 3 3 * Plugin Name: Traceify – Order Tracking for WooCommerce 4 4 * Plugin URI: https://webtend.net/ 5 * Description: Replace WooCommerce's plain order tracking with a beautiful branded page. Send one-click WhatsApp status updates to customers — no API or monthly fee needed.6 * Version: 1.0. 05 * Description: Branded order tracking and shipment tracking for WooCommerce. Add courier tracking numbers and send one-click WhatsApp status updates — no API or monthly fee needed. 6 * Version: 1.0.1 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 7.4 9 * Requires Plugins: woocommerce 9 10 * Author: WebTend 10 11 * Author URI: https://webtend.net/ 11 12 * License: GPL v2 or later 12 13 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 13 * Text Domain: traceify 14 * Domain Path: /languages 14 * Text Domain: traceify-for-woocommerce 15 15 * WC requires at least: 7.0 16 16 * WC tested up to: 9.9 … … 26 26 27 27 // ── Constants ────────────────────────────────────────────────────────────── 28 define( 'TRCFY_VERSION', '1.0. 0' );28 define( 'TRCFY_VERSION', '1.0.1' ); 29 29 define( 'TRCFY_PATH', plugin_dir_path( __FILE__ ) ); 30 30 define( 'TRCFY_URL', plugin_dir_url( __FILE__ ) ); … … 42 42 function trcfy_woocommerce_missing_notice() { 43 43 echo '<div class="notice notice-error"><p>' . 44 esc_html__( ' WC Order Tracker requires WooCommerce to be installed and activated.', 'traceify' ) .44 esc_html__( 'Traceify requires WooCommerce to be installed and activated.', 'traceify-for-woocommerce' ) . 45 45 '</p></div>'; 46 46 } … … 48 48 function trcfy_check_woocommerce() { 49 49 if ( ! class_exists( 'WooCommerce' ) ) { 50 // Only show a notice. deactivate_plugins() is not loaded on the front end 51 // and would cause a fatal error there. 50 52 add_action( 'admin_notices', 'trcfy_woocommerce_missing_notice' ); 51 deactivate_plugins( TRCFY_BASENAME );52 53 return false; 53 54 } … … 60 61 deactivate_plugins( TRCFY_BASENAME ); 61 62 wp_die( 62 esc_html__( ' WC Order Tracker requires WooCommerce. Please install WooCommerce first.', 'traceify' ),63 esc_html__( 'Plugin Activation Error', 'traceify ' ),63 esc_html__( 'Traceify requires WooCommerce. Please install WooCommerce first.', 'traceify-for-woocommerce' ), 64 esc_html__( 'Plugin Activation Error', 'traceify-for-woocommerce' ), 64 65 array( 'back_link' => true ) 65 66 ); … … 83 84 require_once TRCFY_PATH . 'includes/class-trcfy-installer.php'; 84 85 require_once TRCFY_PATH . 'includes/class-trcfy-order-tracker.php'; 86 require_once TRCFY_PATH . 'includes/class-trcfy-order-status.php'; 87 require_once TRCFY_PATH . 'includes/class-trcfy-shipment-tracking.php'; 85 88 require_once TRCFY_PATH . 'includes/class-trcfy-whatsapp.php'; 86 89 require_once TRCFY_PATH . 'includes/class-trcfy-delivery-estimator.php';
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)