PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.4
WooCommerce v10.9.4
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Admin / Features / Fulfillments / FulfillmentOrderNotes.php
woocommerce / src / Admin / Features / Fulfillments Last commit date
DataStore 1 month ago Providers 3 months ago Fulfillment.php 1 month ago FulfillmentException.php 3 months ago FulfillmentOrderNotes.php 3 months ago FulfillmentUtils.php 2 months ago FulfillmentsController.php 3 months ago FulfillmentsManager.php 2 months ago FulfillmentsRenderer.php 1 month ago FulfillmentsSettings.php 3 months ago FulfillmentsTracker.php 3 months ago OrderFulfillmentsRestController.php 1 month ago ShippingProviders.php 3 months ago
FulfillmentOrderNotes.php
400 lines
1 <?php
2 /**
3 * Fulfillment Order Notes.
4 *
5 * Adds order notes for fulfillment lifecycle events.
6 *
7 * @package WooCommerce\Admin\Features\Fulfillments
8 */
9
10 declare( strict_types=1 );
11
12 namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
13
14 use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
15
16 /**
17 * FulfillmentOrderNotes class.
18 *
19 * Hooks into fulfillment lifecycle actions and adds filterable order notes
20 * for fulfillment state changes.
21 *
22 * @since 10.7.0
23 */
24 class FulfillmentOrderNotes {
25
26 /**
27 * Register hooks for fulfillment order notes.
28 */
29 public function register(): void {
30 add_action( 'woocommerce_fulfillment_after_create', array( $this, 'add_fulfillment_created_note' ), 10, 1 );
31 add_action( 'woocommerce_fulfillment_after_update', array( $this, 'add_fulfillment_updated_note' ), 10, 3 );
32 add_action( 'woocommerce_fulfillment_after_delete', array( $this, 'add_fulfillment_deleted_note' ), 10, 1 );
33 }
34
35 /**
36 * Add an order note when a fulfillment is created.
37 *
38 * @param Fulfillment $fulfillment The fulfillment object.
39 */
40 public function add_fulfillment_created_note( Fulfillment $fulfillment ): void {
41 $order = $fulfillment->get_order();
42 if ( ! $order instanceof \WC_Order ) {
43 return;
44 }
45
46 $items_text = $this->format_items( $fulfillment, $order );
47 $tracking_text = $this->format_tracking( $fulfillment );
48 $status = $fulfillment->get_status() ?? 'unfulfilled';
49 $status_label = $this->get_fulfillment_status_label( $status );
50
51 $message = sprintf(
52 /* translators: 1: fulfillment ID, 2: fulfillment status label, 3: item list */
53 __( 'Fulfillment #%1$d created (status: %2$s). Items: %3$s.', 'woocommerce' ),
54 $fulfillment->get_id(),
55 $status_label,
56 $items_text
57 );
58
59 if ( ! empty( $tracking_text ) ) {
60 $message .= ' ' . sprintf(
61 /* translators: %s: tracking number */
62 __( 'Tracking: %s.', 'woocommerce' ),
63 $tracking_text
64 );
65 }
66
67 /**
68 * Filters the order note message when a fulfillment is created.
69 *
70 * Return null to cancel the note.
71 *
72 * @since 10.7.0
73 *
74 * @param string|null $message The note message.
75 * @param Fulfillment $fulfillment The fulfillment object.
76 * @param \WC_Order $order The order object.
77 */
78 $message = apply_filters( 'woocommerce_fulfillment_created_order_note', $message, $fulfillment, $order );
79 $message = $this->normalize_note_message( $message );
80
81 if ( null === $message ) {
82 return;
83 }
84
85 $order->add_order_note( $message, 0, false, array( 'note_group' => OrderNoteGroup::FULFILLMENT ) );
86 }
87
88 /**
89 * Add an order note when a fulfillment is updated.
90 *
91 * Only adds a note when tracked properties change (status, items,
92 * tracking number, tracking URL, shipping provider). If the status
93 * changed, a dedicated status change note is added instead.
94 *
95 * @param Fulfillment $fulfillment The fulfillment object (post-update).
96 * @param array $changes Changes as returned by Fulfillment::get_changes() before
97 * save. Core data props at top level, meta under 'meta_data'.
98 * @param string $previous_status The fulfillment status before the update.
99 */
100 public function add_fulfillment_updated_note( Fulfillment $fulfillment, array $changes = array(), string $previous_status = 'unfulfilled' ): void {
101 if ( empty( $changes ) ) {
102 return;
103 }
104
105 $order = $fulfillment->get_order();
106 if ( ! $order instanceof \WC_Order ) {
107 return;
108 }
109
110 // If status changed, add a dedicated status change note.
111 if ( array_key_exists( 'status', $changes ) ) {
112 $new_status = $changes['status'] ?? 'unfulfilled';
113 $this->add_fulfillment_status_changed_note( $fulfillment, $order, $previous_status, $new_status );
114 return;
115 }
116
117 $items_text = $this->format_items( $fulfillment, $order );
118 $tracking_text = $this->format_tracking( $fulfillment );
119
120 $message = sprintf(
121 /* translators: 1: fulfillment ID, 2: item list */
122 __( 'Fulfillment #%1$d updated. Items: %2$s.', 'woocommerce' ),
123 $fulfillment->get_id(),
124 $items_text
125 );
126
127 if ( ! empty( $tracking_text ) ) {
128 $message .= ' ' . sprintf(
129 /* translators: %s: tracking number */
130 __( 'Tracking: %s.', 'woocommerce' ),
131 $tracking_text
132 );
133 }
134
135 /**
136 * Filters the order note message when a fulfillment is updated.
137 *
138 * Return null to cancel the note.
139 *
140 * @since 10.7.0
141 *
142 * @param string|null $message The note message.
143 * @param Fulfillment $fulfillment The fulfillment object.
144 * @param \WC_Order $order The order object.
145 */
146 $message = apply_filters( 'woocommerce_fulfillment_updated_order_note', $message, $fulfillment, $order );
147 $message = $this->normalize_note_message( $message );
148
149 if ( null === $message ) {
150 return;
151 }
152
153 $order->add_order_note( $message, 0, false, array( 'note_group' => OrderNoteGroup::FULFILLMENT ) );
154 }
155
156 /**
157 * Add an order note when a fulfillment is deleted.
158 *
159 * @param Fulfillment $fulfillment The fulfillment object.
160 */
161 public function add_fulfillment_deleted_note( Fulfillment $fulfillment ): void {
162 $order = $fulfillment->get_order();
163 if ( ! $order instanceof \WC_Order ) {
164 return;
165 }
166
167 $message = sprintf(
168 /* translators: %d: fulfillment ID */
169 __( 'Fulfillment #%d deleted.', 'woocommerce' ),
170 $fulfillment->get_id()
171 );
172
173 /**
174 * Filters the order note message when a fulfillment is deleted.
175 *
176 * Return null to cancel the note.
177 *
178 * @since 10.7.0
179 *
180 * @param string|null $message The note message.
181 * @param Fulfillment $fulfillment The fulfillment object.
182 * @param \WC_Order $order The order object.
183 */
184 $message = apply_filters( 'woocommerce_fulfillment_deleted_order_note', $message, $fulfillment, $order );
185 $message = $this->normalize_note_message( $message );
186
187 if ( null === $message ) {
188 return;
189 }
190
191 $order->add_order_note( $message, 0, false, array( 'note_group' => OrderNoteGroup::FULFILLMENT ) );
192 }
193
194 /**
195 * Add an order note when the order fulfillment status changes.
196 *
197 * Called from FulfillmentsManager when the `_fulfillment_status` meta changes.
198 *
199 * @param \WC_Order $order The order object.
200 * @param string $old_status The previous fulfillment status.
201 * @param string $new_status The new fulfillment status.
202 */
203 public function add_order_fulfillment_status_changed_note( \WC_Order $order, string $old_status, string $new_status ): void {
204 $old_status_label = $this->get_order_fulfillment_status_label( $old_status );
205 $new_status_label = $this->get_order_fulfillment_status_label( $new_status );
206
207 $message = sprintf(
208 /* translators: 1: old fulfillment status label, 2: new fulfillment status label */
209 __( 'Order fulfillment status changed from %1$s to %2$s.', 'woocommerce' ),
210 $old_status_label,
211 $new_status_label
212 );
213
214 /**
215 * Filters the order note message when the order fulfillment status changes.
216 *
217 * Return null to cancel the note.
218 *
219 * @since 10.7.0
220 *
221 * @param string|null $message The note message.
222 * @param \WC_Order $order The order object.
223 * @param string $old_status The previous fulfillment status.
224 * @param string $new_status The new fulfillment status.
225 */
226 $message = apply_filters( 'woocommerce_fulfillment_order_status_changed_order_note', $message, $order, $old_status, $new_status );
227 $message = $this->normalize_note_message( $message );
228
229 if ( null === $message ) {
230 return;
231 }
232
233 $order->add_order_note( $message, 0, false, array( 'note_group' => OrderNoteGroup::FULFILLMENT ) );
234 }
235
236 /**
237 * Add a status change note for a fulfillment.
238 *
239 * @param Fulfillment $fulfillment The fulfillment object.
240 * @param \WC_Order $order The order object.
241 * @param string $old_status The previous status.
242 * @param string $new_status The new status.
243 */
244 private function add_fulfillment_status_changed_note( Fulfillment $fulfillment, \WC_Order $order, string $old_status, string $new_status ): void {
245 $old_status_label = $this->get_fulfillment_status_label( $old_status );
246 $new_status_label = $this->get_fulfillment_status_label( $new_status );
247
248 $message = sprintf(
249 /* translators: 1: fulfillment ID, 2: old status label, 3: new status label */
250 __( 'Fulfillment #%1$d status changed from %2$s to %3$s.', 'woocommerce' ),
251 $fulfillment->get_id(),
252 $old_status_label,
253 $new_status_label
254 );
255
256 /**
257 * Filters the order note message when a fulfillment status changes.
258 *
259 * Return null to cancel the note.
260 *
261 * @since 10.7.0
262 *
263 * @param string|null $message The note message.
264 * @param Fulfillment $fulfillment The fulfillment object.
265 * @param \WC_Order $order The order object.
266 * @param string $old_status The previous status.
267 * @param string $new_status The new status.
268 */
269 $message = apply_filters( 'woocommerce_fulfillment_status_changed_order_note', $message, $fulfillment, $order, $old_status, $new_status );
270 $message = $this->normalize_note_message( $message );
271
272 if ( null === $message ) {
273 return;
274 }
275
276 $order->add_order_note( $message, 0, false, array( 'note_group' => OrderNoteGroup::FULFILLMENT ) );
277 }
278
279 /**
280 * Format fulfillment items as a comma-separated string.
281 *
282 * @param Fulfillment $fulfillment The fulfillment object.
283 * @param \WC_Order $order The order object.
284 * @return string Formatted items string.
285 */
286 private function format_items( Fulfillment $fulfillment, \WC_Order $order ): string {
287 $items = $fulfillment->get_items();
288 $order_items = $order->get_items();
289 $parts = array();
290
291 foreach ( $items as $item ) {
292 $item_id = isset( $item['item_id'] ) ? (int) $item['item_id'] : 0;
293 $qty = isset( $item['qty'] ) ? (int) $item['qty'] : 0;
294 $name = '';
295
296 foreach ( $order_items as $order_item ) {
297 if ( (int) $order_item->get_id() === $item_id ) {
298 $name = $order_item->get_name();
299 break;
300 }
301 }
302
303 if ( empty( $name ) ) {
304 $name = sprintf(
305 /* translators: %d: item ID */
306 __( 'Item #%d', 'woocommerce' ),
307 $item_id
308 );
309 }
310
311 $parts[] = sprintf( '%s x%s', $name, $qty );
312 }
313
314 return implode( ', ', $parts );
315 }
316
317 /**
318 * Format the tracking information from a fulfillment.
319 *
320 * Includes the tracking number, shipping provider, and tracking URL when available.
321 *
322 * @param Fulfillment $fulfillment The fulfillment object.
323 * @return string The formatted tracking information, or empty string if no tracking number is present.
324 */
325 private function format_tracking( Fulfillment $fulfillment ): string {
326 $tracking_number = $fulfillment->get_tracking_number();
327 $shipping_provider = $fulfillment->get_shipment_provider();
328 $tracking_url = $fulfillment->get_tracking_url();
329
330 if ( null === $tracking_number ) {
331 return '';
332 }
333
334 $parts = array( $tracking_number );
335
336 if ( null !== $shipping_provider ) {
337 $parts[] = sprintf(
338 /* translators: %s: shipping provider name */
339 __( 'Provider: %s', 'woocommerce' ),
340 $shipping_provider
341 );
342 }
343
344 if ( null !== $tracking_url ) {
345 $parts[] = sprintf(
346 /* translators: %s: tracking URL */
347 __( 'URL: %s', 'woocommerce' ),
348 $tracking_url
349 );
350 }
351
352 return implode( ', ', $parts );
353 }
354
355 /**
356 * Get the display label for a fulfillment status key.
357 *
358 * @param string $status The fulfillment status key.
359 * @return string The status label, or the key itself if no label is found.
360 */
361 private function get_fulfillment_status_label( string $status ): string {
362 $statuses = FulfillmentUtils::get_fulfillment_statuses();
363 return $statuses[ $status ]['label'] ?? $status;
364 }
365
366 /**
367 * Get the display label for an order fulfillment status key.
368 *
369 * @param string $status The order fulfillment status key.
370 * @return string The status label, or the key itself if no label is found.
371 */
372 private function get_order_fulfillment_status_label( string $status ): string {
373 $statuses = FulfillmentUtils::get_order_fulfillment_statuses();
374 return $statuses[ $status ]['label'] ?? $status;
375 }
376
377 /**
378 * Sanitize an order note message.
379 *
380 * Ensures the message is a string and strips any disallowed HTML tags.
381 *
382 * @param mixed $message The original message.
383 * @return string|null The sanitized message, or null if the message is not valid.
384 */
385 private function normalize_note_message( $message ): ?string {
386 if ( ! $message || ! is_string( $message ) ) {
387 return null;
388 }
389
390 $message = wp_kses_post( $message );
391 $message = trim( $message );
392
393 if ( '' === $message ) {
394 return null;
395 }
396
397 return $message;
398 }
399 }
400