PluginProbe
FareHarbor for WordPress / 3.6
FareHarbor for WordPress v3.6
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, at fareharbor.php

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