PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.11.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.11.1
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / back / Controllers / Lists / Edition.php

Edition.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 10.11.1, at back/Controllers/Lists/Edition.php

489 lines 18.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AcyMailing\Controllers\Lists;
4
5 use AcyMailing\Classes\HistoryClass;
6 use AcyMailing\Classes\ListClass;
7 use AcyMailing\Classes\MailClass;
8 use AcyMailing\Classes\MailStatClass;
9 use AcyMailing\Classes\TagClass;
10 use AcyMailing\Classes\UrlClickClass;
11 use AcyMailing\Controllers\ListsController;
12 use AcyMailing\Helpers\EntitySelectHelper;
13 use AcyMailing\Helpers\WorkflowHelper;
14
15 trait Edition
16 {
17 public function settings(): void
18 {
19 acym_setVar('layout', 'settings');
20
21 $tab = acym_getVar('string', 'step', ListsController::LIST_EDITION_TABS_GENERAL);
22
23 if (empty($tab)) {
24 $tab = ListsController::LIST_EDITION_TABS_GENERAL;
25 }
26
27 $data = [];
28 $data['svg'] = acym_loaderLogo(false);
29 $data['workflowHelper'] = new WorkflowHelper();
30 $data['currentTab'] = $tab;
31 $data['tabs'] = [
32 'general' => ListsController::LIST_EDITION_TABS_GENERAL,
33 'subscribers' => ListsController::LIST_EDITION_TABS_SUBSCRIBERS,
34 'unsubscriptions' => ListsController::LIST_EDITION_TABS_UNSUBSCRIPTIONS,
35 ];
36
37 $listId = acym_getVar('int', 'listId', 0);
38
39 if (!$this->prepareListSettings($data, $listId)) return;
40
41 if ($tab === ListsController::LIST_EDITION_TABS_GENERAL) {
42 $this->prepareTagsSettings($data, $listId);
43 $this->prepareListStat($data, $listId);
44 $this->prepareListStatEvolution($data, $listId);
45 $this->prepareWelcomeUnsubData($data);
46 $this->prepareMultilingualOption($data);
47 } elseif ($tab === ListsController::LIST_EDITION_TABS_SUBSCRIBERS) {
48 $this->prepareSubscribersEntitySelect($data, $listId);
49 $this->prepareSubscribersSettings($data, $listId);
50 } elseif ($tab === ListsController::LIST_EDITION_TABS_UNSUBSCRIPTIONS) {
51 $this->prepareUnsubReasons($data);
52 }
53
54 parent::display($data);
55 }
56
57 private function prepareListSettings(array &$data, int $listId): bool
58 {
59 if (empty($listId)) {
60 $listInformation = new \stdClass();
61 $listInformation->id = '';
62 $listInformation->name = '';
63 $listInformation->frontLabel = '';
64 $listInformation->description = '';
65 $listInformation->active = 1;
66 $listInformation->visible = 1;
67 $listInformation->color = '#'.implode('', [
68 ListClass::COLOR_PARTS[rand(0, 15)],
69 ListClass::COLOR_PARTS[rand(0, 15)],
70 ListClass::COLOR_PARTS[rand(0, 15)],
71 ListClass::COLOR_PARTS[rand(0, 15)],
72 ListClass::COLOR_PARTS[rand(0, 15)],
73 ListClass::COLOR_PARTS[rand(0, 15)],
74 ]);
75 $listInformation->welcome_id = '';
76 $listInformation->unsubscribe_id = '';
77 $listInformation->access = [];
78 $listInformation->tracking = 1;
79 $listInformation->translation = [];
80 $listInformation->display_name = '';
81
82 $this->breadcrumb[acym_translation('ACYM_NEW_LIST')] = acym_completeLink('lists&task=settings');
83 } else {
84 $listClass = new ListClass();
85 $listInformation = $listClass->getOneById($listId);
86 if (is_null($listInformation)) {
87 acym_enqueueMessage(acym_translation('ACYM_LIST_DOESNT_EXIST'), 'error');
88 $this->listing();
89
90 return false;
91 }
92
93
94 $subscribersCount = $listClass->getSubscribersCountPerStatusByListIds([$listId]);
95
96 $this->breadcrumb[acym_escape($listInformation->name)] = acym_completeLink('lists&task=settings&listId='.$listId);
97
98 $listInformation->access = empty($listInformation->access) ? [] : explode(',', $listInformation->access);
99
100 $currentUser = acym_currentUserId();
101 if (!acym_isAdmin() && ($listInformation->cms_user_id != $currentUser)) {
102 $userGroups = acym_getGroupsByUser($currentUser);
103 $canAccess = false;
104
105 foreach ($userGroups as $group) {
106 if (in_array($group, $listInformation->access)) $canAccess = true;
107 }
108
109 if (!$canAccess) {
110 acym_enqueueMessage(acym_translation('ACYM_YOU_DONT_HAVE_ACCESS_TO_THIS_LIST'), 'error');
111
112 $this->listing();
113
114 return false;
115 }
116 }
117 }
118
119 $listInformation->subscribers = [
120 'unsubscribed_users' => 0,
121 'sendable_users' => 0,
122 'unconfirmed_users' => 0,
123 'inactive_users' => 0,
124 ];
125 if (!empty($subscribersCount)) {
126 $listStats = array_shift($subscribersCount);
127 $listInformation->subscribers = [
128 'unsubscribed_users' => $listStats->unsubscribed_users,
129 'sendable_users' => $listStats->sendable_users,
130 'unconfirmed_users' => $listStats->unconfirmed_users,
131 'inactive_users' => $listStats->inactive_users,
132 ];
133 }
134
135 $data['listInformation'] = $listInformation;
136
137 return true;
138 }
139
140 private function prepareTagsSettings(array &$data, int $listId): void
141 {
142 $tagClass = new TagClass();
143 $data['allTags'] = $tagClass->getAllTagsByType(TagClass::TYPE_LIST);
144 $data['listTagsName'] = [];
145 $listsTags = $tagClass->getAllTagsByElementId(TagClass::TYPE_LIST, $listId);
146 foreach ($listsTags as $oneTag) {
147 $data['listTagsName'][] = $oneTag;
148 }
149 }
150
151 private function prepareSubscribersSettings(array &$data, int $listId): void
152 {
153 $data['ordering'] = acym_getVar('string', 'users_ordering', 'id');
154 $data['orderingSortOrder'] = acym_getVar('string', 'users_ordering_sort_order', 'desc');
155 $data['classSortOrder'] = $data['orderingSortOrder'] == 'asc' ? 'acymicon-sort-amount-asc' : 'acymicon-sort-amount-desc';
156 $listClass = new ListClass();
157 $data['subscribers'] = $listClass->getSubscribersForList(
158 [
159 'listIds' => [$listId],
160 'offset' => 0,
161 'limit' => 500,
162 'status' => 1,
163 'orderBy' => $data['ordering'],
164 'orderBySort' => $data['orderingSortOrder'],
165 ]
166 );
167 foreach ($data['subscribers'] as &$oneSub) {
168 if ($oneSub->subscription_date == '0000-00-00 00:00:00') continue;
169 $oneSub->subscription_date = acym_date(strtotime($oneSub->subscription_date), acym_translation('ACYM_DATE_FORMAT_LC2'));
170 }
171 }
172
173 private function prepareSubscribersEntitySelect(array &$data, int $listId): void
174 {
175 if (empty($listId)) {
176 $data['subscribersEntitySelect'] = '';
177
178 return;
179 }
180
181 $entityHelper = new EntitySelectHelper();
182
183 $data['subscribersEntitySelect'] = acym_modal(
184 acym_translation('ACYM_MANAGE_SUBSCRIBERS'),
185 $entityHelper->entitySelect(
186 'user',
187 ['join' => 'join_list-'.$listId],
188 $entityHelper->getColumnsForUser('userlist.user_id'),
189 ['text' => acym_translation('ACYM_CONFIRM'), 'action' => 'saveSubscribers'],
190 true,
191 '',
192 'subscriber'
193 ),
194 'acym__lists__settings__subscribers__entity__modal',
195 [],
196 ['class' => 'cell medium-6 large-shrink button button-secondary']
197 );
198 }
199
200 private function prepareListStat(array &$data, int $listId): void
201 {
202 $data['listStats'] = ['deliveryRate' => 0, 'openRate' => 0, 'clickRate' => 0, 'failRate' => 0, 'bounceRate' => 0];
203 if (empty($listId)) return;
204 $listClass = new ListClass();
205 $mails = $listClass->getMailsByListId($listId);
206 if (empty($mails)) return;
207
208 $mailStatClass = new MailStatClass();
209 $mailsStat = $mailStatClass->getCumulatedStatsByMailIds($mails);
210
211 if (intval($mailsStat->sent) + intval($mailsStat->fails) === 0) return;
212
213 $totalSent = intval($mailsStat->sent) + intval($mailsStat->fails);
214 if (empty($mailsStat->open)) $mailsStat->open = 0;
215 if (empty($mailsStat->fails)) $mailsStat->fails = 0;
216 if (empty($mailsStat->bounces)) $mailsStat->bounces = 0;
217
218 $data['listStats']['openRate'] = number_format($mailsStat->open / $totalSent * 100, 2);
219 $data['listStats']['deliveryRate'] = number_format(($mailsStat->sent - $mailsStat->bounces) / $totalSent * 100, 2);
220 $data['listStats']['failRate'] = number_format($mailsStat->fails / $totalSent * 100, 2);
221 $data['listStats']['bounceRate'] = number_format($mailsStat->bounces / $totalSent * 100, 2);
222
223 $urlClickClass = new UrlClickClass();
224 $nbClicks = $urlClickClass->getClickRateByMailIds($mails);
225 $data['listStats']['clickRate'] = number_format($nbClicks / $totalSent * 100, 2);
226 }
227
228 private function prepareListStatEvolution(array &$data, int $listId): void
229 {
230 $data['evol'] = [];
231 $listClass = new ListClass();
232 $subEvolStat = $listClass->getYearSubEvolutionPerList($listId);
233 if (empty($subEvolStat['subscribers']) && empty($subEvolStat['unsubscribers'])) return;
234
235 $firstMonth = date('n') + 1;
236 $zeroReached = false;
237 $evolSub = [];
238 $evolUnsub = [];
239 for ($i = 0; $i < 12; $i++) {
240 $month = ($firstMonth + $i) % 13;
241 if ($month == 0) $zeroReached = true;
242 if ($zeroReached) $month += 1;
243 $evolSub[$month] = $month.'_0';
244 $evolUnsub[$month] = $month.'_0';
245 }
246
247 foreach ($subEvolStat['subscribers'] as $unit => $monthData) {
248 $evolSub[$monthData->monthSub] = $monthData->monthSub.'_'.$monthData->nbUser;
249 }
250
251 foreach ($subEvolStat['unsubscribers'] as $unit => $monthData) {
252 $evolUnsub[$monthData->monthUnsub] = $monthData->monthUnsub.'_'.$monthData->nbUser;
253 }
254
255 foreach ($evolSub as $month => $oneEvol) {
256 $data['evol'][0][] = $oneEvol;
257 $data['evol'][1][] = $evolUnsub[$month];
258 }
259 }
260
261 protected function prepareWelcomeUnsubData(array &$data): void
262 {
263 $data['tmpls'] = [];
264 if (empty($data['listInformation']->id)) return;
265 $listClass = new ListClass();
266 $mailClass = new MailClass();
267
268 foreach ([MailClass::TYPE_WELCOME => 'welcome', MailClass::TYPE_UNSUBSCRIBE => 'unsub'] as $full => $short) {
269 $mailId = acym_getVar('int', $short.'mailid', 0);
270 if (empty($data['listInformation']->{$full.'_id'}) && !empty($mailId)) {
271 $data['listInformation']->{$full.'_id'} = $mailId;
272 $listInfoSave = clone $data['listInformation'];
273 unset($listInfoSave->subscribers);
274 $savedListId = $listClass->save($listInfoSave);
275 if (empty($savedListId)) {
276 acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVE_LIST'), 'error');
277 }
278 }
279
280 $returnLink = acym_completeLink('lists&task=settings&listId='.$data['listInformation']->id.'&edition=1&'.$short.'mailid={mailid}');
281 $favoriteTemplate = $this->config->get('favorite_template', 0);
282 $startFrom = empty($favoriteTemplate) ? '' : '&from='.$favoriteTemplate;
283
284 if (empty($data['listInformation']->{$full.'_id'})) {
285 $data['tmpls'][$short.'TmplUrl'] = acym_completeLink(
286 'mails&task=edit&step=editEmail&type='.$full.'&type_editor=acyEditor&list_id='.$data['listInformation']->id.'&return='.urlencode(
287 base64_encode($returnLink)
288 ).$startFrom
289 );
290 } else {
291 $data['tmpls'][$short.'TmplUrl'] = acym_completeLink(
292 'mails&task=edit&id='.$data['listInformation']->{$full.'_id'}.'&type='.$full.'&list_id='.$data['listInformation']->id.'&return='.urlencode(
293 base64_encode($returnLink)
294 ).$startFrom
295 );
296 }
297
298 $data['tmpls'][$full] = !empty($data['listInformation']->{$full.'_id'}) ? $mailClass->getOneById($data['listInformation']->{$full.'_id'}) : '';
299 }
300 }
301
302 public function unsetMail(string $type): void
303 {
304 $listClass = new ListClass();
305 $id = acym_getVar('int', 'listId', 0);
306 $list = $listClass->getOneById($id);
307
308 if (empty($list)) {
309 acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVE_LIST'), 'error');
310 $this->listing();
311
312 return;
313 }
314
315 if (!$listClass->hasUserAccess($id)) {
316 die('Access denied for list '.acym_escape($id));
317 }
318
319 $list->$type = null;
320
321 $savedListId = $listClass->save($list);
322 if (!empty($savedListId)) {
323 acym_setVar('listId', $id);
324 $this->settings();
325 } else {
326 acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVE_LIST'), 'error');
327 $this->listing();
328 }
329 }
330
331 public function unsetWelcome(): void
332 {
333 $this->unsetMail('welcome_id');
334 }
335
336 public function unsetUnsubscribe(): void
337 {
338 $this->unsetMail('unsubscribe_id');
339 }
340
341 public function apply(): void
342 {
343 $this->save(false);
344 }
345
346 public function save(bool $goToListing = true): void
347 {
348 acym_checkToken();
349
350 $step = acym_getVar('string', 'step');
351 if ($step === self::LIST_EDITION_TABS_GENERAL) {
352 $listClass = new ListClass();
353 $formData = (object)acym_getVar('array', 'list', []);
354
355 $listId = acym_getVar('int', 'listId', 0);
356 if (!empty($listId)) {
357 $formData->id = $listId;
358 }
359
360 $allowedFields = acym_getColumns('list');
361 $listInformation = new \stdClass();
362 if (empty($formData->welcome_id)) unset($formData->welcome_id);
363 if (empty($formData->unsubscribe_id)) unset($formData->unsubscribe_id);
364 foreach ($formData as $name => $data) {
365 if (!in_array($name, $allowedFields)) {
366 continue;
367 }
368 $listInformation->{$name} = $data;
369 }
370
371 $listInformation->tags = acym_getVar('array', 'list_tags', []);
372
373 if (acym_isAdmin()) {
374 $listInformation->access = empty($listInformation->access) ? '' : ','.implode(',', $listInformation->access).',';
375 } elseif (!empty($formData->id) && !$listClass->hasUserAccess($formData->id)) {
376 die('Cannot save list '.acym_escape($formData->id));
377 }
378
379 $listId = $listClass->save($listInformation);
380
381 if (!empty($listId)) {
382 acym_setVar('listId', $listId);
383 acym_enqueueMessage(acym_translationSprintf('ACYM_LIST_IS_SAVED', $listInformation->name), 'success');
384 $this->saveSubscribersTolist();
385 } else {
386 acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVING'), 'error');
387 if (!empty($listClass->errors)) {
388 acym_enqueueMessage($listClass->errors, 'error');
389 }
390 }
391 }
392
393 if ($goToListing) {
394 $this->listing();
395 } else {
396 $this->settings();
397 }
398 }
399
400 private function saveSubscribersTolist(): bool
401 {
402 $selected = acym_getVar('string', 'acym__entity_select__selected', '[]');
403 $unselected = acym_getVar('string', 'acym__entity_select__unselected', '[]');
404 $usersIds = json_decode(empty($selected) ? '[]' : $selected, true);
405 $usersIdsUnselected = json_decode(empty($unselected) ? '[]' : $unselected, true);
406 $listId = acym_getVar('int', 'listId', 0);
407
408 $listClass = new ListClass();
409 if (empty($listId) || !$listClass->hasUserAccess($listId)) return false;
410
411 acym_arrayToInteger($usersIdsUnselected);
412 if (!empty($usersIdsUnselected)) {
413 acym_query(
414 'UPDATE #__acym_user_has_list
415 SET status = 0, unsubscribe_date = '.acym_escapeDB(acym_date(time(), 'Y-m-d H:i:s')).'
416 WHERE list_id = '.intval($listId).'
417 AND user_id IN ('.implode(', ', $usersIdsUnselected).')'
418 );
419 }
420
421 acym_arrayToInteger($usersIds);
422 if (!empty($usersIds)) {
423 acym_query(
424 'INSERT IGNORE #__acym_user_has_list (`user_id`, `list_id`, `status`, `subscription_date`) (SELECT id, '.intval($listId).', 1, '.acym_escapeDB(
425 acym_date(time(), 'Y-m-d H:i:s')
426 ).' FROM #__acym_user AS user WHERE user.id IN ('.implode(', ', $usersIds).')) ON DUPLICATE KEY UPDATE status = 1'
427 );
428 }
429
430 return true;
431 }
432
433 public function saveSubscribers(): void
434 {
435 acym_checkToken();
436
437 $this->saveSubscribersTolist();
438 $listId = acym_getVar('int', 'listId', 0);
439 acym_setVar('listId', $listId);
440
441 $this->settings();
442 }
443
444 private function sortDataByList(array $data): array
445 {
446 $sortedData = [];
447
448 foreach ($data as $entry) {
449 $pattern = '/(?<!EXECUTED_BY::)\b\d+\b/';
450 preg_match_all($pattern, $entry->data, $listNumbers);
451
452 foreach ($listNumbers[0] as $listNumber) {
453 if (!isset($sortedData[$listNumber])) {
454 $sortedData[$listNumber] = [];
455 }
456
457 $sortedData[$listNumber][] = $entry->unsubscribe_reason;
458 }
459 }
460
461 return $sortedData;
462 }
463
464 private function prepareUnsubReasons(array &$data): void
465 {
466 $historyClass = new HistoryClass();
467 $allReasonsData = $historyClass->getAllUnsubReasons();
468
469 $sortedData = $this->sortDataByList($allReasonsData);
470 $listId = acym_getVar('int', 'listId', 0);
471 $currentListData = $sortedData[$listId] ?? [];
472 $reasonCounts = array_count_values($currentListData);
473
474 $allAnswers = $historyClass->getAllMainLanguageUnsubReasons();
475 $newReasonCounts = [];
476 foreach ($reasonCounts as $key => $value) {
477 if (is_numeric($key) && isset($allAnswers[$key - 1])) {
478 $newReasonCounts[$allAnswers[$key - 1]] = $value;
479 } else {
480 $newReasonCounts[$key] = $value;
481 }
482 }
483
484 arsort($newReasonCounts);
485
486 $data['unsubReasons'] = $newReasonCounts;
487 }
488 }
489