Restaurant Reservations - Version 1.7

Version Description

Download this release

Release Info

Developer NateWr
Plugin Icon 128x128 Restaurant Reservations
Version 1.7
Comparing to
See all releases

Code changes from version 1.6.3 to 1.7

Gruntfile.js CHANGED
@@ -5,6 +5,8 @@ module.exports = function(grunt) {
5
// Project configuration.
6
grunt.initConfig({
7
8
// Configure JSHint
9
jshint: {
10
test: {
@@ -24,33 +26,46 @@ module.exports = function(grunt) {
24
makepot: {
25
target: {
26
options: {
27
- cwd: '', // Directory of files to internationalize.
28
- domainPath: 'languages', // Where to save the POT file.
29
- exclude: [], // List of files or directories to ignore.
30
- include: [], // List of files or directories to include.
31
- i18nToolsPath: '/media/Storage/projects/wordpress/trunk/tools/i18n', // Path to the i18n tools directory.
32
- mainFile: 'restaurant-reservations/restaurant-reservations.php', // Main project file.
33
- potComments: '', // The copyright at the beginning of the POT file.
34
- potFilename: '', // Name of the POT file.
35
- potHeaders: {
36
- poedit: true, // Includes common Poedit headers.
37
- 'x-poedit-keywordslist': true // Include a list of all possible gettext functions.
38
- }, // Headers to add to the generated POT file.
39
- processPot: null, // A callback function for manipulating the POT file.
40
- type: 'wp-plugin', // Type of project (wp-plugin or wp-theme).
41
- updateTimestamp: true // Whether the POT-Creation-Date should be updated without other changes.
42
}
43
}
44
}
45
46
});
47
48
// Load tasks
49
grunt.loadNpmTasks('grunt-contrib-jshint');
50
grunt.loadNpmTasks('grunt-contrib-watch');
51
grunt.loadNpmTasks('grunt-wp-i18n');
52
53
// Default task(s).
54
grunt.registerTask('default', ['watch']);
55
56
};
5
// Project configuration.
6
grunt.initConfig({
7
8
+ pkg: grunt.file.readJSON('package.json'),
9
+
10
// Configure JSHint
11
jshint: {
12
test: {
26
makepot: {
27
target: {
28
options: {
29
+ processPot: function( pot, options ) {
30
+ pot.headers['report-msgid-bugs-to'] = 'https://themeofthecrop.com';
31
+ return pot;
32
+ },
33
+ type: 'wp-plugin',
34
}
35
}
36
+ },
37
+
38
+ // Build a package for distribution
39
+ compress: {
40
+ main: {
41
+ options: {
42
+ archive: 'restaurant-reservations-<%= pkg.version %>.zip'
43
+ },
44
+ files: [
45
+ {
46
+ src: [
47
+ '*', '**/*',
48
+ '!restaurant-reservations-<%= pkg.version %>.zip',
49
+ '!.*', '!Gruntfile.js', '!package.json', '!node_modules', '!node_modules/**/*',
50
+ '!**/.*', '!**/Gruntfile.js', '!**/package.json', '!**/node_modules', '!**/node_modules/**/*',
51
+ ],
52
+ dest: 'restaurant-reservations/',
53
+ }
54
+ ]
55
+ }
56
}
57
58
});
59
60
// Load tasks
61
+ grunt.loadNpmTasks('grunt-contrib-compress');
62
grunt.loadNpmTasks('grunt-contrib-jshint');
63
grunt.loadNpmTasks('grunt-contrib-watch');
64
grunt.loadNpmTasks('grunt-wp-i18n');
65
66
// Default task(s).
67
grunt.registerTask('default', ['watch']);
68
+ grunt.registerTask('build', ['jshint']);
69
+ grunt.registerTask('package', ['build', 'compress']);
70
71
};
assets/addons-backup.json DELETED
@@ -1,29 +0,0 @@
1
- [
2
- {
3
- "id":"custom-fields-for-rtb",
4
- "title":"Custom Fields for Restaurant Reservations",
5
- "url":"http:\/\/themeofthecrop.com\/plugin\/custom-fields-restaurant-reservations\/",
6
- "price":"$30",
7
- "img":"https:\/\/themeofthecrop.com\/promo\/plugins\/custom-fields-for-rtb.png",
8
- "status":"released",
9
- "description":"Add custom fields and edit your booking form with ease."
10
- },
11
- {
12
- "id":"mailchimp-for-rtb",
13
- "title":"MailChimp for Restaurant Reservations",
14
- "url":"http:\/\/themeofthecrop.com\/plugin\/mailchimp-restaurant-reservations\/",
15
- "price":"$20",
16
- "img":"https:\/\/themeofthecrop.com\/promo\/plugins\/mailchimp-for-rtb.png",
17
- "status":"released",
18
- "description":"Subscribe emails from new restaurant reservations to your MailChimp mailing list. <strong>Use a different mailing list provider? Let me know <a href=\"http:\/\/themeofthecrop.com\/2015\/12\/17\/suggest-next-mailing-list-integration\/?utm_source=Plugin&utm_medium=Addon%20List&utm_campaign=Restaurant%20Reservations\">which one</a>.</strong>"
19
- },
20
- {
21
- "id":"export-bookings-for-rtb",
22
- "title":"Export Bookings for Restaurant Reservations",
23
- "url":"http:\/\/themeofthecrop.com\/plugin\/export-bookings-for-restaurant-reservations\/",
24
- "price":"$20",
25
- "img":"https:\/\/themeofthecrop.com\/promo\/plugins\/export-bookings-for-rtb.png",
26
- "status":"released",
27
- "description":"Export your restaurant reservations to PDF and Excel/CSV files."
28
- }
29
- ]
assets/css/admin.css CHANGED
@@ -355,7 +355,7 @@
355
width: 100%;
356
height: 100%;
357
background: rgba(0, 0, 0, 0.8);
358
- z-index: 3;
359
overflow-y: auto;
360
cursor: pointer;
361
visibility: hidden;
@@ -445,6 +445,12 @@
445
-webkit-transition: opacity .25s ease-in-out;
446
}
447
448
.rtb-admin-modal .action-status {
449
display: inline-block;
450
float: right;
@@ -541,6 +547,23 @@
541
#rtb-error-modal .rtb-error-msg {
542
margin-bottom: 1em;
543
}
544
/* Hide the outer scrollbar when the modal is open */
545
.rtb-hide-body-scroll {
546
overflow: hidden !important;
@@ -561,60 +584,35 @@
561
}
562
563
/* Addons Page */
564
- #rtb-addons {
565
margin-top: 2em;
566
}
567
568
- #rtb-addons .rtb-loading {
569
- line-height: 10em;
570
- font-size: 2em;
571
- text-align: center;
572
- text-transform: uppercase;
573
- font-weight: bold;
574
- background: #eee;
575
- background: rgba(0,0,0,0.1);
576
- color: #777;
577
- color: rgba(0,0,0,0.54);
578
- }
579
-
580
- #rtb-addons .rtb-loading .spinner {
581
- float: none;
582
- visibility: visible;
583
display: inline-block;
584
- }
585
-
586
- #rtb-addons .error {
587
- padding: 0.25em 0.5em;
588
- background: #f50;
589
- color: #fff;
590
- }
591
-
592
- #rtb-addons .error a {
593
- color: #fff;
594
- }
595
-
596
- #rtb-addons .addon {
597
margin-bottom: 20px;
598
padding: 20px;
599
background: #fff;
600
- min-height: 128px;
601
border-radius: 3px;
602
- display: none;
603
}
604
605
- #rtb-addons img {
606
float: left;
607
- width: 128px;
608
- height: 128px;
609
margin: 0 20px 20px 0;
610
}
611
612
- #rtb-addons .action {
613
margin-top: 2em;
614
}
615
616
- #rtb-addons .soon,
617
- #rtb-addons .installed {
618
line-height: 28px;
619
display: inline-block;
620
padding: 0 0.75em;
@@ -622,26 +620,39 @@
622
box-shadow: 0 1px 0 #ccc;
623
}
624
625
- #rtb-addons .soon {
626
background: #F0F05E;
627
}
628
629
- #rtb-addons .installed {
630
background: #81F05E;
631
}
632
633
@media screen and (max-width: 600px) {
634
635
- #rtb-addons .addon {
636
text-align: center;
637
}
638
639
- #rtb-addons img {
640
float: none;
641
margin: 0;
642
}
643
}
644
645
/* License page */
646
.rtb-license-setting .status {
647
display: inline-block;
355
width: 100%;
356
height: 100%;
357
background: rgba(0, 0, 0, 0.8);
358
+ z-index: 9999;
359
overflow-y: auto;
360
cursor: pointer;
361
visibility: hidden;
445
-webkit-transition: opacity .25s ease-in-out;
446
}
447
448
+ .rtb-admin-modal .button-link {
449
+ display: inline-block;
450
+ margin-top: 1em;
451
+ line-height: 26px;
452
+ }
453
+
454
.rtb-admin-modal .action-status {
455
display: inline-block;
456
float: right;
547
#rtb-error-modal .rtb-error-msg {
548
margin-bottom: 1em;
549
}
550
+
551
+ .rtb-ban-form .intro {
552
+ margin-top: 0;
553
+ font-weight: bold;
554
+ }
555
+
556
+ .rtb-ban-form .intro span {
557
+ color: #a55;
558
+ }
559
+
560
+ .rtb-ban-form .button-primary {
561
+ display: block;
562
+ width: 100%;
563
+ margin-top: 2em;
564
+ margin-bottom: 2em;
565
+ }
566
+
567
/* Hide the outer scrollbar when the modal is open */
568
.rtb-hide-body-scroll {
569
overflow: hidden !important;
584
}
585
586
/* Addons Page */
587
+ .rtb-addons {
588
margin-top: 2em;
589
}
590
591
+ .rtb-addons .addon {
592
display: inline-block;
593
margin-bottom: 20px;
594
padding: 20px;
595
background: #fff;
596
+ min-height: 150px;
597
border-radius: 3px;
598
+ max-width: 40em;
599
+ margin-right: 20px;
600
+ vertical-align: top;
601
}
602
603
+ .rtb-addons img {
604
float: left;
605
+ width: 150px;
606
+ height: 150px;
607
margin: 0 20px 20px 0;
608
}
609
610
+ .rtb-addons .action {
611
margin-top: 2em;
612
}
613
614
+ .rtb-addons .soon,
615
+ .rtb-addons .installed {
616
line-height: 28px;
617
display: inline-block;
618
padding: 0 0.75em;
620
box-shadow: 0 1px 0 #ccc;
621
}
622
623
+ .rtb-addons .soon {
624
background: #F0F05E;
625
}
626
627
+ .rtb-addons .installed {
628
background: #81F05E;
629
}
630
631
+ .rtb-addons .addon-themes .action .button {
632
+ background: #D24C2B;
633
+ color: #fff;
634
+ border-color: #a53216;
635
+ box-shadow: 0 1px 0 #cc3712;
636
+ }
637
+
638
+ .rtb-addons .addon-themes .action .button:hover,
639
+ .rtb-addons .addon-themes .action .button:focus {
640
+ background: #ff5126;
641
+ }
642
+
643
@media screen and (max-width: 600px) {
644
645
+ .rtb-addons .addon {
646
text-align: center;
647
}
648
649
+ .rtb-addons img {
650
float: none;
651
margin: 0;
652
}
653
}
654
655
+
656
/* License page */
657
.rtb-license-setting .status {
658
display: inline-block;
assets/img/custom-fields.png ADDED
Binary file
assets/img/export-bookings.png ADDED
Binary file
assets/img/mailchimp.png ADDED
Binary file
assets/img/themes.png ADDED
Binary file
assets/js/admin.js CHANGED
@@ -16,7 +16,7 @@ jQuery(document).ready(function ($) {
16
hiddenName: true,
17
18
onStart: function() {
19
- if ( input.val() !== '' ) {
20
var date = new Date( input.val() );
21
if ( Object.prototype.toString.call( date ) === "[object Date]" ) {
22
this.set( 'select', date );
@@ -56,6 +56,9 @@ jQuery(document).ready(function ($) {
56
57
} else if ( target.data( 'action' ) == 'email') {
58
rtb_toggle_email_modal( true, target.data( 'id'), target.data( 'email' ), target.data( 'name' ) );
59
}
60
61
e.preventDefault();
@@ -87,24 +90,29 @@ jQuery(document).ready(function ($) {
87
/**
88
* Modals for the admin page
89
*/
90
- var rtb_booking_modal = $( '#rtb-booking-modal' );
91
- var rtb_booking_modal_fields = rtb_booking_modal.find( '#rtb-booking-form-fields' );
92
- var rtb_booking_modal_submit = rtb_booking_modal.find( 'button' );
93
- var rtb_booking_modal_cancel = rtb_booking_modal.find( '#rtb-cancel-booking-modal' );
94
- var rtb_booking_modal_action_status = rtb_booking_modal.find( '.action-status' );
95
- var rtb_email_modal = $( '#rtb-email-modal' );
96
- var rtb_email_modal_submit = rtb_email_modal.find( 'button' );
97
- var rtb_email_modal_cancel = rtb_email_modal.find( '#rtb-cancel-email-modal' );
98
- var rtb_email_modal_action_status = rtb_email_modal.find( '.action-status' );
99
- var rtb_column_modal = $( '#rtb-column-modal' );
100
- var rtb_column_modal_submit = rtb_column_modal.find( 'button' );
101
- var rtb_column_modal_cancel = rtb_column_modal.find( '#rtb-cancel-column-modal' );
102
- var rtb_column_modal_action_status = rtb_column_modal.find( '.action-status' );
103
- var rtb_details_modal = $( '#rtb-details-modal' );
104
- var rtb_details_modal_close = rtb_details_modal.find( '#rtb-close-details-modal' );
105
- var rtb_details_modal_cancel = rtb_details_modal.find( '#rtb-cancel-details-modal' );
106
- var rtb_booking_modal_error = $( '#rtb-error-modal' );
107
- var rtb_booking_modal_error_msg = rtb_booking_modal_error.find( '.rtb-error-msg' );
108
109
/**
110
* Show or hide the booking form modal
@@ -210,7 +218,11 @@ jQuery(document).ready(function ($) {
210
rtb_details_modal.find( '.actions' ).click( function(e) {
211
var target = $( e.target );
212
rtb_toggle_details_modal( false );
213
- rtb_toggle_email_modal( true, target.data( 'id'), target.data( 'email' ), target.data( 'name' ) );
214
});
215
216
} else {
@@ -222,6 +234,36 @@ jQuery(document).ready(function ($) {
222
}
223
}
224
225
/**
226
* Initialize form field events
227
*/
@@ -391,6 +433,17 @@ jQuery(document).ready(function ($) {
391
}
392
});
393
394
// Close modals when ESC is keyed
395
$(document).keyup( function(e) {
396
if ( e.which == '27' ) {
@@ -399,6 +452,7 @@ jQuery(document).ready(function ($) {
399
rtb_toggle_column_modal( false );
400
rtb_toggle_details_modal( false );
401
rtb_toggle_booking_form_error_modal( false );
402
}
403
});
404
@@ -577,119 +631,88 @@ jQuery(document).ready(function ($) {
577
});
578
});
579
580
- // Show the addons
581
- if ( $( '#rtb-addons' ).length ) {
582
-
583
- var rtbAddons = {
584
-
585
- el: $( '#rtb-addons' ),
586
-
587
- load: function() {
588
-
589
- var params = {
590
- action: 'rtb-addons',
591
- nonce: rtb_addons.nonce
592
- };
593
-
594
- var data = $.param( params );
595
-
596
- // Send Ajax request
597
- var jqxhr = $.post( ajaxurl, data, function( r ) {
598
-
599
- rtbAddons.el.find( '.rtb-loading' ).fadeOut( '250', function() {
600
- if ( r.success ) {
601
- rtbAddons.showAddons( r );
602
- } else {
603
- rtbAddons.showError( r );
604
- }
605
- });
606
-
607
608
- });
609
- },
610
611
- showAddons: function( r ) {
612
613
- if ( typeof r.data == 'undefined' || !r.data.length ) {
614
- rtbAddons.showError();
615
- return false;
616
- }
617
618
- for( var i in r.data ) {
619
- rtbAddons.el.append( rtbAddons.getAddonHTML( r.data[i] ) );
620
- rtbAddons.el.find( '.addon.' + r.data[i].id ).fadeIn();
621
- }
622
- },
623
624
- showError: function( r ) {
625
626
- if ( typeof r.data == 'undefined' || typeof r.data.msg == 'undefined' ) {
627
- rtbAddons.el.html( '<span class="error">' + rtb_addons.strings.error_unknown + '</span>' );
628
- } else {
629
- rtbAddons.el.html( '<span class="error">' + r.data.msg + '</span>' );
630
- }
631
632
- },
633
634
- getAddonHTML: function( addon ) {
635
636
- if ( typeof addon.id === 'undefined' && typeof addon.title === 'undefined' ) {
637
- return;
638
}
639
640
- // Set campaign parameters for addons
641
- addon.url += '?utm_source=Plugin&utm_medium=Addon%20List&utm_campaign=Restaurant%20Reservations';
642
-
643
- var html = '<div class="addon ' + addon.id + '">';
644
645
- if ( typeof addon.url !== 'undefined' && typeof addon.img !== 'undefined' ) {
646
- html += '<a href="' + addon.url + '"><img src="' + addon.img + '"></a>';
647
- } else if ( typeof addon.img !== 'undefind' ) {
648
- html += '<img src="' + addon.img + '">';
649
- }
650
-
651
- html += '<h3>' + addon.title + '</h3>';
652
653
- html += '<div class="details">';
654
655
- if ( typeof addon.description !== 'undefined' ) {
656
- html += '<div class="description">' + addon.description + '</div>';
657
}
658
659
- if ( typeof addon.status !== 'undefined' ) {
660
-
661
- html += '<div class="action">';
662
-
663
- if ( addon.status === 'released' && typeof addon.url !== 'undefined' ) {
664
- html += '<a href="' + addon.url + '" class="button button-primary" target="_blank">';
665
-
666
- if ( typeof addon.price !== 'undefined' && addon.price.length ) {
667
- html += rtb_addons.strings.learn_more;
668
- } else {
669
- html += rtb_addons.strings.free;
670
- }
671
-
672
- html += '</a>';
673
-
674
- } else if ( addon.status === 'installed' ) {
675
- html += '<span class="installed">' + rtb_addons.strings.installed + '</span>';
676
-
677
- } else {
678
- html += '<span class="soon">' + rtb_addons.strings.coming_soon + '</span>';
679
- }
680
-
681
- html += '</div>'; // .action
682
}
683
684
- html += '</div>'; // .details
685
686
- html += '</div>'; // .addon
687
-
688
- return html;
689
}
690
- };
691
-
692
- rtbAddons.load();
693
}
694
695
});
16
hiddenName: true,
17
18
onStart: function() {
19
+ if ( input.val() !== '' ) {
20
var date = new Date( input.val() );
21
if ( Object.prototype.toString.call( date ) === "[object Date]" ) {
22
this.set( 'select', date );
56
57
} else if ( target.data( 'action' ) == 'email') {
58
rtb_toggle_email_modal( true, target.data( 'id'), target.data( 'email' ), target.data( 'name' ) );
59
+
60
+ } else if ( target.data( 'action' ) == 'ban') {
61
+ rtb_toggle_ban_modal( true, target.data( 'id'), target.data( 'email' ), target.data( 'ip' ) );
62
}
63
64
e.preventDefault();
90
/**
91
* Modals for the admin page
92
*/
93
+ var rtb_booking_modal = $( '#rtb-booking-modal' ),
94
+ rtb_booking_modal_fields = rtb_booking_modal.find( '#rtb-booking-form-fields' ),
95
+ rtb_booking_modal_submit = rtb_booking_modal.find( 'button' ),
96
+ rtb_booking_modal_cancel = rtb_booking_modal.find( '#rtb-cancel-booking-modal' ),
97
+ rtb_booking_modal_action_status = rtb_booking_modal.find( '.action-status' ),
98
+ rtb_email_modal = $( '#rtb-email-modal' ),
99
+ rtb_email_modal_submit = rtb_email_modal.find( 'button' ),
100
+ rtb_email_modal_cancel = rtb_email_modal.find( '#rtb-cancel-email-modal' ),
101
+ rtb_email_modal_action_status = rtb_email_modal.find( '.action-status' ),
102
+ rtb_column_modal = $( '#rtb-column-modal' ),
103
+ rtb_column_modal_submit = rtb_column_modal.find( 'button' ),
104
+ rtb_column_modal_cancel = rtb_column_modal.find( '#rtb-cancel-column-modal' ),
105
+ rtb_column_modal_action_status = rtb_column_modal.find( '.action-status' ),
106
+ rtb_details_modal = $( '#rtb-details-modal' ),
107
+ rtb_details_modal_close = rtb_details_modal.find( '#rtb-close-details-modal' ),
108
+ rtb_details_modal_cancel = rtb_details_modal.find( '#rtb-cancel-details-modal' ),
109
+ rtb_booking_modal_error = $( '#rtb-error-modal' ),
110
+ rtb_booking_modal_error_msg = rtb_booking_modal_error.find( '.rtb-error-msg' ),
111
+ rtb_ban_modal = $( '#rtb-ban-modal' ),
112
+ rtb_ban_modal_submit_email = rtb_ban_modal.find( '#rtb-ban-modal-email-btn' ),
113
+ rtb_ban_modal_submit_ip = rtb_ban_modal.find( '#rtb-ban-modal-ip-btn' ),
114
+ rtb_ban_modal_cancel = rtb_ban_modal.find( '#rtb-cancel-ban-modal' ),
115
+ rtb_ban_modal_action_status = rtb_ban_modal.find( '.action-status' );
116
117
/**
118
* Show or hide the booking form modal
218
rtb_details_modal.find( '.actions' ).click( function(e) {
219
var target = $( e.target );
220
rtb_toggle_details_modal( false );
221
+ if ( target.data( 'action' ) == 'email') {
222
+ rtb_toggle_email_modal( true, target.data( 'id'), target.data( 'email' ), target.data( 'name' ) );
223
+ } else if ( target.data( 'action' ) == 'ban') {
224
+ rtb_toggle_ban_modal( true, target.data( 'id'), target.data( 'email' ), target.data( 'ip' ) );
225
+ }
226
});
227
228
} else {
234
}
235
}
236
237
+ /**
238
+ * Show or hide the ban ip/email form modal
239
+ */
240
+ function rtb_toggle_ban_modal( show, id, email, ip ) {
241
+
242
+ if ( show ) {
243
+ rtb_ban_modal.scrollTop( 0 ).addClass( 'is-visible' );
244
+ rtb_ban_modal.find( '#rtb-ban-modal-email' ).text( email );
245
+ rtb_ban_modal.find( '#rtb-ban-modal-ip' ).text( ip );
246
+ if ( rtb_admin.banned_emails.indexOf( email ) > -1 ) {
247
+ rtb_ban_modal_submit_email.prop( 'disabled', true );
248
+ }
249
+ if ( rtb_admin.banned_ips.indexOf( ip ) > -1 ) {
250
+ rtb_ban_modal_submit_ip.prop( 'disabled', true );
251
+ }
252
+
253
+ $( 'body' ).addClass( 'rtb-hide-body-scroll' );
254
+
255
+ } else {
256
+ rtb_ban_modal.removeClass( 'is-visible' );
257
+ rtb_ban_modal.find( '#rtb-ban-modal-email' ).text( '' );
258
+ rtb_ban_modal.find( '#rtb-ban-modal-ip' ).text( '' );
259
+ rtb_ban_modal_submit_email.prop( 'disabled', false );
260
+ rtb_ban_modal_submit_ip.prop( 'disabled', false );
261
+ rtb_ban_modal_cancel.prop( 'disabled', false );
262
+
263
+ $( 'body' ).removeClass( 'rtb-hide-body-scroll' );
264
+ }
265
+ }
266
+
267
/**
268
* Initialize form field events
269
*/
433
}
434
});
435
436
+ // Close ban modal when background or cancel button is clicked
437
+ rtb_ban_modal.click( function(e) {
438
+ if ( $(e.target).is( rtb_ban_modal ) ) {
439
+ rtb_toggle_ban_modal( false );
440
+ }
441
+
442
+ if ( $(e.target).is( rtb_ban_modal_cancel ) && rtb_ban_modal_cancel.prop( 'disabled' ) !== true ) {
443
+ rtb_toggle_ban_modal( false );
444
+ }
445
+ });
446
+
447
// Close modals when ESC is keyed
448
$(document).keyup( function(e) {
449
if ( e.which == '27' ) {
452
rtb_toggle_column_modal( false );
453
rtb_toggle_details_modal( false );
454
rtb_toggle_booking_form_error_modal( false );
455
+ rtb_toggle_ban_modal( false );
456
}
457
});
458
631
});
632
});
633
634
+ // Shared function for banning emails and IPs
635
+ function rtb_ban_modal_submit( e, type ) {
636
637
+ e.preventDefault();
638
+ e.stopPropagation();
639
640
+ if ( $(this).prop( 'disabled' ) === true ) {
641
+ return;
642
+ }
643
644
+ // Loading
645
+ if ( type === 'email' ) {
646
+ rtb_ban_modal_submit_email.prop( 'disabled', true );
647
+ } else if ( type === 'ip' ) {
648
+ rtb_ban_modal_submit_ip.prop( 'disabled', true );
649
+ }
650
+ rtb_ban_modal_cancel.prop( 'disabled', true );
651
+ rtb_ban_modal_action_status.addClass( 'is-visible' );
652
+ rtb_show_action_status( rtb_ban_modal_action_status, 'loading' );
653
654
+ var params = {};
655
656
+ params.action = 'rtb-admin-ban-modal';
657
+ params.nonce = rtb_admin.nonce;
658
+ if ( type === 'email' ) {
659
+ params.email = rtb_ban_modal.find( '#rtb-ban-modal-email' ).text();
660
+ } else if ( type === 'ip' ) {
661
+ params.ip = rtb_ban_modal.find( '#rtb-ban-modal-ip' ).text();
662
+ }
663
664
+ var data = $.param( params );
665
666
+ var jqhxr = $.post( ajaxurl, data, function( r ) {
667
668
+ if ( r.success ) {
669
670
+ if ( type === 'email' ) {
671
+ rtb_admin.banned_emails.push( params.email );
672
+ } else if ( type === 'ip' ) {
673
+ rtb_admin.banned_ips.push( params.ip );
674
}
675
676
+ rtb_show_action_status( rtb_ban_modal_action_status, r.success );
677
678
+ // Hide result status icon after a few seconds
679
+ setTimeout( function() {
680
+ rtb_ban_modal.find( '.action-status' ).removeClass( 'is-visible' );
681
+ }, 1000 );
682
683
+ } else {
684
685
+ if ( typeof r.data == 'undefined' || typeof r.data.error == 'undefined' ) {
686
+ rtb_toggle_booking_form_error_modal( true, rtb_admin.strings.error_unspecified );
687
+ } else {
688
+ rtb_toggle_booking_form_error_modal( true, r.data.msg );
689
}
690
691
+ rtb_ban_modal_cancel.prop( 'disabled', false );
692
+ if ( type === 'email' ) {
693
+ rtb_ban_modal_submit_email.prop( 'disabled', false );
694
+ } else if ( type === 'ip' ) {
695
+ rtb_ban_modal_submit_ip.prop( 'disabled', false );
696
}
697
698
+ rtb_show_action_status( rtb_ban_modal_action_status, false );
699
700
+ // Hide result status icon after a few seconds
701
+ setTimeout( function() {
702
+ rtb_ban_modal.find( '.action-status' ).removeClass( 'is-visible' );
703
+ }, 4000 );
704
}
705
+ });
706
}
707
708
+ // Submit ban email form modal
709
+ rtb_ban_modal_submit_email.click( function(e) {
710
+ rtb_ban_modal_submit( e, 'email' );
711
+ });
712
+
713
+ // Submit ban ip form modal
714
+ rtb_ban_modal_submit_ip.click( function(e) {
715
+ rtb_ban_modal_submit( e, 'ip' );
716
+ });
717
+
718
});
assets/js/booking-form.js CHANGED
@@ -40,7 +40,7 @@ jQuery(document).ready(function ($) {
40
format: rtb_pickadate.date_format,
41
formatSubmit: 'yyyy/mm/dd',
42
hiddenName: true,
43
- min: true,
44
container: 'body',
45
firstDay: rtb_pickadate.first_day,
46
@@ -112,10 +112,14 @@ jQuery(document).ready(function ($) {
112
rtb_booking_form.datepicker.set( 'disable', disable_dates );
113
}
114
115
- rtb_pickadate.late_bookings = parseInt( rtb_pickadate.late_bookings, 10 );
116
- if ( rtb_pickadate.late_bookings >= 1440 ) {
117
- var min = Math.floor( rtb_pickadate.late_bookings / 1440 );
118
- rtb_booking_form.datepicker.set( 'min', min );
119
}
120
121
// If no date has been set, select today's date if it's a valid
@@ -161,15 +165,16 @@ jQuery(document).ready(function ($) {
161
return;
162
}
163
164
- selected_date = new Date( rtb_booking_form.datepicker.get( 'select', 'yyyy/mm/dd' ) );
165
- var selected_date_year = selected_date.getFullYear();
166
- var selected_date_month = selected_date.getMonth();
167
- var selected_date_date = selected_date.getDate();
168
169
// Declaring the first element true inverts the timepicker settings. All
170
// times subsequently declared are valid. Any time that doesn't fall
171
// within those declarations is invalid.
172
- // See: http://amsul.ca/pickadate.js/time.htm#disable-times-all
173
var valid_times = [ rtb_booking_form.get_outer_time_range() ];
174
175
// Check if this date is an exception to the rules
@@ -209,6 +214,8 @@ jQuery(document).ready(function ($) {
209
excp_end_time = [ 24, 0 ]; // End of the day
210
}
211
212
valid_times.push( { from: excp_start_time, to: excp_end_time, inverted: true } );
213
}
214
}
@@ -269,6 +276,8 @@ jQuery(document).ready(function ($) {
269
rule_end_time = [ 24, 0 ]; // End of the day
270
}
271
272
valid_times.push( { from: rule_start_time, to: rule_end_time, inverted: true } );
273
274
}
@@ -337,6 +346,43 @@ jQuery(document).ready(function ($) {
337
}
338
};
339
340
341
rtb_booking_form.init();
342
});
40
format: rtb_pickadate.date_format,
41
formatSubmit: 'yyyy/mm/dd',
42
hiddenName: true,
43
+ min: !rtb_pickadate.allow_past,
44
container: 'body',
45
firstDay: rtb_pickadate.first_day,
46
112
rtb_booking_form.datepicker.set( 'disable', disable_dates );
113
}
114
115
+ if ( typeof rtb_pickadate.late_bookings === 'string' && rtb_pickadate.late_bookings == 'same_day' ) {
116
+ rtb_booking_form.datepicker.set( 'min', 1 );
117
+ } else if ( typeof rtb_pickadate.late_bookings === 'number' && rtb_pickadate.late_bookings % 1 === 0 ) {
118
+ rtb_pickadate.late_bookings = parseInt( rtb_pickadate.late_bookings, 10 );
119
+ if ( rtb_pickadate.late_bookings >= 1440 ) {
120
+ var min = Math.floor( rtb_pickadate.late_bookings / 1440 );
121
+ rtb_booking_form.datepicker.set( 'min', min );
122
+ }
123
}
124
125
// If no date has been set, select today's date if it's a valid
165
return;
166
}
167
168
+ var selected_date = new Date( rtb_booking_form.datepicker.get( 'select', 'yyyy/mm/dd' ) ),
169
+ selected_date_year = selected_date.getFullYear(),
170
+ selected_date_month = selected_date.getMonth(),
171
+ selected_date_date = selected_date.getDate(),
172
+ current_date = new Date();
173
174
// Declaring the first element true inverts the timepicker settings. All
175
// times subsequently declared are valid. Any time that doesn't fall
176
// within those declarations is invalid.
177
+ // See: http://amsul.ca/pickadate.js/time/#disable-times-all
178
var valid_times = [ rtb_booking_form.get_outer_time_range() ];
179
180
// Check if this date is an exception to the rules
214
excp_end_time = [ 24, 0 ]; // End of the day
215
}
216
217
+ excp_start_time = rtb_booking_form.get_earliest_time( excp_start_time, selected_date, current_date );
218
+
219
valid_times.push( { from: excp_start_time, to: excp_end_time, inverted: true } );
220
}
221
}
276
rule_end_time = [ 24, 0 ]; // End of the day
277
}
278
279
+ rule_start_time = rtb_booking_form.get_earliest_time( rule_start_time, selected_date, current_date );
280
+
281
valid_times.push( { from: rule_start_time, to: rule_end_time, inverted: true } );
282
283
}
346
}
347
};
348
349
+ /**
350
+ * Get the earliest valid time
351
+ *
352
+ * This checks the valid time for the day and, if a current day, applies
353
+ * any late booking restrictions. It also ensures that times in the past
354
+ * are not availabe.
355
+ *
356
+ * @param array start_time
357
+ * @param array selected_date
358
+ * @param array current_date
359
+ */
360
+ rtb_booking_form.get_earliest_time = function( start_time, selected_date, current_date ) {
361
+
362
+ // Only make adjustments for current day selections
363
+ if ( selected_date.getDate() !== current_date.getDate() ) {
364
+ return start_time;
365
+ }
366
+
367
+ // Get the number of minutes after midnight to compare
368
+ var start_minutes = ( start_time[0] * 60 ) + start_time[1],
369
+ current_minutes = ( current_date.getHours() * 60 ) + current_date.getMinutes(),
370
+ late_booking_minutes;
371
+
372
+ start_minutes = start_minutes > current_minutes ? start_minutes : current_minutes;
373
+
374
+ if ( typeof rtb_pickadate.late_bookings === 'number' && rtb_pickadate.late_bookings % 1 === 0 ) {
375
+ late_booking_minutes = current_minutes + rtb_pickadate.late_bookings;
376
+ if ( late_booking_minutes > start_minutes ) {
377
+ start_minutes = late_booking_minutes;
378
+ }
379
+ }
380
+
381
+ start_time = [ Math.floor( start_minutes / 60 ), start_minutes % 60 ];
382
+
383
+ return start_time;
384
+ };
385
+
386
387
rtb_booking_form.init();
388
});
includes/Addons.class.php CHANGED
@@ -9,105 +9,13 @@ if ( !class_exists( 'rtbAddons' ) ) {
9
*/
10
class rtbAddons {
11
12
- /**
13
- * API endpoint to retrieve addons list
14
- */
15
- public $api_url;
16
-
17
- /**
18
- * Plugin slug to retrieve addons for
19
- */
20
- public $plugin;
21
-
22
- public function __construct( $args ) {
23
-
24
- $this->parse_args( $args );
25
-
26
- if ( $this->check_config() ) {
27
-
28
- // Add the admin menu
29
- add_action( 'admin_menu', array( $this, 'add_menu_page' ), 100 );
30
-
31
- // Send addon data to the javascript
32
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
33
-
34
- // Receive ajax calls to fetch addons
35
- add_action( 'wp_ajax_nopriv_rtb-addons' , array( $this , 'ajax_nopriv_get_addons' ) );
36
- add_action( 'wp_ajax_rtb-addons', array( $this, 'ajax_get_addons' ) );
37
38
- // Add a newsletter subscription prompt above the addons
39
- add_action( 'rtb_addons_pre', array( $this, 'add_subscribe_pompt' ) );
40
41
- }
42
- }
43
-
44
- /**
45
- * Parse the arguments passed in the construction and assign them to
46
- * internal variables.
47
- */
48
- private function parse_args( $args ) {
49
- foreach ( $args as $key => $val ) {
50
- switch ( $key ) {
51
-
52
- case 'api_url' :
53
- $this->{$key} = esc_url( $val );
54
-
55
- case 'plugin' :
56
- $this->{$key} = esc_attr( $val );
57
-
58
- default :
59
- $this->{$key} = $val;
60
-
61
- }
62
- }
63
-
64
- do_action( $this->plugin . '_addons_parse_args' );
65
- }
66
-
67
- /**
68
- * Check that we have everything we need to render the addons page
69
- */
70
- public function check_config() {
71
-
72
- if ( !empty( $this->api_url ) && !empty( $this->plugin ) ) {
73
- return true;
74
- }
75
-
76
- return false;
77
- }
78
-
79
- /**
80
- * Send addon data to the javascript
81
- */
82
- public function enqueue_admin_assets() {
83
-
84
- // Use the page reference in $admin_page_hooks because
85
- // it changes in SOME hooks when it is translated.
86
- // https://core.trac.wordpress.org/ticket/18857
87
- global $admin_page_hooks;
88
-
89
- $screen = get_current_screen();
90
- if ( empty( $screen ) || empty( $admin_page_hooks['rtb-bookings'] ) ) {
91
- return;
92
- }
93
-
94
- if ( $screen->base == $admin_page_hooks['rtb-bookings'] . '_page_rtb-addons' ) {
95
- wp_localize_script(
96
- 'rtb-admin',
97
- 'rtb_addons',
98
- array(
99
- 'nonce' => wp_create_nonce( 'rtb-addons' ),
100
- 'strings' => array(
101
- 'loading' => __( 'Loading', 'restaurant-reservations' ),
102
- 'error_unknown' => _x( 'An unknown error occured.', 'Error message when retrieving list of addons', 'restaurant-reservations' ),
103
- 'installed' => _x( 'Already Installed', 'Label for an addon that is already installed and activated.', 'restaurant-reservations' ),
104
- 'coming_soon' => _x( 'Coming Soon', 'Label for an addon that is not yet released.', 'restaurant-reservations' ),
105
- 'free' => _x( 'Free', 'Label for an addon that is free.', 'restaurant-reservations' ),
106
- 'learn_more' => _x( 'Get It', 'Label for an addon that is released.', 'restaurant-reservations' ),
107
- )
108
- )
109
- );
110
- }
111
}
112
113
/**
@@ -131,16 +39,77 @@ class rtbAddons {
131
*/
132
public function show_admin_addons_page() {
133
134
- // @todo check for transient and only call the api if its missing
135
?>
136
137
<div class="wrap">
138
<h1><?php _e( 'Addons for Restaurant Reservations', 'restaurant-reservations' ); ?></h1>
139
<?php do_action( 'rtb_addons_pre' ); ?>
140
- <div id="rtb-addons">
141
- <div class="rtb-loading">
142
- <div class="spinner"></div>
143
- Loading
144
</div>
145
</div>
146
<?php do_action( 'rtb_addons_post' ); ?>
@@ -149,64 +118,6 @@ class rtbAddons {
149
<?php
150
}
151
152
- /**
153
- * Handle ajax request for addons from logged out user
154
- */
155
- public function ajax_nopriv_get_addons() {
156
-
157
- wp_send_json_error(
158
- array(
159
- 'error' => 'loggedout',
160
- 'msg' => __( 'You have been logged out. Please login again to retrieve the addons.', 'restaurant-reservations' ),
161
- )
162
- );
163
- }
164
-
165
- /**
166
- * Handle ajax request for addons
167
- */
168
- public function ajax_get_addons() {
169
-
170
- $url = $this->api_url . $this->plugin;
171
-
172
- if ( !check_ajax_referer( 'rtb-addons', 'nonce' ) || !current_user_can( 'manage_options' )) {
173
- wp_send_json_error(
174
- array(
175
- 'error' => 'nopriv',
176
- 'msg' => __( 'You do not have permission to access this page. Please login to an administrator account if you have one.', 'restaurant-reservations' ),
177
- )
178
- );
179
- }
180
-
181
- if ( function_exists( 'curl_init' ) && function_exists( 'curl_setop' ) ) {
182
- $ch = curl_init();
183
- curl_setopt( $ch, CURLOPT_URL, $url );
184
- curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json' ) );
185
- curl_setopt( $ch, CURLOPT_USERAGENT, 'PHP-MCAPI/2.0' );
186
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
187
- curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
188
- $result = curl_exec($ch);
189
- curl_close($ch);
190
-
191
- } elseif ( ini_get( 'allow_url_fopen' ) ) {
192
- $result = @file_get_contents( $url );
193
- } else {
194
- $result = @file_get_contents( RTB_PLUGIN_DIR . '/assets/addons-backup.json' );
195
- }
196
-
197
- if ( $result ) {
198
- // @todo set a transient with this data to reduce calls
199
- wp_send_json_success( json_decode( $result ) );
200
- } else {
201
- wp_send_json_error(
202
- array(
203
- 'error' => 'apifailed',
204
- 'msg' => __( 'The addons list could not be retrieved. Please <a href="">try again</a>. If the problem persists over time, please report it on the <a href="http://wordpress.org/support/plugin/restaurant-reservations" target="_blank">support forums</a>.', 'restaurant-reservations' ),
205
- )
206
- );
207
- }
208
- }
209
-
210
/**
211
* Add a prompt for users to subscribe to the Theme of the Crop mailing list
212
* below the addons list.
@@ -218,7 +129,17 @@ class rtbAddons {
218
?>
219
220
<p>
221
- <?php echo sprintf( esc_html_x( 'Find out when new addons are available by subscribing to the %smonthly newsletter%s or following %sTheme of the Crop%s on Twitter.', 'restaurant-reservations' ), '<a href="http://themeofthecrop.com/about/mailing-list/?utm_source=Plugin&utm_medium=Addon%20List&utm_campaign=Restaurant%20Reservations">', '</a>', '<a href="http://twitter.com/themeofthecrop">', '</a>' ); ?>
222
</p>
223
224
<?php
9
*/
10
class rtbAddons {
11
12
+ public function __construct( ) {
13
14
+ // Add the admin menu
15
+ add_action( 'admin_menu', array( $this, 'add_menu_page' ), 100 );
16
17
+ // Add a newsletter subscription prompt above the addons
18
+ add_action( 'rtb_addons_pre', array( $this, 'add_subscribe_pompt' ) );
19
}
20
21
/**
39
*/
40
public function show_admin_addons_page() {
41
42
+ // Set campaign parameters for addon URLs
43
+ $url_params = '?utm_source=Plugin&utm_medium=Addon%20List&utm_campaign=Restaurant%20Reservations';
44
?>
45
46
<div class="wrap">
47
<h1><?php _e( 'Addons for Restaurant Reservations', 'restaurant-reservations' ); ?></h1>
48
<?php do_action( 'rtb_addons_pre' ); ?>
49
+ <div class="rtb-addons">
50
+ <div class="addon addon-custom-fields">
51
+ <a href="https://themeofthecrop.com/plugins/restaurant-reservations/custom-fields/<?php echo $url_params; ?>">
52
+ <img src="<?php echo RTB_PLUGIN_URL . '/assets/img/custom-fields.png'; ?>">
53
+ </a>
54
+ <h3><?php echo esc_html( 'Custom Fields', 'restaurant-reservations' ); ?></h3>
55
+ <div class="details">
56
+ <div class="description">
57
+ <?php echo esc_html( 'Plan your dinner service better by asking for special seating requests, dietary needs and more when customers book online.', 'restaurant-reservations' ); ?>
58
+ </div>
59
+ <div class="action">
60
+ <a href="https://themeofthecrop.com/plugins/restaurant-reservations/custom-fields/<?php echo $url_params; ?>" class="button button-primary" target="_blank">
61
+ <?php echo esc_html( 'Learn More', 'restaurant-reservations' ); ?>
62
+ </a>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ <div class="addon addon-export-bookings">
67
+ <a href="https://themeofthecrop.com/plugins/restaurant-reservations/export-bookings/<?php echo $url_params; ?>">
68
+ <img src="<?php echo RTB_PLUGIN_URL . '/assets/img/export-bookings.png'; ?>">
69
+ </a>
70
+ <h3><?php echo esc_html( 'Export Bookings', 'restaurant-reservations' ); ?></h3>
71
+ <div class="details">
72
+ <div class="description">
73
+ <?php echo esc_html( 'Easily print your bookings in a PDF or export them to an Excel/CSV file so you can analyze patterns, cull customer data and import bookings into other services.' ); ?>
74
+ </div>
75
+ <div class="action">
76
+ <a href="https://themeofthecrop.com/plugins/restaurant-reservations/export-bookings/<?php echo $url_params; ?>" class="button button-primary" target="_blank">
77
+ <?php echo esc_html( 'Learn More', 'restaurant-reservations' ); ?>
78
+ </a>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ <div class="addon addon-mailchimp">
83
+ <a href="https://themeofthecrop.com/plugins/restaurant-reservations/mailchimp/<?php echo $url_params; ?>">
84
+ <img src="<?php echo RTB_PLUGIN_URL . '/assets/img/mailchimp.png'; ?>">
85
+ </a>
86
+ <h3><?php echo esc_html( 'MailChimp', 'restaurant-reservations' ); ?></h3>
87
+ <div class="details">
88
+ <div class="description">
89
+ <?php echo esc_html( 'Subscribe requests to your MailChimp mailing list and watch your subscription rates grow effortlessly.' ); ?>
90
+ </div>
91
+ <div class="action">
92
+ <a href="https://themeofthecrop.com/plugins/restaurant-reservations/mailchimp/<?php echo $url_params; ?>" class="button button-primary" target="_blank">
93
+ <?php echo esc_html( 'Learn More', 'restaurant-reservations' ); ?>
94
+ </a>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ <div class="addon addon-themes">
99
+ <a href="https://themeofthecrop.com/themes/<?php echo $url_params; ?>">
100
+ <img src="<?php echo RTB_PLUGIN_URL . '/assets/img/themes.png'; ?>">
101
+ </a>
102
+ <h3><?php echo esc_html( 'Restaurant WordPress Themes', 'restaurant-reservations' ); ?></h3>
103
+ <div class="details">
104
+ <div class="description">
105
+ <?php echo esc_html( 'Find the best WordPress restaurant themes that integrate beautifully with your reservations plugin.' ); ?>
106
+ </div>
107
+ <div class="action">
108
+ <a href="https://themeofthecrop.com/themes/<?php echo $url_params; ?>" class="button" target="_blank">
109
+ <?php echo esc_html( 'View Themes', 'restaurant-reservations' ); ?>
110
+ </a>
111
+ </div>
112
+ </div>
113
</div>
114
</div>
115
<?php do_action( 'rtb_addons_post' ); ?>
118
<?php
119
}
120
121
/**
122
* Add a prompt for users to subscribe to the Theme of the Crop mailing list
123
* below the addons list.
129
?>
130
131
<p>
132
+ <?php
133
+ echo sprintf(
134
+ esc_html_x( 'Find out when new addons are available by subscribing to the %smonthly newsletter%s, liking %sTheme of the Crop%s on Facebook, or following %sTheme of the Crop%s on Twitter.', 'restaurant-reservations' ),
135
+ '<a target="_blank" href="https://themeofthecrop.com/about/mailing-list/?utm_source=Plugin&utm_medium=Addon%20List&utm_campaign=Restaurant%20Reservations">',
136
+ '</a>',
137
+ '<a target="_blank" href="https://www.facebook.com/themeofthecrop/">',
138
+ '</a>',
139
+ '<a target="_blank" href="http://twitter.com/themeofthecrop">',
140
+ '</a>'
141
+ );
142
+ ?>
143
</p>
144
145
<?php
includes/AdminBookings.class.php CHANGED
@@ -38,6 +38,8 @@ class rtbAdminBookings {
38
add_action( 'wp_ajax_rtb-admin-email-modal', array( $this, 'email_modal_ajax' ) );
39
add_action( 'wp_ajax_nopriv_rtb-admin-column-modal' , array( $this , 'nopriv_ajax' ) );
40
add_action( 'wp_ajax_rtb-admin-column-modal', array( $this, 'column_modal_ajax' ) );
41
42
// Validate post status and notification fields
43
add_action( 'rtb_validate_booking_submission', array( $this, 'validate_admin_fields' ) );
@@ -270,6 +272,39 @@ class rtbAdminBookings {
270
</div>
271
</div>
272
273
<!-- Restaurant Reservations error message modal -->
274
<div id="rtb-error-modal" class="rtb-admin-modal">
275
<div class="rtb-error rtb-container">
@@ -616,7 +651,9 @@ class rtbAdminBookings {
616
$email->message = $message;
617
$email->set_booking( $booking );
618
if ( $email->prepare_notification() ) {
619
$email->send_notification();
620
}
621
622
// Store email in postmeta for log
@@ -656,6 +693,55 @@ class rtbAdminBookings {
656
wp_send_json_success();
657
}
658
659
/**
660
* Validate post status and notification fields
661
* @since 1.3
38
add_action( 'wp_ajax_rtb-admin-email-modal', array( $this, 'email_modal_ajax' ) );
39
add_action( 'wp_ajax_nopriv_rtb-admin-column-modal' , array( $this , 'nopriv_ajax' ) );
40
add_action( 'wp_ajax_rtb-admin-column-modal', array( $this, 'column_modal_ajax' ) );
41
+ add_action( 'wp_ajax_nopriv_rtb-admin-ban-modal' , array( $this , 'nopriv_ajax' ) );
42
+ add_action( 'wp_ajax_rtb-admin-ban-modal', array( $this, 'ban_modal_ajax' ) );
43
44
// Validate post status and notification fields
45
add_action( 'rtb_validate_booking_submission', array( $this, 'validate_admin_fields' ) );
272
</div>
273
</div>
274
275
+ <!-- Restaurant Reservations ban email/ip modal -->
276
+ <div id="rtb-ban-modal" class="rtb-admin-modal">
277
+ <div class="rtb-ban-form rtb-container">
278
+ <div class="rtb-ban-msg">
279
+ <p class="intro">
280
+ <?php
281
+ printf(
282
+ __( 'Ban future bookings from the email address %s or the IP address %s?', 'restaurant-reservations' ),
283
+ '<span id="rtb-ban-modal-email"></span>',
284
+ '<span id="rtb-ban-modal-ip"></span>'
285
+ );
286
+ ?>
287
+ </p>
288
+ <p>
289
+ <?php
290
+ esc_html_e( 'It is recommended to ban by email address instead of IP. Only ban by IP address to block a malicious user who is using different email addresses to avoid a previous ban.', 'restaurant-reservations' );
291
+ ?>
292
+ </p>
293
+ </div>
294
+ <button class="button button-primary" id="rtb-ban-modal-email-btn">Ban Email</button>
295
+ <button class="button button-primary" id="rtb-ban-modal-ip-btn">Ban IP</button>
296
+ <a href="#" id="rtb-cancel-ban-modal" class="button"><?php _e( 'Close', 'restaurant-reservations' ); ?></a>
297
+ <a class="button-link" href="<?php echo esc_url( admin_url( '/admin.php?page=rtb-settings' ) ); ?>" target="_blank">
298
+ <?php esc_html_e( 'View all bans', 'restaurant-reservations' ); ?>
299
+ </a>
300
+ <div class="action-status">
301
+ <span class="spinner loading"></span>
302
+ <span class="dashicons dashicons-no-alt error"></span>
303
+ <span class="dashicons dashicons-yes success"></span>
304
+ </div>
305
+ </div>
306
+ </div>
307
+
308
<!-- Restaurant Reservations error message modal -->
309
<div id="rtb-error-modal" class="rtb-admin-modal">
310
<div class="rtb-error rtb-container">
651
$email->message = $message;
652
$email->set_booking( $booking );
653
if ( $email->prepare_notification() ) {
654
+ do_action( 'rtb_send_notification_before', $email );
655
$email->send_notification();
656
+ do_action( 'rtb_send_notification_after', $email );
657
}
658
659
// Store email in postmeta for log
693
wp_send_json_success();
694
}
695
696
+ /**
697
+ * Handle ajax requests to ban by IP or email address
698
+ *
699
+ * @since 1.3.1
700
+ */
701
+ public function ban_modal_ajax() {
702
+
703
+ global $rtb_controller;
704
+
705
+ // Authenticate request
706
+ if ( !check_ajax_referer( 'rtb-admin', 'nonce' ) || !current_user_can( 'manage_bookings' ) ) {
707
+ $this->nopriv_ajax();
708
+ }
709
+
710
+ // Ban an email address
711
+ if ( isset( $_POST['email'] ) && !empty( $_POST['email'] ) ) {
712
+ $email = trim( sanitize_text_field( $_POST['email'] ) );
713
+ $banned_emails = preg_split( '/\r\n|\r|\n/', (string) $rtb_controller->settings->get_setting( 'ban-emails' ) );
714
+
715
+ if ( !in_array( $email, $banned_emails ) ) {
716
+ $banned_emails[] = $email;
717
+ $rtb_controller->settings->settings['ban-emails'] = join( "\n", $banned_emails );
718
+ update_option( 'rtb-settings', $rtb_controller->settings->settings );
719
+ }
720
+
721
+ wp_send_json_success();
722
+
723
+ // Ban an IP address
724
+ } elseif ( isset( $_POST['ip'] ) && !empty( $_POST['ip'] ) ) {
725
+ $ip = trim( sanitize_text_field( $_POST['ip'] ) );
726
+ $banned_ips = preg_split( '/\r\n|\r|\n/', (string) $rtb_controller->settings->get_setting( 'ban-ips' ) );
727
+
728
+ if ( !in_array( $ip, $banned_ips ) ) {
729
+ $banned_ips[] = $ip;
730
+ $rtb_controller->settings->settings['ban-ips'] = join( "\n", $banned_ips );
731
+ update_option( 'rtb-settings', $rtb_controller->settings->settings );
732
+ }
733
+
734
+ wp_send_json_success();
735
+ }
736
+
737
+ wp_send_json_error(
738
+ array(
739
+ 'error' => 'no_data',
740
+ 'msg' => __( 'No IP or email address could be found for this ban request.', 'restaurant-reservations' ),
741
+ )
742
+ );
743
+ }
744
+
745
/**
746
* Validate post status and notification fields
747
* @since 1.3
includes/Booking.class.php CHANGED
@@ -80,6 +80,7 @@ class rtbBooking {
80
'phone' => '',
81
'date_submission' => '',
82
'logs' => array(),
83
);
84
85
$meta_defaults = apply_filters( 'rtb_booking_metadata_defaults', $meta_defaults );
@@ -95,6 +96,7 @@ class rtbBooking {
95
$this->phone = $meta['phone'];
96
$this->date_submission = $meta['date_submission'];
97
$this->logs = $meta['logs'];
98
}
99
100
/**
@@ -243,6 +245,15 @@ class rtbBooking {
243
);
244
}
245
246
} else {
247
$late_bookings_seconds = $late_bookings * 60; // Late bookings allowance in seconds
248
if ( $request->format( 'U' ) < ( current_time( 'timestamp' ) + $late_bookings_seconds ) ) {
@@ -264,7 +275,7 @@ class rtbBooking {
264
265
// Check against scheduling exception rules
266
$exceptions = $rtb_controller->settings->get_setting( 'schedule-closed' );
267
- if ( empty( $this->validation_errors ) && !empty( $exceptions ) ) {
268
$exception_is_active = false;
269
$datetime_is_valid = false;
270
foreach( $exceptions as $exception ) {
@@ -298,7 +309,7 @@ class rtbBooking {
298
299
// Check against weekly scheduling rules
300
$rules = $rtb_controller->settings->get_setting( 'schedule-open' );
301
- if ( empty( $exception_is_active ) && empty( $this->validation_errors ) && !empty( $rules ) ) {
302
$request_weekday = strtolower( $request->format( 'l' ) );
303
$time_is_valid = null;
304
$day_is_valid = null;
@@ -394,6 +405,14 @@ class rtbBooking {
394
'message' => sprintf( __( 'We only accept bookings for parties of up to %d people.', 'restaurant-reservations' ), $party_size ),
395
);
396
}
397
}
398
399
// Email/Phone
@@ -429,6 +448,22 @@ class rtbBooking {
429
}
430
}
431
432
do_action( 'rtb_validate_booking_submission', $this );
433
434
}
@@ -482,6 +517,64 @@ class rtbBooking {
482
return false;
483
}
484
485
/**
486
* Add a log entry to the booking
487
*
@@ -534,6 +627,7 @@ class rtbBooking {
534
'email' => $this->email,
535
'phone' => $this->phone,
536
'date_submission' => current_time( 'timestamp' ),
537
);
538
539
if ( !empty( $this->logs ) ) {
80
'phone' => '',
81
'date_submission' => '',
82
'logs' => array(),
83
+ 'ip' => '',
84
);
85
86
$meta_defaults = apply_filters( 'rtb_booking_metadata_defaults', $meta_defaults );
96
$this->phone = $meta['phone'];
97
$this->date_submission = $meta['date_submission'];
98
$this->logs = $meta['logs'];
99
+ $this->ip = $meta['ip'];
100
}
101
102
/**
245
);
246
}
247
248
+ } elseif ( $late_bookings === 'same_day' ) {
249
+ if ( $request->format( 'Y-m-d' ) == current_time( 'Y-m-d' ) ) {
250
+ $this->validation_errors[] = array(
251
+ 'field' => 'time',
252
+ 'error_msg' => 'Booking request made on same day',
253
+ 'message' => __( 'Sorry, bookings can not be made for the same day.', 'restaurant-reservations' ),
254
+ );
255
+ }
256
+
257
} else {
258
$late_bookings_seconds = $late_bookings * 60; // Late bookings allowance in seconds
259
if ( $request->format( 'U' ) < ( current_time( 'timestamp' ) + $late_bookings_seconds ) ) {
275
276
// Check against scheduling exception rules
277
$exceptions = $rtb_controller->settings->get_setting( 'schedule-closed' );
278
+ if ( empty( $this->validation_errors ) && !empty( $exceptions ) && !current_user_can( 'manage_bookings' ) ) {
279
$exception_is_active = false;
280
$datetime_is_valid = false;
281
foreach( $exceptions as $exception ) {
309
310
// Check against weekly scheduling rules
311
$rules = $rtb_controller->settings->get_setting( 'schedule-open' );
312
+ if ( empty( $exception_is_active ) && empty( $this->validation_errors ) && !empty( $rules ) && !current_user_can( 'manage_bookings' ) ) {
313
$request_weekday = strtolower( $request->format( 'l' ) );
314
$time_is_valid = null;
315
$day_is_valid = null;
405
'message' => sprintf( __( 'We only accept bookings for parties of up to %d people.', 'restaurant-reservations' ), $party_size ),
406
);
407
}
408
+ $party_size_min = $rtb_controller->settings->get_setting( 'party-size-min' );
409
+ if ( !empty( $party_size_min ) && $party_size_min > $this->party ) {
410
+ $this->validation_errors[] = array(
411
+ 'field' => 'party',
412
+ 'post_variable' => $this->party,
413
+ 'message' => sprintf( __( 'We only accept bookings for parties of more than %d people.', 'restaurant-reservations' ), $party_size_min ),
414
+ );
415
+ }
416
}
417
418
// Email/Phone
448
}
449
}
450
451
+ // Check if the email or IP is banned
452
+ if ( !current_user_can( 'manage_bookings' ) ) {
453
+ $ip = $_SERVER['REMOTE_ADDR'];
454
+ if ( !$this->is_valid_ip( $ip ) || !$this->is_valid_email( $this->email ) ) {
455
+ $this->validation_errors[] = array(
456
+ 'field' => 'date',
457
+ 'post_variable' => $ip,
458
+ 'message' => __( 'Your booking has been rejected. Please call us if you would like to make a booking.', 'restaurant-reservations' ),
459
+ );
460
+ } elseif ( empty( $this->ip ) ) {
461
+ $this->ip = sanitize_text_field( $ip );
462
+ }
463
+ } elseif ( empty( $this->ip ) ) {
464
+ $this->ip = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
465
+ }
466
+
467
do_action( 'rtb_validate_booking_submission', $this );
468
469
}
517
return false;
518
}
519
520
+ /**
521
+ * Check if an IP address has been banned
522
+ *
523
+ * @param string $ip
524
+ * @return bool
525
+ * @since 1.7
526
+ */
527
+ public function is_valid_ip( $ip = null ) {
528
+
529
+ if ( is_null( $ip ) ) {
530
+ $ip = isset( $this->ip ) ? $this->ip : null;
531
+ if ( is_null( $ip ) ) {
532
+ return false;
533
+ }
534
+ }
535
+
536
+ global $rtb_controller;
537
+
538
+ $banned_ips = array_filter( explode( "\n", $rtb_controller->settings->get_setting( 'ban-ips' ) ) );
539
+
540
+ foreach( $banned_ips as $banned_ip ) {
541
+ if ( $ip == trim( $banned_ip ) ) {
542
+ return false;
543
+ }
544
+ }
545
+
546
+ return true;
547
+ }
548
+
549
+ /**
550
+ * Check if an email address has been banned
551
+ *
552
+ * @param string $email
553
+ * @return bool
554
+ * @since 1.7
555
+ */
556
+ public function is_valid_email( $email = null ) {
557
+
558
+ if ( is_null( $email ) ) {
559
+ $email = isset( $this->email ) ? $this->email : null;
560
+ if ( is_null( $email ) ) {
561
+ return false;
562
+ }
563
+ }
564
+
565
+ global $rtb_controller;
566
+
567
+ $banned_emails = array_filter( explode( "\n", $rtb_controller->settings->get_setting( 'ban-emails' ) ) );
568
+
569
+ foreach( $banned_emails as $banned_email ) {
570
+ if ( $email == trim( $banned_email ) ) {
571
+ return false;
572
+ }
573
+ }
574
+
575
+ return true;
576
+ }
577
+
578
/**
579
* Add a log entry to the booking
580
*
627
'email' => $this->email,
628
'phone' => $this->phone,
629
'date_submission' => current_time( 'timestamp' ),
630
+ 'ip' => $this->ip,
631
);
632
633
if ( !empty( $this->logs ) ) {
includes/Compatibility.class.php CHANGED
@@ -15,9 +15,10 @@ class rtbCompatibility {
15
*/
16
public function __construct() {
17
18
- // Preserve this defined constant in case anyone relied on it
19
// to check if the plugin was active
20
define( 'RTB_TEXTDOMAIN', 'rtbdomain' );
21
22
// Load a .mo file for an old textdomain if one exists
23
add_filter( 'load_textdomain_mofile', array( $this, 'load_old_textdomain' ), 10, 2 );
15
*/
16
public function __construct() {
17
18
+ // Preserve defined constants in case anyone relied on them
19
// to check if the plugin was active
20
define( 'RTB_TEXTDOMAIN', 'rtbdomain' );
21
+ define( 'RTB_LOAD_FRONTEND_ASSETS', apply_filters( 'rtb-load-frontend-assets', true ) );
22
23
// Load a .mo file for an old textdomain if one exists
24
add_filter( 'load_textdomain_mofile', array( $this, 'load_old_textdomain' ), 10, 2 );
includes/MultipleLocations.class.php CHANGED
@@ -81,7 +81,6 @@ if ( ! class_exists( 'rtbMultipleLocations', false ) ) {
81
add_filter( 'rtb_query_args', array( $this, 'modify_query' ), 10, 2 );
82
add_filter( 'rtb_bookings_all_table_columns', array( $this, 'add_location_column' ) );
83
add_filter( 'rtb_bookings_table_column', array( $this, 'print_location_column' ), 10, 3 );
84
- add_filter( 'rtb_bookings_table_column_details', array( $this, 'add_details_column_items' ), 10, 2 );
85
add_action( 'edit_form_after_title', array( $this, 'add_meta_nonce' ) );
86
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
87
add_filter( 'the_content', array( $this, 'append_to_content' ) );
@@ -431,32 +430,6 @@ if ( ! class_exists( 'rtbMultipleLocations', false ) ) {
431
return $location->name;
432
}
433
434
- /**
435
- * Add the location to the details column if the column has been
436
- * hidden
437
- *
438
- * @since 1.6
439
- */
440
- public function add_details_column_items( $details, $booking ) {
441
-
442
- global $rtb_controller;
443
-
444
- $visible_columns = $rtb_controller->bookings->bookings_table->get_columns();
445
- if ( !isset( $visible_columns['location'] ) ) {
446
-
447
- $value = $rtb_controller->bookings->bookings_table->column_default( $booking, 'location' );
448
-
449
- if ( !empty( $value ) ) {
450
- $details[] = array(
451
- 'label' => __( 'Location', 'restaurant-reservations' ),
452
- 'value' => $value,
453
- );
454
- }
455
- }
456
-
457
- return $details;
458
- }
459
-
460
/**
461
* Modify queries to add location taxonomy parameters
462
*
81
add_filter( 'rtb_query_args', array( $this, 'modify_query' ), 10, 2 );
82
add_filter( 'rtb_bookings_all_table_columns', array( $this, 'add_location_column' ) );
83
add_filter( 'rtb_bookings_table_column', array( $this, 'print_location_column' ), 10, 3 );
84
add_action( 'edit_form_after_title', array( $this, 'add_meta_nonce' ) );
85
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
86
add_filter( 'the_content', array( $this, 'append_to_content' ) );
430
return $location->name;
431
}
432
433
/**
434
* Modify queries to add location taxonomy parameters
435
*
includes/Notifications.class.php CHANGED
@@ -171,7 +171,9 @@ class rtbNotifications {
171
if ( $event == $notification->event ) {
172
$notification->set_booking( $this->booking );
173
if ( $notification->prepare_notification() ) {
174
$notification->send_notification();
175
}
176
}
177
}
171
if ( $event == $notification->event ) {
172
$notification->set_booking( $this->booking );
173
if ( $notification->prepare_notification() ) {
174
+ do_action( 'rtb_send_notification_before', $notification );
175
$notification->send_notification();
176
+ do_action( 'rtb_send_notification_after', $notification );
177
}
178
}
179
}
includes/Settings.class.php CHANGED
@@ -90,8 +90,8 @@ class rtbSettings {
90
$this->defaults = array(
91
92
'success-message' => _x( 'Thanks, your booking request is waiting to be confirmed. Updates will be sent to the email address you provided.', 'restaurant-reservations' ),
93
- 'date-format' => _x( 'mmmm d, yyyy', 'Default date format for display. Must match formatting rules at http://amsul.ca/pickadate.js/date.htm#formatting-rules', 'restaurant-reservations' ),
94
- 'time-format' => _x( 'h:i A', 'Default time format for display. Must match formatting rules at http://amsul.ca/pickadate.js/time.htm#formats', 'restaurant-reservations' ),
95
'time-interval' => _x( '30', 'Default interval in minutes when selecting a time.', 'restaurant-reservations' ),
96
97
// Email address where admin notifications should be sent
@@ -262,6 +262,19 @@ Sorry, we could not accomodate your booking request. We\'re full or not open at
262
)
263
);
264
265
$sap->add_setting(
266
'rtb-settings',
267
'rtb-general',
@@ -294,7 +307,7 @@ Sorry, we could not accomodate your booking request. We\'re full or not open at
294
array(
295
'id' => 'date-format',
296
'title' => __( 'Date Format', 'restaurant-reservations' ),
297
- 'description' => sprintf( __( 'Define how the date is formatted on the booking form. %sFormatting rules%s. This only changes the format on the booking form. To change the date format in notification messages, modify your general %sWordPress Settings%s.', 'restaurant-reservations' ), '<a href="http://amsul.ca/pickadate.js/date.htm#formatting-rules">', '</a>', '<a href="' . admin_url( 'options-general.php' ) . '">', '</a>' ),
298
'placeholder' => $this->defaults['date-format'],
299
)
300
);
@@ -306,13 +319,13 @@ Sorry, we could not accomodate your booking request. We\'re full or not open at
306
array(
307
'id' => 'time-format',
308
'title' => __( 'Time Format', 'restaurant-reservations' ),
309
- 'description' => sprintf( __( 'Define how the time is formatted on the booking form. %sFormatting rules%s. This only changes the format on the booking form. To change the time format in notification messages, modify your general %sWordPress Settings%s.', 'restaurant-reservations' ), '<a href="http://amsul.ca/pickadate.js/time.htm#formatting-rules">', '</a>', '<a href="' . admin_url( 'options-general.php' ) . '">', '</a>' ),
310
'placeholder' => $this->defaults['time-format'],
311
)
312
);
313
314
// Add i8n setting for pickadate if the frontend assets are to be loaded
315
- if ( RTB_LOAD_FRONTEND_ASSETS ) {
316
$sap->add_setting(
317
'rtb-settings',
318
'rtb-general',
@@ -326,6 +339,28 @@ Sorry, we could not accomodate your booking request. We\'re full or not open at
326
);
327
}
328
329
$sap->add_section(
330
'rtb-settings',
331
array(
@@ -434,13 +469,14 @@ Sorry, we could not accomodate your booking request. We\'re full or not open at
434
'description' => __( 'Select how late customers can make their booking. (Administrators and Booking Managers are not restricted by this setting.)', 'restaurant-reservations' ),
435
'blank_option' => false,
436
'options' => array(
437
- '' => __( 'Up to the last minute', 'restaurant-reservations' ),
438
- '15' => __( 'At least 15 minutes in advance', 'restaurant-reservations' ),
439
- '30' => __( 'At least 30 minutes in advance', 'restaurant-reservations' ),
440
- '45' => __( 'At least 45 minutes in advance', 'restaurant-reservations' ),
441
- '60' => __( 'At least 1 hour in advance', 'restaurant-reservations' ),
442
- '240' => __( 'At least 4 hours in advance', 'restaurant-reservations' ),
443
- '1440' => __( 'At least 1 day in advance', 'restaurant-reservations' ),
444
)
445
)
446
);
@@ -693,11 +729,13 @@ Sorry, we could not accomodate your booking request. We\'re full or not open at
693
* Get options for the party size setting
694
* @since 1.3
695
*/
696
- public function get_party_size_setting_options() {
697
698
- $options = array(
699
- '' => __( 'Any size', 'restaurant-reservations' ),
700
- );
701
702
$max = apply_filters( 'rtb_party_size_upper_limit', 100 );
703
@@ -715,10 +753,12 @@ Sorry, we could not accomodate your booking request. We\'re full or not open at
715
public function get_form_party_options() {
716
717
$party_size = (int) $this->get_setting( 'party-size' );
718
719
$max = empty( $party_size ) ? apply_filters( 'rtb_party_size_upper_limit', 100 ) : (int) $this->get_setting( 'party-size' );
720
721
- for ( $i = 1; $i <= $max; $i++ ) {
722
$options[$i] = $i;
723
}
724
90
$this->defaults = array(
91
92
'success-message' => _x( 'Thanks, your booking request is waiting to be confirmed. Updates will be sent to the email address you provided.', 'restaurant-reservations' ),
93
+ 'date-format' => _x( 'mmmm d, yyyy', 'Default date format for display. Must match formatting rules at http://amsul.ca/pickadate.js/date/#formats', 'restaurant-reservations' ),
94
+ 'time-format' => _x( 'h:i A', 'Default time format for display. Must match formatting rules at http://amsul.ca/pickadate.js/time/#formats', 'restaurant-reservations' ),
95
'time-interval' => _x( '30', 'Default interval in minutes when selecting a time.', 'restaurant-reservations' ),
96
97
// Email address where admin notifications should be sent
262
)
263
);
264
265
+ $sap->add_setting(
266
+ 'rtb-settings',
267
+ 'rtb-general',
268
+ 'select',
269
+ array(
270
+ 'id' => 'party-size-min',
271
+ 'title' => __( 'Min Party Size', 'restaurant-reservations' ),
272
+ 'description' => __( 'Set a minimum allowed party size for bookings.', 'restaurant-reservations' ),
273
+ 'blank_option' => false,
274
+ 'options' => $this->get_party_size_setting_options( false ),
275
+ )
276
+ );
277
+
278
$sap->add_setting(
279
'rtb-settings',
280
'rtb-general',
307
array(
308
'id' => 'date-format',
309
'title' => __( 'Date Format', 'restaurant-reservations' ),
310
+ 'description' => sprintf( __( 'Define how the date is formatted on the booking form. %sFormatting rules%s. This only changes the format on the booking form. To change the date format in notification messages, modify your general %sWordPress Settings%s.', 'restaurant-reservations' ), '<a href="http://amsul.ca/pickadate.js/date/#formats">', '</a>', '<a href="' . admin_url( 'options-general.php' ) . '">', '</a>' ),
311
'placeholder' => $this->defaults['date-format'],
312
)
313
);
319
array(
320
'id' => 'time-format',
321
'title' => __( 'Time Format', 'restaurant-reservations' ),
322
+ 'description' => sprintf( __( 'Define how the time is formatted on the booking form. %sFormatting rules%s. This only changes the format on the booking form. To change the time format in notification messages, modify your general %sWordPress Settings%s.', 'restaurant-reservations' ), '<a href="http://amsul.ca/pickadate.js/time/#formats">', '</a>', '<a href="' . admin_url( 'options-general.php' ) . '">', '</a>' ),
323
'placeholder' => $this->defaults['time-format'],
324
)
325
);
326
327
// Add i8n setting for pickadate if the frontend assets are to be loaded
328
+ if ( apply_filters( 'rtb-load-frontend-assets', true ) ) {
329
$sap->add_setting(
330
'rtb-settings',
331
'rtb-general',
339
);
340
}
341
342
+ $sap->add_setting(
343
+ 'rtb-settings',
344
+ 'rtb-general',
345
+ 'textarea',
346
+ array(
347
+ 'id' => 'ban-emails',
348
+ 'title' => __( 'Banned Email Addresses', 'restaurant-reservations' ),
349
+ 'description' => __( 'You can block bookings from specific email addresses. Enter each email address on a separate line.', 'restaurant-reservations' ),
350
+ )
351
+ );
352
+
353
+ $sap->add_setting(
354
+ 'rtb-settings',
355
+ 'rtb-general',
356
+ 'textarea',
357
+ array(
358
+ 'id' => 'ban-ips',
359
+ 'title' => __( 'Banned IP Addresses', 'restaurant-reservations' ),
360
+ 'description' => __( 'You can block bookings from specific IP addresses. Enter each IP address on a separate line. Be aware that many internet providers rotate their IP address assignments, so an IP address may accidentally refer to a different user. Also, if you block an IP address used by a public connection, such as cafe WIFI, a public library, or a university network, you may inadvertantly block several people.', 'restaurant-reservations' ),
361
+ )
362
+ );
363
+
364
$sap->add_section(
365
'rtb-settings',
366
array(
469
'description' => __( 'Select how late customers can make their booking. (Administrators and Booking Managers are not restricted by this setting.)', 'restaurant-reservations' ),
470
'blank_option' => false,
471
'options' => array(
472
+ '' => __( 'Up to the last minute', 'restaurant-reservations' ),
473
+ '15' => __( 'At least 15 minutes in advance', 'restaurant-reservations' ),
474
+ '30' => __( 'At least 30 minutes in advance', 'restaurant-reservations' ),
475
+ '45' => __( 'At least 45 minutes in advance', 'restaurant-reservations' ),
476
+ '60' => __( 'At least 1 hour in advance', 'restaurant-reservations' ),
477
+ '240' => __( 'At least 4 hours in advance', 'restaurant-reservations' ),
478
+ '1440' => __( 'At least 24 hours in advance', 'restaurant-reservations' ),
479
+ 'same_day' => __( 'Block same-day bookings', 'restaurant-reservations' ),
480
)
481
)
482
);
729
* Get options for the party size setting
730
* @since 1.3
731
*/
732
+ public function get_party_size_setting_options( $max = true ) {
733
734
+ $options = array();
735
+
736
+ if ( $max ) {
737
+ $options[''] = __( 'Any size', 'restaurant-reservations' );
738
+ }
739
740
$max = apply_filters( 'rtb_party_size_upper_limit', 100 );
741
753
public function get_form_party_options() {
754
755
$party_size = (int) $this->get_setting( 'party-size' );
756
+ $party_size_min = (int) $this->get_setting( 'party-size-min' );
757
758
+ $min = empty( $party_size_min ) ? 1 : (int) $this->get_setting( 'party-size-min' );
759
$max = empty( $party_size ) ? apply_filters( 'rtb_party_size_upper_limit', 100 ) : (int) $this->get_setting( 'party-size' );
760
761
+ for ( $i = $min; $i <= $max; $i++ ) {
762
$options[$i] = $i;
763
}
764
includes/WP_List_Table.BookingsTable.class.php CHANGED
@@ -323,6 +323,7 @@ class rtbBookingsTable extends WP_List_Table {
323
}
324
325
$all_default_columns = $this->get_all_default_columns();
326
327
global $rtb_controller;
328
$visible_columns = $rtb_controller->settings->get_setting( 'bookings-table-columns' );
@@ -333,9 +334,9 @@ class rtbBookingsTable extends WP_List_Table {
333
$columns['cb'] = $all_default_columns['cb'];
334
$columns['date'] = $all_default_columns['date'];
335
336
- foreach( $all_default_columns as $key => $column ) {
337
if ( in_array( $key, $visible_columns ) ) {
338
- $columns[$key] = $all_default_columns[$key];
339
}
340
}
341
$columns['details'] = $all_default_columns['details'];
@@ -374,6 +375,7 @@ class rtbBookingsTable extends WP_List_Table {
374
*/
375
public function get_all_columns() {
376
$columns = $this->get_all_default_columns();
377
return apply_filters( 'rtb_bookings_all_table_columns', $columns );
378
}
379
@@ -394,6 +396,7 @@ class rtbBookingsTable extends WP_List_Table {
394
* @since 0.0.1
395
*/
396
public function column_default( $booking, $column_name ) {
397
switch ( $column_name ) {
398
case 'date' :
399
$value = $booking->format_date( $booking->date );
@@ -407,21 +410,26 @@ class rtbBookingsTable extends WP_List_Table {
407
}
408
409
break;
410
case 'party' :
411
$value = $booking->party;
412
break;
413
case 'name' :
414
$value = $booking->name;
415
break;
416
case 'email' :
417
$value = $booking->email;
418
$value .= '<div class="actions">';
419
$value .= '<a href="#" data-id="' . esc_attr( $booking->ID ) . '" data-action="email" data-email="' . esc_attr( $booking->email ) . '" data-name="' . $booking->name . '">' . __( 'Send Email', 'restaurant-reservations' ) . '</a>';
420
$value .= '</div>';
421
break;
422
case 'phone' :
423
$value = $booking->phone;
424
break;
425
case 'status' :
426
global $rtb_controller;
427
if ( !empty( $rtb_controller->cpts->booking_statuses[$booking->post_status] ) ) {
@@ -432,6 +440,7 @@ class rtbBookingsTable extends WP_List_Table {
432
$value = $booking->post_status;
433
}
434
break;
435
case 'details' :
436
$value = '';
437
@@ -454,6 +463,18 @@ class rtbBookingsTable extends WP_List_Table {
454
$value .= '</ul></div>';
455
}
456
break;
457
default:
458
$value = isset( $booking->$column_name ) ? $booking->$column_name : '';
459
break;
@@ -485,29 +506,22 @@ class rtbBookingsTable extends WP_List_Table {
485
*/
486
public function add_details_column_items( $details, $booking ) {
487
global $rtb_controller;
488
- $visible_columns = $this->get_all_columns();
489
- $default_columns = $this->get_all_default_columns();
490
-
491
- $detail_columns = array_diff( $visible_columns, $default_columns );
492
493
- // Columns which can't be hidden
494
- unset( $default_columns['cb'] );
495
- unset( $default_columns['details'] );
496
- unset( $default_columns['date'] );
497
498
- if ( !empty( $detail_columns ) ) {
499
- foreach( $detail_columns as $key => $label ) {
500
-
501
- $value = $this->column_default( $booking, $key );
502
- if ( empty( $value ) ) {
503
- continue;
504
- }
505
506
- $details[] = array(
507
- 'label' => $label,
508
- 'value' => $value,
509
- );
510
}
511
}
512
513
return $details;
@@ -887,6 +901,12 @@ class rtbBookingsTable extends WP_List_Table {
887
$query = new rtbQuery( $args, 'bookings-table' );
888
$query->parse_request_args();
889
$query->prepare_args();
890
$query->args = apply_filters( 'rtb_bookings_table_query_args', $query->args );
891
892
$this->bookings = $query->get_bookings();
323
}
324
325
$all_default_columns = $this->get_all_default_columns();
326
+ $all_columns = $this->get_all_columns();
327
328
global $rtb_controller;
329
$visible_columns = $rtb_controller->settings->get_setting( 'bookings-table-columns' );
334
$columns['cb'] = $all_default_columns['cb'];
335
$columns['date'] = $all_default_columns['date'];
336
337
+ foreach( $all_columns as $key => $column ) {
338
if ( in_array( $key, $visible_columns ) ) {
339
+ $columns[$key] = $all_columns[$key];
340
}
341
}
342
$columns['details'] = $all_default_columns['details'];
375
*/
376
public function get_all_columns() {
377
$columns = $this->get_all_default_columns();
378
+ $columns['submitted-by'] = __( 'Submitted By', 'restaurant-reservations' );
379
return apply_filters( 'rtb_bookings_all_table_columns', $columns );
380
}
381
396
* @since 0.0.1
397
*/
398
public function column_default( $booking, $column_name ) {
399
+
400
switch ( $column_name ) {
401
case 'date' :
402
$value = $booking->format_date( $booking->date );
410
}
411
412
break;
413
+
414
case 'party' :
415
$value = $booking->party;
416
break;
417
+
418
case 'name' :
419
$value = $booking->name;
420
break;
421
+
422
case 'email' :
423
$value = $booking->email;
424
$value .= '<div class="actions">';
425
$value .= '<a href="#" data-id="' . esc_attr( $booking->ID ) . '" data-action="email" data-email="' . esc_attr( $booking->email ) . '" data-name="' . $booking->name . '">' . __( 'Send Email', 'restaurant-reservations' ) . '</a>';
426
$value .= '</div>';
427
break;
428
+
429
case 'phone' :
430
$value = $booking->phone;
431
break;
432
+
433
case 'status' :
434
global $rtb_controller;
435
if ( !empty( $rtb_controller->cpts->booking_statuses[$booking->post_status] ) ) {
440
$value = $booking->post_status;
441
}
442
break;
443
+
444
case 'details' :
445
$value = '';
446
463
$value .= '</ul></div>';
464
}
465
break;
466
+
467
+ case 'submitted-by' :
468
+ $ip = !empty( $booking->ip ) ? $booking->ip : __( 'Unknown IP', 'restaurant-reservations' );
469
+ $date_submission = isset( $booking->date_submission ) ? $booking->format_date( $booking->date_submission ) : __( 'Unknown Date', 'restaurant-reservations' );
470
+ $value = sprintf( esc_html__( 'Request from %s on %s.', 'restaurant-reservations' ), $ip, $date_submission );
471
+ $value .= '<div class="actions">';
472
+ $value .= '<a href="#" data-action="ban" data-email="' . esc_attr( $booking->email ) . '" data-id="' . absint( $booking->ID ) . '" data-ip="' . $ip . '">';
473
+ $value .= __( 'Ban Customer', 'restaurant-reservations' );
474
+ $value .= '</a>';
475
+ $value .= '</div>';
476
+ break;
477
+
478
default:
479
$value = isset( $booking->$column_name ) ? $booking->$column_name : '';
480
break;
506
*/
507
public function add_details_column_items( $details, $booking ) {
508
global $rtb_controller;
509
+ $visible_columns = $this->get_columns();
510
+ $all_columns = $this->get_all_columns();
511
512
+ $detail_columns = array_diff( $all_columns, $visible_columns );
513
514
+ foreach( $detail_columns as $key => $label ) {
515
516
+ $value = $this->column_default( $booking, $key );
517
+ if ( empty( $value ) ) {
518
+ continue;
519
}
520
+
521
+ $details[] = array(
522
+ 'label' => $label,
523
+ 'value' => $value,
524
+ );
525
}
526
527
return $details;
901
$query = new rtbQuery( $args, 'bookings-table' );
902
$query->parse_request_args();
903
$query->prepare_args();
904
+
905
+ // Sort all bookings by newest first if no specific orderby is in play
906
+ if ( $query->args['date_range'] == 'all' && !isset( $_REQUEST['orderby'] ) ) {
907
+ $query->args['order'] = 'DESC';
908
+ }
909
+
910
$query->args = apply_filters( 'rtb_bookings_table_query_args', $query->args );
911
912
$this->bookings = $query->get_bookings();
includes/integrations/business-profile.php CHANGED
@@ -14,7 +14,7 @@ function rtb_bp_maybe_enable_bp_locations( $post_type ) {
14
}
15
16
global $bpfwp_controller;
17
- if ( isset( $bpfwp_controller ) && isset( $bpfwp_controller->cpts ) ) {
18
return $bpfwp_controller->cpts->location_cpt_slug;
19
}
20
14
}
15
16
global $bpfwp_controller;
17
+ if ( isset( $bpfwp_controller ) && isset( $bpfwp_controller->cpts ) && $bpfwp_controller->settings->get_setting( 'multiple-locations' ) ) {
18
return $bpfwp_controller->cpts->location_cpt_slug;
19
}
20
includes/template-functions.php CHANGED
@@ -110,7 +110,11 @@ function rtb_print_booking_form( $args = array() ) {
110
<?php
111
foreach( $contents['fields'] as $slug => $field ) {
112
113
- $args = empty( $field['callback_args'] ) ? null : $field['callback_args'];
114
115
call_user_func( $field['callback'], $slug, $field['title'], $field['request_input'], $args );
116
}
@@ -172,17 +176,21 @@ function rtb_enqueue_assets() {
172
wp_localize_script(
173
'rtb-booking-form',
174
'rtb_pickadate',
175
- array(
176
- 'date_format' => $rtb_controller->settings->get_setting( 'date-format' ),
177
- 'time_format' => $rtb_controller->settings->get_setting( 'time-format' ),
178
- 'disable_dates' => rtb_get_datepicker_rules(),
179
- 'schedule_open' => $rtb_controller->settings->get_setting( 'schedule-open' ),
180
- 'schedule_closed' => $rtb_controller->settings->get_setting( 'schedule-closed' ),
181
- 'early_bookings' => current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'early-bookings' ),
182
- 'late_bookings' => current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'late-bookings' ),
183
- 'date_onload' => $rtb_controller->settings->get_setting( 'date-onload' ),
184
- 'time_interval' => $rtb_controller->settings->get_setting( 'time-interval' ),
185
- 'first_day' => $rtb_controller->settings->get_setting( 'week-start' ),
186
)
187
);
188
@@ -191,7 +199,7 @@ function rtb_enqueue_assets() {
191
192
/**
193
* Get rules for datepicker date ranges
194
- * See: http://amsul.ca/pickadate.js/date.htm#disable-dates
195
* @since 0.0.1
196
*/
197
if ( !function_exists( 'rtb_get_datepicker_rules' ) ) {
@@ -269,6 +277,7 @@ function rtb_print_form_text_field( $slug, $title, $value, $args = array() ) {
269
$type = empty( $args['input_type'] ) ? 'text' : esc_attr( $args['input_type'] );
270
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
271
$classes[] = 'rtb-text';
272
273
?>
274
@@ -277,7 +286,7 @@ function rtb_print_form_text_field( $slug, $title, $value, $args = array() ) {
277
<label for="rtb-<?php echo $slug; ?>">
278
<?php echo $title; ?>
279
</label>
280
- <input type="<?php echo $type; ?>" name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>" value="<?php echo $value; ?>">
281
</div>
282
283
<?php
@@ -297,6 +306,7 @@ function rtb_print_form_textarea_field( $slug, $title, $value, $args = array() )
297
$value = preg_replace('/\<br(\s*)?\/?\>/i', '', $value);
298
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
299
$classes[] = 'rtb-textarea';
300
301
?>
302
@@ -305,7 +315,7 @@ function rtb_print_form_textarea_field( $slug, $title, $value, $args = array() )
305
<label for="rtb-<?php echo $slug; ?>">
306
<?php echo $title; ?>
307
</label>
308
- <textarea name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>"><?php echo $value; ?></textarea>
309
</div>
310
311
<?php
@@ -325,6 +335,7 @@ function rtb_print_form_select_field( $slug, $title, $value, $args ) {
325
$options = is_array( $args['options'] ) ? $args['options'] : array();
326
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
327
$classes[] = 'rtb-select';
328
329
?>
330
@@ -333,7 +344,7 @@ function rtb_print_form_select_field( $slug, $title, $value, $args ) {
333
<label for="rtb-<?php echo $slug; ?>">
334
<?php echo $title; ?>
335
</label>
336
- <select name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>">
337
<?php foreach ( $options as $opt_value => $opt_label ) : ?>
338
<option value="<?php echo esc_attr( $opt_value ); ?>" <?php selected( $opt_value, $value ); ?>><?php echo esc_attr( $opt_label ); ?></option>
339
<?php endforeach; ?>
@@ -348,7 +359,6 @@ function rtb_print_form_select_field( $slug, $title, $value, $args ) {
348
/**
349
* Print a checkbox form field
350
*
351
- * @uses rtb_print_form_tick_field
352
* @since 1.3.1
353
*/
354
if ( !function_exists( 'rtb_print_form_checkbox_field' ) ) {
@@ -382,7 +392,6 @@ function rtb_print_form_checkbox_field( $slug, $title, $value, $args ) {
382
/**
383
* Print a radio button form field
384
*
385
- * @uses rtb_print_form_tick_field
386
* @since 1.3.1
387
*/
388
if ( !function_exists( 'rtb_print_form_radio_field' ) ) {
@@ -393,6 +402,7 @@ function rtb_print_form_radio_field( $slug, $title, $value, $args ) {
393
$options = is_array( $args['options'] ) ? $args['options'] : array();
394
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
395
$classes[] = 'rtb-radio';
396
397
?>
398
@@ -403,7 +413,7 @@ function rtb_print_form_radio_field( $slug, $title, $value, $args ) {
403
</label>
404
<?php foreach ( $options as $opt_value => $opt_label ) : ?>
405
<label>
406
- <input type="radio" name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>" value="<?php echo esc_attr( $opt_value ); ?>" <?php checked( $opt_value, $value ); ?>>
407
<?php echo $opt_label; ?>
408
</label>
409
<?php endforeach; ?>
@@ -425,13 +435,14 @@ function rtb_print_form_confirm_field( $slug, $title, $value, $args ) {
425
$value = esc_attr( $value );
426
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
427
$classes[] = 'rtb-confirm';
428
429
?>
430
431
<div <?php echo rtb_print_element_class( $slug, $classes ); ?>>
432
<?php echo rtb_print_form_error( $slug ); ?>
433
<label for="rtb-<?php echo $slug; ?>">
434
- <input type="checkbox" name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>" value="1" <?php checked( $value, 1 ); ?>>
435
<?php echo $title; ?>
436
</label>
437
</div>
110
<?php
111
foreach( $contents['fields'] as $slug => $field ) {
112
113
+ $args = empty( $field['callback_args'] ) ? array() : $field['callback_args'];
114
+
115
+ if ( !empty( $field['required'] ) ) {
116
+ $args = array_merge( $args, array( 'required' => $field['required'] ) );
117
+ }
118
119
call_user_func( $field['callback'], $slug, $field['title'], $field['request_input'], $args );
120
}
176
wp_localize_script(
177
'rtb-booking-form',
178
'rtb_pickadate',
179
+ apply_filters(
180
+ 'rtb_pickadate_args',
181
+ array(
182
+ 'date_format' => $rtb_controller->settings->get_setting( 'date-format' ),
183
+ 'time_format' => $rtb_controller->settings->get_setting( 'time-format' ),
184
+ 'disable_dates' => rtb_get_datepicker_rules(),
185
+ 'schedule_open' => $rtb_controller->settings->get_setting( 'schedule-open' ),
186
+ 'schedule_closed' => $rtb_controller->settings->get_setting( 'schedule-closed' ),
187
+ 'early_bookings' => is_admin() && current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'early-bookings' ),
188
+ 'late_bookings' => is_admin() && current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'late-bookings' ),
189
+ 'date_onload' => $rtb_controller->settings->get_setting( 'date-onload' ),
190
+ 'time_interval' => $rtb_controller->settings->get_setting( 'time-interval' ),
191
+ 'first_day' => $rtb_controller->settings->get_setting( 'week-start' ),
192
+ 'allow_past' => is_admin() && current_user_can( 'manage_bookings' ),
193
+ )
194
)
195
);
196
199
200
/**
201
* Get rules for datepicker date ranges
202
+ * See: http://amsul.ca/pickadate.js/date/#disable-dates
203
* @since 0.0.1
204
*/
205
if ( !function_exists( 'rtb_get_datepicker_rules' ) ) {
277
$type = empty( $args['input_type'] ) ? 'text' : esc_attr( $args['input_type'] );
278
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
279
$classes[] = 'rtb-text';
280
+ $required = isset( $args['required'] ) && $args['required'] ? ' required aria-required="true"' : '';
281
282
?>
283
286
<label for="rtb-<?php echo $slug; ?>">
287
<?php echo $title; ?>
288
</label>
289
+ <input type="<?php echo $type; ?>" name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>" value="<?php echo $value; ?>"<?php echo $required; ?>>
290
</div>
291
292
<?php
306
$value = preg_replace('/\<br(\s*)?\/?\>/i', '', $value);
307
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
308
$classes[] = 'rtb-textarea';
309
+ $required = isset( $args['required'] ) && $args['required'] ? ' required aria-required="true"' : '';
310
311
?>
312
315
<label for="rtb-<?php echo $slug; ?>">
316
<?php echo $title; ?>
317
</label>
318
+ <textarea name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>"<?php echo $required; ?>><?php echo $value; ?></textarea>
319
</div>
320
321
<?php
335
$options = is_array( $args['options'] ) ? $args['options'] : array();
336
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
337
$classes[] = 'rtb-select';
338
+ $required = isset( $args['required'] ) && $args['required'] ? ' required aria-required="true"' : '';
339
340
?>
341
344
<label for="rtb-<?php echo $slug; ?>">
345
<?php echo $title; ?>
346
</label>
347
+ <select name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>"<?php echo $required; ?>>
348
<?php foreach ( $options as $opt_value => $opt_label ) : ?>
349
<option value="<?php echo esc_attr( $opt_value ); ?>" <?php selected( $opt_value, $value ); ?>><?php echo esc_attr( $opt_label ); ?></option>
350
<?php endforeach; ?>
359
/**
360
* Print a checkbox form field
361
*
362
* @since 1.3.1
363
*/
364
if ( !function_exists( 'rtb_print_form_checkbox_field' ) ) {
392
/**
393
* Print a radio button form field
394
*
395
* @since 1.3.1
396
*/
397
if ( !function_exists( 'rtb_print_form_radio_field' ) ) {
402
$options = is_array( $args['options'] ) ? $args['options'] : array();
403
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
404
$classes[] = 'rtb-radio';
405
+ $required = isset( $args['required'] ) && $args['required'] ? ' required aria-required="true"' : '';
406
407
?>
408
413
</label>
414
<?php foreach ( $options as $opt_value => $opt_label ) : ?>
415
<label>
416
+ <input type="radio" name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>" value="<?php echo esc_attr( $opt_value ); ?>" <?php checked( $opt_value, $value ); ?><?php echo $required; ?>>
417
<?php echo $opt_label; ?>
418
</label>
419
<?php endforeach; ?>
435
$value = esc_attr( $value );
436
$classes = isset( $args['classes'] ) ? $args['classes'] : array();
437
$classes[] = 'rtb-confirm';
438
+ $required = isset( $args['required'] ) && $args['required'] ? ' required aria-required="true"' : '';
439
440
?>
441
442
<div <?php echo rtb_print_element_class( $slug, $classes ); ?>>
443
<?php echo rtb_print_form_error( $slug ); ?>
444
<label for="rtb-<?php echo $slug; ?>">
445
+ <input type="checkbox" name="rtb-<?php echo $slug; ?>" id="rtb-<?php echo $slug; ?>" value="1" <?php checked( $value, 1 ); ?><?php echo $required; ?>>
446
<?php echo $title; ?>
447
</label>
448
</div>
languages/restaurant-reservations.pot CHANGED
@@ -1,231 +1,230 @@
1
- # Copyright (C) 2016 Restaurant Reservations
2
- # This file is distributed under the same license as the Restaurant Reservations package.
3
msgid ""
4
msgstr ""
5
- "Project-Id-Version: Restaurant Reservations 1.6\n"
6
- "Report-Msgid-Bugs-To: "
7
- "https://wordpress.org/support/plugin/restaurant-reservations\n"
8
- "POT-Creation-Date: 2016-06-20 07:16:22+00:00\n"
9
"MIME-Version: 1.0\n"
10
"Content-Type: text/plain; charset=utf-8\n"
11
"Content-Transfer-Encoding: 8bit\n"
12
"PO-Revision-Date: 2016-MO-DA HO:MI+ZONE\n"
13
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
"Language-Team: LANGUAGE <LL@li.org>\n"
15
- "X-Generator: grunt-wp-i18n 0.4.9\n"
16
- "X-Poedit-KeywordsList: "
17
- "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
18
- "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
19
- "Language: en\n"
20
- "Plural-Forms: nplurals=2; plural=(n != 1);\n"
21
- "X-Poedit-Country: United States\n"
22
- "X-Poedit-SourceCharset: UTF-8\n"
23
- "X-Poedit-Basepath: ../\n"
24
- "X-Poedit-SearchPath-0: .\n"
25
- "X-Poedit-Bookmarks: \n"
26
- "X-Textdomain-Support: yes\n"
27
-
28
- #: includes/Addons.class.php:101
29
- #: includes/WP_List_Table.BookingsTable.class.php:400
30
- msgid "Loading"
31
- msgstr ""
32
33
- #: includes/Addons.class.php:138
34
msgid "Addons for Restaurant Reservations"
35
msgstr ""
36
37
- #: includes/Addons.class.php:160
38
- msgid "You have been logged out. Please login again to retrieve the addons."
39
- msgstr ""
40
-
41
- #: includes/Addons.class.php:176
42
- msgid ""
43
- "You do not have permission to access this page. Please login to an "
44
- "administrator account if you have one."
45
- msgstr ""
46
-
47
- #: includes/Addons.class.php:204
48
- msgid ""
49
- "The addons list could not be retrieved. Please <a href=\"\">try again</a>. "
50
- "If the problem persists over time, please report it on the <a "
51
- "href=\"http://wordpress.org/support/plugin/restaurant-reservations\" "
52
- "target=\"_blank\">support forums</a>."
53
- msgstr ""
54
-
55
- #: includes/AdminBookings.class.php:84
56
msgid "Restaurant Bookings"
57
msgstr ""
58
59
- #: includes/AdminBookings.class.php:85 includes/CustomPostTypes.class.php:42
60
msgid "Add New"
61
msgstr ""
62
63
- #: includes/AdminBookings.class.php:123 includes/AdminBookings.class.php:225
64
msgid "Columns"
65
msgstr ""
66
67
- #: includes/AdminBookings.class.php:163 restaurant-reservations.php:235
68
msgid "Add Booking"
69
msgstr ""
70
71
- #: includes/AdminBookings.class.php:166 includes/AdminBookings.class.php:207
72
- #: includes/AdminBookings.class.php:252
73
msgid "Cancel"
74
msgstr ""
75
76
- #: includes/AdminBookings.class.php:187 includes/AdminBookings.class.php:204
77
- #: includes/WP_List_Table.BookingsTable.class.php:419
78
msgid "Send Email"
79
msgstr ""
80
81
- #: includes/AdminBookings.class.php:194
82
msgid "Subject"
83
msgstr ""
84
85
- #: includes/AdminBookings.class.php:198 includes/Settings.class.php:830
86
- #: includes/WP_List_Table.BookingsTable.class.php:441
87
msgid "Message"
88
msgstr ""
89
90
- #: includes/AdminBookings.class.php:249
91
msgid "Update"
92
msgstr ""
93
94
- #: includes/AdminBookings.class.php:268 includes/AdminBookings.class.php:277
95
msgid "Close"
96
msgstr ""
97
98
- #: includes/AdminBookings.class.php:343
99
msgid "Booking Status"
100
msgstr ""
101
102
- #: includes/AdminBookings.class.php:351
103
msgid "Send notifications"
104
msgstr ""
105
106
- #: includes/AdminBookings.class.php:356
107
msgid "Learn more"
108
msgstr ""
109
110
- #: includes/AdminBookings.class.php:357
111
msgid ""
112
"When adding a booking or changing a booking's status with this form, no "
113
"email notifications will be sent. Check this option if you want to send "
114
"email notifications."
115
msgstr ""
116
117
- #: includes/AdminBookings.class.php:411
118
msgid "You have been logged out. Please %slogin again%s."
119
msgstr ""
120
121
- #: includes/AdminBookings.class.php:447
122
msgid ""
123
"This booking has been sent to the %sTrash%s where it can not be edited. Set "
124
"the booking to Pending or Confirmed to edit it."
125
msgstr ""
126
127
- #: includes/AdminBookings.class.php:464
128
msgid "The booking could not be retrieved. Please reload the page and try again."
129
msgstr ""
130
131
- #: includes/AdminBookings.class.php:546
132
msgid ""
133
"Unable to trash this post. Please try again. If you continue to have "
134
"trouble, please refresh the page."
135
msgstr ""
136
137
- #: includes/AdminBookings.class.php:588
138
msgid "Please enter a message before sending the email."
139
msgstr ""
140
141
- #: includes/AdminBookings.class.php:597
142
msgid "The email could not be sent because some critical information was missing."
143
msgstr ""
144
145
- #: includes/AdminBookings.class.php:609
146
msgid "There was an error loading the booking and the email was not sent."
147
msgstr ""
148
149
- #: includes/AdminBookings.class.php:647
150
msgid "You must select at least one column to display."
151
msgstr ""
152