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

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