PluginProbe
FareHarbor for WordPress / 3.6.10
FareHarbor for WordPress v3.6.10
3.6.15 3.6.14 trunk 1.1 1.2 2.0 2.1 3.0 3.0.1 3.1 3.2 3.3 3.3.1 3.4 3.5 3.6 3.6.1 3.6.10 3.6.11 3.6.12 3.6.13 3.6.2 3.6.3 3.6.4 3.6.5 All 29 releases
fareharbor / fareharbor.php

fareharbor.php in FareHarbor for WordPress 3.6.10, at fareharbor.php

1,196 lines 35.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: FareHarbor for WordPress
4 Plugin URI: https://fareharbor.com/help/setup/wordpress-plugin/
5 Description: Easily add FareHarbor reservation calendars and buttons to your site
6 Version: 3.6.10
7 Author: FareHarbor
8 Author URI: https://fareharbor.com
9 */
10
11 // Make sure this file isn't loaded on its own
12 // -----------------------------------------------
13
14 defined( 'ABSPATH' ) or die( 'Lost? <a href="/">Return home.</a>' );
15
16 // Add init hook
17 // -----------------------------------------------
18
19 add_action( 'init', array( 'fareharbor', 'init' ) );
20
21
22 // Global functions for potential backwards compatability
23 // -----------------------------------------------
24
25 function fh_shortcode( $attrs ) {
26 return fareharbor::fareharbor_shortcode( $attrs );
27 }
28
29 function lightframe_shortcode( $attrs, $content = '' ) {
30 return fareharbor::lightframe_shortcode( $attrs, $content );
31 }
32
33 function partners_shortcode( $attrs ) {
34 return fareharbor::partners_shortcode( $attrs );
35 }
36
37
38 // The important stuff
39 // -----------------------------------------------
40
41 final class fareharbor {
42
43 // This class is just a namespace for static methods & variables
44 private function __construct() {}
45
46 public static $version = '3.6.10';
47
48 // Update the saved version number in the wp_options table
49 // ===============================================
50
51 public static function init() {
52
53 // In a multisite environment some themes may wish to disable
54 // this plugin.
55 if ( apply_filters( 'fareharbor/disabled', false ) )
56 return;
57
58 // Register the shortcodes
59 // -----------------------------------------------
60
61 add_shortcode( 'fareharbor', array( 'fareharbor', 'fareharbor_shortcode' ) );
62 add_shortcode( 'lightframe', array( 'fareharbor', 'lightframe_shortcode' ) );
63 add_shortcode( 'partners', array( 'fareharbor', 'partners_shortcode' ) );
64 add_shortcode( 'itemgrid', array( 'fareharbor', 'itemgrid_shortcode' ) );
65 // add_shortcode( 'bookembed', array( 'fareharbor', 'bookembed_shortcode' ) );
66
67 // Register our Settings Page & Settings
68 // -----------------------------------------------
69
70 add_action( 'admin_menu', array( 'fareharbor', 'register_options_page' ) );
71 add_action( 'admin_init', array( 'fareharbor', 'register_settings' ) );
72
73
74 // Include the script in the footer
75 // -----------------------------------------------
76
77 add_action( 'wp_footer', array( 'fareharbor', 'lightframe_api_footer' ) );
78
79
80 // Maybe include fh-kit styles in header
81 // -----------------------------------------------
82 // Depends on option being set in the admin dashboard
83 add_action( 'wp_enqueue_scripts', array( 'fareharbor', 'maybe_enqueue_fh_kit_styles' ) );
84
85 $saved_version = get_option( 'fareharbor_version' );
86 if ( $saved_version !== self::$version )
87 self::upgrade( $saved_version );
88
89 }
90
91 // Upgrade
92 // ===============================================
93
94 private static function upgrade( $from ) {
95
96 if ( !$from ) {
97 // New install or upgrade from version before 3.0, before we saved
98 // version numbers in the database. No choice but to treat those
99 // as a new install.
100 // No settings should be saved but let's be careful not to override
101 // just in case
102 $saved_settings = get_option( 'fareharbor_settings', array() );
103 if ( !is_array( $saved_settings ) )
104 // Even less likely, but again just in case
105 $saved_settings = array();
106
107 $defaults = array(
108 'fh_responsive_calendars' => 'on',
109 'fh_default_fallback' => 'simple',
110 'fh_auto_lightframe_enabled' => 'on',
111 );
112 update_option( 'fareharbor_settings', $saved_settings + $defaults );
113
114 // All new installs from v3.4 on should use v2 of the stylesheet
115 update_option( 'fareharbor_kit_version', 'v2' );
116 }
117 elseif ( version_compare( $from, '3.4', '<' ) ) {
118 // Can't swap version of old sites that might already be using v1
119 // of the stylesheet!
120 update_option( 'fareharbor_kit_version', 'v1' );
121 }
122
123 update_option( 'fareharbor_version', self::$version, true );
124
125 }
126
127 // Script source
128 // ===============================================
129
130 public static function lightframe_api_footer() {
131
132 $src = 'https://' . self::url() . '/embeds/api/v1/';
133
134 if ( self::get_option( 'fh_auto_lightframe_enabled' ) )
135 $src .= '?autolightframe=yes';
136
137 echo "<!-- FareHarbor plugin activated --><script src=\"$src\"></script>";
138
139 }
140
141
142 // FH-Kit Styles
143 // ===============================================
144
145 public static function maybe_enqueue_fh_kit_styles() {
146
147 if ( self::is_lite() )
148 return;
149
150 if( !self::get_option( 'fh_buttons_active' ) )
151 return;
152
153 $query_string = self::get_option( 'fh_buttons_query' );
154
155 $query_string = strip_tags( $query_string );
156 $query_string = trim( $query_string );
157 $query_string = ltrim( $query_string, '?' );
158
159 // Default to v1 for sites that don't have this in the options table in
160 // case upgrade procedure didn't run. All new installs should get
161 // `fareharbor_kit_version` saved as v2 upon install.
162 $version = get_option( 'fareharbor_kit_version', 'v1' );
163 // Make the version filterable
164 $version = apply_filters( 'fareharbor/fh_kit_version', $version );
165 // Validate. If we got something funky (as opposed to nothing at all) then
166 // we'll default to version 2.
167 if ( !in_array( $version, array( 'v1', 'v2', ), true ) )
168 $version = 'v2';
169
170 $fh_kit_src = "https://fh-kit.com/buttons/$version/";
171
172 if ( $query_string )
173 $fh_kit_src .= '?' . $query_string;
174
175 $fh_kit_src = apply_filters( 'fareharbor/buttons_style_src', $fh_kit_src );
176
177 // the 4th parameter is $version. Leaving it out causes WP to
178 // add ver={current-wp-version} to the url. passing null stops this.
179 wp_enqueue_style( 'fh-buttons', $fh_kit_src, array(), null );
180
181 }
182
183
184 // Default Arguments
185 // ===============================================
186
187 private static $shared_defaults,
188 $lightframe_defaults,
189 $calendar_defaults,
190 $partners_defaults,
191 $itemgrid_defaults,
192 $bookembed_defaults;
193
194 public static function _clear_options() {
195 // This method exists for testing only.
196 self::$options = null;
197 self::$shared_defaults = null;
198 self::$lightframe_defaults = null;
199 self::$calendar_defaults = null;
200 self::$partners_defaults = null;
201 self::$itemgrid_defaults = null;
202 self::$bookembed_defaults = null;
203 }
204
205 private static function init_defaults() {
206
207 if ( isset( self::$shared_defaults ) )
208 return;
209
210 self::$shared_defaults = array(
211
212 'shortname' => self::get_option( 'fh_default_shortname', '' ),
213 'items' => '',
214 'asn' => self::get_option( 'fh_default_asn', '' ),
215 'asn_ref' => self::get_option( 'fh_default_asn_ref', '' ),
216 'ref' => self::get_option( 'fh_default_ref', '' ),
217 'lightframe' => self::get_option( 'fh_default_lightframe', 'yes' ),
218 'full_items' => self::get_option( 'fh_default_full_items', 'no' ),
219 'sheet' => self::get_option( 'fh_default_sheet', '' ),
220 'sheet_uuid' => '',
221 'schedule' => self::get_option( 'fh_default_schedule', '' ),
222 'schedule_uuid' => '',
223 'fallback' => 'simple',
224 'flow' => '',
225 'language' => self::get_option( 'fh_default_language', '' ),
226 'branding' => '',
227 'bookable_only' => '',
228
229 );
230
231 self::$bookembed_defaults =
232 self::$lightframe_defaults = array(
233
234 // 'class' => '',
235 // 'style' => '',
236 // 'id' => '',
237 'view' => 'items',
238 'view_item' => '',
239 'view_availability' => '',
240
241 );
242 self::$bookembed_defaults[ 'fallback' ] = '';
243
244 self::$calendar_defaults = array();
245
246 if ( self::get_option( 'fh_responsive_calendars', false ) )
247 self::$calendar_defaults[ 'type' ] = 'calendar';
248 else
249 self::$calendar_defaults[ 'type' ] = 'calendar-small';
250
251 self::$partners_defaults = array(
252
253 'include' => '',
254
255 );
256
257 self::$itemgrid_defaults = array();
258
259 }
260
261
262 // [lightframe][/lightframe] shortcode
263 // ===============================================
264
265 public static function lightframe_shortcode( $attrs, $content = '' ) {
266
267 $link_attrs = self::lightframe_link_attrs( $attrs );
268
269 if ( $error = self::maybe_handle_shortcode_error( $link_attrs ) )
270 return $error;
271
272 if ( !empty( $attrs[ 'class' ] ) )
273 $link_attrs[ 'class' ] = $attrs[ 'class' ];
274 elseif ( $default_class = self::get_option( 'fh_default_class' ) )
275 $link_attrs[ 'class' ] = $default_class;
276
277 if ( !empty( $attrs[ 'id' ] ) )
278 $link_attrs[ 'id' ] = $attrs[ 'id' ];
279
280 if ( !empty( $attrs[ 'style' ] ) )
281 $link_attrs[ 'style' ] = $attrs[ 'style' ];
282
283 $link_attrs = array_map( 'strip_tags', $link_attrs );
284
285 $link_attrs_string = '';
286 foreach ( $link_attrs as $name => $value ) {
287 $value = esc_attr($value);
288 $link_attrs_string .= " $name=\"$value\"";
289 }
290
291 if ( trim( $content ) )
292 $content = do_shortcode( $content );
293
294 return "<a$link_attrs_string>$content</a>";
295
296 }
297
298 public static function lightframe_link_attrs( $args ) {
299
300 if ( !isset( self::$lightframe_defaults ) )
301 self::init_defaults();
302
303 $args = self::process_args( $args, self::$lightframe_defaults, 'lightframe' );
304
305 if ( isset( $args[ 'error' ] ) )
306 return $args;
307
308 if ( $args[ 'view_availability' ] && !$args[ 'view_item' ] )
309 return array( 'error' => 'view_availability but no view_item' );
310
311 $fallback_url = self::lightframe_fallback_url( $args );
312
313 $api_options = self::lightframe_api_options( $args );
314 $json = strtr( json_encode( $api_options ), '"', "'" );
315
316 return array(
317 'href' => $fallback_url,
318 'target' => '_blank',
319 'onclick' => "FH.open($json); return false;",
320 );
321
322 }
323
324 private static function lightframe_fallback_url( $args, $is_bookembed = false ) {
325
326 // The bookembed url structure is very similar to the simple fallback url structure
327 $is_simple_fallback = ( $args[ 'fallback' ] === '' ) || ( $args[ 'fallback' ] === 'simple' ) || $is_bookembed;
328
329 $url = 'https://' . self::url() . '/';
330
331 if ( $is_bookembed )
332 $url .= 'embeds/script/book/';
333 elseif ( $is_simple_fallback )
334 $url .= 'embeds/book/';
335
336 $url .= $args[ 'shortname' ] . '/';
337
338 if ( !$is_simple_fallback
339 || $args[ 'view' ] === 'all-availability'
340 || $args[ 'view_item' ]
341 ) {
342 $url .= 'items/';
343 }
344
345 if ( $args[ 'view_item' ] ) {
346
347 $url .= $args[ 'view_item' ] . '/';
348
349 if ( $args[ 'view_availability' ] )
350 $url .= 'availability/' . $args[ 'view_availability' ] . '/book/';
351 elseif ( $args[ 'full_items' ] === 'no' )
352 $url .= 'calendar/';
353
354 } elseif ( $args[ 'view' ] === 'all-availability' ) {
355
356 $url .= 'calendar/';
357
358 }
359
360 $query = self::get_shared_args_array( $args, 'dash', $is_simple_fallback, false, true );
361
362 if ( $is_simple_fallback && $args[ 'items' ] )
363 $query[ 'selected-items' ] = $args[ 'items' ];
364
365 if ( $query )
366 $url .= '?' . http_build_query( $query );
367
368 return $url;
369
370 }
371
372 private static function lightframe_api_options( $args ) {
373
374 $lo = array( 'shortname' => $args[ 'shortname' ] );
375
376 // Filter the visible items
377 if ( $args[ 'items' ] )
378 // putting it in an array so it gets brackets in json_encode
379 $lo[ 'items' ] = explode( ',', $args[ 'items' ] );
380
381 // Set the view
382 if ( $args[ 'view_item' ] ) {
383
384 $lo[ 'view' ] = array( 'item' => $args[ 'view_item' ] );
385
386 if ( $args[ 'view_availability' ] )
387 $lo[ 'view' ][ 'availability' ] = $args[ 'view_availability' ];
388
389 } elseif ( in_array( $args[ 'view' ], array( 'items', 'all-availability' ), true ) ) {
390
391 $lo[ 'view' ] = $args[ 'view' ];
392
393 } else {
394
395 $lo[ 'view' ] = 'items';
396
397 }
398
399 // Modifiers: shared args like fallback, asn, asn_ref, etc.
400 $lo += self::get_shared_args_array( $args, 'camel', true, true, true );
401
402 return $lo;
403
404 }
405
406
407 // [bookembed] shortcode
408 // ===============================================
409
410 public static function bookembed_shortcode( $attrs ) {
411
412 $script_src = self::bookembed_script_src( $attrs );
413
414 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
415 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
416
417 }
418
419 public static function bookembed_script_src( $args ) {
420
421 if ( !isset( self::$bookembed_defaults ) )
422 self::init_defaults();
423
424 $args = self::process_args( $args, self::$bookembed_defaults, 'bookembed' );
425
426 if ( isset( $args[ 'error' ] ) )
427 return $args;
428
429 if ( $args[ 'view_availability' ] && !$args[ 'view_item' ] )
430 return array( 'error' => 'view_availability but no view_item' );
431
432 return self::lightframe_fallback_url( $args, true );
433
434 }
435
436
437 // [fareharbor] shortcode (calendar)
438 // ===============================================
439
440 public static function fareharbor_shortcode( $attrs ) {
441
442 $script_src = self::calendar_script_src( $attrs );
443
444 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
445 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
446
447 }
448
449 public static function calendar_script_src( $args ) {
450
451 if ( !isset( self::$calendar_defaults ) )
452 self::init_defaults();
453
454 $args = self::process_args( $args, self::$calendar_defaults, 'fareharbor' );
455
456 if ( isset( $args[ 'error' ] ) )
457 return $args;
458
459 $type = $args[ 'type' ];
460 if ( $type === 'small' )
461 $type = 'calendar-small';
462 elseif ( $type === 'large' || $type === 'responsive' )
463 $type = 'calendar';
464
465 $url_suffix = '';
466 if ( $args[ 'items' ] )
467 $url_suffix = 'items/' . $args[ 'items' ] . '/';
468
469 return self::embed_script_src( $type, $args, $url_suffix, array(), false, true );
470
471 }
472
473
474 // [partners] shortcode
475 // ===============================================
476
477 public static function partners_shortcode( $attrs ) {
478
479 $script_src = self::partners_script_src( $attrs );
480
481 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
482 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
483
484 }
485
486 public static function partners_script_src( $args ) {
487
488 if ( !isset( self::$partners_defaults ) )
489 self::init_defaults();
490
491 $args = self::process_args( $args, self::$partners_defaults, 'partners' );
492
493 if ( isset( $args[ 'error' ] ) )
494 return $args;
495
496 $query = array();
497 if ( $args[ 'include' ] )
498 $query[ 'include' ] = $args[ 'include' ];
499
500 return self::embed_script_src( 'partners', $args, '', $query, true, false );
501
502 }
503
504
505 // [items] shortcode
506 // ===============================================
507
508 public static function itemgrid_shortcode( $attrs ) {
509
510 $script_src = self::itemgrid_script_src( $attrs );
511
512 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
513 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
514
515 }
516
517
518 public static function itemgrid_script_src( $args ) {
519
520 if ( !isset( self::$itemgrid_defaults ) )
521 self::init_defaults();
522
523 $args = self::process_args( $args, self::$itemgrid_defaults, 'itemgrid' );
524
525 if ( isset( $args[ 'error' ] ) )
526 return $args;
527
528 $query = array();
529 if ( $args[ 'items' ] )
530 $query[ 'selected-items' ] = $args[ 'items' ];
531
532 return self::embed_script_src( 'items', $args, '', $query, true, true );
533
534 }
535
536
537 // Shared Shortcode Functionality
538 // ===============================================
539
540 // Handling Argument Input
541 // -----------------------------------------------
542
543 private static function process_args( $args, $defaults, $shortcode_name ) {
544
545 if ( !isset( self::$shared_defaults ) )
546 self::init_defaults();
547
548 $defaults += self::$shared_defaults;
549
550 if ( !is_array( $args ) ) // Just in case.
551 $args = $defaults;
552
553 // Trim whitespace && Strip Tags
554 $args = array_map( array( __CLASS__, 'sanitize' ), $args );
555
556 // Strip smart quotes, because WordPress returns them as part of the value if the shortcode was set up using them
557 $args = str_replace(
558 array( "\xe2\x80\x98", "\xe2\x80\x99", "\xe2\x80\x9c", "\xe2\x80\x9d", chr(145), chr(146), chr(147), chr(148) ),
559 array( '', '', '', '', '', '', '', '' ),
560 $args
561 );
562
563 // Merge in defaults
564 $args = shortcode_atts( $defaults, $args, $shortcode_name );
565
566 // Confirm there's a shortname. All of our shortcodes require this
567 if ( !$args[ 'shortname' ] )
568 return array( 'error' => 'no shortname' );
569
570 // Shortnames only work if lowercase
571 $args[ 'shortname' ] = strtolower( $args[ 'shortname' ] );
572
573 // Clean up item IDs and included companies because users can't be trusted
574 $csv_keys = array( 'items', 'view_item', 'include' );
575 foreach ( $csv_keys as $key )
576 if ( isset( $args[ $key ] ) )
577 $args[ $key ] = self::sanitize_csv( $args[ $key ] );
578
579 if ( $shortcode_name === 'lightframe' || $shortcode_name === 'bookembed' ) {
580
581 if ( !$args[ 'view_item' ] ) {
582 // See if we're filtering to just one item
583 // in that case we treat it as if it were
584 // passed to view_item instead
585 $items_array = explode( ',', $args[ 'items' ] );
586 if ( count( $items_array ) === 1 ) {
587 $args[ 'view_item' ] = $items_array[0];
588 $args[ 'items' ] = '';
589 }
590 }
591
592 }
593
594 return $args;
595
596 }
597
598 public static function sanitize($value)
599 {
600 $sanitized_value = preg_replace('/[^a-zA-Z0-9-_\s,:\/\.=&]/', '', $value);
601
602 return trim(strip_tags($sanitized_value));
603
604 }
605
606 private static function sanitize_csv( $value ) {
607
608 return rtrim( str_replace( ' ', '', $value ), ',' );
609
610 }
611
612
613 // Handling Errors
614 // -----------------------------------------------
615
616 private static $error_messages = array(
617
618 'no shortname'
619 => '<p>Please provide a FareHarbor shortname. (Format: <code>shortname="yourshortname"</code>)</p>',
620 'view_availability but no view_item'
621 => '<p>Please provide <code>view_item</code> if using <code>view_availability</code>.</p>',
622
623 );
624
625 private static function maybe_handle_shortcode_error( $output ) {
626
627 if ( is_array( $output ) && !empty( $output[ 'error' ] ) ) {
628
629 return isset( self::$error_messages[ $output[ 'error' ] ] )
630 ? self::$error_messages[ $output[ 'error' ] ]
631 : '<p>' . $output[ 'error' ] . '</p>';
632
633 }
634
635 return false;
636
637 }
638
639
640 // Scripts for embeds (in use by [partners] and [fareharbor])
641 // -----------------------------------------------
642
643 private static function embed_script_src( $type, $args, $url_suffix, $query, $include_full_items, $include_flow ) {
644
645 $script_src = 'https://' . self::url() . '/embeds/script/'
646 . $type
647 . '/'
648 . $args[ 'shortname' ]
649 . '/'
650 . $url_suffix;
651
652 $args[ 'lightframe' ] = strtolower( trim( $args[ 'lightframe' ] ) );
653 if ( $args[ 'lightframe' ] === 'no' )
654 $query += array( 'lightframe' => $args[ 'lightframe' ] );
655
656 $query += self::get_shared_args_array( $args, 'dash', $include_full_items, true, $include_flow );
657
658 $query_string = http_build_query( $query );
659
660 return $script_src . ( $query_string ? "?$query_string" : '' );
661
662 }
663
664
665 // Shared arguments
666 // -----------------------------------------------
667
668 private static function get_shared_args_array( $args, $casing, $include_full_items, $include_fallback, $include_flow ) {
669
670 $out = array();
671
672 if ( $include_fallback && in_array( $args[ 'fallback' ], array( 'simple', 'classic' ) ) )
673 $out[ 'fallback' ] = $args[ 'fallback' ];
674
675 if ( $include_full_items && $args[ 'full_items' ] !== 'no' )
676 $out[ 'full_items' ] = $args[ 'full_items' ];
677
678 if ( $args[ 'asn' ] ) {
679
680 $out[ 'asn' ] = $args[ 'asn' ];
681
682 if ( $args[ 'asn_ref' ] )
683 $out[ 'asn_ref' ] = $args[ 'asn_ref' ];
684
685 }
686
687 if ( $args[ 'ref' ] )
688 $out[ 'ref' ] = $args[ 'ref' ];
689
690 if ( $args[ 'sheet' ] )
691 $out[ 'sheet' ] = $args[ 'sheet' ];
692
693 if ( $args[ 'sheet_uuid' ] )
694 $out[ 'sheet_uuid' ] = $args[ 'sheet_uuid' ];
695
696 if ( $args[ 'schedule' ] )
697 $out[ 'schedule' ] = $args[ 'schedule' ];
698
699 if ( $args[ 'schedule_uuid' ] )
700 $out[ 'schedule_uuid' ] = $args[ 'schedule_uuid' ];
701
702 if ( $args[ 'language' ] )
703 $out[ 'language' ] = $args[ 'language' ];
704
705 if ( $args[ 'branding' ])
706 $out[ 'branding' ] = $args[ 'branding' ];
707
708 if ( $args[ 'bookable_only' ])
709 $out[ 'bookable_only' ] = $args[ 'bookable_only' ];
710
711
712 if ( $include_flow && $args[ 'flow' ] )
713 $out[ 'flow' ] = $args[ 'flow' ];
714
715 return self::fix_array_key_casing( $out, $casing );
716
717 }
718
719 private static function fix_array_key_casing( $in, $casing ) {
720
721 $out = array();
722 foreach ( $in as $key => $value )
723 $out[ self::fix_casing( $key, $casing ) ] = $value;
724
725 return $out;
726
727 }
728
729 private static function fix_casing( $text, $casing ) {
730 // Assumes $text is already in snake_case
731 switch ( $casing ) {
732
733 case 'camel':
734
735 // ucwords() doesn't support a $delimeters param
736 // until php 5.4.32/5.5.16
737 $text = strtr( $text, '_', ' ' );
738 $text = ucwords( $text );
739 $text = str_replace( ' ', '', $text );
740 // lcfirst() doesn't exist until php 5.3.0
741 $text[0] = strtolower( $text[0] );
742 return $text;
743
744 case 'dash':
745
746 return strtr( $text, '_', '-' );
747
748 }
749
750 return $text;
751
752 }
753
754
755 // FareHarbor URL with optional FH_ENVIRONMENT
756 // -----------------------------------------------
757
758 private static function url() {
759
760 $environment = ( defined( 'FH_ENVIRONMENT' ) && FH_ENVIRONMENT ) ? FH_ENVIRONMENT : '';
761 $environment = apply_filters( 'fareharbor/environment', $environment );
762
763 return trim( $environment )
764 ? trim( $environment ) . '.fareharbor.com'
765 : 'fareharbor.com';
766
767 }
768
769
770 // Settings & Settings Pages
771 // ===============================================
772
773 // Settings
774 // -----------------------------------------------
775
776 private static function is_lite() {
777 // This filter allows fh-kit and the admin page
778 // to be turned off with:
779 // add_filter( 'fareharbor/lite', '__return_true' );
780 return apply_filters( 'fareharbor/lite', false );
781
782 }
783
784 private static $options;
785
786 private static function get_option( $option_name, $default = '', $filtered = true ) {
787
788 $filter_name = str_replace( 'fh_', '', $option_name );
789 $filter_name = str_replace( 'default_', 'defaults/', $filter_name );
790 $filter_name = str_replace( 'buttons_', 'buttons/', $filter_name );
791 $filter_name = "fareharbor/$filter_name";
792
793 if ( self::is_lite() )
794 return $filtered ? apply_filters( $filter_name, $default ) : $default;
795
796 if ( !isset( self::$options ) )
797 self::$options = get_option( 'fareharbor_settings' );
798
799 $value = isset( self::$options[ $option_name ] )
800 ? self::$options[ $option_name ]
801 : $default;
802
803 if ( $filtered )
804 $value = apply_filters( $filter_name, $value );
805
806 return self::sanitize($value);
807
808 }
809
810
811 // The settings page
812 // -----------------------------------------------
813
814 public static function register_options_page() {
815
816 if ( self::is_lite() )
817 return;
818
819 add_options_page(
820 'FareHarbor Plugin Settings',
821 'FareHarbor',
822 'manage_options',
823 __FILE__,
824 array( __CLASS__, 'render_options_page' )
825 );
826
827 }
828
829 public static function register_settings() {
830
831 if ( self::is_lite() )
832 return;
833
834 register_setting(
835 'fareharbor_settings',
836 'fareharbor_settings',
837 array( __CLASS__, 'validate_settings' )
838 );
839
840 add_settings_section(
841 'fh_about_section',
842 'About',
843 array( __CLASS__, 'render_fh_about_section_text' ),
844 __FILE__
845 );
846
847 add_settings_section(
848 'fh_shortcode_defaults_section',
849 'Shortcode Defaults',
850 array( __CLASS__, 'render_fh_shortcode_defaults_section_text' ),
851 __FILE__
852 );
853
854 add_settings_field(
855 'fh_default_shortname',
856 'shortname',
857 array( __CLASS__, 'render_input_field' ),
858 __FILE__,
859 'fh_shortcode_defaults_section',
860 array(
861 'option_name' => 'fh_default_shortname',
862 'description' => 'Your company\'s FareHarbor shortname.',
863 )
864 );
865
866 add_settings_field(
867 'fh_responsive_calendars',
868 'Responsive Calendars',
869 array( __CLASS__, 'render_input_field' ),
870 __FILE__,
871 'fh_shortcode_defaults_section',
872 array(
873 'option_name' => 'fh_responsive_calendars',
874 'type' => 'checkbox',
875 'label' => 'Use responsive calendars by default.',
876 'description' => 'This is the same as [fareharbor type="responsive"].',
877 )
878 );
879
880 add_settings_field(
881 'fh_default_asn',
882 'asn',
883 array( __CLASS__, 'render_input_field' ),
884 __FILE__,
885 'fh_shortcode_defaults_section',
886 array(
887 'option_name' => 'fh_default_asn',
888 'description' => 'The shortname of your partner company. Include if using the ASN network.',
889 )
890 );
891
892 add_settings_field(
893 'fh_default_asn_ref',
894 'asn_ref',
895 array( __CLASS__, 'render_input_field' ),
896 __FILE__,
897 'fh_shortcode_defaults_section',
898 array(
899 'option_name' => 'fh_default_asn_ref',
900 'description' => 'The voucher number that should be set for ASN bookings.',
901 )
902 );
903
904 add_settings_field(
905 'fh_default_ref',
906 'ref',
907 array( __CLASS__, 'render_input_field' ),
908 __FILE__,
909 'fh_shortcode_defaults_section',
910 array(
911 'option_name' => 'fh_default_ref',
912 'description' => 'The online booking reference that should be set for bookings',
913 )
914 );
915
916 add_settings_field(
917 'fh_default_sheet',
918 'sheet',
919 array( __CLASS__, 'render_input_field' ),
920 __FILE__,
921 'fh_shortcode_defaults_section',
922 array(
923 'option_name' => 'fh_default_sheet',
924 'description' => 'The price sheet that should be used while creating bookings.',
925 )
926 );
927
928 add_settings_field(
929 'fh_default_schedule',
930 'schedule',
931 array( __CLASS__, 'render_input_field' ),
932 __FILE__,
933 'fh_shortcode_defaults_section',
934 array(
935 'option_name' => 'fh_default_schedule',
936 'description' => 'The price schedule that should be used while creating bookings.',
937 )
938 );
939
940 add_settings_field(
941 'fh_default_language',
942 'language',
943 array( __CLASS__, 'render_input_field' ),
944 __FILE__,
945 'fh_shortcode_defaults_section',
946 array(
947 'option_name' => 'fh_default_language',
948 'description' => 'The two letter code for the language that FareHarbor pages should be overridden to, instead of detecting the user\'s language. (Not recommended.)',
949 )
950 );
951
952 add_settings_field(
953 'fh_default_full_items',
954 'full_items',
955 array( __CLASS__, 'render_select_field' ),
956 __FILE__,
957 'fh_shortcode_defaults_section',
958 array(
959 'option_name' => 'fh_default_full_items',
960 'choices' => array(
961 'yes',
962 'no',
963 ),
964 'description' => 'Should the Lightframe that is opened include item descriptions and photos? Defaults to "no".',
965 )
966 );
967
968 add_settings_field(
969 'fh_default_lightframe',
970 'lightframe',
971 array( __CLASS__, 'render_select_field' ),
972 __FILE__,
973 'fh_shortcode_defaults_section',
974 array(
975 'option_name' => 'fh_default_lightframe',
976 'choices' => array(
977 'yes',
978 'no',
979 ),
980 'description' => 'Choose "yes" to open new bookings inside a Lightframe. Choose "no" to open them in an external page instead. Defaults to "yes".'
981 )
982 );
983
984 add_settings_field(
985 'fh_default_class',
986 'class',
987 array( __CLASS__, 'render_input_field' ),
988 __FILE__,
989 'fh_shortcode_defaults_section',
990 array(
991 'option_name' => 'fh_default_class',
992 'description' => 'The class option only applies to the [lightframe] shortcode.',
993 )
994 );
995
996 add_settings_section(
997 'fh_auto_lightframe_section',
998 'Automatic Lightframing',
999 array( __CLASS__, 'render_fh_auto_lightframe_section_text' ),
1000 __FILE__
1001 );
1002
1003 add_settings_field(
1004 'fh_auto_lightframe_enabled',
1005 'Auto Lightframing Activation',
1006 array( __CLASS__, 'render_input_field' ),
1007 __FILE__,
1008 'fh_auto_lightframe_section',
1009 array(
1010 'option_name' => 'fh_auto_lightframe_enabled',
1011 'type' => 'checkbox',
1012 'label' => 'Enable auto Lightframing.',
1013 )
1014 );
1015
1016 add_settings_section(
1017 'fh_buttons_section',
1018 'FareHarbor Buttons',
1019 array( __CLASS__, 'render_fh_buttons_section_text' ),
1020 __FILE__
1021 );
1022
1023 add_settings_field(
1024 'fh_buttons_active',
1025 'FH Buttons Activation',
1026 array( __CLASS__, 'render_input_field' ),
1027 __FILE__,
1028 'fh_buttons_section',
1029 array(
1030 'option_name' => 'fh_buttons_active',
1031 'type' => 'checkbox',
1032 'label' => 'Load the FH Buttons stylesheet on all pages.',
1033 )
1034 );
1035
1036 add_settings_field(
1037 'fh_buttons_query',
1038 'Button Colors',
1039 array( __CLASS__, 'render_input_field' ),
1040 __FILE__,
1041 'fh_buttons_section',
1042 array(
1043 'option_name' => 'fh_buttons_query',
1044 'description' => 'Provide colors in the format <code>red=ff0000&green=00ff00</code>',
1045 )
1046 );
1047
1048 }
1049
1050 public static function validate_settings( $input ) {
1051
1052 // Strip tags and trim whitespace
1053 $input = array_map( array( __CLASS__, 'sanitize' ), $input );
1054
1055 // Let's not pollute the DB with empty settings
1056 $input = array_filter( $input );
1057
1058 // Shortnames only work when lowercase
1059 if ( isset( $input[ 'fh_default_shortname' ] ) )
1060 $input[ 'fh_default_shortname' ] = strtolower( $input[ 'fh_default_shortname' ] );
1061
1062 return $input;
1063
1064 }
1065
1066 public static function render_options_page() {
1067
1068 ?>
1069
1070 <div class="wrap">
1071
1072 <h2>FareHarbor Plugin Settings</h2>
1073
1074 <form action="options.php" method="post">
1075
1076 <?php settings_fields( 'fareharbor_settings' ); ?>
1077
1078 <?php do_settings_sections( __FILE__ ); ?>
1079
1080 <p class="submit">
1081 <input name="Submit" type="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes' ); ?>" />
1082 </p>
1083
1084 </form>
1085
1086 </div>
1087
1088 <?php
1089
1090 }
1091
1092 public static function render_fh_about_section_text() {
1093
1094 echo '<p><b>This plugin requires a FareHarbor account to work.</b> FareHarbor provides powerful, intuitive, and highly customizable reservation software for activity and tourism businesses. We can help you enable online booking on your website using this plugin and a whole range of other features. Don\'t have an account? <a href="https://fareharbor.com/join/" target="_blank">Get in touch at fareharbor.com.</a></p><p>If you\'re already with FareHarbor, check out our <a href="https://fareharbor.com/help/setup/wordpress-plugin/" target="_blank">help center article</a> on how to get started with this plugin.</p>';
1095
1096 }
1097
1098 public static function render_fh_shortcode_defaults_section_text() {
1099
1100 echo '<p>Set default options for the [lightframe], [fareharbor], [itemgrid], and [partners] shortcodes here. The options written in when including a shortcode on a page will always take precedence over the default values entered below. <a href="https://fareharbor.com/help/setup/wordpress-plugin/#setting-defaults" target="_blank">Learn how default options work.</a></p>';
1101
1102 }
1103
1104 public static function render_fh_auto_lightframe_section_text() {
1105
1106 echo '<p>Open normal links to FareHarbor as Lightframe overlays, even if the [lightframe] shortcode isn&apos;t used.</p>';
1107
1108 }
1109
1110 public static function render_fh_buttons_section_text() {
1111
1112 echo '<p>FareHarbor can automatically load in a CSS stylesheet which includes classes to make your Lightframe links look like beautifully designed buttons.</p>';
1113
1114 }
1115
1116 public static function render_input_field( $args ) {
1117 // We use this function to render all of our options fields
1118 // $args is supplied as the last parameter to each
1119 // add_settings_field() call in fareharbor::register_settings()
1120 // This function is only run on our settings page in the admin
1121
1122 $type = isset( $args[ 'type' ] ) ? $args[ 'type' ] : 'text';
1123
1124 $option_name = $args[ 'option_name' ];
1125 $value = self::get_option( $option_name, '', false );
1126
1127 // Attributes all input tags need
1128 $attrs = array(
1129 'name' => "fareharbor_settings[$option_name]",
1130 'id' => $option_name,
1131 'type' => $type,
1132 );
1133
1134 // Type-specific attributes
1135 switch ( $type ) {
1136
1137 case 'text':
1138 $attrs[ 'size' ] = '40';
1139 $attrs[ 'value' ] = (string) $value;
1140 break;
1141
1142 case 'checkbox':
1143 if ( $value )
1144 $attrs[ 'checked' ] = 'checked';
1145 break;
1146
1147 }
1148
1149 // Merge in attributes supplied in the arguments
1150 if ( isset( $args[ 'attrs' ] ) )
1151 // attributes from the arguments will override the defaults
1152 $attrs = $args[ 'attrs' ] + $attrs;
1153
1154 // Actually generate the input tag
1155 $out = '<input';
1156 foreach ( $attrs as $name => $value )
1157 $out .= " $name=\"$value\"";
1158 $out .= ' />';
1159
1160 if ( !empty( $args[ 'label' ] ) )
1161 $out .= "<label for=\"$option_name\">{$args[ 'label' ]}</label>";
1162
1163 if ( !empty( $args[ 'description' ] ) )
1164 $out .= "<p class=\"description\">{$args[ 'description' ]}</p>";
1165
1166 // And print it onto the page
1167 echo $out;
1168
1169 }
1170
1171 public static function render_select_field( $args ) {
1172
1173 $option_name = $args[ 'option_name' ];
1174 $value = self::get_option( $option_name, '', false );
1175
1176 ?>
1177
1178 <select name="<?php echo "fareharbor_settings[$option_name]" ?>" id="<?php echo $option_name ?>">
1179
1180 <option value="" <?php selected( '', $value ); ?>></option>
1181
1182 <?php foreach ( $args[ 'choices' ] as $choice ) { ?>
1183 <option value="<?php echo $choice ?>" <?php selected( $choice, $value ) ?>><?php echo $choice ?></option>
1184 <?php } ?>
1185
1186 </select>
1187
1188 <?php
1189
1190 if ( !empty( $args[ 'description' ] ) )
1191 echo "<p class=\"description\">{$args[ 'description' ]}</p>";
1192
1193 }
1194
1195 }
1196