PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
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/Helpers/EditorHelper.php +417 -0 11.1.1 → 11.1.0 View file →
@@ -1,0 +1,417 @@
1 +<?php
2 +
3 +namespace AcyMailing\Helpers;
4 +
5 +use AcyMailing\Classes\MailClass;
6 +use AcyMailing\Classes\ZoneClass;
7 +use AcyMailing\Core\AcymObject;
8 +use AcyMailing\Types\DtextType;
9 +use Joomla\CMS\Editor\Editor as Editor;
10 +use Joomla\CMS\Factory;
11 +
12 +class EditorHelper extends AcymObject
13 +{
14 + private string $width = '95%';
15 + private string $height = '600';
16 +
17 + private int $cols = 100;
18 + private int $rows = 30;
19 +
20 + private $myEditor;
21 + public string $editor = '';
22 +
23 + private string $editorContent = '';
24 + private array $editorConfig = [];
25 + private array $emailsTest;
26 + private string $name = 'editor_content';
27 +
28 + public string $settings = 'editor_settings';
29 + public string $stylesheet = 'editor_stylesheet';
30 + public string $content = '';
31 + public int $mailId = 0;
32 + public bool $automation = false;
33 + public bool $walkThrough = false;
34 +
35 + // Used in the d&d
36 + public array $data = [];
37 + private string $defaultTemplate = '';
38 +
39 + public string $autoSave;
40 +
41 + public function display(): void
42 + {
43 + if ($this->isDragAndDrop()) {
44 + ob_start();
45 + include acym_getPartial('editor', 'default_template');
46 + $this->defaultTemplate = ob_get_clean();
47 +
48 + acym_disableCmsEditor();
49 + $currentEmail = acym_currentUserEmail();
50 + $this->emailsTest = [$currentEmail => $currentEmail];
51 + acym_addScript(false, ACYM_JS.'tinymce/tinymce.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'tinymce/tinymce.min.js'));
52 +
53 + $data = $this->data;
54 + $mailId = empty($data['mail']->mail_id) ? (empty($data['mail']->id) ? 0 : $data['mail']->id) : $data['mail']->mail_id;
55 + $data['tabHelper'] = new TabHelper();
56 + $data['plugins'] = acym_trigger('dynamicText', [$mailId]);
57 + usort(
58 + $data['plugins'],
59 + function ($a, $b) {
60 + return strtolower($a->name ?? '') > strtolower($b->name ?? '') ? 1 : -1;
61 + }
62 + );
63 +
64 + $zoneClass = new ZoneClass();
65 + $data['custom_zones'] = $zoneClass->getAll();
66 + usort($data['custom_zones'], function ($a, $b) {
67 + return strtolower($a->name) > strtolower($b->name) ? 1 : -1;
68 + });
69 +
70 + acym_setVar('mail_id', $mailId);
71 + acym_setVar('mail_type', empty($data['mail']->type) ? '' : $data['mail']->type);
72 + acym_setVar('automation', $this->automation ? 1 : 0);
73 +
74 + include acym_getPartial('editor', 'editor_wysid');
75 + } else {
76 + // Outside of the Acy wrapper to prevent foundation from breaking the 100 different editors we could have here
77 +
78 + // Close acym_content div
79 + if (acym_isLeftMenuNecessary()) echo '</div>';
80 +
81 + // Close acym_wrapper div and open the no foundation div
82 + echo '</div><div class="acym_no_foundation">';
83 +
84 + // Display the editor
85 + $dtextType = new DtextType();
86 + $dtextType->display(['withButton' => false]);
87 +
88 + $method = 'displayWordPress';
89 + $this->$method();
90 +
91 + // The view renderer will close the acym_content div, but since we already closed it, we open a fake one
92 + if (acym_isLeftMenuNecessary()) echo '<div>';
93 + // The view renderer will close the acym_wrapper div, which will be the acym_no_foundation div in this case
94 + }
95 + }
96 +
97 + public function isDragAndDrop(): bool
98 + {
99 + return strpos($this->content, 'acym__wysid__template') !== false || $this->editor === 'acyEditor';
100 + }
101 +
102 + private function displayJoomla(): void
103 + {
104 + $dtextType = new DtextType();
105 + $dtextType->displayButton(
106 + [
107 + 'icon' => 'acymicon-chevrons',
108 + 'text' => acym_translation('ACYM_INSERT_DYNAMIC_TEXT'),
109 + 'class' => 'button button-secondary margin-bottom-0 margin-top-1',
110 + ]
111 + );
112 +
113 + $this->editor = acym_getCMSConfig('editor', 'tinymce');
114 +
115 + if (!class_exists('Joomla\CMS\Editor\Editor')) {
116 + $this->myEditor = Factory::getEditor($this->editor);
117 + } else {
118 + $this->myEditor = Editor::getInstance($this->editor);
119 + }
120 + $this->myEditor->initialise();
121 +
122 + // We allow the background parameter on tr,table and td.
123 + $this->editorConfig['extended_elements'] = 'table[background|cellspacing|cellpadding|width|align|bgcolor|border|style|class|id],tr[background|width|bgcolor|style|class|id|valign],td[background|width|align|bgcolor|valign|colspan|rowspan|height|style|class|id|nowrap]';
124 +
125 + if (!empty($this->mailId)) {
126 + //Load Css editor
127 + $cssurl = acym_completeLink((acym_isAdmin() ? '' : 'front').'mails&task=loadCSS&id='.$this->mailId.'&time='.time());
128 + $classMail = new MailClass();
129 + $filepath = $classMail->createTemplateFile($this->mailId);
130 +
131 + if ($this->editor === 'tinymce') {
132 + $this->editorConfig['content_css_custom'] = $cssurl.'&local=http';
133 + $this->editorConfig['content_css'] = '0';
134 +
135 + // We disable this for Joomla 4 because it might do a fatal due to Joomla 4 TinyMCE params not well formatted
136 + if (!ACYM_J40) {
137 + // Joomla broke the custom css feature in the v3.9.21 so we have to do this
138 + $access = [];
139 + for ($i = 1; $i < 20; $i++) {
140 + $access[] = $i;
141 + }
142 +
143 + $this->editorConfig['configuration'] = (object)[
144 + 'toolbars' => (object)['AcyCustomCSS' => []],
145 + 'setoptions' => [
146 + 'AcyCustomCSS' => (object)[
147 + 'access' => $access,
148 + 'content_css' => '0',
149 + 'content_css_custom' => $cssurl.'&local=http',
150 + ],
151 + ],
152 + ];
153 + }
154 + } elseif ($this->editor === 'jckeditor' || $this->editor === 'fckeditor') {
155 + //For jckeditor, we need to create a fake template.css file... lets do that on the template/css/folder
156 + $this->editorConfig['content_css_custom'] = $filepath;
157 + $this->editorConfig['content_css'] = '0';
158 + $this->editorConfig['editor_css'] = '0';
159 + } else {
160 + //We still create the file so that the user can link to it manually
161 + $fileurl = str_replace(DS, '/', ACYM_MEDIA_FOLDER).'templates/css/template_'.$this->mailId.'.css?time='.time();
162 + $this->editorConfig['custom_css_url'] = $cssurl;
163 + $this->editorConfig['custom_css_file'] = $fileurl;
164 + $this->editorConfig['custom_css_path'] = $filepath;
165 +
166 + // Can be useful for JCE integration for example
167 + if (!empty($filepath)) {
168 + acym_setVar('acycssfile', $fileurl);
169 + }
170 + }
171 + }
172 +
173 + // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- Displaying the CMS editor, cannot be escaped. For Joomla editors.
174 + if (empty($this->editorContent)) {
175 + $this->content = esc_html($this->content);
176 + ob_start();
177 +
178 + echo $this->myEditor->display(
179 + $this->name,
180 + $this->content,
181 + $this->width,
182 + $this->height,
183 + $this->cols,
184 + $this->rows,
185 + ['pagebreak', 'readmore'],
186 + null,
187 + 'com_content',
188 + null,
189 + $this->editorConfig
190 + );
191 +
192 + $this->editorContent = ob_get_clean();
193 + }
194 +
195 + if (method_exists($this->myEditor, 'save')) {
196 + acym_addScript(true, 'function acyOnSaveEditor(){'.$this->myEditor->save($this->name).'}');
197 + }
198 +
199 + echo $this->editorContent;
200 + // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
201 + }
202 +
203 + private function displayWordPress(): void
204 + {
205 + add_filter('mce_external_plugins', [$this, 'addPlugins']);
206 + add_filter('mce_buttons', [$this, 'addButtons']);
207 + add_filter('mce_buttons_2', [$this, 'addButtonsToolbar']);
208 + add_action('media_buttons', [$this, 'addDtextButton']);
209 +
210 + $mailClass = new MailClass();
211 +
212 + $mail = $mailClass->getOneById($this->mailId);
213 + $stylesheet = empty($mail) ? '' : trim(preg_replace('/\s\s+/', ' ', $mailClass->buildCSS($mail->stylesheet)));
214 + $stylesheet = str_replace(['"', "\r\n", "\n"], ['\"', '', ''], $stylesheet);
215 +
216 + $options = [
217 + 'editor_css' => '<style type="text/css">
218 + .alignleft{float:left;margin:0.5em 1em 0.5em 0;}
219 + .aligncenter{display: block;margin-left: auto;margin-right: auto;}
220 + .alignright{float: right;margin: 0.5em 0 0.5em 1em;}
221 + </style>',
222 + 'editor_height' => $this->height,
223 + 'textarea_rows' => $this->rows,
224 + 'wpautop' => false,
225 + 'tinymce' => [
226 + 'content_css' => '',
227 + 'content_style' => '.alignleft{float:left;margin:0.5em 1em 0.5em 0;} .aligncenter{display: block;margin-left: auto;margin-right: auto;} .alignright{float: right;margin: 0.5em 0 0.5em 1em;}'.$stylesheet,
228 + ],
229 + ];
230 +
231 + wp_editor($this->content, $this->name, $options);
232 + }
233 +
234 + public function addDtextButton(string $editor_id = 'content'): void
235 + {
236 + static $instance = 0;
237 + ++$instance;
238 +
239 + printf(
240 + '<button type="button" class="button" id="acym__dtext__button" data-editor="%s"><i class="acymicon-chevrons"></i> %s</button>',
241 + esc_attr($editor_id),
242 + esc_html(acym_translation('ACYM_INSERT_DYNAMIC_TEXT'))
243 + );
244 + }
245 +
246 + // Used in partial editor
247 + private function getWYSIDSettings(): string
248 + {
249 + $ctrl = acym_getVar('string', 'ctrl');
250 + if ($this->isResetCampaign() || !in_array($ctrl, ['dashboard', 'mails', 'campaigns', 'frontmails', 'frontcampaigns'])) {
251 + return '{}';
252 + }
253 +
254 + $mailId = acym_getVar('int', 'from', 0);
255 + if (empty($mailId)) {
256 + if ($this->settings !== 'editor_settings') {
257 + return $this->settings;
258 + }
259 +
260 + $mailId = acym_getVar('int', 'id');
261 + $campaignId = acym_getVar('int', 'campaignId');
262 + if (!empty($campaignId) && $ctrl === 'campaigns') {
263 + $mailId = acym_loadResult('SELECT mail_id FROM #__acym_campaign WHERE id = '.intval($campaignId));
264 + }
265 +
266 + if (empty($mailId)) {
267 + return '{}';
268 + }
269 + }
270 +
271 + $settings = acym_loadResult('SELECT settings FROM #__acym_mail WHERE id = '.intval($mailId));
272 +
273 + return empty($settings) ? '{}' : $settings;
274 + }
275 +
276 + // Used in partial editor
277 + private function getWYSIDStylesheet(): string
278 + {
279 + $ctrl = acym_getVar('string', 'ctrl');
280 + if ($this->isResetCampaign() || !in_array($ctrl, ['mails', 'campaigns', 'frontmails', 'frontcampaigns'])) {
281 + return '';
282 + }
283 +
284 + $mailId = acym_getVar('int', 'from', 0);
285 + if (empty($mailId)) {
286 + if ($this->stylesheet !== 'editor_stylesheet') {
287 + return $this->stylesheet;
288 + }
289 +
290 + $mailId = acym_getVar('int', 'id');
291 + $campaignId = acym_getVar('int', 'campaignId');
292 + if (!empty($campaignId) && in_array($ctrl, ['campaigns', 'frontcampaigns'])) {
293 + $mailId = acym_loadResult('SELECT mail_id FROM #__acym_campaign WHERE id = '.intval($campaignId));
294 + }
295 + }
296 +
297 + $notification = acym_getVar('string', 'notification');
298 + if (!empty($mailId)) {
299 + $stylesheet = acym_loadResult('SELECT stylesheet FROM #__acym_mail WHERE id = '.intval($mailId));
300 + } elseif (!empty($notification)) {
301 + $stylesheet = acym_loadResult(
302 + 'SELECT stylesheet
303 + FROM #__acym_mail
304 + WHERE `type` = '.acym_escapeDB(MailClass::TYPE_NOTIFICATION).'
305 + AND `name` = '.acym_escapeDB($notification)
306 + );
307 + }
308 +
309 + return empty($stylesheet) ? '' : $stylesheet;
310 + }
311 +
312 + private function isResetCampaign(): bool
313 + {
314 + $fromId = acym_getVar('int', 'from', 0);
315 +
316 + return -1 === $fromId;
317 + }
318 +
319 + /**
320 + * Methods used to add buttons to the WordPress editor
321 + */
322 + private function addButtonAtPosition(array &$buttons, string $newButton, string $after): void
323 + {
324 + $position = array_search($after, $buttons);
325 +
326 + if ($position === false) {
327 + array_push($buttons, 'separator', $newButton);
328 + } else {
329 + array_splice($buttons, $position + 1, 0, $newButton);
330 + }
331 + }
332 +
333 + public function addPlugins(array $plugins): array
334 + {
335 + $plugins['table'] = ACYM_JS.'tinymce/table.min.js';
336 +
337 + return $plugins;
338 + }
339 +
340 + public function addButtons(array $buttons): array
341 + {
342 + $position = array_search('wp_more', $buttons);
343 + if ($position !== false) {
344 + $buttons[$position] = '';
345 + }
346 +
347 + array_unshift($buttons, 'separator', 'fontsizeselect');
348 + array_unshift($buttons, 'separator', 'fontselect');
349 + array_push($buttons, 'separator', 'table');
350 +
351 + $this->addButtonAtPosition($buttons, 'alignjustify', 'alignright');
352 + $this->addButtonAtPosition($buttons, 'underline', 'italic');
353 + $this->addButtonAtPosition($buttons, 'strikethrough', 'underline');
354 +
355 + return $buttons;
356 + }
357 +
358 + public function addButtonsToolbar(array $buttons): array
359 + {
360 + $position = array_search('strikethrough', $buttons);
361 + if ($position !== false) {
362 + $buttons[$position] = '';
363 + }
364 + $this->addButtonAtPosition($buttons, 'backcolor', 'forecolor');
365 +
366 + return $buttons;
367 + }
368 +
369 + public function getSettingsStyle($settings): string
370 + {
371 + if (empty($settings)) {
372 + return '';
373 + }
374 +
375 + if (is_string($settings) && substr($settings, 0, 2) === '{"') {
376 + $settings = json_decode($settings, true);
377 + }
378 +
379 + if (!is_array($settings)) {
380 + return '';
381 + }
382 +
383 + $styles = '';
384 + foreach ($settings as $element => $rules) {
385 + $values = '';
386 + foreach ($rules as $ruleName => $value) {
387 + if ($ruleName == 'overridden') continue;
388 + $values .= $ruleName.': '.$value.';';
389 + }
390 + $styles .= '#acym__wysid__template .acym__wysid__column__element__td .acym__wysid__tinymce--text '.$element.':not(.acym__wysid__content-no-settings-style){';
391 + $styles .= $values;
392 + $styles .= '}';
393 +
394 + $styles .= '#acym__wysid__template .acym__wysid__column__element__td .acymailing_content '.$element.':not(.acym__wysid__content-no-settings-style){';
395 + $styles .= $values;
396 + $styles .= '}';
397 + }
398 +
399 + return $styles;
400 + }
401 +
402 + private function getDefaultColors(): string
403 + {
404 + $mailSettings = new \stdClass();
405 + if (isset($this->data['mail']->mail_settings) && !empty($this->data['mail']->mail_settings)) {
406 + $mailSettings = json_decode($this->data['mail']->mail_settings, false);
407 + } elseif (isset($this->data['mailInformation']->mail_settings) && !empty($this->data['mailInformation']->mail_settings)) {
408 + $mailSettings = json_decode($this->data['mailInformation']->mail_settings, false);
409 + }
410 +
411 + if (!empty($mailSettings->mainColors)) {
412 + return $mailSettings->mainColors;
413 + }
414 +
415 + return '';
416 + }
417 +}