Version Description
This update adds support for adding and editing bookings from the admin panel. The bookings panel now shows upcoming bookings by default. The Party field in the booking form is now a dropdown selection. Plus a bunch of new features and fixes. Read the full changelog for details.
Download this release
Release Info
Developer | NateWr |
Plugin | ![]() |
Version | 1.3 |
Comparing to | |
See all releases |
Code changes from version 1.2.3 to 1.3
- assets/addons-backup.json +11 -0
- assets/css/admin.css +243 -2
- assets/js/admin.js +312 -9
- assets/js/booking-form.js +170 -112
- includes/Addons.class.php +27 -16
- includes/AdminBookings.class.php +455 -0
- includes/Booking.class.php +88 -27
- includes/Compatibility.class.php +47 -0
- includes/CustomPostTypes.class.php +18 -18
- includes/Notification.Email.class.php +30 -16
- includes/Notification.class.php +3 -3
- includes/Notifications.class.php +17 -22
- includes/Settings.class.php +333 -117
- includes/WP_List_Table.BookingsTable.class.php +122 -53
- includes/WP_Widget.BookingFormWidget.class.php +2 -2
- includes/template-functions.php +98 -99
- languages/restaurant-reservations-de_DE.mo +0 -0
- languages/restaurant-reservations-de_DE.po +1441 -0
- languages/restaurant-reservations-es_CL.mo +0 -0
- languages/restaurant-reservations-es_CL.po +1201 -0
- languages/restaurant-reservations-nl_NL.MO +0 -0
- languages/{rtbdomain.pot → restaurant-reservations-nl_NL.PO} +747 -643
- languages/restaurant-reservations.pot +1263 -0
- lib/simple-admin-pages/README.md +37 -22
- lib/simple-admin-pages/classes/AdminPage.Menu.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPage.Submenu.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPage.Themes.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPage.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSection.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.Address.class.php +29 -24
- lib/simple-admin-pages/classes/AdminPageSetting.Editor.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.HTML.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.OpeningHours.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.Scheduler.class.php +65 -40
- lib/simple-admin-pages/classes/AdminPageSetting.Select.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.SelectPost.class.php +7 -5
- lib/simple-admin-pages/classes/AdminPageSetting.SelectTaxonomy.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.Text.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.Textarea.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.Toggle.class.php +1 -1
- lib/simple-admin-pages/classes/AdminPageSetting.class.php +34 -6
- lib/simple-admin-pages/classes/Library.class.php +3 -3
- lib/simple-admin-pages/lib/pickadate/legacy.js +125 -2
- lib/simple-admin-pages/lib/pickadate/picker.date.js +1347 -2
- lib/simple-admin-pages/lib/pickadate/picker.js +1117 -2
- lib/simple-admin-pages/lib/pickadate/picker.time.js +1007 -2
- lib/simple-admin-pages/lib/pickadate/themes/default.css +170 -2
- lib/simple-admin-pages/lib/pickadate/themes/default.date.css +301 -1
- lib/simple-admin-pages/lib/pickadate/themes/default.time.css +126 -1
- lib/simple-admin-pages/lib/pickadate/themes/rtl.css +27 -1
- lib/simple-admin-pages/lib/pickadate/translations/ca_ES.js +1 -0
- lib/simple-admin-pages/lib/pickadate/translations/da_DK.js +1 -0
- lib/simple-admin-pages/lib/pickadate/translations/de_DE.js +1 -0
- lib/simple-admin-pages/lib/pickadate/translations/fr_FR.js +4 -4
- lib/simple-admin-pages/lib/pickadate/translations/it_IT.js +10 -4
- lib/simple-admin-pages/lib/pickadate/translations/lt_LT.js +24 -0
- lib/simple-admin-pages/lib/pickadate/translations/lv_LV.js +13 -0
- lib/simple-admin-pages/lib/pickadate/translations/{no_NO.js → nb_NO.js} +1 -0
- lib/simple-admin-pages/lib/pickadate/translations/nl_NL.js +1 -0
- lib/simple-admin-pages/lib/pickadate/translations/pl_PL.js +4 -3
- lib/simple-admin-pages/lib/pickadate/translations/pt_BR.js +3 -2
- lib/simple-admin-pages/lib/pickadate/translations/pt_PT.js +6 -5
- lib/simple-admin-pages/lib/pickadate/translations/sl_SI.js +1 -0
- lib/simple-admin-pages/lib/pickadate/translations/sv_SE.js +10 -5
- lib/simple-admin-pages/lib/pickadate/translations/tr_TR.js +3 -2
- lib/simple-admin-pages/simple-admin-pages.php +0 -5
- readme.txt +28 -7
- restaurant-reservations.php +53 -60
- screenshot-10.png +0 -0
- screenshot-9.png +0 -0
assets/addons-backup.json
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"id":"mailchimp-for-rtb",
|
4 |
+
"title":"MailChimp for Restaurant Reservations",
|
5 |
+
"url":"http:\/\/themeofthecrop.com\/plugin\/mailchimp-restaurant-reservations\/",
|
6 |
+
"price":"$20",
|
7 |
+
"img":"https:\/\/themeofthecrop.com\/promo\/plugins\/mailchimp-for-rtb.png",
|
8 |
+
"status":"released",
|
9 |
+
"description":"Subscribe emails from new restaurant reservations to your MailChimp mailing list."
|
10 |
+
}
|
11 |
+
]
|
assets/css/admin.css
CHANGED
@@ -56,8 +56,8 @@
|
|
56 |
}
|
57 |
|
58 |
#rtb-bookings-table tr.closed {
|
59 |
-
opacity: 0.
|
60 |
-
filter: opacity(alpha=
|
61 |
}
|
62 |
#rtb-bookings-table tr.closed:hover {
|
63 |
opacity: 1;
|
@@ -69,11 +69,252 @@
|
|
69 |
border-left: 4px solid #dd3d36;
|
70 |
}
|
71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
@media screen and (max-width: 782px) {
|
73 |
|
74 |
#rtb-bookings-table .fixed .column-date {
|
75 |
display: table-cell;
|
76 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
}
|
78 |
|
79 |
/* Settings Pages (most of this is handled by the Simple Admin Pages library) */
|
56 |
}
|
57 |
|
58 |
#rtb-bookings-table tr.closed {
|
59 |
+
opacity: 0.6;
|
60 |
+
filter: opacity(alpha=60);
|
61 |
}
|
62 |
#rtb-bookings-table tr.closed:hover {
|
63 |
opacity: 1;
|
69 |
border-left: 4px solid #dd3d36;
|
70 |
}
|
71 |
|
72 |
+
#rtb-bookings-table tr.pending .check-column input[type=checkbox] {
|
73 |
+
margin-left: 4px;
|
74 |
+
}
|
75 |
+
|
76 |
+
#rtb-bookings-table th#date {
|
77 |
+
width: auto;
|
78 |
+
}
|
79 |
+
|
80 |
+
#rtb-bookings-table th#party {
|
81 |
+
width: 3em;
|
82 |
+
}
|
83 |
+
|
84 |
+
#rtb-bookings-table th#message {
|
85 |
+
width: 5em;
|
86 |
+
}
|
87 |
+
|
88 |
+
#rtb-bookings-table .column-date .actions {
|
89 |
+
line-height: 28px;
|
90 |
+
opacity: 0;
|
91 |
+
-webkit-transition: opacity 0.3s 0;
|
92 |
+
-moz-transition: opacity 0.3s 0;
|
93 |
+
transition: opacity 0.3s 0;
|
94 |
+
}
|
95 |
+
|
96 |
+
#rtb-bookings-table tr:hover .column-date .actions {
|
97 |
+
opacity: 1;
|
98 |
+
}
|
99 |
+
|
100 |
+
#rtb-bookings-table .column-date .actions .trash {
|
101 |
+
color: #a00;
|
102 |
+
}
|
103 |
+
|
104 |
+
#rtb-bookings-table .column-date .actions .trash:hover {
|
105 |
+
color: red;
|
106 |
+
}
|
107 |
+
|
108 |
+
#rtb-bookings-table .column-date .status {
|
109 |
+
width: 0;
|
110 |
+
height: 0;
|
111 |
+
overflow: hidden;
|
112 |
+
line-height: 28px;
|
113 |
+
opacity: 0;
|
114 |
+
-webkit-transition: opacity 0.6s 0;
|
115 |
+
-moz-transition: opacity 0.6s 0;
|
116 |
+
transition: opacity 0.6s 0;
|
117 |
+
}
|
118 |
+
|
119 |
+
#rtb-bookings-table .column-date .status .spinner {
|
120 |
+
display: inline-block;
|
121 |
+
float: left;
|
122 |
+
margin: 4px 4px 0 0;
|
123 |
+
vertical-align: middle;
|
124 |
+
}
|
125 |
+
|
126 |
+
#rtb-bookings-table .column-date.loading .actions {
|
127 |
+
display: none;
|
128 |
+
}
|
129 |
+
|
130 |
+
#rtb-bookings-table .column-date.loading .status {
|
131 |
+
width: auto;
|
132 |
+
height: auto;
|
133 |
+
overflow: visible;
|
134 |
+
opacity: 0.5;
|
135 |
+
}
|
136 |
+
|
137 |
+
#rtb-bookings-table tr.notice td {
|
138 |
+
background: #2ea2cc;
|
139 |
+
color: #fff;
|
140 |
+
}
|
141 |
+
|
142 |
+
#rtb-bookings-table tr.notice.trash td {
|
143 |
+
background: #dd3d36;
|
144 |
+
}
|
145 |
+
|
146 |
@media screen and (max-width: 782px) {
|
147 |
|
148 |
#rtb-bookings-table .fixed .column-date {
|
149 |
display: table-cell;
|
150 |
}
|
151 |
+
|
152 |
+
#rtb-bookings-table th#party,
|
153 |
+
#rtb-bookings-table th#message {
|
154 |
+
width: auto;
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
/* Add/edit bookings modal */
|
159 |
+
.rtb-admin-modal {
|
160 |
+
position: fixed;
|
161 |
+
top: 0;
|
162 |
+
left: 0;
|
163 |
+
width: 100%;
|
164 |
+
height: 100%;
|
165 |
+
background: rgba(0, 0, 0, 0.8);
|
166 |
+
z-index: 3;
|
167 |
+
overflow-y: auto;
|
168 |
+
cursor: pointer;
|
169 |
+
visibility: hidden;
|
170 |
+
opacity: 0;
|
171 |
+
-webkit-transition: opacity 0.3s 0, visibility 0 0.3s;
|
172 |
+
-moz-transition: opacity 0.3s 0, visibility 0 0.3s;
|
173 |
+
transition: opacity 0.3s 0, visibility 0 0.3s;
|
174 |
+
}
|
175 |
+
|
176 |
+
.rtb-admin-modal.is-visible {
|
177 |
+
visibility: visible;
|
178 |
+
opacity: 1;
|
179 |
+
-webkit-transition: opacity 0.3s 0, visibility 0 0;
|
180 |
+
-moz-transition: opacity 0.3s 0, visibility 0 0;
|
181 |
+
transition: opacity 0.3s 0, visibility 0 0;
|
182 |
+
}
|
183 |
+
|
184 |
+
.rtb-admin-modal.is-visible .rtb-container {
|
185 |
+
-webkit-transform: translateY(0);
|
186 |
+
-moz-transform: translateY(0);
|
187 |
+
-ms-transform: translateY(0);
|
188 |
+
-o-transform: translateY(0);
|
189 |
+
transform: translateY(0);
|
190 |
+
}
|
191 |
+
|
192 |
+
.rtb-admin-modal .rtb-container {
|
193 |
+
position: relative;
|
194 |
+
width: 90%;
|
195 |
+
max-width: 20em;
|
196 |
+
padding: 2em;
|
197 |
+
background: #FFF;
|
198 |
+
margin: 3em auto 4em;
|
199 |
+
cursor: auto;
|
200 |
+
border-radius: 0.25em;
|
201 |
+
-webkit-transform: translateY(-30px);
|
202 |
+
-moz-transform: translateY(-30px);
|
203 |
+
-ms-transform: translateY(-30px);
|
204 |
+
-o-transform: translateY(-30px);
|
205 |
+
transform: translateY(-30px);
|
206 |
+
-webkit-transition-property: -webkit-transform;
|
207 |
+
-moz-transition-property: -moz-transform;
|
208 |
+
transition-property: transform;
|
209 |
+
-webkit-transition-duration: 0.3s;
|
210 |
+
-moz-transition-duration: 0.3s;
|
211 |
+
transition-duration: 0.3s;
|
212 |
+
}
|
213 |
+
|
214 |
+
#rtb-booking-modal fieldset {
|
215 |
+
padding: 0;
|
216 |
+
}
|
217 |
+
|
218 |
+
#rtb-booking-modal label {
|
219 |
+
color: #777;
|
220 |
+
font-style: italic;
|
221 |
+
}
|
222 |
+
|
223 |
+
#rtb-booking-modal button {
|
224 |
+
margin-top: 1em;
|
225 |
+
margin-right: 1em;
|
226 |
+
}
|
227 |
+
|
228 |
+
#rtb-booking-modal .button {
|
229 |
+
margin-top: 1em;
|
230 |
+
}
|
231 |
+
|
232 |
+
#rtb-booking-modal button,
|
233 |
+
#rtb-booking-modal .button {
|
234 |
+
opacity: 1;
|
235 |
+
transition: opacity .25s ease-in-out;
|
236 |
+
-moz-transition: opacity .25s ease-in-out;
|
237 |
+
-webkit-transition: opacity .25s ease-in-out;
|
238 |
+
}
|
239 |
+
|
240 |
+
#rtb-booking-modal button:disabled,
|
241 |
+
#rtb-booking-modal .button:disabled {
|
242 |
+
opacity: 0.5;
|
243 |
+
transition: opacity .25s ease-in-out;
|
244 |
+
-moz-transition: opacity .25s ease-in-out;
|
245 |
+
-webkit-transition: opacity .25s ease-in-out;
|
246 |
+
}
|
247 |
+
|
248 |
+
#rtb-booking-modal .action-status {
|
249 |
+
display: inline-block;
|
250 |
+
float: right;
|
251 |
+
margin-top: 1em;
|
252 |
+
opacity: 0;
|
253 |
+
transition: opacity .25s ease-in-out;
|
254 |
+
-moz-transition: opacity .25s ease-in-out;
|
255 |
+
-webkit-transition: opacity .25s ease-in-out;
|
256 |
+
}
|
257 |
+
|
258 |
+
#rtb-booking-modal .action-status.is-visible {
|
259 |
+
opacity: 1;
|
260 |
+
}
|
261 |
+
|
262 |
+
#rtb-booking-modal .action-status > span {
|
263 |
+
display: none;
|
264 |
+
background-position: 4px;
|
265 |
+
margin: 0;
|
266 |
+
height: 28px;
|
267 |
+
width: 28px;
|
268 |
+
line-height: 28px;
|
269 |
+
font-size: 28px;
|
270 |
+
}
|
271 |
+
|
272 |
+
#rtb-booking-modal .action-status > .spinner {
|
273 |
+
display: block;
|
274 |
+
}
|
275 |
+
|
276 |
+
#rtb-booking-modal .action-status > .success {
|
277 |
+
color: #7ad03a;
|
278 |
+
}
|
279 |
+
|
280 |
+
#rtb-booking-modal .action-status > .error {
|
281 |
+
color: #dd3d36;
|
282 |
+
}
|
283 |
+
|
284 |
+
#rtb-booking-modal .rtb-error {
|
285 |
+
background: #dd3d36;
|
286 |
+
}
|
287 |
+
|
288 |
+
#rtb-booking-modal .rtb-error a {
|
289 |
+
color: #fff;
|
290 |
+
}
|
291 |
+
|
292 |
+
#rtb-booking-modal input[type="text"],
|
293 |
+
#rtb-booking-modal input[type="email"],
|
294 |
+
#rtb-booking-modal textarea {
|
295 |
+
max-width: 100%;
|
296 |
+
}
|
297 |
+
|
298 |
+
.rtb-description {
|
299 |
+
margin: 0.5em 0;
|
300 |
+
color: #777;
|
301 |
+
max-height: 0;
|
302 |
+
overflow: hidden;
|
303 |
+
-webkit-transition: max-height 0.5s 0;
|
304 |
+
-moz-transition: max-height 0.5s 0;
|
305 |
+
transition: max-height 0.5s 0;
|
306 |
+
}
|
307 |
+
|
308 |
+
.rtb-description.is-visible {
|
309 |
+
max-height: 20em;
|
310 |
+
}
|
311 |
+
|
312 |
+
#rtb-error-modal .rtb-error-msg {
|
313 |
+
margin-bottom: 1em;
|
314 |
+
}
|
315 |
+
/* Hide the outer scrollbar when the modal is open */
|
316 |
+
.rtb-hide-body-scroll {
|
317 |
+
overflow: hidden !important;
|
318 |
}
|
319 |
|
320 |
/* Settings Pages (most of this is handled by the Simple Admin Pages library) */
|
assets/js/admin.js
CHANGED
@@ -15,13 +15,316 @@ jQuery(document).ready(function ($) {
|
|
15 |
$( '#' + message_id ).fadeIn();
|
16 |
$(this).children( '.dashicons' ).removeClass( 'dashicons-testimonial' ).addClass( 'dashicons-welcome-comments' );
|
17 |
}
|
18 |
-
|
19 |
return false;
|
20 |
});
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
// Show the addons
|
23 |
if ( $( '#rtb-addons' ).length ) {
|
24 |
-
|
25 |
var rtbAddons = {
|
26 |
|
27 |
el: $( '#rtb-addons' ),
|
@@ -45,7 +348,7 @@ jQuery(document).ready(function ($) {
|
|
45 |
rtbAddons.showError( r );
|
46 |
}
|
47 |
});
|
48 |
-
|
49 |
|
50 |
});
|
51 |
},
|
@@ -86,19 +389,19 @@ jQuery(document).ready(function ($) {
|
|
86 |
} else if ( typeof addon.img !== 'undefind' ) {
|
87 |
html += '<img src="' + addon.img + '">';
|
88 |
}
|
89 |
-
|
90 |
html += '<h3>' + addon.title + '</h3>';
|
91 |
|
92 |
html += '<div class="details">';
|
93 |
-
|
94 |
if ( typeof addon.description !== 'undefined' ) {
|
95 |
html += '<div class="description">' + addon.description + '</div>';
|
96 |
}
|
97 |
-
|
98 |
if ( typeof addon.status !== 'undefined' ) {
|
99 |
|
100 |
html += '<div class="action">';
|
101 |
-
|
102 |
if ( addon.status === 'released' && typeof addon.url !== 'undefined' ) {
|
103 |
html += '<a href="' + addon.url + '" class="button button-primary" target="_blank">';
|
104 |
|
@@ -119,7 +422,7 @@ jQuery(document).ready(function ($) {
|
|
119 |
|
120 |
html += '</div>'; // .action
|
121 |
}
|
122 |
-
|
123 |
html += '</div>'; // .details
|
124 |
|
125 |
html += '</div>'; // .addon
|
@@ -127,7 +430,7 @@ jQuery(document).ready(function ($) {
|
|
127 |
return html;
|
128 |
}
|
129 |
};
|
130 |
-
|
131 |
rtbAddons.load();
|
132 |
}
|
133 |
|
15 |
$( '#' + message_id ).fadeIn();
|
16 |
$(this).children( '.dashicons' ).removeClass( 'dashicons-testimonial' ).addClass( 'dashicons-welcome-comments' );
|
17 |
}
|
18 |
+
|
19 |
return false;
|
20 |
});
|
21 |
|
22 |
+
// Register clicks on edit/delete links
|
23 |
+
$( '#rtb-bookings-table .column-date .actions' ).click( function(e) {
|
24 |
+
|
25 |
+
var target = $(e.target);
|
26 |
+
var cell = target.parent().parent();
|
27 |
+
|
28 |
+
rtb_booking_loading_spinner( true, cell );
|
29 |
+
|
30 |
+
if ( target.data( 'action' ) == 'edit' ) {
|
31 |
+
rtb_get_booking( target.data( 'id' ), cell );
|
32 |
+
|
33 |
+
} else if ( target.data( 'action' ) == 'trash' ) {
|
34 |
+
rtb_trash_booking( target.data( 'id' ), cell );
|
35 |
+
}
|
36 |
+
|
37 |
+
e.preventDefault();
|
38 |
+
});
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Show/hide loading spinner when edit/delete link clicked
|
42 |
+
*/
|
43 |
+
function rtb_booking_loading_spinner( loading, cell ) {
|
44 |
+
if ( loading ) {
|
45 |
+
cell.addClass( 'loading' );
|
46 |
+
} else {
|
47 |
+
cell.removeClass( 'loading' );
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Modal to add/edit bookings from the admin
|
53 |
+
*/
|
54 |
+
var rtb_booking_modal = $( '#rtb-booking-modal' );
|
55 |
+
var rtb_booking_modal_fields = rtb_booking_modal.find( '#rtb-booking-form-fields' );
|
56 |
+
var rtb_booking_modal_submit = rtb_booking_modal.find( 'button' );
|
57 |
+
var rtb_booking_modal_cancel = rtb_booking_modal.find( '#rtb-cancel-booking-modal' );
|
58 |
+
var rtb_booking_modal_action_status = rtb_booking_modal.find( '.action-status' );
|
59 |
+
var rtb_booking_modal_error = $( '#rtb-error-modal' );
|
60 |
+
var rtb_booking_modal_error_msg = rtb_booking_modal_error.find( '.rtb-error-msg' );
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Show or hide the booking form modal
|
64 |
+
*/
|
65 |
+
function rtb_toggle_booking_form_modal( show, fields, booking ) {
|
66 |
+
|
67 |
+
if ( show ) {
|
68 |
+
rtb_booking_modal.scrollTop( 0 ).addClass( 'is-visible' );
|
69 |
+
|
70 |
+
if ( typeof fields !== 'undefined' ) {
|
71 |
+
rtb_booking_modal_fields.html( fields );
|
72 |
+
rtb_booking_form.init();
|
73 |
+
rtb_init_booking_form_modal_fields();
|
74 |
+
}
|
75 |
+
|
76 |
+
if ( typeof booking == 'undefined' ) {
|
77 |
+
rtb_booking_modal_fields.find( '#rtb-post-status' ).val( 'confirmed' );
|
78 |
+
rtb_booking_modal_submit.html( rtb_admin.strings.add_booking );
|
79 |
+
} else {
|
80 |
+
rtb_booking_modal_submit.html( rtb_admin.strings.edit_booking );
|
81 |
+
rtb_booking_modal.find( 'input[name=ID]' ).val( booking.ID );
|
82 |
+
}
|
83 |
+
|
84 |
+
$( 'body' ).addClass( 'rtb-hide-body-scroll' );
|
85 |
+
|
86 |
+
} else {
|
87 |
+
rtb_booking_modal.removeClass( 'is-visible' );
|
88 |
+
rtb_booking_modal.find( '.rtb-error' ).remove();
|
89 |
+
rtb_booking_modal.find( '.notifications-description' ).removeClass( 'is-visible' );
|
90 |
+
rtb_booking_modal_action_status.removeClass( 'is-visible' );
|
91 |
+
rtb_reset_booking_form_modal_fields();
|
92 |
+
rtb_booking_modal_submit.removeData( 'id' );
|
93 |
+
rtb_booking_modal_submit.prop( 'disabled', false );
|
94 |
+
rtb_booking_modal_cancel.prop( 'disabled', false );
|
95 |
+
rtb_booking_modal.find( 'input[name=ID]' ).val( '' );
|
96 |
+
|
97 |
+
$( 'body' ).removeClass( 'rtb-hide-body-scroll' );
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Show or hide the booking form error modal
|
103 |
+
*/
|
104 |
+
function rtb_toggle_booking_form_error_modal( show, msg ) {
|
105 |
+
|
106 |
+
if ( show ) {
|
107 |
+
rtb_booking_modal_error_msg.html( msg );
|
108 |
+
rtb_booking_modal_error.addClass( 'is-visible' );
|
109 |
+
|
110 |
+
} else {
|
111 |
+
rtb_booking_modal_error.removeClass( 'is-visible' );
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Initialize form field events
|
117 |
+
*/
|
118 |
+
function rtb_init_booking_form_modal_fields() {
|
119 |
+
|
120 |
+
// Show full description for notifications toggle
|
121 |
+
rtb_booking_modal_fields.find( '.rtb-description-prompt' ).click( function() {
|
122 |
+
$(this).parent().siblings( '.rtb-description' ).addClass( 'is-visible' );
|
123 |
+
});
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Reset booking form fields
|
128 |
+
*/
|
129 |
+
function rtb_reset_booking_form_modal_fields() {
|
130 |
+
rtb_booking_modal_fields.find( 'input, select, textarea' ).val( '' );
|
131 |
+
rtb_booking_modal_fields.find( 'input[name=rtb-notifications]' ).removeAttr( 'checked' );
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Retrieve booking from the database
|
136 |
+
*/
|
137 |
+
function rtb_get_booking( id, cell ) {
|
138 |
+
|
139 |
+
var params = {};
|
140 |
+
|
141 |
+
params.action = 'rtb-admin-booking-modal';
|
142 |
+
params.nonce = rtb_admin.nonce;
|
143 |
+
params.booking = {
|
144 |
+
'ID': id
|
145 |
+
};
|
146 |
+
|
147 |
+
var data = $.param( params );
|
148 |
+
|
149 |
+
var jqhxr = $.get( ajaxurl, data, function( r ) {
|
150 |
+
|
151 |
+
if ( r.success ) {
|
152 |
+
rtb_toggle_booking_form_modal( true, r.data.fields, r.data.booking );
|
153 |
+
|
154 |
+
} else {
|
155 |
+
|
156 |
+
if ( typeof r.data.error == 'undefined' ) {
|
157 |
+
rtb_toggle_booking_form_error_modal( true, rtb_admin.strings.error_unspecified );
|
158 |
+
} else {
|
159 |
+
rtb_toggle_booking_form_error_modal( true, r.data.msg );
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
rtb_booking_loading_spinner( false, cell );
|
164 |
+
});
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Trash booking
|
169 |
+
*/
|
170 |
+
function rtb_trash_booking( id, cell ) {
|
171 |
+
|
172 |
+
var params = {};
|
173 |
+
|
174 |
+
params.action = 'rtb-admin-trash-booking';
|
175 |
+
params.nonce = rtb_admin.nonce;
|
176 |
+
params.booking = id;
|
177 |
+
|
178 |
+
var data = $.param( params );
|
179 |
+
|
180 |
+
var jqhxr = $.post( ajaxurl, data, function( r ) {
|
181 |
+
|
182 |
+
if ( r.success ) {
|
183 |
+
|
184 |
+
cell.parent().fadeOut( 500, function() {
|
185 |
+
$(this).remove();
|
186 |
+
});
|
187 |
+
|
188 |
+
var trash_count_el = $( '#rtb-bookings-table .subsubsub .trash .count' );
|
189 |
+
var trash_count = parseInt( trash_count_el.html().match(/\d+/), 10 ) + 1;
|
190 |
+
trash_count_el.html( '(' + trash_count + ')' );
|
191 |
+
|
192 |
+
} else {
|
193 |
+
|
194 |
+
if ( typeof r.data == 'undefined' || typeof r.data.error == 'undefined' ) {
|
195 |
+
rtb_toggle_booking_form_error_modal( true, rtb_admin.strings.error_unspecified );
|
196 |
+
} else {
|
197 |
+
rtb_toggle_booking_form_error_modal( true, r.data.msg );
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
rtb_booking_loading_spinner( false, cell );
|
202 |
+
});
|
203 |
+
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Show the appropriate result status icon
|
208 |
+
*/
|
209 |
+
function rtb_show_action_status( status ) {
|
210 |
+
|
211 |
+
rtb_booking_modal_action_status.find( 'span' ).hide();
|
212 |
+
|
213 |
+
if ( status === true ) {
|
214 |
+
rtb_booking_modal_action_status.find( '.success' ).show();
|
215 |
+
} else if ( status === false ) {
|
216 |
+
rtb_booking_modal_action_status.find( '.error' ).show();
|
217 |
+
} else {
|
218 |
+
rtb_booking_modal_action_status.find( '.spinner' ).show();
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
// Initialize form field events on load
|
223 |
+
rtb_init_booking_form_modal_fields();
|
224 |
+
|
225 |
+
// Reset the form on load
|
226 |
+
// This fixes a strange bug in Firefox where disabled buttons would
|
227 |
+
// persist after the page refreshed. I'm guessing its a cache issue
|
228 |
+
// but this will just reset everything again
|
229 |
+
rtb_toggle_booking_form_modal( false );
|
230 |
+
|
231 |
+
// Show booking form modal
|
232 |
+
$( '.add-booking' ).click( function() {
|
233 |
+
rtb_toggle_booking_form_modal( true );
|
234 |
+
});
|
235 |
+
|
236 |
+
// Close booking form modal when background or cancel button is clicked
|
237 |
+
rtb_booking_modal.click( function(e) {
|
238 |
+
if ( $(e.target).is( rtb_booking_modal ) ) {
|
239 |
+
rtb_toggle_booking_form_modal( false );
|
240 |
+
}
|
241 |
+
|
242 |
+
if ( $(e.target).is( rtb_booking_modal_cancel ) && rtb_booking_modal_cancel.prop( 'disabled' ) === false ) {
|
243 |
+
rtb_toggle_booking_form_modal( false );
|
244 |
+
}
|
245 |
+
});
|
246 |
+
|
247 |
+
// Close booking form modal and error modal when ESC is keyed
|
248 |
+
$(document).keyup( function(e) {
|
249 |
+
if ( e.which == '27' ) {
|
250 |
+
rtb_toggle_booking_form_modal( false );
|
251 |
+
rtb_toggle_booking_form_error_modal( false );
|
252 |
+
}
|
253 |
+
});
|
254 |
+
|
255 |
+
// Close booking form error modal when background or cancel button is clicked
|
256 |
+
rtb_booking_modal_error.click( function(e) {
|
257 |
+
if ( $(e.target).is( rtb_booking_modal_error ) || $(e.target).is( rtb_booking_modal_error.find( 'a.button' ) ) ) {
|
258 |
+
rtb_toggle_booking_form_error_modal( false );
|
259 |
+
}
|
260 |
+
});
|
261 |
+
|
262 |
+
// Submit booking form modal
|
263 |
+
rtb_booking_modal_submit.click( function(e) {
|
264 |
+
|
265 |
+
e.preventDefault();
|
266 |
+
e.stopPropagation();
|
267 |
+
|
268 |
+
if ( $(this).prop( 'disabled' ) === true ) {
|
269 |
+
return;
|
270 |
+
}
|
271 |
+
|
272 |
+
// Loading
|
273 |
+
rtb_booking_modal_submit.prop( 'disabled', true );
|
274 |
+
rtb_booking_modal_cancel.prop( 'disabled', true );
|
275 |
+
rtb_booking_modal_action_status.addClass( 'is-visible' );
|
276 |
+
rtb_show_action_status( 'loading' );
|
277 |
+
|
278 |
+
var params = {};
|
279 |
+
|
280 |
+
params.action = 'rtb-admin-booking-modal';
|
281 |
+
params.nonce = rtb_admin.nonce;
|
282 |
+
params.booking = rtb_booking_modal.find( 'form' ).serializeArray();
|
283 |
+
|
284 |
+
var data = $.param( params );
|
285 |
+
|
286 |
+
var jqhxr = $.post( ajaxurl, data, function( r ) {
|
287 |
+
|
288 |
+
if ( r.success ) {
|
289 |
+
|
290 |
+
// Refresh the page so that the new details are visible
|
291 |
+
window.location.reload();
|
292 |
+
|
293 |
+
} else {
|
294 |
+
|
295 |
+
// Validation failed
|
296 |
+
if ( r.data.error == 'invalid_booking_data' ) {
|
297 |
+
|
298 |
+
// Replace form fields with HTML returned
|
299 |
+
rtb_booking_modal_fields.html( r.data.fields );
|
300 |
+
rtb_booking_form.init();
|
301 |
+
rtb_init_booking_form_modal_fields();
|
302 |
+
|
303 |
+
// Logged out
|
304 |
+
} else if ( r.data.error == 'loggedout' ) {
|
305 |
+
rtb_booking_modal_fields.after( '<div class="rtb-error">' + r.data.msg + '</div>' );
|
306 |
+
|
307 |
+
// Unspecified error
|
308 |
+
} else {
|
309 |
+
rtb_booking_modal_fields.after( '<div class="rtb-error">' + rtb_admin.strings.error_unspecified + '</div>' );
|
310 |
+
}
|
311 |
+
|
312 |
+
rtb_booking_modal_cancel.prop( 'disabled', false );
|
313 |
+
rtb_booking_modal_submit.prop( 'disabled', false );
|
314 |
+
}
|
315 |
+
|
316 |
+
rtb_show_action_status( r.success );
|
317 |
+
|
318 |
+
// Hide result status icon after a few seconds
|
319 |
+
setTimeout( function() {
|
320 |
+
rtb_booking_modal.find( '.action-status' ).removeClass( 'is-visible' );
|
321 |
+
}, 4000 );
|
322 |
+
});
|
323 |
+
});
|
324 |
+
|
325 |
// Show the addons
|
326 |
if ( $( '#rtb-addons' ).length ) {
|
327 |
+
|
328 |
var rtbAddons = {
|
329 |
|
330 |
el: $( '#rtb-addons' ),
|
348 |
rtbAddons.showError( r );
|
349 |
}
|
350 |
});
|
351 |
+
|
352 |
|
353 |
});
|
354 |
},
|
389 |
} else if ( typeof addon.img !== 'undefind' ) {
|
390 |
html += '<img src="' + addon.img + '">';
|
391 |
}
|
392 |
+
|
393 |
html += '<h3>' + addon.title + '</h3>';
|
394 |
|
395 |
html += '<div class="details">';
|
396 |
+
|
397 |
if ( typeof addon.description !== 'undefined' ) {
|
398 |
html += '<div class="description">' + addon.description + '</div>';
|
399 |
}
|
400 |
+
|
401 |
if ( typeof addon.status !== 'undefined' ) {
|
402 |
|
403 |
html += '<div class="action">';
|
404 |
+
|
405 |
if ( addon.status === 'released' && typeof addon.url !== 'undefined' ) {
|
406 |
html += '<a href="' + addon.url + '" class="button button-primary" target="_blank">';
|
407 |
|
422 |
|
423 |
html += '</div>'; // .action
|
424 |
}
|
425 |
+
|
426 |
html += '</div>'; // .details
|
427 |
|
428 |
html += '</div>'; // .addon
|
430 |
return html;
|
431 |
}
|
432 |
};
|
433 |
+
|
434 |
rtbAddons.load();
|
435 |
}
|
436 |
|
assets/js/booking-form.js
CHANGED
@@ -1,138 +1,170 @@
|
|
1 |
/* Javascript for Restaurant Reservations booking form */
|
|
|
|
|
|
|
2 |
jQuery(document).ready(function ($) {
|
3 |
|
4 |
/**
|
5 |
-
*
|
6 |
*/
|
7 |
-
|
8 |
-
$('html, body').animate({
|
9 |
-
scrollTop: $( '.rtb-booking-form .rtb-error' ).first().offset().top + -40
|
10 |
-
}, 500);
|
11 |
-
}
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
|
20 |
-
|
21 |
-
|
|
|
|
|
22 |
|
23 |
-
|
24 |
-
* Enable datepickers on load
|
25 |
-
*/
|
26 |
-
if ( typeof rtb_pickadate !== 'undefined' ) {
|
27 |
-
|
28 |
-
// Declare datepicker
|
29 |
-
var date_input = $( '#rtb-date' ).pickadate({
|
30 |
-
format: rtb_pickadate.date_format,
|
31 |
-
formatSubmit: 'yyyy/mm/dd',
|
32 |
-
hiddenName: true,
|
33 |
-
min: true,
|
34 |
-
container: 'body',
|
35 |
-
|
36 |
-
// Select the value when loaded if a value has been set
|
37 |
-
onStart: function() {
|
38 |
-
if ( $( '#rtb-date' ).val() !== '' ) {
|
39 |
-
var date = new Date( $( '#rtb-date' ).val() );
|
40 |
-
if ( Object.prototype.toString.call( date ) === "[object Date]" ) {
|
41 |
-
this.set( 'select', date );
|
42 |
-
}
|
43 |
-
}
|
44 |
-
}
|
45 |
});
|
46 |
|
47 |
-
//
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
//
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
}
|
64 |
}
|
65 |
-
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
|
68 |
-
|
69 |
-
|
70 |
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
|
|
|
|
86 |
}
|
87 |
-
rtb_pickadate.disable_dates[disable_key] = weekday_num;
|
88 |
}
|
89 |
}
|
90 |
-
}
|
91 |
|
92 |
-
|
93 |
-
|
94 |
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
|
|
110 |
}
|
111 |
}
|
112 |
-
}
|
113 |
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
|
|
122 |
|
123 |
-
|
124 |
-
|
|
|
|
|
125 |
|
126 |
// Reset enabled/disabled rules on this timepicker
|
127 |
-
timepicker.set( 'enable', false );
|
128 |
-
timepicker.set( 'disable', false );
|
129 |
|
130 |
-
if ( datepicker.get() === '' ) {
|
131 |
-
timepicker.set( 'disable', true );
|
132 |
return;
|
133 |
}
|
134 |
|
135 |
-
selected_date = new Date( datepicker.get( 'select', 'yyyy/mm/dd' ) );
|
136 |
var selected_date_year = selected_date.getFullYear();
|
137 |
var selected_date_month = selected_date.getMonth();
|
138 |
var selected_date_date = selected_date.getDate();
|
@@ -141,7 +173,7 @@ jQuery(document).ready(function ($) {
|
|
141 |
// times subsequently declared are valid. Any time that doesn't fall
|
142 |
// within those declarations is invalid.
|
143 |
// See: http://amsul.ca/pickadate.js/time.htm#disable-times-all
|
144 |
-
var valid_times = [
|
145 |
|
146 |
// Check if this date is an exception to the rules
|
147 |
if ( typeof rtb_pickadate.schedule_closed != 'undefined' ) {
|
@@ -161,7 +193,7 @@ jQuery(document).ready(function ($) {
|
|
161 |
|
162 |
// Closed all day
|
163 |
if ( typeof rtb_pickadate.schedule_closed[closed_key].time == 'undefined' ) {
|
164 |
-
timepicker.set( 'disable', [ true ] );
|
165 |
|
166 |
return;
|
167 |
}
|
@@ -188,7 +220,7 @@ jQuery(document).ready(function ($) {
|
|
188 |
|
189 |
// Exit early if this date is an exception
|
190 |
if ( valid_times.length > 1 ) {
|
191 |
-
timepicker.set( 'disable', valid_times );
|
192 |
|
193 |
return;
|
194 |
}
|
@@ -221,7 +253,7 @@ jQuery(document).ready(function ($) {
|
|
221 |
|
222 |
// Closed all day
|
223 |
if ( typeof rtb_pickadate.schedule_open[open_key].time == 'undefined' ) {
|
224 |
-
timepicker.set( 'disable', [ true ] );
|
225 |
|
226 |
return;
|
227 |
}
|
@@ -251,7 +283,7 @@ jQuery(document).ready(function ($) {
|
|
251 |
|
252 |
// Pass any valid times located
|
253 |
if ( valid_times.length > 1 ) {
|
254 |
-
timepicker.set( 'disable', valid_times );
|
255 |
|
256 |
return;
|
257 |
}
|
@@ -259,10 +291,36 @@ jQuery(document).ready(function ($) {
|
|
259 |
}
|
260 |
|
261 |
// Set it to always open if no rules have been defined
|
262 |
-
timepicker.set( 'enable', true );
|
263 |
-
timepicker.set( 'disable', false );
|
264 |
|
265 |
return;
|
266 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
|
|
|
268 |
});
|
1 |
/* Javascript for Restaurant Reservations booking form */
|
2 |
+
|
3 |
+
var rtb_booking_form = rtb_booking_form || {};
|
4 |
+
|
5 |
jQuery(document).ready(function ($) {
|
6 |
|
7 |
/**
|
8 |
+
* Initialize the booking form when loaded
|
9 |
*/
|
10 |
+
rtb_booking_form.init = function() {
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
// Scroll to the first error message on the booking form
|
13 |
+
if ( $( '.rtb-booking-form .rtb-error' ).length ) {
|
14 |
+
$('html, body').animate({
|
15 |
+
scrollTop: $( '.rtb-booking-form .rtb-error' ).first().offset().top + -40
|
16 |
+
}, 500);
|
17 |
+
}
|
18 |
|
19 |
+
// Show the message field on the booking form
|
20 |
+
$( '.rtb-booking-form .add-message a' ).click( function() {
|
21 |
+
$(this).hide();
|
22 |
+
$(this).parent().siblings( '.message' ).addClass( 'message-open' );
|
23 |
|
24 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
});
|
26 |
|
27 |
+
// Show the message field on load if not empty
|
28 |
+
if ( $.trim( $( '.rtb-booking-form .message textarea' ).val() ) ) {
|
29 |
+
$( '.rtb-booking-form .add-message a' ).trigger( 'click' );
|
30 |
+
}
|
31 |
+
|
32 |
+
// Enable datepickers on load
|
33 |
+
if ( typeof rtb_pickadate !== 'undefined' ) {
|
34 |
+
|
35 |
+
// Declare datepicker
|
36 |
+
var date_input = $( '#rtb-date' ).pickadate({
|
37 |
+
format: rtb_pickadate.date_format,
|
38 |
+
formatSubmit: 'yyyy/mm/dd',
|
39 |
+
hiddenName: true,
|
40 |
+
min: true,
|
41 |
+
container: 'body',
|
42 |
+
|
43 |
+
// Workaround bug in current version of pickadate.js
|
44 |
+
// https://github.com/amsul/pickadate.js/issues/609
|
45 |
+
onOpen: function() {
|
46 |
+
input = document.getElementById( 'rtb-date' );
|
47 |
+
window.scrollTo( 0, input.offsetTop );
|
48 |
+
},
|
49 |
+
onClose: function() {
|
50 |
+
input = document.getElementById( 'rtb-date' );
|
51 |
+
window.scrollTo( 0, input.offsetTop );
|
52 |
+
},
|
53 |
+
|
54 |
+
// Select the value when loaded if a value has been set
|
55 |
+
onStart: function() {
|
56 |
+
if ( $( '#rtb-date' ).val() !== '' ) {
|
57 |
+
var date = new Date( $( '#rtb-date' ).val() );
|
58 |
+
if ( Object.prototype.toString.call( date ) === "[object Date]" ) {
|
59 |
+
this.set( 'select', date );
|
60 |
+
}
|
61 |
}
|
62 |
}
|
63 |
+
});
|
64 |
+
|
65 |
+
// Declare timepicker
|
66 |
+
var time_input = $( '#rtb-time' ).pickatime({
|
67 |
+
format: rtb_pickadate.time_format,
|
68 |
+
formatSubmit: 'h:i A',
|
69 |
+
hiddenName: true,
|
70 |
+
interval: parseInt( rtb_pickadate.time_interval, 10 ),
|
71 |
+
container: 'body',
|
72 |
+
|
73 |
+
// Workaround bug in current version of pickadate.js
|
74 |
+
// https://github.com/amsul/pickadate.js/issues/609
|
75 |
+
onOpen: function() {
|
76 |
+
input = document.getElementById( 'rtb-time' );
|
77 |
+
window.scrollTo( 0, input.offsetTop );
|
78 |
+
},
|
79 |
+
onClose: function() {
|
80 |
+
input = document.getElementById( 'rtb-time' );
|
81 |
+
window.scrollTo( 0, input.offsetTop );
|
82 |
+
},
|
83 |
+
|
84 |
+
// Select the value when loaded if a value has been set
|
85 |
+
onStart: function() {
|
86 |
+
if ( $( '#rtb-time' ).val() !== '' ) {
|
87 |
+
var today = new Date();
|
88 |
+
var today_date = today.getFullYear() + '/' + ( today.getMonth() + 1 ) + '/' + today.getDate();
|
89 |
+
var time = new Date( today_date + ' ' + $( '#rtb-time' ).val() );
|
90 |
+
if ( Object.prototype.toString.call( time ) === "[object Date]" ) {
|
91 |
+
this.set( 'select', time );
|
92 |
+
}
|
93 |
+
}
|
94 |
+
}
|
95 |
+
});
|
96 |
|
97 |
+
rtb_booking_form.datepicker = date_input.pickadate( 'picker' );
|
98 |
+
rtb_booking_form.timepicker = time_input.pickatime( 'picker' );
|
99 |
|
100 |
+
if ( typeof rtb_booking_form.datepicker == 'undefined' ) {
|
101 |
+
return;
|
102 |
+
}
|
103 |
|
104 |
+
// Pass conditional configuration parameters
|
105 |
+
if ( rtb_pickadate.disable_dates.length ) {
|
106 |
+
|
107 |
+
// Update weekday dates if start of the week has been modified
|
108 |
+
if ( typeof rtb_booking_form.datepicker.component.settings.firstDay == 'number' ) {
|
109 |
+
var weekday_num = 0;
|
110 |
+
for ( var disable_key in rtb_pickadate.disable_dates ) {
|
111 |
+
if ( typeof rtb_pickadate.disable_dates[disable_key] == 'number' ) {
|
112 |
+
weekday_num = rtb_pickadate.disable_dates[disable_key] - rtb_booking_form.datepicker.component.settings.firstDay;
|
113 |
+
if ( weekday_num < 1 ) {
|
114 |
+
weekday_num = 7;
|
115 |
+
}
|
116 |
+
rtb_pickadate.disable_dates[disable_key] = weekday_num;
|
117 |
}
|
|
|
118 |
}
|
119 |
}
|
|
|
120 |
|
121 |
+
rtb_booking_form.datepicker.set( 'disable', rtb_pickadate.disable_dates );
|
122 |
+
}
|
123 |
|
124 |
+
if ( rtb_pickadate.late_bookings === '1440' ) {
|
125 |
+
rtb_booking_form.datepicker.set( 'min', 1 );
|
126 |
+
}
|
127 |
|
128 |
+
// If no date has been set, select today's date if it's a valid
|
129 |
+
// date. User may opt not to do this in the settings.
|
130 |
+
if ( $( '#rtb-date' ).val() === '' && !$( '.rtb-booking-form .date .rtb-error' ).length ) {
|
131 |
+
|
132 |
+
if ( rtb_pickadate.date_onload == 'soonest' ) {
|
133 |
+
rtb_booking_form.datepicker.set( 'select', new Date() );
|
134 |
+
} else if ( rtb_pickadate.date_onload !== 'empty' ) {
|
135 |
+
var dateToVerify = rtb_booking_form.datepicker.component.create( new Date() );
|
136 |
+
var isDisabled = rtb_booking_form.datepicker.component.disabled( dateToVerify );
|
137 |
+
if ( !isDisabled ) {
|
138 |
+
rtb_booking_form.datepicker.set( 'select', dateToVerify );
|
139 |
+
}
|
140 |
}
|
141 |
}
|
|
|
142 |
|
143 |
+
// Update timepicker on pageload and whenever the datepicker is closed
|
144 |
+
rtb_booking_form.update_timepicker_range();
|
145 |
+
rtb_booking_form.datepicker.on( {
|
146 |
+
close: function() {
|
147 |
+
rtb_booking_form.update_timepicker_range();
|
148 |
+
}
|
149 |
+
});
|
150 |
+
}
|
151 |
+
};
|
152 |
|
153 |
+
/**
|
154 |
+
* Update the timepicker's range based on the currently selected date
|
155 |
+
*/
|
156 |
+
rtb_booking_form.update_timepicker_range = function() {
|
157 |
|
158 |
// Reset enabled/disabled rules on this timepicker
|
159 |
+
rtb_booking_form.timepicker.set( 'enable', false );
|
160 |
+
rtb_booking_form.timepicker.set( 'disable', false );
|
161 |
|
162 |
+
if ( rtb_booking_form.datepicker.get() === '' ) {
|
163 |
+
rtb_booking_form.timepicker.set( 'disable', true );
|
164 |
return;
|
165 |
}
|
166 |
|
167 |
+
selected_date = new Date( rtb_booking_form.datepicker.get( 'select', 'yyyy/mm/dd' ) );
|
168 |
var selected_date_year = selected_date.getFullYear();
|
169 |
var selected_date_month = selected_date.getMonth();
|
170 |
var selected_date_date = selected_date.getDate();
|
173 |
// times subsequently declared are valid. Any time that doesn't fall
|
174 |
// within those declarations is invalid.
|
175 |
// See: http://amsul.ca/pickadate.js/time.htm#disable-times-all
|
176 |
+
var valid_times = [ rtb_booking_form.get_outer_time_range() ];
|
177 |
|
178 |
// Check if this date is an exception to the rules
|
179 |
if ( typeof rtb_pickadate.schedule_closed != 'undefined' ) {
|
193 |
|
194 |
// Closed all day
|
195 |
if ( typeof rtb_pickadate.schedule_closed[closed_key].time == 'undefined' ) {
|
196 |
+
rtb_booking_form.timepicker.set( 'disable', [ true ] );
|
197 |
|
198 |
return;
|
199 |
}
|
220 |
|
221 |
// Exit early if this date is an exception
|
222 |
if ( valid_times.length > 1 ) {
|
223 |
+
rtb_booking_form.timepicker.set( 'disable', valid_times );
|
224 |
|
225 |
return;
|
226 |
}
|
253 |
|
254 |
// Closed all day
|
255 |
if ( typeof rtb_pickadate.schedule_open[open_key].time == 'undefined' ) {
|
256 |
+
rtb_booking_form.timepicker.set( 'disable', [ true ] );
|
257 |
|
258 |
return;
|
259 |
}
|
283 |
|
284 |
// Pass any valid times located
|
285 |
if ( valid_times.length > 1 ) {
|
286 |
+
rtb_booking_form.timepicker.set( 'disable', valid_times );
|
287 |
|
288 |
return;
|
289 |
}
|
291 |
}
|
292 |
|
293 |
// Set it to always open if no rules have been defined
|
294 |
+
rtb_booking_form.timepicker.set( 'enable', true );
|
295 |
+
rtb_booking_form.timepicker.set( 'disable', false );
|
296 |
|
297 |
return;
|
298 |
+
};
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Get the outer times to exclude based on the time interval
|
302 |
+
*
|
303 |
+
* This is a work-around for a bug in pickadate.js
|
304 |
+
* https://github.com/amsul/pickadate.js/issues/614
|
305 |
+
*/
|
306 |
+
rtb_booking_form.get_outer_time_range = function() {
|
307 |
+
|
308 |
+
var interval = rtb_booking_form.timepicker.get( 'interval' );
|
309 |
+
|
310 |
+
var hour = 24;
|
311 |
+
|
312 |
+
while ( interval >= 60 ) {
|
313 |
+
hour--;
|
314 |
+
interval -= 60;
|
315 |
+
}
|
316 |
+
|
317 |
+
if ( interval > 0 ) {
|
318 |
+
hour--;
|
319 |
+
interval = 60 - interval;
|
320 |
+
}
|
321 |
+
|
322 |
+
return { from: [0, 0], to: [ hour, interval ] };
|
323 |
+
};
|
324 |
|
325 |
+
rtb_booking_form.init();
|
326 |
});
|
includes/Addons.class.php
CHANGED
@@ -78,20 +78,29 @@ class rtbAddons {
|
|
78 |
*/
|
79 |
public function enqueue_admin_assets() {
|
80 |
|
|
|
|
|
|
|
|
|
|
|
81 |
$screen = get_current_screen();
|
82 |
-
if ( $screen
|
|
|
|
|
|
|
|
|
83 |
wp_localize_script(
|
84 |
'rtb-admin',
|
85 |
'rtb_addons',
|
86 |
array(
|
87 |
'nonce' => wp_create_nonce( 'rtb-addons' ),
|
88 |
'strings' => array(
|
89 |
-
'loading' => __( 'Loading',
|
90 |
-
'error_unknown' => _x( 'An unknown error occured.', 'Error message when retrieving list of addons',
|
91 |
-
'installed' => _x( 'Already Installed', 'Label for an addon that is already installed and activated.',
|
92 |
-
'coming_soon' => _x( 'Coming Soon', 'Label for an addon that is not yet released.',
|
93 |
-
'free' => _x( 'Free', 'Label for an addon that is free.',
|
94 |
-
'learn_more' => _x( 'Get It', 'Label for an addon that is released.',
|
95 |
)
|
96 |
)
|
97 |
);
|
@@ -105,8 +114,8 @@ class rtbAddons {
|
|
105 |
|
106 |
add_submenu_page(
|
107 |
'rtb-bookings',
|
108 |
-
_x( 'Addons', 'Title of addons page',
|
109 |
-
_x( 'Addons', 'Title of addons page in the admin menu',
|
110 |
'manage_options',
|
111 |
'rtb-addons',
|
112 |
array( $this, 'show_admin_addons_page' )
|
@@ -123,7 +132,7 @@ class rtbAddons {
|
|
123 |
?>
|
124 |
|
125 |
<div class="wrap">
|
126 |
-
<h2><?php _e( 'Addons for Restaurant Reservations',
|
127 |
<?php do_action( 'rtb_addons_pre' ); ?>
|
128 |
<div id="rtb-addons">
|
129 |
<div class="rtb-loading">
|
@@ -145,7 +154,7 @@ class rtbAddons {
|
|
145 |
wp_send_json_error(
|
146 |
array(
|
147 |
'error' => 'loggedout',
|
148 |
-
'msg' => __( 'You have been logged out. Please login again to retrieve the addons.',
|
149 |
)
|
150 |
);
|
151 |
}
|
@@ -161,7 +170,7 @@ class rtbAddons {
|
|
161 |
wp_send_json_error(
|
162 |
array(
|
163 |
'error' => 'nopriv',
|
164 |
-
'msg' => __( 'You do not have permission to access this page. Please login to an administrator account if you have one.',
|
165 |
)
|
166 |
);
|
167 |
}
|
@@ -170,14 +179,16 @@ class rtbAddons {
|
|
170 |
$ch = curl_init();
|
171 |
curl_setopt( $ch, CURLOPT_URL, $url );
|
172 |
curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json' ) );
|
173 |
-
curl_setopt( $ch, CURLOPT_USERAGENT, 'PHP-MCAPI/2.0' );
|
174 |
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
175 |
curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
|
176 |
$result = curl_exec($ch);
|
177 |
curl_close($ch);
|
178 |
-
|
179 |
-
}
|
180 |
$result = @file_get_contents( $url );
|
|
|
|
|
181 |
}
|
182 |
|
183 |
if ( $result ) {
|
@@ -187,7 +198,7 @@ class rtbAddons {
|
|
187 |
wp_send_json_error(
|
188 |
array(
|
189 |
'error' => 'apifailed',
|
190 |
-
'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>.',
|
191 |
)
|
192 |
);
|
193 |
}
|
78 |
*/
|
79 |
public function enqueue_admin_assets() {
|
80 |
|
81 |
+
// Use the page reference in $admin_page_hooks because
|
82 |
+
// it changes in SOME hooks when it is translated.
|
83 |
+
// https://core.trac.wordpress.org/ticket/18857
|
84 |
+
global $admin_page_hooks;
|
85 |
+
|
86 |
$screen = get_current_screen();
|
87 |
+
if ( empty( $screen ) || empty( $admin_page_hooks['rtb-bookings'] ) ) {
|
88 |
+
return;
|
89 |
+
}
|
90 |
+
|
91 |
+
if ( $screen->base == $admin_page_hooks['rtb-bookings'] . '_page_rtb-addons' ) {
|
92 |
wp_localize_script(
|
93 |
'rtb-admin',
|
94 |
'rtb_addons',
|
95 |
array(
|
96 |
'nonce' => wp_create_nonce( 'rtb-addons' ),
|
97 |
'strings' => array(
|
98 |
+
'loading' => __( 'Loading', 'restaurant-reservations' ),
|
99 |
+
'error_unknown' => _x( 'An unknown error occured.', 'Error message when retrieving list of addons', 'restaurant-reservations' ),
|
100 |
+
'installed' => _x( 'Already Installed', 'Label for an addon that is already installed and activated.', 'restaurant-reservations' ),
|
101 |
+
'coming_soon' => _x( 'Coming Soon', 'Label for an addon that is not yet released.', 'restaurant-reservations' ),
|
102 |
+
'free' => _x( 'Free', 'Label for an addon that is free.', 'restaurant-reservations' ),
|
103 |
+
'learn_more' => _x( 'Get It', 'Label for an addon that is released.', 'restaurant-reservations' ),
|
104 |
)
|
105 |
)
|
106 |
);
|
114 |
|
115 |
add_submenu_page(
|
116 |
'rtb-bookings',
|
117 |
+
_x( 'Addons', 'Title of addons page', 'restaurant-reservations' ),
|
118 |
+
_x( 'Addons', 'Title of addons page in the admin menu', 'restaurant-reservations' ),
|
119 |
'manage_options',
|
120 |
'rtb-addons',
|
121 |
array( $this, 'show_admin_addons_page' )
|
132 |
?>
|
133 |
|
134 |
<div class="wrap">
|
135 |
+
<h2><?php _e( 'Addons for Restaurant Reservations', 'restaurant-reservations' ); ?></h2>
|
136 |
<?php do_action( 'rtb_addons_pre' ); ?>
|
137 |
<div id="rtb-addons">
|
138 |
<div class="rtb-loading">
|
154 |
wp_send_json_error(
|
155 |
array(
|
156 |
'error' => 'loggedout',
|
157 |
+
'msg' => __( 'You have been logged out. Please login again to retrieve the addons.', 'restaurant-reservations' ),
|
158 |
)
|
159 |
);
|
160 |
}
|
170 |
wp_send_json_error(
|
171 |
array(
|
172 |
'error' => 'nopriv',
|
173 |
+
'msg' => __( 'You do not have permission to access this page. Please login to an administrator account if you have one.', 'restaurant-reservations' ),
|
174 |
)
|
175 |
);
|
176 |
}
|
179 |
$ch = curl_init();
|
180 |
curl_setopt( $ch, CURLOPT_URL, $url );
|
181 |
curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json' ) );
|
182 |
+
curl_setopt( $ch, CURLOPT_USERAGENT, 'PHP-MCAPI/2.0' );
|
183 |
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
184 |
curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
|
185 |
$result = curl_exec($ch);
|
186 |
curl_close($ch);
|
187 |
+
|
188 |
+
} elseif ( ini_get( 'allow_url_fopen' ) ) {
|
189 |
$result = @file_get_contents( $url );
|
190 |
+
} else {
|
191 |
+
$result = @file_get_contents( RTB_PLUGIN_DIR . '/assets/addons-backup.json' );
|
192 |
}
|
193 |
|
194 |
if ( $result ) {
|
198 |
wp_send_json_error(
|
199 |
array(
|
200 |
'error' => 'apifailed',
|
201 |
+
'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' ),
|
202 |
)
|
203 |
);
|
204 |
}
|
includes/AdminBookings.class.php
ADDED
@@ -0,0 +1,455 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( !defined( 'ABSPATH' ) ) exit;
|
3 |
+
|
4 |
+
if ( !class_exists( 'rtbAdminBookings' ) ) {
|
5 |
+
/**
|
6 |
+
* Class to handle the admin bookings page for Restaurant Reservations
|
7 |
+
*
|
8 |
+
* @since 1.3
|
9 |
+
*/
|
10 |
+
class rtbAdminBookings {
|
11 |
+
|
12 |
+
public function __construct() {
|
13 |
+
|
14 |
+
// Add the admin menu
|
15 |
+
add_action( 'admin_menu', array( $this, 'add_menu_page' ) );
|
16 |
+
|
17 |
+
// Print the booking form modal
|
18 |
+
add_action( 'admin_footer-toplevel_page_rtb-bookings', array( $this, 'print_booking_form_modal' ) );
|
19 |
+
|
20 |
+
// Receive Ajax requests
|
21 |
+
add_action( 'wp_ajax_nopriv_rtb-admin-booking-modal' , array( $this , 'nopriv_ajax' ) );
|
22 |
+
add_action( 'wp_ajax_rtb-admin-booking-modal', array( $this, 'booking_modal_ajax' ) );
|
23 |
+
add_action( 'wp_ajax_nopriv_rtb-admin-trash-booking' , array( $this , 'nopriv_ajax' ) );
|
24 |
+
add_action( 'wp_ajax_rtb-admin-trash-booking', array( $this, 'trash_booking_ajax' ) );
|
25 |
+
|
26 |
+
// Validate post status and notification fields
|
27 |
+
add_action( 'rtb_validate_booking_submission', array( $this, 'validate_admin_fields' ) );
|
28 |
+
|
29 |
+
// Set post status when adding to the database
|
30 |
+
add_filter( 'rtb_insert_booking_data', array( $this, 'insert_booking_data' ), 10, 2 );
|
31 |
+
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Add the top-level admin menu page
|
36 |
+
* @since 0.0.1
|
37 |
+
*/
|
38 |
+
public function add_menu_page() {
|
39 |
+
|
40 |
+
add_menu_page(
|
41 |
+
_x( 'Bookings', 'Title of admin page that lists bookings', 'restaurant-reservations' ),
|
42 |
+
_x( 'Bookings', 'Title of bookings admin menu item', 'restaurant-reservations' ),
|
43 |
+
'manage_bookings',
|
44 |
+
'rtb-bookings',
|
45 |
+
array( $this, 'show_admin_bookings_page' ),
|
46 |
+
'dashicons-calendar',
|
47 |
+
'26.2987'
|
48 |
+
);
|
49 |
+
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Display the admin bookings page
|
54 |
+
* @since 0.0.1
|
55 |
+
*/
|
56 |
+
public function show_admin_bookings_page() {
|
57 |
+
|
58 |
+
require_once( RTB_PLUGIN_DIR . '/includes/WP_List_Table.BookingsTable.class.php' );
|
59 |
+
$bookings_table = new rtbBookingsTable();
|
60 |
+
$bookings_table->prepare_items();
|
61 |
+
?>
|
62 |
+
|
63 |
+
<div class="wrap">
|
64 |
+
<h2>
|
65 |
+
<?php _e( 'Restaurant Bookings', 'restaurant-reservations' ); ?>
|
66 |
+
<a href="#" class="add-new-h2 add-booking"><?php _e( 'Add New', 'restaurant-reservations' ); ?></a>
|
67 |
+
</h2>
|
68 |
+
|
69 |
+
<?php do_action( 'rtb_bookings_table_top' ); ?>
|
70 |
+
<form id="rtb-bookings-table" method="POST" action="">
|
71 |
+
<input type="hidden" name="post_type" value="<?php echo RTB_BOOKING_POST_TYPE; ?>" />
|
72 |
+
<input type="hidden" name="page" value="rtb-bookings">
|
73 |
+
|
74 |
+
<?php $bookings_table->views(); ?>
|
75 |
+
<?php $bookings_table->advanced_filters(); ?>
|
76 |
+
<?php $bookings_table->display(); ?>
|
77 |
+
</form>
|
78 |
+
<?php do_action( 'rtb_bookings_table_btm' ); ?>
|
79 |
+
</div>
|
80 |
+
|
81 |
+
<?php
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Print the booking form modal container on the admin bookings page
|
86 |
+
* @since 0.0.1
|
87 |
+
*/
|
88 |
+
public function print_booking_form_modal() {
|
89 |
+
?>
|
90 |
+
|
91 |
+
<div id="rtb-booking-modal" class="rtb-admin-modal">
|
92 |
+
<div class="rtb-booking-form rtb-container">
|
93 |
+
<form method="POST">
|
94 |
+
<input type="hidden" name="action" value="admin_booking_request">
|
95 |
+
<input type="hidden" name="ID" value="">
|
96 |
+
|
97 |
+
<?php
|
98 |
+
/**
|
99 |
+
* The generated fields are wrapped in a div so we can
|
100 |
+
* replace its contents with an HTML blob passed back from
|
101 |
+
* an Ajax request. This way the field data and error
|
102 |
+
* messages are always populated from the same server-side
|
103 |
+
* code.
|
104 |
+
*/
|
105 |
+
?>
|
106 |
+
<div id="rtb-booking-form-fields">
|
107 |
+
<?php echo $this->print_booking_form_fields(); ?>
|
108 |
+
</div>
|
109 |
+
|
110 |
+
<button type="submit" class="button-primary">
|
111 |
+
<?php _e( 'Add Booking', 'restaurant-reservations' ); ?>
|
112 |
+
</button>
|
113 |
+
<a href="#" class="button" id="rtb-cancel-booking-modal">
|
114 |
+
<?php _e( 'Cancel', 'restaurant-reservations' ); ?>
|
115 |
+
</a>
|
116 |
+
<div class="action-status">
|
117 |
+
<span class="spinner loading"></span>
|
118 |
+
<span class="dashicons dashicons-no-alt error"></span>
|
119 |
+
<span class="dashicons dashicons-yes success"></span>
|
120 |
+
</div>
|
121 |
+
</form>
|
122 |
+
</div>
|
123 |
+
</div>
|
124 |
+
<!-- Restaurant Reservations error message modal -->
|
125 |
+
<div id="rtb-error-modal" class="rtb-admin-modal">
|
126 |
+
<div class="rtb-error rtb-container">
|
127 |
+
<div class="rtb-error-msg"></div>
|
128 |
+
<a href="#" class="button"><?php _e( 'Close', 'restaurant-reservations' ); ?></a>
|
129 |
+
</div>
|
130 |
+
</div>
|
131 |
+
|
132 |
+
<?php
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Retrieve booking form fields used in the admin booking modal. These
|
137 |
+
* fields are also passed back with ajax requests since they render error
|
138 |
+
* messages and populate fields with validated data.
|
139 |
+
* @since 0.0.1
|
140 |
+
*/
|
141 |
+
public function print_booking_form_fields() {
|
142 |
+
|
143 |
+
global $rtb_controller;
|
144 |
+
|
145 |
+
// Add post status and notification fields to admin booking form
|
146 |
+
add_filter( 'rtb_booking_form_fields', array( $this, 'add_admin_fields' ), 20, 2 );
|
147 |
+
|
148 |
+
// Retrieve the form fields
|
149 |
+
$fields = $rtb_controller->settings->get_booking_form_fields( $rtb_controller->request );
|
150 |
+
|
151 |
+
ob_start();
|
152 |
+
?>
|
153 |
+
|
154 |
+
<?php foreach( $fields as $fieldset => $contents ) : ?>
|
155 |
+
<fieldset class="<?php echo $fieldset; ?>">
|
156 |
+
<?php
|
157 |
+
foreach( $contents['fields'] as $slug => $field ) {
|
158 |
+
|
159 |
+
$args = empty( $field['callback_args'] ) ? null : $field['callback_args'];
|
160 |
+
|
161 |
+
call_user_func( $field['callback'], $slug, $field['title'], $field['request_input'], $args );
|
162 |
+
}
|
163 |
+
?>
|
164 |
+
</fieldset>
|
165 |
+
<?php endforeach;
|
166 |
+
|
167 |
+
// Remove the admin fields filter
|
168 |
+
remove_filter( 'rtb_booking_form_fields', array( $this, 'add_admin_fields' ) );
|
169 |
+
|
170 |
+
return ob_get_clean();
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Add the post status and notifications fields to the booking form fields
|
175 |
+
* @since 1.3
|
176 |
+
*/
|
177 |
+
public function add_admin_fields( $fields, $request ) {
|
178 |
+
|
179 |
+
if ( !is_admin() || !current_user_can( 'manage_bookings' ) ) {
|
180 |
+
return $fields;
|
181 |
+
}
|
182 |
+
|
183 |
+
global $rtb_controller;
|
184 |
+
|
185 |
+
// Get all valid booking statuses
|
186 |
+
$booking_statuses = array();
|
187 |
+
foreach( $rtb_controller->cpts->booking_statuses as $status => $args ) {
|
188 |
+
$booking_statuses[ $status ] = $args['label'];
|
189 |
+
}
|
190 |
+
|
191 |
+
$fields['admin'] = array(
|
192 |
+
'fields' => array(
|
193 |
+
'post-status' => array(
|
194 |
+
'title' => __( 'Booking Status', 'restaurant-reservations' ),
|
195 |
+
'request_input' => empty( $request->post_status ) ? '' : $request->post_status,
|
196 |
+
'callback' => 'rtb_print_form_select_field',
|
197 |
+
'callback_args' => array(
|
198 |
+
'options' => $booking_statuses,
|
199 |
+
)
|
200 |
+
),
|
201 |
+
'notifications' => array(
|
202 |
+
'title' => __( 'Send notifications', 'restaurant-reservations' ),
|
203 |
+
'request_input' => empty( $request->send_notifications ) ? false : $request->send_notifications,
|
204 |
+
'callback' => array( $this, 'print_form_send_notifications_field' ),
|
205 |
+
'callback_args' => array(
|
206 |
+
'description' => array(
|
207 |
+
'prompt' => __( 'Learn more', 'restaurant-reservations' ),
|
208 |
+
'text' => __( "When adding a booking or changing a booking's status with this form, no email notifications will be sent. Check this option if you want to send email notifications.", 'restaurant-reservations' ),
|
209 |
+
),
|
210 |
+
),
|
211 |
+
),
|
212 |
+
),
|
213 |
+
);
|
214 |
+
|
215 |
+
return $fields;
|
216 |
+
}
|
217 |
+
|
218 |
+
|
219 |
+
/**
|
220 |
+
* Print a field to toggle notifications when adding/editing a booking from
|
221 |
+
* the admin
|
222 |
+
* @since 1.3
|
223 |
+
*/
|
224 |
+
function print_form_send_notifications_field( $slug, $title, $value, $args ) {
|
225 |
+
|
226 |
+
$slug = esc_attr( $slug );
|
227 |
+
$title = esc_attr( $title );
|
228 |
+
$value = (bool) $value;
|
229 |
+
$description = empty( $args['description'] ) || empty( $args['description']['prompt'] ) || empty( $args['description']['text'] ) ? null : $args['description'];
|
230 |
+
?>
|
231 |
+
|
232 |
+
<div class="<?php echo $slug; ?>">
|
233 |
+
<?php echo rtb_print_form_error( $slug ); ?>
|
234 |
+
<label>
|
235 |
+
<input type="checkbox" name="rtb-<?php echo esc_attr( $slug ); ?>" value="1"<?php checked( $value ); ?>>
|
236 |
+
<?php echo $title; ?>
|
237 |
+
<?php if ( !empty( $description ) ) : ?>
|
238 |
+
<a href="#" class="rtb-description-prompt">
|
239 |
+
<?php echo $description['prompt']; ?>
|
240 |
+
</a>
|
241 |
+
<?php endif; ?>
|
242 |
+
</label>
|
243 |
+
<?php if ( !empty( $description ) ) : ?>
|
244 |
+
<div class="rtb-description">
|
245 |
+
<?php echo $description['text']; ?>
|
246 |
+
</div>
|
247 |
+
<?php endif; ?>
|
248 |
+
</div>
|
249 |
+
|
250 |
+
<?php
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* Handle ajax requests from the admin bookings area from logged out users
|
255 |
+
* @since 1.3
|
256 |
+
*/
|
257 |
+
public function nopriv_ajax() {
|
258 |
+
|
259 |
+
wp_send_json_error(
|
260 |
+
array(
|
261 |
+
'error' => 'loggedout',
|
262 |
+
'msg' => sprintf( __( 'You have been logged out. Please %slogin again%s.', 'restaurant-reservations' ), '<a href="' . wp_login_url( admin_url( 'admin.php?page=rtb-bookings&status=pending' ) ) . '">', '</a>' ),
|
263 |
+
)
|
264 |
+
);
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
* Handle ajax requests from the admin bookings area
|
269 |
+
* @since 1.3
|
270 |
+
*/
|
271 |
+
public function booking_modal_ajax() {
|
272 |
+
|
273 |
+
global $rtb_controller;
|
274 |
+
|
275 |
+
// Authenticate request
|
276 |
+
if ( !check_ajax_referer( 'rtb-admin', 'nonce' ) || !current_user_can( 'manage_bookings' ) ) {
|
277 |
+
$this->nopriv_ajax();
|
278 |
+
}
|
279 |
+
|
280 |
+
// Retrieve a booking with a GET request
|
281 |
+
if ( !empty( $_GET['booking'] ) && !empty( $_GET['booking']['ID'] ) ) {
|
282 |
+
|
283 |
+
$id = (int) $_GET['booking']['ID'];
|
284 |
+
|
285 |
+
require_once( RTB_PLUGIN_DIR . '/includes/Booking.class.php' );
|
286 |
+
$rtb_controller->request = new rtbBooking();
|
287 |
+
$result = $rtb_controller->request->load_post( $id );
|
288 |
+
|
289 |
+
if ( $result ) {
|
290 |
+
|
291 |
+
// Don't allow editing of trashed bookings. This wil force
|
292 |
+
// appropriate use of the trash status and (hopefully) prevent
|
293 |
+
// mistakes in booking management.
|
294 |
+
if ( $rtb_controller->request->post_status == 'trash' ) {
|
295 |
+
wp_send_json_error(
|
296 |
+
array(
|
297 |
+
'error' => 'booking_trashed',
|
298 |
+
'msg' => sprintf( __( 'This booking has been sent to the %sTrash%s where it can not be edited. Set the booking to Pending or Confirmed to edit it.', 'restaurant-reservations' ), '<a href="' . admin_url( 'admin.php?page=rtb-bookings&status=trash' ) . '">', '</a>' ),
|
299 |
+
)
|
300 |
+
);
|
301 |
+
}
|
302 |
+
|
303 |
+
$rtb_controller->request->prepare_request_data();
|
304 |
+
wp_send_json_success(
|
305 |
+
array(
|
306 |
+
'booking' => $rtb_controller->request,
|
307 |
+
'fields' => $this->print_booking_form_fields(),
|
308 |
+
)
|
309 |
+
);
|
310 |
+
|
311 |
+
} else {
|
312 |
+
wp_send_json_error(
|
313 |
+
array(
|
314 |
+
'error' => 'booking_not_found',
|
315 |
+
'msg' => __( 'The booking could not be retrieved. Please reload the page and try again.', 'restaurant-reservations' ),
|
316 |
+
)
|
317 |
+
);
|
318 |
+
}
|
319 |
+
|
320 |
+
// Insert or update a booking with a POST request
|
321 |
+
} elseif ( !empty( $_POST['booking'] ) ) {
|
322 |
+
|
323 |
+
// Set up $_POST object for validation
|
324 |
+
foreach( $_POST['booking'] as $field ) {
|
325 |
+
$_POST[ $field['name'] ] = $field['value'];
|
326 |
+
}
|
327 |
+
|
328 |
+
require_once( RTB_PLUGIN_DIR . '/includes/Booking.class.php' );
|
329 |
+
$rtb_controller->request = new rtbBooking();
|
330 |
+
|
331 |
+
// Add an ID if we're updating the post
|
332 |
+
if ( !empty( $_POST['ID'] ) ) {
|
333 |
+
$rtb_controller->request->ID = (int) $_POST['ID'];
|
334 |
+
}
|
335 |
+
|
336 |
+
// Disable notifications
|
337 |
+
$this->maybe_disable_notifications();
|
338 |
+
|
339 |
+
$result = $rtb_controller->request->insert_booking();
|
340 |
+
|
341 |
+
if ( $result ) {
|
342 |
+
wp_send_json_success(
|
343 |
+
array(
|
344 |
+
'booking' => $rtb_controller->request,
|
345 |
+
)
|
346 |
+
);
|
347 |
+
} else {
|
348 |
+
wp_send_json_error(
|
349 |
+
array(
|
350 |
+
'error' => 'invalid_booking_data',
|
351 |
+
'booking' => $rtb_controller->request,
|
352 |
+
'fields' => $this->print_booking_form_fields(),
|
353 |
+
)
|
354 |
+
);
|
355 |
+
}
|
356 |
+
}
|
357 |
+
|
358 |
+
// Fallback to a valid error
|
359 |
+
wp_send_json_error();
|
360 |
+
}
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Set booking status to trash
|
364 |
+
* @since 1.3
|
365 |
+
*/
|
366 |
+
public function trash_booking_ajax() {
|
367 |
+
|
368 |
+
global $rtb_controller;
|
369 |
+
|
370 |
+
// Authenticate request
|
371 |
+
if ( !check_ajax_referer( 'rtb-admin', 'nonce' ) || !current_user_can( 'manage_bookings' ) || empty( $_POST['booking'] ) ) {
|
372 |
+
$this->nopriv_ajax();
|
373 |
+
}
|
374 |
+
|
375 |
+
$id = (int) $_POST['booking'];
|
376 |
+
|
377 |
+
$result = wp_trash_post( $id );
|
378 |
+
|
379 |
+
if ( $result === false ) {
|
380 |
+
wp_send_json_error(
|
381 |
+
array(
|
382 |
+
'error' => 'trash_failed',
|
383 |
+
'msg' => __( 'Unable to trash this post. Please try again. If you continue to have trouble, please refresh the page.', 'restaurant-reservations' ),
|
384 |
+
)
|
385 |
+
);
|
386 |
+
|
387 |
+
} else {
|
388 |
+
wp_send_json_success(
|
389 |
+
array(
|
390 |
+
'booking' => $id,
|
391 |
+
)
|
392 |
+
);
|
393 |
+
}
|
394 |
+
|
395 |
+
|
396 |
+
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* Validate post status and notification fields
|
401 |
+
* @since 1.3
|
402 |
+
*/
|
403 |
+
public function validate_admin_fields( $booking ) {
|
404 |
+
|
405 |
+
// Only validate in the admin
|
406 |
+
if ( !$_POST['action'] || $_POST['action'] !== 'admin_booking_request' ) {
|
407 |
+
return;
|
408 |
+
}
|
409 |
+
|
410 |
+
global $rtb_controller;
|
411 |
+
|
412 |
+
// Disable Notifications
|
413 |
+
$booking->send_notifications = empty( $_POST['rtb-notifications'] ) ? false : true;
|
414 |
+
}
|
415 |
+
|
416 |
+
/**
|
417 |
+
* Adjust post status when adding/editing a booking from the admin area
|
418 |
+
* @since 1.3
|
419 |
+
*/
|
420 |
+
public function insert_booking_data( $args, $booking ) {
|
421 |
+
|
422 |
+
// Validate user request
|
423 |
+
if ( empty( $_POST['action'] ) || $_POST['action'] !== 'admin_booking_request' || !current_user_can( 'manage_bookings' ) ) {
|
424 |
+
return $args;
|
425 |
+
}
|
426 |
+
|
427 |
+
if ( !empty( $booking->post_status ) ) {
|
428 |
+
$args['post_status'] = $booking->post_status;
|
429 |
+
}
|
430 |
+
|
431 |
+
return $args;
|
432 |
+
}
|
433 |
+
|
434 |
+
/**
|
435 |
+
* Maybe disable notifications when adding/editing bookings from the
|
436 |
+
* admin booking modal
|
437 |
+
* @since 1.3
|
438 |
+
*/
|
439 |
+
public function maybe_disable_notifications() {
|
440 |
+
|
441 |
+
// Don't disable notifications if they have opted to send them
|
442 |
+
if ( !empty( $_POST['rtb-notifications'] ) ) {
|
443 |
+
return;
|
444 |
+
}
|
445 |
+
|
446 |
+
// Disable all notifications. This filter is here in case a
|
447 |
+
// third-party sets up a notification that they don't want to be
|
448 |
+
// disabled even if the user has opted not to send notifications
|
449 |
+
// To exempt a notification, hook into the filter and copy it
|
450 |
+
// from $rtb_notifications to the empty array.
|
451 |
+
global $rtb_controller;
|
452 |
+
$rtb_controller->notifications->notifications = apply_filters( 'rtb_admin_disabled_notifications_exemption', array(), $rtb_controller->notifications->notifications );
|
453 |
+
}
|
454 |
+
}
|
455 |
+
} // endif;
|
includes/Booking.class.php
CHANGED
@@ -60,7 +60,7 @@ class rtbBooking {
|
|
60 |
$this->ID = $post->ID;
|
61 |
$this->name = $post->post_title;
|
62 |
$this->date = $post->post_date;
|
63 |
-
$this->message =
|
64 |
$this->post_status = $post->post_status;
|
65 |
|
66 |
$this->load_post_metadata();
|
@@ -95,6 +95,22 @@ class rtbBooking {
|
|
95 |
$this->date_submission = $meta['date_submission'];
|
96 |
}
|
97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
/**
|
99 |
* Format date
|
100 |
* @since 0.0.1
|
@@ -121,6 +137,12 @@ class rtbBooking {
|
|
121 |
|
122 |
$this->request_processed = true;
|
123 |
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
$this->validate_submission();
|
125 |
if ( $this->is_valid_submission() === false ) {
|
126 |
return false;
|
@@ -132,7 +154,7 @@ class rtbBooking {
|
|
132 |
$this->request_inserted = true;
|
133 |
}
|
134 |
|
135 |
-
do_action( '
|
136 |
|
137 |
return true;
|
138 |
}
|
@@ -153,7 +175,7 @@ class rtbBooking {
|
|
153 |
$this->validation_errors[] = array(
|
154 |
'field' => 'date',
|
155 |
'error_msg' => 'Booking request missing date',
|
156 |
-
'message' => __( 'Please enter the date you would like to book.',
|
157 |
);
|
158 |
|
159 |
} else {
|
@@ -163,7 +185,7 @@ class rtbBooking {
|
|
163 |
$this->validation_errors[] = array(
|
164 |
'field' => 'date',
|
165 |
'error_msg' => $e->getMessage(),
|
166 |
-
'message' => __( 'The date you entered is not valid. Please select from one of the dates in the calendar.',
|
167 |
);
|
168 |
}
|
169 |
}
|
@@ -174,7 +196,7 @@ class rtbBooking {
|
|
174 |
$this->validation_errors[] = array(
|
175 |
'field' => 'time',
|
176 |
'error_msg' => 'Booking request missing time',
|
177 |
-
'message' => __( 'Please enter the time you would like to book.',
|
178 |
);
|
179 |
|
180 |
} else {
|
@@ -184,7 +206,7 @@ class rtbBooking {
|
|
184 |
$this->validation_errors[] = array(
|
185 |
'field' => 'time',
|
186 |
'error_msg' => $e->getMessage(),
|
187 |
-
'message' => __( 'The time you entered is not valid. Please select from one of the times provided.',
|
188 |
);
|
189 |
}
|
190 |
}
|
@@ -201,7 +223,7 @@ class rtbBooking {
|
|
201 |
$this->validation_errors[] = array(
|
202 |
'field' => 'time',
|
203 |
'error_msg' => 'Booking request too far in the future',
|
204 |
-
'message' => sprintf( __( 'Sorry, bookings can not be made more than %s days in advance.',
|
205 |
);
|
206 |
}
|
207 |
}
|
@@ -212,7 +234,7 @@ class rtbBooking {
|
|
212 |
$this->validation_errors[] = array(
|
213 |
'field' => 'time',
|
214 |
'error_msg' => 'Booking request in the past',
|
215 |
-
'message' => __( 'Sorry, bookings can not be made in the past.',
|
216 |
);
|
217 |
}
|
218 |
|
@@ -220,11 +242,11 @@ class rtbBooking {
|
|
220 |
$late_bookings_seconds = $late_bookings * 60; // Late bookings allowance in seconds
|
221 |
if ( $request->format( 'U' ) < ( current_time( 'timestamp' ) + $late_bookings_seconds ) ) {
|
222 |
if ( $late_bookings >= 1440 ) {
|
223 |
-
$late_bookings_message = sprintf( __( 'Sorry, bookings must be made more than %s days in advance.',
|
224 |
} elseif ( $late_bookings >= 60 ) {
|
225 |
-
$late_bookings_message = sprintf( __( 'Sorry, bookings must be made more than %s hours in advance.',
|
226 |
} else {
|
227 |
-
$late_bookings_message = sprintf( __( 'Sorry, bookings must be made more than %s mings in advance.',
|
228 |
}
|
229 |
$this->validation_errors[] = array(
|
230 |
'field' => 'time',
|
@@ -263,7 +285,7 @@ class rtbBooking {
|
|
263 |
$this->validation_errors[] = array(
|
264 |
'field' => 'date',
|
265 |
'error_msg' => 'Booking request made on invalid date or time in an exception rule',
|
266 |
-
'message' => __( 'Sorry, no bookings are being accepted then.',
|
267 |
);
|
268 |
}
|
269 |
}
|
@@ -315,13 +337,13 @@ class rtbBooking {
|
|
315 |
$this->validation_errors[] = array(
|
316 |
'field' => 'date',
|
317 |
'error_msg' => 'Booking request made on an invalid date',
|
318 |
-
'message' => __( 'Sorry, no bookings are being accepted on that date.',
|
319 |
);
|
320 |
} elseif ( !$time_is_valid ) {
|
321 |
$this->validation_errors[] = array(
|
322 |
'field' => 'time',
|
323 |
'error_msg' => 'Booking request made at an invalid time',
|
324 |
-
'message' => __( 'Sorry, no bookings are being accepted at that time.',
|
325 |
);
|
326 |
}
|
327 |
}
|
@@ -343,31 +365,27 @@ class rtbBooking {
|
|
343 |
$this->validation_errors[] = array(
|
344 |
'field' => 'name',
|
345 |
'post_variable' => $this->name,
|
346 |
-
'message' => __( 'Please enter a name for this booking.',
|
347 |
);
|
348 |
}
|
349 |
|
350 |
// Party
|
351 |
-
$this->party = empty( $_POST['rtb-party'] ) ? '' :
|
352 |
if ( empty( $this->party ) ) {
|
353 |
$this->validation_errors[] = array(
|
354 |
'field' => 'party',
|
355 |
'post_variable' => $this->party,
|
356 |
-
'message' => __( 'Please let us know how many people will be in your party.',
|
357 |
);
|
358 |
|
359 |
// Check party size
|
360 |
-
|
361 |
-
// something like that, let's go ahead and allow it. Restaurant manager
|
362 |
-
// can choose to accept or deny it. We'll only evaluate the max party
|
363 |
-
// size criteria on pure digits ("2" or "10").
|
364 |
-
} elseif ( ctype_digit( $this->party ) ) {
|
365 |
$party_size = $rtb_controller->settings->get_setting( 'party-size' );
|
366 |
-
if ( !empty( $party_size ) && $party_size <
|
367 |
$this->validation_errors[] = array(
|
368 |
'field' => 'party',
|
369 |
'post_variable' => $this->party,
|
370 |
-
'message' => sprintf( __( 'We only accept bookings for parties of up to %d people.',
|
371 |
);
|
372 |
}
|
373 |
}
|
@@ -378,13 +396,32 @@ class rtbBooking {
|
|
378 |
$this->validation_errors[] = array(
|
379 |
'field' => 'email',
|
380 |
'post_variable' => $this->email,
|
381 |
-
'message' => __( 'Please enter an email address so we can confirm your booking.',
|
382 |
);
|
383 |
}
|
384 |
|
385 |
// Phone/Message
|
386 |
$this->phone = empty( $_POST['rtb-phone'] ) ? '' : sanitize_text_field( stripslashes_deep( $_POST['rtb-phone'] ) );
|
387 |
-
$this->message = empty( $_POST['rtb-message'] ) ? '' :
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
388 |
|
389 |
do_action( 'rtb_validate_booking_submission', $this );
|
390 |
|
@@ -392,12 +429,32 @@ class rtbBooking {
|
|
392 |
|
393 |
/**
|
394 |
* Check if submission is valid
|
|
|
395 |
* @since 0.0.1
|
396 |
*/
|
397 |
public function is_valid_submission() {
|
|
|
398 |
if ( !count( $this->validation_errors ) ) {
|
399 |
return true;
|
400 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
401 |
return false;
|
402 |
}
|
403 |
|
@@ -412,9 +469,13 @@ class rtbBooking {
|
|
412 |
'post_title' => $this->name,
|
413 |
'post_content' => $this->message,
|
414 |
'post_date' => $this->date,
|
415 |
-
'post_status' =>
|
416 |
);
|
417 |
|
|
|
|
|
|
|
|
|
418 |
$args = apply_filters( 'rtb_insert_booking_data', $args, $this );
|
419 |
|
420 |
$id = wp_insert_post( $args );
|
60 |
$this->ID = $post->ID;
|
61 |
$this->name = $post->post_title;
|
62 |
$this->date = $post->post_date;
|
63 |
+
$this->message = $post->post_content;
|
64 |
$this->post_status = $post->post_status;
|
65 |
|
66 |
$this->load_post_metadata();
|
95 |
$this->date_submission = $meta['date_submission'];
|
96 |
}
|
97 |
|
98 |
+
/**
|
99 |
+
* Prepare booking data loaded from the database for display in a booking
|
100 |
+
* form as request fields. This is used, eg, for splitting datetime values
|
101 |
+
* into date and time fields.
|
102 |
+
* @since 1.3
|
103 |
+
*/
|
104 |
+
public function prepare_request_data() {
|
105 |
+
|
106 |
+
// Split $date to $request_date and $request_time
|
107 |
+
if ( empty( $this->request_date ) || empty( $this->request_time ) ) {
|
108 |
+
$date = new DateTime( $this->date );
|
109 |
+
$this->request_date = $date->format( 'Y/m/d' );
|
110 |
+
$this->request_time = $date->format( 'h:i A' );
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
/**
|
115 |
* Format date
|
116 |
* @since 0.0.1
|
137 |
|
138 |
$this->request_processed = true;
|
139 |
|
140 |
+
if ( empty( $this->ID ) ) {
|
141 |
+
$action = 'insert';
|
142 |
+
} else {
|
143 |
+
$action = 'update';
|
144 |
+
}
|
145 |
+
|
146 |
$this->validate_submission();
|
147 |
if ( $this->is_valid_submission() === false ) {
|
148 |
return false;
|
154 |
$this->request_inserted = true;
|
155 |
}
|
156 |
|
157 |
+
do_action( 'rtb_' . $action . '_booking', $this );
|
158 |
|
159 |
return true;
|
160 |
}
|
175 |
$this->validation_errors[] = array(
|
176 |
'field' => 'date',
|
177 |
'error_msg' => 'Booking request missing date',
|
178 |
+
'message' => __( 'Please enter the date you would like to book.', 'restaurant-reservations' ),
|
179 |
);
|
180 |
|
181 |
} else {
|
185 |
$this->validation_errors[] = array(
|
186 |
'field' => 'date',
|
187 |
'error_msg' => $e->getMessage(),
|
188 |
+
'message' => __( 'The date you entered is not valid. Please select from one of the dates in the calendar.', 'restaurant-reservations' ),
|
189 |
);
|
190 |
}
|
191 |
}
|
196 |
$this->validation_errors[] = array(
|
197 |
'field' => 'time',
|
198 |
'error_msg' => 'Booking request missing time',
|
199 |
+
'message' => __( 'Please enter the time you would like to book.', 'restaurant-reservations' ),
|
200 |
);
|
201 |
|
202 |
} else {
|
206 |
$this->validation_errors[] = array(
|
207 |
'field' => 'time',
|
208 |
'error_msg' => $e->getMessage(),
|
209 |
+
'message' => __( 'The time you entered is not valid. Please select from one of the times provided.', 'restaurant-reservations' ),
|
210 |
);
|
211 |
}
|
212 |
}
|
223 |
$this->validation_errors[] = array(
|
224 |
'field' => 'time',
|
225 |
'error_msg' => 'Booking request too far in the future',
|
226 |
+
'message' => sprintf( __( 'Sorry, bookings can not be made more than %s days in advance.', 'restaurant-reservations' ), $early_bookings ),
|
227 |
);
|
228 |
}
|
229 |
}
|
234 |
$this->validation_errors[] = array(
|
235 |
'field' => 'time',
|
236 |
'error_msg' => 'Booking request in the past',
|
237 |
+
'message' => __( 'Sorry, bookings can not be made in the past.', 'restaurant-reservations' ),
|
238 |
);
|
239 |
}
|
240 |
|
242 |
$late_bookings_seconds = $late_bookings * 60; // Late bookings allowance in seconds
|
243 |
if ( $request->format( 'U' ) < ( current_time( 'timestamp' ) + $late_bookings_seconds ) ) {
|
244 |
if ( $late_bookings >= 1440 ) {
|
245 |
+
$late_bookings_message = sprintf( __( 'Sorry, bookings must be made more than %s days in advance.', 'restaurant-reservations' ), $late_bookings / 1440 );
|
246 |
} elseif ( $late_bookings >= 60 ) {
|
247 |
+
$late_bookings_message = sprintf( __( 'Sorry, bookings must be made more than %s hours in advance.', 'restaurant-reservations' ), $late_bookings / 60 );
|
248 |
} else {
|
249 |
+
$late_bookings_message = sprintf( __( 'Sorry, bookings must be made more than %s mings in advance.', 'restaurant-reservations' ), $late_bookings );
|
250 |
}
|
251 |
$this->validation_errors[] = array(
|
252 |
'field' => 'time',
|
285 |
$this->validation_errors[] = array(
|
286 |
'field' => 'date',
|
287 |
'error_msg' => 'Booking request made on invalid date or time in an exception rule',
|
288 |
+
'message' => __( 'Sorry, no bookings are being accepted then.', 'restaurant-reservations' ),
|
289 |
);
|
290 |
}
|
291 |
}
|
337 |
$this->validation_errors[] = array(
|
338 |
'field' => 'date',
|
339 |
'error_msg' => 'Booking request made on an invalid date',
|
340 |
+
'message' => __( 'Sorry, no bookings are being accepted on that date.', 'restaurant-reservations' ),
|
341 |
);
|
342 |
} elseif ( !$time_is_valid ) {
|
343 |
$this->validation_errors[] = array(
|
344 |
'field' => 'time',
|
345 |
'error_msg' => 'Booking request made at an invalid time',
|
346 |
+
'message' => __( 'Sorry, no bookings are being accepted at that time.', 'restaurant-reservations' ),
|
347 |
);
|
348 |
}
|
349 |
}
|
365 |
$this->validation_errors[] = array(
|
366 |
'field' => 'name',
|
367 |
'post_variable' => $this->name,
|
368 |
+
'message' => __( 'Please enter a name for this booking.', 'restaurant-reservations' ),
|
369 |
);
|
370 |
}
|
371 |
|
372 |
// Party
|
373 |
+
$this->party = empty( $_POST['rtb-party'] ) ? '' : absint( $_POST['rtb-party'] );
|
374 |
if ( empty( $this->party ) ) {
|
375 |
$this->validation_errors[] = array(
|
376 |
'field' => 'party',
|
377 |
'post_variable' => $this->party,
|
378 |
+
'message' => __( 'Please let us know how many people will be in your party.', 'restaurant-reservations' ),
|
379 |
);
|
380 |
|
381 |
// Check party size
|
382 |
+
} else {
|
|
|
|
|
|
|
|
|
383 |
$party_size = $rtb_controller->settings->get_setting( 'party-size' );
|
384 |
+
if ( !empty( $party_size ) && $party_size < $this->party ) {
|
385 |
$this->validation_errors[] = array(
|
386 |
'field' => 'party',
|
387 |
'post_variable' => $this->party,
|
388 |
+
'message' => sprintf( __( 'We only accept bookings for parties of up to %d people.', 'restaurant-reservations' ), $party_size ),
|
389 |
);
|
390 |
}
|
391 |
}
|
396 |
$this->validation_errors[] = array(
|
397 |
'field' => 'email',
|
398 |
'post_variable' => $this->email,
|
399 |
+
'message' => __( 'Please enter an email address so we can confirm your booking.', 'restaurant-reservations' ),
|
400 |
);
|
401 |
}
|
402 |
|
403 |
// Phone/Message
|
404 |
$this->phone = empty( $_POST['rtb-phone'] ) ? '' : sanitize_text_field( stripslashes_deep( $_POST['rtb-phone'] ) );
|
405 |
+
$this->message = empty( $_POST['rtb-message'] ) ? '' : nl2br( wp_kses_post( stripslashes_deep( $_POST['rtb-message'] ) ) );
|
406 |
+
|
407 |
+
// Post Status (define a default post status is none passed)
|
408 |
+
if ( !empty( $_POST['rtb-post-status'] ) && array_key_exists( $_POST['rtb-post-status'], $rtb_controller->cpts->booking_statuses ) ) {
|
409 |
+
$this->status = sanitize_text_field( stripslashes_deep( $_POST['rtb-post-status'] ) );
|
410 |
+
} else {
|
411 |
+
$this->status = 'pending';
|
412 |
+
}
|
413 |
+
|
414 |
+
// Check if any required fields are empty
|
415 |
+
$required_fields = $rtb_controller->settings->get_required_fields();
|
416 |
+
foreach( $required_fields as $slug => $field ) {
|
417 |
+
if ( !$this->field_has_error( $slug ) && empty( $_POST[ 'rtb-' . $slug ] ) ) {
|
418 |
+
$this->validation_errors[] = array(
|
419 |
+
'field' => $slug,
|
420 |
+
'post_variable' => '',
|
421 |
+
'message' => __( 'Please complete this field to request a booking.', 'restaurant-reservations' ),
|
422 |
+
);
|
423 |
+
}
|
424 |
+
}
|
425 |
|
426 |
do_action( 'rtb_validate_booking_submission', $this );
|
427 |
|
429 |
|
430 |
/**
|
431 |
* Check if submission is valid
|
432 |
+
*
|
433 |
* @since 0.0.1
|
434 |
*/
|
435 |
public function is_valid_submission() {
|
436 |
+
|
437 |
if ( !count( $this->validation_errors ) ) {
|
438 |
return true;
|
439 |
}
|
440 |
+
|
441 |
+
return false;
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Check if a field already has an error attached to it
|
446 |
+
*
|
447 |
+
* @field string Field slug
|
448 |
+
* @since 1.3
|
449 |
+
*/
|
450 |
+
public function field_has_error( $field_slug ) {
|
451 |
+
|
452 |
+
foreach( $this->validation_errors as $error ) {
|
453 |
+
if ( $error['field'] == $field_slug ) {
|
454 |
+
return true;
|
455 |
+
}
|
456 |
+
}
|
457 |
+
|
458 |
return false;
|
459 |
}
|
460 |
|
469 |
'post_title' => $this->name,
|
470 |
'post_content' => $this->message,
|
471 |
'post_date' => $this->date,
|
472 |
+
'post_status' => $this->status,
|
473 |
);
|
474 |
|
475 |
+
if ( !empty( $this->ID ) ) {
|
476 |
+
$args['ID'] = $this->ID;
|
477 |
+
}
|
478 |
+
|
479 |
$args = apply_filters( 'rtb_insert_booking_data', $args, $this );
|
480 |
|
481 |
$id = wp_insert_post( $args );
|
includes/Compatibility.class.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( !defined( 'ABSPATH' ) ) exit;
|
3 |
+
|
4 |
+
if ( !class_exists( 'rtbCompatibility' ) ) {
|
5 |
+
/**
|
6 |
+
* Class to handle backwards compatibilty issues for Restaurant Reservations
|
7 |
+
*
|
8 |
+
* @since 1.3
|
9 |
+
*/
|
10 |
+
class rtbCompatibility {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Set up hooks
|
14 |
+
*/
|
15 |
+
public function __construct() {
|
16 |
+
|
17 |
+
// Preserve this defined constant in case anyone relied on it
|
18 |
+
// to check if the plugin was active
|
19 |
+
define( 'RTB_TEXTDOMAIN', 'rtbdomain' );
|
20 |
+
|
21 |
+
// Load a .mo file for an old textdomain if one exists
|
22 |
+
add_filter( 'load_textdomain_mofile', array( $this, 'load_old_textdomain' ), 10, 2 );
|
23 |
+
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Load a .mo file for an old textdomain if one exists
|
28 |
+
*
|
29 |
+
* In versions prior to 1.3, the textdomain did not match the plugin
|
30 |
+
* slug. This had to be changed to comply with upcoming changes to
|
31 |
+
* how translations are managed in the .org repo. This function
|
32 |
+
* checks to see if an old translation file exists and loads it if
|
33 |
+
* it does, so that people don't lose their translations.
|
34 |
+
*
|
35 |
+
* Old textdomain: rtbdomain
|
36 |
+
*/
|
37 |
+
public function load_old_textdomain( $mofile, $textdomain ) {
|
38 |
+
|
39 |
+
if ( $textdomain === 'restaurant-reservations' && 0 === strpos( $mofile, WP_LANG_DIR . '/plugins/' ) && !file_exists( $mofile ) ) {
|
40 |
+
$mofile = dirname( $mofile ) . DIRECTORY_SEPARATOR . str_replace( $textdomain, 'rtbdomain', basename( $mofile ) );
|
41 |
+
}
|
42 |
+
|
43 |
+
return $mofile;
|
44 |
+
}
|
45 |
+
|
46 |
+
}
|
47 |
+
} // endif
|
includes/CustomPostTypes.class.php
CHANGED
@@ -35,19 +35,19 @@ class rtbCustomPostTypes {
|
|
35 |
// Define the booking custom post type
|
36 |
$args = array(
|
37 |
'labels' => array(
|
38 |
-
'name' => __( 'Bookings',
|
39 |
-
'singular_name' => __( 'Booking',
|
40 |
-
'menu_name' => __( 'Bookings',
|
41 |
-
'name_admin_bar' => __( 'Bookings',
|
42 |
-
'add_new' => __( 'Add New',
|
43 |
-
'add_new_item' => __( 'Add New Booking',
|
44 |
-
'edit_item' => __( 'Edit Booking',
|
45 |
-
'new_item' => __( 'New Booking',
|
46 |
-
'view_item' => __( 'View Booking',
|
47 |
-
'search_items' => __( 'Search Bookings',
|
48 |
-
'not_found' => __( 'No bookings found',
|
49 |
-
'not_found_in_trash' => __( 'No bookings found in trash',
|
50 |
-
'all_items' => __( 'All Bookings',
|
51 |
),
|
52 |
'menu_icon' => 'dashicons-calendar',
|
53 |
'public' => false,
|
@@ -77,31 +77,31 @@ class rtbCustomPostTypes {
|
|
77 |
public function set_booking_statuses() {
|
78 |
|
79 |
$this->booking_statuses['pending'] = array(
|
80 |
-
'label' => _x( 'Pending', 'Booking status when it is pending review',
|
81 |
'default' => true, // Whether or not this status is part of WP Core
|
82 |
'user_selectable' => true, // Whether or not a user can set a booking to this status
|
83 |
);
|
84 |
|
85 |
$this->booking_statuses['confirmed'] = array (
|
86 |
-
'label' => _x( 'Confirmed', 'Booking status for a confirmed booking',
|
87 |
'default' => false, // Whether or not this status is part of WP Core
|
88 |
'user_selectable' => true, // Whether or not a user can set a booking to this status
|
89 |
'public' => false,
|
90 |
'exclude_from_search' => true,
|
91 |
'show_in_admin_all_list' => true,
|
92 |
'show_in_admin_status_list' => true,
|
93 |
-
'label_count' => _n_noop( 'Confirmed <span class="count">(%s)</span>', 'Confirmed <span class="count">(%s)</span>',
|
94 |
);
|
95 |
|
96 |
$this->booking_statuses['closed'] = array(
|
97 |
-
'label' => _x( 'Closed', 'Booking status for a closed booking',
|
98 |
'default' => false, // Whether or not this status is part of WP Core
|
99 |
'user_selectable' => true, // Whether or not a user can set a booking to this status
|
100 |
'public' => false,
|