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