| @@ -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); | |