PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.15
VikBooking Hotel Booking Engine & PMS v1.8.15
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.15, at admin/helpers/admin_widgets.php

924 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 * 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 'inquiries_chat',
282 'currency_converter',
283 ];
284 // push container
285 array_push($section->containers, $container);
286 // push section
287 array_push($sections, $section);
288
289 // new section
290 $section = new stdClass;
291 $section->name = 'Bottom';
292 $section->containers = [];
293 // start container
294 $container = new stdClass;
295 $container->size = 'medium';
296 $container->widgets = [
297 'last_reservations',
298 ];
299 // push container
300 array_push($section->containers, $container);
301 // start container
302 $container = new stdClass;
303 $container->size = 'medium';
304 $container->widgets = [
305 'next_bookings',
306 ];
307 // push container
308 array_push($section->containers, $container);
309 // push section
310 array_push($sections, $section);
311
312 // new section
313 $section = new stdClass;
314 $section->name = 'Bottom 2';
315 $section->containers = [];
316 // start container
317 $container = new stdClass;
318 $container->size = 'medium';
319 $container->widgets = [
320 'orphan_dates',
321 'rooms_locked',
322 ];
323 // push container
324 array_push($section->containers, $container);
325 // start container
326 $container = new stdClass;
327 $container->size = 'medium';
328 $container->widgets = [
329 'sticky_notes',
330 ];
331 // push container
332 array_push($section->containers, $container);
333 // push section
334 array_push($sections, $section);
335
336 // compose the final map object
337 $map = new stdClass;
338 $map->sections = $sections;
339
340 return $map;
341 }
342
343 /**
344 * Gets the list of admin widgets instantiated.
345 *
346 * @return array list of admin widget objects.
347 */
348 public function getWidgets()
349 {
350 return $this->widgets;
351 }
352
353 /**
354 * Gets a single admin widget instantiated.
355 *
356 * @param string $id the widget identifier.
357 *
358 * @return mixed the admin widget object, false otherwise.
359 */
360 public function getWidget($id)
361 {
362 $id = $this->simplifyId($id);
363
364 foreach ($this->widgets as $widget) {
365 if ($widget->getIdentifier() == $id) {
366 return $widget;
367 }
368 }
369
370 return false;
371 }
372
373 /**
374 * Gets a list of sorted widget names, ids, descriptions, icons and styles.
375 * If called with pre-loading, widgets will be able to load their CSS and JS
376 * assets. Moreover, pre-loading a widget can return a watch-data object to
377 * implement the notifications scheduling of a specific widget.
378 *
379 * @param bool $preload whether to call the widget's preload method.
380 *
381 * @return array associative and sorted widgets list.
382 *
383 * @since 1.15.0 (J) - 1.5.0 (WP) added support for icons and style names.
384 * implemented widgets preloading for assets.
385 */
386 public function getWidgetNames($preload = false)
387 {
388 // containers
389 $names = [];
390 $pool = [];
391 $watch = [];
392
393 foreach ($this->widgets as $widget) {
394 // get widget details
395 $id = $widget->getIdentifier();
396 $name = $widget->getName();
397 $descr = $widget->getDescription();
398
399 if ($preload) {
400 // preload widget's CSS/JS assets (if any)
401 $watch_data = array_key_exists($id, static::$preloaded) ? static::$preloaded[$id] : $widget->preload();
402
403 if ($watch_data) {
404 // assign watching data to this widget
405 $watch[$id] = $watch_data;
406 }
407
408 // overwrite cache for the preloaded widget result
409 static::$preloaded[$id] = $watch_data;
410 }
411
412 // build widget info object
413 $wtdata = new stdClass;
414 $wtdata->id = $id;
415 $wtdata->name = $name;
416 $wtdata->descr = $descr;
417 $wtdata->icon = $widget->getIcon();
418 $wtdata->style = str_replace(array(' ', '_'), '-', $widget->getStyleName());
419 $wtdata->priority = $widget->getPriority();
420
421 // set object for sorting
422 $names[$name] = $wtdata;
423 }
424
425 // apply sorting by name
426 ksort($names);
427
428 // apply sorting by priority
429 usort($names, function($a, $b) {
430 // the higher the priority is, the higher the position will be
431 return $b->priority - $a->priority;
432 });
433
434 if ($this->widgets_pos_list) {
435 // get the custom positions list
436 $widgets_pos_list = $this->widgets_pos_list;
437 // apply custom sorting
438 usort($names, function($a, $b) use ($widgets_pos_list) {
439 $wa_id = $a->id;
440 $wb_id = $b->id;
441
442 if (($widgets_pos_list[$wa_id] ?? null) && ($widgets_pos_list[$wb_id] ?? null)) {
443 // the higher the custom position is, the lower the sorting position will be
444 return $widgets_pos_list[$wa_id] > $widgets_pos_list[$wb_id] ? 1 : -1;
445 }
446
447 return 0;
448 });
449 }
450
451 // push sorted widgets to pool
452 foreach ($names as $wtdata) {
453 $pool[] = $wtdata;
454 }
455
456 /**
457 * In case some widgets were pre-loaded for watching certain
458 * events, enqueue the watch-data list to the document.
459 */
460 if ($watch) {
461 // schedule the browser notifications watching data
462 VBONotificationScheduler::getInstance()->registerWatchData($watch);
463 }
464
465 // return the list of admin widgets
466 return $pool;
467 }
468
469 /**
470 * Gets the current or default map of admin widgets.
471 * If no map currently set, stores the default map.
472 *
473 * @return array the associative map of sections,
474 * containers and widgets.
475 */
476 public function getWidgetsMap()
477 {
478 $config = VBOFactory::getConfig();
479
480 $map = $config->get('admin_widgets_map', null);
481
482 if ($map) {
483 $map = json_decode($map);
484 return is_object($map) && !empty($map->sections) && is_array($map->sections) ? $map : $this->getDefaultWidgetsMap();
485 }
486
487 $default_map = $this->getDefaultWidgetsMap();
488
489 $config->set('admin_widgets_map', $default_map);
490
491 return $default_map;
492 }
493
494 /**
495 * Updates the map of admin widgets.
496 *
497 * @param array $sections the list of sections for the map.
498 *
499 * @return bool True on success, false otherwise.
500 */
501 public function updateWidgetsMap($sections)
502 {
503 if (!is_array($sections) || !$sections) {
504 return false;
505 }
506
507 // prepare new map object
508 $map = new stdClass;
509 $map->sections = $sections;
510
511 VBOFactory::getConfig()->set('admin_widgets_map', $map);
512
513 return true;
514 }
515
516 /**
517 * Restores the default admin widgets map.
518 * First it resets the settings of each widget.
519 *
520 * @return bool True on success, false otherwise.
521 */
522 public function restoreDefaultWidgetsMap()
523 {
524 foreach ($this->widgets as $widget) {
525 $widget->resetSettings();
526 }
527
528 $default_map = $this->getDefaultWidgetsMap();
529
530 return $this->updateWidgetsMap($default_map->sections);
531 }
532
533 /**
534 * Forces the rendering of a specific widget identifier.
535 *
536 * @param string $id the widget identifier.
537 * @param ?VBOMultitaskData $data optional multitask data for the widget.
538 *
539 * @return void
540 */
541 public function renderWidget($id, ?VBOMultitaskData $data = null)
542 {
543 $id = $this->simplifyId($id);
544
545 foreach ($this->widgets as $widget) {
546 if ($widget->getIdentifier() == $id) {
547 // render the requested widget
548 $widget->render($data);
549
550 // return void
551 return;
552 }
553 }
554 }
555
556 /**
557 * Maps the size identifier to a CSS class.
558 *
559 * @param string $size the container size identifier.
560 *
561 * @return string the full CSS class for the container.
562 */
563 public function getContainerCssClass($size)
564 {
565 $css_size_map = [
566 'small' => 'vbo-admin-widgets-container-small',
567 'medium' => 'vbo-admin-widgets-container-medium',
568 'large' => 'vbo-admin-widgets-container-large',
569 'full' => 'vbo-admin-widgets-container-fullwidth',
570 ];
571
572 return isset($css_size_map[$size]) ? $css_size_map[$size] : $css_size_map['full'];
573 }
574
575 /**
576 * Returns an associative array with the class names for the containers.
577 *
578 * @return array a text representation list of all sizes.
579 */
580 public function getContainerClassNames()
581 {
582 return array(
583 'full' => array(
584 'name' => JText::translate('VBO_WIDGETS_CONTFULL'),
585 'css' => $this->getContainerCssClass('full'),
586 ),
587 'large' => array(
588 'name' => JText::translate('VBO_WIDGETS_CONTLARGE'),
589 'css' => $this->getContainerCssClass('large'),
590 ),
591 'medium' => array(
592 'name' => JText::translate('VBO_WIDGETS_CONTMEDIUM'),
593 'css' => $this->getContainerCssClass('medium'),
594 ),
595 'small' => array(
596 'name' => JText::translate('VBO_WIDGETS_CONTSMALL'),
597 'css' => $this->getContainerCssClass('small'),
598 ),
599 );
600 }
601
602 /**
603 * Maps the size identifier to the corresponding name.
604 *
605 * @param string $size the container size identifier.
606 *
607 * @return string the size name for the container.
608 */
609 public function getContainerName($size)
610 {
611 $names = $this->getContainerClassNames();
612
613 return isset($names[$size]) ? $names[$size]['name'] : $names['full']['name'];
614 }
615
616 /**
617 * Many widgets may need to know some values about the rooms.
618 * This method uses the static instance of the class to cache data.
619 *
620 * @return void
621 */
622 protected function loadRoomsData()
623 {
624 if (isset(static::$helper['all_rooms_ids'])) {
625 // do not execute the same queries again
626 return;
627 }
628
629 $all_rooms_ids = [];
630 $all_rooms_units = [];
631 $all_rooms_features = [];
632 $unpublished_rooms = [];
633 $tot_rooms_units = 0;
634
635 $q = "SELECT `id`,`name`,`units`,`params`,`avail` FROM `#__vikbooking_rooms`;";
636 $this->dbo->setQuery($q);
637 $all_rooms = $this->dbo->loadAssocList();
638 if ($all_rooms) {
639 foreach ($all_rooms as $k => $r) {
640 if ($r['avail'] < 1) {
641 $unpublished_rooms[] = $r['id'];
642 } else {
643 $tot_rooms_units += $r['units'];
644 }
645 $all_rooms_ids[$r['id']] = $r['name'];
646 $all_rooms_units[$r['id']] = $r['units'];
647 $rparams = json_decode((string) $r['params'], true);
648 $all_rooms_features[$r['id']] = is_array($rparams) && array_key_exists('features', $rparams) && is_array($rparams['features']) ? $rparams['features'] : [];
649 }
650 }
651
652 // update static values
653 static::$helper['all_rooms_ids'] = $all_rooms_ids;
654 static::$helper['all_rooms_units'] = $all_rooms_units;
655 static::$helper['all_rooms_features'] = $all_rooms_features;
656 static::$helper['unpublished_rooms'] = $unpublished_rooms;
657 static::$helper['tot_rooms_units'] = $tot_rooms_units;
658 }
659
660 /**
661 * Many widgets could use this method to access cached information.
662 *
663 * @param string $key the data key identifier.
664 *
665 * @return mixed array/int on success, false otherwise.
666 */
667 public function getRoomsData($key)
668 {
669 if (empty($key)) {
670 return false;
671 }
672
673 if (!static::$helper) {
674 $this->loadRoomsData();
675 }
676
677 if (isset(static::$helper[$key])) {
678 return static::$helper[$key];
679 }
680
681 return false;
682 }
683
684 /**
685 * Helper method to load all busy real records for all rooms for dates near today.
686 * This is useful to avoid double queries in the various widgets and to get data
687 * about yesterday, today and the next week.
688 *
689 * @return array
690 *
691 * @since 1.15.2 (J) - 1.5.5 (WP) changed the way limit timestamps are calculated.
692 */
693 public function loadBusyRecordsUnclosed()
694 {
695 if (!isset(static::$helper['all_rooms_ids'])) {
696 $this->loadRoomsData();
697 }
698
699 if (isset(static::$helper['busy_records_unclosed'])) {
700 return static::$helper['busy_records_unclosed'];
701 }
702
703 // cache value and return it
704 $base_from_ts = mktime(0, 0, 0, date("n"), (date("j") - 1), date("Y"));
705 $base_end_ts = mktime(23, 59, 59, date("n"), (date("j") + 7), date("Y"));
706 static::$helper['busy_records_unclosed'] = VikBooking::loadBusyRecordsUnclosed(array_keys(static::$helper['all_rooms_ids']), $base_from_ts, $base_end_ts);
707
708 return static::$helper['busy_records_unclosed'];
709 }
710
711 /**
712 * The first time the widget's customizer is open, the welcome is displayed.
713 * Congig value >= 1 means hide the welcome text, 0 or lower means show it.
714 *
715 * @return bool
716 */
717 public function showWelcome()
718 {
719 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='admin_widgets_welcome';";
720 $this->dbo->setQuery($q);
721 $show_welcome = $this->dbo->loadResult();
722 if ($show_welcome !== null) {
723 return ((int)$show_welcome < 1);
724 }
725
726 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('admin_widgets_welcome', '0');";
727 $this->dbo->setQuery($q);
728 $this->dbo->execute();
729
730 return true;
731 }
732
733 /**
734 * Updates the status of the welcome message for the widget's customizer.
735 * Congig value >= 1 means hide the welcome text, 0 or lower means show it.
736 *
737 * @param int $val the new value to set in the configuration.
738 *
739 * @return void
740 */
741 public function updateWelcome($val)
742 {
743 $q = "SELECT `setting` FROM `#__vikbooking_config` WHERE `param`='admin_widgets_welcome';";
744 $this->dbo->setQuery($q);
745 $this->dbo->execute();
746 if ($this->dbo->getNumRows()) {
747 $q = "UPDATE `#__vikbooking_config` SET `setting`=" . $this->dbo->quote((int)$val) . " WHERE `param`='admin_widgets_welcome';";
748 $this->dbo->setQuery($q);
749 $this->dbo->execute();
750 return;
751 }
752
753 $q = "INSERT INTO `#__vikbooking_config` (`param`,`setting`) VALUES ('admin_widgets_welcome', " . $this->dbo->quote((int)$val) . ");";
754 $this->dbo->setQuery($q);
755 $this->dbo->execute();
756 return;
757 }
758
759 /**
760 * Gets the default map for multitasking pages.
761 *
762 * @return object the associative map of widgets.
763 */
764 protected function getDefaultMultitaskingMap()
765 {
766 $map = new stdClass;
767
768 // booking details page
769 $map->editorder = [
770 'reminders',
771 'check_availability',
772 'bookings_calendar',
773 ];
774
775 // booking modifying page
776 $map->editbusy = [
777 'bookings_calendar',
778 'check_availability',
779 'reminders',
780 ];
781
782 // availability overview
783 $map->overv = [
784 'reminders',
785 'rates_flow',
786 'latest_events',
787 ];
788
789 return $map;
790 }
791
792 /**
793 * Gets the list of widgets assigned to the current page.
794 *
795 * @param string $page the name of the current View/task.
796 * @param bool $whole whether to get the entire map object.
797 *
798 * @return array|object the list of widgets for the given page,
799 * or entire map object if $whole is true.
800 */
801 public function getMultitaskingMap($page = null, $whole = false)
802 {
803 // get saved map
804 $saved_map = VBOFactory::getConfig()->get('multitasking_map');
805 if (!empty($saved_map)) {
806 // try decoding the map data
807 $saved_map = json_decode($saved_map);
808 }
809
810 if (!is_object($saved_map)) {
811 // revert to the default map
812 $saved_map = $this->getDefaultMultitaskingMap();
813 }
814
815 if ($whole) {
816 // do not proceed and return the entire map object
817 return $saved_map;
818 }
819
820 if (empty($page) || !is_string($page)) {
821 return [];
822 }
823
824 return isset($saved_map->$page) && is_array($saved_map->$page) ? $saved_map->$page : [];
825 }
826
827 /**
828 * Updates the map of multitasking widgets.
829 *
830 * @param string $page the name of the current View/task.
831 * @param array|string $widgets the list of or the widget(s) to set.
832 * @param int $action 0 = replace, -1 = prepend, 1 = append.
833 *
834 * @return bool true on success, false otherwise.
835 */
836 public function updateMultitaskingMap($page, $widgets, $action = 0)
837 {
838 if (empty($page) || !is_string($page)) {
839 return false;
840 }
841
842 // check if we have one widget or a list
843 $widgets = is_string($widgets) ? [$widgets] : $widgets;
844 if (!is_array($widgets)) {
845 return false;
846 }
847
848 // get the whole current map
849 $map = $this->getMultitaskingMap($page, true);
850
851 if (!isset($map->$page)) {
852 $map->$page = [];
853 }
854
855 if ($action > 0) {
856 // append widgets
857 foreach ($widgets as $widget_id) {
858 if (empty($widget_id)) {
859 continue;
860 }
861 array_push($map->$page, $widget_id);
862 }
863 } elseif ($action < 0) {
864 // prepend widgets
865 foreach ($widgets as $widget_id) {
866 if (empty($widget_id)) {
867 continue;
868 }
869 array_unshift($map->$page, $widget_id);
870 }
871 } else {
872 // replace current list when $action === 0
873 $map->$page = $widgets;
874 }
875
876 // update configuration record
877 VBOFactory::getConfig()->set('multitasking_map', json_encode($map));
878
879 return true;
880 }
881
882 /**
883 * Sets the position for an admin widget in the multitask panel.
884 *
885 * @param array $pos_list Associative list of widget positions.
886 *
887 * @return array The updated widgets position list.
888 *
889 * @since 1.16.10 (J) - 1.6.10 (WP)
890 */
891 public function setMultitaskingWidgetPos($pos_list)
892 {
893 if (!is_array($pos_list)) {
894 return false;
895 }
896
897 // turn all position values into integers
898 $pos_list = array_map(function($pos) {
899 return (int) $pos;
900 }, $pos_list);
901
902 // update configuration record
903 VBOFactory::getConfig()->set('multitasking_wpos', $pos_list);
904
905 return $pos_list;
906 }
907
908 /**
909 * Admin widgets used to be named as the entire file name,
910 * inclusive of the ".php" extension. For BC we make sure
911 * to evaluate the admin widget identifiers correclty.
912 *
913 * @param string $id the widget identifier to simplify.
914 *
915 * @return string the simplified widget identifier.
916 *
917 * @since 1.15.0 (J) - 1.5.0 (WP)
918 */
919 protected function simplifyId($id)
920 {
921 return str_replace('.php', '', $id);
922 }
923 }
924