ListsController::LIST_EDITION_TABS_GENERAL, 'subscribers' => ListsController::LIST_EDITION_TABS_SUBSCRIBERS, 'unsubscriptions' => ListsController::LIST_EDITION_TABS_UNSUBSCRIPTIONS, ]; $listId = acym_getVar('int', 'listId', 0); if (!$this->prepareListSettings($data, $listId)) return; if ($tab === ListsController::LIST_EDITION_TABS_GENERAL) { $this->prepareTagsSettings($data, $listId); $this->prepareListStat($data, $listId); $this->prepareListStatEvolution($data, $listId); $this->prepareWelcomeUnsubData($data); $this->prepareMultilingualOption($data); } elseif ($tab === ListsController::LIST_EDITION_TABS_SUBSCRIBERS) { $this->prepareSubscribersEntitySelect($data, $listId); $this->prepareSubscribersSettings($data, $listId); } elseif ($tab === ListsController::LIST_EDITION_TABS_UNSUBSCRIPTIONS) { $this->prepareUnsubReasons($data); } parent::display($data); } private function prepareListSettings(array &$data, int $listId): bool { if (empty($listId)) { $listInformation = new \stdClass(); $listInformation->id = ''; $listInformation->name = ''; $listInformation->frontLabel = ''; $listInformation->description = ''; $listInformation->active = 1; $listInformation->visible = 1; $listInformation->color = '#'.implode('', [ ListClass::COLOR_PARTS[acym_rand(0, 15)], ListClass::COLOR_PARTS[acym_rand(0, 15)], ListClass::COLOR_PARTS[acym_rand(0, 15)], ListClass::COLOR_PARTS[acym_rand(0, 15)], ListClass::COLOR_PARTS[acym_rand(0, 15)], ListClass::COLOR_PARTS[acym_rand(0, 15)], ]); $listInformation->welcome_id = ''; $listInformation->unsubscribe_id = ''; $listInformation->access = []; $listInformation->tracking = 1; $listInformation->translation = []; $listInformation->display_name = ''; $this->breadcrumb[acym_translation('ACYM_NEW_LIST')] = acym_completeLink('lists&task=settings'); } else { $listClass = new ListClass(); $listInformation = $listClass->getOneById($listId); if (is_null($listInformation)) { acym_enqueueMessage(acym_translation('ACYM_LIST_DOESNT_EXIST'), 'error'); $this->listing(); return false; } $subscribersCount = $listClass->getSubscribersCountPerStatusByListIds([$listId]); $this->breadcrumb[$listInformation->name] = acym_completeLink('lists&task=settings&listId='.$listId); $listInformation->access = empty($listInformation->access) ? [] : explode(',', $listInformation->access); $currentUser = acym_currentUserId(); if (!acym_isAdmin() && ($listInformation->cms_user_id != $currentUser)) { $userGroups = acym_getGroupsByUser($currentUser); $canAccess = false; foreach ($userGroups as $group) { if (in_array($group, $listInformation->access)) $canAccess = true; } if (!$canAccess) { acym_enqueueMessage(acym_translation('ACYM_YOU_DONT_HAVE_ACCESS_TO_THIS_LIST'), 'error'); $this->listing(); return false; } } } $listInformation->subscribers = [ 'unsubscribed_users' => 0, 'sendable_users' => 0, 'unconfirmed_users' => 0, 'inactive_users' => 0, ]; if (!empty($subscribersCount)) { $listStats = array_shift($subscribersCount); $listInformation->subscribers = [ 'unsubscribed_users' => $listStats->unsubscribed_users, 'sendable_users' => $listStats->sendable_users, 'unconfirmed_users' => $listStats->unconfirmed_users, 'inactive_users' => $listStats->inactive_users, ]; } $data['listInformation'] = $listInformation; return true; } private function prepareTagsSettings(array &$data, int $listId): void { $tagClass = new TagClass(); $data['allTags'] = $tagClass->getAllTagsByType(TagClass::TYPE_LIST); $data['listTagsName'] = []; $listsTags = $tagClass->getAllTagsByElementId(TagClass::TYPE_LIST, $listId); foreach ($listsTags as $oneTag) { $data['listTagsName'][] = $oneTag; } } private function prepareSubscribersSettings(array &$data, int $listId): void { $data['ordering'] = acym_getVar('string', 'users_ordering', 'id'); $data['orderingSortOrder'] = acym_getVar('string', 'users_ordering_sort_order', 'desc'); $data['classSortOrder'] = $data['orderingSortOrder'] == 'asc' ? 'acymicon-sort-amount-asc' : 'acymicon-sort-amount-desc'; $listClass = new ListClass(); $data['subscribers'] = $listClass->getSubscribersForList( [ 'listIds' => [$listId], 'offset' => 0, 'limit' => 500, 'status' => 1, 'orderBy' => $data['ordering'], 'orderBySort' => $data['orderingSortOrder'], ] ); foreach ($data['subscribers'] as &$oneSub) { if ($oneSub->subscription_date == '0000-00-00 00:00:00') continue; $oneSub->subscription_date = acym_date(strtotime($oneSub->subscription_date), acym_translation('ACYM_DATE_FORMAT_LC2')); } } private function prepareSubscribersEntitySelect(array &$data, int $listId): void { if (empty($listId)) { $data['subscribersEntitySelect'] = ''; return; } $data['subscribersEntitySelect'] = $listId; } private function prepareListStat(array &$data, int $listId): void { $data['listStats'] = ['deliveryRate' => 0, 'openRate' => 0, 'clickRate' => 0, 'failRate' => 0, 'bounceRate' => 0]; if (empty($listId)) return; $listClass = new ListClass(); $mails = $listClass->getMailsByListId($listId); if (empty($mails)) return; $mailStatClass = new MailStatClass(); $mailsStat = $mailStatClass->getCumulatedStatsByMailIds($mails); if (intval($mailsStat->sent) + intval($mailsStat->fails) === 0) return; $totalSent = intval($mailsStat->sent) + intval($mailsStat->fails); if (empty($mailsStat->open)) $mailsStat->open = 0; if (empty($mailsStat->fails)) $mailsStat->fails = 0; if (empty($mailsStat->bounces)) $mailsStat->bounces = 0; $data['listStats']['openRate'] = number_format($mailsStat->open / $totalSent * 100, 2); $data['listStats']['deliveryRate'] = number_format(($mailsStat->sent - $mailsStat->bounces) / $totalSent * 100, 2); $data['listStats']['failRate'] = number_format($mailsStat->fails / $totalSent * 100, 2); $data['listStats']['bounceRate'] = number_format($mailsStat->bounces / $totalSent * 100, 2); $urlClickClass = new UrlClickClass(); $nbClicks = $urlClickClass->getClickRateByMailIds($mails); $data['listStats']['clickRate'] = number_format($nbClicks / $totalSent * 100, 2); } private function prepareListStatEvolution(array &$data, int $listId): void { $data['evol'] = []; $listClass = new ListClass(); $subEvolStat = $listClass->getYearSubEvolutionPerList($listId); if (empty($subEvolStat['subscribers']) && empty($subEvolStat['unsubscribers'])) return; // Init tables ordered by month number starting on month from one year ago $firstMonth = gmdate('n') + 1; $zeroReached = false; $evolSub = []; $evolUnsub = []; for ($i = 0; $i < 12; $i++) { $month = ($firstMonth + $i) % 13; if ($month == 0) $zeroReached = true; if ($zeroReached) $month += 1; $evolSub[$month] = $month.'_0'; $evolUnsub[$month] = $month.'_0'; } foreach ($subEvolStat['subscribers'] as $unit => $monthData) { $evolSub[$monthData->monthSub] = $monthData->monthSub.'_'.$monthData->nbUser; } foreach ($subEvolStat['unsubscribers'] as $unit => $monthData) { $evolUnsub[$monthData->monthUnsub] = $monthData->monthUnsub.'_'.$monthData->nbUser; } foreach ($evolSub as $month => $oneEvol) { $data['evol'][0][] = $oneEvol; $data['evol'][1][] = $evolUnsub[$month]; } } protected function prepareWelcomeUnsubData(array &$data): void { $data['tmpls'] = []; if (empty($data['listInformation']->id)) return; $listClass = new ListClass(); $mailClass = new MailClass(); foreach ([MailClass::TYPE_WELCOME => 'welcome', MailClass::TYPE_UNSUBSCRIBE => 'unsub'] as $full => $short) { $mailId = acym_getVar('int', $short.'mailid', 0); if (empty($data['listInformation']->{$full.'_id'}) && !empty($mailId)) { $data['listInformation']->{$full.'_id'} = $mailId; $listInfoSave = clone $data['listInformation']; unset($listInfoSave->subscribers); $savedListId = $listClass->save($listInfoSave); if (empty($savedListId)) { acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVE_LIST'), 'error'); } } $returnLink = acym_completeLink('lists&task=settings&listId='.$data['listInformation']->id.'&edition=1&'.$short.'mailid={mailid}'); $favoriteTemplate = $mailClass->getFavoriteTemplateId(); $startFrom = empty($favoriteTemplate) ? '' : '&from='.$favoriteTemplate; if (empty($data['listInformation']->{$full.'_id'})) { $data['tmpls'][$short.'TmplUrl'] = acym_completeLink( 'mails&task=edit&step=editEmail&type='.$full.'&type_editor=acyEditor&list_id='.$data['listInformation']->id.'&return='.urlencode( base64_encode($returnLink) ).$startFrom ); } else { $data['tmpls'][$short.'TmplUrl'] = acym_completeLink( 'mails&task=edit&id='.$data['listInformation']->{$full.'_id'}.'&type='.$full.'&list_id='.$data['listInformation']->id.'&return='.urlencode( base64_encode($returnLink) ).$startFrom ); } $data['tmpls'][$full] = !empty($data['listInformation']->{$full.'_id'}) ? $mailClass->getOneById($data['listInformation']->{$full.'_id'}) : ''; } } public function unsetMail(string $type): void { wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token'); $listClass = new ListClass(); $id = acym_getVar('int', 'listId', 0); $list = $listClass->getOneById($id); if (empty($list)) { acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVE_LIST'), 'error'); $this->listing(); return; } if (!$listClass->hasUserAccess($id)) { die('Access denied for list '.esc_html($id)); } $list->$type = null; $savedListId = $listClass->save($list); if (!empty($savedListId)) { acym_setVar('listId', $id); $this->settings(); } else { acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVE_LIST'), 'error'); $this->listing(); } } public function unsetWelcome(): void { $this->unsetMail('welcome_id'); } public function unsetUnsubscribe(): void { $this->unsetMail('unsubscribe_id'); } public function apply(): void { $this->save(false); } public function save(bool $goToListing = true): void { wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token'); $step = acym_getVar('string', 'step'); if ($step === self::LIST_EDITION_TABS_GENERAL) { $listClass = new ListClass(); $formData = (object)acym_getVar('array', 'list', []); $listId = acym_getVar('int', 'listId', 0); if (!empty($listId)) { $formData->id = $listId; } $allowedFields = acym_getColumns('list'); $listInformation = new \stdClass(); if (empty($formData->welcome_id)) unset($formData->welcome_id); if (empty($formData->unsubscribe_id)) unset($formData->unsubscribe_id); foreach ($formData as $name => $data) { if (!in_array($name, $allowedFields)) { continue; } $listInformation->{$name} = $data; } $listInformation->tags = acym_getVar('array', 'list_tags', []); if (acym_isAdmin()) { $listInformation->access = empty($listInformation->access) ? '' : ','.implode(',', $listInformation->access).','; } elseif (!empty($formData->id) && !$listClass->hasUserAccess($formData->id)) { die('Cannot save list '.esc_html($formData->id)); } $listId = $listClass->save($listInformation); if (!empty($listId)) { acym_setVar('listId', $listId); acym_enqueueMessage(acym_translationSprintf('ACYM_LIST_IS_SAVED', $listInformation->name), 'success'); $this->saveSubscribersTolist(); } else { acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVING'), 'error'); if (!empty($listClass->errors)) { acym_enqueueMessage($listClass->errors, 'error'); } } } if ($goToListing) { $this->listing(); } else { $this->settings(); } } private function saveSubscribersTolist(): bool { $selected = acym_getVar('string', 'acym__entity_select__selected', '[]'); $unselected = acym_getVar('string', 'acym__entity_select__unselected', '[]'); $usersIds = json_decode(empty($selected) ? '[]' : $selected, true); $usersIdsUnselected = json_decode(empty($unselected) ? '[]' : $unselected, true); $listId = acym_getVar('int', 'listId', 0); $listClass = new ListClass(); if (empty($listId) || !$listClass->hasUserAccess($listId)) return false; acym_arrayToInteger($usersIdsUnselected); if (!empty($usersIdsUnselected)) { acym_query( 'UPDATE #__acym_user_has_list SET status = 0, unsubscribe_date = '.acym_escapeDB(acym_date(time(), 'Y-m-d H:i:s')).' WHERE list_id = '.intval($listId).' AND user_id IN ('.implode(', ', $usersIdsUnselected).')' ); } acym_arrayToInteger($usersIds); if (!empty($usersIds)) { acym_query( 'INSERT IGNORE #__acym_user_has_list (`user_id`, `list_id`, `status`, `subscription_date`) (SELECT id, '.intval($listId).', 1, '.acym_escapeDB( acym_date(time(), 'Y-m-d H:i:s') ).' FROM #__acym_user AS user WHERE user.id IN ('.implode(', ', $usersIds).')) ON DUPLICATE KEY UPDATE status = 1' ); } return true; } public function saveSubscribers(): void { wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token'); $this->saveSubscribersTolist(); $listId = acym_getVar('int', 'listId', 0); acym_setVar('listId', $listId); $this->settings(); } private function sortDataByList(array $data): array { $sortedData = []; foreach ($data as $entry) { $pattern = '/(?data, $listNumbers); foreach ($listNumbers[0] as $listNumber) { if (!isset($sortedData[$listNumber])) { $sortedData[$listNumber] = []; } $sortedData[$listNumber][] = $entry->unsubscribe_reason; } } return $sortedData; } private function prepareUnsubReasons(array &$data): void { $historyClass = new HistoryClass(); $allReasonsData = $historyClass->getAllUnsubReasons(); $sortedData = $this->sortDataByList($allReasonsData); $listId = acym_getVar('int', 'listId', 0); $currentListData = $sortedData[$listId] ?? []; $reasonCounts = array_count_values($currentListData); $allAnswers = $historyClass->getAllMainLanguageUnsubReasons(); $newReasonCounts = []; foreach ($reasonCounts as $key => $value) { if (is_numeric($key) && isset($allAnswers[$key - 1])) { $newReasonCounts[$allAnswers[$key - 1]] = $value; } else { $newReasonCounts[$key] = $value; } } arsort($newReasonCounts); $data['unsubReasons'] = $newReasonCounts; } }