PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Automation / Integrations / WooCommerce / Fields / OrderFieldsFactory.php
mailpoet / lib / Automation / Integrations / WooCommerce / Fields Last commit date
CustomerFieldsFactory.php 11 months ago CustomerOrderFieldsFactory.php 1 year ago CustomerReviewFieldsFactory.php 1 year ago CustomerSubscriptionFieldsFactory.php 11 months ago OrderFieldsFactory.php 2 months ago TermOptionsBuilder.php 2 years ago TermParentsLoader.php 1 year ago index.php 3 years ago
OrderFieldsFactory.php
462 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Automation\Integrations\WooCommerce\Fields;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use DateTimeImmutable;
9 use MailPoet\Automation\Engine\Data\Field;
10 use MailPoet\Automation\Engine\WordPress;
11 use MailPoet\Automation\Integrations\WooCommerce\Payloads\OrderPayload;
12 use MailPoet\Automation\Integrations\WooCommerce\WooCommerce;
13 use WC_Order;
14 use WC_Order_Item_Product;
15 use WC_Payment_Gateway;
16 use WC_Product;
17 use WP_Post;
18
19 class OrderFieldsFactory {
20 /** @var TermOptionsBuilder */
21 private $termOptionsBuilder;
22
23 /** @var TermParentsLoader */
24 private $termParentsLoader;
25
26 /** @var WordPress */
27 private $wordPress;
28
29 /** @var WooCommerce */
30 private $wooCommerce;
31
32 public function __construct(
33 TermOptionsBuilder $termOptionsBuilder,
34 TermParentsLoader $termParentsLoader,
35 WordPress $wordPress,
36 WooCommerce $wooCommerce
37 ) {
38 $this->termOptionsBuilder = $termOptionsBuilder;
39 $this->termParentsLoader = $termParentsLoader;
40 $this->wordPress = $wordPress;
41 $this->wooCommerce = $wooCommerce;
42 }
43
44 /** @return Field[] */
45 public function getFields(): array {
46 return array_merge(
47 [
48 new Field(
49 'woocommerce:order:billing-company',
50 Field::TYPE_STRING,
51 __('Billing company', 'mailpoet'),
52 function (OrderPayload $payload) {
53 return $payload->getOrder()->get_billing_company();
54 }
55 ),
56 new Field(
57 'woocommerce:order:billing-phone',
58 Field::TYPE_STRING,
59 __('Billing phone', 'mailpoet'),
60 function (OrderPayload $payload) {
61 return $payload->getOrder()->get_billing_phone();
62 }
63 ),
64 new Field(
65 'woocommerce:order:billing-city',
66 Field::TYPE_STRING,
67 __('Billing city', 'mailpoet'),
68 function (OrderPayload $payload) {
69 return $payload->getOrder()->get_billing_city();
70 }
71 ),
72 new Field(
73 'woocommerce:order:billing-postcode',
74 Field::TYPE_STRING,
75 __('Billing postcode', 'mailpoet'),
76 function (OrderPayload $payload) {
77 return $payload->getOrder()->get_billing_postcode();
78 }
79 ),
80 new Field(
81 'woocommerce:order:billing-state',
82 Field::TYPE_STRING,
83 __('Billing state/county', 'mailpoet'),
84 function (OrderPayload $payload) {
85 return $payload->getOrder()->get_billing_state();
86 }
87 ),
88 new Field(
89 'woocommerce:order:billing-country',
90 Field::TYPE_ENUM,
91 __('Billing country', 'mailpoet'),
92 function (OrderPayload $payload) {
93 return $payload->getOrder()->get_billing_country();
94 },
95 [
96 'options' => $this->getBillingCountryOptions(),
97 ]
98 ),
99 new Field(
100 'woocommerce:order:shipping-company',
101 Field::TYPE_STRING,
102 __('Shipping company', 'mailpoet'),
103 function (OrderPayload $payload) {
104 return $payload->getOrder()->get_shipping_company();
105 }
106 ),
107 new Field(
108 'woocommerce:order:shipping-phone',
109 Field::TYPE_STRING,
110 __('Shipping phone', 'mailpoet'),
111 function (OrderPayload $payload) {
112 return $payload->getOrder()->get_shipping_phone();
113 }
114 ),
115 new Field(
116 'woocommerce:order:shipping-city',
117 Field::TYPE_STRING,
118 __('Shipping city', 'mailpoet'),
119 function (OrderPayload $payload) {
120 return $payload->getOrder()->get_shipping_city();
121 }
122 ),
123 new Field(
124 'woocommerce:order:shipping-postcode',
125 Field::TYPE_STRING,
126 __('Shipping postcode', 'mailpoet'),
127 function (OrderPayload $payload) {
128 return $payload->getOrder()->get_shipping_postcode();
129 }
130 ),
131 new Field(
132 'woocommerce:order:shipping-state',
133 Field::TYPE_STRING,
134 __('Shipping state/county', 'mailpoet'),
135 function (OrderPayload $payload) {
136 return $payload->getOrder()->get_shipping_state();
137 }
138 ),
139 new Field(
140 'woocommerce:order:shipping-country',
141 Field::TYPE_ENUM,
142 __('Shipping country', 'mailpoet'),
143 function (OrderPayload $payload) {
144 return $payload->getOrder()->get_shipping_country();
145 },
146 [
147 'options' => $this->getShippingCountryOptions(),
148 ]
149 ),
150 new Field(
151 'woocommerce:order:created-date',
152 Field::TYPE_DATETIME,
153 __('Created date', 'mailpoet'),
154 function (OrderPayload $payload) {
155 return $payload->getOrder()->get_date_created();
156 }
157 ),
158 new Field(
159 'woocommerce:order:created-via',
160 Field::TYPE_ENUM,
161 __('Created via', 'mailpoet'),
162 function (OrderPayload $payload) {
163 return $payload->getOrder()->get_created_via();
164 },
165 [
166 'options' => $this->getOrderCreatedViaOptions(),
167 ]
168 ),
169 new Field(
170 'woocommerce:order:paid-date',
171 Field::TYPE_DATETIME,
172 __('Paid date', 'mailpoet'),
173 function (OrderPayload $payload) {
174 return $payload->getOrder()->get_date_paid();
175 }
176 ),
177 new Field(
178 'woocommerce:order:customer-note',
179 Field::TYPE_STRING,
180 __('Customer provided note', 'mailpoet'),
181 function (OrderPayload $payload) {
182 return $payload->getOrder()->get_customer_note();
183 }
184 ),
185 new Field(
186 'woocommerce:order:payment-method',
187 Field::TYPE_ENUM,
188 __('Payment method', 'mailpoet'),
189 function (OrderPayload $payload) {
190 return $payload->getOrder()->get_payment_method();
191 },
192 [
193 'options' => $this->getOrderPaymentOptions(),
194 ]
195 ),
196 new Field(
197 'woocommerce:order:status',
198 Field::TYPE_ENUM,
199 __('Status', 'mailpoet'),
200 function (OrderPayload $payload) {
201 return $payload->getOrder()->get_status();
202 },
203 [
204 'options' => $this->getOrderStatusOptions(),
205 ]
206 ),
207 new Field(
208 'woocommerce:order:total',
209 Field::TYPE_NUMBER,
210 __('Total', 'mailpoet'),
211 function (OrderPayload $payload) {
212 return (float)$payload->getOrder()->get_total();
213 }
214 ),
215 new Field(
216 'woocommerce:order:coupons',
217 Field::TYPE_ENUM_ARRAY,
218 __('Used coupons', 'mailpoet'),
219 function (OrderPayload $payload) {
220 return $payload->getOrder()->get_coupon_codes();
221 },
222 [
223 'options' => $this->getCouponOptions(),
224 ]
225 ),
226 new Field(
227 'woocommerce:order:is-first-order',
228 Field::TYPE_BOOLEAN,
229 __('Is first order', 'mailpoet'),
230 function (OrderPayload $payload) {
231 $order = $payload->getOrder();
232 return !$this->previousOrderExists($order);
233 }
234 ),
235 new Field(
236 'woocommerce:order:categories',
237 Field::TYPE_ENUM_ARRAY,
238 __('Categories', 'mailpoet'),
239 function (OrderPayload $payload) {
240 $products = $this->getProducts($payload->getOrder());
241 $categoryIds = [];
242 foreach ($products as $product) {
243 $categoryIds = array_merge($categoryIds, $product->get_category_ids());
244 }
245 $categoryIds = array_merge($categoryIds, $this->termParentsLoader->getParentIds($categoryIds));
246 sort($categoryIds);
247 return array_unique($categoryIds);
248 },
249 [
250 'options' => $this->termOptionsBuilder->getTermOptions('product_cat'),
251 ]
252 ),
253 new Field(
254 'woocommerce:order:tags',
255 Field::TYPE_ENUM_ARRAY,
256 __('Tags', 'mailpoet'),
257 function (OrderPayload $payload) {
258 $products = $this->getProducts($payload->getOrder());
259 $tagIds = [];
260 foreach ($products as $product) {
261 $tagIds = array_merge($tagIds, $product->get_tag_ids());
262 }
263 sort($tagIds);
264 return array_unique($tagIds);
265 },
266 [
267 'options' => $this->termOptionsBuilder->getTermOptions('product_tag'),
268 ]
269 ),
270 new Field(
271 'woocommerce:order:products',
272 Field::TYPE_ENUM_ARRAY,
273 __('Products', 'mailpoet'),
274 function (OrderPayload $payload) {
275 $products = $this->getProducts($payload->getOrder());
276 return array_map(function (WC_Product $product) {
277 return $product->get_id();
278 }, $products);
279 },
280 [
281 'options' => $this->getProductOptions(),
282 ]
283 ),
284 new Field(
285 'woocommerce:order:product-types',
286 Field::TYPE_ENUM_ARRAY,
287 __('Product types', 'mailpoet'),
288 function (OrderPayload $payload) {
289 $products = $this->getProducts($payload->getOrder());
290 $types = array_map(function (WC_Product $product) {
291 return $product->get_type();
292 }, $products);
293 return array_values(array_unique($types));
294 },
295 [
296 'options' => $this->getProductTypeOptions(),
297 ]
298 ),
299 ]
300 );
301 }
302
303 private function getBillingCountryOptions(): array {
304 $options = [];
305 foreach (WC()->countries->get_allowed_countries() as $code => $name) {
306 $options[] = ['id' => $code, 'name' => $name];
307 }
308 return $options;
309 }
310
311 private function getShippingCountryOptions(): array {
312 $options = [];
313 foreach (WC()->countries->get_shipping_countries() as $code => $name) {
314 $options[] = ['id' => $code, 'name' => $name];
315 }
316 return $options;
317 }
318
319 private function getOrderPaymentOptions(): array {
320 $gateways = WC()->payment_gateways()->get_available_payment_gateways();
321 $options = [];
322 foreach ($gateways as $gateway) {
323 if ($gateway instanceof WC_Payment_Gateway && $gateway->enabled === 'yes') {
324 $options[] = ['id' => $gateway->id, 'name' => $gateway->title];
325 }
326 }
327 return $options;
328 }
329
330 private function getOrderStatusOptions(): array {
331 $statuses = $this->wooCommerce->wcGetOrderStatuses();
332 $options = [];
333 foreach ($statuses as $id => $name) {
334 $options[] = [
335 // WooCommerce order statuses are internally saved with 'wc-' prefix:
336 // https://github.com/woocommerce/woocommerce/blob/9c58f198/plugins/woocommerce/includes/wc-order-functions.php#L98-L109
337 // However, when getting the status from the order object, it doesn't have the prefix.
338 // To make the status codes consistent, we remove the prefix here and only work with unprefixed statuses.
339 'id' => substr($id, 0, 3) === 'wc-' ? substr($id, 3) : $id,
340 'name' => $name,
341 ];
342 }
343 return $options;
344 }
345
346 private function getCouponOptions(): array {
347 $coupons = $this->wordPress->getPosts([
348 'post_type' => 'shop_coupon',
349 'post_status' => 'publish',
350 'posts_per_page' => -1,
351 'orderby' => 'name',
352 'order' => 'asc',
353 ]);
354
355 $options = [];
356 foreach ($coupons as $coupon) {
357 if ($coupon instanceof WP_Post) {
358 // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
359 $options[] = ['id' => $coupon->post_title, 'name' => $coupon->post_title];
360 }
361 }
362 return $options;
363 }
364
365 private function previousOrderExists(WC_Order $order): bool {
366 $dateCreated = $order->get_date_created() ?? new DateTimeImmutable('now', $this->wordPress->wpTimezone());
367 $query = [
368 'date_created' => '<=' . $dateCreated->getTimestamp(),
369 'limit' => 2,
370 'return' => 'ids',
371 ];
372
373 if ($order->get_customer_id() > 0) {
374 $query['customer_id'] = $order->get_customer_id();
375 } else {
376 $query['billing_email'] = $order->get_billing_email();
377 }
378
379 $orderIds = (array)$this->wooCommerce->wcGetOrders($query);
380 return count($orderIds) > 1 && min($orderIds) < $order->get_id();
381 }
382
383 /** @return WC_Product[] */
384 private function getProducts(WC_Order $order): array {
385 $products = [];
386 foreach ($order->get_items() as $item) {
387 if (!$item instanceof WC_Order_Item_Product) {
388 continue;
389 }
390
391 $product = $item->get_product();
392 if (!$product instanceof WC_Product) {
393 continue;
394 }
395 if (!$product->is_type('variation')) {
396 $products[] = $product;
397 continue;
398 }
399
400 $parentProduct = $this->wooCommerce->wcGetProduct($product->get_parent_id());
401 if (!$parentProduct instanceof WC_Product) {
402 continue;
403 }
404 $products[] = $parentProduct;
405 }
406 return array_unique($products);
407 }
408
409 private function getProductOptions(): array {
410 global $wpdb;
411 $products = $wpdb->get_results(
412 "
413 SELECT ID, post_title
414 FROM {$wpdb->posts}
415 WHERE post_type = 'product'
416 AND post_status = 'publish'
417 ORDER BY post_title ASC
418 ",
419 ARRAY_A
420 );
421
422 return array_map(function ($product) {
423 /** @var array{ID:int, post_title:string} $product */
424 $id = $product['ID'];
425 $title = $product['post_title'];
426 return ['id' => (int)$id, 'name' => "$title (#$id)"];
427 }, (array)$products);
428 }
429
430 private function getProductTypeOptions(): array {
431 if (!function_exists('wc_get_product_types')) {
432 return [];
433 }
434 $options = [];
435 foreach (wc_get_product_types() as $id => $name) {
436 $options[] = ['id' => $id, 'name' => $name];
437 }
438 return $options;
439 }
440
441 private function getOrderCreatedViaOptions(): array {
442 // Common sources for WooCommerce orders
443 // https://github.com/search?q=repo%3Awoocommerce%2Fwoocommerce+order-%3Eset_created_via&type=code
444 $sources = [
445 'checkout' => __('Checkout', 'mailpoet'),
446 'admin' => __('Admin', 'mailpoet'),
447 'rest-api' => __('REST API', 'mailpoet'),
448 'webhook' => __('Webhook', 'mailpoet'),
449 'subscription' => __('Subscription', 'mailpoet'),
450 'pos' => __('POS', 'mailpoet'),
451 'checkout-draft' => __('Checkout Draft', 'mailpoet'),
452 ];
453
454 $options = [];
455 foreach ($sources as $id => $name) {
456 $options[] = ['id' => $id, 'name' => $name];
457 }
458
459 return $options;
460 }
461 }
462