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 / EmailEditor / Integrations / MailPoet / EmailApiController.php
mailpoet / lib / EmailEditor / Integrations / MailPoet Last commit date
Blocks 10 months ago Coupons 1 month ago Endpoints 2 months ago Patterns 1 month ago PersonalizationTags 3 days ago ProductCollection 1 month ago Templates 2 months ago AutomationEmailContextProvider.php 1 month ago AutomationEmailPreviewOrderProvider.php 1 month ago BlockEmailContentDetector.php 1 month ago Cli.php 2 weeks ago DependencyNotice.php 10 months ago EditorPageRenderer.php 1 week ago EmailApiController.php 1 week ago EmailEditor.php 2 months ago EmailEditorPreviewEmail.php 9 months ago Logger.php 10 months ago MailPoetCssInliner.php 8 months ago MailpoetCssInlinerFactory.php 1 year ago PersonalizationTagManager.php 4 days ago index.php 2 years ago
EmailApiController.php
378 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\EmailEditor\Integrations\MailPoet;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Entities\NewsletterEntity;
9 use MailPoet\Entities\NewsletterOptionEntity;
10 use MailPoet\Entities\NewsletterOptionFieldEntity;
11 use MailPoet\Entities\NewsletterSegmentEntity;
12 use MailPoet\Entities\SegmentEntity;
13 use MailPoet\Newsletter\NewslettersRepository;
14 use MailPoet\Newsletter\Options\NewsletterOptionFieldsRepository;
15 use MailPoet\Newsletter\Options\NewsletterOptionsRepository;
16 use MailPoet\Newsletter\Segment\NewsletterSegmentRepository;
17 use MailPoet\Newsletter\Sending\TimeZoneCampaignScheduler;
18 use MailPoet\Newsletter\Sharing\ShareVisibility;
19 use MailPoet\Newsletter\Url as NewsletterUrl;
20 use MailPoet\NotFoundException;
21 use MailPoet\UnexpectedValueException;
22 use MailPoet\Validator\Builder;
23 use MailPoetVendor\Doctrine\ORM\EntityManager;
24
25 class EmailApiController {
26 /** @var NewslettersRepository */
27 private $newsletterRepository;
28
29 /** @var NewsletterUrl */
30 private $newsletterUrl;
31
32 /** @var NewsletterOptionFieldsRepository */
33 private $newsletterOptionFieldsRepository;
34
35 /** @var NewsletterOptionsRepository */
36 private $newsletterOptionsRepository;
37
38 /** @var NewsletterSegmentRepository */
39 private $newsletterSegmentRepository;
40
41 /** @var EntityManager */
42 private $entityManager;
43
44 /** @var ShareVisibility */
45 private $shareVisibility;
46
47 public function __construct(
48 NewslettersRepository $newsletterRepository,
49 NewsletterUrl $newsletterUrl,
50 NewsletterOptionFieldsRepository $newsletterOptionFieldsRepository,
51 NewsletterOptionsRepository $newsletterOptionsRepository,
52 NewsletterSegmentRepository $newsletterSegmentRepository,
53 EntityManager $entityManager,
54 ShareVisibility $shareVisibility
55 ) {
56 $this->newsletterRepository = $newsletterRepository;
57 $this->newsletterUrl = $newsletterUrl;
58 $this->newsletterOptionFieldsRepository = $newsletterOptionFieldsRepository;
59 $this->newsletterOptionsRepository = $newsletterOptionsRepository;
60 $this->newsletterSegmentRepository = $newsletterSegmentRepository;
61 $this->entityManager = $entityManager;
62 $this->shareVisibility = $shareVisibility;
63 }
64
65 /**
66 * @param array $postEmailData - WP_Post data
67 * @return array - MailPoet specific email data that will be attached to the post API response
68 */
69 public function getEmailData($postEmailData): array {
70 $newsletter = $this->newsletterRepository->findOneBy(['wpPost' => $postEmailData['id']]);
71 $isAutomationNewsletter = $newsletter && ($newsletter->isAutomation() || $newsletter->isAutomationTransactional());
72 $showInArchive = $newsletter
73 ? $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_EXCLUDE_FROM_ARCHIVE) !== '1'
74 : true;
75 return [
76 'id' => $newsletter ? $newsletter->getId() : null,
77 'type' => $newsletter ? $newsletter->getType() : '',
78 'subject' => $newsletter ? $newsletter->getSubject() : '',
79 'preheader' => $newsletter ? $newsletter->getPreheader() : '',
80 'sender_name' => $newsletter ? $newsletter->getSenderName() : '',
81 'sender_address' => $newsletter ? $newsletter->getSenderAddress() : '',
82 'reply_to_name' => $newsletter ? $newsletter->getReplyToName() : '',
83 'reply_to_address' => $newsletter ? $newsletter->getReplyToAddress() : '',
84 'preview_url' => $this->newsletterUrl->getViewInBrowserUrl($newsletter),
85 'deleted_at' => $newsletter && $newsletter->getDeletedAt() !== null ? $newsletter->getDeletedAt()->format('c') : null,
86 'scheduled_at' => $newsletter ? $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SCHEDULED_AT) : null,
87 'schedule_mode' => $newsletter ? $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SCHEDULE_MODE) : null,
88 'scheduled_local_date' => $newsletter ? $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SCHEDULED_LOCAL_DATE) : null,
89 'scheduled_local_time' => $newsletter ? $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SCHEDULED_LOCAL_TIME) : null,
90 'utm_campaign' => $newsletter ? $newsletter->getGaCampaign() : '',
91 'segment_ids' => $newsletter ? $newsletter->getSegmentIds() : [],
92 'is_automation_newsletter' => $isAutomationNewsletter,
93 'share_url' => $newsletter && $this->shareVisibility->isSupported($newsletter)
94 ? $this->newsletterUrl->getPublicShareUrl($newsletter)
95 : '',
96 'share_visibility' => $newsletter
97 ? $this->shareVisibility->getConfiguredVisibility($newsletter)
98 : ShareVisibility::VISIBILITY_DEFAULT,
99 'effective_share_visibility' => $newsletter
100 ? $this->shareVisibility->getEffectiveVisibility($newsletter)
101 : $this->shareVisibility->getDefaultVisibility(),
102 'can_share' => $newsletter ? $this->shareVisibility->canShare($newsletter) : false,
103 'show_in_archive' => $showInArchive,
104 ];
105 }
106
107 /**
108 * Update MailPoet specific data we store with Emails.
109 */
110 public function saveEmailData(array $data, \WP_Post $emailPost): void {
111 $newsletter = $this->newsletterRepository->findOneById($data['id']);
112 if (!$newsletter) {
113 throw new NotFoundException('Newsletter was not found');
114 }
115 if ($newsletter->getWpPostId() !== $emailPost->ID) {
116 throw new UnexpectedValueException('Newsletter ID does not match the post ID');
117 }
118
119 $newsletter->setSubject($data['subject']);
120 $newsletter->setPreheader($data['preheader']);
121
122 if (array_key_exists('sender_name', $data)) {
123 $newsletter->setSenderName($data['sender_name']);
124 }
125
126 if (array_key_exists('sender_address', $data)) {
127 $newsletter->setSenderAddress($data['sender_address']);
128 }
129
130 if (array_key_exists('reply_to_name', $data)) {
131 $newsletter->setReplyToName($data['reply_to_name']);
132 }
133
134 if (array_key_exists('reply_to_address', $data)) {
135 $newsletter->setReplyToAddress($data['reply_to_address']);
136 }
137
138 if (isset($data['utm_campaign'])) {
139 $newsletter->setGaCampaign($data['utm_campaign']);
140 }
141
142 if (isset($data['deleted_at'])) {
143 if (empty($data['deleted_at'])) {
144 $data['deleted_at'] = null;
145 } else {
146 $data['deleted_at'] = new \DateTime($data['deleted_at']);
147 }
148 $newsletter->setDeletedAt($data['deleted_at']);
149 }
150
151 if (array_key_exists('scheduled_at', $data)) {
152 $this->updateScheduledAtOption($newsletter, $data['scheduled_at']);
153 }
154
155 if (array_key_exists('schedule_mode', $data)) {
156 $this->updateScheduleModeOption($newsletter, $data['schedule_mode']);
157 }
158
159 if (array_key_exists('scheduled_local_date', $data)) {
160 $this->updateScheduledLocalOption(
161 $newsletter,
162 NewsletterOptionFieldEntity::NAME_SCHEDULED_LOCAL_DATE,
163 $data['scheduled_local_date'],
164 'Y-m-d',
165 'Invalid scheduled_local_date format. Expected a Y-m-d date string.'
166 );
167 }
168
169 if (array_key_exists('scheduled_local_time', $data)) {
170 $this->updateScheduledLocalOption(
171 $newsletter,
172 NewsletterOptionFieldEntity::NAME_SCHEDULED_LOCAL_TIME,
173 $data['scheduled_local_time'],
174 'H:i:s',
175 'Invalid scheduled_local_time format. Expected a H:i:s time string.'
176 );
177 }
178
179 if (array_key_exists('share_visibility', $data)) {
180 $this->updateOption(
181 $newsletter,
182 NewsletterOptionFieldEntity::NAME_SHARE_VISIBILITY,
183 $this->shareVisibility->sanitize((string)$data['share_visibility'])
184 );
185 }
186
187 if (array_key_exists('show_in_archive', $data)) {
188 $this->updateShowInArchiveOption($newsletter, $data['show_in_archive']);
189 }
190
191 if (isset($data['segment_ids']) && is_array($data['segment_ids'])) {
192 $this->updateSegments($newsletter, $data['segment_ids']);
193 $this->entityManager->refresh($newsletter);
194 }
195
196 $this->newsletterRepository->flush();
197 }
198
199 private function updateShowInArchiveOption(NewsletterEntity $newsletter, $showInArchiveValue): void {
200 if (!is_bool($showInArchiveValue)) {
201 throw new UnexpectedValueException('Invalid show_in_archive value. Expected a boolean.');
202 }
203
204 if ($newsletter->getType() !== NewsletterEntity::TYPE_STANDARD) {
205 return;
206 }
207
208 $this->updateOption(
209 $newsletter,
210 NewsletterOptionFieldEntity::NAME_EXCLUDE_FROM_ARCHIVE,
211 $showInArchiveValue ? '0' : '1'
212 );
213 }
214
215 private function updateOption($newsletter, string $optionName, $optionValue): void {
216 $optionField = $this->newsletterOptionFieldsRepository->findOneBy([
217 'name' => $optionName,
218 'newsletterType' => $newsletter->getType(),
219 ]);
220
221 if (!$optionField) {
222 return;
223 }
224
225 $option = $this->newsletterOptionsRepository->findOneBy([
226 'newsletter' => $newsletter,
227 'optionField' => $optionField,
228 ]);
229
230 if (!$option) {
231 $option = new NewsletterOptionEntity($newsletter, $optionField);
232 $this->newsletterOptionsRepository->persist($option);
233 $newsletter->getOptions()->add($option);
234 }
235
236 $option->setValue($optionValue);
237 }
238
239 private function updateScheduleModeOption(NewsletterEntity $newsletter, $scheduleModeValue): void {
240 $allowedModes = [
241 TimeZoneCampaignScheduler::SCHEDULE_MODE_WEBSITE_TIME,
242 TimeZoneCampaignScheduler::SCHEDULE_MODE_SUBSCRIBER_TIMEZONE,
243 ];
244 if ($scheduleModeValue !== null && $scheduleModeValue !== '' && !in_array($scheduleModeValue, $allowedModes, true)) {
245 throw new UnexpectedValueException('Invalid schedule_mode value.');
246 }
247
248 $this->updateOption($newsletter, NewsletterOptionFieldEntity::NAME_SCHEDULE_MODE, $scheduleModeValue);
249
250 // Subscriber timezone scheduling has no scheduled_at datetime, so the isScheduled
251 // option derived from scheduled_at would stay '0' and sending would dispatch to the
252 // immediate path instead of TimeZoneCampaignScheduler.
253 if ($scheduleModeValue === TimeZoneCampaignScheduler::SCHEDULE_MODE_SUBSCRIBER_TIMEZONE) {
254 $this->updateOption($newsletter, NewsletterOptionFieldEntity::NAME_IS_SCHEDULED, '1');
255 return;
256 }
257
258 // Switching back to website time must re-derive isScheduled from scheduledAt,
259 // otherwise a payload without the scheduled_at key would leave isScheduled
260 // stuck at '1' with no datetime and sending would take the scheduled path.
261 if ($scheduleModeValue === TimeZoneCampaignScheduler::SCHEDULE_MODE_WEBSITE_TIME) {
262 $scheduledAt = $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_SCHEDULED_AT);
263 $this->updateOption(
264 $newsletter,
265 NewsletterOptionFieldEntity::NAME_IS_SCHEDULED,
266 $scheduledAt !== null && $scheduledAt !== '' ? '1' : '0'
267 );
268 }
269 }
270
271 private function updateScheduledLocalOption(NewsletterEntity $newsletter, string $optionName, $value, string $format, string $errorMessage): void {
272 if ($value !== null && $value !== '') {
273 $parsed = is_string($value) ? \DateTimeImmutable::createFromFormat("!{$format}", $value) : false;
274 if (!$parsed || $parsed->format($format) !== $value) {
275 throw new UnexpectedValueException($errorMessage);
276 }
277 }
278
279 $this->updateOption($newsletter, $optionName, $value);
280 }
281
282 private function updateScheduledAtOption($newsletter, $scheduledAtValue): void {
283 // Validate the scheduled_at value
284 if ($scheduledAtValue !== null && $scheduledAtValue !== '') {
285 try {
286 new \DateTime($scheduledAtValue);
287 } catch (\Exception $e) {
288 throw new UnexpectedValueException('Invalid scheduled_at format. Expected a valid datetime string.');
289 }
290 }
291
292 $this->updateOption($newsletter, NewsletterOptionFieldEntity::NAME_SCHEDULED_AT, $scheduledAtValue);
293
294 // Also update the isScheduled option
295 $this->updateOption(
296 $newsletter,
297 NewsletterOptionFieldEntity::NAME_IS_SCHEDULED,
298 $scheduledAtValue !== null && $scheduledAtValue !== '' ? '1' : '0'
299 );
300 }
301
302 /**
303 * @param array $segmentIds Array of segment IDs
304 */
305 private function updateSegments($newsletter, array $segmentIds): void {
306 // Normalize segment IDs to integers for consistent strict comparison
307 $segmentIds = array_map('intval', $segmentIds);
308
309 // Remove existing segments that are not in the new list
310 $existingSegments = $newsletter->getNewsletterSegments();
311 foreach ($existingSegments as $newsletterSegment) {
312 $segment = $newsletterSegment->getSegment();
313 if (!$segment || !in_array($segment->getId(), $segmentIds, true)) {
314 $this->entityManager->remove($newsletterSegment);
315 }
316 }
317
318 // Add new segments
319 foreach ($segmentIds as $segmentId) {
320 $segmentIdInt = (int)$segmentId;
321 $segment = $this->entityManager->getReference(SegmentEntity::class, $segmentIdInt);
322 if (!$segment) {
323 continue;
324 }
325
326 // Check if the newsletter-segment relationship already exists
327 $existingRelation = $this->newsletterSegmentRepository->findOneBy([
328 'newsletter' => $newsletter,
329 'segment' => $segment,
330 ]);
331
332 if (!$existingRelation) {
333 $newsletterSegment = new NewsletterSegmentEntity($newsletter, $segment);
334 $this->entityManager->persist($newsletterSegment);
335 }
336 }
337 $this->entityManager->flush();
338 }
339
340 public function trashEmail(\WP_Post $wpPost) {
341 $newsletter = $this->newsletterRepository->findOneBy(['wpPost' => $wpPost->ID]);
342 if (!$newsletter) {
343 throw new NotFoundException('Newsletter was not found');
344 }
345 if ($newsletter->getWpPostId() !== $wpPost->ID) {
346 throw new UnexpectedValueException('Newsletter ID does not match the post ID');
347 }
348 $this->newsletterRepository->bulkTrash([$newsletter->getId()]);
349 }
350
351 public function getEmailDataSchema(): array {
352 return Builder::object([
353 'id' => Builder::integer()->nullable(),
354 'type' => Builder::string(),
355 'subject' => Builder::string(),
356 'preheader' => Builder::string(),
357 'sender_name' => Builder::string(),
358 'sender_address' => Builder::string(),
359 'reply_to_name' => Builder::string(),
360 'reply_to_address' => Builder::string(),
361 'preview_url' => Builder::string(),
362 'deleted_at' => Builder::string()->nullable(),
363 'scheduled_at' => Builder::string()->nullable(),
364 'schedule_mode' => Builder::string()->nullable(),
365 'scheduled_local_date' => Builder::string()->nullable(),
366 'scheduled_local_time' => Builder::string()->nullable(),
367 'utm_campaign' => Builder::string(),
368 'segment_ids' => Builder::array(),
369 'is_automation_newsletter' => Builder::boolean(),
370 'share_url' => Builder::string(),
371 'share_visibility' => Builder::string(),
372 'effective_share_visibility' => Builder::string(),
373 'can_share' => Builder::boolean(),
374 'show_in_archive' => Builder::boolean(),
375 ])->toArray();
376 }
377 }
378