PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.3 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 / API / JSON / v1 / SubscriberStats.php
mailpoet / lib / API / JSON / v1 Last commit date
Analytics.php 3 years ago AutomatedLatestContent.php 2 months ago AutomaticEmails.php 3 years ago Captcha.php 1 year ago Coupons.php 2 years ago CustomFields.php 2 months ago DynamicProducts.php 1 year ago DynamicSegments.php 2 months ago FeatureFlags.php 3 years ago Forms.php 2 months ago Help.php 1 year ago ImportExport.php 2 months ago Mailer.php 1 year ago NewsletterLinks.php 2 months ago NewsletterTemplates.php 2 months ago Newsletters.php 2 months ago Premium.php 10 months ago RedirectResponse.php 1 year ago Segments.php 2 months ago SendingQueue.php 2 months ago Services.php 6 months ago Settings.php 2 months ago Setup.php 1 year ago StatisticsExport.php 3 months ago SubscriberStats.php 1 month ago Subscribers.php 2 months ago Tags.php 3 years ago UserFlags.php 2 years ago WoocommerceProductVariations.php 2 months ago WoocommerceSettings.php 3 years ago index.php 3 years ago
SubscriberStats.php
384 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\API\JSON\v1;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\API\JSON\Endpoint as APIEndpoint;
9 use MailPoet\API\JSON\Error as APIError;
10 use MailPoet\Config\AccessControl;
11 use MailPoet\Entities\CustomFieldEntity;
12 use MailPoet\Entities\StatisticsUnsubscribeEntity;
13 use MailPoet\Entities\SubscriberEntity;
14 use MailPoet\Statistics\StatisticsUnsubscribesRepository;
15 use MailPoet\Statistics\UnsubscribeReasonTracker;
16 use MailPoet\Subscribers\Source;
17 use MailPoet\Subscribers\Statistics\SubscriberStatistics;
18 use MailPoet\Subscribers\Statistics\SubscriberStatisticsRepository;
19 use MailPoet\Subscribers\SubscribersRepository;
20 use MailPoet\WooCommerce\Helper;
21 use MailPoet\WP\Functions as WPFunctions;
22 use MailPoetVendor\Carbon\Carbon;
23
24 class SubscriberStats extends APIEndpoint {
25 public $permissions = [
26 'global' => AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
27 ];
28
29 /** @var SubscribersRepository */
30 private $subscribersRepository;
31
32 /** @var SubscriberStatisticsRepository */
33 private $subscribersStatisticsRepository;
34
35 /** @var Helper */
36 private $wooCommerceHelper;
37
38 /** @var WPFunctions */
39 private $wp;
40
41 /** @var StatisticsUnsubscribesRepository */
42 private $statisticsUnsubscribesRepository;
43
44 /** @var UnsubscribeReasonTracker */
45 private $unsubscribeReasonTracker;
46
47 public function __construct(
48 SubscribersRepository $subscribersRepository,
49 SubscriberStatisticsRepository $subscribersStatisticsRepository,
50 Helper $wooCommerceHelper,
51 WPFunctions $wp,
52 StatisticsUnsubscribesRepository $statisticsUnsubscribesRepository,
53 UnsubscribeReasonTracker $unsubscribeReasonTracker
54 ) {
55 $this->subscribersRepository = $subscribersRepository;
56 $this->subscribersStatisticsRepository = $subscribersStatisticsRepository;
57 $this->wooCommerceHelper = $wooCommerceHelper;
58 $this->wp = $wp;
59 $this->statisticsUnsubscribesRepository = $statisticsUnsubscribesRepository;
60 $this->unsubscribeReasonTracker = $unsubscribeReasonTracker;
61 }
62
63 public function get($data) {
64 $subscriber = isset($data['subscriber_id'])
65 ? $this->subscribersRepository->findOneById((int)$data['subscriber_id'])
66 : null;
67 if (!$subscriber instanceof SubscriberEntity) {
68 return $this->errorResponse([
69 APIError::NOT_FOUND => __('This subscriber does not exist.', 'mailpoet'),
70 ]);
71 }
72 $isWooActive = $this->wooCommerceHelper->isWooCommerceActive();
73 $isWoocommerceUser = (bool)$subscriber->getIsWoocommerceUser();
74 $dateFormat = 'Y-m-d H:i:s';
75 $subscribedAt = $subscriber->getLastSubscribedAt() ?: $subscriber->getCreatedAt();
76 $response = [
77 'email' => $subscriber->getEmail(),
78 'engagement_score' => $subscriber->getEngagementScore(),
79 'engagement_score_type' => $this->subscribersStatisticsRepository->getEngagementScoreType($subscriber),
80 'is_woo_active' => $isWooActive,
81 'is_woocommerce_user' => $isWoocommerceUser,
82 'avatar_url' => $this->wp->getAvatarUrl($subscriber->getEmail(), ['size' => 96]) ?: null,
83 'subscribed_at' => $subscribedAt instanceof \DateTimeInterface ? $subscribedAt->format($dateFormat) : null,
84 'source_label' => $this->getSourceLabel($subscriber->getSource()),
85 ];
86
87 $statsMapper = function(SubscriberStatistics $statistics, string $key, string $timeframe) {
88 return [
89 'key' => $key,
90 'timeframe' => $timeframe,
91 'total_sent' => $statistics->getTotalSentCount(),
92 'open' => $statistics->getOpenCount(),
93 'machine_open' => $statistics->getMachineOpenCount(),
94 'click' => $statistics->getClickCount(),
95 'woocommerce' => $statistics->getWooCommerceRevenue() ? $statistics->getWooCommerceRevenue()->asArray() : null,
96 ];
97 };
98
99 $now = Carbon::now();
100 $periods = [
101 [
102 'key' => '7_days',
103 'label' => __('7 days', 'mailpoet'),
104 'start' => $now->copy()->subDays(7),
105 ],
106 [
107 'key' => '30_days',
108 'label' => __('30 days', 'mailpoet'),
109 'start' => $now->copy()->subDays(30),
110 ],
111 [
112 'key' => '3_months',
113 'label' => __('3 months', 'mailpoet'),
114 'start' => $now->copy()->subMonths(3),
115 ],
116 [
117 'key' => '12_months',
118 'label' => __('12 months', 'mailpoet'),
119 'start' => $now->copy()->subMonths(12),
120 ],
121 [
122 'key' => 'lifetime',
123 'label' => __('Lifetime', 'mailpoet'),
124 'start' => null,
125 ],
126 ];
127
128 $lifetimeStats = $this->subscribersStatisticsRepository->getStatistics($subscriber);
129 $response['periodic_stats'] = [];
130 foreach ($periods as $period) {
131 $periodStats = $period['key'] === 'lifetime'
132 ? $lifetimeStats
133 : $this->subscribersStatisticsRepository->getStatistics($subscriber, $period['start']);
134 $response['periodic_stats'][] = $statsMapper($periodStats, $period['key'], $period['label']);
135 }
136
137 $response['profile'] = $this->getProfile($subscriber, $isWooActive);
138
139 if ($isWooActive && $isWoocommerceUser) {
140 $lifetimeRevenue = $lifetimeStats->getWooCommerceRevenue();
141 if ($lifetimeRevenue !== null) {
142 $response['woocommerce_overview'] = [
143 'orders_count' => $lifetimeRevenue->getOrdersCount(),
144 'total_revenue_formatted' => $lifetimeRevenue->getFormattedValue(),
145 'average_order_value_formatted' => $lifetimeRevenue->getFormattedAverageValue(),
146 'orders_url' => $this->getCustomerOrdersUrl($subscriber),
147 ];
148 }
149 }
150
151 $lastEngagement = $subscriber->getLastEngagementAt();
152 if ($lastEngagement instanceof \DateTimeInterface) {
153 $response['last_engagement'] = $lastEngagement->format($dateFormat);
154 }
155 $lastClick = $subscriber->getLastClickAt();
156 if ($lastClick instanceof \DateTimeInterface) {
157 $response['last_click'] = $lastClick->format($dateFormat);
158 }
159 $lastOpen = $subscriber->getLastOpenAt();
160 if ($lastOpen instanceof \DateTimeInterface) {
161 $response['last_open'] = $lastOpen->format($dateFormat);
162 }
163 $lastPageView = $subscriber->getLastPageViewAt();
164 if ($lastPageView instanceof \DateTimeInterface) {
165 $response['last_page_view'] = $lastPageView->format($dateFormat);
166 }
167 $lastPurchase = $subscriber->getLastPurchaseAt();
168 if ($lastPurchase instanceof \DateTimeInterface) {
169 $response['last_purchase'] = $lastPurchase->format($dateFormat);
170 }
171 $lastSending = $subscriber->getLastSendingAt();
172 if ($lastSending instanceof \DateTimeInterface) {
173 $response['last_sending'] = $lastSending->format($dateFormat);
174 }
175 return $this->successResponse($response);
176 }
177
178 private function getSourceLabel(?string $source): ?string {
179 switch ($source) {
180 case Source::FORM:
181 return __('MailPoet subscription form', 'mailpoet');
182 case Source::IMPORTED:
183 return __('import', 'mailpoet');
184 case Source::ADMINISTRATOR:
185 return __('admin', 'mailpoet');
186 case Source::API:
187 return __('API', 'mailpoet');
188 case Source::WORDPRESS_USER:
189 return __('WordPress user sync', 'mailpoet');
190 case Source::WORDPRESS_USER_DELETED:
191 return __('WordPress user (deleted)', 'mailpoet');
192 case Source::WOOCOMMERCE_USER:
193 return __('WooCommerce customer sync', 'mailpoet');
194 case Source::WOOCOMMERCE_CHECKOUT:
195 return __('WooCommerce checkout', 'mailpoet');
196 default:
197 return null;
198 }
199 }
200
201 private function getProfile(SubscriberEntity $subscriber, bool $isWooActive): array {
202 return [
203 'status' => $subscriber->getStatus(),
204 'first_name' => $subscriber->getFirstName(),
205 'last_name' => $subscriber->getLastName(),
206 'email' => $subscriber->getEmail(),
207 'shipping_address' => $isWooActive ? $this->getShippingAddress($subscriber) : [],
208 'tags' => $this->getTags($subscriber),
209 'segments' => $this->getSegments($subscriber),
210 'custom_fields' => $this->getCustomFields($subscriber),
211 'unsubscribe_reason' => $this->getProfileUnsubscribeReason($subscriber),
212 ];
213 }
214
215 private function getProfileUnsubscribeReason(SubscriberEntity $subscriber): ?string {
216 $latest = $this->statisticsUnsubscribesRepository->findLatestForSubscriber($subscriber);
217 if (!$latest instanceof StatisticsUnsubscribeEntity) {
218 return null;
219 }
220 $reason = $latest->getReason();
221 $reasonText = $latest->getReasonText();
222 $trimmedText = $reasonText !== null ? trim($reasonText) : '';
223 if ($trimmedText !== '') {
224 return $trimmedText;
225 }
226 $labels = $this->unsubscribeReasonTracker->getReasonLabels();
227 if ($reason !== null && isset($labels[$reason])) {
228 return $labels[$reason];
229 }
230 return __('No reason provided', 'mailpoet');
231 }
232
233 private function getTags(SubscriberEntity $subscriber): array {
234 $result = [];
235 foreach ($subscriber->getSubscriberTags() as $subscriberTag) {
236 $tag = $subscriberTag->getTag();
237 if (!$tag) {
238 continue;
239 }
240 $result[] = [
241 'id' => (string)$subscriberTag->getId(),
242 'subscriber_id' => (string)$subscriber->getId(),
243 'tag_id' => (string)$tag->getId(),
244 'name' => $tag->getName(),
245 ];
246 }
247 return $result;
248 }
249
250 private function getSegments(SubscriberEntity $subscriber): array {
251 $result = [];
252 foreach ($subscriber->getSubscriberSegments(SubscriberEntity::STATUS_SUBSCRIBED) as $subscriberSegment) {
253 $segment = $subscriberSegment->getSegment();
254 if (!$segment) {
255 continue;
256 }
257 $result[] = [
258 'id' => (string)$segment->getId(),
259 'name' => $segment->getName(),
260 ];
261 }
262 return $result;
263 }
264
265 private function getCustomFields(SubscriberEntity $subscriber): array {
266 $result = [];
267 foreach ($subscriber->getSubscriberCustomFields() as $subscriberCustomField) {
268 $customField = $subscriberCustomField->getCustomField();
269 if (!$customField instanceof CustomFieldEntity) {
270 continue;
271 }
272 $value = $subscriberCustomField->getValue();
273 if ($value === '') {
274 continue;
275 }
276 $result[] = [
277 'id' => (string)$customField->getId(),
278 'name' => $customField->getName(),
279 'value' => $value,
280 ];
281 }
282 return $result;
283 }
284
285 private function getShippingAddress(SubscriberEntity $subscriber): array {
286 $address = [];
287 $customer = null;
288 $wpUserId = $subscriber->getWpUserId();
289 if ($wpUserId) {
290 $customer = $this->wooCommerceHelper->wcGetCustomer((int)$wpUserId);
291 if ($customer) {
292 $address = $this->getShippingAddressParts($customer);
293 }
294 }
295
296 if (!$address && ($subscriber->getIsWoocommerceUser() || $customer)) {
297 $order = $this->getLatestWooCommerceOrderByEmail($subscriber->getEmail());
298 if ($order) {
299 $address = $this->getShippingAddressParts($order);
300 }
301 }
302
303 return $this->formatShippingAddress($address);
304 }
305
306 private function getLatestWooCommerceOrderByEmail(string $email) {
307 $orders = $this->wooCommerceHelper->wcGetOrders([
308 'billing_email' => $email,
309 'limit' => 1,
310 'orderby' => 'date',
311 'order' => 'DESC',
312 ]);
313 return $orders[0] ?? null;
314 }
315
316 private function getShippingAddressParts($source): array {
317 $address = [];
318 $hasAddress = false;
319 foreach (['first_name', 'last_name', 'company', 'address_1', 'address_2', 'city', 'state', 'postcode', 'country'] as $field) {
320 $method = 'get_shipping_' . $field;
321 $address[$field] = method_exists($source, $method) ? trim((string)$source->$method()) : '';
322 if (in_array($field, ['address_1', 'address_2', 'city', 'postcode'], true) && $address[$field] !== '') {
323 $hasAddress = true;
324 }
325 }
326 if (!$hasAddress) {
327 return [];
328 }
329 return array_filter($address, function($value) {
330 return $value !== '';
331 });
332 }
333
334 private function formatShippingAddress(array $address): array {
335 if (!$address) {
336 return [];
337 }
338
339 $formatted = '';
340 try {
341 $formatted = (string)$this->wooCommerceHelper->WC()->countries->get_formatted_address($address);
342 } catch (\Throwable $e) {
343 $formatted = '';
344 }
345
346 if ($formatted !== '') {
347 $formatted = str_replace(['<br/>', '<br />', '<br>'], "\n", $formatted);
348 return array_values(array_filter(
349 array_map('trim', explode("\n", strip_tags($formatted)))
350 ));
351 }
352
353 $lines = [
354 trim(implode(' ', array_filter([
355 $address['first_name'] ?? '',
356 $address['last_name'] ?? '',
357 ]))),
358 $address['company'] ?? '',
359 $address['address_1'] ?? '',
360 $address['address_2'] ?? '',
361 trim(implode(' ', array_filter([
362 $address['city'] ?? '',
363 $address['state'] ?? '',
364 $address['postcode'] ?? '',
365 ]))),
366 $address['country'] ?? '',
367 ];
368 return array_values(array_filter(array_map('trim', $lines)));
369 }
370
371 private function getCustomerOrdersUrl(SubscriberEntity $subscriber): string {
372 $path = $this->wooCommerceHelper->isWooCommerceCustomOrdersTableEnabled()
373 ? 'admin.php?page=wc-orders'
374 : 'edit.php?post_type=shop_order';
375 $wpUserId = $subscriber->getWpUserId();
376 if ($wpUserId) {
377 $path .= '&_customer_user=' . (int)$wpUserId;
378 } else {
379 $path .= '&s=' . rawurlencode($subscriber->getEmail());
380 }
381 return $this->wp->adminUrl($path);
382 }
383 }
384