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

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