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/Core/AcymController.php +129 -61 10.0.1 → 11.1.0 View file →
@@ -1,10 +1,8 @@
1 1 <?php
2 2
3 3 namespace AcyMailing\Core;
4 4
5 -use AcyMailing\Helpers\HeaderHelper;
6 -
7 5 abstract class AcymController extends AcymObject
8 6 {
9 7 private $currentClass = null;
10 8 private string $sessionName;
@@ -25,14 +23,19 @@
25 23 parent::__construct();
26 24
27 25 $classname = get_class($this);
28 26 $classname = substr($classname, strrpos($classname, '\\') + 1);
29 - $ctrlpos = strpos($classname, 'Controller');
30 - $this->name = strtolower(substr($classname, 0, $ctrlpos));
27 + $this->name = strtolower(
28 + substr(
29 + $classname,
30 + 0,
31 + strpos($classname, 'Controller')
32 + )
33 + );
31 34
32 35 $currentClassName = 'AcyMailing\\Classes\\'.rtrim(ucfirst(str_replace(['Front', 'front'], '', $this->name)), 's').'Class';
33 36 if (class_exists($currentClassName)) {
34 - $this->currentClass = new $currentClassName;
37 + $this->currentClass = new $currentClassName();
35 38 }
36 39 $this->sessionName = 'acym_filters_'.$this->name;
37 40 $this->taskCalled = acym_getVar('string', 'task', '');
38 41
@@ -38,73 +41,98 @@
38 41
39 42 $this->breadcrumb['AcyMailing'] = acym_completeLink('dashboard');
40 43 }
41 44
42 - private function initSession()
45 + private function initSession(): void
43 46 {
44 - acym_session();
45 - if (empty($_SESSION[$this->sessionName])) {
46 - $_SESSION[$this->sessionName] = [];
47 + $controllerSession = acym_getVar('array', $this->sessionName, [], 'SESSION');
48 + if (empty($controllerSession)) {
49 + acym_setSession($this->sessionName, []);
47 50 }
48 51 }
49 52
50 - public function getVarFiltersListing($type, $varName, $default, $overrideIfNull = false)
53 + /**
54 + * @param mixed $default
55 + *
56 + * @return mixed
57 + */
58 + public function getVarFiltersListing(string $type, string $varName, $default, bool $overrideIfNull = false)
51 59 {
52 - if ($this->taskCalled == 'clearFilters') return $default;
60 + if ($this->taskCalled === 'clearFilters') {
61 + return $default;
62 + }
53 63
54 64 $this->initSession();
55 - $returnValue = acym_getVar($type, $varName);
56 65
57 - if (is_null($returnValue) && $overrideIfNull) $returnValue = $default;
66 + $isVarInRequest = !is_null(acym_getVar('raw', $varName, null, '', ACYM_ALLOWRAW));
67 + $returnValue = $isVarInRequest ? acym_getVar($type, $varName) : null;
58 68
69 + if (is_null($returnValue) && $overrideIfNull) {
70 + $returnValue = $default;
71 + }
72 +
59 73 if (!is_null($returnValue)) {
60 - $_SESSION[$this->sessionName][$varName] = $returnValue;
74 + $controllerSession = acym_getVar('array', $this->sessionName, [], 'SESSION');
75 + $controllerSession[$varName] = $returnValue;
76 + acym_setSession($this->sessionName, $controllerSession);
61 77
62 78 return $returnValue;
63 79 }
64 80
65 - if (!empty($_SESSION[$this->sessionName][$varName])) {
66 - return $_SESSION[$this->sessionName][$varName];
81 + $filters = acym_getVar('array', $this->sessionName, [], 'SESSION');
82 + if (!empty($filters[$varName])) {
83 + return $filters[$varName];
67 84 }
68 85
69 86 return $default;
70 87 }
71 88
72 - public function setVarFiltersListing($varName, $value)
89 + public function setVarFiltersListing(string $varName, int $value): void
73 90 {
74 91 acym_setVar($varName, $value);
75 92 $this->initSession();
76 - $_SESSION[$this->sessionName][$varName] = $value;
93 + $controllerSession = acym_getVar('array', $this->sessionName, [], 'SESSION');
94 + $controllerSession[$varName] = $value;
95 + acym_setSession($this->sessionName, $controllerSession);
77 96 }
78 97
79 - public function clearFilters()
98 + /**
99 + * Called using data-task
100 + */
101 + public function clearFilters(): void
80 102 {
81 - $this->initSession();
82 - $_SESSION[$this->sessionName] = [];
103 + acym_setSession($this->sessionName, []);
83 104
84 105 $taskToCall = acym_getVar('string', 'cleartask', $this->defaulttask);
85 - $this->call($taskToCall);
106 + if (in_array($taskToCall, ['campaigns_auto', 'welcome', 'unsubscribe', $this->defaulttask])) {
107 + $this->call($taskToCall);
108 + }
86 109 }
87 110
88 - public function call($task)
111 + public function call(string $task, bool $isFront = false): void
89 112 {
90 - if (!in_array($task, ['countResultsTotal', 'countGlobalBySegmentId', 'countResults']) && strpos($task, 'Ajax') === false && !acym_isAllowed($this->name, $task)) {
113 + if (
114 + !in_array($task, $this->publicFrontTasks, true)
115 + && !acym_isAllowed($this->name, $task)
116 + ) {
91 117 acym_enqueueMessage(acym_translation('ACYM_ACCESS_DENIED'), 'warning');
92 - acym_redirect(acym_completeLink('dashboard'));
118 + acym_redirect($isFront ? ACYM_LIVE : acym_completeLink('dashboard'));
93 119
94 120 return;
95 121 }
96 122
97 - if (!method_exists($this, $task)) {
123 + // If task doesn't exist, redirect to default task + add message
124 + if (!is_callable([$this, $task])) {
98 125 acym_enqueueMessage(acym_translation('ACYM_NON_EXISTING_PAGE'), 'warning');
99 126 $task = $this->defaulttask;
100 127 acym_setVar('task', $task);
101 128 }
102 129
130 + // Call the task
103 131 $this->$task();
104 132 }
105 133
106 - public function loadScripts($task)
134 + public function loadScripts(string $task): void
107 135 {
108 136 if (empty($this->loadScripts)) return;
109 137
110 138 $scripts = [];
@@ -121,8 +149,16 @@
121 149 if (in_array('editor-wysid', $scripts)) {
122 150 acym_addStyle(false, ACYM_CSS.'editorWYSID.min.css?v='.filemtime(ACYM_MEDIA.'css'.DS.'editorWYSID.min.css'));
123 151 acym_addScript(false, ACYM_JS.'editor_wysid_utils.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'editor_wysid_utils.min.js'));
124 152
153 + acym_addScript(
154 + true,
155 + 'const ACYM_UNSPLASH_KEY = "'.addslashes($this->config->get('unsplash_key', '')).'";
156 + const ACYM_GIPHY_KEY = "'.addslashes($this->config->get('giphy_key', '')).'";
157 + const ACYM_SAVE_THUMBNAIL = '.(acym_isAdmin() ? (int)$this->config->get('save_thumbnail', 0) : 0).';'
158 + );
159 +
160 + // Automatically add editor dependencies
125 161 $scripts = array_merge($scripts, ['colorpicker', 'datepicker', 'thumbnail', 'foundation-email', 'parse-css', 'vue-prism-editor', 'masonry']);
126 162
127 163 if (empty($scripts['vue-applications'])) {
128 164 $scripts['vue-applications'] = ['code_editor'];
@@ -140,12 +176,14 @@
140 176 acym_addStyle(false, ACYM_CSS.'libraries/spectrum.min.css?v='.filemtime(ACYM_MEDIA.'css'.DS.'libraries'.DS.'spectrum.min.css'));
141 177 }
142 178
143 179 if (in_array('datepicker', $scripts)) {
144 - acym_addScript(false, ACYM_JS.'libraries/moment.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'moment.min.js'));
145 - acym_addScript(false, ACYM_JS.'libraries/rome.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'rome.min.js'));
146 - acym_addScript(false, ACYM_JS.'libraries/material-datetime-picker.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'material-datetime-picker.min.js'));
147 - acym_addStyle(false, ACYM_CSS.'libraries/material-datetime-picker.min.css?v='.filemtime(ACYM_MEDIA.'css'.DS.'libraries'.DS.'material-datetime-picker.min.css'));
180 + if (ACYM_CMS === 'joomla') {
181 + acym_addScript(false, ACYM_JS.'libraries/moment.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'moment.min.js'));
182 + } else {
183 + wp_enqueue_script('moment');
184 + }
185 + acym_addScript(true, 'window.ACYM_DATE_NOW = "'.gmdate('Y-m-d\TH:i', time() + acym_getTimeOffsetCMS()).'";');
148 186 }
149 187
150 188 if (in_array('dtextPicker', $scripts)) {
151 189 acym_addScript(false, ACYM_JS.'dtext_picker.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'dtext_picker.min.js'));
@@ -169,10 +207,12 @@
169 207 acym_addScript(false, ACYM_JS.'libraries/masonry.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'masonry.min.js'));
170 208 }
171 209
172 210 if (!empty($scripts['vue-applications'])) {
211 + //vuejs javascript library
173 212 acym_addScript(false, ACYM_JS.'libraries/vuejs.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'vuejs.min.js'));
174 213 acym_addScript(false, ACYM_JS.'libraries/vue-infinite-scroll.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'vue-infinite-scroll.min.js'));
214 + //All the component created to use in vue app (ex: select2 component)
175 215 acym_addScript(false, ACYM_JS.'vue/vue_components.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'vue'.DS.'vue_components.min.js'));
176 216 foreach ($scripts['vue-applications'] as $script) {
177 217 acym_addScript(false, ACYM_JS.'vue/'.$script.'.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'vue'.DS.$script.'.min.js'));
178 218 }
@@ -195,14 +235,13 @@
195 235 {
196 236 return $this->name;
197 237 }
198 238
199 - public function display($data = [])
239 + public function display(array $data = []): void
200 240 {
201 241 if (acym_isAdmin()) {
202 242 if (!acym_isNoTemplate()) {
203 - $header = new HeaderHelper();
204 - $data['header'] = $header->display($this->breadcrumb);
243 + $data['breadcrumb'] = $this->breadcrumb;
205 244 }
206 245 $viewNamespace = 'AcyMailing\\Views\\';
207 246 } else {
208 247 $viewNamespace = 'AcyMailing\\FrontViews\\';
@@ -209,19 +248,22 @@
209 248 }
210 249
211 250 $viewName = ucfirst($this->getName());
212 251 $viewNamespace .= $viewName.'\\'.$viewName.'View';
213 - $view = new $viewNamespace;
252 + $view = new $viewNamespace();
214 253 $view->display($this, $data);
215 254 }
216 255
217 - public function cancel()
256 + /**
257 + * Called using data-task
258 + */
259 + public function cancel(): void
218 260 {
219 261 acym_setVar('layout', 'listing');
220 262 $this->display();
221 263 }
222 264
223 - public function listing()
265 + public function listing(): void
224 266 {
225 267 acym_setVar('layout', 'listing');
226 268
227 269 $this->display();
@@ -226,14 +268,13 @@
226 268
227 269 $this->display();
228 270 }
229 271
230 - public function edit()
272 + public function edit(): void
231 273 {
232 274 $nextstep = acym_getVar('string', 'nextstep', '');
233 - $step = acym_getVar('string', 'step', '');
234 275 if (empty($nextstep)) {
235 - $nextstep = $step;
276 + $nextstep = acym_getVar('string', 'step', '');
236 277 }
237 278
238 279 if (empty($nextstep)) {
239 280 acym_setVar('layout', 'edit');
@@ -239,30 +280,39 @@
239 280 acym_setVar('layout', 'edit');
240 281
241 282 $this->display();
242 283 } else {
284 + if (!is_callable([$this, $nextstep])) {
285 + acym_enqueueMessage(acym_translation('ACYM_NON_EXISTING_PAGE'), 'warning');
286 + $this->listing();
287 +
288 + return;
289 + }
290 +
243 291 acym_setVar('step', $nextstep);
244 292
245 - return $this->$nextstep();
293 + $this->$nextstep();
246 294 }
247 295 }
248 296
249 - public function apply()
297 + public function apply(): void
250 298 {
251 - $this->store();
299 + if (method_exists($this, 'store')) {
300 + $this->store();
301 + }
252 302
253 - return $this->edit();
303 + $this->edit();
254 304 }
255 305
256 - public function add()
306 + public function add(): void
257 307 {
258 308 acym_setVar('cid', []);
259 309 acym_setVar('layout', 'form');
260 310
261 - return $this->display();
311 + $this->display();
262 312 }
263 313
264 - public function save()
314 + public function save(): void
265 315 {
266 316 $step = acym_getVar('string', 'step', '');
267 317
268 318 if (!empty($step)) {
@@ -267,22 +317,26 @@
267 317
268 318 if (!empty($step)) {
269 319 $saveMethod = 'save'.ucfirst($step);
270 320 if (!method_exists($this, $saveMethod)) {
271 - die('Save method '.acym_escape($saveMethod).' not found');
321 + die('Save method '.esc_html($saveMethod).' not found');
272 322 }
273 323
274 - return $this->$saveMethod();
324 + $this->$saveMethod();
325 +
326 + return;
275 327 }
276 328
277 - if (method_exists($this, 'store')) $this->store();
329 + if (method_exists($this, 'store')) {
330 + $this->store();
331 + }
278 332
279 - return $this->listing();
333 + $this->listing();
280 334 }
281 335
282 - public function delete()
336 + public function delete(): void
283 337 {
284 - acym_checkToken();
338 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
285 339 $ids = acym_getVar('array', 'elements_checked', []);
286 340 $allChecked = acym_getVar('string', 'checkbox_all');
287 341 $currentPage = explode('_', acym_getVar('string', 'page', ''));
288 342 $pageNumber = $this->getVarFiltersListing('int', end($currentPage).'_pagination_page', 1);
@@ -288,19 +342,21 @@
288 342 $pageNumber = $this->getVarFiltersListing('int', end($currentPage).'_pagination_page', 1);
289 343
290 344 if (!empty($ids) && !empty($this->currentClass)) {
291 345 $this->currentClass->delete($ids);
292 - if ($allChecked == 'on') {
346 + if ($allChecked === 'on') {
293 347 $this->setVarFiltersListing(end($currentPage).'_pagination_page', $pageNumber - 1);
294 348 }
295 349 }
296 350
297 - if (!acym_getVar('bool', 'no_listing', false)) $this->listing();
351 + if (!acym_getVar('bool', 'no_listing', false)) {
352 + $this->listing();
353 + }
298 354 }
299 355
300 - public function setActive()
356 + public function setActive(): void
301 357 {
302 - acym_checkToken();
358 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
303 359 $ids = acym_getVar('array', 'elements_checked', []);
304 360
305 361 if (!empty($ids) && !empty($this->currentClass)) {
306 362 $this->currentClass->setActive($ids);
@@ -308,11 +364,11 @@
308 364
309 365 $this->listing();
310 366 }
311 367
312 - public function setInactive()
368 + public function setInactive(): void
313 369 {
314 - acym_checkToken();
370 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
315 371 $ids = acym_getVar('array', 'elements_checked', []);
316 372
317 373 if (!empty($ids) && !empty($this->currentClass)) {
318 374 $this->currentClass->setInactive($ids);
@@ -320,14 +376,15 @@
320 376
321 377 $this->listing();
322 378 }
323 379
324 - public function getMatchingElementsFromData($requestData, &$status, &$page, $class = '')
380 + public function getMatchingElementsFromData(array $requestData, string &$status, int &$page, string $class = ''): array
325 381 {
326 382 $className = 'AcyMailing\\Classes\\'.ucfirst(strtolower($class)).'Class';
327 383 $classElement = empty($class) ? $this->currentClass : new $className();
328 384 $matchingElement = $classElement->getMatchingElements($requestData);
329 385
386 + // No result and no search used, we revert to default listing (all)
330 387 if (empty($matchingElement['elements'])) {
331 388 if (!empty($status) && empty($requestData['search']) && empty($requestData['tag'])) {
332 389 $status = '';
333 390 $requestData['status'] = $status;
@@ -340,13 +397,19 @@
340 397
341 398 $matchingElement = $classElement->getMatchingElements($requestData);
342 399 }
343 400
401 + $matchingElement['total']->total = intval($matchingElement['total']->total);
402 +
344 403 return $matchingElement;
345 404 }
346 405
406 + /**
407 + * Used in front/acym.php
408 + */
347 409 public function checkTaskFront(string $task = ''): void
348 410 {
411 + // For cron tasks created by users on their own server, for Joomla 4
349 412 if ($this->getName() === 'cron') {
350 413 $task = 'cron';
351 414 }
352 415
@@ -353,8 +416,9 @@
353 416 if (empty($task) && !empty($this->defaulttask)) {
354 417 $task = $this->defaulttask;
355 418 }
356 419
420 + // Handle whitelisted tasks
357 421 if (in_array($task, $this->publicFrontTasks)) {
358 422 $this->$task();
359 423
360 424 return;
@@ -359,17 +423,20 @@
359 423
360 424 return;
361 425 }
362 426
427 + // No front-end management for WordPress users
363 428 if (empty(acym_currentUserId()) || ACYM_CMS !== 'joomla' || !acym_level(ACYM_ENTERPRISE)) {
364 429 acym_redirect(acym_rootURI(), 'Front-end management not available');
365 430 }
366 431
432 + // If there is no menu, someone typed the URL manually
367 433 $currentMenu = acym_getMenu();
368 434 if (empty($currentMenu)) {
369 435 acym_redirect(acym_rootURI(), 'Direct access denied');
370 436 }
371 437
438 + // We whitelist specific routes when having access to specific menus
372 439 if ($this->isTaskAllowed($currentMenu->link, $task)) {
373 440 $this->$task();
374 441
375 442 return;
@@ -374,8 +441,9 @@
374 441
375 442 return;
376 443 }
377 444
445 + // Blacklist tasks by default
378 446 acym_redirect(acym_rootURI(), 'Unknown route, access denied');
379 447 }
380 448
381 449 private function isTaskAllowed(string $menuUrl, string $task): bool
@@ -392,9 +460,9 @@
392 460
393 461 return false;
394 462 }
395 463
396 - protected function prepareMultilingualOption(&$data)
464 + protected function prepareMultilingualOption(array &$data): void
397 465 {
398 466 if (!acym_isMultilingual()) return;
399 467
400 468 $data['translation_languages'] = acym_getMultilingualLanguages();