PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.2
VikBooking Hotel Booking Engine & PMS v1.7.2
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / libraries / adapter / application / document.php

document.php in VikBooking Hotel Booking Engine & PMS 1.7.2, at libraries/adapter/application/document.php

625 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikWP - Libraries
4 * @subpackage adapter.application
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * Document class, provides an easy interface to parse and display a document
16 * using the Joomla standard functions.
17 *
18 * @since 10.0
19 */
20 class JDocument
21 {
22 /**
23 * An array to cache the meta data set using this class.
24 *
25 * @var array
26 */
27 protected $data = [];
28
29 /**
30 * A list containing all the style declarations loaded.
31 *
32 * @var array
33 */
34 protected $styleDeclarations = [];
35
36 /**
37 * Array of scripts options.
38 *
39 * @var array
40 * @since 10.1.14
41 */
42 protected $scriptOptions = [];
43
44 /**
45 * Array of scripts declarations to be
46 * appended after the body.
47 *
48 * @var array
49 * @since 10.1.29
50 */
51 protected $ajaxScripts = [];
52
53 /**
54 * Adds the possibility to override the callback used to register
55 * something within the head.
56 *
57 * @param callable
58 * @since 10.1.51
59 */
60 public $attachToHeadCustomCallback = null;
61
62 /**
63 * Sets a meta tag in the front-end only.
64 *
65 * @param string $name Name of the meta HTML tag.
66 * @param mixed $content Value of the meta HTML tag as array or string.
67 * @param string $attribute Attribute to use in the meta HTML tag.
68 *
69 * @return self This object to support chaining.
70 *
71 * @uses attachToHead()
72 */
73 public function setMetaData($name, $content, $attribute = 'name')
74 {
75 $attribute = empty($attribute) || !is_string($attribute) ? 'name' : $attribute;
76
77 if (is_scalar($content))
78 {
79 $content = array($content);
80 }
81
82 $this->attachToHead(function() use ($name, $content, $attribute)
83 {
84 foreach ($content as $cont)
85 {
86 echo "<meta {$attribute}=\"{$name}\" content=\"" . esc_attr($cont) . "\" />\n";
87 }
88 }, true);
89
90 $this->data[$name] = $content;
91
92 return $this;
93 }
94
95 /**
96 * Gets a meta tag.
97 * Since Wordpress doesn't own a system to handle meta data,
98 * we can only return a cached version of the data set using this class.
99 *
100 * @param string $name Name of the meta HTML tag.
101 *
102 * @return string
103 */
104 public function getMetaData($name)
105 {
106 if (isset($this->data[$name]))
107 {
108 return $this->data[$name];
109 }
110
111 return '';
112 }
113
114 /**
115 * Sets the title of the document in the front-end only.
116 *
117 * @param string $title The title to be set.
118 *
119 * @return self This object to support chaining.
120 *
121 * @link https://developer.wordpress.org/reference/hooks/wp_title/ (Wordpress < 4.4)
122 * @link https://developer.wordpress.org/reference/functions/wp_get_document_title/ (Wordpress 4.4+)
123 */
124 public function setTitle($title)
125 {
126 /**
127 * We should use the hook 'pre_get_document_title' (available from WP >= v4.4),
128 * instead of 'wp_title', or the title won't actually be set.
129 *
130 * @since 10.1.23
131 */
132 add_filter('pre_get_document_title', function() use ($title)
133 {
134 return $title;
135 });
136
137 return $this;
138 }
139
140 /**
141 * Return the title of the document.
142 *
143 * @return string
144 *
145 * @link https://developer.wordpress.org/reference/hooks/wp_title/ (Wordpress < 4.4)
146 * @link https://developer.wordpress.org/reference/functions/wp_get_document_title/ (Wordpress 4.4+)
147 */
148 public function getTitle()
149 {
150 global $wp_version;
151
152 if (version_compare($wp_version, '4.4', '>='))
153 {
154 return wp_get_document_title();
155 }
156
157 return wp_title('&raquo;', false);
158 }
159
160 /**
161 * Sets the description of the document.
162 *
163 * @param string $desc The description to be set.
164 *
165 * @return self This object to support chaining.
166 *
167 * @uses setMetaData()
168 */
169 public function setDescription($desc)
170 {
171 return $this->setMetaData('description', (string) $desc);
172 }
173
174 /**
175 * Return the description of the document.
176 *
177 * @return string
178 *
179 * @uses getMetaData()
180 */
181 public function getDescription()
182 {
183 return $this->getMetaData('description');
184 }
185
186 /**
187 * Adds a linked script to the page.
188 *
189 * @param string $url URL to the linked script.
190 * @param array $options Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9')
191 * @param array $attribs Array of attributes. Example: array('id' => 'scriptid', 'async' => 'async', 'data-test' => 1)
192 *
193 * @return self This object to support chaining.
194 *
195 * @link https://developer.wordpress.org/reference/functions/wp_register_script/
196 */
197 public function addScript($url, $options = [], $attribs = [])
198 {
199 // check if the script should be loaded using WP native libs
200 $version = array_key_exists('version', $options) ? $options['version'] : null;
201 $footer = array_key_exists('footer', $options) ? (bool) $options['footer'] : false;
202 $id = empty($attribs['id']) ? md5($url) : $attribs['id'];
203
204 /**
205 * Use filter to approve/deny the loading of the given script.
206 *
207 * @param boolean $load The recursive filtered value (default 'true').
208 * @param string $url The resource URL.
209 * @param string $id The script ID attribute.
210 * @param string $version The script version, if specified.
211 * @param boolean $footer True whether the script is going to be loaded in the footer.
212 *
213 * @return boolean True to load the resource, false to ignore it.
214 *
215 * @since 10.1.25
216 */
217 $load = apply_filters('vik_before_include_script', true, $url, $id, $version, $footer);
218
219 if ($load)
220 {
221 // make sure this is not an AJAX call
222 if (!wp_doing_ajax())
223 {
224 // if the headers have been sent, the script must be registered in the footer.
225 if (headers_sent())
226 {
227 $footer = true;
228 }
229
230 // the default array of dependencies
231 $deps = [
232 'jquery-core',
233 'jquery-ui-core',
234 ];
235
236 /**
237 * Added support to custom dependencies.
238 *
239 * @since 10.1.38
240 */
241 if (!empty($options['dependencies']))
242 {
243 // join default dependencies with the given ones
244 $deps = array_merge($deps, (array) $options['dependencies']);
245 // get rid of duplicates
246 $deps = array_values(array_unique($deps));
247 }
248
249 // loads scripts always after jQuery Core (included by Wordpress)
250 wp_register_script($id, $url, $deps, $version, $footer);
251 wp_enqueue_script($id);
252 }
253 // since the footer is already printed, we need to each our script directly
254 else if ($url)
255 {
256 if ($version)
257 {
258 $url .= '?ver=' . $version;
259 }
260
261 echo '<script type="text/javascript" src="' . $url . '"></script>';
262 }
263 }
264
265 return $this;
266 }
267
268 /**
269 * Adds a script to the page.
270 *
271 * @param string $content Script snippet.
272 * @param string $type Scripting mime (defaults to 'text/javascript').
273 *
274 * @return self This object to support chaining.
275 *
276 * @uses attachToHead()
277 */
278 public function addScriptDeclaration($content, $type = 'text/javascript')
279 {
280 /**
281 * Always use the script declaration without checking
282 * if it has been already loaded.
283 *
284 * @since 10.1.17
285 */
286 $this->attachToHead(function() use ($content, $type)
287 {
288 /**
289 * Use "joomla-options new" class in case we are attaching a JSON string.
290 * The "new" word means that the options has to be loaded.
291 *
292 * @since 10.1.14
293 */
294 $class = $type == 'application/json' ? ' class="joomla-options new"' : '';
295
296 echo "<script type=\"{$type}\"{$class}>\n{$content}\n</script>\n";
297 });
298
299 return $this;
300 }
301
302 /**
303 * Adds a linked stylesheet to the page.
304 *
305 * @param string $url URL to the linked style sheet.
306 * @param array $options Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9')
307 * @param array $attribs Array of attributes. Example: array('id' => 'stylesheet', 'data-test' => 1)
308 *
309 * @return self This object to support chaining.
310 *
311 * @link https://codex.wordpress.org/Function_Reference/wp_register_style
312 */
313 public function addStyleSheet($url, $options = [], $attribs = [])
314 {
315 $version = array_key_exists('version', $options) ? $options['version'] : null;
316 $media = array_key_exists('media', $options) ? (string) $options['media'] : 'all';
317 $id = empty($attribs['id']) ? md5($url) : $attribs['id'];
318
319 /**
320 * Use filter to approve/deny the loading of the given stylesheet.
321 *
322 * @param boolean $load The recursive filtered value (default 'true').
323 * @param string $url The resource URL.
324 * @param string $id The stylesheet ID attribute.
325 * @param string $version The stylesheet version, if specified.
326 *
327 * @return boolean True to load the resource, false to ignore it.
328 *
329 * @since 10.1.25
330 */
331 $load = apply_filters('vik_before_include_style', true, $url, $id, $version);
332
333 if ($load)
334 {
335 // attach the style to the <head> only if the headers haven't been sent
336 // and if we are not doing an AJAX call
337 if (!headers_sent() && !wp_doing_ajax())
338 {
339 $deps = [];
340
341 /**
342 * Added support to custom dependencies.
343 *
344 * @since 10.1.38
345 */
346 if (!empty($options['dependencies']))
347 {
348 // join default dependencies with the given ones
349 $deps = array_merge($deps, (array) $options['dependencies']);
350 // get rid of duplicates
351 $deps = array_values(array_unique($deps));
352 }
353
354 wp_register_style($id, $url, $deps, $version, $media);
355 wp_enqueue_style($id);
356 }
357 // otherwise print the style in the document <body>
358 else
359 {
360 if ($version)
361 {
362 $url .= '?ver=' . $version;
363 }
364
365 echo '<link rel="stylesheet" id="' . $id . '" href="' . $url . '" type="text/css" media="' . $media . '">';
366 }
367 }
368
369 return $this;
370 }
371
372 /**
373 * Adds a stylesheet declaration to the page.
374 *
375 * @param string $content Style declaration.
376 * @param string $type Type of stylesheet (defaults to 'text/css').
377 *
378 * @return self This object to support chaining.
379 *
380 * @uses attachToHead()
381 */
382 public function addStyleDeclaration($content, $type = 'text/css')
383 {
384 if (!in_array($content, $this->styleDeclarations))
385 {
386 $this->attachToHead(function() use ($content, $type)
387 {
388 echo "<style type=\"{$type}\">\n{$content}\n</style>\n";
389 });
390
391 $this->styleDeclarations[] = $content;
392 }
393
394 return $this;
395 }
396
397 /**
398 * Internal method execute a callback within the <head> tags.
399 * The callback will be attached to the wp_head or admin_head hooks
400 * depending on the section we are currently using.
401 *
402 * @param mixed $callback The callback or the function name to attach.
403 * @param boolean $frontOnly True to attach the method only in the front-end.
404 *
405 * @return void
406 *
407 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/wp_head
408 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/admin_head
409 * @link https://developer.wordpress.org/reference/hooks/wp_print_footer_scripts/
410 * @link https://developer.wordpress.org/reference/hooks/admin_print_footer_scripts/
411 */
412 protected function attachToHead($callback, $frontOnly = false)
413 {
414 $app = JFactory::getApplication();
415
416 // make sure we are in the front-end or the back-end is allowed
417 if ($app->isSite() || !$frontOnly)
418 {
419 /**
420 * If provided, use the custom callback instead.
421 *
422 * @since 10.1.51
423 */
424 if (is_callable($this->attachToHeadCustomCallback))
425 {
426 // invoke callback and teminate
427 return call_user_func_array($this->attachToHeadCustomCallback, [$callback]);
428 }
429
430 // make sure we are not doing an AJAX call
431 if (!wp_doing_ajax())
432 {
433 $head_hook = $app->isAdmin() ? 'admin_head' : 'wp_head';
434
435 // make sure that the head hook that we are using haven't been called yet,
436 // otherwise our script will never be executed
437 if (!headers_sent() && !did_action($head_hook))
438 {
439 // admin_head hook for the back-end <head>
440 // wp_head hook for the front-end <head>
441 add_action($head_hook, $callback);
442 }
443 else
444 {
445 // admin_print_footer_scripts hook for the back-end <footer>
446 // wp_footer wp_print_footer_scripts for the front-end <footer>
447 add_action($app->isAdmin() ? 'admin_print_footer_scripts' : 'wp_print_footer_scripts', $callback);
448
449 /**
450 * NOTE: do not use 'wp_footer' hook because it prints the script declarations
451 * always before the <script> tags, causing errors for missing resources.
452 */
453 }
454 }
455 // we need to invoke our callback directly
456 else
457 {
458 // push scripts within the AJAX callbacks
459 $this->ajaxScripts[] = $callback;
460 }
461 }
462 }
463
464 /**
465 * Returns the AJAX scripts that should be included after
466 * the body in order to properly access all the needed elements.
467 *
468 * @return string
469 *
470 * @since 10.1.29
471 */
472 public function getAjaxScripts()
473 {
474 // start buffering
475 ob_start();
476
477 // iterate registered scripts
478 foreach ($this->ajaxScripts as $callback)
479 {
480 // invoke the callback to print the script
481 call_user_func($callback);
482 }
483
484 // catch buffer
485 $js = ob_get_contents();
486 // clear buffer
487 ob_end_clean();
488
489 // empty list
490 $this->ajaxScripts = [];
491
492 return $js;
493 }
494
495 /**
496 * Add options for script.
497 *
498 * @param string $key Name in Storage.
499 * @param mixed $options Scrip options as array or string.
500 * @param boolean $merge Whether merge with existing (true) or replace (false).
501 *
502 * @return self This object to support chaining.
503 *
504 * @since 10.1.14
505 */
506 public function addScriptOptions($key, $options, $merge = true)
507 {
508 if (empty($this->scriptOptions[$key]))
509 {
510 $this->scriptOptions[$key] = [];
511 }
512
513 if ($merge && is_array($options))
514 {
515 $this->scriptOptions[$key] = array_replace_recursive($this->scriptOptions[$key], $options);
516 }
517 else
518 {
519 $this->scriptOptions[$key] = $options;
520 }
521
522 return $this;
523 }
524
525 /**
526 * Get script(s) options.
527 *
528 * @param string $key Name in Storage.
529 *
530 * @return array Options for given $key, or all script options.
531 *
532 * @since 10.1.14
533 */
534 public function getScriptOptions($key = null)
535 {
536 if ($key)
537 {
538 return (empty($this->scriptOptions[$key])) ? [] : $this->scriptOptions[$key];
539 }
540 else
541 {
542 return $this->scriptOptions;
543 }
544 }
545
546 /**
547 * Returns the document charset encoding.
548 *
549 * @return string
550 *
551 * @since 10.1.20
552 */
553 public function getCharset()
554 {
555 $output = get_option('blog_charset');
556
557 if (!$output)
558 {
559 $output = 'UTF-8';
560 }
561
562 return $output;
563 }
564
565 /**
566 * Returns the document language.
567 *
568 * @return string
569 *
570 * @since 10.1.20
571 */
572 public function getLanguage()
573 {
574 return strtolower(JFactory::getLanguage()->getTag());
575 }
576
577 /**
578 * Returns the document direction declaration.
579 *
580 * @return string
581 *
582 * @since 10.1.20
583 */
584 public function getDirection()
585 {
586 if (function_exists('is_rtl'))
587 {
588 $output = is_rtl() ? 'rtl' : 'ltr';
589 }
590 else
591 {
592 $output = 'ltr';
593 }
594
595 return $output;
596 }
597
598 /**
599 * Adds `<link>` tags to the head of the document.
600 *
601 * $relType defaults to 'rel' as it is the most common relation type used
602 * ('rev' refers to reverse relation, 'rel' indicates normal, forward relation).
603 * Typical tag: `<link href="index.php" rel="Start">`.
604 *
605 * @param string $href The link that is being related.
606 * @param string $relation Relation of link.
607 * @param string $relType Relation type attribute. Either rel or rev (default: 'rel').
608 * @param array $attribs Associative array of remaining attributes.
609 *
610 * @return self This object to support chaining.
611 *
612 * @since 10.1.48
613 */
614 public function addHeadLink(string $href, string $relation, string $relType = 'rel', array $attribs = [])
615 {
616 $this->attachToHead(function() use ($href, $relation, $relType, $attribs)
617 {
618 JLoader::import('adapter.utilities.array');
619 echo "<link href=\"{$href}\" {$relType}=\"$relation\" " . ArrayHelper::toString($attribs) . " />\n";
620 });
621
622 return $this;
623 }
624 }
625