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 / Segments.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
Segments.php
289 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 Exception;
9 use MailPoet\API\JSON\Endpoint as APIEndpoint;
10 use MailPoet\API\JSON\Error as APIError;
11 use MailPoet\API\JSON\Response;
12 use MailPoet\API\JSON\ResponseBuilders\SegmentsResponseBuilder;
13 use MailPoet\Config\AccessControl;
14 use MailPoet\ConflictException;
15 use MailPoet\Cron\CronWorkerScheduler;
16 use MailPoet\Cron\Workers\WooCommerceSync;
17 use MailPoet\Doctrine\Validator\ValidationException;
18 use MailPoet\Entities\SegmentEntity;
19 use MailPoet\Entities\SubscriberEntity;
20 use MailPoet\Form\FormsRepository;
21 use MailPoet\Newsletter\Segment\NewsletterSegmentRepository;
22 use MailPoet\Segments\SegmentSaveController;
23 use MailPoet\Segments\SegmentsRepository;
24 use MailPoet\Segments\SegmentSubscribersRepository;
25 use MailPoet\Segments\WP;
26 use MailPoet\Subscribers\SubscribersRepository;
27
28 class Segments extends APIEndpoint {
29 public $permissions = [
30 'global' => AccessControl::PERMISSION_MANAGE_SEGMENTS,
31 ];
32
33 /** @var SegmentsRepository */
34 private $segmentsRepository;
35
36 /** @var SegmentsResponseBuilder */
37 private $segmentsResponseBuilder;
38
39 /** @var SegmentSaveController */
40 private $segmentSavecontroller;
41
42 /** @var SubscribersRepository */
43 private $subscribersRepository;
44
45 /** @var WP */
46 private $wpSegment;
47
48 /** @var NewsletterSegmentRepository */
49 private $newsletterSegmentRepository;
50
51 /** @var CronWorkerScheduler */
52 private $cronWorkerScheduler;
53
54 /** @var FormsRepository */
55 private $formsRepository;
56
57 /** @var SegmentSubscribersRepository */
58 private $segmentSubscribersRepository;
59
60 public function __construct(
61 SegmentsRepository $segmentsRepository,
62 SegmentsResponseBuilder $segmentsResponseBuilder,
63 SegmentSaveController $segmentSavecontroller,
64 SegmentSubscribersRepository $segmentSubscribersRepository,
65 SubscribersRepository $subscribersRepository,
66 WP $wpSegment,
67 NewsletterSegmentRepository $newsletterSegmentRepository,
68 CronWorkerScheduler $cronWorkerScheduler,
69 FormsRepository $formsRepository
70 ) {
71 $this->segmentsRepository = $segmentsRepository;
72 $this->segmentsResponseBuilder = $segmentsResponseBuilder;
73 $this->segmentSavecontroller = $segmentSavecontroller;
74 $this->subscribersRepository = $subscribersRepository;
75 $this->wpSegment = $wpSegment;
76 $this->newsletterSegmentRepository = $newsletterSegmentRepository;
77 $this->cronWorkerScheduler = $cronWorkerScheduler;
78 $this->formsRepository = $formsRepository;
79 $this->segmentSubscribersRepository = $segmentSubscribersRepository;
80 }
81
82 public function get($data = []) {
83 $id = (isset($data['id']) ? (int)$data['id'] : false);
84 $segment = $this->segmentsRepository->findOneById($id);
85 if ($segment instanceof SegmentEntity) {
86 return $this->successResponse($this->segmentsResponseBuilder->build($segment));
87 } else {
88 return $this->errorResponse([
89 APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet'),
90 ]);
91 }
92 }
93
94 public function save($data = []) {
95 try {
96 $data['name'] = isset($data['name']) ? sanitize_text_field($data['name']) : '';
97 $data['description'] = isset($data['description']) ? sanitize_textarea_field($data['description']) : '';
98 if (array_key_exists('public_description', $data)) {
99 $data['public_description'] = sanitize_textarea_field((string)$data['public_description']);
100 }
101 $segment = $this->segmentSavecontroller->save($data);
102 } catch (ValidationException $exception) {
103 return $this->badRequest([
104 APIError::BAD_REQUEST => __('Please specify a name.', 'mailpoet'),
105 ]);
106 } catch (ConflictException $exception) {
107 return $this->badRequest([
108 APIError::BAD_REQUEST => __('Another record already exists. Please specify a different "name".', 'mailpoet'),
109 ]);
110 }
111 $response = $this->segmentsResponseBuilder->build($segment);
112 return $this->successResponse($response);
113 }
114
115 public function restore($data = []) {
116 $segment = $this->getSegment($data);
117 if ($segment instanceof SegmentEntity) {
118 if (!$this->isTrashOrRestoreAllowed($segment)) {
119 return $this->errorResponse([
120 APIError::FORBIDDEN => __('This list cannot be moved to trash.', 'mailpoet'),
121 ]);
122 }
123 // When the segment is of type WP_USERS we want to restore all its subscribers
124 if ($segment->getType() === SegmentEntity::TYPE_WP_USERS) {
125 $subscribers = $this->subscribersRepository->findBySegment((int)$segment->getId());
126 $subscriberIds = array_map(function (SubscriberEntity $subscriberEntity): int {
127 return (int)$subscriberEntity->getId();
128 }, $subscribers);
129 $this->subscribersRepository->bulkRestore($subscriberIds);
130 }
131
132 $this->segmentsRepository->bulkRestore([$segment->getId()], $segment->getType());
133 $this->segmentsRepository->refresh($segment);
134 return $this->successResponse(
135 $this->segmentsResponseBuilder->build($segment),
136 ['count' => 1]
137 );
138 } else {
139 return $this->errorResponse([
140 APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet'),
141 ]);
142 }
143 }
144
145 public function trash($data = []) {
146 $segment = $this->getSegment($data);
147 if (!$segment instanceof SegmentEntity) {
148
149 return $this->errorResponse([
150 APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet'),
151 ]);
152 }
153
154 if (!$this->isTrashOrRestoreAllowed($segment)) {
155 return $this->errorResponse([
156 APIError::FORBIDDEN => __('This list cannot be moved to trash.', 'mailpoet'),
157 ]);
158 }
159
160 $activelyUsedNewslettersSubjects = $this->newsletterSegmentRepository->getSubjectsOfActivelyUsedEmailsForSegments([$segment->getId()]);
161 if (isset($activelyUsedNewslettersSubjects[$segment->getId()])) {
162 return $this->badRequest([
163 APIError::BAD_REQUEST => str_replace(
164 '%1$s',
165 "'" . join("', '", $activelyUsedNewslettersSubjects[$segment->getId()]) . "'",
166 // translators: %1$s is a comma-separated list of emails for which the segment is used.
167 _x('List cannot be deleted because it’s used for %1$s email', 'Alert shown when trying to delete segment, which is assigned to any automatic emails.', 'mailpoet')
168 ),
169 ]);
170 }
171
172 $activelyUsedFormNames = $this->formsRepository->getNamesOfFormsForSegments();
173 if (isset($activelyUsedFormNames[$segment->getId()])) {
174 return $this->badRequest([
175 APIError::BAD_REQUEST => str_replace(
176 '%1$s',
177 "'" . join("', '", $activelyUsedFormNames[$segment->getId()]) . "'",
178 // translators: %1$s is a comma-separated list of forms for which the segment is used.
179 _nx(
180 'List cannot be deleted because it’s used for %1$s form',
181 'List cannot be deleted because it’s used for %1$s forms',
182 count($activelyUsedFormNames[$segment->getId()]),
183 'Alert shown when trying to delete segment, when it is assigned to a form.',
184 'mailpoet'
185 )
186 ),
187 ]);
188 }
189
190 // When the segment is of type WP_USERS we want to trash all subscribers who aren't subscribed in another list
191 if ($segment->getType() === SegmentEntity::TYPE_WP_USERS) {
192 $subscribers = $this->subscribersRepository->findExclusiveSubscribersBySegment((int)$segment->getId());
193 $subscriberIds = array_map(function (SubscriberEntity $subscriberEntity): int {
194 return (int)$subscriberEntity->getId();
195 }, $subscribers);
196 $this->subscribersRepository->bulkTrash($subscriberIds);
197 }
198
199 $this->segmentsRepository->doTrash([$segment->getId()], $segment->getType());
200 $this->segmentsRepository->refresh($segment);
201 return $this->successResponse(
202 $this->segmentsResponseBuilder->build($segment),
203 ['count' => 1]
204 );
205 }
206
207 public function delete($data = []) {
208 $segment = $this->getSegment($data);
209 if ($segment instanceof SegmentEntity) {
210 $this->segmentsRepository->bulkDelete([$segment->getId()]);
211 return $this->successResponse(null, ['count' => 1]);
212 } else {
213 return $this->errorResponse([
214 APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet'),
215 ]);
216 }
217 }
218
219 public function duplicate($data = []) {
220 $segment = $this->getSegment($data);
221
222 if ($segment instanceof SegmentEntity) {
223 try {
224 $duplicate = $this->segmentSavecontroller->duplicate($segment);
225 } catch (Exception $e) {
226 return $this->errorResponse([
227 APIError::UNKNOWN => __('Duplicating of segment failed.', 'mailpoet'),
228 ], [], Response::STATUS_UNKNOWN);
229 }
230 return $this->successResponse(
231 $this->segmentsResponseBuilder->build($duplicate),
232 ['count' => 1]
233 );
234 } else {
235 return $this->errorResponse([
236 APIError::NOT_FOUND => __('This list does not exist.', 'mailpoet'),
237 ]);
238 }
239 }
240
241 public function synchronize($data) {
242 try {
243 if ($data['type'] === SegmentEntity::TYPE_WC_USERS) {
244 $this->cronWorkerScheduler->scheduleImmediatelyIfNotRunning(WooCommerceSync::TASK_TYPE);
245 } else {
246 $this->wpSegment->synchronizeUsers();
247 }
248 } catch (\Exception $e) {
249 return $this->errorResponse([
250 $e->getCode() => $e->getMessage(),
251 ]);
252 }
253
254 return $this->successResponse(null);
255 }
256
257 public function subscriberCount($data = []) {
258 $segmentIds = $data['segmentIds'] ?? [];
259 if (empty($segmentIds)) {
260 return $this->errorResponse([
261 APIError::BAD_REQUEST => __('No segment IDs provided.', 'mailpoet'),
262 ]);
263 }
264 $filterSegmentId = $data['filterSegmentId'] ?? null;
265 $status = $data['status'] ?? SubscriberEntity::STATUS_SUBSCRIBED;
266 $response['count'] = $this->segmentSubscribersRepository->getSubscribersCountBySegmentIds($segmentIds, $status, $filterSegmentId);
267
268 return $this->successResponse($response);
269 }
270
271 private function isTrashOrRestoreAllowed(SegmentEntity $segment): bool {
272 $allowedSegmentTypes = [
273 SegmentEntity::TYPE_DEFAULT,
274 SegmentEntity::TYPE_WP_USERS,
275 ];
276 if (in_array($segment->getType(), $allowedSegmentTypes, true)) {
277 return true;
278 }
279
280 return false;
281 }
282
283 private function getSegment(array $data): ?SegmentEntity {
284 return isset($data['id'])
285 ? $this->segmentsRepository->findOneById((int)$data['id'])
286 : null;
287 }
288 }
289