PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
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
← All changes | vikbooking.php +1039 -0 1.6.3 → 1.8.16 View file →
@@ -1,0 +1,1039 @@
1 +<?php
2 +/*
3 +Plugin Name: VikBooking
4 +Plugin URI: https://vikwp.com/plugin/vikbooking
5 +Description: Certified Booking Engine for Hotels and Accommodations.
6 +Version: 1.8.16
7 +Author: E4J s.r.l.
8 +Author URI: https://vikwp.com
9 +License: GPL2
10 +License URI: https://www.gnu.org/licenses/gpl-2.0.html
11 +Text Domain: vikbooking
12 +Domain Path: /languages
13 +*/
14 +
15 +// No direct access
16 +defined('ABSPATH') or die('No script kiddies please!');
17 +
18 +// autoload dependencies
19 +require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'autoload.php';
20 +
21 +// handle install/uninstall
22 +register_activation_hook(__FILE__, array('VikBookingInstaller', 'activate'));
23 +register_deactivation_hook(__FILE__, array('VikBookingInstaller', 'deactivate'));
24 +register_uninstall_hook(__FILE__, array('VikBookingInstaller', 'delete'));
25 +
26 +// init Installer
27 +add_action('init', array('VikBookingInstaller', 'onInit'));
28 +
29 +/**
30 + * Fires after all automatic updates have run.
31 + * Completes the update scheduled in background.
32 + *
33 + * @param array $results The results of all attempted updates.
34 + *
35 + * @since 1.3.12
36 + */
37 +add_action('automatic_updates_complete', array('VikBookingInstaller', 'automaticUpdate'));
38 +
39 +/**
40 + * Filters whether to automatically update core, a plugin, a theme, or a language.
41 + * Used to automatically turn off the update in case a PRO version expired.
42 + *
43 + * @param bool|null $update Whether to update. The value of null is internally used
44 + * to detect whether nothing has hooked into this filter.
45 + * @param object $item The update offer.
46 + *
47 + * @since 1.3.12
48 + */
49 +add_filter('auto_update_plugin', array('VikBookingInstaller', 'useAutoUpdate'), 10, 2);
50 +
51 +/**
52 + * Fires at the end of the update message container in each
53 + * row of the plugins list table.
54 + *
55 + * The dynamic portion of the hook name, `$file`, refers to the path
56 + * of the plugin's primary file relative to the plugins directory.
57 + *
58 + * @link https://developer.wordpress.org/reference/hooks/in_plugin_update_message-file/
59 + *
60 + * @param array $data An array of plugin metadata.
61 + * @param array $response An array of metadata about the available plugin update.
62 + *
63 + * @since 1.3.12
64 + */
65 +add_action('in_plugin_update_message-vikbooking/vikbooking.php', array('VikBookingInstaller', 'getUpdateMessage'), 10, 2);
66 +
67 +// init pagination layout
68 +VikBookingBuilder::setupPaginationLayout();
69 +// init html helpers
70 +VikBookingBuilder::setupHtmlHelpers();
71 +// init payment framework
72 +VikBookingBuilder::configurePaymentFramework();
73 +// setup hooks to extend the backup functionalities
74 +VikBookingBuilder::setupBackupSystem();
75 +
76 +// setup plugin overrides management
77 +add_action('plugins_loaded', array('VikBookingBuilder', 'setupOverridesManager'));
78 +
79 +// setup lite system
80 +add_action('plugins_loaded', array('VikBookingLiteManager', 'setup'));
81 +add_action('plugins_loaded', array('VikChannelManagerLiteManager', 'setup'));
82 +
83 +/**
84 + * Added support for screen options.
85 + * Parameters such as the list limit can be changed from there.
86 + *
87 + * @since 1.2.5
88 + */
89 +add_action('current_screen', array('VikBookingScreen', 'options'));
90 +add_filter('set-screen-option', array('VikBookingScreen', 'saveOption'), 10, 3);
91 +/**
92 + * Due to WordPress 5.4.2 changes, we need to attach
93 + * VikBooking to a dedicated hook in order to
94 + * allow the update of the list limit.
95 + *
96 + * @since 1.3.5
97 + */
98 +add_filter('set_screen_option_vikbooking_list_limit', array('VikBookingScreen', 'saveOption'), 10, 3);
99 +
100 +// init Session
101 +add_action('init', array('JSessionHandler', 'start'), 1);
102 +add_action('wp_logout', array('JSessionHandler', 'destroy'));
103 +
104 +// filter page link to rewrite URI
105 +add_action('plugins_loaded', function()
106 +{
107 + // installer class will check the update status
108 + VikBookingInstaller::update();
109 +
110 + global $pagenow;
111 +
112 + $app = JFactory::getApplication();
113 + $input = $app->input;
114 +
115 + // check if the URI contains option=com_vikbooking
116 + if ($input->get('option') == 'com_vikbooking')
117 + {
118 + // make sure we are not contacting the AJAX and POST end-points
119 + if (!wp_doing_ajax() && $pagenow != 'admin-post.php')
120 + {
121 + /**
122 + * Include page in query string only if we are in the back-end,
123 + * because WordPress 5.5 seems to break the page loading in case
124 + * that argument has been included in query string.
125 + *
126 + * It is not needed to include this argument in the front-end
127 + * as the page should lean on the reached shortcode only.
128 + *
129 + * @since 1.3.7
130 + */
131 + if ($app->isAdmin())
132 + {
133 + // inject page=vikbooking in GET superglobal
134 + $input->get->set('page', 'vikbooking');
135 + }
136 + }
137 + else
138 + {
139 + // inject action=vikbooking in GET superglobal for AJAX and POST requests
140 + $_GET['action'] = 'vikbooking';
141 + }
142 + }
143 + elseif ($input->get('page') == 'vikbooking' || $input->get('action') == 'vikbooking')
144 + {
145 + // inject option=com_vikbooking in GET superglobal
146 + $_GET['option'] = 'com_vikbooking';
147 + }
148 +});
149 +
150 +// process the request and obtain the response
151 +add_action('init', function()
152 +{
153 + /**
154 + * Language files should no longer be loaded during 'plugins_loaded'.
155 + *
156 + * @since 1.7.6
157 + */
158 + VikBookingBuilder::loadLanguage();
159 +
160 + $app = JFactory::getApplication();
161 + $input = $app->input;
162 +
163 + // if we are in the front-end, try to parse the URL to inject
164 + // option, view and args in the input request
165 + if ($app->isSite() && VIKBOOKING_SITE_PREPROCESS)
166 + {
167 + // get post ID from current URL
168 + $id = url_to_postid(JUri::current());
169 +
170 + if ($id)
171 + {
172 + // get shortcode admin model
173 + $model = JModel::getInstance('vikbooking', 'shortcode', 'admin');
174 + // get shortcode searching by post ID (false to avoid returning a new item)
175 + $shortcode = $model->getItem(array('post_id' => $id), false);
176 +
177 + if ($shortcode)
178 + {
179 + // build args array using the shortcode attributes
180 + $args = (array) json_decode($shortcode->json, true);
181 + $args['view'] = $shortcode->type;
182 + $args['option'] = 'com_vikbooking';
183 +
184 + // inject the shortcode args into the input request
185 + foreach ($args as $k => $v)
186 + {
187 + // inject only if not defined
188 + $input->def($k, $v);
189 + }
190 + }
191 + }
192 + }
193 +
194 + // process VikBooking only if it has been requested via GET or POST
195 + if ($input->get('option') == 'com_vikbooking' || $input->get('page') == 'vikbooking')
196 + {
197 + VikBookingBody::process();
198 + }
199 +});
200 +
201 +// handle AJAX requests
202 +add_action('wp_ajax_vikbooking', 'handle_vikbooking_ajax');
203 +add_action('wp_ajax_nopriv_vikbooking', 'handle_vikbooking_ajax');
204 +
205 +function handle_vikbooking_ajax()
206 +{
207 + VikBookingBody::getHtml();
208 +
209 + // die to get a valid response
210 + wp_die();
211 +}
212 +
213 +// setup admin menu
214 +add_action('admin_menu', array('VikBookingBuilder', 'setupAdminMenu'));
215 +
216 +// register widgets
217 +add_action('widgets_init', array('VikBookingBuilder', 'setupWidgets'));
218 +
219 +/**
220 + * Load plugin language when registering the widgets as well.
221 + * Since translations are now loaded at "init", they might not be available yet.
222 + *
223 + * @since 1.8.4
224 + */
225 +add_action('widgets_init', ['VikBookingBuilder', 'loadLanguage'], 1);
226 +
227 +// handle shortcodes (SITE controller dispatcher)
228 +add_shortcode('vikbooking', function($atts, $content = null)
229 +{
230 + $app = JFactory::getApplication();
231 +
232 + /**
233 + * Force the application client to "site" every time a shortcode is executed.
234 + *
235 + * @since 1.5.5
236 + */
237 + $app->setClient('site');
238 +
239 + // wrap attributes in a registry
240 + $args = new JObject($atts);
241 +
242 + // get the VIEW (empty if not set)
243 + $view = $args->get('view', '');
244 +
245 + // load the FORM of the view
246 + JLoader::import('adapter.form.form');
247 + $path = implode(DIRECTORY_SEPARATOR, array(VBO_SITE_PATH, 'views', $view, 'tmpl', 'default.xml'));
248 + // raises an exception if the VIEW is not set
249 + $form = JForm::getInstance($view, $path);
250 +
251 + // get all the XML form fields
252 + $fields = $form->getFields();
253 +
254 + // filter the fields to get a list of allowed names
255 + $fields = array_map(function($f)
256 + {
257 + return (string) $f->attributes()->name;
258 + }, $fields);
259 +
260 + // inject query vars
261 + $input = $app->input;
262 + // since we are going to render the controller manually,
263 + // we don't need to push the option into $_REQUEST pool.
264 + // $input->set('option', 'com_vikbooking');
265 +
266 + // Inject shortcode vars only if they are not set
267 + // in the request. This is used to allow the navigation
268 + // between the pages.
269 + $input->def('view', $view);
270 +
271 + foreach ($fields as $k)
272 + {
273 + $input->def($k, $args->get($k));
274 + }
275 +
276 + /**
277 + * When saving a shortcode block through Gutenberg,
278 + * WordPress tries to reach the page to check what happens.
279 + * Some views of VikBooking may immediately redirect the users to
280 + * another page URI.
281 + * This redirect breaks the request made by WordPress for the
282 + * validation of the page, which follows the new location.
283 + * The code below prevents the execution of the controller
284 + * in case the URI matches the REST API end-point.
285 + *
286 + * @since 1.7
287 + */
288 + $rest_prefix = trailingslashit(rest_get_url_prefix());
289 + $is_rest_api = strpos($input->server->getString('REQUEST_URI', ''), $rest_prefix) !== false
290 + || JUri::getInstance($input->server->getString('REQUEST_URI', ''))->hasVar('rest_route')
291 + || strpos($input->server->getString('REQUEST_URI', ''), '/wp-admin/') !== false;
292 +
293 + if ($is_rest_api && in_array($input->get('view'), ['tinyurl']))
294 + {
295 + // return an empty string to prevent any redirects
296 + return '';
297 + }
298 +
299 + // dispatch the controller
300 + return VikBookingBody::getHtml(true);
301 +});
302 +
303 +// the callback is fired before the VBO controller is dispatched
304 +add_action('vikbooking_before_dispatch', function()
305 +{
306 + $app = JFactory::getApplication();
307 + $user = Jfactory::getUser();
308 +
309 + // initialize timezone handler
310 + JDate::getDefaultTimezone();
311 + date_default_timezone_set($app->get('offset', 'UTC'));
312 +
313 + // check if the user is authorised to access the back-end (only if the client is 'admin')
314 + if ($app->isAdmin() && !$user->authorise('core.manage', 'com_vikbooking'))
315 + {
316 + if ($user->guest)
317 + {
318 + // if the user is not logged, redirect to login page
319 + $app->redirect('index.php');
320 + exit;
321 + }
322 + else
323 + {
324 + // otherwise raise an exception
325 + wp_die(
326 + '<h1>' . JText::translate('FATAL_ERROR') . '</h1>' .
327 + '<p>' . JText::translate('RESOURCE_AUTH_ERROR') . '</p>',
328 + 403
329 + );
330 + }
331 + }
332 +
333 + // main library
334 + require_once VBO_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikbooking.php';
335 +
336 + if ($app->isAdmin())
337 + {
338 + require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'vikbooking.php';
339 + require_once VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'jv_helper.php';
340 + }
341 + else
342 + {
343 + // Invoke VCM before the rendering
344 + VikBooking::detectUserAgent();
345 + VikBooking::invokeChannelManager();
346 + VikBooking::getTracker();
347 + VikBooking::loadPreferredColorStyles();
348 + }
349 +
350 + /**
351 + * Prevent some pages from performing an auto-redirect when running
352 + * the Bricks plugin preview.
353 + *
354 + * @since 1.7.7
355 + */
356 + if ($app->input->get('bricks') === 'run' && in_array($app->input->get('view'), ['tinyurl']))
357 + {
358 + $app->input->set('view', '');
359 + }
360 +});
361 +
362 +// instead using the default server timezone, try to use the one
363 +// specified within the WordPress configuration
364 +add_filter('vik_date_default_timezone', function($timezone)
365 +{
366 + return JFactory::getApplication()->get('offset', $timezone);
367 +});
368 +
369 +// the callback is fired once the VBO controller has been dispatched
370 +add_action('vikbooking_after_dispatch', function()
371 +{
372 + // load assets after dispatching the controller to avoid
373 + // including JS and CSS when an AJAX function exits or dies
374 + VikBookingAssets::load();
375 +
376 + /**
377 + * Load javascript core.
378 + *
379 + * @since 1.1.8
380 + */
381 + JHtml::fetch('behavior.core');
382 +
383 + // restore standard timezone
384 + date_default_timezone_set(JDate::getDefaultTimezone());
385 +
386 + /**
387 + * @note when the headers have been sent or when
388 + * the request is AJAX, the assets (CSS and JS) are
389 + * appended to the document after the
390 + * response dispatched by the controller.
391 + */
392 +});
393 +
394 +// End-point for front-end post actions.
395 +// The end-point URL must be built as .../wp-admin/admin-post.php
396 +// and requires $_POST['action'] == 'vikbooking' to be submitted through a form or GET.
397 +add_action('admin_post_vikbooking', 'handle_vikbooking_endpoint'); // if the user is logged in
398 +add_action('admin_post_nopriv_vikbooking', 'handle_vikbooking_endpoint'); // if the user in not logged in
399 +
400 +// handle POST end-point
401 +function handle_vikbooking_endpoint()
402 +{
403 + // get PLAIN response
404 + echo VikBookingBody::getResponse();
405 +}
406 +
407 +// Hook used to access the PAGE details when a user is
408 +// creating or updating it. This is helpful to make a relation
409 +// between the page and the injected shortcode.
410 +add_action('save_post', function($post_id)
411 +{
412 + // get model to access all the existing shortcodes
413 + $model = JModel::getInstance('vikbooking', 'shortcodes', 'admin');
414 + $shortcodes = $model->all(array('id', 'shortcode', 'post_id'));
415 +
416 + // get post data
417 + $post = get_post($post_id);
418 +
419 + /**
420 + * Check if we are editing a child post as Gutenberg
421 + * seems to use always the inherit status, which
422 + * refers to a post parent.
423 + *
424 + * @since 1.0.17
425 + */
426 + if ($post->post_status != 'publish' && !empty($post->post_parent) && $post->post_parent != $post_id)
427 + {
428 + // fallback to obtain parent post data
429 + $post = get_post($post->post_parent);
430 +
431 + /**
432 + * Use new post ID.
433 + *
434 + * @since 1.2.7 Fixed post ID property name.
435 + */
436 + $post_id = $post->ID;
437 + }
438 +
439 + if ($post->post_status != 'publish')
440 + {
441 + // ignore drafts auto-save
442 + return;
443 + }
444 +
445 + // get shortcode model
446 + $shortcodeModel = JModel::getInstance('vikbooking', 'shortcode', 'admin');
447 +
448 + /**
449 + * Since we need unique post IDs, all the shortcodes
450 + * that are assigned to the specified $post_id should
451 + * be detached.
452 + *
453 + * @since 1.0.17
454 + */
455 + foreach ($shortcodes as $data)
456 + {
457 + if ($data->post_id == $post_id)
458 + {
459 + // The post is already assigned to a shortcode.
460 + // Unset it to avoid duplicated.
461 + $data->post_id = 0;
462 + $shortcodeModel->save($data);
463 + }
464 + }
465 +
466 + // iterate the shortcodes
467 + foreach ($shortcodes as $data)
468 + {
469 + // check if the content of the post contains the shortcode
470 + if (strpos($post->post_content, html_entity_decode($data->shortcode)) !== false)
471 + {
472 + // inject the POST ID
473 + $data->post_id = $post_id;
474 +
475 + // update shortcode
476 + $shortcodeModel->save($data);
477 +
478 + // stop iterating
479 + return;
480 + }
481 + }
482 +});
483 +
484 +// Hook used to unset temporarily the relationship
485 +// between the trashed post and the shortcode.
486 +add_action('trashed_post', function($post_id)
487 +{
488 + // get shortcode model
489 + $model = JModel::getInstance('vikbooking', 'shortcode', 'admin');
490 +
491 + // get the shortcode attached to the trashed post ID
492 + $item = $model->getItem(array('post_id' => $post_id), false);
493 +
494 + // if the item exists, temporarily detach the relationship
495 + if ($item)
496 + {
497 + $item->post_id = 0;
498 + $item->tmp_post_id = $post_id;
499 +
500 + $model->save($item);
501 + }
502 +});
503 +
504 +// Hook used to restore permanently the relationship
505 +// between the untrashed post and the shortcode.
506 +add_action('untrashed_post', function($post_id)
507 +{
508 + // get shortcode model
509 + $model = JModel::getInstance('vikbooking', 'shortcode', 'admin');
510 +
511 + // get the shortcode attached to the untrashed post ID
512 + $item = $model->getItem(array('tmp_post_id' => $post_id), false);
513 +
514 + // if the item exists, re-attach the relationship
515 + if ($item)
516 + {
517 + $item->post_id = $post_id;
518 + $item->tmp_post_id = 0;
519 +
520 + $model->save($item);
521 + }
522 +});
523 +
524 +// Hook used to temporarily detach the relationship
525 +// between the deleted post and the shortcode.
526 +add_action('deleted_post', function($post_id)
527 +{
528 + // get shortcode model
529 + $model = JModel::getInstance('vikbooking', 'shortcode', 'admin');
530 +
531 + // get the shortcode attached to the trashed post ID
532 + $item = $model->getItem(array('tmp_post_id' => $post_id), false);
533 +
534 + // If no item found, the "trash" feature is probably disabled.
535 + // Try to take a look for a shortcode with an active relationship.
536 + if (!$item)
537 + {
538 + $item = $model->getItem(array('post_id' => $post_id), false);
539 + }
540 +
541 + // if the item exists, permanently detach the relationship
542 + if ($item)
543 + {
544 + $item->post_id = 0;
545 + $item->tmp_post_id = 0;
546 +
547 + $model->save($item);
548 + }
549 +});
550 +
551 +if (JFactory::getApplication()->isAdmin() && !wp_doing_ajax())
552 +{
553 + /**
554 + * @todo should we restrict these filters to the post managements pages only?
555 + */
556 +
557 + VikBookingLoader::import('system.mce');
558 +
559 + // add new buttons
560 + add_filter('mce_buttons', array('VikBookingTinyMCE', 'addShortcodesButton'));
561 +
562 + // load the button handlers
563 + add_filter('mce_external_plugins', array('VikBookingTinyMCE', 'registerShortcodesScript'));
564 +}
565 +
566 +/**
567 + * Always load the Gutenberg shortcodes block to support the preview rendering.
568 + *
569 + * @since 1.6.7
570 + */
571 +VikBookingLoader::import('system.gutenberg');
572 +add_action('init', ['VikBookingGutenberg', 'registerShortcodesScript']);
573 +
574 +/**
575 + * Dispatch the uninstallation of VikBooking
576 + * every time a new blog (multisite) is deleted.
577 + *
578 + * Fires after the site is deleted from the network (WP 4.8.0 or higher).
579 + *
580 + * @param integer $blog_id The site ID.
581 + * @param boolean $drop True if site's tables should be dropped. Default is false.
582 + *
583 + * @since 1.0.6
584 + */
585 +add_action('deleted_blog', function($blog_id, $drop)
586 +{
587 + VikBookingInstaller::uninstall($drop);
588 +}, 10, 2);
589 +
590 +/**
591 + * Once the plugins have been loaded, evaluates to execute the
592 + * scheduled cron jobs.
593 + *
594 + * Scheduling is processed in case a cron job is hitting wp-cron file
595 + * or in case a user is visiting the website.
596 + *
597 + * @since 1.5.10 Schedules a different hook for each cron.
598 + * @since 1.6.5 Added priority to PHP_INT_MAX - 1 to allow Vik Channel Manager
599 + * to have all the intervals scheduled by Vik Booking.
600 + */
601 +add_action('plugins_loaded', array('VikBookingCron', 'setup'), (PHP_INT_MAX - 1));
602 +
603 +/**
604 + * Action used to register a periodic check of the automatic payments scheduled.
605 + * This hook will be called by a scheduled event in WP-Cron.
606 + *
607 + * @since 1.6.10
608 + */
609 +add_action('vikbooking_cron_payments_scheduled', function()
610 +{
611 + // watch the automatic payments scheduled, if any
612 + VBOModelPayschedules::getInstance()->watch();
613 +});
614 +
615 +/**
616 + * Action used to register a periodic performance cleaning check.
617 + * This hook will be called by a scheduled event in WP-Cron.
618 + *
619 + * @since 1.7.2
620 + * @since 1.8.7 scheduled DAC expired passcodes cleaning.
621 + */
622 +add_action('vikbooking_cron_performance_cleaner', function()
623 +{
624 + // performance cleaning check
625 + VBOPerformanceCleaner::runCheck();
626 + // clean up expired passcodes from smart locks
627 + VBOFactory::getDoorAccessControl()->cleanExpiredPasscodes();
628 +});
629 +
630 +/**
631 + * Action used to register a periodic check of door-access-control framework.
632 + * This hook will be called by a scheduled event in WP-Cron.
633 + *
634 + * @since 1.8.4
635 + * @since 1.8.6 added support to watch the devices first access.
636 + */
637 +add_action('vikbooking_cron_door_access_control', function()
638 +{
639 + // watch if any booking is approaching the check-in date
640 + VBOFactory::getDoorAccessControl()->handleUpcomingArrivals();
641 + // watch if passcodes get used for the first time
642 + VBOFactory::getDoorAccessControl()->watchFirstAccess();
643 +});
644 +
645 +/**
646 + * Action used to register a periodic database cleaning check.
647 + * This hook will be called by a scheduled event in WP-Cron.
648 + *
649 + * @since 1.8.5
650 + */
651 +add_action('vikbooking_cron_db_optimization', ['VBOPerformanceCleaner', 'optimizeDatabase']);
652 +
653 +/**
654 + * Install the scheduling of the hook within WP-Cron needed
655 + * to watch and process the automatic payments scheduled.
656 + *
657 + * @since 1.6.10
658 + * @since 1.7.2 registered "vikbooking_cron_performance_cleaner".
659 + * @since 1.8.4 registered "vikbooking_cron_door_access_control".
660 + * @since 1.8.5 registered "vikbooking_cron_db_optimization".
661 + */
662 +add_action('plugins_loaded', function()
663 +{
664 + // make sure the cron event hasn't been yet scheduled.
665 + if (!wp_next_scheduled('vikbooking_cron_payments_scheduled'))
666 + {
667 + // schedule event starting from the current time for "every half hour"
668 + // such interval will be installed by VikBookingCron::setup()
669 + wp_schedule_event(time(), 'half_hour', 'vikbooking_cron_payments_scheduled');
670 + }
671 +
672 + // make sure the cron event hasn't been yet scheduled.
673 + if (!wp_next_scheduled('vikbooking_cron_performance_cleaner'))
674 + {
675 + // schedule event starting from the current time for "every week"
676 + wp_schedule_event(time(), 'weekly', 'vikbooking_cron_performance_cleaner');
677 + }
678 +
679 + // make sure the cron event hasn't been yet scheduled.
680 + if (!wp_next_scheduled('vikbooking_cron_door_access_control'))
681 + {
682 + // schedule event starting from the current time for "every hour"
683 + wp_schedule_event(time(), 'hourly', 'vikbooking_cron_door_access_control');
684 + }
685 +
686 + // make sure the cron event hasn't been yet scheduled.
687 + if (!wp_next_scheduled('vikbooking_cron_db_optimization'))
688 + {
689 + // schedule event starting from the current time for "every hour"
690 + wp_schedule_event(time(), 'hourly', 'vikbooking_cron_db_optimization');
691 + }
692 +}, (PHP_INT_MAX - 1));
693 +
694 +/**
695 + * Filters the action links displayed for each plugin in the Plugins list table.
696 + * Hook used to filter the "deactivation" link and ask a feedback every time that
697 + * button is clicked.
698 + *
699 + * @param array $actions An array of plugin action links. By default this can include 'activate',
700 + * 'deactivate', and 'delete'. With Multisite active this can also include
701 + * 'network_active' and 'network_only' items.
702 + * @param string $plugin_file Path to the plugin file relative to the plugins directory.
703 + * @param array $plugin_data An array of plugin data. See `get_plugin_data()`.
704 + * @param string $context The plugin context. By default this can include 'all', 'active', 'inactive',
705 + * 'recently_activated', 'upgrade', 'mustuse', 'dropins', and 'search'.
706 + *
707 + * @since 1.2.13
708 + */
709 +add_filter('plugin_action_links', array('VikBookingFeedback', 'deactivate'), 10, 4);
710 +
711 +/**
712 + * Adjusts the timezone of the website before dispatching
713 + * a widget as we are currently outside of the main plugin and
714 + * the timezone have probably been restored to the default one.
715 + *
716 + * @param string $id The widget ID (path name).
717 + * @param JObject &$params The widget configuration registry.
718 + *
719 + * @since 1.2.10
720 + */
721 +add_action('vik_widget_before_dispatch_site', function($id, &$params)
722 +{
723 + // initialize timezone handler
724 + JDate::getDefaultTimezone();
725 + date_default_timezone_set(JFactory::getApplication()->get('offset', 'UTC'));
726 +}, 10, 2);
727 +
728 +/**
729 + * Restores the timezone of the website after dispatching
730 + * a widget in order to avoid strange behaviors with other plugins.
731 + *
732 + * @param string $id The widget ID (path name).
733 + * @param string &$html The HTML of the widget to display.
734 + *
735 + * @since 1.2.10
736 + */
737 +add_action('vik_widget_after_dispatch_site', function($id, &$html)
738 +{
739 + // restore standard timezone
740 + date_default_timezone_set(JDate::getDefaultTimezone());
741 +}, 10, 2);
742 +
743 +/**
744 + * Added support for Loco Translate.
745 + * In case some translations have been edited by using this plugin,
746 + * we should look within the Loco Translate folder to check whether
747 + * the requested translation is available.
748 + *
749 + * @param boolean $loaded True if the translation has been already loaded.
750 + * @param string $domain The plugin text domain to load.
751 + *
752 + * @return boolean True if a new translation is loaded.
753 + *
754 + * @since 1.6.0
755 + */
756 +add_filter('vik_plugin_load_language', function($loaded, $domain)
757 +{
758 + // proceed only in case the translation hasn't been loaded
759 + // and Loco Translate plugin is installed
760 + if (!$loaded && is_dir(WP_LANG_DIR . DIRECTORY_SEPARATOR . 'loco'))
761 + {
762 + // Build LOCO path.
763 + // Since load_plugin_textdomain accepts only relative paths,
764 + // we should go back to the /wp-contents/ folder first.
765 + $loco = implode(DIRECTORY_SEPARATOR, array('..', 'languages', 'loco', 'plugins'));
766 +
767 + // try to load the plugin translation from Loco folder
768 + $loaded = load_plugin_textdomain($domain, false, $loco);
769 + }
770 +
771 + return $loaded;
772 +}, 10, 2);
773 +
774 +/**
775 + * Display notice messages in third party plugins
776 + * to suggest the import of the reservations.
777 + *
778 + * @since 1.3.5
779 + */
780 +add_action('admin_notices', function()
781 +{
782 + // main library
783 + require_once VBO_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikbooking.php';
784 +
785 + // load supported plugins
786 + $supported_plugins = VikBooking::canImportBookingsFromThirdPartyPlugins();
787 +
788 + if (wp_doing_ajax() || $supported_plugins === false)
789 + {
790 + return;
791 + }
792 +
793 + $lookup = array(
794 + 'admin.php' => 'page',
795 + 'edit.php' => 'post_type',
796 + );
797 +
798 + global $pagenow;
799 +
800 + if (!isset($lookup[$pagenow]))
801 + {
802 + // page not observed
803 + return;
804 + }
805 +
806 + $input = JFactory::getApplication()->input;
807 +
808 + if (!preg_match("/^mphb_/i", $input->get($lookup[$pagenow])))
809 + {
810 + return;
811 + }
812 +
813 + // get logo URI
814 + $backlogo = VikBooking::getBackendLogo();
815 + ?>
816 + <style>
817 + #mphb-vbo-import-notice {
818 + display: inline-block;
819 + width: 100%;
820 + box-sizing: border-box;
821 + border-left-color: #cc9907;
822 + box-shadow: 0 5px 10px rgba(0,0,0,.05);
823 + }
824 + #mphb-vbo-import-notice a.vbo-import-button {
825 + float: right;
826 + border: none;
827 + font-size: 14px;
828 + margin: 18px 10px;
829 + padding: 12px 29px;
830 + color: #FFF;
831 + text-shadow: none;
832 + font-weight: bold;
833 + background: #3AA03C;
834 + -moz-border-radius: 3px;
835 + border-radius: 3px;
836 + -webkit-border-radius: 3px;
837 + text-decoration: none;
838 + height: 50px;
839 + text-align: center;
840 + text-transform: uppercase;
841 + box-shadow: none;
842 + line-height: 26px;
843 + }
844 + a.vbo-import-button:hover {
845 + background: #43BD45 !important;
846 + }
847 + .vbo-import-logo {
848 + display: inline-block;
849 + margin-top: 21px;
850 + max-width: 49px;
851 + }
852 + .vbo-import-text {
853 + font-size: 18px;
854 + display: inline-block;
855 + vertical-align: top;
856 + margin: 31px 10px 10px 10px;
857 + }
858 + </style>
859 +
860 + <div class="notice is-dismissible notice-info" id="mphb-vbo-import-notice">
861 + <div class="vbo-import-wrap">
862 + <p>
863 + <span class="vbo-import-logo">
864 + <img src="<?php echo VBO_ADMIN_URI . (!empty($backlogo) ? "resources/{$backlogo}" : 'vikbooking.png'); ?>" alt="VikBooking Logo" />
865 + </span>
866 + <span class="vbo-import-text"><?php echo JText::sprintf('VBO_IMPBFROM_INTO_VBO', $supported_plugins['mphb']); ?></span>
867 + <a class="button vbo-import-button" href="admin.php?option=com_vikbooking&view=importbftpp"><?php echo JText::translate('VBO_IMPBFTPP_DOIMPORT_SHORT'); ?></a>
868 + </p>
869 + </div>
870 + </div>
871 + <?php
872 +});
873 +
874 +/**
875 + * Detect outdated VCM versions.
876 + *
877 + * @since 1.8.13
878 + */
879 +add_action('admin_notices', function()
880 +{
881 + global $pagenow;
882 +
883 + if (wp_doing_ajax())
884 + {
885 + // nothing to check
886 + return;
887 + }
888 +
889 + $option = JFactory::getApplication()->input->get('option');
890 + $inPlugins = in_array($option, ['com_vikbooking', 'com_vikchannelmanager']);
891 +
892 + if (!$inPlugins && $pagenow != 'plugins.php')
893 + {
894 + // nothing to check
895 + return;
896 + }
897 +
898 + if (!defined('VIKCHANNELMANAGER_SOFTWARE_VERSION') || version_compare(VIKCHANNELMANAGER_SOFTWARE_VERSION, VIKCHANNELMANAGER_MINIMUM_VERSION, '>='))
899 + {
900 + // check passed
901 + return;
902 + }
903 +
904 + echo JLayoutHelper::render(
905 + 'html.vcm.version',
906 + ['page' => $inPlugins ? preg_replace('/^com_/', '', $option) : $pagenow],
907 + null,
908 + ['component' => 'com_vikbooking']
909 + );
910 +});
911 +
912 +/**
913 + * Downloads the RSS feeds after loading the dashboard of VikBooking.
914 + *
915 + * @since 1.3.9
916 + */
917 +add_action('vikbooking_after_display_dashboard', array('VikBookingRssFeeds', 'download'));
918 +
919 +/**
920 + * Trigger event to allow the plugins to include custom HTML within the view.
921 + * It is possible to return an associative array to group the HTML strings
922 + * under different fieldsets. Plain/html string will be always pushed within
923 + * the "custom" fieldset instead.
924 + *
925 + * Displays the RSS configuration.
926 + *
927 + * @param mixed $forms The HTML to display.
928 + * @param mixed $view The current view instance.
929 + *
930 + * @return mixed The HTML to display.
931 + *
932 + * @since 1.3.9
933 + */
934 +add_filter('vikbooking_display_view_config_global', array('VikBookingRssFeeds', 'config'), 10, 2);
935 +
936 +/**
937 + * Save the RSS configuration every time "saveconfig" task is reached.
938 + *
939 + * @since 1.3.9
940 + */
941 +add_action('vikbooking_before_dispatch', function()
942 +{
943 + $input = JFactory::getApplication()->input;
944 +
945 + if ($input->get('task') == 'saveconfig')
946 + {
947 + VikBookingRssFeeds::save();
948 + }
949 +});
950 +
951 +/**
952 + * Hook used to manipulate the RSS channels to which the plugin is subscribed.
953 + *
954 + * @param array $channels A list of RSS permalinks.
955 + * @param boolean $status True to return only the published channels.
956 + *
957 + * @return array A list of supported channels.
958 + *
959 + * @since 1.3.9
960 + */
961 +add_filter('vikbooking_fetch_rss_channels', array('VikBookingRssFeeds', 'getChannels'), 10, 2);
962 +
963 +/**
964 + * Hook used to apply some stuff before returning the RSS reader.
965 + *
966 + * @param JRssReader &$rss The RSS reader handler.
967 + *
968 + * @since 1.3.9
969 + */
970 +add_action('vikbooking_before_use_rss', array('VikBookingRssFeeds', 'ready'));
971 +
972 +/**
973 + * Hook used to support browser notifications on any /wp-admin
974 + * page that doesn't belong to Vik Booking. Note that the hook
975 + * should be 'admin_footer' and not 'admin_print_footer_scripts'.
976 + *
977 + * @since 1.5.0
978 + */
979 +add_action('admin_footer', function()
980 +{
981 + $app = JFactory::getApplication();
982 + $input = $app->input;
983 +
984 + // make sure we are not inside Vik Booking
985 + if ($input->get('option') == 'com_vikbooking' || $input->get('page') == 'vikbooking' || $input->get('action') == 'vikbooking')
986 + {
987 + return;
988 + }
989 +
990 + /**
991 + * Avoid conflicts with third-party page-builder plugins that may simulate the front-end.
992 + *
993 + * @since 1.8.1
994 + */
995 + if (!$app->isClient('administrator'))
996 + {
997 + return;
998 + }
999 +
1000 + /**
1001 + * Let third party plugins stop Vik Booking from loading assets on other wp-admin pages.
1002 + *
1003 + * @since 1.6.1
1004 + */
1005 + $allowed = apply_filters('vikbooking_load_external_assets', true);
1006 + if (!$allowed)
1007 + {
1008 + return;
1009 + }
1010 +
1011 + // initialize timezone handler
1012 + JDate::getDefaultTimezone();
1013 + date_default_timezone_set($app->get('offset', 'UTC'));
1014 +
1015 + // load the necessary assets for external pages
1016 + VikBookingAssets::loadForExternal();
1017 +
1018 + // restore standard timezone
1019 + date_default_timezone_set(JDate::getDefaultTimezone());
1020 +
1021 + /**
1022 + * Reload system configuration scripts to allow
1023 + * Vik Booking to preload texts also on VCM.
1024 + *
1025 + * @since 1.6.0
1026 + */
1027 + JHtml::fetch('behavior.core');
1028 +});
1029 +
1030 +/**
1031 + * Prevent WordPress Themes from running wptexturize() that may erroneously
1032 + * detect HTML tags among raw JavaScript code, by encoding ampersand symbols.
1033 + *
1034 + * @since 1.6.9
1035 + */
1036 +add_filter('run_wptexturize', function($run_texturize)
1037 +{
1038 + return is_admin() ? $run_texturize : false;
1039 +}, PHP_INT_MAX);