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 | libraries/system/rssfeeds.php +450 -0 1.6.3 → 1.8.16 View file →
@@ -1,0 +1,450 @@
1 +<?php
2 +/**
3 + * @package VikBooking - Libraries
4 + * @subpackage system
5 + * @author E4J s.r.l.
6 + * @copyright Copyright (C) 2020 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 + * Helper class used to manage settings related to RSS feeds.
16 + *
17 + * @since 1.3.9
18 + */
19 +class VikBookingRssFeeds
20 +{
21 + /**
22 + * Hook used to manipulate the RSS channels.
23 + *
24 + * @param array $channels A list of RSS permalinks.
25 + * @param boolean $published True to return only the published channels.
26 + *
27 + * @return array The channels to use for RSS subscription.
28 + */
29 + public static function getChannels(array $channels = array(), $published = true)
30 + {
31 + // subscribe reader to the following channels
32 + $default = array(
33 + 'https://vikwp.com/rss/news/',
34 + 'https://vikwp.com/rss/promo/',
35 + 'https://vikwp.com/rss/tips/',
36 + );
37 +
38 + // allow channels manipulation only to PRO users
39 + if (VikBookingLicense::isPro() && $published)
40 + {
41 + $user = JFactory::getUser();
42 +
43 + // get channels configuration
44 + $config = get_user_meta($user->id, 'vikbooking_rss_urls', true);
45 +
46 + // make sure we have a configuration
47 + if (is_array($config))
48 + {
49 + // take only the active channels
50 + $default = array_intersect($default, $config);
51 + }
52 + }
53 +
54 + // apply filters only in case we need the final URI
55 + if ($published)
56 + {
57 + // build query string for each channel
58 + $default = array_map(function($url)
59 + {
60 + // create URI
61 + $url = new JUri($url);
62 +
63 + // append format and type
64 + $url->setVar('format', 'feed');
65 + $url->setVar('type', 'rss');
66 +
67 + // apply tag filter (8: vikbooking, 12: vbo-lite, 16: vbo-pro)
68 + $tags = array(8);
69 +
70 + if (VikBookingLicense::isPro())
71 + {
72 + // PRO tag
73 + $tags[] = 16;
74 + }
75 + else
76 + {
77 + // LITE tag
78 + $tags[] = 12;
79 + }
80 +
81 + $url->setVar('filter_tag', $tags);
82 +
83 + // take language from WP locale
84 + $langtag = JFactory::getLanguage()->getTag();
85 +
86 + // look for language part
87 + if (preg_match("/^([a-z]{2,})[\-_][a-z]{2,}$/i", $langtag, $match))
88 + {
89 + // Append language to URI.
90 + // In case the language is not supported, the system
91 + // will fallback to the default one.
92 + $url->setVar('lang', end($match));
93 + }
94 +
95 + // take only the channel string
96 + return (string) $url;
97 + }, $default);
98 + }
99 +
100 + // merge default channels with existing ones
101 + return array_merge($channels, $default);
102 + }
103 +
104 + /**
105 + * Downloads the latest feed and display it, if any.
106 + *
107 + * @return void
108 + */
109 + public static function download()
110 + {
111 + $app = JFactory::getApplication();
112 + $user = JFactory::getUser();
113 +
114 + // make sure that all the following conditions are verified
115 + $conditions = (
116 + // we are not doing AJAX
117 + !wp_doing_ajax()
118 + // we are in the back-end
119 + && $app->isClient('administrator')
120 + // the user is an administrator
121 + && $user->authorise('core.admin', 'com_vikbooking')
122 + // the dashboard should display the RSS feeds
123 + && static::isDashboard()
124 + // the initial setup was at least started
125 + && static::hasMinimumSetup()
126 + );
127 +
128 + // validate conditions flag
129 + if ($conditions)
130 + {
131 + // instantiate RSS reader
132 + $rss = VikBookingBuilder::setupRssReader();
133 +
134 + try
135 + {
136 + // prepare download options
137 + $options = array(
138 + // take only one item
139 + 'limit' => 1,
140 + // take only visible feeds
141 + 'new' => true,
142 + // take oldest feed
143 + 'order' => 'asc',
144 + );
145 +
146 + // try to download the feed
147 + $feed = $rss->download($options);
148 +
149 + if ($feed)
150 + {
151 + // opt-in missing, ask the user to agree to our terms
152 + echo JLayoutHelper::render('html.rss.feed', array('feed' => $feed));
153 + }
154 + }
155 + catch (JRssOptInException $e)
156 + {
157 + // opt-in missing, ask the user to agree to our terms
158 + echo JLayoutHelper::render('html.rss.optin');
159 + }
160 + catch (Throwable $e)
161 + {
162 + // service declined, go ahead silently
163 + }
164 + }
165 + }
166 +
167 + /**
168 + * Displays the configuration fieldset to manage the opt-in.
169 + *
170 + * @param mixed $forms The HTML to display.
171 + * @param mixed $view The current view instance.
172 + *
173 + * @return mixed The HTML to display.
174 + *
175 + * @return mixed The HTML to display.
176 + */
177 + public static function config($forms, $view)
178 + {
179 + $app = JFactory::getApplication();
180 + $user = JFactory::getUser();
181 +
182 + if (!is_array($forms))
183 + {
184 + $forms = array();
185 + }
186 +
187 + // make sure we are under VikBooking
188 + if ($app->input->get('option') != 'com_vikbooking')
189 + {
190 + // do not go ahead
191 + return $forms;
192 + }
193 +
194 + // instantiate RSS reader
195 + $rss = VikBookingBuilder::setupRssReader();
196 +
197 + // set up configuration array
198 + $config = array();
199 +
200 + try
201 + {
202 + $config['optin'] = $rss->optedIn();
203 + }
204 + catch (Exception $e)
205 + {
206 + $config['optin'] = false;
207 + }
208 +
209 + // get published channels
210 + $config['channels'] = $rss->getChannels();
211 +
212 + // take only the host and path because the query string might vary
213 + $config['channels'] = array_map(function($url)
214 + {
215 + $url = new JUri($url);
216 + $url->setQuery('');
217 + return (string) $url;
218 + }, $config['channels']);
219 +
220 + // load all supported channels
221 + $list = apply_filters('vikbooking_fetch_rss_channels', array(), false);
222 +
223 + $channels = array();
224 +
225 + // iterate channels to fetch a readable label
226 + foreach ($list as $url)
227 + {
228 + $url = new JUri($url);
229 +
230 + // get path without trailing slash
231 + $key = trim($url->toString(array('host', 'path')), '/');
232 + // explode paths
233 + $chunks = explode('/', $key);
234 + // take only the last
235 + $key = array_pop($chunks);
236 +
237 + // prepend path recursively in case of non-unique path
238 + while (isset($channels[$key]) && $chunks)
239 + {
240 + $key = array_pop($chunks) . ' ' . $key;
241 + }
242 +
243 + // remove query from URL
244 + $url->setQuery('');
245 +
246 + // register channel
247 + $channels[$key] = (string) $url;
248 + }
249 +
250 + // get display dashboard from user meta
251 + $config['dashboard'] = static::isDashboard();
252 +
253 + // prepare layout data
254 + $data = array(
255 + 'rss' => $rss,
256 + 'config' => $config,
257 + 'channels' => $channels,
258 + );
259 +
260 + // include sub-fieldset to enable RSS configuration
261 + $layout = new JLayoutFile('html.rss.config');
262 + // render layout
263 + $html = $layout->render($data);
264 +
265 + // create an apposite fieldset for RSS
266 + $forms['RSS'] = $html;
267 +
268 + return $forms;
269 + }
270 +
271 + /**
272 + * Saves the opt-in choice made by the user.
273 + *
274 + * @return void
275 + */
276 + public static function save()
277 + {
278 + $app = JFactory::getApplication();
279 + $user = JFactory::getUser();
280 +
281 + // make sure we are under VikBooking
282 + if ($app->input->get('option') != 'com_vikbooking')
283 + {
284 + // do not go ahead
285 + return;
286 + }
287 +
288 + // instantiate RSS reader
289 + $rss = VikBookingBuilder::setupRssReader();
290 +
291 + try
292 + {
293 + $status = $rss->optedIn();
294 + }
295 + catch (Exception $e)
296 + {
297 + $status = false;
298 + }
299 +
300 + $input = JFactory::getApplication()->input;
301 +
302 + // get user choice
303 + $choice = $input->getBool('rss_optin_status', false);
304 +
305 + // check whether the choice changed
306 + if ($choice != $status)
307 + {
308 + // update choice
309 + $rss->optIn($choice);
310 + }
311 +
312 + // recover display dashboard from request
313 + $dashboard = $input->get('rss_display_dashboard', 0, 'uint');
314 +
315 + // update dashboard visibility
316 + update_user_meta($user->id, 'vikbooking_rss_display_dashboard', $dashboard);
317 +
318 + // allow channels manipulation only to PRO users
319 + if (VikBookingLicense::isPro())
320 + {
321 + // recover specified channels from request
322 + $channels = $input->get('rss_channel_url', array(), 'string');
323 +
324 + // update channels configuration
325 + update_user_meta($user->id, 'vikbooking_rss_urls', $channels);
326 + }
327 + }
328 +
329 + /**
330 + * Adjusts the RSS class to the plugin needs.
331 + * Executes before using it.
332 + *
333 + * @param JRssReader $rss The RSS reader handler.
334 + *
335 + * @return void
336 + */
337 + public static function ready(&$rss)
338 + {
339 + /**
340 + * Filters the HTML that is allowed for a given context.
341 + *
342 + * @since 3.5.0
343 + *
344 + * @param array $tags An associative array containing the supported tags
345 + * and all the related attributes.
346 + * @param string $context Context name.
347 + */
348 + add_filter('wp_kses_allowed_html', function($tags, $context)
349 + {
350 + // make sure we are filtering a POST context
351 + if ($context == 'post')
352 + {
353 + // add support for input field
354 + $tags['input'] = [
355 + 'type' => true,
356 + 'name' => true,
357 + 'id' => true,
358 + 'class' => true,
359 + 'value' => true,
360 + 'style' => true,
361 + 'disabled' => true,
362 + 'readonly' => true,
363 + ];
364 +
365 + // add support for textarea field
366 + $tags['textarea'] = [
367 + 'name' => true,
368 + 'id' => true,
369 + 'class' => true,
370 + 'style' => true,
371 + 'rows' => true,
372 + 'cols' => true,
373 + 'disabled' => true,
374 + 'readonly' => true,
375 + ];
376 +
377 + // add support for button
378 + if (isset($tags['button']))
379 + {
380 + // just include the use of onclick attribute
381 + $tags['button']['onclick'] = true;
382 + }
383 + else
384 + {
385 + // define all supported attributes
386 + $tags['button'] = [
387 + 'type' => true,
388 + 'id' => true,
389 + 'class' => true,
390 + 'style' => true,
391 + 'onclick' => true,
392 + 'disabled' => true,
393 + ];
394 + }
395 +
396 + // add support for source under a <video> tag
397 + $tags['source'] = [
398 + 'src' => true,
399 + ];
400 + }
401 +
402 + return $tags;
403 + }, 10, 2);
404 + }
405 +
406 + /**
407 + * Returns true in case the RSS feeds should be displayed
408 + * within the dashboard of VikBooking.
409 + *
410 + * @return boolean
411 + */
412 + public static function isDashboard()
413 + {
414 + $user = JFactory::getUser();
415 +
416 + // get display dashboard from user meta
417 + $dashboard = get_user_meta($user->id, 'vikbooking_rss_display_dashboard', true);
418 +
419 + // make sure we have a number
420 + if (preg_match("/^[01]$/", (string) $dashboard))
421 + {
422 + // cast value to boolean
423 + $dashboard = (bool) $dashboard;
424 + }
425 + else
426 + {
427 + // missing configuration, always show by default
428 + $dashboard = true;
429 + }
430 +
431 + return $dashboard;
432 + }
433 +
434 + /**
435 + * Returns true in case a minimum setup has been started.
436 + *
437 + * @return boolean
438 + */
439 + public static function hasMinimumSetup()
440 + {
441 + $dbo = JFactory::getDbo();
442 +
443 + $q = "SELECT `id` FROM `#__vikbooking_rooms`";
444 +
445 + $dbo->setQuery($q);
446 + $dbo->execute();
447 +
448 + return ($dbo->getNumRows() > 0);
449 + }
450 +}