Restaurant Reservations - Version 2.1.7

Version Description

(2020-06-05) = - Includes a new RTU feature, booking by table - Fixes an issue with the way payments are processed using one of the payment gateways

Download this release

Release Info

Developer Rustaurius
Plugin Icon 128x128 Restaurant Reservations
Version 2.1.7
Comparing to
See all releases

Code changes from version 2.1.6 to 2.1.7

assets/css/admin.css CHANGED
@@ -2561,9 +2561,36 @@ NEW STYLING FOR ADD/DELETE AREAS LIKE CUSTOM FIELDS
2561
 
2562
 
2563
 
 
 
2564
  /*********************************/
2565
- /*** TEMPORARY ***/
2566
  /*********************************/
2567
- ul.rtb-dashboard-new-footer-two-menu:first-of-type {
2568
- display: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2569
  }
2561
 
2562
 
2563
 
2564
+
2565
+
2566
  /*********************************/
2567
+ /*** RESTAURANT TABLES ***/
2568
  /*********************************/
2569
+ #rtb-combinations-popup {
2570
+ position: fixed;
2571
+ top: 10%;
2572
+ right: 0;
2573
+ left: 0;
2574
+ width: 90%;
2575
+ max-width: 600px;
2576
+ padding: 2em;
2577
+ background: #FFF;
2578
+ margin: 3em auto 4em;
2579
+ cursor: auto;
2580
+ z-index: 10000;
2581
+ }
2582
+ #rtb-combinations-popup-background {
2583
+ position: fixed;
2584
+ top: 0;
2585
+ left: 0;
2586
+ width: 100%;
2587
+ height: 100%;
2588
+ background: rgba(0, 0, 0, 0.8);
2589
+ z-index: 9999;
2590
+ overflow-y: auto;
2591
+ cursor: pointer;
2592
+ }
2593
+ #rtb-combinations-submit {
2594
+ margin-top: 12px;
2595
+ cursor: pointer;
2596
  }
assets/js/admin.js CHANGED
@@ -1056,3 +1056,110 @@ jQuery(document).ready(function($){
1056
  }
1057
  });
1058
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1056
  }
1057
  });
1058
  });
1059
+
1060
+
1061
+ // OPTIONS PAGE TABLE COMBINATIONS
1062
+ jQuery(document).ready(function($) {
1063
+ $( '.rtb-new-admin-add-button' ).on( 'click', function() {
1064
+ setTimeout( rtb_combination_handler, 500);
1065
+ setTimeout( rtb_table_section_added, 500);
1066
+ });
1067
+
1068
+ rtb_combination_handler();
1069
+ rtb_table_section_name_handler();
1070
+ rtb_table_selection_delete_handler();
1071
+ });
1072
+
1073
+ function rtb_combination_handler() {
1074
+ jQuery( '.sap-infinite-table-combinations' ).off( 'click' );
1075
+ jQuery( '.sap-infinite-table-combinations' ).on( 'click', function() {
1076
+
1077
+ if ( jQuery( '#rtb-combinations-popup' ).length ) { return; }
1078
+
1079
+ var table_number = jQuery( this ).parent().parent().find( '.sap-infinite-table-number' ).val();
1080
+ var combinations = jQuery( this ).val().split( ',' );
1081
+
1082
+ var html = '<div id="rtb-combinations-popup-background"></div>';
1083
+ html += '<div id="rtb-combinations-popup" data-input_name="' + jQuery( this ).attr( 'name' ) + '">';
1084
+ html += '<h4>Adjacent Tables</h4>';
1085
+ html += '<div id="rtb-combinations-options">';
1086
+
1087
+ jQuery( '.sap-infinite-table-number' ).each( function() {
1088
+ if ( jQuery( this ).val() && jQuery( this ).val() != table_number ) {
1089
+ html += '<div class="rtb-combinations-option-container">';
1090
+ html += '<input type="checkbox" class="rtb-combination-option" value="' + jQuery( this ).val() + '" ' + ( combinations.includes( jQuery( this ).val() ) ? 'checked' : '' ) + ' /> ' + jQuery( this ).val();
1091
+ html += '</div>';
1092
+ }
1093
+ });
1094
+
1095
+ html += '</div>';
1096
+ html += '<div id="rtb-combinations-submit">Confirm</div>';
1097
+ html += '</div>';
1098
+
1099
+ jQuery( 'body' ).append( html );
1100
+
1101
+ rtb_table_popup_handlers();
1102
+ });
1103
+
1104
+ }
1105
+
1106
+ function rtb_table_popup_handlers() {
1107
+
1108
+ jQuery( '#rtb-combinations-submit' ).off( 'click' );
1109
+ jQuery( '#rtb-combinations-submit' ).on( 'click', function() {
1110
+
1111
+ var combinations = '';
1112
+
1113
+ jQuery( '.rtb-combination-option' ).each( function() {
1114
+ if ( jQuery( this ).prop('checked') ) { combinations += ( combinations.length ? ',' : '' ) + jQuery( this ).val(); }
1115
+ });
1116
+
1117
+ var input_name = jQuery( '#rtb-combinations-popup' ).data( 'input_name' );
1118
+
1119
+ jQuery( '.sap-infinite-table-combinations[name="' + input_name + '"]' ).attr( 'value', combinations );
1120
+
1121
+ jQuery( '#rtb-combinations-popup, #rtb-combinations-popup-background' ).remove();
1122
+
1123
+ infiniteTableSaveData( jQuery( '.sap-infinite-table-combinations[name="' + input_name + '"]' ).closest( '.sap-infinite-table' ) );
1124
+ });
1125
+
1126
+ jQuery( '#rtb-combinations-popup-background' ).on( 'click', function() {
1127
+
1128
+ jQuery( '#rtb-combinations-popup, #rtb-combinations-popup-background' ).remove();
1129
+ });
1130
+ }
1131
+
1132
+ function rtb_table_section_added() {
1133
+
1134
+ var new_row = jQuery( '#sap-table-rtb-table-sections tbody tr:last-of-type' );
1135
+ var section_id = new_row.find( '.sap-infinite-table-section_id' ).val();
1136
+ var section_name = new_row.find( '.sap-infinite-table-name' ).val();
1137
+
1138
+ jQuery( '.sap-infinite-table-section' ).append( '<option value="' + section_id + '">' + section_name + '</option>' );
1139
+
1140
+ rtb_table_section_name_handler();
1141
+ rtb_table_selection_delete_handler();
1142
+ }
1143
+
1144
+ function rtb_table_section_name_handler() {
1145
+
1146
+ jQuery( '.sap-infinite-table-name' ).off( 'keyup.table_section_name_update' );
1147
+ jQuery( '.sap-infinite-table-name' ).on( 'keyup.table_section_name_update', function() {
1148
+
1149
+ var section_name = jQuery( this ).val();
1150
+ var section_id = jQuery( this ).closest( '.sap-inifinite-table-row' ).find( '.sap-infinite-table-id' ).val();
1151
+
1152
+ jQuery( '.sap-infinite-table-section option[value="' + section_id + '"]' ).html( section_name );
1153
+ });
1154
+ }
1155
+
1156
+ function rtb_table_selection_delete_handler() {
1157
+
1158
+ jQuery( '#sap-table-rtb-table-sections' ).off( 'click.table_section_delete' );
1159
+ jQuery( '#sap-table-rtb-table-sections' ).on( 'click.table_section_delete', function() {
1160
+
1161
+ var section_id = jQuery( this ).closest( '.sap-inifinite-table-row' ).find( '.sap-infinite-table-section_id' ).val();
1162
+
1163
+ jQuery( '.sap-infinite-table-section option[value="' + section_id + '"]' ).remove();
1164
+ });
1165
+ }
assets/js/booking-form.js CHANGED
@@ -162,14 +162,20 @@ jQuery(document).ready(function ($) {
162
  close: function() {
163
  rtb_booking_form.update_timepicker_range();
164
  rtb_booking_form.update_party_size_select();
 
165
  }
166
  });
167
 
168
  rtb_booking_form.timepicker.on( {
169
  close: function() {
170
  rtb_booking_form.update_party_size_select();
 
171
  }
172
  });
 
 
 
 
173
  }
174
  };
175
 
@@ -426,6 +432,7 @@ jQuery(document).ready(function ($) {
426
  };
427
 
428
  rtb_booking_form.update_party_size_select = function() {
 
429
  if ( rtb_pickadate.enable_max_reservations && rtb_pickadate.max_people ) {
430
  var partySelect = $('#rtb-party'),
431
  selected_date = new Date( rtb_booking_form.datepicker.get( 'select', 'yyyy/mm/dd' ) ),
@@ -466,6 +473,57 @@ jQuery(document).ready(function ($) {
466
  }
467
  }
468
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
 
470
  rtb_booking_form.init();
471
  });
162
  close: function() {
163
  rtb_booking_form.update_timepicker_range();
164
  rtb_booking_form.update_party_size_select();
165
+ rtb_booking_form.update_possible_tables();
166
  }
167
  });
168
 
169
  rtb_booking_form.timepicker.on( {
170
  close: function() {
171
  rtb_booking_form.update_party_size_select();
172
+ rtb_booking_form.update_possible_tables();
173
  }
174
  });
175
+
176
+ $( '#rtb-party' ).on( 'change', function() {
177
+ rtb_booking_form.update_possible_tables();
178
+ })
179
  }
180
  };
181
 
432
  };
433
 
434
  rtb_booking_form.update_party_size_select = function() {
435
+
436
  if ( rtb_pickadate.enable_max_reservations && rtb_pickadate.max_people ) {
437
  var partySelect = $('#rtb-party'),
438
  selected_date = new Date( rtb_booking_form.datepicker.get( 'select', 'yyyy/mm/dd' ) ),
473
  }
474
  }
475
 
476
+ rtb_booking_form.update_possible_tables = function() { console.log( "Called0");
477
+
478
+ if ( rtb_pickadate.enable_tables ) { console.log( "Called1");
479
+
480
+ var table_select = $('#rtb-table'),
481
+ party = $('#rtb-party').val(),
482
+ selected_date = new Date( rtb_booking_form.datepicker.get( 'select', 'yyyy/mm/dd' ) ),
483
+ selected_date_year = selected_date.getFullYear(),
484
+ selected_date_month = selected_date.getMonth(),
485
+ selected_date_date = selected_date.getDate(),
486
+ selected_time = rtb_booking_form.timepicker.get('value');
487
+
488
+ if ( ! selected_time || ! party ) { return; }
489
+
490
+ selected_date_month = ('0' + (selected_date_month + 1)).slice(-2);
491
+ selected_date_date = ('0' + selected_date_date).slice(-2);
492
+
493
+ //reset table selection
494
+ table_select.prop("selectedIndex", 0).change();
495
+
496
+ //remove table combinations
497
+ table_select.find('> option').each( function() {
498
+ if ( $( this ).val().indexOf( ',' ) !== -1 ) { $( this ).remove(); }
499
+ })
500
+
501
+ var data = 'year=' + selected_date_year + '&month=' + selected_date_month + '&day=' + selected_date_date + '&time=' + selected_time + '&party=' + party + '&action=rtb_get_available_tables'; console.log(data);
502
+ jQuery.post( ajaxurl, data, function( response ) {
503
+ if ( ! response ) {
504
+ return;
505
+ }
506
+
507
+ response = jQuery.parseJSON(response);
508
+
509
+ var available_tables = response.available_tables; console.log( available_tables );
510
+
511
+ table_select.prop('disabled', false);
512
+
513
+ table_select.find('> option').hide();
514
+
515
+ jQuery.each(available_tables, function(index, element) {
516
+
517
+ if ( index.indexOf( ',' ) === -1 ) { table_select.find('> option[value="' + index + '"]').show(); console.log( "unhiding" ); }
518
+ else {
519
+ table_select.append( '<option value="' + index + '">' + element + '</option>' ); console.log( "creating" );
520
+ }
521
+
522
+ });
523
+ });
524
+ }
525
+
526
+ }
527
 
528
  rtb_booking_form.init();
529
  });
includes/Ajax.class.php CHANGED
@@ -33,6 +33,12 @@ if ( !class_exists( 'rtbAJAX' ) ) {
33
  */
34
  public $time;
35
 
 
 
 
 
 
 
36
  public function __construct() {
37
 
38
  add_action( 'wp_ajax_rtb_get_available_time_slots', array( $this, 'get_time_slots' ) );
@@ -46,6 +52,11 @@ if ( !class_exists( 'rtbAJAX' ) ) {
46
 
47
  add_action( 'wp_ajax_rtb_get_available_party_size', array( $this, 'get_available_party_size' ) );
48
  add_action( 'wp_ajax_nopriv_rtb_get_available_party_size', array( $this, 'get_available_party_size' ) );
 
 
 
 
 
49
  }
50
 
51
  /**
@@ -525,6 +536,139 @@ if ( !class_exists( 'rtbAJAX' ) ) {
525
  }
526
  }
527
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  public function format_pickadate_time( $time ) {
529
  return array( date( 'G', $time ), date( 'i', $time ) );
530
  }
33
  */
34
  public $time;
35
 
36
+ /**
37
+ * The party size we're looking to find valid tables for
38
+ * @since 2.1.7
39
+ */
40
+ public $party;
41
+
42
  public function __construct() {
43
 
44
  add_action( 'wp_ajax_rtb_get_available_time_slots', array( $this, 'get_time_slots' ) );
52
 
53
  add_action( 'wp_ajax_rtb_get_available_party_size', array( $this, 'get_available_party_size' ) );
54
  add_action( 'wp_ajax_nopriv_rtb_get_available_party_size', array( $this, 'get_available_party_size' ) );
55
+
56
+ add_action( 'wp_ajax_rtb_get_available_tables', array( $this, 'get_available_tables' ) );
57
+ add_action( 'wp_ajax_nopriv_rtb_get_available_tables', array( $this, 'get_available_tables' ) );
58
+
59
+ // add_action( 'admin_init', array( $this, 'get_available_tables' ) );
60
  }
61
 
62
  /**
536
  }
537
  }
538
 
539
+ /**
540
+ * Get tables available to be booked at a specific time and party size
541
+ * @since 2.1.7
542
+ */
543
+ public function get_available_tables() {
544
+ global $rtb_controller;
545
+
546
+ $tables = $rtb_controller->settings->get_sorted_tables();
547
+
548
+ $this->year = isset( $_POST['year'] ) ? sanitize_text_field( $_POST['year'] ) : false;
549
+ $this->month = isset( $_POST['month'] ) ? sanitize_text_field( $_POST['month'] ) : false;
550
+ $this->day = isset( $_POST['day'] ) ? sanitize_text_field( $_POST['day'] ) : false;
551
+ $this->time = isset( $_POST['time'] ) ? sanitize_text_field( $_POST['time'] ) : false;
552
+ $this->party = isset( $_POST['party'] ) ? sanitize_text_field( $_POST['party'] ) : false;
553
+
554
+ /*$this->year = 2020;
555
+ $this->month = 06;
556
+ $this->day = 12;
557
+ $this->time = '02:15 PM';
558
+ $this->party = 12;*/
559
+
560
+ if ( ! isset( $this->year ) or ! isset( $this->month ) or ! isset( $this->day ) or ! isset( $this->time ) ) { return false; }
561
+
562
+ $datetime = strtotime( $this->year . '-' . $this->month . '-' . $this->day . ' ' . $this->time );
563
+
564
+ $valid_tables = rtb_get_valid_tables( $datetime );
565
+
566
+ if ( isset( $this->party ) ) {
567
+
568
+ $possible_combinations = array();
569
+ foreach ( $valid_tables as $valid_table ) {
570
+
571
+ // If the party size is between the min and max for the table, great
572
+ if ( $tables[ $valid_table ]->min_people <= $this->party and $tables[ $valid_table ]->max_people >= $this->party ) {
573
+
574
+ $possible_combinations[] = $valid_table;
575
+ }
576
+ // If the party is above the minimum for the table, look to see if combinations could work
577
+ elseif ( $tables[ $valid_table ]->min_people <= $this->party ) {
578
+
579
+ $combination = $this->get_combinations_chain( $tables, $valid_tables, $valid_table, $tables[ $valid_table ]->max_people, $this->party );
580
+
581
+ if ( $combination ) { $possible_combinations[] = $combination; }
582
+ }
583
+
584
+ $return_tables = $this->format_tables( $possible_combinations );
585
+ }
586
+ }
587
+ else {
588
+ $return_tables = $this->format_tables( $valid_tables );
589
+ }
590
+
591
+ $response = (object) array( 'available_tables' => $return_tables);
592
+
593
+ echo json_encode($response);
594
+
595
+ die();
596
+ }
597
+
598
+ /**
599
+ * Recursively go through table combinations to find one that has enough seats
600
+ * @since 2.1.7
601
+ */
602
+ public function get_combinations_chain( $tables, $valid_tables, $table_chain, $current_size, $needed_size ) {
603
+
604
+ $current_table = substr( $table_chain, strrpos($table_chain, ',') ? strrpos($table_chain, ',') + 1 : 0 );
605
+
606
+ if ( ! $tables[ $current_table ]->combinations ) { return false; }
607
+
608
+ $possible_tables = explode( ',', $tables[ $current_table ]->combinations );
609
+
610
+ foreach ( $possible_tables as $possible_table ) {
611
+
612
+ // Only search larger table numbers to avoid going over the same combinations multiple times
613
+ if ( $possible_table < $current_table ) { continue; }
614
+
615
+ // If the table has already been booked, continue
616
+ if ( !in_array( $possible_table, $valid_tables) ) { continue; }
617
+
618
+ // If the table can hold the group on its own, continue
619
+ if ( $tables[ $possible_table ]->max_people >= $needed_size ) { continue; }
620
+
621
+ $current_size += $tables[ $possible_table ]->max_people;
622
+ $table_chain .= ',' . $possible_table;
623
+
624
+ if ( $current_size >= $needed_size ) { return $table_chain; }
625
+ else {
626
+ // Keep going to see if we can add more tables to make it work
627
+ $table_chain = $this->get_combinations_chain( $tables, $valid_tables, $table_chain, $current_size, $needed_size );
628
+
629
+ if ( $table_chain ) { return $table_chain; }
630
+ }
631
+ }
632
+
633
+ //no viable combination found
634
+ return false;
635
+ }
636
+
637
+ /**
638
+ * Format the tables available to be booked as number(s)_string => human_value pairs
639
+ * @since 2.1.7
640
+ */
641
+ public function format_tables ( $table_numbers ) {
642
+ global $rtb_controller;
643
+
644
+ $formatted_tables = array();
645
+
646
+ $tables = json_decode( html_entity_decode( $rtb_controller->settings->get_setting( 'rtb-tables' ) ) );
647
+
648
+ foreach ( $table_numbers as $table_number ) {
649
+
650
+ $table_parts = explode( ',', $table_number );
651
+
652
+ $table_values = array(
653
+ 'numbers' => '',
654
+ 'min_people' => 0,
655
+ 'max_people' => 0
656
+ );
657
+
658
+ foreach ( $tables as $table ) {
659
+ if ( in_array($table->number, $table_parts) ) {
660
+ $table_values['numbers'] .= ( strlen( $table_values['numbers'] ) ? ', ' : '' ) . $table->number;
661
+ $table_values['min_people'] += $table->min_people;
662
+ $table_values['max_people'] += $table->max_people;
663
+ }
664
+ }
665
+
666
+ $formatted_tables[ $table_values['numbers'] ] = $table_values['numbers'] . ' - (min. ' . $table_values['min_people'] . '/max. ' . $table_values['max_people'] . ')';
667
+ }
668
+
669
+ return $formatted_tables;
670
+ }
671
+
672
  public function format_pickadate_time( $time ) {
673
  return array( date( 'G', $time ), date( 'i', $time ) );
674
  }
includes/Booking.class.php CHANGED
@@ -83,6 +83,7 @@ class rtbBooking {
83
  'ip' => '',
84
  'consent_acquired' => '',
85
  'deposit' => '0',
 
86
  'receipt_id' => '',
87
  'reminder_sent' => false,
88
  'late_arrival_sent' => false,
@@ -104,6 +105,7 @@ class rtbBooking {
104
  $this->ip = $meta['ip'];
105
  $this->consent_acquired = $meta['consent_acquired'];
106
  $this->deposit = $meta['deposit'];
 
107
  $this->receipt_id = $meta['receipt_id'];
108
  $this->late_arrival_sent = $meta['late_arrival_sent'];
109
  $this->reminder_sent = $meta['reminder_sent'];
@@ -478,6 +480,29 @@ class rtbBooking {
478
  );
479
  }
480
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  // reCAPTCHA
482
  if ( $rtb_controller->settings->get_setting( 'enable-captcha' ) && !is_admin() ) {
483
  if ( ! isset($_POST['g-recaptcha-response']) ) {
@@ -660,6 +685,22 @@ class rtbBooking {
660
  return true;
661
  }
662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
  /**
664
  * Check whether the number of reservations occurring at the same time is below the threshold
665
  * where reservations get automatically confirmed
@@ -881,6 +922,10 @@ class rtbBooking {
881
  $meta['deposit'] = $this->deposit;
882
  }
883
 
 
 
 
 
884
  if ( !empty( $this->receipt_id ) ) {
885
  $meta['receipt_id'] = $this->receipt_id;
886
  }
83
  'ip' => '',
84
  'consent_acquired' => '',
85
  'deposit' => '0',
86
+ 'table' => '',
87
  'receipt_id' => '',
88
  'reminder_sent' => false,
89
  'late_arrival_sent' => false,
105
  $this->ip = $meta['ip'];
106
  $this->consent_acquired = $meta['consent_acquired'];
107
  $this->deposit = $meta['deposit'];
108
+ $this->table = $meta['table'];
109
  $this->receipt_id = $meta['receipt_id'];
110
  $this->late_arrival_sent = $meta['late_arrival_sent'];
111
  $this->reminder_sent = $meta['reminder_sent'];
480
  );
481
  }
482
 
483
+ // Table
484
+ $table = empty( $_POST['rtb-table'] ) ? array() : explode( ',', sanitize_text_field( stripslashes_deep( $_POST['rtb-table'] ) ) );
485
+ $this->table = is_array( $table ) ? array_map( 'intval', $table ) : array();
486
+
487
+ $table_required = $rtb_controller->settings->get_setting( 'require-table' );
488
+ if ( $table_required && empty( $this->table ) ) {
489
+ $this->validation_errors[] = array(
490
+ 'field' => 'table',
491
+ 'post_variable' => $this->table,
492
+ 'message' => __( 'Please select a table for your booking.', 'restaurant-reservations' ),
493
+ );
494
+ }
495
+
496
+ // check whether there is a time conflict for a particular table
497
+ $valid_table = $this->table ? $this->is_valid_table() : true;
498
+ if ( ! $valid_table ) {
499
+ $this->validation_errors[] = array(
500
+ 'field' => 'table',
501
+ 'post_variable' => $this->table,
502
+ 'message' => __( 'Please select a valid table for your booking.', 'restaurant-reservations' ),
503
+ );
504
+ }
505
+
506
  // reCAPTCHA
507
  if ( $rtb_controller->settings->get_setting( 'enable-captcha' ) && !is_admin() ) {
508
  if ( ! isset($_POST['g-recaptcha-response']) ) {
685
  return true;
686
  }
687
 
688
+ /**
689
+ * Check if a table(s) is valid (not already taken during a specific timeslot)
690
+ *
691
+ * @return bool
692
+ * @since 2.1.7
693
+ */
694
+ public function is_valid_table() {
695
+ global $rtb_controller;
696
+
697
+ if ( ! $this->table or ! is_array( $this->table ) ) { return false; }
698
+
699
+ $valid_tables = rtb_get_valid_tables( $this->date );
700
+
701
+ return $this->table == array_intersect( $this->table, $valid_tables );
702
+ }
703
+
704
  /**
705
  * Check whether the number of reservations occurring at the same time is below the threshold
706
  * where reservations get automatically confirmed
922
  $meta['deposit'] = $this->deposit;
923
  }
924
 
925
+ if ( !empty( $this->table ) ) {
926
+ $meta['table'] = $this->table;
927
+ }
928
+
929
  if ( !empty( $this->receipt_id ) ) {
930
  $meta['receipt_id'] = $this->receipt_id;
931
  }
includes/Cron.class.php CHANGED
@@ -24,7 +24,7 @@ class rtbCron {
24
  }
25
 
26
  /**
27
- * Adds in 2, 5, 15, and 30 minute cron intervals
28
  *
29
  * @var array $schedules
30
  * @since 2.0.0
24
  }
25
 
26
  /**
27
+ * Adds in 10 minute cron interval
28
  *
29
  * @var array $schedules
30
  * @since 2.0.0
includes/Dashboard.class.php CHANGED
@@ -197,7 +197,7 @@ class rtbDashboard {
197
  <div class="rtb-dashboard-new-widget-box-bottom">
198
  <ul class="rtb-dashboard-support-widgets">
199
  <li>
200
- <a href="https://www.youtube.com/channel/UCZPuaoetCJB1vZOmpnMxJNw/featured" target="_blank">
201
  <img src="<?php echo plugins_url( '../assets/img/ewd-support-icon-youtube.png', __FILE__ ); ?>">
202
  <div class="rtb-dashboard-support-widgets-text">YouTube Tutorials</div>
203
  </a>
@@ -424,13 +424,13 @@ class rtbDashboard {
424
  </div>
425
  <ul class="rtb-dashboard-new-footer-two-menu">
426
  <li>SOCIAL</li>
427
- <li><a href="https://www.facebook.com/EtoileWebDesign/" target="_blank">Facebook</a></li>
428
- <li><a href="https://twitter.com/EtoileWebDesign" target="_blank">Twitter</a></li>
429
- <li><a href="https://www.fivestarplugins.com/blog/" target="_blank">Blog</a></li>
430
  </ul>
431
  <ul class="rtb-dashboard-new-footer-two-menu">
432
  <li>SUPPORT</li>
433
- <li><a href="https://www.youtube.com/channel/UCZPuaoetCJB1vZOmpnMxJNw/featured" target="_blank">YouTube Tutorials</a></li>
434
  <li><a href="http://doc.fivestarplugins.com/plugins/restaurant-reservations/" target="_blank">Documentation</a></li>
435
  <li><a href="https://www.fivestarplugins.com/support-center/" target="_blank">Get Support</a></li>
436
  <li><a href="https://wordpress.org/plugins/restaurant-reservations/#faq" target="_blank">FAQs</a></li>
197
  <div class="rtb-dashboard-new-widget-box-bottom">
198
  <ul class="rtb-dashboard-support-widgets">
199
  <li>
200
+ <a href="https://www.youtube.com/watch?v=b6x0QkgHBKI&list=PLEndQUuhlvSpWIb_sbRdFsHSkDADYU7JF" target="_blank">
201
  <img src="<?php echo plugins_url( '../assets/img/ewd-support-icon-youtube.png', __FILE__ ); ?>">
202
  <div class="rtb-dashboard-support-widgets-text">YouTube Tutorials</div>
203
  </a>
424
  </div>
425
  <ul class="rtb-dashboard-new-footer-two-menu">
426
  <li>SOCIAL</li>
427
+ <li><a href="https://www.facebook.com/fivestarplugins/" target="_blank">Facebook</a></li>
428
+ <li><a href="https://twitter.com/fivestarplugins" target="_blank">Twitter</a></li>
429
+ <li><a href="https://www.fivestarplugins.com/category/blog/" target="_blank">Blog</a></li>
430
  </ul>
431
  <ul class="rtb-dashboard-new-footer-two-menu">
432
  <li>SUPPORT</li>
433
+ <li><a href="https://www.youtube.com/watch?v=b6x0QkgHBKI&list=PLEndQUuhlvSpWIb_sbRdFsHSkDADYU7JF" target="_blank">YouTube Tutorials</a></li>
434
  <li><a href="http://doc.fivestarplugins.com/plugins/restaurant-reservations/" target="_blank">Documentation</a></li>
435
  <li><a href="https://www.fivestarplugins.com/support-center/" target="_blank">Get Support</a></li>
436
  <li><a href="https://wordpress.org/plugins/restaurant-reservations/#faq" target="_blank">FAQs</a></li>
includes/Permissions.class.php CHANGED
@@ -22,9 +22,10 @@ class rtbPermissions {
22
  "templates" => 2,
23
  "designer" => 2,
24
  "premium_view_bookings" => 2,
25
- "premium_table_restrictions" => 2,
26
  "payments" => 3,
27
  "reminders" => 3,
 
28
  );
29
  }
30
 
22
  "templates" => 2,
23
  "designer" => 2,
24
  "premium_view_bookings" => 2,
25
+ "premium_seat_restrictions" => 2,
26
  "payments" => 3,
27
  "reminders" => 3,
28
+ "premium_table_restrictions" => 3
29
  );
30
  }
31
 
includes/Settings.class.php CHANGED
@@ -373,6 +373,8 @@ class rtbSettings {
373
  'ebfrtb-pdf-lib' => 'mpdf',
374
  'ebfrtb-csv-date-format' => get_option( 'date_format' ) . ' ' . get_option( 'time_format' ),
375
 
 
 
376
  // MailChimp defaults
377
  'mc-optprompt' => __( 'Sign up for our mailing list.', 'restaurant-reservations' ),
378
 
@@ -1137,15 +1139,6 @@ If you were not the one to cancel this booking, please contact us.
1137
  }
1138
  else { $premium_view_bookings_permissions = array(); }
1139
 
1140
- if ( ! $rtb_controller->permissions->check_permission('premium_table_restrictions') ) {
1141
- $premium_table_restrictions_permissions = array(
1142
- 'disabled' => true,
1143
- 'disabled_image'=> 'https://www.etoilewebdesign.com/wp-content/uploads/2018/06/Logo-White-Filled40-px.png',
1144
- 'purchase_link' => 'https://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/'
1145
- );
1146
- }
1147
- else { $premium_table_restrictions_permissions = array(); }
1148
-
1149
  $sap->add_section(
1150
  'rtb-settings',
1151
  array(
@@ -1203,25 +1196,119 @@ If you were not the one to cancel this booking, please contact us.
1203
  )
1204
  );
1205
 
 
 
 
 
 
 
 
 
 
1206
  $sap->add_section(
1207
  'rtb-settings',
1208
  array_merge(
1209
  array(
1210
- 'id' => 'rtb-table-seat-assignments',
1211
- 'title' => __( 'Table/Seat Restrictions', 'restaurant-reservations' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1212
  'tab' => 'rtb-premium',
1213
  ),
1214
- $premium_table_restrictions_permissions
1215
  )
1216
  );
1217
  $sap->add_setting(
1218
  'rtb-settings',
1219
- 'rtb-table-seat-assignments',
1220
  'count',
1221
  array(
1222
  'id' => 'rtb-dining-block-length',
1223
  'title' => __( 'Dining Block Length', 'restaurant-reservations' ),
1224
- 'description' => __( 'How long does a meal generally last? This setting affects a table and/or seat unavailable for after someone makes a reservation.', 'restaurant-reservations' ),
1225
  'default' => $this->defaults['rtb-dining-block-length'],
1226
  'blank_option' => false,
1227
  'min_value' => 10,
@@ -1233,7 +1320,7 @@ If you were not the one to cancel this booking, please contact us.
1233
 
1234
  $sap->add_setting(
1235
  'rtb-settings',
1236
- 'rtb-table-seat-assignments',
1237
  'toggle',
1238
  array(
1239
  'id' => 'rtb-enable-max-tables',
@@ -1244,7 +1331,7 @@ If you were not the one to cancel this booking, please contact us.
1244
 
1245
  $sap->add_setting(
1246
  'rtb-settings',
1247
- 'rtb-table-seat-assignments',
1248
  'count',
1249
  array(
1250
  'id' => 'rtb-max-tables-count',
@@ -1258,7 +1345,7 @@ If you were not the one to cancel this booking, please contact us.
1258
 
1259
  $sap->add_setting(
1260
  'rtb-settings',
1261
- 'rtb-table-seat-assignments',
1262
  'count',
1263
  array(
1264
  'id' => 'rtb-max-people-count',
@@ -1272,7 +1359,7 @@ If you were not the one to cancel this booking, please contact us.
1272
 
1273
  $sap->add_setting(
1274
  'rtb-settings',
1275
- 'rtb-table-seat-assignments',
1276
  'count',
1277
  array(
1278
  'id' => 'auto-confirm-max-reservations',
@@ -1286,7 +1373,7 @@ If you were not the one to cancel this booking, please contact us.
1286
 
1287
  $sap->add_setting(
1288
  'rtb-settings',
1289
- 'rtb-table-seat-assignments',
1290
  'count',
1291
  array(
1292
  'id' => 'auto-confirm-max-seats',
@@ -1298,90 +1385,120 @@ If you were not the one to cancel this booking, please contact us.
1298
  )
1299
  );
1300
 
1301
- if ( ! $rtb_controller->permissions->check_permission('mailchimp') ) {
1302
- $mailchimp_permissions = array(
1303
  'disabled' => true,
1304
  'disabled_image'=> 'https://www.etoilewebdesign.com/wp-content/uploads/2018/06/Logo-White-Filled40-px.png',
1305
- 'purchase_link' => 'https://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/'
 
1306
  );
1307
  }
1308
- else { $mailchimp_permissions = array(); }
1309
 
1310
  $sap->add_section(
1311
  'rtb-settings',
1312
  array_merge(
1313
  array(
1314
- 'id' => 'rtb-mailchimp',
1315
- 'title' => __( 'MailChimp', 'restaurant-reservations' ),
1316
  'tab' => 'rtb-premium',
1317
  ),
1318
- $mailchimp_permissions
1319
  )
1320
  );
1321
-
1322
- // MailChimp API key
1323
  $sap->add_setting(
1324
  'rtb-settings',
1325
- 'rtb-mailchimp',
1326
- 'mcapikey',
1327
  array(
1328
- 'id' => 'mc-apikey',
1329
- 'title' => __( 'MailChimp API Key', 'restaurant-reservations' ),
1330
- 'description' => '<a href="https://admin.mailchimp.com/account/api/" target="_blank">' . __( 'Retrieve or create an API key for your MailChimp account', 'restaurant-reservations' ) . '</a>',
1331
- 'placeholder' => __( 'API Key', 'restaurant-reservations' ),
1332
- 'string_status_connected' => __( 'Connected', 'restaurant-reservations' ),
1333
- 'string_status_error' => __( 'Invalid Key', 'restaurant-reservations' ),
1334
  )
1335
  );
1336
-
1337
- // Don't show the settings until an API key has been successfully entered
1338
- if ( $rtb_controller->mailchimp->status === true ) {
1339
-
1340
- // MailChimp list and merge fields
1341
- $sap->add_setting(
1342
- 'rtb-settings',
1343
- 'rtb-mailchimp',
1344
- 'mclistmerge',
1345
- array(
1346
- 'id' => 'mc-lists',
1347
- 'title' => __( 'Subscribe List', 'restaurant-reservations' ),
1348
- 'description' => __( 'New booking requests will be subscribed to this list.', 'restaurant-reservations' ),
1349
- 'fields' => $rtb_controller->mailchimp->merge_fields,
1350
- 'string_loading' => __( 'Loading...', 'restaurant-reservations' ),
1351
- )
1352
- );
1353
-
1354
- // Opt-out Option
1355
- $sap->add_setting(
1356
- 'rtb-settings',
1357
- 'rtb-mailchimp',
1358
- 'select',
1359
- array(
1360
- 'id' => 'mc-optout',
1361
- 'title' => __( 'Opt-in', 'restaurant-reservations' ),
1362
- 'description' => __( 'Whether to show an option for users to opt-in to being signed up for your mailing list when making a reservation.', 'restaurant-reservations' ),
1363
- 'blank_option' => false,
1364
- 'options' => array(
1365
- '' => __( 'Show opt-in prompt', 'restaurant-reservations' ),
1366
- 'checked' => __( 'Show pre-checked opt-in prompt', 'restaurant-reservations' ),
1367
- 'no' => __( 'Don\'t show opt-in prompt', 'restaurant-reservations' ),
1368
  ),
 
 
 
 
 
 
 
 
 
 
1369
  )
1370
- );
1371
-
1372
- // Opt-out prompt text
1373
- $sap->add_setting(
1374
- 'rtb-settings',
1375
- 'rtb-mailchimp',
1376
- 'text',
1377
- array(
1378
- 'id' => 'mc-optprompt',
1379
- 'title' => __( 'Opt-in Prompt', 'restaurant-reservations' ),
1380
- 'description' => __( 'Text to display with the opt-in option.', 'restaurant-reservations' ),
1381
- 'placeholder' => $this->defaults['mc-optprompt'],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1382
  )
1383
- );
1384
- }
1385
 
1386
  if ( ! $rtb_controller->permissions->check_permission('designer') ) {
1387
  $designer_permissions = array(
@@ -2515,6 +2632,59 @@ If you were not the one to cancel this booking, please contact us.
2515
  return apply_filters( 'rtb_form_party_options', $options );
2516
  }
2517
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2518
  /**
2519
  * Retrieve form fields
2520
  *
@@ -2665,6 +2835,25 @@ If you were not the one to cancel this booking, please contact us.
2665
  );
2666
  }
2667
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2668
  return apply_filters( 'rtb_booking_form_fields', $fields, $request, $args );
2669
  }
2670
 
@@ -2775,5 +2964,22 @@ If you were not the one to cancel this booking, please contact us.
2775
  return $ad - $bd;
2776
  }
2777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2778
  }
2779
  } // endif;
373
  'ebfrtb-pdf-lib' => 'mpdf',
374
  'ebfrtb-csv-date-format' => get_option( 'date_format' ) . ' ' . get_option( 'time_format' ),
375
 
376
+ 'table-sections' => array(),
377
+
378
  // MailChimp defaults
379
  'mc-optprompt' => __( 'Sign up for our mailing list.', 'restaurant-reservations' ),
380
 
1139
  }
1140
  else { $premium_view_bookings_permissions = array(); }
1141
 
 
 
 
 
 
 
 
 
 
1142
  $sap->add_section(
1143
  'rtb-settings',
1144
  array(
1196
  )
1197
  );
1198
 
1199
+ if ( ! $rtb_controller->permissions->check_permission('mailchimp') ) {
1200
+ $mailchimp_permissions = array(
1201
+ 'disabled' => true,
1202
+ 'disabled_image'=> 'https://www.etoilewebdesign.com/wp-content/uploads/2018/06/Logo-White-Filled40-px.png',
1203
+ 'purchase_link' => 'https://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/'
1204
+ );
1205
+ }
1206
+ else { $mailchimp_permissions = array(); }
1207
+
1208
  $sap->add_section(
1209
  'rtb-settings',
1210
  array_merge(
1211
  array(
1212
+ 'id' => 'rtb-mailchimp',
1213
+ 'title' => __( 'MailChimp', 'restaurant-reservations' ),
1214
+ 'tab' => 'rtb-premium',
1215
+ ),
1216
+ $mailchimp_permissions
1217
+ )
1218
+ );
1219
+
1220
+ // MailChimp API key
1221
+ $sap->add_setting(
1222
+ 'rtb-settings',
1223
+ 'rtb-mailchimp',
1224
+ 'mcapikey',
1225
+ array(
1226
+ 'id' => 'mc-apikey',
1227
+ 'title' => __( 'MailChimp API Key', 'restaurant-reservations' ),
1228
+ 'description' => '<a href="https://admin.mailchimp.com/account/api/" target="_blank">' . __( 'Retrieve or create an API key for your MailChimp account', 'restaurant-reservations' ) . '</a>',
1229
+ 'placeholder' => __( 'API Key', 'restaurant-reservations' ),
1230
+ 'string_status_connected' => __( 'Connected', 'restaurant-reservations' ),
1231
+ 'string_status_error' => __( 'Invalid Key', 'restaurant-reservations' ),
1232
+ )
1233
+ );
1234
+
1235
+ // Don't show the settings until an API key has been successfully entered
1236
+ if ( $rtb_controller->mailchimp->status === true ) {
1237
+
1238
+ // MailChimp list and merge fields
1239
+ $sap->add_setting(
1240
+ 'rtb-settings',
1241
+ 'rtb-mailchimp',
1242
+ 'mclistmerge',
1243
+ array(
1244
+ 'id' => 'mc-lists',
1245
+ 'title' => __( 'Subscribe List', 'restaurant-reservations' ),
1246
+ 'description' => __( 'New booking requests will be subscribed to this list.', 'restaurant-reservations' ),
1247
+ 'fields' => $rtb_controller->mailchimp->merge_fields,
1248
+ 'string_loading' => __( 'Loading...', 'restaurant-reservations' ),
1249
+ )
1250
+ );
1251
+
1252
+ // Opt-out Option
1253
+ $sap->add_setting(
1254
+ 'rtb-settings',
1255
+ 'rtb-mailchimp',
1256
+ 'select',
1257
+ array(
1258
+ 'id' => 'mc-optout',
1259
+ 'title' => __( 'Opt-in', 'restaurant-reservations' ),
1260
+ 'description' => __( 'Whether to show an option for users to opt-in to being signed up for your mailing list when making a reservation.', 'restaurant-reservations' ),
1261
+ 'blank_option' => false,
1262
+ 'options' => array(
1263
+ '' => __( 'Show opt-in prompt', 'restaurant-reservations' ),
1264
+ 'checked' => __( 'Show pre-checked opt-in prompt', 'restaurant-reservations' ),
1265
+ 'no' => __( 'Don\'t show opt-in prompt', 'restaurant-reservations' ),
1266
+ ),
1267
+ )
1268
+ );
1269
+
1270
+ // Opt-out prompt text
1271
+ $sap->add_setting(
1272
+ 'rtb-settings',
1273
+ 'rtb-mailchimp',
1274
+ 'text',
1275
+ array(
1276
+ 'id' => 'mc-optprompt',
1277
+ 'title' => __( 'Opt-in Prompt', 'restaurant-reservations' ),
1278
+ 'description' => __( 'Text to display with the opt-in option.', 'restaurant-reservations' ),
1279
+ 'placeholder' => $this->defaults['mc-optprompt'],
1280
+ )
1281
+ );
1282
+ }
1283
+
1284
+ if ( ! $rtb_controller->permissions->check_permission('premium_seat_restrictions') ) {
1285
+ $premium_seat_restrictions_permissions = array(
1286
+ 'disabled' => true,
1287
+ 'disabled_image'=> 'https://www.etoilewebdesign.com/wp-content/uploads/2018/06/Logo-White-Filled40-px.png',
1288
+ 'purchase_link' => 'https://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/'
1289
+ );
1290
+ }
1291
+ else { $premium_seat_restrictions_permissions = array(); }
1292
+
1293
+ $sap->add_section(
1294
+ 'rtb-settings',
1295
+ array_merge(
1296
+ array(
1297
+ 'id' => 'rtb-seat-assignments',
1298
+ 'title' => __( 'Seat Restrictions', 'restaurant-reservations' ),
1299
  'tab' => 'rtb-premium',
1300
  ),
1301
+ $premium_seat_restrictions_permissions
1302
  )
1303
  );
1304
  $sap->add_setting(
1305
  'rtb-settings',
1306
+ 'rtb-seat-assignments',
1307
  'count',
1308
  array(
1309
  'id' => 'rtb-dining-block-length',
1310
  'title' => __( 'Dining Block Length', 'restaurant-reservations' ),
1311
+ 'description' => __( 'How long does a meal generally last? This setting affects a how long a slot and/or seat unavailable for after someone makes a reservation.', 'restaurant-reservations' ),
1312
  'default' => $this->defaults['rtb-dining-block-length'],
1313
  'blank_option' => false,
1314
  'min_value' => 10,
1320
 
1321
  $sap->add_setting(
1322
  'rtb-settings',
1323
+ 'rtb-seat-assignments',
1324
  'toggle',
1325
  array(
1326
  'id' => 'rtb-enable-max-tables',
1331
 
1332
  $sap->add_setting(
1333
  'rtb-settings',
1334
+ 'rtb-seat-assignments',
1335
  'count',
1336
  array(
1337
  'id' => 'rtb-max-tables-count',
1345
 
1346
  $sap->add_setting(
1347
  'rtb-settings',
1348
+ 'rtb-seat-assignments',
1349
  'count',
1350
  array(
1351
  'id' => 'rtb-max-people-count',
1359
 
1360
  $sap->add_setting(
1361
  'rtb-settings',
1362
+ 'rtb-seat-assignments',
1363
  'count',
1364
  array(
1365
  'id' => 'auto-confirm-max-reservations',
1373
 
1374
  $sap->add_setting(
1375
  'rtb-settings',
1376
+ 'rtb-seat-assignments',
1377
  'count',
1378
  array(
1379
  'id' => 'auto-confirm-max-seats',
1385
  )
1386
  );
1387
 
1388
+ if ( ! $rtb_controller->permissions->check_permission('premium_table_restrictions') ) {
1389
+ $premium_table_restrictions_permissions = array(
1390
  'disabled' => true,
1391
  'disabled_image'=> 'https://www.etoilewebdesign.com/wp-content/uploads/2018/06/Logo-White-Filled40-px.png',
1392
+ 'purchase_link' => 'https://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/',
1393
+ 'ultimate_needed' => 'Yes'
1394
  );
1395
  }
1396
+ else { $premium_table_restrictions_permissions = array(); }
1397
 
1398
  $sap->add_section(
1399
  'rtb-settings',
1400
  array_merge(
1401
  array(
1402
+ 'id' => 'rtb-table-assignments',
1403
+ 'title' => __( 'Table Restrictions', 'restaurant-reservations' ),
1404
  'tab' => 'rtb-premium',
1405
  ),
1406
+ $premium_table_restrictions_permissions
1407
  )
1408
  );
 
 
1409
  $sap->add_setting(
1410
  'rtb-settings',
1411
+ 'rtb-table-assignments',
1412
+ 'toggle',
1413
  array(
1414
+ 'id' => 'enable-tables',
1415
+ 'title' => __( 'Enable Table Selection', 'restaurant-reservations' ),
1416
+ 'description' => __( 'Allow guests to select a table that they\'d like to sit at during their visit.', 'restaurant-reservations' )
 
 
 
1417
  )
1418
  );
1419
+ $sap->add_setting(
1420
+ 'rtb-settings',
1421
+ 'rtb-table-assignments',
1422
+ 'toggle',
1423
+ array(
1424
+ 'id' => 'require-table',
1425
+ 'title' => __( 'Require Table Selection', 'restaurant-reservations' ),
1426
+ 'description' => __( 'Don\'t allow a reservation to be made without a valid table selected, even if all other booking criteria are met (acceptable party size, below max reservations/seats).', 'restaurant-reservations' )
1427
+ )
1428
+ );
1429
+ $sap->add_setting(
1430
+ 'rtb-settings',
1431
+ 'rtb-table-assignments',
1432
+ 'infinite_table',
1433
+ array(
1434
+ 'id' => 'rtb-table-sections',
1435
+ 'title' => __( 'Sections', 'restaurant-reservations' ),
1436
+ 'add_label' => __( 'Add Section', 'restaurant-reservations' ),
1437
+ //'description' => __( 'Use this area to sections for your tables. These can help your guests to book a table in their preferred area, and can be closed earlier than the restaurant as a whole if a certain section closes early (ex. outdoor patio). Closing exceptions will still apply to sections.', 'restaurant-reservations' ),
1438
+ 'description' => __( 'Use this area to sections for your tables. These can help your guests to book a table in their preferred area.', 'restaurant-reservations' ),
1439
+ 'fields' => array(
1440
+ 'section_id' => array(
1441
+ 'type' => 'id',
1442
+ 'label' => __('Section ID', 'restaurant-reservations' ),
1443
+ 'required' => true
1444
+ ),
1445
+ 'name' => array(
1446
+ 'type' => 'text',
1447
+ 'label' => __('Section Name', 'restaurant-reservations' ),
1448
+ 'required' => true
 
 
1449
  ),
1450
+ 'description' => array(
1451
+ 'type' => 'textarea',
1452
+ 'label' => __('Description', 'restaurant-reservations' ),
1453
+ 'required' => true
1454
+ )/*,
1455
+ 'schedule' => array(
1456
+ 'type' => 'scheduler',
1457
+ 'label' => __('Schedule', 'restaurant-reservations' ),
1458
+ 'required' => true
1459
+ )*/
1460
  )
1461
+ )
1462
+ );
1463
+ $sap->add_setting(
1464
+ 'rtb-settings',
1465
+ 'rtb-table-assignments',
1466
+ 'infinite_table',
1467
+ array(
1468
+ 'id' => 'rtb-tables',
1469
+ 'title' => __( 'Tables', 'restaurant-reservations' ),
1470
+ 'add_label' => __( 'Add Table', 'restaurant-reservations' ),
1471
+ 'description' => __( 'Use this area to create tables that can each be customized. This information will be used to let customers select a table that meets their requirements (party size, date/time available).', 'restaurant-reservations' ),
1472
+ 'fields' => array(
1473
+ 'number' => array(
1474
+ 'type' => 'text',
1475
+ 'label' => __('Table Number', 'restaurant-reservations' ),
1476
+ 'required' => true
1477
+ ),
1478
+ 'min_people' => array(
1479
+ 'type' => 'number',
1480
+ 'label' => __('Min. People', 'restaurant-reservations' ),
1481
+ 'required' => true
1482
+ ),
1483
+ 'max_people' => array(
1484
+ 'type' => 'number',
1485
+ 'label' => __('Max. People', 'restaurant-reservations' ),
1486
+ 'required' => true
1487
+ ),
1488
+ 'section' => array(
1489
+ 'type' => 'select',
1490
+ 'label' => __('Section', 'restaurant-reservations' ),
1491
+ 'required' => false,
1492
+ 'options' => $this->get_table_section_options()
1493
+ ),
1494
+ 'combinations' => array(
1495
+ 'type' => 'text',
1496
+ 'label' => __('Combines With', 'restaurant-reservations' ),
1497
+ 'required' => false
1498
+ )
1499
  )
1500
+ )
1501
+ );
1502
 
1503
  if ( ! $rtb_controller->permissions->check_permission('designer') ) {
1504
  $designer_permissions = array(
2632
  return apply_filters( 'rtb_form_party_options', $options );
2633
  }
2634
 
2635
+ /**
2636
+ * Get options for the table select field in the booking form
2637
+ * @since 2.1.7
2638
+ */
2639
+ public function get_form_table_options() {
2640
+
2641
+ $options = array();
2642
+
2643
+ $table_sections = json_decode( html_entity_decode( $this->get_setting( 'rtb-table-sections' ) ) );
2644
+ $tables = json_decode( html_entity_decode( $this->get_setting( 'rtb-tables' ) ) );
2645
+
2646
+ foreach ( $tables as $table ) {
2647
+
2648
+ foreach ( $table_sections as $table_section ) {
2649
+ if ( $table_section->section_id == $table->section ) { $table_section_name = $table_section->name; }
2650
+ }
2651
+
2652
+ $options[ $table->number ] = $table->number . ' - ' . $table_section_name . ' (min. ' . $table->min_people . '/max. ' . $table->max_people . ')';
2653
+ }
2654
+
2655
+ return $options;
2656
+ }
2657
+
2658
+ /**
2659
+ * Returns the tables data as $table_number => $table pairs, calls load if necessary
2660
+ * @since 2.1.7
2661
+ */
2662
+ public function get_sorted_tables() {
2663
+
2664
+ if ( ! isset( $this->sorted_tables ) ){
2665
+
2666
+ $this->load_sorted_tables();
2667
+ }
2668
+
2669
+ return $this->sorted_tables;
2670
+ }
2671
+
2672
+ /**
2673
+ * Loads the tables data as $table_number => $table pairs
2674
+ * @since 2.1.7
2675
+ */
2676
+ public function load_sorted_tables() {
2677
+
2678
+ $tables = json_decode( html_entity_decode( $this->get_setting( 'rtb-tables' ) ) );
2679
+
2680
+ $sorted_tables = array();
2681
+ foreach ( $tables as $table ) {
2682
+ $sorted_tables[ $table->number ] = $table;
2683
+ }
2684
+
2685
+ $this->sorted_tables = $sorted_tables;
2686
+ }
2687
+
2688
  /**
2689
  * Retrieve form fields
2690
  *
2835
  );
2836
  }
2837
 
2838
+ $enable_tables = $rtb_controller->settings->get_setting( 'enable-tables' );
2839
+ $require_table = $rtb_controller->settings->get_setting( 'require-table' );
2840
+ if ( $enable_tables ) {
2841
+
2842
+
2843
+ $fields['reservation']['fields']['table'] = array(
2844
+ 'title' => __( 'Table(s)', 'restaurant-reservations' ),
2845
+ 'request_input' => empty( $request->table ) ? '' : $request->table,
2846
+ 'callback' => 'rtb_print_form_select_field',
2847
+ 'callback_args' => array(
2848
+ 'options' => $this->get_form_table_options(),
2849
+ 'empty_option' => true,
2850
+ 'disabled' => true
2851
+ ),
2852
+ 'required' => $require_table,
2853
+ 'order' => 999
2854
+ );
2855
+ }
2856
+
2857
  return apply_filters( 'rtb_booking_form_fields', $fields, $request, $args );
2858
  }
2859
 
2964
  return $ad - $bd;
2965
  }
2966
 
2967
+ /**
2968
+ * Return the table sections as value/name pairs
2969
+ *
2970
+ * @since 2.1.7
2971
+ */
2972
+ public function get_table_section_options() {
2973
+
2974
+ $table_sections = json_decode( html_entity_decode( $this->get_setting( 'rtb-table-sections' ) ) );
2975
+
2976
+ $table_section_options = array();
2977
+ foreach ( $table_sections as $table_section ) {
2978
+ $table_section_options[ $table_section->section_id ] = $table_section->name;
2979
+ }
2980
+
2981
+ return $table_section_options;
2982
+ }
2983
+
2984
  }
2985
  } // endif;
includes/WP_List_Table.BookingsTable.class.php CHANGED
@@ -368,6 +368,7 @@ class rtbBookingsTable extends WP_List_Table {
368
  );
369
 
370
  if ( $rtb_controller->settings->get_setting( 'require-deposit' ) ) { $columns['deposit'] = __( 'Deposit', 'restaurant-reservations' ) ; }
 
371
 
372
  // This is so that deposit comes before details, is there a better way to do this?
373
  $columns['details'] = __( 'Details', 'restaurant-reservations' );
@@ -448,7 +449,12 @@ class rtbBookingsTable extends WP_List_Table {
448
 
449
  case 'deposit' :
450
  $currency_symbol = $rtb_controller->settings->get_setting( 'rtb-stripe-currency-symbol' );
451
- $value = ( $currency_symbol ? $currency_symbol : '$' ) . $booking->deposit;
 
 
 
 
 
452
  break;
453
 
454
  case 'status' :
368
  );
369
 
370
  if ( $rtb_controller->settings->get_setting( 'require-deposit' ) ) { $columns['deposit'] = __( 'Deposit', 'restaurant-reservations' ) ; }
371
+ if ( $rtb_controller->settings->get_setting( 'enable-tables' ) ) { $columns['table'] = __( 'Table', 'restaurant-reservations' ) ; }
372
 
373
  // This is so that deposit comes before details, is there a better way to do this?
374
  $columns['details'] = __( 'Details', 'restaurant-reservations' );
449
 
450
  case 'deposit' :
451
  $currency_symbol = $rtb_controller->settings->get_setting( 'rtb-stripe-currency-symbol' );
452
+ $value = ( $currency_symbol ? $currency_symbol : '$' ) . esc_html( $booking->deposit );
453
+ break;
454
+
455
+ case 'table' :
456
+ $table = is_array( $booking->table ) ? $booking->table : array();
457
+ $value = esc_html( implode( ',', $table ) );
458
  break;
459
 
460
  case 'status' :
includes/template-functions.php CHANGED
@@ -100,9 +100,9 @@ function rtb_print_booking_form( $args = array() ) {
100
  <?php if ( ( $rtb_controller->request->request_inserted === true and ! $rtb_controller->settings->get_setting( 'require-deposit' ) ) or ( isset($_GET['payment']) and $_GET['payment'] == 'paid' ) ) : ?>
101
 
102
  <?php
103
- if($rtb_controller->request->post_status == 'confirmed'){
104
  if( $rtb_controller->settings->get_setting('confirmed-redirect-page') != '' ){
105
- header( 'location:' . $rtb_controller->settings->get_setting('confirmed-redirect-page') );
106
  }
107
  else{
108
  ?>
@@ -112,9 +112,9 @@ function rtb_print_booking_form( $args = array() ) {
112
  <?php
113
  }
114
  }
115
- else{
116
- if( $rtb_controller->settings->get_setting('pending-redirect-page') != '' ){
117
- header( 'location:' . $rtb_controller->settings->get_setting('pending-redirect-page') );
118
  }
119
  else{
120
  ?>
@@ -308,7 +308,7 @@ function rtb_process_stripe_payment() {
308
 
309
  // Define the form's action parameter
310
  $booking_page = $rtb_controller->settings->get_setting( 'booking-page' );
311
- if ( !empty( $booking_page ) ) {
312
  $booking_page = get_permalink( $booking_page );
313
  }
314
  else { $booking_page = get_permalink(); }
@@ -357,6 +357,9 @@ function rtb_process_stripe_payment() {
357
  }
358
  } // endif;
359
 
 
 
 
360
 
361
  // If there's an IPN request, add our setup function to potentially handle it
362
  if ( isset($_POST['ipn_track_id']) ) { add_action( 'init', 'rtb_setup_paypal_ipn', 1); }
@@ -372,8 +375,6 @@ function rtb_setup_paypal_ipn() {
372
  if ( ! $rtb_controller->settings->get_setting( 'require-deposit' ) ) { return; }
373
 
374
  rtb_handle_paypal_ipn();
375
- add_action('init', 'rtb_add_ob_start');
376
- add_action('shutdown', 'rtb_flush_ob_end');
377
  }
378
  } // endif;
379
 
@@ -465,7 +466,7 @@ function rtb_handle_paypal_ipn() {
465
  * @since 2.1.0
466
  */
467
  if ( !function_exists( 'rtb_add_ob_start' ) ) {
468
- function rtb_add_ob_start() { update_option( "EWD_Debugging2", "Second init function called" );
469
  ob_start();
470
  }
471
  } // endif;
@@ -700,6 +701,7 @@ function rtb_enqueue_assets() {
700
  'late_bookings' => is_admin() && current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'late-bookings' ),
701
  'enable_max_reservations' => is_admin() && current_user_can( 'manage_bookings' ) ? false : $rtb_controller->settings->get_setting( 'rtb-enable-max-tables' ),
702
  'max_people' => is_admin() && current_user_can( 'manage_bookings' ) ? 100 : $rtb_controller->settings->get_setting( 'rtb-max-people-count' ),
 
703
  'date_onload' => $rtb_controller->settings->get_setting( 'date-onload' ),
704
  'time_interval' => $rtb_controller->settings->get_setting( 'time-interval' ),
705
  'first_day' => $rtb_controller->settings->get_setting( 'week-start' ),
@@ -858,9 +860,10 @@ function rtb_print_form_select_field( $slug, $title, $value, $args ) {
858
  <label for="rtb-<?php echo $slug; ?>">
859
  <?php echo $title; ?>
860
  </label>
861
- <select name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>"<?php echo $required; ?>>
 
862
  <?php foreach ( $options as $opt_value => $opt_label ) : ?>
863
- <option value="<?php echo esc_attr( $opt_value ); ?>" <?php selected( $opt_value, $value ); ?>><?php echo esc_attr( $opt_label ); ?></option>
864
  <?php endforeach; ?>
865
  </select>
866
  </div>
@@ -1115,7 +1118,63 @@ if ( !function_exists( 'rtb_add_custom_styling' ) ) {
1115
  }
1116
  }
1117
 
1118
- if ( !function_exists('rtb_esc_js') ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1119
  function rtb_esc_js( $value ) {
1120
 
1121
  return preg_replace( '/[^a-zA-Z ,.-:\/]/', '', $value );
100
  <?php if ( ( $rtb_controller->request->request_inserted === true and ! $rtb_controller->settings->get_setting( 'require-deposit' ) ) or ( isset($_GET['payment']) and $_GET['payment'] == 'paid' ) ) : ?>
101
 
102
  <?php
103
+ if ( $rtb_controller->request->post_status == 'confirmed' ) {
104
  if( $rtb_controller->settings->get_setting('confirmed-redirect-page') != '' ){
105
+ header( 'Location:' . $rtb_controller->settings->get_setting('confirmed-redirect-page') );
106
  }
107
  else{
108
  ?>
112
  <?php
113
  }
114
  }
115
+ else {
116
+ if( $rtb_controller->settings->get_setting('pending-redirect-page') != '' ) {
117
+ header( 'Location:' . $rtb_controller->settings->get_setting('pending-redirect-page') );
118
  }
119
  else{
120
  ?>
308
 
309
  // Define the form's action parameter
310
  $booking_page = $rtb_controller->settings->get_setting( 'booking-page' );
311
+ if ( ! empty( $booking_page ) ) {
312
  $booking_page = get_permalink( $booking_page );
313
  }
314
  else { $booking_page = get_permalink(); }
357
  }
358
  } // endif;
359
 
360
+ // add an output buffer layer for the plugin
361
+ add_action('init', 'rtb_add_ob_start');
362
+ add_action('shutdown', 'rtb_flush_ob_end');
363
 
364
  // If there's an IPN request, add our setup function to potentially handle it
365
  if ( isset($_POST['ipn_track_id']) ) { add_action( 'init', 'rtb_setup_paypal_ipn', 1); }
375
  if ( ! $rtb_controller->settings->get_setting( 'require-deposit' ) ) { return; }
376
 
377
  rtb_handle_paypal_ipn();
 
 
378
  }
379
  } // endif;
380
 
466
  * @since 2.1.0
467
  */
468
  if ( !function_exists( 'rtb_add_ob_start' ) ) {
469
+ function rtb_add_ob_start() {
470
  ob_start();
471
  }
472
  } // endif;
701
  'late_bookings' => is_admin() && current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'late-bookings' ),
702
  'enable_max_reservations' => is_admin() && current_user_can( 'manage_bookings' ) ? false : $rtb_controller->settings->get_setting( 'rtb-enable-max-tables' ),
703
  'max_people' => is_admin() && current_user_can( 'manage_bookings' ) ? 100 : $rtb_controller->settings->get_setting( 'rtb-max-people-count' ),
704
+ 'enable_tables' => $rtb_controller->settings->get_setting( 'enable-tables' ),
705
  'date_onload' => $rtb_controller->settings->get_setting( 'date-onload' ),
706
  'time_interval' => $rtb_controller->settings->get_setting( 'time-interval' ),
707
  'first_day' => $rtb_controller->settings->get_setting( 'week-start' ),
860
  <label for="rtb-<?php echo $slug; ?>">
861
  <?php echo $title; ?>
862
  </label>
863
+ <select name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>"<?php echo $required; ?> <?php echo ( isset( $args['disabled'] ) and $args['disabled'] ) ? 'disabled' : ''; ?>>
864
+ <?php if ( isset( $args['empty_option'] ) and $args['empty_option'] ) { ?> <option></option> <?php } ?>
865
  <?php foreach ( $options as $opt_value => $opt_label ) : ?>
866
+ <option value="<?php echo esc_attr( $opt_value ); ?>" <?php ! is_array( $value ) ? selected( $opt_value, $value ) : false; ?>><?php echo esc_attr( $opt_label ); ?></option>
867
  <?php endforeach; ?>
868
  </select>
869
  </div>
1118
  }
1119
  }
1120
 
1121
+ /**
1122
+ * Retrieve tables that are available to be booked at a specific date/time
1123
+ *
1124
+ * @datetime int|string of the date/time to check
1125
+ * @since 2.1.7
1126
+ */
1127
+ if ( ! function_exists( 'rtb_get_valid_tables') ) {
1128
+ function rtb_get_valid_tables( $datetime ) {
1129
+ global $rtb_controller;
1130
+
1131
+ $request_time = is_int( $datetime) ? $datetime : strtotime( $datetime );
1132
+
1133
+ if ( ! $request_time ) { return false; }
1134
+
1135
+ $tables = $rtb_controller->settings->get_sorted_tables();
1136
+
1137
+ $table_numbers = array_keys( $tables );
1138
+
1139
+ if ( empty( $table_numbers ) ) { return $table_numbers; }
1140
+
1141
+ $dining_block_setting = $rtb_controller->settings->get_setting( 'rtb-dining-block-length' );
1142
+ $dining_block = substr( $dining_block_setting, 0, strpos( $dining_block_setting, '_' ) );
1143
+ $dining_block_seconds = ( $dining_block * 60 - 1 ); // Take 1 second off, to avoid bookings that start or end exactly at the beginning of a booking block
1144
+
1145
+ $args = array(
1146
+ 'posts_per_page' => -1,
1147
+ 'date_range' => 'dates',
1148
+ 'start_date' => date( 'Y', $request_time ) . '-' . date( 'm', $request_time ) . '-' . date( 'd', $request_time ),
1149
+ 'end_date' => date( 'Y', $request_time ) . '-' . date( 'm', $request_time ) . '-' . date( 'd', $request_time )
1150
+ );
1151
+
1152
+ require_once( RTB_PLUGIN_DIR . '/includes/Query.class.php' );
1153
+ $query = new rtbQuery( $args );
1154
+ $query->prepare_args();
1155
+
1156
+ // Get all current bookings sorted by date
1157
+ $bookings = $query->get_bookings();
1158
+
1159
+ $request_time_start = $request_time - $dining_block_seconds;
1160
+ $request_time_end = $request_time + $dining_block_seconds;
1161
+
1162
+ foreach ( $bookings as $booking ) {
1163
+ $booking_time = strtotime( $booking->date );
1164
+
1165
+ if ( $booking_time < $request_time_start or $booking_time > $request_time_end ) { continue; }
1166
+
1167
+ if ( ! isset( $booking->table ) or ! is_array( $booking->table ) ) { continue; }
1168
+
1169
+ $remaining_tables = array_diff( $table_numbers, $booking->table );
1170
+ $table_numbers = $remaining_tables;
1171
+ }
1172
+
1173
+ return $table_numbers;
1174
+ }
1175
+ }
1176
+
1177
+ if ( ! function_exists( 'rtb_esc_js' ) ) {
1178
  function rtb_esc_js( $value ) {
1179
 
1180
  return preg_replace( '/[^a-zA-Z ,.-:\/]/', '', $value );
lib/simple-admin-pages/classes/AdminPageSetting.Count.class.php CHANGED
@@ -33,7 +33,7 @@ class sapAdminPageSettingCount_2_2_0 extends sapAdminPageSetting_2_2_0 {
33
  * @since 2.0
34
  */
35
  public $scripts = array(
36
- 'sap-infinite-table' => array(
37
  'path' => 'js/count.js',
38
  'dependencies' => array( 'jquery' ),
39
  'version' => '2.2.0',
33
  * @since 2.0
34
  */
35
  public $scripts = array(
36
+ 'sap-count' => array(
37
  'path' => 'js/count.js',
38
  'dependencies' => array( 'jquery' ),
39
  'version' => '2.2.0',
lib/simple-admin-pages/classes/AdminPageSetting.InfiniteTable.class.php CHANGED
@@ -79,7 +79,7 @@ class sapAdminPageSettingInfiniteTable_2_2_0 extends sapAdminPageSetting_2_2_0 {
79
  <fieldset>
80
  <div class='sap-infinite-table <?php echo ( $this->disabled ? 'disabled' : ''); ?>' data-fieldids='<?php echo $fields; ?>'>
81
  <input type='hidden' name='<?php echo $input_name; ?>' value='<?php echo $this->value; ?>' />
82
- <table>
83
  <thead>
84
  <tr>
85
  <?php foreach ($this->fields as $field) { ?>
@@ -93,11 +93,20 @@ class sapAdminPageSettingInfiniteTable_2_2_0 extends sapAdminPageSetting_2_2_0 {
93
  <tr class='sap-inifinite-table-row' data-rowid='<?php echo $row_count; ?>'>
94
  <?php foreach ($this->fields as $field_id => $field) { ?>
95
  <td>
 
 
 
96
  <?php if ($field['type'] == 'text') : ?>
97
- <input type='text' name='<?php echo $field_id . "_" . $row_count; ?>' value='<?php echo $row->$field_id; ?>' />
 
 
 
 
 
 
98
  <?php endif; ?>
99
  <?php if ($field['type'] == 'select') : ?>
100
- <select name='<?php echo $field_id . "_" . $row_count; ?>'>
101
  <?php foreach ($field['options'] as $option_value => $option_name) { ?>
102
  <option value='<?php echo $option_value; ?>' <?php echo ($row->$field_id == $option_value ? 'selected="selected"' : ''); ?>><?php echo $option_name; ?></option>
103
  <?php }?>
@@ -114,11 +123,20 @@ class sapAdminPageSettingInfiniteTable_2_2_0 extends sapAdminPageSetting_2_2_0 {
114
  <tr class='sap-inifite-table-row-template sap-hidden'>
115
  <?php foreach ($this->fields as $field_id => $field) { ?>
116
  <td>
 
 
 
117
  <?php if ($field['type'] == 'text') : ?>
118
- <input type='text' name='<?php echo $field_id; ?>' value='' />
 
 
 
 
 
 
119
  <?php endif; ?>
120
  <?php if ($field['type'] == 'select') : ?>
121
- <select name='<?php echo $field_id; ?>'>
122
  <?php foreach ($field['options'] as $option_value => $option_name) { ?>
123
  <option value='<?php echo $option_value; ?>'><?php echo $option_name; ?></option>
124
  <?php }?>
@@ -129,8 +147,8 @@ class sapAdminPageSettingInfiniteTable_2_2_0 extends sapAdminPageSetting_2_2_0 {
129
  <td class='sap-infinite-table-row-delete'><?php _e('Delete'); ?></td>
130
  </tr>
131
  <tr class='sap-infinite-table-add-row'>
132
- <td colspan="4">
133
- <a class="rtb-new-admin-add-button">&plus; <?php _e('ADD ROW'); ?></a>
134
  </td>
135
  </tr>
136
  </tfoot>
79
  <fieldset>
80
  <div class='sap-infinite-table <?php echo ( $this->disabled ? 'disabled' : ''); ?>' data-fieldids='<?php echo $fields; ?>'>
81
  <input type='hidden' name='<?php echo $input_name; ?>' value='<?php echo $this->value; ?>' />
82
+ <table id='sap-table-<?php echo $this->id; ?>'>
83
  <thead>
84
  <tr>
85
  <?php foreach ($this->fields as $field) { ?>
93
  <tr class='sap-inifinite-table-row' data-rowid='<?php echo $row_count; ?>'>
94
  <?php foreach ($this->fields as $field_id => $field) { ?>
95
  <td>
96
+ <?php if ($field['type'] == 'id') : ?>
97
+ <input type='hidden' name='<?php echo $field_id . "_" . $row_count; ?>' class='sap-infinite-table-<?php echo $field_id; ?> sap-infinite-table-id' value='<?php echo $row->$field_id; ?>' /> <?php echo $row->$field_id; ?>
98
+ <?php endif; ?>
99
  <?php if ($field['type'] == 'text') : ?>
100
+ <input type='text' name='<?php echo $field_id . "_" . $row_count; ?>' class='sap-infinite-table-<?php echo $field_id; ?>' value='<?php echo $row->$field_id; ?>' />
101
+ <?php endif; ?>
102
+ <?php if ($field['type'] == 'number') : ?>
103
+ <input type='number' name='<?php echo $field_id . "_" . $row_count; ?>' class='sap-infinite-table-<?php echo $field_id; ?>' value='<?php echo $row->$field_id; ?>' />
104
+ <?php endif; ?>
105
+ <?php if ($field['type'] == 'textarea') : ?>
106
+ <textarea name='<?php echo $field_id . "_" . $row_count; ?>' class='sap-infinite-table-<?php echo $field_id; ?>'><?php echo $row->$field_id; ?></textarea>
107
  <?php endif; ?>
108
  <?php if ($field['type'] == 'select') : ?>
109
+ <select name='<?php echo $field_id . "_" . $row_count; ?>' class='sap-infinite-table-<?php echo $field_id; ?>'>
110
  <?php foreach ($field['options'] as $option_value => $option_name) { ?>
111
  <option value='<?php echo $option_value; ?>' <?php echo ($row->$field_id == $option_value ? 'selected="selected"' : ''); ?>><?php echo $option_name; ?></option>
112
  <?php }?>
123
  <tr class='sap-inifite-table-row-template sap-hidden'>
124
  <?php foreach ($this->fields as $field_id => $field) { ?>
125
  <td>
126
+ <?php if ($field['type'] == 'id') : ?>
127
+ <input type='hidden' name='<?php echo $field_id; ?>' class='sap-infinite-table-<?php echo $field_id; ?> sap-infinite-table-id' value='' /><span class='sap-infinite-table-id-html'></span>
128
+ <?php endif; ?>
129
  <?php if ($field['type'] == 'text') : ?>
130
+ <input type='text' name='<?php echo $field_id; ?>' class='sap-infinite-table-<?php echo $field_id; ?>' value='' />
131
+ <?php endif; ?>
132
+ <?php if ($field['type'] == 'number') : ?>
133
+ <input type='number' name='<?php echo $field_id; ?>' class='sap-infinite-table-<?php echo $field_id; ?>' value='' />
134
+ <?php endif; ?>
135
+ <?php if ($field['type'] == 'textarea') : ?>
136
+ <textarea name='<?php echo $field_id; ?>' class='sap-infinite-table-<?php echo $field_id; ?>'></textarea>
137
  <?php endif; ?>
138
  <?php if ($field['type'] == 'select') : ?>
139
+ <select name='<?php echo $field_id; ?>' class='sap-infinite-table-<?php echo $field_id; ?>'>
140
  <?php foreach ($field['options'] as $option_value => $option_name) { ?>
141
  <option value='<?php echo $option_value; ?>'><?php echo $option_name; ?></option>
142
  <?php }?>
147
  <td class='sap-infinite-table-row-delete'><?php _e('Delete'); ?></td>
148
  </tr>
149
  <tr class='sap-infinite-table-add-row'>
150
+ <td colspan="<?php echo sizeOf( $this->fields ); ?>">
151
+ <a class="rtb-new-admin-add-button">&plus; <?php echo $this->add_label; ?></a>
152
  </td>
153
  </tr>
154
  </tfoot>
lib/simple-admin-pages/css/infinite_table.css ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ .sap-hidden {
2
+ display: none;
3
+ }
lib/simple-admin-pages/js/infinite_table.js CHANGED
@@ -1,15 +1,22 @@
1
  jQuery(document).ready(function ($) {
2
- jQuery('.sap-infinite-table-add-row').on('click', function() {
3
- var max_row = findInfiniteTableMaxRow();
4
 
5
- jQuery('.sap-inifite-table-row-template').clone().appendTo('.sap-infinite-table tbody');
 
6
 
7
- jQuery('.sap-infinite-table tbody .sap-inifite-table-row-template').removeClass('sap-inifite-table-row-template').addClass('sap-inifinite-table-row').addClass('sap-new-infinite-row');
8
- jQuery('.sap-new-infinite-row').data('rowid', max_row + 1);
9
- jQuery('.sap-new-infinite-row input, .sap-new-infinite-row select').each(function() {
10
- jQuery(this).attr('name', jQuery(this).attr('name') + '_' + (max_row + 1));
 
 
11
  });
12
- jQuery('.sap-new-infinite-row').removeClass('sap-new-infinite-row').removeClass('sap-hidden');
 
 
 
 
13
 
14
  setInfiniteTableDeleteHandlers();
15
  setInfiniteTableUpdateHandlers();
@@ -23,49 +30,55 @@ jQuery(document).ready(function ($) {
23
  function findInfiniteTableMaxRow() {
24
  var max_row = 0;
25
 
26
- jQuery('.sap-inifinite-table-row').each(function() {
27
- max_row = Math.max(jQuery(this).data('rowid'), max_row);
28
  });
29
 
30
  return max_row;
31
  }
32
 
33
  function setInfiniteTableDeleteHandlers() {
34
- jQuery('.sap-infinite-table-row-delete').off('click');
35
- jQuery('.sap-infinite-table-row-delete').on('click', function() {
36
- jQuery(this).parent().remove();
 
 
 
 
37
 
38
- infiniteTableSaveData();
 
39
  });
40
  }
41
 
42
  function setInfiniteTableUpdateHandlers() {
43
- jQuery('.sap-inifinite-table-row input').off('keyup');
44
- jQuery('.sap-inifinite-table-row input').on('keyup', function() {
45
- infiniteTableSaveData();
46
  });
47
 
48
- jQuery('.sap-inifinite-table-row select').off('change');
49
- jQuery('.sap-inifinite-table-row select').on('change', function() {
50
- infiniteTableSaveData();
51
  });
52
  }
53
 
54
- function infiniteTableSaveData() {
55
- var fields = jQuery('.sap-infinite-table').data('fieldids').split(',');
56
  var data = [];
57
 
58
- jQuery('.sap-inifinite-table-row').each(function() {
59
  var row_id = jQuery(this).data('rowid');
60
  var row_data = {};
61
 
62
  jQuery(fields).each(function(index, field) {
63
- if ( jQuery('input[name="' + field + '_' + row_id + '"]').length ) { row_data[field] = jQuery('input[name="' + field + '_' + row_id + '"]').val(); }
64
- else { row_data[field] = jQuery('select[name="' + field + '_' + row_id + '"]').val(); }
 
65
  });
66
 
67
  data.push(row_data);
68
  });
69
 
70
- jQuery('.sap-infinite-table input[type="hidden"]').val(JSON.stringify(data));
71
  }
1
  jQuery(document).ready(function ($) {
2
+ jQuery( '.sap-infinite-table-add-row' ).on( 'click', function() {
3
+ var max_row = findInfiniteTableMaxRow();
4
 
5
+ var tfoot = jQuery( this ).closest( 'tfoot' );
6
+ var tbody = jQuery( this ).closest( '.sap-infinite-table' ).find( 'tbody' );
7
 
8
+ tfoot.find( '.sap-inifite-table-row-template' ).clone().appendTo( tbody );
9
+
10
+ jQuery( '.sap-infinite-table tbody .sap-inifite-table-row-template' ).removeClass( 'sap-inifite-table-row-template' ).addClass( 'sap-inifinite-table-row' ).addClass( 'sap-new-infinite-row' );
11
+ jQuery( '.sap-new-infinite-row' ).data('rowid', max_row + 1);
12
+ jQuery( '.sap-new-infinite-row input, .sap-new-infinite-row select, .sap-new-infinite-row textarea' ).each(function() {
13
+ jQuery(this).attr( 'name', jQuery(this).attr( 'name' ) + '_' + (max_row + 1));
14
  });
15
+
16
+ jQuery( '.sap-new-infinite-row' ).find('.sap-infinite-table-id').val( max_row + 1 );
17
+ jQuery( '.sap-new-infinite-row' ).find('.sap-infinite-table-id-html').html( max_row + 1 );
18
+
19
+ jQuery( '.sap-new-infinite-row' ).removeClass( 'sap-new-infinite-row' ).removeClass( 'sap-hidden' );
20
 
21
  setInfiniteTableDeleteHandlers();
22
  setInfiniteTableUpdateHandlers();
30
  function findInfiniteTableMaxRow() {
31
  var max_row = 0;
32
 
33
+ jQuery( '.sap-inifinite-table-row' ).each(function() {
34
+ max_row = Math.max(jQuery(this).data( 'rowid' ), max_row);
35
  });
36
 
37
  return max_row;
38
  }
39
 
40
  function setInfiniteTableDeleteHandlers() {
41
+ jQuery( '.sap-infinite-table-row-delete' ).off( 'click.delete_row' );
42
+ jQuery( '.sap-infinite-table-row-delete' ).on( 'click.delete_row', function() {
43
+ var table = jQuery( this ).closest( '.sap-infinite-table' );
44
+
45
+ // give anything hooked into the delete action a chance to process before removing
46
+ setTimeout( function() {
47
+ jQuery(this).parent().remove();
48
 
49
+ infiniteTableSaveData( table );
50
+ }, 200);
51
  });
52
  }
53
 
54
  function setInfiniteTableUpdateHandlers() {
55
+ jQuery( '.sap-inifinite-table-row input, .sap-inifinite-table-row textarea').off( 'keyup.update_fields' );
56
+ jQuery( '.sap-inifinite-table-row input, .sap-inifinite-table-row textarea').on( 'keyup.update_fields', function() {
57
+ infiniteTableSaveData( jQuery( this ).closest( '.sap-infinite-table' ) );
58
  });
59
 
60
+ jQuery( '.sap-inifinite-table-row select' ).off( 'change.update_fields' );
61
+ jQuery( '.sap-inifinite-table-row select' ).on( 'change.update_fields', function() {
62
+ infiniteTableSaveData( jQuery( this ).closest( '.sap-infinite-table' ) );
63
  });
64
  }
65
 
66
+ function infiniteTableSaveData( table ) {
67
+ var fields = table.data( 'fieldids' ).split( ',' );
68
  var data = [];
69
 
70
+ jQuery( table ).find( '.sap-inifinite-table-row' ).each(function() {
71
  var row_id = jQuery(this).data('rowid');
72
  var row_data = {};
73
 
74
  jQuery(fields).each(function(index, field) {
75
+ if ( jQuery( 'input[name="' + field + '_' + row_id + '"]' ).length ) { row_data[field] = jQuery( 'input[name="' + field + '_' + row_id + '"]' ).val(); }
76
+ else if ( jQuery( 'select[name="' + field + '_' + row_id + '"]' ).length ) { row_data[field] = jQuery( 'select[name="' + field + '_' + row_id + '"]' ).val(); }
77
+ else if ( jQuery( 'textarea[name="' + field + '_' + row_id + '"]' ).length ) { row_data[field] = jQuery( 'textarea[name="' + field + '_' + row_id + '"]' ).val(); }
78
  });
79
 
80
  data.push(row_data);
81
  });
82
 
83
+ jQuery( table ).find( 'input[type="hidden"]:not( .sap-infinite-table-id )' ).val(JSON.stringify(data));
84
  }
readme.txt CHANGED
@@ -1,4 +1,4 @@
1
- === Five Star Restaurant Reservations ===
2
  Contributors: FiveStarPlugins
3
  Requires at Least: 4.4
4
  Tested Up To: 5.4
@@ -63,6 +63,16 @@ With the premium version of our restaurant reservations plugin, you can extend t
63
  * Automatic Reservation Confirmation: Enable automatic confirmation of a reservation request if that date/time is currently below the maximum reservation or seat number.
64
  * Styling Options: Many styling options are included that let you set the color, font-size, borders, etc. for the different elements of the form.
65
 
 
 
 
 
 
 
 
 
 
 
66
  For further information and purchasing options, please visit our <a href="https://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/" target="_blank">WordPress restaurant reservations</a> homepage.
67
 
68
  [youtube https://www.youtube.com/watch?v=0DigZnw_3Qw]
@@ -184,6 +194,10 @@ Find answers to even more questions in the [FAQ](http://doc.fivestarplugins.com/
184
 
185
  == Changelog ==
186
 
 
 
 
 
187
  = 2.1.6 (2020-05-29) =
188
  - Fixes an issue with the view bookings form where the date would not select correctly if it was being included using the shortcode instead of the option
189
 
1
+ === Five Star Restaurant Reservations - WordPress Booking Plugin ===
2
  Contributors: FiveStarPlugins
3
  Requires at Least: 4.4
4
  Tested Up To: 5.4
63
  * Automatic Reservation Confirmation: Enable automatic confirmation of a reservation request if that date/time is currently below the maximum reservation or seat number.
64
  * Styling Options: Many styling options are included that let you set the color, font-size, borders, etc. for the different elements of the form.
65
 
66
+ = Restaurant Reservations Ultimate =
67
+
68
+ The ultimate version of our restaurant reservations plugin is meant for restaurants that want to take their reservations to the next level. It several powerful features to give you the ultimate reservations experience including:
69
+
70
+ * Booking by Table: Add your restaurant's table in the setting panel, and let (or require) guests to select a table(s) when they make their reservation, based on the booking time and party size.
71
+ * Booking Deposits: Require a deposit, either per guest or per reservation, when someone makes a reservation to help prevent no-shows.
72
+ * Reservation Reminders: Send out an email or SMS message before a booking at a time that you specify (ex. 4 hours before a reservation).
73
+ * Late-Arrival Notices: Send out an email or SMS message when a guest is late by a specified amount for their reservation.
74
+
75
+
76
  For further information and purchasing options, please visit our <a href="https://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/" target="_blank">WordPress restaurant reservations</a> homepage.
77
 
78
  [youtube https://www.youtube.com/watch?v=0DigZnw_3Qw]
194
 
195
  == Changelog ==
196
 
197
+ = 2.1.7 (2020-06-05) =
198
+ - Includes a new RTU feature, booking by table
199
+ - Fixes an issue with the way payments are processed using one of the payment gateways
200
+
201
  = 2.1.6 (2020-05-29) =
202
  - Fixes an issue with the view bookings form where the date would not select correctly if it was being included using the shortcode instead of the option
203
 
restaurant-reservations.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
  /**
3
- * Plugin Name: Five Star Restaurant Reservations
4
  * Plugin URI: http://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/
5
  * Description: Restaurant reservations made easy. Accept bookings online. Quickly confirm or reject reservations, send email notifications, set booking times and more.
6
- * Version: 2.1.6
7
  * Author: FiveStarPlugins
8
  * Author URI: https://profiles.wordpress.org/fivestarplugins/
9
  * Text Domain: restaurant-reservations
1
  <?php
2
  /**
3
+ * Plugin Name: Five Star Restaurant Reservations - WordPress Booking Plugin
4
  * Plugin URI: http://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/
5
  * Description: Restaurant reservations made easy. Accept bookings online. Quickly confirm or reject reservations, send email notifications, set booking times and more.
6
+ * Version: 2.1.7
7
  * Author: FiveStarPlugins
8
  * Author URI: https://profiles.wordpress.org/fivestarplugins/
9
  * Text Domain: restaurant-reservations