PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.2
VikBooking Hotel Booking Engine & PMS v1.7.2
1.8.16 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 All 37 releases
vikbooking / admin / helpers / admin_widgets.php

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

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