PluginProbe
FareHarbor for WordPress / 3.6.12
FareHarbor for WordPress v3.6.12
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.12, at fareharbor.php

1,199 lines 35.3 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.12
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.12';
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 'package' => '',
229
230 );
231
232 self::$bookembed_defaults =
233 self::$lightframe_defaults = array(
234
235 // 'class' => '',
236 // 'style' => '',
237 // 'id' => '',
238 'view' => 'items',
239 'view_item' => '',
240 'view_availability' => '',
241
242 );
243 self::$bookembed_defaults[ 'fallback' ] = '';
244
245 self::$calendar_defaults = array();
246
247 if ( self::get_option( 'fh_responsive_calendars', false ) )
248 self::$calendar_defaults[ 'type' ] = 'calendar';
249 else
250 self::$calendar_defaults[ 'type' ] = 'calendar-small';
251
252 self::$partners_defaults = array(
253
254 'include' => '',
255
256 );
257
258 self::$itemgrid_defaults = array();
259
260 }
261
262
263 // [lightframe][/lightframe] shortcode
264 // ===============================================
265
266 public static function lightframe_shortcode( $attrs, $content = '' ) {
267
268 $link_attrs = self::lightframe_link_attrs( $attrs );
269
270 if ( $error = self::maybe_handle_shortcode_error( $link_attrs ) )
271 return $error;
272
273 if ( !empty( $attrs[ 'class' ] ) )
274 $link_attrs[ 'class' ] = $attrs[ 'class' ];
275 elseif ( $default_class = self::get_option( 'fh_default_class' ) )
276 $link_attrs[ 'class' ] = $default_class;
277
278 if ( !empty( $attrs[ 'id' ] ) )
279 $link_attrs[ 'id' ] = $attrs[ 'id' ];
280
281 if ( !empty( $attrs[ 'style' ] ) )
282 $link_attrs[ 'style' ] = $attrs[ 'style' ];
283
284 $link_attrs = array_map( 'strip_tags', $link_attrs );
285
286 $link_attrs_string = '';
287 foreach ( $link_attrs as $name => $value ) {
288 $value = esc_attr($value);
289 $link_attrs_string .= " $name=\"$value\"";
290 }
291
292 if ( trim( $content ) )
293 $content = do_shortcode( $content );
294
295 return "<a$link_attrs_string>$content</a>";
296
297 }
298
299 public static function lightframe_link_attrs( $args ) {
300
301 if ( !isset( self::$lightframe_defaults ) )
302 self::init_defaults();
303
304 $args = self::process_args( $args, self::$lightframe_defaults, 'lightframe' );
305
306 if ( isset( $args[ 'error' ] ) )
307 return $args;
308
309 if ( $args[ 'view_availability' ] && !$args[ 'view_item' ] )
310 return array( 'error' => 'view_availability but no view_item' );
311
312 $fallback_url = self::lightframe_fallback_url( $args );
313
314 $api_options = self::lightframe_api_options( $args );
315 $json = strtr( json_encode( $api_options ), '"', "'" );
316
317 return array(
318 'href' => $fallback_url,
319 'target' => '_blank',
320 'onclick' => "FH.open($json); return false;",
321 );
322
323 }
324
325 private static function lightframe_fallback_url( $args, $is_bookembed = false ) {
326
327 // The bookembed url structure is very similar to the simple fallback url structure
328 $is_simple_fallback = ( $args[ 'fallback' ] === '' ) || ( $args[ 'fallback' ] === 'simple' ) || $is_bookembed;
329
330 $url = 'https://' . self::url() . '/';
331
332 if ( $is_bookembed )
333 $url .= 'embeds/script/book/';
334 elseif ( $is_simple_fallback )
335 $url .= 'embeds/book/';
336
337 $url .= $args[ 'shortname' ] . '/';
338
339 if ( !$is_simple_fallback
340 || $args[ 'view' ] === 'all-availability'
341 || $args[ 'view_item' ]
342 ) {
343 $url .= 'items/';
344 }
345
346 if ( $args[ 'view_item' ] ) {
347
348 $url .= $args[ 'view_item' ] . '/';
349
350 if ( $args[ 'view_availability' ] )
351 $url .= 'availability/' . $args[ 'view_availability' ] . '/book/';
352 elseif ( $args[ 'full_items' ] === 'no' )
353 $url .= 'calendar/';
354
355 } elseif ( $args[ 'view' ] === 'all-availability' ) {
356
357 $url .= 'calendar/';
358
359 }
360
361 $query = self::get_shared_args_array( $args, 'dash', $is_simple_fallback, false, true );
362
363 if ( $is_simple_fallback && $args[ 'items' ] )
364 $query[ 'selected-items' ] = $args[ 'items' ];
365
366 if ( $query )
367 $url .= '?' . http_build_query( $query );
368
369 return $url;
370
371 }
372
373 private static function lightframe_api_options( $args ) {
374
375 $lo = array( 'shortname' => $args[ 'shortname' ] );
376
377 // Filter the visible items
378 if ( $args[ 'items' ] )
379 // putting it in an array so it gets brackets in json_encode
380 $lo[ 'items' ] = explode( ',', $args[ 'items' ] );
381
382 // Set the view
383 if ( $args[ 'view_item' ] ) {
384
385 $lo[ 'view' ] = array( 'item' => $args[ 'view_item' ] );
386
387 if ( $args[ 'view_availability' ] )
388 $lo[ 'view' ][ 'availability' ] = $args[ 'view_availability' ];
389
390 } elseif ( in_array( $args[ 'view' ], array( 'items', 'all-availability' ), true ) ) {
391
392 $lo[ 'view' ] = $args[ 'view' ];
393
394 } else {
395
396 $lo[ 'view' ] = 'items';
397
398 }
399
400 // Modifiers: shared args like fallback, asn, asn_ref, etc.
401 $lo += self::get_shared_args_array( $args, 'camel', true, true, true );
402
403 return $lo;
404
405 }
406
407
408 // [bookembed] shortcode
409 // ===============================================
410
411 public static function bookembed_shortcode( $attrs ) {
412
413 $script_src = self::bookembed_script_src( $attrs );
414
415 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
416 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
417
418 }
419
420 public static function bookembed_script_src( $args ) {
421
422 if ( !isset( self::$bookembed_defaults ) )
423 self::init_defaults();
424
425 $args = self::process_args( $args, self::$bookembed_defaults, 'bookembed' );
426
427 if ( isset( $args[ 'error' ] ) )
428 return $args;
429
430 if ( $args[ 'view_availability' ] && !$args[ 'view_item' ] )
431 return array( 'error' => 'view_availability but no view_item' );
432
433 return self::lightframe_fallback_url( $args, true );
434
435 }
436
437
438 // [fareharbor] shortcode (calendar)
439 // ===============================================
440
441 public static function fareharbor_shortcode( $attrs ) {
442
443 $script_src = self::calendar_script_src( $attrs );
444
445 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
446 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
447
448 }
449
450 public static function calendar_script_src( $args ) {
451
452 if ( !isset( self::$calendar_defaults ) )
453 self::init_defaults();
454
455 $args = self::process_args( $args, self::$calendar_defaults, 'fareharbor' );
456
457 if ( isset( $args[ 'error' ] ) )
458 return $args;
459
460 $type = $args[ 'type' ];
461 if ( $type === 'small' )
462 $type = 'calendar-small';
463 elseif ( $type === 'large' || $type === 'responsive' )
464 $type = 'calendar';
465
466 $url_suffix = '';
467 if ( $args[ 'items' ] )
468 $url_suffix = 'items/' . $args[ 'items' ] . '/';
469
470 return self::embed_script_src( $type, $args, $url_suffix, array(), false, true );
471
472 }
473
474
475 // [partners] shortcode
476 // ===============================================
477
478 public static function partners_shortcode( $attrs ) {
479
480 $script_src = self::partners_script_src( $attrs );
481
482 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
483 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
484
485 }
486
487 public static function partners_script_src( $args ) {
488
489 if ( !isset( self::$partners_defaults ) )
490 self::init_defaults();
491
492 $args = self::process_args( $args, self::$partners_defaults, 'partners' );
493
494 if ( isset( $args[ 'error' ] ) )
495 return $args;
496
497 $query = array();
498 if ( $args[ 'include' ] )
499 $query[ 'include' ] = $args[ 'include' ];
500
501 return self::embed_script_src( 'partners', $args, '', $query, true, false );
502
503 }
504
505
506 // [items] shortcode
507 // ===============================================
508
509 public static function itemgrid_shortcode( $attrs ) {
510
511 $script_src = self::itemgrid_script_src( $attrs );
512
513 $maybe_error = self::maybe_handle_shortcode_error( $script_src );
514 return $maybe_error ? $maybe_error : "<script src=\"$script_src\"></script>";
515
516 }
517
518
519 public static function itemgrid_script_src( $args ) {
520
521 if ( !isset( self::$itemgrid_defaults ) )
522 self::init_defaults();
523
524 $args = self::process_args( $args, self::$itemgrid_defaults, 'itemgrid' );
525
526 if ( isset( $args[ 'error' ] ) )
527 return $args;
528
529 $query = array();
530 if ( $args[ 'items' ] )
531 $query[ 'selected-items' ] = $args[ 'items' ];
532
533 return self::embed_script_src( 'items', $args, '', $query, true, true );
534
535 }
536
537
538 // Shared Shortcode Functionality
539 // ===============================================
540
541 // Handling Argument Input
542 // -----------------------------------------------
543
544 private static function process_args( $args, $defaults, $shortcode_name ) {
545
546 if ( !isset( self::$shared_defaults ) )
547 self::init_defaults();
548
549 $defaults += self::$shared_defaults;
550
551 if ( !is_array( $args ) ) // Just in case.
552 $args = $defaults;
553
554 // Trim whitespace && Strip Tags
555 $args = array_map( array( __CLASS__, 'sanitize' ), $args );
556
557 // Strip smart quotes, because WordPress returns them as part of the value if the shortcode was set up using them
558 $args = str_replace(
559 array( "\xe2\x80\x98", "\xe2\x80\x99", "\xe2\x80\x9c", "\xe2\x80\x9d", chr(145), chr(146), chr(147), chr(148) ),
560 array( '', '', '', '', '', '', '', '' ),
561 $args
562 );
563
564 // Merge in defaults
565 $args = shortcode_atts( $defaults, $args, $shortcode_name );
566
567 // Confirm there's a shortname. All of our shortcodes require this
568 if ( !$args[ 'shortname' ] )
569 return array( 'error' => 'no shortname' );
570
571 // Shortnames only work if lowercase
572 $args[ 'shortname' ] = strtolower( $args[ 'shortname' ] );
573
574 // Clean up item IDs and included companies because users can't be trusted
575 $csv_keys = array( 'items', 'view_item', 'include' );
576 foreach ( $csv_keys as $key )
577 if ( isset( $args[ $key ] ) )
578 $args[ $key ] = self::sanitize_csv( $args[ $key ] );
579
580 if ( $shortcode_name === 'lightframe' || $shortcode_name === 'bookembed' ) {
581
582 if ( !$args[ 'view_item' ] ) {
583 // See if we're filtering to just one item
584 // in that case we treat it as if it were
585 // passed to view_item instead
586 $items_array = explode( ',', $args[ 'items' ] );
587 if ( count( $items_array ) === 1 ) {
588 $args[ 'view_item' ] = $items_array[0];
589 $args[ 'items' ] = '';
590 }
591 }
592
593 }
594
595 return $args;
596
597 }
598
599 public static function sanitize($value)
600 {
601 $sanitized_value = preg_replace('/[^a-zA-Z0-9-_\s,:\/\.=&]/', '', $value);
602
603 return trim(strip_tags($sanitized_value));
604
605 }
606
607 private static function sanitize_csv( $value ) {
608
609 return rtrim( str_replace( ' ', '', $value ), ',' );
610
611 }
612
613
614 // Handling Errors
615 // -----------------------------------------------
616
617 private static $error_messages = array(
618
619 'no shortname'
620 => '<p>Please provide a FareHarbor shortname. (Format: <code>shortname="yourshortname"</code>)</p>',
621 'view_availability but no view_item'
622 => '<p>Please provide <code>view_item</code> if using <code>view_availability</code>.</p>',
623
624 );
625
626 private static function maybe_handle_shortcode_error( $output ) {
627
628 if ( is_array( $output ) && !empty( $output[ 'error' ] ) ) {
629
630 return isset( self::$error_messages[ $output[ 'error' ] ] )
631 ? self::$error_messages[ $output[ 'error' ] ]
632 : '<p>' . $output[ 'error' ] . '</p>';
633
634 }
635
636 return false;
637
638 }
639
640
641 // Scripts for embeds (in use by [partners] and [fareharbor])
642 // -----------------------------------------------
643
644 private static function embed_script_src( $type, $args, $url_suffix, $query, $include_full_items, $include_flow ) {
645
646 $script_src = 'https://' . self::url() . '/embeds/script/'
647 . $type
648 . '/'
649 . $args[ 'shortname' ]
650 . '/'
651 . $url_suffix;
652
653 $args[ 'lightframe' ] = strtolower( trim( $args[ 'lightframe' ] ) );
654 if ( $args[ 'lightframe' ] === 'no' )
655 $query += array( 'lightframe' => $args[ 'lightframe' ] );
656
657 $query += self::get_shared_args_array( $args, 'dash', $include_full_items, true, $include_flow );
658
659 $query_string = http_build_query( $query );
660
661 return $script_src . ( $query_string ? "?$query_string" : '' );
662
663 }
664
665
666 // Shared arguments
667 // -----------------------------------------------
668
669 private static function get_shared_args_array( $args, $casing, $include_full_items, $include_fallback, $include_flow ) {
670
671 $out = array();
672
673 if ( $include_fallback && in_array( $args[ 'fallback' ], array( 'simple', 'classic' ) ) )
674 $out[ 'fallback' ] = $args[ 'fallback' ];
675
676 if ( $include_full_items && $args[ 'full_items' ] !== 'no' )
677 $out[ 'full_items' ] = $args[ 'full_items' ];
678
679 if ( $args[ 'asn' ] ) {
680
681 $out[ 'asn' ] = $args[ 'asn' ];
682
683 if ( $args[ 'asn_ref' ] )
684 $out[ 'asn_ref' ] = $args[ 'asn_ref' ];
685
686 }
687
688 if ( $args[ 'ref' ] )
689 $out[ 'ref' ] = $args[ 'ref' ];
690
691 if ( $args[ 'sheet' ] )
692 $out[ 'sheet' ] = $args[ 'sheet' ];
693
694 if ( $args[ 'sheet_uuid' ] )
695 $out[ 'sheet_uuid' ] = $args[ 'sheet_uuid' ];
696
697 if ( $args[ 'schedule' ] )
698 $out[ 'schedule' ] = $args[ 'schedule' ];
699
700 if ( $args[ 'schedule_uuid' ] )
701 $out[ 'schedule_uuid' ] = $args[ 'schedule_uuid' ];
702
703 if ( $args[ 'language' ] )
704 $out[ 'language' ] = $args[ 'language' ];
705
706 if ( $args[ 'branding' ])
707 $out[ 'branding' ] = $args[ 'branding' ];
708
709 if ( $args[ 'bookable_only' ])
710 $out[ 'bookable_only' ] = $args[ 'bookable_only' ];
711
712 if ( $args[ 'package' ])
713 $out[ 'package' ] = $args[ 'package' ];
714
715 if ( $include_flow && $args[ 'flow' ] )
716 $out[ 'flow' ] = $args[ 'flow' ];
717
718 return self::fix_array_key_casing( $out, $casing );
719
720 }
721
722 private static function fix_array_key_casing( $in, $casing ) {
723
724 $out = array();
725 foreach ( $in as $key => $value )
726 $out[ self::fix_casing( $key, $casing ) ] = $value;
727
728 return $out;
729
730 }
731
732 private static function fix_casing( $text, $casing ) {
733 // Assumes $text is already in snake_case
734 switch ( $casing ) {
735
736 case 'camel':
737
738 // ucwords() doesn't support a $delimeters param
739 // until php 5.4.32/5.5.16
740 $text = strtr( $text, '_', ' ' );
741 $text = ucwords( $text );
742 $text = str_replace( ' ', '', $text );
743 // lcfirst() doesn't exist until php 5.3.0
744 $text[0] = strtolower( $text[0] );
745 return $text;
746
747 case 'dash':
748
749 return strtr( $text, '_', '-' );
750
751 }
752
753 return $text;
754
755 }
756
757
758 // FareHarbor URL with optional FH_ENVIRONMENT
759 // -----------------------------------------------
760
761 private static function url() {
762
763 $environment = ( defined( 'FH_ENVIRONMENT' ) && FH_ENVIRONMENT ) ? FH_ENVIRONMENT : '';
764 $environment = apply_filters( 'fareharbor/environment', $environment );
765
766 return trim( $environment )
767 ? trim( $environment ) . '.fareharbor.com'
768 : 'fareharbor.com';
769
770 }
771
772
773 // Settings & Settings Pages
774 // ===============================================
775
776 // Settings
777 // -----------------------------------------------
778
779 private static function is_lite() {
780 // This filter allows fh-kit and the admin page
781 // to be turned off with:
782 // add_filter( 'fareharbor/lite', '__return_true' );
783 return apply_filters( 'fareharbor/lite', false );
784
785 }
786
787 private static $options;
788
789 private static function get_option( $option_name, $default = '', $filtered = true ) {
790
791 $filter_name = str_replace( 'fh_', '', $option_name );
792 $filter_name = str_replace( 'default_', 'defaults/', $filter_name );
793 $filter_name = str_replace( 'buttons_', 'buttons/', $filter_name );
794 $filter_name = "fareharbor/$filter_name";
795
796 if ( self::is_lite() )
797 return $filtered ? apply_filters( $filter_name, $default ) : $default;
798
799 if ( !isset( self::$options ) )
800 self::$options = get_option( 'fareharbor_settings' );
801
802 $value = isset( self::$options[ $option_name ] )
803 ? self::$options[ $option_name ]
804 : $default;
805
806 if ( $filtered )
807 $value = apply_filters( $filter_name, $value );
808
809 return self::sanitize($value);
810
811 }
812
813
814 // The settings page
815 // -----------------------------------------------
816
817 public static function register_options_page() {
818
819 if ( self::is_lite() )
820 return;
821
822 add_options_page(
823 'FareHarbor Plugin Settings',
824 'FareHarbor',
825 'manage_options',
826 __FILE__,
827 array( __CLASS__, 'render_options_page' )
828 );
829
830 }
831
832 public static function register_settings() {
833
834 if ( self::is_lite() )
835 return;
836
837 register_setting(
838 'fareharbor_settings',
839 'fareharbor_settings',
840 array( __CLASS__, 'validate_settings' )
841 );
842
843 add_settings_section(
844 'fh_about_section',
845 'About',
846 array( __CLASS__, 'render_fh_about_section_text' ),
847 __FILE__
848 );
849
850 add_settings_section(
851 'fh_shortcode_defaults_section',
852 'Shortcode Defaults',
853 array( __CLASS__, 'render_fh_shortcode_defaults_section_text' ),
854 __FILE__
855 );
856
857 add_settings_field(
858 'fh_default_shortname',
859 'shortname',
860 array( __CLASS__, 'render_input_field' ),
861 __FILE__,
862 'fh_shortcode_defaults_section',
863 array(
864 'option_name' => 'fh_default_shortname',
865 'description' => 'Your company\'s FareHarbor shortname.',
866 )
867 );
868
869 add_settings_field(
870 'fh_responsive_calendars',
871 'Responsive Calendars',
872 array( __CLASS__, 'render_input_field' ),
873 __FILE__,
874 'fh_shortcode_defaults_section',
875 array(
876 'option_name' => 'fh_responsive_calendars',
877 'type' => 'checkbox',
878 'label' => 'Use responsive calendars by default.',
879 'description' => 'This is the same as [fareharbor type="responsive"].',
880 )
881 );
882
883 add_settings_field(
884 'fh_default_asn',
885 'asn',
886 array( __CLASS__, 'render_input_field' ),
887 __FILE__,
888 'fh_shortcode_defaults_section',
889 array(
890 'option_name' => 'fh_default_asn',
891 'description' => 'The shortname of your partner company. Include if using the ASN network.',
892 )
893 );
894
895 add_settings_field(
896 'fh_default_asn_ref',
897 'asn_ref',
898 array( __CLASS__, 'render_input_field' ),
899 __FILE__,
900 'fh_shortcode_defaults_section',
901 array(
902 'option_name' => 'fh_default_asn_ref',
903 'description' => 'The voucher number that should be set for ASN bookings.',
904 )
905 );
906
907 add_settings_field(
908 'fh_default_ref',
909 'ref',
910 array( __CLASS__, 'render_input_field' ),
911 __FILE__,
912 'fh_shortcode_defaults_section',
913 array(
914 'option_name' => 'fh_default_ref',
915 'description' => 'The online booking reference that should be set for bookings',
916 )
917 );
918
919 add_settings_field(
920 'fh_default_sheet',
921 'sheet',
922 array( __CLASS__, 'render_input_field' ),
923 __FILE__,
924 'fh_shortcode_defaults_section',
925 array(
926 'option_name' => 'fh_default_sheet',
927 'description' => 'The price sheet that should be used while creating bookings.',
928 )
929 );
930
931 add_settings_field(
932 'fh_default_schedule',
933 'schedule',
934 array( __CLASS__, 'render_input_field' ),
935 __FILE__,
936 'fh_shortcode_defaults_section',
937 array(
938 'option_name' => 'fh_default_schedule',
939 'description' => 'The price schedule that should be used while creating bookings.',
940 )
941 );
942
943 add_settings_field(
944 'fh_default_language',
945 'language',
946 array( __CLASS__, 'render_input_field' ),
947 __FILE__,
948 'fh_shortcode_defaults_section',
949 array(
950 'option_name' => 'fh_default_language',
951 'description' => 'The two letter code for the language that FareHarbor pages should be overridden to, instead of detecting the user\'s language. (Not recommended.)',
952 )
953 );
954
955 add_settings_field(
956 'fh_default_full_items',
957 'full_items',
958 array( __CLASS__, 'render_select_field' ),
959 __FILE__,
960 'fh_shortcode_defaults_section',
961 array(
962 'option_name' => 'fh_default_full_items',
963 'choices' => array(
964 'yes',
965 'no',
966 ),
967 'description' => 'Should the Lightframe that is opened include item descriptions and photos? Defaults to "no".',
968 )
969 );
970
971 add_settings_field(
972 'fh_default_lightframe',
973 'lightframe',
974 array( __CLASS__, 'render_select_field' ),
975 __FILE__,
976 'fh_shortcode_defaults_section',
977 array(
978 'option_name' => 'fh_default_lightframe',
979 'choices' => array(
980 'yes',
981 'no',
982 ),
983 'description' => 'Choose "yes" to open new bookings inside a Lightframe. Choose "no" to open them in an external page instead. Defaults to "yes".'
984 )
985 );
986
987 add_settings_field(
988 'fh_default_class',
989 'class',
990 array( __CLASS__, 'render_input_field' ),
991 __FILE__,
992 'fh_shortcode_defaults_section',
993 array(
994 'option_name' => 'fh_default_class',
995 'description' => 'The class option only applies to the [lightframe] shortcode.',
996 )
997 );
998
999 add_settings_section(
1000 'fh_auto_lightframe_section',
1001 'Automatic Lightframing',
1002 array( __CLASS__, 'render_fh_auto_lightframe_section_text' ),
1003 __FILE__
1004 );
1005
1006 add_settings_field(
1007 'fh_auto_lightframe_enabled',
1008 'Auto Lightframing Activation',
1009 array( __CLASS__, 'render_input_field' ),
1010 __FILE__,
1011 'fh_auto_lightframe_section',
1012 array(
1013 'option_name' => 'fh_auto_lightframe_enabled',
1014 'type' => 'checkbox',
1015 'label' => 'Enable auto Lightframing.',
1016 )
1017 );
1018
1019 add_settings_section(
1020 'fh_buttons_section',
1021 'FareHarbor Buttons',
1022 array( __CLASS__, 'render_fh_buttons_section_text' ),
1023 __FILE__
1024 );
1025
1026 add_settings_field(
1027 'fh_buttons_active',
1028 'FH Buttons Activation',
1029 array( __CLASS__, 'render_input_field' ),
1030 __FILE__,
1031 'fh_buttons_section',
1032 array(
1033 'option_name' => 'fh_buttons_active',
1034 'type' => 'checkbox',
1035 'label' => 'Load the FH Buttons stylesheet on all pages.',
1036 )
1037 );
1038
1039 add_settings_field(
1040 'fh_buttons_query',
1041 'Button Colors',
1042 array( __CLASS__, 'render_input_field' ),
1043 __FILE__,
1044 'fh_buttons_section',
1045 array(
1046 'option_name' => 'fh_buttons_query',
1047 'description' => 'Provide colors in the format <code>red=ff0000&green=00ff00</code>',
1048 )
1049 );
1050
1051 }
1052
1053 public static function validate_settings( $input ) {
1054
1055 // Strip tags and trim whitespace
1056 $input = array_map( array( __CLASS__, 'sanitize' ), $input );
1057
1058 // Let's not pollute the DB with empty settings
1059 $input = array_filter( $input );
1060
1061 // Shortnames only work when lowercase
1062 if ( isset( $input[ 'fh_default_shortname' ] ) )
1063 $input[ 'fh_default_shortname' ] = strtolower( $input[ 'fh_default_shortname' ] );
1064
1065 return $input;
1066
1067 }
1068
1069 public static function render_options_page() {
1070
1071 ?>
1072
1073 <div class="wrap">
1074
1075 <h2>FareHarbor Plugin Settings</h2>
1076
1077 <form action="options.php" method="post">
1078
1079 <?php settings_fields( 'fareharbor_settings' ); ?>
1080
1081 <?php do_settings_sections( __FILE__ ); ?>
1082
1083 <p class="submit">
1084 <input name="Submit" type="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes' ); ?>" />
1085 </p>
1086
1087 </form>
1088
1089 </div>
1090
1091 <?php
1092
1093 }
1094
1095 public static function render_fh_about_section_text() {
1096
1097 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>';
1098
1099 }
1100
1101 public static function render_fh_shortcode_defaults_section_text() {
1102
1103 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>';
1104
1105 }
1106
1107 public static function render_fh_auto_lightframe_section_text() {
1108
1109 echo '<p>Open normal links to FareHarbor as Lightframe overlays, even if the [lightframe] shortcode isn&apos;t used.</p>';
1110
1111 }
1112
1113 public static function render_fh_buttons_section_text() {
1114
1115 echo '<p>FareHarbor can automatically load in a CSS stylesheet which includes classes to make your Lightframe links look like beautifully designed buttons.</p>';
1116
1117 }
1118
1119 public static function render_input_field( $args ) {
1120 // We use this function to render all of our options fields
1121 // $args is supplied as the last parameter to each
1122 // add_settings_field() call in fareharbor::register_settings()
1123 // This function is only run on our settings page in the admin
1124
1125 $type = isset( $args[ 'type' ] ) ? $args[ 'type' ] : 'text';
1126
1127 $option_name = $args[ 'option_name' ];
1128 $value = self::get_option( $option_name, '', false );
1129
1130 // Attributes all input tags need
1131 $attrs = array(
1132 'name' => "fareharbor_settings[$option_name]",
1133 'id' => $option_name,
1134 'type' => $type,
1135 );
1136
1137 // Type-specific attributes
1138 switch ( $type ) {
1139
1140 case 'text':
1141 $attrs[ 'size' ] = '40';
1142 $attrs[ 'value' ] = (string) $value;
1143 break;
1144
1145 case 'checkbox':
1146 if ( $value )
1147 $attrs[ 'checked' ] = 'checked';
1148 break;
1149
1150 }
1151
1152 // Merge in attributes supplied in the arguments
1153 if ( isset( $args[ 'attrs' ] ) )
1154 // attributes from the arguments will override the defaults
1155 $attrs = $args[ 'attrs' ] + $attrs;
1156
1157 // Actually generate the input tag
1158 $out = '<input';
1159 foreach ( $attrs as $name => $value )
1160 $out .= " $name=\"$value\"";
1161 $out .= ' />';
1162
1163 if ( !empty( $args[ 'label' ] ) )
1164 $out .= "<label for=\"$option_name\">{$args[ 'label' ]}</label>";
1165
1166 if ( !empty( $args[ 'description' ] ) )
1167 $out .= "<p class=\"description\">{$args[ 'description' ]}</p>";
1168
1169 // And print it onto the page
1170 echo $out;
1171
1172 }
1173
1174 public static function render_select_field( $args ) {
1175
1176 $option_name = $args[ 'option_name' ];
1177 $value = self::get_option( $option_name, '', false );
1178
1179 ?>
1180
1181 <select name="<?php echo "fareharbor_settings[$option_name]" ?>" id="<?php echo $option_name ?>">
1182
1183 <option value="" <?php selected( '', $value ); ?>></option>
1184
1185 <?php foreach ( $args[ 'choices' ] as $choice ) { ?>
1186 <option value="<?php echo $choice ?>" <?php selected( $choice, $value ) ?>><?php echo $choice ?></option>
1187 <?php } ?>
1188
1189 </select>
1190
1191 <?php
1192
1193 if ( !empty( $args[ 'description' ] ) )
1194 echo "<p class=\"description\">{$args[ 'description' ]}</p>";
1195
1196 }
1197
1198 }
1199