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 / Core / AcymPlugin.php

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

1,609 lines 60.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 public string $cms = 'all';
13 public string $name = '';
14 public bool $installed = true;
15
16 protected array $addonDefinition;
17 protected PluginHelper $pluginHelper;
18
19 protected int $rootCategoryId = 1;
20 protected array $categories;
21 protected array $catvalues = [];
22 private array $cats = [];
23 private array $subCategories = [];
24
25 protected array $tagvalues = [];
26
27 protected array $tags = [];
28 protected object $pageInfo;
29 protected array $searchFields = [];
30 protected string $querySelect = '';
31 protected string $query = '';
32 protected array $filters = [];
33 protected string $elementIdTable = '';
34 protected string $elementIdColumn = '';
35
36 public object $pluginDescription;
37 public object $generateCampaignResult;
38
39 protected ?object $defaultValues;
40 protected string $emailLanguage = '';
41 private int $campaignId;
42 private string $campaignType;
43
44 protected array $displayOptions = [];
45 protected array $replaceOptions = [];
46 protected array $elementOptions = [];
47 protected array $customOptions = [];
48
49 private array $sendingPlugins = [
50 'wp_mail_smtp' => 'WP Mail SMTP',
51 ];
52
53 public array $errors = [];
54 public string $logFilename = '';
55 protected int $responseCode;
56
57 private bool $active;
58 public array $settings = [];
59 private array $savedSettings = [];
60
61 public function __construct()
62 {
63 parent::__construct();
64
65 $this->elementOptions = ['wrappedText' => [acym_translation('ACYM_WRAPPED_TEXT')]];
66
67 $this->pluginHelper = new PluginHelper();
68 $this->pageInfo = new \stdClass();
69
70 $this->pluginDescription = new \stdClass();
71 $this->pluginDescription->plugin = get_class($this);
72
73 $this->name = strtolower(substr($this->pluginDescription->plugin, 7));
74
75 $this->generateCampaignResult = new \stdClass();
76 $this->generateCampaignResult->status = true;
77 $this->generateCampaignResult->message = '';
78
79 $this->campaignId = acym_getVar('int', 'campaignId', 0);
80 $this->campaignType = acym_getVar('string', 'campaign_type', '');
81
82 $pluginClass = new PluginClass();
83 $currentAddon = $pluginClass->getOnePluginByFolderName($this->name);
84 $this->active = empty($currentAddon) || $currentAddon->active;
85
86 if (!empty($currentAddon->settings)) {
87 if (is_string($currentAddon->settings)) {
88 $this->savedSettings = json_decode($currentAddon->settings, true);
89 } else {
90 $this->savedSettings = $currentAddon->settings;
91 }
92 }
93
94 $this->logFilename = acym_getErrorLogFilename(empty($this->name) ? get_class($this) : $this->name);
95 }
96
97 protected function displaySelectionZone(string $zoneContent): void
98 {
99 ?>
100 <p class="acym__wysid__right__toolbar__p acym__wysid__right__toolbar__p__open acym__title">
101 <?php echo acym_escape(acym_translation('ACYM_CONTENT_TO_INSERT')); ?><i class="acymicon-keyboard-arrow-up"></i>
102 </p>
103 <div class="acym__wysid__right__toolbar__design--show acym__wysid__right__toolbar__design acym__wysid__context__modal__container">
104 <?php echo $zoneContent; ?>
105 </div>
106 <?php
107 }
108
109 public function displayListing(): void
110 {
111 echo $this->prepareListing();
112 }
113
114 public function prepareListing()
115 {
116 $this->pageInfo->limit = 10;
117 $this->pageInfo->page = acym_getVar('int', 'pagination_page_ajax', 1);
118 $this->pageInfo->start = ($this->pageInfo->page - 1) * $this->pageInfo->limit;
119 $this->pageInfo->search = acym_getVar('string', 'plugin_search', '');
120 $this->pageInfo->filter_cat = acym_getVar('int', 'plugin_category', 0);
121 $this->pageInfo->orderdir = 'DESC';
122 $this->pageInfo->loadMore = acym_getVar('boolean', 'loadMore', false);
123
124 if (!empty($this->pageInfo->search) && !empty($this->searchFields)) {
125 $searchVal = '%'.acym_getEscaped($this->pageInfo->search, true).'%';
126 $this->filters[] = implode(' LIKE '.acym_escapeDB($searchVal).' OR ', $this->searchFields).' LIKE '.acym_escapeDB($searchVal);
127 }
128
129 return '';
130 }
131
132 public function getElements(): array
133 {
134 $conditions = '';
135 if (!empty($this->filters)) {
136 $conditions = ' WHERE ('.implode(') AND (', $this->filters).')';
137 }
138
139 $ordering = '';
140 if (!empty($this->pageInfo->order)) {
141 $ordering = ' ORDER BY '.acym_secureDBColumn($this->pageInfo->order).' '.acym_secureDBColumn($this->pageInfo->orderdir);
142 }
143
144 $rows = acym_loadObjectList($this->querySelect.$this->query.$conditions.$ordering, '', $this->pageInfo->start, $this->pageInfo->limit);
145 $this->pageInfo->total = acym_loadResult('SELECT COUNT(*) '.$this->query.$conditions.$ordering);
146
147 if (!empty($this->defaultValues->id) && $this->defaultValues->defaultPluginTab === $this->name) {
148 $found = false;
149 foreach ($rows as $oneRow) {
150 if (intval($oneRow->{$this->elementIdColumn}) === intval($this->defaultValues->id)) {
151 $found = true;
152 }
153 }
154
155 if (!$found) {
156 $conditions = ' WHERE '.$this->elementIdTable.'.'.$this->elementIdColumn.' = '.intval($this->defaultValues->id);
157 $row = acym_loadObject($this->querySelect.$this->query.$conditions);
158 if (!empty($row)) {
159 $rows[] = $row;
160 }
161 }
162 }
163
164 return $rows;
165 }
166
167 protected function getFilteringZone(bool $categoryFilter = true): string
168 {
169 $result = '<div class="grid-x" id="plugin_listing_filters">
170 <div class="cell medium-6">
171 <input type="text" name="plugin_search" placeholder="'.acym_escape(acym_translation('ACYM_SEARCH')).'"/>
172 </div>
173 <div class="cell medium-6 grid-x">
174 <div class="cell hide-for-small-only medium-auto"></div>
175 <div class="cell medium-shrink">';
176
177 if ($categoryFilter) {
178 $result .= $this->getCategoryFilter();
179 }
180
181 $result .= '</div>
182 </div>
183 </div>';
184
185 return $result;
186 }
187
188 public function prepareWPCategories(string $type): void
189 {
190 $this->categories = acym_loadObjectList(
191 'SELECT cat.term_taxonomy_id AS id, parent.term_taxonomy_id AS parent_id, catdetails.name AS title
192 FROM `#__term_taxonomy` AS cat
193 JOIN `#__terms` AS catdetails ON cat.term_id = catdetails.term_id
194 LEFT JOIN `#__term_taxonomy` AS parent ON cat.parent = parent.term_id
195 WHERE cat.taxonomy = '.acym_escapeDB($type)
196 );
197 foreach ($this->categories as $i => $oneCat) {
198 if (empty($oneCat->parent_id)) {
199 $this->categories[$i]->parent_id = $this->rootCategoryId;
200 }
201 }
202 }
203
204 protected function getCategoryFilter()
205 {
206 $filter_cat = acym_getVar('int', 'plugin_category', 0);
207 $this->catvalues = [];
208 $this->catvalues[] = acym_selectOption(0, 'ACYM_ALL');
209
210 $this->cats = [];
211 $this->subCategories = [];
212 if (!empty($this->categories)) {
213 foreach ($this->categories as $oneCat) {
214 $this->cats[$oneCat->parent_id][] = $oneCat;
215 }
216 $this->handleChildrenCategories($this->rootCategoryId);
217 foreach ($this->categories as $oneCat) {
218 $this->subCategories[$oneCat->id] = $this->getSubCats($oneCat->id);
219 }
220 }
221
222 return acym_select(
223 $this->catvalues,
224 'plugin_category',
225 intval($filter_cat),
226 ['class' => 'plugin_category_select']
227 );
228 }
229
230 private function getSubCats(int $categoryId): array
231 {
232 $result = [$categoryId];
233 if (empty($this->cats[$categoryId])) {
234 return $result;
235 }
236
237 foreach ($this->cats[$categoryId] as $oneSubCategory) {
238 $result = array_merge($result, $this->getSubCats($oneSubCategory->id));
239 }
240
241 return $result;
242 }
243
244 protected function handleChildrenCategories(int $parent_id, int $level = 0): void
245 {
246 if (empty($this->cats[$parent_id])) return;
247
248 foreach ($this->cats[$parent_id] as $cat) {
249 $this->catvalues[] = acym_selectOption($cat->id, str_repeat(' - - ', $level).$cat->title);
250 $this->handleChildrenCategories($cat->id, $level + 1);
251 }
252 }
253
254 protected function getSubCategories(int $categoryId): array
255 {
256 $this->getCategoryFilter();
257
258 return $this->subCategories[$categoryId];
259 }
260
261 protected function autoContentOptions(array &$options, ?string $type = null): void
262 {
263 if ($type === 'event') {
264 $options[] = [
265 'title' => 'ACYM_FROM',
266 'type' => 'date',
267 'name' => 'from',
268 'default' => time(),
269 'relativeDate' => '+',
270 ];
271
272 $options[] = [
273 'title' => 'ACYM_TO',
274 'type' => 'date',
275 'name' => 'to',
276 'default' => '',
277 'relativeDate' => '+',
278 ];
279 } elseif ($type !== 'simple') {
280 $options[] = [
281 'title' => 'ACYM_MIN_PUBLISH_DATE',
282 'tooltip' => 'ACYM_MIN_PUBLISH_DATE_DESC',
283 'type' => 'date',
284 'name' => 'min_publish',
285 'default' => '',
286 'relativeDate' => '-',
287 ];
288 }
289
290 $options[] = [
291 'title' => 'ACYM_COLUMNS',
292 'type' => 'number',
293 'name' => 'cols',
294 'default' => 1,
295 ];
296
297 $options[] = [
298 'title' => 'ACYM_COLUMN_HORIZONTAL_PADDING',
299 'type' => 'number',
300 'name' => 'hpadding',
301 'default' => 10,
302 ];
303
304 $options[] = [
305 'title' => 'ACYM_COLUMN_VERTICAL_PADDING',
306 'type' => 'number',
307 'name' => 'vpadding',
308 'default' => 10,
309 ];
310
311 $options[] = [
312 'title' => 'ACYM_MAX_NB_ELEMENTS',
313 'type' => 'number',
314 'name' => 'max',
315 'default' => 20,
316 ];
317 }
318
319 protected function autoCampaignOptions(array &$options, bool $modified = false): void
320 {
321 if (empty($this->campaignId) && empty($this->campaignType)) {
322 return;
323 } elseif (!empty($this->campaignId) && (empty($this->campaignType) || $this->campaignType !== 'auto')) {
324 $campaignClass = new CampaignClass();
325 $campaign = $campaignClass->getOneById($this->campaignId);
326 if ($campaign->sending_type !== 'auto') return;
327 } elseif (empty($this->campaignId) && !empty($this->campaignType) && $this->campaignType !== 'auto') {
328 return;
329 }
330
331 $options[] = [
332 'title' => 'ACYM_DOCUMENTATION',
333 'type' => 'custom',
334 'name' => 'documentation',
335 'output' => '<a target="_blank" href="'.ACYM_DOCUMENTATION.'main-pages/campaigns/automatic-campaigns#dont-send-twice-the-same-content"><i class="acymicon-book"></i></a>',
336 'js' => '',
337 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
338 ];
339
340 if ($modified) {
341 $options[] = [
342 'title' => 'ACYM_DATE',
343 'type' => 'select',
344 'name' => 'datefilter',
345 'default' => 'onlynew',
346 'tooltip' => 'ACYM_ONLY_NEWLY_CREATED_DESC',
347 'options' => [
348 '' => 'ACYM_NO_FILTER',
349 'onlynew' => 'ACYM_ONLY_NEWLY_CREATED',
350 'onlymodified' => 'ACYM_ONLY_NEWLY_MODIFIED',
351 ],
352 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
353 ];
354 } else {
355 $options[] = [
356 'title' => 'ACYM_ONLY_NEWLY_CREATED',
357 'type' => 'boolean',
358 'name' => 'onlynew',
359 'default' => true,
360 'tooltip' => 'ACYM_ONLY_NEWLY_CREATED_DESC',
361 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
362 ];
363 }
364
365 $options[] = [
366 'title' => 'ACYM_MIN_NB_ELEMENTS',
367 'type' => 'number',
368 'name' => 'min',
369 'default' => 0,
370 'tooltip' => 'ACYM_MIN_NB_ELEMENTS_DESC',
371 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
372 ];
373 }
374
375 protected function getElementsListing(array $options): string
376 {
377 if ($this->pageInfo->loadMore) {
378 return $this->getInnerListing($options);
379 }
380 $listing = '<div id="plugin_listing" class="acym__popup__listing">';
381 $listing .= '<input type="hidden" name="plugin" value="'.acym_escape(get_class($this)).'" />';
382
383 $listing .= '<div class="cell grid-x hide-for-small-only plugin_listing_headers">';
384 foreach ($options['header'] as $oneColumn) {
385 $class = empty($oneColumn['class']) ? '' : ' '.$oneColumn['class'];
386 $listing .= '<div class="cell plugin_listing_headers__title medium-'.$oneColumn['size'].$class.'">'.acym_translation($oneColumn['label']).'</div>';
387 }
388 $listing .= '</div>';
389
390 $listing .= $this->getInnerListing($options);
391
392 $listing .= '<input type="hidden" value="1" id="acym_pagination__ajax__load-more" name="acym_pagination__ajax__load-more">';
393 $listing .= '</div>';
394
395 return $listing;
396 }
397
398 private function getInnerListing(array $options): string
399 {
400 if (empty($options['rows']) && $this->pageInfo->loadMore) {
401 $listing = '<h3 class="cell acym__listing__empty__load-more text-center">'.acym_translation('ACYM_NO_MORE_RESULTS').'</h3>';
402 } elseif (empty($options['rows'])) {
403 $listing = '<h1 class="cell acym__listing__empty__search__modal text-center">'.acym_translation('ACYM_NO_RESULTS_FOUND').'</h1>';
404 } else {
405 $selected = explode(',', acym_getVar('string', 'selected', ''));
406 if (!empty($this->defaultValues->id)) {
407 $selected = [$this->defaultValues->id];
408 }
409
410 $listing = '';
411 foreach ($options['rows'] as $row) {
412 $class = 'cell grid-x acym__row__no-listing acym__listing__row__popup';
413 if (in_array($row->{$options['id']}, $selected)) {
414 $class .= ' selected_row';
415 }
416
417 $listing .= '<div
418 class="'.$class.'"
419 data-id="'.acym_escape($row->{$options['id']}).'"
420 onclick="applyContent'.acym_escape($this->name).'(\''.acym_escape($row->{$options['id']}).'\', this);">';
421
422 foreach ($options['header'] as $column => $oneColumn) {
423 $value = $row->$column;
424
425 if (!empty($oneColumn['type'])) {
426 if ($oneColumn['type'] === 'date') {
427 if (empty($value)) {
428 $value = '-';
429 } else {
430 if (!is_numeric($value) && $value != '0000-00-00 00:00:00') {
431 $value = strtotime($value);
432 }
433 $tooltip = acym_date($value, acym_translation('ACYM_DATE_FORMAT_LC2'));
434 $value = acym_tooltip(
435 [
436 'hoveredText' => acym_date($value, acym_translation('ACYM_DATE_FORMAT_LC5')),
437 'textShownInTooltip' => $tooltip,
438 ]
439 );
440 }
441 } elseif ($oneColumn['type'] === 'int') {
442 $value = intval($value);
443 }
444 }
445
446 $class = empty($oneColumn['class']) ? '' : ' '.$oneColumn['class'];
447 $listing .= '<div class="cell medium-'.$oneColumn['size'].$class.'">'.$value.'</div>';
448 }
449
450 $listing .= '</div>';
451 }
452 }
453
454 return $listing;
455 }
456
457 protected function getCategoryListing(): string
458 {
459 $listing = '';
460 if (empty($this->catvalues)) {
461 $listing .= '<h1 class="cell acym__listing__empty__search__modal text-center">'.acym_translation('ACYM_NO_RESULTS_FOUND').'</h1>';
462
463 return $listing;
464 }
465
466 $listing .= '<div class="acym__popup__listing padding-0">';
467 $selected = [];
468 if (!empty($this->defaultValues->id) && strpos($this->defaultValues->id, '-')) {
469 $selected = explode('-', $this->defaultValues->id);
470 }
471 foreach ($this->catvalues as $oneCat) {
472 if (empty($oneCat->value)) continue;
473
474 $classes = 'cell grid-x acym__row__no-listing acym__listing__row__popup';
475 if (in_array($oneCat->value, $selected)) {
476 $classes .= ' selected_row';
477 }
478 $listing .= '<div class="'.$classes.'" data-id="'.intval($oneCat->value).'" onclick="applyContentauto'.acym_escape($this->name).'('.intval($oneCat->value).', this);">
479 <div class="cell medium-5">'.acym_escape($oneCat->text).'</div>
480 </div>';
481 }
482 $listing .= '</div>';
483
484 return $listing;
485 }
486
487 protected function getTagListing(): string
488 {
489 $listing = '';
490 if (empty($this->tagvalues)) {
491 $listing .= '<h1 class="cell acym__listing__empty__search__modal text-center">'.acym_translation('ACYM_NO_RESULTS_FOUND').'</h1>';
492
493 return $listing;
494 }
495
496 $listing .= '<div class="acym__popup__listing padding-0">';
497 $selected = [];
498 if (!empty($this->defaultValues->id) && strpos($this->defaultValues->id, '-')) {
499 $selected = explode('-', $this->defaultValues->id);
500 }
501 $termIdName = 'term_id';
502 if ('wordpress' === ACYM_CMS) {
503 $termIdName = 'term_taxonomy_id';
504 }
505 foreach ($this->tagvalues as $oneTag) {
506 if (empty($oneTag->$termIdName)) continue;
507
508 $class = 'cell grid-x acym__row__no-listing acym__listing__row__popup';
509 if (in_array($oneTag->$termIdName, $selected)) $class .= ' selected_row';
510 $listing .= '<div class="'.$class.'" data-id="'.intval($oneTag->$termIdName).'" onclick="applyContent'.acym_escape($this->name).'_tags('.intval($oneTag->$termIdName).', this);">
511 <div class="cell medium-5">'.acym_escape($oneTag->name).'</div>
512 </div>';
513 }
514 $listing .= '</div>';
515
516 return $listing;
517 }
518
519 protected function replaceMultiple(object &$email)
520 {
521 $this->generateByCategory($email);
522 if (empty($this->tags)) return;
523
524 $this->pluginHelper->replaceTags($email, $this->tags, true);
525 }
526
527 protected function handleOrderBy(string &$query, object $parameter, ?string $table = null)
528 {
529 if (empty($parameter->order)) return;
530
531 $ordering = explode(',', $parameter->order);
532 if ($ordering[0] === 'rand') {
533 $query .= ' ORDER BY rand()';
534 } else {
535 $table = null === $table ? '' : $table.'.';
536 $column = $ordering[0];
537
538 if (strpos($column, '.') !== false) {
539 $parts = explode('.', $column, 2);
540 $table = acym_secureDBColumn($parts[0]).'.';
541 $column = $parts[1];
542 }
543
544 $query .= ' ORDER BY '.$table.'`'.acym_secureDBColumn(trim($column)).'` '.acym_secureDBColumn(trim($ordering[1]));
545 }
546 }
547
548 protected function handleMax(string &$query, object $parameter): void
549 {
550 if (empty($parameter->max)) {
551 $parameter->max = 20;
552 }
553 $query .= ' LIMIT '.intval($parameter->max);
554 }
555
556 protected function handleMin(array $elements, object $parameter): void
557 {
558 if (!empty($parameter->min) && count($elements) < $parameter->min) {
559 $this->generateCampaignResult->status = false;
560 $this->generateCampaignResult->message = acym_translationSprintf(
561 'ACYM_GENERATE_CAMPAIGN_NOT_ENOUGH_CONTENT',
562 $this->pluginDescription->name,
563 count($elements),
564 $parameter->min
565 );
566 }
567 }
568
569 protected function getLastGenerated(int $mailId): int
570 {
571 $campaignClass = new CampaignClass();
572
573 return $campaignClass->getLastGenerated($mailId);
574 }
575
576 protected function finalizeCategoryFormat(string $query, object $parameter, ?string $table = null): string
577 {
578 $this->handleOrderBy($query, $parameter, $table);
579 $this->handleMax($query, $parameter);
580
581 $elements = acym_loadResultArray($query);
582
583 return $this->formatIndividualTags($elements, $parameter);
584 }
585
586 protected function formatIndividualTags(array $elements, object $parameter): string
587 {
588 $this->handleMin($elements, $parameter);
589
590 if (empty($elements)) return '';
591
592 $elements = $this->groupByCategory($elements);
593
594 $customLayout = ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'_auto.php';
595 if (file_exists($customLayout)) {
596 ob_start();
597 require $customLayout;
598
599 return ob_get_clean();
600 }
601
602 $arrayElements = $this->buildIndividualTags($elements, $parameter);
603
604 return $this->pluginHelper->getFormattedResult($arrayElements, $parameter);
605 }
606
607 protected function buildIndividualTags(array $elements, object $parameter): array
608 {
609 $arrayElements = [];
610 unset($parameter->id);
611
612 $i = 0;
613 foreach ($elements as $oneElementId) {
614 $args = [];
615 $args[] = $this->name.':'.$oneElementId;
616
617 foreach ($parameter as $oneParam => $val) {
618 if (is_bool($val)) {
619 $args[] = $oneParam;
620 } else {
621 $args[] = $oneParam.':'.$val;
622 }
623 }
624
625 if ($i % 2 === 1 && !empty($parameter->alternate)) {
626 $args[] = 'invert';
627 }
628
629 $arrayElements[] = '{'.implode('| ', $args).'}';
630
631 $i++;
632 }
633
634 return $arrayElements;
635 }
636
637 protected function groupByCategory(array $elements)
638 {
639 return $elements;
640 }
641
642 protected function getSelectedArea(object $parameter): array
643 {
644 $allcats = explode('-', $parameter->id);
645 $selectedArea = [];
646 foreach ($allcats as $oneCat) {
647 if (empty($oneCat)) continue;
648 $selectedArea[] = intval($oneCat);
649 }
650
651 return $selectedArea;
652 }
653
654 protected function replaceOne(object &$email): void
655 {
656 $tags = $this->pluginHelper->extractTags($email, $this->name);
657 if (empty($tags)) return;
658
659 $newConfiguration = [
660 'dcontent_default_'.get_class($this) => json_encode(end($tags)),
661 ];
662 $this->config->saveConfig($newConfiguration);
663
664 if (method_exists($this, 'loadLibraries') && !$this->loadLibraries($email)) {
665 return;
666 }
667
668 $this->emailLanguage = $email->links_language;
669 $translationTool = $this->config->get('translate_content', 'no');
670
671 $tagsReplaced = [];
672 foreach ($tags as $i => $oneTag) {
673 if (isset($tagsReplaced[$i])) continue;
674
675 if (!empty($this->emailLanguage) && $translationTool !== 'no' && acym_isMultilingual()) {
676 $oneTag->id = $this->getTranslationId($oneTag->id, $translationTool);
677 }
678 $tagsReplaced[$i] = $this->replaceIndividualContent($oneTag);
679 }
680
681 $email->custom_view = file_exists(ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'.html');
682
683 $this->pluginHelper->replaceTags($email, $tagsReplaced, true);
684 }
685
686 protected function initIndividualContent(object &$tag, string $query)
687 {
688 $element = acym_loadObject($query);
689
690 if (empty($element)) {
691 if (acym_isAdmin()) {
692 acym_enqueueMessage(acym_translationSprintf('ACYM_CONTENT_NOT_FOUND', $tag->id), 'notice');
693 }
694
695 return null;
696 }
697
698 if (empty($tag->display)) {
699 $tag->display = [];
700 } else {
701 $tag->display = explode(',', $tag->display);
702 }
703
704 return $element;
705 }
706
707 protected function getCustomLayoutVars(object $element): array
708 {
709 $varFields = [];
710 $varFields['{picthtml}'] = '';
711 foreach ($element as $fieldName => $oneField) {
712 if (is_object($oneField) || is_array($oneField)) {
713 $varFields['{'.$fieldName.'}'] = json_encode($oneField);
714 } else {
715 $varFields['{'.$fieldName.'}'] = $oneField;
716 }
717 }
718
719 return $varFields;
720 }
721
722 protected function finalizeElementFormat(string $htmlResult, object $insertionOptions, array $dataShortcodes): string
723 {
724 $fullCustomLayoutPath = ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'.php';
725 if ($this->config->get('php_overrides', 0) == 1 && file_exists($fullCustomLayoutPath)) {
726 ob_start();
727 require $fullCustomLayoutPath;
728 $viewContent = ob_get_clean();
729 $htmlResult = str_replace(array_keys($dataShortcodes), $dataShortcodes, $viewContent);
730 } else {
731 $customLayoutPath = ACYM_CUSTOM_PLUGIN_LAYOUT.$this->name.'.html';
732 if (file_exists($customLayoutPath)) {
733 $dataShortcodes['{wrappedText}'] = $this->pluginHelper->wrappedText;
734 $viewContent = acym_fileGetContent($customLayoutPath);
735 $viewContentReplace = str_replace(array_keys($dataShortcodes), $dataShortcodes, $viewContent);
736 if ($viewContent !== $viewContentReplace) {
737 $htmlResult = $viewContentReplace;
738 }
739 }
740 }
741
742 $allShortcodesList = '<table><tr><th>Shortcode</th><th>Value</th></tr>';
743 foreach ($dataShortcodes as $name => $value) {
744 if (!is_string($value)) {
745 continue;
746 }
747
748 $allShortcodesList .= '<tr><td>'.trim($name, '{}').'</td><td>'.$value.'</td></tr>';
749 }
750 $allShortcodesList .= '</table>';
751 $htmlResult = str_replace('{allshortcodes}', $allShortcodesList, $htmlResult);
752
753 return $this->pluginHelper->managePicts($insertionOptions, $htmlResult);
754 }
755
756 protected function filtersFromConditions(array &$filters): void
757 {
758 $newFilters = [];
759
760 $this->onAcymDeclareConditions($newFilters);
761 foreach ($newFilters as $oneType) {
762 foreach ($oneType as $oneFilterName => $oneFilter) {
763 if (!empty($oneFilter->option)) $oneFilter->option = str_replace(['acym_condition', '[conditions]'], ['acym_action', '[filters]'], $oneFilter->option);
764 $filters[$oneFilterName] = $oneFilter;
765 }
766 }
767 }
768
769 protected function getElementTags(string $type, int $id): array
770 {
771 $tags = acym_loadObjectList(
772 'SELECT tags.`title`, tags.`alias`, tags.`id`
773 FROM #__tags AS tags
774 JOIN #__contentitem_tag_map AS map ON tags.`id` = map.`tag_id`
775 WHERE map.`type_alias` = '.acym_escapeDB($type).'
776 AND map.`content_item_id` = '.intval($id)
777 );
778
779 if (empty($tags)) return [];
780
781 $displayTags = [];
782 foreach ($tags as $oneTag) {
783 $displayTags[] = '<a href="index.php?option=com_tags&view=tag&id='.$oneTag->id.':'.$oneTag->alias.'" target="_blank">'.$oneTag->title.'</a>';
784 }
785
786 return $displayTags;
787 }
788
789 protected function getFormattedValue(array $fieldValues)
790 {
791 $field = $fieldValues[0];
792
793 if (!empty($field->fieldparams) && !is_array($field->fieldparams)) {
794 $field->fieldparams = json_decode($field->fieldparams, true);
795 }
796
797 switch ($field->type) {
798 case 'calendar':
799 $format = acym_translation($field->fieldparams['showtime'] == '1' ? 'ACYM_DATE_FORMAT_LC2' : 'ACYM_DATE_FORMAT_LC1');
800 $field->value = HTMLHelper::_('date', $field->value, $format);
801 break;
802
803 case 'checkboxes':
804 case 'list':
805 case 'radio':
806 $values = [];
807 foreach ($fieldValues as $oneValue) {
808 foreach ($field->fieldparams['options'] as $oneOPT) {
809 if ($oneOPT['value'] == $oneValue->value) {
810 $values[] = $oneOPT['name'];
811 break;
812 }
813 }
814 }
815
816 $field->value = implode(', ', $values);
817 break;
818
819 case 'dpcalendar':
820 if (empty($field->value)) {
821 $field->value = '';
822 break;
823 }
824
825 $title = acym_loadResult('SELECT `title` FROM #__categories WHERE `id` = '.intval($field->value));
826 if (empty($title)) {
827 $field->value = '';
828 } else {
829 $date = '#year='.acym_date('now', 'Y').'&month='.acym_date('now', 'm').'&day='.acym_date('now', 'd').'&view=month';
830 $field->value = '<a target="_blank" href="index.php?option=com_dpcalendar&view=calendar&id='.intval($field->value).$date.'">'.$title.'</a>';
831 }
832 break;
833
834 case 'imagelist':
835 if (!empty($field->fieldparams['directory']) && strlen($field->fieldparams['directory']) > 1) {
836 $field->value = '/'.$field->value;
837 } else {
838 $field->fieldparams['directory'] = '';
839 }
840 $field->value = '<img src="images/'.$field->fieldparams['directory'].$field->value.'" />';
841 break;
842
843 case 'media':
844 $value = '';
845 if (!empty($field->value)) {
846 if (substr($field->value, 0, 1) === '{') {
847 $value = json_decode($field->value, true);
848 if (!empty($value['imagefile'])) {
849 $alt = empty($value['alt_text']) ? '' : ' alt="'.acym_escape($value['alt_text']).'"';
850 $value = '<img src="'.$value['imagefile'].'"'.$alt.' />';
851 }
852 } else {
853 $value = '<img src="'.$field->value.'" alt="" />';
854 }
855 }
856
857 $field->value = $value;
858 break;
859
860 case 'repeatable':
861 if (!empty($field->value)) {
862 $values = is_string($field->value) ? json_decode($field->value) : $field->value;
863 $formattedValues = [];
864 foreach ($values as $oneSetOfValues) {
865 $formattedSet = [];
866 foreach ($oneSetOfValues as $oneLabel => $oneValue) {
867 if (empty($oneValue)) continue;
868
869 foreach ($field->fieldparams['fields'] as $oneField) {
870 if ($oneField['fieldname'] !== $oneLabel) continue;
871
872 if ($oneField['fieldtype'] === 'media') {
873 $oneValue = '<img src="'.$oneValue.'" alt="" />';
874 }
875
876 $formattedSet[] = $oneValue;
877 break;
878 }
879 }
880
881 if (empty($formattedSet)) continue;
882 $formattedValues[] = implode(', ', $formattedSet);
883 }
884
885 $field->value = empty($formattedSet) ? '' : '<ul><li>'.implode('</li><li>', $formattedValues).'</li></ul>';
886 }
887 break;
888
889 case 'sql':
890 if (empty($field->options)) {
891 $field->options = acym_loadObjectList($field->fieldparams['query'], 'value');
892 }
893
894 $field->value = $field->options[$field->value]->text;
895 break;
896
897 case 'url':
898 $field->value = '<a target="_blank" href="'.$field->value.'">'.$field->value.'</a>';
899 break;
900
901 case 'user':
902 $field->value = acym_currentUserName($field->value);
903 break;
904
905 case 'usergrouplist':
906 if (empty($field->usergroups)) {
907 $field->usergroups = acym_loadObjectList('SELECT id, title FROM #__usergroups', 'id');
908 }
909
910 if (empty($field->usergroups[$field->value])) {
911 $field->value = '';
912 break;
913 }
914 $field->value = $field->usergroups[$field->value]->title;
915 break;
916 case 'subform':
917 if (!empty($field->value)) {
918 $rows = is_string($field->value) ? json_decode($field->value, true) : $field->value;
919
920 $formattedValues = [];
921 foreach ($rows as $values) {
922 $fieldValues = [];
923 foreach ($values as $fieldIdentifier => $fieldValue) {
924 $fieldId = str_replace('field', '', $fieldIdentifier);
925 $oneFieldDefinition = acym_loadObject(
926 'SELECT `field`.*
927 FROM #__fields AS `field`
928 WHERE `field`.`id` = '.intval($fieldId)
929 );
930
931 if (empty($oneFieldDefinition)) {
932 break 3;
933 }
934
935 $multiCompatibleValues = [];
936 if (is_array($fieldValue)) {
937 foreach ($fieldValue as $oneFieldValue) {
938 $oneValue = clone $oneFieldDefinition;
939 $oneValue->value = $oneFieldValue;
940 $multiCompatibleValues[] = $oneValue;
941 }
942 } else {
943 $oneFieldDefinition->value = $fieldValue;
944 $multiCompatibleValues[] = $oneFieldDefinition;
945 }
946
947 $fieldValues[] = $oneFieldDefinition->label.': '.$this->getFormattedValue($multiCompatibleValues);
948 }
949 $formattedValues[] = implode(', ', $fieldValues);
950 }
951
952 $field->value = empty($formattedValues) ? '' : '<ul><li>'.implode('</li><li>', $formattedValues).'</li></ul>';
953 }
954 }
955
956 return $field->value;
957 }
958
959 protected function getLanguage(?string $elementLanguage = null, bool $onlyValue = false): string
960 {
961 $value = $this->emailLanguage;
962 if (!empty($elementLanguage) && $elementLanguage !== '*') {
963 $value = $elementLanguage;
964 }
965
966 if (empty($value)) {
967 return '';
968 }
969
970 if (ACYM_CMS === 'joomla' && acym_isPluginActive('languagefilter')) {
971 $languages = acym_loadObjectList('SELECT * FROM #__languages', 'lang_code');
972 if (isset($languages[$value])) {
973 $value = $languages[$value]->sef;
974 } else {
975 $value = substr($value, 0, strpos($value, '-'));
976 }
977
978 if ($onlyValue) {
979 return $value;
980 }
981
982 return '&lang='.$value;
983 } else {
984 if ($onlyValue) {
985 return $value;
986 }
987
988 return '&language='.$value;
989 }
990 }
991
992 protected function finalizeLink(string $link, $tag = null, $sef = true): string
993 {
994 if (acym_isPluginActive('languagefilter')) {
995 if (strpos($link, 'lang=') === false && !empty($this->emailLanguage)) {
996 $link .= strpos($link, '?') === false ? '?' : '&';
997 $link .= 'lang='.substr($this->emailLanguage, 0, strpos($this->emailLanguage, '-'));
998 }
999 } else {
1000 if (strpos($link, 'language=') === false && !empty($this->emailLanguage)) {
1001 $link .= strpos($link, '?') === false ? '?' : '&';
1002 $link .= 'language='.$this->emailLanguage;
1003 }
1004 }
1005
1006 if (!empty($tag->autologin)) {
1007 $link .= (strpos($link, '?') ? '&' : '?').'autoSubId={subscriber:id}&subKey={subscriber:autologin_token|urlencode}';
1008 }
1009
1010 if (is_bool($tag)) {
1011 $sef = $tag;
1012 }
1013
1014 return acym_frontendLink($link, false, $sef);
1015 }
1016
1017 protected function handleCustomFields(object $tag, array &$customFields): void
1018 {
1019 if (empty($tag->custom)) {
1020 return;
1021 }
1022
1023 $tag->custom = explode(',', $tag->custom);
1024 acym_arrayToInteger($tag->custom);
1025
1026 $rawfields = acym_loadObjectList(
1027 'SELECT `field`.*, `values`.`value`
1028 FROM #__fields_values AS `values`
1029 JOIN #__fields AS `field` ON `values`.`field_id` = `field`.`id`
1030 WHERE `values`.`item_id` = '.intval($tag->id).' AND `field`.`id` IN ('.implode(', ', $tag->custom).')'
1031 );
1032
1033 $fields = [];
1034 foreach ($rawfields as $field) {
1035 $fields[$field->id][] = $field;
1036 }
1037
1038 usort($fields, function ($a, $b) {
1039 return $a[0]->ordering <=> $b[0]->ordering;
1040 });
1041
1042 foreach ($fields as $fieldValues) {
1043 $value = $this->getFormattedValue($fieldValues);
1044
1045 if (empty($value)) continue;
1046
1047 $customFields[] = [
1048 $value,
1049 $fieldValues[0]->label,
1050 ];
1051 }
1052 }
1053
1054 protected function getIntro(string $text): string
1055 {
1056 $pageBreak = null;
1057 $possibleBreaks = [
1058 '<!--more-->',
1059 '<hr id="system-readmore" />',
1060 '<!--nextpage-->',
1061 ];
1062
1063 foreach ($possibleBreaks as $oneBreak) {
1064 if (strpos($text, $oneBreak) !== false) {
1065 $pageBreak = $oneBreak;
1066 break;
1067 }
1068 }
1069
1070 if (empty($pageBreak)) {
1071 return $text;
1072 }
1073
1074 $split = explode($pageBreak, $text, 2);
1075
1076 return array_shift($split);
1077 }
1078
1079 public function displayCustomViewEditor(string &$output): void
1080 {
1081 $plugin = new \stdClass();
1082 $plugin->folder_name = $this->name;
1083 $plugin->settings = $this->settings;
1084 $this->generateSettings($plugin);
1085
1086 if (empty($plugin->settings['custom_view'])) {
1087 return;
1088 }
1089
1090 $output .= '<p class="acym__wysid__right__toolbar__p acym__wysid__right__toolbar__p__open acym__title">';
1091 $output .= acym_translation('ACYM_ADDON_SETTINGS');
1092 $output .= '<i class="acymicon-keyboard-arrow-up"></i></p>';
1093 $output .= '<div class="acym__wysid__right__toolbar__design--show acym__wysid__right__toolbar__design acym__wysid__context__modal__container">';
1094 $output .= $plugin->settings['custom_view'];
1095 $output .= '</div>';
1096 }
1097
1098 public function generateSettings(object $plugin): bool
1099 {
1100 if (empty($plugin->settings)) return false;
1101
1102 if (array_key_exists('not_installed', $plugin->settings)) {
1103 $plugin->settings = 'not_installed';
1104
1105 return true;
1106 }
1107
1108 foreach ($plugin->settings as $key => $field) {
1109 $text = '';
1110 if (empty($field['type'])) {
1111 $plugin->settings[$key] = $text;
1112 continue;
1113 }
1114
1115 $id = $plugin->folder_name.'_'.$key;
1116 $name = $plugin->folder_name.'['.$key.']';
1117 if (!empty($field['label'])) {
1118 $field['label'] = acym_translation($field['label']);
1119 }
1120
1121 if (!empty($field['info'])) {
1122 $field['label'] .= acym_info(
1123 [
1124 'textShownInTooltip' => acym_translation($field['info']),
1125 'classText' => 'wysid_tooltip',
1126 'isWarning' => !empty($field['info_warning']),
1127 ]
1128 );
1129 }
1130
1131 if ($field['type'] === 'checkbox') {
1132 $classLabel = 'shrink';
1133 $text .= '<label for="'.acym_escape($id).'" class="cell '.acym_escape($classLabel).'">'.acym_escape($field['label']).'</label>';
1134 $text .= '<input id="'.acym_escape($id).'" class="cell shrink" type="checkbox" name="'.acym_escape($name).'" '.(empty($field['value']) ? '' : 'checked').'>';
1135 } elseif ($field['type'] === 'switch') {
1136 $text .= acym_switch(
1137 $name,
1138 $field['value'],
1139 $field['label'],
1140 [],
1141 'large-7'
1142 );
1143 } elseif ($field['type'] === 'select') {
1144 $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1145 $text .= acym_select(
1146 $field['data'],
1147 $name,
1148 $field['value'],
1149 ['class' => 'acym__select'],
1150 'value',
1151 'text',
1152 false,
1153 true
1154 );
1155 } elseif ($field['type'] === 'multiple_select') {
1156 $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1157 $text .= acym_selectMultiple(
1158 $field['data'],
1159 $name,
1160 empty($field['value']) ? [] : $field['value'],
1161 ['class' => 'acym__select']
1162 );
1163 } elseif ($field['type'] === 'text') {
1164 $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1165 $text .= '<input type="text" name="'.$name.'" value="'.acym_escape($field['value']).'" class="cell shrink">';
1166 } elseif ($field['type'] === 'number') {
1167 $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1168 $text .= '<input type="number" name="'.$name.'" value="'.acym_escape($field['value']).'" class="cell large-2 medium-5">';
1169 if (!empty($field['post_text'])) $text .= '<span class="cell shrink">'.strtolower($field['post_text']).'</span>';
1170 } elseif ($field['type'] === 'radio') {
1171 $text .= '<p class="cell">'.$field['label'].'</p>';
1172 $text .= acym_radio(
1173 $field['data'],
1174 $name,
1175 $field['value']
1176 );
1177 } elseif ($field['type'] === 'date') {
1178 $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1179 $text .= acym_dateField(
1180 $name,
1181 $field['value'],
1182 'cell shrink'
1183 );
1184 } elseif ($field['type'] === 'custom_view' && acym_isAdmin()) {
1185 $idCustomView = 'acym__plugins__installed__custom-view__'.$this->name;
1186 $ctrl = acym_getVar('string', 'ctrl', '');
1187 $classTooltip = $ctrl === 'dynamics' ? '' : 'wysid_tooltip';
1188 $text .= '<label class="cell">';
1189 $text .= acym_translation('ACYM_CUSTOM_VIEW');
1190 $text .= acym_info(
1191 [
1192 'textShownInTooltip' => 'ACYM_CUSTOM_VIEW_DESC',
1193 'classText' => $classTooltip,
1194 ]
1195 );
1196 $text .= '</label>';
1197
1198 if (empty($field['tags'])) {
1199 $field['tags'] = [];
1200 }
1201
1202 $modalContent = '<div id="'.acym_escape($idCustomView).'" class="cell grid-x acym__plugins__installed__custom-view" acym-data-tags="'.acym_escape(
1203 json_encode($field['tags'])
1204 ).'">
1205 <h2 class="cell text-center acym__title__primary__color">'.acym_translationSprintf('ACYM_CUSTOM_VIEW_FOR_X', $this->pluginDescription->name).'</h2>
1206 <div class="cell grid-x acym__plugins__installed__custom-view__edit-container">
1207 <div class="acym__plugins__installed__custom-view__editor-loader grid-x cell align-center acym_vcenter" v-if="loading">'.acym_loaderLogo().'</div>
1208 <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>
1209 <div class="cell grid-x medium-3 margin-left-1 acym__plugins__installed__custom-view__tags">
1210 <h3 class="acym__title acym__title__secondary cell text-center">'.acym_translation('ACYM_DYNAMIC_CONTENT').acym_info(
1211 [
1212 'textShownInTooltip' => acym_translation('ACYM_DYNAMIC_CONTENT_DESC'),
1213 ]
1214 ).'</h3>
1215 <div class="cell acym__plugins__installed__custom-view__tag" v-for="(trad, tag) in tags" :key="tag" @click.prevent="insertTag(tag)">{{ trad }}</div>
1216 </div>
1217 </div>
1218 <div class="cell grid-x acym__plugins__installed__custom-view__actions acym_vcenter margin-top-1 padding-bottom-1">
1219 <div class="cell auto grid-x">
1220 <button type="button" class="cell shrink button-secondary button" @click="resetView">'.acym_translation('ACYM_RESET_VIEW').'</button>
1221 <div class="cell shrink margin-right-2 acym_vcenter margin-left-1">
1222 <i v-if="deleting" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1223 <span v-if="deleted">{{ messageDeleted }}</span>
1224 </div>
1225 </div>
1226 <div class="cell auto align-right grid-x">
1227 <div class="cell shrink margin-right-2 acym_vcenter">
1228 <i v-if="saving" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1229 <span v-if="saved">{{ messageSaved }}</span>
1230 </div>
1231 <button @click="save()" class="cell shrink button" type="button">'.acym_translation('ACYM_SAVE_NEW_CUSTOM_VIEW_VERSION').'</button>
1232 </div>
1233 </div>
1234 </div>';
1235 $text .= acym_modal(
1236 acym_translation('ACYM_EDIT_CUSTOM_VIEW'),
1237 $modalContent,
1238 null,
1239 [
1240 'acym-data-plugins-id' => $idCustomView,
1241 'acym-data-plugin-class' => get_class($this),
1242 'acym-data-plugin-folder' => $this->name,
1243 ],
1244 ['class' => 'cell button']
1245 );
1246 } elseif ($field['type'] == 'multikeyvalue') {
1247 $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1248
1249 $text .= '<div class="multikeyvalue_container grid-x">';
1250
1251 if (!empty($field['value'])) {
1252 $headers = json_decode($field['value'], true);
1253 foreach ($headers as $headerKey => $headerValue) {
1254 $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_DKIM_KEY', true).'" value="'.acym_escape($headerKey).'"/>';
1255 $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_VALUE', true).'" value="'.acym_escape($headerValue).'" />';
1256 $text .= '<div class="multikeyvalue_container_separator cell small-6"></div>';
1257 }
1258 }
1259
1260 $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_DKIM_KEY', true).'" value=""/>';
1261 $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_VALUE', true).'" value="" />';
1262
1263 $text .= '<button class="button multikeyvalue_container_new">'.acym_translation('ACYM_ADD_NEW').'</button>';
1264
1265 $text .= '<input type="hidden" name="'.$name.'" value="" />';
1266 $text .= '</div>';
1267 } elseif ($field['type'] == 'custom') {
1268 $text .= $field['content'];
1269 }
1270 $plugin->settings[$key] = $text;
1271 }
1272
1273 return true;
1274 }
1275
1276 public function loadCSS(string $css, bool $raw = false, ?string $path = null): void
1277 {
1278 if (!$raw) {
1279 if (empty($path)) $path = ACYM_DYNAMICS_URL.$this->name;
1280 $css = $path.'/css/'.$css.'.css';
1281 }
1282 acym_addStyle($raw, $css);
1283 }
1284
1285 public function loadJavascript(string $js, bool $raw = false, ?string $path = null): void
1286 {
1287 if (!$raw) {
1288 if (empty($path)) $path = ACYM_DYNAMICS_URL.$this->name;
1289 $js = $path.'/js/'.$js.'.js';
1290 }
1291 acym_addScript($raw, $js);
1292 }
1293
1294 public function includeView(string $view, array $data = [], ?string $path = null): string
1295 {
1296 if (empty($path)) {
1297 $path = ACYM_ADDONS_FOLDER_PATH.$this->name.DS.'views'.DS.$view.'.php';
1298 } else {
1299 $path = $path.DS.'views'.DS.$view.'.php';
1300 }
1301
1302 if (!file_exists($path)) {
1303 throw new \Exception(acym_translation('ACYM_NON_EXISTING_PAGE'));
1304 }
1305
1306 ob_start();
1307 include $path;
1308
1309 return ob_get_clean();
1310 }
1311
1312 public function onAcymAddSettings(array &$plugins): void
1313 {
1314 if (method_exists($this, 'initSettings')) {
1315 $this->initSettings();
1316 }
1317
1318 foreach ($plugins as $key => $plugin) {
1319 if ($plugin->folder_name === $this->name) {
1320 if (!empty($plugin->settings)) {
1321 foreach ($plugin->settings as $keySettings => $value) {
1322 if (isset($this->settings[$keySettings]['value'])) {
1323 $this->settings[$keySettings]['value'] = $plugin->settings[$keySettings]['value'];
1324 }
1325 }
1326 }
1327 $plugins[$key]->settings = $this->settings;
1328
1329 $this->generateSettings($plugins[$key]);
1330 break;
1331 }
1332 }
1333 }
1334
1335 protected function getParam(string $name, $default = '')
1336 {
1337 return $this->savedSettings[$name]['value'] ?? $default;
1338 }
1339
1340 protected function getTranslationId(int $elementId, string $translationTool, bool $defaultLanguage = false)
1341 {
1342 return $elementId;
1343 }
1344
1345 public function filterSpecialMailsDailySend(array &$specialMails, int $time, string $mailType): void
1346 {
1347 $dailyHour = $this->config->get('daily_hour', '12');
1348 $dailyMinute = $this->config->get('daily_minute', '00');
1349 $dayBasedOnCMSTimezone = acym_date('now', 'Y-m-d');
1350 $dayBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$dailyHour.':'.$dailyMinute);
1351
1352 $campaignClass = new CampaignClass();
1353
1354 $tmpMails = [];
1355 foreach ($specialMails as $oneMail) {
1356 if ($oneMail->sending_type === $mailType) {
1357 $noNextTrigger = empty($oneMail->next_trigger);
1358 $nextTriggerIsNow = date('m-d', $oneMail->next_trigger) == date('m-d', $dayBasedOnCMSTimezoneAtSpecifiedHour);
1359 $nextTriggerIsInPast = $oneMail->next_trigger < $time;
1360 if ($time >= $dayBasedOnCMSTimezoneAtSpecifiedHour && ($noNextTrigger || $nextTriggerIsNow || $nextTriggerIsInPast)) {
1361 $oneMail->next_trigger = acym_getTime('tomorrow '.$dailyHour.':'.$dailyMinute);
1362 $oneMail->last_generated = $time;
1363 $campaignClass->save($oneMail);
1364 $tmpMails[] = $oneMail;
1365 }
1366 } else {
1367 $tmpMails[] = $oneMail;
1368 }
1369 }
1370 $specialMails = $tmpMails;
1371 }
1372
1373 protected function getIdsSelectAjax(): array
1374 {
1375 $ids = acym_getVar('string', 'id');
1376 if (empty($ids)) {
1377 return [];
1378 }
1379
1380 $ids = explode(',', $ids);
1381 acym_arrayToInteger($ids);
1382
1383 return $ids;
1384 }
1385
1386 protected function cleanExtensionContent(string $text)
1387 {
1388 if (ACYM_CMS === 'wordpress') {
1389 if (!acym_isExtensionActive('classic-editor/classic-editor.php') || strpos($text, '<!-- wp:') !== false) {
1390 return $text;
1391 }
1392
1393 return nl2br($text);
1394 } else {
1395 return preg_replace('#\{igallery[^}]+\}#Ui', '', $text);
1396 }
1397 }
1398
1399 protected function callApiSendingMethod(string $url, array $data = [], array $headers = [], string $type = 'GET', array $authentication = [], bool $dataDecoded = false): array
1400 {
1401 if (!empty($headers) && empty($headers[0])) {
1402 $newHeaders = [];
1403 foreach ($headers as $key => $value) {
1404 $newHeaders[] = $key.': '.$value;
1405 }
1406 $headers = $newHeaders;
1407 }
1408
1409 $curl = curl_init();
1410
1411 $optionsArray = [
1412 CURLOPT_URL => $url,
1413 CURLOPT_RETURNTRANSFER => true,
1414 CURLOPT_ENCODING => '',
1415 CURLOPT_MAXREDIRS => 10,
1416 CURLOPT_TIMEOUT => 30,
1417 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
1418 CURLOPT_CUSTOMREQUEST => $type,
1419 CURLOPT_HTTPHEADER => $headers,
1420 CURLOPT_SSL_VERIFYHOST => 0,
1421 CURLOPT_SSL_VERIFYPEER => 0,
1422 ];
1423
1424 if (!empty($data)) {
1425 if (empty($dataDecoded)) {
1426 $optionsArray[CURLOPT_POSTFIELDS] = json_encode($data);
1427 } elseif ($dataDecoded === true) {
1428 $optionsArray[CURLOPT_POSTFIELDS] = $data;
1429 }
1430 }
1431
1432 if (!empty($authentication)) {
1433 $optionsArray[CURLOPT_USERPWD] = $authentication['name'].':'.$authentication['pwd'];
1434 }
1435
1436 curl_setopt_array(
1437 $curl,
1438 $optionsArray
1439 );
1440
1441 $response = curl_exec($curl);
1442 $error = curl_error($curl);
1443 $this->responseCode = (int)curl_getinfo($curl, CURLINFO_HTTP_CODE);
1444
1445 if ($error) {
1446 return ['error_curl' => $error];
1447 } else {
1448 $response = json_decode($response, true);
1449
1450 return $response === null ? ['error_curl' => 'Malformed response'] : $response;
1451 }
1452 }
1453
1454 protected function getTestCredentialsSendingMethodButton(string $sendingMethodId): string
1455 {
1456 return '<div class="cell grid-x margin-top-1 acym__sending__methods__credentials__test">
1457 <button type="button" sending-method-id="'.acym_escape($sendingMethodId).'" class="acym__configuration__sending__method-test cell shrink button button-secondary">
1458 '.acym_translation('ACYM_TEST_CREDENTIALS').'
1459 </button>
1460 <span class="acym__configuration__sending__method-icon cell shrink margin-left-1 acym_vcenter"></span>
1461 <span class="acym__configuration__sending__method-test__message cell shrink margin-left-1 acym_vcenter"></span>
1462 </div>';
1463 }
1464
1465 public function getCopySettingsButton(array $data, string $sendingMethodId, string $fromPlugin, bool $withContainer = true): string
1466 {
1467 if (empty($data[$fromPlugin.'_installed'])) {
1468 return '';
1469 }
1470
1471 $button = '<button
1472 type="button"
1473 class="cell shrink button button-secondary acym__configuration__copy__mail__settings"
1474 acym-data-plugin="'.acym_escape($fromPlugin).'"
1475 acym-data-method="'.acym_escape($sendingMethodId).'">
1476 '.acym_translationSprintf('ACYM_COPY_SETTINGS_FROM', $this->sendingPlugins[$fromPlugin]).'
1477 </button>
1478 <span class="acym__configuration__sending__method-icon cell shrink margin-left-1 acym_vcenter"></span>';
1479
1480 if ($withContainer) {
1481 $button = '<div class="cell grid-x margin-top-1">'.$button.'</div>';
1482 }
1483
1484 return $button;
1485 }
1486
1487 protected function getLinks(string $account = '', string $pricing = ''): string
1488 {
1489 if (empty($account) && empty($pricing)) return '';
1490
1491 $html = '<div class="cell grid-x acym-grid-margin-x shrink acym_vcenter"><p class="cell shrink">'.acym_translation('ACYM_DONT_HAVE_ACCOUNT').'</p>';
1492 if (!empty($account)) $html .= '<a target="_blank" class="cell shrink" href="'.$account.'">'.acym_translation('ACYM_CREATE_ONE').'</a>';
1493 if (!empty($account) && !empty($pricing)) $html .= '<p class="cell shrink">'.strtolower(acym_translation('ACYM_OR')).'</p>';
1494 if (!empty($pricing)) $html .= '<a target="_blank" class="cell shrink" href="'.$pricing.'">'.acym_translation('ACYM_CHECK_THEIR_PRICING').'</a>';
1495 $html .= '</div>';
1496
1497 return $html;
1498 }
1499
1500 public function onAcymGetSendingMethodsSelected(array &$data): void
1501 {
1502 if (ACYM_CMS === 'wordpress') {
1503 $this->config->load();
1504 }
1505
1506 $mailerMethod = $this->config->get('mailer_method', 'phpmail');
1507 foreach ($data['sendingMethods'] as $key => $sendingMethod) {
1508 $data['sendingMethods'][$key]['selected'] = $key == $mailerMethod;
1509 }
1510 }
1511
1512 public function errorCallback(): void
1513 {
1514 foreach ($this->errors as $error) {
1515 acym_logError($error, empty($this->name) ? get_class($this) : $this->name);
1516 }
1517
1518 $this->errors = [];
1519 }
1520
1521 public function isLogFileEmpty(): bool
1522 {
1523 return !acym_isLogFileErrorExist(empty($this->name) ? get_class($this) : $this->name);
1524 }
1525
1526 public function initCustomView(bool $customFields = false): void
1527 {
1528 $page = acym_getVar('cmd', 'page');
1529 if (is_array($page)) return;
1530 if (!empty($page) && is_string($page)) {
1531 $page = str_replace(ACYM_COMPONENT.'_', '', $page);
1532 }
1533 $ctrl = acym_getVar('cmd', 'ctrl', $page);
1534 if (!in_array($ctrl, ['plugins', 'dynamics'])) return;
1535
1536 $task = acym_getVar('cmd', 'task', 'installed');
1537
1538 if (($ctrl === 'plugins' && $task === 'installed') || ($this->active && $ctrl === 'dynamics' && $task === 'trigger')) {
1539 $this->initElementOptionsCustomView();
1540 $this->initReplaceOptionsCustomView();
1541 if ($customFields) $this->initCustomOptionsCustomView();
1542 }
1543 }
1544
1545 public function processDateToCheck(array $options): \DateTime
1546 {
1547 $dateNowWithTimeZone = acym_date('now', 'Y-m-d h:i:s');
1548 $dateToCheck = new \DateTime($dateNowWithTimeZone);
1549 $interval = new \DateInterval('P'.intval($options['days']).'D');
1550 if ($options['relative'] === 'before') {
1551 $dateToCheck->add($interval);
1552 } else {
1553 $dateToCheck->sub($interval);
1554 }
1555
1556 return $dateToCheck;
1557 }
1558
1559 public function onAcymCheckInstalled(bool &$installed): void
1560 {
1561 $installed = $this->installed;
1562 }
1563
1564 protected function getLinkTranslated(string $link): string
1565 {
1566 if (empty($this->emailLanguage)) return $link;
1567 if (!acym_isMultilingual()) return $link;
1568
1569 $translationTool = $this->config->get('translate_content', 'no');
1570 if ($translationTool !== 'wpml') return $link;
1571
1572 if (!acym_isExtensionActive('sitepress-multilingual-cms/sitepress.php')) return $link;
1573
1574 $languageCode = substr($this->emailLanguage, 0, 2);
1575
1576 return apply_filters('wpml_permalink', $link, $languageCode);
1577 }
1578
1579 protected function replaceShortcode(string $content): string
1580 {
1581 $content = do_shortcode($content);
1582
1583 return preg_replace('#<!-- wp:shortcode -->(.*)<!-- /wp:shortcode -->#Uis', '$1', $content);
1584 }
1585
1586 protected function fixDivStructure(string $text): string
1587 {
1588 $nbOpeningDivs = substr_count($text, '<div');
1589 $nbClosingDivs = substr_count($text, '</div>');
1590
1591 if ($nbOpeningDivs > $nbClosingDivs) {
1592 $text .= str_repeat('</div>', $nbOpeningDivs - $nbClosingDivs);
1593 } elseif ($nbOpeningDivs < $nbClosingDivs) {
1594 $text = str_repeat('<div>', $nbClosingDivs - $nbOpeningDivs).$text;
1595 }
1596
1597 return $text;
1598 }
1599
1600 protected function getBounceAddress(object $mailerHelper): string
1601 {
1602 if (method_exists($mailerHelper, 'getSendSettings')) {
1603 return $mailerHelper->getSendSettings('bounce_email');
1604 } else {
1605 return $this->config->get('bounce_email');
1606 }
1607 }
1608 }
1609