PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.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
← All changes | back/Core/AcymPlugin.php +0 -1929 11.1.0 → 11.1.1 View file →
@@ -1,1929 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Core;
4 -
5 -use AcyMailing\Classes\CampaignClass;
6 -use AcyMailing\Classes\PluginClass;
7 -use AcyMailing\Helpers\PluginHelper;
8 -use Joomla\CMS\HTML\HTMLHelper;
9 -
10 -class AcymPlugin extends AcymObject
11 -{
12 - // The row placeholders are replaced by the JS when a row is added to the form
13 - const CONDITION_FIELD_NAME = 'acym_condition[conditions][__numor__][__numand__]';
14 - const FILTER_FIELD_NAME = 'acym_action[filters][__numor__][__numand__]';
15 - const MAILBOX_ACTION_FIELD_NAME = 'acym_action[__num__]';
16 -
17 - public string $cms = 'all';
18 - public string $name = '';
19 - public bool $installed = true;
20 -
21 - protected array $addonDefinition;
22 - protected PluginHelper $pluginHelper;
23 -
24 - protected int $rootCategoryId = 1;
25 - protected array $categories;
26 - protected array $catvalues = [];
27 - private array $cats = [];
28 - private array $subCategories = [];
29 -
30 - protected array $tagvalues = [];
31 -
32 - protected array $tags = [];
33 - protected object $pageInfo;
34 - protected array $searchFields = [];
35 - protected string $querySelect = '';
36 - protected string $query = '';
37 - protected array $filters = [];
38 - protected string $elementIdTable = '';
39 - protected string $elementIdColumn = '';
40 -
41 - public object $pluginDescription;
42 - public object $generateCampaignResult;
43 -
44 - protected ?object $defaultValues;
45 - protected string $emailLanguage = '';
46 - private int $campaignId;
47 - private string $campaignType;
48 -
49 - protected array $displayOptions = [];
50 - protected array $replaceOptions = [];
51 - protected array $elementOptions = [];
52 - protected array $customOptions = [];
53 -
54 - private array $sendingPlugins = [
55 - 'wp_mail_smtp' => 'WP Mail SMTP',
56 - ];
57 -
58 - public array $errors = [];
59 - public string $logFilename = '';
60 - protected int $responseCode;
61 -
62 - private bool $active;
63 - public array $settings = [];
64 - private array $savedSettings = [];
65 -
66 - public array $automationTriggers = [];
67 - public array $automationActions = [];
68 - public array $automationConditions = [];
69 - public array $automationFilters = [];
70 - public array $mailboxActions = [];
71 -
72 - public function __construct()
73 - {
74 - parent::__construct();
75 -
76 - $this->elementOptions = ['wrappedText' => [acym_translation('ACYM_WRAPPED_TEXT')]];
77 -
78 - //TODO only load this helper once even if 50 plugins are loaded
79 - $this->pluginHelper = new PluginHelper();
80 - $this->pageInfo = new \stdClass();
81 -
82 - $this->pluginDescription = new \stdClass();
83 - $this->pluginDescription->plugin = get_class($this);
84 -
85 - $this->name = strtolower(substr($this->pluginDescription->plugin, 7));
86 -
87 - $this->generateCampaignResult = new \stdClass();
88 - $this->generateCampaignResult->status = true;
89 - $this->generateCampaignResult->message = '';
90 -
91 - $this->campaignId = acym_getVar('int', 'campaignId', 0);
92 - $this->campaignType = acym_getVar('string', 'campaign_type', '');
93 -
94 - $pluginClass = new PluginClass();
95 - $currentAddon = $pluginClass->getOnePluginByFolderName($this->name);
96 - $this->active = empty($currentAddon) || $currentAddon->active;
97 -
98 - if (!empty($currentAddon->settings)) {
99 - if (is_string($currentAddon->settings)) {
100 - $this->savedSettings = json_decode($currentAddon->settings, true);
101 - } else {
102 - $this->savedSettings = $currentAddon->settings;
103 - }
104 - }
105 -
106 - $this->logFilename = acym_getErrorLogFilename(empty($this->name) ? get_class($this) : $this->name);
107 - }
108 -
109 - protected function displaySelectionZone(string $zoneContent): void
110 - {
111 - ?>
112 - <p class="acym__wysid__right__toolbar__p acym__wysid__right__toolbar__p__open acym__title">
113 - <?php echo esc_html(acym_translation('ACYM_CONTENT_TO_INSERT')); ?><i class="acymicon-keyboard-arrow-up"></i>
114 - </p>
115 - <div class="acym__wysid__right__toolbar__design--show acym__wysid__right__toolbar__design acym__wysid__context__modal__container">
116 - <?php echo $zoneContent; ?>
117 - </div>
118 - <?php
119 - }
120 -
121 - /**
122 - * Called using ajax
123 - */
124 - public function displayListing(): void
125 - {
126 - echo $this->prepareListing();
127 - }
128 -
129 - public function prepareListing()
130 - {
131 - $this->pageInfo->limit = 10;
132 - $this->pageInfo->page = acym_getVar('int', 'pagination_page_ajax', 1);
133 - $this->pageInfo->start = ($this->pageInfo->page - 1) * $this->pageInfo->limit;
134 - $this->pageInfo->search = acym_getVar('string', 'plugin_search', '');
135 - $this->pageInfo->filter_cat = acym_getVar('int', 'plugin_category', 0);
136 - $this->pageInfo->orderdir = 'DESC';
137 - $this->pageInfo->loadMore = acym_getVar('boolean', 'loadMore', false);
138 -
139 - if (!empty($this->pageInfo->search) && !empty($this->searchFields)) {
140 - $searchVal = '%'.acym_getEscaped($this->pageInfo->search, true).'%';
141 - $this->filters[] = implode(' LIKE '.acym_escapeDB($searchVal).' OR ', $this->searchFields).' LIKE '.acym_escapeDB($searchVal);
142 - }
143 -
144 - return '';
145 - }
146 -
147 - public function getElements(): array
148 - {
149 - $conditions = '';
150 - if (!empty($this->filters)) {
151 - $conditions = ' WHERE ('.implode(') AND (', $this->filters).')';
152 - }
153 -
154 - $ordering = '';
155 - if (!empty($this->pageInfo->order)) {
156 - $ordering = ' ORDER BY '.acym_secureDBColumn($this->pageInfo->order).' '.acym_secureDBColumn($this->pageInfo->orderdir);
157 - }
158 -
159 - $rows = acym_loadObjectList($this->querySelect.$this->query.$conditions.$ordering, '', $this->pageInfo->start, $this->pageInfo->limit);
160 - $this->pageInfo->total = acym_loadResult('SELECT COUNT(*) '.$this->query.$conditions.$ordering);
161 -
162 - if (!empty($this->defaultValues->id) && $this->defaultValues->defaultPluginTab === $this->name) {
163 - $found = false;
164 - foreach ($rows as $oneRow) {
165 - if (intval($oneRow->{$this->elementIdColumn}) === intval($this->defaultValues->id)) {
166 - $found = true;
167 - }
168 - }
169 -
170 - if (!$found) {
171 - $conditions = ' WHERE '.$this->elementIdTable.'.'.$this->elementIdColumn.' = '.intval($this->defaultValues->id);
172 - $row = acym_loadObject($this->querySelect.$this->query.$conditions);
173 - if (!empty($row)) {
174 - $rows[] = $row;
175 - }
176 - }
177 - }
178 -
179 - return $rows;
180 - }
181 -
182 - protected function getFilteringZone(bool $categoryFilter = true): string
183 - {
184 - $result = '<div class="grid-x" id="plugin_listing_filters">
185 - <div class="cell medium-6">
186 - <input type="text" name="plugin_search" placeholder="'.esc_attr(acym_translation('ACYM_SEARCH')).'"/>
187 - </div>
188 - <div class="cell medium-6 grid-x">
189 - <div class="cell hide-for-small-only medium-auto"></div>
190 - <div class="cell medium-shrink">';
191 -
192 - if ($categoryFilter) {
193 - $result .= $this->getCategoryFilter();
194 - }
195 -
196 - $result .= '</div>
197 - </div>
198 - </div>';
199 -
200 - return $result;
201 - }
202 -
203 - public function prepareWPCategories(string $type): void
204 - {
205 - $this->categories = acym_loadObjectList(
206 - 'SELECT cat.term_taxonomy_id AS id, parent.term_taxonomy_id AS parent_id, catdetails.name AS title
207 - FROM `#__term_taxonomy` AS cat
208 - JOIN `#__terms` AS catdetails ON cat.term_id = catdetails.term_id
209 - LEFT JOIN `#__term_taxonomy` AS parent ON cat.parent = parent.term_id
210 - WHERE cat.taxonomy = '.acym_escapeDB($type)
211 - );
212 - foreach ($this->categories as $i => $oneCat) {
213 - if (empty($oneCat->parent_id)) {
214 - $this->categories[$i]->parent_id = $this->rootCategoryId;
215 - }
216 - }
217 - }
218 -
219 - protected function getCategoryFilter()
220 - {
221 - $filter_cat = acym_getVar('int', 'plugin_category', 0);
222 - $this->catvalues = [];
223 - $this->catvalues[] = acym_selectOption(0, 'ACYM_ALL');
224 -
225 - $this->cats = [];
226 - $this->subCategories = [];
227 - if (!empty($this->categories)) {
228 - foreach ($this->categories as $oneCat) {
229 - $this->cats[$oneCat->parent_id][] = $oneCat;
230 - }
231 - $this->handleChildrenCategories($this->rootCategoryId);
232 - foreach ($this->categories as $oneCat) {
233 - $this->subCategories[$oneCat->id] = $this->getSubCats($oneCat->id);
234 - }
235 - }
236 -
237 - return acym_select(
238 - $this->catvalues,
239 - 'plugin_category',
240 - intval($filter_cat),
241 - ['class' => 'plugin_category_select']
242 - );
243 - }
244 -
245 - private function getSubCats(int $categoryId): array
246 - {
247 - $result = [$categoryId];
248 - if (empty($this->cats[$categoryId])) {
249 - return $result;
250 - }
251 -
252 - foreach ($this->cats[$categoryId] as $oneSubCategory) {
253 - $result = array_merge($result, $this->getSubCats($oneSubCategory->id));
254 - }
255 -
256 - return $result;
257 - }
258 -
259 - protected function handleChildrenCategories(int $parent_id, int $level = 0): void
260 - {
261 - if (empty($this->cats[$parent_id])) return;
262 -
263 - foreach ($this->cats[$parent_id] as $cat) {
264 - $this->catvalues[] = acym_selectOption($cat->id, str_repeat(' - - ', $level).$cat->title);
265 - $this->handleChildrenCategories($cat->id, $level + 1);
266 - }
267 - }
268 -
269 - protected function getSubCategories(int $categoryId): array
270 - {
271 - $this->getCategoryFilter();
272 -
273 - return $this->subCategories[$categoryId];
274 - }
275 -
276 - protected function autoContentOptions(array &$options, ?string $type = null): void
277 - {
278 - if ($type === 'event') {
279 - $options[] = [
280 - 'title' => 'ACYM_FROM',
281 - 'type' => 'date',
282 - 'name' => 'from',
283 - 'default' => time(),
284 - 'relativeDate' => '+',
285 - ];
286 -
287 - $options[] = [
288 - 'title' => 'ACYM_TO',
289 - 'type' => 'date',
290 - 'name' => 'to',
291 - 'default' => '',
292 - 'relativeDate' => '+',
293 - ];
294 - } elseif ($type !== 'simple') {
295 - $options[] = [
296 - 'title' => 'ACYM_MIN_PUBLISH_DATE',
297 - 'tooltip' => 'ACYM_MIN_PUBLISH_DATE_DESC',
298 - 'type' => 'date',
299 - 'name' => 'min_publish',
300 - 'default' => '',
301 - 'relativeDate' => '-',
302 - ];
303 - }
304 -
305 - $options[] = [
306 - 'title' => 'ACYM_COLUMNS',
307 - 'type' => 'number',
308 - 'name' => 'cols',
309 - 'default' => 1,
310 - ];
311 -
312 - $options[] = [
313 - 'title' => 'ACYM_COLUMN_HORIZONTAL_PADDING',
314 - 'type' => 'number',
315 - 'name' => 'hpadding',
316 - 'default' => 10,
317 - ];
318 -
319 - $options[] = [
320 - 'title' => 'ACYM_COLUMN_VERTICAL_PADDING',
321 - 'type' => 'number',
322 - 'name' => 'vpadding',
323 - 'default' => 10,
324 - ];
325 -
326 - $options[] = [
327 - 'title' => 'ACYM_MAX_NB_ELEMENTS',
328 - 'type' => 'number',
329 - 'name' => 'max',
330 - 'default' => 20,
331 - ];
332 - }
333 -
334 - protected function autoCampaignOptions(array &$options, bool $modified = false): void
335 - {
336 - if (empty($this->campaignId) && empty($this->campaignType)) {
337 - return;
338 - } elseif (!empty($this->campaignId) && (empty($this->campaignType) || $this->campaignType !== 'auto')) {
339 - $campaignClass = new CampaignClass();
340 - $campaign = $campaignClass->getOneById($this->campaignId);
341 - if ($campaign->sending_type !== 'auto') return;
342 - } elseif (empty($this->campaignId) && !empty($this->campaignType) && $this->campaignType !== 'auto') {
343 - return;
344 - }
345 -
346 - $options[] = [
347 - 'title' => 'ACYM_DOCUMENTATION',
348 - 'type' => 'custom',
349 - 'name' => 'documentation',
350 - 'output' => static function (): void {
351 - echo '<a target="_blank" href="'.esc_url(
352 - ACYM_DOCUMENTATION.'main-pages/campaigns/automatic-campaigns#dont-send-twice-the-same-content'
353 - ).'"><i class="acymicon-book"></i></a>';
354 - },
355 - 'js' => '',
356 - 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
357 - ];
358 -
359 - if ($modified) {
360 - $options[] = [
361 - 'title' => 'ACYM_DATE',
362 - 'type' => 'select',
363 - 'name' => 'datefilter',
364 - 'default' => 'onlynew',
365 - 'tooltip' => 'ACYM_ONLY_NEWLY_CREATED_DESC',
366 - 'options' => [
367 - '' => 'ACYM_NO_FILTER',
368 - 'onlynew' => 'ACYM_ONLY_NEWLY_CREATED',
369 - 'onlymodified' => 'ACYM_ONLY_NEWLY_MODIFIED',
370 - ],
371 - 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
372 - ];
373 - } else {
374 - $options[] = [
375 - 'title' => 'ACYM_ONLY_NEWLY_CREATED',
376 - 'type' => 'boolean',
377 - 'name' => 'onlynew',
378 - 'default' => true,
379 - 'tooltip' => 'ACYM_ONLY_NEWLY_CREATED_DESC',
380 - 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
381 - ];
382 - }
383 -
384 - $options[] = [
385 - 'title' => 'ACYM_MIN_NB_ELEMENTS',
386 - 'type' => 'number',
387 - 'name' => 'min',
388 - 'default' => 0,
389 - 'tooltip' => 'ACYM_MIN_NB_ELEMENTS_DESC',
390 - 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
391 - ];
392 - }
393 -
394 - protected function getElementsListing(array $options): string
395 - {
396 - if ($this->pageInfo->loadMore) {
397 - ob_start();
398 - $this->displayInnerListing($options);
399 -
400 - return ob_get_clean();
401 - }
402 - $listing = '<div id="plugin_listing" class="acym__popup__listing">';
403 - $listing .= '<input type="hidden" name="plugin" value="'.esc_attr(get_class($this)).'" />';
404 -
405 - // Column names
406 - $listing .= '<div class="cell grid-x hide-for-small-only plugin_listing_headers">';
407 - foreach ($options['header'] as $oneColumn) {
408 - $class = empty($oneColumn['class']) ? '' : ' '.$oneColumn['class'];
409 - $listing .= '<div class="cell plugin_listing_headers__title medium-'.$oneColumn['size'].$class.'">'.acym_translation($oneColumn['label']).'</div>';
410 - }
411 - $listing .= '</div>';
412 -
413 - ob_start();
414 - $this->displayInnerListing($options);
415 - $listing .= ob_get_clean();
416 -
417 - $listing .= '<input type="hidden" value="1" id="acym_pagination__ajax__load-more" name="acym_pagination__ajax__load-more">';
418 - $listing .= '</div>';
419 -
420 - return $listing;
421 - }
422 -
423 - private function displayInnerListing(array $options): void
424 - {
425 - if (empty($options['rows'])) {
426 - if ($this->pageInfo->loadMore) {
427 - echo '<h3 class="cell acym__listing__empty__load-more text-center">'.esc_html(acym_translation('ACYM_NO_MORE_RESULTS')).'</h3>';
428 - } else {
429 - echo '<h1 class="cell acym__listing__empty__search__modal text-center">'.esc_html(acym_translation('ACYM_NO_RESULTS_FOUND')).'</h1>';
430 - }
431 -
432 - return;
433 - }
434 -
435 - $selected = explode(',', acym_getVar('string', 'selected', ''));
436 - if (!empty($this->defaultValues->id)) {
437 - $selected = [$this->defaultValues->id];
438 - }
439 -
440 - foreach ($options['rows'] as $row) {
441 - $class = 'cell grid-x acym__row__no-listing acym__listing__row__popup';
442 - if (in_array($row->{$options['id']}, $selected)) {
443 - $class .= ' selected_row';
444 - }
445 -
446 - echo '<div
447 - class="'.esc_attr($class).'"
448 - data-id="'.esc_attr($row->{$options['id']}).'"
449 - onclick="applyContent'.esc_attr($this->name).'(\''.esc_attr($row->{$options['id']}).'\', this);">';
450 -
451 - foreach ($options['header'] as $column => $oneColumn) {
452 - $value = $row->$column;
453 - $class = empty($oneColumn['class']) ? '' : ' '.$oneColumn['class'];
454 -
455 - echo '<div class="cell medium-'.esc_attr($oneColumn['size'].$class).'">';
456 -
457 - if (!empty($oneColumn['type'])) {
458 - if ($oneColumn['type'] === 'date') {
459 - if (empty($value)) {
460 - echo '-';
461 - } else {
462 - if (!is_numeric($value) && $value != '0000-00-00 00:00:00') {
463 - $value = strtotime($value);
464 - }
465 - $tooltip = acym_date($value, acym_translation('ACYM_DATE_FORMAT_LC2'));
466 - acym_tooltip(
467 - [
468 - 'hoveredText' => acym_date($value, acym_translation('ACYM_DATE_FORMAT_LC5')),
469 - 'textShownInTooltip' => $tooltip,
470 - ]
471 - );
472 - }
473 - } elseif ($oneColumn['type'] === 'int') {
474 - echo intval($value);
475 - } else {
476 - echo esc_html($value);
477 - }
478 - } else {
479 - echo esc_html($value);
480 - }
481 -
482 - echo '</div>';
483 - }
484 -
485 - echo '</div>';
486 - }
487 - }
488 -
489 - protected function getCategoryListing(): string
490 - {
491 - $listing = '';
492 - if (empty($this->catvalues)) {
493 - $listing .= '<h1 class="cell acym__listing__empty__search__modal text-center">'.acym_translation('ACYM_NO_RESULTS_FOUND').'</h1>';
494 -
495 - return $listing;
496 - }
497 -
498 - $listing .= '<div class="acym__popup__listing padding-0">';
499 - $selected = [];
500 - if (!empty($this->defaultValues->id) && strpos($this->defaultValues->id, '-')) {
501 - $selected = explode('-', $this->defaultValues->id);
502 - }
503 - foreach ($this->catvalues as $oneCat) {
504 - if (empty($oneCat->value)) continue;
505 -
506 - $classes = 'cell grid-x acym__row__no-listing acym__listing__row__popup';
507 - if (in_array($oneCat->value, $selected)) {
508 - $classes .= ' selected_row';
509 - }
510 - $listing .= '<div class="'.$classes.'" data-id="'.intval($oneCat->value).'" onclick="applyContentauto'.esc_attr($this->name).'('.intval($oneCat->value).', this);">
511 - <div class="cell medium-5">'.esc_html($oneCat->text).'</div>
512 - </div>';
513 - }
514 - $listing .= '</div>';
515 -
516 - return $listing;
517 - }
518 -
519 - protected function getTagListing(): string
520 - {
521 - $listing = '';
522 - if (empty($this->tagvalues)) {
523 - $listing .= '<h1 class="cell acym__listing__empty__search__modal text-center">'.acym_translation('ACYM_NO_RESULTS_FOUND').'</h1>';
524 -
525 - return $listing;
526 - }
527 -
528 - $listing .= '<div class="acym__popup__listing padding-0">';
529 - $selected = [];
530 - if (!empty($this->defaultValues->id) && strpos($this->defaultValues->id, '-')) {
531 - $selected = explode('-', $this->defaultValues->id);
532 - }
533 - $termIdName = 'term_id';
534 - if ('wordpress' === ACYM_CMS) {
535 - $termIdName = 'term_taxonomy_id';
536 - }
537 - foreach ($this->tagvalues as $oneTag) {
538 - if (empty($oneTag->$termIdName)) continue;
539 -
540 - $class = 'cell grid-x acym__row__no-listing acym__listing__row__popup';
541 - if (in_array($oneTag->$termIdName, $selected)) {
542 - $class .= ' selected_row';
543 - }
544 - $listing .= '<div class="'.esc_attr($class).'"
545 - data-id="'.intval($oneTag->$termIdName).'"
546 - onclick="applyContent'.esc_attr($this->name).'_tags('.intval($oneTag->$termIdName).', this);">
547 - <div class="cell medium-5">'.esc_html($oneTag->name).'</div>
548 - </div>';
549 - }
550 - $listing .= '</div>';
551 -
552 - return $listing;
553 - }
554 -
555 - protected function replaceMultiple(object &$email)
556 - {
557 - $this->generateByCategory($email);
558 - if (empty($this->tags)) return;
559 -
560 - $this->pluginHelper->replaceTags($email, $this->tags, true);
561 - }
562 -
563 - protected function handleOrderBy(string &$query, object $parameter, ?string $table = null)
564 - {
565 - if (empty($parameter->order)) return;
566 -
567 - $ordering = explode(',', $parameter->order);
568 - if ($ordering[0] === 'rand') {
569 - $query .= ' ORDER BY rand()';
570 - } else {
571 - $table = null === $table ? '' : $table.'.';
572 - $column = $ordering[0];
573 -
574 - if (strpos($column, '.') !== false) {
575 - $parts = explode('.', $column, 2);
576 - $table = acym_secureDBColumn($parts[0]).'.';
577 - $column = $parts[1];
578 - }
579 -
580 - $query .= ' ORDER BY '.$table.'`'.acym_secureDBColumn(trim($column)).'` '.acym_secureDBColumn(trim($ordering[1]));
581 - }
582 - }
583 -
584 - protected function handleMax(string &$query, object $parameter): void
585 - {
586 - if (empty($parameter->max)) {
587 - $parameter->max = 20;
588 - }
589 - $query .= ' LIMIT '.intval($parameter->max);
590 - }
591 -
592 - protected function handleMin(array $elements, object $parameter): void
593 - {
594 - if (!empty($parameter->min) && count($elements) < $parameter->min) {
595 - $this->generateCampaignResult->status = false;
596 - $this->generateCampaignResult->message = acym_translationSprintf(
597 - 'ACYM_GENERATE_CAMPAIGN_NOT_ENOUGH_CONTENT',
598 - $this->pluginDescription->name,
599 - count($elements),
600 - $parameter->min
601 - );
602 - }
603 - }
604 -
605 - protected function getLastGenerated(int $mailId): int
606 - {
607 - $campaignClass = new CampaignClass();
608 -
609 - return $campaignClass->getLastGenerated($mailId);
610 - }
611 -
612 - /**
613 - * Returns the individual elements tags based on a query result
614 - */
615 - protected function finalizeCategoryFormat(string $query, object $parameter, ?string $table = null): string
616 - {
617 - $this->handleOrderBy($query, $parameter, $table);
618 - $this->handleMax($query, $parameter);
619 -
620 - $elements = acym_loadResultArray($query);
621 -
622 - return $this->formatIndividualTags($elements, $parameter);
623 - }
624 -
625 - protected function formatIndividualTags(array $elements, object $parameter): string
626 - {
627 - $this->handleMin($elements, $parameter);
628 -
629 - if (empty($elements)) return '';
630 -
631 - $elements = $this->groupByCategory($elements);
632 -
633 - $customLayout = ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'_auto.php';
634 - if (file_exists($customLayout)) {
635 - ob_start();
636 - require $customLayout;
637 -
638 - return ob_get_clean();
639 - }
640 -
641 - $arrayElements = $this->buildIndividualTags($elements, $parameter);
642 -
643 - return $this->pluginHelper->getFormattedResult($arrayElements, $parameter);
644 - }
645 -
646 - protected function buildIndividualTags(array $elements, object $parameter): array
647 - {
648 - $arrayElements = [];
649 - unset($parameter->id);
650 -
651 - $i = 0;
652 - foreach ($elements as $oneElementId) {
653 - $args = [];
654 - $args[] = $this->name.':'.$oneElementId;
655 -
656 - foreach ($parameter as $oneParam => $val) {
657 - if (is_bool($val)) {
658 - $args[] = $oneParam;
659 - } else {
660 - $args[] = $oneParam.':'.$val;
661 - }
662 - }
663 -
664 - if ($i % 2 === 1 && !empty($parameter->alternate)) {
665 - $args[] = 'invert';
666 - }
667 -
668 - $arrayElements[] = '{'.implode('| ', $args).'}';
669 -
670 - $i++;
671 - }
672 -
673 - return $arrayElements;
674 - }
675 -
676 - /**
677 - * This method can be overridden in the add-on when a group by category option is added
678 - */
679 - protected function groupByCategory(array $elements)
680 - {
681 - return $elements;
682 - }
683 -
684 - protected function getSelectedArea(object $parameter): array
685 - {
686 - $allcats = explode('-', $parameter->id);
687 - $selectedArea = [];
688 - foreach ($allcats as $oneCat) {
689 - if (empty($oneCat)) continue;
690 - $selectedArea[] = intval($oneCat);
691 - }
692 -
693 - return $selectedArea;
694 - }
695 -
696 - protected function replaceOne(object &$email): void
697 - {
698 - $tags = $this->pluginHelper->extractTags($email, $this->name);
699 - if (empty($tags)) return;
700 -
701 - $newConfiguration = [
702 - 'dcontent_default_'.get_class($this) => json_encode(end($tags)),
703 - ];
704 - $this->config->saveConfig($newConfiguration);
705 -
706 - if (method_exists($this, 'loadLibraries') && !$this->loadLibraries($email)) {
707 - return;
708 - }
709 -
710 - $this->emailLanguage = $email->links_language;
711 - $translationTool = $this->config->get('translate_content', 'no');
712 -
713 - $tagsReplaced = [];
714 - foreach ($tags as $i => $oneTag) {
715 - if (isset($tagsReplaced[$i])) continue;
716 -
717 - if (!empty($this->emailLanguage) && $translationTool !== 'no' && acym_isMultilingual()) {
718 - $oneTag->id = $this->getTranslationId($oneTag->id, $translationTool);
719 - }
720 - $tagsReplaced[$i] = $this->replaceIndividualContent($oneTag);
721 - }
722 -
723 - $email->custom_view = file_exists(ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'.html');
724 -
725 - $this->pluginHelper->replaceTags($email, $tagsReplaced, true);
726 - }
727 -
728 - protected function initIndividualContent(object &$tag, string $query)
729 - {
730 - $element = acym_loadObject($query);
731 -
732 - if (empty($element)) {
733 - if (acym_isAdmin()) {
734 - acym_enqueueMessage(acym_translationSprintf('ACYM_CONTENT_NOT_FOUND', $tag->id), 'notice');
735 - }
736 -
737 - return null;
738 - }
739 -
740 - if (empty($tag->display)) {
741 - $tag->display = [];
742 - } else {
743 - $tag->display = explode(',', $tag->display);
744 - }
745 -
746 - return $element;
747 - }
748 -
749 - protected function getCustomLayoutVars(object $element): array
750 - {
751 - $varFields = [];
752 - $varFields['{picthtml}'] = '';
753 - foreach ($element as $fieldName => $oneField) {
754 - if (is_object($oneField) || is_array($oneField)) {
755 - $varFields['{'.$fieldName.'}'] = json_encode($oneField);
756 - } else {
757 - $varFields['{'.$fieldName.'}'] = $oneField;
758 - }
759 - }
760 -
761 - return $varFields;
762 - }
763 -
764 - /**
765 - * Handles the custom layouts and the pictures management
766 - *
767 - * @param string $htmlResult What will be inserted in the email
768 - * @param object $insertionOptions Selected options when inserting dcontent
769 - * @param array $dataShortcodes Data used as shortcodes in custom layouts
770 - */
771 - protected function finalizeElementFormat(string $htmlResult, object $insertionOptions, array $dataShortcodes): string
772 - {
773 - // Hidden feature, users can do a PHP custom view
774 - $fullCustomLayoutPath = ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'.php';
775 - if ($this->config->get('php_overrides', 0) == 1 && file_exists($fullCustomLayoutPath)) {
776 - ob_start();
777 - require $fullCustomLayoutPath;
778 - $viewContent = ob_get_clean();
779 - $htmlResult = str_replace(array_keys($dataShortcodes), $dataShortcodes, $viewContent);
780 - } else {
781 - // Default custom view feature with only HTML for security reasons
782 - $customLayoutPath = ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'.html';
783 - if (file_exists($customLayoutPath)) {
784 - $dataShortcodes['{wrappedText}'] = $this->pluginHelper->wrappedText;
785 - $viewContent = acym_fileGetContent($customLayoutPath);
786 - $viewContentReplace = str_replace(array_keys($dataShortcodes), $dataShortcodes, $viewContent);
787 - if ($viewContent !== $viewContentReplace) {
788 - $htmlResult = $viewContentReplace;
789 - }
790 - }
791 - }
792 -
793 - $allShortcodesList = '<table><tr><th>Shortcode</th><th>Value</th></tr>';
794 - foreach ($dataShortcodes as $name => $value) {
795 - if (!is_string($value)) {
796 - continue;
797 - }
798 -
799 - $allShortcodesList .= '<tr><td>'.trim($name, '{}').'</td><td>'.$value.'</td></tr>';
800 - }
801 - $allShortcodesList .= '</table>';
802 - $htmlResult = str_replace('{allshortcodes}', $allShortcodesList, $htmlResult);
803 -
804 - // Resize/remove pictures if needed
805 - return $this->pluginHelper->managePicts($insertionOptions, $htmlResult);
806 - }
807 -
808 - /**
809 - * Keep this method untyped until v12
810 - */
811 - public function onAcymDeclareTriggers(&$triggers, &$defaultValues)
812 - {
813 - if (empty($this->automationTriggers) && method_exists($this, 'initAutomationTriggers')) {
814 - $this->initAutomationTriggers();
815 - }
816 -
817 - foreach ($this->automationTriggers as $group => $groupTriggers) {
818 - foreach ($groupTriggers as $key => $name) {
819 - $triggers[$group][$key] = $this->declareTrigger($key, $name, $defaultValues, $group);
820 - }
821 - }
822 - }
823 -
824 - /**
825 - * Keep this method untyped until v12
826 - */
827 - public function onAcymDeclareTriggersScenario(&$triggers, &$defaultValues)
828 - {
829 - $this->onAcymDeclareTriggers($triggers, $defaultValues);
830 - }
831 -
832 - /**
833 - * Declares name and options callbacks for automation/scenario triggers
834 - */
835 - protected function declareTrigger(string $key, string $name, $defaultValues = [], string $group = 'user'): object
836 - {
837 - $trigger = new \stdClass();
838 - $trigger->name = $name;
839 -
840 - if (!is_array($defaultValues)) {
841 - $defaultValues = [];
842 - }
843 -
844 - $method = 'displayTriggerOptions_'.$key;
845 - if (!method_exists($this, $method)) {
846 - $method = 'displayTriggerOptions';
847 - }
848 -
849 - if (method_exists($this, $method)) {
850 - $automationFieldName = '[triggers]['.$group.']['.$key.']';
851 - $trigger->displayOptions = function (?string $fieldName = null) use ($method, $defaultValues, $key, $automationFieldName): void {
852 - $this->$method($fieldName === null ? $automationFieldName : $fieldName, $defaultValues, $key);
853 - };
854 - }
855 -
856 - return $trigger;
857 - }
858 -
859 - public function onAcymDeclareActions(array &$actions): void
860 - {
861 - if (empty($this->automationActions) && method_exists($this, 'initAutomationActions')) {
862 - $this->initAutomationActions();
863 - }
864 -
865 - foreach ($this->automationActions as $key => $name) {
866 - $actions[$key] = $this->declareAction($key, $name);
867 - }
868 - }
869 -
870 - public function onAcymDeclareActionsScenario(array &$actions): void
871 - {
872 - $this->onAcymDeclareActions($actions);
873 - }
874 -
875 - /**
876 - * Declares name and options callbacks for an automation/scenario action
877 - */
878 - protected function declareAction(string $key, string $name): object
879 - {
880 - $action = new \stdClass();
881 - $action->name = $name;
882 -
883 - $method = 'displayActionOptions_'.$key;
884 - if (!method_exists($this, $method)) {
885 - $method = 'displayActionOptions';
886 - }
887 -
888 - if (method_exists($this, $method)) {
889 - $action->displayOptions = function () use ($method, $key): void {
890 - $this->$method($key);
891 - };
892 - }
893 -
894 - return $action;
895 - }
896 -
897 - public function onAcymDeclareConditions(array &$conditions): void
898 - {
899 - if (empty($this->automationConditions) && method_exists($this, 'initAutomationConditions')) {
900 - $this->initAutomationConditions();
901 - }
902 -
903 - foreach ($this->automationConditions as $group => $groupConditions) {
904 - foreach ($groupConditions as $key => $name) {
905 - $conditions[$group][$key] = $this->declareCondition($key, $name);
906 - }
907 - }
908 - }
909 -
910 - public function onAcymDeclareConditionsScenario(array &$conditions): void
911 - {
912 - $this->onAcymDeclareConditions($conditions);
913 - }
914 -
915 - public function onAcymDeclareFilters(array &$filters): void
916 - {
917 - if (empty($this->automationFilters) && method_exists($this, 'initAutomationFilters')) {
918 - $this->initAutomationFilters();
919 - }
920 -
921 - foreach ($this->automationFilters as $key => $name) {
922 - $filters[$key] = $this->declareFilter($key, $name);
923 - }
924 - }
925 -
926 - /**
927 - * Returns a field name without its acym_condition / acym_action prefix.
928 - */
929 - protected function getFieldNameWithoutPrefix(string $fieldName): string
930 - {
931 - return str_replace(['acym_condition', 'acym_action'], '', $fieldName);
932 - }
933 -
934 - protected function declareCondition(string $key, string $name): object
935 - {
936 - $condition = new \stdClass();
937 - $condition->name = $name;
938 -
939 - $renderer = $this->getOptionsRenderer('displayConditionOptions', $key, self::CONDITION_FIELD_NAME.'['.$key.']');
940 - if ($renderer !== null) {
941 - $condition->displayOptions = $renderer;
942 - }
943 -
944 - return $condition;
945 - }
946 -
947 - public function onAcymMailboxActionDefine(&$actions)
948 - {
949 - if (empty($this->mailboxActions) && method_exists($this, 'initMailboxActions')) {
950 - $this->initMailboxActions();
951 - }
952 -
953 - foreach ($this->mailboxActions as $key => $name) {
954 - $actions[$key] = $this->declareMailboxAction($key, $name);
955 - }
956 - }
957 -
958 - /**
959 - * A follow-up condition row: a translated sentence holding the selectors the add-on built.
960 - */
961 - protected function followupConditionRow(string $translationKey, string ...$fields): callable
962 - {
963 - return static function () use ($translationKey, $fields): void {
964 - echo acym_translationSprintf($translationKey, ...$fields);
965 - };
966 - }
967 -
968 - protected function declareMailboxAction(string $key, string $name): object
969 - {
970 - $action = new \stdClass();
971 - $action->name = $name;
972 -
973 - $renderer = $this->getOptionsRenderer('displayMailboxActionOptions', $key, self::MAILBOX_ACTION_FIELD_NAME.'['.$key.']');
974 - if ($renderer !== null) {
975 - $action->displayOptions = $renderer;
976 - }
977 -
978 - return $action;
979 - }
980 -
981 - protected function declareFilter(string $key, string $name): object
982 - {
983 - $filter = new \stdClass();
984 - $filter->name = $name;
985 -
986 - $renderer = $this->getOptionsRenderer('displayFilterOptions', $key, self::FILTER_FIELD_NAME.'['.$key.']');
987 - if ($renderer !== null) {
988 - $filter->displayOptions = $renderer;
989 - }
990 -
991 - return $filter;
992 - }
993 -
994 - /**
995 - * Builds the callback that displays the option fields of a declaration.
996 - */
997 - private function getOptionsRenderer(string $methodPrefix, string $key, string $defaultFieldName): ?callable
998 - {
999 - $method = $methodPrefix.'_'.$key;
1000 - if (!method_exists($this, $method)) {
1001 - $method = $methodPrefix;
1002 - }
1003 -
1004 - if (!method_exists($this, $method)) {
1005 - return null;
1006 - }
1007 -
1008 - return function (?string $fieldName = null) use ($method, $key, $defaultFieldName): void {
1009 - $this->$method($fieldName === null ? $defaultFieldName : $fieldName, $key);
1010 - };
1011 - }
1012 -
1013 - /**
1014 - * Most add-ons offer the same choices as conditions and as filters, the only difference being the name the fields are nested under
1015 - */
1016 - protected function filtersFromConditions(array &$filters): void
1017 - {
1018 - $conditions = [];
1019 - $this->onAcymDeclareConditions($conditions);
1020 -
1021 - foreach ($conditions as $oneGroup) {
1022 - foreach ($oneGroup as $oneFilterName => $oneFilter) {
1023 - $renderer = $this->getOptionsRenderer('displayConditionOptions', $oneFilterName, self::FILTER_FIELD_NAME.'['.$oneFilterName.']');
1024 - if ($renderer !== null) {
1025 - $oneFilter->displayOptions = $renderer;
1026 - } elseif (!empty($oneFilter->option)) {
1027 - // TODO: remove this on version 12, only there for retro-compat of add-ons/plugins not updated along with AcyMailing
1028 - $oneFilter->option = str_replace(['acym_condition', '[conditions]'], ['acym_action', '[filters]'], $oneFilter->option);
1029 - }
1030 -
1031 - $filters[$oneFilterName] = $oneFilter;
1032 - }
1033 - }
1034 - }
1035 -
1036 - protected function getElementTags(string $type, int $id): array
1037 - {
1038 - $tags = acym_loadObjectList(
1039 - 'SELECT tags.`title`, tags.`alias`, tags.`id`
1040 - FROM #__tags AS tags
1041 - JOIN #__contentitem_tag_map AS map ON tags.`id` = map.`tag_id`
1042 - WHERE map.`type_alias` = '.acym_escapeDB($type).'
1043 - AND map.`content_item_id` = '.intval($id)
1044 - );
1045 -
1046 - if (empty($tags)) return [];
1047 -
1048 - $displayTags = [];
1049 - foreach ($tags as $oneTag) {
1050 - $displayTags[] = '<a href="index.php?option=com_tags&view=tag&id='.$oneTag->id.':'.$oneTag->alias.'" target="_blank">'.$oneTag->title.'</a>';
1051 - }
1052 -
1053 - return $displayTags;
1054 - }
1055 -
1056 - /**
1057 - * @return mixed
1058 - */
1059 - protected function getFormattedValue(array $fieldValues)
1060 - {
1061 - $field = $fieldValues[0];
1062 -
1063 - if (!empty($field->fieldparams) && !is_array($field->fieldparams)) {
1064 - $field->fieldparams = json_decode($field->fieldparams, true);
1065 - }
1066 -
1067 - switch ($field->type) {
1068 - case 'calendar':
1069 - $format = acym_translation($field->fieldparams['showtime'] == '1' ? 'ACYM_DATE_FORMAT_LC2' : 'ACYM_DATE_FORMAT_LC1');
1070 - $field->value = HTMLHelper::_('date', $field->value, $format);
1071 - break;
1072 -
1073 - case 'checkboxes':
1074 - case 'list':
1075 - case 'radio':
1076 - $values = [];
1077 - foreach ($fieldValues as $oneValue) {
1078 - foreach ($field->fieldparams['options'] as $oneOPT) {
1079 - if ($oneOPT['value'] == $oneValue->value) {
1080 - $values[] = $oneOPT['name'];
1081 - break;
1082 - }
1083 - }
1084 - }
1085 -
1086 - $field->value = implode(', ', $values);
1087 - break;
1088 -
1089 - case 'dpcalendar':
1090 - if (empty($field->value)) {
1091 - $field->value = '';
1092 - break;
1093 - }
1094 -
1095 - $title = acym_loadResult('SELECT `title` FROM #__categories WHERE `id` = '.intval($field->value));
1096 - if (empty($title)) {
1097 - $field->value = '';
1098 - } else {
1099 - $date = '#year='.acym_date('now', 'Y').'&month='.acym_date('now', 'm').'&day='.acym_date('now', 'd').'&view=month';
1100 - $field->value = '<a target="_blank" href="index.php?option=com_dpcalendar&view=calendar&id='.intval($field->value).$date.'">'.$title.'</a>';
1101 - }
1102 - break;
1103 -
1104 - case 'imagelist':
1105 - if (!empty($field->fieldparams['directory']) && strlen($field->fieldparams['directory']) > 1) {
1106 - $field->value = '/'.$field->value;
1107 - } else {
1108 - $field->fieldparams['directory'] = '';
1109 - }
1110 - $field->value = '<img src="images/'.$field->fieldparams['directory'].$field->value.'" />';
1111 - break;
1112 -
1113 - case 'media':
1114 - $value = '';
1115 - if (!empty($field->value)) {
1116 - if (substr($field->value, 0, 1) === '{') {
1117 - $value = json_decode($field->value, true);
1118 - if (!empty($value['imagefile'])) {
1119 - $alt = empty($value['alt_text']) ? '' : ' alt="'.esc_attr($value['alt_text']).'"';
1120 - $value = '<img src="'.$value['imagefile'].'"'.$alt.' />';
1121 - }
1122 - } else {
1123 - $value = '<img src="'.$field->value.'" alt="" />';
1124 - }
1125 - }
1126 -
1127 - $field->value = $value;
1128 - break;
1129 -
1130 - case 'repeatable':
1131 - if (!empty($field->value)) {
1132 - $values = is_string($field->value) ? json_decode($field->value) : $field->value;
1133 - $formattedValues = [];
1134 - foreach ($values as $oneSetOfValues) {
1135 - $formattedSet = [];
1136 - foreach ($oneSetOfValues as $oneLabel => $oneValue) {
1137 - if (empty($oneValue)) continue;
1138 -
1139 - foreach ($field->fieldparams['fields'] as $oneField) {
1140 - if ($oneField['fieldname'] !== $oneLabel) continue;
1141 -
1142 - if ($oneField['fieldtype'] === 'media') {
1143 - $oneValue = '<img src="'.$oneValue.'" alt="" />';
1144 - }
1145 -
1146 - $formattedSet[] = $oneValue;
1147 - break;
1148 - }
1149 - }
1150 -
1151 - if (empty($formattedSet)) continue;
1152 - $formattedValues[] = implode(', ', $formattedSet);
1153 - }
1154 -
1155 - $field->value = empty($formattedSet) ? '' : '<ul><li>'.implode('</li><li>', $formattedValues).'</li></ul>';
1156 - }
1157 - break;
1158 -
1159 - case 'sql':
1160 - if (empty($field->options)) {
1161 - $field->options = acym_loadObjectList($field->fieldparams['query'], 'value');
1162 - }
1163 -
1164 - $field->value = $field->options[$field->value]->text;
1165 - break;
1166 -
1167 - case 'url':
1168 - $field->value = '<a target="_blank" href="'.$field->value.'">'.$field->value.'</a>';
1169 - break;
1170 -
1171 - case 'user':
1172 - $field->value = acym_currentUserName($field->value);
1173 - break;
1174 -
1175 - case 'usergrouplist':
1176 - if (empty($field->usergroups)) {
1177 - $field->usergroups = acym_loadObjectList('SELECT id, title FROM #__usergroups', 'id');
1178 - }
1179 -
1180 - if (empty($field->usergroups[$field->value])) {
1181 - $field->value = '';
1182 - break;
1183 - }
1184 - $field->value = $field->usergroups[$field->value]->title;
1185 - break;
1186 - case 'subform':
1187 - if (!empty($field->value)) {
1188 - $rows = is_string($field->value) ? json_decode($field->value, true) : $field->value;
1189 -
1190 - $formattedValues = [];
1191 - foreach ($rows as $values) {
1192 - $fieldValues = [];
1193 - foreach ($values as $fieldIdentifier => $fieldValue) {
1194 - $fieldId = str_replace('field', '', $fieldIdentifier);
1195 - $oneFieldDefinition = acym_loadObject(
1196 - 'SELECT `field`.*
1197 - FROM #__fields AS `field`
1198 - WHERE `field`.`id` = '.intval($fieldId)
1199 - );
1200 -
1201 - if (empty($oneFieldDefinition)) {
1202 - break 3;
1203 - }
1204 -
1205 - $multiCompatibleValues = [];
1206 - if (is_array($fieldValue)) {
1207 - foreach ($fieldValue as $oneFieldValue) {
1208 - $oneValue = clone $oneFieldDefinition;
1209 - $oneValue->value = $oneFieldValue;
1210 - $multiCompatibleValues[] = $oneValue;
1211 - }
1212 - } else {
1213 - $oneFieldDefinition->value = $fieldValue;
1214 - $multiCompatibleValues[] = $oneFieldDefinition;
1215 - }
1216 -
1217 - $fieldValues[] = $oneFieldDefinition->label.': '.$this->getFormattedValue($multiCompatibleValues);
1218 - }
1219 - $formattedValues[] = implode(', ', $fieldValues);
1220 - }
1221 -
1222 - $field->value = empty($formattedValues) ? '' : '<ul><li>'.implode('</li><li>', $formattedValues).'</li></ul>';
1223 - }
1224 - }
1225 -
1226 - return $field->value;
1227 - }
1228 -
1229 - protected function getLanguage(?string $elementLanguage = null, bool $onlyValue = false): string
1230 - {
1231 - $value = $this->emailLanguage;
1232 - if (!empty($elementLanguage) && $elementLanguage !== '*') {
1233 - $value = $elementLanguage;
1234 - }
1235 -
1236 - if (empty($value)) {
1237 - return '';
1238 - }
1239 -
1240 - if (ACYM_CMS === 'joomla' && acym_isPluginActive('languagefilter')) {
1241 - $languages = acym_loadObjectList('SELECT * FROM #__languages', 'lang_code');
1242 - if (isset($languages[$value])) {
1243 - $value = $languages[$value]->sef;
1244 - } else {
1245 - $value = substr($value, 0, strpos($value, '-'));
1246 - }
1247 -
1248 - if ($onlyValue) {
1249 - return $value;
1250 - }
1251 -
1252 - return '&lang='.$value;
1253 - } else {
1254 - if ($onlyValue) {
1255 - return $value;
1256 - }
1257 -
1258 - return '&language='.$value;
1259 - }
1260 - }
1261 -
1262 - // Don't add types for $tag and $sef, for retro-compatibility
1263 - protected function finalizeLink(string $link, $tag = null, $sef = true): string
1264 - {
1265 - if (acym_isPluginActive('languagefilter')) {
1266 - if (strpos($link, 'lang=') === false && !empty($this->emailLanguage)) {
1267 - $link .= strpos($link, '?') === false ? '?' : '&';
1268 - $link .= 'lang='.substr($this->emailLanguage, 0, strpos($this->emailLanguage, '-'));
1269 - }
1270 - } else {
1271 - if (strpos($link, 'language=') === false && !empty($this->emailLanguage)) {
1272 - $link .= strpos($link, '?') === false ? '?' : '&';
1273 - $link .= 'language='.$this->emailLanguage;
1274 - }
1275 - }
1276 -
1277 - if (!empty($tag->autologin)) {
1278 - $link .= (strpos($link, '?') ? '&' : '?').'autoSubId={subscriber:id}&subKey={subscriber:autologin_token|urlencode}';
1279 - }
1280 -
1281 - // Retro-compatibility for add-on versions before the v8.6.0
1282 - if (is_bool($tag)) {
1283 - $sef = $tag;
1284 - }
1285 -
1286 - return acym_frontendLink($link, false, $sef);
1287 - }
1288 -
1289 - protected function handleCustomFields(object $tag, array &$customFields): void
1290 - {
1291 - if (empty($tag->custom)) {
1292 - return;
1293 - }
1294 -
1295 - $tag->custom = explode(',', $tag->custom);
1296 - acym_arrayToInteger($tag->custom);
1297 -
1298 - $rawfields = acym_loadObjectList(
1299 - 'SELECT `field`.*, `values`.`value`
1300 - FROM #__fields_values AS `values`
1301 - JOIN #__fields AS `field` ON `values`.`field_id` = `field`.`id`
1302 - WHERE `values`.`item_id` = '.intval($tag->id).' AND `field`.`id` IN ('.implode(', ', $tag->custom).')'
1303 - );
1304 -
1305 - $fields = [];
1306 - foreach ($rawfields as $field) {
1307 - $fields[$field->id][] = $field;
1308 - }
1309 -
1310 - usort($fields, function ($a, $b) {
1311 - return $a[0]->ordering <=> $b[0]->ordering;
1312 - });
1313 -
1314 - foreach ($fields as $fieldValues) {
1315 - $value = $this->getFormattedValue($fieldValues);
1316 -
1317 - if (empty($value)) continue;
1318 -
1319 - $customFields[] = [
1320 - $value,
1321 - $fieldValues[0]->label,
1322 - ];
1323 - }
1324 - }
1325 -
1326 - protected function getIntro(string $text): string
1327 - {
1328 - $pageBreak = null;
1329 - $possibleBreaks = [
1330 - '<!--more-->',
1331 - '<hr id="system-readmore" />',
1332 - '<!--nextpage-->',
1333 - ];
1334 -
1335 - foreach ($possibleBreaks as $oneBreak) {
1336 - if (strpos($text, $oneBreak) !== false) {
1337 - $pageBreak = $oneBreak;
1338 - break;
1339 - }
1340 - }
1341 -
1342 - if (empty($pageBreak)) {
1343 - return $text;
1344 - }
1345 -
1346 - $split = explode($pageBreak, $text, 2);
1347 -
1348 - return array_shift($split);
1349 - }
1350 -
1351 - public function displayCustomViewEditor(): void
1352 - {
1353 - if (empty($this->settings['custom_view']) || !acym_isAdmin()) {
1354 - return;
1355 - }
1356 -
1357 - echo '<p class="acym__wysid__right__toolbar__p acym__wysid__right__toolbar__p__open acym__title">';
1358 - echo esc_html(acym_translation('ACYM_ADDON_SETTINGS'));
1359 - echo '<i class="acymicon-keyboard-arrow-up"></i></p>';
1360 - echo '<div class="acym__wysid__right__toolbar__design--show acym__wysid__right__toolbar__design acym__wysid__context__modal__container">';
1361 - $this->displayCustomView($this->settings['custom_view']);
1362 - echo '</div>';
1363 - }
1364 -
1365 - public function generateSettings(object $plugin): bool
1366 - {
1367 - if (empty($plugin->settings)) {
1368 - return false;
1369 - }
1370 -
1371 - if (array_key_exists('not_installed', $plugin->settings)) {
1372 - $plugin->settings = 'not_installed';
1373 -
1374 - return true;
1375 - }
1376 -
1377 - foreach ($plugin->settings as $key => $field) {
1378 - $text = '';
1379 - if (empty($field['type'])) {
1380 - $plugin->settings[$key] = $text;
1381 - continue;
1382 - }
1383 -
1384 - $id = $plugin->folder_name.'_'.$key;
1385 - $name = $plugin->folder_name.'['.$key.']';
1386 - if (!empty($field['label'])) {
1387 - $field['label'] = acym_translation($field['label']);
1388 - }
1389 -
1390 - if (!empty($field['info'])) {
1391 - ob_start();
1392 - acym_info(
1393 - [
1394 - 'textShownInTooltip' => acym_translation($field['info']),
1395 - 'classText' => 'wysid_tooltip',
1396 - 'isWarning' => !empty($field['info_warning']),
1397 - ]
1398 - );
1399 - $field['label'] .= ob_get_clean();
1400 - }
1401 -
1402 - if ($field['type'] === 'checkbox') {
1403 - $classLabel = 'shrink';
1404 - $text .= '<label for="'.esc_attr($id).'" class="cell '.esc_attr($classLabel).'">'.esc_html($field['label']).'</label>';
1405 - $text .= '<input id="'.esc_attr($id).'" class="cell shrink" type="checkbox" name="'.esc_attr($name).'" '.checked(
1406 - !empty($field['value']),
1407 - true,
1408 - false
1409 - ).'>';
1410 - } elseif ($field['type'] === 'switch') {
1411 - ob_start();
1412 - acym_switch([
1413 - 'name' => $name,
1414 - 'value' => $field['value'],
1415 - 'label' => $field['label'],
1416 - 'labelClass' => 'large-7',
1417 - ]);
1418 - $text .= ob_get_clean();
1419 - } elseif ($field['type'] === 'select') {
1420 - $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1421 - $text .= acym_select(
1422 - $field['data'],
1423 - $name,
1424 - $field['value'],
1425 - ['class' => 'acym__select'],
1426 - 'value',
1427 - 'text',
1428 - false,
1429 - true
1430 - );
1431 - } elseif ($field['type'] === 'multiple_select') {
1432 - $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1433 - $text .= acym_selectMultiple(
1434 - $field['data'],
1435 - $name,
1436 - empty($field['value']) ? [] : $field['value'],
1437 - ['class' => 'acym__select']
1438 - );
1439 - } elseif ($field['type'] === 'text') {
1440 - $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1441 - $text .= '<input type="text" name="'.$name.'" value="'.esc_attr($field['value']).'" class="cell shrink">';
1442 - } elseif ($field['type'] === 'number') {
1443 - $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1444 - $text .= '<input type="number" name="'.$name.'" value="'.esc_attr($field['value']).'" class="cell large-2 medium-5">';
1445 - if (!empty($field['post_text'])) $text .= '<span class="cell shrink">'.strtolower($field['post_text']).'</span>';
1446 - } elseif ($field['type'] === 'radio') {
1447 - $text .= '<p class="cell">'.$field['label'].'</p>';
1448 - ob_start();
1449 - acym_radio(
1450 - $field['data'],
1451 - $name,
1452 - $field['value']
1453 - );
1454 - $text .= ob_get_clean();
1455 - } elseif ($field['type'] === 'date') {
1456 - $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1457 - $text .= acym_dateField(
1458 - $name,
1459 - $field['value'],
1460 - 'cell shrink'
1461 - );
1462 - } elseif ($field['type'] === 'custom_view') {
1463 - ob_start();
1464 - $this->displayCustomView($field);
1465 - $text .= ob_get_clean();
1466 - } elseif ($field['type'] === 'multikeyvalue') {
1467 - $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1468 -
1469 - $text .= '<div class="multikeyvalue_container grid-x">';
1470 -
1471 - if (!empty($field['value'])) {
1472 - $headers = json_decode($field['value'], true);
1473 - foreach ($headers as $headerKey => $headerValue) {
1474 - $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_DKIM_KEY')).'" value="'.esc_attr($headerKey).'"/>';
1475 - $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_VALUE')).'" value="'.esc_attr($headerValue).'" />';
1476 - $text .= '<div class="multikeyvalue_container_separator cell small-6"></div>';
1477 - }
1478 - }
1479 -
1480 - $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_DKIM_KEY')).'" value=""/>';
1481 - $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_VALUE')).'" value="" />';
1482 -
1483 - $text .= '<button class="button multikeyvalue_container_new">'.esc_html(acym_translation('ACYM_ADD_NEW')).'</button>';
1484 -
1485 - $text .= '<input type="hidden" name="'.esc_attr($name).'" value="" />';
1486 - $text .= '</div>';
1487 - } elseif ($field['type'] === 'custom') {
1488 - $text .= $field['content'];
1489 - }
1490 - $plugin->settings[$key] = $text;
1491 - }
1492 -
1493 - return true;
1494 - }
1495 -
1496 - protected function displayCustomView(array $field): void
1497 - {
1498 - if (!acym_isAdmin()) {
1499 - return;
1500 - }
1501 -
1502 - $idCustomView = 'acym__plugins__installed__custom-view__'.$this->name;
1503 - $ctrl = acym_getVar('string', 'ctrl', '');
1504 - $classTooltip = $ctrl === 'dynamics' ? '' : 'wysid_tooltip';
1505 -
1506 - echo '<label class="cell">';
1507 - echo esc_html(acym_translation('ACYM_CUSTOM_VIEW'));
1508 - acym_info(
1509 - [
1510 - 'textShownInTooltip' => 'ACYM_CUSTOM_VIEW_DESC',
1511 - 'classText' => $classTooltip,
1512 - ]
1513 - );
1514 - echo '</label>';
1515 -
1516 - if (empty($field['tags'])) {
1517 - $field['tags'] = [];
1518 - }
1519 -
1520 - ob_start();
1521 - acym_info(
1522 - [
1523 - 'textShownInTooltip' => acym_translation('ACYM_DYNAMIC_CONTENT_DESC'),
1524 - ]
1525 - );
1526 - $tooltip = ob_get_clean();
1527 -
1528 - $modalContent = '<div id="'.esc_attr($idCustomView).'" class="cell grid-x acym__plugins__installed__custom-view" acym-data-tags="'.esc_attr(
1529 - json_encode($field['tags'])
1530 - ).'">
1531 - <h2 class="cell text-center acym__title__primary__color">'.esc_html(acym_translationSprintf('ACYM_CUSTOM_VIEW_FOR_X', $this->pluginDescription->name)).'</h2>
1532 - <div class="cell grid-x acym__plugins__installed__custom-view__edit-container">
1533 - <div class="acym__plugins__installed__custom-view__editor-loader grid-x cell align-center acym_vcenter" v-if="loading">
1534 - <div class="cell shrink acym_loader_logo">
1535 - '.acym_fileGetContent(ACYM_IMAGES.'logos/logo_grey.svg').'
1536 - </div>
1537 - </div>
1538 - <vue-prism-editor :emitEvents="true" class="cell acym__plugins__installed__custom-view__code cell auto" v-model="code" :language="language" lineNumbers="true"></vue-prism-editor>
1539 - <div class="cell grid-x medium-3 margin-left-1 acym__plugins__installed__custom-view__tags">
1540 - <h3 class="acym__title acym__title__secondary cell text-center">'.esc_html(acym_translation('ACYM_DYNAMIC_CONTENT')).$tooltip.'</h3>
1541 - <div class="cell acym__plugins__installed__custom-view__tag" v-for="(trad, tag) in tags" :key="tag" @click.prevent="insertTag(tag)">{{ trad }}</div>
1542 - </div>
1543 - </div>
1544 - <div class="cell grid-x acym__plugins__installed__custom-view__actions acym_vcenter margin-top-1 padding-bottom-1">
1545 - <div class="cell auto grid-x">
1546 - <button type="button" class="cell shrink button-secondary button" @click="resetView">'.esc_html(acym_translation('ACYM_RESET_VIEW')).'</button>
1547 - <div class="cell shrink margin-right-2 acym_vcenter margin-left-1">
1548 - <i v-if="deleting" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1549 - <span v-if="deleted">{{ messageDeleted }}</span>
1550 - </div>
1551 - </div>
1552 - <div class="cell auto align-right grid-x">
1553 - <div class="cell shrink margin-right-2 acym_vcenter">
1554 - <i v-if="saving" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1555 - <span v-if="saved">{{ messageSaved }}</span>
1556 - </div>
1557 - <button @click="save()" class="cell shrink button" type="button">'.esc_html(acym_translation('ACYM_SAVE_NEW_CUSTOM_VIEW_VERSION')).'</button>
1558 - </div>
1559 - </div>
1560 - </div>';
1561 -
1562 - acym_modal(
1563 - acym_translation('ACYM_EDIT_CUSTOM_VIEW'),
1564 - $modalContent,
1565 - null,
1566 - [
1567 - 'acym-data-plugins-id' => $idCustomView,
1568 - 'acym-data-plugin-class' => get_class($this),
1569 - 'acym-data-plugin-folder' => $this->name,
1570 - ],
1571 - ['class' => 'cell button']
1572 - );
1573 - }
1574 -
1575 - /**
1576 - * Called using ajax
1577 - *
1578 - * @param string $css This attribute is the name of the file in the folder css of the plugin OR it can be raw CSS
1579 - */
1580 - public function loadCSS(string $css, bool $raw = false, ?string $path = null): void
1581 - {
1582 - if (!$raw) {
1583 - if (empty($path)) $path = ACYM_DYNAMICS_URL.$this->name;
1584 - $css = $path.'/css/'.$css.'.css';
1585 - }
1586 - acym_addStyle($raw, $css);
1587 - }
1588 -
1589 - /**
1590 - * @param string $js This attribute is the name of the file in the folder js of the plugin OR it can be raw Javascript
1591 - */
1592 - public function loadJavascript(string $js, bool $raw = false, ?string $path = null): void
1593 - {
1594 - if (!$raw) {
1595 - if (empty($path)) $path = ACYM_DYNAMICS_URL.$this->name;
1596 - $js = $path.'/js/'.$js.'.js';
1597 - }
1598 - acym_addScript($raw, $js);
1599 - }
1600 -
1601 - public function includeView(string $view, array $data = [], ?string $path = null): string
1602 - {
1603 - if (empty($path)) {
1604 - $path = ACYM_ADDONS_FOLDER_PATH.$this->name.DS.'views'.DS.$view.'.php';
1605 - } else {
1606 - $path = $path.DS.'views'.DS.$view.'.php';
1607 - }
1608 -
1609 - if (!file_exists($path)) {
1610 - throw new \Exception(esc_attr(acym_translation('ACYM_NON_EXISTING_PAGE')));
1611 - }
1612 -
1613 - ob_start();
1614 - include $path;
1615 -
1616 - return ob_get_clean();
1617 - }
1618 -
1619 - /**
1620 - * This function will parse and show all settings
1621 - */
1622 - public function onAcymAddSettings(array &$plugins): void
1623 - {
1624 - if (method_exists($this, 'initSettings')) {
1625 - $this->initSettings();
1626 - }
1627 -
1628 - foreach ($plugins as $key => $plugin) {
1629 - if ($plugin->folder_name === $this->name) {
1630 - if (!empty($plugin->settings)) {
1631 - foreach ($plugin->settings as $keySettings => $value) {
1632 - if (isset($this->settings[$keySettings]['value'])) {
1633 - $this->settings[$keySettings]['value'] = $plugin->settings[$keySettings]['value'];
1634 - }
1635 - }
1636 - }
1637 - $plugins[$key]->settings = $this->settings;
1638 -
1639 - $this->generateSettings($plugins[$key]);
1640 - break;
1641 - }
1642 - }
1643 - }
1644 -
1645 - /**
1646 - * @param mixed $default
1647 - *
1648 - * @return mixed
1649 - */
1650 - protected function getParam(string $name, $default = '')
1651 - {
1652 - return $this->savedSettings[$name]['value'] ?? $default;
1653 - }
1654 -
1655 - protected function getTranslationId(int $elementId, string $translationTool, bool $defaultLanguage = false)
1656 - {
1657 - return $elementId;
1658 - }
1659 -
1660 - public function filterSpecialMailsDailySend(array &$specialMails, int $time, string $mailType): void
1661 - {
1662 - // Only once a day
1663 - $dailyHour = $this->config->get('daily_hour', '12');
1664 - $dailyMinute = $this->config->get('daily_minute', '00');
1665 - // The day it is currently based on the timezone specified in the CMS configuration
1666 - $dayBasedOnCMSTimezone = acym_date('now', 'Y-m-d');
1667 - // The UTC timestamp of the current day based on the CMS timezone, at the specified hour
1668 - $dayBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$dailyHour.':'.$dailyMinute);
1669 -
1670 - $campaignClass = new CampaignClass();
1671 -
1672 - $tmpMails = [];
1673 - foreach ($specialMails as $oneMail) {
1674 - if ($oneMail->sending_type === $mailType) {
1675 - $noNextTrigger = empty($oneMail->next_trigger);
1676 - $nextTriggerIsNow = gmdate('m-d', $oneMail->next_trigger) == gmdate('m-d', $dayBasedOnCMSTimezoneAtSpecifiedHour);
1677 - $nextTriggerIsInPast = $oneMail->next_trigger < $time;
1678 - if ($time >= $dayBasedOnCMSTimezoneAtSpecifiedHour && ($noNextTrigger || $nextTriggerIsNow || $nextTriggerIsInPast)) {
1679 - $oneMail->next_trigger = acym_getTime('tomorrow '.$dailyHour.':'.$dailyMinute);
1680 - $oneMail->last_generated = $time;
1681 - $campaignClass->save($oneMail);
1682 - $tmpMails[] = $oneMail;
1683 - }
1684 - } else {
1685 - $tmpMails[] = $oneMail;
1686 - }
1687 - }
1688 - $specialMails = $tmpMails;
1689 - }
1690 -
1691 - protected function getIdsSelectAjax(): array
1692 - {
1693 - $ids = acym_getVar('string', 'id');
1694 - if (empty($ids)) {
1695 - return [];
1696 - }
1697 -
1698 - $ids = explode(',', $ids);
1699 - acym_arrayToInteger($ids);
1700 -
1701 - return $ids;
1702 - }
1703 -
1704 - protected function cleanExtensionContent(string $text)
1705 - {
1706 - if (ACYM_CMS === 'wordpress') {
1707 - if (!acym_isExtensionActive('classic-editor/classic-editor.php') || strpos($text, '<!-- wp:') !== false) {
1708 - return $text;
1709 - }
1710 -
1711 - return nl2br($text);
1712 - } else {
1713 - return preg_replace('#\{igallery[^}]+\}#Ui', '', $text);
1714 - }
1715 - }
1716 -
1717 - protected function callApiSendingMethod(
1718 - string $url,
1719 - array $data = [],
1720 - array $headers = [],
1721 - string $type = 'GET',
1722 - array $authentication = [],
1723 - bool $dataDecoded = false,
1724 - array $files = []
1725 - ): array {
1726 - $assocHeaders = [];
1727 - foreach ($headers as $key => $value) {
1728 - if (is_int($key)) {
1729 - $parts = explode(':', $value, 2);
1730 - if (count($parts) === 2) {
1731 - $assocHeaders[trim($parts[0])] = trim($parts[1]);
1732 - }
1733 - } else {
1734 - $assocHeaders[$key] = $value;
1735 - }
1736 - }
1737 -
1738 - if (!empty($authentication)) {
1739 - $assocHeaders['Authorization'] = 'Basic '.base64_encode($authentication['name'].':'.$authentication['pwd']);
1740 - }
1741 -
1742 - $result = acym_makeCurlCall(
1743 - $url,
1744 - [
1745 - 'method' => strtoupper($type),
1746 - 'headers' => $assocHeaders,
1747 - 'data' => $data,
1748 - 'files' => $files,
1749 - // Some APIs (Mailgun) expect the data as a raw multipart body, not encoded
1750 - 'multipart' => $dataDecoded === true,
1751 - 'verifySsl' => false,
1752 - ]
1753 - );
1754 -
1755 - $this->responseCode = (int)($result['status_code'] ?? 0);
1756 - unset($result['status_code']);
1757 -
1758 - if (isset($result['error'])) {
1759 - return ['error_curl' => $result['error']];
1760 - }
1761 -
1762 - return $result;
1763 - }
1764 -
1765 - protected function getTestCredentialsSendingMethodButton(string $sendingMethodId): void
1766 - {
1767 - echo '<div class="cell grid-x margin-top-1 acym__sending__methods__credentials__test">
1768 - <button type="button" sending-method-id="'.esc_attr($sendingMethodId).'" class="acym__configuration__sending__method-test cell shrink button button-secondary">
1769 - '.esc_html(acym_translation('ACYM_TEST_CREDENTIALS')).'
1770 - </button>
1771 - <span class="acym__configuration__sending__method-icon cell shrink margin-left-1 acym_vcenter"></span>
1772 - <span class="acym__configuration__sending__method-test__message cell shrink margin-left-1 acym_vcenter"></span>
1773 - </div>';
1774 - }
1775 -
1776 - public function getCopySettingsButton(array $data, string $sendingMethodId, string $fromPlugin, bool $withContainer = true): void
1777 - {
1778 - if (empty($data[$fromPlugin.'_installed'])) {
1779 - return;
1780 - }
1781 -
1782 - if ($withContainer) {
1783 - echo '<div class="cell grid-x margin-top-1">';
1784 - }
1785 -
1786 - echo '<button
1787 - type="button"
1788 - class="cell shrink button button-secondary acym__configuration__copy__mail__settings"
1789 - acym-data-plugin="'.esc_attr($fromPlugin).'"
1790 - acym-data-method="'.esc_attr($sendingMethodId).'">
1791 - '.esc_html(acym_translationSprintf('ACYM_COPY_SETTINGS_FROM', $this->sendingPlugins[$fromPlugin])).'
1792 - </button>
1793 - <span class="acym__configuration__sending__method-icon cell shrink margin-left-1 acym_vcenter"></span>';
1794 -
1795 - if ($withContainer) {
1796 - echo '</div>';
1797 - }
1798 - }
1799 -
1800 - protected function getLinks(string $account = '', string $pricing = ''): void
1801 - {
1802 - if (empty($account) && empty($pricing)) {
1803 - return;
1804 - }
1805 -
1806 - echo '<div class="cell grid-x acym-grid-margin-x shrink acym_vcenter"><p class="cell shrink">'.esc_html(acym_translation('ACYM_DONT_HAVE_ACCOUNT')).'</p>';
1807 - if (!empty($account)) {
1808 - echo '<a target="_blank" class="cell shrink" href="'.esc_url($account).'">'.esc_html(acym_translation('ACYM_CREATE_ONE')).'</a>';
1809 - }
1810 - if (!empty($account) && !empty($pricing)) {
1811 - echo '<p class="cell shrink">'.esc_html(strtolower(acym_translation('ACYM_OR'))).'</p>';
1812 - }
1813 - if (!empty($pricing)) {
1814 - echo '<a target="_blank" class="cell shrink" href="'.esc_url($pricing).'">'.esc_html(acym_translation('ACYM_CHECK_THEIR_PRICING')).'</a>';
1815 - }
1816 - echo '</div>';
1817 - }
1818 -
1819 - public function onAcymGetSendingMethodsSelected(array &$data): void
1820 - {
1821 - if (ACYM_CMS === 'wordpress') {
1822 - $this->config->load();
1823 - }
1824 -
1825 - $mailerMethod = $this->config->get('mailer_method', 'phpmail');
1826 - foreach ($data['sendingMethods'] as $key => $sendingMethod) {
1827 - $data['sendingMethods'][$key]['selected'] = $key == $mailerMethod;
1828 - }
1829 - }
1830 -
1831 - public function errorCallback(): void
1832 - {
1833 - foreach ($this->errors as $error) {
1834 - acym_logError($error, empty($this->name) ? get_class($this) : $this->name);
1835 - }
1836 -
1837 - $this->errors = [];
1838 - }
1839 -
1840 - public function isLogFileEmpty(): bool
1841 - {
1842 - return !acym_isLogFileErrorExist(empty($this->name) ? get_class($this) : $this->name);
1843 - }
1844 -
1845 - public function initCustomView(bool $customFields = false): void
1846 - {
1847 - $page = acym_getVar('cmd', 'page');
1848 - if (is_array($page)) return;
1849 - if (!empty($page) && is_string($page)) {
1850 - $page = str_replace(ACYM_COMPONENT.'_', '', $page);
1851 - }
1852 - $ctrl = acym_getVar('cmd', 'ctrl', $page);
1853 - if (!in_array($ctrl, ['plugins', 'dynamics'])) return;
1854 -
1855 - $task = acym_getVar('cmd', 'task', 'installed');
1856 -
1857 - // Installed add-ons page or installed + editor
1858 - if (($ctrl === 'plugins' && $task === 'installed') || ($this->active && $ctrl === 'dynamics' && $task === 'trigger')) {
1859 - $this->initElementOptionsCustomView();
1860 - $this->initReplaceOptionsCustomView();
1861 - if ($customFields) $this->initCustomOptionsCustomView();
1862 - }
1863 - }
1864 -
1865 - public function processDateToCheck(array $options): \DateTime
1866 - {
1867 - $dateNowWithTimeZone = acym_date('now', 'Y-m-d h:i:s');
1868 - $dateToCheck = new \DateTime($dateNowWithTimeZone);
1869 - $interval = new \DateInterval('P'.intval($options['days']).'D');
1870 - if ($options['relative'] === 'before') {
1871 - $dateToCheck->add($interval);
1872 - } else {
1873 - $dateToCheck->sub($interval);
1874 - }
1875 -
1876 - return $dateToCheck;
1877 - }
1878 -
1879 - public function onAcymCheckInstalled(bool &$installed): void
1880 - {
1881 - $installed = $this->installed;
1882 - }
1883 -
1884 - protected function getLinkTranslated(string $link): string
1885 - {
1886 - if (empty($this->emailLanguage)) return $link;
1887 - if (!acym_isMultilingual()) return $link;
1888 -
1889 - $translationTool = $this->config->get('translate_content', 'no');
1890 - if ($translationTool !== 'wpml') return $link;
1891 -
1892 - if (!acym_isExtensionActive('sitepress-multilingual-cms/sitepress.php')) return $link;
1893 -
1894 - $languageCode = substr($this->emailLanguage, 0, 2);
1895 -
1896 - // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML hook for integration.
1897 - return apply_filters('wpml_permalink', $link, $languageCode);
1898 - }
1899 -
1900 - protected function replaceShortcode(string $content): string
1901 - {
1902 - $content = do_shortcode($content);
1903 -
1904 - return preg_replace('#<!-- wp:shortcode -->(.*)<!-- /wp:shortcode -->#Uis', '$1', $content);
1905 - }
1906 -
1907 - protected function fixDivStructure(string $text): string
1908 - {
1909 - $nbOpeningDivs = substr_count($text, '<div');
1910 - $nbClosingDivs = substr_count($text, '</div>');
1911 -
1912 - if ($nbOpeningDivs > $nbClosingDivs) {
1913 - $text .= str_repeat('</div>', $nbOpeningDivs - $nbClosingDivs);
1914 - } elseif ($nbOpeningDivs < $nbClosingDivs) {
1915 - $text = str_repeat('<div>', $nbClosingDivs - $nbOpeningDivs).$text;
1916 - }
1917 -
1918 - return $text;
1919 - }
1920 -
1921 - protected function getBounceAddress(object $mailerHelper): string
1922 - {
1923 - if (method_exists($mailerHelper, 'getSendSettings')) {
1924 - return $mailerHelper->getSendSettings('bounce_email');
1925 - } else {
1926 - return $this->config->get('bounce_email');
1927 - }
1928 - }
1929 -}