PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.6
VikBooking Hotel Booking Engine & PMS v1.8.6
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / admin / helpers / admin_widgets.php

admin_widgets.php in VikBooking Hotel Booking Engine & PMS 1.8.6, at admin/helpers/admin_widgets.php

925 lines 23.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 /**
14 * Helper class for the administrator widgets.
15 *
16 * @since 1.14 (J) - 1.4.0 (WP)
17 */
18 class VikBookingHelperAdminWidgets
19 {
20 /**
21 * The singleton instance of the class.
22 *
23 * @var VikBookingHelperAdminWidgets
24 */
25 protected static $instance = null;
26
27 /**
28 * An array to store some cached/static values.
29 *
30 * @var array
31 */
32 protected static $helper = null;
33
34 /**
35 * List of preloaded widgets.
36 *
37 * @var array
38 *
39 * @since 1.18.3 (J) - 1.8.3 (WP)
40 */
41 protected static $preloaded = [];
42
43 /**
44 * The database handler instance.
45 *
46 * @var object
47 */
48 protected $dbo;
49
50 /**
51 * The list of widget instances loaded.
52 *
53 * @var array
54 */
55 protected $widgets;
56
57 /**
58 * The list of widget positions in the multitask panel.
59 *
60 * @var array
61 *
62 * @since 1.16.10 (J) - 1.6.10 (WP)
63 */
64 protected $widgets_pos_list;
65
66 /**
67 * Class constructor is protected.
68 *
69 * @see getInstance()
70 */
71 protected function __construct()
72 {
73 static::$helper = [];
74 $this->dbo = JFactory::getDbo();
75 $this->widgets = [];
76 $this->widgets_pos_list = (array) VBOFactory::getConfig()->getArray('multitasking_wpos', []);
77 $this->load();
78 }
79
80 /**
81 * Returns the global object, either
82 * a new instance or the existing instance
83 * if the class was already instantiated.
84 *
85 * @return self A new instance of the class.
86 */
87 public static function getInstance()
88 {
89 if (is_null(static::$instance)) {
90 static::$instance = new static();
91 }
92
93 return static::$instance;
94 }
95
96 /**
97 * Loads a list of all available admin widgets.
98 *
99 * @return self
100 */
101 protected function load()
102 {
103 /** @var VBOPlatformDispatcherInterface */
104 $dispatcher = VBOFactory::getPlatform()->getDispatcher();
105
106 // require main/parent admin-widget class
107 require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'admin_widget.php');
108
109 $widgets_base = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'widgets' . DIRECTORY_SEPARATOR;
110 $widgets_files = glob($widgets_base . '*.php');
111 $widgets_banned = [];
112
113 /**
114 * Trigger event to let other plugins register additional widgets.
115 *
116 * @return array A list of supported widgets.
117 */
118 $list = $dispatcher->filter('onLoadAdminWidgets');
119
120 foreach ($list as $chunk) {
121 // merge default widget files with the returned ones
122 $widgets_files = array_merge($widgets_files, (array)$chunk);
123 }
124
125 /**
126 * Trigger event to let other plugins unregister specific widgets.
127 *
128 * @return array A list of widget identifiers to unload.
129 *
130 * @since 1.16.0 (J) - 1.6.0 (WP)
131 */
132 $unloaded = $dispatcher->filter('onUnloadAdminWidgets');
133
134 foreach ($unloaded as $chunk) {
135 // merge all the the returned ones
136 $widgets_banned = array_merge($widgets_banned, (array)$chunk);
137 }
138
139 // parse all admin widgets
140 foreach ($widgets_files as $wf) {
141 try {
142 /**
143 * Require widget class file only if available, to allow registering classes at
144 * runtime by third-party plugins without needing to have a dedicated PHP file.
145 * The widget class must obviously exist all the times, but the file must not.
146 */
147 if (is_file($wf)) {
148 require_once($wf);
149 }
150
151 // widget identifier
152 $widget_identif = basename($wf, '.php');
153
154 // check if the widget was unloaded
155 if (in_array($widget_identif, $widgets_banned)) {
156 continue;
157 }
158
159 // build widget class name
160 $classname = 'VikBookingAdminWidget' . str_replace(' ', '', ucwords(str_replace('_', ' ', $widget_identif)));
161
162 if (class_exists($classname)) {
163 // instantiate widget object
164 $widget = new $classname();
165
166 /**
167 * Call the widget's preflight method to see if it's compatible with the current environment.
168 *
169 * @since 1.16.10 (J) - 1.6.10 (WP)
170 */
171 if (!$widget->preflight()) {
172 continue;
173 }
174
175 // push the installed widget object
176 $this->widgets[] = $widget;
177 }
178 } catch (Exception $e) {
179 // do nothing
180 }
181 }
182
183 return $this;
184 }
185
186 /**
187 * Gets the default map of admin widgets.
188 *
189 * @return object the associative map of sections,
190 * containers and widgets.
191 */
192 protected function getDefaultWidgetsMap()
193 {
194 // sections container
195 $sections = [];
196
197 // build default sections
198
199 // new section
200 $section = new stdClass;
201 $section->name = 'Top';
202 $section->containers = [];
203 // start container
204 $container = new stdClass;
205 $container->size = 'medium';
206 $container->widgets = [
207 'sticky_notes',
208 'arriving_today',
209 'departing_today',
210 'check_availability',
211 'latest_events',
212 ];
213 // push container
214 array_push($section->containers, $container);
215 // start container
216 $container = new stdClass;
217 $container->size = 'small';
218 $container->widgets = [
219 'guest_messages',
220 'latest_from_guests',
221 'booking_details',
222 'visitors_counter',
223 ];
224 // push container
225 array_push($section->containers, $container);
226 // start container
227 $container = new stdClass;
228 $container->size = 'small';
229 $container->widgets = [
230 'aitools',
231 'forecast',
232 'bookings_calendar',
233 'reminders',
234 ];
235 // push container
236 array_push($section->containers, $container);
237 // push section
238 array_push($sections, $section);
239
240 // new section
241 $section = new stdClass;
242 $section->name = 'Middle';
243 $section->containers = [];
244 // start container
245 $container = new stdClass;
246 $container->size = 'full';
247 $container->widgets = [
248 'today_rooms_occupancy',
249 'weekly_bookings',
250 ];
251 // push container
252 array_push($section->containers, $container);
253 // push section
254 array_push($sections, $section);
255
256 // new section
257 $section = new stdClass;
258 $section->name = 'Middle 2';
259 $section->containers = [];
260 // start container
261 $container = new stdClass;
262 $container->size = 'small';
263 $container->widgets = [
264 'latest_events',
265 ];
266 // push container
267 array_push($section->containers, $container);
268 // start container
269 $container = new stdClass;
270 $container->size = 'small';
271 $container->widgets = [
272 'rates_flow',
273 ];
274 // push container
275 array_push($section->containers, $container);
276 // start container
277 $container = new stdClass;
278 $container->size = 'medium';
279 $container->widgets = [
280 'finance',
281 'currency_converter',
282 ];
283 // push container
284 array_push($section->containers, $container);
285 // push section
286 array_push($sections, $section);
287
288 // new section
289 $section = new stdClass;
290 $section->name = 'Bottom';
291 $section->containers = [];
292 // start container
293 $container = new stdClass;
294 $container->size = 'medium';
295 $container->widgets = [
296 'last_reservations',
297 ];
298 // push container
299 array_push($section->containers, $container);
300 // start container
301 $container = new stdClass;
302 $container->size = 'medium';
303 $container->widgets = [
304 'next_bookings',
305 ];
306 // push container
307 array_push($section->containers, $container);
308 // push section
309 array_push($sections, $section);
310
311 // new section
312 $section = new stdClass;
313 $section->name = 'Bottom 2';
314 $section->containers = [];
315 // start container
316 $container = new stdClass;
317 $container->size = 'medium';
318 $container->widgets = [
319 'orphan_dates',
320 'rooms_locked',
321 ];
322 // push container
323 array_push($section->containers, $container);
324 // start container
325 $container = new stdClass;
326 $container->size = 'medium';
327 $container->widgets = [
328 'sticky_notes',
329 ];
330 // push container
331 array_push($section->containers, $container);
332 // push section
333 array_push($sections, $section);
334
335 // compose the final map object
336 $map = new stdClass;
337 $map->sections = $sections;
338
339 return $map;
340 }
341
342 /**
343 * Gets the list of admin widgets instantiated.
344 *
345 * @return array list of admin widget objects.
346 */
347 public function getWidgets()
348 {
349 return $this->widgets;
350 }
351
352 /**
353 * Gets a single admin widget instantiated.
354 *
355 * @param string $id the widget identifier.
356 *
357 * @return mixed the admin widget object, false otherwise.
358 */
359 public function getWidget($id)
360 {
361 $id = $this->simplifyId($id);
362
363 foreach ($this->widgets as $widget) {
364 if ($widget->getIdentifier() == $id) {
365 return $widget;
366 }
367 }
368
369 return false;
370 }
371
372 /**
373 * Gets a list of sorted widget names, ids, descriptions, icons and styles.
374 * If called with pre-loading, widgets will be able to load their CSS and JS
375 * assets. Moreover, pre-loading a widget can return a watch-data object to
376 * implement the notifications scheduling of a specific widget.
377 *
378 * @param bool $preload whether to call the widget's preload method.
379 *
380 * @return array associative and sorted widgets list.
381 *
382 * @since 1.15.0 (J) - 1.5.0 (WP) added support for icons and style names.
383 * implemented widgets preloading for assets.
384 */
385 public function getWidgetNames($preload = false)
386 {
387 // containers
388 $names = [];
389 $pool = [];
390 $watch = [];
391
392 foreach ($this->widgets as $widget) {
393 // get widget details
394 $id = $widget->getIdentifier();
395 $name = $widget->getName();
396 $descr = $widget->getDescription();
397
398 if ($preload) {
399 // preload widget's CSS/JS assets (if any)
400 $watch_data = array_key_exists($id, static::$preloaded) ? static::$preloaded[$id] : $widget->preload();
401
402 if ($watch_data) {
403 // assign watching data to this widget
404 $watch[$id] = $watch_data;
405 }
406
407 // overwrite cache for the preloaded widget result
408 static::$preloaded[$id] = $watch_data;
409 }
410
411 // build widget info object
412 $wtdata = new stdClass;
413 $wtdata->id = $id;
414 $wtdata->name = $name;
415 $wtdata->descr = $descr;
416 $wtdata->icon = $widget->getIcon();
417 $wtdata->style = str_replace(array(' ', '_'), '-', $widget->getStyleName());
418 $wtdata->priority = $widget->getPriority();
419
420 // set object for sorting
421 $names[$name] = $wtdata;
422 }
423
424 // apply sorting by name
425 ksort($names);
426
427 // apply sorting by priority
428 usort($names, function($a, $b) {
429 // the higher the priority is, the higher the position will be
430 return $b->priority - $a->priority;
431 });
432
433 if ($this->widgets_pos_list) {
434 // get the custom positions list
435 $widgets_pos_list = $this->widgets_pos_list;
436 // apply custom sorting
437 usort($names, function($a, $b) use ($widgets_pos_list) {
438 $wa_id = $a->id;
439 $wb_id = $b->id;
440
441 if (($widgets_pos_list[$wa_id] ?? null) && ($widgets_pos_list[$wb_id] ?? null)) {
442 // the higher the custom position is, the lower the sorting position will be
443 return $widgets_pos_list[$wa_id] > $widgets_pos_list[$wb_id] ? 1 : -1;
444 }
445
446 return 0;
447 });
448 }
449
450 // push sorted widgets to pool
451 foreach ($names as $wtdata) {
452 $pool[] = $wtdata;
453 }
454
455 /**
456 * In case some widgets were pre-loaded for watching certain
457 * events, enqueue the watch-data list to the document.
458 */
459 if ($watch) {
460 // schedule the browser notifications watching data
461 VBONotificationScheduler::getInstance()->registerWatchData($watch);
462 }
463
464 // return the list of admin widgets
465 return $pool;
466 }
467
468 /**
469 * Gets the current or default map of admin widgets.
470 * If no map currently set, stores the default map.
471 *
472 * @return array the associative map of sections,
473 * containers and widgets.
474 */
475 public function getWidgetsMap()
476 {
477 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='admin_widgets_map';";
478 $this->dbo->setQuery($q);
479 $map = $this->dbo->loadResult();
480 if ($map) {
481 $map = json_decode($map);
482 return is_object($map) && !empty($map->sections) && is_array($map->sections) ? $map : $this->getDefaultWidgetsMap();
483 }
484
485 $default_map = $this->getDefaultWidgetsMap();
486 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('admin_widgets_map', " . $this->dbo->quote(json_encode($default_map)) . ");";
487 $this->dbo->setQuery($q);
488 $this->dbo->execute();
489
490 return $default_map;
491 }
492
493 /**
494 * Updates the map of admin widgets.
495 *
496 * @param array $sections the list of sections for the map.
497 *
498 * @return bool True on success, false otherwise.
499 */
500 public function updateWidgetsMap($sections)
501 {
502 if (!is_array($sections) || !$sections) {
503 return false;
504 }
505
506 // prepare new map object
507 $map = new stdClass;
508 $map->sections = $sections;
509
510 $q = "UPDATE `#__vikbooking_config` SET `setting`=" . $this->dbo->quote(json_encode($map)) . " WHERE `param`='admin_widgets_map';";
511 $this->dbo->setQuery($q);
512 $this->dbo->execute();
513
514 return true;
515 }
516
517 /**
518 * Restores the default admin widgets map.
519 * First it resets the settings of each widget.
520 *
521 * @return bool True on success, false otherwise.
522 */
523 public function restoreDefaultWidgetsMap()
524 {
525 foreach ($this->widgets as $widget) {
526 $widget->resetSettings();
527 }
528
529 $default_map = $this->getDefaultWidgetsMap();
530
531 return $this->updateWidgetsMap($default_map->sections);
532 }
533
534 /**
535 * Forces the rendering of a specific widget identifier.
536 *
537 * @param string $id the widget identifier.
538 * @param ?VBOMultitaskData $data optional multitask data for the widget.
539 *
540 * @return void
541 */
542 public function renderWidget($id, ?VBOMultitaskData $data = null)
543 {
544 $id = $this->simplifyId($id);
545
546 foreach ($this->widgets as $widget) {
547 if ($widget->getIdentifier() == $id) {
548 // render the requested widget
549 $widget->render($data);
550
551 // return void
552 return;
553 }
554 }
555 }
556
557 /**
558 * Maps the size identifier to a CSS class.
559 *
560 * @param string $size the container size identifier.
561 *
562 * @return string the full CSS class for the container.
563 */
564 public function getContainerCssClass($size)
565 {
566 $css_size_map = [
567 'small' => 'vbo-admin-widgets-container-small',
568 'medium' => 'vbo-admin-widgets-container-medium',
569 'large' => 'vbo-admin-widgets-container-large',
570 'full' => 'vbo-admin-widgets-container-fullwidth',
571 ];
572
573 return isset($css_size_map[$size]) ? $css_size_map[$size] : $css_size_map['full'];
574 }
575
576 /**
577 * Returns an associative array with the class names for the containers.
578 *
579 * @return array a text representation list of all sizes.
580 */
581 public function getContainerClassNames()
582 {
583 return array(
584 'full' => array(
585 'name' => JText::translate('VBO_WIDGETS_CONTFULL'),
586 'css' => $this->getContainerCssClass('full'),
587 ),
588 'large' => array(
589 'name' => JText::translate('VBO_WIDGETS_CONTLARGE'),
590 'css' => $this->getContainerCssClass('large'),
591 ),
592 'medium' => array(
593 'name' => JText::translate('VBO_WIDGETS_CONTMEDIUM'),
594 'css' => $this->getContainerCssClass('medium'),
595 ),
596 'small' => array(
597 'name' => JText::translate('VBO_WIDGETS_CONTSMALL'),
598 'css' => $this->getContainerCssClass('small'),
599 ),
600 );
601 }
602
603 /**
604 * Maps the size identifier to the corresponding name.
605 *
606 * @param string $size the container size identifier.
607 *
608 * @return string the size name for the container.
609 */
610 public function getContainerName($size)
611 {
612 $names = $this->getContainerClassNames();
613
614 return isset($names[$size]) ? $names[$size]['name'] : $names['full']['name'];
615 }
616
617 /**
618 * Many widgets may need to know some values about the rooms.
619 * This method uses the static instance of the class to cache data.
620 *
621 * @return void
622 */
623 protected function loadRoomsData()
624 {
625 if (isset(static::$helper['all_rooms_ids'])) {
626 // do not execute the same queries again
627 return;
628 }
629
630 $all_rooms_ids = [];
631 $all_rooms_units = [];
632 $all_rooms_features = [];
633 $unpublished_rooms = [];
634 $tot_rooms_units = 0;
635
636 $q = "SELECT `id`,`name`,`units`,`params`,`avail` FROM `#__vikbooking_rooms`;";
637 $this->dbo->setQuery($q);
638 $all_rooms = $this->dbo->loadAssocList();
639 if ($all_rooms) {
640 foreach ($all_rooms as $k => $r) {
641 if ($r['avail'] < 1) {
642 $unpublished_rooms[] = $r['id'];
643 } else {
644 $tot_rooms_units += $r['units'];
645 }
646 $all_rooms_ids[$r['id']] = $r['name'];
647 $all_rooms_units[$r['id']] = $r['units'];
648 $rparams = json_decode((string) $r['params'], true);
649 $all_rooms_features[$r['id']] = is_array($rparams) && array_key_exists('features', $rparams) && is_array($rparams['features']) ? $rparams['features'] : [];
650 }
651 }
652
653 // update static values
654 static::$helper['all_rooms_ids'] = $all_rooms_ids;
655 static::$helper['all_rooms_units'] = $all_rooms_units;
656 static::$helper['all_rooms_features'] = $all_rooms_features;
657 static::$helper['unpublished_rooms'] = $unpublished_rooms;
658 static::$helper['tot_rooms_units'] = $tot_rooms_units;
659 }
660
661 /**
662 * Many widgets could use this method to access cached information.
663 *
664 * @param string $key the data key identifier.
665 *
666 * @return mixed array/int on success, false otherwise.
667 */
668 public function getRoomsData($key)
669 {
670 if (empty($key)) {
671 return false;
672 }
673
674 if (!static::$helper) {
675 $this->loadRoomsData();
676 }
677
678 if (isset(static::$helper[$key])) {
679 return static::$helper[$key];
680 }
681
682 return false;
683 }
684
685 /**
686 * Helper method to load all busy real records for all rooms for dates near today.
687 * This is useful to avoid double queries in the various widgets and to get data
688 * about yesterday, today and the next week.
689 *
690 * @return array
691 *
692 * @since 1.15.2 (J) - 1.5.5 (WP) changed the way limit timestamps are calculated.
693 */
694 public function loadBusyRecordsUnclosed()
695 {
696 if (!isset(static::$helper['all_rooms_ids'])) {
697 $this->loadRoomsData();
698 }
699
700 if (isset(static::$helper['busy_records_unclosed'])) {
701 return static::$helper['busy_records_unclosed'];
702 }
703
704 // cache value and return it
705 $base_from_ts = mktime(0, 0, 0, date("n"), (date("j") - 1), date("Y"));
706 $base_end_ts = mktime(23, 59, 59, date("n"), (date("j") + 7), date("Y"));
707 static::$helper['busy_records_unclosed'] = VikBooking::loadBusyRecordsUnclosed(array_keys(static::$helper['all_rooms_ids']), $base_from_ts, $base_end_ts);
708
709 return static::$helper['busy_records_unclosed'];
710 }
711
712 /**
713 * The first time the widget's customizer is open, the welcome is displayed.
714 * Congig value >= 1 means hide the welcome text, 0 or lower means show it.
715 *
716 * @return bool
717 */
718 public function showWelcome()
719 {
720 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='admin_widgets_welcome';";
721 $this->dbo->setQuery($q);
722 $show_welcome = $this->dbo->loadResult();
723 if ($show_welcome !== null) {
724 return ((int)$show_welcome < 1);
725 }
726
727 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('admin_widgets_welcome', '0');";
728 $this->dbo->setQuery($q);
729 $this->dbo->execute();
730
731 return true;
732 }
733
734 /**
735 * Updates the status of the welcome message for the widget's customizer.
736 * Congig value >= 1 means hide the welcome text, 0 or lower means show it.
737 *
738 * @param int $val the new value to set in the configuration.
739 *
740 * @return void
741 */
742 public function updateWelcome($val)
743 {
744 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='admin_widgets_welcome';";
745 $this->dbo->setQuery($q);
746 $this->dbo->execute();
747 if ($this->dbo->getNumRows()) {
748 $q = "UPDATE `#__vikbooking_config` SET `setting`=" . $this->dbo->quote((int)$val) . " WHERE `param`='admin_widgets_welcome';";
749 $this->dbo->setQuery($q);
750 $this->dbo->execute();
751 return;
752 }
753
754 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('admin_widgets_welcome', " . $this->dbo->quote((int)$val) . ");";
755 $this->dbo->setQuery($q);
756 $this->dbo->execute();
757 return;
758 }
759
760 /**
761 * Gets the default map for multitasking pages.
762 *
763 * @return object the associative map of widgets.
764 */
765 protected function getDefaultMultitaskingMap()
766 {
767 $map = new stdClass;
768
769 // booking details page
770 $map->editorder = [
771 'reminders',
772 'check_availability',
773 'bookings_calendar',
774 ];
775
776 // booking modifying page
777 $map->editbusy = [
778 'bookings_calendar',
779 'check_availability',
780 'reminders',
781 ];
782
783 // availability overview
784 $map->overv = [
785 'reminders',
786 'rates_flow',
787 'latest_events',
788 ];
789
790 return $map;
791 }
792
793 /**
794 * Gets the list of widgets assigned to the current page.
795 *
796 * @param string $page the name of the current View/task.
797 * @param bool $whole whether to get the entire map object.
798 *
799 * @return array|object the list of widgets for the given page,
800 * or entire map object if $whole is true.
801 */
802 public function getMultitaskingMap($page = null, $whole = false)
803 {
804 // get saved map
805 $saved_map = VBOFactory::getConfig()->get('multitasking_map');
806 if (!empty($saved_map)) {
807 // try decoding the map data
808 $saved_map = json_decode($saved_map);
809 }
810
811 if (!is_object($saved_map)) {
812 // revert to the default map
813 $saved_map = $this->getDefaultMultitaskingMap();
814 }
815
816 if ($whole) {
817 // do not proceed and return the entire map object
818 return $saved_map;
819 }
820
821 if (empty($page) || !is_string($page)) {
822 return [];
823 }
824
825 return isset($saved_map->$page) && is_array($saved_map->$page) ? $saved_map->$page : [];
826 }
827
828 /**
829 * Updates the map of multitasking widgets.
830 *
831 * @param string $page the name of the current View/task.
832 * @param array|string $widgets the list of or the widget(s) to set.
833 * @param int $action 0 = replace, -1 = prepend, 1 = append.
834 *
835 * @return bool true on success, false otherwise.
836 */
837 public function updateMultitaskingMap($page, $widgets, $action = 0)
838 {
839 if (empty($page) || !is_string($page)) {
840 return false;
841 }
842
843 // check if we have one widget or a list
844 $widgets = is_string($widgets) ? [$widgets] : $widgets;
845 if (!is_array($widgets)) {
846 return false;
847 }
848
849 // get the whole current map
850 $map = $this->getMultitaskingMap($page, true);
851
852 if (!isset($map->$page)) {
853 $map->$page = [];
854 }
855
856 if ($action > 0) {
857 // append widgets
858 foreach ($widgets as $widget_id) {
859 if (empty($widget_id)) {
860 continue;
861 }
862 array_push($map->$page, $widget_id);
863 }
864 } elseif ($action < 0) {
865 // prepend widgets
866 foreach ($widgets as $widget_id) {
867 if (empty($widget_id)) {
868 continue;
869 }
870 array_unshift($map->$page, $widget_id);
871 }
872 } else {
873 // replace current list when $action === 0
874 $map->$page = $widgets;
875 }
876
877 // update configuration record
878 VBOFactory::getConfig()->set('multitasking_map', json_encode($map));
879
880 return true;
881 }
882
883 /**
884 * Sets the position for an admin widget in the multitask panel.
885 *
886 * @param array $pos_list Associative list of widget positions.
887 *
888 * @return array The updated widgets position list.
889 *
890 * @since 1.16.10 (J) - 1.6.10 (WP)
891 */
892 public function setMultitaskingWidgetPos($pos_list)
893 {
894 if (!is_array($pos_list)) {
895 return false;
896 }
897
898 // turn all position values into integers
899 $pos_list = array_map(function($pos) {
900 return (int) $pos;
901 }, $pos_list);
902
903 // update configuration record
904 VBOFactory::getConfig()->set('multitasking_wpos', $pos_list);
905
906 return $pos_list;
907 }
908
909 /**
910 * Admin widgets used to be named as the entire file name,
911 * inclusive of the ".php" extension. For BC we make sure
912 * to evaluate the admin widget identifiers correclty.
913 *
914 * @param string $id the widget identifier to simplify.
915 *
916 * @return string the simplified widget identifier.
917 *
918 * @since 1.15.0 (J) - 1.5.0 (WP)
919 */
920 protected function simplifyId($id)
921 {
922 return str_replace('.php', '', $id);
923 }
924 }
925