Events Manager - Version 5.9.11

Version Description

= * updated JS to remove any deprecated functionality in jQuery v3.5, * changed timepicker library to (timepicker)[https://github.com/jonthornton/jquery-timepicker/] * added $target to Event_Location->output() function parameters * fixed EM_Event->output() errors causing booking emails to fail if containing #EVENTLOCATION placeholders for non-virtual events * added $send_email and $ignore_spaces params to EM_Bookings::set_status() * added em_booking_admin action to top of single booking admin area * added updatemeta() function to EM_Booking, * fixed some minor PHP warnings, * added ticket availability re-check during EM_Booking::validate() for bookings stored in session before saving

Download this release

Release Info

Developer netweblogic
Plugin Icon 128x128 Events Manager
Version 5.9.11
Comparing to
See all releases

Code changes from version 5.9.10 to 5.9.11

Files changed (75) hide show
  1. admin/em-bookings.php +7 -6
  2. admin/em-ms-options.php +6 -6
  3. admin/em-options.php +5 -5
  4. admin/settings/tabs/general.php +2 -2
  5. classes/em-booking.php +40 -9
  6. classes/em-bookings.php +4 -2
  7. classes/em-event-posts-admin.php +2 -2
  8. classes/em-event.php +7 -5
  9. classes/em-ticket.php +2 -1
  10. classes/em-tickets-bookings.php +15 -5
  11. classes/em-tickets.php +8 -2
  12. classes/event-locations/em-event-location-url.php +1 -1
  13. classes/event-locations/em-event-location.php +1 -1
  14. events-manager.php +3 -3
  15. includes/css/events_manager.css +3 -7
  16. includes/css/events_manager_admin.css +1 -5
  17. includes/js/admin-settings.js +16 -16
  18. includes/js/events-manager.js +57 -45
  19. readme.txt +18 -3
  20. templates/forms/event/bookings-ticket-form.php +2 -2
  21. templates/forms/event/recurring-when.php +2 -2
  22. templates/forms/event/when-with-recurring.php +3 -3
  23. templates/forms/event/when.php +2 -2
  24. templates/templates/search/geo.js +2 -2
  25. trunk/admin/bookings/em-cancelled.php +0 -137
  26. trunk/admin/bookings/em-confirmed.php +0 -144
  27. trunk/admin/bookings/em-events.php +0 -153
  28. trunk/admin/bookings/em-pending.php +0 -159
  29. trunk/admin/bookings/em-person.php +0 -152
  30. trunk/admin/bookings/em-rejected.php +0 -137
  31. trunk/admin/em-admin.php +0 -324
  32. trunk/admin/em-bookings.php +0 -560
  33. trunk/admin/em-data-privacy.php +0 -531
  34. trunk/admin/em-docs.php +0 -464
  35. trunk/admin/em-help.php +0 -72
  36. trunk/admin/em-ms-locations.php +0 -52
  37. trunk/admin/em-ms-options.php +0 -248
  38. trunk/admin/em-options.php +0 -1042
  39. trunk/admin/settings/tabs/bookings.php +0 -153
  40. trunk/admin/settings/tabs/emails.php +0 -177
  41. trunk/admin/settings/tabs/formats.php +0 -465
  42. trunk/admin/settings/tabs/general.php +0 -358
  43. trunk/admin/settings/tabs/pages.php +0 -724
  44. trunk/admin/settings/updates/timezone-backcompat.php +0 -112
  45. trunk/admin/settings/wpfc-admin.php +0 -48
  46. trunk/buddypress/bp-em-activity.php +0 -221
  47. trunk/buddypress/bp-em-core.php +0 -352
  48. trunk/buddypress/bp-em-groups.php +0 -151
  49. trunk/buddypress/bp-em-notifications.php +0 -91
  50. trunk/buddypress/bp-em-templatetags.php +0 -21
  51. trunk/buddypress/screens/attending.php +0 -29
  52. trunk/buddypress/screens/group-events.php +0 -30
  53. trunk/buddypress/screens/my-bookings.php +0 -37
  54. trunk/buddypress/screens/my-events.php +0 -55
  55. trunk/buddypress/screens/my-group-events.php +0 -27
  56. trunk/buddypress/screens/my-locations.php +0 -51
  57. trunk/buddypress/screens/profile.php +0 -32
  58. trunk/classes/em-admin-notice.php +0 -178
  59. trunk/classes/em-admin-notices.php +0 -204
  60. trunk/classes/em-booking.php +0 -1310
  61. trunk/classes/em-bookings-table.php +0 -673
  62. trunk/classes/em-bookings.php +0 -835
  63. trunk/classes/em-calendar.php +0 -485
  64. trunk/classes/em-categories-admin.php +0 -61
  65. trunk/classes/em-categories-frontend.php +0 -125
  66. trunk/classes/em-categories.php +0 -72
  67. trunk/classes/em-category.php +0 -32
  68. trunk/classes/em-datetime.php +0 -339
  69. trunk/classes/em-datetimezone.php +0 -83
  70. trunk/classes/em-event-post-admin.php +0 -528
  71. trunk/classes/em-event-post.php +0 -350
  72. trunk/classes/em-event-posts-admin.php +0 -421
  73. trunk/classes/em-event.php +0 -3547
  74. trunk/classes/em-events.php +0 -740
  75. trunk/classes/em-exception.php +0 -68
admin/em-bookings.php CHANGED
@@ -186,6 +186,7 @@ function em_bookings_single(){
186
  <?php
187
  return false;
188
  }
 
189
  ?>
190
  <div class='wrap' id="em-bookings-admin-booking">
191
  <?php if( is_admin() ): ?><h1><?php else: ?><h2><?php endif; ?>
@@ -239,11 +240,11 @@ function em_bookings_single(){
239
  </form>
240
  <script type="text/javascript">
241
  jQuery(document).ready( function($){
242
- $('#em-booking-person-modify').click(function(){
243
  $('.em-booking-person-details').hide();
244
  $('.em-booking-person-editor').show();
245
  });
246
- $('#em-booking-person-modify-cancel').click(function(){
247
  $('.em-booking-person-details').show();
248
  $('.em-booking-person-editor').hide();
249
  });
@@ -424,22 +425,22 @@ function em_bookings_single(){
424
  </form>
425
  <script type="text/javascript">
426
  jQuery(document).ready( function($){
427
- $('#em-booking-submit-modify').click(function(){
428
  $('.em-booking-single-info').hide();
429
  $('.em-booking-single-edit').show();
430
  });
431
- $('#em-booking-submit-cancel').click(function(){
432
  $('.em-booking-single-info').show();
433
  $('.em-booking-single-edit').hide();
434
  });
435
  $('.em-booking-single-info').show();
436
  $('.em-booking-single-edit').hide();
437
 
438
- $('#em-booking-submit-status-modify').click(function(){
439
  $('.em-booking-single-status-info').hide();
440
  $('.em-booking-single-status-edit').show();
441
  });
442
- $('#em-booking-submit-status-cancel').click(function(){
443
  $('.em-booking-single-status-info').show();
444
  $('.em-booking-single-status-edit').hide();
445
  });
186
  <?php
187
  return false;
188
  }
189
+ do_action('em_booking_admin', $EM_Booking);
190
  ?>
191
  <div class='wrap' id="em-bookings-admin-booking">
192
  <?php if( is_admin() ): ?><h1><?php else: ?><h2><?php endif; ?>
240
  </form>
241
  <script type="text/javascript">
242
  jQuery(document).ready( function($){
243
+ $('#em-booking-person-modify').on('click', function(){
244
  $('.em-booking-person-details').hide();
245
  $('.em-booking-person-editor').show();
246
  });
247
+ $('#em-booking-person-modify-cancel').on('click', function(){
248
  $('.em-booking-person-details').show();
249
  $('.em-booking-person-editor').hide();
250
  });
425
  </form>
426
  <script type="text/javascript">
427
  jQuery(document).ready( function($){
428
+ $('#em-booking-submit-modify').on('click', function(){
429
  $('.em-booking-single-info').hide();
430
  $('.em-booking-single-edit').show();
431
  });
432
+ $('#em-booking-submit-cancel').on('click', function(){
433
  $('.em-booking-single-info').show();
434
  $('.em-booking-single-edit').hide();
435
  });
436
  $('.em-booking-single-info').show();
437
  $('.em-booking-single-edit').hide();
438
 
439
+ $('#em-booking-submit-status-modify').on('click', function(){
440
  $('.em-booking-single-status-info').hide();
441
  $('.em-booking-single-status-edit').show();
442
  });
443
+ $('#em-booking-submit-status-cancel').on('click', function(){
444
  $('.em-booking-single-status-info').show();
445
  $('.em-booking-single-status-edit').hide();
446
  });
admin/em-ms-options.php CHANGED
@@ -84,7 +84,7 @@ function em_ms_admin_options_page() {
84
  <script type="text/javascript" charset="utf-8">
85
  jQuery(document).ready(function($){
86
  //events
87
- $('input[name="dbem_ms_global_events"]').change(function(){
88
  if( $('input:radio[name="dbem_ms_global_events"]:checked').val() == 1 ){
89
  $("tr#dbem_ms_global_events_links_row").show();
90
  $('input:radio[name="dbem_ms_global_events_links"]:checked').trigger('change');
@@ -92,7 +92,7 @@ function em_ms_admin_options_page() {
92
  $("tr#dbem_ms_global_events_links_row, tr#dbem_ms_events_slug_row").hide();
93
  }
94
  }).first().trigger('change');
95
- $('input[name="dbem_ms_global_events_links"]').change(function(){
96
  if( $('input:radio[name="dbem_ms_global_events_links"]:checked').val() == 1 ){
97
  $("tr#dbem_ms_events_slug_row").hide();
98
  }else{
@@ -100,14 +100,14 @@ function em_ms_admin_options_page() {
100
  }
101
  }).first().trigger('change');
102
  //locations
103
- $('input[name="dbem_ms_mainblog_locations"]').change(function(){
104
  if( $('input:radio[name="dbem_ms_mainblog_locations"]:checked').val() == 1 ){
105
  $("tbody.em-global-locations").hide();
106
  }else{
107
  $("tbody.em-global-locations").show();
108
  }
109
  }).first().trigger('change');
110
- $('input[name="dbem_ms_global_locations"]').change(function(){
111
  if( $('input:radio[name="dbem_ms_global_locations"]:checked').val() == 1 ){
112
  $("tr#dbem_ms_global_locations_links_row").show();
113
  $('input:radio[name="dbem_ms_global_locations_links"]:checked').trigger('change');
@@ -115,7 +115,7 @@ function em_ms_admin_options_page() {
115
  $("tr#dbem_ms_global_locations_links_row, tr#dbem_ms_locations_slug_row").hide();
116
  }
117
  }).first().trigger('change');
118
- $('input[name="dbem_ms_global_locations_links"]').change(function(){
119
  if( $('input:radio[name="dbem_ms_global_locations_links"]:checked').val() == 1 ){
120
  $("tr#dbem_ms_locations_slug_row").hide();
121
  }else{
@@ -123,7 +123,7 @@ function em_ms_admin_options_page() {
123
  }
124
  });
125
  //MS Mode selection hiders
126
- $('input[name="dbem_ms_global_table"]').change(function(){ //global
127
  if( $('input:radio[name="dbem_ms_global_table"]:checked').val() == 1 ){
128
  $("tbody.em-global-options").show();
129
  $('input:radio[name="dbem_ms_mainblog_locations"]:checked').trigger('change');
84
  <script type="text/javascript" charset="utf-8">
85
  jQuery(document).ready(function($){
86
  //events
87
+ $('input[name="dbem_ms_global_events"]').on('change', function(){
88
  if( $('input:radio[name="dbem_ms_global_events"]:checked').val() == 1 ){
89
  $("tr#dbem_ms_global_events_links_row").show();
90
  $('input:radio[name="dbem_ms_global_events_links"]:checked').trigger('change');
92
  $("tr#dbem_ms_global_events_links_row, tr#dbem_ms_events_slug_row").hide();
93
  }
94
  }).first().trigger('change');
95
+ $('input[name="dbem_ms_global_events_links"]').on('change', function(){
96
  if( $('input:radio[name="dbem_ms_global_events_links"]:checked').val() == 1 ){
97
  $("tr#dbem_ms_events_slug_row").hide();
98
  }else{
100
  }
101
  }).first().trigger('change');
102
  //locations
103
+ $('input[name="dbem_ms_mainblog_locations"]').on('change', function(){
104
  if( $('input:radio[name="dbem_ms_mainblog_locations"]:checked').val() == 1 ){
105
  $("tbody.em-global-locations").hide();
106
  }else{
107
  $("tbody.em-global-locations").show();
108
  }
109
  }).first().trigger('change');
110
+ $('input[name="dbem_ms_global_locations"]').on('change', function(){
111
  if( $('input:radio[name="dbem_ms_global_locations"]:checked').val() == 1 ){
112
  $("tr#dbem_ms_global_locations_links_row").show();
113
  $('input:radio[name="dbem_ms_global_locations_links"]:checked').trigger('change');
115
  $("tr#dbem_ms_global_locations_links_row, tr#dbem_ms_locations_slug_row").hide();
116
  }
117
  }).first().trigger('change');
118
+ $('input[name="dbem_ms_global_locations_links"]').on('change', function(){
119
  if( $('input:radio[name="dbem_ms_global_locations_links"]:checked').val() == 1 ){
120
  $("tr#dbem_ms_locations_slug_row").hide();
121
  }else{
123
  }
124
  });
125
  //MS Mode selection hiders
126
+ $('input[name="dbem_ms_global_table"]').on('change', function(){ //global
127
  if( $('input:radio[name="dbem_ms_global_table"]:checked').val() == 1 ){
128
  $("tbody.em-global-options").show();
129
  $('input:radio[name="dbem_ms_mainblog_locations"]:checked').trigger('change');
admin/em-options.php CHANGED
@@ -629,7 +629,7 @@ function em_admin_option_box_email(){
629
  </table>
630
  <script type="text/javascript" charset="utf-8">
631
  jQuery(document).ready(function($){
632
- $('#dbem_rsvp_mail_send_method_row select').change(function(){
633
  el = $(this);
634
  if( el.find(':selected').val() == 'smtp' ){
635
  $('.em-email-settings-smtp').show();
@@ -637,7 +637,7 @@ function em_admin_option_box_email(){
637
  $('.em-email-settings-smtp').hide();
638
  }
639
  }).trigger('change');
640
- $('input#em-admin-check-email').click(function(e,el){
641
  var email_data = $('.em-email-form input, .em-email-form select').serialize();
642
  $.ajax({
643
  url: EM.ajaxurl,
@@ -837,7 +837,7 @@ function em_admin_option_box_uninstall(){
837
  </td>
838
  <script type="text/javascript" charset="utf-8">
839
  jQuery(document).ready(function($){
840
- $('a#em-admin-import-settings').click(function(e,el){
841
  var thisform = $(this).closest('form');
842
  thisform.find('input[type=text], textarea, select, input[type=radio], input[type=hidden]').prop('disabled', true);
843
  thisform.find('input[name=_wpnonce]').val('<?php echo esc_attr($import_nonce); ?>').prop('disabled', false);
@@ -931,14 +931,14 @@ function em_admin_option_box_uninstall(){
931
  </td>
932
  <script type="text/javascript" charset="utf-8">
933
  jQuery(document).ready(function($){
934
- $('select[name="timezone_reset_value"]').change( function( e ){
935
  if( $(this).val() == '' ){
936
  $('a#em-reset-event-timezones').css({opacity:0.5, cursor:'default'});
937
  }else{
938
  $('a#em-reset-event-timezones').css({opacity:1, cursor:'pointer'});
939
  }
940
  }).trigger('change');
941
- $('a#em-reset-event-timezones').click(function(e,el){
942
  if( $('select[name="timezone_reset_value"]').val() == '' ) return false;
943
  var thisform = $(this).closest('form');
944
  thisform.find('input, textarea, select').prop('disabled', true);
629
  </table>
630
  <script type="text/javascript" charset="utf-8">
631
  jQuery(document).ready(function($){
632
+ $('#dbem_rsvp_mail_send_method_row select').on('change', function(){
633
  el = $(this);
634
  if( el.find(':selected').val() == 'smtp' ){
635
  $('.em-email-settings-smtp').show();
637
  $('.em-email-settings-smtp').hide();
638
  }
639
  }).trigger('change');
640
+ $('input#em-admin-check-email').on('click', function(e,el){
641
  var email_data = $('.em-email-form input, .em-email-form select').serialize();
642
  $.ajax({
643
  url: EM.ajaxurl,
837
  </td>
838
  <script type="text/javascript" charset="utf-8">
839
  jQuery(document).ready(function($){
840
+ $('a#em-admin-import-settings').on('click', function(e,el){
841
  var thisform = $(this).closest('form');
842
  thisform.find('input[type=text], textarea, select, input[type=radio], input[type=hidden]').prop('disabled', true);
843
  thisform.find('input[name=_wpnonce]').val('<?php echo esc_attr($import_nonce); ?>').prop('disabled', false);
931
  </td>
932
  <script type="text/javascript" charset="utf-8">
933
  jQuery(document).ready(function($){
934
+ $('select[name="timezone_reset_value"]').on('change', function( e ){
935
  if( $(this).val() == '' ){
936
  $('a#em-reset-event-timezones').css({opacity:0.5, cursor:'default'});
937
  }else{
938
  $('a#em-reset-event-timezones').css({opacity:1, cursor:'pointer'});
939
  }
940
  }).trigger('change');
941
+ $('a#em-reset-event-timezones').on('click', function(e,el){
942
  if( $('select[name="timezone_reset_value"]').val() == '' ) return false;
943
  var thisform = $(this).closest('form');
944
  thisform.find('input, textarea, select').prop('disabled', true);
admin/settings/tabs/general.php CHANGED
@@ -292,7 +292,7 @@
292
  </table>
293
  <script type="text/javascript">
294
  jQuery(document).ready(function($){
295
- $('input:radio[name="dbem_js_limit"]').change(function(){
296
  if( $('input:radio[name="dbem_js_limit"]:checked').val() == 1 ){
297
  $('tbody#dbem-js-limit-options').show();
298
  }else{
@@ -300,7 +300,7 @@
300
  }
301
  }).trigger('change');
302
 
303
- $('input:radio[name="dbem_css_limit"]').change(function(){
304
  if( $('input:radio[name="dbem_css_limit"]:checked').val() == 1 ){
305
  $('tbody#dbem-css-limit-options').show();
306
  }else{
292
  </table>
293
  <script type="text/javascript">
294
  jQuery(document).ready(function($){
295
+ $('input:radio[name="dbem_js_limit"]').on('change', function(){
296
  if( $('input:radio[name="dbem_js_limit"]:checked').val() == 1 ){
297
  $('tbody#dbem-js-limit-options').show();
298
  }else{
300
  }
301
  }).trigger('change');
302
 
303
+ $('input:radio[name="dbem_css_limit"]').on('change', function(){
304
  if( $('input:radio[name="dbem_css_limit"]:checked').val() == 1 ){
305
  $('tbody#dbem-css-limit-options').show();
306
  }else{
classes/em-booking.php CHANGED
@@ -276,6 +276,22 @@ class EM_Booking extends EM_Object{
276
  return apply_filters('em_booking_save', false, $this, false);
277
  }
278
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  /**
280
  * Load a record into this object by passing an associative array of table criteria to search for.
281
  * Returns boolean depending on whether a record is found or not.
@@ -361,18 +377,32 @@ class EM_Booking extends EM_Object{
361
  foreach($this->get_tickets_bookings()->tickets_bookings as $EM_Ticket_Booking){ /* @var $EM_Ticket_Booking EM_Ticket_Booking */
362
  if ( !$EM_Ticket_Booking->validate() ){
363
  $ticket_validation[] = false;
364
- $result = $basic && !in_array(false,$ticket_validation);
365
  }
366
- $this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
367
  }
368
  $result = $basic && !in_array(false,$ticket_validation);
369
  }else{
370
  $result = false;
371
  }
372
- //is there enough space overall?
373
- if( !$override_availability && $this->get_event()->get_bookings()->get_available_spaces() < $this->get_spaces() ){
374
- $result = false;
375
- $this->add_error(get_option('dbem_booking_feedback_full'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  }
377
  //can we book this amount of spaces at once?
378
  if( $this->get_event()->event_rsvp_spaces > 0 && $this->get_spaces() > $this->get_event()->event_rsvp_spaces ){
@@ -624,7 +654,8 @@ class EM_Booking extends EM_Object{
624
  if( !empty($adjustment['amount']) ){
625
  if( !empty($adjustment['tax']) && $adjustment['tax'] == $pre_or_post ){
626
  if( !empty($adjustment['type']) ){
627
- $adjustment_summary_item = array('name' => $adjustment['name'], 'desc' => $adjustment['desc'], 'adjustment'=>'0', 'amount_adjusted'=>0, 'tax'=>$pre_or_post);
 
628
  if( $adjustment['type'] == '%' ){ //adjustment by percentage
629
  $adjustment_summary_item['amount_adjusted'] = round($price * ($adjustment['amount']/100),2);
630
  $adjustment_summary_item['amount'] = $this->format_price($adjustment_summary_item['amount_adjusted']);
@@ -716,7 +747,7 @@ class EM_Booking extends EM_Object{
716
 
717
  /**
718
  * Gets the ticket object this booking belongs to, saves a reference in ticket property
719
- * @return EM_Tickets_Bookings
720
  */
721
  function get_tickets_bookings(){
722
  global $wpdb;
@@ -1122,7 +1153,7 @@ class EM_Booking extends EM_Object{
1122
  break;
1123
  case '#_BOOKINGADMINURL':
1124
  case '#_BOOKINGADMINLINK':
1125
- $bookings_link = esc_url( add_query_arg('booking_id', $this->booking_id, $this->event->get_bookings_url()) );
1126
  if($result == '#_BOOKINGADMINLINK'){
1127
  $replace = '<a href="'.$bookings_link.'">'.esc_html__('Edit Booking', 'events-manager'). '</a>';
1128
  }else{
276
  return apply_filters('em_booking_save', false, $this, false);
277
  }
278
 
279
+ /**
280
+ * Update a specific key value in the booking meta data, or create one if it doesn't exist.
281
+ * @param $meta_key
282
+ * @param $meta_value
283
+ * @return bool
284
+ * @since 5.9.11
285
+ */
286
+ public function update_meta( $meta_key, $meta_value ){
287
+ global $wpdb;
288
+ if( !$this->booking_id ) return false;
289
+ $this->booking_meta[$meta_key] = $meta_value;
290
+ $booking_meta = serialize($this->booking_meta);
291
+ $result = $wpdb->update( EM_BOOKINGS_TABLE, array('booking_meta' => $booking_meta), array('booking_id' => $this->booking_id) );
292
+ return apply_filters('em_booking_update_meta', $result !== false, $meta_key, $meta_value, $this);
293
+ }
294
+
295
  /**
296
  * Load a record into this object by passing an associative array of table criteria to search for.
297
  * Returns boolean depending on whether a record is found or not.
377
  foreach($this->get_tickets_bookings()->tickets_bookings as $EM_Ticket_Booking){ /* @var $EM_Ticket_Booking EM_Ticket_Booking */
378
  if ( !$EM_Ticket_Booking->validate() ){
379
  $ticket_validation[] = false;
380
+ $this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
381
  }
 
382
  }
383
  $result = $basic && !in_array(false,$ticket_validation);
384
  }else{
385
  $result = false;
386
  }
387
+ if( !$override_availability ){
388
+ // are bookings even available due to event and ticket cut-offs/restrictions? This is checked earlier in booking processes, but is relevant in checkout/cart situations where a previously-made booking is validated just before checkout
389
+ if( $this->get_event()->rsvp_end()->getTimestamp() < time() ){
390
+ $result = false;
391
+ $this->add_error(get_option('dbem_bookings_form_msg_closed'));
392
+ }else{
393
+ foreach( $this->get_tickets_bookings() as $EM_Ticket_Booking ){
394
+ if( !$EM_Ticket_Booking->get_ticket()->is_available() ){
395
+ $result = false;
396
+ $message = __('The ticket %s is no longer available.', 'events-manager');
397
+ $this->add_error(get_option('dbem_booking_feedback_ticket_unavailable', sprintf($message, "'".$EM_Ticket_Booking->get_ticket()->name."'")));
398
+ }
399
+ }
400
+ }
401
+ //is there enough space overall?
402
+ if( $this->get_event()->get_bookings()->get_available_spaces() < $this->get_spaces() ){
403
+ $result = false;
404
+ $this->add_error(get_option('dbem_booking_feedback_full'));
405
+ }
406
  }
407
  //can we book this amount of spaces at once?
408
  if( $this->get_event()->event_rsvp_spaces > 0 && $this->get_spaces() > $this->get_event()->event_rsvp_spaces ){
654
  if( !empty($adjustment['amount']) ){
655
  if( !empty($adjustment['tax']) && $adjustment['tax'] == $pre_or_post ){
656
  if( !empty($adjustment['type']) ){
657
+ $desc = !empty($adjustment['desc']) ? $adjustment['desc'] : '';
658
+ $adjustment_summary_item = array('name' => $adjustment['name'], 'desc' => $desc, 'adjustment'=>'0', 'amount_adjusted'=>0, 'tax'=>$pre_or_post);
659
  if( $adjustment['type'] == '%' ){ //adjustment by percentage
660
  $adjustment_summary_item['amount_adjusted'] = round($price * ($adjustment['amount']/100),2);
661
  $adjustment_summary_item['amount'] = $this->format_price($adjustment_summary_item['amount_adjusted']);
747
 
748
  /**
749
  * Gets the ticket object this booking belongs to, saves a reference in ticket property
750
+ * @return EM_Tickets_Bookings EM_Tickets_Bookings
751
  */
752
  function get_tickets_bookings(){
753
  global $wpdb;
1153
  break;
1154
  case '#_BOOKINGADMINURL':
1155
  case '#_BOOKINGADMINLINK':
1156
+ $bookings_link = esc_url( add_query_arg('booking_id', $this->booking_id, $this->get_event()->get_bookings_url()) );
1157
  if($result == '#_BOOKINGADMINLINK'){
1158
  $replace = '<a href="'.$bookings_link.'">'.esc_html__('Edit Booking', 'events-manager'). '</a>';
1159
  }else{
classes/em-bookings.php CHANGED
@@ -367,9 +367,11 @@ class EM_Bookings extends EM_Object implements Iterator{
367
  /**
368
  * @param int $status
369
  * @param array|int $booking_ids
 
 
370
  * @return bool
371
  */
372
- function set_status($status, $booking_ids){
373
  //FIXME status should work with instantiated object
374
  if( self::array_is_numeric($booking_ids) ){
375
  //Get all the bookings
@@ -381,7 +383,7 @@ class EM_Bookings extends EM_Object implements Iterator{
381
  $this->feedback_message = __('Bookings %s. Mails Sent.', 'events-manager');
382
  return false;
383
  }
384
- $results[] = $EM_Booking->set_status($status);
385
  }
386
  if( !in_array('false',$results) ){
387
  $this->feedback_message = __('Bookings %s. Mails Sent.', 'events-manager');
367
  /**
368
  * @param int $status
369
  * @param array|int $booking_ids
370
+ * @param bool $send_email
371
+ * @param bool $ignore_spaces
372
  * @return bool
373
  */
374
+ function set_status( $status, $booking_ids, $send_email = true, $ignore_spaces = false ){
375
  //FIXME status should work with instantiated object
376
  if( self::array_is_numeric($booking_ids) ){
377
  //Get all the bookings
383
  $this->feedback_message = __('Bookings %s. Mails Sent.', 'events-manager');
384
  return false;
385
  }
386
+ $results[] = $EM_Booking->set_status($status, $send_email, $ignore_spaces);
387
  }
388
  if( !in_array('false',$results) ){
389
  $this->feedback_message = __('Bookings %s. Mails Sent.', 'events-manager');
classes/em-event-posts-admin.php CHANGED
@@ -40,13 +40,13 @@ class EM_Event_Posts_Admin{
40
  <script type="text/javascript">
41
  jQuery(document).ready( function($){
42
  $('.inline-edit-date').prev().css('display','none').next().css('display','none').next().css('display','none');
43
- $('.em-detach-link').click(function( event ){
44
  if( !confirm(EM.event_detach_warning) ){
45
  event.preventDefault();
46
  return false;
47
  }
48
  });
49
- $('.em-delete-recurrence-link').click(function( event ){
50
  if( !confirm(EM.delete_recurrence_warning) ){
51
  event.preventDefault();
52
  return false;
40
  <script type="text/javascript">
41
  jQuery(document).ready( function($){
42
  $('.inline-edit-date').prev().css('display','none').next().css('display','none').next().css('display','none');
43
+ $('.em-detach-link').on('click', function( event ){
44
  if( !confirm(EM.event_detach_warning) ){
45
  event.preventDefault();
46
  return false;
47
  }
48
  });
49
+ $('.em-delete-recurrence-link').on('click', function( event ){
50
  if( !confirm(EM.delete_recurrence_warning) ){
51
  event.preventDefault();
52
  return false;
classes/em-event.php CHANGED
@@ -2410,7 +2410,7 @@ class EM_Event extends EM_Object{
2410
  }
2411
  }
2412
  }
2413
- if( $min === false ) $min = 0;
2414
  if( $min != $max ){
2415
  $replace = em_get_currency_formatted($min).' - '.em_get_currency_formatted($max);
2416
  }else{
@@ -2635,10 +2635,12 @@ class EM_Event extends EM_Object{
2635
  break;
2636
  //Event location (not physical location)
2637
  case '#_EVENTLOCATION':
2638
- if( !empty($placeholders[3][$key]) ){
2639
- $replace = $this->get_event_location()->output($placeholders[3][$key]);
2640
- }else{
2641
- $replace = $this->get_event_location()->output();
 
 
2642
  }
2643
  break;
2644
  default:
2410
  }
2411
  }
2412
  }
2413
+ if( empty($min) ) $min = 0;
2414
  if( $min != $max ){
2415
  $replace = em_get_currency_formatted($min).' - '.em_get_currency_formatted($max);
2416
  }else{
2635
  break;
2636
  //Event location (not physical location)
2637
  case '#_EVENTLOCATION':
2638
+ if( $this->has_event_location() ) {
2639
+ if (!empty($placeholders[3][$key])) {
2640
+ $replace = $this->get_event_location()->output( $placeholders[3][$key], $target );
2641
+ } else {
2642
+ $replace = $this->get_event_location()->output( null, $target );
2643
+ }
2644
  }
2645
  break;
2646
  default:
classes/em-ticket.php CHANGED
@@ -111,6 +111,7 @@ class EM_Ticket extends EM_Object{
111
  }
112
  }
113
  $this->compat_keys();
 
114
  do_action('em_ticket',$this, $ticket_data, $ticket);
115
  }
116
 
@@ -429,7 +430,7 @@ class EM_Ticket extends EM_Object{
429
  */
430
  function get_price_without_tax( $format = false ){
431
  if( $format ) return $this->format_price($this->ticket_price);
432
- return $this->ticket_price;
433
  }
434
 
435
  /**
111
  }
112
  }
113
  $this->compat_keys();
114
+ if( empty($this->ticket_price) ) $this->ticket_price = 0;
115
  do_action('em_ticket',$this, $ticket_data, $ticket);
116
  }
117
 
430
  */
431
  function get_price_without_tax( $format = false ){
432
  if( $format ) return $this->format_price($this->ticket_price);
433
+ return $this->ticket_price;
434
  }
435
 
436
  /**
classes/em-tickets-bookings.php CHANGED
@@ -292,20 +292,30 @@ class EM_Tickets_Bookings extends EM_Object implements Iterator, Countable {
292
  //Iterator Implementation
293
  public function rewind(){
294
  reset($this->tickets_bookings);
295
- }
 
 
 
 
296
  public function current(){
297
  $var = current($this->tickets_bookings);
298
  return $var;
299
- }
 
 
 
300
  public function key(){
301
  $var = key($this->tickets_bookings);
302
  return $var;
303
- }
304
- public function next(){
 
 
 
305
  $var = next($this->tickets_bookings);
306
  return $var;
307
  }
308
- public function valid(){
309
  $key = key($this->tickets_bookings);
310
  $var = ($key !== NULL && $key !== FALSE);
311
  return $var;
292
  //Iterator Implementation
293
  public function rewind(){
294
  reset($this->tickets_bookings);
295
+ }
296
+
297
+ /**
298
+ * @return EM_Ticket_Booking
299
+ */
300
  public function current(){
301
  $var = current($this->tickets_bookings);
302
  return $var;
303
+ }
304
+ /**
305
+ * @return int Ticket ID
306
+ */
307
  public function key(){
308
  $var = key($this->tickets_bookings);
309
  return $var;
310
+ }
311
+ /**
312
+ * @return EM_Ticket_Booking
313
+ */
314
+ public function next(){
315
  $var = next($this->tickets_bookings);
316
  return $var;
317
  }
318
+ public function valid(){
319
  $key = key($this->tickets_bookings);
320
  $var = ($key !== NULL && $key !== FALSE);
321
  return $var;
classes/em-tickets.php CHANGED
@@ -259,7 +259,10 @@ class EM_Tickets extends EM_Object implements Iterator, Countable {
259
  //Iterator Implementation
260
  public function rewind(){
261
  reset($this->tickets);
262
- }
 
 
 
263
  public function current(){
264
  $var = current($this->tickets);
265
  return $var;
@@ -267,7 +270,10 @@ class EM_Tickets extends EM_Object implements Iterator, Countable {
267
  public function key(){
268
  $var = key($this->tickets);
269
  return $var;
270
- }
 
 
 
271
  public function next(){
272
  $var = next($this->tickets);
273
  return $var;
259
  //Iterator Implementation
260
  public function rewind(){
261
  reset($this->tickets);
262
+ }
263
+ /**
264
+ * @return EM_Ticket
265
+ */
266
  public function current(){
267
  $var = current($this->tickets);
268
  return $var;
270
  public function key(){
271
  $var = key($this->tickets);
272
  return $var;
273
+ }
274
+ /**
275
+ * @return EM_Ticket
276
+ */
277
  public function next(){
278
  $var = next($this->tickets);
279
  return $var;
classes/event-locations/em-event-location-url.php CHANGED
@@ -57,7 +57,7 @@ class URL extends Event_Location {
57
  return parent::get_label($label_type);
58
  }
59
 
60
- public function output( $what = null ){
61
  if( $what === null ){
62
  return '<a href="'. esc_url($this->url) .'" target="_blank">'. esc_html($this->text) .'</a>';
63
  }elseif( $what === '_self' ){
57
  return parent::get_label($label_type);
58
  }
59
 
60
+ public function output( $what = null, $target = null ){
61
  if( $what === null ){
62
  return '<a href="'. esc_url($this->url) .'" target="_blank">'. esc_html($this->text) .'</a>';
63
  }elseif( $what === '_self' ){
classes/event-locations/em-event-location.php CHANGED
@@ -192,7 +192,7 @@ class Event_Location {
192
  return static::$type;
193
  }
194
 
195
- public function output( $what = null ){
196
  if( $what !== null && $what !== 'type' ){
197
  return esc_html($this->$what);
198
  }else{
192
  return static::$type;
193
  }
194
 
195
+ public function output( $what = null, $target = null ){
196
  if( $what !== null && $what !== 'type' ){
197
  return esc_html($this->$what);
198
  }else{
events-manager.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  Plugin Name: Events Manager
4
- Version: 5.9.10
5
  Plugin URI: http://wp-events-plugin.com
6
  Description: Event registration and booking management for WordPress. Recurring events, locations, webinars, google maps, rss, ical, booking registration and more!
7
  Author: Marcus Sykes
@@ -10,7 +10,7 @@ Text Domain: events-manager
10
  */
11
 
12
  /*
13
- Copyright (c) 2020, Marcus Sykes
14
 
15
  This program is free software; you can redistribute it and/or
16
  modify it under the terms of the GNU General Public License
@@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28
  */
29
 
30
  // Setting constants
31
- define('EM_VERSION', 5.993); //self expanatory, although version currently may not correspond directly with published version number
32
  define('EM_PRO_MIN_VERSION', 2.6712); //self expanatory
33
  define('EM_PRO_MIN_VERSION_CRITICAL', 2.377); //self expanatory
34
  define('EM_DIR', dirname( __FILE__ )); //an absolute path to this directory
1
  <?php
2
  /*
3
  Plugin Name: Events Manager
4
+ Version: 5.9.11
5
  Plugin URI: http://wp-events-plugin.com
6
  Description: Event registration and booking management for WordPress. Recurring events, locations, webinars, google maps, rss, ical, booking registration and more!
7
  Author: Marcus Sykes
10
  */
11
 
12
  /*
13
+ Copyright (c) 2021, Marcus Sykes
14
 
15
  This program is free software; you can redistribute it and/or
16
  modify it under the terms of the GNU General Public License
28
  */
29
 
30
  // Setting constants
31
+ define('EM_VERSION', 5.994); //self expanatory, although version currently may not correspond directly with published version number
32
  define('EM_PRO_MIN_VERSION', 2.6712); //self expanatory
33
  define('EM_PRO_MIN_VERSION_CRITICAL', 2.377); //self expanatory
34
  define('EM_DIR', dirname( __FILE__ )); //an absolute path to this directory
includes/css/events_manager.css CHANGED
@@ -262,10 +262,6 @@ Please edit your theme's CSS to override this
262
  }
263
 
264
  /* Time Picker */
265
- #start-time, #end-time { width:7em;}
266
- #start-time.error, #end-time.error { border:#cc0000 1px solid; }
267
- div.time-picker { position: absolute; height: 191px; width:5em; /* needed for IE */ overflow: auto; background: #fff; border: 1px solid #aaa; z-index: 99; margin: 0; }
268
- div.time-picker-12hours { width:7em; /* needed for IE */ }
269
- div.time-picker ul { list-style-type: none; margin: 0; padding: 0; }
270
- div.time-picker li { cursor: pointer; height: 10px; font: 12px/1 Helvetica, Arial, sans-serif; padding: 4px 3px; }
271
- div.time-picker li.selected { background: #0063CE; color: #fff; }
262
  }
263
 
264
  /* Time Picker */
265
+ .em-time-input { width:7em;}
266
+ .em-time-range .em-time-input.error, .em-time-input.error { border:#cc0000 1px solid; }
267
+ .ui-timepicker-wrapper{overflow-y:auto;max-height:150px;width:6.5em;background:#fff;border:1px solid #ddd;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);outline:0;z-index:10052;margin:0}.ui-timepicker-wrapper.ui-timepicker-with-duration{width:13em}.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30,.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60{width:11em}.ui-timepicker-list,.ui-timepicker-list li{margin:0;padding:0;list-style:none}.ui-timepicker-duration{margin-left:5px;color:#888}.ui-timepicker-list:hover .ui-timepicker-duration{color:#888}.ui-timepicker-list li{padding:3px 0 3px 5px;cursor:pointer;white-space:nowrap;color:#000}.ui-timepicker-list:hover .ui-timepicker-selected{background:#fff;color:#000}.ui-timepicker-list .ui-timepicker-selected:hover,.ui-timepicker-list li:hover,li.ui-timepicker-selected{background:#1980ec;color:#fff}.ui-timepicker-list li:hover .ui-timepicker-duration,li.ui-timepicker-selected .ui-timepicker-duration{color:#ccc}.ui-timepicker-list li.ui-timepicker-disabled,.ui-timepicker-list li.ui-timepicker-disabled:hover,.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled{color:#888;cursor:default}.ui-timepicker-list li.ui-timepicker-disabled:hover,.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled{background:#f2f2f2}
 
 
 
 
includes/css/events_manager_admin.css CHANGED
@@ -200,8 +200,4 @@ table.em-caps-table th, table.em-caps-table td { width:auto !important; }
200
 
201
  /* Time Picker */
202
  .em-time-input.error { border:#cc0000 1px solid; }
203
- div.time-picker { position: absolute; height: 191px; width:4.5em; /* needed for IE */ overflow: auto; background: #fff; border: 1px solid #aaa; z-index: 99; margin: 0; }
204
- div.time-picker-12hours { width:6.5em; /* needed for IE */ }
205
- div.time-picker ul { list-style-type: none; margin: 0; padding: 0; }
206
- div.time-picker li { cursor: pointer; height: 10px; font: 12px/1 Helvetica, Arial, sans-serif; padding: 4px 3px; }
207
- div.time-picker li.selected { background: #0063CE; color: #fff; }
200
 
201
  /* Time Picker */
202
  .em-time-input.error { border:#cc0000 1px solid; }
203
+ .ui-timepicker-wrapper{overflow-y:auto;max-height:150px;width:6.5em;background:#fff;border:1px solid #ddd;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);outline:0;z-index:10052;margin:0}.ui-timepicker-wrapper.ui-timepicker-with-duration{width:13em}.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30,.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60{width:11em}.ui-timepicker-list,.ui-timepicker-list li{margin:0;padding:0;list-style:none}.ui-timepicker-duration{margin-left:5px;color:#888}.ui-timepicker-list:hover .ui-timepicker-duration{color:#888}.ui-timepicker-list li{padding:3px 0 3px 5px;cursor:pointer;white-space:nowrap;color:#000}.ui-timepicker-list:hover .ui-timepicker-selected{background:#fff;color:#000}.ui-timepicker-list .ui-timepicker-selected:hover,.ui-timepicker-list li:hover,li.ui-timepicker-selected{background:#1980ec;color:#fff}.ui-timepicker-list li:hover .ui-timepicker-duration,li.ui-timepicker-selected .ui-timepicker-duration{color:#ccc}.ui-timepicker-list li.ui-timepicker-disabled,.ui-timepicker-list li.ui-timepicker-disabled:hover,.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled{color:#888;cursor:default}.ui-timepicker-list li.ui-timepicker-disabled:hover,.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled{background:#f2f2f2}
 
 
 
 
includes/js/admin-settings.js CHANGED
@@ -2,7 +2,7 @@ jQuery(document).ready(function($){
2
  //Meta Box Options
3
  var open_close = $('<a href="#" style="display:block; float:right; clear:right; margin:10px;">'+EM.open_text+'</a>');
4
  $('#em-options-title').before(open_close);
5
- open_close.click( function(e){
6
  e.preventDefault();
7
  if($(this).text() == EM.close_text){
8
  $(".postbox").addClass('closed');
@@ -12,10 +12,10 @@ jQuery(document).ready(function($){
12
  $(this).text(EM.close_text);
13
  }
14
  });
15
- $(".postbox > h3").click(function(){ $(this).parent().toggleClass('closed'); });
16
  $(".postbox").addClass('closed');
17
  //Navigation Tabs
18
- $('.tabs-active .nav-tab-wrapper .nav-tab').click(function(){
19
  el = $(this);
20
  elid = el.attr('id');
21
  $('.em-menu-group').hide();
@@ -23,7 +23,7 @@ jQuery(document).ready(function($){
23
  $(".postbox").addClass('closed');
24
  open_close.text(EM.open_text);
25
  });
26
- $('.nav-tab-wrapper .nav-tab').click(function(){
27
  $('.nav-tab-wrapper .nav-tab').removeClass('nav-tab-active').blur();
28
  $(this).addClass('nav-tab-active');
29
  });
@@ -43,8 +43,8 @@ jQuery(document).ready(function($){
43
  //set to general tab by default, so we can also add clicked subsections
44
  document.location = navUrl+"#general";
45
  }
46
- $('.nav-tab-link').click(function(){ $($(this).attr('rel')).trigger('click'); }); //links to mimick tabs
47
- $('input[type="submit"]').click(function(){
48
  var el = $(this).parents('.postbox').first();
49
  var docloc = document.location.toString().split('#');
50
  var newloc = docloc[0];
@@ -60,21 +60,21 @@ jQuery(document).ready(function($){
60
  $(this).closest('form').append('<input type="hidden" name="tab_path" value="'+ tab_path +'" />');
61
  });
62
  //Page Options
63
- $('input[name="dbem_cp_events_has_archive"]').change(function(){ //event archives
64
  if( $('input:radio[name="dbem_cp_events_has_archive"]:checked').val() == 1 ){
65
  $('tbody.em-event-archive-sub-options').show();
66
  }else{
67
  $('tbody.em-event-archive-sub-options').hide();
68
  }
69
  }).trigger('change');
70
- $('select[name="dbem_events_page"]').change(function(){
71
  if( $('select[name="dbem_events_page"]').val() == 0 ){
72
  $('tbody.em-event-page-options').hide();
73
  }else{
74
  $('tbody.em-event-page-options').show();
75
  }
76
  }).trigger('change');
77
- $('input[name="dbem_cp_locations_has_archive"]').change(function(){ //location archives
78
  if( $('input:radio[name="dbem_cp_locations_has_archive"]:checked').val() == 1 ){
79
  $('tbody.em-location-archive-sub-options').show();
80
  }else{
@@ -92,7 +92,7 @@ jQuery(document).ready(function($){
92
  });
93
  $('input:radio[name=dbem_disable_title_rewrites]').trigger('change');
94
  //for event grouping
95
- $('select[name="dbem_event_list_groupby"]').change(function(){
96
  if( $('select[name="dbem_event_list_groupby"]').val() == 0 ){
97
  $('tr#dbem_event_list_groupby_header_format_row, tr#dbem_event_list_groupby_format_row').hide();
98
  }else{
@@ -100,33 +100,33 @@ jQuery(document).ready(function($){
100
  }
101
  }).trigger('change');
102
  //ML Stuff
103
- $('.em-translatable').click(function(){
104
  $(this).nextAll('.em-ml-options').toggle();
105
  });
106
  //radio triggers
107
- $('input[type="radio"].em-trigger').change(function(e){
108
  var el = $(this);
109
  el.val() == '1' ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
110
  });
111
  $('input[type="radio"].em-trigger:checked').trigger('change');
112
- $('input[type="radio"].em-untrigger').change(function(e){
113
  var el = $(this);
114
  el.val() == '0' ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
115
  });
116
  $('input[type="radio"].em-untrigger:checked').trigger('change');
117
  //checkbox triggers
118
- $('input[type="checkbox"].em-trigger').change(function(e){
119
  var el = $(this);
120
  el.prop('checked') ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
121
  });
122
  $('input[type="checkbox"].em-trigger').trigger('change');
123
- $('input[type="checkbox"].em-untrigger').change(function(e){
124
  var el = $(this);
125
  !el.prop('checked') ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
126
  });
127
  $('input[type="checkbox"].em-untrigger').trigger('change');
128
  //admin tools confirm
129
- $('a.admin-tools-db-cleanup').click( function( e ){
130
  if( !confirm(EM.admin_db_cleanup_warning) ){
131
  e.preventDefault();
132
  return false;
2
  //Meta Box Options
3
  var open_close = $('<a href="#" style="display:block; float:right; clear:right; margin:10px;">'+EM.open_text+'</a>');
4
  $('#em-options-title').before(open_close);
5
+ open_close.on('click', function(e){
6
  e.preventDefault();
7
  if($(this).text() == EM.close_text){
8
  $(".postbox").addClass('closed');
12
  $(this).text(EM.close_text);
13
  }
14
  });
15
+ $(".postbox > h3").on('click', function(){ $(this).parent().toggleClass('closed'); });
16
  $(".postbox").addClass('closed');
17
  //Navigation Tabs
18
+ $('.tabs-active .nav-tab-wrapper .nav-tab').on('click', function(){
19
  el = $(this);
20
  elid = el.attr('id');
21
  $('.em-menu-group').hide();
23
  $(".postbox").addClass('closed');
24
  open_close.text(EM.open_text);
25
  });
26
+ $('.nav-tab-wrapper .nav-tab').on('click', function(){
27
  $('.nav-tab-wrapper .nav-tab').removeClass('nav-tab-active').blur();
28
  $(this).addClass('nav-tab-active');
29
  });
43
  //set to general tab by default, so we can also add clicked subsections
44
  document.location = navUrl+"#general";
45
  }
46
+ $('.nav-tab-link').on('click', function(){ $($(this).attr('rel')).trigger('click'); }); //links to mimick tabs
47
+ $('input[type="submit"]').on('click', function(){
48
  var el = $(this).parents('.postbox').first();
49
  var docloc = document.location.toString().split('#');
50
  var newloc = docloc[0];
60
  $(this).closest('form').append('<input type="hidden" name="tab_path" value="'+ tab_path +'" />');
61
  });
62
  //Page Options
63
+ $('input[name="dbem_cp_events_has_archive"]').on('change', function(){ //event archives
64
  if( $('input:radio[name="dbem_cp_events_has_archive"]:checked').val() == 1 ){
65
  $('tbody.em-event-archive-sub-options').show();
66
  }else{
67
  $('tbody.em-event-archive-sub-options').hide();
68
  }
69
  }).trigger('change');
70
+ $('select[name="dbem_events_page"]').on('change', function(){
71
  if( $('select[name="dbem_events_page"]').val() == 0 ){
72
  $('tbody.em-event-page-options').hide();
73
  }else{
74
  $('tbody.em-event-page-options').show();
75
  }
76
  }).trigger('change');
77
+ $('input[name="dbem_cp_locations_has_archive"]').on('change', function(){ //location archives
78
  if( $('input:radio[name="dbem_cp_locations_has_archive"]:checked').val() == 1 ){
79
  $('tbody.em-location-archive-sub-options').show();
80
  }else{
92
  });
93
  $('input:radio[name=dbem_disable_title_rewrites]').trigger('change');
94
  //for event grouping
95
+ $('select[name="dbem_event_list_groupby"]').on('change', function(){
96
  if( $('select[name="dbem_event_list_groupby"]').val() == 0 ){
97
  $('tr#dbem_event_list_groupby_header_format_row, tr#dbem_event_list_groupby_format_row').hide();
98
  }else{
100
  }
101
  }).trigger('change');
102
  //ML Stuff
103
+ $('.em-translatable').on('click', function(){
104
  $(this).nextAll('.em-ml-options').toggle();
105
  });
106
  //radio triggers
107
+ $('input[type="radio"].em-trigger').on('change', function(e){
108
  var el = $(this);
109
  el.val() == '1' ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
110
  });
111
  $('input[type="radio"].em-trigger:checked').trigger('change');
112
+ $('input[type="radio"].em-untrigger').on('change', function(e){
113
  var el = $(this);
114
  el.val() == '0' ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
115
  });
116
  $('input[type="radio"].em-untrigger:checked').trigger('change');
117
  //checkbox triggers
118
+ $('input[type="checkbox"].em-trigger').on('change', function(e){
119
  var el = $(this);
120
  el.prop('checked') ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
121
  });
122
  $('input[type="checkbox"].em-trigger').trigger('change');
123
+ $('input[type="checkbox"].em-untrigger').on('change', function(e){
124
  var el = $(this);
125
  !el.prop('checked') ? $(el.attr('data-trigger')).show() : $(el.attr('data-trigger')).hide();
126
  });
127
  $('input[type="checkbox"].em-untrigger').trigger('change');
128
  //admin tools confirm
129
+ $('a.admin-tools-db-cleanup').on('click', function( e ){
130
  if( !confirm(EM.admin_db_cleanup_warning) ){
131
  e.preventDefault();
132
  return false;
includes/js/events-manager.js CHANGED
@@ -41,14 +41,14 @@ jQuery(document).ready( function($){
41
  if( 'placeholder' in document.createElement('input') ){
42
  $('input.em-events-search-text, input.em-search-text').attr('placeholder', EM.search_term_placeholder);
43
  }else{
44
- $('input.em-events-search-text, input.em-search-text').blur(function(){
45
  if( this.value=='' ) this.value = EM.search_term_placeholder;
46
- }).focus(function(){
47
  if( this.value == EM.search_term_placeholder ) this.value='';
48
  }).trigger('blur');
49
  }
50
  }
51
- $('.em-search-form select[name=country]').change( function(){
52
  var el = $(this);
53
  $('.em-search select[name=state]').html('<option value="">'+EM.txt_loading+'</option>');
54
  $('.em-search select[name=region]').html('<option value="">'+EM.txt_loading+'</option>');
@@ -70,7 +70,7 @@ jQuery(document).ready( function($){
70
  }
71
  });
72
 
73
- $('.em-search-form select[name=region]').change( function(){
74
  $('.em-search select[name=state]').html('<option value="">'+EM.txt_loading+'</option>');
75
  $('.em-search select[name=town]').html('<option value="">'+EM.txt_loading+'</option>');
76
  var data = {
@@ -84,7 +84,7 @@ jQuery(document).ready( function($){
84
  $('.em-search select[name=town]').load( EM.ajaxurl, data );
85
  });
86
 
87
- $('.em-search-form select[name=state]').change( function(){
88
  $('.em-search select[name=town]').html('<option value="">'+EM.txt_loading+'</option>');
89
  var data = {
90
  action : 'search_towns',
@@ -176,7 +176,7 @@ jQuery(document).ready( function($){
176
  });
177
  //Event Editor
178
  //Recurrence Warnings
179
- $('#event-form.em-event-admin-recurring').submit( function(event){
180
  var form = $(this);
181
  if( form.find('input[name="event_reschedule"]').first().val() == 1 ){
182
  var warning_text = EM.event_reschedule_warning;
@@ -191,14 +191,14 @@ jQuery(document).ready( function($){
191
  }
192
  });
193
  //Buttons for recurrence warnings within event editor forms
194
- $('.em-reschedule-trigger').click(function(e){
195
  e.preventDefault();
196
  var trigger = $(this);
197
  trigger.closest('.em-recurrence-reschedule').find(trigger.data('target')).removeClass('reschedule-hidden');
198
  trigger.siblings('.em-reschedule-value').val(1);
199
  trigger.addClass('reschedule-hidden').siblings('a').removeClass('reschedule-hidden');
200
  });
201
- $('.em-reschedule-cancel').click(function(e){
202
  e.preventDefault();
203
  var trigger = $(this);
204
  trigger.closest('.em-recurrence-reschedule').find(trigger.data('target')).addClass('reschedule-hidden');
@@ -208,7 +208,7 @@ jQuery(document).ready( function($){
208
  //Tickets & Bookings
209
  if( $("#em-tickets-form").length > 0 ){
210
  //Enable/Disable Bookings
211
- $('#event-rsvp').click( function(event){
212
  if( !this.checked ){
213
  confirmation = confirm(EM.disable_bookings_warning);
214
  if( confirmation == false ){
@@ -232,7 +232,7 @@ jQuery(document).ready( function($){
232
  };
233
  //recurrences and cut-off logic for ticket availability
234
  if( $('#em-recurrence-checkbox').length > 0 ){
235
- $('#em-recurrence-checkbox').change(function(){
236
  if( $('#em-recurrence-checkbox').is(':checked') ){
237
  $('#em-tickets-form .ticket-dates-from-recurring, #em-tickets-form .ticket-dates-to-recurring, #event-rsvp-options .em-booking-date-recurring').show();
238
  $('#em-tickets-form .ticket-dates-from-normal, #em-tickets-form .ticket-dates-to-normal, #event-rsvp-options .em-booking-date-normal, #em-tickets-form .hidden').hide();
@@ -248,7 +248,7 @@ jQuery(document).ready( function($){
248
  $('#em-tickets-form .ticket-dates-from-recurring, #em-tickets-form .ticket-dates-to-recurring, #event-rsvp-options .em-booking-date-recurring, #em-tickets-form .hidden').hide();
249
  }
250
  //Add a new ticket
251
- $("#em-tickets-add").click(function(e){
252
  e.preventDefault();
253
  reset_ticket_forms();
254
  //create copy of template slot, insert so ready for population
@@ -264,7 +264,11 @@ jQuery(document).ready( function($){
264
  slot.show().find('.ticket-actions-edit').trigger('click');
265
  //refresh datepicker and values
266
  slot.find('.em-date-input-loc').datepicker('destroy').removeAttr('id'); //clear all datepickers
267
- slot.find('.em-time-input').unbind().each(function(index, el){ this.timePicker = false; }); //clear all timepickers - consequently, also other click/blur/change events, recreate the further down
 
 
 
 
268
  em_setup_datepicker(slot);
269
  em_setup_timepicker(slot);
270
  $('html, body').animate({ scrollTop: slot.offset().top - 30 }); //sends user to form
@@ -459,7 +463,7 @@ jQuery(document).ready( function($){
459
  buttons: [{
460
  text: EM.bookings_export_save,
461
  click: function(e){
462
- $(this).children('form').submit();
463
  $(this).dialog('close');
464
  }
465
  }]
@@ -481,7 +485,7 @@ jQuery(document).ready( function($){
481
  };
482
  //Sync export overlay with table search field changes
483
  $('#em-bookings-table form select').each(function(i, el){
484
- $(el).change(function(e){
485
  var select_el = $(this);
486
  var input_par = $('#em-bookings-table-export-form input[name='+select_el.attr('name')+']');
487
  var input_par_selected = select_el.find('option:selected');
@@ -490,7 +494,7 @@ jQuery(document).ready( function($){
490
  });
491
 
492
  export_overlay_show_tickets();
493
- $('#em-bookings-table-export-form input[name=show_tickets]').click(export_overlay_show_tickets);
494
  //Sortables
495
  $( ".em-bookings-cols-sortable" ).sortable({
496
  connectWith: ".em-bookings-cols-sortable",
@@ -655,7 +659,7 @@ jQuery(document).ready( function($){
655
  $("#localised-date").show();
656
  $("#localised-end-date").show();
657
 
658
- $('#em-wrapper input.select-all').change(function(){
659
  if($(this).is(':checked')){
660
  $('input.row-selector').prop('checked', true);
661
  $('input.select-all').prop('checked', true);
@@ -668,12 +672,12 @@ jQuery(document).ready( function($){
668
  updateIntervalDescriptor();
669
  updateIntervalSelectors();
670
  updateShowHideRecurrence();
671
- $('input#event-recurrence').change(updateShowHideRecurrence);
672
 
673
  // recurrency elements
674
- $('input#recurrence-interval').keyup(updateIntervalDescriptor);
675
- $('select#recurrence-frequency').change(updateIntervalDescriptor);
676
- $('select#recurrence-frequency').change(updateIntervalSelectors);
677
 
678
  /* Load any maps */
679
  if( $('.em-location-map').length > 0 || $('.em-locations-map').length > 0 || $('#em-map').length > 0 || $('.em-search-geo').length > 0 ){
@@ -681,7 +685,7 @@ jQuery(document).ready( function($){
681
  }
682
 
683
  /* Location Type Selection */
684
- $('.em-location-types .em-location-types-select').change(function(){
685
  let el = $(this);
686
  if( el.val() == 0 ){
687
  $('.em-location-type').hide();
@@ -737,7 +741,7 @@ jQuery(document).ready( function($){
737
  html_val = "<a>" + em_esc_attr(item.label) + '<br><span style="font-size:11px"><em>'+ em_esc_attr(item.address) + ', ' + em_esc_attr(item.town)+"</em></span></a>";
738
  return jQuery( "<li></li>" ).data( "item.autocomplete", item ).append(html_val).appendTo( ul );
739
  };
740
- jQuery('#em-location-reset a').click( function(){
741
  jQuery('div.em-location-data input').css('background-color','#fff').val('').prop('readonly', false);
742
  jQuery('div.em-location-data select').css('background-color','#fff').css('color', 'auto').prop('disabled', false);
743
  jQuery('div.em-location-data option:selected').removeAttr('selected');
@@ -854,7 +858,7 @@ function em_setup_datepicker(wrap){
854
  dateValue.val(dateValue_value);
855
  }
856
  //add logic for texts
857
- dateInput.change(function(){
858
  if( jQuery(this).val() == '' ){
859
  jQuery(this).nextAll('.em-date-input').first().val('');
860
  }
@@ -887,45 +891,51 @@ function em_setup_datepicker(wrap){
887
  });
888
  }
889
  }
890
-
891
  function em_setup_timepicker(wrap){
892
  wrap = jQuery(wrap);
893
  var timepicker_options = {
894
- show24Hours: EM.show24hours == 1,
895
  step:15
896
  }
 
897
  jQuery(document).triggerHandler('em_timepicker_options', timepicker_options);
898
- wrap.find(".em-time-input").timePicker(timepicker_options);
899
-
900
  // Keep the duration between the two inputs.
901
  wrap.find(".em-time-range input.em-time-start").each( function(i, el){
902
- jQuery(el).data('oldTime', jQuery.timePicker(el).getTime());
903
- }).change( function() {
 
904
  var start = jQuery(this);
905
  var end = start.nextAll('.em-time-end');
906
  if (end.val()) { // Only update when second input has a value.
907
- // Calculate duration.
908
  var oldTime = start.data('oldTime');
909
- var duration = (jQuery.timePicker(end).getTime() - oldTime);
910
- var time = jQuery.timePicker(start).getTime();
911
- if( jQuery.timePicker(end).getTime() >= oldTime ){
912
- // Calculate and update the time in the second input.
913
- jQuery.timePicker(end).setTime(new Date(new Date(time.getTime() + duration)));
914
  }
915
- start.data('oldTime', time);
916
  }
917
  });
918
  // Validate.
919
- wrap.find(".em-time-range input.em-time-end").change(function() {
920
  var end = jQuery(this);
921
  var start = end.prevAll('.em-time-start');
 
 
 
922
  if( start.val() ){
923
- if( jQuery.timePicker(start).getTime() > jQuery.timePicker(this).getTime() && ( jQuery('.em-date-end').val().length == 0 || jQuery('.em-date-start').val() == jQuery('.em-date-end').val() ) ) { end.addClass("error"); }
924
  else { end.removeClass("error"); }
925
  }
926
  });
 
 
 
927
  //Sort out all day checkbox
928
- wrap.find('.em-time-range input.em-time-all-day').change(function(){
929
  var allday = jQuery(this);
930
  if( allday.is(':checked') ){
931
  allday.siblings('.em-time-input').css('background-color','#ccc');
@@ -1055,7 +1065,7 @@ function em_maps_load_location(el){
1055
  maps[map_id].panBy(40,-70);
1056
 
1057
  //JS Hook for handling map after instantiation
1058
- //Example hook, which you can add elsewhere in your theme's JS - jQuery(document).bind('em_maps_location_hook', function(){ alert('hi');} );
1059
  jQuery(document).triggerHandler('em_maps_location_hook', [maps[map_id], infoWindow, maps_markers[map_id], map_id]);
1060
  //map resize listener
1061
  jQuery(window).on('resize', function(e) {
@@ -1064,7 +1074,7 @@ function em_maps_load_location(el){
1064
  maps[map_id].panBy(40,-70);
1065
  });
1066
  }
1067
- jQuery(document).bind('em_search_ajax', function(e, vars, wrapper){
1068
  if( em_maps_loaded ){
1069
  wrapper.find('.em-location-map').each( function(index, el){ em_maps_load_location(el); } );
1070
  wrapper.find('.em-locations-map').each( function(index, el){ em_maps_load_locations(el); });
@@ -1132,8 +1142,8 @@ function em_maps() {
1132
  });
1133
  }
1134
  };
1135
- jQuery('#location-select-id, input#location-id').change( function(){get_map_by_id(jQuery(this).val());} );
1136
- jQuery('#location-name, #location-town, #location-address, #location-state, #location-postcode, #location-country').change( function(){
1137
  //build address
1138
  if( jQuery(this).prop('readonly') === true ) return;
1139
  var addresses = [ jQuery('#location-address').val(), jQuery('#location-town').val(), jQuery('#location-state').val(), jQuery('#location-postcode').val() ];
@@ -1227,5 +1237,7 @@ function em_esc_attr( str ){
1227
  return str.replace(/</gi,'&lt;').replace(/>/gi,'&gt;');
1228
  }
1229
 
1230
- /* jQuery timePicker - http://labs.perifer.se/timedatepicker/ @ http://github.com/perifer/timePicker commit 100644 */
1231
- (function(e){function t(t,n,r,i){t.value=e(n).text();e(t).change();if(!navigator.userAgent.match(/msie/i)){t.focus()}r.hide()}function n(e,t){var n=e.getHours();var i=t.show24Hours?n:(n+11)%12+1;var s=e.getMinutes();return r(i)+t.separator+r(s)+(t.show24Hours?"":n<12?" AM":" PM")}function r(e){return(e<10?"0":"")+e}function i(e,t){return typeof e=="object"?o(e):s(e,t)}function s(e,t){if(e){var n=e.split(t.separator);var r=parseFloat(n[0]);var i=parseFloat(n[1]);if(!t.show24Hours){if(r===12&&e.indexOf("AM")!==-1){r=0}else if(r!==12&&e.indexOf("PM")!==-1){r+=12}}var s=new Date(0,0,0,r,i,0);return o(s)}return null}function o(e){e.setFullYear(2001);e.setMonth(0);e.setDate(0);return e}e.fn.timePicker=function(t){var n=e.extend({},e.fn.timePicker.defaults,t);return this.each(function(){e.timePicker(this,n)})};e.timePicker=function(t,n){var r=e(t)[0];return r.timePicker||(r.timePicker=new jQuery._timePicker(r,n))};e.timePicker.version="0.3";e._timePicker=function(r,u){var a=false;var f=false;var l=i(u.startTime,u);var c=i(u.endTime,u);var h="selected";var p="li."+h;e(r).attr("autocomplete","OFF");var d=[];var v=new Date(l);while(v<=c){d[d.length]=n(v,u);v=new Date(v.setMinutes(v.getMinutes()+u.step))}var m=e('<div class="time-picker'+(u.show24Hours?"":" time-picker-12hours")+'"></div>');var g=e("<ul></ul>");for(var y=0;y<d.length;y++){g.append("<li>"+d[y]+"</li>")}m.append(g);m.appendTo("body").hide();m.mouseover(function(){a=true}).mouseout(function(){a=false});e("li",g).mouseover(function(){if(!f){e(p,m).removeClass(h);e(this).addClass(h)}}).mousedown(function(){a=true}).click(function(){t(r,this,m,u);a=false});var b=function(){if(m.is(":visible")){return false}e("li",m).removeClass(h);var t=e(r).offset();m.css({top:t.top+r.offsetHeight,left:t.left});m.show();var i=r.value?s(r.value,u):l;var a=l.getHours()*60+l.getMinutes();var f=i.getHours()*60+i.getMinutes()-a;var p=Math.round(f/u.step);var d=o(new Date(0,0,0,0,p*u.step+a,0));d=l<d&&d<=c?d:l;var v=e("li:contains("+n(d,u)+")",m);if(v.length){v.addClass(h);m[0].scrollTop=v[0].offsetTop}return true};e(r).focus(b).click(b);e(r).blur(function(){if(!a){m.hide()}});e(r)["keydown"](function(n){var i;f=true;var s=m[0].scrollTop;switch(n.keyCode){case 38:if(b()){return false}i=e(p,g);var o=i.prev().addClass(h)[0];if(o){i.removeClass(h);if(o.offsetTop<s){m[0].scrollTop=s-o.offsetHeight}}else{i.removeClass(h);o=e("li:last",g).addClass(h)[0];m[0].scrollTop=o.offsetTop-o.offsetHeight}return false;break;case 40:if(b()){return false}i=e(p,g);var a=i.next().addClass(h)[0];if(a){i.removeClass(h);if(a.offsetTop+a.offsetHeight>s+m[0].offsetHeight){m[0].scrollTop=s+a.offsetHeight}}else{i.removeClass(h);a=e("li:first",g).addClass(h)[0];m[0].scrollTop=0}return false;break;case 13:if(m.is(":visible")){var l=e(p,g)[0];t(r,l,m,u)}return false;break;case 27:m.hide();return false;break}return true});e(r).keyup(function(e){f=false});this.getTime=function(){return s(r.value,u)};this.setTime=function(t){r.value=n(i(t,u),u);e(r).change()}};e.fn.timePicker.defaults={step:30,startTime:new Date(0,0,0,0,0,0),endTime:new Date(0,0,0,23,30,0),separator:":",show24Hours:true}})(jQuery)
 
 
41
  if( 'placeholder' in document.createElement('input') ){
42
  $('input.em-events-search-text, input.em-search-text').attr('placeholder', EM.search_term_placeholder);
43
  }else{
44
+ $('input.em-events-search-text, input.em-search-text').on('blur', function(){
45
  if( this.value=='' ) this.value = EM.search_term_placeholder;
46
+ }).on('focus', function(){
47
  if( this.value == EM.search_term_placeholder ) this.value='';
48
  }).trigger('blur');
49
  }
50
  }
51
+ $('.em-search-form select[name=country]').on('change', function(){
52
  var el = $(this);
53
  $('.em-search select[name=state]').html('<option value="">'+EM.txt_loading+'</option>');
54
  $('.em-search select[name=region]').html('<option value="">'+EM.txt_loading+'</option>');
70
  }
71
  });
72
 
73
+ $('.em-search-form select[name=region]').on('change', function(){
74
  $('.em-search select[name=state]').html('<option value="">'+EM.txt_loading+'</option>');
75
  $('.em-search select[name=town]').html('<option value="">'+EM.txt_loading+'</option>');
76
  var data = {
84
  $('.em-search select[name=town]').load( EM.ajaxurl, data );
85
  });
86
 
87
+ $('.em-search-form select[name=state]').on('change', function(){
88
  $('.em-search select[name=town]').html('<option value="">'+EM.txt_loading+'</option>');
89
  var data = {
90
  action : 'search_towns',
176
  });
177
  //Event Editor
178
  //Recurrence Warnings
179
+ $('#event-form.em-event-admin-recurring').on('submit', function(event){
180
  var form = $(this);
181
  if( form.find('input[name="event_reschedule"]').first().val() == 1 ){
182
  var warning_text = EM.event_reschedule_warning;
191
  }
192
  });
193
  //Buttons for recurrence warnings within event editor forms
194
+ $('.em-reschedule-trigger').on('click', function(e){
195
  e.preventDefault();
196
  var trigger = $(this);
197
  trigger.closest('.em-recurrence-reschedule').find(trigger.data('target')).removeClass('reschedule-hidden');
198
  trigger.siblings('.em-reschedule-value').val(1);
199
  trigger.addClass('reschedule-hidden').siblings('a').removeClass('reschedule-hidden');
200
  });
201
+ $('.em-reschedule-cancel').on('click', function(e){
202
  e.preventDefault();
203
  var trigger = $(this);
204
  trigger.closest('.em-recurrence-reschedule').find(trigger.data('target')).addClass('reschedule-hidden');
208
  //Tickets & Bookings
209
  if( $("#em-tickets-form").length > 0 ){
210
  //Enable/Disable Bookings
211
+ $('#event-rsvp').on('click', function(event){
212
  if( !this.checked ){
213
  confirmation = confirm(EM.disable_bookings_warning);
214
  if( confirmation == false ){
232
  };
233
  //recurrences and cut-off logic for ticket availability
234
  if( $('#em-recurrence-checkbox').length > 0 ){
235
+ $('#em-recurrence-checkbox').on('change', function(){
236
  if( $('#em-recurrence-checkbox').is(':checked') ){
237
  $('#em-tickets-form .ticket-dates-from-recurring, #em-tickets-form .ticket-dates-to-recurring, #event-rsvp-options .em-booking-date-recurring').show();
238
  $('#em-tickets-form .ticket-dates-from-normal, #em-tickets-form .ticket-dates-to-normal, #event-rsvp-options .em-booking-date-normal, #em-tickets-form .hidden').hide();
248
  $('#em-tickets-form .ticket-dates-from-recurring, #em-tickets-form .ticket-dates-to-recurring, #event-rsvp-options .em-booking-date-recurring, #em-tickets-form .hidden').hide();
249
  }
250
  //Add a new ticket
251
+ $("#em-tickets-add").on('click', function(e){
252
  e.preventDefault();
253
  reset_ticket_forms();
254
  //create copy of template slot, insert so ready for population
264
  slot.show().find('.ticket-actions-edit').trigger('click');
265
  //refresh datepicker and values
266
  slot.find('.em-date-input-loc').datepicker('destroy').removeAttr('id'); //clear all datepickers
267
+ slot.find('.em-time-input').off().each(function(index, el){
268
+ if( typeof this.timepickerObj == 'object' ){
269
+ this.timepicker('remove');
270
+ }
271
+ }); //clear all timepickers - consequently, also other click/blur/change events, recreate the further down
272
  em_setup_datepicker(slot);
273
  em_setup_timepicker(slot);
274
  $('html, body').animate({ scrollTop: slot.offset().top - 30 }); //sends user to form
463
  buttons: [{
464
  text: EM.bookings_export_save,
465
  click: function(e){
466
+ $(this).children('form').trigger('submit');
467
  $(this).dialog('close');
468
  }
469
  }]
485
  };
486
  //Sync export overlay with table search field changes
487
  $('#em-bookings-table form select').each(function(i, el){
488
+ $(el).on('change', function(e){
489
  var select_el = $(this);
490
  var input_par = $('#em-bookings-table-export-form input[name='+select_el.attr('name')+']');
491
  var input_par_selected = select_el.find('option:selected');
494
  });
495
 
496
  export_overlay_show_tickets();
497
+ $('#em-bookings-table-export-form input[name=show_tickets]').on('click', export_overlay_show_tickets);
498
  //Sortables
499
  $( ".em-bookings-cols-sortable" ).sortable({
500
  connectWith: ".em-bookings-cols-sortable",
659
  $("#localised-date").show();
660
  $("#localised-end-date").show();
661
 
662
+ $('#em-wrapper input.select-all').on('change', function(){
663
  if($(this).is(':checked')){
664
  $('input.row-selector').prop('checked', true);
665
  $('input.select-all').prop('checked', true);
672
  updateIntervalDescriptor();
673
  updateIntervalSelectors();
674
  updateShowHideRecurrence();
675
+ $('input#event-recurrence').on('change', updateShowHideRecurrence);
676
 
677
  // recurrency elements
678
+ $('input#recurrence-interval').on('keyup', updateIntervalDescriptor);
679
+ $('select#recurrence-frequency').on('change', updateIntervalDescriptor);
680
+ $('select#recurrence-frequency').on('change', updateIntervalSelectors);
681
 
682
  /* Load any maps */
683
  if( $('.em-location-map').length > 0 || $('.em-locations-map').length > 0 || $('#em-map').length > 0 || $('.em-search-geo').length > 0 ){
685
  }
686
 
687
  /* Location Type Selection */
688
+ $('.em-location-types .em-location-types-select').on('change', function(){
689
  let el = $(this);
690
  if( el.val() == 0 ){
691
  $('.em-location-type').hide();
741
  html_val = "<a>" + em_esc_attr(item.label) + '<br><span style="font-size:11px"><em>'+ em_esc_attr(item.address) + ', ' + em_esc_attr(item.town)+"</em></span></a>";
742
  return jQuery( "<li></li>" ).data( "item.autocomplete", item ).append(html_val).appendTo( ul );
743
  };
744
+ jQuery('#em-location-reset a').on('click', function(){
745
  jQuery('div.em-location-data input').css('background-color','#fff').val('').prop('readonly', false);
746
  jQuery('div.em-location-data select').css('background-color','#fff').css('color', 'auto').prop('disabled', false);
747
  jQuery('div.em-location-data option:selected').removeAttr('selected');
858
  dateValue.val(dateValue_value);
859
  }
860
  //add logic for texts
861
+ dateInput.on('change', function(){
862
  if( jQuery(this).val() == '' ){
863
  jQuery(this).nextAll('.em-date-input').first().val('');
864
  }
891
  });
892
  }
893
  }
 
894
  function em_setup_timepicker(wrap){
895
  wrap = jQuery(wrap);
896
  var timepicker_options = {
 
897
  step:15
898
  }
899
+ timepicker_options.timeFormat = EM.show24hours == 1 ? 'G:i':'g:i A';
900
  jQuery(document).triggerHandler('em_timepicker_options', timepicker_options);
901
+ wrap.find(".em-time-input").timepicker(timepicker_options);
902
+
903
  // Keep the duration between the two inputs.
904
  wrap.find(".em-time-range input.em-time-start").each( function(i, el){
905
+ var time = jQuery(el);
906
+ time.data('oldTime', time.timepicker('getSecondsFromMidnight'));
907
+ }).on('change', function() {
908
  var start = jQuery(this);
909
  var end = start.nextAll('.em-time-end');
910
  if (end.val()) { // Only update when second input has a value.
911
+ // Calculate duration.
912
  var oldTime = start.data('oldTime');
913
+ var duration = (end.timepicker('getSecondsFromMidnight') - oldTime) * 1000;
914
+ var time = start.timepicker('getSecondsFromMidnight');
915
+ if( end.timepicker('getSecondsFromMidnight') >= oldTime ){
916
+ // Calculate and update the time in the second input.
917
+ end.timepicker('setTime', new Date(start.timepicker('getTime').getTime() + duration));
918
  }
919
+ start.data('oldTime', time);
920
  }
921
  });
922
  // Validate.
923
+ wrap.find(".event-form-when .em-time-range input.em-time-end").on('change', function() {
924
  var end = jQuery(this);
925
  var start = end.prevAll('.em-time-start');
926
+ var wrapper = end.closest('.event-form-when');
927
+ var start_date = wrapper.find('.em-date-end').val();
928
+ var end_date = wrapper.find('.em-date-start').val();
929
  if( start.val() ){
930
+ if( start.timepicker('getTime') > end.timepicker('getTime') && ( end_date.length == 0 || start_date == end_date ) ) { end.addClass("error"); }
931
  else { end.removeClass("error"); }
932
  }
933
  });
934
+ wrap.find(".event-form-when .em-date-end").on('change', function(){
935
+ jQuery(this).closest('.event-form-when').find('.em-time-end').trigger('change');
936
+ });
937
  //Sort out all day checkbox
938
+ wrap.find('.em-time-range input.em-time-all-day').on('change', function(){
939
  var allday = jQuery(this);
940
  if( allday.is(':checked') ){
941
  allday.siblings('.em-time-input').css('background-color','#ccc');
1065
  maps[map_id].panBy(40,-70);
1066
 
1067
  //JS Hook for handling map after instantiation
1068
+ //Example hook, which you can add elsewhere in your theme's JS - jQuery(document).on('em_maps_location_hook', function(){ alert('hi');} );
1069
  jQuery(document).triggerHandler('em_maps_location_hook', [maps[map_id], infoWindow, maps_markers[map_id], map_id]);
1070
  //map resize listener
1071
  jQuery(window).on('resize', function(e) {
1074
  maps[map_id].panBy(40,-70);
1075
  });
1076
  }
1077
+ jQuery(document).on('em_search_ajax', function(e, vars, wrapper){
1078
  if( em_maps_loaded ){
1079
  wrapper.find('.em-location-map').each( function(index, el){ em_maps_load_location(el); } );
1080
  wrapper.find('.em-locations-map').each( function(index, el){ em_maps_load_locations(el); });
1142
  });
1143
  }
1144
  };
1145
+ jQuery('#location-select-id, input#location-id').on('change', function(){get_map_by_id(jQuery(this).val());} );
1146
+ jQuery('#location-name, #location-town, #location-address, #location-state, #location-postcode, #location-country').on('change', function(){
1147
  //build address
1148
  if( jQuery(this).prop('readonly') === true ) return;
1149
  var addresses = [ jQuery('#location-address').val(), jQuery('#location-town').val(), jQuery('#location-state').val(), jQuery('#location-postcode').val() ];
1237
  return str.replace(/</gi,'&lt;').replace(/>/gi,'&gt;');
1238
  }
1239
 
1240
+ /*!
1241
+ * jquery-timepicker v1.13.16 - Copyright (c) 2020 Jon Thornton - https://www.jonthornton.com/jquery-timepicker/
1242
+ */
1243
+ (function(){"use strict";function _typeof(obj){"@babel/helpers - typeof";if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){_typeof=function(obj){return typeof obj}}else{_typeof=function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj}}return _typeof(obj)}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function")}}function _defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}function _createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);return Constructor}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);if(enumerableOnly)symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable});keys.push.apply(keys,symbols)}return keys}function _objectSpread2(target){for(var i=1;i<arguments.length;i++){var source=arguments[i]!=null?arguments[i]:{};if(i%2){ownKeys(Object(source),true).forEach(function(key){_defineProperty(target,key,source[key])})}else if(Object.getOwnPropertyDescriptors){Object.defineProperties(target,Object.getOwnPropertyDescriptors(source))}else{ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key))})}}return target}function _unsupportedIterableToArray(o,minLen){if(!o)return;if(typeof o==="string")return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(n);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}function _arrayLikeToArray(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function _createForOfIteratorHelper(o){if(typeof Symbol==="undefined"||o[Symbol.iterator]==null){if(Array.isArray(o)||(o=_unsupportedIterableToArray(o))){var i=0;var F=function(){};return{s:F,n:function(){if(i>=o.length)return{done:true};return{done:false,value:o[i++]}},e:function(e){throw e},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var it,normalCompletion=true,didErr=false,err;return{s:function(){it=o[Symbol.iterator]()},n:function(){var step=it.next();normalCompletion=step.done;return step},e:function(e){didErr=true;err=e},f:function(){try{if(!normalCompletion&&it.return!=null)it.return()}finally{if(didErr)throw err}}}}var ONE_DAY=86400;var roundingFunction=function roundingFunction(seconds,settings){if(seconds===null){return null}else if(typeof settings.step!=="number"){return seconds}else{var offset=seconds%(settings.step*60);var start=settings.minTime||0;offset-=start%(settings.step*60);if(offset>=settings.step*30){seconds+=settings.step*60-offset}else{seconds-=offset}return _moduloSeconds(seconds,settings)}};function _moduloSeconds(seconds,settings){if(seconds==ONE_DAY&&settings.show2400){return seconds}return seconds%ONE_DAY}var DEFAULT_SETTINGS={appendTo:"body",className:null,closeOnWindowScroll:false,disableTextInput:false,disableTimeRanges:[],disableTouchKeyboard:false,durationTime:null,forceRoundTime:false,lang:{},listWidth:null,maxTime:null,minTime:null,noneOption:false,orientation:"l",roundingFunction:roundingFunction,scrollDefault:null,selectOnBlur:false,show2400:false,showDuration:false,showOn:["click","focus"],showOnFocus:true,step:30,stopScrollPropagation:false,timeFormat:"g:ia",typeaheadHighlight:true,useSelect:false,wrapHours:true};var DEFAULT_LANG={am:"am",pm:"pm",AM:"AM",PM:"PM",decimal:".",mins:"mins",hr:"hr",hrs:"hrs"};var Timepicker=function(){function Timepicker(targetEl){var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};_classCallCheck(this,Timepicker);this._handleFormatValue=this._handleFormatValue.bind(this);this._handleKeyUp=this._handleKeyUp.bind(this);this.targetEl=targetEl;var attrOptions=Timepicker.extractAttrOptions(targetEl,Object.keys(DEFAULT_SETTINGS));this.settings=this.parseSettings(_objectSpread2(_objectSpread2(_objectSpread2({},DEFAULT_SETTINGS),options),attrOptions))}_createClass(Timepicker,[{key:"hideMe",value:function hideMe(){if(this.settings.useSelect){this.targetEl.blur();return}if(!this.list||!Timepicker.isVisible(this.list)){return}if(this.settings.selectOnBlur){this._selectValue()}this.list.hide();var hideTimepickerEvent=new CustomEvent("hideTimepicker");this.targetEl.dispatchEvent(hideTimepickerEvent)}},{key:"_findRow",value:function _findRow(value){if(!value&&value!==0){return false}var out=false;var value=this.settings.roundingFunction(value,this.settings);if(!this.list){return false}this.list.find("li").each(function(i,obj){var parsed=Number.parseInt(obj.dataset.time);if(Number.isNaN(parsed)){return}if(parsed==value){out=obj;return false}});return out}},{key:"_hideKeyboard",value:function _hideKeyboard(){return(window.navigator.msMaxTouchPoints||"ontouchstart"in document)&&this.settings.disableTouchKeyboard}},{key:"_setTimeValue",value:function _setTimeValue(value,source){if(this.targetEl.nodeName==="INPUT"){if(value!==null||this.targetEl.value!=""){this.targetEl.value=value}var tp=this;var settings=tp.settings;if(settings.useSelect&&source!="select"&&tp.list){tp.list.val(tp._roundAndFormatTime(tp.time2int(value)))}}var selectTimeEvent=new Event("selectTime");if(this.selectedValue!=value){this.selectedValue=value;var changeTimeEvent=new Event("changeTime");var changeEvent=new CustomEvent("change",{detail:"timepicker"});if(source=="select"){this.targetEl.dispatchEvent(selectTimeEvent);this.targetEl.dispatchEvent(changeTimeEvent);this.targetEl.dispatchEvent(changeEvent)}else if(["error","initial"].indexOf(source)==-1){this.targetEl.dispatchEvent(changeTimeEvent)}return true}else{if(["error","initial"].indexOf(source)==-1){this.targetEl.dispatchEvent(selectTimeEvent)}return false}}},{key:"_getTimeValue",value:function _getTimeValue(){if(this.targetEl.nodeName==="INPUT"){return this.targetEl.value}else{return this.selectedValue}}},{key:"_selectValue",value:function _selectValue(){var tp=this;var settings=tp.settings;var list=tp.list;var cursor=list.find(".ui-timepicker-selected");if(cursor.hasClass("ui-timepicker-disabled")){return false}if(!cursor.length){return true}var timeValue=cursor.get(0).dataset.time;if(timeValue){var parsedTimeValue=Number.parseInt(timeValue);if(!Number.isNaN(parsedTimeValue)){timeValue=parsedTimeValue}}if(timeValue!==null){if(typeof timeValue!="string"){timeValue=tp._int2time(timeValue)}tp._setTimeValue(timeValue,"select")}return true}},{key:"time2int",value:function time2int(timeString){if(timeString===""||timeString===null||timeString===undefined)return null;if(timeString instanceof Date){return timeString.getHours()*3600+timeString.getMinutes()*60+timeString.getSeconds()}if(typeof timeString!="string"){return timeString}timeString=timeString.toLowerCase().replace(/[\s\.]/g,"");if(timeString.slice(-1)=="a"||timeString.slice(-1)=="p"){timeString+="m"}var pattern=/^(([^0-9]*))?([0-9]?[0-9])(([0-5][0-9]))?(([0-5][0-9]))?(([^0-9]*))$/;var hasDelimetersMatch=timeString.match(/\W/);if(hasDelimetersMatch){pattern=/^(([^0-9]*))?([0-9]?[0-9])(\W+([0-5][0-9]?))?(\W+([0-5][0-9]))?(([^0-9]*))$/}var time=timeString.match(pattern);if(!time){return null}var hour=parseInt(time[3]*1,10);var ampm=time[2]||time[9];var hours=hour;var minutes=time[5]*1||0;var seconds=time[7]*1||0;if(!ampm&&time[3].length==2&&time[3][0]=="0"){ampm="am"}if(hour<=12&&ampm){ampm=ampm.trim();var isPm=ampm==this.settings.lang.pm||ampm==this.settings.lang.PM;if(hour==12){hours=isPm?12:0}else{hours=hour+(isPm?12:0)}}else{var t=hour*3600+minutes*60+seconds;if(t>=ONE_DAY+(this.settings.show2400?1:0)){if(this.settings.wrapHours===false){return null}hours=hour%24}}var timeInt=hours*3600+minutes*60+seconds;if(hour<12&&!ampm&&this.settings._twelveHourTime&&this.settings.scrollDefault){var delta=timeInt-this.settings.scrollDefault();if(delta<0&&delta>=ONE_DAY/-2){timeInt=(timeInt+ONE_DAY/2)%ONE_DAY}}return timeInt}},{key:"parseSettings",value:function parseSettings(settings){var _this=this;settings.lang=_objectSpread2(_objectSpread2({},DEFAULT_LANG),settings.lang);this.settings=settings;if(settings.minTime){settings.minTime=this.time2int(settings.minTime)}if(settings.maxTime){settings.maxTime=this.time2int(settings.maxTime)}if(settings.listWidth){settings.listWidth=this.time2int(settings.listWidth)}if(settings.durationTime&&typeof settings.durationTime!=="function"){settings.durationTime=this.time2int(settings.durationTime)}if(settings.scrollDefault=="now"){settings.scrollDefault=function(){return settings.roundingFunction(_this.time2int(new Date),settings)}}else if(settings.scrollDefault&&typeof settings.scrollDefault!="function"){var val=settings.scrollDefault;settings.scrollDefault=function(){return settings.roundingFunction(_this.time2int(val),settings)}}else if(settings.minTime){settings.scrollDefault=function(){return settings.roundingFunction(settings.minTime,settings)}}if(typeof settings.timeFormat==="string"&&settings.timeFormat.match(/[gh]/)){settings._twelveHourTime=true}if(settings.showOnFocus===false&&settings.showOn.indexOf("focus")!=-1){settings.showOn.splice(settings.showOn.indexOf("focus"),1)}if(!settings.disableTimeRanges){settings.disableTimeRanges=[]}if(settings.disableTimeRanges.length>0){for(var i in settings.disableTimeRanges){settings.disableTimeRanges[i]=[this.time2int(settings.disableTimeRanges[i][0]),this.time2int(settings.disableTimeRanges[i][1])]}settings.disableTimeRanges=settings.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var i=settings.disableTimeRanges.length-1;i>0;i--){if(settings.disableTimeRanges[i][0]<=settings.disableTimeRanges[i-1][1]){settings.disableTimeRanges[i-1]=[Math.min(settings.disableTimeRanges[i][0],settings.disableTimeRanges[i-1][0]),Math.max(settings.disableTimeRanges[i][1],settings.disableTimeRanges[i-1][1])];settings.disableTimeRanges.splice(i,1)}}}return settings}},{key:"_disableTextInputHandler",value:function _disableTextInputHandler(e){switch(e.keyCode){case 13:case 9:return;default:e.preventDefault()}}},{key:"_int2duration",value:function _int2duration(seconds,step){seconds=Math.abs(seconds);var minutes=Math.round(seconds/60),duration=[],hours,mins;if(minutes<60){duration=[minutes,this.settings.lang.mins]}else{hours=Math.floor(minutes/60);mins=minutes%60;if(step==30&&mins==30){hours+=this.settings.lang.decimal+5}duration.push(hours);duration.push(hours==1?this.settings.lang.hr:this.settings.lang.hrs);if(step!=30&&mins){duration.push(mins);duration.push(this.settings.lang.mins)}}return duration.join(" ")}},{key:"_roundAndFormatTime",value:function _roundAndFormatTime(seconds){seconds=this.settings.roundingFunction(seconds,this.settings);if(seconds!==null){return this._int2time(seconds)}}},{key:"_int2time",value:function _int2time(timeInt){if(typeof timeInt!="number"){return null}var seconds=parseInt(timeInt%60),minutes=parseInt(timeInt/60%60),hours=parseInt(timeInt/(60*60)%24);var time=new Date(1970,0,2,hours,minutes,seconds,0);if(isNaN(time.getTime())){return null}if(typeof this.settings.timeFormat==="function"){return this.settings.timeFormat(time)}var output="";var hour,code;for(var i=0;i<this.settings.timeFormat.length;i++){code=this.settings.timeFormat.charAt(i);switch(code){case"a":output+=time.getHours()>11?this.settings.lang.pm:this.settings.lang.am;break;case"A":output+=time.getHours()>11?this.settings.lang.PM:this.settings.lang.AM;break;case"g":hour=time.getHours()%12;output+=hour===0?"12":hour;break;case"G":hour=time.getHours();if(timeInt===ONE_DAY)hour=this.settings.show2400?24:0;output+=hour;break;case"h":hour=time.getHours()%12;if(hour!==0&&hour<10){hour="0"+hour}output+=hour===0?"12":hour;break;case"H":hour=time.getHours();if(timeInt===ONE_DAY)hour=this.settings.show2400?24:0;output+=hour>9?hour:"0"+hour;break;case"i":var minutes=time.getMinutes();output+=minutes>9?minutes:"0"+minutes;break;case"s":seconds=time.getSeconds();output+=seconds>9?seconds:"0"+seconds;break;case"\\":i++;output+=this.settings.timeFormat.charAt(i);break;default:output+=code}}return output}},{key:"_setSelected",value:function _setSelected(){var list=this.list;list.find("li").removeClass("ui-timepicker-selected");var timeValue=this.time2int(this._getTimeValue());if(timeValue===null){return}var selected=this._findRow(timeValue);if(selected){var selectedRect=selected.getBoundingClientRect();var listRect=list.get(0).getBoundingClientRect();var topDelta=selectedRect.top-listRect.top;if(topDelta+selectedRect.height>listRect.height||topDelta<0){var newScroll=list.scrollTop()+(selectedRect.top-listRect.top)-selectedRect.height;list.scrollTop(newScroll)}var parsed=Number.parseInt(selected.dataset.time);if(this.settings.forceRoundTime||parsed===timeValue){selected.classList.add("ui-timepicker-selected")}}}},{key:"_isFocused",value:function _isFocused(el){return el===document.activeElement}},{key:"_handleFormatValue",value:function _handleFormatValue(e){if(e&&e.detail=="timepicker"){return}this._formatValue(e)}},{key:"_formatValue",value:function _formatValue(e,origin){if(this.targetEl.value===""){this._setTimeValue(null,origin);return}if(this._isFocused(this.targetEl)&&(!e||e.type!="change")){return}var settings=this.settings;var seconds=this.time2int(this.targetEl.value);if(seconds===null){var timeFormatErrorEvent=new CustomEvent("timeFormatError");this.targetEl.dispatchEvent(timeFormatErrorEvent);return}var rangeError=false;if(settings.minTime!==null&&settings.maxTime!==null&&(seconds<settings.minTime||seconds>settings.maxTime)){rangeError=true}var _iterator=_createForOfIteratorHelper(settings.disableTimeRanges),_step;try{for(_iterator.s();!(_step=_iterator.n()).done;){var range=_step.value;if(seconds>=range[0]&&seconds<range[1]){rangeError=true;break}}}catch(err){_iterator.e(err)}finally{_iterator.f()}if(settings.forceRoundTime){var roundSeconds=settings.roundingFunction(seconds,settings);if(roundSeconds!=seconds){seconds=roundSeconds;origin=null}}var prettyTime=this._int2time(seconds);if(rangeError){this._setTimeValue(prettyTime);var timeRangeErrorEvent=new CustomEvent("timeRangeError");this.targetEl.dispatchEvent(timeRangeErrorEvent)}else{this._setTimeValue(prettyTime,origin)}}},{key:"_generateNoneElement",value:function _generateNoneElement(optionValue,useSelect){var label,className,value;if(_typeof(optionValue)=="object"){label=optionValue.label;className=optionValue.className;value=optionValue.value}else if(typeof optionValue=="string"){label=optionValue;value=""}else{$.error("Invalid noneOption value")}var el;if(useSelect){el=document.createElement("option");el.value=value}else{el=document.createElement("li");el.dataset.time=String(value)}el.innerText=label;el.classList.add(className);return el}},{key:"_handleKeyUp",value:function _handleKeyUp(e){if(!this.list||!Timepicker.isVisible(this.list)||this.settings.disableTextInput){return true}if(e.type==="paste"||e.type==="cut"){setTimeout(function(){if(this.settings.typeaheadHighlight){this._setSelected()}else{this.list.hide()}},0);return}switch(e.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:if(this.settings.typeaheadHighlight){this._setSelected()}else{this.list.hide()}break}}}],[{key:"extractAttrOptions",value:function extractAttrOptions(element,keys){var output={};var _iterator2=_createForOfIteratorHelper(keys),_step2;try{for(_iterator2.s();!(_step2=_iterator2.n()).done;){var key=_step2.value;if(key in element.dataset){output[key]=element.dataset[key]}}}catch(err){_iterator2.e(err)}finally{_iterator2.f()}return output}},{key:"isVisible",value:function isVisible(elem){var el=elem[0];return el.offsetWidth>0&&el.offsetHeight>0}},{key:"hideAll",value:function hideAll(){var _iterator3=_createForOfIteratorHelper(document.getElementsByClassName("ui-timepicker-input")),_step3;try{for(_iterator3.s();!(_step3=_iterator3.n()).done;){var el=_step3.value;var tp=el.timepickerObj;if(tp){tp.hideMe()}}}catch(err){_iterator3.e(err)}finally{_iterator3.f()}}}]);return Timepicker}();(function(factory){if((typeof exports==="undefined"?"undefined":_typeof(exports))==="object"&&exports&&(typeof module==="undefined"?"undefined":_typeof(module))==="object"&&module&&module.exports===exports){factory(require("jquery"))}else if(typeof define==="function"&&define.amd){define(["jquery"],factory)}else{factory(jQuery)}})(function($){var _lang={};var methods={init:function init(options){return this.each(function(){var self=$(this);var tp=new Timepicker(this,options);var settings=tp.settings;_lang=settings.lang;this.timepickerObj=tp;self.addClass("ui-timepicker-input");if(settings.useSelect){_render(self)}else{self.prop("autocomplete","off");if(settings.showOn){for(var i in settings.showOn){self.on(settings.showOn[i]+".timepicker",methods.show)}}self.on("change.timepicker",tp._handleFormatValue);self.on("keydown.timepicker",_keydownhandler);self.on("keyup.timepicker",tp._handleKeyUp);if(settings.disableTextInput){self.on("keydown.timepicker",tp._disableTextInputHandler)}self.on("cut.timepicker",tp._handleKeyUp);self.on("paste.timepicker",tp._handleKeyUp);tp._formatValue(null,"initial")}})},show:function show(e){var self=$(this);var tp=self[0].timepickerObj;var settings=tp.settings;if(e){e.preventDefault()}if(settings.useSelect){tp.list.trigger("focus");return}if(tp._hideKeyboard()){self.trigger("blur")}var list=tp.list;if(self.prop("readonly")){return}if(!list||list.length===0||typeof settings.durationTime==="function"){_render(self);list=tp.list}if(Timepicker.isVisible(list)){return}if(self.is("input")){tp.selectedValue=self.val()}tp._setSelected();Timepicker.hideAll();if(typeof settings.listWidth=="number"){list.width(self.outerWidth()*settings.listWidth)}list.show();var listOffset={};if(settings.orientation.match(/r/)){listOffset.left=self.offset().left+self.outerWidth()-list.outerWidth()+parseInt(list.css("marginLeft").replace("px",""),10)}else if(settings.orientation.match(/l/)){listOffset.left=self.offset().left+parseInt(list.css("marginLeft").replace("px",""),10)}else if(settings.orientation.match(/c/)){listOffset.left=self.offset().left+(self.outerWidth()-list.outerWidth())/2+parseInt(list.css("marginLeft").replace("px",""),10)}var verticalOrientation;if(settings.orientation.match(/t/)){verticalOrientation="t"}else if(settings.orientation.match(/b/)){verticalOrientation="b"}else if(self.offset().top+self.outerHeight(true)+list.outerHeight()>$(window).height()+$(window).scrollTop()){verticalOrientation="t"}else{verticalOrientation="b"}if(verticalOrientation=="t"){list.addClass("ui-timepicker-positioned-top");listOffset.top=self.offset().top-list.outerHeight()+parseInt(list.css("marginTop").replace("px",""),10)}else{list.removeClass("ui-timepicker-positioned-top");listOffset.top=self.offset().top+self.outerHeight()+parseInt(list.css("marginTop").replace("px",""),10)}list.offset(listOffset);var selected=list.find(".ui-timepicker-selected");if(!selected.length){var timeInt=tp.time2int(tp._getTimeValue());if(timeInt!==null){selected=$(tp._findRow(timeInt))}else if(settings.scrollDefault){selected=$(tp._findRow(settings.scrollDefault()))}}if(!selected.length||selected.hasClass("ui-timepicker-disabled")){selected=list.find("li:not(.ui-timepicker-disabled):first")}if(selected&&selected.length){var topOffset=list.scrollTop()+selected.position().top-selected.outerHeight();list.scrollTop(topOffset)}else{list.scrollTop(0)}if(settings.stopScrollPropagation){$(document).on("wheel.ui-timepicker",".ui-timepicker-wrapper",function(e){e.preventDefault();var currentScroll=$(this).scrollTop();$(this).scrollTop(currentScroll+e.originalEvent.deltaY)})}$(document).on("mousedown.ui-timepicker",_closeHandler);$(window).on("resize.ui-timepicker",_closeHandler);if(settings.closeOnWindowScroll){$(document).on("scroll.ui-timepicker",_closeHandler)}self.trigger("showTimepicker");return this},hide:function hide(e){var tp=this[0].timepickerObj;if(tp){tp.hideMe()}Timepicker.hideAll();return this},option:function option(key,value){if(typeof key=="string"&&typeof value=="undefined"){var tp=this[0].timepickerObj;return tp.settings[key]}return this.each(function(){var self=$(this);var tp=self[0].timepickerObj;var settings=tp.settings;var list=tp.list;if(_typeof(key)=="object"){settings=$.extend(settings,key)}else if(typeof key=="string"){settings[key]=value}settings=tp.parseSettings(settings);tp.settings=settings;tp._formatValue({type:"change"},"initial");if(list){list.remove();tp.list=null}if(settings.useSelect){_render(self)}})},getSecondsFromMidnight:function getSecondsFromMidnight(){var tp=this[0].timepickerObj;return tp.time2int(tp._getTimeValue())},getTime:function getTime(relative_date){var tp=this[0].timepickerObj;var time_string=tp._getTimeValue();if(!time_string){return null}var offset=tp.time2int(time_string);if(offset===null){return null}if(!relative_date){relative_date=new Date}var time=new Date(relative_date);time.setHours(offset/3600);time.setMinutes(offset%3600/60);time.setSeconds(offset%60);time.setMilliseconds(0);return time},isVisible:function isVisible(){var tp=this[0].timepickerObj;return!!(tp&&tp.list&&Timepicker.isVisible(tp.list))},setTime:function setTime(value){var tp=this[0].timepickerObj;var settings=tp.settings;if(settings.forceRoundTime){var prettyTime=tp._roundAndFormatTime(tp.time2int(value))}else{var prettyTime=tp._int2time(tp.time2int(value))}if(value&&prettyTime===null&&settings.noneOption){prettyTime=value}tp._setTimeValue(prettyTime,"initial");tp._formatValue({type:"change"},"initial");if(tp&&tp.list){tp._setSelected()}return this},remove:function remove(){var self=this;if(!self.hasClass("ui-timepicker-input")){return}var tp=self[0].timepickerObj;var settings=tp.settings;self.removeAttr("autocomplete","off");self.removeClass("ui-timepicker-input");self.removeData("timepicker-obj");self.off(".timepicker");if(tp.list){tp.list.remove()}if(settings.useSelect){self.show()}tp.list=null;return this}};function _render(self){var tp=self[0].timepickerObj;var list=tp.list;var settings=tp.settings;if(list&&list.length){list.remove();tp.list=null}if(settings.useSelect){list=$("<select></select>",{class:"ui-timepicker-select"});if(self.attr("name")){list.attr("name","ui-timepicker-"+self.attr("name"))}var wrapped_list=list}else{list=$("<ul></ul>",{class:"ui-timepicker-list"});var wrapped_list=$("<div></div>",{class:"ui-timepicker-wrapper",tabindex:-1});wrapped_list.css({display:"none",position:"absolute"}).append(list)}if(settings.noneOption){if(settings.noneOption===true){settings.noneOption=settings.useSelect?"Time...":"None"}if($.isArray(settings.noneOption)){for(var i in settings.noneOption){if(parseInt(i,10)==i){var noneElement=tp._generateNoneElement(settings.noneOption[i],settings.useSelect);list.append(noneElement)}}}else{var noneElement=tp._generateNoneElement(settings.noneOption,settings.useSelect);list.append(noneElement)}}if(settings.className){wrapped_list.addClass(settings.className)}if((settings.minTime!==null||settings.durationTime!==null)&&settings.showDuration){var stepval=typeof settings.step=="function"?"function":settings.step;wrapped_list.addClass("ui-timepicker-with-duration");wrapped_list.addClass("ui-timepicker-step-"+settings.step)}var durStart=settings.minTime;if(typeof settings.durationTime==="function"){durStart=tp.time2int(settings.durationTime())}else if(settings.durationTime!==null){durStart=settings.durationTime}var start=settings.minTime!==null?settings.minTime:0;var end=settings.maxTime!==null?settings.maxTime:start+ONE_DAY-1;if(end<start){end+=ONE_DAY}if(end===ONE_DAY-1&&$.type(settings.timeFormat)==="string"&&settings.show2400){end=ONE_DAY}var dr=settings.disableTimeRanges;var drCur=0;var drLen=dr.length;var stepFunc=settings.step;if(typeof stepFunc!="function"){stepFunc=function stepFunc(){return settings.step}}for(var i=start,j=0;i<=end;j++,i+=stepFunc(j)*60){var timeInt=i;var timeString=tp._int2time(timeInt);if(settings.useSelect){var row=$("<option></option>",{value:timeString});row.text(timeString)}else{var row=$("<li></li>");row.addClass(timeInt%ONE_DAY<ONE_DAY/2?"ui-timepicker-am":"ui-timepicker-pm");row.attr("data-time",roundingFunction(timeInt,settings));row.text(timeString)}if((settings.minTime!==null||settings.durationTime!==null)&&settings.showDuration){var durationString=tp._int2duration(i-durStart,settings.step);if(settings.useSelect){row.text(row.text()+" ("+durationString+")")}else{var duration=$("<span></span>",{class:"ui-timepicker-duration"});duration.text(" ("+durationString+")");row.append(duration)}}if(drCur<drLen){if(timeInt>=dr[drCur][1]){drCur+=1}if(dr[drCur]&&timeInt>=dr[drCur][0]&&timeInt<dr[drCur][1]){if(settings.useSelect){row.prop("disabled",true)}else{row.addClass("ui-timepicker-disabled")}}}list.append(row)}wrapped_list.data("timepicker-input",self);tp.list=wrapped_list;if(settings.useSelect){if(self.val()){list.val(tp._roundAndFormatTime(tp.time2int(self.val())))}list.on("focus",function(){$(this).data("timepicker-input").trigger("showTimepicker")});list.on("blur",function(){$(this).data("timepicker-input").trigger("hideTimepicker")});list.on("change",function(){tp._setTimeValue($(this).val(),"select")});tp._setTimeValue(list.val(),"initial");self.hide().after(list)}else{var appendTo=settings.appendTo;if(typeof appendTo==="string"){appendTo=$(appendTo)}else if(typeof appendTo==="function"){appendTo=appendTo(self)}appendTo.append(wrapped_list);tp._setSelected();list.on("mousedown click","li",function(e){self.off("focus.timepicker");self.on("focus.timepicker-ie-hack",function(){self.off("focus.timepicker-ie-hack");self.on("focus.timepicker",methods.show)});if(!tp._hideKeyboard()){self[0].focus()}list.find("li").removeClass("ui-timepicker-selected");$(this).addClass("ui-timepicker-selected");if(tp._selectValue()){self.trigger("hideTimepicker");list.on("mouseup.timepicker click.timepicker","li",function(e){list.off("mouseup.timepicker click.timepicker");wrapped_list.hide()})}})}}function _closeHandler(e){if(e.target==window){return}var target=$(e.target);if(target.closest(".ui-timepicker-input").length||target.closest(".ui-timepicker-wrapper").length){return}Timepicker.hideAll();$(document).off(".ui-timepicker");$(window).off(".ui-timepicker")}function _keydownhandler(e){var self=$(this);var tp=self[0].timepickerObj;var list=tp.list;if(!list||!Timepicker.isVisible(list)){if(e.keyCode==40){methods.show.call(self.get(0));list=tp.list;if(!tp._hideKeyboard()){self.trigger("focus")}}else{return true}}switch(e.keyCode){case 13:if(tp._selectValue()){tp._formatValue({type:"change"});tp.hideMe()}e.preventDefault();return false;case 38:var selected=list.find(".ui-timepicker-selected");if(!selected.length){list.find("li").each(function(i,obj){if($(obj).position().top>0){selected=$(obj);return false}});selected.addClass("ui-timepicker-selected")}else if(!selected.is(":first-child")){selected.removeClass("ui-timepicker-selected");selected.prev().addClass("ui-timepicker-selected");if(selected.prev().position().top<selected.outerHeight()){list.scrollTop(list.scrollTop()-selected.outerHeight())}}return false;case 40:selected=list.find(".ui-timepicker-selected");if(selected.length===0){list.find("li").each(function(i,obj){if($(obj).position().top>0){selected=$(obj);return false}});selected.addClass("ui-timepicker-selected")}else if(!selected.is(":last-child")){selected.removeClass("ui-timepicker-selected");selected.next().addClass("ui-timepicker-selected");if(selected.next().position().top+2*selected.outerHeight()>list.outerHeight()){list.scrollTop(list.scrollTop()+selected.outerHeight())}}return false;case 27:list.find("li").removeClass("ui-timepicker-selected");tp.hideMe();break;case 9:tp.hideMe();break;default:return true}}$.fn.timepicker=function(method){if(!this.length)return this;if(methods[method]){if(!this.hasClass("ui-timepicker-input")){return this}return methods[method].apply(this,Array.prototype.slice.call(arguments,1))}else if(_typeof(method)==="object"||!method){return methods.init.apply(this,arguments)}else{$.error("Method "+method+" does not exist on jQuery.timepicker")}};$.fn.timepicker.defaults=DEFAULT_SETTINGS})})();
readme.txt CHANGED
@@ -4,8 +4,8 @@ Donate link: http://wp-events-plugin.com
4
  Tags: bookings, calendar, tickets, events, buddypress, event management, google maps, maps, locations, registration, zoom
5
  Text Domain: events-manager
6
  Requires at least: 5.2
7
- Tested up to: 5.6
8
- Stable tag: 5.9.10
9
  Requires PHP: 5.3
10
 
11
  Fully featured event registration management including recurring events, locations management, calendar, Google map integration, booking management
@@ -63,9 +63,13 @@ We provide the tools to [help you be GDPR compliant](http://wp-events-plugin.com
63
  * settings to control what can be exported/erased as well as where/when to place consent requests
64
  * sample text for your site privacy policy describing what Events Manager does with personal data
65
 
66
- = Go Pro =
 
 
 
67
  We have a premium "Pro" add-on for Events Manager which not only demonstrates the flexibility of Events Manager, but also adds some important features including but not limited to:
68
 
 
69
  * PayPal, Stripe, Authorize.net and Offline Payments
70
  * Custom booking forms
71
  * Individual Attendee custom forms
@@ -115,6 +119,17 @@ See our [FAQ](http://wp-events-plugin.com/documentation/faq/) page, which is upd
115
  6. Manage attendees with various booking reports
116
 
117
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
118
  = 5.9.10 =
119
  * fixed event locations not getting synced with translations (WPML) and requires re-saving events to take effect
120
  * fixed incorrect dates in calendars for some specific server setups - props to @davidkryzaniak
4
  Tags: bookings, calendar, tickets, events, buddypress, event management, google maps, maps, locations, registration, zoom
5
  Text Domain: events-manager
6
  Requires at least: 5.2
7
+ Tested up to: 5.7
8
+ Stable tag: 5.9.11
9
  Requires PHP: 5.3
10
 
11
  Fully featured event registration management including recurring events, locations management, calendar, Google map integration, booking management
63
  * settings to control what can be exported/erased as well as where/when to place consent requests
64
  * sample text for your site privacy policy describing what Events Manager does with personal data
65
 
66
+ = Premium Features =
67
+
68
+ * NEW * Check out our WooCommerce add-on! Sell bookings directly with WooCommerce.
69
+
70
  We have a premium "Pro" add-on for Events Manager which not only demonstrates the flexibility of Events Manager, but also adds some important features including but not limited to:
71
 
72
+ * WooCommerce integration included FREE (limited-time offer)
73
  * PayPal, Stripe, Authorize.net and Offline Payments
74
  * Custom booking forms
75
  * Individual Attendee custom forms
119
  6. Manage attendees with various booking reports
120
 
121
  == Changelog ==
122
+ = 5.9.11 =
123
+ * updated JS to remove any deprecated functionality in jQuery v3.5,
124
+ * changed timepicker library to (timepicker)[https://github.com/jonthornton/jquery-timepicker/]
125
+ * added $target to Event_Location->output() function parameters
126
+ * fixed EM_Event->output() errors causing booking emails to fail if containing #_EVENTLOCATION placeholders for non-virtual events
127
+ * added $send_email and $ignore_spaces params to EM_Bookings::set_status()
128
+ * added em_booking_admin action to top of single booking admin area
129
+ * added update_meta() function to EM_Booking,
130
+ * fixed some minor PHP warnings,
131
+ * added ticket availability re-check during EM_Booking::validate() for bookings stored in session before saving
132
+
133
  = 5.9.10 =
134
  * fixed event locations not getting synced with translations (WPML) and requires re-saving events to take effect
135
  * fixed incorrect dates in calendars for some specific server setups - props to @davidkryzaniak
templates/forms/event/bookings-ticket-form.php CHANGED
@@ -52,7 +52,7 @@ $col_count = absint($col_count); //now we know it's a number
52
  </select>
53
  </div>
54
  <?php echo esc_html_x('at', 'time','events-manager'); ?>
55
- <input id="start-time" class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="em_tickets[<?php echo $col_count; ?>][ticket_start_time]" value="<?php echo ( !empty($EM_Ticket->ticket_start) ) ? $EM_Ticket->start()->format( em_get_hour_format() ):''; ?>" />
56
  </div>
57
  <div class="ticket-dates-to">
58
  <label title="<?php esc_attr_e('Add a start or end date (or both) to impose time constraints on ticket availability. Leave either blank for no upper/lower limit.','events-manager'); ?>">
@@ -71,7 +71,7 @@ $col_count = absint($col_count); //now we know it's a number
71
  </select>
72
  </div>
73
  <?php echo esc_html_x('at', 'time','events-manager'); ?>
74
- <input id="end-time" class="em-time-input em-time-end ticket-times-to-normal" type="text" size="8" maxlength="8" name="em_tickets[<?php echo $col_count; ?>][ticket_end_time]" value="<?php echo ( !empty($EM_Ticket->ticket_end) ) ? $EM_Ticket->end()->format( em_get_hour_format() ):''; ?>" />
75
  </div>
76
  </div>
77
  <?php if( !get_option('dbem_bookings_tickets_single') || count($EM_Ticket->get_event()->get_tickets()->tickets) > 1 ): ?>
52
  </select>
53
  </div>
54
  <?php echo esc_html_x('at', 'time','events-manager'); ?>
55
+ <input class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="em_tickets[<?php echo $col_count; ?>][ticket_start_time]" value="<?php echo ( !empty($EM_Ticket->ticket_start) ) ? $EM_Ticket->start()->format( em_get_hour_format() ):''; ?>" />
56
  </div>
57
  <div class="ticket-dates-to">
58
  <label title="<?php esc_attr_e('Add a start or end date (or both) to impose time constraints on ticket availability. Leave either blank for no upper/lower limit.','events-manager'); ?>">
71
  </select>
72
  </div>
73
  <?php echo esc_html_x('at', 'time','events-manager'); ?>
74
+ <input class="em-time-input em-time-end ticket-times-to-normal" type="text" size="8" maxlength="8" name="em_tickets[<?php echo $col_count; ?>][ticket_end_time]" value="<?php echo ( !empty($EM_Ticket->ticket_end) ) ? $EM_Ticket->end()->format( em_get_hour_format() ):''; ?>" />
75
  </div>
76
  </div>
77
  <?php if( !get_option('dbem_bookings_tickets_single') || count($EM_Ticket->get_event()->get_tickets()->tickets) > 1 ): ?>
templates/forms/event/recurring-when.php CHANGED
@@ -8,9 +8,9 @@ $classes = array();
8
  <div id="em-form-recurrence" class="event-form-recurrence event-form-when">
9
  <p class="em-time-range">
10
  <?php _e('Events start from','events-manager'); ?>
11
- <input id="start-time" class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="event_start_time" value="<?php echo $EM_Event->start()->i18n($hours_format); ?>" />
12
  <?php _e('to','events-manager'); ?>
13
- <input id="end-time" class="em-time-input em-time-end" type="text" size="8" maxlength="8" name="event_end_time" value="<?php echo $EM_Event->end()->i18n($hours_format); ?>" />
14
  <?php _e('All day','events-manager'); ?> <input type="checkbox" class="em-time-allday" name="event_all_day" id="em-time-all-day" value="1" <?php if(!empty($EM_Event->event_all_day)) echo 'checked="checked"'; ?> />
15
  </p>
16
  <?php if( get_option('dbem_timezone_enabled') ): ?>
8
  <div id="em-form-recurrence" class="event-form-recurrence event-form-when">
9
  <p class="em-time-range">
10
  <?php _e('Events start from','events-manager'); ?>
11
+ <input class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="event_start_time" value="<?php echo $EM_Event->start()->i18n($hours_format); ?>" />
12
  <?php _e('to','events-manager'); ?>
13
+ <input class="em-time-input em-time-end" type="text" size="8" maxlength="8" name="event_end_time" value="<?php echo $EM_Event->end()->i18n($hours_format); ?>" />
14
  <?php _e('All day','events-manager'); ?> <input type="checkbox" class="em-time-allday" name="event_all_day" id="em-time-all-day" value="1" <?php if(!empty($EM_Event->event_all_day)) echo 'checked="checked"'; ?> />
15
  </p>
16
  <?php if( get_option('dbem_timezone_enabled') ): ?>
templates/forms/event/when-with-recurring.php CHANGED
@@ -21,9 +21,9 @@ $admin_recurring = is_admin() && $EM_Event->is_recurring();
21
  <p>
22
  <span class="em-recurring-text"><?php _e('Events start from','events-manager'); ?></span>
23
  <span class="em-event-text"><?php _e('Event starts at','events-manager'); ?></span>
24
- <input id="start-time" class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="event_start_time" value="<?php echo $EM_Event->start()->i18n($hours_format); ?>" />
25
  <?php _e('to','events-manager'); ?>
26
- <input id="end-time" class="em-time-input em-time-end" type="text" size="8" maxlength="8" name="event_end_time" value="<?php echo $EM_Event->end()->i18n($hours_format); ?>" />
27
  <?php _e('All day','events-manager'); ?> <input type="checkbox" class="em-time-allday" name="event_all_day" id="em-time-all-day" value="1" <?php if(!empty($EM_Event->event_all_day)) echo 'checked="checked"'; ?> />
28
  </p>
29
  <?php if( get_option('dbem_timezone_enabled') ): ?>
@@ -80,7 +80,7 @@ $admin_recurring = is_admin() && $EM_Event->is_recurring();
80
  <script type="text/javascript">
81
  //<![CDATA[
82
  jQuery(document).ready( function($) {
83
- $('#em-recurrence-checkbox').change(function(){
84
  if( $('#em-recurrence-checkbox').is(':checked') ){
85
  $('.em-recurring-text').show();
86
  $('.em-event-text').hide();
21
  <p>
22
  <span class="em-recurring-text"><?php _e('Events start from','events-manager'); ?></span>
23
  <span class="em-event-text"><?php _e('Event starts at','events-manager'); ?></span>
24
+ <input class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="event_start_time" value="<?php echo $EM_Event->start()->i18n($hours_format); ?>" />
25
  <?php _e('to','events-manager'); ?>
26
+ <input class="em-time-input em-time-end" type="text" size="8" maxlength="8" name="event_end_time" value="<?php echo $EM_Event->end()->i18n($hours_format); ?>" />
27
  <?php _e('All day','events-manager'); ?> <input type="checkbox" class="em-time-allday" name="event_all_day" id="em-time-all-day" value="1" <?php if(!empty($EM_Event->event_all_day)) echo 'checked="checked"'; ?> />
28
  </p>
29
  <?php if( get_option('dbem_timezone_enabled') ): ?>
80
  <script type="text/javascript">
81
  //<![CDATA[
82
  jQuery(document).ready( function($) {
83
+ $('#em-recurrence-checkbox').on('change', function(){
84
  if( $('#em-recurrence-checkbox').is(':checked') ){
85
  $('.em-recurring-text').show();
86
  $('.em-event-text').hide();
templates/forms/event/when.php CHANGED
@@ -14,9 +14,9 @@ $required = apply_filters('em_required_html','<i>*</i>');
14
  </p>
15
  <p class="em-time-range">
16
  <span class="em-event-text"><?php _e('Event starts at','events-manager'); ?></span>
17
- <input id="start-time" class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="event_start_time" value="<?php echo $EM_Event->start()->format($hours_format); ?>" />
18
  <?php _e('to','events-manager'); ?>
19
- <input id="end-time" class="em-time-input em-time-end" type="text" size="8" maxlength="8" name="event_end_time" value="<?php echo $EM_Event->end()->format($hours_format); ?>" />
20
  <?php _e('All day','events-manager'); ?> <input type="checkbox" class="em-time-all-day" name="event_all_day" id="em-time-all-day" value="1" <?php if(!empty($EM_Event->event_all_day)) echo 'checked="checked"'; ?> />
21
  </p>
22
  <?php if( get_option('dbem_timezone_enabled') ): ?>
14
  </p>
15
  <p class="em-time-range">
16
  <span class="em-event-text"><?php _e('Event starts at','events-manager'); ?></span>
17
+ <input class="em-time-input em-time-start" type="text" size="8" maxlength="8" name="event_start_time" value="<?php echo $EM_Event->start()->format($hours_format); ?>" />
18
  <?php _e('to','events-manager'); ?>
19
+ <input class="em-time-input em-time-end" type="text" size="8" maxlength="8" name="event_end_time" value="<?php echo $EM_Event->end()->format($hours_format); ?>" />
20
  <?php _e('All day','events-manager'); ?> <input type="checkbox" class="em-time-all-day" name="event_all_day" id="em-time-all-day" value="1" <?php if(!empty($EM_Event->event_all_day)) echo 'checked="checked"'; ?> />
21
  </p>
22
  <?php if( get_option('dbem_timezone_enabled') ): ?>
templates/templates/search/geo.js CHANGED
@@ -85,13 +85,13 @@ function em_geo_search_init(){
85
  }else{
86
  geo_field_status(false);
87
  }
88
- }).keyup( function(e) {
89
  if( this.value == '' ){ geo_field_status(false); }
90
  else if( wrapper.data('last-search') != this.value ){ geo_field_status('off'); }
91
  input.data('last-key', e.which);
92
  }).blur( function(e){ //create HTML 5 placeholder effect if not HTML 5
93
  if( this.value == '' && !('placeholder' in document.createElement('input')) ) this.value = EM.geo_placeholder;
94
- }).focus( function(e){
95
  if( this.value == EM.geo_placeholder ) this.value='';
96
  input.data('last-key', 13);
97
  }).attr('placeholder', EM.geo_placeholder);
85
  }else{
86
  geo_field_status(false);
87
  }
88
+ }).on('keyup', function(e) {
89
  if( this.value == '' ){ geo_field_status(false); }
90
  else if( wrapper.data('last-search') != this.value ){ geo_field_status('off'); }
91
  input.data('last-key', e.which);
92
  }).blur( function(e){ //create HTML 5 placeholder effect if not HTML 5
93
  if( this.value == '' && !('placeholder' in document.createElement('input')) ) this.value = EM.geo_placeholder;
94
+ }).on('focus', function(e){
95
  if( this.value == EM.geo_placeholder ) this.value='';
96
  input.data('last-key', 13);
97
  }).attr('placeholder', EM.geo_placeholder);
trunk/admin/bookings/em-cancelled.php DELETED
@@ -1,137 +0,0 @@
1
- <?php
2
- /**
3
- * Generates a "widget" table of confirmed bookings for a specific event.
4
- *
5
- * @param int $event_id
6
- */
7
- function em_bookings_cancelled_table(){
8
- global $EM_Event, $EM_Ticket, $wpdb, $current_user;
9
-
10
- $action_scope = ( !empty($_REQUEST['em_obj']) && $_REQUEST['em_obj'] == 'em_bookings_cancelled_table' );
11
- $action = ( $action_scope && !empty($_GET ['action']) ) ? $_GET ['action']:'';
12
- $order = ( $action_scope && !empty($_GET ['order']) ) ? $_GET ['order']:'ASC';
13
- $limit = ( $action_scope && !empty($_GET['limit']) ) ? $_GET['limit'] : 20;//Default limit
14
- $page = ( $action_scope && !empty($_GET['pno']) ) ? $_GET['pno']:1;
15
- $offset = ( $action_scope && $page > 1 ) ? ($page-1)*$limit : 0;
16
-
17
- if( is_object($EM_Ticket) ){
18
- $EM_Bookings = $EM_Ticket->get_bookings()->get_cancelled_bookings();
19
- }else{
20
- if( is_object($EM_Event) ){
21
- $EM_Bookings = $EM_Event->get_bookings()->get_cancelled_bookings();
22
- }else{
23
- return false;
24
- }
25
- }
26
- $bookings_count = (is_array($EM_Bookings->bookings)) ? count($EM_Bookings->bookings):0;
27
- ?>
28
- <div class='wrap em_bookings_pending_table em_obj'>
29
- <form id='bookings-filter' method='get' action='<?php bloginfo('wpurl') ?>/wp-admin/edit.php'>
30
- <input type="hidden" name="em_obj" value="em_bookings_pending_table" />
31
- <!--
32
- <ul class="subsubsub">
33
- <li>
34
- <a href='edit.php?post_type=post' class="current">All <span class="count">(1)</span></a> |
35
- </li>
36
- </ul>
37
- <p class="search-box">
38
- <label class="screen-reader-text" for="post-search-input"><?php _e('Search', 'events-manager'); ?>:</label>
39
- <input type="text" id="post-search-input" name="em_search" value="<?php echo (!empty($_GET['em_search'])) ? esc_attr($_GET['em_search']):''; ?>" />
40
- <input type="submit" value="<?php _e('Search', 'events-manager'); ?>" class="button" />
41
- </p>
42
- -->
43
- <?php if ( $bookings_count >= $limit ) : ?>
44
- <div class='tablenav'>
45
- <!--
46
- <div class="alignleft actions">
47
- <select name="action">
48
- <option value="-1" selected="selected">
49
- <?php _e('Bulk Actions', 'events-manager'); ?>
50
- </option>
51
- <option value="approve">
52
- <?php _e('Approve', 'events-manager'); ?>
53
- </option>
54
- <option value="decline">
55
- <?php _e('Decline', 'events-manager'); ?>
56
- </option>
57
- </select>
58
- <input type="submit" id="post-query-submit" value="Filter" class="button-secondary" />
59
- </div>
60
- -->
61
- <!--
62
- <div class="view-switch">
63
- <a href="/wp-admin/edit.php?mode=list"><img class="current" id="view-switch-list" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="List View" alt="List View" name="view-switch-list" /></a> <a href="/wp-admin/edit.php?mode=excerpt"><img id="view-switch-excerpt" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="Excerpt View" alt="Excerpt View" name="view-switch-excerpt" /></a>
64
- </div>
65
- -->
66
- <?php
67
- if ( $bookings_count >= $limit ) {
68
- $bookings_nav = em_admin_paginate( $bookings_count, $limit, $page, array('em_ajax'=>0, 'em_obj'=>'em_bookings_confirmed_table'));
69
- echo $bookings_nav;
70
- }
71
- ?>
72
- <div class="clear"></div>
73
- </div>
74
- <?php endif; ?>
75
- <div class="clear"></div>
76
- <?php if( $bookings_count > 0 ): ?>
77
- <div class='table-wrap'>
78
- <table id='dbem-bookings-table' class='widefat post '>
79
- <thead>
80
- <tr>
81
- <th class='manage-column column-cb check-column' scope='col'>
82
- <input class='select-all' type="checkbox" value='1' />
83
- </th>
84
- <th class='manage-column' scope='col'><?php _e('Booker', 'events-manager'); ?></th>
85
- <th class='manage-column' scope='col'><?php _e('E-mail', 'events-manager'); ?></th>
86
- <th class='manage-column' scope='col'><?php _e('Phone number', 'events-manager'); ?></th>
87
- <th class='manage-column' scope='col'><?php _e('Spaces', 'events-manager'); ?></th>
88
- <th class='manage-column' scope='col'>&nbsp;</th>
89
- </tr>
90
- </thead>
91
- <tbody>
92
- <?php
93
- $rowno = 0;
94
- $event_count = 0;
95
- foreach ($EM_Bookings->bookings as $EM_Booking) {
96
- if( ($rowno < $limit || empty($limit)) && ($event_count >= $offset || $offset === 0) ) {
97
- $rowno++;
98
- ?>
99
- <tr>
100
- <th scope="row" class="check-column" style="padding:7px 0px 7px;"><input type='checkbox' value='<?php echo $EM_Booking->booking_id ?>' name='bookings[]'/></th>
101
- <td><a href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;person_id=<?php echo $EM_Booking->person->ID; ?>"><?php echo $EM_Booking->person->get_name() ?></a></td>
102
- <td><?php echo $EM_Booking->person->user_email ?></td>
103
- <td><?php echo $EM_Booking->person->phone ?></td>
104
- <td><?php echo $EM_Booking->get_spaces() ?></td>
105
- <td>
106
- <?php
107
- $approve_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_approve', 'booking_id'=>$EM_Booking->booking_id));
108
- $delete_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id));
109
- $edit_url = em_add_get_params($_SERVER['REQUEST_URI'], array('booking_id'=>$EM_Booking->booking_id, 'em_ajax'=>null, 'em_obj'=>null));
110
- ?>
111
- <a class="em-bookings-approve" href="<?php echo $approve_url ?>"><?php _e('Restore','events-manager'); ?></a> |
112
- <a class="em-bookings-edit" href="<?php echo $edit_url; ?>"><?php _e('Edit/View','events-manager'); ?></a> |
113
- <a class="em-bookings-delete" href="<?php echo $delete_url ?>"><?php _e('Delete','events-manager'); ?></a>
114
- </td>
115
- </tr>
116
- <?php
117
- }
118
- $event_count++;
119
- }
120
- ?>
121
- </tbody>
122
- </table>
123
- </div>
124
- <?php else: ?>
125
- <?php _e('No cancelled bookings.', 'events-manager'); ?>
126
- <?php endif; ?>
127
- </form>
128
- <?php if( !empty($bookings_nav) && $EM_Bookings >= $limit ) : ?>
129
- <div class='tablenav'>
130
- <?php echo $bookings_nav; ?>
131
- <div class="clear"></div>
132
- </div>
133
- <?php endif; ?>
134
- </div>
135
- <?php
136
- }
137
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/bookings/em-confirmed.php DELETED
@@ -1,144 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Generates a "widget" table of confirmed bookings for a specific event.
5
- *
6
- * @param int $event_id
7
- */
8
- function em_bookings_confirmed_table(){
9
- global $EM_Event, $EM_Ticket, $wpdb, $current_user;
10
-
11
- $action_scope = ( !empty($_REQUEST['em_obj']) && $_REQUEST['em_obj'] == 'em_bookings_confirmed_table' );
12
- $action = ( $action_scope && !empty($_GET ['action']) ) ? $_GET ['action']:'';
13
- $order = ( $action_scope && !empty($_GET ['order']) ) ? $_GET ['order']:'ASC';
14
- $limit = ( $action_scope && !empty($_GET['limit']) ) ? $_GET['limit'] : 20;//Default limit
15
- $page = ( $action_scope && !empty($_GET['pno']) ) ? $_GET['pno']:1;
16
- $offset = ( $action_scope && $page > 1 ) ? ($page-1)*$limit : 0;
17
-
18
- if( is_object($EM_Ticket) ){
19
- $EM_Bookings = $EM_Ticket->get_bookings()->get_bookings();
20
- }else{
21
- if( is_object($EM_Event) ){
22
- $EM_Bookings = $EM_Event->get_bookings()->get_bookings();
23
- }else{
24
- return false;
25
- }
26
- }
27
- $bookings_count = (is_array($EM_Bookings->bookings)) ? count($EM_Bookings->bookings):0;
28
- ?>
29
- <div class='wrap em_bookings_pending_table em_obj'>
30
- <form id='bookings-filter' method='get' action='<?php bloginfo('wpurl') ?>/wp-admin/edit.php'>
31
- <input type="hidden" name="em_obj" value="em_bookings_pending_table" />
32
- <!--
33
- <ul class="subsubsub">
34
- <li>
35
- <a href='edit.php?post_type=post' class="current">All <span class="count">(1)</span></a> |
36
- </li>
37
- </ul>
38
- <p class="search-box">
39
- <label class="screen-reader-text" for="post-search-input"><?php _e('Search', 'events-manager'); ?>:</label>
40
- <input type="text" id="post-search-input" name="em_search" value="<?php echo (!empty($_GET['em_search'])) ? esc_attr($_GET['em_search']):''; ?>" />
41
- <input type="submit" value="<?php _e('Search', 'events-manager'); ?>" class="button" />
42
- </p>
43
- -->
44
- <?php if ( $bookings_count >= $limit ) : ?>
45
- <div class='tablenav'>
46
- <!--
47
- <div class="alignleft actions">
48
- <select name="action">
49
- <option value="-1" selected="selected">
50
- <?php _e('Bulk Actions', 'events-manager'); ?>
51
- </option>
52
- <option value="approve">
53
- <?php _e('Approve', 'events-manager'); ?>
54
- </option>
55
- <option value="decline">
56
- <?php _e('Decline', 'events-manager'); ?>
57
- </option>
58
- </select>
59
- <input type="submit" id="post-query-submit" value="Filter" class="button-secondary" />
60
- </div>
61
- -->
62
- <!--
63
- <div class="view-switch">
64
- <a href="/wp-admin/edit.php?mode=list"><img class="current" id="view-switch-list" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="List View" alt="List View" name="view-switch-list" /></a> <a href="/wp-admin/edit.php?mode=excerpt"><img id="view-switch-excerpt" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="Excerpt View" alt="Excerpt View" name="view-switch-excerpt" /></a>
65
- </div>
66
- -->
67
- <?php
68
- if ( $bookings_count >= $limit ) {
69
- $bookings_nav = em_admin_paginate($bookings_count, $limit, $page, array('em_ajax'=>0, 'em_obj'=>'em_bookings_confirmed_table'));
70
- echo $bookings_nav;
71
- }
72
- ?>
73
- <div class="clear"></div>
74
- </div>
75
- <?php endif; ?>
76
- <div class="clear"></div>
77
- <?php if( $bookings_count > 0 ): ?>
78
- <div class='table-wrap'>
79
- <table id='dbem-bookings-table' class='widefat post '>
80
- <thead>
81
- <tr>
82
- <th class='manage-column column-cb check-column' scope='col'>
83
- <input class='select-all' type="checkbox" value='1' />
84
- </th>
85
- <th class='manage-column' scope='col'><?php _e('Booker', 'events-manager'); ?></th>
86
- <th class='manage-column' scope='col'><?php _e('E-mail', 'events-manager'); ?></th>
87
- <th class='manage-column' scope='col'><?php _e('Phone number', 'events-manager'); ?></th>
88
- <th class='manage-column' scope='col'><?php _e('Spaces', 'events-manager'); ?></th>
89
- <th class='manage-column' scope='col'>&nbsp;</th>
90
- </tr>
91
- </thead>
92
- <tbody>
93
- <?php
94
- $rowno = 0;
95
- $event_count = 0;
96
- foreach ($EM_Bookings->bookings as $EM_Booking) {
97
- if( ($rowno < $limit || empty($limit)) && ($event_count >= $offset || $offset === 0) ) {
98
- $rowno++;
99
- ?>
100
- <tr>
101
- <th scope="row" class="check-column" style="padding:7px 0px 7px;"><input type='checkbox' value='<?php echo $EM_Booking->booking_id ?>' name='bookings[]'/></th>
102
- <td><a href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;person_id=<?php echo $EM_Booking->person_id; ?>"><?php echo $EM_Booking->person->get_name() ?></a></td>
103
- <td><?php echo $EM_Booking->person->user_email ?></td>
104
- <td><?php echo $EM_Booking->person->phone ?></td>
105
- <td><?php echo $EM_Booking->get_spaces() ?></td>
106
- <td>
107
- <?php
108
- $unapprove_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_unapprove', 'booking_id'=>$EM_Booking->booking_id));
109
- $reject_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_reject', 'booking_id'=>$EM_Booking->booking_id));
110
- $delete_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id));
111
- $edit_url = em_add_get_params($_SERVER['REQUEST_URI'], array('booking_id'=>$EM_Booking->booking_id, 'em_ajax'=>null, 'em_obj'=>null));
112
- ?>
113
- <?php if( current_user_can('manage_bookings') && get_option('dbem_bookings_approval') ): ?>
114
- <a class="em-bookings-unapprove" href="<?php echo $unapprove_url ?>"><?php _e('Unapprove','events-manager'); ?></a> |
115
- <?php else: ?>
116
- <a class="em-bookings-reject" href="<?php echo $reject_url ?>"><?php _e('Reject','events-manager'); ?></a> |
117
- <?php endif; ?>
118
- <span class="trash"><a class="em-bookings-delete" href="<?php echo $delete_url ?>"><?php _e('Delete','events-manager'); ?></a></span> |
119
- <a class="em-bookings-edit" href="<?php echo $edit_url; ?>"><?php _e('Edit/View','events-manager'); ?></a>
120
- </td>
121
- </tr>
122
- <?php
123
- }
124
- $event_count++;
125
- }
126
- ?>
127
- </tbody>
128
- </table>
129
- </div>
130
- <?php else: ?>
131
- <?php _e('No confirmed bookings.', 'events-manager'); ?>
132
- <?php endif; ?>
133
- </form>
134
- <?php if( !empty($bookings_nav) && $EM_Bookings >= $limit ) : ?>
135
- <div class='tablenav'>
136
- <?php echo $bookings_nav; ?>
137
- <div class="clear"></div>
138
- </div>
139
- <?php endif; ?>
140
- </div>
141
- <?php
142
-
143
- }
144
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/bookings/em-events.php DELETED
@@ -1,153 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Determines whether to show event page or events page, and saves any updates to the event or events
5
- * @return null
6
- */
7
- function em_bookings_events_table() {
8
- //TODO Simplify panel for events, use form flags to detect certain actions (e.g. submitted, etc)
9
- global $wpdb;
10
-
11
- $scope_names = array (
12
- 'past' => __ ( 'Past events', 'events-manager'),
13
- 'all' => __ ( 'All events', 'events-manager'),
14
- 'future' => __ ( 'Future events', 'events-manager')
15
- );
16
-
17
- $action_scope = ( !empty($_REQUEST['em_obj']) && $_REQUEST['em_obj'] == 'em_bookings_events_table' );
18
- $action = ( $action_scope && !empty($_GET ['action']) ) ? $_GET ['action']:'';
19
- $order = ( $action_scope && !empty($_GET ['order']) ) ? $_GET ['order']:'ASC';
20
- $limit = ( $action_scope && !empty($_GET['limit']) ) ? $_GET['limit'] : 20;//Default limit
21
- $page = ( $action_scope && !empty($_GET['pno']) ) ? $_GET['pno']:1;
22
- $offset = ( $action_scope && $page > 1 ) ? ($page-1)*$limit : 0;
23
- $scope = ( $action_scope && !empty($_GET ['scope']) && array_key_exists($_GET ['scope'], $scope_names) ) ? $_GET ['scope']:'future';
24
-
25
- // No action, only showing the events list
26
- switch ($scope) {
27
- case "past" :
28
- $title = __ ( 'Past Events', 'events-manager');
29
- break;
30
- case "all" :
31
- $title = __ ( 'All Events', 'events-manager');
32
- break;
33
- default :
34
- $title = __ ( 'Future Events', 'events-manager');
35
- $scope = "future";
36
- }
37
- $owner = !current_user_can('manage_others_bookings') ? get_current_user_id() : false;
38
- $events = EM_Events::get( array('scope'=>$scope, 'limit'=>$limit, 'offset' => $offset, 'order'=>$order, 'orderby'=>'event_start', 'bookings'=>true, 'owner' => $owner, 'pagination' => 1 ) );
39
- $events_count = EM_Events::$num_rows_found;
40
-
41
- $use_events_end = get_option ( 'dbem_use_event_end' );
42
- ?>
43
- <div class="wrap em_bookings_events_table em_obj">
44
- <form id="posts-filter" action="" method="get">
45
- <input type="hidden" name="em_obj" value="em_bookings_events_table" />
46
- <?php if(!empty($_GET['page'])): ?>
47
- <input type='hidden' name='page' value='events-manager-bookings' />
48
- <?php endif; ?>
49
- <div class="tablenav">
50
- <div class="alignleft actions">
51
- <!--
52
- <select name="action">
53
- <option value="-1" selected="selected"><?php esc_html_e( 'Bulk Actions' ); ?></option>
54
- <option value="deleteEvents"><?php esc_html_e( 'Delete selected','events-manager'); ?></option>
55
- </select>
56
- <input type="submit" value="<?php esc_html_e( 'Apply' ); ?>" name="doaction2" id="doaction2" class="button-secondary action" />
57
- -->
58
- <select name="scope">
59
- <?php
60
- foreach ( $scope_names as $key => $value ) {
61
- $selected = "";
62
- if ($key == $scope)
63
- $selected = "selected='selected'";
64
- echo "<option value='$key' $selected>$value</option> ";
65
- }
66
- ?>
67
- </select>
68
- <input id="post-query-submit" class="button-secondary" type="submit" value="<?php esc_html_e( 'Filter' )?>" />
69
- </div>
70
- <!--
71
- <div class="view-switch">
72
- <a href="/wp-admin/edit.php?mode=list"><img class="current" id="view-switch-list" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="List View" alt="List View" name="view-switch-list" /></a> <a href="/wp-admin/edit.php?mode=excerpt"><img id="view-switch-excerpt" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="Excerpt View" alt="Excerpt View" name="view-switch-excerpt" /></a>
73
- </div>
74
- -->
75
- <?php
76
- if ( $events_count >= $limit ) {
77
- $events_nav = em_admin_paginate( $events_count, $limit, $page, array('em_ajax'=>0, 'em_obj'=>'em_bookings_events_table'));
78
- echo $events_nav;
79
- }
80
- ?>
81
- </div>
82
- <div class="clear"></div>
83
- <?php
84
- if (empty ( $events )) {
85
- // TODO localize
86
- _e ( 'no events','events-manager');
87
- } else {
88
- ?>
89
- <div class='table-wrap'>
90
- <table class="widefat">
91
- <thead>
92
- <tr>
93
- <th><?php esc_html_e( 'Event', 'events-manager'); ?></th>
94
- <th><?php esc_html_e( 'Date and time', 'events-manager'); ?></th>
95
- </tr>
96
- </thead>
97
- <tbody>
98
- <?php
99
- $rowno = 0;
100
- foreach ( $events as $EM_Event ) {
101
- /* @var $event EM_Event */
102
- $rowno++;
103
- $class = ($rowno % 2) ? ' class="alternate"' : '';
104
- $style = "";
105
-
106
- if ($EM_Event->start()->getTimestamp() < time() && $EM_Event->end()->getTimestamp() < time()){
107
- $style = "style ='background-color: #FADDB7;'";
108
- }
109
- ?>
110
- <tr <?php echo "$class $style"; ?>>
111
- <td>
112
- <strong>
113
- <?php echo $EM_Event->output('#_BOOKINGSLINK'); ?>
114
- </strong>
115
- &ndash;
116
- <?php esc_html_e("Booked Spaces",'events-manager') ?>: <?php echo $EM_Event->get_bookings()->get_booked_spaces()."/".$EM_Event->get_spaces() ?>
117
- <?php if( get_option('dbem_bookings_approval') == 1 ) : ?>
118
- | <?php esc_html_e("Pending",'events-manager') ?>: <?php echo $EM_Event->get_bookings()->get_pending_spaces(); ?>
119
- <?php endif; ?>
120
- </td>
121
-
122
- <td>
123
- <?php echo $EM_Event->output_dates(false, " - "). ' @ ' . $EM_Event->output_times(false, ' - '); ?>
124
- </td>
125
- </tr>
126
- <?php
127
- }
128
- ?>
129
- </tbody>
130
- </table>
131
- </div>
132
- <?php
133
- } // end of table
134
- ?>
135
- <div class='tablenav'>
136
- <div class="alignleft actions">
137
- <br class='clear' />
138
- </div>
139
- <?php if (!empty($events_nav) && $events_count >= $limit ) : ?>
140
- <div class="tablenav-pages">
141
- <?php
142
- echo $events_nav;
143
- ?>
144
- </div>
145
- <?php endif; ?>
146
- <br class='clear' />
147
- </div>
148
- </form>
149
- </div>
150
- <?php
151
- }
152
-
153
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/bookings/em-pending.php DELETED
@@ -1,159 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Generates a "widget" table of pending bookings with some quick admin operation options.
5
- * If event id supplied then only pending bookings for that event will show.
6
- *
7
- * @param int $event_id
8
- */
9
- function em_bookings_pending_table($event_id = false){
10
- global $EM_Event, $EM_Ticket, $wpdb, $current_user;
11
-
12
- if( get_option('dbem_bookings_approval') == 0 ){
13
- return false;
14
- }
15
-
16
- $action_scope = ( !empty($_REQUEST['em_obj']) && $_REQUEST['em_obj'] == 'em_bookings_pending_table' );
17
- $action = ( $action_scope && !empty($_GET ['action']) ) ? $_GET ['action']:'';
18
- $order = ( $action_scope && !empty($_GET ['order']) ) ? $_GET ['order']:'ASC';
19
- $limit = ( $action_scope && !empty($_GET['limit']) ) ? $_GET['limit'] : 20;//Default limit
20
- $page = ( $action_scope && !empty($_GET['pno']) ) ? $_GET['pno']:1;
21
- $offset = ( $action_scope && $page > 1 ) ? ($page-1)*$limit : 0;
22
-
23
- if( is_object($EM_Ticket) ){
24
- $EM_Bookings = $EM_Ticket->get_bookings()->get_pending_bookings();
25
- }else{
26
- if( is_object($EM_Event) ){
27
- $EM_Bookings = $EM_Event->get_bookings()->get_pending_bookings();
28
- }else{
29
- //To optimize performance, we can do one query here for all pending bookings to show.
30
- $EM_Bookings = EM_Bookings::get(array('status'=>0));
31
- $events = array();
32
- //Now let's create events and bookings for this:
33
- foreach($EM_Bookings->bookings as $EM_Booking){
34
- //create event
35
- if( !array_key_exists($EM_Booking->event_id,$events) ){
36
- $events[$EM_Booking->event_id] = new EM_Event($EM_Booking->event_id);
37
- }
38
- }
39
- }
40
- }
41
- $bookings_count = (is_array($EM_Bookings->bookings)) ? count($EM_Bookings->bookings):0;
42
- ?>
43
- <div class='wrap em_bookings_pending_table em_obj'>
44
- <form id='bookings-filter' method='get' action='<?php bloginfo('wpurl') ?>/wp-admin/edit.php'>
45
- <input type="hidden" name="em_obj" value="em_bookings_pending_table" />
46
- <!--
47
- <ul class="subsubsub">
48
- <li>
49
- <a href='edit.php?post_type=post' class="current">All <span class="count">(1)</span></a> |
50
- </li>
51
- </ul>
52
- <p class="search-box">
53
- <label class="screen-reader-text" for="post-search-input"><?php _e('Search', 'events-manager'); ?>:</label>
54
- <input type="text" id="post-search-input" name="em_search" value="<?php echo (!empty($_GET['em_search'])) ? esc_attr($_GET['em_search']):''; ?>" />
55
- <input type="submit" value="<?php _e('Search', 'events-manager'); ?>" class="button" />
56
- </p>
57
- -->
58
- <?php if ( $bookings_count >= $limit ) : ?>
59
- <div class='tablenav'>
60
- <!--
61
- <div class="alignleft actions">
62
- <select name="action">
63
- <option value="-1" selected="selected">
64
- <?php _e('Bulk Actions', 'events-manager'); ?>
65
- </option>
66
- <option value="approve">
67
- <?php _e('Approve', 'events-manager'); ?>
68
- </option>
69
- <option value="decline">
70
- <?php _e('Decline', 'events-manager'); ?>
71
- </option>
72
- </select>
73
- <input type="submit" id="post-query-submit" value="Filter" class="button-secondary" />
74
- </div>
75
- -->
76
- <!--
77
- <div class="view-switch">
78
- <a href="/wp-admin/edit.php?mode=list"><img class="current" id="view-switch-list" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="List View" alt="List View" name="view-switch-list" /></a> <a href="/wp-admin/edit.php?mode=excerpt"><img id="view-switch-excerpt" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="Excerpt View" alt="Excerpt View" name="view-switch-excerpt" /></a>
79
- </div>
80
- -->
81
- <?php
82
- if ( $bookings_count >= $limit ) {
83
- $bookings_nav = em_admin_paginate( $bookings_count, $limit, $page, array('em_ajax'=>0, 'em_obj'=>'em_bookings_pending_table'));
84
- echo $bookings_nav;
85
- }
86
- ?>
87
- <div class="clear"></div>
88
- </div>
89
- <?php endif; ?>
90
- <div class="clear"></div>
91
- <?php if( $bookings_count > 0 ): ?>
92
- <div class='table-wrap'>
93
- <table id='dbem-bookings-table' class='widefat post '>
94
- <thead>
95
- <tr>
96
- <th class='manage-column column-cb check-column' scope='col'>
97
- <input class='select-all' type="checkbox" value='1' />
98
- </th>
99
- <th class='manage-column' scope='col'><?php _e('Booker', 'events-manager'); ?></th>
100
- <?php if( !is_object($EM_Event) && !is_object($EM_Ticket) ): ?>
101
- <th class='manage-column' scope="col"><?php _e('Event', 'events-manager'); ?></th>
102
- <?php endif; ?>
103
- <th class='manage-column' scope='col'><?php _e('E-mail', 'events-manager'); ?></th>
104
- <th class='manage-column' scope='col'><?php _e('Phone number', 'events-manager'); ?></th>
105
- <th class='manage-column' scope='col'><?php _e('Spaces', 'events-manager'); ?></th>
106
- <th class='manage-column' scope='col'>&nbsp;</th>
107
- </tr>
108
- </thead>
109
- <tbody>
110
- <?php
111
- $rowno = 0;
112
- $event_count = 0;
113
- foreach ($EM_Bookings->bookings as $EM_Booking) {
114
- if( ($rowno < $limit || empty($limit)) && ($event_count >= $offset || $offset === 0) ) {
115
- $rowno++;
116
- ?>
117
- <tr>
118
- <th scope="row" class="check-column" style="padding:7px 0px 7px;"><input type='checkbox' value='<?php echo $EM_Booking->booking_id ?>' name='bookings[]'/></th>
119
- <td><a href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;person_id=<?php echo $EM_Booking->person->ID; ?>"><?php echo $EM_Booking->person->get_name() ?></a></td>
120
- <?php if( !is_object($EM_Event) && !is_object($EM_Ticket) ): ?>
121
- <td><a href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;event_id=<?php echo $EM_Booking->event_id; ?>"><?php echo $events[$EM_Booking->event_id]->name ?></a></td>
122
- <?php endif; ?>
123
- <td><?php echo $EM_Booking->person->user_email ?></td>
124
- <td><?php echo $EM_Booking->person->phone ?></td>
125
- <td><?php echo $EM_Booking->get_spaces() ?></td>
126
- <td>
127
- <?php
128
- $approve_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_approve', 'booking_id'=>$EM_Booking->booking_id));
129
- $reject_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_reject', 'booking_id'=>$EM_Booking->booking_id));
130
- $delete_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id));
131
- ?>
132
- <a class="em-bookings-approve" href="<?php echo $approve_url ?>"><?php _e('Approve','events-manager'); ?></a> |
133
- <a class="em-bookings-reject" href="<?php echo $reject_url ?>"><?php _e('Reject','events-manager'); ?></a> |
134
- <span class="trash"><a class="em-bookings-delete" href="<?php echo $delete_url ?>"><?php _e('Delete','events-manager'); ?></a></span> |
135
- <a class="em-bookings-edit" href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;booking_id=<?php echo $EM_Booking->booking_id; ?>"><?php _e('Edit/View','events-manager'); ?></a>
136
- </td>
137
- </tr>
138
- <?php
139
- }
140
- $event_count++;
141
- }
142
- ?>
143
- </tbody>
144
- </table>
145
- </div>
146
- <?php else: ?>
147
- <?php _e('No pending bookings.', 'events-manager'); ?>
148
- <?php endif; ?>
149
- </form>
150
- <?php if( !empty($bookings_nav) && $EM_Bookings >= $limit ) : ?>
151
- <div class='tablenav'>
152
- <?php echo $bookings_nav; ?>
153
- <div class="clear"></div>
154
- </div>
155
- <?php endif; ?>
156
- </div>
157
- <?php
158
- }
159
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/bookings/em-person.php DELETED
@@ -1,152 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Generates a "widget" table of confirmed bookings for a specific event.
5
- *
6
- * @param int $event_id
7
- */
8
- function em_bookings_person_table(){
9
- global $wpdb, $current_user,$EM_Person;
10
- if(!is_object($EM_Person)){
11
- return false;
12
- }
13
- $action_scope = ( !empty($_REQUEST['em_obj']) && $_REQUEST['em_obj'] == 'em_bookings_confirmed_table' );
14
- $action = ( $action_scope && !empty($_GET ['action']) ) ? $_GET ['action']:'';
15
- $order = ( $action_scope && !empty($_GET ['order']) ) ? $_GET ['order']:'ASC';
16
- $limit = ( $action_scope && !empty($_GET['limit']) ) ? $_GET['limit'] : 20;//Default limit
17
- $page = ( $action_scope && !empty($_GET['pno']) ) ? $_GET['pno']:1;
18
- $offset = ( $action_scope && $page > 1 ) ? ($page-1)*$limit : 0;
19
-
20
- $bookings = $EM_Person->get_bookings();
21
- $bookings_count = count($bookings);
22
- if($bookings_count > 0){
23
- //Get events here in one query to speed things up
24
- foreach($bookings as $EM_Booking){
25
- $event_ids[] = $EM_Booking->event_id;
26
- }
27
- $events = EM_Events::get($event_ids);
28
- }
29
- ?>
30
- <div class='wrap em_bookings_pending_table em_obj'>
31
- <form id='bookings-filter' method='get' action='<?php bloginfo('wpurl') ?>/wp-admin/edit.php'>
32
- <input type="hidden" name="em_obj" value="em_bookings_pending_table" />
33
- <!--
34
- <ul class="subsubsub">
35
- <li>
36
- <a href='edit.php?post_type=post' class="current">All <span class="count">(1)</span></a> |
37
- </li>
38
- </ul>
39
- <p class="search-box">
40
- <label class="screen-reader-text" for="post-search-input"><?php _e('Search', 'events-manager'); ?>:</label>
41
- <input type="text" id="post-search-input" name="em_search" value="<?php echo (!empty($_GET['em_search'])) ? esc_attr($_GET['em_search']):''; ?>" />
42
- <input type="submit" value="<?php _e('Search', 'events-manager'); ?>" class="button" />
43
- </p>
44
- -->
45
- <?php if ( $bookings_count >= $limit ) : ?>
46
- <div class='tablenav'>
47
- <!--
48
- <div class="alignleft actions">
49
- <select name="action">
50
- <option value="-1" selected="selected">
51
- <?php _e('Bulk Actions', 'events-manager'); ?>
52
- </option>
53
- <option value="approve">
54
- <?php _e('Approve', 'events-manager'); ?>
55
- </option>
56
- <option value="decline">
57
- <?php _e('Decline', 'events-manager'); ?>
58
- </option>
59
- </select>
60
- <input type="submit" id="post-query-submit" value="Filter" class="button-secondary" />
61
- </div>
62
- -->
63
- <!--
64
- <div class="view-switch">
65
- <a href="/wp-admin/edit.php?mode=list"><img class="current" id="view-switch-list" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="List View" alt="List View" name="view-switch-list" /></a> <a href="/wp-admin/edit.php?mode=excerpt"><img id="view-switch-excerpt" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="Excerpt View" alt="Excerpt View" name="view-switch-excerpt" /></a>
66
- </div>
67
- -->
68
- <?php
69
- if ( $bookings_count >= $limit ) {
70
- $bookings_nav = em_admin_paginate( $bookings_count, $limit, $page, array('em_ajax'=>0, 'em_obj'=>'em_bookings_confirmed_table'));
71
- echo $bookings_nav;
72
- }
73
- ?>
74
- <div class="clear"></div>
75
- </div>
76
- <?php endif; ?>
77
- <div class="clear"></div>
78
- <?php if( $bookings_count > 0 ): ?>
79
- <div class='table-wrap'>
80
- <table id='dbem-bookings-table' class='widefat post '>
81
- <thead>
82
- <tr>
83
- <th class='manage-column column-cb check-column' scope='col'>
84
- <input class='select-all' type="checkbox" value='1' />
85
- </th>
86
- <th class='manage-column' scope='col'><?php _e('Event', 'events-manager'); ?></th>
87
- <th class='manage-column' scope='col'><?php _e('Spaces', 'events-manager'); ?></th>
88
- <th class='manage-column' scope='col'><?php _e('Status', 'events-manager'); ?></th>
89
- <th class='manage-column' scope='col'>&nbsp;</th>
90
- </tr>
91
- </thead>
92
- <tbody>
93
- <?php
94
- $rowno = 0;
95
- $event_count = 0;
96
- foreach ($bookings as $EM_Booking) {
97
- $EM_Event = $events[$EM_Booking->event_id];
98
- if( $EM_Event->can_manage('edit_events','edit_others_events') && ($rowno < $limit || empty($limit)) && ($event_count >= $offset || $offset === 0) ) {
99
- $rowno++;
100
- ?>
101
- <tr>
102
- <th scope="row" class="check-column" style="padding:7px 0px 7px;"><input type='checkbox' value='<?php echo $EM_Booking->booking_id ?>' name='bookings[]'/></th>
103
- <td><a class="row-title" href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;event_id=<?php echo $EM_Event->event_id ?>"><?php echo ($EM_Event->event_name); ?></a></td>
104
- <td><?php echo $EM_Booking->get_spaces() ?></td>
105
- <td><?php echo $EM_Booking->status_array[$EM_Booking->booking_status]; ?>
106
- </td>
107
- <td>
108
- <?php
109
- $unapprove_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_unapprove', 'booking_id'=>$EM_Booking->booking_id));
110
- $approve_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_approve', 'booking_id'=>$EM_Booking->booking_id));
111
- $reject_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_reject', 'booking_id'=>$EM_Booking->booking_id));
112
- $delete_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id));
113
- ?>
114
- <?php if( get_option('dbem_bookings_approval') && ($EM_Booking->booking_status == 0 ) ): ?>
115
- <a class="em-bookings-approve" href="<?php echo $approve_url ?>"><?php _e('Approve','events-manager'); ?></a> |
116
- <?php endif; ?>
117
- <?php if( get_option('dbem_bookings_approval') && $EM_Booking->booking_status == 1 ): ?>
118
- <a class="em-bookings-unapprove" href="<?php echo $unapprove_url ?>"><?php _e('Unapprove','events-manager'); ?></a> |
119
- <?php endif; ?>
120
- <?php if( $EM_Booking->booking_status == 2 ): ?>
121
- <a class="em-bookings-approve" href="<?php echo $approve_url ?>"><?php _e('Restore','events-manager'); ?></a> |
122
- <?php endif; ?>
123
- <?php if( $EM_Booking->booking_status == 0 || $EM_Booking->booking_status == 1 ): ?>
124
- <a class="em-bookings-reject" href="<?php echo $reject_url ?>"><?php _e('Reject','events-manager'); ?></a> |
125
- <?php endif; ?>
126
- <a class="em-bookings-edit" href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;booking_id=<?php echo $EM_Booking->booking_id; ?>"><?php _e('Edit/View','events-manager'); ?></a> |
127
- <span class="trash"><a class="em-bookings-delete" href="<?php echo $delete_url ?>"><?php _e('Delete','events-manager'); ?></a></span>
128
- </td>
129
- </tr>
130
- <?php
131
- }
132
- $event_count++;
133
- }
134
- ?>
135
- </tbody>
136
- </table>
137
- </div>
138
- <?php else: ?>
139
- <?php _e('No confirmed bookings.', 'events-manager'); ?>
140
- <?php endif; ?>
141
- </form>
142
- <?php if( !empty($bookings_nav) && $bookings >= $limit ) : ?>
143
- <div class='tablenav'>
144
- <?php echo $bookings_nav; ?>
145
- <div class="clear"></div>
146
- </div>
147
- <?php endif; ?>
148
- </div>
149
- <?php
150
-
151
- }
152
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/bookings/em-rejected.php DELETED
@@ -1,137 +0,0 @@
1
- <?php
2
- /**
3
- * Generates a "widget" table of confirmed bookings for a specific event.
4
- *
5
- * @param int $event_id
6
- */
7
- function em_bookings_rejected_table(){
8
- global $EM_Event, $EM_Ticket, $wpdb, $current_user;
9
-
10
- $action_scope = ( !empty($_REQUEST['em_obj']) && $_REQUEST['em_obj'] == 'em_bookings_confirmed_table' );
11
- $action = ( $action_scope && !empty($_GET ['action']) ) ? $_GET ['action']:'';
12
- $order = ( $action_scope && !empty($_GET ['order']) ) ? $_GET ['order']:'ASC';
13
- $limit = ( $action_scope && !empty($_GET['limit']) ) ? $_GET['limit'] : 20;//Default limit
14
- $page = ( $action_scope && !empty($_GET['pno']) ) ? $_GET['pno']:1;
15
- $offset = ( $action_scope && $page > 1 ) ? ($page-1)*$limit : 0;
16
-
17
- if( is_object($EM_Ticket) ){
18
- $EM_Bookings = $EM_Ticket->get_bookings()->get_rejected_bookings();
19
- }else{
20
- if( is_object($EM_Event) ){
21
- $EM_Bookings = $EM_Event->get_bookings()->get_rejected_bookings();
22
- }else{
23
- return false;
24
- }
25
- }
26
- $bookings_count = (is_array($EM_Bookings->bookings)) ? count($EM_Bookings->bookings):0;
27
- ?>
28
- <div class='wrap em_bookings_pending_table em_obj'>
29
- <form id='bookings-filter' method='get' action='<?php bloginfo('wpurl') ?>/wp-admin/edit.php'>
30
- <input type="hidden" name="em_obj" value="em_bookings_pending_table" />
31
- <!--
32
- <ul class="subsubsub">
33
- <li>
34
- <a href='edit.php?post_type=post' class="current">All <span class="count">(1)</span></a> |
35
- </li>
36
- </ul>
37
- <p class="search-box">
38
- <label class="screen-reader-text" for="post-search-input"><?php _e('Search', 'events-manager'); ?>:</label>
39
- <input type="text" id="post-search-input" name="em_search" value="<?php echo (!empty($_GET['em_search'])) ? esc_attr($_GET['em_search']):''; ?>" />
40
- <input type="submit" value="<?php _e('Search', 'events-manager'); ?>" class="button" />
41
- </p>
42
- -->
43
- <?php if ( $bookings_count >= $limit ) : ?>
44
- <div class='tablenav'>
45
- <!--
46
- <div class="alignleft actions">
47
- <select name="action">
48
- <option value="-1" selected="selected">
49
- <?php _e('Bulk Actions', 'events-manager'); ?>
50
- </option>
51
- <option value="approve">
52
- <?php _e('Approve', 'events-manager'); ?>
53
- </option>
54
- <option value="decline">
55
- <?php _e('Decline', 'events-manager'); ?>
56
- </option>
57
- </select>
58
- <input type="submit" id="post-query-submit" value="Filter" class="button-secondary" />
59
- </div>
60
- -->
61
- <!--
62
- <div class="view-switch">
63
- <a href="/wp-admin/edit.php?mode=list"><img class="current" id="view-switch-list" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="List View" alt="List View" name="view-switch-list" /></a> <a href="/wp-admin/edit.php?mode=excerpt"><img id="view-switch-excerpt" src="http://wordpress.lan/wp-includes/images/blank.gif" width="20" height="20" title="Excerpt View" alt="Excerpt View" name="view-switch-excerpt" /></a>
64
- </div>
65
- -->
66
- <?php
67
- if ( $bookings_count >= $limit ) {
68
- $bookings_nav = em_admin_paginate( $bookings_count, $limit, $page, array('em_ajax'=>0, 'em_obj'=>'em_bookings_confirmed_table'));
69
- echo $bookings_nav;
70
- }
71
- ?>
72
- <div class="clear"></div>
73
- </div>
74
- <?php endif; ?>
75
- <div class="clear"></div>
76
- <?php if( $bookings_count > 0 ): ?>
77
- <div class='table-wrap'>
78
- <table id='dbem-bookings-table' class='widefat post '>
79
- <thead>
80
- <tr>
81
- <th class='manage-column column-cb check-column' scope='col'>
82
- <input class='select-all' type="checkbox" value='1' />
83
- </th>
84
- <th class='manage-column' scope='col'><?php _e('Booker', 'events-manager'); ?></th>
85
- <th class='manage-column' scope='col'><?php _e('E-mail', 'events-manager'); ?></th>
86
- <th class='manage-column' scope='col'><?php _e('Phone number', 'events-manager'); ?></th>
87
- <th class='manage-column' scope='col'><?php _e('Spaces', 'events-manager'); ?></th>
88
- <th class='manage-column' scope='col'>&nbsp;</th>
89
- </tr>
90
- </thead>
91
- <tbody>
92
- <?php
93
- $rowno = 0;
94
- $event_count = 0;
95
- foreach ($EM_Bookings->bookings as $EM_Booking) {
96
- if( ($rowno < $limit || empty($limit)) && ($event_count >= $offset || $offset === 0) ) {
97
- $rowno++;
98
- ?>
99
- <tr>
100
- <th scope="row" class="check-column" style="padding:7px 0px 7px;"><input type='checkbox' value='<?php echo $EM_Booking->booking_id ?>' name='bookings[]'/></th>
101
- <td><a href="<?php echo EM_ADMIN_URL; ?>&amp;page=events-manager-bookings&amp;person_id=<?php echo $EM_Booking->person->ID; ?>"><?php echo $EM_Booking->person->get_name() ?></a></td>
102
- <td><?php echo $EM_Booking->person->user_email ?></td>
103
- <td><?php echo $EM_Booking->person->phone ?></td>
104
- <td><?php echo $EM_Booking->get_spaces() ?></td>
105
- <td>
106
- <?php
107
- $approve_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_approve', 'booking_id'=>$EM_Booking->booking_id));
108
- $delete_url = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id));
109
- $edit_url = em_add_get_params($_SERVER['REQUEST_URI'], array('booking_id'=>$EM_Booking->booking_id, 'em_ajax'=>null, 'em_obj'=>null));
110
- ?>
111
- <a class="em-bookings-approve" href="<?php echo $approve_url ?>"><?php _e('Approve','events-manager'); ?></a> |
112
- <a class="em-bookings-edit" href="<?php echo $edit_url ?>"><?php _e('Edit/View','events-manager'); ?></a> |
113
- <span class="trash"><a class="em-bookings-delete" href="<?php echo $delete_url ?>"><?php _e('Delete','events-manager'); ?></a></span>
114
- </td>
115
- </tr>
116
- <?php
117
- }
118
- $event_count++;
119
- }
120
- ?>
121
- </tbody>
122
- </table>
123
- </div>
124
- <?php else: ?>
125
- <?php _e('No rejected bookings.', 'events-manager'); ?>
126
- <?php endif; ?>
127
- </form>
128
- <?php if( !empty($bookings_nav) && $EM_Bookings >= $limit ) : ?>
129
- <div class='tablenav'>
130
- <?php echo $bookings_nav; ?>
131
- <div class="clear"></div>
132
- </div>
133
- <?php endif; ?>
134
- </div>
135
- <?php
136
- }
137
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-admin.php DELETED
@@ -1,324 +0,0 @@
1
- <?php
2
- //Admin functions
3
- function em_admin_menu(){
4
- global $menu, $submenu, $pagenow;
5
- //Count pending bookings
6
- if( get_option('dbem_rsvp_enabled') ){
7
- $bookings_num = '';
8
- $bookings_pending_count = apply_filters('em_bookings_pending_count',0);
9
- if( get_option('dbem_bookings_approval') == 1){
10
- $bookings_pending_count += EM_Bookings::count(array('status'=>'0', 'blog'=>get_current_blog_id()));
11
- }
12
- if($bookings_pending_count > 0){
13
- $bookings_num = '<span class="update-plugins count-'.$bookings_pending_count.'"><span class="plugin-count">'.$bookings_pending_count.'</span></span>';
14
- }
15
- }else{
16
- $bookings_num = '';
17
- $bookings_pending_count = 0;
18
- }
19
- //Count pending events
20
- $events_num = '';
21
- $events_pending_count = EM_Events::count(array('status'=>0, 'scope'=>'all', 'blog'=>get_current_blog_id()));
22
- //TODO Add flexible permissions
23
- if($events_pending_count > 0){
24
- $events_num = '<span class="update-plugins count-'.$events_pending_count.'"><span class="plugin-count">'.$events_pending_count.'</span></span>';
25
- }
26
- //Count pending recurring events
27
- $events_recurring_num = '';
28
- $events_recurring_pending_count = EM_Events::count(array('status'=>0, 'recurring'=>1, 'scope'=>'all', 'blog'=>get_current_blog_id()));
29
- //TODO Add flexible permissions
30
- if($events_recurring_pending_count > 0){
31
- $events_recurring_num = '<span class="update-plugins count-'.$events_recurring_pending_count.'"><span class="plugin-count">'.$events_recurring_pending_count.'</span></span>';
32
- }
33
- $both_pending_count = apply_filters('em_items_pending_count', $events_pending_count + $bookings_pending_count + $events_recurring_pending_count);
34
- $both_num = ($both_pending_count > 0) ? '<span class="update-plugins count-'.$both_pending_count.'"><span class="plugin-count">'.$both_pending_count.'</span></span>':'';
35
- // Add a submenu to the custom top-level menu:
36
- $plugin_pages = array();
37
- if( get_option('dbem_rsvp_enabled') ){
38
- $plugin_pages['bookings'] = add_submenu_page('edit.php?post_type='.EM_POST_TYPE_EVENT, __('Bookings', 'events-manager'), __('Bookings', 'events-manager').$bookings_num, 'manage_bookings', 'events-manager-bookings', "em_bookings_page");
39
- }
40
- $plugin_pages['options'] = add_submenu_page('edit.php?post_type='.EM_POST_TYPE_EVENT, __('Events Manager Settings','events-manager'),__('Settings','events-manager'), 'manage_options', "events-manager-options", 'em_admin_options_page');
41
- $plugin_pages['help'] = add_submenu_page('edit.php?post_type='.EM_POST_TYPE_EVENT, __('Getting Help for Events Manager','events-manager'),__('Help','events-manager'), 'manage_options', "events-manager-help", 'em_admin_help_page');
42
- //If multisite global with locations set to be saved in main blogs we can force locations to be created on the main blog only
43
- if( EM_MS_GLOBAL && !is_main_site() && get_site_option('dbem_ms_mainblog_locations') ){
44
- include( dirname(__FILE__)."/em-ms-locations.php" );
45
- $plugin_pages['locations'] = add_submenu_page('edit.php?post_type='.EM_POST_TYPE_EVENT, __('Locations','events-manager'),__('Locations','events-manager'), 'read_others_locations', "locations", 'em_admin_ms_locations');
46
- }
47
- $plugin_pages = apply_filters('em_create_events_submenu',$plugin_pages);
48
- //We have to modify the menus manually
49
- if( !empty($both_num) ){ //Main Event Menu
50
- //go through the menu array and modify the events menu if found
51
- foreach ( (array)$menu as $key => $parent_menu ) {
52
- if ( $parent_menu[2] == 'edit.php?post_type='.EM_POST_TYPE_EVENT ){
53
- $menu[$key][0] = $menu[$key][0]. $both_num;
54
- break;
55
- }
56
- }
57
- }
58
- if( !empty($events_num) && !empty($submenu['edit.php?post_type='.EM_POST_TYPE_EVENT]) ){ //Submenu Event Item
59
- //go through the menu array and modify the events menu if found
60
- foreach ( (array)$submenu['edit.php?post_type='.EM_POST_TYPE_EVENT] as $key => $submenu_item ) {
61
- if ( $submenu_item[2] == 'edit.php?post_type='.EM_POST_TYPE_EVENT ){
62
- $submenu['edit.php?post_type='.EM_POST_TYPE_EVENT][$key][0] = $submenu['edit.php?post_type='.EM_POST_TYPE_EVENT][$key][0]. $events_num;
63
- break;
64
- }
65
- }
66
- }
67
- if( !empty($events_recurring_num) && !empty($submenu['edit.php?post_type='.EM_POST_TYPE_EVENT]) ){ //Submenu Recurring Event Item
68
- //go through the menu array and modify the events menu if found
69
- foreach ( (array)$submenu['edit.php?post_type='.EM_POST_TYPE_EVENT] as $key => $submenu_item ) {
70
- if ( $submenu_item[2] == 'edit.php?post_type=event-recurring' ){
71
- $submenu['edit.php?post_type='.EM_POST_TYPE_EVENT][$key][0] = $submenu['edit.php?post_type='.EM_POST_TYPE_EVENT][$key][0]. $events_recurring_num;
72
- break;
73
- }
74
- }
75
- }
76
- /* Hack! Add location/recurrence isn't possible atm so this is a workaround */
77
- global $_wp_submenu_nopriv;
78
- if( $pagenow == 'post-new.php' && !empty($_REQUEST['post_type']) ){
79
- if( $_REQUEST['post_type'] == EM_POST_TYPE_LOCATION && !empty($_wp_submenu_nopriv['edit.php']['post-new.php']) && current_user_can('edit_locations') ){
80
- unset($_wp_submenu_nopriv['edit.php']['post-new.php']);
81
- }
82
- if( $_REQUEST['post_type'] == 'event-recurring' && !empty($_wp_submenu_nopriv['edit.php']['post-new.php']) && current_user_can('edit_recurring_events') ){
83
- unset($_wp_submenu_nopriv['edit.php']['post-new.php']);
84
- }
85
- }
86
- }
87
- add_action('admin_menu','em_admin_menu');
88
-
89
- function em_admin_dashicon(){
90
- ?>
91
- <style type="text/css">
92
- @font-face {
93
- font-family: 'em_dashicons';
94
- src: url('<?php echo EM_DIR_URI; ?>includes/fonts/em-dashicons.eot'); // this is for IE
95
- }
96
- @font-face {
97
- font-family: 'em_dashicons';
98
- src: url(data:application/font-woff;charset=utf-8;base64,d09GRk9UVE8AAAVIAAoAAAAABQAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABDRkYgAAAA9AAAAb8AAAG/+vk+uU9TLzIAAAK0AAAAYAAAAGAIIvy2Y21hcAAAAxQAAABMAAAATBpVzFdnYXNwAAADYAAAAAgAAAAIAAAAEGhlYWQAAANoAAAANgAAADYBZ6hBaGhlYQAAA6AAAAAkAAAAJAPIAeZobXR4AAADxAAAABQAAAAUAwAAM21heHAAAAPYAAAABgAAAAYABVAAbmFtZQAAA+AAAAFFAAABRVcZpu5wb3N0AAAFKAAAACAAAAAgAAMAAAEABAQAAQEBCGljb21vb24AAQIAAQA6+BwC+BsD+BgEHgoAGVP/i4seCgAZU/+LiwwHi2v4lPh0BR0AAAB2Dx0AAAB7ER0AAAAJHQAAAbYSAAYBAQgPERMWG2ljb21vb25pY29tb29udTB1MXUyMHVFNjAwAAACAYkAAwAFAgABAAQABwAKAA0BLfyUDvyUDvyUDvuUDvcu+FoVfIuAgIt9CItYBYt8loCai5mLlpaLmgiLvgWLmYCWfYsI93qLFX2Lf4CLfQiLWAWLfJeAmYuZi5eWi5oIi74Fi5l/ln2LCPth+0cVi1hYi4u+vosFpYsVvouLWFiLi74F2IsVvouLWFiLi74F14sVv4uLWFeLi74Fiz4VvouLWFiLi74FPosVv4uLWFeLi74FPosVv4uLWFeLi74FP4sVvouLWFiLi74F1z8Vv4uLV1eLi78F2IsVv4uLV1eLi78F9y33ihWGc3d5cotui3Wii6gIi5cFdI91jXiLd4t1iXWHCIt+BYtvdHRui3KLd52Go2yCdoSLi4uLi2eLfIv7lfduWYuLi4v3bb2L95WLmYuwi4uLi3aSbJQIDviUFPiUFYsMCgAAAwIAAZAABQAAAUwBZgAAAEcBTAFmAAAA9QAZAIQAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADmAAHg/+D/4AHgACAAAAABAAAAAAAAAAAAAAAgAAAAAAACAAAAAwAAABQAAwABAAAAFAAEADgAAAAKAAgAAgACAAEAIOYA//3//wAAAAAAIOYA//3//wAB/+MaBAADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAEAAIXyBpNfDzz1AAsCAAAAAADQMTPCAAAAANAxM8IAAP/6AeYBxgAAAAgAAgAAAAAAAAABAAAB4P/gAAACAAAAAAAB5gABAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAEAAAACAAAzAABQAAAFAAAAAAAOAK4AAQAAAAAAAQAOAAAAAQAAAAAAAgAOAEcAAQAAAAAAAwAOACQAAQAAAAAABAAOAFUAAQAAAAAABQAWAA4AAQAAAAAABgAHADIAAQAAAAAACgA0AGMAAwABBAkAAQAOAAAAAwABBAkAAgAOAEcAAwABBAkAAwAOACQAAwABBAkABAAOAFUAAwABBAkABQAWAA4AAwABBAkABgAOADkAAwABBAkACgA0AGMAaQBjAG8AbQBvAG8AbgBWAGUAcgBzAGkAbwBuACAAMQAuADAAaQBjAG8AbQBvAG8Abmljb21vb24AaQBjAG8AbQBvAG8AbgBSAGUAZwB1AGwAYQByAGkAYwBvAG0AbwBvAG4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format('woff'),
99
- url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMggi/LYAAAC8AAAAYGNtYXAaVcxXAAABHAAAAExnYXNwAAAAEAAAAWgAAAAIZ2x5ZsaoTWEAAAFwAAACFGhlYWQBZ6hBAAADhAAAADZoaGVhA8gB5gAAA7wAAAAkaG10eAMAADMAAAPgAAAAFGxvY2EAKAEeAAAD9AAAAAxtYXhwABMAowAABAAAAAAgbmFtZVcZpu4AAAQgAAABRXBvc3QAAwAAAAAFaAAAACAAAwIAAZAABQAAAUwBZgAAAEcBTAFmAAAA9QAZAIQAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADmAAHg/+D/4AHgACAAAAABAAAAAAAAAAAAAAAgAAAAAAACAAAAAwAAABQAAwABAAAAFAAEADgAAAAKAAgAAgACAAEAIOYA//3//wAAAAAAIOYA//3//wAB/+MaBAADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAADQAz//oB5gHGABoANQA6AD8ARABJAE4AUwBYAF0AYgBnAKAAABMiBgcOAQcXBhYXHgEzMjY3PgE3JzYmJy4BIzMiBgcOARcHHgEXHgEzMjY3PgEnNy4BJy4BIwcXIzczOwEXIzc7AQcjJzsBFyM3BzMHIycjMxcjNyMzByMnIzMXIzcXMwcjJzsBFyM3Nw4BBw4BIyImJy4BJzcuASciJiMiBiMOAQ8BFgYHDgEjIiYnLgEnDgEzIhYHHgEzIjYnNiYzIiYnmgUKAgUDAQEBBQMECAcECgMEAwEBAQUCBQgG5wYJBAMFAQEBAwUCCwQGCQQDBQEBAQMFAgsEzgE0ATIbMgE0AUw0ATIBTTMBNQEBNAEyAUwzATUBTjUBMwFLMgE0AUs1ATMBTjMBNQGYAQoGBxAKChQFCAcBAQoPCQcRBgkOCQgRBwEBCgUIEgwIEgUICAMWHgEBAQEB2QEB2gEBAQEBHBgBxgQDBAkFMwYJBAMEBAMECQYzBQkEAwQEAwQJBTMGCQQDBAQDBAkGMwUJBAMEszMzMzMzMzMzTTMzMzMzMzMzTDQ0NDT2CQ8GBQcIBwcTCwwCAgEBAQECAg0KEwcHCAcFBg8JBwkoC8FycsELKAkHAAEAAAABAACs5UCKXw889QALAgAAAAAA0DEzwgAAAADQMTPCAAD/+gHmAcYAAAAIAAIAAAAAAAAAAQAAAeD/4AAAAgAAAAAAAeYAAQAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAABAAAAAgAAMwAAAAAACgAUAB4BCgABAAAABQChAA0AAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEADgAAAAEAAAAAAAIADgBHAAEAAAAAAAMADgAkAAEAAAAAAAQADgBVAAEAAAAAAAUAFgAOAAEAAAAAAAYABwAyAAEAAAAAAAoANABjAAMAAQQJAAEADgAAAAMAAQQJAAIADgBHAAMAAQQJAAMADgAkAAMAAQQJAAQADgBVAAMAAQQJAAUAFgAOAAMAAQQJAAYADgA5AAMAAQQJAAoANABjAGkAYwBvAG0AbwBvAG4AVgBlAHIAcwBpAG8AbgAgADEALgAwAGkAYwBvAG0AbwBvAG5pY29tb29uAGkAYwBvAG0AbwBvAG4AUgBlAGcAdQBsAGEAcgBpAGMAbwBtAG8AbwBuAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) format('truetype');
100
- font-weight: normal;
101
- font-style: normal;
102
- }
103
- .menu-icon-event .dashicons-calendar:before, #toplevel_page_events-manager-options .dashicons-calendar:before {
104
- font-family: 'em_dashicons';
105
- content: '\e600';
106
- }
107
- </style>
108
- <?php
109
- }
110
- add_action('admin_head','em_admin_dashicon');
111
-
112
- function em_ms_admin_menu(){
113
- add_menu_page( __('Events Manager','events-manager'), __('Events Manager','events-manager'), 'activate_plugins', 'events-manager-options', 'em_ms_admin_options_page', 'dashicons-calendar' );
114
- add_submenu_page('events-manager-options', __('Update Blogs','events-manager'),__('Update Blogs','events-manager'), 'activate_plugins', "events-manager-update", 'em_ms_upgrade');
115
- }
116
- add_action('network_admin_menu','em_ms_admin_menu');
117
-
118
- function em_admin_init(){
119
- //in MS global mode and locations are stored in the main blog, then a user must have at least a subscriber role
120
- if( EM_MS_GLOBAL && is_user_logged_in() && !is_main_site() && get_site_option('dbem_ms_mainblog_locations') ){
121
- EM_Object::ms_global_switch();
122
- $user = new WP_User(get_current_user_id());
123
- if( count($user->roles) == 0 ){
124
- $user->set_role('subscriber');
125
- }
126
- EM_Object::ms_global_switch_back();
127
- }
128
- }
129
- add_action('admin_init','em_admin_init');
130
-
131
- /**
132
- * Generate warnings and notices in the admin area
133
- */
134
- function em_admin_warnings() {
135
- global $EM_Notices;
136
- //If we're editing the events page show hello to new user
137
- $events_page_id = get_option ( 'dbem_events_page' );
138
- $dismiss_link_joiner = ( count($_GET) > 0 ) ? '&amp;':'?';
139
-
140
- if( current_user_can('activate_plugins') ){
141
- //New User Intro
142
- if (isset ( $_GET ['disable_hello_to_user'] ) && $_GET ['disable_hello_to_user'] == 'true'){
143
- // Disable Hello to new user if requested
144
- update_option('dbem_hello_to_user',0);
145
- }elseif ( get_option ( 'dbem_hello_to_user' ) ) {
146
- //FIXME update welcome msg with good links
147
- $advice = sprintf( __("<p>Events Manager is ready to go! It is highly recommended you read the <a href='%s'>Getting Started</a> guide on our site, as well as checking out the <a href='%s'>Settings Page</a>. <a href='%s' title='Don't show this advice again'>Dismiss</a></p>", 'events-manager'), 'http://wp-events-plugin.com/documentation/getting-started-guide/?utm_source=em&utm_medium=plugin&utm_content=installationlink&utm_campaign=plugin_links', EM_ADMIN_URL .'&amp;page=events-manager-options', esc_url($_SERVER['REQUEST_URI'].$dismiss_link_joiner.'disable_hello_to_user=true'));
148
- ?>
149
- <div id="message" class="updated">
150
- <?php echo $advice; ?>
151
- </div>
152
- <?php
153
- }
154
-
155
- //If events page couldn't be created or is missing
156
- if( !empty($_GET['em_dismiss_events_page']) ){
157
- update_option('dbem_dismiss_events_page',1);
158
- }else{
159
- if ( !get_page($events_page_id) && !get_option('dbem_dismiss_events_page') ){
160
- ?>
161
- <div id="em_page_error" class="updated">
162
- <p><?php echo sprintf ( __( 'Uh Oh! For some reason WordPress could not create an events page for you (or you just deleted it). Not to worry though, all you have to do is create an empty page, name it whatever you want, and select it as your events page in your <a href="%s">settings page</a>. Sorry for the extra step! If you know what you are doing, you may have done this on purpose, if so <a href="%s">ignore this message</a>', 'events-manager'), EM_ADMIN_URL .'&amp;page=events-manager-options', esc_url($_SERVER['REQUEST_URI'].$dismiss_link_joiner.'em_dismiss_events_page=1') ); ?></p>
163
- </div>
164
- <?php
165
- }
166
- }
167
-
168
- if( is_multisite() && !empty($_REQUEST['page']) && $_REQUEST['page']=='events-manager-options' && em_wp_is_super_admin() && get_option('dbem_ms_update_nag') ){
169
- if( !empty($_GET['disable_dbem_ms_update_nag']) ){
170
- delete_site_option('dbem_ms_update_nag');
171
- }else{
172
- ?>
173
- <div id="em_page_error" class="updated">
174
- <p><?php echo sprintf(__('MultiSite options have moved <a href="%s">here</a>. <a href="%s">Dismiss message</a>','events-manager'),admin_url().'network/admin.php?page=events-manager-options', esc_url($_SERVER['REQUEST_URI'].'&amp;disable_dbem_ms_update_nag=1')); ?></p>
175
- </div>
176
- <?php
177
- }
178
- }
179
-
180
- if( em_wp_is_super_admin() && get_option('dbem_migrate_images_nag') ){
181
- if( !empty($_GET['disable_dbem_migrate_images_nag']) ){
182
- delete_site_option('dbem_migrate_images_nag');
183
- }else{
184
- ?>
185
- <div id="em_page_error" class="updated">
186
- <p><?php echo sprintf(__('Whilst they will still appear using placeholders, you need to <a href="%s">migrate your location and event images</a> in order for them to appear in your edit forms and media library. <a href="%s">Dismiss message</a>','events-manager'),admin_url().'edit.php?post_type=event&page=events-manager-options&em_migrate_images=1&_wpnonce='.wp_create_nonce('em_migrate_images'), em_add_get_params($_SERVER['REQUEST_URI'], array('disable_dbem_migrate_images_nag' => 1))); ?></p>
187
- </div>
188
- <?php
189
- }
190
- }
191
- if( !empty($_REQUEST['page']) && 'events-manager-options' == $_REQUEST['page'] && get_option('dbem_pro_dev_updates') == 1 ){
192
- ?>
193
- <div id="message" class="updated">
194
- <p><?php echo sprintf(__('Dev Mode active: Just a friendly reminder that you are updating to development versions. Only admins see this message, and it will go away when you disable this <a href="#pro-api">here</a> in your settings.','events-manager'),'<code>define(\'EMP_DEV_UPDATES\',true);</code>'); ?></p>
195
- </div>
196
- <?php
197
- }
198
- if( class_exists('SitePress') && !class_exists('EM_WPML') && !get_site_option('disable_em_wpml_warning') ){
199
- if( !empty($_REQUEST['disable_em_wpml_warning']) ){
200
- update_site_option('disable_em_wpml_warning',1);
201
- }else{
202
- ?>
203
- <div id="message" class="updated">
204
- <p><?php echo sprintf(__('It looks like you have WPML enabled on your site. We advise you also install our extra <a href="%s">Events Manager WPML Connector</a> plugin which helps the two work better together. <a href="%s">Dismiss message</a>','events-manager'),'http://wordpress.org/extend/plugins/events-manager-wpml/', esc_url(add_query_arg(array('disable_em_wpml_warning'=>1)))); ?></p>
205
- </div>
206
- <?php
207
- }
208
- }
209
- if( array_key_exists('dbem_disable_timthumb', wp_load_alloptions()) ){
210
- if( !empty($_REQUEST['dbem_disable_timthumb']) ){
211
- delete_option('dbem_disable_timthumb',1);
212
- }else{
213
- ?>
214
- <div id="message" class="updated">
215
- <p>We have stopped using TimThumb for thumbnails in Events Manager, <a href="http://wp-events-plugin.com/blog/2014/12/05/bye-timthumb/">please see this post</a> for more information on how this may affect you and what options are available to you. <a href="<?php echo esc_url(add_query_arg(array('dbem_disable_timthumb'=>1))); ?>">Dismiss</a></p>
216
- </div>
217
- <?php
218
- }
219
- }
220
- }
221
- //Warn about EM page edit
222
- if ( preg_match( '/(post|page).php/', $_SERVER ['SCRIPT_NAME']) && isset ( $_GET ['action'] ) && $_GET ['action'] == 'edit' && isset ( $_GET ['post'] ) && $_GET ['post'] == "$events_page_id") {
223
- $message = sprintf ( __ ( "This page corresponds to the <strong>Events Manager</strong> %s page. Its content will be overridden by Events Manager, although if you include the word CONTENTS (exactly in capitals) and surround it with other text, only CONTENTS will be overwritten. If you want to change the way your events look, go to the <a href='%s'>settings</a> page. ", 'events-manager'), __('Events','events-manager'), EM_ADMIN_URL .'&amp;page=events-manager-options' );
224
- $notice = "<div class='error'><p>$message</p></div>";
225
- echo $notice;
226
- }
227
- echo $EM_Notices;
228
- }
229
- add_action ( 'admin_notices', 'em_admin_warnings', 100 );
230
-
231
- /**
232
- * Settings link in the plugins page menu
233
- * @param array $links
234
- * @param string $file
235
- * @return array
236
- */
237
- function em_plugin_action_links($actions, $file, $plugin_data) {
238
- $new_actions = array();
239
- $new_actions[] = sprintf( '<a href="'.EM_ADMIN_URL.'&amp;page=events-manager-options">%s</a>', __('Settings', 'events-manager') );
240
- $new_actions = array_merge($new_actions, $actions);
241
- if( is_multisite() ){
242
- $uninstall_url = admin_url().'network/admin.php?page=events-manager-options&amp;action=uninstall&amp;_wpnonce='.wp_create_nonce('em_uninstall_'.get_current_user_id().'_wpnonce');
243
- }else{
244
- $uninstall_url = EM_ADMIN_URL.'&amp;page=events-manager-options&amp;action=uninstall&amp;_wpnonce='.wp_create_nonce('em_uninstall_'.get_current_user_id().'_wpnonce');
245
- }
246
- $new_actions[] = '<span class="delete"><a href="'.$uninstall_url.'" class="delete">'.__('Uninstall','events-manager').'</a></span>';
247
- return $new_actions;
248
- }
249
- add_filter( 'plugin_action_links_events-manager/events-manager.php', 'em_plugin_action_links', 10, 3 );
250
-
251
- //Updates and Dev versions
252
- function em_updates_check( $transient ) {
253
- // Check if the transient contains the 'checked' information
254
- if( empty( $transient->checked ) )
255
- return $transient;
256
-
257
- //only bother if we're checking for dev versions
258
- if( get_option('em_check_dev_version') || get_option('dbem_pro_dev_updates') ){
259
- //check WP repo for trunk version
260
- $plugin_slugs = apply_filters('em_org_dev_version_slugs', array('events-manager'=> EM_SLUG));
261
- foreach( $plugin_slugs as $org_slug => $wp_slug ) {
262
- $request = wp_remote_get('https://plugins.svn.wordpress.org/'.$org_slug.'/trunk/'.$org_slug.'.php');
263
-
264
- if (!is_wp_error($request)) {
265
- preg_match('/Version: ([0-9a-z\.]+)/', $request['body'], $matches);
266
-
267
- if (!empty($matches[1])) {
268
- //we have a version number!
269
- if (version_compare($transient->checked[$wp_slug], $matches[1]) < 0) {
270
- $response = new stdClass();
271
- $response->slug = $wp_slug;
272
- $response->new_version = $matches[1];
273
- $response->url = 'http://wordpress.org/extend/plugins/'.$org_slug.'/';
274
- $response->package = 'http://downloads.wordpress.org/plugin/'.$org_slug.'.zip';
275
- $icon_test = wp_remote_get('https://ps.w.org/'.$org_slug.'/assets/icon-128x128.png');
276
- if( !is_wp_error($icon_test) && $icon_test['response']['code'] == 200 ){
277
- $response->icons = array(
278
- '1x' => 'https://ps.w.org/'.$org_slug.'/assets/icon-128x128.png',
279
- '2x' => 'https://ps.w.org/'.$org_slug.'/assets/icon-256x256.png'
280
- );
281
- }
282
- $transient->response[$wp_slug] = $response;
283
- }
284
- }
285
- }
286
- }
287
-
288
- delete_option('em_check_dev_version');
289
- }
290
-
291
- return $transient;
292
- }
293
- add_filter('pre_set_site_transient_update_plugins', 'em_updates_check', 100); // Hook into the plugin update check and mod for dev version
294
-
295
- function em_user_action_links( $actions, $user ){
296
- if ( !is_network_admin() && current_user_can( 'manage_others_bookings' ) ){
297
- if( get_option('dbem_edit_bookings_page') && (!is_admin() || !empty($_REQUEST['is_public'])) ){
298
- $my_bookings_page = get_permalink(get_option('dbem_edit_bookings_page'));
299
- $bookings_link = em_add_get_params($my_bookings_page, array('person_id'=>$user->ID), false);
300
- }else{
301
- $bookings_link = EM_ADMIN_URL. "&page=events-manager-bookings&person_id=".$user->ID;
302
- }
303
- $actions['bookings'] = "<a href='$bookings_link'>" . __( 'Bookings','events-manager') . "</a>";
304
- }
305
- return $actions;
306
- }
307
- add_filter('user_row_actions','em_user_action_links',10,2);
308
-
309
- function em_pro_update_notice(){
310
- // Check EM Pro update min
311
- if( defined('EMP_VERSION') && EMP_VERSION < EM_PRO_MIN_VERSION && !defined('EMP_DISABLE_WARNINGS') ) {
312
- $data = get_site_option('dbem_data');
313
- $possible_notices = is_array($data) && !empty($data['admin_notices']) ? $data['admin_notices'] : array();
314
- //we may have something to show, so we make sure that there's something to show right now
315
- if( !isset($possible_notices['em-pro-updates']) ) {
316
- ?>
317
- <div id="em_page_error" class="notice notice-warning">
318
- <p><?php _e('There is a newer version of Events Manager Pro which is recommended for this current version of Events Manager as new features have been added. Please go to the plugin website and download the latest update.','events-manager'); ?></p>
319
- </div>
320
- <?php
321
- }
322
- }
323
- }
324
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-bookings.php DELETED
@@ -1,560 +0,0 @@
1
- <?php
2
- /**
3
- * Deprecated - see em-actions.php - this will be removed at some point in 6.0
4
- * Check if there's any admin-related actions to take for bookings. All actions are caught here.
5
- * @return null
6
- * @todo remove in 6.0
7
- */
8
- function em_admin_actions_bookings() {
9
- global $EM_Event;
10
- if( is_object($EM_Event) && !empty($_REQUEST['action']) ){
11
- if( $_REQUEST['action'] == 'bookings_export_csv' && wp_verify_nonce($_REQUEST['_wpnonce'],'bookings_export_csv') ){
12
- $EM_Event->get_bookings()->export_csv();
13
- exit();
14
- }
15
- }
16
- }
17
- add_action('admin_init','em_admin_actions_bookings',100);
18
-
19
- /**
20
- * Decide what content to show in the bookings section.
21
- */
22
- function em_bookings_page(){
23
- //First any actions take priority
24
- do_action('em_bookings_admin_page');
25
- if( !empty($_REQUEST['_wpnonce']) ){ $_REQUEST['_wpnonce'] = $_GET['_wpnonce'] = $_POST['_wpnonce'] = esc_attr($_REQUEST['_wpnonce']); } //XSS fix just in case here too
26
- if( !empty($_REQUEST['action']) && substr($_REQUEST['action'],0,7) != 'booking' ){ //actions not starting with booking_
27
- do_action('em_bookings_'.$_REQUEST['action']);
28
- }elseif( !empty($_REQUEST['booking_id']) ){
29
- em_bookings_single();
30
- }elseif( !empty($_REQUEST['person_id']) ){
31
- em_bookings_person();
32
- }elseif( !empty($_REQUEST['ticket_id']) ){
33
- em_bookings_ticket();
34
- }elseif( !empty($_REQUEST['event_id']) ){
35
- em_bookings_event();
36
- }else{
37
- em_bookings_dashboard();
38
- }
39
- }
40
-
41
- /**
42
- * Generates the bookings dashboard, showing information on all events
43
- */
44
- function em_bookings_dashboard(){
45
- global $EM_Notices;
46
- ?>
47
- <div class='wrap em-bookings-dashboard'>
48
- <?php if( is_admin() ): ?>
49
- <h1><?php esc_html_e('Event Bookings Dashboard', 'events-manager'); ?></h1>
50
- <?php else: echo $EM_Notices; ?>
51
- <?php endif; ?>
52
- <div class="em-bookings-recent">
53
- <h2><?php esc_html_e('Recent Bookings','events-manager'); ?></h2>
54
- <?php
55
- $EM_Bookings_Table = new EM_Bookings_Table();
56
- $EM_Bookings_Table->status = get_option('dbem_bookings_approval') ? 'needs-attention':'confirmed';
57
- $EM_Bookings_Table->output();
58
- ?>
59
- </div>
60
- <br class="clear" />
61
- <div class="em-bookings-events">
62
- <h2><?php esc_html_e('Events With Bookings Enabled','events-manager'); ?></h2>
63
- <?php em_bookings_events_table(); ?>
64
- <?php do_action('em_bookings_dashboard'); ?>
65
- </div>
66
- </div>
67
- <?php
68
- }
69
-
70
- /**
71
- * Shows all booking data for a single event
72
- */
73
- function em_bookings_event(){
74
- global $EM_Event,$EM_Person,$EM_Notices;
75
- //check that user can access this page
76
- if( is_object($EM_Event) && !$EM_Event->can_manage('manage_bookings','manage_others_bookings') ){
77
- ?>
78
- <div class="wrap"><h2><?php esc_html_e('Unauthorized Access','events-manager'); ?></h2><p><?php esc_html_e('You do not have the rights to manage this event.','events-manager'); ?></p></div>
79
- <?php
80
- return false;
81
- }
82
- $header_button_classes = is_admin() ? 'page-title-action':'button add-new-h2';
83
- ?>
84
- <div class='wrap'>
85
- <?php if( is_admin() ): ?><h1 class="wp-heading-inline"><?php else: ?><h2><?php endif; ?>
86
- <?php echo sprintf(__('Manage %s Bookings', 'events-manager'), "'{$EM_Event->event_name}'"); ?>
87
- <?php if( is_admin() ): ?></h1><?php endif; ?>
88
- <a href="<?php echo $EM_Event->get_permalink(); ?>" class="<?php echo $header_button_classes; ?>"><?php echo sprintf(__('View %s','events-manager'), __('Event', 'events-manager')) ?></a>
89
- <a href="<?php echo $EM_Event->get_edit_url(); ?>" class="<?php echo $header_button_classes; ?>"><?php echo sprintf(__('Edit %s','events-manager'), __('Event', 'events-manager')) ?></a>
90
- <?php if( locate_template('plugins/events-manager/templates/csv-event-bookings.php', false) ): //support for legacy template ?>
91
- <a href='<?php echo EM_ADMIN_URL ."&amp;page=events-manager-bookings&amp;action=bookings_export_csv&amp;_wpnonce=".wp_create_nonce('bookings_export_csv')."&amp;event_id=".$EM_Event->event_id ?>' class="<?php echo $header_button_classes; ?>"><?php esc_html_e('Export CSV','events-manager')?></a>
92
- <?php endif; ?>
93
- <?php do_action('em_admin_event_booking_options_buttons'); ?>
94
- <?php if( !is_admin() ): ?></h2><?php else: ?><hr class="wp-header-end" /><?php endif; ?>
95
- <?php if( !is_admin() ) echo $EM_Notices; ?>
96
- <div>
97
- <p><strong><?php esc_html_e('Event Name','events-manager'); ?></strong> : <?php echo esc_html($EM_Event->event_name); ?></p>
98
- <p>
99
- <strong><?php esc_html_e('Availability','events-manager'); ?></strong> :
100
- <?php echo $EM_Event->get_bookings()->get_booked_spaces() . '/'. $EM_Event->get_spaces() ." ". __('Spaces confirmed','events-manager'); ?>
101
- <?php if( get_option('dbem_bookings_approval_reserved') ): ?>
102
- , <?php echo $EM_Event->get_bookings()->get_available_spaces() . '/'. $EM_Event->get_spaces() ." ". __('Available spaces','events-manager'); ?>
103
- <?php endif; ?>
104
- </p>
105
- <p>
106
- <strong><?php esc_html_e('Date','events-manager'); ?></strong> :
107
- <?php echo $EM_Event->output_dates(false, " - "). ' @ ' . $EM_Event->output_times(false, ' - '); ?>
108
- </p>
109
- <p>
110
- <strong><?php esc_html_e('Location','events-manager'); ?></strong> :
111
- <?php if( $EM_Event->location_id == 0 ): ?>
112
- <em><?php esc_html_e('No Location', 'events-manager'); ?></em>
113
- <?php else: ?>
114
- <a class="row-title" href="<?php echo admin_url(); ?>post.php?action=edit&amp;post=<?php echo $EM_Event->get_location()->post_id ?>"><?php echo ($EM_Event->get_location()->location_name); ?></a>
115
- <?php endif; ?>
116
- </p>
117
- </div>
118
- <h2><?php esc_html_e('Bookings','events-manager'); ?></h2>
119
- <?php
120
- $EM_Bookings_Table = new EM_Bookings_Table();
121
- $EM_Bookings_Table->status = 'all';
122
- $EM_Bookings_Table->output();
123
- ?>
124
- <?php do_action('em_bookings_event_footer', $EM_Event); ?>
125
- </div>
126
- <?php
127
- }
128
-
129
- /**
130
- * Shows a ticket view
131
- */
132
- function em_bookings_ticket(){
133
- global $EM_Ticket,$EM_Notices;
134
- $EM_Event = $EM_Ticket->get_event();
135
- //check that user can access this page
136
- if( is_object($EM_Ticket) && !$EM_Ticket->can_manage() ){
137
- ?>
138
- <div class="wrap"><h2><?php esc_html_e('Unauthorized Access','events-manager'); ?></h2><p><?php esc_html_e('You do not have the rights to manage this ticket.','events-manager'); ?></p></div>
139
- <?php
140
- return false;
141
- }
142
- $header_button_classes = is_admin() ? 'page-title-action':'button add-new-h2';
143
- ?>
144
- <div class='wrap'>
145
- <?php if( is_admin() ): ?><h1 class="wp-heading-inline"><?php else: ?><h2><?php endif; ?>
146
- <?php echo sprintf(__('Ticket for %s', 'events-manager'), "'{$EM_Event->name}'"); ?>
147
- <?php if( is_admin() ): ?></h1><?php endif; ?>
148
- <a href="<?php echo $EM_Event->get_edit_url(); ?>" class="<?php echo $header_button_classes; ?>"><?php esc_html_e('View/Edit Event','events-manager') ?></a>
149
- <a href="<?php echo $EM_Event->get_bookings_url(); ?>" class="<?php echo $header_button_classes; ?>"><?php esc_html_e('View Event Bookings','events-manager') ?></a>
150
-
151
- <?php if( !is_admin() ): ?></h2><?php else: ?><hr class="wp-header-end" /><?php endif; ?>
152
- <?php if( !is_admin() ) echo $EM_Notices; ?>
153
- <div>
154
- <table>
155
- <tr><td><?php echo __('Name','events-manager'); ?></td><td></td><td><?php echo $EM_Ticket->ticket_name; ?></td></tr>
156
- <tr><td><?php echo __('Description','events-manager'); ?>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td><td></td><td><?php echo ($EM_Ticket->ticket_description) ? $EM_Ticket->ticket_description : '-'; ?></td></tr>
157
- <tr><td><?php echo __('Price','events-manager'); ?></td><td></td><td><?php echo ($EM_Ticket->ticket_price) ? $EM_Ticket->ticket_price : '-'; ?></td></tr>
158
- <tr><td><?php echo __('Spaces','events-manager'); ?></td><td></td><td><?php echo ($EM_Ticket->ticket_spaces) ? $EM_Ticket->ticket_spaces : '-'; ?></td></tr>
159
- <tr><td><?php echo __('Min','events-manager'); ?></td><td></td><td><?php echo ($EM_Ticket->ticket_min) ? $EM_Ticket->ticket_min : '-'; ?></td></tr>
160
- <tr><td><?php echo __('Max','events-manager'); ?></td><td></td><td><?php echo ($EM_Ticket->ticket_max) ? $EM_Ticket->ticket_max : '-'; ?></td></tr>
161
- <tr><td><?php echo __('Start','events-manager'); ?></td><td></td><td><?php echo ($EM_Ticket->ticket_start) ? $EM_Ticket->start()->formatDefault() : '-'; ?></td></tr>
162
- <tr><td><?php echo __('End','events-manager'); ?></td><td></td><td><?php echo ($EM_Ticket->ticket_end) ? $EM_Ticket->end()->formatDefault() : '-'; ?></td></tr>
163
- <?php do_action('em_booking_admin_ticket_row', $EM_Ticket); ?>
164
- </table>
165
- </div>
166
- <h2><?php esc_html_e('Bookings','events-manager'); ?></h2>
167
- <?php
168
- $EM_Bookings_Table = new EM_Bookings_Table();
169
- $EM_Bookings_Table->status = get_option('dbem_bookings_approval') ? 'needs-attention':'confirmed';
170
- $EM_Bookings_Table->output();
171
- ?>
172
- <?php do_action('em_bookings_ticket_footer', $EM_Ticket); ?>
173
- </div>
174
- <?php
175
- }
176
-
177
- /**
178
- * Shows a single booking for a single person.
179
- */
180
- function em_bookings_single(){
181
- global $EM_Booking, $EM_Notices; /* @var $EM_Booking EM_Booking */
182
- //check that user can access this page
183
- if( is_object($EM_Booking) && !$EM_Booking->can_manage() ){
184
- ?>
185
- <div class="wrap"><h2><?php esc_html_e('Unauthorized Access','events-manager'); ?></h2><p><?php esc_html_e('You do not have the rights to manage this event.','events-manager'); ?></p></div>
186
- <?php
187
- return false;
188
- }
189
- ?>
190
- <div class='wrap' id="em-bookings-admin-booking">
191
- <?php if( is_admin() ): ?><h1><?php else: ?><h2><?php endif; ?>
192
- <?php esc_html_e('Edit Booking', 'events-manager'); ?>
193
- <?php if( !is_admin() ): ?></h2><?php else: ?></h1><?php endif; ?>
194
- <?php if( !is_admin() ) echo $EM_Notices; ?>
195
- <div class="metabox-holder">
196
- <div class="postbox-container" style="width:99.5%">
197
- <div class="postbox">
198
- <h3>
199
- <?php esc_html_e( 'Event Details', 'events-manager'); ?>
200
- </h3>
201
- <div class="inside">
202
- <?php
203
- $EM_Event = $EM_Booking->get_event();
204
- ?>
205
- <table>
206
- <tr><td><strong><?php esc_html_e('Name','events-manager'); ?></strong></td><td><a class="row-title" href="<?php echo $EM_Event->get_bookings_url(); ?>"><?php echo ($EM_Event->event_name); ?></a></td></tr>
207
- <tr>
208
- <td><strong><?php esc_html_e('Date/Time','events-manager'); ?>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong></td>
209
- <td>
210
- <?php echo $EM_Event->output('#_EVENTDATES @ #_EVENTTIMES'); ?>
211
- </td>
212
- </tr>
213
- </table>
214
- <?php do_action('em_bookings_admin_booking_event', $EM_Event); ?>
215
- </div>
216
- </div>
217
- <div class="postbox">
218
- <h3>
219
- <?php esc_html_e( 'Personal Details', 'events-manager'); ?>
220
- </h3>
221
- <div class="inside">
222
- <div class="em-booking-person-details">
223
- <?php echo $EM_Booking->get_person()->display_summary(); ?>
224
- <?php if( $EM_Booking->is_no_user() ): ?>
225
- <input type="button" class="button-secondary" id="em-booking-person-modify" value="<?php esc_attr_e('Edit Details','events-manager'); ?>" />
226
- <?php endif; ?>
227
- </div>
228
- <?php if( $EM_Booking->is_no_user() ): ?>
229
- <form action="" method="post" class="em-booking-person-form">
230
- <div class="em-booking-person-editor" style="display:none;">
231
- <?php echo $EM_Booking->get_person_editor(); ?>
232
- <input type='hidden' name='action' value='booking_modify_person'/>
233
- <input type='hidden' name='booking_id' value='<?php echo $EM_Booking->booking_id; ?>'/>
234
- <input type='hidden' name='event_id' value='<?php echo $EM_Event->event_id; ?>'/>
235
- <input type='hidden' name='_wpnonce' value='<?php echo wp_create_nonce('booking_modify_person_'.$EM_Booking->booking_id); ?>'/>
236
- <input type="submit" class="button-primary em-button em-booking-person-modify-submit" id="em-booking-person-modify-submit" value="<?php esc_attr_e('Submit Changes', 'events-manager'); ?>" />
237
- <input type="button" id="em-booking-person-modify-cancel" class="button-secondary em-button" value="<?php esc_attr_e('Cancel','events-manager'); ?>" />
238
- </div>
239
- </form>
240
- <script type="text/javascript">
241
- jQuery(document).ready( function($){
242
- $('#em-booking-person-modify').on('click', function(){
243
- $('.em-booking-person-details').hide();
244
- $('.em-booking-person-editor').show();
245
- });
246
- $('#em-booking-person-modify-cancel').on('click', function(){
247
- $('.em-booking-person-details').show();
248
- $('.em-booking-person-editor').hide();
249
- });
250
- });
251
- </script>
252
- <?php endif; ?>
253
- <?php do_action('em_bookings_admin_booking_person', $EM_Booking); ?>
254
- </div>
255
- </div>
256
- <div class="postbox">
257
- <h3>
258
- <?php esc_html_e( 'Booking Details', 'events-manager'); ?>
259
- </h3>
260
- <div class="inside">
261
- <?php
262
- $EM_Event = $EM_Booking->get_event();
263
- $shown_tickets = array();
264
- ?>
265
- <div>
266
- <form action="" method="post" class="em-booking-single-status-info">
267
- <strong><?php esc_html_e('Status','events-manager'); ?> : </strong>
268
- <?php echo $EM_Booking->get_status(); ?>
269
- <input type="button" class="button-secondary em-button em-booking-submit-status-modify" id="em-booking-submit-status-modify" value="<?php esc_attr_e('Change', 'events-manager'); ?>" />
270
- <input type="submit" class="button-primary em-button em-booking-resend-email" id="em-booking-resend-email" value="<?php esc_attr_e('Resend Email', 'events-manager'); ?>" />
271
- <input type='hidden' name='action' value='booking_resend_email'/>
272
- <input type='hidden' name='booking_id' value='<?php echo $EM_Booking->booking_id; ?>'/>
273
- <input type='hidden' name='event_id' value='<?php echo $EM_Event->event_id; ?>'/>
274
- <input type='hidden' name='_wpnonce' value='<?php echo wp_create_nonce('booking_resend_email_'.$EM_Booking->booking_id); ?>'/>
275
- </form>
276
- <form action="" method="post" class="em-booking-single-status-edit">
277
- <strong><?php esc_html_e('Status','events-manager'); ?> : </strong>
278
- <select name="booking_status">
279
- <?php foreach($EM_Booking->status_array as $status => $status_name): ?>
280
- <option value="<?php echo esc_attr($status); ?>" <?php if($status == $EM_Booking->booking_status){ echo 'selected="selected"'; } ?>><?php echo esc_html($status_name); ?></option>
281
- <?php endforeach; ?>
282
- </select>
283
- <input type="checkbox" checked="checked" name="send_email" value="1" />
284
- <?php esc_html_e('Send Email','events-manager'); ?>
285
- <input type="submit" class="button-primary em-button em-booking-submit-status" id="em-booking-submit-status" value="<?php esc_attr_e('Submit Changes', 'events-manager'); ?>" />
286
- <input type="button" class="button-secondary em-button em-booking-submit-status-cancel" id="em-booking-submit-status-cancel" value="<?php esc_attr_e('Cancel', 'events-manager'); ?>" />
287
- <input type='hidden' name='action' value='booking_set_status'/>
288
- <input type='hidden' name='booking_id' value='<?php echo $EM_Booking->booking_id; ?>'/>
289
- <input type='hidden' name='event_id' value='<?php echo $EM_Event->event_id; ?>'/>
290
- <input type='hidden' name='_wpnonce' value='<?php echo wp_create_nonce('booking_set_status_'.$EM_Booking->booking_id); ?>'/>
291
- <br /><em><?php echo wp_kses_data(__('<strong>Notes:</strong> Ticket availability not taken into account when approving new bookings (i.e. you can overbook).','events-manager')); ?></em>
292
- </form>
293
- </div>
294
- <form action="" method="post" class="em-booking-form">
295
- <table class="em-tickets-bookings-table" cellpadding="0" cellspacing="0">
296
- <thead>
297
- <tr>
298
- <th><?php esc_html_e('Ticket Type','events-manager'); ?></th>
299
- <th><?php esc_html_e('Spaces','events-manager'); ?></th>
300
- <th><?php esc_html_e('Price','events-manager'); ?></th>
301
- </tr>
302
- </thead>
303
- <tbody>
304
- <?php foreach($EM_Booking->get_tickets_bookings()->tickets_bookings as $EM_Ticket_Booking): /* @var $EM_Ticket_Booking EM_Ticket_Booking */ ?>
305
- <tr>
306
- <td class="ticket-type"><a class="row-title" href="<?php echo em_add_get_params($EM_Event->get_bookings_url(), array('ticket_id'=>$EM_Ticket_Booking->ticket_id)); ?>"><?php echo $EM_Ticket_Booking->get_ticket()->ticket_name ?></a></td>
307
- <td>
308
- <span class="em-booking-single-info"><?php echo $EM_Ticket_Booking->get_spaces(); ?></span>
309
- <div class="em-booking-single-edit"><input name="em_tickets[<?php echo $EM_Ticket_Booking->ticket_id; ?>][spaces]" class="em-ticket-select" id="em-ticket-spaces-<?php echo $EM_Ticket_Booking->ticket_id; ?>" value="<?php echo $EM_Ticket_Booking->get_spaces(); ?>" /></div>
310
- </td>
311
- <td><?php echo $EM_Ticket_Booking->get_price(true,true); ?></td>
312
- </tr>
313
- <?php
314
- $shown_tickets[] = $EM_Ticket_Booking->ticket_id;
315
- do_action('em_bookings_admin_ticket_row', $EM_Ticket_Booking->get_ticket(), $EM_Booking);
316
- ?>
317
- <?php endforeach; ?>
318
- <?php if( count($shown_tickets) < count($EM_Event->get_bookings()->get_tickets()->tickets)): ?><tr>
319
- <?php foreach($EM_Event->get_bookings()->get_tickets()->tickets as $EM_Ticket): /* @var $EM_Ticket EM_Ticket */ ?>
320
- <?php if( !in_array($EM_Ticket->ticket_id, $shown_tickets) ): ?>
321
- <tr>
322
- <td class="ticket-type"><a class="row-title" href="<?php echo em_add_get_params($EM_Event->get_bookings_url(), array('ticket_id'=>$EM_Ticket->ticket_id)); ?>"><?php echo $EM_Ticket->ticket_name ?></a></td>
323
- <td>
324
- <span class="em-booking-single-info">0</span>
325
- <div class="em-booking-single-edit"><input name="em_tickets[<?php echo $EM_Ticket->ticket_id; ?>][spaces]" class="em-ticket-select" id="em-ticket-spaces-<?php echo $EM_Ticket->ticket_id; ?>" value="0" /></div>
326
- </td>
327
- <td><?php echo em_get_currency_symbol() ?>0.00</td>
328
- </tr>
329
- <?php do_action('em_bookings_admin_ticket_row', $EM_Ticket, $EM_Booking); ?>
330
- <?php endif; ?>
331
- <?php endforeach; ?>
332
- <?php endif; ?>
333
- </tbody>
334
- <tfoot>
335
- <?php
336
- do_action('em_bookings_admin_ticket_totals_header');
337
- $price_summary = $EM_Booking->get_price_summary_array();
338
- //we should now have an array of information including base price, taxes and post/pre tax discounts
339
- ?>
340
- <tr>
341
- <th><?php esc_html_e('Price','events-manager'); ?></th>
342
- <th><?php echo sprintf(__('%d Spaces','events-manager'), $EM_Booking->get_spaces()); ?></th>
343
- <th><?php echo $EM_Booking->get_price_base(true); ?></th>
344
- </tr>
345
- <?php if( count($price_summary['discounts_pre_tax']) > 0 ): ?>
346
- <?php foreach( $price_summary['discounts_pre_tax'] as $discount_summary ): ?>
347
- <tr>
348
- <th><?php echo $discount_summary['name']; ?></th>
349
- <th><?php echo $discount_summary['adjustment']; ?></th>
350
- <th>- <?php echo $discount_summary['amount']; ?></th>
351
- </tr>
352
- <?php endforeach; ?>
353
- <?php endif; ?>
354
- <?php if( count($price_summary['surcharges_pre_tax']) > 0 ): ?>
355
- <?php foreach( $price_summary['surcharges_pre_tax'] as $surcharge_summary ): ?>
356
- <tr>
357
- <th><?php echo $surcharge_summary['name']; ?></th>
358
- <th><?php echo $surcharge_summary['adjustment']; ?></th>
359
- <th><?php echo $surcharge_summary['amount']; ?></th>
360
- </tr>
361
- <?php endforeach; ?>
362
- <?php endif; ?>
363
- <?php if( !empty($price_summary['taxes']['amount']) ): ?>
364
- <tr>
365
- <th><?php esc_html_e('Tax','events-manager'); ?></th>
366
- <th>
367
- <span class="em-booking-single-info"><?php echo $price_summary['taxes']['rate'] ?></span>
368
- <div class="em-booking-single-edit"><input name="booking_tax_rate" value="<?php echo esc_attr($EM_Booking->get_tax_rate()); ?>">%</div>
369
- </th>
370
- <th><?php echo $price_summary['taxes']['amount']; ?></th>
371
- </tr>
372
- <?php endif; ?>
373
- <?php if( count($price_summary['discounts_post_tax']) > 0 ): ?>
374
- <?php foreach( $price_summary['discounts_post_tax'] as $discount_summary ): ?>
375
- <tr>
376
- <th><?php echo $discount_summary['name']; ?></th>
377
- <th><?php echo $discount_summary['adjustment']; ?></th>
378
- <th>- <?php echo $discount_summary['amount']; ?></th>
379
- </tr>
380
- <?php endforeach; ?>
381
- <?php endif; ?>
382
- <?php if( count($price_summary['surcharges_post_tax']) > 0 ): ?>
383
- <?php foreach( $price_summary['surcharges_post_tax'] as $surcharge_summary ): ?>
384
- <tr>
385
- <th><?php echo $surcharge_summary['name']; ?></th>
386
- <th><?php echo $surcharge_summary['adjustment']; ?></th>
387
- <th><?php echo $surcharge_summary['amount']; ?></th>
388
- </tr>
389
- <?php endforeach; ?>
390
- <?php endif; ?>
391
- <tr class="em-hr">
392
- <th><?php esc_html_e('Total Price','events-manager'); ?></th>
393
- <th>&nbsp;</th>
394
- <th><?php echo $price_summary['total']; ?></th>
395
- </tr>
396
- <?php do_action('em_bookings_admin_ticket_totals_footer', $EM_Booking); ?>
397
- </tfoot>
398
- </table>
399
- <table class="em-form-fields" cellspacing="0" cellpadding="0">
400
- <?php if( !has_action('em_bookings_single_custom') ): //default behavior ?>
401
- <tr>
402
- <th><?php esc_html_e('Comment','events-manager'); ?></th>
403
- <td>
404
- <span class="em-booking-single-info"><?php echo esc_html($EM_Booking->booking_comment); ?></span>
405
- <div class="em-booking-single-edit"><textarea name="booking_comment"><?php echo esc_html($EM_Booking->booking_comment); ?></textarea></div>
406
- </td>
407
- </tr>
408
- <?php else: do_action('em_bookings_single_custom',$EM_Booking); //do your own thing, e.g. pro ?>
409
- <?php endif; ?>
410
- </table>
411
- <p class="em-booking-single-info">
412
- <input type="button" class="button-secondary em-button em-booking-submit-modify" id="em-booking-submit-modify" value="<?php esc_attr_e('Modify Booking', 'events-manager'); ?>" />
413
- </p>
414
- <p class="em-booking-single-edit">
415
- <em><?php _e('<strong>Notes:</strong> Ticket availability not taken into account (i.e. you can overbook). Emails are not resent automatically.','events-manager'); ?></em>
416
- <br /><br />
417
- <input type="submit" class="button-primary em-button em-booking-submit" id="em-booking-submit" value="<?php esc_attr_e('Submit Changes', 'events-manager'); ?>" />
418
- <input type="button" class="button-secondary em-button em-booking-submit-cancel" id="em-booking-submit-cancel" value="<?php esc_attr_e('Cancel', 'events-manager'); ?>" />
419
- <input type='hidden' name='action' value='booking_save'/>
420
- <input type='hidden' name='booking_id' value='<?php echo $EM_Booking->booking_id; ?>'/>
421
- <input type='hidden' name='event_id' value='<?php echo $EM_Event->event_id; ?>'/>
422
- <input type='hidden' name='_wpnonce' value='<?php echo wp_create_nonce('booking_save_'.$EM_Booking->booking_id); ?>'/>
423
- </p>
424
- </form>
425
- <script type="text/javascript">
426
- jQuery(document).ready( function($){
427
- $('#em-booking-submit-modify').on('click', function(){
428
- $('.em-booking-single-info').hide();
429
- $('.em-booking-single-edit').show();
430
- });
431
- $('#em-booking-submit-cancel').on('click', function(){
432
- $('.em-booking-single-info').show();
433
- $('.em-booking-single-edit').hide();
434
- });
435
- $('.em-booking-single-info').show();
436
- $('.em-booking-single-edit').hide();
437
-
438
- $('#em-booking-submit-status-modify').on('click', function(){
439
- $('.em-booking-single-status-info').hide();
440
- $('.em-booking-single-status-edit').show();
441
- });
442
- $('#em-booking-submit-status-cancel').on('click', function(){
443
- $('.em-booking-single-status-info').show();
444
- $('.em-booking-single-status-edit').hide();
445
- });
446
- $('.em-booking-single-status-info').show();
447
- $('.em-booking-single-status-edit').hide();
448
- });
449
- </script>
450
- </div>
451
- </div>
452
- <div id="em-booking-notes" class="postbox">
453
- <h3>
454
- <?php esc_html_e( 'Booking Notes', 'events-manager'); ?>
455
- </h3>
456
- <div class="inside">
457
- <p><?php esc_html_e('You can add private notes below for internal reference that only event managers will see.','events-manager'); ?></p>
458
- <?php foreach( $EM_Booking->get_notes() as $note ):
459
- $user = new EM_Person($note['author']);
460
- ?>
461
- <div>
462
- <?php echo sprintf(esc_html_x('%1$s - %2$s wrote','[Date] - [Name] wrote','events-manager'), date(get_option('date_format'), $note['timestamp']), $user->get_name()); ?>:
463
- <p style="background:#efefef; padding:5px;"><?php echo nl2br($note['note']); ?></p>
464
- </div>
465
- <?php endforeach; ?>
466
- <form method="post" action="" style="padding:5px;">
467
- <textarea class="widefat" rows="5" name="booking_note"></textarea>
468
- <input type="hidden" name="action" value="bookings_add_note" />
469
- <input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce('bookings_add_note'); ?>" />
470
- <input type="submit" class="em-button button-primary" value="<?php esc_html_e('Add Note', 'events-manager'); ?>" />
471
- </form>
472
- </div>
473
- </div>
474
- <?php do_action('em_bookings_single_metabox_footer', $EM_Booking); ?>
475
- </div>
476
- </div>
477
- <br style="clear:both;" />
478
- <?php do_action('em_bookings_single_footer', $EM_Booking); ?>
479
- </div>
480
- <?php
481
-
482
- }
483
-
484
- /**
485
- * Shows all bookings made by one person.
486
- */
487
- function em_bookings_person(){
488
- global $EM_Person, $EM_Notices;
489
- $EM_Person->get_bookings();
490
- $has_booking = false;
491
- foreach($EM_Person->get_bookings() as $EM_Booking){
492
- if($EM_Booking->can_manage('manage_bookings','manage_others_bookings')){
493
- $has_booking = true;
494
- }
495
- }
496
- if( !$has_booking && !current_user_can('manage_others_bookings') ){
497
- ?>
498
- <div class="wrap"><h2><?php esc_html_e('Unauthorized Access','events-manager'); ?></h2><p><?php esc_html_e('You do not have the rights to manage this event.','events-manager'); ?></p></div>
499
- <?php
500
- return false;
501
- }
502
- $header_button_classes = is_admin() ? 'page-title-action':'button add-new-h2';
503
- ?>
504
- <div class='wrap'>
505
- <?php if( is_admin() ): ?><h1 class="wp-heading-inline"><?php else: ?><h2><?php endif; ?>
506
- <?php esc_html_e('Manage Person\'s Booking', 'events-manager'); ?>
507
- <?php if( is_admin() ): ?></h1><?php endif; ?>
508
- <?php if( current_user_can('edit_users') ) : ?>
509
- <a href="<?php echo admin_url('user-edit.php?user_id='.$EM_Person->ID); ?>" class="<?php echo $header_button_classes; ?>"><?php esc_html_e('Edit User','events-manager') ?></a>
510
- <?php endif; ?>
511
- <?php if( current_user_can('delete_users') ) : ?>
512
- <a href="<?php echo wp_nonce_url( admin_url("users.php?action=delete&amp;user=$EM_Person->ID"), 'bulk-users' ); ?>" class="<?php echo $header_button_classes; ?>"><?php esc_html_e('Delete User','events-manager') ?></a>
513
- <?php endif; ?>
514
- <?php if( !is_admin() ): ?></h2><?php else: ?><hr class="wp-header-end" /><?php endif; ?>
515
- <?php if( !is_admin() ) echo $EM_Notices; ?>
516
- <?php do_action('em_bookings_person_header'); ?>
517
- <div id="poststuff" class="metabox-holder has-right-sidebar">
518
- <div id="post-body">
519
- <div id="post-body-content">
520
- <div id="event_name" class="stuffbox">
521
- <h3>
522
- <?php esc_html_e( 'Personal Details', 'events-manager'); ?>
523
- </h3>
524
- <div class="inside">
525
- <?php echo $EM_Person->display_summary(); ?>
526
- </div>
527
- </div>
528
- </div>
529
- </div>
530
- </div>
531
- <br style="clear:both;" />
532
- <?php do_action('em_bookings_person_body_1'); ?>
533
- <h2><?php esc_html_e('Past And Present Bookings','events-manager'); ?></h2>
534
- <?php
535
- $EM_Bookings_Table = new EM_Bookings_Table();
536
- $EM_Bookings_Table->status = 'all';
537
- $EM_Bookings_Table->scope = 'all';
538
- $EM_Bookings_Table->output();
539
- ?>
540
- <?php do_action('em_bookings_person_footer', $EM_Person); ?>
541
- </div>
542
- <?php
543
- }
544
-
545
- function em_printable_booking_report() {
546
- global $EM_Event;
547
- //check that user can access this page
548
- if( isset($_GET['page']) && $_GET['page']=='events-manager-bookings' && isset($_GET['action']) && $_GET['action'] == 'bookings_report' && is_object($EM_Event)){
549
- if( is_object($EM_Event) && !$EM_Event->can_manage('edit_events','edit_others_events') ){
550
- ?>
551
- <div class="wrap"><h2><?php esc_html_e('Unauthorized Access','events-manager'); ?></h2><p><?php esc_html_e('You do not have the rights to manage this event.','events-manager'); ?></p></div>
552
- <?php
553
- return false;
554
- }
555
- em_locate_template('templates/bookings-event-printable.php', true);
556
- die();
557
- }
558
- }
559
- add_action('admin_init', 'em_printable_booking_report');
560
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-data-privacy.php DELETED
@@ -1,531 +0,0 @@
1
- <?php
2
- /*
3
- * This file deals with new privacy tools included in WP 4.9.6 and in line with aiding users with conforming to the GPDR rules.
4
- * Note that consent mechanisms are not included here and will be baked directly into the templates or Pro booking forms.
5
- */
6
- class EM_Data_Privacy {
7
-
8
- public static function init(){
9
- add_action( 'admin_init', 'EM_Data_Privacy::privacy_policy_content' );
10
- add_filter( 'wp_privacy_personal_data_erasers', 'EM_Data_Privacy::register_eraser', 10 );
11
- add_filter( 'wp_privacy_personal_data_exporters', 'EM_Data_Privacy::register_exporter', 10 );
12
- add_action( 'wp_privacy_personal_data_export_file_created', 'EM_Data_Privacy::export_cleanup');
13
- }
14
-
15
- public static function privacy_policy_content() {
16
- if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
17
- return;
18
- }
19
-
20
- $content = array();
21
- $content[] = sprintf(
22
- __('We use Google services to generate maps and provide autocompletion when searching for events by location, which may collect data via your browser in accordance to Google\'s <a href="%s">privacy policy</a>.', 'events-manager' ),
23
- 'https://policies.google.com/privacy'
24
- );
25
- $content[] = __('We collect and store information you submit to us when making a booking, for the purpose of reserving your requested spaces at our event and maintaining a record of attendance.', 'events-manager' );
26
- $content[] = __('We collect and store information you submit to us about events (and corresponding locations) you would like to publish on our site.', 'events-manager' );
27
- $content[] = __('We may use cookies to temporarily store information about a booking in progress as well as any error/confirmation messages whilst submitting or managing your events and locations.', 'events-manager' );
28
-
29
- wp_add_privacy_policy_content(
30
- __('Events Manager', 'events-manager'),
31
- wp_kses_post( '<p>'. implode('</p><p>', $content) .'</p>' )
32
- );
33
- }
34
-
35
- public static function register_eraser( $erasers ) {
36
- if( get_option('dbem_data_privacy_erase_bookings') ){
37
- $erasers['events-manager-bookings'] = array(
38
- 'eraser_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Bookings', 'events-manager'),
39
- 'callback' => 'EM_Data_Privacy::erase_bookings',
40
- );
41
- }
42
- if( get_option('dbem_data_privacy_erase_events') ){
43
- $erasers['events-manager-recurring-events'] = array(
44
- 'eraser_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Recurring Events', 'events-manager'),
45
- 'callback' => 'EM_Data_Privacy::erase_recurring_events',
46
- );
47
- $erasers['events-manager-events'] = array(
48
- 'eraser_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Events', 'events-manager'),
49
- 'callback' => 'EM_Data_Privacy::erase_events',
50
- );
51
- }
52
- if( get_option('dbem_data_privacy_erase_locations') ){
53
- $erasers['events-manager-locations'] = array(
54
- 'eraser_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Locations', 'events-manager'),
55
- 'callback' => 'EM_Data_Privacy::erase_locations',
56
- );
57
- }
58
- //in this case we don't register location deletion because we only need to handle anonymous events, locations submitted anonymously shouldn't have any personal data associated with it (unless a user submitted their home address anonymously!)
59
- return $erasers;
60
- }
61
-
62
- public static function erase_bookings( $email_address, $page = 1 ) {
63
- $page = (int) $page;
64
- $limit = apply_filters('em_data_privacy_export_limit', 100);
65
- $messages = array();
66
- $user = get_user_by('email', $email_address); //is user or no-user?
67
-
68
- if( $user !== false && get_option('dbem_data_privacy_erase_bookings') == 2 ){
69
- //we're only deleting anonymous bookings, and letting WP handle user/booking deletion the traditional way for registered accounts
70
- $done = true;
71
- }else{
72
- //get items to erase
73
- $booking_ids = self::get_bookings($email_address, $page);
74
-
75
- $items_removed = $items_retained = false;
76
- foreach ( $booking_ids as $booking_id ) {
77
- $EM_Booking = em_get_booking($booking_id);
78
- if( $EM_Booking->delete() ){
79
- $items_removed = true;
80
- }else{
81
- $items_retained = true;
82
- $messages = array_merge($messages, $EM_Booking->get_errors());
83
- }
84
- }
85
- if( $items_removed ) add_action('em_data_privacy_bookings_deleted', $booking_ids);
86
-
87
- // Tell core if we have more comments to work on still
88
- $done = count( $booking_ids ) < $limit;
89
- }
90
- return array(
91
- 'items_removed' => $items_removed,
92
- 'items_retained' => $items_retained, // always false in this example
93
- 'messages' => $messages, // no messages in this example
94
- 'done' => $done,
95
- );
96
- }
97
-
98
- public static function erase_recurring_events( $email_address, $page = 1 ) {
99
- return self::erase_events( $email_address, $page, 'event-recurring');
100
- }
101
-
102
- public static function erase_events( $email_address, $page = 1, $post_type = false ) {
103
- $user = get_user_by('email', $email_address); //is user or no-user?
104
- if( !$post_type ) $post_type = EM_POST_TYPE_EVENT; //default to event
105
- $page = (int) $page;
106
- $limit = apply_filters('em_data_privacy_erase_limit', 100);
107
- $items_removed = $items_retained = false;
108
- $messages = array();
109
-
110
- if( $user !== false && get_option('dbem_data_privacy_erase_events') == 2 ){
111
- //we're only deleting anonymous events, and letting WP handle CPT deletion the traditional way for registered accounts
112
- $done = true;
113
- }else{
114
- //get event IDs submitted by user or "anonymously" by email
115
- $events = self::get_cpts($email_address, $page, $post_type);
116
-
117
- foreach( $events as $post_id ){
118
- $EM_Event = em_get_event($post_id, 'post_id');
119
- //erase the location first
120
- $EM_Location = $EM_Event->get_location();
121
- if( $EM_Location->location_id && get_option('dbem_data_privacy_erase_locations', 2) ){
122
- //prior to 5.9.3 locations submitted alongside anonymous events didn't store email info, so for older locations we can only assume if the location is guest submitted and only linked to this one event
123
- $user_probably_owns_location = $user === false && empty($EM_Location->owner_email) && $EM_Location->location_owner == get_option('dbem_events_anonymous_user');
124
- if( $user_probably_owns_location ){
125
- //depending on settings delete location only if it has no other events (eventually if we're deleting the last event of this user with the same location, it'll only have one event)
126
- if( get_option('dbem_data_privacy_erase_locations', 2) == 1 || EM_Events::count(array('location_id' => $EM_Location->location_id, 'status' => 'all')) <= 1 ){
127
- if( $EM_Location->delete(true) ){
128
- $items_removed = true;
129
- }else{
130
- $items_retained = true;
131
- }
132
- }
133
- }
134
- }
135
- //now erase the event
136
- if( $EM_Event->delete(true) ){
137
- $items_removed = true;
138
- }else{
139
- $items_retained = true;
140
- $messages = array_merge($messages, $EM_Event->get_errors());
141
- }
142
- }
143
- // Tell core if we have more comments to work on still
144
- $done = count( $events ) < $limit;
145
- }
146
- return array(
147
- 'items_removed' => $items_removed,
148
- 'items_retained' => $items_retained, // always false in this example
149
- 'messages' => $messages, // no messages in this example
150
- 'done' => $done,
151
- );
152
- }
153
-
154
- public static function erase_locations( $email_address, $page = 1 ) {
155
- $page = (int) $page;
156
- $limit = apply_filters('em_data_privacy_erase_limit', 100);
157
- $items_removed = $items_retained = false;
158
- $messages = array();
159
-
160
- $locations_count = 0;
161
- $locations = self::get_cpts($email_address, $page, EM_POST_TYPE_LOCATION);
162
- foreach( $locations as $post_id ){
163
- $EM_Location = em_get_location( $post_id, 'post_id' ); /* @var EM_Location $EM_Location */
164
- if( $EM_Location->delete(true) ){
165
- $items_removed = true;
166
- }else{
167
- $items_retained = true;
168
- $messages = array_merge($messages, $EM_Location->get_errors());
169
- }
170
- $locations_count++;
171
- }
172
- // Tell core if we have more comments to work on still
173
- $done = $locations_count < $limit;
174
- return array(
175
- 'items_removed' => $items_removed,
176
- 'items_retained' => $items_retained, // always false in this example
177
- 'messages' => $messages, // no messages in this example
178
- 'done' => $done,
179
- );
180
- }
181
-
182
- public static function register_exporter( $exporters ) {
183
- $exporters['events-manager-user'] = array(
184
- 'exporter_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' .__( 'Further Information', 'events-manager' ),
185
- 'callback' => 'EM_Data_Privacy::export_user',
186
- );
187
- if( get_option('dbem_data_privacy_export_bookings') ){
188
- $exporters['events-manager-bookings'] = array(
189
- 'exporter_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Bookings', 'events-manager'),
190
- 'callback' => 'EM_Data_Privacy::export_bookings',
191
- );
192
- }
193
- if( get_option('dbem_data_privacy_export_events') ){
194
- $exporters['events-manager-recurring-events'] = array(
195
- 'exporter_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Recurring Events', 'events-manager'),
196
- 'callback' => 'EM_Data_Privacy::export_recurring_events',
197
- );
198
- $exporters['events-manager-events'] = array(
199
- 'exporter_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Events', 'events-manager'),
200
- 'callback' => 'EM_Data_Privacy::export_events',
201
- );
202
- }
203
- if( get_option('dbem_data_privacy_export_locations') ){
204
- $exporters['events-manager-locations'] = array(
205
- 'exporter_friendly_name' => __( 'Events Manager', 'events-manager' ) . ' - ' . __('Locations', 'events-manager'),
206
- 'callback' => 'EM_Data_Privacy::export_locations',
207
- );
208
- }
209
- return $exporters;
210
- }
211
-
212
- public static function export_cleanup(){
213
- delete_post_meta( absint($_REQUEST['id']), '_em_locations_exported');
214
- delete_post_meta( absint($_REQUEST['id']), '_em_bookings_exported' );
215
- }
216
-
217
- public static function export_user( $email_address ){
218
- $user = get_user_by('email', $email_address); //is user or no-user?
219
- $export_items = array();
220
- if( $user !== false ){
221
- //we add to the WP User section
222
- $data_to_export[] = array(
223
- 'group_id' => 'user',
224
- 'group_label' => __( 'User' ),
225
- 'item_id' => "user-{$user->ID}",
226
- 'data' => array(),
227
- );
228
- $dbem_phone = get_user_meta($user->ID, 'dbem_phone', true);
229
- if( !empty($dbem_phone) ){
230
- $export_item['data'][] = array( 'name' => __('Phone', 'events-manager'), 'value' => $dbem_phone );
231
- }
232
- $export_item = apply_filters('em_data_privacy_export_user', $export_item, $user);
233
- if( !empty($export_item['data']) ){
234
- $export_items[] = $export_item;
235
- }
236
- }
237
- return array(
238
- 'data' => $export_items,
239
- 'done' => true,
240
- );
241
- }
242
-
243
- public static function export_bookings( $email_address, $page = 1 ) {
244
- $page = (int) $page;
245
- $limit = apply_filters('em_data_privacy_export_limit', 100);
246
-
247
- $export_items = array();
248
- $items_count = 0;
249
-
250
- //check if we're only exporting bookings to those who made anonymous bookings
251
- $user = get_user_by('email', $email_address); //is user or no-user?
252
- if( $user !== false && get_option('dbem_data_privacy_export_bookings') == 2 ) return array( 'data' => $export_items, 'done' => true ); //return if user is registered and we're only exporting anon bookings
253
-
254
- $bookings = self::get_bookings($email_address, $page);
255
-
256
- $booking_export_default = array(
257
- 'group_id' => 'events-manager-bookings',
258
- 'group_label' => __('Bookings', 'events-manager'),
259
- 'item_id' => 'booking-ID', //replace ID with booking ID
260
- 'data' => array() // replace this with assoc array of name/value key arrays
261
- );
262
- $booking_price_adjustments = array(
263
- 'discounts_pre_tax' => __('Discounts Before Taxes','events-manager'),
264
- 'surcharges_pre_tax' => __('Surcharges Before Taxes','events-manager'),
265
- 'discounts_post_tax' => __('Discounts (After Taxes)','events-manager'),
266
- 'surcharges_post_tax' => __('Surcharges (After Taxes)','events-manager')
267
- );
268
-
269
- foreach ( $bookings as $booking_id ) {
270
- $EM_Booking = em_get_booking($booking_id);
271
- $export_item = $booking_export_default;
272
- $export_item['item_id'] = 'booking-'.$EM_Booking->booking_id;
273
- $export_item['data']['status'] = array('name' => __('Status','events-manager'), 'value' => $EM_Booking->get_status() );
274
- $export_item['data']['date'] = array('name' => __('Date','events-manager'), 'value' => $EM_Booking->date()->getDateTime() . ' ' . $EM_Booking->date()->getTimezone()->getName() );
275
- $export_item['data']['event'] = array('name' => __('Event','events-manager'), 'value' => $EM_Booking->get_event()->output('#_EVENTLINK - #_EVENTDATES @ #_EVENTTIMES') );
276
- if( $EM_Booking->person_id == 0 ){
277
- foreach( $EM_Booking->get_person()->get_summary() as $key => $info ){
278
- $export_item['data']['field-'.$key] = $info;
279
- }
280
- }
281
- $booking_tickets = array();
282
- foreach($EM_Booking->get_tickets_bookings()->tickets_bookings as $EM_Ticket_Booking){ /* @var EM_Ticket_Booking $EM_Ticket_Booking */
283
- $booking_tickets[] = $EM_Ticket_Booking->get_ticket()->ticket_name . ' x '. $EM_Ticket_Booking->get_spaces() . ' @ ' . $EM_Ticket_Booking->get_price(true);
284
- }
285
- $export_item['data']['tickets'] = array('name' => __('Tickets', 'events-manager-pro'), 'value' => implode('<br>', $booking_tickets));
286
- $export_item['data']['sub-total'] = array('name' => __('Sub Total','events-manager'), 'value' => $EM_Booking->get_price_base(true));
287
- $price_summary = $EM_Booking->get_price_summary_array();
288
- foreach( $booking_price_adjustments as $adjustment_key => $adjustment_title ){
289
- if( count($price_summary[$adjustment_key]) > 0 ){
290
- $adjustments = array();
291
- foreach( $price_summary[$adjustment_key] as $adjustment ){
292
- $adjustments[] = "{$adjustment['name']} @ {$adjustment['amount']}";
293
- }
294
- $export_item['data'][$adjustment_key] = array('name' => $adjustment_title, 'value' => implode('<br>', $adjustments));
295
- }
296
- }
297
- if( !empty($price_summary['taxes']['amount']) ){
298
- $export_item['data']['taxes'] = array('name' => __('Taxes','events-manager'), 'value' => "({$price_summary['taxes']['rate']}) {$price_summary['taxes']['amount']}");
299
- }
300
- $export_item['data']['total'] = array('name' => __('Total Price','events-manager'), 'value' => $price_summary['total']);
301
- //booking notes - can be exempt with a filter since maybe notes have private info
302
- if( apply_filters('em_data_privacy_export_bookings_include_notes', true, $EM_Booking) ){
303
- $booking_notes = $EM_Booking->get_notes();
304
- if( !empty($booking_notes) ){
305
- $booking_notes_data = array();
306
- foreach( $booking_notes as $booking_note ){
307
- $booking_notes_data[] = date(get_option('date_format'), $booking_note['timestamp']) .' - '. $booking_note['note'];
308
- }
309
- $export_item['data']['notes'] = array('name' => __( 'Booking Notes', 'events-manager'), 'value' => implode('<br><br>', $booking_notes_data));
310
- }
311
- }
312
- $export_item = apply_filters('em_data_privacy_export_bookings_item', $export_item, $EM_Booking);
313
- $export_items[] = $export_item;
314
- $export_items = apply_filters('em_data_privacy_export_bookings_items_after_item', $export_items, $export_item, $EM_Booking); //could be used for cross-referencing and add-ing other groups e.g. Multiple Bookings in Pro
315
- $items_count++;
316
- if( $items_count == $limit ) break;
317
- }
318
-
319
- $done = $items_count < $limit; //if we didn't reach limit of bookings then we must be done
320
- return array(
321
- 'data' => $export_items,
322
- 'done' => $done,
323
- );
324
- }
325
-
326
- public static function export_recurring_events( $email_address, $page = 1){
327
- return self::export_events( $email_address, $page, 'event-recurring' );
328
- }
329
-
330
- public static function export_events( $email_address, $page = 1, $post_type = false ) {
331
- if( !$post_type ) $post_type = EM_POST_TYPE_EVENT; //default to event
332
- $page = (int) $page;
333
- $limit = apply_filters('em_data_privacy_export_limit', 100);
334
- $user = get_user_by('email', $email_address); //is user or no-user?
335
- $export_items = array();
336
- $items_count = 0;
337
-
338
- //check if we're only exporting events to those who submitted anonymously
339
- if( $user !== false && get_option('dbem_data_privacy_export_events') == 2 ) return array( 'data' => $export_items, 'done' => true ); //return if user is registered and we're only exporting anon events
340
-
341
- //prepare some location stuff for use within events
342
- $locations_export_default = array(
343
- 'group_id' => 'events-manager-'.EM_POST_TYPE_LOCATION,
344
- 'group_label' => __('Locations', 'events-manager'),
345
- 'item_id' => 'location-post-ID', //replace ID with booking ID
346
- 'data' => array() // replace this with assoc array of name/value key arrays
347
- );
348
- $locations_exported = get_post_meta( absint($_REQUEST['id']), '_em_locations_exported', true);
349
- if( empty($locations_exported) ) $locations_exported = array();
350
-
351
- //EVENTS
352
- $event_export_default = array(
353
- 'group_id' => 'events-manager-'.$post_type,
354
- 'item_id' => 'event-post-ID', //replace ID with booking ID
355
- 'data' => array() // replace this with assoc array of name/value key arrays
356
- );
357
- $event_export_default['group_label'] = $post_type == 'event-recurring' ? __('Recurring Events', 'events-manager'):__('Events', 'events-manager');
358
-
359
- //get event IDs submitted by user or "anonymously" by email
360
- $events = self::get_cpts($email_address, $page, $post_type);
361
-
362
- foreach( $events as $post_id ){
363
- $EM_Event = em_get_event($post_id, 'post_id');
364
- $export_item = $event_export_default;
365
- $export_item['item_id'] = 'event-post-'.$EM_Event->post_id;
366
- $export_item['data'][] = array('name' => __('Event Name','events-manager'), 'value' => $EM_Event->event_name );
367
- $export_item['data'][] = array('name' => sprintf(__('%s Status','events-manager'), __('Event','events-manager')), 'value' => $EM_Event->post_status );
368
- if( $post_type == EM_POST_TYPE_EVENT && $EM_Event->event_status == 1 ){
369
- $export_item['data'][] = array('name' => sprintf(__('%s URL','events-manager'), __('Event','events-manager')), 'value' => $EM_Event->get_permalink() );
370
- }
371
- if( $post_type == 'event-recurring' ){
372
- $export_item['data'][] = array('name' => __('When','events-manager'), 'value' => $EM_Event->output('#_EVENTDATES @ #_EVENTTIMES').'<br>'.$EM_Event->get_recurrence_description() );
373
- }else{
374
- $export_item['data'][] = array('name' => __('When','events-manager'), 'value' => $EM_Event->output('#_EVENTDATES @ #_EVENTTIMES') );
375
- }
376
- $export_item['data'][] = array('name' => __('Timezone','events-manager'), 'value' => $EM_Event->start()->getTimezone()->getName() );
377
- if( !empty($EM_Event->event_owner_name) ) $export_item['data'][] = array('name' => __('Name','events-manager'), 'value' => $EM_Event->event_owner_name );
378
- if( $EM_Event->get_location()->location_id ){
379
- $EM_Location = $EM_Event->get_location();
380
- $export_item['data'][] = array('name' => __('Location','events-manager'), 'value' => $EM_Location->location_name . ', '. $EM_Location->get_full_address() .', '. $EM_Location->location_country);
381
- //put this location as a new export item
382
- $already_exported = in_array($EM_Location->location_id, $locations_exported);
383
- $user_probably_owns_location = $user === false && empty($EM_Location->owner_email) && $EM_Location->location_owner == get_option('dbem_events_anonymous_user');
384
- $user_submitted_location = $user === false && $EM_Location->owner_email == $email_address;
385
- $user_owns_location = $user !== false && $EM_Location->location_owner == $user->ID;
386
- if( !$already_exported && ($user_owns_location || $user_submitted_location || $user_probably_owns_location) ){
387
- $location_export_item = $locations_export_default;
388
- $location_export_item['item_id'] = 'location-post-'.$EM_Location->post_id;
389
- $location_export_item['data'][] = array('name' => __('Name','events-manager'), 'value' => $EM_Location->location_name );
390
- $location_export_item['data'][] = array('name' => __('Address','events-manager'), 'value' => $EM_Location->get_full_address() .', '. $EM_Location->location_country );
391
- $location_export_item['data'][] = array('name' => __('Coordinates','events-manager'), 'value' => $EM_Location->location_latitude .', '. $EM_Location->location_longitude );
392
- $location_export_item['data'][] = array('name' => sprintf(__('%s Status','events-manager'), __('Location','events-manager')), 'value' => $EM_Location->post_status );
393
- if( $EM_Location->post_status == 'publish' ){
394
- $location_export_item['data'][] = array('name' => sprintf(__('%s URL','events-manager'), __('Location','events-manager')), 'value' => $EM_Location->get_permalink() );
395
- }
396
- foreach( $EM_Location->location_attributes as $k => $v ){
397
- $location_export_item['data'][] = array('name' => $k, 'value' => $v);
398
- }
399
- $location_export_item = apply_filters('em_data_privacy_export_locations_item', $location_export_item, $EM_Location);
400
- $export_items[] = $location_export_item;
401
- $export_items = apply_filters('em_data_privacy_export_locations_items_after_item', $export_items, $location_export_item, $EM_Location); //could be used for cross-referencing and add-ing other groups e.g. Multiple Bookings in Pro
402
- $items_count++;
403
- $locations_exported[] = $EM_Location->location_id;
404
- }
405
- }
406
- if( $EM_Event->event_rsvp ){
407
- $tickets = array();
408
- foreach( $EM_Event->get_tickets() as $EM_Ticket ){ /* @var EM_Ticket $EM_Ticket */
409
- $ticket = array($EM_Ticket->ticket_name, $EM_Ticket->ticket_description, $EM_Ticket->get_price(true));
410
- if( empty($EM_Ticket->ticket_description) ) unset($ticket[1]);
411
- $tickets[] = implode( ' - ', $ticket);
412
- }
413
- $export_item['data'][] = array('name' => __('Tickets','events-manager'), 'value' => implode('<br>', $tickets) );
414
- }
415
- foreach( $EM_Event->event_attributes as $k => $v ){
416
- $export_item['data'][] = array('name' => $k, 'value' => $v);
417
- }
418
- $export_item = apply_filters('em_data_privacy_export_events_item', $export_item, $EM_Event);
419
- $export_items[] = $export_item;
420
- $export_items = apply_filters('em_data_privacy_export_events_items_after_item', $export_items, $export_item, $EM_Event); //could be used for cross-referencing and add-ing other groups e.g. Multiple Bookings in Pro
421
- $items_count++;
422
- if( $items_count >= $limit ) break;
423
- }
424
-
425
- $done = $items_count < $limit; //if we didn't reach limit of bookings then we must be done
426
- update_post_meta( absint($_REQUEST['id']), '_em_locations_exported', $locations_exported);
427
- return array(
428
- 'data' => $export_items,
429
- 'done' => $done,
430
- );
431
- }
432
-
433
- public static function export_locations( $email_address, $page = 1 ) {
434
- $page = (int) $page;
435
- $limit = apply_filters('em_data_privacy_export_limit', 100);
436
- $offset = ($page -1) * $limit;
437
- $user = get_user_by('email', $email_address); //is user or no-user?
438
- $export_items = array();
439
- $items_count = 0;
440
-
441
- $locations_export_default = array(
442
- 'group_id' => 'events-manager-'.EM_POST_TYPE_LOCATION,
443
- 'group_label' => __('Locations', 'events-manager'),
444
- 'item_id' => 'location-post-ID', //replace ID with booking ID
445
- 'data' => array() // replace this with assoc array of name/value key arrays
446
- );
447
-
448
- //Locations - previous to 5.9.4 locations submitted anonymously did nint include
449
- $locations_exported = get_post_meta( absint($_REQUEST['id']), '_em_locations_exported', true );
450
- if( empty($locations_exported) ) $locations_exported = array();
451
-
452
- $locations = self::get_cpts($email_address, $page, EM_POST_TYPE_LOCATION);
453
- foreach( $locations as $post_id ){
454
- $EM_Location = em_get_location( $post_id, 'post_id' ); /* @var EM_Location $EM_Location */
455
- if( !in_array($EM_Location->location_id, $locations_exported) ){
456
- $location_export_item = $locations_export_default;
457
- $location_export_item['item_id'] = 'event-post-'.$EM_Location->post_id;
458
- $location_export_item['data'][] = array('name' => __('Name','events-manager'), 'value' => $EM_Location->location_name );
459
- $location_export_item['data'][] = array('name' => sprintf(__('%s Status','events-manager'), __('Location','events-manager')), 'value' => $EM_Location->post_status );
460
- if( $EM_Location->post_status == 'publish' ){
461
- $location_export_item['data'][] = array('name' => sprintf(__('%s URL','events-manager'), __('Location','events-manager')), 'value' => $EM_Location->get_permalink() );
462
- }
463
- $location_export_item['data'][] = array('name' => __('Address','events-manager'), 'value' => $EM_Location->get_full_address() .', '. $EM_Location->location_country );
464
- $location_export_item['data'][] = array('name' => __('Coordinates','events-manager'), 'value' => $EM_Location->location_latitude .', '. $EM_Location->location_longitude );
465
- foreach( $EM_Location->location_attributes as $k => $v ){
466
- $location_export_item['data'][] = array('name' => $k, 'value' => $v);
467
- }
468
- $location_export_item = apply_filters('em_data_privacy_export_locations_item', $location_export_item, $EM_Location);
469
- $export_items[] = $location_export_item;
470
- $export_items = apply_filters('em_data_privacy_export_locations_items_after_item', $export_items, $location_export_item, $EM_Location); //could be used for cross-referencing and add-ing other groups e.g. Multiple Bookings in Pro
471
- $locations_exported[] = $EM_Location->location_id;
472
- $items_count++;
473
- if( $items_count == $limit ) break;
474
- }
475
- }
476
- update_post_meta( absint($_REQUEST['id']), '_em_locations_exported', $locations_exported );
477
- $done = $items_count < $limit; //if we didn't reach limit of bookings then we must be done
478
- return array(
479
- 'data' => $export_items,
480
- 'done' => $done,
481
- );
482
- }
483
-
484
- public static function get_cpts($email_address, $page, $post_type ){
485
- global $wpdb;
486
- $page = (int) $page;
487
- $limit = apply_filters('em_data_privacy_export_limit', 100);
488
- $offset = ($page -1) * $limit;
489
- $user = get_user_by('email', $email_address); //is user or no-user?
490
- $anon_email_key = $post_type == EM_POST_TYPE_LOCATION ? '_owner_email':'_event_owner_email';
491
- //get event IDs submitted by user or "anonymously" by email
492
- $events = array();
493
- if( $user !== false ){
494
- $sql = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_author = %d AND post_type = %s LIMIT %d OFFSET %d", $user->ID, $post_type, $limit, $offset);
495
- $events = $wpdb->get_col($sql);
496
- }
497
- //if user ever submitted anonymous events with same email, we also process these
498
- $sql = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE ID IN (SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key=%s AND meta_value=%s) AND post_type = %s LIMIT %d OFFSET %d", $anon_email_key, $email_address, $post_type, $limit, $offset);
499
- $events = array_merge($events, $wpdb->get_col($sql));
500
- return $events;
501
- }
502
-
503
- public static function get_bookings( $email_address, $page ){
504
- global $wpdb;
505
- $page = (int) $page;
506
- $limit = apply_filters('em_data_privacy_export_limit', 100);
507
- $offset = ($page -1) * $limit;
508
- $user = get_user_by('email', $email_address); //is user or no-user?
509
-
510
- $conditions = array();
511
- if( $user !== false ){
512
- $conditions[] = $wpdb->prepare('person_id = %d', $user->ID);
513
- }
514
- $conditions[] = $wpdb->prepare('person_id=0 AND booking_meta LIKE %s', "%\"user_email\";s:".strlen($email_address).":\"$email_address\"%"); //find any booking that may have their email, anonymous or previous email address.
515
- $bookings = $wpdb->get_col('SELECT booking_id FROM '.EM_BOOKINGS_TABLE.' WHERE '. implode(' OR ', $conditions) .' LIMIT '.$limit . ' OFFSET '.$offset);
516
-
517
- return $bookings;
518
-
519
- }
520
- }
521
- EM_Data_Privacy::init();
522
- /*
523
- add_action('admin_init', function(){
524
- $data = EM_Data_Privacy::exporter('subscriber@netweblogic.com');
525
- echo "<table>";
526
- foreach( $data['data'] as $items ){
527
- foreach($items['data'] as $item) echo "<tr><th>{$item['name']}</th><td>{$item['value']}</td>";
528
- }
529
- echo "</table>";
530
- die();
531
- }); //*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-docs.php DELETED
@@ -1,464 +0,0 @@
1
- <?php
2
-
3
- function em_docs_init($force_init = false){
4
- global $pagenow;
5
- if( ($pagenow == 'edit.php' && !empty($_GET['page']) && $_GET['page']=='events-manager-help' && class_exists('EM_Event')) || $force_init){
6
- add_action('wp_head', 'emd_head');
7
- //Generate the docs
8
- global $EM_Documentation;
9
- $EM_Documentation = array(
10
- 'arguments' => array(
11
- 'events' => array(
12
- 'blog' => array( 'desc' => sprintf('Limit search to %s created in a specific blog id (MultiSite only)','events')),
13
- 'bookings' => array( 'desc'=> 'Include only events with bookings enabled. Use \'user\' to show events a logged in user has booked.'.'1 = yes, 0 = no'),
14
- 'category' => array( 'desc'=> str_replace('%s','categories', 'Supply a single id, slug or comma-separated ids or slugs (e.g. "1,%s-slug,3") to limit the search to events in any of these %s. You can also use negative numbers and slugs to exclude specific %s (e.g. -1,-exclude-%s,-3). If you mix inclusions and exclusions, all events with included %s AND without excluded %s will be shown. You can also use &amp; to separate ids and slugs, in which case events must contain (or not contain) both %s to be shown.'), 'default'=>0),
15
- 'event' => array( 'desc'=> sprintf('Supply a single id or comma-separated ids (e.g. "1,2,3") to limit the search to %s with the %s.','events', 'event_id(s)'), 'default'=>0),
16
- 'group' => array( 'desc' => 'Limit search to events belonging to a specific group id (BuddyPress only). Using \'my\' will show events belonging to groups the logged in user is a member of.'),
17
- 'near' => array('desc'=>'Accepts a comma-separated coordinates (e.g. 1,1) value, which searches for events or locations located near this coordinate.'),
18
- 'near_unit' => array('desc'=>'The distance unit used when a near attribute is provided.', 'default'=>'mi', 'args'=>'mi or km'),
19
- 'near_distance' => array('desc'=>'The radius distance when searching with the near attribute. near_unit will determine whether this is in miles or kilometers.'),
20
- 'owner' => array('desc'=> 'Limits returned results to a specific owner, identified by their user id (e.g. list events or locations owned by user)', 'default'=>0),
21
- 'post_id' => array( 'desc' => sprintf('Supply a single id or comma-separated ids (e.g. "1,2,3") to limit the search to %s with the %s.','events', 'post_id(s)')),
22
- 'private' => array( 'desc' => sprintf('Display private %s within your list?','events'), 'args' => '1 = yes, 0 = no', 'default' => 'If user can view private events, 1, otherwise 0.'),
23
- 'private_only' => array( 'desc' =>sprintf('Display only private %s ?','events'), 'args' => '1 = yes, 0 = no', 'default' => '0'),
24
- 'recurrences' => array( 'desc'=> 'Show only recurrences if set to 1 or non-recurrences if set to 0, shows all events if not used.'),
25
- 'recurrence' => array( 'desc'=> 'If set to the event id of the recurring event, this will show only events this event recurrences.', 'default'=>0),
26
- 'recurring' => array( 'desc'=> 'If set to 1, will only show recurring event templates. Only useful if you know what you\'re doing, use recurrence or recurrences if you want to filter event recurrences.', 'default'=>0),
27
- 'scope' => array( 'desc'=> 'Choose the time frame of events to show. Additionally you can supply dates (in format of YYYY-MM-DD), either single for events on a specific date or two dates separated by a comma (e.g. 2010-12-25,2010-12-31) for events ocurring between these dates.', 'default'=>'future', 'args'=>array("future", "past", "today", "tomorrow", "month", "next-month", "1-months", "2-months", "3-months", "6-months", "12-months","all")),
28
- 'search' => array( 'desc'=> 'Do a search for this string within event name, details and location address.' ),
29
- 'status' => array( 'desc' => sprintf('Limit search to %s with a spefic status (1 is active, 0 is pending approval)','events'), 'default'=>1),
30
- 'tag' => array( 'desc'=> str_replace('%s', 'tags', 'Supply a single id, slug or comma-separated ids or slugs (e.g. "1,%s-slug,3") to limit the search to events in any of these %s. You can also use negative numbers and slugs to exclude specific %s (e.g. -1,-exclude-%s,-3). If you mix inclusions and exclusions, all events with included %s AND without excluded %s will be shown. You can also use &amp; to separate ids and slugs, in which case events must contain (or not contain) both %s to be shown.'), 'default'=>0),
31
- 'year' => array( 'desc'=> 'If set to a year (e.g. 2010) only events that start or end during this year/month will be returned. Does not work as intended if used with scope.', 'default'=>''),
32
- 'has_location' => array( 'desc'=> 'When set to true, only events WITH an assigned location will be shown, has priority over no_location.', 'default'=>''),
33
- 'no_location' => array( 'desc'=> 'When set to true, only events WITHOUT an assigned location will be shown.', 'default'=>''),
34
- 'groupby' => array( 'desc'=> 'Show one event for each unique value of the provide field name, along with events contaning no defined value for that field. See our <a href="http://wp-events-plugin.com/documentation/event-search-attributes/event-location-grouping-ordering/">grouping documentation</a> for more information.', 'default'=>0, 'args'=>'Database field name from the wp_em_events or wp_em_locations tables, e.g. <code>event_name</code> or <code>location_name</code>', 'since'=>'5.8'),
35
- 'groupby_orderby' => array( 'desc'=> 'When groupby is defined, the fields defined here will determine the sorting of events in each group. See our <a href="http://wp-events-plugin.com/documentation/event-search-attributes/event-location-grouping-ordering/">grouping documentation</a> for more information.', 'default'=>'event_start_date,event_start_time', 'args'=>'Database fields (comma-seperated) in the wp_em_events and wp_em_locations tables, e.g. <code>event_start_date,event_start_time</code> or <code>location_name</code>', 'since'=>'5.8'),
36
- 'groupby_order' => array( 'desc'=> 'Indicates the alphabeitcal/numerical/date order of the sorting in groupby_orderby. Choose between ASC (ascending) and DESC (descending), case insensitive.', 'default'=>'ASC', 'since'=>'5.8'),
37
- ),
38
- 'locations' => array(
39
- 'blog' => array( 'desc' => sprintf('Limit search to %s created in a specific blog id (MultiSite only)','locations')),
40
- 'country' => array( 'desc'=> sprintf('Search for %s in this %s (no partial matches, case sensitive).','locations','Country'), 'default' => 'none', 'args'=>'Use two-character country codes as defined in <a href="http://countrycode.org/">countrycode.org</a>, can be comma-separated e.g. US,GB,ES'),
41
- 'eventful' => array( 'desc'=> 'If set to 1 will only show locations that have at least one event occurring during the scope.', 'default' => 0),
42
- 'eventless' => array( 'desc'=> 'If set to 1 will only show locations that have no events occurring during the scope.', 'default' => 0),
43
- 'location' => array( 'desc'=> sprintf('Supply a single id or comma-separated ids (e.g. "1,2,3") to limit the search to %s with the %s.','locations', 'location_id(s)'), 'default'=>0),
44
- 'near' => array('desc'=>'Accepts a comma-separated coordinates (e.g. 1,1) value, which searches for events or locations located near this coordinate.'),
45
- 'near_unit' => array('desc'=>'The distance unit used when a near attribute is provided.', 'default'=>'mi', 'args'=>'mi or km'),
46
- 'near_distance' => array('desc'=>'The radius distance when searching with the near attribute. near_unit will determine whether this is in miles or kilometers.'),
47
- 'owner' => array('desc'=> 'Limits returned results to a specific owner, identified by their user id (e.g. list events or locations owned by user)', 'default'=>0),
48
- 'post_id' => array( 'desc' => sprintf('Supply a single id or comma-separated ids (e.g. "1,2,3") to limit the search to %s with the %s.','locations', 'post_id(s)')),
49
- 'postcode' => array( 'desc'=> sprintf('Search for %s in this %s (no partial matches, case sensitive).','locations','Postcode'), 'default' => 'none'),
50
- 'private' => array( 'desc' => sprintf('Display private %s within your list?','locations'), 'args' => '1 = yes, 0 = no', 'default' => 'If user can view private locations, 1, otherwise 0.'),
51
- 'private_only' => array( 'desc' =>sprintf('Display only private %s ?','locations'), 'args' => '1 = yes, 0 = no', 'default' => '0'),
52
- 'region' => array( 'desc'=> sprintf('Search for %s in this %s (no partial matches, case sensitive).','locations','Region'), 'default' => 'none'),
53
- 'scope' => array( 'default' => 'all'),
54
- 'state' => array( 'desc'=> sprintf('Search for %s in this %s (no partial matches, case sensitive).','locations','State'), 'default' => 'none'),
55
- 'status' => array( 'desc' => sprintf('Limit search to %s with a spefic status (1 is active, 0 is pending approval)','locations'), 'default'=>1),
56
- 'town' => array( 'desc'=> sprintf('Search for %s in this %s (no partial matches, case sensitive).','locations','Town'), 'default' => 'none'),
57
- 'groupby' => array( 'desc'=> 'Show one location for each unique value of the provide field name, along with locations contaning no defined value for that field. See our <a href="http://wp-events-plugin.com/documentation/event-search-attributes/event-location-grouping-ordering/">grouping documentation</a> for more information.', 'default'=>0, 'args'=>'Database field name from the wp_em_events or wp_em_locations tables, e.g. <code>event_name</code> or <code>location_name</code>', 'since'=>'5.8'),
58
- 'groupby_orderby' => array( 'desc'=> 'When groupby is defined, the fields defined here will determine the sorting of events in each group. See our <a href="http://wp-events-plugin.com/documentation/event-search-attributes/event-location-grouping-ordering/">grouping documentation</a> for more information.', 'default'=>'event_start_date,event_start_time', 'args'=>'Database fields (comma-seperated) in the wp_em_events and wp_em_locations tables, e.g. <code>location_country,location_town</code> or <code>location_name</code>', 'since'=>'5.8'),
59
- 'groupby_order' => array( 'desc'=> 'Indicates the alphabeitcal/numerical/date order of the sorting in groupby_orderby. Choose between ASC (ascending) and DESC (descending), case insensitive.', 'default'=>'ASC', 'since'=>'5.8'),
60
- ),
61
- 'categories' => array(
62
- '' => array( 'desc' => 'See the <a href="http://codex.wordpress.org/Function_Reference/get_terms">WordPress get_terms() Codex</a> for a list of possible search attributes/arguments.'),
63
- ),
64
- 'tags' => array(
65
- '' => array( 'desc' => 'See the <a href="http://codex.wordpress.org/Function_Reference/get_terms">WordPress get_terms() Codex</a> for a list of possible search attributes/arguments.'),
66
- ),
67
- 'calendar' => array(
68
- 'full' => array( 'desc'=> 'If set to 1 it will display a full calendar that shows event names.', 'default' => 0),
69
- 'long_events' => array( 'desc'=> 'If set to 1, will show events that last longer than a day.', 'default' => 0),
70
- ),
71
- //The object is commonly shared by all, so entries above overwrite entries here
72
- 'general' => array(
73
- 'array' => array( 'desc'=> 'If you supply this as an argument, the returned data will be in an array, not an object (only useful wen using PHP, not shortcodes)', 'default'=>0),
74
- 'format_header' => array( 'desc'=> sprintf('If you are displaying lists (e.g. listing events), you can supply the %s html and placeholders here.','header'), 'default'=> 'If the <em>format</em> attribute is not provided, the relevant default format will be taken from the settings page.'),
75
- 'format' => array( 'desc'=> 'If you are displaying some information with the shortcode or function (e.g. listing events), you can supply the html and placeholders here. When providing a custom format value, format_header and format_footer will be blank if not also provided.', 'default'=> 'The relevant default format will be taken from the settings page.'),
76
- 'format_footer' => array( 'desc'=> sprintf('If you are displaying lists (e.g. listing events), you can supply the %s html and placeholders here.','footer'), 'default'=> 'If the <em>format</em> attribute is not provided, the relevant default format will be taken from the settings page.'),
77
- 'limit' => array( 'desc'=> 'Limits the amount of values returned to this number.', 'default'=>'0 (no limit)'),
78
- 'offset' => array( 'desc'=> 'For example, if you have ten results, if you set this to 5, only the last 5 results will be returned. A limit higher than 0 is required for offsets to work.', 'default'=>0),
79
- 'order' => array( 'desc'=> 'Indicates the alphabeitcal/numerical order of the lists. Choose between ASC (ascending) and DESC (descending).', 'default'=>'ASC'),
80
- 'orderby' => array( 'desc'=> 'Choose what fields to order your results by. You can supply a single field or multiple comma-separated fields (e.g. "event_start_date,event_name").', 'default'=>0, 'args'=>'Database table fields, e.g. <code>event_name</code> or <code>location_name</code>'),
81
- 'pagination' => array('desc'=> 'When using a function or shortcode that outputs items (e.g. [events_list] for events, [locations_list] for locations), if the number of items supercede the limit of items to show, setting this to 1 will show page links under the list.', 'default'=>0),
82
- 'page' => array('desc' => 'Which page shall be shown. Requires pagination to be set to 1 and will override the offset value if also provided.'),
83
- 'page_queryvar' => array('desc'=>'The default parameter name used to figure out the page number to show is pno, provide a unique name if you want to display two lists on the same page with independent pagination.'),
84
- )
85
- ),
86
- 'placeholders' => array(
87
- 'events' => array(
88
- 'Event Details' => array(
89
- 'placeholders' => array(
90
- '#_EVENTID' => array( 'desc' => 'Shows the event ID number in the wp_em_events table.' ),
91
- '#_EVENTPOSTID' => array( 'desc' => 'Shows the event corresponding Post ID in the wp_posts table.' ),
92
- '#_EVENTNAME' => array( 'desc' => 'Displays the name of the event.' ),
93
- '#_EVENTNOTES' => array( 'desc' => 'Shows the description of the event.' ),
94
- '#_EVENTEXCERPT' => array( 'desc' => 'If an excerpt has been added to the event, it will be used. If you added a <a href="http://en.support.wordpress.com/splitting-content/more-tag/">more tag</a> to your event description, only the content before this tag will show.' ),
95
- '#_EVENTEXCERPT{words,...}' => array( 'desc' => 'If an excerpt has not been added to the event you can use this format <code>#_EVENTEXCERPT{10,...}</code>, where 10 is the number of words to show and ... is what is used at the cut-off point.' ),
96
- '#_EVENTEXCERPTCUT' => array( 'desc' => 'Same as <code>#_EVENTEXCERPT</code> (and also accepts the <code>{words,...}</code> arguments) but will also cut excerpts as well as post content. Default word limit is 55 and cut-off is <code>[...]</code>' ),
97
- '#_EVENTIMAGE' => array( 'desc' => 'Shows the event image, if available.' ),
98
- '#_EVENTIMAGE{x,y}' => array( 'desc' => 'Shows the event image thumbnail, x and y are width and height respectively, both being numbers e.g. <code>#_EVENTIMAGE{100,100}</code>. If 0 is used for either width or height, the corresponding dimension will be proportionally sized' ),
99
- '#_EVENTCATEGORIES' => array( 'desc' => 'Shows a list of category links this event belongs to.' ),
100
- '#_EVENTCATEGORIESIMAGES' => array( 'desc' => 'Shows a list of category images this event belongs to. Categories without an image will be ignored.' ),
101
- '#_EVENTTAGS' => array( 'desc' => 'Shows a list of tag links this event belongs to.' ),
102
- '#_EVENTLOCATION' => array( 'desc' => 'Displays information about the event location, which is different from a physical location. <a href="https://wp-events-plugin.com/documentation/location-types/">See our documentation for more information</a>, as each location type may display different information and will have different additional placeholders.' ),
103
- '#_RECURRINGDATERANGE' => array( 'desc' => 'Range of dates between the start/end of the recurring event pattern for an event recurrence, blank for non-recurrences.' ),
104
- '#_RECURRINGPATTERN' => array( 'desc' => 'Describes the pattern of a recurring event when used on an event recurrence, blank for non-recurrences.' ),
105
- '#_RECURRINGID' => array( 'desc' => 'The event ID of the recurring event template when displayed on a recurrence, blank for non-recurrences.' ),
106
- )
107
- ),
108
- 'Date and Times' => array(
109
- 'desc' => 'These are shortcut placeholders for pre-formatted dates and times. See the Custom Date/Time Formatting section below for more refined formatting placeholders.',
110
- 'placeholders' => array(
111
- '#_24HSTARTTIME' => array( 'desc' => 'Displays the start time in a 24 hours format (e.g. 16:30).' ),
112
- '#_24HENDTIME' => array( 'desc' => 'Displays the end time in a 24 hours format (e.g. 18:30).' ),
113
- '#_12HSTARTTIME' => array( 'desc' => 'Displays the start time in a 12 hours format (e.g. 4:30 PM).' ),
114
- '#_12HENDTIME' => array( 'desc' => 'Displays the end time in a 12 hours format (e.g. 6:30 PM).' ),
115
- '#_EVENTTIMES' => array( 'desc' => 'Displays either a single time, time-span, or "All Day" depending on your event times. Format is taken from your Events Manager settings page.' ),
116
- '#_EVENTDATES' => array( 'desc' => 'Displays either a single date or a date range depending on your event dates. Format is taken from your Events Manager settings page.' ),
117
- )
118
- ),
119
- 'Custom Date/Time Formatting' => array(
120
- 'desc' => 'Events Manager allows extremely flexible date formatting by using <a href="http://www.php.net/manual/en/function.date.php">PHP date syntax format characters</a> along with placeholders.',
121
- 'placeholders' => array(
122
- '# or #@' => array( 'desc' => 'Prepend <code>#</code> or <code>#@</code> before a valid PHP date syntax format character to show start and end date/time information respectively (e.g. <code>#F</code> will show the starting month name like "January", #@h shows the end hour).' ),
123
- '#_{x} or #@_{x}' => array( 'desc' => 'You can also create a date format without prepending # to each character by wrapping a valid php date() format in <code>#_{}</code> or <code>#@_{}</code> (e.g. <code>#_{d/m/Y}</code>). If there is no end date (or is same as start date), the value is not shown. This is useful if you want to show event end dates only on events that are longer than one day, e.g. <code>#j #M #Y #@_{ \u\n\t\i\l j M Y}</code>.' ),
124
- )
125
- ),
126
- 'WordPress-relative Timezone Date/Time Placeholders' => array(
127
- 'desc' => 'These placeholders are extensions of the default Date/Time placholders, but instead will display the time of the event relative to your WordPress timezone rather than the local time of the event itself. Your WordPress site timezone is found in your <em><strong>Dashboard > Settings > General</strong></em> settings page.',
128
- 'placeholders' => array(
129
- '#_24HSTARTTIME_SITE' => array( 'desc' => 'Sames as <code>#_24HSTARTTIME</code> but displays time relative to your site timezone.' ),
130
- '#_24HENDTIME_SITE' => array( 'desc' => 'Sames as <code>#_24HENDTIME</code> but displays time relative to your site timezone.' ),
131
- '#_12HSTARTTIME_SITE' => array( 'desc' => 'Sames as <code>#_12HSTARTTIME</code> but displays time relative to your site timezone.' ),
132
- '#_12HENDTIME_SITE' => array( 'desc' => 'Sames as <code>#_12HENDTIME</code> but displays time relative to your site timezone.' ),
133
- '#_EVENTTIMES_SITE' => array( 'desc' => 'Sames as <code>#_EVENTTIMES</code> but displays times relative to your site timezone.' ),
134
- '#_EVENTDATES_SITE' => array( 'desc' => 'Sames as <code>#_EVENTDATES</code> but displays dates relative to your site timezone (dates can be different for events near midnight in a different timezone).' ),
135
- '#__{x} or #@__{x}' => array( 'desc' => 'Same as <code>#_{x}</code> or <code>#@_{x}</code> but displays the time of the event relative to your WordPress timezone rather than the local time of the event itself.' ),
136
- )
137
- ),
138
- 'Viewer Timezone Date/Time Placeholders' => array(
139
- 'desc' => 'These placeholders are extensions of the default Date/Time placholders, but instead will display the time of the event relative to the visitor timezone rather than the local event start time. This time is based on the user browser settings and JavaScript, so this may not always be accurate if a visitor is travelling and does not update their browser timezone, or if they have disabled JS on their browser.',
140
- 'placeholders' => array(
141
- '#_24HSTARTTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_24HSTARTTIME</code> but displays time relative to your visitor browser timezone.' ),
142
- '#_24HENDTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_24HENDTIME</code> but displays time relative to your visitor browser timezone.' ),
143
- '#_12HSTARTTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_12HSTARTTIME</code> but displays time relative to your visitor browser timezone.' ),
144
- '#_12HENDTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_12HENDTIME</code> but displays time relative to your visitor browser timezone.' ),
145
- '#_EVENTTIMES_LOCAL' => array( 'desc' => 'Sames as <code>#_EVENTTIMES</code> but displays time relative to your visitor browser timezone.' ),
146
- '#_EVENTTIMES_LOCAL{...}' => array( 'desc' => 'Sames as <code>#_EVENTTIMES_LOCAL</code> but displays custom format by replacing <code>...</code> with <a href="https://momentjs.com/docs/#/displaying/"> documented Moment JS formatting syntax</a>.'),
147
- '#_EVENTDATES_LOCAL' => array( 'desc' => 'Sames as <code>#_EVENTDATES</code> but displays dates relative to your site timezone (dates can be different for events near midnight in a different timezone).' ),
148
- '#_EVENTDATES_LOCAL{...}' => array( 'desc' => 'Sames as <code>#_EVENTDATES_LOCAL</code> but displays custom format by replacing <code>...</code> with <a href="https://momentjs.com/docs/#/displaying/"> documented Moment JS formatting syntax</a>.'),
149
- )
150
- ),
151
- 'Links/URLs' => array(
152
- 'placeholders' => array(
153
- '#_EVENTIMAGEURL' => array( 'desc' => 'Shows the event image url, if available.' ),
154
- '#_EVENTURL' => array( 'desc' => 'Simply prints the event URL. You can use this placeholder to build your own customised links.' ),
155
- '#_EVENTLINK' => array( 'desc' => 'Displays the event name with a link to the event page.' ),
156
- '#_EDITEVENTLINK' => array( 'desc' => 'Inserts a link to the admin or buddypress (if activated) edit event page, only if a user is logged in and is allowed to edit the event.' ),
157
- '#_EDITEVENTURL' => array( 'desc' => 'Inserts a url to the admin or buddypress (if activated) edit event page, only if a user is logged in and is allowed to edit the event.' ),
158
- )
159
- ),
160
- 'Custom Attributes' => array(
161
- 'desc' => 'Events Manager allows you to create dynamic attributes to your events, which act as extra information fields for your events (e.g. "Dress Code"). For more information see <a href="http://wp-events-plugin.com/documentation/event-attributes/">our online documentation</a> for more info on attributes.',
162
- 'placeholders' => array(
163
- '#_ATT{key}' => array('desc'=> 'This key will appear as an option when adding attributes to your event.'),
164
- '#_ATT{key}{alternative text}' => array('desc'=> 'This key will appear as an option when adding attributes to your event. The text in the second braces will appear if the attribute is not defined or left blank for that event.'),
165
- '#_ATT{key}{option 1|option 2|option 3|etc.}' => array('desc'=> 'This key will appear as an option when adding attributes to your event. The second braces are optional and will use a select box with these values as input. If no valid value is defined, the first option is used.'),
166
- )
167
- ),
168
- 'Bookings' => array(
169
- 'desc' => 'These placeholders will only show if bookings are enabled for the given event and in the events manager settings page. Spaces placeholders will default to 0',
170
- 'placeholders' => array(
171
- '#_BOOKINGFORM' => array( 'desc' => 'Adds a booking forms for this event.' ),
172
- '#_BOOKINGBUTTON' => array( 'desc' => 'A single button that will appear to logged in users, if they click on it, they apply for a booking. This button will only display if there is one ticket.' ),
173
- '#_AVAILABLESPACES' => array( 'desc' => 'Shows available spaces for the event.' ),
174
- '#_BOOKEDSPACES' => array( 'desc' => 'Shows the amount of currently booked spaces for the event.' ),
175
- '#_PENDINGSPACES' => array( 'desc' => 'Shows the amount of pending spaces for the event.' ),
176
- '#_SPACES' => array( 'desc' => 'Shows the total spaces for the event.' ),
177
- '#_ATTENDEES' => array( 'desc' => 'Shows the list of user avatars attending the event.' ),
178
- '#_ATTENDEESLIST' => array( 'desc' => 'Shows the list of people attending the event.' ),
179
- '#_ATTENDEESPENDINGLIST' => array( 'desc' => 'Shows the list of people with a pending booking for the event.' ),
180
- '#_BOOKINGSURL' => array( 'desc' => 'Shows the url to the admin, front-end or buddypress (if activated) bookings management page for this event. Only shown if user is logged in and able to manage bookings.' ),
181
- '#_BOOKINGSLINK' => array( 'desc' => 'Shows a link to the admin, front-end or buddypress (if activated) bookings management page for this event. Only shown if user is logged in and able to manage bookings.' ),
182
- '#_EVENTPRICERANGE' => array( 'desc' => 'Shows a "maximum - minimum" price range for available tickets at the time of display, or a single price if there is no range. Once bookings are closed this will show a 0 value, if you have enabled \'Show unavailable tickets\' in your booking settings these will be included. Price is formatted according to currency formatting in your settings page.' ),
183
- '#_EVENTPRICERANGEALL' => array( 'desc' => 'Like #_EVENTPRICERANGE but shows all tickets price range whether or not bookings or individual tickets are available.' ),
184
- '#_EVENTPRICEMIN' => array( 'desc' => 'Shows the lowest available ticket price for this event. Will display a value of 0 if no ticket is available.' ),
185
- '#_EVENTPRICEMAX' => array( 'desc' => 'Shows the highest available ticket price for this event. Will display a value of 0 if no ticket is avaialble.' ),
186
- '#_EVENTPRICEMINALL' => array( 'desc' => 'Shows the lowest ticket price for this event, whether available or not.' ),
187
- '#_EVENTPRICEMAXALL' => array( 'desc' => 'Shows the highest ticket price for this event, whether available or not.' ),
188
- )
189
- ),
190
- 'Contact Details' => array(
191
- 'desc' => 'The values here are taken from the chosen contact for the specific event, or the default contact in the settings page.',
192
- 'placeholders' => array(
193
- '#_CONTACTNAME' => array( 'desc' => 'Name of the contact person for this event (as shown in the dropdown when adding an event).' ),
194
- '#_CONTACTUSERNAME' => array( 'desc' => 'Contact person\'s username.' ),
195
- '#_CONTACTEMAIL' => array( 'desc' => 'E-mail of the contact person for this event.' ),
196
- '#_CONTACTURL' => array( 'desc' => 'Website of the contact person for this event.' ),
197
- '#_CONTACTPHONE' => array( 'desc' => 'Phone number of the contact person for this event. Can be set in the user profile page.' ),
198
- '#_CONTACTAVATAR' => array( 'desc' => 'Contact person\'s avatar.' ),
199
- '#_CONTACTPROFILELINK' => array( 'desc' => 'Contact person\'s "Profile" link. Only works with BuddyPress enabled.' ),
200
- '#_CONTACTPROFILEURL' => array( 'desc' => 'Contact person\'s profile url. Only works with BuddyPress enabled.' ),
201
- '#_CONTACTID' => array( 'desc' => 'Contact person\'s WordPress user ID.'),
202
- '#_CONTACTMETA' => array( 'desc' => 'Display any user meta of a WordPress account by including the meta key, e.g. #_CONTACTMETA{dbem_phone}'),
203
- )
204
- ),
205
- 'iCal/Calendar' => array(
206
- 'placeholders' => array(
207
- '#_EVENTICALURL' => array( 'desc' => 'Displays the URL of the event ical feed (ics file format).' ),
208
- '#_EVENTICALLINK' => array( 'desc' => 'Displays an html link to the event ical feed (ics file format).' ),
209
- '#_EVENTWEBCALURL' => array( 'desc' => 'Same as #_EVENTICALURL, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
210
- '#_EVENTWEBCALLINK' => array( 'desc' => 'Same as #_EVENTICALLINK, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
211
- '#_EVENTGCALURL' => array( 'desc' => 'Displays URL which would take the user to Google Calendar and pre-fill their add new event form.' ),
212
- '#_EVENTGCALLINK' => array( 'desc' => 'Displays a button which would take the user to Google Calendar and pre-fill their add new event form.' )
213
- )
214
- ),
215
- ),
216
- 'event-locations' => array(
217
- 'Event Location URLs' => array(
218
- 'placeholders' => array(
219
- '#_EVENTLOCATION' => array( 'desc' => 'An HTML link, opens in a new tab.' ),
220
- '#_EVENTLOCATION{url}' => array( 'desc' => 'Just the URL.' ),
221
- '#_EVENTLOCATION{text}' => array( 'desc' => 'Just the Link Text' ),
222
- '#_EVENTLOCATION{_self}' => array( 'desc' => 'Regular HTML link' ),
223
- '#_EVENTLOCATION{_parent}' => array( 'desc' => 'HTML link with target=”_parent”' ),
224
- '#_EVENTLOCATION{_top}' => array( 'desc' => 'HTML link with target=”_top”' )
225
- )
226
- ),
227
- ),
228
- 'categories' => array(
229
- 'Category Details' => array(
230
- 'desc' => 'You can use these when displaying categories or for showing the first available category in an event format.',
231
- 'placeholders' => array(
232
- '#_CATEGORYNAME' => array( 'desc' => 'Shows the category name.' ),
233
- '#_CATEGORYID' => array( 'desc' => 'Shows the category ID.' ),
234
- '#_CATEGORYSLUG' => array( 'desc' => 'Shows the category slug.' ),
235
- '#_CATEGORYLINK' => array( 'desc' => 'Category name with a link to the category page.' ),
236
- '#_CATEGORYURL' => array( 'desc' => 'URL of the category page.' ),
237
- '#_CATEGORYCOLOR' => array( 'desc' => 'Shows the category color (useful for inline styling), in hex format, if no color is defined the default category color from your settings page will be used.' ),
238
- '#_CATEGORYIMAGE' => array( 'desc' => 'Shows the category image, if available.' ),
239
- '#_CATEGORYIMAGE{x,y}' => array( 'desc' => 'Shows the category image thumbnail if available, x and y are width and height respectively, both being numbers e.g. <code>#_CATEGORYIMAGE{100,100}</code>. If 0 is used for either width or height, the corresponding dimension will be proportionally sized.' ),
240
- '#_CATEGORYIMAGEURL' => array( 'desc' => 'Shows the category image url, if available.' ),
241
- '#_CATEGORYNOTES' => array( 'desc' => 'Shows the category description.' )
242
- )
243
- ),
244
- 'Related Events' => array(
245
- 'desc' => 'You can show lists of other events belonging to this category. The formatting of the list is the same as a normal events list.',
246
- 'placeholders' => array(
247
- '#_CATEGORYPASTEVENTS' => array( 'desc' => 'Will show a list of all past events with this category.' ),
248
- '#_CATEGORYNEXTEVENTS' => array( 'desc' => 'Will show a list of all future events with this category.' ),
249
- '#_CATEGORYALLEVENTS' => array( 'desc' => 'Will show a list of all events with this category.' ),
250
- '#_CATEGORYNEXTEVENT' => array( 'desc' => 'Will show the next event with this category.' )
251
- )
252
- ),
253
- 'iCal/RSS Feeds' => array(
254
- 'placeholders' => array(
255
- '#_CATEGORYICALURL' => array( 'desc' => 'Displays the URL of the event ical feed (ics file format) which shows all events with this category.', 'since'=>'5.5.2' ),
256
- '#_CATEGORYICALLINK' => array( 'desc' => 'Displays an html link to the event ical feed (ics file format) which shows all events with this category.', 'since'=>'5.5.2' ),
257
- '#_CATEGORYWEBCALURL' => array( 'desc' => 'Same as #_CATEGORYICALURL, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
258
- '#_CATEGORYWEBCALLINK' => array( 'desc' => 'Same as #_CATEGORYICALLINK, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
259
- '#_CATEGORYRSSURL' => array( 'desc' => 'Displays the URL of an RSS feed showing all upcoming events happening in this category.', 'since'=>'5.5.2' ),
260
- '#_CATEGORYRSSLINK' => array( 'desc' => 'Displays an html link to an RSS feed showing all upcoming events happening in this category.', 'since'=>'5.5.2' )
261
- )
262
- )
263
- ),
264
- 'tags' => array(
265
- 'Tag Details' => array(
266
- 'desc' => 'You can use these when displaying tags or for showing the first available tag in an event format.',
267
- 'placeholders' => array(
268
- '#_TAGNAME' => array( 'desc' => 'Shows the tag name.' ),
269
- '#_TAGID' => array( 'desc' => 'Shows the tag ID.' ),
270
- '#_TAGSLUG' => array( 'desc' => 'Shows the tag slug.' ),
271
- '#_TAGLINK' => array( 'desc' => 'Tag name with a link to the tag page.' ),
272
- '#_TAGURL' => array( 'desc' => 'URL of the tag page.' ),
273
- '#_TAGNOTES' => array( 'desc' => 'Shows the tag description.' ),
274
- '#_TAGCOLOR' => array( 'desc' => 'Shows the tag color (useful for inline styling), in hex format, if no color is defined the default tag color from your settings page will be used.' ),
275
- '#_TAGIMAGE' => array( 'desc' => 'Shows the tag image, if available.' ),
276
- '#_TAGIMAGE{x,y}' => array( 'desc' => 'Shows the tag image thumbnail if available, x and y are width and height respectively, both being numbers e.g. <code>#_TAGIMAGE{100,100}</code>. If 0 is used for either width or height, the corresponding dimension will be proportionally sized.' ),
277
- '#_TAGIMAGEURL' => array( 'desc' => 'Shows the tag image url, if available.' ),
278
- )
279
- ),
280
- 'Related Events' => array(
281
- 'desc' => 'You can show lists of other events belonging to this tag. The formatting of the list is the same as a normal events list.',
282
- 'placeholders' => array(
283
- '#_TAGPASTEVENTS' => array( 'desc' => 'Will show a list of all past events with this tag.' ),
284
- '#_TAGNEXTEVENTS' => array( 'desc' => 'Will show a list of all future events with this tag.' ),
285
- '#_TAGALLEVENTS' => array( 'desc' => 'Will show a list of all events with this tag.' ),
286
- '#_TAGNEXTEVENT' => array( 'desc' => 'Will show the next event with this tag.' )
287
- )
288
- ),
289
- 'iCal/RSS Feeds' => array(
290
- 'placeholders' => array(
291
- '#_TAGICALURL' => array( 'desc' => 'Displays the URL of the event ical feed (ics file format) which shows all events with this tag.', 'since'=>'5.5.2' ),
292
- '#_TAGICALLINK' => array( 'desc' => 'Displays an html link to the event ical feed (ics file format) which shows all events with this tag.' , 'since'=>'5.5.2'),
293
- '#_TAGWEBCALURL' => array( 'desc' => 'Same as #_TAGICALURL, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
294
- '#_TAGWEBCALLINK' => array( 'desc' => 'Same as #_TAGICALLINK, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
295
- '#_TAGRSSURL' => array( 'desc' => 'Displays the URL of an RSS feed showing all upcoming events happening in this tag.', 'since'=>'5.5.2' ),
296
- '#_TAGRSSLINK' => array( 'desc' => 'Displays an html link to an RSS feed showing all upcoming events happening in this tag.', 'since'=>'5.5.2' )
297
- )
298
- )
299
- ),
300
- 'locations' => array(
301
- 'Location Details' => array(
302
- 'desc' => '',
303
- 'placeholders' => array(
304
- '#_LOCATIONID' => array( 'desc' => 'Shows the event ID number in the wp_em_locations table.' ),
305
- '#_LOCATIONPOSTID' => array( 'desc' => 'Shows the location corresponding Post ID in the wp_posts table.' ),
306
- '#_LOCATIONNAME' => array( 'desc' => 'Displays the location name.' ),
307
- '#_LOCATIONADDRESS' => array( 'desc' => 'Displays the address.' ),
308
- '#_LOCATIONTOWN' => array( 'desc' => 'Displays the town.' ),
309
- '#_LOCATIONSTATE' => array( 'desc' => 'Displays the state/county.' ),
310
- '#_LOCATIONPOSTCODE' => array( 'desc' => 'Displays the postcode.' ),
311
- '#_LOCATIONREGION' => array( 'desc' => 'Displays the region.' ),
312
- '#_LOCATIONCOUNTRY' => array( 'desc' => 'Displays the country.' ),
313
- '#_LOCATIONLONGITUDE' => array( 'desc' => 'Displays the longitude, used for locating in Google Maps.' ),
314
- '#_LOCATIONLATITUDE' => array( 'desc' => 'Displays the latitude, used for locating in Google Maps.' ),
315
- '#_LOCATIONMAP' => array( 'desc' => 'Displays a google map showing where the location is located (Will not show if maps are disabled in the settings page)' ),
316
- '#_LOCATIONNOTES' => array( 'desc' => 'Shows the location description.' ),
317
- '#_LOCATIONEXCERPT' => array( 'desc' => 'If an excerpt has been added to the location, it will be used. If you added a <a href="http://en.support.wordpress.com/splitting-content/more-tag/">more tag</a> to your location description, only the content before this tag will show.' ),
318
- '#_LOCATIONEXCERPT{words, ...}' => array( 'desc' => 'If an excerpt has not been added to the location, only a specific length is shown, e.g. <code>#_EVENTEXCERPT{10,...}</code> where 10 is the number of words to show and ... is what is used at the cut-off point.' ),
319
- '#_LOCATIONEXCERPTCUT' => array( 'desc' => 'Same as <code>#_LOCATIONEXCERPT</code> (and also accepts the <code>{words,...}</code> arguments) but will also cut excerpts as well as post content. Default word limit is 55 and cut-off is <code>[...]</code>' ),
320
- '#_LOCATIONIMAGE' => array( 'desc' => 'Shows the location image.' ),
321
- '#_LOCATIONIMAGE{x,y}' => array( 'desc' => 'Shows the location image thumbnail, x and y are width and height respectively, both being numbers e.g. <code>#_LOCATIONIMAGE{100,100}</code>. If 0 is used for either width or height, the corresponding dimension will be proportionally sized.' ),
322
- '#_LOCATIONIMAGEURL' => array( 'desc' => 'Shows the location image url, if available.' ),
323
- '#_LOCATIONFULLLINE' => array( 'desc' => 'Shows a comma-separated line of location information, ommitting blanks (format of address, town, state, postcode, region' ),
324
- '#_LOCATIONFULLBR' => array( 'desc' => 'Shows a line-break (br tag) separated location information, ommitting blanks (format of address, town, state, postcode, region' ),
325
- )
326
- ),
327
- 'Custom Attributes' => array(
328
- 'desc' => 'Events Manager allows you to create dynamic attributes to your locations, which act as extra information fields for your locations (e.g. "Dress Code"). For more information see <a href="http://wp-events-plugin.com/documentation/event-attributes/">our online documentation</a> for more info on attributes.',
329
- 'placeholders' => array(
330
- '#_LATT{key}' => array('desc'=> 'This key will appear as an option when adding attributes to your location.'),
331
- '#_LATT{key}{alternative text}' => array('desc'=> 'This key will appear as an option when adding attributes to your location. The text in the second braces will appear if the attribute is not defined or left blank for that location.'),
332
- '#_LATT{key}{option 1|option 2|option 3|etc.}' => array('desc'=> 'This key will appear as an option when adding attributes to your location. The second braces are optional and will use a select box with these values as input. If no valid value is defined, the first option is used.'),
333
- )
334
- ),
335
- 'Links' => array(
336
- 'placeholders' => array(
337
- '#_LOCATIONURL' => array( 'desc' => 'Simply prints the location URL. You can use this placeholder to build your own customised links.' ),
338
- '#_LOCATIONLINK' => array( 'desc' => 'Displays the location name with a link to the location page.' ),
339
- '#_EDITLOCATIONLINK' => array( 'desc' => 'Inserts a link to the admin or buddypress (if activated) edit location page, only if a user is logged in and is allowed to edit the location.' ),
340
- '#_EDITLOCATIONURL' => array( 'desc' => 'Inserts a url to the admin or buddypress (if activated) edit location page, only if a user is logged in and is allowed to edit the location.' )
341
- )
342
- ),
343
- 'Related Events' => array(
344
- 'desc' => 'You can show lists of other events that are being held at this location. The formatting of the list is the same as a normal events list.',
345
- 'placeholders' => array(
346
- '#_LOCATIONPASTEVENTS' => array( 'desc' => 'Will show a list of all past events at this location.' ),
347
- '#_LOCATIONNEXTEVENTS' => array( 'desc' => 'Will show a list of all future events at this location.' ),
348
- '#_LOCATIONALLEVENTS' => array( 'desc' => 'Will show a list of all events at this location.' ),
349
- '#_LOCATIONNEXTEVENT' => array( 'desc' => 'Will show a link to the next event at this location, or the no events message.' ),
350
- )
351
- ),
352
- 'iCal/RSS Feeds' => array(
353
- 'placeholders' => array(
354
- '#_LOCATIONICALURL' => array( 'desc' => 'Displays the URL of the location ical feed (ics file format) which shows all events happening at that location.', 'since'=>'5.5.2' ),
355
- '#_LOCATIONICALLINK' => array( 'desc' => 'Displays an html link to the event ical feed (ics file format) which shows all events happening at that location.', 'since'=>'5.5.2' ),
356
- '#_LOCATIONWEBCALURL' => array( 'desc' => 'Same as #_LOCATIONICALURL, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
357
- '#_LOCATIONWEBCALLINK' => array( 'desc' => 'Same as #_LOCATIONICALLINK, but using the <a href="https://en.wikipedia.org/wiki/Webcal">webcal:// protocol</a>, which will open up various calendar apps automatically including iCalendar, Outlook and Google Calendar.', 'since'=>'5.8' ),
358
- '#_LOCATIONRSSURL' => array( 'desc' => 'Displays the URL of an RSS feed showing all upcoming events happening at this location.', 'since'=>'5.5.2' ),
359
- '#_LOCATIONRSSLINK' => array( 'desc' => 'Displays an html link to an RSS feed showing all upcoming events happening at this location.', 'since'=>'5.5.2' )
360
- )
361
- )
362
- ),
363
- 'bookings' => array(
364
- 'Individual Booking Information' => array(
365
- 'desc' => 'When a specific booking is displayed (on screen and on email), you can use these placeholders to show specific information about the booking. Event and Location placeholders are also available in these cases.',
366
- 'placeholders' => array(
367
- '#_BOOKINGID' => array( 'desc' => 'The unique ID of this booking, useful if you are making your own customizations to this plugin.' ),
368
- '#_BOOKINGNAME' => array( 'desc' => 'Name of person who made the booking.' ),
369
- '#_BOOKINGEMAIL' => array( 'desc' => 'Email of person who made the booking.' ),
370
- '#_BOOKINGPHONE' => array( 'desc' => 'Phone number of person who made the booking.' ),
371
- '#_BOOKINGSPACES' => array( 'desc' => 'Number of spaces the person has booked.' ),
372
- '#_BOOKINGCOMMENT' => array( 'desc' => 'Any specific comments made by the person who made the booking.' ),
373
- '#_BOOKINGTICKETNAME' => array( 'desc' => 'Name of the ticket booked. Useful in single ticket mode, if multiple tickets are booked a random ticket is used.' ),
374
- '#_BOOKINGTICKETDESCRIPTION' => array( 'desc' => 'Description of the ticket booked. Useful in single ticket mode, if multiple tickets are booked a random ticket is used.' ),
375
- '#_BOOKINGTICKETPRICE' => array( 'desc' => 'Booked ticket price with currency symbol (e.g. $ 10.00). Useful in single ticket mode, if multiple tickets are booked a random ticket is used.' ),
376
- '#_BOOKINGTICKETS' => array( 'desc' => 'A list of booked tickets. You can modify this by using template files and modifying templates/emails/bookingtickets.php' ),
377
- '#_BOOKINGSUMMARY' => array( 'desc' => 'Shows a breakdown of price/quantity booked by ticket, followed by a summary of price totals, taxes, and other discounts applied.' ),
378
- '#_BOOKINGFORMCUSTOM{field_id}' => array( 'desc' => sprintf('(<a href="%s">pro only</a>) Shows booking form custom fields. The field_id value must match that of your custom booking form field.','http://wp-events-plugin.com/features/') ),
379
- '#_BOOKINGFORMCUSTOMREG{field_id}' => array( 'desc' => sprintf('(<a href="%s">pro only</a>) Shows booking form custom fields that are used for guest user registration. The field_id value must match that of your custom booking form field.','http://wp-events-plugin.com/features/') ),
380
- '#_BOOKINGFORMCUSTOMFIELDS' => array( 'desc' => sprintf('(<a href="%s">pro only</a>) Generates a list of booking form custom fields that are used in the booking.','http://wp-events-plugin.com/features/') ),
381
- '#_BOOKINGATTENDEES' => array('desc' => sprintf('(<a href="%s">pro only</a>) Generates a list of attendee information displaying the filled in form data for each attendee (requires individual attendee forms enabled for the event). This list is split by ticket type, then by individual attendee.','http://wp-events-plugin.com/features/')), //coupons too!
382
- '#_BOOKINGADMINURL' => array( 'desc' => 'URL for admins to view and manage the booking. This should only be used on admin-specific email templates.' ),
383
- '#_BOOKINGADMINLINK' => array( 'desc' => 'HTML link for admins to view and manage the booking. This should only be used on admin-specific email templates.' ),
384
- )
385
- ),
386
- 'Pricing Information' => array(
387
- 'desc' => '',
388
- 'placeholders' => array(
389
- '#_BOOKINGPRICE' => array( 'desc' => 'Displays booking total price (tax inclusion depends on your booking settings).' ),
390
- '#_BOOKINGPRICETAX' => array( 'desc' => 'Displays booking total tax.' ),
391
- '#_BOOKINGPRICEWITHOUTTAX' => array( 'desc' => 'Displays booking total without tax.' ),
392
- '#_BOOKINGPRICEWITHTAX' => array( 'desc' => 'Displays booking total with tax.' ),
393
- )
394
- ),
395
- 'Ticket Information' => array(
396
- 'desc' => '',
397
- 'placeholders' => array(
398
- '#_BOOKINGTICKETS' => array( 'desc' => 'Shows a breakdown of tickets and pricing, defined in the <code>emails/bookingtickets.php</code> template. (See <a href="http://wp-events-plugin.com/documentation/using-template-files/">Using Template Files</a> for more information)' ),
399
- '#_BOOKINGTICKETDESCRIPTION' => array( 'desc' => 'Shows the description of the first ticket booked (useful in single ticket mode/events).' ),
400
- '#_BOOKINGTICKETPRICE' => array( 'desc' => 'Shows the price of the first ticket booked, tax inclusion depending on your booking settings (useful in single ticket mode/events).' ),
401
- '#_BOOKINGTICKETTAX' => array( 'desc' => 'Shows the tax of the first ticket booked (useful in single ticket mode/events).' ),
402
- '#_BOOKINGTICKETPRICEWITHTAX' => array( 'desc' => 'Shows the price including tax of the first ticket booked (useful in single ticket mode/events).' ),
403
- '#_BOOKINGTICKETPRICEWITHOUTTAX' => array( 'desc' => 'Shows the price excluding tax of the first ticket booked (useful in single ticket mode/events).' ),
404
- )
405
- ),
406
- 'Links' => array(
407
- 'desc' => 'People are able to manage their bookings. Below are some placeholder which automatically provides correctly formatted urls',
408
- 'placeholders' => array(
409
- '#_BOOKINGLISTURL' => array( 'desc' => 'URL to page showing that users booked events.' )
410
- )
411
- ),
412
- 'Gateway-Specific Information' => array(
413
- 'desc' => 'Information pertaining to speicifc gateways. '. sprintf('Requires <a href="%s">Events Manager Pro</a>','http://wp-events-plugin.com/features/'),
414
- 'placeholders' => array(
415
- '#_BOOKINGTXNID' => array( 'desc' => '<em>Online Payments Only</em> - Prints the transaction ID of this booking if available.' )
416
- )
417
- ),
418
- 'Coupon Information' => array(
419
- 'desc' => 'When a booking has been made with a coupon, you can display coupon information using these placeholders. If no coupon is used, nothing will be shown. '.sprintf('Requires <a href="%s">Events Manager Pro</a>','http://wp-events-plugin.com/features/'),
420
- 'placeholders' => array(
421
- '#_BOOKINGCOUPON' => array('desc' => 'Displays the coupon code followed by the amount/percentage discounted.'),
422
- '#_BOOKINGCOUPONCODE' => array('desc' => 'Displays the coupon code used.'),
423
- '#_BOOKINGCOUPONNAME' => array('desc' => 'Displays the name given to this coupon.'),
424
- '#_BOOKINGCOUPONDISCOUNT' => array('desc' => 'Displays amount/percentage discounted (e.g. 25% Off).'),
425
- '#_BOOKINGCOUPONDESCRIPTION' => array('desc' => 'Displays the coupon description.'),
426
- )
427
- ),
428
- ),
429
- ),
430
- //TODO add capabilites explanations
431
- 'capabilities' => array()
432
- );
433
- $EM_Documentation = apply_filters('em_documentation', $EM_Documentation);
434
- }
435
- }
436
- add_action('init', 'em_docs_init');
437
-
438
- function em_docs_placeholders($atts){
439
- ob_start();
440
- ?>
441
- <div class="em-docs">
442
- <?php
443
- global $EM_Documentation;
444
- $type = $atts['type'];
445
- $data = $EM_Documentation['placeholders'][$type];
446
- foreach($data as $sectionTitle => $details) : ?>
447
- <div>
448
- <h3><?php echo $sectionTitle; ?></h3>
449
- <?php if( !empty($details['desc']) ): ?>
450
- <p><?php echo $details['desc']; ?></p>
451
- <?php endif; ?>
452
- <dl>
453
- <?php foreach($details['placeholders'] as $placeholder => $desc ): ?>
454
- <dt><b><?php echo $placeholder; ?></b></dt>
455
- <dd><?php echo $desc['desc']; ?></dd>
456
- <?php endforeach; ?>
457
- </dl>
458
- </div>
459
- <?php endforeach; ?>
460
- </div>
461
- <?php
462
- return ob_get_clean();
463
- }
464
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-help.php DELETED
@@ -1,72 +0,0 @@
1
- <?php
2
- /**
3
- * Display function for the support page. here we can give links to forums and special upgrade instructions e.g. migration features
4
- */
5
- function em_admin_help_page(){
6
- global $wpdb;
7
- ?>
8
- <div class="wrap">
9
- <h1><?php _e('Getting Help for Events Manager','events-manager'); ?></h1>
10
- <div class="em-docs">
11
- <h2>Where To Get Help</h2>
12
- <p>
13
- This page is only a small portion of the event documentation which is here for quick reference. If you're just starting out, we recommend you visit the following places for further support:
14
- </p>
15
- <ol>
16
- <li>New users are strongly encouraged to have a look at our <a href="http://wp-events-plugin.com/documentation/getting-started-guide/">getting started guide</a>.</li>
17
- <li>Browse the other documentation pages and <a href="http://wp-events-plugin.com/tutorials/">tutorials</a>.</li>
18
- <li>View the <a href="http://wp-events-plugin.com/documentation/faq/">FAQ</a> for general questions and <a href="http://wp-events-plugin.com/documentation/troubleshooting/">Troubleshooting</a> for common issues. These are regularly updated with recent issues.</li>
19
- <li>Rather than trying to contact us directly, we request you use the <a href="http://wordpress.org/tags/events-manager?forum_id=10">support forums</a> as others may be experiencing the same issues as you. For faster support via private member forums and extra features please consider <a href="http://wp-events-plugin.com/events-manager-pro/">upgrading to pro</a>.</li>
20
- </ol>
21
- <p>
22
- If you can't find what you're looking for in the documentation, you may find help on our <a href="http://wp-events-plugin.com/forums/">support forums</a>.
23
- </p>
24
- <h2><?php _e('Placeholders for customizing event pages','events-manager'); ?></h2>
25
- <p><?php echo sprintf( __("In the <a href='%s'>settings page</a>, you'll find various textboxes where you can edit how event information looks, such as for event and location lists. Using the placeholders below, you can choose what information should be displayed.",'events-manager'), EM_ADMIN_URL .'&amp;events-manager-options'); ?></p>
26
- <a name="event-placeholders"></a>
27
- <h3 style="margin-top:20px;"><?php _e('Event Related Placeholders','events-manager'); ?></h3>
28
- <?php echo em_docs_placeholders( array('type'=>'events') ); ?>
29
- <h3 style="margin-top:20px;"><?php _e('Event Location Placeholders','events-manager'); ?></h3>
30
- <?php echo em_docs_placeholders( array('type'=>'event-locations') ); ?>
31
- <a name="category-placeholders"></a>
32
- <h3><?php _e('Category Related Placeholders','events-manager'); ?></h3>
33
- <?php echo em_docs_placeholders( array('type'=>'categories') ); ?>
34
- <h3><?php _e('Tag Related Placeholders','events-manager'); ?></h3>
35
- <?php echo em_docs_placeholders( array('type'=>'tags') ); ?>
36
- <a name="location-placeholders"></a>
37
- <h3><?php _e('Location Related Placeholders','events-manager'); ?></h3>
38
- <?php echo em_docs_placeholders( array('type'=>'locations') ); ?>
39
- <a name="booking-placeholders"></a>
40
- <h3><?php _e('Booking Related Placeholders','events-manager'); ?></h3>
41
- <?php echo em_docs_placeholders( array('type'=>'bookings') ); ?>
42
- </div>
43
- <?php
44
-
45
- //Is this a previously imported installation?
46
- $old_table_name = $wpdb->prefix.'dbem_events';
47
- if( $wpdb->get_var("SHOW TABLES LIKE '$old_table_name'") == $old_table_name ){
48
- ?>
49
- <hr style="margin:30px 10px;" />
50
- <div class="updated">
51
- <h3>Troubleshooting upgrades from version 2.x to 3.x</h3>
52
- <p>We notice that you upgraded from version 2, as we are now using new database tables, and we do not delete the old tables in case something went wrong with this upgrade.</p>
53
- <p>If something went wrong with the update to version 3 read on:</p>
54
- <h4>Scenario 1: the plugin is working, but for some reason the old events weren't imported</h4>
55
- <p>You can safely reimport your old events from the previous tables without any risk of deleting them. However, if you click the link below <b>YOU WILL OVERWRITE ANY NEW EVENTS YOU CREATED IN VERSION 3</b></p>
56
- <p><a onclick="return confirm('Are you sure you want to do this? Any new changes made since updating will be overwritten by your old ones, and this cannot be undone');" href="<?php echo wp_nonce_url( EM_ADMIN_URL .'&amp;events-manager-help&em_reimport=1', 'em_reimport' ) ?>">Reimport Events from version 2</a></p>
57
- <h4>Scenario 2: the plugin is not working, I want to go back to version 2!</h4>
58
- <p>You can safely downgrade and will not lose any information.</p>
59
- <ol>
60
- <li>First of all, <a href='http://downloads.wordpress.org/plugin/events-manager.2.2.2.zip'>dowload a copy of version 2.2</a></li>
61
- <li>Deactivate and delete Events Manager in the plugin page</li>
62
- <li><a href="<?php bloginfo('wpurl'); ?>/wp-admin/plugin-install.php?tab=upload">Upload the zip file you just downloaded here</a></li>
63
- <li>Let the developers know, of any bugs you ran into while upgrading. We'll help you out if there is a simple solution, and will fix reported bugs within days, if not quicker!</li>
64
- </ol>
65
- </div>
66
- <?php
67
- }
68
- ?>
69
- </div>
70
- <?php
71
- }
72
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-ms-locations.php DELETED
@@ -1,52 +0,0 @@
1
- <?php
2
- /**
3
- * Looks at the request values, saves/updates and then displays the right menu in the admin
4
- * @return null
5
- */
6
- function em_admin_ms_locations() {
7
- //TODO EM_Location is globalized, use it fully here
8
- global $EM_Location;
9
- //Take actions
10
- if( !empty($_REQUEST['action']) && ($_REQUEST['action'] == "edit" || $_REQUEST['action'] == "location_save")) {
11
- em_admin_location();
12
- } else {
13
- // no action, just a locations list
14
- em_admin_locations();
15
- }
16
- }
17
-
18
- function em_admin_locations($message='', $fill_fields = false) {
19
- global $current_site;
20
- ?>
21
- <div class='wrap'>
22
- <div id='icon-edit' class='icon32'>
23
- <br/>
24
- </div>
25
- <h2>
26
- <?php _e('Locations', 'events-manager'); ?>
27
- </h2>
28
- <?php em_locations_admin(array('url' => $_SERVER['REQUEST_URI'])); ?>
29
- </div>
30
- <?php
31
- }
32
-
33
- function em_admin_location($message = "") {
34
- global $EM_Location;
35
- if( empty($EM_Location) || !is_object($EM_Location) ){
36
- $title = __('Add location', 'events-manager');
37
- $EM_Location = new EM_Location();
38
- }else{
39
- $title = __('Edit location', 'events-manager');
40
- }
41
- ?>
42
- <div class='wrap'>
43
- <div id='icon-edit' class='icon32'>
44
- <br/>
45
- </div>
46
- <h2><?php echo $title ?></h2>
47
- <?php em_location_form(); ?>
48
- </div>
49
- <?php
50
- }
51
-
52
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-ms-options.php DELETED
@@ -1,248 +0,0 @@
1
- <?php
2
- function em_ms_upgrade( $blog_id ){
3
- ?>
4
- <div class="wrap">
5
- <div id='icon-options-general' class='icon32'><br /></div>
6
- <h2><?php esc_html_e('Update Network','events-manager'); ?></h2>
7
- <?php
8
- $site_updates = EM_Options::site_get('updates');
9
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'upgrade_network' && check_admin_referer('em_ms_upgrade') ){
10
- global $current_site,$wpdb;
11
- $blog_ids = $wpdb->get_col('SELECT blog_id FROM '.$wpdb->blogs.' WHERE site_id='.$current_site->id);
12
- echo '<ul>';
13
- foreach($blog_ids as $blog_id){
14
- $plugin_basename = plugin_basename(dirname(dirname(__FILE__)).'/events-manager.php');
15
- if( in_array( $plugin_basename, (array) get_blog_option($blog_id, 'active_plugins', array() ) ) || is_plugin_active_for_network($plugin_basename) ){
16
- if( EM_VERSION > get_blog_option($blog_id, 'dbem_version', 0) ){
17
- switch_to_blog($blog_id);
18
- require_once( dirname(__FILE__).'/../em-install.php');
19
- em_install();
20
- echo "<li>".sprintf(_x('Updated %s.', 'Multisite Blog Update','events-manager'), get_bloginfo('blogname'))."</li>";
21
- restore_current_blog();
22
- }else{
23
- echo "<li>".sprintf(_x('%s is up to date.', 'Multisite Blog Update','events-manager'), get_blog_option($blog_id, 'blogname'))."</li>";
24
- }
25
- }else{
26
- echo "<li>".sprintf(_x('%s does not have Events Manager activated.', 'Multisite Blog Update','events-manager'), get_blog_option($blog_id, 'blogname'))."</li>";
27
- }
28
- }
29
- echo '</ul>';
30
- echo "<p>".esc_html__('Update process has finished.', 'events-manager')."</p>";
31
- }elseif( !empty($_REQUEST['action']) && !empty($site_updates[$_REQUEST['action']]) ){
32
- do_action('em_admin_update_ms_'.$_REQUEST['action']);
33
- }else{
34
- ?>
35
- <form action="" method="post">
36
- <p><?php esc_html_e('To update your network blogs with the latest Events Manager automatically, click the update button below.','events-manager'); ?></p>
37
- <input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce('em_ms_upgrade'); ?>" />
38
- <input type="hidden" name="action" value="upgrade_network" />
39
- <input type="submit" value="<?php esc_attr_e('Update Network','events-manager'); ?>" class="button-primary" />
40
- </form>
41
- <?php
42
- //extra upgrade stuff
43
- foreach( $site_updates as $update => $update_data ){
44
- do_action('em_admin_update_ms_settings_'.$update, $update_data);
45
- }
46
- }
47
- ?>
48
- </div>
49
- <?php
50
- }
51
-
52
- /**
53
- * Displays network-related options in the network admin section
54
- * @uses em_options_save() to save settings
55
- */
56
- function em_ms_admin_options_page() {
57
- global $wpdb,$EM_Notices;
58
- //Check for uninstall/reset request
59
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'uninstall' ){
60
- em_admin_options_uninstall_page();
61
- return;
62
- }
63
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'reset' ){
64
- em_admin_options_reset_page();
65
- return;
66
- }
67
- em_pro_update_notice();
68
- //TODO place all options into an array
69
- $tabs_enabled = defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS;
70
- $events_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#event-placeholders">'. __('Event Related Placeholders','events-manager') .'</a>';
71
- $locations_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#location-placeholders">'. __('Location Related Placeholders','events-manager') .'</a>';
72
- $bookings_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#booking-placeholders">'. __('Booking Related Placeholders','events-manager') .'</a>';
73
- $categories_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#category-placeholders">'. __('Category Related Placeholders','events-manager') .'</a>';
74
- $events_placeholder_tip = " ". sprintf(__('This accepts %s and %s placeholders.','events-manager'),$events_placeholders, $locations_placeholders);
75
- $locations_placeholder_tip = " ". sprintf(__('This accepts %s placeholders.','events-manager'), $locations_placeholders);
76
- $categories_placeholder_tip = " ". sprintf(__('This accepts %s placeholders.','events-manager'), $categories_placeholders);
77
- $bookings_placeholder_tip = " ". sprintf(__('This accepts %s, %s and %s placeholders.','events-manager'), $bookings_placeholders, $events_placeholders, $locations_placeholders);
78
-
79
- global $save_button;
80
- $save_button = '<tr><th>&nbsp;</th><td><p class="submit" style="margin:0px; padding:0px; text-align:right;"><input type="submit" class="button-primary" name="Submit" value="'. __( 'Save Changes', 'events-manager') .' ('. __('All','events-manager') .')" /></p></td></tr>';
81
- //Do some multisite checking here for reuse
82
- ?>
83
- <script type="text/javascript" charset="utf-8"><?php include(EM_DIR.'/includes/js/admin-settings.js'); ?></script>
84
- <script type="text/javascript" charset="utf-8">
85
- jQuery(document).ready(function($){
86
- //events
87
- $('input[name="dbem_ms_global_events"]').on('change', function(){
88
- if( $('input:radio[name="dbem_ms_global_events"]:checked').val() == 1 ){
89
- $("tr#dbem_ms_global_events_links_row").show();
90
- $('input:radio[name="dbem_ms_global_events_links"]:checked').trigger('change');
91
- }else{
92
- $("tr#dbem_ms_global_events_links_row, tr#dbem_ms_events_slug_row").hide();
93
- }
94
- }).first().trigger('change');
95
- $('input[name="dbem_ms_global_events_links"]').on('change', function(){
96
- if( $('input:radio[name="dbem_ms_global_events_links"]:checked').val() == 1 ){
97
- $("tr#dbem_ms_events_slug_row").hide();
98
- }else{
99
- $("tr#dbem_ms_events_slug_row").show();
100
- }
101
- }).first().trigger('change');
102
- //locations
103
- $('input[name="dbem_ms_mainblog_locations"]').on('change', function(){
104
- if( $('input:radio[name="dbem_ms_mainblog_locations"]:checked').val() == 1 ){
105
- $("tbody.em-global-locations").hide();
106
- }else{
107
- $("tbody.em-global-locations").show();
108
- }
109
- }).first().trigger('change');
110
- $('input[name="dbem_ms_global_locations"]').on('change', function(){
111
- if( $('input:radio[name="dbem_ms_global_locations"]:checked').val() == 1 ){
112
- $("tr#dbem_ms_global_locations_links_row").show();
113
- $('input:radio[name="dbem_ms_global_locations_links"]:checked').trigger('change');
114
- }else{
115
- $("tr#dbem_ms_global_locations_links_row, tr#dbem_ms_locations_slug_row").hide();
116
- }
117
- }).first().trigger('change');
118
- $('input[name="dbem_ms_global_locations_links"]').on('change', function(){
119
- if( $('input:radio[name="dbem_ms_global_locations_links"]:checked').val() == 1 ){
120
- $("tr#dbem_ms_locations_slug_row").hide();
121
- }else{
122
- $("tr#dbem_ms_locations_slug_row").show();
123
- }
124
- });
125
- //MS Mode selection hiders
126
- $('input[name="dbem_ms_global_table"]').on('change', function(){ //global
127
- if( $('input:radio[name="dbem_ms_global_table"]:checked').val() == 1 ){
128
- $("tbody.em-global-options").show();
129
- $('input:radio[name="dbem_ms_mainblog_locations"]:checked').trigger('change');
130
- }else{
131
- $("tbody.em-global-options").hide();
132
- }
133
- }).first().trigger('change');
134
- });
135
- </script>
136
- <style type="text/css">.postbox h3 { cursor:pointer; }</style>
137
- <div class="wrap <?php if(empty($tabs_enabled)) echo 'tabs-active' ?>">
138
- <div id='icon-options-general' class='icon32'><br /></div>
139
- <h1 id="em-options-title"><?php _e ( 'Event Manager Options', 'events-manager'); ?></h1>
140
- <h2 class="nav-tab-wrapper">
141
- <?php
142
- if( $tabs_enabled ){
143
- $general_tab_link = esc_url(add_query_arg( array('em_tab'=>'general')));
144
- }else{
145
- $general_tab_link = '';
146
- }
147
- ?>
148
- <a href="<?php echo $general_tab_link ?>#general" id="em-menu-general" class="nav-tab nav-tab-active"><?php esc_html_e('General','events-manager'); ?></a>
149
- <?php
150
- $custom_tabs = apply_filters('em_ms_options_page_tabs', array());
151
- foreach( $custom_tabs as $tab_key => $tab_name ){
152
- $tab_link = !empty($tabs_enabled) ? esc_url(add_query_arg( array('em_tab'=>$tab_key))) : '';
153
- $active_class = !empty($tabs_enabled) && !empty($_GET['em_tab']) && $_GET['em_tab'] == $tab_key ? 'nav-tab-active':'';
154
- echo "<a href='$tab_link#$tab_key' id='em-menu-$tab_key' class='nav-tab $active_class'>$tab_name</a>";
155
- }
156
- ?>
157
- </h2>
158
- <?php echo $EM_Notices; ?>
159
- <form id="em-options-form" method="post" action="">
160
- <div class="metabox-holder">
161
- <!-- // TODO Move style in css -->
162
- <div class='postbox-container' style='width: 99.5%'>
163
- <div id="">
164
- <?php if( !$tabs_enabled || ($tabs_enabled && (empty($_REQUEST['em_tab']) || $_REQUEST['em_tab'] == 'general')) ): //make less changes for now, since we don't have any core tabs to add yet ?>
165
- <div class="em-menu-general em-menu-group">
166
- <div class="postbox " id="em-opt-ms-options" >
167
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Multi Site Options', 'events-manager'); ?></span></h3>
168
- <div class="inside">
169
- <table class="form-table">
170
- <?php
171
- em_options_radio_binary ( __( 'Enable global tables mode?', 'events-manager'), 'dbem_ms_global_table', __( 'Setting this to yes will make all events save in the main site event tables (EM must also be activated). This allows you to share events across different blogs, such as showing events in your network whilst allowing users to display and manage their events within their own blog. Bear in mind that activating this will mean old events created on the sub-blogs will not be accessible anymore, and if you switch back they will be but new events created during global events mode will only remain on the main site.','events-manager') );
172
- ?>
173
- <tbody class="em-global-options">
174
- <?php
175
- global $current_site;
176
- $global_slug_tip = __('%s belonging to other sub-sites will have an extra slug prepended to it so that your main site can differentiate between its own %s and those belonging to other sites in your network.','events-manager');
177
- $global_link_tip = __( 'When displaying global %s on the main site you have the option of users viewing the %s details on the main site or being directed to the sub-site.','events-manager');
178
- $global_post_tip = __( 'Displays %s from all sites on the network by default. You can still restrict %s by blog using shortcodes and template tags coupled with the <code>blog</code> attribute. Requires global tables to be turned on.','events-manager');
179
- $global_link_tip2 = __('You <strong>must</strong> have assigned a %s page in your <a href="%s">main blog settings</a> for this to work.','events-manager');
180
- $options_page_link = get_admin_url($current_site->blog_id, 'edit.php?post_type='.EM_POST_TYPE_EVENT.'&page=events-manager-options#pages');
181
- ?><tr class="em-header"><td><h4><?php echo sprintf(__('%s Options','events-manager'),__('Event','events-manager')); ?></h4></td></tr><?php
182
- em_options_radio_binary ( sprintf(__( 'Display global events on main blog?', 'events-manager'), __('events','events-manager')), 'dbem_ms_global_events', sprintf($global_post_tip, __('events','events-manager'), __('events','events-manager')) );
183
- em_options_radio_binary ( sprintf(__( 'Link sub-site %s directly to sub-site?', 'events-manager'), __('events','events-manager')), 'dbem_ms_global_events_links', sprintf($global_link_tip, __('events','events-manager'), __('event','events-manager')).sprintf($global_link_tip2, __('event','events-manager'), $options_page_link) );
184
- em_options_input_text ( sprintf(__( 'Global %s slug', 'events-manager'),__('event','events-manager')), 'dbem_ms_events_slug', sprintf($global_slug_tip, __('Events','events-manager'), __('events','events-manager')).__('Example:','events-manager').'<code>http://yoursite.com/events/<strong>event</strong>/subsite-event-slug/', EM_EVENT_SLUG );
185
- ?><tr class="em-header"><td><h4><?php echo sprintf(__('%s Options','events-manager'),__('Location','events-manager')); ?></h4></td></tr><?php
186
- em_options_radio_binary ( sprintf(__( 'Locations on main blog?', 'events-manager'), __('locations','events-manager')), 'dbem_ms_mainblog_locations', __('If you would prefer all your locations to belong to your main blog, users in sub-sites will still be able to create locations, but the actual locations are created and reside in the main blog.','events-manager') );
187
- ?>
188
- </tbody>
189
- <tbody class="em-global-options em-global-locations">
190
- <?php
191
- em_options_radio_binary ( sprintf(__( 'Display global %s on main blog?', 'events-manager'), __('locations','events-manager')), 'dbem_ms_global_locations', sprintf($global_post_tip, __('locations','events-manager'), __('locations','events-manager')) );
192
- em_options_radio_binary ( sprintf(__( 'Link sub-site %s directly to sub-site?', 'events-manager'), __('locations','events-manager')), 'dbem_ms_global_locations_links', sprintf($global_link_tip, __('locations','events-manager'), __('location','events-manager')).sprintf($global_link_tip2, __('location','events-manager'), $options_page_link) );
193
- em_options_input_text ( sprintf(__( 'Global %s slug', 'events-manager'),__('location','events-manager')), 'dbem_ms_locations_slug', sprintf($global_slug_tip, __('Locations','events-manager'), __('locations','events-manager')).__('Example:','events-manager').'<code>http://yoursite.com/locations/<strong>location</strong>/subsite-location-slug/', EM_LOCATION_SLUG );
194
- ?>
195
- </tbody>
196
- <?php echo $save_button; ?>
197
- </table>
198
-
199
- </div> <!-- . inside -->
200
- </div> <!-- .postbox -->
201
-
202
- <?php
203
- //including shared MS/non-MS boxes
204
- em_admin_option_box_caps();
205
- em_admin_option_box_image_sizes();
206
- em_admin_option_box_email();
207
- em_admin_option_box_uninstall();
208
- ?>
209
-
210
- <?php do_action('em_ms_options_page_footer'); ?>
211
- </div> <!-- .em-menu-general -->
212
- <?php endif; ?>
213
- <?php
214
- //other tabs
215
- if( $tabs_enabled ){
216
- if( array_key_exists($_REQUEST['em_tab'], $custom_tabs) ){
217
- ?>
218
- <div class="em-menu-bookings em-menu-group">
219
- <?php do_action('em_ms_options_page_tab_'. $_REQUEST['em_tab']); ?>
220
- </div>
221
- <?php
222
- }
223
- }else{
224
- foreach( $custom_tabs as $tab_key => $tab_name ){
225
- ?>
226
- <div class="em-menu-<?php echo esc_attr($tab_key) ?> em-menu-group" style="display:none;">
227
- <?php do_action('em_ms_options_page_tab_'. $tab_key); ?>
228
- </div>
229
- <?php
230
- }
231
- }
232
- ?>
233
-
234
- <p class="submit">
235
- <input type="submit" class="button-primary" name="Submit" value="<?php esc_attr_e( 'Save Changes', 'events-manager'); ?>" />
236
- <input type="hidden" name="em-submitted" value="1" />
237
- <input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce('events-manager-options'); ?>" />
238
- </p>
239
-
240
- </div> <!-- .metabox-sortables -->
241
- </div> <!-- .postbox-container -->
242
-
243
- </div> <!-- .metabox-holder -->
244
- </form>
245
- </div>
246
- <?php
247
- }
248
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/em-options.php DELETED
@@ -1,1042 +0,0 @@
1
- <?php
2
-
3
- //Function composing the options subpanel
4
- function em_options_save(){
5
- global $EM_Notices; /* @var EM_Notices $EM_Notices */
6
- /*
7
- * Here's the idea, we have an array of all options that need super admin approval if in multi-site mode
8
- * since options are only updated here, its one place fit all
9
- */
10
- if( current_user_can('manage_options') && !empty($_POST['em-submitted']) && check_admin_referer('events-manager-options','_wpnonce') ){
11
- //Build the array of options here
12
- $post = $_POST;
13
- foreach ($_POST as $postKey => $postValue){
14
- if( $postKey != 'dbem_data' && substr($postKey, 0, 5) == 'dbem_' ){
15
- //TODO some more validation/reporting
16
- $numeric_options = array('dbem_locations_default_limit','dbem_events_default_limit');
17
- if( in_array($postKey, array('dbem_bookings_notify_admin','dbem_event_submitted_email_admin','dbem_js_limit_events_form','dbem_js_limit_search','dbem_js_limit_general','dbem_css_limit_include','dbem_css_limit_exclude','dbem_search_form_geo_distance_options')) ){ $postValue = str_replace(' ', '', $postValue); } //clean up comma separated emails, no spaces needed
18
- if( in_array($postKey,$numeric_options) && !is_numeric($postValue) ){
19
- //Do nothing, keep old setting.
20
- }elseif( ($postKey == 'dbem_category_default_color' || $postKey == 'dbem_tag_default_color') && !sanitize_hex_color($postValue) ){
21
- $EM_Notices->add_error( sprintf(esc_html_x('Colors must be in a valid %s format, such as #FF00EE.', 'hex format', 'events-manager'), '<a href="http://en.wikipedia.org/wiki/Web_colors">hex</a>').' '. esc_html__('This setting was not changed.', 'events-manager'), true);
22
- }elseif( $postKey == 'dbem_oauth' && is_array($postValue) ){
23
- foreach($postValue as $postValue_key=>$postValue_val){
24
- EM_Options::set($postValue_key, wp_unslash($postValue_val), 'dbem_oauth');
25
- }
26
- }else{
27
- //TODO slashes being added?
28
- if( is_array($postValue) ){
29
- foreach($postValue as $postValue_key=>$postValue_val) $postValue[$postValue_key] = wp_unslash($postValue_val);
30
- }else{
31
- $postValue = wp_unslash($postValue);
32
- }
33
- update_option($postKey, $postValue);
34
- }
35
- }elseif( $postKey == 'dbem_data' && is_array($postValue) ){
36
- foreach( $postValue as $postK => $postV ){
37
- //TODO slashes being added?
38
- if( is_array($postV) ){
39
- foreach($postV as $postValue_key=>$postValue_val) $postV[$postValue_key] = wp_unslash($postValue_val);
40
- }else{
41
- $postV = wp_unslash($postV);
42
- }
43
- EM_Options::set( $postK, $postV );
44
- }
45
- }
46
- }
47
- //set capabilities
48
- if( !empty($_POST['em_capabilities']) && is_array($_POST['em_capabilities']) && (!is_multisite() || is_multisite() && em_wp_is_super_admin()) ){
49
- global $em_capabilities_array, $wp_roles;
50
- if( is_multisite() && is_network_admin() && $_POST['dbem_ms_global_caps'] == 1 ){
51
- //apply_caps_to_blog
52
- global $current_site,$wpdb;
53
- $blog_ids = $wpdb->get_col('SELECT blog_id FROM '.$wpdb->blogs.' WHERE site_id='.$current_site->id);
54
- foreach($blog_ids as $blog_id){
55
- switch_to_blog($blog_id);
56
- //normal blog role application
57
- foreach( $wp_roles->role_objects as $role_name => $role ){
58
- foreach( array_keys($em_capabilities_array) as $capability){
59
- if( !empty($_POST['em_capabilities'][$role_name][$capability]) ){
60
- $role->add_cap($capability);
61
- }else{
62
- $role->remove_cap($capability);
63
- }
64
- }
65
- }
66
- restore_current_blog();
67
- }
68
- }elseif( !is_network_admin() ){
69
- //normal blog role application
70
- foreach( $wp_roles->role_objects as $role_name => $role ){
71
- foreach( array_keys($em_capabilities_array) as $capability){
72
- if( !empty($_POST['em_capabilities'][$role_name][$capability]) ){
73
- $role->add_cap($capability);
74
- }else{
75
- $role->remove_cap($capability);
76
- }
77
- }
78
- }
79
- }
80
- }
81
- update_option('dbem_flush_needed',1);
82
- do_action('em_options_save');
83
- $EM_Notices->add_confirm('<strong>'.__('Changes saved.', 'events-manager').'</strong>', true);
84
- $referrer = em_wp_get_referer();
85
- //add tab hash path to url if supplied
86
- if( !empty($_REQUEST['tab_path']) ){
87
- $referrer_array = explode('#', $referrer);
88
- $referrer = esc_url_raw($referrer_array[0] . '#' . $_REQUEST['tab_path']);
89
- }
90
- wp_safe_redirect($referrer);
91
- exit();
92
- }
93
- //Migration
94
- if( !empty($_GET['em_migrate_images']) && check_admin_referer('em_migrate_images','_wpnonce') && get_option('dbem_migrate_images') ){
95
- include(plugin_dir_path(__FILE__).'../em-install.php');
96
- $result = em_migrate_uploads();
97
- if($result){
98
- $failed = ( $result['fail'] > 0 ) ? $result['fail'] . ' images failed to migrate.' : '';
99
- $EM_Notices->add_confirm('<strong>'.$result['success'].' images migrated successfully. '.$failed.'</strong>');
100
- }
101
- wp_safe_redirect(admin_url().'edit.php?post_type=event&page=events-manager-options&em_migrate_images');
102
- }elseif( !empty($_GET['em_not_migrate_images']) && check_admin_referer('em_not_migrate_images','_wpnonce') ){
103
- delete_option('dbem_migrate_images_nag');
104
- delete_option('dbem_migrate_images');
105
- }
106
- //Uninstall
107
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'uninstall' && current_user_can('activate_plugins') && !empty($_REQUEST['confirmed']) && check_admin_referer('em_uninstall_'.get_current_user_id().'_wpnonce') && em_wp_is_super_admin() ){
108
- if( check_admin_referer('em_uninstall_'.get_current_user_id().'_confirmed','_wpnonce2') ){
109
- //We have a go to uninstall
110
- global $wpdb;
111
- //delete EM posts
112
- remove_action('before_delete_post',array('EM_Location_Post_Admin','before_delete_post'),10,1);
113
- remove_action('before_delete_post',array('EM_Event_Post_Admin','before_delete_post'),10,1);
114
- remove_action('before_delete_post',array('EM_Event_Recurring_Post_Admin','before_delete_post'),10,1);
115
- $post_ids = $wpdb->get_col('SELECT ID FROM '.$wpdb->posts." WHERE post_type IN ('".EM_POST_TYPE_EVENT."','".EM_POST_TYPE_LOCATION."','event-recurring')");
116
- foreach($post_ids as $post_id){
117
- wp_delete_post($post_id);
118
- }
119
- //delete categories
120
- $cat_terms = get_terms(EM_TAXONOMY_CATEGORY, array('hide_empty'=>false));
121
- foreach($cat_terms as $cat_term){
122
- wp_delete_term($cat_term->term_id, EM_TAXONOMY_CATEGORY);
123
- }
124
- $tag_terms = get_terms(EM_TAXONOMY_TAG, array('hide_empty'=>false));
125
- foreach($tag_terms as $tag_term){
126
- wp_delete_term($tag_term->term_id, EM_TAXONOMY_TAG);
127
- }
128
- //delete EM tables
129
- $wpdb->query('DROP TABLE '.EM_EVENTS_TABLE);
130
- $wpdb->query('DROP TABLE '.EM_BOOKINGS_TABLE);
131
- $wpdb->query('DROP TABLE '.EM_LOCATIONS_TABLE);
132
- $wpdb->query('DROP TABLE '.EM_TICKETS_TABLE);
133
- $wpdb->query('DROP TABLE '.EM_TICKETS_BOOKINGS_TABLE);
134
- $wpdb->query('DROP TABLE '.EM_RECURRENCE_TABLE);
135
- $wpdb->query('DROP TABLE '.EM_META_TABLE);
136
-
137
- //delete options
138
- $wpdb->query('DELETE FROM '.$wpdb->options.' WHERE option_name LIKE \'em_%\' OR option_name LIKE \'dbem_%\'');
139
- //deactivate and go!
140
- deactivate_plugins(array('events-manager/events-manager.php','events-manager-pro/events-manager-pro.php'), true);
141
- wp_safe_redirect(admin_url('plugins.php?deactivate=true'));
142
- exit();
143
- }
144
- }
145
- //Reset
146
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'reset' && !empty($_REQUEST['confirmed']) && check_admin_referer('em_reset_'.get_current_user_id().'_wpnonce') && em_wp_is_super_admin() ){
147
- if( check_admin_referer('em_reset_'.get_current_user_id().'_confirmed','_wpnonce2') ){
148
- //We have a go to uninstall
149
- global $wpdb;
150
- //delete options
151
- $wpdb->query('DELETE FROM '.$wpdb->options.' WHERE option_name LIKE \'em_%\' OR option_name LIKE \'dbem_%\'');
152
- //reset capabilities
153
- global $em_capabilities_array, $wp_roles;
154
- foreach( $wp_roles->role_objects as $role_name => $role ){
155
- foreach( array_keys($em_capabilities_array) as $capability){
156
- $role->remove_cap($capability);
157
- }
158
- }
159
- //go back to plugin options page
160
- $EM_Notices->add_confirm(__('Settings have been reset back to default. Your events, locations and categories have not been modified.','events-manager'), true);
161
- wp_safe_redirect(em_wp_get_referer());
162
- exit();
163
- }
164
- }
165
- //Cleanup Event Orphans
166
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'cleanup_event_orphans' && check_admin_referer('em_cleanup_event_orphans_'.get_current_user_id().'_wpnonce') && em_wp_is_super_admin() ){
167
- //Firstly, get all orphans
168
- global $wpdb;
169
- $sql = 'SELECT event_id FROM '.EM_EVENTS_TABLE.' WHERE post_id NOT IN (SELECT ID FROM ' .$wpdb->posts. ' WHERE post_type="'. EM_POST_TYPE_EVENT .'" OR post_type="event-recurring")';
170
- if( EM_MS_GLOBAL ){
171
- if( is_main_site() ){
172
- $sql .= $wpdb->prepare(' AND (blog_id=%d or blog_id IS NULL)', get_current_blog_id());
173
- }else{
174
- $sql .= $wpdb->prepare(' AND blog_id=%d', get_current_blog_id());
175
- }
176
- }
177
- $results = $wpdb->get_col($sql);
178
- $deleted_events = 0;
179
- foreach( $results as $event_id ){
180
- $EM_Event = new EM_Event($event_id);
181
- if( !empty($EM_Event->orphaned_event) && $EM_Event->delete() ){
182
- $deleted_events++;
183
- }
184
- }
185
- //go back to plugin options page
186
- $EM_Notices->add_confirm(sprintf(__('Found %d orphaned events, deleted %d successfully','events-manager'), count($results), $deleted_events), true);
187
- wp_safe_redirect(em_wp_get_referer());
188
- exit();
189
- }
190
- //Force Update Recheck - Workaround for now
191
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'recheck_updates' && check_admin_referer('em_recheck_updates_'.get_current_user_id().'_wpnonce') && em_wp_is_super_admin() ){
192
- //force recheck of plugin updates, to refresh dl links
193
- delete_transient('update_plugins');
194
- delete_site_transient('update_plugins');
195
- $EM_Notices->add_confirm(__('If there are any new updates, you should now see them in your Plugins or Updates admin pages.','events-manager'), true);
196
- wp_safe_redirect(em_wp_get_referer());
197
- exit();
198
- }
199
- //Flag version checking to look at trunk, not tag
200
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'check_devs' && check_admin_referer('em_check_devs_wpnonce') && em_wp_is_super_admin() ){
201
- //delete transients, and add a flag to recheck dev version next time round
202
- delete_transient('update_plugins');
203
- delete_site_transient('update_plugins');
204
- update_option('em_check_dev_version', true);
205
- $EM_Notices->add_confirm(__('Checking for dev versions.','events-manager').' '. __('If there are any new updates, you should now see them in your Plugins or Updates admin pages.','events-manager'), true);
206
- wp_safe_redirect(em_wp_get_referer());
207
- exit();
208
- }
209
- //import EM settings
210
- if( !empty($_REQUEST['action']) && ( ($_REQUEST['action'] == 'import_em_settings' && check_admin_referer('import_em_settings')) || (is_multisite() && $_REQUEST['action'] == 'import_em_ms_settings' && check_admin_referer('import_em_ms_settings')) ) && em_wp_is_super_admin() ){
211
- //upload uniquely named file to system for usage later
212
- if( !empty($_FILES['import_settings_file']['size']) && is_uploaded_file($_FILES['import_settings_file']['tmp_name']) ){
213
- $settings = file_get_contents($_FILES['import_settings_file']['tmp_name']);
214
- $settings = json_decode($settings, true);
215
- if( is_array($settings) ){
216
- if( is_multisite() && $_REQUEST['action'] == 'import_em_ms_settings' ){
217
- global $EM_MS_Globals, $wpdb;
218
- $sitewide_options = $EM_MS_Globals->get_globals();
219
- foreach( $settings as $k => $v ){
220
- if( in_array($k, $sitewide_options) ) update_site_option($k, $v);
221
- }
222
- }else{
223
- foreach( $settings as $k => $v ){
224
- if( preg_match('/^(?:db)emp?_/', $k) ){
225
- update_option($k, $v);
226
- }
227
- }
228
- }
229
- $EM_Notices->add_confirm(__('Settings imported.','events-manager'), true);
230
- wp_safe_redirect(em_wp_get_referer());
231
- exit();
232
- }
233
- }
234
- $EM_Notices->add_error(__('Please upload a valid txt file containing Events Manager import settings.','events-manager'), true);
235
- wp_safe_redirect(em_wp_get_referer());
236
- exit();
237
- }
238
- //export EM settings
239
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'export_em_settings' && check_admin_referer('export_em_settings') && em_wp_is_super_admin() ){
240
- global $wpdb;
241
- $results = $wpdb->get_results('SELECT option_name, option_value FROM '.$wpdb->options ." WHERE option_name LIKE 'dbem_%' OR option_name LIKE 'emp_%' OR option_name LIKE 'em_%'", ARRAY_A);
242
- $options = array();
243
- foreach( $results as $result ) $options[$result['option_name']] = $result['option_value'];
244
- header('Content-Type: text/plain; charset=utf-8');
245
- header('Content-Disposition: attachment; filename="events-manager-settings.txt"');
246
- echo json_encode($options);
247
- exit();
248
- }elseif( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'export_em_ms_settings' && check_admin_referer('export_em_ms_settings') && is_multisite() && em_wp_is_super_admin() ){
249
- //delete transients, and add a flag to recheck dev version next time round
250
- global $EM_MS_Globals, $wpdb;
251
- $options = array();
252
- $sitewide_options = $EM_MS_Globals->get_globals();
253
- foreach( $sitewide_options as $option ) $options[$option] = get_site_option($option);
254
- header('Content-Type: text/plain; charset=utf-8');
255
- header('Content-Disposition: attachment; filename="events-manager-settings.txt"');
256
- echo json_encode($options);
257
- exit();
258
- }
259
-
260
- //reset timezones
261
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'reset_timezones' && check_admin_referer('reset_timezones') && em_wp_is_super_admin() ){
262
- include(EM_DIR.'/em-install.php');
263
- if( empty($_REQUEST['timezone_reset_value']) ) return;
264
- $timezone = str_replace('UTC ', '', $_REQUEST['timezone_reset_value']);
265
- if( is_multisite() ){
266
- if( !empty($_REQUEST['timezone_reset_blog']) && is_numeric($_REQUEST['timezone_reset_blog']) ){
267
- $blog_id = $_REQUEST['timezone_reset_blog'];
268
- switch_to_blog($blog_id);
269
- if( $timezone == 'default' ){
270
- $timezone = str_replace(' ', EM_DateTimeZone::create()->getName());
271
- }
272
- $blog_name = get_bloginfo('name');
273
- $result = em_migrate_datetime_timezones(true, true, $timezone);
274
- restore_current_blog();
275
- }elseif( !empty($_REQUEST['timezone_reset_blog']) && ($_REQUEST['timezone_reset_blog'] == 'all' || $_REQUEST['timezone_reset_blog'] == 'all-resume') ){
276
- global $wpdb, $current_site;
277
- $blog_ids = $blog_ids_progress = get_site_option('dbem_reset_timezone_multisite_progress', false);
278
- if( !is_array($blog_ids) || $_REQUEST['timezone_reset_blog'] == 'all' ){
279
- $blog_ids = $blog_ids_progress = $wpdb->get_col('SELECT blog_id FROM '.$wpdb->blogs.' WHERE site_id='.$current_site->id);
280
- update_site_option('dbem_reset_timezone_multisite_progress', $blog_ids_progress);
281
- }
282
- foreach($blog_ids as $k => $blog_id){
283
- $result = true;
284
- $plugin_basename = plugin_basename(dirname(dirname(__FILE__)).'/events-manager.php');
285
- if( in_array( $plugin_basename, (array) get_blog_option($blog_id, 'active_plugins', array() ) ) || is_plugin_active_for_network($plugin_basename) ){
286
- switch_to_blog($blog_id);
287
- $blog_timezone = $timezone == 'default' ? str_replace(' ', '', EM_DateTimeZone::create()->getName()) : $timezone;
288
- $blog_name = get_bloginfo('name');
289
- $blog_result = em_migrate_datetime_timezones(true, true, $blog_timezone);
290
- if( !$blog_result ){
291
- $fails[$blog_id] = $blog_name;
292
- }else{
293
- unset($blog_ids_progress[$k]);
294
- update_site_option('dbem_reset_timezone_multisite_progress', $blog_ids_progress);
295
- }
296
- }
297
- }
298
- if( !empty($fails) ){
299
- $result = __('The following blog timezones could not be successfully reset:', 'events-manager');
300
- $result .= '<ul>';
301
- foreach( $fails as $fail ) $result .= '<li>'.$fail.'</li>';
302
- $result .= '</ul>';
303
- }else{
304
- delete_site_option('dbem_reset_timezone_multisite_progress');
305
- EM_Admin_Notices::remove('date_time_migration_5.9_multisite', true);
306
- }
307
- restore_current_blog();
308
- }else{
309
- $result = __('A valid blog ID must be provided, you can only reset one blog at a time.','events-manager');
310
- }
311
- }else{
312
- $result = em_migrate_datetime_timezones(true, true, $timezone);
313
- }
314
- if( $result !== true ){
315
- $EM_Notices->add_error($result, true);
316
- }else{
317
- if( is_multisite() ){
318
- if( $_REQUEST['timezone_reset_blog'] == 'all' || $_REQUEST['timezone_reset_blog'] == 'all-resume' ){
319
- $EM_Notices->add_confirm(sprintf(__('Event timezones on all blogs have been reset to %s.','events-manager'), '<code>'.$timezone.'</code>'), true);
320
- }else{
321
- $EM_Notices->add_confirm(sprintf(__('Event timezones for blog %s have been reset to %s.','events-manager'), '<code>'.$blog_name.'</code>', '<code>'.$timezone.'</code>'), true);
322
- }
323
- }else{
324
- $EM_Notices->add_confirm(sprintf(__('Event timezones have been reset to %s.','events-manager'), '<code>'.$timezone.'</code>'), true);
325
- }
326
- }
327
- wp_safe_redirect(em_wp_get_referer());
328
- exit();
329
- }
330
-
331
- //update scripts that may need to run
332
- $blog_updates = is_multisite() ? array_merge(EM_Options::get('updates'), EM_Options::site_get('updates')) : EM_Options::get('updates');
333
- if( is_array($blog_updates) ) {
334
- foreach ( $blog_updates as $update => $update_data ) {
335
- $filename = EM_DIR . '/admin/settings/updates/' . $update . '.php';
336
- if ( file_exists( $filename ) ) {
337
- include_once( $filename );
338
- }
339
- do_action( 'em_admin_update_' . $update, $update_data );
340
- }
341
- }
342
- }
343
- add_action('admin_init', 'em_options_save');
344
-
345
- function em_admin_email_test_ajax(){
346
- if( wp_verify_nonce($_REQUEST['_check_email_nonce'],'check_email') && current_user_can('activate_plugins') ){
347
- $subject = __("Events Manager Test Email",'events-manager');
348
- $content = __('Congratulations! Your email settings work.','events-manager');
349
- $current_user = get_user_by('id', get_current_user_id());
350
- //add filters for options used in EM_Mailer so the current supplied ones are used
351
- ob_start();
352
- function pre_option_dbem_mail_sender_name(){ return sanitize_text_field($_REQUEST['dbem_mail_sender_name']); }
353
- add_filter('pre_option_dbem_mail_sender_name', 'pre_option_dbem_mail_sender_name');
354
- function pre_option_dbem_mail_sender_address(){ return sanitize_text_field($_REQUEST['dbem_mail_sender_address']); }
355
- add_filter('pre_option_dbem_mail_sender_address', 'pre_option_dbem_mail_sender_address');
356
- function pre_option_dbem_rsvp_mail_send_method(){ return sanitize_text_field($_REQUEST['dbem_rsvp_mail_send_method']); }
357
- add_filter('pre_option_dbem_rsvp_mail_send_method', 'pre_option_dbem_rsvp_mail_send_method');
358
- function pre_option_dbem_rsvp_mail_port(){ return sanitize_text_field($_REQUEST['dbem_rsvp_mail_port']); }
359
- add_filter('pre_option_dbem_rsvp_mail_port', 'pre_option_dbem_rsvp_mail_port');
360
- function pre_option_dbem_smtp_encryption(){ return sanitize_text_field($_REQUEST['dbem_smtp_encryption']); }
361
- add_filter('pre_option_dbem_smtp_encryption', 'pre_option_dbem_smtp_encryption');
362
- function pre_option_dbem_smtp_autotls(){ return sanitize_text_field($_REQUEST['dbem_smtp_autotls']); }
363
- add_filter('pre_option_dbem_smtp_autotls', 'pre_option_dbem_smtp_autotls');
364
- function pre_option_dbem_rsvp_mail_SMTPAuth(){ return sanitize_text_field($_REQUEST['dbem_rsvp_mail_SMTPAuth']); }
365
- add_filter('pre_option_dbem_rsvp_mail_SMTPAuth', 'pre_option_dbem_rsvp_mail_SMTPAuth');
366
- function pre_option_dbem_smtp_host(){ return sanitize_text_field($_REQUEST['dbem_smtp_host']); }
367
- add_filter('pre_option_dbem_smtp_host', 'pre_option_dbem_smtp_host');
368
- function pre_option_dbem_smtp_username(){ return sanitize_text_field($_REQUEST['dbem_smtp_username']); }
369
- add_filter('pre_option_dbem_smtp_username', 'pre_option_dbem_smtp_username');
370
- function pre_option_dbem_smtp_password(){ return sanitize_text_field($_REQUEST['dbem_smtp_password']); }
371
- add_filter('pre_option_dbem_smtp_password', 'pre_option_dbem_smtp_password');
372
- ob_clean(); //remove any php errors/warnings output
373
- $EM_Event = new EM_Event();
374
- if( $EM_Event->email_send($subject,$content,$current_user->user_email) ){
375
- $result = array(
376
- 'result' => true,
377
- 'message' => sprintf(__('Email sent successfully to %s','events-manager'),$current_user->user_email)
378
- );
379
- }else{
380
- $result = array(
381
- 'result' => false,
382
- 'message' => __('Email not sent.','events-manager')." <ul><li>".implode('</li><li>',$EM_Event->get_errors()).'</li></ul>'
383
- );
384
- }
385
- echo EM_Object::json_encode($result);
386
- }
387
- exit();
388
- }
389
- add_action('wp_ajax_em_admin_test_email','em_admin_email_test_ajax');
390
-
391
- function em_admin_options_reset_page(){
392
- if( check_admin_referer('em_reset_'.get_current_user_id().'_wpnonce') && em_wp_is_super_admin() ){
393
- ?>
394
- <div class="wrap">
395
- <div id='icon-options-general' class='icon32'><br /></div>
396
- <h2><?php _e('Reset Events Manager','events-manager'); ?></h2>
397
- <p style="color:red; font-weight:bold;"><?php _e('Are you sure you want to reset Events Manager?','events-manager')?></p>
398
- <p style="font-weight:bold;"><?php _e('All your settings, including email templates and template formats for Events Manager will be deleted.','events-manager')?></p>
399
- <p>
400
- <a href="<?php echo esc_url(add_query_arg(array('_wpnonce2' => wp_create_nonce('em_reset_'.get_current_user_id().'_confirmed'), 'confirmed'=>1))); ?>" class="button-primary"><?php _e('Reset Events Manager','events-manager'); ?></a>
401
- <a href="<?php echo esc_url(em_wp_get_referer()); ?>" class="button-secondary"><?php _e('Cancel','events-manager'); ?></a>
402
- </p>
403
- </div>
404
- <?php
405
- }
406
- }
407
- function em_admin_options_uninstall_page(){
408
- if( check_admin_referer('em_uninstall_'.get_current_user_id().'_wpnonce') && em_wp_is_super_admin() ){
409
- ?>
410
- <div class="wrap">
411
- <div id='icon-options-general' class='icon32'><br /></div>
412
- <h2><?php _e('Uninstall Events Manager','events-manager'); ?></h2>
413
- <p style="color:red; font-weight:bold;"><?php _e('Are you sure you want to uninstall Events Manager?','events-manager')?></p>
414
- <p style="font-weight:bold;"><?php _e('All your settings and events will be permanently deleted. This cannot be undone.','events-manager')?></p>
415
- <p><?php echo sprintf(__('If you just want to deactivate the plugin, <a href="%s">go to your plugins page</a>.','events-manager'), wp_nonce_url(admin_url('plugins.php'))); ?></p>
416
- <p>
417
- <a href="<?php echo esc_url(add_query_arg(array('_wpnonce2' => wp_create_nonce('em_uninstall_'.get_current_user_id().'_confirmed'), 'confirmed'=>1))); ?>" class="button-primary"><?php _e('Uninstall and Deactivate','events-manager'); ?></a>
418
- <a href="<?php echo esc_url(em_wp_get_referer()); ?>" class="button-secondary"><?php _e('Cancel','events-manager'); ?></a>
419
- </p>
420
- </div>
421
- <?php
422
- }
423
- }
424
-
425
- function em_admin_options_page() {
426
- global $wpdb, $EM_Notices;
427
- //Check for uninstall/reset request
428
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'uninstall' ){
429
- em_admin_options_uninstall_page();
430
- return;
431
- }
432
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'reset' ){
433
- em_admin_options_reset_page();
434
- return;
435
- }
436
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'update' && !empty($_REQUEST['update_action']) ){
437
- do_action('em_admin_update_settings_confirm_'.$_REQUEST['update_action']);
438
- return;
439
- }
440
- //substitute dropdowns with input boxes for some situations to improve speed, e.g. if there 1000s of locations or users
441
- $total_users = $wpdb->get_var("SELECT COUNT(ID) FROM {$wpdb->users};");
442
- if( $total_users > 100 && !defined('EM_OPTIMIZE_SETTINGS_PAGE_USERS') ){ define('EM_OPTIMIZE_SETTINGS_PAGE_USERS',true); }
443
- $total_locations = EM_Locations::count();
444
- if( $total_locations > 100 && !defined('EM_OPTIMIZE_SETTINGS_PAGE_LOCATIONS') ){ define('EM_OPTIMIZE_SETTINGS_PAGE_LOCATIONS',true); }
445
- //TODO place all options into an array
446
- global $events_placeholder_tip, $locations_placeholder_tip, $categories_placeholder_tip, $bookings_placeholder_tip;
447
- $events_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;page=events-manager-help#event-placeholders">'. __('Event Related Placeholders','events-manager') .'</a>';
448
- $locations_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;page=events-manager-help#location-placeholders">'. __('Location Related Placeholders','events-manager') .'</a>';
449
- $bookings_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;page=events-manager-help#booking-placeholders">'. __('Booking Related Placeholders','events-manager') .'</a>';
450
- $categories_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;page=events-manager-help#category-placeholders">'. __('Category Related Placeholders','events-manager') .'</a>';
451
- $events_placeholder_tip = " ". sprintf(__('This accepts %s and %s placeholders.','events-manager'),$events_placeholders, $locations_placeholders);
452
- $locations_placeholder_tip = " ". sprintf(__('This accepts %s placeholders.','events-manager'), $locations_placeholders);
453
- $categories_placeholder_tip = " ". sprintf(__('This accepts %s placeholders.','events-manager'), $categories_placeholders);
454
- $bookings_placeholder_tip = " ". sprintf(__('This accepts %s, %s and %s placeholders.','events-manager'), $bookings_placeholders, $events_placeholders, $locations_placeholders);
455
-
456
- global $save_button;
457
- $save_button = '<tr><th>&nbsp;</th><td><p class="submit" style="margin:0px; padding:0px; text-align:right;"><input type="submit" class="button-primary" name="Submit" value="'. __( 'Save Changes', 'events-manager') .' ('. __('All','events-manager') .')" /></p></td></tr>';
458
-
459
- if( !is_multisite() ) em_pro_update_notice();
460
-
461
- if( defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS ){
462
- $tabs_enabled = true;
463
- $general_tab_link = esc_url(add_query_arg( array('em_tab'=>'general')));
464
- $pages_tab_link = esc_url(add_query_arg( array('em_tab'=>'pages')));
465
- $formats_tab_link = esc_url(add_query_arg( array('em_tab'=>'formats')));
466
- $bookings_tab_link = esc_url(add_query_arg( array('em_tab'=>'bookings')));
467
- $emails_tab_link = esc_url(add_query_arg( array('em_tab'=>'emails')));
468
- }else{
469
- $general_tab_link = $pages_tab_link = $formats_tab_link = $bookings_tab_link = $emails_tab_link = '';
470
- }
471
- ?>
472
- <script type="text/javascript" charset="utf-8"><?php include(EM_DIR.'/includes/js/admin-settings.js'); ?></script>
473
- <style type="text/css">.postbox h3 { cursor:pointer; }</style>
474
- <div class="wrap <?php if(empty($tabs_enabled)) echo 'tabs-active' ?>">
475
- <h1 id="em-options-title"><?php _e ( 'Event Manager Options', 'events-manager'); ?></h1>
476
- <h2 class="nav-tab-wrapper">
477
- <a href="<?php echo $general_tab_link; ?>#general" id="em-menu-general" class="nav-tab nav-tab-active"><?php _e('General','events-manager'); ?></a>
478
- <a href="<?php echo $pages_tab_link; ?>#pages" id="em-menu-pages" class="nav-tab"><?php _e('Pages','events-manager'); ?></a>
479
- <a href="<?php echo $formats_tab_link; ?>#formats" id="em-menu-formats" class="nav-tab"><?php _e('Formatting','events-manager'); ?></a>
480
- <?php if( get_option('dbem_rsvp_enabled') ): ?>
481
- <a href="<?php echo $bookings_tab_link; ?>#bookings" id="em-menu-bookings" class="nav-tab"><?php _e('Bookings','events-manager'); ?></a>
482
- <?php endif; ?>
483
- <a href="<?php echo $emails_tab_link; ?>#emails" id="em-menu-emails" class="nav-tab"><?php _e('Emails','events-manager'); ?></a>
484
- <?php
485
- $custom_tabs = apply_filters('em_options_page_tabs', array());
486
- foreach( $custom_tabs as $tab_key => $tab_name ){
487
- $tab_link = !empty($tabs_enabled) ? esc_url(add_query_arg( array('em_tab'=>$tab_key))) : '';
488
- $active_class = !empty($tabs_enabled) && !empty($_GET['em_tab']) && $_GET['em_tab'] == $tab_key ? 'nav-tab-active':'';
489
- echo "<a href='$tab_link#$tab_key' id='em-menu-$tab_key' class='nav-tab $active_class'>$tab_name</a>";
490
- }
491
- ?>
492
- </h2>
493
- <form id="em-options-form" method="post" action="">
494
- <div class="metabox-holder">
495
- <!-- // TODO Move style in css -->
496
- <div class='postbox-container' style='width: 99.5%'>
497
- <div id="">
498
-
499
- <?php
500
- if( !empty($tabs_enabled) ){
501
- if( empty($_REQUEST['em_tab']) || $_REQUEST['em_tab'] == 'general' ){
502
- include('settings/tabs/general.php');
503
- }else{
504
- if( $_REQUEST['em_tab'] == 'pages' ) include('settings/tabs/pages.php');
505
- if( $_REQUEST['em_tab'] == 'formats' ) include('settings/tabs/formats.php');
506
- if( get_option('dbem_rsvp_enabled') && $_REQUEST['em_tab'] == 'bookings' ){
507
- include('settings/tabs/bookings.php');
508
- }
509
- if( $_REQUEST['em_tab'] == 'emails' ) include('settings/tabs/emails.php');
510
- if( array_key_exists($_REQUEST['em_tab'], $custom_tabs) ){
511
- ?>
512
- <div class="em-menu-<?php echo esc_attr($_REQUEST['em_tab']) ?> em-menu-group">
513
- <?php do_action('em_options_page_tab_'. $_REQUEST['em_tab']); ?>
514
- </div>
515
- <?php
516
- }
517
- }
518
- }else{
519
- include('settings/tabs/general.php');
520
- include('settings/tabs/pages.php');
521
- include('settings/tabs/formats.php');
522
- if( get_option('dbem_rsvp_enabled') ){
523
- include('settings/tabs/bookings.php');
524
- }
525
- include('settings/tabs/emails.php');
526
- foreach( $custom_tabs as $tab_key => $tab_name ){
527
- ?>
528
- <div class="em-menu-<?php echo esc_attr($tab_key) ?> em-menu-group" style="display:none;">
529
- <?php do_action('em_options_page_tab_'. $tab_key); ?>
530
- </div>
531
- <?php
532
- }
533
- }
534
- ?>
535
-
536
- <?php /*
537
- <div class="postbox " >
538
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Debug Modes', 'events-manager'); ?> </span></h3>
539
- <div class="inside">
540
- <table class='form-table'>
541
- <?php
542
- em_options_radio_binary ( __( 'EM Debug Mode?', 'events-manager'), 'dbem_debug', __( 'Setting this to yes will display different content to admins for event pages and emails so you can see all the available placeholders and their values.', 'events-manager') );
543
- em_options_radio_binary ( __( 'WP Debug Mode?', 'events-manager'), 'dbem_wp_debug', __( 'This will turn WP_DEBUG mode on. Useful if you want to troubleshoot php errors without looking at your logs.', 'events-manager') );
544
- ?>
545
- </table>
546
- </div> <!-- . inside -->
547
- </div> <!-- .postbox -->
548
- */ ?>
549
-
550
- <p class="submit">
551
- <input type="submit" class="button-primary" name="Submit" value="<?php esc_attr_e( 'Save Changes', 'events-manager'); ?>" />
552
- <input type="hidden" name="em-submitted" value="1" />
553
- <input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce('events-manager-options'); ?>" />
554
- </p>
555
-
556
- </div> <!-- .metabox-sortables -->
557
- </div> <!-- .postbox-container -->
558
-
559
- </div> <!-- .metabox-holder -->
560
- </form>
561
- </div>
562
- <?php
563
- }
564
-
565
- /**
566
- * Meta options box for image sizes. Shared in both MS and Normal options page, hence it's own function
567
- */
568
- function em_admin_option_box_image_sizes(){
569
- global $save_button;
570
- ?>
571
- <div class="postbox " id="em-opt-image-sizes" >
572
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Image Sizes', 'events-manager'); ?> </span></h3>
573
- <div class="inside">
574
- <p class="em-boxheader"><?php _e('These settings will only apply to the image uploading if using our front-end forms. In your WP admin area, images are handled by WordPress.','events-manager'); ?></p>
575
- <table class='form-table'>
576
- <?php
577
- em_options_input_text ( __( 'Maximum width (px)', 'events-manager'), 'dbem_image_max_width', __( 'The maximum allowed width for images uploads', 'events-manager') );
578
- em_options_input_text ( __( 'Minimum width (px)', 'events-manager'), 'dbem_image_min_width', __( 'The minimum allowed width for images uploads', 'events-manager') );
579
- em_options_input_text ( __( 'Maximum height (px)', 'events-manager'), 'dbem_image_max_height', __( "The maximum allowed height for images uploaded, in pixels", 'events-manager') );
580
- em_options_input_text ( __( 'Minimum height (px)', 'events-manager'), 'dbem_image_min_height', __( "The minimum allowed height for images uploaded, in pixels", 'events-manager') );
581
- em_options_input_text ( __( 'Maximum size (bytes)', 'events-manager'), 'dbem_image_max_size', __( "The maximum allowed size for images uploaded, in bytes", 'events-manager') );
582
- echo $save_button;
583
- ?>
584
- </table>
585
- </div> <!-- . inside -->
586
- </div> <!-- .postbox -->
587
- <?php
588
- }
589
-
590
- /**
591
- * Meta options box for email settings. Shared in both MS and Normal options page, hence it's own function
592
- */
593
- function em_admin_option_box_email(){
594
- global $save_button;
595
- $current_user = get_user_by('id', get_current_user_id());
596
- ?>
597
- <div class="postbox " id="em-opt-email-settings">
598
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Email Settings', 'events-manager'); ?></span></h3>
599
- <div class="inside em-email-form">
600
- <p class="em-email-settings-check em-boxheader">
601
- <em><?php _e('Before you save your changes, you can quickly send yourself a test email by clicking this button.','events-manager'); ?>
602
- <?php echo sprintf(__('A test email will be sent to your account email - %s','events-manager'), $current_user->user_email . ' <a href="'.admin_url( 'profile.php' ).'">'.__('edit','events-manager').'</a>'); ?></em><br />
603
- <input type="button" id="em-admin-check-email" class="button-secondary" value="<?php esc_attr_e('Test Email Settings','events-manager'); ?>" />
604
- <input type="hidden" name="_check_email_nonce" value="<?php echo wp_create_nonce('check_email'); ?>" />
605
- <span id="em-email-settings-check-status"></span>
606
- </p>
607
- <table class="form-table">
608
- <?php
609
- em_options_input_text ( __( 'Notification sender name', 'events-manager'), 'dbem_mail_sender_name', __( "Insert the display name of the notification sender.", 'events-manager') );
610
- em_options_input_text ( __( 'Notification sender address', 'events-manager'), 'dbem_mail_sender_address', __( "Insert the address of the notification sender.", 'events-manager') );
611
- em_options_select ( __( 'Mail sending method', 'events-manager'), 'dbem_rsvp_mail_send_method', array ('smtp' => 'SMTP', 'mail' => __( 'PHP mail function', 'events-manager'), 'sendmail' => 'Sendmail', 'qmail' => 'Qmail', 'wp_mail' => 'WP Mail' ), __( 'Select the method to send email notification.', 'events-manager') );
612
- em_options_radio_binary ( __( 'Send HTML Emails?', 'events-manager'), 'dbem_smtp_html', __( 'If set to yes, your emails will be sent in HTML format, otherwise plaintext.', 'events-manager').' '.__( 'Depending on server settings, some sending methods may ignore this settings.', 'events-manager') );
613
- em_options_radio_binary ( __( 'Add br tags to HTML emails?', 'events-manager'), 'dbem_smtp_html_br', __( 'If HTML emails are enabled, br tags will automatically be added for new lines.', 'events-manager') );
614
- ?>
615
- <tbody class="em-email-settings-smtp">
616
- <?php
617
- em_options_input_text ( 'Mail sending port', 'dbem_rsvp_mail_port', __( "The port through which you e-mail notifications will be sent. Make sure the firewall doesn't block this port", 'events-manager') );
618
- em_options_radio_binary ( __( 'Use SMTP authentication?', 'events-manager'), 'dbem_rsvp_mail_SMTPAuth', __( 'SMTP authentication is often needed. If you use Gmail, make sure to set this parameter to Yes', 'events-manager') );
619
- em_options_select ( __( 'SMTP Encryption', 'events-manager'), 'dbem_smtp_encryption', array ('0' => __( 'None', 'events-manager'), 'ssl' => 'SSL', 'tls' => 'TLS' ), __( 'Encryption is always recommended if your SMTP server supports it. If your server supports TLS, this is also the most recommended method.', 'events-manager') );
620
- em_options_radio_binary ( __( 'AutoTLS', 'events-manager'), 'dbem_smtp_autotls', __( 'We recommend leaving this on unless you are experiencing issues configuring your email.', 'events-manager') );
621
- em_options_input_text ( 'SMTP host', 'dbem_smtp_host', __( "The SMTP host. Usually it corresponds to 'localhost'. If you use Gmail, set this value to 'tls://smtp.gmail.com:587'.", 'events-manager') );
622
- em_options_input_text ( __( 'SMTP username', 'events-manager'), 'dbem_smtp_username', __( "Insert the username to be used to access your SMTP server.", 'events-manager') );
623
- em_options_input_password ( __( 'SMTP password', 'events-manager'), "dbem_smtp_password", __( "Insert the password to be used to access your SMTP server", 'events-manager') );
624
- ?>
625
- </tbody>
626
- <?php
627
- echo $save_button;
628
- ?>
629
- </table>
630
- <script type="text/javascript" charset="utf-8">
631
- jQuery(document).ready(function($){
632
- $('#dbem_rsvp_mail_send_method_row select').on('change', function(){
633
- el = $(this);
634
- if( el.find(':selected').val() == 'smtp' ){
635
- $('.em-email-settings-smtp').show();
636
- }else{
637
- $('.em-email-settings-smtp').hide();
638
- }
639
- }).trigger('change');
640
- $('input#em-admin-check-email').on('click', function(e,el){
641
- var email_data = $('.em-email-form input, .em-email-form select').serialize();
642
- $.ajax({
643
- url: EM.ajaxurl,
644
- dataType: 'json',
645
- data: email_data+"&action=em_admin_test_email",
646
- success: function(data){
647
- if(data.result && data.message){
648
- $('#em-email-settings-check-status').css({'color':'green','display':'block'}).html(data.message);
649
- }else{
650
- var msg = (data.message) ? data.message:'Email not sent';
651
- $('#em-email-settings-check-status').css({'color':'red','display':'block'}).html(msg);
652
- }
653
- },
654
- error: function(){ $('#em-email-settings-check-status').css({'color':'red','display':'block'}).html('Server Error'); },
655
- beforeSend: function(){ $('input#em-admin-check-email').val('<?php _e('Checking...','events-manager') ?>'); },
656
- complete: function(){ $('input#em-admin-check-email').val('<?php _e('Test Email Settings','events-manager'); ?>'); }
657
- });
658
- });
659
- });
660
- </script>
661
- </div> <!-- . inside -->
662
- </div> <!-- .postbox -->
663
- <?php
664
- }
665
-
666
- /**
667
- * Meta options box for user capabilities. Shared in both MS and Normal options page, hence it's own function
668
- */
669
- function em_admin_option_box_caps(){
670
- global $save_button, $wpdb;
671
- ?>
672
- <div class="postbox" id="em-opt-user-caps" >
673
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'User Capabilities', 'events-manager'); ?></span></h3>
674
- <div class="inside">
675
- <table class="form-table">
676
- <tr><td colspan="2" class="em-boxheader">
677
- <p><strong><?php _e('Warning: Changing these values may result in exposing previously hidden information to all users.', 'events-manager')?></strong></p>
678
- <p><em><?php _e('You can now give fine grained control with regards to what your users can do with events. Each user role can have perform different sets of actions.','events-manager'); ?></em></p>
679
- </td></tr>
680
- <?php
681
- global $wp_roles;
682
- $cap_docs = array(
683
- sprintf(__('%s Capabilities','events-manager'),__('Event','events-manager')) => array(
684
- /* Event Capabilities */
685
- 'publish_events' => sprintf(__('Users can publish %s and skip any admin approval','events-manager'),__('events','events-manager')),
686
- 'delete_others_events' => sprintf(__('User can delete other users %s','events-manager'),__('events','events-manager')),
687
- 'edit_others_events' => sprintf(__('User can edit other users %s','events-manager'),__('events','events-manager')),
688
- 'delete_events' => sprintf(__('User can delete their own %s','events-manager'),__('events','events-manager')),
689
- 'edit_events' => sprintf(__('User can create and edit %s','events-manager'),__('events','events-manager')),
690
- 'read_private_events' => sprintf(__('User can view private %s','events-manager'),__('events','events-manager')),
691
- /*'read_events' => sprintf(__('User can view %s','events-manager'),__('events','events-manager')),*/
692
- ),
693
- sprintf(__('%s Capabilities','events-manager'),__('Recurring Event','events-manager')) => array(
694
- /* Recurring Event Capabilties */
695
- 'publish_recurring_events' => sprintf(__('Users can publish %s and skip any admin approval','events-manager'),__('recurring events','events-manager')),
696
- 'delete_others_recurring_events' => sprintf(__('User can delete other users %s','events-manager'),__('recurring events','events-manager')),
697
- 'edit_others_recurring_events' => sprintf(__('User can edit other users %s','events-manager'),__('recurring events','events-manager')),
698
- 'delete_recurring_events' => sprintf(__('User can delete their own %s','events-manager'),__('recurring events','events-manager')),
699
- 'edit_recurring_events' => sprintf(__('User can create and edit %s','events-manager'),__('recurring events','events-manager'))
700
- ),
701
- sprintf(__('%s Capabilities','events-manager'),__('Location','events-manager')) => array(
702
- /* Location Capabilities */
703
- 'publish_locations' => sprintf(__('Users can publish %s and skip any admin approval','events-manager'),__('locations','events-manager')),
704
- 'delete_others_locations' => sprintf(__('User can delete other users %s','events-manager'),__('locations','events-manager')),
705
- 'edit_others_locations' => sprintf(__('User can edit other users %s','events-manager'),__('locations','events-manager')),
706
- 'delete_locations' => sprintf(__('User can delete their own %s','events-manager'),__('locations','events-manager')),
707
- 'edit_locations' => sprintf(__('User can create and edit %s','events-manager'),__('locations','events-manager')),
708
- 'read_private_locations' => sprintf(__('User can view private %s','events-manager'),__('locations','events-manager')),
709
- 'read_others_locations' => __('User can use other user locations for their events.','events-manager'),
710
- /*'read_locations' => sprintf(__('User can view %s','events-manager'),__('locations','events-manager')),*/
711
- ),
712
- sprintf(__('%s Capabilities','events-manager'),__('Other','events-manager')) => array(
713
- /* Category Capabilities */
714
- 'delete_event_categories' => sprintf(__('User can delete %s categories and tags.','events-manager'),__('event','events-manager')),
715
- 'edit_event_categories' => sprintf(__('User can edit %s categories and tags.','events-manager'),__('event','events-manager')),
716
- /* Booking Capabilities */
717
- 'manage_others_bookings' => __('User can manage other users individual bookings and event booking settings.','events-manager'),
718
- 'manage_bookings' => __('User can use and manage bookings with their events.','events-manager'),
719
- 'upload_event_images' => __('User can upload images along with their events and locations.','events-manager')
720
- )
721
- );
722
- ?>
723
- <?php
724
- if( is_multisite() && is_network_admin() ){
725
- echo em_options_radio_binary(__('Apply global capabilities?','events-manager'), 'dbem_ms_global_caps', __('If set to yes the capabilities will be applied all your network blogs and you will not be able to set custom capabilities each blog. You can select no later and visit specific blog settings pages to add/remove capabilities.','events-manager') );
726
- }
727
- ?>
728
- <tr><td colspan="2">
729
- <table class="em-caps-table" style="width:auto;" cellspacing="0" cellpadding="0">
730
- <thead>
731
- <tr>
732
- <td>&nbsp;</td>
733
- <?php
734
- $odd = 0;
735
- foreach(array_keys($cap_docs) as $capability_group){
736
- ?><th class="<?php echo ( !is_int($odd/2) ) ? 'odd':''; ?>"><?php echo $capability_group ?></th><?php
737
- $odd++;
738
- }
739
- ?>
740
- </tr>
741
- </thead>
742
- <tbody>
743
- <?php foreach($wp_roles->role_objects as $role): ?>
744
- <tr>
745
- <td class="cap"><strong><?php echo $role->name; ?></strong></td>
746
- <?php
747
- $odd = 0;
748
- foreach($cap_docs as $capability_group){
749
- ?>
750
- <td class="<?php echo ( !is_int($odd/2) ) ? 'odd':''; ?>">
751
- <?php foreach($capability_group as $cap => $cap_help){ ?>
752
- <input type="checkbox" name="em_capabilities[<?php echo $role->name; ?>][<?php echo $cap ?>]" value="1" id="<?php echo $role->name.'_'.$cap; ?>" <?php echo $role->has_cap($cap) ? 'checked="checked"':''; ?> />
753
- &nbsp;<label for="<?php echo $role->name.'_'.$cap; ?>"><?php echo $cap; ?></label>&nbsp;<a href="#" title="<?php echo $cap_help; ?>">?</a>
754
- <br />
755
- <?php } ?>
756
- </td>
757
- <?php
758
- $odd++;
759
- }
760
- ?>
761
- </tr>
762
- <?php endforeach; ?>
763
- </tbody>
764
- </table>
765
- </td></tr>
766
- <?php echo $save_button; ?>
767
- </table>
768
- </div> <!-- . inside -->
769
- </div> <!-- .postbox -->
770
- <?php
771
- }
772
-
773
- function em_admin_option_box_uninstall(){
774
- global $save_button;
775
- if( is_multisite() ){
776
- $uninstall_url = admin_url().'network/admin.php?page=events-manager-options&amp;action=uninstall&amp;_wpnonce='.wp_create_nonce('em_uninstall_'.get_current_user_id().'_wpnonce');
777
- $reset_url = admin_url().'network/admin.php?page=events-manager-options&amp;action=reset&amp;_wpnonce='.wp_create_nonce('em_reset_'.get_current_user_id().'_wpnonce');
778
- $recheck_updates_url = admin_url().'network/admin.php?page=events-manager-options&amp;action=recheck_updates&amp;_wpnonce='.wp_create_nonce('em_recheck_updates_'.get_current_user_id().'_wpnonce');
779
- $cleanup_event_orphans_url = admin_url().'network/admin.php?page=events-manager-options&amp;action=cleanup_event_orphans&amp;_wpnonce='.wp_create_nonce('em_cleanup_event_orphans_'.get_current_user_id().'_wpnonce');
780
- $check_devs = admin_url().'network/admin.php?page=events-manager-options&amp;action=check_devs&amp;_wpnonce='.wp_create_nonce('em_check_devs_wpnonce');
781
- $export_settings_url = admin_url().'network/admin.php?page=events-manager-options&amp;action=export_em_ms_settings&amp;_wpnonce='.wp_create_nonce('export_em_ms_settings');
782
- $import_nonce = wp_create_nonce('import_em_ms_settings');
783
- }else{
784
- $uninstall_url = EM_ADMIN_URL.'&amp;page=events-manager-options&amp;action=uninstall&amp;_wpnonce='.wp_create_nonce('em_uninstall_'.get_current_user_id().'_wpnonce');
785
- $reset_url = EM_ADMIN_URL.'&amp;page=events-manager-options&amp;action=reset&amp;_wpnonce='.wp_create_nonce('em_reset_'.get_current_user_id().'_wpnonce');
786
- $recheck_updates_url = EM_ADMIN_URL.'&amp;page=events-manager-options&amp;action=recheck_updates&amp;_wpnonce='.wp_create_nonce('em_recheck_updates_'.get_current_user_id().'_wpnonce');
787
- $cleanup_event_orphans_url= EM_ADMIN_URL.'&amp;page=events-manager-options&amp;action=cleanup_event_orphans&amp;_wpnonce='.wp_create_nonce('em_cleanup_event_orphans_'.get_current_user_id().'_wpnonce');
788
- $check_devs = EM_ADMIN_URL.'&amp;page=events-manager-options&amp;action=check_devs&amp;_wpnonce='.wp_create_nonce('em_check_devs_wpnonce');
789
- $export_settings_url = EM_ADMIN_URL.'&amp;page=events-manager-options&amp;action=export_em_settings&amp;_wpnonce='.wp_create_nonce('export_em_settings');
790
- $import_nonce = wp_create_nonce('import_em_settings');
791
- }
792
- $reset_timezone_nonce = wp_create_nonce('reset_timezones');
793
- $options_data = get_option('dbem_data');
794
- ?>
795
- <div class="postbox" id="em-opt-admin-tools" >
796
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Admin Tools', 'events-manager'); ?> (<?php _e ( 'Advanced', 'events-manager'); ?>)</span></h3>
797
- <div class="inside">
798
-
799
- <?php
800
- //update scripts that may need to run
801
- $blog_updates = is_multisite() ? array_merge(EM_Options::get('updates'), EM_Options::site_get('updates')) : EM_Options::get('updates');
802
- foreach( $blog_updates as $update => $update_data ){
803
- do_action('em_admin_update_settings_'.$update, $update_data);
804
- }
805
- ?>
806
-
807
- <table class="form-table">
808
- <tr class="em-header"><td colspan="2">
809
- <h4><?php _e ( 'Development Versions &amp; Updates', 'events-manager'); ?></h4>
810
- <p><?php _e('We\'re always making improvements, adding features and fixing bugs between releases. We incrementally make these changes in between updates and make it available as a development version. You can download these manually, but we\'ve made it easy for you. <strong>Warning:</strong> Development versions are not always fully tested before release, use wisely!','events-manager'); ?></p>
811
- </td></tr>
812
- <?php em_options_radio_binary ( __( 'Enable Dev Updates?', 'events-manager'), 'dbem_pro_dev_updates', __('If enabled, the latest dev version will always be checked instead of the latest stable version of the plugin.', 'events-manager') ); ?>
813
- <tr>
814
- <th style="text-align:right;"><a href="<?php echo $recheck_updates_url; ?>" class="button-secondary"><?php _e('Re-Check Updates','events-manager'); ?></a></th>
815
- <td><?php _e('If you would like to check and see if there is a new stable update.','events-manager'); ?></td>
816
- </tr>
817
- <tr>
818
- <th style="text-align:right;"><a href="<?php echo $check_devs; ?>" class="button-secondary"><?php _e('Check Dev Versions','events-manager'); ?></a></th>
819
- <td><?php _e('If you would like to download a dev version, but just as a one-off, you can force a dev version check by clicking the button below. If there is one available, it should appear in your plugin updates page as a regular update.','events-manager'); ?></td>
820
- </tr>
821
- </table>
822
-
823
- <table class="form-table">
824
- <tr class="em-header"><td colspan="2">
825
- <h4><?php esc_html_e( 'Import/Export Settings', 'events-manager'); ?></h4>
826
- <?php if( is_multisite() && is_network_admin() ): ?>
827
- <p><?php esc_html_e("Within the network admin area, only network-specific settings will be exported or imported. For individual site settings please visit the relevant site within your network.", 'events-manager'); ?></p>
828
- <?php endif; ?>
829
- </td></tr>
830
- <tr>
831
- <th style="text-align:right;">
832
- <a href="#" class="button-secondary" id="em-admin-import-settings"><?php esc_html_e('Import Settings','events-manager'); ?></a>
833
- </th>
834
- <td>
835
- <input type="file" name="import_settings_file" id="em-admin-import-settings-file" />
836
- <p><em><?php echo esc_html(sprintf(__('Choose a settings file saved from a backup or another Events Manager installation and click the \'%s\' button.','events-manager'), __('Import Settings','events-manager'))); ?></em></p>
837
- </td>
838
- <script type="text/javascript" charset="utf-8">
839
- jQuery(document).ready(function($){
840
- $('a#em-admin-import-settings').on('click', function(e,el){
841
- var thisform = $(this).closest('form');
842
- thisform.find('input[type=text], textarea, select, input[type=radio], input[type=hidden]').prop('disabled', true);
843
- thisform.find('input[name=_wpnonce]').val('<?php echo esc_attr($import_nonce); ?>').prop('disabled', false);
844
- thisform.append($('<input type="hidden" name="action" value="<?php echo is_multisite() ? 'import_em_ms_settings':'import_em_settings'; ?>" />'));
845
- thisform.attr('enctype', 'multipart/form-data').submit();
846
- });
847
- });
848
- </script>
849
- </tr>
850
- <tr>
851
- <th style="text-align:right;">
852
- <a href="<?php echo $export_settings_url; ?>" class="button-secondary"><?php esc_html_e('Export Settings','events-manager'); ?></a>
853
- </th>
854
- <td><p><?php esc_html_e('Export your Events Manager settings and restore them here or on another website running this plugin.','events-manager'); ?></p></td>
855
- </tr>
856
- </table>
857
-
858
-
859
- <table class="form-table">
860
- <tr class="em-header"><td colspan="2">
861
- <h4><?php esc_html_e( 'Database Cleanup', 'events-manager'); ?></h4>
862
- </td></tr>
863
- <tr>
864
- <th style="text-align:right;"><a href="<?php echo $cleanup_event_orphans_url; ?>" class="button-secondary admin-tools-db-cleanup"><?php _e('Remove Orphaned Events','events-manager'); ?></a></th>
865
- <td>
866
- <?php
867
- global $wpdb;
868
- $sql = 'SELECT count(*) FROM '.EM_EVENTS_TABLE.' WHERE post_id NOT IN (SELECT ID FROM ' .$wpdb->posts. ' WHERE post_type="'. EM_POST_TYPE_EVENT .'" OR post_type="event-recurring")';
869
- if( EM_MS_GLOBAL ){
870
- if( is_main_site() ){
871
- $sql .= $wpdb->prepare(' AND (blog_id=%d or blog_id IS NULL)', get_current_blog_id());
872
- }else{
873
- $sql .= $wpdb->prepare(' AND blog_id=%d', get_current_blog_id());
874
- }
875
- }
876
- $results = $wpdb->get_var($sql);
877
- echo sprintf(esc_html__('Orphaned events may show on your event lists but not point to real event pages, and can be deleted. %d potentially orphaned events have been found.', 'events-manager'), $results);
878
- ?>
879
- </td>
880
- </tr>
881
- </table>
882
- <script type="text/javascript">
883
- if( typeof EM == 'object' ){ EM.admin_db_cleanup_warning = '<?php echo esc_js(__('Are you sure you want to proceed? We recommend you back up your database first, just in case!', 'events-manager')); ?>'; }
884
- </script>
885
-
886
- <table class="form-table">
887
- <tr class="em-header"><td colspan="2">
888
- <h4><?php _e ( 'Reset Timezones', 'events-manager'); ?></h4>
889
- <?php if( is_multisite() && get_site_option('dbem_reset_timezone_multisite_progress', false) !== false ): ?>
890
- <p style="color:red;">
891
- <?php
892
- echo sprintf( esc_html__('Your last attempt to reset all blogs to a certain timezone did not complete successfully. You can attempt to reset only those blogs that weren\'t completed by selecting your desired timezone again and then %s from the dropdowns below', 'events-manager'), '<code>'.esc_html__('Resume Previous Attempt (All Blogs)', 'events-manager').'</code>' );
893
- ?>
894
- </p>
895
- <?php endif; ?>
896
- </td></tr>
897
- <tr>
898
- <th style="text-align:right;">
899
- <a href="#" class="button-secondary" id="em-reset-event-timezones"><?php esc_html_e('Reset Event Timezones','events-manager'); ?></a>
900
- </th>
901
- <td>
902
- <select name="timezone_reset_value" class="em-reset-event-timezones">
903
- <?php
904
- if( is_multisite() ){
905
- $timezone_default = 'none';
906
- echo '<option value="default">'.__('Blog Default Timezone', 'events-manager').'</option>';
907
- }else{
908
- $timezone_default = str_replace(' ', '', EM_DateTimeZone::create()->getName());
909
- }
910
- ?>
911
- <?php echo wp_timezone_choice($timezone_default); ?>
912
- </select>
913
- <?php if( is_multisite() ): ?>
914
- <select name="timezone_reset_blog" class="em-reset-event-timezones">
915
- <option value="0"><?php esc_html_e('Select a blog...', 'events-manager'); ?></option>
916
- <option value="all"><?php esc_html_e('All Blogs', 'events-manager'); ?></option>
917
- <?php if( is_multisite() && get_site_option('dbem_reset_timezone_multisite_progress', false) !== false ): ?>
918
- <option value="all-resume"><?php esc_html_e('Resume Previous Attempt (All Blogs)', 'events-manager'); ?></option>
919
- <?php endif; ?>
920
- <?php
921
- foreach( get_sites() as $WP_Site){ /* @var WP_Site $WP_Site */
922
- echo '<option value="'.esc_attr($WP_Site->blog_id).'">'. esc_html($WP_Site->blogname) .'</option>';
923
- }
924
- ?>
925
- </select>
926
- <?php endif; ?>
927
- <p>
928
- <em><?php esc_html_e('Select a Timezone to reset all your blog events to.','events-manager'); ?></em><br />
929
- <em><strong><?php esc_html_e('WARNING! This cannot be undone and will overwrite all event timezones, you may want to back up your database first!','events-manager'); ?></strong></em>
930
- </p>
931
- </td>
932
- <script type="text/javascript" charset="utf-8">
933
- jQuery(document).ready(function($){
934
- $('select[name="timezone_reset_value"]').on('change', function( e ){
935
- if( $(this).val() == '' ){
936
- $('a#em-reset-event-timezones').css({opacity:0.5, cursor:'default'});
937
- }else{
938
- $('a#em-reset-event-timezones').css({opacity:1, cursor:'pointer'});
939
- }
940
- }).trigger('change');
941
- $('a#em-reset-event-timezones').on('click', function(e,el){
942
- if( $('select[name="timezone_reset_value"]').val() == '' ) return false;
943
- var thisform = $(this).closest('form');
944
- thisform.find('input, textarea, select').prop('disabled', true);
945
- thisform.find('select.em-reset-event-timezones').prop('disabled', false);
946
- thisform.find('input[name=_wpnonce]').val('<?php echo esc_attr($reset_timezone_nonce); ?>').prop('disabled', false);
947
- thisform.append($('<input type="hidden" name="action" value="<?php echo is_multisite() ? 'reset_timezones':'reset_timezones'; ?>" />'));
948
- thisform.submit();
949
- });
950
- });
951
- </script>
952
- </td></tr>
953
- </table>
954
-
955
- <table class="form-table">
956
- <tr class="em-header"><td colspan="2">
957
- <h4><?php _e ( 'Uninstall/Reset', 'events-manager'); ?></h4>
958
- <p><?php _e('Use the buttons below to uninstall Events Manager completely from your system or reset Events Manager to original settings and keep your event data.','events-manager'); ?></p>
959
- </td></tr>
960
- <tr><td colspan="2">
961
- <a href="<?php echo $uninstall_url; ?>" class="button-secondary"><?php _e('Uninstall','events-manager'); ?></a>
962
- <a href="<?php echo $reset_url; ?>" class="button-secondary"><?php _e('Reset','events-manager'); ?></a>
963
- </td></tr>
964
- </table>
965
- <?php do_action('em_options_page_panel_admin_tools'); ?>
966
- <?php echo $save_button; ?>
967
- </div>
968
- </div>
969
- <?php
970
- }
971
-
972
- /**
973
- * Meta options box for privacy and data protection rules for GDPR (and other dp laws) compliancy
974
- */
975
- function em_admin_option_box_data_privacy(){
976
- global $save_button;
977
- $privacy_options = array(
978
- 0 => __('Do not include', 'events-manager'),
979
- 1 => __('Include all', 'events-manager'),
980
- 2 => __('Include only guest submissions', 'events-manager')
981
- );
982
- ?>
983
- <div class="postbox " id="em-opt-data-privacy" >
984
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Privacy', 'events-manager'); ?> </span></h3>
985
- <div class="inside">
986
- <p class="em-boxheader"><?php echo sprintf(__('Depending on the nature of your site, you will be subject to one or more national and international privacy/data protection laws such as the %s. Below are some options that you can use to tailor how Events Manager interacts with WordPress privacy tools.','events-manager'), '<a href=http://ec.europa.eu/justice/smedataprotect/index_en.htm">GDPR</a>'); ?></p>
987
- <p class="em-boxheader"><?php echo sprintf(__('For more information see our <a href="%s">data privacy documentation</a>.','events-manager'), 'http://wp-events-plugin.com/documentation/data-privacy-gdpr-compliance/'); ?></p>
988
- <p class="em-boxheader"><?php echo __('All options below relate to data that may have been submitted by or collected from the user requesting their personal data, which would also include events and locations where they are the author.', 'events-manager'); ?></p>
989
- <table class='form-table'>
990
- <thead>
991
- <tr class="em-header">
992
- <th colspan="2"><h4><?php esc_html_e('Export Personal Data'); ?></h4></th>
993
- </tr>
994
- </thead>
995
- <?php
996
- em_options_select ( __( 'Events', 'events-manager'), 'dbem_data_privacy_export_events', $privacy_options );
997
- em_options_select ( __( 'Locations', 'events-manager'), 'dbem_data_privacy_export_locations', $privacy_options, __('Locations submitted by guest users are not included, unless they are linked to events also submitted by them.', 'events-manager') );
998
- em_options_select ( __( 'Bookings', 'events-manager'), 'dbem_data_privacy_export_bookings', $privacy_options, __('This is specific to bookings made by the user, not bookings that may have been made to events they own.', 'events-manager'), $privacy_options );
999
- ?>
1000
- <thead>
1001
- <tr class="em-header">
1002
- <th colspan="2"><h4><?php esc_html_e('Erase Personal Data'); ?></h4></th>
1003
- </tr>
1004
- </thead>
1005
- <?php
1006
- em_options_select ( __( 'Events', 'events-manager'), 'dbem_data_privacy_erase_events', $privacy_options );
1007
- em_options_select ( __( 'Locations', 'events-manager'), 'dbem_data_privacy_erase_locations', $privacy_options, __('Locations submitted by guest users are not included, unless they are linked to events also submitted by them.', 'events-manager') );
1008
- em_options_select ( __( 'Bookings', 'events-manager'), 'dbem_data_privacy_erase_bookings', $privacy_options, __('This is specific to bookings made by the user, not bookings that may have been made to events they own.', 'events-manager'), $privacy_options );
1009
- ?>
1010
- <thead>
1011
- <tr class="em-header">
1012
- <th colspan="2">
1013
- <h4><?php esc_html_e('Consent', 'events-manager'); ?></h4>
1014
- <p><?php esc_html_e('If you collect personal data, you may want to request their consent. The options below will automatically add checkboxes requesting this consent.', 'events-manager'); ?></p>
1015
- </th>
1016
- </tr>
1017
- </thead>
1018
- <?php
1019
- $consent_options = array(
1020
- 0 => __('Do not show', 'events-manager'),
1021
- 1 => __('Show to all', 'events-manager'),
1022
- 2 => __('Only show to guests', 'events-manager')
1023
- );
1024
- $consent_remember = array(
1025
- 0 => __('Always show and ask for consent', 'events-manager'),
1026
- 1 => __('Remember and hide checkbox', 'events-manager'),
1027
- 2 => __('Remember and show checkbox', 'events-manager')
1028
- );
1029
- em_options_input_text( __('Consent Text', 'events-manager'), 'dbem_data_privacy_consent_text', __('%s will be replaced by a link to your site privacy policy page.', 'events-manager') );
1030
- em_options_select( __('Remembering Consent', 'events-manager'), 'dbem_data_privacy_consent_remember', $consent_remember, __('You can hide or leave the consent box checked for registered users who have provided consent previously.', 'events-manager') );
1031
- em_options_select( __( 'Event Submission Forms', 'events-manager'), 'dbem_data_privacy_consent_events', $privacy_options );
1032
- em_options_select( __( 'Location Submission Forms', 'events-manager'), 'dbem_data_privacy_consent_locations', $privacy_options );
1033
- em_options_select( __( 'Bookings Forms', 'events-manager'), 'dbem_data_privacy_consent_bookings', $privacy_options );
1034
-
1035
- echo $save_button;
1036
- ?>
1037
- </table>
1038
- </div> <!-- . inside -->
1039
- </div> <!-- .postbox -->
1040
- <?php
1041
- }
1042
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/settings/tabs/bookings.php DELETED
@@ -1,153 +0,0 @@
1
- <?php if( !function_exists('current_user_can') || !current_user_can('manage_options') ) return; ?>
2
- <!-- BOOKING OPTIONS -->
3
- <div class="em-menu-bookings em-menu-group" <?php if( !defined('EM_SETTINGS_TABS') || !EM_SETTINGS_TABS) : ?>style="display:none;"<?php endif; ?>>
4
-
5
- <div class="postbox " id="em-opt-bookings-general" >
6
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__( '%s Options', 'events-manager'),__('General','events-manager')); ?> </span></h3>
7
- <div class="inside">
8
- <table class='form-table'>
9
- <?php
10
- em_options_radio_binary ( __( 'Allow guest bookings?', 'events-manager'), 'dbem_bookings_anonymous', __( 'If enabled, guest visitors can supply an email address and a user account will automatically be created for them along with their booking. They will be also be able to log back in with that newly created account.', 'events-manager') );
11
- em_options_radio_binary ( __( 'Approval Required?', 'events-manager'), 'dbem_bookings_approval', __( 'Bookings will not be confirmed until the event administrator approves it.', 'events-manager').' '.__( 'This setting is not applicable when using payment gateways, see individual gateways for approval settings.', 'events-manager'));
12
- em_options_radio_binary ( __( 'Reserved unconfirmed spaces?', 'events-manager'), 'dbem_bookings_approval_reserved', __( 'By default, event spaces become unavailable once there are enough CONFIRMED bookings. To reserve spaces even if unapproved, choose yes.', 'events-manager') );
13
- em_options_radio_binary ( __( 'Can users cancel their booking?', 'events-manager'), 'dbem_bookings_user_cancellation', __( 'If enabled, users can cancel their bookings themselves from their bookings page.', 'events-manager') );
14
- em_options_radio_binary ( __( 'Allow overbooking when approving?', 'events-manager'), 'dbem_bookings_approval_overbooking', __( 'If you get a lot of pending bookings and you decide to allow more bookings than spaces allow, setting this to yes will allow you to override the event space limit when manually approving.', 'events-manager') );
15
- em_options_radio_binary ( __( 'Allow double bookings?', 'events-manager'), 'dbem_bookings_double', __( 'If enabled, users can book an event more than once.', 'events-manager') );
16
- echo $save_button;
17
- ?>
18
- </table>
19
- </div> <!-- . inside -->
20
- </div> <!-- .postbox -->
21
-
22
- <div class="postbox " id="em-opt-pricing-options" >
23
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__( '%s Options', 'events-manager'),__('Pricing','events-manager')); ?> </span></h3>
24
- <div class="inside">
25
- <table class='form-table'>
26
- <?php
27
- /* Tax & Currency */
28
- em_options_select ( __( 'Currency', 'events-manager'), 'dbem_bookings_currency', em_get_currencies()->names, __( 'Choose your currency for displaying event pricing.', 'events-manager') );
29
- em_options_input_text ( __( 'Thousands Separator', 'events-manager'), 'dbem_bookings_currency_thousands_sep', '<code>'.get_option('dbem_bookings_currency_thousands_sep')." = ".em_get_currency_symbol().'100<strong>'.get_option('dbem_bookings_currency_thousands_sep').'</strong>000<strong>'.get_option('dbem_bookings_currency_decimal_point').'</strong>00</code>' );
30
- em_options_input_text ( __( 'Decimal Point', 'events-manager'), 'dbem_bookings_currency_decimal_point', '<code>'.get_option('dbem_bookings_currency_decimal_point')." = ".em_get_currency_symbol().'100<strong>'.get_option('dbem_bookings_currency_decimal_point').'</strong>00</code>' );
31
- em_options_input_text ( __( 'Currency Format', 'events-manager'), 'dbem_bookings_currency_format', __('Choose how prices are displayed. <code>@</code> will be replaced by the currency symbol, and <code>#</code> will be replaced by the number.','events-manager').' <code>'.get_option('dbem_bookings_currency_format')." = ".em_get_currency_formatted('10000000').'</code>');
32
- em_options_input_text ( __( 'Tax Rate', 'events-manager'), 'dbem_bookings_tax', __( 'Add a tax rate to your ticket prices (entering 10 will add 10% to the ticket price).', 'events-manager') );
33
- em_options_radio_binary ( __( 'Add tax to ticket price?', 'events-manager'), 'dbem_bookings_tax_auto_add', __( 'When displaying ticket prices and booking totals, include the tax automatically?', 'events-manager') );
34
- echo $save_button;
35
- ?>
36
- </table>
37
- </div> <!-- . inside -->
38
- </div> <!-- .postbox -->
39
-
40
- <div class="postbox " id="em-opt-booking-feedbacks" >
41
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e( 'Customize Feedback Messages', 'events-manager'); ?> </span></h3>
42
- <div class="inside">
43
- <p><?php _e('Below you will find texts that will be displayed to users in various areas during the bookings process, particularly on booking forms.','events-manager'); ?></p>
44
- <table class='form-table'>
45
- <tr class="em-header"><td colspan='2'><h4><?php _e('My Bookings messages','events-manager') ?></h4></td></tr>
46
- <?php
47
- em_options_input_text ( __( 'Booking Cancelled', 'events-manager'), 'dbem_booking_feedback_cancelled', __( 'When a user cancels their booking, this message will be displayed confirming the cancellation.', 'events-manager') );
48
- em_options_input_text ( __( 'Booking Cancellation Warning', 'events-manager'), 'dbem_booking_warning_cancel', __( 'When a user chooses to cancel a booking, this warning is displayed for them to confirm.', 'events-manager') );
49
- ?>
50
- <tr class="em-header"><td colspan='2'><h4><?php _e('Booking form texts/messages','events-manager') ?></h4></td></tr>
51
- <?php
52
- em_options_input_text ( __( 'Bookings disabled', 'events-manager'), 'dbem_bookings_form_msg_disabled', __( 'An event with no bookings.', 'events-manager') );
53
- em_options_input_text ( __( 'Bookings closed', 'events-manager'), 'dbem_bookings_form_msg_closed', __( 'Bookings have closed (e.g. event has started).', 'events-manager') );
54
- em_options_input_text ( __( 'Fully booked', 'events-manager'), 'dbem_bookings_form_msg_full', __( 'Event is fully booked.', 'events-manager') );
55
- em_options_input_text ( __( 'Already attending', 'events-manager'), 'dbem_bookings_form_msg_attending', __( 'If already attending and double bookings are disabled, this message will be displayed, followed by a link to the users booking page.', 'events-manager') );
56
- em_options_input_text ( __( 'Manage bookings link text', 'events-manager'), 'dbem_bookings_form_msg_bookings_link', __( 'Link text used for link to user bookings.', 'events-manager') );
57
- ?>
58
- <tr class="em-header"><td colspan='2'><h4><?php _e('Booking form feedback messages','events-manager') ?></h4></td></tr>
59
- <tr><td colspan='2'><?php _e('When a booking is made by a user, a feedback message is shown depending on the result, which can be customized below.','events-manager'); ?></td></tr>
60
- <?php
61
- em_options_input_text ( __( 'Successful booking', 'events-manager'), 'dbem_booking_feedback', __( 'When a booking is registered and confirmed.', 'events-manager') );
62
- em_options_input_text ( __( 'Successful pending booking', 'events-manager'), 'dbem_booking_feedback_pending', __( 'When a booking is registered but pending.', 'events-manager') );
63
- em_options_input_text ( __( 'Not enough spaces', 'events-manager'), 'dbem_booking_feedback_full', __( 'When a booking cannot be made due to lack of spaces.', 'events-manager') );
64
- em_options_input_text ( __( 'Errors', 'events-manager'), 'dbem_booking_feedback_error', __( 'When a booking cannot be made due to an error when filling the form. Below this, there will be a dynamic list of errors.', 'events-manager') );
65
- em_options_input_text ( __( 'Email Exists', 'events-manager'), 'dbem_booking_feedback_email_exists', __( 'When a guest tries to book using an email registered with a user account.', 'events-manager') );
66
- em_options_input_text ( __( 'User must log in', 'events-manager'), 'dbem_booking_feedback_log_in', __( 'When a user must log in before making a booking.', 'events-manager') );
67
- em_options_input_text ( __( 'Error mailing user', 'events-manager'), 'dbem_booking_feedback_nomail', __( 'If a booking is made and an email cannot be sent, this is added to the success message.', 'events-manager') );
68
- em_options_input_text ( __( 'Already booked', 'events-manager'), 'dbem_booking_feedback_already_booked', __( 'If the user made a previous booking and cannot double-book.', 'events-manager') );
69
- em_options_input_text ( __( 'No spaces booked', 'events-manager'), 'dbem_booking_feedback_min_space', __( 'If the user tries to make a booking without requesting any spaces.', 'events-manager') );$notice_full = __('Sold Out', 'events-manager');
70
- em_options_input_text ( __( 'Maximum spaces per booking', 'events-manager'), 'dbem_booking_feedback_spaces_limit', __( 'If the user tries to make a booking with spaces that exceeds the maximum number of spaces per booking.', 'events-manager').' '. __('%d will be replaced by a number.','events-manager') );
71
- ?>
72
- <tr class="em-header"><td colspan='2'><h4><?php _e('Booking button feedback messages','events-manager') ?></h4></td></tr>
73
- <tr><td colspan='2'><?php echo sprintf(__('With the %s placeholder, the below texts will be used.','events-manager'),'<code>#_BOOKINGBUTTON</code>'); ?></td></tr>
74
- <?php
75
- em_options_input_text ( __( 'User can book', 'events-manager'), 'dbem_booking_button_msg_book', '');
76
- em_options_input_text ( __( 'Booking in progress', 'events-manager'), 'dbem_booking_button_msg_booking', '');
77
- em_options_input_text ( __( 'Booking complete', 'events-manager'), 'dbem_booking_button_msg_booked', '');
78
- em_options_input_text ( __( 'Booking already made', 'events-manager'), 'dbem_booking_button_msg_already_booked', '');
79
- em_options_input_text ( __( 'Booking error', 'events-manager'), 'dbem_booking_button_msg_error', '');
80
- em_options_input_text ( __( 'Event fully booked', 'events-manager'), 'dbem_booking_button_msg_full', '');
81
- em_options_input_text ( __( 'Bookings closed', 'events-manager'), 'dbem_booking_button_msg_closed', '');
82
- em_options_input_text ( __( 'Cancel', 'events-manager'), 'dbem_booking_button_msg_cancel', '');
83
- em_options_input_text ( __( 'Cancelation in progress', 'events-manager'), 'dbem_booking_button_msg_canceling', '');
84
- em_options_input_text ( __( 'Cancelation complete', 'events-manager'), 'dbem_booking_button_msg_cancelled', '');
85
- em_options_input_text ( __( 'Cancelation error', 'events-manager'), 'dbem_booking_button_msg_cancel_error', '');
86
-
87
- echo $save_button;
88
- ?>
89
- </table>
90
- </div> <!-- . inside -->
91
- </div> <!-- .postbox -->
92
-
93
- <div class="postbox " id="em-opt-booking-form-options" >
94
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__( '%s Options', 'events-manager'),__('Booking Form','events-manager')); ?> </span></h3>
95
- <div class="inside">
96
- <table class='form-table'>
97
- <?php
98
- em_options_radio_binary ( __( 'Display login form?', 'events-manager'), 'dbem_bookings_login_form', __( 'Choose whether or not to display a login form in the booking form area to remind your members to log in before booking.', 'events-manager') );
99
- em_options_input_text ( __( 'Submit button text', 'events-manager'), 'dbem_bookings_submit_button', sprintf(__( 'The text used by the submit button. To use an image instead, enter the full url starting with %s or %s.', 'events-manager'), '<code>http://</code>','<code>https://</code>') );
100
- do_action('em_options_booking_form_options');
101
- echo $save_button;
102
- ?>
103
- </table>
104
- </div> <!-- . inside -->
105
- </div> <!-- .postbox -->
106
-
107
- <div class="postbox " id="em-opt-ticket-options" >
108
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__( '%s Options', 'events-manager'),__('Ticket','events-manager')); ?> </span></h3>
109
- <div class="inside">
110
- <table class='form-table'>
111
- <?php
112
- em_options_radio_binary ( __( 'Single ticket mode?', 'events-manager'), 'dbem_bookings_tickets_single', __( 'In single ticket mode, users can only create one ticket per event (and will not see options to add more tickets).', 'events-manager') );
113
- em_options_radio_binary ( __( 'Show ticket table in single ticket mode?', 'events-manager'), 'dbem_bookings_tickets_single_form', __( 'If you prefer a ticket table like with multiple tickets, even for single ticket events, enable this.', 'events-manager') );
114
- em_options_radio_binary ( __( 'Show unavailable tickets?', 'events-manager'), 'dbem_bookings_tickets_show_unavailable', __( 'You can choose whether or not to show unavailable tickets to visitors.', 'events-manager') );
115
- em_options_radio_binary ( __( 'Show member-only tickets?', 'events-manager'), 'dbem_bookings_tickets_show_member_tickets', sprintf(__('%s must be set to yes for this to work.', 'events-manager'), '<strong>'.__( 'Show unavailable tickets?', 'events-manager').'</strong>').' '.__( 'If there are member-only tickets, you can choose whether or not to show these tickets to guests.','events-manager') );
116
-
117
- em_options_radio_binary ( __( 'Show multiple tickets if logged out?', 'events-manager'), 'dbem_bookings_tickets_show_loggedout', __( 'If guests cannot make bookings, they will be asked to register in order to book. However, enabling this will still show available tickets.', 'events-manager') );
118
- em_options_radio_binary ( __( 'Enable custom ticket ordering?', 'events-manager'), 'dbem_bookings_tickets_ordering', __( 'When enabled, users can custom-order their tickets using drag and drop. If enabled, saved ordering supercedes the default ticket ordering below.', 'events-manager') );
119
- $ticket_orders = apply_filters('em_tickets_orderby_options', array(
120
- 'ticket_price DESC, ticket_name ASC'=>__('Ticket Price (Descending)','events-manager'),
121
- 'ticket_price ASC, ticket_name ASC'=>__('Ticket Price (Ascending)','events-manager'),
122
- 'ticket_name ASC, ticket_price DESC'=>__('Ticket Name (Ascending)','events-manager'),
123
- 'ticket_name DESC, ticket_price DESC'=>__('Ticket Name (Descending)','events-manager')
124
- ));
125
- em_options_select ( __( 'Order Tickets By', 'events-manager'), 'dbem_bookings_tickets_orderby', $ticket_orders, __( 'Choose which order your tickets appear.', 'events-manager') );
126
- echo $save_button;
127
- ?>
128
- </table>
129
- </div> <!-- . inside -->
130
- </div> <!-- .postbox -->
131
-
132
- <div class="postbox " id="em-opt-no-user-bookings" >
133
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e('No-User Booking Mode','events-manager'); ?> </span></h3>
134
- <div class="inside">
135
- <table class='form-table'>
136
- <tr><td colspan='2'>
137
- <p><?php _e('The option below allows you to disable user accounts, yet you will still see the supplied personal information for each booking.','events-manager'); ?></p>
138
- <p><?php _e('By default, when a booking is made by a user, this booking is tied to a user account, if the user is not registered nor logged in and guest bookings are enabled, an account will be created for them.','events-manager'); ?></p>
139
- <p><?php _e('Users with accounts (which would be created by other means when this mode is enabled) will still be able to log in and make bookings linked to their account as normal.','events-manager'); ?></p>
140
- <p><?php _e('<strong>Warning : </strong> Various features afforded to users with an account will not be available, e.g. viewing bookings. Once you enable this and select a user, modifying these values will prevent older non-user bookings from displaying the correct information.','events-manager'); ?></p>
141
- </td></tr>
142
- <?php
143
- em_options_radio_binary ( __( 'Enable No-User Booking Mode?', 'events-manager'), 'dbem_bookings_registration_disable', __( 'This disables user registrations for bookings.', 'events-manager') );
144
- em_options_radio_binary ( __( 'Allow bookings with registered emails?', 'events-manager'), 'dbem_bookings_registration_disable_user_emails', __( 'By default, if a guest tries to book an event using the email of a user account on your site they will be asked to log in, selecting yes will bypass this security measure.', 'events-manager').'<br />'.__('<strong>Warning : </strong> By enabling this, registered users will not be able to see bookings they make as guests in their "My Bookings" page.','events-manager') );
145
- echo $save_button;
146
- ?>
147
- </table>
148
- </div> <!-- . inside -->
149
- </div> <!-- .postbox -->
150
-
151
- <?php do_action('em_options_page_footer_bookings'); ?>
152
-
153
- </div> <!-- .em-menu-bookings -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/settings/tabs/emails.php DELETED
@@ -1,177 +0,0 @@
1
- <?php if( !function_exists('current_user_can') || !current_user_can('manage_options') ) return; ?>
2
- <!-- EMAIL OPTIONS -->
3
- <div class="em-menu-emails em-menu-group" <?php if( !defined('EM_SETTINGS_TABS') || !EM_SETTINGS_TABS) : ?>style="display:none;"<?php endif; ?>>
4
-
5
- <?php if ( !is_multisite() ) { em_admin_option_box_email(); } ?>
6
-
7
- <?php if( get_option('dbem_rsvp_enabled') ): ?>
8
- <div class="postbox " id="em-opt-booking-emails">
9
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Booking Email Templates', 'events-manager'); ?> </span></h3>
10
- <div class="inside">
11
- <?php do_action('em_options_page_booking_email_templates_options_top'); ?>
12
- <table class='form-table'>
13
- <?php
14
- $email_subject_tip = __('You can disable this email by leaving the subject blank.','events-manager');
15
- em_options_input_text ( __( 'Email events admin?', 'events-manager'), 'dbem_bookings_notify_admin', __( "If you would like every event booking confirmation email sent to an administrator write their email here (leave blank to not send an email).", 'events-manager').' '.__('For multiple emails, separate by commas (e.g. email1@test.com,email2@test.com,etc.)','events-manager') );
16
- em_options_radio_binary ( __( 'Email event owner?', 'events-manager'), 'dbem_bookings_contact_email', __( 'Check this option if you want the event contact to receive an email when someone books places. An email will be sent when a booking is first made (regardless if confirmed or pending)', 'events-manager') );
17
- do_action('em_options_page_booking_email_templates_options_subtop');
18
- ?>
19
- <tr class="em-header"><td colspan='2'><h4><?php _e('Event Admin/Owner Emails', 'events-manager'); ?></h4></td></tr>
20
- <tbody class="em-subsection">
21
- <tr class="em-subheader"><td colspan='2'>
22
- <h5><?php _e('Confirmed booking email','events-manager') ?></h5>
23
- <em><?php echo __('This is sent when a person\'s booking is confirmed. This will be sent automatically if approvals are required and the booking is approved. If approvals are disabled, this is sent out when a user first submits their booking.','events-manager').$bookings_placeholder_tip ?></em>
24
- </td></tr>
25
- <?php
26
- em_options_input_text ( __( 'Booking confirmed email subject', 'events-manager'), 'dbem_bookings_contact_email_confirmed_subject', $email_subject_tip );
27
- em_options_textarea ( __( 'Booking confirmed email', 'events-manager'), 'dbem_bookings_contact_email_confirmed_body', '' );
28
- ?>
29
- <tr class="em-subheader"><td colspan='2'>
30
- <h5><?php _e('Pending booking email','events-manager') ?></h5>
31
- <em><?php echo __('This is sent when a person\'s booking is pending. If approvals are enabled, this is sent out when a user first submits their booking.','events-manager').$bookings_placeholder_tip ?></em>
32
- </td></tr>
33
- <?php
34
- em_options_input_text ( __( 'Booking pending email subject', 'events-manager'), 'dbem_bookings_contact_email_pending_subject', $email_subject_tip );
35
- em_options_textarea ( __( 'Booking pending email', 'events-manager'), 'dbem_bookings_contact_email_pending_body', '' );
36
- ?>
37
- <tr class="em-subheader"><td colspan='2'>
38
- <h5><?php _e('Booking cancelled','events-manager') ?></h5>
39
- <em><?php echo __('An email will be sent to the event contact if someone cancels their booking.','events-manager').$bookings_placeholder_tip ?></em>
40
- </td></tr>
41
- <?php
42
- em_options_input_text ( __( 'Booking cancelled email subject', 'events-manager'), 'dbem_bookings_contact_email_cancelled_subject', $email_subject_tip );
43
- em_options_textarea ( __( 'Booking cancelled email', 'events-manager'), 'dbem_bookings_contact_email_cancelled_body', '' );
44
- ?>
45
- <tr class="em-subheader"><td colspan='2'>
46
- <h5><?php _e('Rejected booking email','events-manager') ?></h5>
47
- <em><?php echo __( 'This will be sent to event admins when a booking is rejected.', 'events-manager').$bookings_placeholder_tip ?></em>
48
- </td></tr>
49
- <?php
50
- em_options_input_text ( __( 'Booking rejected email subject', 'events-manager'), 'dbem_bookings_contact_email_rejected_subject', $email_subject_tip );
51
- em_options_textarea ( __( 'Booking rejected email', 'events-manager'), 'dbem_bookings_contact_email_rejected_body', '' );
52
- ?>
53
- </tbody>
54
- <tr class="em-header"><td colspan='2'><h4><?php _e('Booked User Emails', 'events-manager'); ?></h4></td></tr>
55
- <tbody class="em-subsection">
56
- <tr class="em-subheader"><td colspan='2'>
57
- <h5><?php _e('Confirmed booking email','events-manager') ?></h5>
58
- <em><?php echo __('This is sent when a person\'s booking is confirmed. This will be sent automatically if approvals are required and the booking is approved. If approvals are disabled, this is sent out when a user first submits their booking.','events-manager').$bookings_placeholder_tip ?></em>
59
- </td></tr>
60
- <?php
61
- em_options_input_text ( __( 'Booking confirmed email subject', 'events-manager'), 'dbem_bookings_email_confirmed_subject', $email_subject_tip );
62
- em_options_textarea ( __( 'Booking confirmed email', 'events-manager'), 'dbem_bookings_email_confirmed_body', '' );
63
- ?>
64
- <tr class="em-subheader"><td colspan='2'>
65
- <h5><?php _e('Pending booking email','events-manager') ?></h5>
66
- <em><?php echo __( 'This will be sent to the person when they first submit their booking. Not relevant if bookings don\'t require approval.', 'events-manager').$bookings_placeholder_tip ?></em>
67
- </td></tr>
68
- <?php
69
- em_options_input_text ( __( 'Booking pending email subject', 'events-manager'), 'dbem_bookings_email_pending_subject', $email_subject_tip);
70
- em_options_textarea ( __( 'Booking pending email', 'events-manager'), 'dbem_bookings_email_pending_body','') ;
71
- ?>
72
- <tr class="em-subheader"><td colspan='2'>
73
- <h5><?php _e('Booking cancelled','events-manager') ?></h5>
74
- <em><?php echo __('This will be sent when a user cancels their booking.','events-manager').$bookings_placeholder_tip ?></em>
75
- </td></tr>
76
- <?php
77
- em_options_input_text ( __( 'Booking cancelled email subject', 'events-manager'), 'dbem_bookings_email_cancelled_subject', $email_subject_tip );
78
- em_options_textarea ( __( 'Booking cancelled email', 'events-manager'), 'dbem_bookings_email_cancelled_body', '' );
79
- ?>
80
- <tr class="em-subheader"><td colspan='2'>
81
- <h5><?php _e('Rejected booking email','events-manager') ?></h5>
82
- <em><?php echo __( 'This will be sent automatically when a booking is rejected. Not relevant if bookings don\'t require approval.', 'events-manager').$bookings_placeholder_tip ?></em>
83
- </td></tr>
84
- <?php
85
- em_options_input_text ( __( 'Booking rejected email subject', 'events-manager'), 'dbem_bookings_email_rejected_subject', $email_subject_tip );
86
- em_options_textarea ( __( 'Booking rejected email', 'events-manager'), 'dbem_bookings_email_rejected_body', '' );
87
- ?>
88
- </tbody>
89
- <?php do_action('em_options_page_booking_email_templates_options_bottom'); ?>
90
- <?php echo $save_button; ?>
91
- </table>
92
- </div> <!-- . inside -->
93
- </div> <!-- .postbox -->
94
- <?php endif; ?>
95
-
96
- <?php if( get_option('dbem_rsvp_enabled') ): ?>
97
- <div class="postbox " id="em-opt-registration-emails">
98
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Registration Email Templates', 'events-manager'); ?> </span></h3>
99
- <div class="inside">
100
- <p class="em-boxheader">
101
- <?php echo sprintf(__('This is only applicable when %s is not active.','events-manager'), '<em>'.__('No-User Booking Mode','events-manager').'</em>'); ?>
102
- <?php _e('When a guest user makes a booking for the first time in Events Manager, a new user account is created for them and they are sent their credentials in a separate email, which can be modified below.','events-manager'); ?>
103
- </p>
104
- <table class='form-table'>
105
- <?php
106
- em_options_radio_binary ( __( 'Disable new registration email?', 'events-manager'), 'dbem_email_disable_registration', __( 'Check this option if you want to prevent the WordPress registration email from going out when a user anonymously books an event.', 'events-manager') );
107
-
108
- em_options_input_text ( __( 'Registration email subject', 'events-manager'), 'dbem_bookings_email_registration_subject' );
109
- em_options_textarea ( __( 'Registration email', 'events-manager'), 'dbem_bookings_email_registration_body', sprintf(__('%s is replaced by username, %s is replaced by the user password and %s is replaced by a link to create a password.','events-manager'),'<code>%username%</code>','<code>%password%</code>','<code>%passwordurl%</code>') );
110
- echo $save_button;
111
- ?>
112
- </table>
113
- </div> <!-- . inside -->
114
- </div> <!-- .postbox -->
115
- <?php endif; ?>
116
-
117
- <div class="postbox " id="em-opt-event-submission-emails" >
118
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Event Submission Templates', 'events-manager'); ?> </span></h3>
119
- <div class="inside">
120
- <table class='form-table'>
121
- <tr class="em-header"><td colspan='2'><h4><?php _e('Event Admin Emails', 'events-manager'); ?></h4></td></tr>
122
- <?php
123
- em_options_input_text ( __( 'Administrator Email', 'events-manager'), 'dbem_event_submitted_email_admin', __('Event submission notifications will be sent to emails added here.','events-manager').' '.__('If left blank, no emails will be sent. Separate emails with commas for more than one email.','events-manager') );
124
- ?>
125
- <tbody class="em-subsection">
126
- <tr class="em-subheader"><td colspan='2'>
127
- <h5><?php _e('Event Submitted','events-manager') ?></h5>
128
- <em><?php echo __('An email will be sent to your administrator emails when an event is submitted and pending approval.','events-manager').$bookings_placeholder_tip ?></em>
129
- </td></tr>
130
- <?php
131
- em_options_input_text ( __( 'Event submitted subject', 'events-manager'), 'dbem_event_submitted_email_subject', __('If left blank, this email will not be sent.','events-manager') );
132
- em_options_textarea ( __( 'Event submitted email', 'events-manager'), 'dbem_event_submitted_email_body', '' );
133
- ?>
134
- <tr class="em-subheader"><td colspan='2'>
135
- <h5><?php _e('Event Re-Submitted','events-manager') ?></h5>
136
- <em><?php echo __('When a user modifies a previously published event, it will be put back into pending review status and will not be published until you re-approve it.','events-manager').$bookings_placeholder_tip ?></em>
137
- </td></tr>
138
- <?php
139
- em_options_input_text ( __( 'Event resubmitted subject', 'events-manager'), 'dbem_event_resubmitted_email_subject', __('If left blank, this email will not be sent.','events-manager') );
140
- em_options_textarea ( __( 'Event resubmitted email', 'events-manager'), 'dbem_event_resubmitted_email_body', '' );
141
- ?>
142
- <tr class="em-subheader"><td colspan='2'>
143
- <h5><?php _e('Event Published','events-manager') ?></h5>
144
- <em><?php echo __('An email will be sent to an administrator of your choice when an event is published by users who are not administrators.','events-manager').$bookings_placeholder_tip ?>
145
- </td></tr>
146
- <?php
147
- em_options_input_text ( __( 'Event published subject', 'events-manager'), 'dbem_event_published_email_subject', __('If left blank, this email will not be sent.','events-manager') );
148
- em_options_textarea ( __( 'Event published email', 'events-manager'), 'dbem_event_published_email_body', '' );
149
- ?>
150
- </tbody>
151
- <tr class="em-header"><td colspan='2'><h4><?php _e('Event Submitter Emails', 'events-manager'); ?></h4></td></tr>
152
- <tbody class="em-subsection">
153
- <tr class="em-subheader"><td colspan='2'>
154
- <h5><?php _e('Event Approved','events-manager') ?></h5>
155
- <em><?php echo __('An email will be sent to the event owner when their event is approved. Users requiring event approval do not have the <code>publish_events</code> capability.','events-manager').$bookings_placeholder_tip ?>
156
- </td></tr>
157
- <?php
158
- em_options_input_text ( __( 'Event approved subject', 'events-manager'), 'dbem_event_approved_email_subject', __('If left blank, this email will not be sent.','events-manager') );
159
- em_options_textarea ( __( 'Event approved email', 'events-manager'), 'dbem_event_approved_email_body', '' );
160
- ?>
161
- <tr class="em-subheader"><td colspan='2'>
162
- <h5><?php _e('Event Reapproved','events-manager') ?></h5>
163
- <?php echo __('When a user modifies a previously published event, it will be put back into pending review status and will not be published until you re-approve it.','events-manager').$bookings_placeholder_tip ?>
164
- </td></tr>
165
- <?php
166
- em_options_input_text ( __( 'Event reapproved subject', 'events-manager'), 'dbem_event_reapproved_email_subject', __('If left blank, this email will not be sent.','events-manager') );
167
- em_options_textarea ( __( 'Event reapproved email', 'events-manager'), 'dbem_event_reapproved_email_body', '' );
168
- ?>
169
- </tbody>
170
- <?php echo $save_button; ?>
171
- </table>
172
- </div> <!-- . inside -->
173
- </div> <!-- .postbox -->
174
-
175
- <?php do_action('em_options_page_footer_emails'); ?>
176
-
177
- </div><!-- .em-group-emails -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/settings/tabs/formats.php DELETED
@@ -1,465 +0,0 @@
1
- <?php if( !function_exists('current_user_can') || !current_user_can('manage_options') ) return; ?>
2
- <!-- FORMAT OPTIONS -->
3
- <div class="em-menu-formats em-menu-group" <?php if( !defined('EM_SETTINGS_TABS') || !EM_SETTINGS_TABS) : ?>style="display:none;"<?php endif; ?>>
4
- <div class="postbox " id="em-opt-events-formats" >
5
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Events', 'events-manager'); ?> </span></h3>
6
- <div class="inside">
7
- <table class="form-table">
8
- <tr class="em-header"><td colspan="2">
9
- <h4><?php echo sprintf(__('%s Page','events-manager'),__('Events','events-manager')); ?></h4>
10
- <p><?php _e('These formats will be used on your events page. This will also be used if you do not provide specified formats in other event lists, like in shortcodes.','events-manager'); ?></p>
11
- </td></tr>
12
- <?php
13
- $grouby_modes = array(0=>__('None','events-manager'), 'yearly'=>__('Yearly','events-manager'), 'monthly'=>__('Monthly','events-manager'), 'weekly'=>__('Weekly','events-manager'), 'daily'=>__('Daily','events-manager'));
14
- em_options_select(__('Events page grouping','events-manager'), 'dbem_event_list_groupby', $grouby_modes, __('If you choose a group by mode, your events page will display events in groups of your chosen time range.','events-manager'));
15
- em_options_input_text(__('Events page grouping header','events-manager'), 'dbem_event_list_groupby_header_format', __('Choose how to format your group headings.','events-manager').' '. sprintf(__('#s will be replaced by the date format below', 'events-manager'), 'http://codex.wordpress.org/Formatting_Date_and_Time'));
16
- em_options_input_text(__('Events page grouping date format','events-manager'), 'dbem_event_list_groupby_format', __('Choose how to format your group heading dates. Leave blank for default.','events-manager').' '. sprintf(__('Date and Time formats follow the <a href="%s">WordPress time formatting conventions</a>', 'events-manager'), 'http://codex.wordpress.org/Formatting_Date_and_Time'));
17
- em_options_textarea ( __( 'Default event list format header', 'events-manager'), 'dbem_event_list_item_format_header', __( 'This content will appear just above your code for the default event list format. Default is blank', 'events-manager') );
18
- em_options_textarea ( __( 'Default event list format', 'events-manager'), 'dbem_event_list_item_format', __( 'The format of any events in a list.', 'events-manager').$events_placeholder_tip );
19
- em_options_textarea ( __( 'Default event list format footer', 'events-manager'), 'dbem_event_list_item_format_footer', __( 'This content will appear just below your code for the default event list format. Default is blank', 'events-manager') );
20
- em_options_input_text ( __( 'No events message', 'events-manager'), 'dbem_no_events_message', __( 'The message displayed when no events are available.', 'events-manager') );
21
- em_options_input_text ( __( 'List events by date title', 'events-manager'), 'dbem_list_date_title', __( 'If viewing a page for events on a specific date, this is the title that would show up. To insert date values, use <a href="http://www.php.net/manual/en/function.date.php">PHP time format characters</a> with a <code>#</code> symbol before them, i.e. <code>#m</code>, <code>#M</code>, <code>#j</code>, etc.<br/>', 'events-manager') );
22
- ?>
23
- <tr class="em-header">
24
- <td colspan="2">
25
- <h4><?php echo sprintf(__('Single %s Page','events-manager'),__('Event','events-manager')); ?></h4>
26
- <em><?php echo sprintf(__('These formats can be used on %s pages or on other areas of your site displaying an %s.','events-manager'),__('event','events-manager'),__('event','events-manager'));?></em>
27
- </tr>
28
- <?php
29
- if( EM_MS_GLOBAL && !get_option('dbem_ms_global_events_links') ){
30
- em_options_input_text ( sprintf(__( 'Single %s title format', 'events-manager'),__('event','events-manager')), 'dbem_event_page_title_format', sprintf(__( 'The format of a single %s page title.', 'events-manager'),__('event','events-manager')).' '.__( 'This is only used when showing events from other blogs.', 'events-manager').$events_placeholder_tip );
31
- }
32
- em_options_textarea ( sprintf(__('Single %s page format', 'events-manager'),__('event','events-manager')), 'dbem_single_event_format', sprintf(__( 'The format used to display %s content on single pages or elsewhere on your site.', 'events-manager'),__('event','events-manager')).$events_placeholder_tip );
33
- ?>
34
- <tr class="em-header">
35
- <td colspan="2">
36
- <h4><?php echo sprintf(__('%s Excerpts','events-manager'),__('Event','events-manager')); ?></h4>
37
- <em><?php echo sprintf(__('These formats can be used when WordPress automatically displays %s excerpts on your site and %s is enabled in your %s settings tab.','events-manager'),__('event','events-manager'),'<strong>'.__( 'Override Excerpts with Formats?', 'events-manager').'</strong>','<a href="#formats" class="nav-tab-link" rel="#em-menu-pages">'.__('Pages','events-manager').' &gt; '.sprintf(__('%s List/Archives','events-manager'),__('Event','events-manager')).'</a>');?></em>
38
- </td>
39
- </tr>
40
- <?php
41
- em_options_textarea ( sprintf(__('%s excerpt', 'events-manager'),__('Event','events-manager')), 'dbem_event_excerpt_format', __( 'Used if an excerpt has been defined.', 'events-manager').$events_placeholder_tip );
42
- em_options_textarea ( sprintf(__('%s excerpt fallback', 'events-manager'),__('Event','events-manager')), 'dbem_event_excerpt_alt_format', __( 'Used if an excerpt has not been defined.', 'events-manager').$events_placeholder_tip );
43
-
44
- echo $save_button;
45
- ?>
46
- </table>
47
- </div> <!-- . inside -->
48
- </div> <!-- .postbox -->
49
-
50
- <div class="postbox " id="em-opt-search-form" >
51
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Search Form', 'events-manager'); ?> </span></h3>
52
- <div class="inside">
53
- <table class="form-table em-search-form-main">
54
- <tr class="em-header"><td colspan="2"><h4><?php _e('Main Search Fields','events-manager'); ?></h4></td></tr>
55
- <tbody class="em-subsection">
56
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'Search', 'events-manager'); ?></h5></td></tr>
57
- <?php
58
- em_options_radio_binary ( __( 'Show text search?', 'events-manager'), 'dbem_search_form_text', '', '', '#dbem_search_form_text_label_row' );
59
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_text_label', __('Appears within the input box.','events-manager') );
60
- ?>
61
- </tbody>
62
- <tbody class="em-settings-geocoding em-subsection">
63
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'Geolocation Search', 'events-manager'); ?></h5></td></tr>
64
- <?php
65
- em_options_radio_binary ( __( 'Show geolocation search?', 'events-manager'), 'dbem_search_form_geo', '', '', '#dbem_search_form_geo_label_row, #dbem_search_form_geo_distance_default_row, #dbem_search_form_geo_unit_default_row' );
66
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_geo_label', __('Appears within the input box.','events-manager') );
67
- em_options_input_text ( __( 'Default distance', 'events-manager'), 'dbem_search_form_geo_distance_default', __('Enter a number.','events-manager'), '');
68
- em_options_select ( __( 'Default distance unit', 'events-manager'), 'dbem_search_form_geo_unit_default', array('km'=>'km','mi'=>'mi'), '');
69
- ?>
70
- </tbody>
71
- </table>
72
- <table class="form-table">
73
- <tr class="em-header"><td colspan="2"><h4><?php _e('Advanced Search Fields','events-manager'); ?></h4></td></tr>
74
- <?php
75
- em_options_radio_binary ( __( 'Enable advanced fields?', 'events-manager'), 'dbem_search_form_advanced', __('Enables additional advanced search fields such as dates, country, etc.','events-manager'), '', '.em-search-form-advanced' );
76
- ?>
77
- <tbody class="em-search-form-advanced">
78
- <?php
79
- em_options_input_text ( __( 'Search button text', 'events-manager'), 'dbem_search_form_submit', __("If there's no fields to show in the main search section, this button will be used instead at the bottom of the advanced fields.",'events-manager'));
80
- em_options_radio_binary ( __( 'Hidden by default?', 'events-manager'), 'dbem_search_form_advanced_hidden', __('If set to yes, advanced search fields will be hidden by default and can be revealed by clicking the "Advanced Search" link.','events-manager'), '', '#dbem_search_form_advanced_show_row, #dbem_search_form_advanced_hide_row' );
81
- em_options_input_text ( __( 'Show label', 'events-manager'), 'dbem_search_form_advanced_show', __('Appears as the label for this search option.','events-manager') );
82
- em_options_input_text ( __( 'Hide label', 'events-manager'), 'dbem_search_form_advanced_hide', __('Appears as the label for this search option.','events-manager') );
83
- ?>
84
- </tbody>
85
- <tbody class="em-search-form-advanced em-subsection">
86
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'Dates', 'events-manager'); ?></h5></td></tr>
87
- <?php
88
- em_options_radio_binary ( __( 'Show date range?', 'events-manager'), 'dbem_search_form_dates', '', '', '#dbem_search_form_dates_label_row, #dbem_search_form_dates_separator_row' );
89
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_dates_label', __('Appears as the label for this search option.','events-manager') );
90
- em_options_input_text ( __( 'Date Separator', 'events-manager'), 'dbem_search_form_dates_separator', sprintf(__( 'For when start/end %s are present, this will separate the two (include spaces here if necessary).', 'events-manager'), __('dates','events-manager')) );
91
- ?>
92
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'Category', 'events-manager'); ?></h5></td></tr>
93
- <?php
94
- em_options_radio_binary ( __( 'Show categories?', 'events-manager'), 'dbem_search_form_categories', '', '', '#dbem_search_form_category_label_row, #dbem_search_form_categories_label_row' );
95
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_category_label', __('Appears as the label for this search option.','events-manager') );
96
- em_options_input_text ( __( 'Categories dropdown label', 'events-manager'), 'dbem_search_form_categories_label', __('Appears as the first default search option.','events-manager') );
97
- ?>
98
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'Geolocation Search', 'events-manager'); ?></h5></td></tr>
99
- <?php
100
- em_options_radio_binary ( __( 'Show distance options?', 'events-manager'), 'dbem_search_form_geo_units', '', '', '#dbem_search_form_geo_units_label_row, #dbem_search_form_geo_distance_options_row' );
101
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_geo_units_label', __('Appears as the label for this search option.','events-manager') );
102
- em_options_input_text ( __( 'Distance Values', 'events-manager'), 'dbem_search_form_geo_distance_options', __('The numerical units shown to those searching by distance. Use comma-separated numbers, such as "25,50,100".','events-manager') );
103
- ?>
104
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'Country', 'events-manager'); ?></h5></td></tr>
105
- <?php
106
- em_options_radio_binary ( __( 'Show countries?', 'events-manager'), 'dbem_search_form_countries', '', '', '#dbem_search_form_default_country_row, #dbem_search_form_country_label_row, #dbem_search_form_countries_label_row' );
107
- em_options_select ( __( 'Default Country', 'events-manager'), 'dbem_search_form_default_country', em_get_countries(__('no default country', 'events-manager')), __('Search form will be pre-selected with this country.','events-manager') );
108
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_country_label', __('Appears as the label for this search option.','events-manager') );
109
- em_options_input_text ( __( 'All countries text', 'events-manager'), 'dbem_search_form_countries_label', __('Appears as the first default search option.','events-manager') );
110
- ?>
111
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'Region', 'events-manager'); ?></h5></td></tr>
112
- <?php
113
- em_options_radio_binary ( __( 'Show regions?', 'events-manager'), 'dbem_search_form_regions', '', '', '#dbem_search_form_region_label_row, #dbem_search_form_regions_label_row' );
114
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_region_label', __('Appears as the label for this search option.','events-manager') );
115
- em_options_input_text ( __( 'All regions text', 'events-manager'), 'dbem_search_form_regions_label', __('Appears as the first default search option.','events-manager') );
116
- ?>
117
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'State/County', 'events-manager'); ?></h5></td></tr>
118
- <?php
119
- em_options_radio_binary ( __( 'Show states?', 'events-manager'), 'dbem_search_form_states', '', '', '#dbem_search_form_state_label_row, #dbem_search_form_states_label_row' );
120
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_state_label', __('Appears as the label for this search option.','events-manager') );
121
- em_options_input_text ( __( 'All states text', 'events-manager'), 'dbem_search_form_states_label', __('Appears as the first default search option.','events-manager') );
122
- ?>
123
- <tr class="em-subheader"><td colspan="2"><h5><?php esc_html_e( 'City/Town', 'events-manager'); ?></h5></td></tr>
124
- <?php
125
- em_options_radio_binary ( __( 'Show towns/cities?', 'events-manager'), 'dbem_search_form_towns', '', '', '#dbem_search_form_town_label_row, #dbem_search_form_towns_label_row' );
126
- em_options_input_text ( __( 'Label', 'events-manager'), 'dbem_search_form_town_label', __('Appears as the label for this search option.','events-manager') );
127
- em_options_input_text ( __( 'All towns/cities text', 'events-manager'), 'dbem_search_form_towns_label', __('Appears as the first default search option.','events-manager') );
128
- ?>
129
- </tbody>
130
- <?php echo $save_button; ?>
131
- </table>
132
- </div> <!-- . inside -->
133
- </div> <!-- .postbox -->
134
-
135
- <div class="postbox " id="em-opt-date-time" >
136
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Date/Time', 'events-manager'); ?> </span></h3>
137
- <div class="inside">
138
- <p class="em-boxheader"><?php
139
- $date_time_format_tip = sprintf(__('Date and Time formats follow the <a href="%s">WordPress time formatting conventions</a>', 'events-manager'), 'http://codex.wordpress.org/Formatting_Date_and_Time');
140
- echo $date_time_format_tip;
141
- ?></p>
142
- <table class="form-table">
143
- <?php
144
- em_options_input_text ( __( 'Date Format', 'events-manager'), 'dbem_date_format', sprintf(__('For use with the %s placeholder','events-manager'),'<code>#_EVENTDATES</code>') );
145
- em_options_input_text ( __( 'Date Picker Format', 'events-manager'), 'dbem_date_format_js', sprintf(__( 'Same as <em>Date Format</em>, but this is used for the datepickers used by Events Manager. This uses a slightly different format to the others on here, for a list of characters to use, visit the <a href="%s">jQuery formatDate reference</a>', 'events-manager'),'https://api.jqueryui.com/datepicker/#utility-formatDate') );
146
- em_options_input_text ( __( 'Date Separator', 'events-manager'), 'dbem_dates_separator', sprintf(__( 'For when start/end %s are present, this will separate the two (include spaces here if necessary).', 'events-manager'), __('dates','events-manager')) );
147
- em_options_input_text ( __( 'Time Format', 'events-manager'), 'dbem_time_format', sprintf(__('For use with the %s placeholder','events-manager'),'<code>#_EVENTTIMES</code>') );
148
- em_options_input_text ( __( 'Time Separator', 'events-manager'), 'dbem_times_separator', sprintf(__( 'For when start/end %s are present, this will separate the two (include spaces here if necessary).', 'events-manager'), __('times','events-manager')) );
149
- em_options_input_text ( __( 'All Day Message', 'events-manager'), 'dbem_event_all_day_message', sprintf(__( 'If an event lasts all day, this text will show if using the %s placeholder', 'events-manager'), '<code>#_EVENTTIMES</code>') );
150
- em_options_radio_binary ( __( 'Use 24h Format?', 'events-manager'), 'dbem_time_24h', __( 'When creating events, would you like your times to be shown in 24 hour format?', 'events-manager') );
151
- echo $save_button;
152
- ?>
153
- </table>
154
- </div> <!-- . inside -->
155
- </div> <!-- .postbox -->
156
-
157
- <div class="postbox " id="em-opt-calendar-formats" >
158
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Calendar', 'events-manager'); ?></span></h3>
159
- <div class="inside">
160
- <table class="form-table">
161
- <?php
162
- em_options_radio_binary ( __( 'Link directly to event on day with single event?', 'events-manager'), 'dbem_calendar_direct_links', __( "If a calendar day has only one event, you can force a direct link to the event (recommended to avoid duplicate content).",'events-manager') );
163
- em_options_radio_binary ( __( 'Show list on day with single event?', 'events-manager'), 'dbem_display_calendar_day_single', __( "By default, if a calendar day only has one event, it display a single event when clicking on the link of that calendar date. If you select Yes here, you will get always see a list of events.",'events-manager') );
164
- ?>
165
- <tr class="em-header"><td colspan="2"><h4><?php _e('Full-Size Calendar','events-manager'); ?></h4></td></tr>
166
- <?php
167
- em_options_input_text ( __( 'Month format', 'events-manager'), 'dbem_full_calendar_month_format', __('The format of the month/year header of the calendar.','events-manager').' '.$date_time_format_tip);
168
- em_options_input_text ( __( 'Event format', 'events-manager'), 'dbem_full_calendar_event_format', __( 'The format of each event when displayed in the full calendar. Remember to include <code>li</code> tags before and after the event.', 'events-manager').$events_placeholder_tip );
169
- em_options_radio_binary( __( 'Abbreviated weekdays?', 'events-manager'), 'dbem_full_calendar_abbreviated_weekdays', __( 'Use abbreviations, e.g. Friday = Fri. Useful for certain languages where abbreviations differ from full names.','events-manager') );
170
- em_options_input_text ( __( 'Initial lengths', 'events-manager'), 'dbem_full_calendar_initials_length', __( 'Shorten the calendar headings containing the days of the week, use 0 for the full name.', 'events-manager').$events_placeholder_tip);
171
- em_options_radio_binary( __( 'Show Long Events?', 'events-manager'), 'dbem_full_calendar_long_events', __( 'Events with multiple dates will appear on each of those dates in the calendar.','events-manager') );
172
- ?>
173
- <tr class="em-header"><td colspan="2"><h4><?php _e('Small Calendar','events-manager'); ?></h4></td></tr>
174
- <?php
175
- em_options_input_text ( __( 'Month format', 'events-manager'), 'dbem_small_calendar_month_format', __('The format of the month/year header of the calendar.','events-manager').' '.$date_time_format_tip);
176
- em_options_input_text ( __( 'Event titles', 'events-manager'), 'dbem_small_calendar_event_title_format', __( 'The format of the title, corresponding to the text that appears when hovering on an eventful calendar day.', 'events-manager').$events_placeholder_tip );
177
- em_options_input_text ( __( 'Title separator', 'events-manager'), 'dbem_small_calendar_event_title_separator', __( 'The separator appearing on the above title when more than one events are taking place on the same day.', 'events-manager') );
178
- em_options_radio_binary( __( 'Abbreviated weekdays', 'events-manager'), 'dbem_small_calendar_abbreviated_weekdays', __( 'The calendar headings uses abbreviated weekdays','events-manager') );
179
- em_options_input_text ( __( 'Initial lengths', 'events-manager'), 'dbem_small_calendar_initials_length', __( 'Shorten the calendar headings containing the days of the week, use 0 for the full name.', 'events-manager').$events_placeholder_tip );
180
- em_options_radio_binary( __( 'Show Long Events?', 'events-manager'), 'dbem_small_calendar_long_events', __( 'Events with multiple dates will appear on each of those dates in the calendar.','events-manager') );
181
- ?>
182
- <tr class="em-header"><td colspan="2"><h4><?php echo __('Calendar Day Event List Settings','events-manager'); ?></h4></td></tr>
183
- <tr valign="top" id='dbem_display_calendar_orderby_row'>
184
- <th scope="row"><?php _e('Default event list ordering','events-manager'); ?></th>
185
- <td>
186
- <select name="dbem_display_calendar_orderby" >
187
- <?php
188
- $orderby_options = apply_filters('dbem_display_calendar_orderby_ddm', array(
189
- 'event_name,event_start_time' => __('Order by event name, then event start time','events-manager'),
190
- 'event_start_time,event_name' => __('Order by event start time, then event name','events-manager')
191
- ));
192
- ?>
193
- <?php foreach($orderby_options as $key => $value) : ?>
194
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_display_calendar_orderby')) ? "selected='selected'" : ''; ?>>
195
- <?php echo esc_html($value) ?>
196
- </option>
197
- <?php endforeach; ?>
198
- </select>
199
- <select name="dbem_display_calendar_order" >
200
- <?php
201
- $ascending = __('Ascending','events-manager');
202
- $descending = __('Descending','events-manager');
203
- $order_options = apply_filters('dbem_display_calendar_order_ddm', array(
204
- 'ASC' => __('All Ascending','events-manager'),
205
- 'DESC,ASC' => "$descending, $ascending",
206
- 'DESC,DESC' => "$descending, $descending",
207
- 'DESC' => __('All Descending','events-manager')
208
- ));
209
- ?>
210
- <?php foreach( $order_options as $key => $value) : ?>
211
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_display_calendar_order')) ? "selected='selected'" : ''; ?>>
212
- <?php echo esc_html($value) ?>
213
- </option>
214
- <?php endforeach; ?>
215
- </select>
216
- <br/>
217
- <em><?php _e('When Events Manager displays lists of events the default behavior is ordering by start date in ascending order. To change this, modify the values above.','events-manager'); ?></em>
218
- </td>
219
- </tr>
220
- <?php
221
- em_options_input_text ( __( 'Calendar events/day limit', 'events-manager'), 'dbem_display_calendar_events_limit', __( 'Limits the number of events on each calendar day. Leave blank for no limit.', 'events-manager') );
222
- em_options_input_text ( __( 'More Events message', 'events-manager'), 'dbem_display_calendar_events_limit_msg', __( 'Text with link to calendar day page with all events for that day if there are more events than the limit above, leave blank for no link as the day number is also a link.', 'events-manager') );
223
- ?>
224
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('iCal Feed Settings','events-manager'),__('Event','events-manager')); ?></h4></td></tr>
225
- <?php
226
- em_options_input_text ( __( 'iCal Title', 'events-manager'), 'dbem_ical_description_format', __( 'The title that will appear in the calendar.', 'events-manager').$events_placeholder_tip );
227
- em_options_input_text ( __( 'iCal Description', 'events-manager'), 'dbem_ical_real_description_format', __( 'The description of the event that will appear in the calendar.', 'events-manager').$events_placeholder_tip );
228
- em_options_input_text ( __( 'iCal Location', 'events-manager'), 'dbem_ical_location_format', __( 'The location information that will appear in the calendar.', 'events-manager').$events_placeholder_tip );
229
- em_options_select( __('iCal Scope','events-manager'), 'dbem_ical_scope', em_get_scopes(), __('Choose to show events within a specific time range.','events-manager'));
230
- em_options_input_text ( __( 'iCal Limit', 'events-manager'), 'dbem_ical_limit', __( 'Limits the number of future events shown (0 = unlimited).', 'events-manager') );
231
- echo $save_button;
232
- ?>
233
- </table>
234
- </div> <!-- . inside -->
235
- </div> <!-- .postbox -->
236
-
237
- <?php if( get_option('dbem_locations_enabled') ): ?>
238
- <div class="postbox " id="em-opt-locations-formats" >
239
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Locations', 'events-manager'); ?> </span></h3>
240
- <div class="inside">
241
- <table class="form-table">
242
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('%s Page','events-manager'),__('Locations','events-manager')); ?></h4></td></tr>
243
- <?php
244
- em_options_textarea ( sprintf(__('%s list header format','events-manager'),__('Locations','events-manager')), 'dbem_location_list_item_format_header', sprintf(__( 'This content will appear just above your code for the %s list format below. Default is blank', 'events-manager'), __('locations','events-manager')) );
245
- em_options_textarea ( sprintf(__('%s list item format','events-manager'),__('Locations','events-manager')), 'dbem_location_list_item_format', sprintf(__( 'The format of a single %s in a list.', 'events-manager'), __('locations','events-manager')).$locations_placeholder_tip );
246
- em_options_textarea ( sprintf(__('%s list footer format','events-manager'),__('Locations','events-manager')), 'dbem_location_list_item_format_footer', sprintf(__( 'This content will appear just below your code for the %s list format above. Default is blank', 'events-manager'), __('locations','events-manager')) );
247
- em_options_input_text ( sprintf(__( 'No %s message', 'events-manager'),__('Locations','events-manager')), 'dbem_no_locations_message', sprintf( __( 'The message displayed when no %s are available.', 'events-manager'), __('locations','events-manager')) );
248
- ?>
249
- <tr class="em-header">
250
- <td colspan="2">
251
- <h4><?php echo sprintf(__('Single %s Page','events-manager'),__('Location','events-manager')); ?></h4>
252
- <em><?php echo sprintf(__('These formats can be used on %s pages or on other areas of your site displaying an %s.','events-manager'),__('location','events-manager'),__('location','events-manager'));?></em>
253
- </tr>
254
- <?php
255
- if( EM_MS_GLOBAL && get_option('dbem_ms_global_location_links') ){
256
- em_options_input_text (sprintf( __( 'Single %s title format', 'events-manager'),__('location','events-manager')), 'dbem_location_page_title_format', sprintf(__( 'The format of a single %s page title.', 'events-manager'),__('location','events-manager')).$locations_placeholder_tip );
257
- }
258
- em_options_textarea ( sprintf(__('Single %s page format', 'events-manager'),__('location','events-manager')), 'dbem_single_location_format', sprintf(__( 'The format of a single %s page.', 'events-manager'),__('location','events-manager')).$locations_placeholder_tip );
259
- ?>
260
- <tr class="em-header">
261
- <td colspan="2">
262
- <h4><?php echo sprintf(__('%s Excerpts','events-manager'),__('Location','events-manager')); ?></h4>
263
- <em><?php echo sprintf(__('These formats can be used when WordPress automatically displays %s excerpts on your site and %s is enabled in your %s settings tab.','events-manager'),__('location','events-manager'),'<strong>'.__( 'Override Excerpts with Formats?', 'events-manager').'</strong>','<a href="#formats" class="nav-tab-link" rel="#em-menu-pages">'.__('Pages','events-manager').' &gt; '.sprintf(__('%s List/Archives','events-manager'),__('Location','events-manager')).'</a>');?></em>
264
- </td>
265
- </tr>
266
- <?php
267
- em_options_textarea ( sprintf(__('%s excerpt', 'events-manager'),__('Location','events-manager')), 'dbem_location_excerpt_format', __( 'Used if an excerpt has been defined.', 'events-manager').$locations_placeholder_tip );
268
- em_options_textarea ( sprintf(__('%s excerpt fallback', 'events-manager'),__('Location','events-manager')), 'dbem_location_excerpt_alt_format', __( 'Used if an excerpt has not been defined.', 'events-manager').$locations_placeholder_tip );
269
- ?>
270
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('%s List Formats','events-manager'),__('Event','events-manager')); ?></h4></td></tr>
271
- <?php
272
- em_options_input_text ( __( 'Default event list format header', 'events-manager'), 'dbem_location_event_list_item_header_format', __( 'This content will appear just above your code for the default event list format. Default is blank', 'events-manager') );
273
- em_options_textarea ( sprintf(__( 'Default %s list format', 'events-manager'),__('events','events-manager')), 'dbem_location_event_list_item_format', sprintf(__( 'The format of the events the list inserted in the location page through the %s element.', 'events-manager').$events_placeholder_tip, '<code>#_LOCATIONNEXTEVENTS</code>, <code>#_LOCATIONPASTEVENTS</code>, <code>#_LOCATIONALLEVENTS</code>') );
274
- em_options_input_text ( __( 'Default event list format footer', 'events-manager'), 'dbem_location_event_list_item_footer_format', __( 'This content will appear just below your code for the default event list format. Default is blank', 'events-manager') );
275
- em_options_textarea ( sprintf(__( 'No %s message', 'events-manager'),__('events','events-manager')), 'dbem_location_no_events_message', sprintf(__( 'The message to be displayed in the list generated by %s when no events are available.', 'events-manager'), '<code>#_LOCATIONNEXTEVENTS</code>, <code>#_LOCATIONPASTEVENTS</code>, <code>#_LOCATIONALLEVENTS</code>') );
276
- ?>
277
- <tr class="em-header"><td colspan="2">
278
- <h4><?php echo sprintf(__('Single %s Format','events-manager'),__('Event','events-manager')); ?></h4>
279
- <p><?php echo sprintf(__('The settings below are used when using the %s placeholder','events-manager'), '<code>#_LOCATIONNEXTEVENT</code>'); ?></p>
280
- </td></tr>
281
- <?php
282
- em_options_input_text ( __( 'Next event format', 'events-manager'), 'dbem_location_event_single_format', sprintf(__( 'The format of the next upcoming event in this %s.', 'events-manager'),__('location','events-manager')).$events_placeholder_tip );
283
- em_options_input_text ( sprintf(__( 'No %s message', 'events-manager'),__('events','events-manager')), 'dbem_location_no_event_message', sprintf(__( 'The message to be displayed in the list generated by %s when no events are available.', 'events-manager'), '<code>#_LOCATIONNEXTEVENT</code>') );
284
- echo $save_button;
285
- ?>
286
- </table>
287
- </div> <!-- . inside -->
288
- </div> <!-- .postbox -->
289
- <?php endif; ?>
290
-
291
- <?php if( get_option('dbem_categories_enabled') && !(EM_MS_GLOBAL && !is_main_site()) ): ?>
292
- <div class="postbox " id="em-opt-categories-formats" >
293
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Event Categories', 'events-manager'); ?> </span></h3>
294
- <div class="inside">
295
- <table class="form-table">
296
- <?php
297
- em_options_input_text(sprintf(esc_html__('Default %s color','events-manager'), esc_html__('category','events-manager')), 'dbem_category_default_color', sprintf(esc_html_x('Colors must be in a valid %s format, such as #FF00EE.', 'hex format', 'events-manager'), '<a href="http://en.wikipedia.org/wiki/Web_colors">hex</a>'));
298
- ?>
299
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('%s Page','events-manager'),__('Categories','events-manager')); ?></h4></td></tr>
300
- <?php
301
- em_options_textarea ( sprintf(__('%s list header format','events-manager'),__('Categories','events-manager')), 'dbem_categories_list_item_format_header', sprintf(__( 'This content will appear just above your code for the %s list format below. Default is blank', 'events-manager'), __('categories','events-manager')) );
302
- em_options_textarea ( sprintf(__('%s list item format','events-manager'),__('Categories','events-manager')), 'dbem_categories_list_item_format', sprintf(__( 'The format of a single %s in a list.', 'events-manager'), __('categories','events-manager')).$categories_placeholder_tip );
303
- em_options_textarea ( sprintf(__('%s list footer format','events-manager'),__('Categories','events-manager')), 'dbem_categories_list_item_format_footer', sprintf(__( 'This content will appear just below your code for the %s list format above. Default is blank', 'events-manager'), __('categories','events-manager')) );
304
- em_options_input_text ( sprintf(__( 'No %s message', 'events-manager'),__('Categories','events-manager')), 'dbem_no_categories_message', sprintf( __( 'The message displayed when no %s are available.', 'events-manager'), __('categories','events-manager')) );
305
- ?>
306
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('Single %s Page','events-manager'),__('Category','events-manager')); ?></h4></td></tr>
307
- <?php
308
- em_options_input_text ( sprintf(__( 'Single %s title format', 'events-manager'),__('category','events-manager')), 'dbem_category_page_title_format', __( 'The format of a single category page title.', 'events-manager').$categories_placeholder_tip );
309
- em_options_textarea ( sprintf(__('Single %s page format', 'events-manager'),__('category','events-manager')), 'dbem_category_page_format', sprintf(__( 'The format of a single %s page.', 'events-manager'),__('category','events-manager')).$categories_placeholder_tip );
310
- ?>
311
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('%s List Formats','events-manager'),__('Event','events-manager')); ?></h4></td></tr>
312
- <?php
313
- em_options_input_text ( __( 'Default event list format header', 'events-manager'), 'dbem_category_event_list_item_header_format', __( 'This content will appear just above your code for the default event list format. Default is blank', 'events-manager') );
314
- em_options_textarea ( sprintf(__( 'Default %s list format', 'events-manager'),__('events','events-manager')), 'dbem_category_event_list_item_format', sprintf(__( 'The format of the events the list inserted in the category page through the %s element.', 'events-manager').$events_placeholder_tip, '<code>#_CATEGORYPASTEVENTS</code>, <code>#_CATEGORYNEXTEVENTS</code>, <code>#_CATEGORYALLEVENTS</code>') );
315
- em_options_input_text ( __( 'Default event list format footer', 'events-manager'), 'dbem_category_event_list_item_footer_format', __( 'This content will appear just below your code for the default event list format. Default is blank', 'events-manager') );
316
- em_options_textarea ( sprintf(__( 'No %s message', 'events-manager'),__('events','events-manager')), 'dbem_category_no_events_message', sprintf(__( 'The message to be displayed in the list generated by %s when no events are available.', 'events-manager'), '<code>#_CATEGORYPASTEVENTS</code>, <code>#_CATEGORYNEXTEVENTS</code>, <code>#_CATEGORYALLEVENTS</code>') );
317
- ?>
318
- <tr class="em-header"><td colspan="2">
319
- <h4><?php echo sprintf(__('Single %s Format','events-manager'),__('Event','events-manager')); ?></h4>
320
- <p><?php echo sprintf(__('The settings below are used when using the %s placeholder','events-manager'), '<code>#_CATEGORYNEXTEVENT</code>'); ?></p>
321
- </td></tr>
322
- <?php
323
- em_options_input_text ( __( 'Next event format', 'events-manager'), 'dbem_category_event_single_format', sprintf(__( 'The format of the next upcoming event in this %s.', 'events-manager'),__('category','events-manager')).$events_placeholder_tip );
324
- em_options_input_text ( sprintf(__( 'No %s message', 'events-manager'),__('events','events-manager')), 'dbem_category_no_event_message', sprintf(__( 'The message to be displayed in the list generated by %s when no events are available.', 'events-manager'), '<code>#_CATEGORYNEXTEVENT</code>') );
325
- echo $save_button;
326
- ?>
327
- </table>
328
- </div> <!-- . inside -->
329
- </div> <!-- .postbox -->
330
- <?php endif; ?>
331
-
332
- <?php if( get_option('dbem_tags_enabled') ): ?>
333
- <div class="postbox " id="em-opt-tags-formats" >
334
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Event Tags', 'events-manager'); ?> </span></h3>
335
- <div class="inside">
336
- <table class="form-table">
337
- <?php
338
- em_options_input_text(sprintf(esc_html__('Default %s color','events-manager'), esc_html__('tag','events-manager')), 'dbem_tag_default_color', sprintf(esc_html_x('Colors must be in a valid %s format, such as #FF00EE.', 'hex format', 'events-manager'), '<a href="http://en.wikipedia.org/wiki/Web_colors">hex</a>'));
339
- ?>
340
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('%s Page','events-manager'),__('Tags','events-manager')); ?></h4></td></tr>
341
- <?php
342
- em_options_textarea ( sprintf(__('%s list header format','events-manager'),__('Tags','events-manager')), 'dbem_tags_list_item_format_header', sprintf(__( 'This content will appear just above your code for the %s list format below. Default is blank', 'events-manager'), __('tags','events-manager')) );
343
- em_options_textarea ( sprintf(__('%s list item format','events-manager'),__('Tags','events-manager')), 'dbem_tags_list_item_format', sprintf(__( 'The format of a single %s in a list.', 'events-manager'), __('tags','events-manager')).$categories_placeholder_tip );
344
- em_options_textarea ( sprintf(__('%s list footer format','events-manager'),__('Tags','events-manager')), 'dbem_tags_list_item_format_footer', sprintf(__( 'This content will appear just below your code for the %s list format above. Default is blank', 'events-manager'), __('tags','events-manager')) );
345
- em_options_input_text ( sprintf(__( 'No %s message', 'events-manager'),__('Tags','events-manager')), 'dbem_no_tags_message', sprintf( __( 'The message displayed when no %s are available.', 'events-manager'), __('tags','events-manager')) );
346
- ?>
347
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('Single %s Page','events-manager'),__('Tag','events-manager')); ?></h4></td></tr>
348
- <?php
349
- em_options_input_text ( sprintf(__( 'Single %s title format', 'events-manager'),__('tag','events-manager')), 'dbem_tag_page_title_format', __( 'The format of a single tag page title.', 'events-manager').$categories_placeholder_tip );
350
- em_options_textarea ( sprintf(__('Single %s page format', 'events-manager'),__('tag','events-manager')), 'dbem_tag_page_format', sprintf(__( 'The format of a single %s page.', 'events-manager'),__('tag','events-manager')).$categories_placeholder_tip );
351
- ?>
352
- <tr class="em-header"><td colspan="2"><h4><?php echo sprintf(__('%s List Formats','events-manager'),__('Event','events-manager')); ?></h4></td></tr>
353
- <?php
354
- em_options_input_text ( __( 'Default event list format header', 'events-manager'), 'dbem_tag_event_list_item_header_format', __( 'This content will appear just above your code for the default event list format. Default is blank', 'events-manager') );
355
- em_options_textarea ( sprintf(__( 'Default %s list format', 'events-manager'),__('events','events-manager')), 'dbem_tag_event_list_item_format', __( 'The format of the events the list inserted in the tag page through the <code>#_TAGNEXTEVENTS</code>, <code>#_TAGNEXTEVENTS</code> and <code>#_TAGALLEVENTS</code> element.', 'events-manager').$categories_placeholder_tip );
356
- em_options_input_text ( __( 'Default event list format footer', 'events-manager'), 'dbem_tag_event_list_item_footer_format', __( 'This content will appear just below your code for the default event list format. Default is blank', 'events-manager') );
357
- em_options_textarea ( sprintf(__( 'No %s message', 'events-manager'),__('events','events-manager')), 'dbem_tag_no_events_message', __( 'The message to be displayed in the list generated by <code>#_TAGNEXTEVENTS</code>, <code>#_TAGNEXTEVENTS</code> and <code>#_TAGALLEVENTS</code> when no events are available.', 'events-manager') );
358
- ?>
359
- <tr class="em-header"><td colspan="2">
360
- <h4><?php echo sprintf(__('Single %s Format','events-manager'),__('Event','events-manager')); ?></h4>
361
- <p><?php echo sprintf(__('The settings below are used when using the %s placeholder','events-manager'), '<code>#_TAGNEXTEVENT</code>'); ?></p>
362
- </td></tr>
363
- <?php
364
- em_options_input_text ( __( 'Next event format', 'events-manager'), 'dbem_tag_event_single_format', sprintf(__( 'The format of the next upcoming event in this %s.', 'events-manager'),__('tag','events-manager')).$events_placeholder_tip );
365
- em_options_input_text ( sprintf(__( 'No %s message', 'events-manager'),__('events','events-manager')), 'dbem_tag_no_event_message', sprintf(__( 'The message to be displayed in the list generated by %s when no events are available.', 'events-manager'), '<code>#_CATEGORYNEXTEVENT</code>') );
366
- echo $save_button;
367
- ?>
368
- </table>
369
- </div> <!-- . inside -->
370
- </div> <!-- .postbox -->
371
- <?php endif; ?>
372
-
373
- <div class="postbox " id="em-opt-rss-formats" >
374
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'RSS', 'events-manager'); ?> </span></h3>
375
- <div class="inside">
376
- <table class="form-table">
377
- <?php
378
- em_options_input_text ( __( 'RSS main title', 'events-manager'), 'dbem_rss_main_title', __( 'The main title of your RSS events feed.', 'events-manager').$events_placeholder_tip );
379
- em_options_input_text ( __( 'RSS main description', 'events-manager'), 'dbem_rss_main_description', __( 'The main description of your RSS events feed.', 'events-manager') );
380
- em_options_input_text ( __( 'RSS title format', 'events-manager'), 'dbem_rss_title_format', __( 'The format of the title of each item in the events RSS feed.', 'events-manager').$events_placeholder_tip );
381
- em_options_input_text ( __( 'RSS description format', 'events-manager'), 'dbem_rss_description_format', __( 'The format of the description of each item in the events RSS feed.', 'events-manager').$events_placeholder_tip );
382
- em_options_input_text ( __( 'RSS limit', 'events-manager'), 'dbem_rss_limit', __( 'Limits the number of future events shown (0 = unlimited).', 'events-manager') );
383
- em_options_select( __('RSS Scope','events-manager'), 'dbem_rss_scope', em_get_scopes(), __('Choose to show events within a specific time range.','events-manager'));
384
- ?>
385
- <tr valign="top" id='dbem_rss_orderby_row'>
386
- <th scope="row"><?php _e('Default event list ordering','events-manager'); ?></th>
387
- <td>
388
- <select name="dbem_rss_orderby" >
389
- <?php
390
- $orderby_options = apply_filters('em_settings_events_default_orderby_ddm', array(
391
- 'event_start_date,event_start_time,event_name' => __('Order by start date, start time, then event name','events-manager'),
392
- 'event_name,event_start_date,event_start_time' => __('Order by name, start date, then start time','events-manager'),
393
- 'event_name,event_end_date,event_end_time' => __('Order by name, end date, then end time','events-manager'),
394
- 'event_end_date,event_end_time,event_name' => __('Order by end date, end time, then event name','events-manager'),
395
- ));
396
- ?>
397
- <?php foreach($orderby_options as $key => $value) : ?>
398
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_rss_orderby')) ? "selected='selected'" : ''; ?>>
399
- <?php echo esc_html($value); ?>
400
- </option>
401
- <?php endforeach; ?>
402
- </select>
403
- <select name="dbem_rss_order" >
404
- <?php
405
- $ascending = __('Ascending','events-manager');
406
- $descending = __('Descending','events-manager');
407
- $order_options = apply_filters('em_settings_events_default_order_ddm', array(
408
- 'ASC' => __('All Ascending','events-manager'),
409
- 'DESC,ASC,ASC' => __("$descending, $ascending, $ascending",'events-manager'),
410
- 'DESC,DESC,ASC' => __("$descending, $descending, $ascending",'events-manager'),
411
- 'DESC' => __('All Descending','events-manager'),
412
- 'ASC,DESC,ASC' => __("$ascending, $descending, $ascending",'events-manager'),
413
- 'ASC,DESC,DESC' => __("$ascending, $descending, $descending",'events-manager'),
414
- 'ASC,ASC,DESC' => __("$ascending, $ascending, $descending",'events-manager'),
415
- 'DESC,ASC,DESC' => __("$descending, $ascending, $descending",'events-manager'),
416
- ));
417
- ?>
418
- <?php foreach( $order_options as $key => $value) : ?>
419
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_rss_order')) ? "selected='selected'" : ''; ?>>
420
- <?php echo esc_html($value); ?>
421
- </option>
422
- <?php endforeach; ?>
423
- </select>
424
- <br/>
425
- <em><?php _e('When Events Manager displays lists of events the default behavior is ordering by start date in ascending order. To change this, modify the values above.','events-manager'); ?></em>
426
- </td>
427
- </tr>
428
- <?php
429
- echo $save_button;
430
- ?>
431
- </table>
432
- </div> <!-- . inside -->
433
- </div> <!-- .postbox -->
434
-
435
- <div class="postbox " id="em-opt-maps-formats" >
436
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Maps', 'events-manager'); ?> </span></h3>
437
- <div class="inside">
438
- <p class="em-boxheader"><?php echo sprintf(__('You can use Google Maps to show where your events are located. For more information on using maps, <a href="%s">see our documentation</a>.','events-manager'),'http://wp-events-plugin.com/documentation/google-maps/'); ?>
439
- <table class='form-table'>
440
- <tr valign="top">
441
- <?php em_options_input_text(__('Default map width','events-manager'), 'dbem_map_default_width', sprintf(__('Can be in form of pixels or a percentage such as %s or %s.', 'events-manager'), '<code>100%</code>', '<code>100px</code>')); ?>
442
- <?php em_options_input_text(__('Default map height','events-manager'), 'dbem_map_default_height', sprintf(__('Can be in form of pixels or a percentage such as %s or %s.', 'events-manager'), '<code>100%</code>', '<code>100px</code>')); ?>
443
- </tr>
444
- <tr class="em-header"><td colspan="2">
445
- <h4><?php _e('Global Map Format','events-manager'); ?></h4>
446
- <p><?php echo sprintf(__('If you use the %s <a href="%s">shortcode</a>, you can display a map of all your locations and events, the settings below will be used.','events-manager'), '<code>[locations_map]</code>','http://wp-events-plugin.com/documentation/shortcodes/'); ?></p>
447
- </td></tr>
448
- <?php
449
- em_options_textarea ( __( 'Location balloon format', 'events-manager'), 'dbem_map_text_format', __( 'The format of the text appearing in the balloon describing the location.', 'events-manager').' '.__( 'Event.', 'events-manager').$locations_placeholder_tip );
450
- ?>
451
- <tr class="em-header"><td colspan="2">
452
- <h4><?php _e('Single Location/Event Map Format','events-manager'); ?></h4>
453
- <p><?php echo sprintf(_e('If you use the <code>#_LOCATIONMAP</code> <a href="%s">placeholder</a> when displaying individual event and location information, the settings below will be used.','events-manager'), '<code>[locations_map]</code>','http://wp-events-plugin.com/documentation/placeholders/'); ?></p>
454
- </td></tr>
455
- <?php
456
- em_options_textarea ( __( 'Location balloon format', 'events-manager'), 'dbem_location_baloon_format', __( 'The format of the text appearing in the balloon describing the location.', 'events-manager').$events_placeholder_tip );
457
- echo $save_button;
458
- ?>
459
- </table>
460
- </div> <!-- . inside -->
461
- </div> <!-- .postbox -->
462
-
463
- <?php do_action('em_options_page_footer_formats'); ?>
464
-
465
- </div> <!-- .em-menu-formats -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/settings/tabs/general.php DELETED
@@ -1,358 +0,0 @@
1
- <?php if( !function_exists('current_user_can') || !current_user_can('manage_options') ) return; ?>
2
- <!-- GENERAL OPTIONS -->
3
- <div class="em-menu-general em-menu-group">
4
- <div class="postbox " id="em-opt-general" >
5
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div> <h3><span><?php _e ( 'General Options', 'events-manager'); ?> </span></h3>
6
- <div class="inside">
7
- <table class="form-table">
8
- <?php em_options_radio_binary ( __( 'Disable thumbnails?', 'events-manager'), 'dbem_thumbnails_enabled', __( 'Select yes to disable Events Manager from enabling thumbnails (some themes may already have this enabled, which we cannot be turned off here).','events-manager') ); ?>
9
- <tr class="em-header">
10
- <td colspan="2">
11
- <h4><?php echo sprintf(__('%s Settings','events-manager'),__('Event','events-manager')); ?></h4>
12
- </td>
13
- </tr>
14
- <?php
15
- em_options_radio_binary ( __( 'Enable Timezone Support?', 'events-manager'), 'dbem_timezone_enabled', sprintf(__( 'Each event can have its own timezone if enabled. If set to no, then all newly created events will have the blog timezone, which currently is set to %s','events-manager'), '<code>'.EM_DateTimeZone::create()->getName().'</code>'), '', '.event-timezone-option' );
16
- ?>
17
- <tr class="event-timezone-option">
18
- <th>
19
- <label for="event-timezone"><?php esc_html_e('Default Timezone', 'events-manager'); ?></label>
20
- </th>
21
- <td>
22
- <select id="event-timezone" name="dbem_timezone_default">
23
- <?php echo wp_timezone_choice( get_option('dbem_timezone_default') ); ?>
24
- </select><br />
25
- <i><?php esc_html_e('When creating a new event, this timezone will be applied by default.','events-manager'); ?></i>
26
- </td>
27
- </tr>
28
- <?php
29
- em_options_radio_binary ( __( 'Enable recurrence?', 'events-manager'), 'dbem_recurrence_enabled', __( 'Select yes to enable the recurrence features feature','events-manager') );
30
- em_options_radio_binary ( __( 'Enable bookings?', 'events-manager'), 'dbem_rsvp_enabled', __( 'Select yes to allow bookings and tickets for events.','events-manager') );
31
- em_options_radio_binary ( __( 'Enable tags?', 'events-manager'), 'dbem_tags_enabled', __( 'Select yes to enable the tag features','events-manager') );
32
- if( !(EM_MS_GLOBAL && !is_main_site()) ){
33
- em_options_radio_binary ( __( 'Enable categories?', 'events-manager'), 'dbem_categories_enabled', __( 'Select yes to enable the category features','events-manager') );
34
- if( get_option('dbem_categories_enabled') ){
35
- /*default category*/
36
- $category_options = array();
37
- $category_options[0] = __('no default category','events-manager');
38
- $EM_Categories = EM_Categories::get();
39
- foreach($EM_Categories as $EM_Category){
40
- $category_options[$EM_Category->id] = $EM_Category->name;
41
- }
42
- echo "<tr><th>".__( 'Default Category', 'events-manager')."</th><td>";
43
- wp_dropdown_categories(array( 'hide_empty' => 0, 'name' => 'dbem_default_category', 'hierarchical' => true, 'taxonomy' => EM_TAXONOMY_CATEGORY, 'selected' => get_option('dbem_default_category'), 'show_option_none' => __('None','events-manager'), 'class'=>''));
44
- echo "</br><em>" .__( 'This option allows you to select the default category when adding an event.','events-manager').' '.__('If an event does not have a category assigned when editing, this one will be assigned automatically.','events-manager')."</em>";
45
- echo "</td></tr>";
46
- }
47
- }
48
- em_options_radio_binary ( sprintf(__( 'Enable %s attributes?', 'events-manager'),__('event','events-manager')), 'dbem_attributes_enabled', __( 'Select yes to enable the attributes feature','events-manager') );
49
- em_options_radio_binary ( sprintf(__( 'Enable %s custom fields?', 'events-manager'),__('event','events-manager')), 'dbem_cp_events_custom_fields', __( 'Custom fields are the same as attributes, except you cannot restrict specific values, users can add any kind of custom field name/value pair. Only available in the WordPress admin area.','events-manager') );
50
- if( get_option('dbem_attributes_enabled') ){
51
- em_options_textarea ( sprintf(__( '%s Attributes', 'events-manager'),__('Event','events-manager')), 'dbem_placeholders_custom', sprintf(__( "You can also add event attributes here, one per line in this format <code>#_ATT{key}</code>. They will not appear on event pages unless you insert them into another template below, but you may want to store extra information about an event for other uses. <a href='%s'>More information on placeholders.</a>", 'events-manager'), EM_ADMIN_URL .'&amp;page=events-manager-help') );
52
- }
53
- ?>
54
- <tr class="em-header">
55
- <td colspan="2">
56
- <h4><?php echo sprintf(__('%s Settings','events-manager'),__('Location','events-manager')); ?></h4>
57
- </td>
58
- </tr>
59
- <?php
60
- em_options_radio_binary ( __( 'Enable locations?', 'events-manager'), 'dbem_locations_enabled', __( 'If you disable locations, bear in mind that you should remove your location page, shortcodes and related placeholders from your <a href="#formats" class="nav-tab-link" rel="#em-menu-formats">formats</a>.','events-manager'), '', '.em-location-type-option' );
61
- ?>
62
- <tbody class="em-location-type-option">
63
- <?php
64
- em_options_radio_binary ( __( 'Require locations for events?', 'events-manager'), 'dbem_require_location', __( 'Setting this to no will allow you to submit events without locations. You can use the <code>{no_location}...{/no_location}</code> or <code>{has_location}..{/has_location}</code> conditional placeholder to selectively display location information.','events-manager') );
65
- ?>
66
- <tr valign="top" id='dbem_location_types_row'>
67
- <th scope="row"><?php esc_html_e('Location Types', 'events-manager'); ?></th>
68
- <td>
69
- <?php
70
- $location_types = get_option('dbem_location_types', array());
71
- ?>
72
- <label>
73
- <input type="checkbox" name="dbem_location_types[location]" value="1" <?php if( !empty($location_types['location']) ) echo 'checked'; ?> data-trigger=".em-location-type-option-physical" class="em-trigger">
74
- <?php esc_html_e('Physicial Locations', 'events-manager'); ?>
75
- </label>
76
- <?php foreach (EM_Event_Locations\Event_Locations::get_types() as $event_location_type => $EM_Event_Location_Class): /* @var EM_Event_Locations\Event_Location $EM_Event_Location_Class */ ?>
77
- <br>
78
- <label>
79
- <input type="checkbox" name="dbem_location_types[<?php echo esc_attr($event_location_type); ?>]" value="1" <?php if( !empty($location_types[$event_location_type]) ) echo 'checked'; ?> data-trigger=".em-location-type-option-<?php echo esc_attr($event_location_type); ?>" class="em-trigger">
80
- <?php echo $EM_Event_Location_Class::get_label('plural'); ?>
81
- </label>
82
- <?php endforeach; ?>
83
- <p><em><?php echo sprintf( esc_html__('You can allow different location types which can be assigned to an event. For more information see our %s.', 'events-manager'), '<a href="http://wp-events-plugin.com/documentation/location-types/" target="_blank">'.esc_html__('documentation', 'events-manager').'</a>'); ?></em></p>
84
- </td>
85
- </tr>
86
- </tbody>
87
- </table>
88
- <table class="form-table em-location-type-option">
89
- <tbody class="em-location-type-option-physical">
90
- <tr class="em-subheader">
91
- <td colspan="2">
92
- <h5><?php esc_html_e('Physicial Locations', 'events-manager'); ?></h5>
93
- </td>
94
- </tr>
95
- <?php
96
- if( get_option('dbem_locations_enabled') ){
97
- em_options_radio_binary ( __( 'Use dropdown for locations?', 'events-manager'), 'dbem_use_select_for_locations', __( 'Select yes to select location from a drop-down menu; location selection will be faster, but you will lose the ability to insert locations with events','events-manager') );
98
- em_options_radio_binary ( sprintf(__( 'Enable %s attributes?', 'events-manager'),__('location','events-manager')), 'dbem_location_attributes_enabled', __( 'Select yes to enable the attributes feature','events-manager') );
99
- em_options_radio_binary ( sprintf(__( 'Enable %s custom fields?', 'events-manager'),__('location','events-manager')), 'dbem_cp_locations_custom_fields', __( 'Custom fields are the same as attributes, except you cannot restrict specific values, users can add any kind of custom field name/value pair. Only available in the WordPress admin area.','events-manager') );
100
- if( get_option('dbem_location_attributes_enabled') ){
101
- em_options_textarea ( sprintf(__( '%s Attributes', 'events-manager'),__('Location','events-manager')), 'dbem_location_placeholders_custom', sprintf(__( "You can also add location attributes here, one per line in this format <code>#_LATT{key}</code>. They will not appear on location pages unless you insert them into another template below, but you may want to store extra information about an event for other uses. <a href='%s'>More information on placeholders.</a>", 'events-manager'), EM_ADMIN_URL .'&amp;page=events-manager-help') );
102
- }
103
- /*default location*/
104
- if( defined('EM_OPTIMIZE_SETTINGS_PAGE_LOCATIONS') && EM_OPTIMIZE_SETTINGS_PAGE_LOCATIONS ){
105
- em_options_input_text( __( 'Default Location', 'events-manager'), 'dbem_default_location', __('Please enter your Location ID, or leave blank for no location.','events-manager').' '.__( 'This option allows you to select the default location when adding an event.','events-manager')." ".__('(not applicable with event ownership on presently, coming soon!)','events-manager') );
106
- }else{
107
- $location_options = array();
108
- $location_options[0] = __('no default location','events-manager');
109
- $EM_Locations = EM_Locations::get();
110
- foreach($EM_Locations as $EM_Location){
111
- $location_options[$EM_Location->location_id] = $EM_Location->location_name;
112
- }
113
- em_options_select ( __( 'Default Location', 'events-manager'), 'dbem_default_location', $location_options, __('Please enter your Location ID.','events-manager').' '.__( 'This option allows you to select the default location when adding an event.','events-manager')." ".__('(not applicable with event ownership on presently, coming soon!)','events-manager') );
114
- }
115
-
116
- /*default location country*/
117
- em_options_select ( __( 'Default Location Country', 'events-manager'), 'dbem_location_default_country', em_get_countries(__('no default country', 'events-manager')), __('If you select a default country, that will be pre-selected when creating a new location.','events-manager') );
118
- }
119
- ?>
120
- </tbody>
121
- </table>
122
- <table class="form-table">
123
- <tr class="em-header">
124
- <td colspan="2">
125
- <h4><?php echo sprintf(__('%s Settings','events-manager'),__('Other','events-manager')); ?></h4>
126
- </td>
127
- </tr>
128
- <?php
129
- em_options_radio_binary ( __('Show some love?','events-manager'), 'dbem_credits', __( 'Hundreds of free hours have gone into making this free plugin, show your support and add a small link to the plugin website at the bottom of your event pages.','events-manager') );
130
- echo $save_button;
131
- ?>
132
- </table>
133
-
134
- </div> <!-- . inside -->
135
- </div> <!-- .postbox -->
136
-
137
- <?php if ( !is_multisite() ){ em_admin_option_box_image_sizes(); } ?>
138
-
139
- <?php if ( !is_multisite() || (em_wp_is_super_admin() && !get_site_option('dbem_ms_global_caps')) ){ em_admin_option_box_caps(); } ?>
140
-
141
- <div class="postbox" id="em-opt-google-maps" >
142
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Google Maps and Location Services', 'events-manager'); ?></span></h3>
143
- <div class="inside">
144
- <div class="em-boxheader">
145
- <p><?php esc_html_e('Google Maps API provides you with ways to display maps of your locations and help site visitors find events near their desired locations.','events-manager'); ?></p>
146
- <p style="font-weight: bold; color:#ca4a1f;">
147
- <?php
148
- $msg = esc_html__('Google may charge you for usage, depending on how much traffic your site receives. For more information about how and where Events Manager uses the Google Maps API, and how to manage costs, please see our %s page.', 'events-manager');
149
- echo sprintf($msg, '<a href="https://wp-events-plugin.com/documentation/google-maps/api-usage/?utm_source=plugin&utm_medium=settings&utm_campaign=gmaps-general">'.esc_html__('documentation', 'events-manager').'</a>');
150
- ?>
151
- </p>
152
- </div>
153
- <table class="form-table">
154
- <?php
155
- em_options_radio_binary( esc_html__( 'Enable Google Maps integration?', 'events-manager'), 'dbem_gmap_is_active', esc_html__( 'Check this option to enable Google Map integration.', 'events-manager'), '', '.em-google-maps-enabled' );
156
- ?>
157
- <tbody class="form-table em-google-maps-enabled">
158
- <?php
159
- em_options_input_text(__('Google Maps API Browser Key','events-manager'), 'dbem_google_maps_browser_key', sprintf(__('Google Maps require an API key, please see our %s page for instructions on obtaining one.', 'events-manager'), '<a href="https://wp-events-plugin.com/documentation/google-maps/api-key/?utm_source=plugin&utm_medium=settings&utm_campaign=gmaps-api-key">'.esc_html__('documentation','events-manager').'</a>'));
160
- $google_map_options = apply_filters('em_settings_google_maps_options', array(
161
- 'dynamic' => _x('Dynamic', 'Google Map Type', 'events-manager'),
162
- 'embed' => _x('Embedded', 'Google Map Type', 'events-manager')
163
- ));
164
- $google_map_options_pro = !defined('EMP_VERSION') || EMP_VERSION < 2.64 ? '<strong>'.sprintf(__('Upgrade to %s for more options!', 'events-manager'), '<a target="_blank" href="https://wp-events-plugin.com/google-maps/static-maps/?utm_source=plugin&utm_medium=settings&utm_campaign=gmaps-types">Events Manager Pro</a>').'</strong>' : '';
165
- $google_map_options_desc = sprintf(__('Google offers different map displays, each with varying prices and free usage allowance. See our %s page for more information on these display options.', 'events-manager'), '<a href="https://wp-events-plugin.com/google-maps/map-types/?utm_source=plugin&utm_medium=settings&utm_campaign=gmaps-types">'.__('documentation', 'events-manager').'</a>') .' '. $google_map_options_pro;
166
- em_options_select(__('Google Map Type', 'events-manager'), 'dbem_gmap_type', $google_map_options, $google_map_options_desc);
167
- $embed_options = array('place' => __('Location name and address', 'events-manager'), 'address' => __('Address only', 'events-manager'), 'coordinates' => __('Location coordinates', 'events-manager'));
168
- em_options_select(__('Embed Display Type', 'events-manager'), 'dbem_gmap_embed_type', $embed_options, __('When displaying embedded maps for a location, choose what information Google will use to generate a map from, each producing varying results.', 'events-manager'));
169
- em_options_textarea(__('Google Maps Style', 'events-manager'), 'dbem_google_maps_styles', sprintf(__('You can add styles to your maps to give them a unique look. Build one using the %s or choose from the many free templates on %s paste the generated JSON code here.', 'events-manager'), '<a href="https://mapstyle.withgoogle.com/" target="_blank">'.esc_html__('Google Maps Styling Wizard', 'events-manager').'</a>', '<a href="https://snazzymaps.com/explore" target="_blank">Snazzy Maps</a>'));
170
- ?>
171
- </tbody>
172
- <tbody class="form-table em-google-maps-enabled em-google-maps-static">
173
- <?php do_action('em_settings_google_maps_general'); ?>
174
- </tbody>
175
- <?php
176
- echo $save_button;
177
- ?>
178
- </table>
179
- </div> <!-- . inside -->
180
- </div> <!-- .postbox -->
181
-
182
- <div class="postbox" id="em-opt-event-submissions" >
183
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Event Submission Forms', 'events-manager'); ?></span></h3>
184
- <div class="inside">
185
- <table class="form-table">
186
- <tr><td colspan="2" class="em-boxheader">
187
- <?php echo sprintf(__('You can allow users to publicly submit events on your blog by using the %s shortcode, and enabling anonymous submissions below.','events-manager'), '<code>[event_form]</code>'); ?>
188
- </td></tr>
189
- <?php
190
- em_options_radio_binary ( __( 'Use Visual Editor?', 'events-manager'), 'dbem_events_form_editor', __( 'Users can now use the WordPress editor for easy HTML entry in the submission form.', 'events-manager') );
191
- em_options_radio_binary ( __( 'Show form again?', 'events-manager'), 'dbem_events_form_reshow', __( 'When a user submits their event, you can display a new event form again.', 'events-manager') );
192
- em_options_textarea ( __( 'Success Message', 'events-manager'), 'dbem_events_form_result_success', __( 'Customize the message your user sees when they submitted their event.', 'events-manager').$events_placeholder_tip );
193
- em_options_textarea ( __( 'Successfully Updated Message', 'events-manager'), 'dbem_events_form_result_success_updated', __( 'Customize the message your user sees when they resubmit/update their event.', 'events-manager').$events_placeholder_tip );
194
- ?>
195
- <tr class="em-header"><td colspan="2">
196
- <h4><?php echo sprintf(__('Anonymous event submissions','events-manager'), '<code>[event_form]</code>'); ?></h4>
197
- </td></tr>
198
- <?php
199
- em_options_radio_binary ( __( 'Allow anonymous event submissions?', 'events-manager'), 'dbem_events_anonymous_submissions', __( 'Would you like to allow users to submit bookings anonymously? If so, you can use the new [event_form] shortcode or <code>em_event_form()</code> template tag with this enabled.', 'events-manager') );
200
- if( defined('EM_OPTIMIZE_SETTINGS_PAGE_USERS') && EM_OPTIMIZE_SETTINGS_PAGE_USERS ){
201
- em_options_input_text( __('Guest Default User', 'events-manager'), 'dbem_events_anonymous_user', __('Please add a User ID.','events-manager').' '.__( 'Events require a user to own them. In order to allow events to be submitted anonymously you need to assign that event a specific user. We recommend you create a "Anonymous" subscriber with a very good password and use that. Guests will have the same event permissions as this user when submitting.', 'events-manager') );
202
- }else{
203
- em_options_select ( __('Guest Default User', 'events-manager'), 'dbem_events_anonymous_user', em_get_wp_users (), __( 'Events require a user to own them. In order to allow events to be submitted anonymously you need to assign that event a specific user. We recommend you create a "Anonymous" subscriber with a very good password and use that. Guests will have the same event permissions as this user when submitting.', 'events-manager') );
204
- }
205
- em_options_textarea ( __( 'Success Message', 'events-manager'), 'dbem_events_anonymous_result_success', __( 'Anonymous submitters cannot see or modify their event once submitted. You can customize the success message they see here.', 'events-manager').$events_placeholder_tip );
206
- ?>
207
- <?php echo $save_button; ?>
208
- </table>
209
- </div> <!-- . inside -->
210
- </div> <!-- .postbox -->
211
-
212
- <?php do_action('em_options_page_footer'); ?>
213
-
214
- <?php /*
215
- <div class="postbox" id="em-opt-geo" >
216
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Geo APIs', 'events-manager'); ?> <em>(Beta)</em></span></h3>
217
- <div class="inside">
218
- <p><?php esc_html_e('Geocoding is the process of converting addresses into geographic coordinates, which can be used to find events and locations near a specific coordinate.','events-manager'); ?></p>
219
- <table class="form-table">
220
- <?php
221
- em_options_radio_binary ( __( 'Enable Geocoding Features?', 'events-manager'), 'dbem_geo', '', '', '.em-settings-geocoding');
222
- ?>
223
- </table>
224
- <div class="em-settings-geocoding">
225
- <h4>GeoNames API (geonames.org)</h4>
226
- <p>We make use of the <a href="http://www.geonames.org">GeoNames</a> web service to suggest locations/addresses to users when searching, and converting these into coordinates.</p>
227
- <p>To be able to use these services, you must <a href="http://www.geonames.org/login">register an account</a>, activate the free webservice and enter your username below. You are allowed up to 30,000 requests per day, if you require more you can purchase credits from your account.</p>
228
- <table class="form-table">
229
- <?php em_options_input_text ( __( 'GeoNames Username', 'events-manager'), 'dbem_geonames_username', __('If left blank, this service will not be used.','events-manager')); ?>
230
- </table>
231
- </div>
232
- <table class="form-table"><?php echo $save_button; ?></table>
233
- </div> <!-- . inside -->
234
- </div> <!-- .postbox -->
235
- */ ?>
236
-
237
- <div class="postbox" id="em-opt-performance-optimization" >
238
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Performance Optimization', 'events-manager'); ?> (<?php _e('Advanced','events-manager'); ?>)</span></h3>
239
- <div class="inside">
240
- <?php
241
- $performance_opt_page_instructions = __('In the boxes below, you are expected to write the page IDs. For multiple pages, use comma-separated values e.g. 1,2,3. Entering 0 means EVERY page, -1 means the home page.','events-manager');
242
- ?>
243
- <div class="em-boxheader">
244
- <p><?php _e('This section allows you to configure parts of this plugin that will improve performance on your site and increase page speeds by reducing extra files from being unnecessarily included on pages as well as reducing server loads where possible. This only applies to pages outside the admin area.','events-manager'); ?></p>
245
- <p><strong><?php _e('Warning!','events-manager'); ?></strong> <?php echo sprintf(__('This is for advanced users, you should know what you\'re doing here or things will not work properly. For more information on how these options work see our <a href="%s" target="_blank">optimization recommendations</a>','events-manager'), 'http://wp-events-plugin.com/documentation/optimization-recommendations/'); ?></p>
246
- </div>
247
- <table class="form-table">
248
- <tr class="em-header"><td colspan="2">
249
- <h4><?php _e('JavaScript Files','events-manager'); ?></h4>
250
- </td></tr>
251
- <?php
252
- em_options_radio_binary ( __( 'Limit JS file loading?', 'events-manager'), 'dbem_js_limit', __( 'Prevent unnecessary loading of JavaScript files on pages where they are not needed.', 'events-manager') );
253
- ?>
254
- <tbody id="dbem-js-limit-options">
255
- <tr class="em-subheader"><td colspan="2">
256
- <?php
257
- _e('Aside from pages we automatically generate and include certain jQuery files, if you are using Widgets, Shortcode or PHP to display specific items you may need to tell us where you are using them for them to work properly. Below are options for you to include specific jQuery dependencies only on certain pages.','events-manager');
258
- echo $performance_opt_page_instructions;
259
- ?>
260
- </td></tr>
261
- <?php
262
- em_options_input_text( __( 'General JS', 'events-manager'), 'dbem_js_limit_general', __( 'Loads our own JS file if no other dependencies are already loaded, which is still needed for many items generated by EM using JavaScript such as Calendars, Maps and Booking Forms/Buttons', 'events-manager'), 0 );
263
- em_options_input_text( __( 'Search Forms', 'events-manager'), 'dbem_js_limit_search', __( 'Include pages where you use shortcodes or widgets to display event search forms.', 'events-manager') );
264
- em_options_input_text( __( 'Event Edit and Submission Forms', 'events-manager'), 'dbem_js_limit_events_form', __( 'Include pages where you use shortcode or PHP to display event submission forms.', 'events-manager') );
265
- em_options_input_text( __( 'Booking Management Pages', 'events-manager'), 'dbem_js_limit_edit_bookings', __( 'Include pages where you use shortcode or PHP to display event submission forms.', 'events-manager') );
266
- ?>
267
- </tbody>
268
- <tr class="em-header"><td colspan="2">
269
- <h4><?php _e('CSS File','events-manager'); ?></h4>
270
- </td></tr>
271
- <?php
272
- em_options_radio_binary ( __( 'Limit loading of our CSS files?', 'events-manager'), 'dbem_css_limit', __( 'Enabling this will prevent us from loading our CSS file on every page, and will only load on specific pages generated by Events Manager.', 'events-manager') );
273
- ?>
274
- <tbody id="dbem-css-limit-options">
275
- <tr class="em-subheader"><td colspan="2">
276
- <?php echo $performance_opt_page_instructions; ?>
277
- </td></tr>
278
- <?php
279
- em_options_input_text( __( 'Include on', 'events-manager'), 'dbem_css_limit_include', __( 'Our CSS file will only be INCLUDED on all of these pages.', 'events-manager'), 0 );
280
- em_options_input_text( __( 'Exclude on', 'events-manager'), 'dbem_css_limit_exclude', __( 'Our CSS file will be EXCLUDED on all of these pages. Takes precedence over inclusion rules.', 'events-manager'), 0 );
281
- ?>
282
- </tbody>
283
- <?php
284
- ?>
285
- <tr class="em-header"><td colspan="2">
286
- <h4><?php _e('Thumbnails','events-manager'); ?></h4>
287
- </td></tr>
288
- <?php
289
- em_options_radio_binary ( __( 'Disable WordPress Thumbnails?', 'events-manager'), 'dbem_disable_thumbnails', __( 'If set to yes, full sized images will be used and HTML width and height attributes will be used to determine the size.', 'events-manager').' '.sprintf(__('Setting this to yes will also make your images crop efficiently with the %s feature in the %s plugin.','events-manager'), '<a href="http://jetpack.me/support/photon/">Photon</a>','<a href="https://wordpress.org/plugins/jetpack/">JetPack</a>') );
290
- ?>
291
- <?php echo $save_button; ?>
292
- </table>
293
- <script type="text/javascript">
294
- jQuery(document).ready(function($){
295
- $('input:radio[name="dbem_js_limit"]').on('change', function(){
296
- if( $('input:radio[name="dbem_js_limit"]:checked').val() == 1 ){
297
- $('tbody#dbem-js-limit-options').show();
298
- }else{
299
- $('tbody#dbem-js-limit-options').hide();
300
- }
301
- }).trigger('change');
302
-
303
- $('input:radio[name="dbem_css_limit"]').on('change', function(){
304
- if( $('input:radio[name="dbem_css_limit"]:checked').val() == 1 ){
305
- $('tbody#dbem-css-limit-options').show();
306
- }else{
307
- $('tbody#dbem-css-limit-options').hide();
308
- }
309
- }).trigger('change');
310
- });
311
- </script>
312
- </div> <!-- . inside -->
313
- </div> <!-- .postbox -->
314
-
315
- <div class="postbox" id="em-opt-style-options" >
316
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'Styling Options', 'events-manager'); ?> (<?php _e('Advanced','events-manager'); ?>) <em>(Beta)</em></span></h3>
317
- <div class="inside">
318
- <p class="em-boxheader">
319
- <?php _e('Events Manager imposes a minimal amount of styling on websites so that your themes can take over.','events-manager'); ?>
320
- <?php _e('Below are some additional options for individual pages and sections, which you can turn on to enforce custom styling provided by the plugin or off if you want to do your own custom styling.','events-manager'); ?>
321
- </p>
322
- <table class="form-table">
323
- <?php
324
- em_options_radio_binary ( __( 'Search forms', 'events-manager'), 'dbem_css_search');
325
- ?>
326
- <tr class="em-subheader"><td colspan="2">The options below currently have no effect, but are there so you know what may be added in future updates. You can leave them on if you want furture styling to take effect, or turn them off to keep your current styles as is.</td><tr>
327
- <?php
328
- em_options_radio_binary ( __( 'Event/Location admin pages', 'events-manager'), 'dbem_css_editors' );
329
- em_options_radio_binary ( __( 'Booking admin pages', 'events-manager'), 'dbem_css_rsvpadmin' );
330
- em_options_radio_binary ( __( 'Events list page', 'events-manager'), 'dbem_css_evlist' );
331
- em_options_radio_binary ( __( 'Locations list page', 'events-manager'), 'dbem_css_loclist' );
332
- em_options_radio_binary ( __( 'Event booking forms', 'events-manager'), 'dbem_css_rsvp' );
333
- em_options_radio_binary ( __( 'Categories list page', 'events-manager'), 'dbem_css_catlist' );
334
- em_options_radio_binary ( __( 'Tags list page', 'events-manager'), 'dbem_css_taglist' );
335
- echo $save_button;
336
- ?>
337
- </table>
338
- </div> <!-- . inside -->
339
- </div> <!-- .postbox -->
340
-
341
- <?php em_admin_option_box_data_privacy(); ?>
342
- <?php if ( !is_multisite() ) { em_admin_option_box_uninstall(); } ?>
343
-
344
- <?php if( get_option('dbem_migrate_images') ): ?>
345
- <div class="postbox " >
346
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span>Migrate Images From Version 4</span></h3>
347
- <div class="inside">
348
- <?php /* Not translating as it's temporary */ //EM4 ?>
349
- <p>You have the option of migrating images from version 4 so they become the equivalent of 'featured images' like with regular WordPress posts and pages and are also available in your media library.</p>
350
- <p>Your event and location images will still display correctly on the front-end even if you don't migrate, but will not show up within your edit location/event pages in the admin area.</p>
351
- <p>
352
- <a href="<?php echo esc_url($_SERVER['REQUEST_URI']); ?>&amp;em_migrate_images=1&amp;_wpnonce=<?php echo wp_create_nonce('em_migrate_images'); ?>">Migrate Images</a><br />
353
- <a href="<?php echo esc_url($_SERVER['REQUEST_URI']); ?>&amp;em_not_migrate_images=1&amp;_wpnonce=<?php echo wp_create_nonce('em_not_migrate_images'); ?>">Do Not Migrate Images</a>
354
- </p>
355
- </div> <!-- . inside -->
356
- </div> <!-- .postbox -->
357
- <?php endif; ?>
358
- </div> <!-- .em-menu-general -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/settings/tabs/pages.php DELETED
@@ -1,724 +0,0 @@
1
- <?php if( !function_exists('current_user_can') || !current_user_can('manage_options') ) return; ?>
2
- <!-- PAGE OPTIONS -->
3
- <div class="em-menu-pages em-menu-group" <?php if( !defined('EM_SETTINGS_TABS') || !EM_SETTINGS_TABS) : ?>style="display:none;"<?php endif; ?>>
4
- <?php
5
- $template_page_tip = __( "Many themes display extra meta information on post pages such as 'posted by' or 'post date' information, which may not be desired. Usually, page templates contain less clutter.", 'events-manager');
6
- $template_page_tip .= ' '. __("If you choose 'Pages' then %s will be shown using your theme default page template, alternatively choose from page templates that come with your specific theme.",'events-manager');
7
- $template_page_tip .= ' '. str_replace('#','http://codex.wordpress.org/Post_Types#Template_Files',__("Be aware that some themes will not work with this option, if so (or you want to make your own changes), you can create a file named <code>single-%s.php</code> <a href='#'>as shown on the WordPress codex</a>, and leave this set to Posts.", 'events-manager'));
8
- $body_class_tip = __('If you would like to add extra classes to your body html tag when a single %s page is displayed, enter it here. May be useful or necessary if your theme requires special class names for specific templates.','events-manager');
9
- $post_class_tip = __('Same concept as the body classes option, but some themes also use the <code>post_class()</code> function within page content to differentiate styling between post types.','events-manager');
10
- $format_override_tip = __("By using formats, you can control how your %s are displayed from within the Events Manager <a href='#formats' class='nav-tab-link' rel='#em-menu-formats'>Formatting</a> tab above without having to edit your theme files.",'events-manager');
11
- $page_templates = array(''=>__('Posts'), 'page' => __('Pages'), __('Theme Templates','events-manager') => array_flip(get_page_templates()));
12
- ?>
13
- <div class="postbox" id="em-opt-permalinks" >
14
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__('Permalink Slugs','events-manager')); ?></span></h3>
15
- <div class="inside">
16
- <p class="em-boxheader"><?php _e('You can change the permalink structure of your events, locations, categories and tags here. Be aware that you may want to set up redirects if you change your permalink structures to maintain SEO rankings.','events-manager'); ?></p>
17
- <table class="form-table">
18
- <?php
19
- em_options_input_text ( __( 'Events', 'events-manager'), 'dbem_cp_events_slug', sprintf(__('e.g. %s - you can use / Separators too', 'events-manager'), '<strong>'.home_url().'/<code>'.esc_html(get_option('dbem_cp_events_slug',EM_POST_TYPE_EVENT_SLUG)).'</code>/2012-olympics/</strong>'), EM_POST_TYPE_EVENT_SLUG );
20
- if( get_option('dbem_locations_enabled') && !(EM_MS_GLOBAL && get_site_option('dbem_ms_mainblog_locations') && !is_main_site()) ){
21
- em_options_input_text ( __( 'Locations', 'events-manager'), 'dbem_cp_locations_slug', sprintf(__('e.g. %s - you can use / Separators too', 'events-manager'), '<strong>'.home_url().'/<code>'.esc_html(get_option('dbem_cp_locations_slug',EM_POST_TYPE_LOCATION_SLUG)).'</code>/wembley-stadium/</strong>'), EM_POST_TYPE_LOCATION_SLUG );
22
- }
23
- if( get_option('dbem_categories_enabled') && !(EM_MS_GLOBAL && !is_main_site()) ){
24
- em_options_input_text ( __( 'Event Categories', 'events-manager'), 'dbem_taxonomy_category_slug', sprintf(__('e.g. %s - you can use / Separators too', 'events-manager'), '<strong>'.home_url().'/<code>'.esc_html(get_option('dbem_taxonomy_category_slug',EM_TAXONOMY_CATEGORY_SLUG)).'</code>/sports/</strong>'), EM_TAXONOMY_CATEGORY_SLUG );
25
- }
26
- if( get_option('dbem_tags_enabled') ){
27
- em_options_input_text ( __( 'Event Tags', 'events-manager'), 'dbem_taxonomy_tag_slug', sprintf(__('e.g. %s - you can use / Separators too', 'events-manager'), '<strong>'.home_url().'/<code>'.esc_html(get_option('dbem_taxonomy_tag_slug',EM_TAXONOMY_TAG_SLUG)).'</code>/running/</strong>'), EM_TAXONOMY_TAG_SLUG );
28
- }
29
- echo $save_button;
30
- ?>
31
- </table>
32
- </div> <!-- . inside -->
33
- </div> <!-- .postbox -->
34
-
35
- <div class="postbox " id="em-opt-event-pages" >
36
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__('%s Pages','events-manager'),__('Event','events-manager')); ?></span></h3>
37
- <div class="inside">
38
- <table class="form-table">
39
- <?php
40
- //em_options_radio_binary ( sprintf(__( 'Display %s as', 'events-manager'),__('events','events-manager')), 'dbem_cp_events_template_page', sprintf($template_page_tip, EM_POST_TYPE_EVENT), array(__('Posts'),__('Pages')) );
41
- em_options_select( sprintf(__( 'Display %s as', 'events-manager'),__('events','events-manager')), 'dbem_cp_events_template', $page_templates, sprintf($template_page_tip, __('events','events-manager'), EM_POST_TYPE_EVENT) );
42
- em_options_input_text( __('Body Classes','events-manager'), 'dbem_cp_events_body_class', sprintf($body_class_tip, __('event','events-manager')) );
43
- em_options_input_text( __('Post Classes','events-manager'), 'dbem_cp_events_post_class', $post_class_tip );
44
- em_options_radio_binary ( __( 'Override with Formats?', 'events-manager'), 'dbem_cp_events_formats', sprintf($format_override_tip,__('events','events-manager')));
45
- em_options_radio_binary ( __( 'Enable Comments?', 'events-manager'), 'dbem_cp_events_comments', sprintf(__('If you would like to disable comments entirely, disable this, otherwise you can disable comments on each single %s. Note that %s with comments enabled will still be until you resave them.','events-manager'),__('event','events-manager'),__('events','events-manager')));
46
- echo $save_button;
47
- ?>
48
- </table>
49
- </div> <!-- . inside -->
50
- </div> <!-- .postbox -->
51
-
52
- <div class="postbox " id="em-opt-event-archives" >
53
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__('%s List/Archives','events-manager'),__('Event','events-manager')); ?></span></h3>
54
- <div class="inside">
55
- <table class="form-table">
56
- <tr>
57
- <th><?php echo sprintf(__( 'Events page', 'events-manager')); ?></th>
58
- <td>
59
- <?php wp_dropdown_pages(array('name'=>'dbem_events_page', 'selected'=>get_option('dbem_events_page'), 'show_option_none'=>sprintf(__('[No %s Page]', 'events-manager'),__('Events','events-manager')) )); ?>
60
- <br />
61
- <em><?php echo __( 'This option allows you to select which page to use as an events page. If you do not select an events page, to display event lists you can enable event archives or use the appropriate shortcodes and/or template tags.','events-manager'); ?></em>
62
- </td>
63
- </tr>
64
- <tbody class="em-event-page-options">
65
- <?php
66
- em_options_radio_binary ( __( 'Show events search?', 'events-manager'), 'dbem_events_page_search_form', __( "If set to yes, a search form will appear just above your list of events.", 'events-manager') );
67
- em_options_radio_binary ( __( 'Display calendar in events page?', 'events-manager'), 'dbem_display_calendar_in_events_page', __( 'This options allows to display the full-sized calendar on the events page, instead of the default list.','events-manager') );
68
- em_options_radio_binary ( __( 'Disable title rewriting?', 'events-manager'), 'dbem_disable_title_rewrites', __( "Some WordPress themes don't follow best practices when generating navigation menus, and so the automatic title rewriting feature may cause problems, if your menus aren't working correctly on the event pages, try setting this to 'Yes', and provide an appropriate HTML title format below.",'events-manager') );
69
- em_options_input_text ( __( 'Event Manager titles', 'events-manager'), 'dbem_title_html', __( "This only setting only matters if you selected 'Yes' to above. You will notice the events page titles aren't being rewritten, and you have a new title underneath the default page name. This is where you control the HTML of this title. Make sure you keep the #_PAGETITLE placeholder here, as that's what is rewritten by events manager. To control what's rewritten in this title, see settings further down for page titles.", 'events-manager') );
70
- ?>
71
- </tbody>
72
- <tr class="em-header">
73
- <td colspan="2">
74
- <h4><?php echo sprintf(__('WordPress %s Archives','events-manager'), __('Event','events-manager')); ?></h4>
75
- <p><?php echo sprintf(__('%s custom post types can have archives, just like normal WordPress posts. If enabled, should you visit your base slug url %s and you will see an post-formatted archive of previous %s', 'events-manager'), __('Event','events-manager'), '<code>'.home_url().'/'.esc_html(get_option('dbem_cp_events_slug',EM_POST_TYPE_EVENT_SLUG)).'/</code>', __('events','events-manager')); ?></p>
76
- <p><?php echo sprintf(__('Note that assigning a %s page above will override this archive if the URLs collide (which is the default setting, and is recommended for maximum plugin compatibility). You can have both at the same time, but you must ensure that your page and %s slugs are different.','events-manager'), __('events','events-manager'), __('event','events-manager')); ?></p>
77
- </td>
78
- </tr>
79
- <tbody class="em-event-archive-options">
80
- <?php
81
- em_options_radio_binary ( __( 'Enable Archives?', 'events-manager'), 'dbem_cp_events_has_archive', __( "Allow WordPress post-style archives.", 'events-manager') );
82
- ?>
83
- </tbody>
84
- <tbody class="em-event-archive-options em-event-archive-sub-options">
85
- <tr valign="top">
86
- <th scope="row"><?php _e('Default event archive ordering','events-manager'); ?></th>
87
- <td>
88
- <select name="dbem_events_default_archive_orderby" >
89
- <?php
90
- $event_archive_orderby_options = apply_filters('em_settings_events_default_archive_orderby_ddm', array(
91
- '_event_start' => __('Order by start date, start time','events-manager'),
92
- 'title' => __('Order by name','events-manager')
93
- ));
94
- ?>
95
- <?php foreach($event_archive_orderby_options as $key => $value) : ?>
96
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_events_default_archive_orderby')) ? "selected='selected'" : ''; ?>>
97
- <?php echo esc_html($value); ?>
98
- </option>
99
- <?php endforeach; ?>
100
- </select>
101
- <select name="dbem_events_default_archive_order" >
102
- <?php
103
- $ascending = __('Ascending','events-manager');
104
- $descending = __('Descending','events-manager');
105
- $event_archive_order_options = apply_filters('em_settings_events_default_archive_order_ddm', array(
106
- 'ASC' => __('Ascending','events-manager'),
107
- 'DESC' => __('Descending','events-manager')
108
- ));
109
- ?>
110
- <?php foreach( $event_archive_order_options as $key => $value) : ?>
111
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_events_default_archive_order')) ? "selected='selected'" : ''; ?>>
112
- <?php echo esc_html($value); ?>
113
- </option>
114
- <?php endforeach; ?>
115
- </select>
116
- <br/>
117
- <em><?php _e('When Events Manager displays lists of events the default behavior is ordering by start date in ascending order. To change this, modify the values above.','events-manager'); ?></em>
118
- </td>
119
- </tr>
120
- <?php
121
- em_options_select( __('Event archives scope','events-manager'), 'dbem_events_archive_scope', em_get_scopes() );
122
- ?>
123
- </tbody>
124
- <tr class="em-header">
125
- <td colspan="2">
126
- <h4><?php echo _e('General settings','events-manager'); ?></h4>
127
- </td>
128
- </tr>
129
- <?php
130
- em_options_radio_binary ( __( 'Override with Formats?', 'events-manager'), 'dbem_cp_events_archive_formats', sprintf($format_override_tip,__('events','events-manager')));
131
- em_options_radio_binary ( __( 'Override Excerpts with Formats?', 'events-manager'), 'dbem_cp_events_excerpt_formats', sprintf($format_override_tip,__('events','events-manager')));
132
- em_options_radio_binary ( __( 'Are current events past events?', 'events-manager'), 'dbem_events_current_are_past', __( "By default, events that have an end date later than today will be included in searches, set this to yes to consider events that started 'yesterday' as past.", 'events-manager') );
133
- em_options_radio_binary ( __( 'Include in WordPress Searches?', 'events-manager'), 'dbem_cp_events_search_results', sprintf(__( "Allow %s to appear in the built-in search results.", 'events-manager'),__('events','events-manager')) );
134
- ?>
135
- <tr class="em-header">
136
- <td colspan="2">
137
- <h4><?php echo sprintf(__('Default %s list options','events-manager'), __('event','events-manager')); ?></h4>
138
- <p><?php _e('These can be overridden when using shortcode or template tags.','events-manager'); ?></p>
139
- </td>
140
- </tr>
141
- <tr valign="top" id='dbem_events_default_orderby_row'>
142
- <th scope="row"><?php _e('Default event list ordering','events-manager'); ?></th>
143
- <td>
144
- <select name="dbem_events_default_orderby" >
145
- <?php
146
- $event_list_orderby_options = apply_filters('em_settings_events_default_orderby_ddm', array(
147
- 'event_start_date,event_start_time,event_name' => __('Order by start date, start time, then event name','events-manager'),
148
- 'event_name,event_start_date,event_start_time' => __('Order by name, start date, then start time','events-manager'),
149
- 'event_name,event_end_date,event_end_time' => __('Order by name, end date, then end time','events-manager'),
150
- 'event_end_date,event_end_time,event_name' => __('Order by end date, end time, then event name','events-manager'),
151
- ));
152
- ?>
153
- <?php foreach($event_list_orderby_options as $key => $value) : ?>
154
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_events_default_orderby')) ? "selected='selected'" : ''; ?>>
155
- <?php echo esc_html($value); ?>
156
- </option>
157
- <?php endforeach; ?>
158
- </select>
159
- <select name="dbem_events_default_order" >
160
- <?php
161
- $ascending = __('Ascending','events-manager');
162
- $descending = __('Descending','events-manager');
163
- $event_list_order_options = apply_filters('em_settings_events_default_order_ddm', array(
164
- 'ASC' => __('All Ascending','events-manager'),
165
- 'DESC,ASC,ASC' => __("$descending, $ascending, $ascending",'events-manager'),
166
- 'DESC,DESC,ASC' => __("$descending, $descending, $ascending",'events-manager'),
167
- 'DESC' => __('All Descending','events-manager'),
168
- 'ASC,DESC,ASC' => __("$ascending, $descending, $ascending",'events-manager'),
169
- 'ASC,DESC,DESC' => __("$ascending, $descending, $descending",'events-manager'),
170
- 'ASC,ASC,DESC' => __("$ascending, $ascending, $descending",'events-manager'),
171
- 'DESC,ASC,DESC' => __("$descending, $ascending, $descending",'events-manager'),
172
- ));
173
- ?>
174
- <?php foreach( $event_list_order_options as $key => $value) : ?>
175
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_events_default_order')) ? "selected='selected'" : ''; ?>>
176
- <?php echo esc_html($value); ?>
177
- </option>
178
- <?php endforeach; ?>
179
- </select>
180
- <br/>
181
- <em><?php _e('When Events Manager displays lists of events the default behavior is ordering by start date in ascending order. To change this, modify the values above.','events-manager'); ?></em>
182
- </td>
183
- </tr>
184
- <?php
185
- em_options_select( __('Event list scope','events-manager'), 'dbem_events_page_scope', em_get_scopes(), __('Only show events starting within a certain time limit on the events page. Default is future events with no end time limit.','events-manager') );
186
- em_options_input_text ( __( 'Event List Limits', 'events-manager'), 'dbem_events_default_limit', __( "This will control how many events are shown on one list by default.", 'events-manager') );
187
- echo $save_button;
188
- ?>
189
- </table>
190
- </div> <!-- . inside -->
191
- </div> <!-- .postbox -->
192
-
193
- <?php if( get_option('dbem_locations_enabled') ): ?>
194
- <div class="postbox " id="em-opt-location-pages" >
195
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__('%s Pages','events-manager'),__('Location','events-manager')); ?></span></h3>
196
- <div class="inside">
197
- <table class="form-table">
198
- <?php
199
- //em_options_radio_binary ( sprintf(__( 'Display %s as', 'events-manager'),__('locations','events-manager')), 'dbem_cp_locations_template_page', sprintf($template_page_tip, EM_POST_TYPE_LOCATION), array(__('Posts'),__('Pages')) );
200
- em_options_select( sprintf(__( 'Display %s as', 'events-manager'),__('locations','events-manager')), 'dbem_cp_locations_template', $page_templates, sprintf($template_page_tip, __('locations','events-manager'), EM_POST_TYPE_LOCATION) );
201
- em_options_input_text( __('Body Classes','events-manager'), 'dbem_cp_locations_body_class', sprintf($body_class_tip, __('location','events-manager')) );
202
- em_options_input_text( __('Post Classes','events-manager'), 'dbem_cp_locations_post_class', $post_class_tip );
203
- em_options_radio_binary ( __( 'Override with Formats?', 'events-manager'), 'dbem_cp_locations_formats', sprintf($format_override_tip,__('locations','events-manager')));
204
- em_options_radio_binary ( __( 'Enable Comments?', 'events-manager'), 'dbem_cp_locations_comments', sprintf(__('If you would like to disable comments entirely, disable this, otherwise you can disable comments on each single %s. Note that %s with comments enabled will still be until you resave them.','events-manager'),__('location','events-manager'),__('locations','events-manager')));
205
- ?>
206
- <tr class="em-header">
207
- <td colspan="2">
208
- <h4><?php echo sprintf(esc_html__('Default %s list options','events-manager'), __('event','events-manager')); ?></h4>
209
- <p><?php echo sprintf(esc_html__('The options below are applied to the %s placeholders.', 'events-manager'), '<code>#_LOCATIONNEXTEVENTS</code>, <code>#_LOCATIONPASTEVENTS</code>, <code>#_LOCATIONALLEVENTS</code>'); ?></p>
210
- </td>
211
- </tr>
212
- <tr valign="top" id='dbem_location_events_default_orderby_row'>
213
- <th scope="row"><?php _e('Default event list ordering','events-manager'); ?></th>
214
- <td>
215
- <select name="dbem_location_event_list_orderby" >
216
- <?php foreach($event_list_orderby_options as $key => $value) : ?>
217
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_location_event_list_orderby')) ? "selected='selected'" : ''; ?>>
218
- <?php echo esc_html($value); ?>
219
- </option>
220
- <?php endforeach; ?>
221
- </select>
222
- <select name="dbem_location_event_list_order" >
223
- <?php foreach( $event_list_order_options as $key => $value) : ?>
224
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_location_event_list_order')) ? "selected='selected'" : ''; ?>>
225
- <?php echo esc_html($value); ?>
226
- </option>
227
- <?php endforeach; ?>
228
- </select>
229
- <br/>
230
- <em><?php _e('When Events Manager displays lists of events the default behavior is ordering by start date in ascending order. To change this, modify the values above.','events-manager'); ?></em>
231
- </td>
232
- </tr>
233
- <?php
234
- em_options_input_text ( __( 'Event List Limits', 'events-manager'), 'dbem_location_event_list_limit', sprintf(__( "Controls how many events being held at a location are shown per page when using placeholders such as %s. Leave blank for no limit.", 'events-manager'), '<code>#_LOCATIONNEXTEVENTS</code>') );
235
- echo $save_button;
236
- ?>
237
- </table>
238
- </div> <!-- . inside -->
239
- </div> <!-- .postbox -->
240
-
241
- <div class="postbox " id="em-opt-location-archives" >
242
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__('%s List/Archives','events-manager'),__('Location','events-manager')); ?></span></h3>
243
- <div class="inside">
244
- <table class="form-table">
245
- <tr>
246
- <th><?php echo sprintf(__( '%s page', 'events-manager'),__('Locations','events-manager')); ?></th>
247
- <td>
248
- <?php wp_dropdown_pages(array('name'=>'dbem_locations_page', 'selected'=>get_option('dbem_locations_page'), 'show_option_none'=>sprintf(__('[No %s Page]', 'events-manager'),__('Locations','events-manager')) )); ?>
249
- <br />
250
- <em><?php echo sprintf(__( 'This option allows you to select which page to use as the %s page. If you do not select a %s page, to display lists you can enable archives or use the appropriate shortcodes and/or template tags.','events-manager'),__('locations','events-manager'),__('locations','events-manager')); ?></em>
251
- </td>
252
- </tr>
253
- <?php
254
- em_options_radio_binary ( __( 'Show locations search?', 'events-manager'), 'dbem_locations_page_search_form', __( "If set to yes, a search form will appear just above your list of locations.", 'events-manager') );
255
- ?>
256
- <tr class="em-header">
257
- <td colspan="2">
258
- <h4><?php echo sprintf(__('WordPress %s Archives','events-manager'), __('Location','events-manager')); ?></h4>
259
- <p><?php echo sprintf(__('%s custom post types can have archives, just like normal WordPress posts. If enabled, should you visit your base slug url %s and you will see an post-formatted archive of previous %s', 'events-manager'), __('Location','events-manager'), '<code>'.home_url().'/'.esc_html(get_option('dbem_cp_locations_slug',EM_POST_TYPE_LOCATION_SLUG)).'/</code>', __('locations','events-manager')); ?></p>
260
- <p><?php echo sprintf(__('Note that assigning a %s page above will override this archive if the URLs collide (which is the default settings, and is recommended for maximum plugin compatibility). You can have both at the same time, but you must ensure that your page and %s slugs are different.','events-manager'), __('locations','events-manager'), __('location','events-manager')); ?></p>
261
- </td>
262
- </tr>
263
- <tbody class="em-location-archive-options">
264
- <?php
265
- em_options_radio_binary ( __( 'Enable Archives?', 'events-manager'), 'dbem_cp_locations_has_archive', __( "Allow WordPress post-style archives.", 'events-manager') );
266
- ?>
267
- </tbody>
268
- <tbody class="em-location-archive-options em-location-archive-sub-options">
269
- <tr valign="top">
270
- <th scope="row"><?php _e('Default archive ordering','events-manager'); ?></th>
271
- <td>
272
- <select name="dbem_locations_default_archive_orderby" >
273
- <?php
274
- $locations_list_orderby_options = apply_filters('em_settings_locations_default_archive_orderby_ddm', array(
275
- '_location_country' => sprintf(__('Order by %s','events-manager'),__('Country','events-manager')),
276
- '_location_town' => sprintf(__('Order by %s','events-manager'),__('Town','events-manager')),
277
- 'title' => sprintf(__('Order by %s','events-manager'),__('Name','events-manager'))
278
- ));
279
- ?>
280
- <?php foreach($locations_list_orderby_options as $key => $value) : ?>
281
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_locations_default_archive_orderby')) ? "selected='selected'" : ''; ?>>
282
- <?php echo esc_html($value) ?>
283
- </option>
284
- <?php endforeach; ?>
285
- </select>
286
- <select name="dbem_locations_default_archive_order" >
287
- <?php
288
- $ascending = __('Ascending','events-manager');
289
- $descending = __('Descending','events-manager');
290
- $locations_list_order_options = apply_filters('em_settings_locations_default_archive_order_ddm', array(
291
- 'ASC' => __('Ascending','events-manager'),
292
- 'DESC' => __('Descending','events-manager')
293
- ));
294
- ?>
295
- <?php foreach( $locations_list_order_options as $key => $value) : ?>
296
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_locations_default_archive_order')) ? "selected='selected'" : ''; ?>>
297
- <?php echo esc_html($value) ?>
298
- </option>
299
- <?php endforeach; ?>
300
- </select>
301
- </td>
302
- </tr>
303
- </tbody>
304
- <tr class="em-header">
305
- <td colspan="2">
306
- <h4><?php echo _e('General settings','events-manager'); ?></h4>
307
- </td>
308
- </tr>
309
- <?php
310
- em_options_radio_binary ( __( 'Override with Formats?', 'events-manager'), 'dbem_cp_locations_archive_formats', sprintf($format_override_tip,__('locations','events-manager')));
311
- em_options_radio_binary ( __( 'Override Excerpts with Formats?', 'events-manager'), 'dbem_cp_locations_excerpt_formats', sprintf($format_override_tip,__('locations','events-manager')));
312
- em_options_radio_binary ( __( 'Include in WordPress Searches?', 'events-manager'), 'dbem_cp_locations_search_results', sprintf(__( "Allow %s to appear in the built-in search results.", 'events-manager'),__('locations','events-manager')) );
313
- ?>
314
- <tr class="em-header">
315
- <td colspan="2">
316
- <h4><?php echo sprintf(__('Default %s list options','events-manager'), __('location','events-manager')); ?></h4>
317
- <p><?php _e('These can be overridden when using shortcode or template tags.','events-manager'); ?></p>
318
- </td>
319
- </tr>
320
- <tr valign="top" id='dbem_locations_default_orderby_row'>
321
- <th scope="row"><?php _e('Default list ordering','events-manager'); ?></th>
322
- <td>
323
- <select name="dbem_locations_default_orderby" >
324
- <?php
325
- $locations_list_orderby_options = apply_filters('em_settings_locations_default_orderby_ddm', array(
326
- 'location_country' => sprintf(__('Order by %s','events-manager'),__('Country','events-manager')),
327
- 'location_town' => sprintf(__('Order by %s','events-manager'),__('Town','events-manager')),
328
- 'location_name' => sprintf(__('Order by %s','events-manager'),__('Name','events-manager'))
329
- ));
330
- ?>
331
- <?php foreach($locations_list_orderby_options as $key => $value) : ?>
332
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_locations_default_orderby')) ? "selected='selected'" : ''; ?>>
333
- <?php echo esc_html($value) ?>
334
- </option>
335
- <?php endforeach; ?>
336
- </select>
337
- <select name="dbem_locations_default_order" >
338
- <?php
339
- $ascending = __('Ascending','events-manager');
340
- $descending = __('Descending','events-manager');
341
- $locations_list_order_options = apply_filters('em_settings_locations_default_order_ddm', array(
342
- 'ASC' => __('Ascending','events-manager'),
343
- 'DESC' => __('Descending','events-manager')
344
- ));
345
- ?>
346
- <?php foreach( $locations_list_order_options as $key => $value) : ?>
347
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_locations_default_order')) ? "selected='selected'" : ''; ?>>
348
- <?php echo esc_html($value) ?>
349
- </option>
350
- <?php endforeach; ?>
351
- </select>
352
- </td>
353
- </tr>
354
- <?php
355
- em_options_input_text ( __( 'List Limits', 'events-manager'), 'dbem_locations_default_limit', sprintf(__( "This will control how many %s are shown on one list by default.", 'events-manager'),__('locations','events-manager')) );
356
- echo $save_button;
357
- ?>
358
- </table>
359
- </div> <!-- . inside -->
360
- </div> <!-- .postbox -->
361
- <?php endif; ?>
362
-
363
- <?php if( get_option('dbem_categories_enabled') && !(EM_MS_GLOBAL && !is_main_site()) ): ?>
364
- <div class="postbox " id="em-opt-categories-pages" >
365
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo __('Event Categories','events-manager'); ?></span></h3>
366
- <div class="inside">
367
- <div class="em-boxheader">
368
- <p>
369
- <?php echo sprintf(__('%s are a <a href="%s" target="_blank">WordPress custom taxonomy</a>.','events-manager'), __('Event Categories','events-manager'), 'http://codex.wordpress.org/Taxonomies');?>
370
- <?php echo sprintf(__('%s can be displayed just like normal WordPress custom taxonomies in an archive-style format, however Events Manager by default allows you to completely change the standard look of these archives and use our own <a href="%s">custom formatting</a> methods.','events-manager'), __('Event Categories','events-manager'), EM_ADMIN_URL .'&amp;page=events-manager-help#event-placeholders'); ?>
371
- </p>
372
- <p>
373
- <?php echo sprintf(__('Due to how we change how this custom taxonomy is displayed when overriding with formats it is strongly advised that you assign a %s page below, which increases compatibility with various plugins and themes.','events-manager'), __('categories','events-manager')); ?>
374
- <?php sprintf(__('<a href="%s">See some more information</a> on how %s work when overriding with formats.','events-manager'), '#', __('categories','events-manager')); //not ready yet, but make translatable ?>
375
- </p>
376
- </div>
377
- <table class="form-table">
378
- <tr>
379
- <th><?php echo sprintf(__( '%s page', 'events-manager'),__('Categories','events-manager')); ?></th>
380
- <td>
381
- <?php wp_dropdown_pages(array('name'=>'dbem_categories_page','selected'=>get_option('dbem_categories_page'), 'show_option_none'=>sprintf(__('[No %s Page]', 'events-manager'),__('Categories','events-manager')) )); ?>
382
- <br />
383
- <em><?php echo sprintf(__( 'This option allows you to select which page to use as the %s page.','events-manager'),__('categories','events-manager')); ?></em>
384
- </td>
385
- </tr>
386
- <tr class="em-header">
387
- <td colspan="2">
388
- <h4><?php echo _e('General settings','events-manager'); ?></h4>
389
- <p><?php echo esc_html(sprintf(__('Viewing a general WordPress taxonomy page such as %s will show a list of events just like it would regular posts for a regular category or tag. Below you can edit things such as the order events are displayed, or completely override the archive look with our formats feature.','events-manager'), __('categories', 'events-manager'))); ?></p>
390
- </td>
391
- </tr>
392
- <?php
393
- em_options_radio_binary ( __( 'Override with Formats?', 'events-manager'), 'dbem_cp_categories_formats', sprintf($format_override_tip,__('categories','events-manager'))." ".__('Setting this to yes will make categories display as a page rather than an archive.', 'events-manager'), '', '.em-default-categories-archive-ordering', true);
394
- ?>
395
- <tr valign="top" class="em-default-categories-archive-ordering">
396
- <th scope="row"><?php _e('Default event archive ordering','events-manager'); ?></th>
397
- <td>
398
- <select name="dbem_categories_default_archive_orderby" >
399
- <?php foreach($event_archive_orderby_options as $key => $value) : ?>
400
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_categories_default_archive_orderby')) ? "selected='selected'" : ''; ?>>
401
- <?php echo esc_html($value) ?>
402
- </option>
403
- <?php endforeach; ?>
404
- </select>
405
- <select name="dbem_categories_default_archive_order" >
406
- <?php foreach( $event_archive_order_options as $key => $value) : ?>
407
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_categories_default_archive_order')) ? "selected='selected'" : ''; ?>>
408
- <?php echo esc_html($value) ?>
409
- </option>
410
- <?php endforeach; ?>
411
- </select>
412
- <br /><?php echo esc_html(sprintf(__('When listing event archives for a %s, this order is applied.', 'events-manager'), __('category', 'events-manager'))); ?>
413
- </td>
414
- </tr>
415
- <tr class="em-header">
416
- <td colspan="2">
417
- <h4><?php echo sprintf(__('Default %s list options','events-manager'), __('category','events-manager')); ?></h4>
418
- <p><?php _e('These can be overridden when using shortcode or template tags.','events-manager'); ?></p>
419
- </td>
420
- </tr>
421
- <tr valign="top" id='dbem_categories_default_orderby_row'>
422
- <th scope="row"><?php _e('Default list ordering','events-manager'); ?></th>
423
- <td>
424
- <select name="dbem_categories_default_orderby" >
425
- <?php
426
- $categories_list_orderby_options = apply_filters('em_settings_categories_default_orderby_ddm', array(
427
- 'id' => sprintf(__('Order by %s','events-manager'),__('ID','events-manager')),
428
- 'count' => sprintf(__('Order by %s','events-manager'),__('Count','events-manager')),
429
- 'name' => sprintf(__('Order by %s','events-manager'),__('Name','events-manager')),
430
- 'slug' => sprintf(__('Order by %s','events-manager'),__('Slug','events-manager')),
431
- 'term_group' => sprintf(__('Order by %s','events-manager'),'term_group'),
432
- ));
433
- ?>
434
- <?php foreach($categories_list_orderby_options as $key => $value) : ?>
435
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_categories_default_orderby')) ? "selected='selected'" : ''; ?>>
436
- <?php echo esc_html($value) ?>
437
- </option>
438
- <?php endforeach; ?>
439
- </select>
440
- <select name="dbem_categories_default_order" >
441
- <?php
442
- $ascending = __('Ascending','events-manager');
443
- $descending = __('Descending','events-manager');
444
- $categories_list_order_options = apply_filters('em_settings_categories_default_order_ddm', array(
445
- 'ASC' => __('Ascending','events-manager'),
446
- 'DESC' => __('Descending','events-manager')
447
- ));
448
- ?>
449
- <?php foreach( $categories_list_order_options as $key => $value) : ?>
450
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_categories_default_order')) ? "selected='selected'" : ''; ?>>
451
- <?php echo esc_html($value) ?>
452
- </option>
453
- <?php endforeach; ?>
454
- </select>
455
- <br /><?php echo __('When listing categories, this order is applied.', 'events-manager'); ?>
456
- </td>
457
- </tr>
458
- <?php
459
- em_options_input_text ( __( 'List Limits', 'events-manager'), 'dbem_categories_default_limit', sprintf(__( "This will control how many %s are shown on one list by default.", 'events-manager'),__('categories','events-manager')) );
460
- ?>
461
- <tr class="em-header">
462
- <td colspan="2">
463
- <h4><?php echo sprintf(esc_html__('Default %s list options','events-manager'), __('event','events-manager')); ?></h4>
464
- <p><?php echo sprintf(esc_html__('The options below are applied to the %s placeholders.', 'events-manager'), '<code>#_CATEGORYPASTEVENTS</code>, <code>#_CATEGORYNEXTEVENTS</code>, <code>#_CATEGORYALLEVENTS</code>'); ?></p>
465
- </td>
466
- </tr>
467
- <tr valign="top" id='dbem_category_events_default_orderby_row'>
468
- <th scope="row"><?php _e('Default event list ordering','events-manager'); ?></th>
469
- <td>
470
- <select name="dbem_category_event_list_orderby" >
471
- <?php foreach($event_list_orderby_options as $key => $value) : ?>
472
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_category_event_list_orderby')) ? "selected='selected'" : ''; ?>>
473
- <?php echo esc_html($value); ?>
474
- </option>
475
- <?php endforeach; ?>
476
- </select>
477
- <select name="dbem_category_event_list_order" >
478
- <?php foreach( $event_list_order_options as $key => $value) : ?>
479
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_category_event_list_order')) ? "selected='selected'" : ''; ?>>
480
- <?php echo esc_html($value); ?>
481
- </option>
482
- <?php endforeach; ?>
483
- </select>
484
- <br/>
485
- <em><?php _e('When Events Manager displays lists of events the default behavior is ordering by start date in ascending order. To change this, modify the values above.','events-manager'); ?></em>
486
- </td>
487
- </tr>
488
- <?php
489
- em_options_input_text ( __( 'Event List Limits', 'events-manager'), 'dbem_category_event_list_limit', sprintf(__( "Controls how many events belonging to a category are shown per page when using placeholders such as %s. Leave blank for no limit.", 'events-manager'), '<code>#_CATEGORYNEXTEVENTS</code>') );
490
- echo $save_button;
491
- ?>
492
- </table>
493
- </div> <!-- . inside -->
494
- </div> <!-- .postbox -->
495
- <?php endif; ?>
496
-
497
- <?php if( get_option('dbem_tags_enabled') ): //disabled for now, will add tag stuff later ?>
498
- <div class="postbox " id="em-opt-tags-pages" >
499
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo __('Event Tags','events-manager'); ?></span></h3>
500
- <div class="inside">
501
- <div class="em-boxheader">
502
- <p>
503
- <?php echo sprintf(__('%s are a <a href="%s" target="_blank">WordPress custom taxonomy</a>.','events-manager'), __('Event Tags','events-manager'), 'http://codex.wordpress.org/Taxonomies');?>
504
- <?php echo sprintf(__('%s can be displayed just like normal WordPress custom taxonomies in an archive-style format, however Events Manager by default allows you to completely change the standard look of these archives and use our own <a href="%s">custom formatting</a> methods.','events-manager'), __('Event Tags','events-manager'), EM_ADMIN_URL .'&amp;page=events-manager-help#event-placeholders'); ?>
505
- </p>
506
- <p>
507
- <?php echo sprintf(__('Due to how we change how this custom taxonomy is displayed when overriding with formats it is strongly advised that you assign a %s page below, which increases compatibility with various plugins and themes.','events-manager'), __('tags','events-manager')); ?>
508
- <?php sprintf(__('<a href="%s">See some more information</a> on how %s work when overriding with formats.','events-manager'), '#', __('tags','events-manager')); //not ready yet, but make translatable ?>
509
- </p>
510
- </div>
511
- <table class="form-table">
512
- <tr>
513
- <th><?php echo sprintf(__( '%s page', 'events-manager'),__('Tags','events-manager')); ?></th>
514
- <td>
515
- <?php wp_dropdown_pages(array('name'=>'dbem_tags_page','selected'=>get_option('dbem_tags_page'), 'show_option_none'=>sprintf(__('[No %s Page]', 'events-manager'),__('Tags','events-manager')) )); ?>
516
- <br />
517
- <em><?php echo sprintf(__( 'This option allows you to select which page to use as the %s page.','events-manager'),__('tags','events-manager'),__('tags','events-manager')); ?></em>
518
- </td>
519
- </tr>
520
- <tr class="em-header">
521
- <td colspan="2">
522
- <h4><?php echo _e('General settings','events-manager'); ?></h4>
523
- <p><?php echo esc_html(sprintf(__('Viewing a general WordPress taxonomy page such as %s will show a list of events just like it would regular posts for a regular category or tag. Below you can edit things such as the order events are displayed, or completely override the archive look with our formats feature.','events-manager'), __('tags', 'events-manager'))); ?></p>
524
- </td>
525
- </tr>
526
- <?php
527
- em_options_radio_binary ( __( 'Override with Formats?', 'events-manager'), 'dbem_cp_tags_formats', sprintf($format_override_tip,__('tags','events-manager')), '', '.em-default-tags-archive-ordering', true);
528
- ?>
529
- <tr valign="top" class="em-default-tags-archive-ordering">
530
- <th scope="row"><?php _e('Default event archive ordering','events-manager'); ?></th>
531
- <td>
532
- <select name="dbem_tags_default_archive_orderby" >
533
- <?php foreach($event_archive_orderby_options as $key => $value) : ?>
534
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_tags_default_archive_orderby')) ? "selected='selected'" : ''; ?>>
535
- <?php echo esc_html($value) ?>
536
- </option>
537
- <?php endforeach; ?>
538
- </select>
539
- <select name="dbem_tags_default_archive_order" >
540
- <?php foreach( $event_archive_order_options as $key => $value) : ?>
541
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_tags_default_archive_order')) ? "selected='selected'" : ''; ?>>
542
- <?php echo esc_html($value) ?>
543
- </option>
544
- <?php endforeach; ?>
545
- </select>
546
- <br /><?php echo esc_html(sprintf(__('When listing event archives for a %s, this order is applied.', 'events-manager'), __('tag', 'events-manager'))); ?>
547
- </td>
548
- </tr>
549
- <tr class="em-header">
550
- <td colspan="2">
551
- <h4><?php echo sprintf(__('Default %s list options','events-manager'), __('tag','events-manager')); ?></h4>
552
- <p><?php _e('These can be overridden when using shortcode or template tags.','events-manager'); ?></p>
553
- </td>
554
- </tr>
555
- <tr valign="top" id='dbem_tags_default_orderby_row'>
556
- <th scope="row"><?php _e('Default list ordering','events-manager'); ?></th>
557
- <td>
558
- <select name="dbem_tags_default_orderby" >
559
- <?php
560
- $tags_list_orderby_options = apply_filters('em_settings_tags_default_orderby_ddm', array(
561
- 'id' => sprintf(__('Order by %s','events-manager'),__('ID','events-manager')),
562
- 'count' => sprintf(__('Order by %s','events-manager'),__('Count','events-manager')),
563
- 'name' => sprintf(__('Order by %s','events-manager'),__('Name','events-manager')),
564
- 'slug' => sprintf(__('Order by %s','events-manager'),__('Slug','events-manager')),
565
- 'term_group' => sprintf(__('Order by %s','events-manager'),'term_group'),
566
- ));
567
- ?>
568
- <?php foreach($tags_list_orderby_options as $key => $value) : ?>
569
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_tags_default_orderby')) ? "selected='selected'" : ''; ?>>
570
- <?php echo esc_html($value) ?>
571
- </option>
572
- <?php endforeach; ?>
573
- </select>
574
- <select name="dbem_tags_default_order" >
575
- <?php
576
- $ascending = __('Ascending','events-manager');
577
- $descending = __('Descending','events-manager');
578
- $tags_list_order_options = apply_filters('em_settings_tags_default_order_ddm', array(
579
- 'ASC' => __('Ascending','events-manager'),
580
- 'DESC' => __('Descending','events-manager')
581
- ));
582
- ?>
583
- <?php foreach( $tags_list_order_options as $key => $value) : ?>
584
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_tags_default_order')) ? "selected='selected'" : ''; ?>>
585
- <?php echo esc_html($value) ?>
586
- </option>
587
- <?php endforeach; ?>
588
- </select>
589
- <br /><?php echo __('When listing tags, this order is applied.', 'events-manager'); ?>
590
- </td>
591
- </tr>
592
- <?php
593
- em_options_input_text ( __( 'List Limits', 'events-manager'), 'dbem_tags_default_limit', sprintf(__( "This will control how many %s are shown on one list by default.", 'events-manager'),__('tags','events-manager')) );
594
- ?>
595
- <tr class="em-header">
596
- <td colspan="2">
597
- <h4><?php echo sprintf(esc_html__('Default %s list options','events-manager'), __('event','events-manager')); ?></h4>
598
- <p><?php echo sprintf(esc_html__('The options below are applied to the %s placeholders.', 'events-manager'), '<code>#_TAGPASTEVENTS</code>, <code>#_TAGNEXTEVENTS</code>, <code>#_TAGALLEVENTS</code>'); ?></p>
599
- </td>
600
- </tr>
601
- <tr valign="top" id='dbem_tag_events_default_orderby_row'>
602
- <th scope="row"><?php _e('Default event list ordering','events-manager'); ?></th>
603
- <td>
604
- <select name="dbem_tag_event_list_orderby" >
605
- <?php foreach($event_list_orderby_options as $key => $value) : ?>
606
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_tag_event_list_orderby')) ? "selected='selected'" : ''; ?>>
607
- <?php echo esc_html($value); ?>
608
- </option>
609
- <?php endforeach; ?>
610
- </select>
611
- <select name="dbem_tag_event_list_order" >
612
- <?php foreach( $event_list_order_options as $key => $value) : ?>
613
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_tag_event_list_order')) ? "selected='selected'" : ''; ?>>
614
- <?php echo esc_html($value); ?>
615
- </option>
616
- <?php endforeach; ?>
617
- </select>
618
- <br/>
619
- <em><?php _e('When Events Manager displays lists of events the default behavior is ordering by start date in ascending order. To change this, modify the values above.','events-manager'); ?></em>
620
- </td>
621
- </tr>
622
- <?php
623
- em_options_input_text ( __( 'Event List Limits', 'events-manager'), 'dbem_tag_event_list_limit', sprintf(__( "Controls how many events belonging to a tag are shown per page when using placeholders such as %s. Leave blank for no limit.", 'events-manager'), '<code>#_TAGNEXTEVENTS</code>') );
624
- echo $save_button; ?>
625
- </table>
626
- </div> <!-- . inside -->
627
- </div> <!-- .postbox -->
628
- <?php endif; ?>
629
-
630
- <div class="postbox " id="em-opt-other-pages" >
631
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__('%s Pages','events-manager'),__('Other','events-manager')); ?></span></h3>
632
- <div class="inside">
633
- <p class="em-boxheader"><?php _e('These pages allow you to provide an event management interface outside the admin area on whatever page you want on your website. Bear in mind that this is overridden by BuddyPress if activated.', 'events-manager'); ?></p>
634
- <table class="form-table">
635
- <?php
636
- $other_pages_tip = 'Using the %s shortcode, you can allow users to manage %s outside the admin area.';
637
- ?>
638
- <tr class="em-header">
639
- <td colspan="2">
640
- <h4><?php _e('My Bookings','events-manager'); ?></h4>
641
- <p><?php _e('This page is where people that have made bookings for an event can go and view their previous bookings.','events-manager'); ?>
642
- </td>
643
- </tr>
644
- <tr>
645
- <th><?php echo sprintf(__( '%s page', 'events-manager'),__('My bookings','events-manager')); ?>
646
- </th>
647
- <td>
648
- <?php wp_dropdown_pages(array('name'=>'dbem_my_bookings_page', 'selected'=>get_option('dbem_my_bookings_page'), 'show_option_none'=>'['.__('None', 'events-manager').']' )); ?>
649
- <br />
650
- <em><?php echo sprintf(__('Users can view their bookings for other events on this page.','events-manager'),'<code>[my_bookings]</code>',__('bookings','events-manager')); ?></em>
651
- </td>
652
- </tr>
653
- <tr valign="top" id='dbem_bookings_default_orderby_row'>
654
- <th scope="row"><?php _e('Default list ordering','events-manager'); ?></th>
655
- <td>
656
- <select name="dbem_bookings_default_orderby" >
657
- <?php
658
- $orderby_options = apply_filters('em_settings_bookings_default_orderby_ddm', array(
659
- 'event_name' => sprintf(__('Order by %s','events-manager'),__('Event Name','events-manager')),
660
- 'event_start_date' => sprintf(__('Order by %s','events-manager'),__('Start Date','events-manager')),
661
- 'booking_date' => sprintf(__('Order by %s','events-manager'),__('Booking Date','events-manager'))
662
- ));
663
- ?>
664
- <?php foreach($orderby_options as $key => $value) : ?>
665
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_bookings_default_orderby')) ? "selected='selected'" : ''; ?>>
666
- <?php echo esc_html($value) ?>
667
- </option>
668
- <?php endforeach; ?>
669
- </select>
670
- <select name="dbem_bookings_default_order" >
671
- <?php
672
- $ascending = __('Ascending','events-manager');
673
- $descending = __('Descending','events-manager');
674
- $order_options = apply_filters('em_settings_bookings_default_order_ddm', array(
675
- 'ASC' => __('Ascending','events-manager'),
676
- 'DESC' => __('Descending','events-manager')
677
- ));
678
- ?>
679
- <?php foreach( $order_options as $key => $value) : ?>
680
- <option value='<?php echo esc_attr($key) ?>' <?php echo ($key == get_option('dbem_bookings_default_order')) ? "selected='selected'" : ''; ?>>
681
- <?php echo esc_html($value) ?>
682
- </option>
683
- <?php endforeach; ?>
684
- </select>
685
- </td>
686
- </tr>
687
- <tr class="em-header">
688
- <td colspan="2">
689
- <h4><?php _e('Front-end management pages','events-manager'); ?></h4>
690
- <p><?php _e('Users with the relevant permissions can manage their own events and bookings to these events on the following pages.','events-manager'); ?></p>
691
- </td>
692
- </tr>
693
- <tr>
694
- <th><?php echo sprintf(__( '%s page', 'events-manager'),__('Edit events','events-manager')); ?></th>
695
- <td>
696
- <?php wp_dropdown_pages(array('name'=>'dbem_edit_events_page', 'selected'=>get_option('dbem_edit_events_page'), 'show_option_none'=>'['.__('None', 'events-manager').']' )); ?>
697
- <br />
698
- <em><?php echo sprintf(__('Users can view, add and edit their %s on this page.','events-manager'),__('events','events-manager')); ?></em>
699
- </td>
700
- </tr>
701
- <tr>
702
- <th><?php echo sprintf(__( '%s page', 'events-manager'),__('Edit locations','events-manager')); ?></th>
703
- <td>
704
- <?php wp_dropdown_pages(array('name'=>'dbem_edit_locations_page', 'selected'=>get_option('dbem_edit_locations_page'), 'show_option_none'=>'['.__('None', 'events-manager').']' )); ?>
705
- <br />
706
- <em><?php echo sprintf(__('Users can view, add and edit their %s on this page.','events-manager'),__('locations','events-manager')); ?></em>
707
- </td>
708
- </tr>
709
- <tr>
710
- <th><?php echo sprintf(__( '%s page', 'events-manager'),__('Manage bookings','events-manager')); ?></th>
711
- <td>
712
- <?php wp_dropdown_pages(array('name'=>'dbem_edit_bookings_page', 'selected'=>get_option('dbem_edit_bookings_page'), 'show_option_none'=>'['.__('None', 'events-manager').']' )); ?>
713
- <br />
714
- <em><?php _e('Users can manage bookings for their events on this page.','events-manager'); ?></em>
715
- </td>
716
- </tr>
717
- <?php echo $save_button; ?>
718
- </table>
719
- </div> <!-- . inside -->
720
- </div> <!-- .postbox -->
721
-
722
- <?php do_action('em_options_page_footer_pages'); ?>
723
-
724
- </div> <!-- .em-menu-pages -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/settings/updates/timezone-backcompat.php DELETED
@@ -1,112 +0,0 @@
1
- <?php
2
- //This file will handle upgradeing from EM < 5.9 for timezones, removing the unecessary postmeta fields.
3
- function em_admin_update_timezone_backcompat_site( $site_id = false ){
4
- global $wpdb;
5
- if( is_multisite() && $site_id != false ){ switch_to_blog($site_id); }
6
- $sql = $wpdb->prepare('DELETE FROM '.$wpdb->postmeta.' WHERE meta_key=%s OR meta_key=%s', array('_start_ts', '_end_ts'));
7
- $result = $wpdb->query($sql);
8
- if( $result !== false && !is_multisite() ){
9
- EM_Options::remove('updates', 'timezone-backcompat');
10
- EM_Admin_Notices::remove('date_time_migration');
11
- }
12
- if( is_multisite() && $site_id != false ){ restore_current_blog(); }
13
- return $result !== false;
14
- }
15
-
16
- function em_admin_update_timezone_backcompat(){
17
- if( !empty($_REQUEST['confirmed']) && check_admin_referer('em_timezone_backcompat_confirmed') && em_wp_is_super_admin() ){
18
- global $wpdb, $EM_Notices;
19
- if( em_admin_update_timezone_backcompat_site() ){
20
- $EM_Notices->add_confirm(__('You have successfully finalized upgrading your site.', 'events-manager'), true);
21
- $redirect = esc_url_raw( remove_query_arg(array('action','update','confirmed','_wpnonce')) );
22
- wp_safe_redirect($redirect);
23
- exit();
24
- }else{
25
- $EM_Notices->add_error(__('There was an error upgrading your site, please try again or contact support.', 'events-manager'), true);
26
- $redirect = esc_url_raw( remove_query_arg(array('confirmed','_wpnonce')) );
27
- wp_safe_redirect($redirect);
28
- exit();
29
- }
30
- }
31
- }
32
- add_action('em_admin_update_timezone-backcompat', 'em_admin_update_timezone_backcompat');
33
-
34
- function em_admin_update_settings_timezone_backcompat(){
35
- if( is_multisite() ) return;
36
- ?>
37
- <div>
38
- <h4 style="color:#ca4a1f;"><?php esc_html_e ( 'Finalize Timezones Upgrade', 'events-manager'); ?></h4>
39
- <p><?php esc_html_e('Events Manager 5.9 introduced timezone functionality, which does not require certain fields in your database. To maintain backwards compatibility with earlier versions, these fields will still be created.','events-manager'); ?></p>
40
- <p><?php esc_html_e('This is not a required step to enable any extra functionality, and therefore is not urgent. Only until you are happy with the upgrade and are confident you don\'t need to downgrade, finalize your upgrade by deleting and discontinuing these fields.','events-manager'); ?></p>
41
- <p><a href="<?php echo esc_url(EM_ADMIN_URL.'&page=events-manager-options&amp;action=update&update_action=timezone-backcompat'); ?>" class="button-secondary"><?php esc_html_e ( 'Finalize Timezones Upgrade', 'events-manager'); ?></a>
42
- </div>
43
- <?php
44
- }
45
- add_action('em_admin_update_settings_timezone-backcompat', 'em_admin_update_settings_timezone_backcompat');
46
-
47
- function em_admin_update_settings_confirm_timezone_backcompat(){
48
- ?>
49
- <div class="wrap">
50
- <h1><?php esc_html_e ( 'Finalize Timezones Upgrade', 'events-manager'); ?></h1>
51
- <p><?php esc_html_e('Events Manager 5.9 introduced timezone functionality, which does not require certain fields in your database. To maintain backwards compatibility with earlier versions, these fields will still be created.','events-manager'); ?></p>
52
- <p><?php esc_html_e('This is not a required step to enable any extra functionality, and therefore is not urgent. Only until you are happy with the upgrade and are confident you don\'t need to downgrade, finalize your upgrade by deleting and discontinuing these fields.','events-manager'); ?></p>
53
- <p style="font-weight:bold;"><?php esc_html_e('We recommend you back up your database! Once the upgrade is finalized, you cannot downgrade to an earlier version of the plugin. This cannot be undone.','events-manager')?></p>
54
- <p>
55
- <a href="<?php echo esc_url(add_query_arg(array('_wpnonce' => wp_create_nonce('em_timezone_backcompat_confirmed'), 'confirmed'=>1))); ?>" class="button-primary"><?php _e('Finalize Timezones Upgrade','events-manager'); ?></a>
56
- <a href="<?php echo esc_url(em_wp_get_referer()); ?>" class="button-secondary"><?php _e('Cancel','events-manager'); ?></a>
57
- </p>
58
- </div>
59
- <?php
60
- }
61
- add_action('em_admin_update_settings_confirm_timezone-backcompat', 'em_admin_update_settings_confirm_timezone_backcompat');
62
-
63
- function em_admin_update_ms_settings_timezone_backcompat(){
64
- ?>
65
- <div>
66
- <br><hr>
67
- <h2 style="color:#ca4a1f;"><?php esc_html_e( 'Finalize Timezones Upgrade', 'events-manager'); ?></h2>
68
- <p><?php esc_html_e('Events Manager 5.9 introduced timezone functionality, which does not require certain fields in your database. To maintain backwards compatibility with earlier versions, these fields will still be created.','events-manager'); ?></p>
69
- <p><?php esc_html_e('This is not a required step to enable any extra functionality, and therefore is not urgent. Only until you are happy with the upgrade and are confident you don\'t need to downgrade, finalize your upgrade by deleting and discontinuing these fields.','events-manager'); ?></p>
70
- <p style="font-weight:bold;"><?php esc_html_e('We recommend you back up your database! Once the upgrade is finalized, you cannot downgrade to an earlier version of the plugin. This cannot be undone.','events-manager')?></p>
71
- <p>
72
- <a href="<?php echo esc_url(add_query_arg(array('action'=>'timezone-backcompat', '_wpnonce' => wp_create_nonce('em_ms_finalize_timezone_upgrade')))); ?>" class="button-primary">
73
- <?php esc_html_e ( 'Finalize Timezones Upgrade', 'events-manager'); ?>
74
- </a>
75
- </p>
76
- </div>
77
- <?php
78
- }
79
- add_action('em_admin_update_ms_settings_timezone-backcompat', 'em_admin_update_ms_settings_timezone_backcompat');
80
-
81
- function em_admin_update_ms_timezone_backcompat(){
82
- if( check_admin_referer('em_ms_finalize_timezone_upgrade') && em_wp_is_super_admin() ){
83
- global $current_site,$wpdb;
84
- $blog_ids = $wpdb->get_col('SELECT blog_id FROM '.$wpdb->blogs.' WHERE site_id='.$current_site->id);
85
- $result = true;
86
- echo '<h2 style="color:#ca4a1f;">'. esc_html__( 'Finalize Timezones Upgrade', 'events-manager') .'</h2>';
87
- echo '<ul>';
88
- $plugin_basename = plugin_basename(EM_DIR.'/events-manager.php');
89
- $network_active = is_plugin_active_for_network($plugin_basename);
90
- foreach($blog_ids as $blog_id){
91
- if( $network_active || is_plugin_active($plugin_basename.'/events-manager.php') ){
92
- if( em_admin_update_timezone_backcompat_site($blog_id) ){
93
- echo "<li>".sprintf(_x('Updated %s.', 'Multisite Blog Update','events-manager'), get_blog_option($blog_id, 'blogname'))."</li>";
94
- }else{
95
- echo "<li>".sprintf(_x('Failed to update %s.', 'Multisite Blog Update','events-manager'), get_blog_option($blog_id, 'blogname'))."</li>";
96
- $result = false;
97
- }
98
- }else{
99
- echo "<li>".sprintf(_x('%s does not have Events Manager activated.', 'Multisite Blog Update','events-manager'), get_blog_option($blog_id, 'blogname'))."</li>";
100
- }
101
- }
102
- echo '</ul>';
103
- if( $result ){
104
- EM_Admin_Notices::remove('date_time_migration', true);
105
- EM_Options::site_remove('updates', 'timezone-backcompat');
106
- echo "<p>".esc_html__('Update process has finished.', 'events-manager')."</p>";
107
- }else{
108
- echo "<p>".esc_html__('An error has occurred, not all sites were upgraded successfully.', 'events-manager')."</p>";
109
- }
110
- }
111
- }
112
- add_action('em_admin_update_ms_timezone-backcompat', 'em_admin_update_ms_timezone_backcompat');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/admin/settings/wpfc-admin.php DELETED
@@ -1,48 +0,0 @@
1
- <?php
2
- /**
3
- * Adds a note to the event post type in the admin area, so it's obvious EM is interfering.
4
- */
5
- function wpfc_admin_options_post_type_event(){
6
- echo " - <i>powered by Events Manager</i>";
7
- }
8
- add_action('wpfc_admin_options_post_type_event','wpfc_admin_options_post_type_event');
9
-
10
- function wpfc_em_admin_notice(){
11
- if( !empty($_REQUEST['page']) && $_REQUEST['page'] == 'wp-fullcalendar'){
12
- ?>
13
- <div class="updated"><p><?php echo sprintf(__('If you choose the Event post type whilst Events Manager is activated, you can also visit the <a href="%s">Events Manager settings page</a> for a few more options when displaying event information on your calendar.','events-manager'), admin_url('edit.php?post_type='.EM_POST_TYPE_EVENT.'&page=events-manager-options')); ?></p></div>
14
- <?php
15
- }
16
- }
17
- add_action('admin_notices', 'wpfc_em_admin_notice');
18
-
19
- function wpfc_em_admin_options(){
20
- ?>
21
- <div class="postbox " >
22
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3 class='hndle'><span><?php _e ( 'Full Calendar Options', 'events-manager'); ?> </span></h3>
23
- <div class="inside">
24
- <p class="em-boxheader"><?php echo sprintf(__('Looking for the rest of the FullCalendar Options? They\'ve moved <a href="%s">here</a>, the options below are for overriding specific bits relevant to Events Manager.','events-manager'), admin_url('options-general.php?page=wp-fullcalendar')); ?></p>
25
- <table class='form-table'>
26
- <?php
27
- global $events_placeholder_tip, $save_button;
28
- em_options_radio_binary ( __( 'Override calendar on events page?', 'events-manager'), 'dbem_emfc_override_calendar', __( 'If set to yes, the FullCalendar will be used instead of the standard calendar on the events page.', 'events-manager') );
29
- em_options_radio_binary ( __( 'Override calendar shortcode?', 'events-manager'), 'dbem_emfc_override_shortcode', __( 'Overrides the default calendar shortcode. You can also use [events_fullcalendar] instead.','events-manager') );
30
- em_options_input_text ( __( 'Event title format', 'events-manager'), 'dbem_emfc_full_calendar_event_format', __('HTML is not accepted.','events-manager').' '.$events_placeholder_tip, '#_EVENTNAME' );
31
- em_options_textarea( __( 'Event tooltips format', 'events-manager'), 'dbem_emfc_qtips_format', __('If you enable tips, this information will be shown, which can include HTML.','events-manager').' '.$events_placeholder_tip, '#_EVENTNAME' );$positions_options = array();
32
- ?>
33
- </table>
34
- <?php echo $save_button; ?>
35
- </div> <!-- . inside -->
36
- </div> <!-- .postbox -->
37
- <?php
38
- }
39
- add_action('em_options_page_footer', 'wpfc_em_admin_options');
40
-
41
- function wpfc_em_install(){
42
- //check for updates - try adding one option, if it works then it's a first time install so add more
43
- if( current_user_can('manage_options') && get_option('dbem_emfc_full_calendar_event_format', false) ){
44
- add_option('dbem_emfc_full_calendar_event_format','#_EVENTTIMES - #_EVENTNAME');
45
- add_option('dbem_emfc_qtips_format', '{has_image}<div style="float:left; margin:0px 5px 5px 0px;">#_EVENTIMAGE{75,75}</div>{/has_image}#_EVENTEXCERPT');
46
- }
47
- }
48
- add_action('init', 'wpfc_em_install');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/bp-em-activity.php DELETED
@@ -1,221 +0,0 @@
1
- <?php
2
- // This file handles hooks/filter requiring activity stream publications
3
-
4
- /**
5
- * bp_em_record_activity()
6
- *
7
- * If the activity stream component is installed, this function will record activity items for your
8
- * component.
9
- */
10
- function bp_em_record_activity( $args = '' ) {
11
- if ( !function_exists( 'bp_activity_add' ) )
12
- return false;
13
-
14
- $defaults = array(
15
- 'id' => false,
16
- 'user_id' => '',
17
- 'action' => '',
18
- 'content' => '',
19
- 'primary_link' => '',
20
- 'component' => 'events-manager',
21
- 'type' => false,
22
- 'item_id' => false,
23
- 'secondary_item_id' => false,
24
- 'recorded_time' => gmdate( "Y-m-d H:i:s" ),
25
- 'hide_sitewide' => false
26
- );
27
-
28
- $r = wp_parse_args( $args, $defaults );
29
- extract( $r );
30
- return bp_activity_add( array( 'id' => $id, 'user_id' => $user_id, 'action' => $action, 'content' => $content, 'primary_link' => $primary_link, 'component' => $component, 'type' => $type, 'item_id' => $item_id, 'secondary_item_id' => $secondary_item_id, 'recorded_time' => $recorded_time, 'hide_sitewide' => $hide_sitewide ) );
31
- }
32
-
33
- function em_bp_register_activity_actions() {
34
-
35
- if ( !bp_is_active( 'events' ) ) {
36
- return false;
37
- }
38
-
39
- $bp = buddypress();
40
-
41
- // @todo - Figure out why adding a second bp_activity_set_action creates two 'Bookings' actions in backend and different booking status front-end e.g. when friendships created/accepted do not
42
- bp_activity_set_action(
43
- $bp->events->id,
44
- 'new_booking',
45
- __( 'Bookings', 'events-manager'),
46
- 'em_bp_events_format_activity_action_bookings',
47
- __( 'Bookings', 'events-manager'),
48
- array( 'activity', 'member' )
49
- );
50
- /*
51
- bp_activity_set_action(
52
- $bp->events->id,
53
- 'booking_cancelled',
54
- __( 'Booking Cancelled', 'events-manager'),
55
- 'em_bp_events_format_activity_action_bookings',
56
- __( 'Bookings', 'events-manager'),
57
- array( 'activity', 'member' )
58
- );
59
- */
60
-
61
- bp_activity_set_action(
62
- $bp->events->id,
63
- 'new_event',
64
- __('New Event','events-manager'),
65
- 'em_bp_events_format_activity_action_events',
66
- __( 'Events', 'events-manager'),
67
- array( 'activity', 'member' )
68
- );
69
- }
70
- add_action( 'bp_register_activity_actions', 'em_bp_register_activity_actions' );
71
-
72
- /**
73
- * Not yet used fully - formats booking-related actions
74
- * @param string $action
75
- * @param object $activity
76
- * @return string
77
- */
78
- function em_bp_events_format_activity_action_bookings( $action, $activity ) {
79
- return '';
80
- $member_link = bp_core_get_userlink( $activity->user_id );
81
- $EM_Booking = em_get_booking( $activity->item );
82
-
83
- $action = '';
84
- switch ($activity->type){
85
- case 'new_booking':
86
- if( $activity->component == 'groups' ){
87
- $action = sprintf(__('%s is attending %s of the group %s.','events-manager'), $member_link, $event_link, $group_link );
88
- }else{
89
- $action = sprintf(__('%s is attending %s.','events-manager'), $member_link, $event_link );
90
- }
91
- break;
92
- case 'cancelled_booking':
93
- if( $activity->component == 'groups' ){
94
- $action = sprintf(__('%s will not be attending %s of group %s anymore.','events-manager'), $user_link, $event_link, $group_link );
95
- }else{
96
- $action = sprintf(__('%s will not be attending %s anymore.','events-manager'), $user_link, $event_link );
97
- }
98
- break;
99
- }
100
-
101
- return apply_filters( 'bp_events_format_activity_action_bookings', $action, $activity );
102
- }
103
-
104
- /**
105
- * Not yet used fully - formats event-related actions
106
- * @param string $action
107
- * @param object $activity
108
- * @return string
109
- */
110
- function em_bp_events_format_activity_action_events( $action, $activity ) {
111
- return '';
112
- $member_link = bp_core_get_userlink( $activity->user_id );
113
- $EM_Event = em_get_event( $activity->item_id );
114
-
115
- $action = sprintf(__('%s added the event %s','events-manager'), $member_link, $EM_Event->output('#_EVENTLINK') );
116
-
117
- return apply_filters( 'bp_events_format_activity_action_events', $action, $activity );
118
- }
119
-
120
- /**
121
- * Records new events to the activity stream.
122
- * @param unknown_type $result
123
- * @param unknown_type $EM_Event
124
- * @return unknown
125
- */
126
- function bp_em_record_activity_event_save( $result, $EM_Event ){
127
- if( $result && $EM_Event->event_status == 1 && $EM_Event->get_previous_status() != 1 ){
128
- $user = get_userdata($EM_Event->event_owner);
129
- $member_link = bp_core_get_user_domain($user->ID);
130
- if( empty($EM_Event->group_id) ){
131
- bp_em_record_activity( array(
132
- 'user_id' => $user->ID,
133
- 'action' => sprintf(__('%s added the event %s','events-manager'), "<a href='".$member_link."'>".$user->display_name."</a>", $EM_Event->output('#_EVENTLINK') ),
134
- 'primary_link' => $EM_Event->output('#_EVENTURL'),
135
- 'type' => 'new_event',
136
- 'item_id' => $EM_Event->event_id,
137
- 'hide_sitewide' => $EM_Event->event_private
138
- ));
139
- }else{
140
- //tis a group event
141
- $group = new BP_Groups_Group($EM_Event->group_id);
142
- bp_em_record_activity( array(
143
- 'user_id' => $user->ID,
144
- 'action' => sprintf(__('%s added the event %s to %s.','events-manager'), "<a href='".$member_link."'>".$user->display_name."</a>", $EM_Event->output('#_EVENTLINK'), '<a href="'.bp_get_group_permalink($group).'">'.bp_get_group_name($group).'</a>' ),
145
- 'component' => 'groups',
146
- 'type' => 'new_event',
147
- 'item_id' => $EM_Event->group_id,
148
- 'hide_sitewide' => $EM_Event->event_private
149
- ));
150
- }
151
- }
152
- return $result;
153
- }
154
- add_filter('em_event_save','bp_em_record_activity_event_save', 10, 2);
155
-
156
- /**
157
- * @param boolean $result
158
- * @param EM_Booking $EM_Booking
159
- * @return boolean
160
- */
161
- function bp_em_record_activity_booking_save( $result, $EM_Booking ){
162
- /* @todo this isn't good at detecting status changes. */
163
- if( !empty($EM_Booking->event_id) && $result ){
164
- $action_type = 'new_booking';
165
- if( !empty($EM_Booking->last_bp_activity) && $EM_Booking->last_bp_activity == $action_type ) return $result; //prevent duplicates
166
- $EM_Booking->last_bp_activity = $action_type;
167
- $rejected_statuses = array(0,2,3); //these statuses apply to rejected/cancelled bookings
168
- $user = $EM_Booking->get_person();
169
- $member_link = bp_core_get_user_domain($user->ID);
170
- $user_link = "<a href='".$member_link."/'>".$user->display_name."</a>";
171
- $event_link = $EM_Booking->get_event()->output('#_EVENTLINK');
172
- $status = $EM_Booking->booking_status;
173
- $EM_Event = $EM_Booking->get_event();
174
- if( empty($EM_Event->group_id) ){
175
- if( $status == 1 || (!get_option('dbem_bookings_approval') && $status < 2) ){
176
- $action = sprintf(__('%s is attending %s.','events-manager'), $user_link, $event_link );
177
- }elseif( ($EM_Booking->previous_status == 1 || (!get_option('dbem_bookings_approval') && $EM_Booking->previous_status < 2)) && in_array($status, $rejected_statuses) ){
178
- $action = sprintf(__('%s will not be attending %s anymore.','events-manager'), $user_link, $event_link );
179
- //$action_type = 'cancelled_booking';
180
- }
181
- }else{
182
- $group = new BP_Groups_Group($EM_Event->group_id);
183
- $group_link = '<a href="'.bp_get_group_permalink($group).'">'.bp_get_group_name($group).'</a>';
184
- if( $status == 1 || (!get_option('dbem_bookings_approval') && $status < 2) ){
185
- $action = sprintf(__('%s is attending %s of the group %s.','events-manager'), $user_link, $event_link, $group_link );
186
- }elseif( ($EM_Booking->previous_status == 1 || (!get_option('dbem_bookings_approval') && $EM_Booking->previous_status < 2)) && in_array($status, $rejected_statuses) ){
187
- $action = sprintf(__('%s will not be attending %s of group %s anymore.','events-manager'), $user_link, $event_link, $group_link );
188
- //$action_type = 'cancelled_booking';
189
- }
190
- }
191
- if( !empty($action) ){
192
- if( empty($EM_Event->group_id) ){
193
- bp_em_record_activity( array(
194
- 'user_id' => $EM_Booking->person->ID,
195
- 'action' => $action,
196
- 'primary_link' => $EM_Event->output('#_EVENTURL'),
197
- 'type' => $action_type,
198
- 'item_id' => $EM_Event->event_id,
199
- 'secondary_item_id' => $EM_Booking->booking_id,
200
- 'hide_sitewide' => $EM_Event->event_private
201
- ));
202
- }else{
203
- //tis a group event
204
- bp_em_record_activity( array(
205
- 'component' => 'groups',
206
- 'user_id' => $EM_Booking->person->ID,
207
- 'action' => $action,
208
- 'primary_link' => $EM_Event->output('#_EVENTURL'),
209
- 'type' => $action_type,
210
- 'item_id' => $EM_Event->group_id,
211
- 'secondary_item_id' => $EM_Booking->booking_id,
212
- 'hide_sitewide' => $EM_Event->event_private
213
- ));
214
- }
215
- }
216
- }
217
- return $result;
218
- }
219
- add_filter('em_booking_set_status','bp_em_record_activity_booking_save', 100, 2);
220
- add_filter('em_booking_save','bp_em_record_activity_booking_save', 100, 2);
221
- add_filter('em_booking_delete','bp_em_record_activity_booking_save', 100, 2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/bp-em-core.php DELETED
@@ -1,352 +0,0 @@
1
- <?php
2
- //Main loader for buddypress
3
- /**
4
- * Events Manager component for BuddyPress
5
- * @author marcus
6
- * @since 5.0
7
- */
8
- class BP_EM_Component extends BP_Component {
9
-
10
- function __construct() {
11
- global $bp;
12
- parent::start('events', __('Events', 'events-manager'), EM_DIR);
13
- $this->includes();
14
- //TODO make BP component optional
15
- $bp->active_components[$this->id] = '1';
16
- }
17
-
18
- function includes( $includes = array() ) {
19
- // Files to include
20
- $includes = array(
21
- 'buddypress/bp-em-activity.php',
22
- 'buddypress/bp-em-templatetags.php',
23
- 'buddypress/bp-em-notifications.php',
24
- 'buddypress/screens/profile.php',
25
- 'buddypress/screens/my-events.php',
26
- 'buddypress/screens/my-locations.php',
27
- 'buddypress/screens/attending.php',
28
- 'buddypress/screens/my-bookings.php',
29
- 'buddypress/screens/my-group-events.php'
30
- );
31
- if( bp_is_active('groups') ){
32
- $includes[] = 'buddypress/screens/group-events.php';
33
- $includes[] = 'buddypress/bp-em-groups.php';
34
- }
35
- parent::includes( $includes );
36
- //TODO add admin pages for extra BP specific settings
37
- }
38
-
39
- /**
40
- * Sets up the global Events Manager BuddyPress Components
41
- */
42
- function setup_globals( $args = array() ) {
43
- global $bp, $wpdb;
44
- // Define a slug constant that will be used to view this components pages
45
- if ( !defined( 'BP_EM_SLUG' ) )
46
- define ( 'BP_EM_SLUG', str_replace('/','-', EM_POST_TYPE_EVENT_SLUG) );
47
-
48
- // Set up the $globals array to be passed along to parent::setup_globals()
49
- $globals = array(
50
- 'slug' => BP_EM_SLUG,
51
- 'has_directory' => false, //already done by EM
52
- 'notification_callback' => 'bp_em_format_notifications',
53
- 'search_string' => sprintf(__( 'Search %s...', 'events-manager'),__('Events','events-manager')),
54
- );
55
-
56
- // Let BP_Component::setup_globals() do its work.
57
- parent::setup_globals( $globals );
58
-
59
- //quick link shortcut - may need to revisit this
60
- $bp->{$this->id}->link = trailingslashit($bp->loggedin_user->domain).BP_EM_SLUG.'/';
61
- }
62
-
63
- public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
64
- global $blog_id;
65
- //check multisite or normal mode for correct permission checking
66
- if(is_multisite() && $blog_id != BP_ROOT_BLOG){
67
- //FIXME MS mode doesn't seem to recognize cross subsite caps, using the proper functions, for now we use switch_blog.
68
- switch_to_blog(BP_ROOT_BLOG);
69
- $can_manage_events = current_user_can_for_blog(BP_ROOT_BLOG, 'edit_events');
70
- $can_manage_locations = current_user_can_for_blog(BP_ROOT_BLOG, 'edit_locations');
71
- $can_manage_bookings = current_user_can_for_blog(BP_ROOT_BLOG, 'manage_bookings');
72
- restore_current_blog();
73
- }else{
74
- $can_manage_events = current_user_can('edit_events');
75
- $can_manage_locations = current_user_can('edit_locations');
76
- $can_manage_bookings = current_user_can('manage_bookings');
77
- }
78
- /* Add 'Events' to the main user profile navigation */
79
- $event_count = EM_Events::count( array( 'scope'=>'future', 'owner'=> bp_displayed_user_id() ));
80
- if( empty($event_count) ) $event_count = 0;
81
- $event_count_span = $event_count > 0 ? ' <span class="count">'.esc_html($event_count).'</span>':'';
82
- $main_nav = array(
83
- 'name' => __( 'Events', 'events-manager'). $event_count_span,
84
- 'slug' => em_bp_get_slug(),
85
- 'position' => 80,
86
- 'screen_function' => 'bp_em_events',
87
- 'default_subnav_slug' => 'profile'
88
- );
89
-
90
- $em_link = trailingslashit( bp_displayed_user_domain() . em_bp_get_slug() );
91
-
92
- /* Create SubNav Items */
93
- $sub_nav[] = array(
94
- 'name' => __( 'My Profile', 'events-manager'),
95
- 'slug' => 'profile',
96
- 'parent_slug' => em_bp_get_slug(),
97
- 'parent_url' => $em_link,
98
- 'screen_function' => 'bp_em_events',
99
- 'position' => 10
100
- );
101
-
102
- if( get_option('dbem_rsvp_enabled') ) { // Only if bookings enabled
103
- $sub_nav[] = array(
104
- 'name' => __( 'Events I\'m Attending', 'events-manager'),
105
- 'slug' => 'attending',
106
- 'parent_slug' => em_bp_get_slug(),
107
- 'parent_url' => $em_link,
108
- 'screen_function' => 'bp_em_attending',
109
- 'position' => 20,
110
- 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile
111
- );
112
- }
113
-
114
- if( $can_manage_events ){
115
- $sub_nav[] = array(
116
- 'name' => __( 'My Events', 'events-manager'),
117
- 'slug' => 'my-events',
118
- 'parent_slug' => em_bp_get_slug(),
119
- 'parent_url' => $em_link,
120
- 'screen_function' => 'bp_em_my_events',
121
- 'position' => 30,
122
- 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile
123
- );
124
- }
125
-
126
- if( $can_manage_locations && get_option('dbem_locations_enabled') ){
127
- $sub_nav[] = array(
128
- 'name' => __( 'My Locations', 'events-manager'),
129
- 'slug' => 'my-locations',
130
- 'parent_slug' => em_bp_get_slug(),
131
- 'parent_url' => $em_link,
132
- 'screen_function' => 'bp_em_my_locations',
133
- 'position' => 40,
134
- 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile
135
- );
136
- }
137
-
138
- if( $can_manage_bookings && get_option('dbem_rsvp_enabled') ){
139
- $sub_nav[] = array(
140
- 'name' => __( 'My Event Bookings', 'events-manager'),
141
- 'slug' => 'my-bookings',
142
- 'parent_slug' => em_bp_get_slug(),
143
- 'parent_url' => $em_link,
144
- 'screen_function' => 'bp_em_my_bookings',
145
- 'position' => 50,
146
- 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile
147
- );
148
- }
149
-
150
- if( bp_is_active('groups') ){
151
- /* Create Profile Group Sub-Nav */
152
- $sub_nav[] = array(
153
- 'name' => __( 'Events', 'events-manager'),
154
- 'slug' => 'group-events',
155
- 'parent_slug' => bp_get_groups_slug(),
156
- 'parent_url' =>trailingslashit( bp_displayed_user_domain() . bp_get_groups_slug() ),
157
- 'screen_function' => 'bp_em_my_group_events',
158
- 'position' => 60,
159
- 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile
160
- );
161
- }
162
-
163
- $main_nav = apply_filters('em_bp_menu_main_nav', $main_nav);
164
- $sub_nav = apply_filters('em_bp_menu_sub_nav', $sub_nav);
165
-
166
- parent::setup_nav( $main_nav, $sub_nav );
167
- add_action( 'bp_init', array(&$this, 'setup_group_nav') );
168
- }
169
-
170
- public function setup_admin_bar( $wp_admin_nav = array() ) {
171
- global $bp, $blog_id;
172
-
173
- // Prevent debug notices
174
- $wp_admin_nav = array();
175
-
176
- // Menus for logged in user
177
- if ( is_user_logged_in() ) {
178
- //check multisite or normal mode for correct permission checking
179
- if(is_multisite() && $blog_id != BP_ROOT_BLOG){
180
- //FIXME MS mode doesn't seem to recognize cross subsite caps, using the proper functions, for now we use switch_blog.
181
- $current_blog = $blog_id;
182
- switch_to_blog(BP_ROOT_BLOG);
183
- $can_manage_events = current_user_can_for_blog(BP_ROOT_BLOG, 'edit_events');
184
- $can_manage_locations = current_user_can_for_blog(BP_ROOT_BLOG, 'edit_locations');
185
- $can_manage_bookings = current_user_can_for_blog(BP_ROOT_BLOG, 'manage_bookings');
186
- restore_current_blog();
187
- }else{
188
- $can_manage_events = current_user_can('edit_events');
189
- $can_manage_locations = current_user_can('edit_locations');
190
- $can_manage_bookings = current_user_can('manage_bookings');
191
- }
192
-
193
- $em_link = trailingslashit( bp_loggedin_user_domain() . em_bp_get_slug() );
194
-
195
- /* Add 'Events' to the main user profile navigation */
196
- $wp_admin_nav[] = array(
197
- 'parent' => $bp->my_account_menu_id,
198
- 'id' => 'my-em-' . $this->id,
199
- 'title' => __( 'Events', 'events-manager'),
200
- 'href' => $em_link
201
- );
202
-
203
- /* Create SubNav Items */
204
- $wp_admin_nav[] = array(
205
- 'parent' => 'my-em-' . $this->id,
206
- 'id' => 'my-em-' . $this->id .'-profile',
207
- 'title' => __( 'My Profile', 'events-manager'),
208
- 'href' => $em_link.'profile/'
209
- );
210
-
211
- $wp_admin_nav[] = array(
212
- 'parent' => 'my-em-' . $this->id,
213
- 'id' => 'my-em-' . $this->id .'-attending',
214
- 'title' => __( 'Events I\'m Attending', 'events-manager'),
215
- 'href' => $em_link.'attending/'
216
- );
217
-
218
- if( $can_manage_events ){
219
- $wp_admin_nav[] = array(
220
- 'parent' => 'my-em-' . $this->id,
221
- 'id' => 'my-em-' . $this->id .'-my-events',
222
- 'title' => __( 'My Events', 'events-manager'),
223
- 'href' => $em_link.'my-events/'
224
- );
225
- }
226
-
227
- if( $can_manage_locations && get_option('dbem_locations_enabled') ){
228
- $wp_admin_nav[] = array(
229
- 'parent' => 'my-em-' . $this->id,
230
- 'id' => 'my-em-' . $this->id .'-my-locations',
231
- 'title' => __( 'My Locations', 'events-manager'),
232
- 'href' => $em_link.'my-locations/'
233
- );
234
- }
235
-
236
- if( $can_manage_bookings && get_option('dbem_rsvp_enabled') ){
237
- $wp_admin_nav[] = array(
238
- 'parent' => 'my-em-' . $this->id,
239
- 'id' => 'my-em-' . $this->id .'-my-bookings',
240
- 'title' => __( 'My Event Bookings', 'events-manager'),
241
- 'href' => $em_link.'my-bookings/'
242
- );
243
- }
244
-
245
- if( bp_is_active('groups') ){
246
- /* Create Profile Group Sub-Nav */
247
- $wp_admin_nav[] = array(
248
- 'parent' => 'my-account-groups',
249
- 'id' => 'my-account-groups-' . $this->id ,
250
- 'title' => __( 'Events', 'events-manager'),
251
- 'href' => trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) . 'group-events/'
252
- );
253
- }
254
- }
255
-
256
- parent::setup_admin_bar( $wp_admin_nav );
257
- }
258
-
259
- function setup_group_nav(){
260
- global $bp;
261
- /* Add some group subnav items */
262
- $user_access = false;
263
- $group_link = '';
264
- if( bp_is_active('groups') && !empty($bp->groups->current_group) ){
265
- $group_link = $bp->root_domain . '/' . bp_get_groups_root_slug() . '/' . $bp->groups->current_group->slug . '/';
266
- $user_access = $bp->groups->current_group->user_has_access;
267
- if( !empty($bp->current_component) && $bp->current_component == 'groups' ){
268
- $count = EM_Events::count(array('group'=>$bp->groups->current_group->id));
269
- if( empty($count) ) $count = 0;
270
- }
271
- bp_core_new_subnav_item( array(
272
- 'name' => __( 'Events', 'events-manager') . " <span>$count</span>",
273
- 'slug' => 'events',
274
- 'parent_url' => $group_link,
275
- 'parent_slug' => $bp->groups->current_group->slug,
276
- 'screen_function' => 'bp_em_group_events',
277
- 'position' => 50,
278
- 'user_has_access' => $user_access,
279
- 'item_css_id' => 'events'
280
- ));
281
- }
282
- }
283
- }
284
- function bp_em_load_core_component() {
285
- global $bp;
286
- $bp->events = new BP_EM_Component();
287
- }
288
- add_action( 'bp_loaded', 'bp_em_load_core_component' );
289
-
290
- if( !is_admin() || ( defined('DOING_AJAX') && !empty($_REQUEST['is_public'])) ){
291
- /*
292
- * Links and URL Rewriting
293
- */
294
- function em_bp_rewrite_edit_url($url, $EM_Event){
295
- global $bp;
296
- return $bp->events->link.'my-events/?action=edit&event_id='.$EM_Event->event_id;
297
- }
298
- function em_bp_rewrite_events_admin_url( $url ){
299
- global $bp;
300
- return $bp->events->link.'my-events/';
301
- }
302
- if( !get_option('dbem_edit_events_page') ){
303
- add_filter('em_event_get_edit_url','em_bp_rewrite_edit_url',10,2);
304
- add_filter('em_get_events_admin_url','em_bp_rewrite_edit_url',10,2);
305
- }
306
-
307
- function em_bp_rewrite_bookings_url($url, $EM_Event){
308
- global $bp;
309
- return $bp->events->link.'my-bookings/?event_id='.$EM_Event->event_id;
310
- }
311
- if( !get_option('dbem_edit_bookings_page') ){
312
- add_filter('em_event_get_bookings_url','em_bp_rewrite_bookings_url',10,2);
313
- }
314
-
315
- function em_bp_rewrite_edit_location_url($url, $EM_Location){
316
- global $bp;
317
- return $bp->events->link.'my-locations/?action=edit&location_id='.$EM_Location->location_id;
318
- }
319
- if( !get_option('dbem_edit_locations_page') ){
320
- add_filter('em_location_get_edit_url','em_bp_rewrite_edit_location_url',10,2);
321
- }
322
- }
323
-
324
- //CSS and JS Loading
325
- function bp_em_enqueue_scripts( ){
326
- if( bp_is_current_component('events') || (bp_is_current_component('groups') && bp_is_current_action('group-events')) ){
327
- add_filter('option_dbem_js_limit', '__return_false');
328
- add_filter('option_dbem_css_limit', '__return_false');
329
- }
330
-
331
- }
332
- add_action('wp_enqueue_scripts','bp_em_enqueue_scripts',1);
333
-
334
- function bp_em_messages_js_compat() {
335
- if(bp_is_messages_compose_screen()){
336
- wp_deregister_script( 'events-manager' );
337
- }
338
- }
339
- add_action( 'wp_print_scripts', 'bp_em_messages_js_compat', 100 );
340
-
341
- /**
342
- * Delete events when you delete a user.
343
- */
344
- function bp_em_remove_data( $user_id ) {
345
- $EM_Events = EM_Events::get(array('scope'=>'all','owner'=>$user_id, 'status'=>false));
346
- EM_Events::delete($EM_Events);
347
- }
348
- add_action( 'wpmu_delete_user', 'bp_em_remove_data', 1 );
349
- add_action( 'delete_user', 'bp_em_remove_data', 1 );
350
-
351
- define('EM_BP_LOADED',true); //so we know
352
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/bp-em-groups.php DELETED
@@ -1,151 +0,0 @@
1
- <?php
2
- /**
3
- * Turns an event private if the event belongs to a private BP Group
4
- * @param EM_Event $EM_Event
5
- */
6
- function bp_em_group_event_save($result, $EM_Event){
7
- if( is_object($EM_Event) && !empty($EM_Event->event_id) ){
8
- if( !empty($_REQUEST['group_id']) && is_numeric($_REQUEST['group_id']) && bp_is_active('groups') ){
9
- //firstly, we check that the event has been published, otherwise users without publish rights can submit an event at a private group and event is marked private/published immediately
10
- if( $EM_Event->event_status == 1 ){
11
- //we have been requested an event creation tied to a group, so does this group exist, and does this person have admin rights to it?
12
- if( groups_is_user_admin(get_current_user_id(), absint($_REQUEST['group_id']) ) ){
13
- $EM_Event->group_id = absint($_REQUEST['group_id']);
14
- }
15
- if( !empty($EM_Event->group_id) ){
16
- //if group is private, make it private
17
- $group = groups_get_group(array('group_id'=>$EM_Event->group_id));
18
- $is_member = groups_is_user_member(get_current_user_id(), $EM_Event->group_id) || groups_is_user_admin(get_current_user_id(), $EM_Event->group_id) || groups_is_user_mod(get_current_user_id(), $EM_Event->group_id);
19
- if( $group->status != 'public' && $is_member ){
20
- //Make sure event status is private and set post status to private
21
- global $wpdb;
22
- $EM_Event->event_private = 1;
23
- $wpdb->update($wpdb->posts, array('post_status'=>'private'), array('ID'=>$EM_Event->post_id));
24
- $wpdb->update(EM_EVENTS_TABLE, array('event_private'=>1), array('event_id'=>$EM_Event->event_id));
25
- }
26
- }
27
- }
28
- }else{
29
- $EM_Event->group_id = null;
30
- }
31
- }
32
- return $result;
33
- }
34
- add_action('em_event_save','bp_em_group_event_save',1,2);
35
-
36
- /**
37
- * Overrides the default capability of the user for another owner's event if the user is a group admin and the event belongs to a group.
38
- * User must have the relevant permissions globally in order to inherit that capability for this event as well.
39
- * @param boolean $result
40
- * @param EM_Event $EM_Event
41
- */
42
- function bp_em_group_event_can_manage( $result, $EM_Event, $owner_capability, $admin_capability, $user_to_check){
43
- if( !$result && $EM_Event->event_owner != get_current_user_id() && !empty($EM_Event->group_id) && bp_is_active('groups') ){ //only override if already false, incase it's true
44
- //if the user is an admin of this group, and actually has the relevant permissions globally, they can manage this event
45
- $EM_Object = new EM_Object(); //create new object to prevent infinite loop should we call $EM_Event->can_manage();
46
- if( groups_is_user_admin(get_current_user_id(),$EM_Event->group_id) && $EM_Object->can_manage($owner_capability, $admin_capability, $user_to_check) ){
47
- //This user is an admin of the owner's group, so they can edit this event.
48
- array_pop($EM_Event->errors); //remove last error
49
- return true;
50
- }else{
51
- $EM_Event->add_error($EM_Object->get_errors()); //add any applicable errors
52
- }
53
- }
54
- return $result;
55
- }
56
- add_filter('em_event_can_manage','bp_em_group_event_can_manage',1,5);
57
-
58
-
59
- function bp_em_group_events_accepted_searches($searches){
60
- if( bp_is_active('groups') ){
61
- $searches[] = 'group';
62
- }
63
- return $searches;
64
- }
65
- add_filter('em_accepted_searches','bp_em_group_events_accepted_searches',1,1);
66
-
67
- function bp_em_group_events_get_default_search($searches, $array){
68
- if( !empty($array['group']) && (is_numeric($array['group']) || $array['group'] == 'my' || $array['group'] == 'this') && bp_is_active('groups') ){
69
- if($array['group'] == 'this'){ //shows current group, if applicable
70
- if( is_numeric(bp_get_current_group_id()) ){
71
- $searches['group'] = bp_get_current_group_id();
72
- }
73
- }else{
74
- $searches['group'] = $array['group'];
75
- }
76
- }
77
- return $searches;
78
- }
79
- add_filter('em_events_get_default_search','bp_em_group_events_get_default_search',1,2);
80
-
81
- /*
82
- * Privacy Functions
83
- */
84
- function bp_em_group_events_build_sql_conditions( $conditions, $args ){
85
- if( !empty($args['group']) && is_numeric($args['group']) ){
86
- $conditions['group'] = "( `group_id`={$args['group']} )";
87
- }elseif( !empty($args['group']) && $args['group'] == 'my' ){
88
- $groups = groups_get_user_groups(get_current_user_id());
89
- if( count($groups) > 0 ){
90
- $conditions['group'] = "( `group_id` IN (".implode(',',$groups['groups']).") )";
91
- }
92
- }
93
- //deal with private groups and events
94
- if( is_user_logged_in() ){
95
- global $wpdb;
96
- //find out what private groups they belong to, and don't show private group events not in their memberships
97
- $group_ids = BP_Groups_Member::get_group_ids(get_current_user_id());
98
- if( $group_ids['total'] > 0){
99
- $conditions['group_privacy'] = "(`event_private`=0 OR (`event_private`=1 AND (`group_id` IS NULL OR `group_id` = 0)) OR (`event_private`=1 AND `group_id` IN (".implode(',',$group_ids['groups']).")))";
100
- }else{
101
- //find out what private groups they belong to, and don't show private group events not in their memberships
102
- $conditions['group_privacy'] = "(`event_private`=0 OR (`event_private`=1 AND (`group_id` IS NULL OR `group_id` = 0)))";
103
- }
104
- }
105
- return $conditions;
106
- }
107
- add_filter('em_events_build_sql_conditions','bp_em_group_events_build_sql_conditions',1,2);
108
-
109
-
110
- /**
111
- * Checks if the event is private and either belongs to a group or private group, as members of that group should be able to see the post even if not able to see private events.
112
- * @param string $template
113
- * @return string
114
- */
115
- function bp_em_private_event_check($template){
116
- global $post, $wpdb, $wp_query, $bp;
117
- if( $post->post_type == EM_POST_TYPE_EVENT ){
118
- $EM_Event = em_get_event($post);
119
- //echo "<pre>"; print_r($EM_Event); echo "</pre>"; die();
120
- if( !empty($EM_Event->event_private) && !empty($EM_Event->group_id) ){
121
- if( is_user_logged_in() ){
122
- //make sure user is a member of this group, whether private or not, private groups just aren't shown to non-members of a group
123
- $id_lookup = $wpdb->get_var( $wpdb->prepare( "SELECT m.group_id FROM {$bp->groups->table_name_members} m WHERE m.group_id = %s AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $EM_Event->group_id, get_current_user_id() ) );
124
- if($id_lookup != $EM_Event->group_id){
125
- unset($post);
126
- $wp_query->set_404();
127
- $template = locate_template(array('404.php'),false);
128
- }
129
- }else{
130
- unset($post);
131
- $wp_query->set_404();
132
- $template = locate_template(array('404.php'),false);
133
- }
134
- }
135
- }
136
- return $template;
137
- }
138
- add_filter('single_template','bp_em_private_event_check',20);
139
-
140
- /*
141
- * Admin Meta Boxes
142
- */
143
- function bp_em_meta_boxes(){
144
- add_meta_box('em-event-group', __('Group Ownership','events-manager'), 'bp_em_meta_box_group',EM_POST_TYPE_EVENT, 'side','low');
145
- add_meta_box('em-event-group', __('Group Ownership','events-manager'), 'bp_em_meta_box_group','event-recurring', 'side','low');
146
- }
147
- add_action('add_meta_boxes', 'bp_em_meta_boxes');
148
-
149
- function bp_em_meta_box_group(){
150
- em_locate_template('forms/event/group.php',true);
151
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/bp-em-notifications.php DELETED
@@ -1,91 +0,0 @@
1
- <?php
2
- //This file handles hooks requiring notifications
3
-
4
- /**
5
- * bp_em_format_notifications()
6
- *
7
- * The format notification function will take DB entries for notifications and format them
8
- * so that they can be displayed and read on the screen.
9
- *
10
- * Notifications are "screen" notifications, that is, they appear on the notifications menu
11
- * in the site wide navigation bar. They are not for email notifications.
12
- *
13
- *
14
- * The recording is done by using bp_core_add_notification() which you can search for in this file for
15
- * ems of usage.
16
- */
17
- function bp_em_format_notifications( $action, $item_id, $secondary_item_id, $total_items ) {
18
- global $bp;
19
- switch ( $action ) {
20
- case 'pending_booking':
21
- //Count pending bookings
22
- if( get_option('dbem_bookings_approval')){
23
- if ( $total_items > 1 ) {
24
- return '<a href="' . $bp->loggedin_user->domain . $bp->events->slug . '/my-bookings/" title="' . __( 'My Bookings', 'events-manager') . '">' . __('You have a pending booking','events-manager'). '</a>';
25
- } else {
26
- return apply_filters( 'bp_em_format_new_booking_notification', '<a href="' . $bp->loggedin_user->domain . $bp->events->slug . '/my-bookings/" title="' . __( 'My Bookings', 'events-manager') . '">' . sprintf(__('You have %s pending bookings','events-manager'), $total_items). '</a>' );
27
- }
28
- }
29
- break;
30
- case 'confirmed_booking':
31
- //Count pending bookings
32
- if ( $total_items > 1 ) {
33
- return apply_filters( 'bp_em_format_confirmed_booking_notifications', '<a href="' . $bp->loggedin_user->domain . $bp->events->slug . '/my-bookings/" title="' . __( 'My Bookings', 'events-manager') . '">' . __('You have a confirmed booking','events-manager'). '</a>' );
34
- } else {
35
- return apply_filters( 'bp_em_format_confirmed_booking_notification', '<a href="' . $bp->loggedin_user->domain . $bp->events->slug . '/my-bookings/" title="' . __( 'My Bookings', 'events-manager') . '">' . sprintf(__('You have %s confirmed bookings','events-manager'), $total_items). '</a>' );
36
- }
37
- break;
38
- case 'cancelled_booking':
39
- //Count pending bookings
40
- if ( $total_items > 1 ) {
41
- return apply_filters( 'bp_em_format_cancelled_booking_notifications', '<a href="' . $bp->loggedin_user->domain . $bp->events->slug . '/my-bookings/" title="' . __( 'My Bookings', 'events-manager') . '">' . __('A user cancelled a booking','events-manager'). '</a>' );
42
- } else {
43
- return apply_filters( 'bp_em_format_cancelled_booking_notification', '<a href="' . $bp->loggedin_user->domain . $bp->events->slug . '/my-bookings/" title="' . __( 'My Bookings', 'events-manager') . '">' . sprintf(__('%s users cancelled bookings.','events-manager'), $total_items). '</a>' );
44
- }
45
- break;
46
- }
47
- do_action( 'bp_em_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
48
-
49
- return false;
50
- }
51
-
52
- /**
53
- * Remove a screen notification for a user.
54
- */
55
- function bp_em_remove_screen_notifications() {
56
- global $bp;
57
- if( function_exists('bp_notifications_delete_notifications_by_type') ){
58
- bp_notifications_delete_notifications_by_type( $bp->loggedin_user->id, $bp->events->slug, 'attending' );
59
- }
60
- }
61
- add_action( 'bp_em_my_events', 'bp_em_remove_screen_notifications' );
62
- add_action( 'xprofile_screen_display_profile', 'bp_em_remove_screen_notifications' );
63
-
64
- /**
65
- * Catch booking saves and add a BP notification.
66
- * @param boolean $result
67
- * @param EM_Booking $EM_Booking
68
- * @return boolean
69
- */
70
- function bp_em_add_booking_notification($result, $EM_Booking){
71
- global $bp;
72
- if( !function_exists('bp_notifications_add_notification') ) return $result; //no need if notifications are disabled
73
- if( get_option('dbem_bookings_approval') && $EM_Booking->get_status() == 0 ){
74
- $action = 'pending_booking';
75
- }elseif( $EM_Booking->get_status() == 1 || (get_option('dbem_bookings_approval') && $EM_Booking->get_status() == 0) ){
76
- $action = 'confirmed_booking';
77
- }elseif( $EM_Booking->get_status() == 3 ){
78
- $action = 'cancelled_booking';
79
- }
80
- if( !empty($action) && !$EM_Booking->is_no_user() ){
81
- bp_notifications_add_notification( array(
82
- 'item_id' => $EM_Booking->booking_id,
83
- 'secondary_item_id' => $EM_Booking->event_id,
84
- 'user_id' => $EM_Booking->get_event()->get_contact()->ID,
85
- 'component_name' => 'events',
86
- 'component_action' => $action
87
- ));
88
- }
89
- return $result;
90
- }
91
- add_filter('em_booking_save','bp_em_add_booking_notification',1,2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/bp-em-templatetags.php DELETED
@@ -1,21 +0,0 @@
1
- <?php
2
- /**
3
- * Echo the Events Manager BuddyPresss component's slug
4
- * @since 5.0
5
- */
6
- function em_bp_slug() {
7
- echo em_bp_get_slug();
8
- }
9
- /**
10
- * Return the Events Manager BuddyPresss component's slug
11
- *
12
- * @since 5.0
13
- * @uses apply_filters() Filter 'em_bp_get_slug' to change the output
14
- * @return str $slug The slug from $bp->events->slug, if it exists
15
- */
16
- function em_bp_get_slug() {
17
- global $bp;
18
- // Avoid PHP warnings, in case the value is not set for some reason
19
- $slug = !empty( $bp->events->slug ) ? $bp->events->slug : BP_EM_SLUG;
20
- return apply_filters( 'em_bp_get_slug', $slug );
21
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/screens/attending.php DELETED
@@ -1,29 +0,0 @@
1
- <?php
2
- /**
3
- * bp_em_screen_two()
4
- *
5
- * Sets up and displays the screen output for the sub nav item "em/screen-two"
6
- */
7
- function bp_em_attending() {
8
- global $bp;
9
- /**
10
- * If the user has not Accepted or Rejected anything, then the code above will not run,
11
- * we can continue and load the template.
12
- */
13
- do_action( 'bp_em_attending' );
14
-
15
- add_action( 'bp_template_title', 'bp_em_attending_title' );
16
- add_action( 'bp_template_content', 'bp_em_attending_content' );
17
-
18
- /* Finally load the plugin template file. */
19
- bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'members/single/plugins' ) );
20
- }
21
-
22
- function bp_em_attending_title() {
23
- _e( 'Events I\'m Attending', 'events-manager');
24
- }
25
-
26
- function bp_em_attending_content() {
27
- //We can use the same template as the public user interface for non bp sites
28
- em_my_bookings();
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/screens/group-events.php DELETED
@@ -1,30 +0,0 @@
1
- <?php
2
- /**
3
- * Controller for the event views in BP (using mvc terms here)
4
- */
5
- function bp_em_group_events() {
6
- global $bp;
7
- do_action( 'bp_em_group_events' );
8
-
9
- //plug into EM admin code (at least for now)
10
- include_once(EM_DIR.'/admin/em-admin.php');
11
-
12
- add_action( 'bp_template_title', 'bp_em_group_events_title' );
13
- add_action( 'bp_template_content', 'bp_em_group_events_content' );
14
-
15
- /* Finally load the plugin template file. */
16
- bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'groups/single/plugins' ) );
17
- }
18
-
19
- function bp_em_group_events_title() {
20
- _e( 'Group Events', 'events-manager');
21
- }
22
- /**
23
- * Determines whether to show event page or events page, and saves any updates to the event or events
24
- * @return null
25
- */
26
- function bp_em_group_events_content() {
27
- em_locate_template('buddypress/group-events.php', true);
28
- }
29
-
30
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/screens/my-bookings.php DELETED
@@ -1,37 +0,0 @@
1
- <?php
2
- /**
3
- * bp_em_screen_two()
4
- *
5
- * Sets up and displays the screen output for the sub nav item "em/screen-two"
6
- */
7
- function bp_em_my_bookings() {
8
- global $bp, $EM_Event;
9
-
10
- //assume any notifications here are considered viewed via this page
11
- if( function_exists('bp_notifications_delete_notifications_by_type') ){
12
- bp_notifications_delete_notifications_by_type(get_current_user_id(), 'events','pending_booking');
13
- bp_notifications_delete_notifications_by_type(get_current_user_id(), 'events','confirmed_booking');
14
- bp_notifications_delete_notifications_by_type(get_current_user_id(), 'events','cancelled_booking');
15
- }
16
-
17
- em_load_event();
18
- /**
19
- * If the user has not Accepted or Rejected anything, then the code above will not run,
20
- * we can continue and load the template.
21
- */
22
- do_action( 'bp_em_my_bookings' );
23
-
24
- add_action( 'bp_template_title', 'bp_em_my_bookings_title' );
25
- add_action( 'bp_template_content', 'bp_em_my_bookings_content' );
26
-
27
- /* Finally load the plugin template file. */
28
- bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'members/single/plugins' ) );
29
- }
30
-
31
- function bp_em_my_bookings_title() {
32
- _e( 'My Event Bookings', 'events-manager');
33
- }
34
-
35
- function bp_em_my_bookings_content() {
36
- em_locate_template('buddypress/my-bookings.php',true);
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/screens/my-events.php DELETED
@@ -1,55 +0,0 @@
1
- <?php
2
- /**
3
- * Controller for the event views in BP (using mvc terms here)
4
- */
5
- function bp_em_my_events() {
6
- global $bp, $EM_Event;
7
- if( !is_object($EM_Event) && !empty($_REQUEST['event_id']) ){
8
- $EM_Event = new EM_Event( absint($_REQUEST['event_id']) );
9
- }
10
-
11
- do_action( 'bp_em_my_events' );
12
-
13
- $template_title = 'bp_em_my_events_title';
14
- $template_content = 'bp_em_my_events_content';
15
-
16
- if( !empty($_GET['action']) ){
17
- switch($_GET['action']){
18
- case 'edit':
19
- $template_title = 'bp_em_my_events_editor_title';
20
- break;
21
- }
22
- }
23
-
24
- add_action( 'bp_template_title', $template_title );
25
- add_action( 'bp_template_content', $template_content );
26
-
27
- /* Finally load the plugin template file. */
28
- bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'members/single/plugins' ) );
29
- }
30
-
31
- function bp_em_my_events_title() {
32
- _e( 'My Events', 'events-manager');
33
- }
34
-
35
- /**
36
- * Determines whether to show event page or events page, and saves any updates to the event or events
37
- * @return null
38
- */
39
- function bp_em_my_events_content() {
40
- em_locate_template('buddypress/my-events.php', true);
41
- }
42
-
43
- function bp_em_my_events_editor_title() {
44
- global $EM_Event;
45
- if( is_object($EM_Event) ){
46
- if($EM_Event->is_recurring()){
47
- echo __( "Reschedule Events", 'events-manager')." '{$EM_Event->event_name}'";
48
- }else{
49
- echo __( "Edit Event", 'events-manager') . " '" . $EM_Event->event_name . "'";
50
- }
51
- }else{
52
- _e( 'Add Event', 'events-manager');
53
- }
54
- }
55
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/screens/my-group-events.php DELETED
@@ -1,27 +0,0 @@
1
- <?php
2
- /**
3
- * Controller for the event views in BP (using mvc terms here)
4
- */
5
- function bp_em_my_group_events() {
6
- global $bp;
7
- do_action( 'bp_em_my_group_events' );
8
-
9
- //plug into EM admin code (at least for now)
10
- include_once(EM_DIR.'/admin/em-admin.php');
11
-
12
- add_action( 'bp_template_title', 'bp_em_my_group_events_title' );
13
- add_action( 'bp_template_content', 'bp_em_my_group_events_content' );
14
-
15
- /* Finally load the plugin template file. */
16
- bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'members/single/plugins' ) );
17
- }
18
-
19
- function bp_em_my_group_events_title() {
20
- _e( 'Group Events', 'events-manager');
21
- }
22
-
23
- function bp_em_my_group_events_content(){
24
- em_locate_template('buddypress/my-group-events.php', true);
25
- }
26
-
27
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/screens/my-locations.php DELETED
@@ -1,51 +0,0 @@
1
- <?php
2
- /**
3
- * Controller for the location views in BP (using mvc terms here)
4
- */
5
- function bp_em_my_locations() {
6
- global $bp, $EM_Location;
7
- if( !is_object($EM_Location) && !empty($_REQUEST['location_id']) ){
8
- $EM_Location = new EM_Location( absint($_REQUEST['location_id']) );
9
- }
10
-
11
- do_action( 'bp_em_my_locations' );
12
-
13
- $template_title = 'bp_em_my_locations_title';
14
- $template_content = 'bp_em_my_locations_content';
15
-
16
- if( !empty($_GET['action']) ){
17
- switch($_GET['action']){
18
- case 'edit':
19
- $template_title = 'bp_em_my_locations_editor_title';
20
- break;
21
- }
22
- }
23
-
24
- add_action( 'bp_template_title', $template_title );
25
- add_action( 'bp_template_content', $template_content );
26
-
27
- /* Finally load the plugin template file. */
28
- bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'members/single/plugins' ) );
29
- }
30
-
31
- function bp_em_my_locations_title() {
32
- _e( 'My Locations', 'events-manager');
33
- }
34
-
35
- /**
36
- * Determines whether to show location page or locations page, and saves any updates to the location or locations
37
- * @return null
38
- */
39
- function bp_em_my_locations_content() {
40
- em_locate_template('buddypress/my-locations.php', true);
41
- }
42
-
43
- function bp_em_my_locations_editor_title() {
44
- global $EM_Location;
45
- if( empty($EM_Location) || !is_object($EM_Location) ){
46
- $title = __('Add Location', 'events-manager');
47
- }else{
48
- $title = __('Edit Location', 'events-manager');
49
- }
50
- }
51
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/buddypress/screens/profile.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
- /**
3
- * bp_em_screen_one()
4
- *
5
- * Sets up and displays the screen output for the sub nav item "em/screen-one"
6
- */
7
- function bp_em_events() {
8
- global $bp, $EM_Notices;
9
-
10
- if( bp_is_my_profile() ){
11
- $EM_Notices->add_info( __('You are currently viewing your public page, this is what other users will see.', 'events-manager') );
12
- }
13
-
14
- /* Add a do action here, so your component can be extended by others. */
15
- do_action( 'bp_em_events' );
16
-
17
- add_action( 'bp_template_title', 'bp_em_events_title' );
18
- add_action( 'bp_template_content', 'bp_em_events_content' );
19
- bp_core_load_template( apply_filters( 'bp_core_template_plugin', 'members/single/plugins' ) );
20
- //bp_core_load_template( apply_filters( 'bp_em_template_screen_one', 'em/screen-one' ) );
21
- }
22
- /***
23
- * The second argument of each of the above add_action() calls is a function that will
24
- * display the corresponding information. The functions are presented below:
25
- */
26
- function bp_em_events_title() {
27
- _e( 'Events', 'events-manager');
28
- }
29
-
30
- function bp_em_events_content() {
31
- em_locate_template('buddypress/profile.php',true);
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-admin-notice.php DELETED
@@ -1,178 +0,0 @@
1
- <?php
2
- /**
3
- * A single admin notice which contains information about who to display it to, what to dispaly, when and where to display it.
4
- * @since 5.8.2.0
5
- */
6
- class EM_Admin_Notice {
7
-
8
- /**
9
- * Notice key
10
- * @var string
11
- */
12
- public $name = '';
13
- /**
14
- * Which user should see this message. Can be 'admin', 'all' (or false), or a specific capability.
15
- * Note that 'admin' in MultiSite context is considered a super admin, use the 'manage_options' cap instead.
16
- * @var string
17
- */
18
- public $who = 'admin';
19
- /**
20
- * What kind of notices this is, which can be 'success','info','warning' or 'error'
21
- * @var string
22
- */
23
- public $what = 'info';
24
- /**
25
- * Timestamp indicating when a notice should be shown. If empty, message will show immediately.
26
- * @var int
27
- */
28
- public $when;
29
- /**
30
- * Where a message should be shown. Values accepted are 'all' (all pages), 'network_admin', 'plugin' (plugin-specific pages), 'settings'
31
- * or any value representing an admin page in the events admin menu, e.g. 'events-manager-bookings' would be the bookings admin page.
32
- *
33
- * @var string
34
- */
35
- public $where = 'settings';
36
- /**
37
- * The actual message that will be displayed. If left blank, a filter will be applied upon output with format
38
- * em_admin_notice_output_{$this->name}
39
- * @var string
40
- */
41
- public $message = false; //the message
42
- /**
43
- * Whether a message is dismissable
44
- * @var boolean
45
- */
46
- public $dismissible = true;
47
- /**
48
- * If a message is dismissable and this is set to true, it will be shown to every user matching the who property until dismissed.
49
- * This is also set to true by default if the user type is not 'admin' and not previously set to true or false by the em_admin_notice_ hook.
50
- * @var boolean
51
- */
52
- protected $user_notice = null;
53
- /**
54
- * If set to true, this is treated as a network-level notice, meaning it can apply to all sites on the network or the network admin in MultiSite mode.
55
- * @var bool
56
- */
57
- public $network = false;
58
-
59
- public function __construct( $key, $type = false, $message = false ){
60
- //process the supplied data
61
- if( empty($message) ){
62
- if( empty($type) && is_array($key) ){
63
- $notice = $key;
64
- }elseif( is_array($type) ){
65
- $this->name = $key;
66
- $notice = $type;
67
- }elseif( is_array($key) ){
68
- $notice = $key;
69
- }else{
70
- //we may even have simply a key/name for this notice, for hooking later on
71
- if( is_string($key) ) $this->name = $key;
72
- $notice = array();
73
- }
74
- }else{
75
- //here we expect a string for eveything
76
- $notice = array('name'=> (string) $key, 'what' => (string) $type, 'message' => (string) $message) ;
77
- }
78
- //we should have an array to process at this point
79
- foreach( $notice as $key => $value ){
80
- $this->$key = $value;
81
- }
82
- //call a hook
83
- do_action('em_admin_notice_'.$this->name, $this);
84
- if( !is_multisite() && $this->where == 'network_admin' ) $this->where = 'settings';
85
- }
86
-
87
- public function __set( $prop, $val ){
88
- $this->$prop = $val;
89
- }
90
-
91
- public function __get( $prop ){
92
- if( $prop == 'user_notice' ){
93
- return $this->is_user_notice();
94
- }
95
- }
96
-
97
- /**
98
- * Returns whether or not this object should be dismissed on a per-user basis.
99
- * @return boolean
100
- */
101
- public function is_user_notice(){
102
- if( $this->who != 'admin' && $this->user_notice === null ){
103
- //user_notice was not specifically set, so if notice is dismissible and not targetted at admins we assume it's dismissed at per-user basis
104
- return $this->dismissible;
105
- }
106
- return $this->user_notice;
107
- }
108
-
109
- /**
110
- * Returns notice as an array with non-default values.
111
- * @return array
112
- */
113
- public function to_array(){
114
- $default = new EM_Admin_Notice('default');
115
- $notice = array();
116
- foreach( get_class_vars('EM_Admin_Notice') as $var => $val ){
117
- if( $this->$var != $default->$var ) $notice[$var] = $this->$var;
118
- }
119
- return $notice;
120
- }
121
-
122
- public function can_show(){
123
- //check that we have at least a notice to show
124
- if( empty($this->name) ) return false;
125
- //can we display due to time?
126
- $return = ( empty($this->when) || $this->when <= time() );
127
- //who to display it to
128
- if( $return && !empty($this->who) && $this->who != 'all' ){
129
- $return = false; //unless this test passes, don't show it
130
- if( $this->who == 'all' ) $return = true;
131
- elseif ( $this->who == 'admin' ){
132
- if( $this->network && em_wp_is_super_admin() ) $return = true;
133
- elseif( current_user_can('manage_options') ) $return = true;
134
- }
135
- elseif( $this->who == 'blog_admin' && current_user_can('manage_options') ) $return = true;
136
- elseif( !$return && current_user_can($this->who) ) $return = true;
137
- }
138
- //can we display due to location?
139
- if( $return ){
140
- $return = false; //unless this test passes, don't show it
141
- if( empty($this->where) || $this->where == 'all' ){
142
- $return = true;
143
- }elseif( !empty($_REQUEST['post_type']) && in_array($_REQUEST['post_type'], array(EM_POST_TYPE_EVENT, EM_POST_TYPE_LOCATION, 'event-recurring')) ){
144
- if( $this->where == 'plugin' ) $return = true;
145
- elseif( empty($_REQUEST['page']) && in_array($this->where, array(EM_POST_TYPE_EVENT, EM_POST_TYPE_LOCATION, 'event-recurring')) ) $return = true;
146
- elseif( $this->where == 'settings' && !empty($_REQUEST['page']) && $_REQUEST['page'] == 'events-manager-options' ) $return = true;
147
- elseif( !empty($_REQUEST['page']) && ($this->where == $_REQUEST['page'] || (is_array($this->where) && in_array($_REQUEST['page'], $this->where))) ) $return = true;
148
- }elseif( is_network_admin() && !empty($_REQUEST['page']) && preg_match('/^events\-manager\-/', $_REQUEST['page']) ){
149
- $return = $this->where == 'plugin' || $this->where == 'settings' || $this->where == 'network_admin';
150
- }elseif( !empty($_REQUEST['page']) && ($this->where == $_REQUEST['page'] || (is_array($this->where) && in_array($_REQUEST['page'], $this->where))) ){
151
- $return = true;
152
- }
153
- }
154
- //does this even have a message we can display?
155
- if( $return && empty($this->message)){
156
- $this->message = apply_filters('em_admin_notice_'.$this->name .'_message', false, $this);
157
- $return = !empty($this->message);
158
- }
159
- //is this user-dismissable, and if so, did this user dismiss it?
160
- if( $return && $this->is_user_notice() ){
161
- $user_id = get_current_user_id();
162
- $dismissed_notices = get_user_meta( $user_id, '_em_dismissed_notices', true);
163
- $return = empty($dismissed_notices) || !in_array($this->name, $dismissed_notices);
164
- }
165
- return $return;
166
- }
167
-
168
- public function output(){
169
- if( empty($this->message) ) return false;
170
- $action = $this->network ? 'em_dismiss_network_admin_notice':'em_dismiss_admin_notice';
171
- ?>
172
- <div class="em-admin-notice notice notice-<?php echo esc_attr($this->what); ?> <?php if($this->dismissible) echo 'is-dismissible'?>" id="notice-<?php echo esc_attr($this->name); ?>" data-dismiss-action="<?php echo $action; ?>" data-dismiss-key="<?php echo esc_attr($this->name); ?>">
173
- <p><?php echo $this->message; ?></p>
174
- </div>
175
- <?php
176
- return true;
177
- }
178
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-admin-notices.php DELETED
@@ -1,204 +0,0 @@
1
- <?php
2
- /**
3
- * Handles the registration and display of admin notices, including storage and retrieval of individual EM_Admin_Notice notice objects.
4
- * @since 5.8.2.0
5
- */
6
- class EM_Admin_Notices {
7
-
8
- /**
9
- * Flag for whether or not to add dismissable notice JS to admin page footer.
10
- * @var boolean
11
- */
12
- public static $js_footer = false;
13
-
14
- /**
15
- * Initialize EM Admin Notices by adding the relevant hooks.
16
- */
17
- public static function init(){
18
- add_action('admin_notices', 'EM_Admin_Notices::admin_notices');
19
- add_action('wp_ajax_em_dismiss_admin_notice', 'EM_Admin_Notices::dismiss_admin_notice');
20
- if( is_multisite() ){
21
- add_action('admin_notices', 'EM_Admin_Notices::network_admin_notices');
22
- add_action('network_admin_notices', 'EM_Admin_Notices::network_admin_notices');
23
- add_action('wp_ajax_em_dismiss_network_admin_notice', 'EM_Admin_Notices::dismiss_admin_notice');
24
- }
25
- }
26
-
27
- /**
28
- * Adds an admin notice to the site. If $network is set to true, notice will be saved at network level.
29
- * If a string is provided as $EM_Admin_Notice, it will be considered as a notice requiring a hook to ouptut anything.
30
- * If a notice with an identical key is provided, it will overwrite the previously stored notice.
31
- * When adding a notice that all users will see and can dismiss, it's recommended you use a hook to build the EM_Admin_Notice object, to avoid storing unecessary data in the DB
32
- * @param EM_Admin_Notice|string $EM_Admin_Notice
33
- * @param boolean $network
34
- * @return boolean Returns true if added successfully, false if not or if the exact same record exists.
35
- */
36
- public static function add( $EM_Admin_Notice, $network = false ){
37
- $network = $network && is_multisite(); //make sure we are actually in multisite!
38
- if( is_string($EM_Admin_Notice) ){
39
- $EM_Admin_Notice = new EM_Admin_Notice( $EM_Admin_Notice );
40
- $hook_notice = true;
41
- }
42
- if( !$EM_Admin_Notice->name ) return false;
43
- //get options data
44
- $data = $network ? get_site_option('dbem_data') : get_option('dbem_data');
45
- $data = empty($data) ? array() : maybe_unserialize($data);
46
- if( !is_array($data)) $data = array();
47
- $notices_data = $network ? get_site_option('dbem_admin_notices') : get_option('dbem_admin_notices');
48
- $notices_data = empty($notices_data) ? array() : maybe_unserialize($notices_data);
49
- if( !is_array($notices_data)) $notices_data = array(); //we store the data regarldess of whether a message will require a hook, since it contains location and caps considtions
50
- //start building data
51
- $notices = !empty($data['admin_notices']) ? $data['admin_notices'] : array();
52
- $notices[$EM_Admin_Notice->name] = !empty($EM_Admin_Notice->when) ? $EM_Admin_Notice->when : 0;
53
- if( empty($hook_notice) ){ //we only skip this if simply a key is provided initially in $EM_Admin_Notice
54
- $notices_data[$EM_Admin_Notice->name] = $EM_Admin_Notice->to_array();
55
- }
56
- if( !empty($notices) ){
57
- $data['admin_notices'] = $notices;
58
- $update_notices = $network ? update_site_option('dbem_data', $data) : update_option('dbem_data', $data);
59
- $update_notices_data = true;
60
- if( !empty($notices_data) ){
61
- $update_notices_data = $network ? update_site_option('dbem_admin_notices', $notices_data) : update_option('dbem_admin_notices', $notices_data, false);
62
- }
63
- return $update_notices && $update_notices_data;
64
- }
65
- return false;
66
- }
67
-
68
- /**
69
- * Remove an admin notice. If $network is true, then a network-level admin notice will be removed.
70
- * @param string $notice_key
71
- * @param string $network
72
- * @return boolean Returns true if successfully deleted, false if there's an error or if there's nothing to delete.
73
- */
74
- public static function remove( $notice_key, $network = false ){
75
- $network = $network && is_multisite(); //make sure we are actually in multisite!
76
- $data = $network ? get_site_option('dbem_data') : get_option('dbem_data');
77
- if( !empty($data['admin_notices']) && isset($data['admin_notices'][$notice_key])){
78
- unset($data['admin_notices'][$notice_key]);
79
- if( empty($data['admin_notices']) ) unset($data['admin_notices']);
80
- $result = $update_notices_data = $network ? update_site_option('dbem_data', $data) : update_option('dbem_data', $data);
81
- $notices_data = $network ? get_site_option('dbem_admin_notices') : get_option('dbem_admin_notices');
82
- if( !empty($notices_data[$notice_key]) ){
83
- unset($notices_data[$notice_key]);
84
- if( empty($notices_data) ){
85
- $update_notices_data = $network ? delete_site_option('dbem_admin_notices') : delete_option('dbem_admin_notices');
86
- }else{
87
- $update_notices_data = $network ? update_site_option('dbem_admin_notices', $notices_data) : update_option('dbem_admin_notices', $notices_data, false);
88
- }
89
- }
90
- return $result && $update_notices_data;
91
- }
92
- return false;
93
- }
94
-
95
- /**
96
- * Adds admin notice to network rather than specific blog. Equivalent to self::add( $EM_Admin_Notice, true );
97
- * @see EM_Admin_Notices::add()
98
- */
99
- public static function network_add( $EM_Admin_Notice ){ return self::add( $EM_Admin_Notice, true ); }
100
-
101
- /**
102
- * Removes admin notice from network rather than specific blog. Equivalent to self::remove( $EM_Admin_Notice, true );
103
- * @see EM_Admin_Notices::remove()
104
- */
105
- public static function network_remove( $notice_key ){ return self::remove( $notice_key, true ); }
106
-
107
- /**
108
- * Output the admin notices we need to output now. If $network is true, MultiSite network messages will be output.
109
- * @param string $network
110
- */
111
- public static function admin_notices( $network = false ){
112
- $notices = array();
113
- $data = $network ? get_site_option('dbem_data') : get_option('dbem_data');
114
- $possible_notices = is_array($data) && !empty($data['admin_notices']) ? $data['admin_notices'] : array();
115
- //we may have something to show, so we make sure that there's something to show right now
116
- foreach( $possible_notices as $key => $val ){
117
- //to avoid extra loading etc. we weed out time-based notices that aren't triggered right now
118
- if( empty($val) || ($val > 0 && $val < time()) ){
119
- //we have a match, so we add this to $notices
120
- $notices[$key] = self::get_notice($key, $network);
121
- }
122
- }
123
- self::output( $notices, $network );
124
- }
125
-
126
- public static function get_notice( $key, $network = false ){
127
- //build notice object
128
- $notice_data = $network ? get_site_option('dbem_admin_notices') : get_option('dbem_admin_notices');
129
- if( empty($notice_data[$key]) || !is_array($notice_data[$key]) ){
130
- $notice = array('name'=>$key, 'network'=>$network);
131
- }else{
132
- $notice = $notice_data[$key];
133
- $notice['network'] = $network;
134
- }
135
- return new EM_Admin_Notice($notice);
136
- }
137
-
138
- /**
139
- * Outputs admin notices at network level, same as EM_Admin_Notices::admin_notices(true)
140
- * @see EM_Admin_Notices::admin_notices()
141
- */
142
- public static function network_admin_notices(){ self::admin_notices(true); }
143
-
144
- /**
145
- * Outputs admin notices and calls the dismissable JS to be output at footer of admin page.
146
- * If $network is true, only MultiSite network-level notices will be shown.
147
- * @param array $notices
148
- * @param boolean $network
149
- */
150
- public static function output( $notices, $network = false ){
151
- foreach( $notices as $EM_Admin_Notice ){
152
- //output the notice if meant to
153
- if( $EM_Admin_Notice->can_show() ){
154
- if( $EM_Admin_Notice->output() ) self::$js_footer = true;
155
- }
156
- }
157
- if( self::$js_footer ){
158
- add_action('admin_footer', 'EM_Admin_Notices::admin_footer');
159
- }
160
- }
161
-
162
- /**
163
- * If called via AJAX, the notice will be removed.
164
- */
165
- public static function dismiss_admin_notice(){
166
- if( empty($_REQUEST['notice']) ) return;
167
- $key = $_REQUEST['notice'];
168
- $network = $_REQUEST['action'] == 'em_dismiss_network_admin_notice';
169
- //get the notice
170
- $EM_Admin_Notice = self::get_notice($key, $network);
171
- if( $EM_Admin_Notice->is_user_notice() ){
172
- //user-specific notices are flagged on the user-level
173
- $user_id = get_current_user_id();
174
- $dismissed_notices = get_user_meta( $user_id, '_em_dismissed_notices', true);
175
- $dismissed_notices = is_array($dismissed_notices) ? $dismissed_notices : array();
176
- if( !in_array($EM_Admin_Notice->name, $dismissed_notices) ){
177
- $dismissed_notices[] = $EM_Admin_Notice->name;
178
- $result = update_user_meta( $user_id, '_em_dismissed_notices', $dismissed_notices);
179
- }
180
- }else{
181
- $result = self::remove($_REQUEST['notice'], $network);
182
- }
183
- echo !empty($result) ? 'Thou art dismissed!' : 'Thou shall not pass!';
184
- exit();
185
- }
186
-
187
- /**
188
- * Outputs JS for dismissing notices.
189
- */
190
- public static function admin_footer(){
191
- ?>
192
- <script type="text/javascript">
193
- jQuery(document).ready( function($){
194
- $('.em-admin-notice').on('click', 'button.notice-dismiss', function(e){
195
- var the_notice = $(this).closest('.em-admin-notice');
196
- $.get('<?php echo admin_url('admin-ajax.php'); ?>', {'action' : the_notice.data('dismiss-action'), 'notice' : the_notice.data('dismiss-key') });
197
- });
198
- });
199
- </script>
200
- <?php
201
- }
202
- }
203
- include('em-admin-notice.php');
204
- EM_Admin_Notices::init();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-booking.php DELETED
@@ -1,1310 +0,0 @@
1
- <?php
2
- /**
3
- * gets a booking in a more db-friendly manner, allows hooking into booking object right after instantiation
4
- * @param mixed $id
5
- * @param mixed $search_by
6
- * @return EM_Booking
7
- */
8
- function em_get_booking($id = false) {
9
- global $EM_Booking;
10
- //check if it's not already global so we don't instantiate again
11
- if( is_object($EM_Booking) && get_class($EM_Booking) == 'EM_Booking' ){
12
- if( is_object($id) && $EM_Booking->booking_id == $id->booking_id ){
13
- return apply_filters('em_get_booking', $EM_Booking);
14
- }else{
15
- if( is_numeric($id) && $EM_Booking->booking_id == $id ){
16
- return apply_filters('em_get_booking', $EM_Booking);
17
- }elseif( is_array($id) && !empty($id['booking_id']) && $EM_Booking->booking_id == $id['booking_id'] ){
18
- return apply_filters('em_get_booking', $EM_Booking);
19
- }
20
- }
21
- }
22
- if( is_object($id) && get_class($id) == 'EM_Booking' ){
23
- return apply_filters('em_get_booking', $id);
24
- }else{
25
- return apply_filters('em_get_booking', new EM_Booking($id));
26
- }
27
- }
28
- /**
29
- * Contains all information and relevant functions surrounding a single booking made with Events Manager
30
- * @property int|false $booking_status
31
- * @property string $language
32
- */
33
- class EM_Booking extends EM_Object{
34
- //DB Fields
35
- var $booking_id;
36
- var $event_id;
37
- var $person_id;
38
- var $booking_price = null;
39
- var $booking_spaces;
40
- var $booking_comment;
41
- protected $booking_status = false;
42
- var $booking_tax_rate = null;
43
- var $booking_taxes = null;
44
- var $booking_meta = array();
45
- var $fields = array(
46
- 'booking_id' => array('name'=>'id','type'=>'%d'),
47
- 'event_id' => array('name'=>'event_id','type'=>'%d'),
48
- 'person_id' => array('name'=>'person_id','type'=>'%d'),
49
- 'booking_price' => array('name'=>'price','type'=>'%f'),
50
- 'booking_spaces' => array('name'=>'spaces','type'=>'%d'),
51
- 'booking_comment' => array('name'=>'comment','type'=>'%s'),
52
- 'booking_status' => array('name'=>'status','type'=>'%d'),
53
- 'booking_tax_rate' => array('name'=>'tax_rate','type'=>'%f','null'=>1),
54
- 'booking_taxes' => array('name'=>'taxes','type'=>'%f','null'=>1),
55
- 'booking_meta' => array('name'=>'meta','type'=>'%s')
56
- );
57
- //Other Vars
58
- /**
59
- * array of notes by admins on this booking. loaded from em_meta table in construct
60
- * @var array
61
- */
62
- var $notes;
63
- /**
64
- * Deprecated as of 5.8.2, previously used to store timestamp of booking date. Use EM_Booking->date()->getTimestamp() instead.
65
- * @var int
66
- */
67
- private $timestamp;
68
- /**
69
- * The date of the booking, in UTC time, represented as a DATETIME mysql value.
70
- * @var string
71
- */
72
- protected $booking_date;
73
- /**
74
- * Contains the booking date in EM_DateTime object form.
75
- * @var EM_DateTime
76
- */
77
- protected $date;
78
- /**
79
- * @var EM_Person
80
- */
81
- var $person;
82
- var $required_fields = array('booking_id', 'event_id', 'person_id', 'booking_spaces');
83
- var $feedback_message = "";
84
- var $errors = array();
85
- /**
86
- * when using EM_Booking::email_send(), this number is updated with sent emails
87
- * @var int
88
- */
89
- var $mails_sent = 0;
90
- /**
91
- * Contains an array of custom fields for a booking. This is loaded from em_meta, where the booking_custom name contains arrays of data.
92
- * @var array
93
- */
94
- var $custom = array();
95
- /**
96
- * If saved in this instance, you can see what previous approval status was.
97
- * @var int
98
- */
99
- var $previous_status = false;
100
- /**
101
- * The booking approval status number corresponds to a state in this array.
102
- * @var array
103
- */
104
- var $status_array = array();
105
- /**
106
- * @var EM_Tickets
107
- */
108
- var $tickets;
109
- /**
110
- * @var EM_Event
111
- */
112
- var $event;
113
- /**
114
- * @var EM_Tickets_Bookings
115
- */
116
- var $tickets_bookings;
117
- /**
118
- * If set to true, this booking can be managed by any logged in user.
119
- * @var EM_Tickets_Bookings
120
- */
121
- var $manage_override;
122
-
123
- /**
124
- * Creates booking object and retrieves booking data (default is a blank booking object). Accepts either array of booking data (from db) or a booking id.
125
- * @param mixed $booking_data
126
- * @return null
127
- */
128
- function __construct( $booking_data = false ){
129
- //Get the person for this booking
130
- global $wpdb;
131
- if( $booking_data !== false ){
132
- //Load booking data
133
- $booking = array();
134
- if( is_array($booking_data) ){
135
- $booking = $booking_data;
136
- }elseif( is_numeric($booking_data) ){
137
- //Retrieving from the database
138
- $sql = $wpdb->prepare("SELECT * FROM ". EM_BOOKINGS_TABLE ." WHERE booking_id =%d", $booking_data);
139
- $booking = $wpdb->get_row($sql, ARRAY_A);
140
- }
141
- //booking meta
142
- $booking['booking_meta'] = (!empty($booking['booking_meta'])) ? maybe_unserialize($booking['booking_meta']):array();
143
- //Save into the object
144
- $this->to_object($booking);
145
- $this->previous_status = $this->booking_status;
146
- $this->get_person();
147
- $this->booking_date = !empty($booking['booking_date']) ? $booking['booking_date']:false;
148
- }
149
- //Do it here so things appear in the po file.
150
- $this->status_array = array(
151
- 0 => __('Pending','events-manager'),
152
- 1 => __('Approved','events-manager'),
153
- 2 => __('Rejected','events-manager'),
154
- 3 => __('Cancelled','events-manager'),
155
- 4 => __('Awaiting Online Payment','events-manager'),
156
- 5 => __('Awaiting Payment','events-manager')
157
- );
158
- $this->compat_keys(); //depricating in 6.0
159
- //do some legacy checking here for bookings made prior to 5.4, due to how taxes are calculated
160
- $this->get_tax_rate();
161
- if( !empty($this->legacy_tax_rate) ){
162
- //reset booking_price, it'll be recalculated later (if you're using this property directly, don't use $this->get_price())
163
- $this->booking_price = $this->booking_taxes = null;
164
- }
165
- do_action('em_booking', $this, $booking_data);
166
- }
167
-
168
-
169
- function __get( $var ){
170
- //get the modified or created date from the DB only if requested, and save to object
171
- if( $var == 'timestamp' ){
172
- if( $this->date() === false ) return 0;
173
- return $this->date()->getTimestampWithOffset();
174
- }elseif( $var == 'language' ){
175
- if( !empty($this->booking_meta['lang']) ){
176
- return $this->booking_meta['lang'];
177
- }
178
- }elseif( $var == 'booking_status' ){
179
- return ($this->booking_status == 0 && !get_option('dbem_bookings_approval') ) ? 1:$this->booking_status;
180
- }
181
- return null;
182
- }
183
-
184
- public function __set( $prop, $val ){
185
- if( $prop == 'timestamp' ){
186
- if( $this->date() !== false ) $this->date()->setTimestamp($val);
187
- }elseif( $prop == 'language' ){
188
- $this->booking_meta['lang'] = $val;
189
- }else{
190
- $this->$prop = $val;
191
- }
192
- }
193
-
194
- public function __isset( $prop ){
195
- if( $prop == 'timestamp' ) return $this->date()->getTimestamp() > 0;
196
- if( $prop == 'language' ) return !empty($this->booking_meta['lang']);
197
- return parent::__isset( $prop );
198
- }
199
-
200
- function get_notes(){
201
- global $wpdb;
202
- if( !is_array($this->notes) && !empty($this->booking_id) ){
203
- $notes = $wpdb->get_results("SELECT * FROM ". EM_META_TABLE ." WHERE meta_key='booking-note' AND object_id ='{$this->booking_id}'", ARRAY_A);
204
- $this->notes = array();
205
- foreach($notes as $note){
206
- $this->notes[] = unserialize($note['meta_value']);
207
- }
208
- }elseif( empty($this->booking_id) ){
209
- $this->notes = array();
210
- }
211
- return $this->notes;
212
- }
213
-
214
- /**
215
- * Saves the booking into the database, whether a new or existing booking
216
- * @param bool $mail whether or not to email the user and contact people
217
- * @return boolean
218
- */
219
- function save($mail = true){
220
- global $wpdb;
221
- $table = EM_BOOKINGS_TABLE;
222
- do_action('em_booking_save_pre',$this);
223
- if( $this->can_manage() ){
224
- //update prices, spaces, person_id
225
- $this->get_spaces(true);
226
- $this->calculate_price();
227
- $this->person_id = (empty($this->person_id)) ? $this->get_person()->ID : $this->person_id;
228
- //Step 1. Save the booking
229
- $data = $this->to_array();
230
- $data['booking_meta'] = serialize($data['booking_meta']);
231
- //update or save
232
- if($this->booking_id != ''){
233
- $update = true;
234
- $where = array( 'booking_id' => $this->booking_id );
235
- $result = $wpdb->update($table, $data, $where, $this->get_types($data));
236
- $result = ($result !== false);
237
- $this->feedback_message = __('Changes saved','events-manager');
238
- }else{
239
- $update = false;
240
- $data_types = $this->get_types($data);
241
- $data['booking_date'] = $this->booking_date = gmdate('Y-m-d H:i:s');
242
- $data_types[] = '%s';
243
- $result = $wpdb->insert($table, $data, $data_types);
244
- $this->booking_id = $wpdb->insert_id;
245
- $this->feedback_message = __('Your booking has been recorded','events-manager');
246
- }
247
- //Step 2. Insert ticket bookings for this booking id if no errors so far
248
- if( $result === false ){
249
- $this->feedback_message = __('There was a problem saving the booking.', 'events-manager');
250
- $this->errors[] = __('There was a problem saving the booking.', 'events-manager');
251
- }else{
252
- $tickets_bookings_result = $this->get_tickets_bookings()->save();
253
- if( !$tickets_bookings_result ){
254
- if( !$update ){
255
- //delete the booking and tickets, instead of a transaction
256
- $this->delete();
257
- }
258
- $this->errors[] = __('There was a problem saving the booking.', 'events-manager');
259
- $this->add_error( $this->get_tickets_bookings()->get_errors() );
260
- }
261
- }
262
- // Step 3. Run filter for return value before sending emails
263
- $this->compat_keys();
264
- $return = apply_filters('em_booking_save', ( count($this->errors) == 0 ), $this, $update);
265
- //Final Step: email if necessary after all the saving has been done
266
- if ( count($this->errors) == 0 && $mail ) {
267
- $this->email();
268
- }
269
- return $return;
270
- }else{
271
- $this->feedback_message = __('There was a problem saving the booking.', 'events-manager');
272
- if( !$this->can_manage() ){
273
- $this->add_error(sprintf(__('You cannot manage this %s.', 'events-manager'),__('Booking','events-manager')));
274
- }
275
- }
276
- return apply_filters('em_booking_save', false, $this, false);
277
- }
278
-
279
- /**
280
- * Load a record into this object by passing an associative array of table criteria to search for.
281
- * Returns boolean depending on whether a record is found or not.
282
- * @param $search
283
- * @return boolean
284
- */
285
- function get($search) {
286
- global $wpdb;
287
- $conds = array();
288
- foreach($search as $key => $value) {
289
- if( array_key_exists($key, $this->fields) ){
290
- $value = esc_sql($value);
291
- $conds[] = "`$key`='$value'";
292
- }
293
- }
294
- $sql = "SELECT * FROM ". EM_BOOKINGS_TABLE ." WHERE " . implode(' AND ', $conds) ;
295
- $result = $wpdb->get_row($sql, ARRAY_A);
296
- if($result){
297
- $this->to_object($result);
298
- $this->person = new EM_Person($this->person_id);
299
- return true;
300
- }else{
301
- return false;
302
- }
303
- }
304
-
305
- /**
306
- * Get posted data and save it into the object (not db)
307
- * @return boolean
308
- */
309
- function get_post( $override_availability = false ){
310
- $this->tickets_bookings = new EM_Tickets_Bookings($this->booking_id);
311
- do_action('em_booking_get_post_pre',$this);
312
- $result = array();
313
- $this->event_id = absint($_REQUEST['event_id']);
314
- if( isset($_REQUEST['em_tickets']) && is_array($_REQUEST['em_tickets']) && ($_REQUEST['em_tickets'] || $override_availability) ){
315
- foreach( $_REQUEST['em_tickets'] as $ticket_id => $values){
316
- //make sure ticket exists
317
- $ticket_id = absint($ticket_id);
318
- if( !empty($values['spaces']) || $override_availability ){
319
- $args = array('ticket_id'=>$ticket_id, 'ticket_booking_spaces'=> absint($values['spaces']), 'booking_id'=>$this->booking_id);
320
- if($this->get_event()->get_bookings()->ticket_exists($ticket_id)){
321
- $EM_Ticket_Booking = new EM_Ticket_Booking($args);
322
- $EM_Ticket_Booking->booking = $this;
323
- if( !$this->tickets_bookings->add( $EM_Ticket_Booking, $override_availability ) ){
324
- $this->add_error($this->tickets_bookings->get_errors());
325
- }
326
- }else{
327
- $this->errors[]=__('You are trying to book a non-existent ticket for this event.','events-manager');
328
- }
329
- }
330
- }
331
- $this->booking_comment = (!empty($_REQUEST['booking_comment'])) ? wp_kses_data(wp_unslash($_REQUEST['booking_comment'])):'';
332
- //allow editing of tax rate
333
- if( !empty($this->booking_id) && $this->can_manage() ){
334
- $this->booking_tax_rate = (!empty($_REQUEST['booking_tax_rate']) && is_numeric($_REQUEST['booking_tax_rate'])) ? $_REQUEST['booking_tax_rate']:$this->booking_tax_rate;
335
- }
336
- //recalculate spaces/price
337
- $this->get_spaces(true);
338
- $this->calculate_price();
339
- //get person
340
- $this->get_person();
341
- //re-run compatiblity keys function
342
- $this->compat_keys(); //depracating in 6.0
343
- }
344
- return apply_filters('em_booking_get_post',count($this->errors) == 0,$this);
345
- }
346
-
347
- function validate( $override_availability = false ){
348
- //step 1, basic info
349
- $basic = (
350
- (empty($this->event_id) || is_numeric($this->event_id)) &&
351
- (empty($this->person_id) || is_numeric($this->person_id)) &&
352
- is_numeric($this->booking_spaces) && $this->booking_spaces > 0
353
- );
354
- //give some errors in step 1
355
- if( $this->booking_spaces == 0 ){
356
- $this->add_error(get_option('dbem_booking_feedback_min_space'));
357
- }
358
- //step 2, tickets bookings info
359
- if( count($this->get_tickets_bookings()) > 0 ){
360
- $ticket_validation = array();
361
- foreach($this->get_tickets_bookings()->tickets_bookings as $EM_Ticket_Booking){ /* @var $EM_Ticket_Booking EM_Ticket_Booking */
362
- if ( !$EM_Ticket_Booking->validate() ){
363
- $ticket_validation[] = false;
364
- $result = $basic && !in_array(false,$ticket_validation);
365
- }
366
- $this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
367
- }
368
- $result = $basic && !in_array(false,$ticket_validation);
369
- }else{
370
- $result = false;
371
- }
372
- //is there enough space overall?
373
- if( !$override_availability && $this->get_event()->get_bookings()->get_available_spaces() < $this->get_spaces() ){
374
- $result = false;
375
- $this->add_error(get_option('dbem_booking_feedback_full'));
376
- }
377
- //can we book this amount of spaces at once?
378
- if( $this->get_event()->event_rsvp_spaces > 0 && $this->get_spaces() > $this->get_event()->event_rsvp_spaces ){
379
- $result = false;
380
- $this->add_error( sprintf(get_option('dbem_booking_feedback_spaces_limit'), $this->get_event()->event_rsvp_spaces));
381
- }
382
- return apply_filters('em_booking_validate',$result,$this);
383
- }
384
-
385
- /**
386
- * Get the total number of spaces booked in THIS booking. Setting $force_refresh to true will recheck spaces, even if previously done so.
387
- * @param boolean $force_refresh
388
- * @return int
389
- */
390
- function get_spaces( $force_refresh=false ){
391
- if($this->booking_spaces == 0 || $force_refresh == true ){
392
- $this->booking_spaces = $this->get_tickets_bookings()->get_spaces($force_refresh);
393
- }
394
- return apply_filters('em_booking_get_spaces',$this->booking_spaces,$this);
395
- }
396
-
397
- /* Price Calculations */
398
-
399
- /**
400
- * Gets the total price for this whole booking, including any discounts, taxes, and any other additional items. In other words, what the person has to pay or has supposedly paid.
401
- * This price shouldn't change once established, unless there's any alteration to the booking itself that'd affect the price, such as a change in ticket numbers, discount, etc.
402
- * @param boolean $format
403
- * @return double|string
404
- */
405
- function get_price( $format = false, $format_depricated = null ){
406
- if( $format_depricated !== null ) $format = $format_depricated; //support for old parameters, will be depricated soon
407
- //recalculate price here only if price is not actually set
408
- if( $this->booking_price === null ){
409
- $this->calculate_price();
410
- /* Deprecated filter - Equivalent of em_booking_calculate_price, please use that instead */
411
- $this->booking_price = apply_filters('em_booking_get_price', $this->booking_price, $this);
412
- }
413
- //return booking_price, formatted or not
414
- if($format){
415
- return $this->format_price($this->booking_price);
416
- }
417
- return round($this->booking_price,2);
418
- }
419
-
420
- /**
421
- * Total of tickets without taxes, discounts or any other modification. No filter given here for that very reason!
422
- * @param boolean $format
423
- * @return double|string
424
- */
425
- function get_price_base( $format = false ){
426
- $price = apply_filters('em_booking_get_price_base', $this->get_tickets_bookings()->get_price(), $this);
427
- if($format){
428
- return $this->format_price($price);
429
- }
430
- return $price;
431
- }
432
-
433
- function get_price_pre_taxes( $format = false, $include_adjustments = true ){
434
- $price = $base_price = $this->get_price_base();
435
- //apply pre-tax discounts
436
- if( $include_adjustments ){
437
- $price -= $this->get_price_adjustments_amount('discounts', 'pre', $base_price);
438
- $price += $this->get_price_adjustments_amount('surcharges', 'pre', $base_price);
439
- }
440
- $price = apply_filters('em_booking_get_price_pre_taxes', $price, $base_price, $this, $include_adjustments);
441
- if( $price < 0 ){ $price = 0; } //no negative prices
442
- //return amount of taxes applied, formatted or not
443
- if( $format ) return $this->format_price($price);
444
- return $price;
445
- }
446
-
447
- /**
448
- * Gets price AFTER taxes and (optionally) post-tax discounts and surcharges have also been added.
449
- * @param boolean $format
450
- * @param boolean $include_adjustments If set to true discounts and surcharges won't be applied to the overall price.
451
- * @return double|string
452
- */
453
- function get_price_post_taxes( $format = false, $include_adjustments = true ){
454
- //get price before taxes
455
- $price = $this->get_price_pre_taxes( false, $include_adjustments );
456
- //add taxes to price
457
- if( $this->get_tax_rate() > 0 ){
458
- $this->booking_taxes = $price * ($this->get_tax_rate()/100); //calculate and save tax amount
459
- $price += $this->booking_taxes; //add taxes
460
- $this->taxes_applied = true;
461
- }
462
- //apply post-tax discounts
463
- $price_after_taxes = $price;
464
- if( $include_adjustments ){
465
- $price -= $this->get_price_adjustments_amount('discounts', 'post', $price_after_taxes);
466
- $price += $this->get_price_adjustments_amount('surcharges', 'post', $price_after_taxes);
467
- }
468
- $price = apply_filters('em_booking_get_price_post_taxes', $price, $price_after_taxes, $this, $include_adjustments);
469
- if( $price < 0 ){ $price = 0; } //no negative prices
470
- //return amount of taxes applied, formatted or not
471
- if( $format ) return $this->format_price($price);
472
- return $price;
473
- }
474
-
475
- /**
476
- * Get amount of taxes applied to this booking price.
477
- * @param boolean $format
478
- * @return double|string
479
- */
480
- function get_price_taxes( $format=false ){
481
- if( $this->booking_taxes !== null ){
482
- $this->booking_taxes; //taxes already calculated
483
- }else{
484
- $this->calculate_price(); //recalculate price and taxes
485
- }
486
- //return amount of taxes applied, formatted or not
487
- if( $format ){
488
- return $this->format_price($this->booking_taxes);
489
- }
490
- return $this->booking_taxes;
491
- }
492
-
493
- /**
494
- * Calculates (or recalculates) the price of this booking including taxes, discounts etc., saves it to the booking_price property and writes to relevant properties booking_meta variables
495
- * @return double
496
- */
497
- function calculate_price(){
498
- //any programatic price adjustments should be added here, otherwise you need to run this function again
499
- do_action('em_booking_pre_calculate_price', $this);
500
- //reset price and taxes calculations
501
- $this->booking_price = $this->booking_taxes = null;
502
- //get post-tax price and save it to booking_price
503
- $this->booking_price = apply_filters('em_booking_calculate_price', $this->get_price_post_taxes(), $this);
504
- return $this->booking_price;
505
- }
506
-
507
- /*
508
- * Gets tax rate of booking
509
- * @see EM_Object::get_tax_rate()
510
- */
511
- function get_tax_rate( $decimal = false ){
512
- if( $this->booking_tax_rate === null ){
513
- //booking not saved or tax never defined
514
- if( !empty($this->booking_id) && get_option('dbem_legacy_bookings_tax', 'x') !== 'x'){ //even if 0 if defined as tax rate we still use it, delete the option entirely to stop
515
- //no tax applied yet to an existing booking, or tax possibly applied (but handled separately in EM_Tickets_Bookings but in legacy < v5.4
516
- //sort out MultiSite nuances
517
- if( EM_MS_GLOBAL && $this->get_event()->blog_id != get_current_blog_id() ){
518
- //MultiSite AND Global tables enabled AND this event belongs to another blog - get settings for blog that published the event
519
- $this->booking_tax_rate = get_blog_option($this->get_event()->blog_id, 'dbem_legacy_bookings_tax');
520
- }else{
521
- //get booking from current site, whether or not we're in MultiSite
522
- $this->booking_tax_rate = get_option('dbem_legacy_bookings_tax');
523
- }
524
- $this->legacy_tax_rate = true;
525
- }else{
526
- //first time we're applying tax rate
527
- $this->booking_tax_rate = $this->get_event()->get_tax_rate();
528
- }
529
- }
530
- $this->booking_tax_rate = $this->booking_tax_rate > 0 ? $this->booking_tax_rate : 0;
531
- $this->booking_tax_rate = apply_filters('em_booking_get_tax_rate', $this->booking_tax_rate, $this);
532
- if( $this->booking_tax_rate > 0 && $decimal ){
533
- return $this->booking_tax_rate / 100;
534
- }else{
535
- return $this->booking_tax_rate;
536
- }
537
- }
538
-
539
- /* START Price Adjustment Functions */
540
- //now we can use one function for both discounts and surcharges, the three functions below are now deprecated.
541
- /**
542
- * DEPRECATED. Use $this->get_price_adjustments('discounts'); instead.
543
- */
544
- function get_price_discounts(){
545
- return apply_filters('em_booking_get_price_discounts', $this->get_price_adjustments('discounts'), $this);
546
- }
547
- /**
548
- * DEPRECATED - Use $this->get_price_adjustments_amount('discounts', $pre_or_post, $price); instead.
549
- */
550
- function get_price_discounts_amount( $pre_or_post = 'pre', $price = false ){
551
- return $this->get_price_adjustments_amount( 'discounts', $pre_or_post, $price );
552
- }
553
- /**
554
- * DEPRECATED - Use get_price_discounts_summary('discounts', $pre_or_post, $price); instead.
555
- */
556
- function get_price_discounts_summary( $pre_or_post = 'pre', $price = false ){
557
- return $this->get_price_adjustments_summary( 'discounts', $pre_or_post, $price );
558
- }
559
-
560
- /**
561
- * Returns an array of discounts to be applied to a booking. Here is an example of an array item that is expected:
562
- * array('name' => 'Name of Discount', 'type'=>'% or #', 'amount'=> 0.00, 'desc' => 'Comments about discount', 'tax'=>'pre/post', 'data' => 'any info for hooks to use' );
563
- * About the array keys:
564
- * type - # means a fixed amount of discount, % means a percentage off the base price
565
- * amount - if type is a percentage, it is written as a number from 0-100, e.g. 10 = 10%
566
- * tax - 'pre' means discount is applied before tax, 'post' means after tax
567
- * data - any data to be stored that can be used by actions/filters
568
- * @param string $type The type of adjustment you would like to retrieve. This would normally be 'discounts' or 'surcharges'.
569
- * @return array
570
- */
571
- function get_price_adjustments( $type ){
572
- $adjustments = array();
573
- if( !empty($this->booking_meta[$type]) && is_array($this->booking_meta[$type]) ){
574
- $adjustments = $this->booking_meta[$type];
575
- }
576
- //run this filter to be backwards compatible, e.g. em_booking_get_price_discount
577
- if( $type == 'discounts' ){
578
- $adjustments = apply_filters('em_booking_get_price_discounts', $adjustments, $this);
579
- }
580
- return apply_filters('em_booking_get_price_adjustments', $adjustments, $type, $this);
581
- }
582
-
583
- /**
584
- * Returns a numerical amount to adjust the price by, in the context of a certain type and before or after taxes.
585
- * This will be a positive number whether or not this is to be added or subtracted from the price.
586
- * @param string $type The type of adjustment to get, which would normally be 'discounts' or 'surcharges'
587
- * @param string $pre_or_post Adjustments limited to 'pre' (before), 'post' (after) taxes or 'both'
588
- * @param float $price Price relative to be adjusted.
589
- * @return float
590
- */
591
- function get_price_adjustments_amount( $type, $pre_or_post = 'both', $price = false ){
592
- $adjustments = $this->get_price_adjustments_summary($type, $pre_or_post, $price);
593
- $adjustment_amount = 0;
594
- foreach($adjustments as $adjustment){
595
- $adjustment_amount += $adjustment['amount_adjusted'];
596
- }
597
- return $adjustment_amount;
598
- }
599
-
600
- /**
601
- * Provides an array summary of adjustments to make to the price, in the context of a certain type and before or after taxes.
602
- * @param string $type The type of adjustment to get, which would normally be 'discounts' or 'surcharges'
603
- * @param string $pre_or_post Adjustments limited to 'pre' (before), 'post' (after) taxes or 'both'
604
- * @param float $price Price to calculate relative to adjustments. If not supplied or if $pre_or_post is 'both', price is automatically obtained from booking instance according to pre/post taxes requirement.
605
- * @return array
606
- */
607
- function get_price_adjustments_summary( $type, $pre_or_post = 'both', $price = false ){
608
- if( $pre_or_post == 'both' ){
609
- $adjustment_summary_pre = $this->get_price_adjustments_summary($type, 'pre');
610
- $adjustment_summary_post = $this->get_price_adjustments_summary($type, 'post');
611
- return $adjustment_summary = array_merge($adjustment_summary_pre, $adjustment_summary_post);
612
- }
613
- $adjustments = $this->get_price_adjustments($type);
614
- $adjustment_summary = array();
615
- if( $price === false ){
616
- if( $pre_or_post == 'post' ){
617
- $price = $this->get_price_pre_taxes() + $this->get_price_taxes();
618
- }else{
619
- $price = $this->get_price_base();
620
- }
621
- }
622
- foreach($adjustments as $adjustment){
623
- $adjustment_amount = 0;
624
- if( !empty($adjustment['amount']) ){
625
- if( !empty($adjustment['tax']) && $adjustment['tax'] == $pre_or_post ){
626
- if( !empty($adjustment['type']) ){
627
- $adjustment_summary_item = array('name' => $adjustment['name'], 'desc' => $adjustment['desc'], 'adjustment'=>'0', 'amount_adjusted'=>0, 'tax'=>$pre_or_post);
628
- if( $adjustment['type'] == '%' ){ //adjustment by percentage
629
- $adjustment_summary_item['amount_adjusted'] = round($price * ($adjustment['amount']/100),2);
630
- $adjustment_summary_item['amount'] = $this->format_price($adjustment_summary_item['amount_adjusted']);
631
- $adjustment_summary_item['adjustment'] = number_format($adjustment['amount'],2).'%';
632
- $adjustment_summary[] = $adjustment_summary_item;
633
- }elseif( $adjustment['type'] == '#' ){ //adjustment by amount
634
- $adjustment_summary_item['amount_adjusted'] = round($adjustment['amount'],2);
635
- $adjustment_summary_item['amount'] = $this->format_price($adjustment_summary_item['amount_adjusted']);
636
- $adjustment_summary_item['adjustment'] = $this->format_price($adjustment['amount']);
637
- $adjustment_summary[] = $adjustment_summary_item;
638
- }
639
- }
640
- }
641
- }
642
- }
643
- return $adjustment_summary;
644
- }
645
- /* END Price Adjustment Functions */
646
-
647
- /**
648
- * When generating totals at the bottom of a booking, this creates a useful array for displaying the summary in a meaningful way.
649
- */
650
- function get_price_summary_array(){
651
- $summary = array();
652
- //get base price of bookings
653
- $summary['total_base'] = $this->get_price_base();
654
- //apply pre-tax discounts
655
- $summary['discounts_pre_tax'] = $this->get_price_adjustments_summary('discounts', 'pre');
656
- $summary['surcharges_pre_tax'] = $this->get_price_adjustments_summary('surcharges', 'pre');
657
- //add taxes to price
658
- $summary['taxes'] = array('rate'=> 0, 'amount'=> 0);
659
- if( $this->get_price_taxes() > 0 ){
660
- $summary['taxes'] = array('rate'=> number_format($this->get_tax_rate(),2, get_option('dbem_bookings_currency_decimal_point'), get_option('dbem_bookings_currency_thousands_sep')).'%', 'amount'=> $this->get_price_taxes(true));
661
- }
662
- //apply post-tax discounts
663
- $summary['discounts_post_tax'] = $this->get_price_adjustments_summary('discounts', 'post');
664
- $summary['surcharges_post_tax'] = $this->get_price_adjustments_summary('surcharges', 'post');
665
- //final price
666
- $summary['total'] = $this->get_price(true);
667
- return $summary;
668
- }
669
-
670
- /**
671
- * Returns the amount paid for this booking. By default, a booking is considered either paid in full or not at all depending on whether the booking is confirmed or not.
672
- * @param boolean $format If set to true a currency-formatted string value is returned
673
- * @return string|float
674
- */
675
- function get_total_paid( $format = false ){
676
- $status = ($this->booking_status == 0 && !get_option('dbem_bookings_approval') ) ? 1:$this->booking_status;
677
- $total = $status ? $this->get_price() : 0;
678
- $total = apply_filters('em_booking_get_total_paid', $total, $this);
679
- if( $format ){
680
- return $this->format_price($total);
681
- }
682
- return $total;
683
- }
684
-
685
-
686
- /* Get Objects linked to booking */
687
-
688
- /**
689
- * Gets the event this booking belongs to and saves a reference in the event property
690
- * @return EM_Event
691
- */
692
- function get_event(){
693
- global $EM_Event;
694
- if( is_object($this->event) && get_class($this->event)=='EM_Event' && $this->event->event_id == $this->event_id ){
695
- return $this->event;
696
- }elseif( is_object($EM_Event) && $EM_Event->event_id == $this->event_id ){
697
- $this->event = $EM_Event;
698
- }else{
699
- $this->event = em_get_event($this->event_id, 'event_id');
700
- }
701
- return apply_filters('em_booking_get_event', $this->event, $this);
702
- }
703
-
704
- /**
705
- * Gets the ticket object this booking belongs to, saves a reference in ticket property
706
- * @return EM_Tickets
707
- */
708
- function get_tickets(){
709
- if( is_object($this->tickets) && get_class($this->tickets)=='EM_Tickets' ){
710
- return apply_filters('em_booking_get_tickets', $this->tickets, $this);
711
- }else{
712
- $this->tickets = new EM_Tickets($this);
713
- }
714
- return apply_filters('em_booking_get_tickets', $this->tickets, $this);
715
- }
716
-
717
- /**
718
- * Gets the ticket object this booking belongs to, saves a reference in ticket property
719
- * @return EM_Tickets_Bookings
720
- */
721
- function get_tickets_bookings(){
722
- global $wpdb;
723
- if( !is_object($this->tickets_bookings) || get_class($this->tickets_bookings)!='EM_Tickets_Bookings'){
724
- $this->tickets_bookings = new EM_Tickets_Bookings($this);
725
- }
726
- return apply_filters('em_booking_get_tickets_bookings', $this->tickets_bookings, $this);
727
- }
728
-
729
- /**
730
- * @return EM_Person
731
- */
732
- function get_person(){
733
- global $EM_Person;
734
- if( is_object($this->person) && get_class($this->person)=='EM_Person' && ($this->person->ID == $this->person_id || empty($this->person_id) ) ){
735
- //This person is already included, so don't do anything
736
- }elseif( is_object($EM_Person) && ($EM_Person->ID === $this->person_id || $this->booking_id == '') ){
737
- $this->person = $EM_Person;
738
- $this->person_id = $this->person->ID;
739
- }elseif( is_numeric($this->person_id) ){
740
- $this->person = new EM_Person($this->person_id);
741
- }else{
742
- $this->person = new EM_Person(0);
743
- $this->person_id = $this->person->ID;
744
- }
745
- //if this user is the parent user of disabled registrations, replace user details here:
746
- if( $this->person->ID === 0 && (empty($this->person->loaded_no_user) || $this->person->loaded_no_user != $this->booking_id) ){
747
- //override any registration data into the person objet
748
- if( !empty($this->booking_meta['registration']) ){
749
- foreach($this->booking_meta['registration'] as $key => $value){
750
- $this->person->$key = $value;
751
- }
752
- }
753
- $this->person->user_email = ( !empty($this->booking_meta['registration']['user_email']) ) ? $this->booking_meta['registration']['user_email']:$this->person->user_email;
754
- //if a full name is given, overwrite the first/last name values IF they are also not defined
755
- if( !empty($this->booking_meta['registration']['user_name']) ){
756
- if( !empty($this->booking_meta['registration']['first_name']) ){
757
- //first name is defined, so we remove it from full name in case we need the rest for surname
758
- $last_name = trim(str_replace($this->booking_meta['registration']['first_name'], '', $this->booking_meta['registration']['user_name']));
759
- //if last name isn't defined, provide the rest of the name minus the first name we just removed
760
- if( empty($this->booking_meta['registration']['last_name']) ){
761
- $this->booking_meta['registration']['last_name'] = $last_name;
762
- }
763
- }else{
764
- //no first name defined, check for last name and act accordingly
765
- if( !empty($this->booking_meta['registration']['last_name']) ){
766
- //we do opposite of above, remove last name from full name and use the rest as first name
767
- $first_name = trim(str_replace($this->booking_meta['registration']['last_name'], '', $this->booking_meta['registration']['user_name']));
768
- $this->booking_meta['registration']['first_name'] = $first_name;
769
- }else{
770
- //no defined first or last name, so we use the name and take first string for first name, second part for surname
771
- $name_string = explode(' ',$this->booking_meta['registration']['user_name']);
772
- $this->booking_meta['registration']['first_name'] = array_shift($name_string);
773
- $this->booking_meta['registration']['last_name'] = implode(' ', $name_string);
774
- }
775
- }
776
- }
777
- $this->person->user_firstname = ( !empty($this->booking_meta['registration']['first_name']) ) ? $this->booking_meta['registration']['first_name']:__('Guest User','events-manager');
778
- $this->person->first_name = $this->person->user_firstname;
779
- $this->person->user_lastname = ( !empty($this->booking_meta['registration']['last_name']) ) ? $this->booking_meta['registration']['last_name']:'';
780
- $this->person->last_name = $this->person->user_lastname;
781
- $this->person->phone = ( !empty($this->booking_meta['registration']['dbem_phone']) ) ? $this->booking_meta['registration']['dbem_phone']:__('Not Supplied','events-manager');
782
- //build display name
783
- $full_name = $this->person->user_firstname . " " . $this->person->user_lastname ;
784
- $full_name = trim($full_name);
785
- $display_name = ( empty($full_name) ) ? __('Guest User','events-manager'):$full_name;
786
- $this->person->display_name = $display_name;
787
- $this->person->loaded_no_user = $this->booking_id;
788
- }
789
- return apply_filters('em_booking_get_person', $this->person, $this);
790
- }
791
-
792
- /**
793
- * Gets personal information from the $_REQUEST array and saves it to the $EM_Booking->booking_meta['registration'] array
794
- * @return boolean
795
- */
796
- function get_person_post(){
797
- $user_data = array();
798
- $registration = true;
799
- if( empty($this->booking_meta['registration']) ) $this->booking_meta['registration'] = array();
800
- // Check the e-mail address
801
- $user_email = trim(wp_unslash($_REQUEST['user_email'])); //apostrophes will not be allowed otherwise
802
- if ( $user_email == '' ) {
803
- $registration = false;
804
- $this->add_error(__( '<strong>ERROR</strong>: Please type your e-mail address.', 'events-manager') );
805
- } elseif ( !is_email( $user_email ) ) {
806
- $registration = false;
807
- $this->add_error( __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.', 'events-manager') );
808
- }elseif(email_exists( $user_email ) && !get_option('dbem_bookings_registration_disable_user_emails') ){
809
- $registration = false;
810
- $this->add_error( get_option('dbem_booking_feedback_email_exists') );
811
- }else{
812
- $user_data['user_email'] = $user_email;
813
- }
814
- //Check the user name
815
- if( !empty($_REQUEST['user_name']) ){
816
- //split full name up and save full, first and last names
817
- $user_data['user_name'] = wp_kses(wp_unslash($_REQUEST['user_name']), array());
818
- $name_string = explode(' ',$user_data['user_name']);
819
- $user_data['first_name'] = array_shift($name_string);
820
- $user_data['last_name'] = implode(' ', $name_string);
821
- }else{
822
- //Check the first/last name
823
- $name_string = array();
824
- if( !empty($_REQUEST['first_name']) ){
825
- $user_data['first_name'] = $name_string[] = wp_kses(wp_unslash($_REQUEST['first_name']), array());
826
- }
827
- if( !empty($_REQUEST['last_name']) ){
828
- $user_data['last_name'] = $name_string[] = wp_kses(wp_unslash($_REQUEST['last_name']), array());
829
- }
830
- if( !empty($name_string) ) $user_data['user_name'] = implode(' ', $name_string);
831
- }
832
- //Check the phone
833
- if( !empty($_REQUEST['dbem_phone']) ){
834
- $user_data['dbem_phone'] = wp_kses(wp_unslash($_REQUEST['dbem_phone']), array());
835
- }
836
- //Add booking meta
837
- if( $registration ){
838
- $this->booking_meta['registration'] = array_merge($this->booking_meta['registration'], $user_data); //in case someone else added stuff
839
- }
840
- $registration = apply_filters('em_booking_get_person_post', $registration, $this);
841
- if( $registration ){
842
- $this->feedback_message = __('Personal details have successfully been modified.', 'events-manager');
843
- }
844
- return $registration;
845
- }
846
-
847
- /**
848
- * Displays a form containing user fields, used in no-user booking mode for editing guest users within a booking
849
- * @return string
850
- */
851
- function get_person_editor(){
852
- ob_start();
853
- $name = $this->get_person()->get_name();
854
- $email = $this->get_person()->user_email;
855
- $phone = ($this->get_person()->phone != __('Not Supplied','events-manager')) ? $this->get_person()->phone:'';
856
- if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'booking_modify_person' ){
857
- $name = !empty($_REQUEST['user_name']) ? sanitize_text_field($_REQUEST['user_name']):$name;
858
- $email = !empty($_REQUEST['user_email']) ? sanitize_email($_REQUEST['user_email']):$email;
859
- $phone = !empty($_REQUEST['dbem_phone']) ? sanitize_text_field($_REQUEST['dbem_phone']):$phone;
860
- }
861
- ?>
862
- <table class="em-form-fields">
863
- <tr><th><?php _e('Name','events-manager'); ?> : </th><td><input type="text" name="user_name" value="<?php echo esc_attr($name); ?>" /></td></tr>
864
- <tr><th><?php _e('Email','events-manager'); ?> : </th><td><input type="text" name="user_email" value="<?php echo esc_attr($email); ?>" /></td></tr>
865
- <tr><th><?php _e('Phone','events-manager'); ?> : </th><td><input type="text" name="dbem_phone" value="<?php echo esc_attr($phone); ?>" /></td></tr>
866
- </table>
867
- <?php
868
- return apply_filters('em_booking_get_person_editor', ob_get_clean(), $this);
869
- }
870
-
871
- /**
872
- * Returns a string representation of the booking's status
873
- * @return string
874
- */
875
- function get_status(){
876
- $status = ($this->booking_status == 0 && !get_option('dbem_bookings_approval') ) ? 1:$this->booking_status;
877
- return apply_filters('em_booking_get_status', $this->status_array[$status], $this);
878
- }
879
-
880
- /**
881
- * I wonder what this does....
882
- * @return boolean
883
- */
884
- function delete(){
885
- global $wpdb;
886
- $result = false;
887
- if( $this->can_manage('manage_bookings','manage_others_bookings') ){
888
- $sql = $wpdb->prepare("DELETE FROM ". EM_BOOKINGS_TABLE . " WHERE booking_id=%d", $this->booking_id);
889
- $result = $wpdb->query( $sql );
890
- if( $result !== false ){
891
- //delete the tickets too
892
- $this->get_tickets_bookings()->delete();
893
- $this->previous_status = $this->booking_status;
894
- $this->booking_status = false;
895
- $this->feedback_message = sprintf(__('%s deleted', 'events-manager'), __('Booking','events-manager'));
896
- $wpdb->delete( EM_META_TABLE, array('meta_key'=>'booking-note', 'object_id' => $this->booking_id), array('%s','%d'));
897
- do_action('em_booking_deleted', $this);
898
- }else{
899
- $this->add_error(sprintf(__('%s could not be deleted', 'events-manager'), __('Booking','events-manager')));
900
- }
901
- }
902
- do_action('em_bookings_deleted', $result, array($this->booking_id), $this);
903
- return apply_filters('em_booking_delete',( $result !== false ), $this);
904
- }
905
-
906
- function cancel($email = true){
907
- if( $this->person->ID == get_current_user_id() ){
908
- $this->manage_override = true; //normally, users can't manage a booking, only event owners, so we allow them to mod their booking status in this case only.
909
- }
910
- return $this->set_status(3, $email);
911
- }
912
-
913
- /**
914
- * Approve a booking.
915
- * @return bool
916
- */
917
- function approve($email = true, $ignore_spaces = false){
918
- return $this->set_status(1, $email, $ignore_spaces);
919
- }
920
- /**
921
- * Reject a booking and save
922
- * @return bool
923
- */
924
- function reject($email = true){
925
- return $this->set_status(2, $email);
926
- }
927
- /**
928
- * Unapprove a booking.
929
- * @return bool
930
- */
931
- function unapprove($email = true){
932
- return $this->set_status(0, $email);
933
- }
934
-
935
- /**
936
- * Change the status of the booking. This will save to the Database too.
937
- * @param int $status
938
- * @return boolean
939
- */
940
- function set_status($status, $email = true, $ignore_spaces = false){
941
- global $wpdb;
942
- $action_string = strtolower($this->status_array[$status]);
943
- //if we're approving we can't approve a booking if spaces are full, so check before it's approved.
944
- if(!$ignore_spaces && $status == 1){
945
- if( !$this->is_reserved() && $this->get_event()->get_bookings()->get_available_spaces() < $this->get_spaces() && !get_option('dbem_bookings_approval_overbooking') ){
946
- $this->feedback_message = sprintf(__('Not approved, spaces full.','events-manager'), $action_string);
947
- $this->add_error($this->feedback_message);
948
- return apply_filters('em_booking_set_status', false, $this);
949
- }
950
- }
951
- $this->previous_status = $this->booking_status;
952
- $this->booking_status = $status;
953
- $result = $wpdb->query($wpdb->prepare('UPDATE '.EM_BOOKINGS_TABLE.' SET booking_status=%d WHERE booking_id=%d', array($status, $this->booking_id)));
954
- if($result !== false){
955
- $this->feedback_message = sprintf(__('Booking %s.','events-manager'), $action_string);
956
- $result = apply_filters('em_booking_set_status', $result, $this); // run the filter before emails go out, in case others need to hook in first
957
- if( $result && $email && $this->previous_status != $this->booking_status ){ //email if status has changed
958
- if( $this->email() ){
959
- if( $this->mails_sent > 0 ){
960
- $this->feedback_message .= " ".__('Email Sent.','events-manager');
961
- }
962
- }else{
963
- //extra errors may be logged by email() in EM_Object
964
- $this->feedback_message .= ' <span style="color:red">'.__('ERROR : Email Not Sent.','events-manager').'</span>';
965
- $this->add_error(__('ERROR : Email Not Sent.','events-manager'));
966
- }
967
- }
968
- }else{
969
- //errors should be logged by save()
970
- $this->feedback_message = sprintf(__('Booking could not be %s.','events-manager'), $action_string);
971
- $this->add_error(sprintf(__('Booking could not be %s.','events-manager'), $action_string));
972
- $result = apply_filters('em_booking_set_status', false, $this);
973
- }
974
- return $result;
975
- }
976
-
977
- /**
978
- * Returns true if booking is reserving a space at this event, whether confirmed or not
979
- */
980
- function is_reserved(){
981
- $result = false;
982
- if( $this->booking_status == 0 && get_option('dbem_bookings_approval_reserved') ){
983
- $result = true;
984
- }elseif( $this->booking_status == 0 && !get_option('dbem_bookings_approval') ){
985
- $result = true;
986
- }elseif( $this->booking_status == 1 ){
987
- $result = true;
988
- }
989
- return apply_filters('em_booking_is_reserved', $result, $this);
990
- }
991
-
992
- /**
993
- * Returns true if booking is associated with a non-registered user, i.e. booked as a guest 'no user mode'.
994
- * @return mixed
995
- */
996
- function is_no_user(){
997
- return apply_filters('em_booking_is_no_user', $this->get_person()->ID === 0, $this);
998
- }
999
-
1000
- /**
1001
- * Returns true if booking is either pending or reserved but not confirmed (which is assumed pending)
1002
- */
1003
- function is_pending(){
1004
- $result = ($this->is_reserved() || $this->booking_status == 0) && $this->booking_status != 1;
1005
- return apply_filters('em_booking_is_pending', $result, $this);
1006
- }
1007
-
1008
- /**
1009
- * Add a booking note to this booking. returns wpdb result or false if use can't manage this event.
1010
- * @param string $note
1011
- * @return mixed
1012
- */
1013
- function add_note( $note_text ){
1014
- global $wpdb;
1015
- if( $this->can_manage() ){
1016
- $this->get_notes();
1017
- $note = array('author'=>get_current_user_id(),'note'=>wp_kses_data($note_text),'timestamp'=>time());
1018
- $this->notes[] = $note;
1019
- $this->feedback_message = __('Booking note successfully added.','events-manager');
1020
- return $wpdb->insert(EM_META_TABLE, array('object_id'=>$this->booking_id, 'meta_key'=>'booking-note', 'meta_value'=> serialize($note)),array('%d','%s','%s'));
1021
- }
1022
- return false;
1023
- }
1024
-
1025
- function get_admin_url(){
1026
- if( get_option('dbem_edit_bookings_page') && (!is_admin() || !empty($_REQUEST['is_public'])) ){
1027
- $my_bookings_page = get_permalink(get_option('dbem_edit_bookings_page'));
1028
- $bookings_link = em_add_get_params($my_bookings_page, array('event_id'=>$this->event_id, 'booking_id'=>$this->booking_id), false);
1029
- }else{
1030
- if( $this->get_event()->blog_id != get_current_blog_id() ){
1031
- $bookings_link = get_admin_url($this->get_event()->blog_id, 'edit.php?post_type='.EM_POST_TYPE_EVENT."&page=events-manager-bookings&event_id=".$this->event_id."&booking_id=".$this->booking_id);
1032
- }else{
1033
- $bookings_link = EM_ADMIN_URL. "&page=events-manager-bookings&event_id=".$this->event_id."&booking_id=".$this->booking_id;
1034
- }
1035
- }
1036
- return apply_filters('em_booking_get_bookings_url', $bookings_link, $this);
1037
- }
1038
-
1039
- function output($format, $target="html") {
1040
- do_action('em_booking_output_pre', $this, $format, $target);
1041
- preg_match_all("/(#@?_?[A-Za-z0-9]+)({([^}]+)})?/", $format, $placeholders);
1042
- foreach( $this->get_tickets() as $EM_Ticket){ /* @var $EM_Ticket EM_Ticket */ break; } //Get first ticket for single ticket placeholders
1043
- $output_string = $format;
1044
- $replaces = array();
1045
- foreach($placeholders[1] as $key => $result) {
1046
- $replace = '';
1047
- $full_result = $placeholders[0][$key];
1048
- $placeholder_atts = array($result);
1049
- if( !empty($placeholders[3][$key]) ) $placeholder_atts[] = $placeholders[3][$key];
1050
- switch( $result ){
1051
- case '#_BOOKINGID':
1052
- $replace = $this->booking_id;
1053
- break;
1054
- case '#_RESPNAME' : //deprecated
1055
- case '#_BOOKINGNAME':
1056
- $replace = $this->get_person()->get_name();
1057
- break;
1058
- case '#_RESPEMAIL' : //deprecated
1059
- case '#_BOOKINGEMAIL':
1060
- $replace = $this->get_person()->user_email;
1061
- break;
1062
- case '#_RESPPHONE' : //deprecated
1063
- case '#_BOOKINGPHONE':
1064
- $replace = $this->get_person()->phone;
1065
- break;
1066
- case '#_BOOKINGSPACES':
1067
- $replace = $this->get_spaces();
1068
- break;
1069
- case '#_BOOKINGDATE':
1070
- $replace = ( $this->date() !== false ) ? $this->date()->i18n( em_get_date_format() ):'n/a';
1071
- break;
1072
- case '#_BOOKINGTIME':
1073
- $replace = ( $this->date() !== false ) ? $this->date()->i18n( em_get_hour_format() ):'n/a';
1074
- break;
1075
- case '#_BOOKINGDATETIME':
1076
- $replace = ( $this->date() !== false ) ? $this->date()->i18n( em_get_date_format().' '.em_get_hour_format()):'n/a';
1077
- break;
1078
- case '#_BOOKINGLISTURL':
1079
- $replace = em_get_my_bookings_url();
1080
- break;
1081
- case '#_COMMENT' : //deprecated
1082
- case '#_BOOKINGCOMMENT':
1083
- $replace = $this->booking_comment;
1084
- break;
1085
- case '#_BOOKINGPRICEWITHOUTTAX':
1086
- $replace = $this->format_price($this->get_price() - $this->get_price_taxes());
1087
- break;
1088
- case '#_BOOKINGPRICETAX':
1089
- $replace = $this->get_price_taxes(true);
1090
- break;
1091
- case '#_BOOKINGPRICEWITHTAX':
1092
- case '#_BOOKINGPRICE':
1093
- $replace = $this->get_price(true);
1094
- break;
1095
- case '#_BOOKINGTICKETNAME':
1096
- $replace = $EM_Ticket->name;
1097
- break;
1098
- case '#_BOOKINGTICKETDESCRIPTION':
1099
- $replace = $EM_Ticket->description;
1100
- break;
1101
- case '#_BOOKINGTICKETPRICEWITHTAX':
1102
- $replace = $this->format_price( $EM_Ticket->get_price_without_tax() * (1+$this->get_tax_rate()/100) );
1103
- break;
1104
- case '#_BOOKINGTICKETPRICEWITHOUTTAX':
1105
- $replace = $EM_Ticket->get_price_without_tax(true);
1106
- break;
1107
- case '#_BOOKINGTICKETTAX':
1108
- $replace = $this->format_price( $EM_Ticket->get_price_without_tax() * ($this->get_tax_rate()/100) );
1109
- break;
1110
- case '#_BOOKINGTICKETPRICE':
1111
- $replace = $EM_Ticket->get_price(true);
1112
- break;
1113
- case '#_BOOKINGTICKETS':
1114
- ob_start();
1115
- em_locate_template('emails/bookingtickets.php', true, array('EM_Booking'=>$this));
1116
- $replace = ob_get_clean();
1117
- break;
1118
- case '#_BOOKINGSUMMARY':
1119
- ob_start();
1120
- em_locate_template('emails/bookingsummary.php', true, array('EM_Booking'=>$this));
1121
- $replace = ob_get_clean();
1122
- break;
1123
- case '#_BOOKINGADMINURL':
1124
- case '#_BOOKINGADMINLINK':
1125
- $bookings_link = esc_url( add_query_arg('booking_id', $this->booking_id, $this->event->get_bookings_url()) );
1126
- if($result == '#_BOOKINGADMINLINK'){
1127
- $replace = '<a href="'.$bookings_link.'">'.esc_html__('Edit Booking', 'events-manager'). '</a>';
1128
- }else{
1129
- $replace = $bookings_link;
1130
- }
1131
- break;
1132
- default:
1133
- $replace = $full_result;
1134
- break;
1135
- }
1136
- $replaces[$full_result] = apply_filters('em_booking_output_placeholder', $replace, $this, $full_result, $target, $placeholder_atts);
1137
- }
1138
- //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
1139
- krsort($replaces);
1140
- foreach($replaces as $full_result => $replacement){
1141
- $output_string = str_replace($full_result, $replacement , $output_string );
1142
- }
1143
- //run event output too, since this is never run from within events and will not infinitely loop
1144
- $EM_Event = apply_filters('em_booking_output_event', $this->get_event(), $this); //allows us to override the booking event info if it belongs to a parent or translation
1145
- $output_string = $EM_Event->output($output_string, $target);
1146
- return apply_filters('em_booking_output', $output_string, $this, $format, $target);
1147
- }
1148
-
1149
- /**
1150
- * @param boolean $email_admin
1151
- * @param boolean $force_resend
1152
- * @param boolean $email_attendee
1153
- * @return boolean
1154
- */
1155
- function email( $email_admin = true, $force_resend = false, $email_attendee = true ){
1156
- $result = true;
1157
- $this->mails_sent = 0;
1158
-
1159
-
1160
- //Make sure event matches booking, and that booking used to be approved.
1161
- if( $this->booking_status !== $this->previous_status || $force_resend ){
1162
- // before we format dates or any other language-specific placeholders, make sure we're translating the site language, not the user profile language in the admin area (e.g. if an admin is sending a booking confirmation email), assuming this isn't a ML-enabled site.
1163
- if( !EM_ML::$is_ml && is_admin() && EM_ML::$wplang != get_user_locale() ) EM_ML::switch_locale(EM_ML::$wplang);
1164
- do_action('em_booking_email_before_send', $this);
1165
- //get event info and refresh all bookings
1166
- $EM_Event = $this->get_event(); //We NEED event details here.
1167
- $EM_Event->get_bookings(true); //refresh all bookings
1168
- //messages can be overridden just before being sent
1169
- $msg = $this->email_messages();
1170
-
1171
- //Send user (booker) emails
1172
- if( !empty($msg['user']['subject']) && $email_attendee ){
1173
- $msg['user']['subject'] = $this->output($msg['user']['subject'], 'raw');
1174
- $msg['user']['body'] = $this->output($msg['user']['body'], 'email');
1175
- $attachments = array();
1176
- if( !empty($msg['user']['attachments']) && is_array($msg['user']['attachments']) ){
1177
- $attachments = $msg['user']['attachments'];
1178
- }
1179
- //Send to the person booking
1180
- if( !$this->email_send( $msg['user']['subject'], $msg['user']['body'], $this->get_person()->user_email, $attachments) ){
1181
- $result = false;
1182
- }else{
1183
- $this->mails_sent++;
1184
- }
1185
- }
1186
-
1187
- //Send admin/contact emails if this isn't the event owner or an events admin
1188
- if( $email_admin && !empty($msg['admin']['subject']) ){ //emails won't be sent if admin is logged in unless they book themselves
1189
- //get admin emails that need to be notified, hook here to add extra admin emails
1190
- $admin_emails = str_replace(' ','',get_option('dbem_bookings_notify_admin'));
1191
- $admin_emails = apply_filters('em_booking_admin_emails', explode(',', $admin_emails), $this); //supply emails as array
1192
- if( get_option('dbem_bookings_contact_email') == 1 && !empty($EM_Event->get_contact()->user_email) ){
1193
- //add event owner contact email to list of admin emails
1194
- $admin_emails[] = $EM_Event->get_contact()->user_email;
1195
- }
1196
- foreach($admin_emails as $key => $email){ if( !is_email($email) ) unset($admin_emails[$key]); } //remove bad emails
1197
- //proceed to email admins if need be
1198
- if( !empty($admin_emails) ){
1199
- //Only gets sent if this is a pending booking, unless approvals are disabled.
1200
- $msg['admin']['subject'] = $this->output($msg['admin']['subject'],'raw');
1201
- $msg['admin']['body'] = $this->output($msg['admin']['body'], 'email');
1202
- $attachments = array();
1203
- if( !empty($msg['admin']['attachments']) && is_array($msg['admin']['attachments']) ){
1204
- $attachments = $msg['admin']['attachments'];
1205
- }
1206
- //email admins
1207
- if( !$this->email_send( $msg['admin']['subject'], $msg['admin']['body'], $admin_emails, $attachments) && current_user_can('manage_options') ){
1208
- $this->errors[] = __('Confirmation email could not be sent to admin. Registrant should have gotten their email (only admin see this warning).','events-manager');
1209
- $result = false;
1210
- }else{
1211
- $this->mails_sent++;
1212
- }
1213
- }
1214
- }
1215
- do_action('em_booking_email_after_send', $this);
1216
- if( !EM_ML::$is_ml && is_admin() ) EM_ML::restore_locale(); // restore the locale back for the rest of the site, which will happen if we switched it earlier
1217
- }
1218
- return apply_filters('em_booking_email', $result, $this, $email_admin, $force_resend, $email_attendee);
1219
- //TODO need error checking for booking mail send
1220
- }
1221
-
1222
- function email_messages(){
1223
- $msg = array( 'user'=> array('subject'=>'', 'body'=>''), 'admin'=> array('subject'=>'', 'body'=>'')); //blank msg template
1224
- //admin messages won't change whether pending or already approved
1225
- switch( $this->booking_status ){
1226
- case 0:
1227
- case 5: //TODO remove offline status from here and move to pro
1228
- $msg['user']['subject'] = get_option('dbem_bookings_email_pending_subject');
1229
- $msg['user']['body'] = get_option('dbem_bookings_email_pending_body');
1230
- //admins should get something (if set to)
1231
- $msg['admin']['subject'] = get_option('dbem_bookings_contact_email_pending_subject');
1232
- $msg['admin']['body'] = get_option('dbem_bookings_contact_email_pending_body');
1233
- break;
1234
- case 1:
1235
- $msg['user']['subject'] = get_option('dbem_bookings_email_confirmed_subject');
1236
- $msg['user']['body'] = get_option('dbem_bookings_email_confirmed_body');
1237
- //admins should get something (if set to)
1238
- $msg['admin']['subject'] = get_option('dbem_bookings_contact_email_confirmed_subject');
1239
- $msg['admin']['body'] = get_option('dbem_bookings_contact_email_confirmed_body');
1240
- break;
1241
- case 2:
1242
- $msg['user']['subject'] = get_option('dbem_bookings_email_rejected_subject');
1243
- $msg['user']['body'] = get_option('dbem_bookings_email_rejected_body');
1244
- //admins should get something (if set to)
1245
- $msg['admin']['subject'] = get_option('dbem_bookings_contact_email_rejected_subject');
1246
- $msg['admin']['body'] = get_option('dbem_bookings_contact_email_rejected_body');
1247
- break;
1248
- case 3:
1249
- $msg['user']['subject'] = get_option('dbem_bookings_email_cancelled_subject');
1250
- $msg['user']['body'] = get_option('dbem_bookings_email_cancelled_body');
1251
- //admins should get something (if set to)
1252
- $msg['admin']['subject'] = get_option('dbem_bookings_contact_email_cancelled_subject');
1253
- $msg['admin']['body'] = get_option('dbem_bookings_contact_email_cancelled_body');
1254
- break;
1255
- }
1256
- return apply_filters('em_booking_email_messages', $msg, $this);
1257
- }
1258
-
1259
- /**
1260
- * Returns an EM_DateTime representation of when booking was made in UTC timezone. If no valid date defined, false will be returned
1261
- * @param boolean $utc_timezone
1262
- * @return EM_DateTime
1263
- * @throws Exception
1264
- */
1265
- public function date( $utc_timezone = false ){
1266
- if( empty($this->date) || !$this->date->valid ){
1267
- if( !empty($this->booking_date ) ){
1268
- $this->date = new EM_DateTime($this->booking_date, 'UTC');
1269
- }else{
1270
- //we retrn a date regardless but it's not based on a 'valid' booking date
1271
- $this->date = new EM_DateTime();
1272
- $this->date->valid = false;
1273
- }
1274
- }
1275
- //Set to UTC timezone if requested, local blog time by default
1276
- if( $utc_timezone ){
1277
- $timezone = 'UTC';
1278
- }else{
1279
- //we could set this to false but this way we might avoid creating a new timezone if it's already in this one
1280
- $timezone = get_option( 'timezone_string' );
1281
- if( !$timezone ) $timezone = get_option('gmt_offset');
1282
- }
1283
- $this->date->setTimezone($timezone);
1284
- return $this->date;
1285
- }
1286
-
1287
- /**
1288
- * Can the user manage this event?
1289
- */
1290
- function can_manage( $owner_capability = false, $admin_capability = false, $user_to_check = false ){
1291
- return $this->get_event()->can_manage('manage_bookings','manage_others_bookings') || empty($this->booking_id) || !empty($this->manage_override);
1292
- }
1293
-
1294
- /**
1295
- * Returns this object in the form of an array
1296
- * @return array
1297
- */
1298
- function to_array($person = false){
1299
- $booking = array();
1300
- //Core Data
1301
- $booking = parent::to_array();
1302
- //Person Data
1303
- if($person && is_object($this->person)){
1304
- $person = $this->person->to_array();
1305
- $booking = array_merge($booking, $person);
1306
- }
1307
- return $booking;
1308
- }
1309
- }
1310
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-bookings-table.php DELETED
@@ -1,673 +0,0 @@
1
- <?php
2
- //Builds a table of bookings, still work in progress...
3
- class EM_Bookings_Table{
4
- /**
5
- * associative array of collumns that'll be shown in order from left to right
6
- *
7
- * * key - collumn name in the databse, what will be used when searching
8
- * * value - label for use in collumn headers
9
- * @var array
10
- */
11
- public $cols = array('user_name','event_name','booking_spaces','booking_status','booking_price','actions');
12
- /**
13
- * Asoociative array of available collumn keys and corresponding headers, which will be used to display this table of bookings
14
- * @var unknown_type
15
- */
16
- public $cols_template = array();
17
- public $sortable_cols = array('booking_date');
18
- /**
19
- * Object we're viewing bookings in relation to.
20
- * @var object
21
- */
22
- public $cols_view;
23
- /**
24
- * Index key used for looking up status information we're filtering in the booking table
25
- * @var string
26
- */
27
- public $string = 'needs-attention';
28
- /**
29
- * Associative array of status information.
30
- *
31
- * * key - status index value
32
- * * value - associative array containing keys
33
- * ** label - the label for use in filter forms
34
- * ** search - array or integer status numbers to search
35
- *
36
- * @var array
37
- */
38
- public $statuses = array();
39
- /**
40
- * Maximum number of rows to show
41
- * @var int
42
- */
43
- public $limit = 20;
44
- public $order = 'ASC';
45
- public $orderby = 'booking_name';
46
- public $page = 1;
47
- public $offset = 0;
48
- public $scope = 'future';
49
- public $show_tickets = false;
50
- public $bookings_count = 0;
51
-
52
- function __construct($show_tickets = false){
53
- $this->statuses = array(
54
- 'all' => array('label'=>__('All','events-manager'), 'search'=>false),
55
- 'pending' => array('label'=>__('Pending','events-manager'), 'search'=>0),
56
- 'confirmed' => array('label'=>__('Confirmed','events-manager'), 'search'=>1),
57
- 'cancelled' => array('label'=>__('Cancelled','events-manager'), 'search'=>3),
58
- 'rejected' => array('label'=>__('Rejected','events-manager'), 'search'=>2),
59
- 'needs-attention' => array('label'=>__('Needs Attention','events-manager'), 'search'=>array(0)),
60
- 'incomplete' => array('label'=>__('Incomplete Bookings','events-manager'), 'search'=>array(0))
61
- );
62
- if( !get_option('dbem_bookings_approval') ){
63
- unset($this->statuses['pending']);
64
- unset($this->statuses['incomplete']);
65
- $this->statuses['confirmed']['search'] = array(0,1);
66
- }
67
- //Set basic vars
68
- $this->order = ( !empty($_REQUEST ['order']) && $_REQUEST ['order'] == 'DESC' ) ? 'DESC':'ASC';
69
- $this->orderby = ( !empty($_REQUEST ['orderby']) ) ? sanitize_sql_orderby($_REQUEST['orderby']):'booking_name';
70
- $this->limit = ( !empty($_REQUEST['limit']) && is_numeric($_REQUEST['limit'])) ? $_REQUEST['limit'] : 20;//Default limit
71
- $this->page = ( !empty($_REQUEST['pno']) && is_numeric($_REQUEST['pno']) ) ? $_REQUEST['pno']:1;
72
- $this->offset = ( $this->page > 1 ) ? ($this->page-1)*$this->limit : 0;
73
- $this->scope = ( !empty($_REQUEST['scope']) && array_key_exists($_REQUEST ['scope'], em_get_scopes()) ) ? sanitize_text_field($_REQUEST['scope']):'future';
74
- $this->status = ( !empty($_REQUEST['status']) && array_key_exists($_REQUEST['status'], $this->statuses) ) ? sanitize_text_field($_REQUEST['status']):'needs-attention';
75
- //build template of possible collumns
76
- $this->cols_template = apply_filters('em_bookings_table_cols_template', array(
77
- 'user_login' => __('Username', 'events-manager'),
78
- 'user_name'=>__('Name','events-manager'),
79
- 'first_name'=>__('First Name','events-manager'),
80
- 'last_name'=>__('Last Name','events-manager'),
81
- 'event_name'=>__('Event','events-manager'),
82
- 'event_date'=>__('Event Date(s)','events-manager'),
83
- 'event_time'=>__('Event Time(s)','events-manager'),
84
- 'user_email'=>__('E-mail','events-manager'),
85
- 'dbem_phone'=>__('Phone Number','events-manager'),
86
- 'booking_spaces'=>__('Spaces','events-manager'),
87
- 'booking_status'=>__('Status','events-manager'),
88
- 'booking_date'=>__('Booking Date','events-manager'),
89
- 'booking_price'=>__('Total','events-manager'),
90
- 'booking_id'=>__('Booking ID','events-manager'),
91
- 'booking_comment'=>__('Booking Comment','events-manager')
92
- ), $this);
93
- $this->cols_tickets_template = apply_filters('em_bookings_table_cols_tickets_template', array(
94
- 'ticket_name'=>__('Ticket Name','events-manager'),
95
- 'ticket_description'=>__('Ticket Description','events-manager'),
96
- 'ticket_price'=>__('Ticket Price','events-manager'),
97
- 'ticket_total'=>__('Ticket Total','events-manager'),
98
- 'ticket_id'=>__('Ticket ID','events-manager')
99
- ), $this);
100
- //add tickets to template if we're showing rows by booking-ticket
101
- if( $show_tickets ){
102
- $this->show_tickets = true;
103
- $this->cols = array('user_name','event_name','ticket_name','ticket_price','booking_spaces','booking_status','actions');
104
- $this->cols_template = array_merge( $this->cols_template, $this->cols_tickets_template);
105
- }
106
- $this->cols_template['actions'] = __('Actions','events-manager');
107
- //calculate collumns if post requests
108
- if( !empty($_REQUEST['cols']) ){
109
- if( is_array($_REQUEST['cols']) ){
110
- $this->cols = array();
111
- foreach( $_REQUEST['cols'] as $k => $col ){
112
- $this->cols[$k] = sanitize_text_field($col);
113
- }
114
- }else{
115
- foreach( explode(',',$_REQUEST['cols']) as $k => $col ){
116
- if( array_key_exists($col, $this->cols_template) ){
117
- $this->cols[$k] = $col;
118
- }
119
- }
120
- }
121
- }
122
- //load collumn view settings
123
- if( $this->get_person() !== false ){
124
- $this->cols_view = $this->get_person();
125
- }elseif( $this->get_ticket() !== false ){
126
- $this->cols_view = $this->get_ticket();
127
- }elseif( $this->get_event() !== false ){
128
- $this->cols_view = $this->get_event();
129
- }
130
- //save collumns depending on context and user preferences
131
- if( empty($_REQUEST['cols']) ){
132
- if(!empty($this->cols_view) && is_object($this->cols_view)){
133
- //check if user has settings for object type
134
- $settings = get_user_meta(get_current_user_id(), 'em_bookings_view-'.get_class($this->cols_view), true );
135
- }else{
136
- $settings = get_user_meta(get_current_user_id(), 'em_bookings_view', true );
137
- }
138
- if( !empty($settings) ){
139
- $this->cols = $settings;
140
- }
141
- }elseif( !empty($_REQUEST['cols']) && empty($_REQUEST['no_save']) ){ //save view settings for next time
142
- if( !empty($this->cols_view) && is_object($this->cols_view) ){
143
- update_user_meta(get_current_user_id(), 'em_bookings_view-'.get_class($this->cols_view), $this->cols );
144
- }else{
145
- update_user_meta(get_current_user_id(), 'em_bookings_view', $this->cols );
146
- }
147
- }
148
- //clean any columns from saved views that no longer exist
149
- foreach($this->cols as $col_key => $col_name){
150
- if( !array_key_exists($col_name, $this->cols_template)){
151
- unset($this->cols[$col_key]);
152
- }
153
- }
154
- do_action('em_bookings_table', $this);
155
- }
156
-
157
-
158
- /**
159
- * @return EM_Person|false
160
- */
161
- function get_person(){
162
- global $EM_Person;
163
- if( !empty($this->person) && is_object($this->person) ){
164
- return $this->person;
165
- }elseif( !empty($_REQUEST['person_id']) && !empty($EM_Person) && is_object($EM_Person) ){
166
- return $EM_Person;
167
- }
168
- return false;
169
- }
170
- /**
171
- * @return EM_Ticket|false
172
- */
173
- function get_ticket(){
174
- global $EM_Ticket;
175
- if( !empty($this->ticket) && is_object($this->ticket) ){
176
- return $this->ticket;
177
- }elseif( !empty($EM_Ticket) && is_object($EM_Ticket) ){
178
- return $EM_Ticket;
179
- }
180
- return false;
181
- }
182
- /**
183
- * @return $EM_Event|false
184
- */
185
- function get_event(){
186
- global $EM_Event;
187
- if( !empty($this->event) && is_object($this->event) ){
188
- return $this->event;
189
- }elseif( !empty($EM_Event) && is_object($EM_Event) ){
190
- return $EM_Event;
191
- }
192
- return false;
193
- }
194
-
195
- /**
196
- * Gets the bookings for this object instance according to its settings
197
- * @param boolean $force_refresh
198
- * @return EM_Bookings
199
- */
200
- function get_bookings($force_refresh = true){
201
- if( empty($this->bookings) || $force_refresh ){
202
- $EM_Ticket = $this->get_ticket();
203
- $EM_Event = $this->get_event();
204
- $EM_Person = $this->get_person();
205
- $default_args = apply_filters('em_bookings_table_get_bookings_args', array('limit'=>$this->limit,'offset'=>$this->offset), $this);
206
- if( $EM_Person !== false ){
207
- $args = array('person'=>$EM_Person->ID,'scope'=>$this->scope,'status'=>$this->get_status_search(),'order'=>$this->order,'orderby'=>$this->orderby);
208
- $this->bookings_count = EM_Bookings::count($args);
209
- $this->bookings = EM_Bookings::get(array_merge($args, $default_args));
210
- }elseif( $EM_Ticket !== false ){
211
- //searching bookings with a specific ticket
212
- $args = array('ticket_id'=>$EM_Ticket->ticket_id, 'order'=>$this->order,'orderby'=>$this->orderby);
213
- $this->bookings_count = EM_Bookings::count($args);
214
- $this->bookings = EM_Bookings::get(array_merge($args, $default_args));
215
- }elseif( $EM_Event !== false ){
216
- //bookings for an event
217
- $args = array('event'=>$EM_Event->event_id,'scope'=>false,'status'=>$this->get_status_search(),'order'=>$this->order,'orderby'=>$this->orderby);
218
- $args['owner'] = !current_user_can('manage_others_bookings') ? get_current_user_id() : false;
219
- $this->bookings_count = EM_Bookings::count($args);
220
- $this->bookings = EM_Bookings::get(array_merge($args, $default_args));
221
- }else{
222
- //all bookings for a status
223
- $args = array('status'=>$this->get_status_search(),'scope'=>$this->scope,'order'=>$this->order,'orderby'=>$this->orderby);
224
- $args['owner'] = !current_user_can('manage_others_bookings') ? get_current_user_id() : false;
225
- $this->bookings_count = EM_Bookings::count($args);
226
- $this->bookings = EM_Bookings::get(array_merge($args, $default_args));
227
- }
228
- }
229
- return $this->bookings;
230
- }
231
-
232
- function get_count(){
233
- return $this->bookings_count;
234
- }
235
-
236
- function get_status_search(){
237
- if(is_array($this->statuses[$this->status]['search'])){
238
- return implode(',',$this->statuses[$this->status]['search']);
239
- }
240
- return $this->statuses[$this->status]['search'];
241
- }
242
-
243
- function output(){
244
- do_action('em_bookings_table_header',$this); //won't be overwritten by JS
245
- $this->output_overlays();
246
- $this->output_table();
247
- do_action('em_bookings_table_footer',$this); //won't be overwritten by JS
248
- }
249
-
250
- function output_overlays(){
251
- $EM_Ticket = $this->get_ticket();
252
- $EM_Event = $this->get_event();
253
- $EM_Person = $this->get_person();
254
- ?>
255
- <div id="em-bookings-table-settings" class="em-bookings-table-overlay" style="display:none;" title="<?php esc_attr_e('Bookings Table Settings','events-manager'); ?>">
256
- <form id="em-bookings-table-settings-form" class="em-bookings-table-form" action="" method="post">
257
- <p><?php _e('Modify what information is displayed in this booking table.','events-manager') ?></p>
258
- <div id="em-bookings-table-settings-form-cols">
259
- <p>
260
- <strong><?php _e('Columns to show','events-manager')?></strong><br />
261
- <?php _e('Drag items to or from the left column to add or remove them.','events-manager'); ?>
262
- </p>
263
- <ul id="em-bookings-cols-active" class="em-bookings-cols-sortable">
264
- <?php foreach( $this->cols as $col_key ): ?>
265
- <li class="ui-state-highlight">
266
- <input id="em-bookings-col-<?php echo esc_attr($col_key); ?>" type="hidden" name="<?php echo esc_attr($col_key); ?>" value="1" class="em-bookings-col-item" />
267
- <?php echo esc_html($this->cols_template[$col_key]); ?>
268
- </li>
269
- <?php endforeach; ?>
270
- </ul>
271
- <ul id="em-bookings-cols-inactive" class="em-bookings-cols-sortable">
272
- <?php foreach( $this->cols_template as $col_key => $col_data ): ?>
273
- <?php if( !in_array($col_key, $this->cols) ): ?>
274
- <li class="ui-state-default">
275
- <input id="em-bookings-col-<?php echo esc_attr($col_key); ?>" type="hidden" name="<?php echo esc_attr($col_key); ?>" value="0" class="em-bookings-col-item" />
276
- <?php echo esc_html($col_data); ?>
277
- </li>
278
- <?php endif; ?>
279
- <?php endforeach; ?>
280
- </ul>
281
- </div>
282
- </form>
283
- </div>
284
- <div id="em-bookings-table-export" class="em-bookings-table-overlay" style="display:none;" title="<?php esc_attr_e('Export Bookings','events-manager'); ?>">
285
- <form id="em-bookings-table-export-form" class="em-bookings-table-form" action="" method="post">
286
- <p><?php esc_html_e('Select the options below and export all the bookings you have currently filtered (all pages) into a CSV spreadsheet format.','events-manager') ?></p>
287
- <?php if( !get_option('dbem_bookings_tickets_single') ): //single ticket mode means no splitting by ticket type ?>
288
- <p><?php esc_html_e('Split bookings by ticket type','events-manager')?> <input type="checkbox" name="show_tickets" value="1" />
289
- <a href="#" title="<?php esc_attr_e('If your events have multiple tickets, enabling this will show a separate row for each ticket within a booking.','events-manager'); ?>">?</a>
290
- <?php endif; ?>
291
- <?php do_action('em_bookings_table_export_options'); ?>
292
- <div id="em-bookings-table-settings-form-cols">
293
- <p><strong><?php esc_html_e('Columns to export','events-manager')?></strong></p>
294
- <ul id="em-bookings-export-cols-active" class="em-bookings-cols-sortable">
295
- <?php foreach( $this->cols as $col_key ): ?>
296
- <li class="ui-state-highlight">
297
- <input id="em-bookings-col-<?php echo esc_attr($col_key); ?>" type="hidden" name="cols[<?php echo esc_attr($col_key); ?>]" value="1" class="em-bookings-col-item" />
298
- <?php echo esc_html($this->cols_template[$col_key]); ?>
299
- </li>
300
- <?php endforeach; ?>
301
- </ul>
302
- <ul id="em-bookings-export-cols-inactive" class="em-bookings-cols-sortable">
303
- <?php foreach( $this->cols_template as $col_key => $col_data ): ?>
304
- <?php if( !in_array($col_key, $this->cols) ): ?>
305
- <li class="ui-state-default">
306
- <input id="em-bookings-col-<?php echo esc_attr($col_key); ?>" type="hidden" name="cols[<?php echo esc_attr($col_key); ?>]" value="0" class="em-bookings-col-item" />
307
- <?php echo esc_html($col_data); ?>
308
- </li>
309
- <?php endif; ?>
310
- <?php endforeach; ?>
311
- <?php if( !$this->show_tickets ): ?>
312
- <?php foreach( $this->cols_tickets_template as $col_key => $col_data ): ?>
313
- <?php if( !in_array($col_key, $this->cols) ): ?>
314
- <li class="ui-state-default <?php if(array_key_exists($col_key, $this->cols_tickets_template)) echo 'em-bookings-col-item-ticket'; ?>">
315
- <input id="em-bookings-col-<?php echo esc_attr($col_key); ?>" type="hidden" name="cols[<?php echo esc_attr($col_key); ?>]" value="0" class="em-bookings-col-item" />
316
- <?php echo esc_html($col_data); ?>
317
- </li>
318
- <?php endif; ?>
319
- <?php endforeach; ?>
320
- <?php endif; ?>
321
- </ul>
322
- </div>
323
- <?php if( $EM_Event !== false ): ?>
324
- <input type="hidden" name="event_id" value='<?php echo esc_attr($EM_Event->event_id); ?>' />
325
- <?php endif; ?>
326
- <?php if( $EM_Ticket !== false ): ?>
327
- <input type="hidden" name="ticket_id" value='<?php echo esc_attr($EM_Ticket->ticket_id); ?>' />
328
- <?php endif; ?>
329
- <?php if( $EM_Person !== false ): ?>
330
- <input type="hidden" name="person_id" value='<?php echo esc_attr($EM_Person->ID); ?>' />
331
- <?php endif; ?>
332
- <input type="hidden" name="scope" value='<?php echo esc_attr($this->scope); ?>' />
333
- <input type="hidden" name="status" value='<?php echo esc_attr($this->status); ?>' />
334
- <input type="hidden" name="no_save" value='1' />
335
- <input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce('export_bookings_csv'); ?>" />
336
- <input type="hidden" name="action" value="export_bookings_csv" />
337
- </form>
338
- </div>
339
- <br class="clear" />
340
- <?php
341
- }
342
-
343
- function output_table(){
344
- $EM_Ticket = $this->get_ticket();
345
- $EM_Event = $this->get_event();
346
- $EM_Person = $this->get_person();
347
- $this->get_bookings(true); //get bookings and refresh
348
- ?>
349
- <div class='em-bookings-table em_obj' id="em-bookings-table">
350
- <form class='bookings-filter' method='post' action='<?php echo esc_url(bloginfo('wpurl')); ?>/wp-admin/edit.php'>
351
- <?php if( $EM_Event !== false ): ?>
352
- <input type="hidden" name="event_id" value='<?php echo esc_attr($EM_Event->event_id); ?>' />
353
- <?php endif; ?>
354
- <?php if( $EM_Ticket !== false ): ?>
355
- <input type="hidden" name="ticket_id" value='<?php echo esc_attr($EM_Ticket->ticket_id); ?>' />
356
- <?php endif; ?>
357
- <?php if( $EM_Person !== false ): ?>
358
- <input type="hidden" name="person_id" value='<?php echo esc_attr($EM_Person->ID); ?>' />
359
- <?php endif; ?>
360
- <input type="hidden" name="is_public" value="<?php echo ( !empty($_REQUEST['is_public']) || !is_admin() ) ? 1:0; ?>" />
361
- <input type="hidden" name="pno" value='<?php echo esc_attr($this->page); ?>' />
362
- <input type="hidden" name="order" value='<?php echo esc_attr($this->order); ?>' />
363
- <input type="hidden" name="orderby" value='<?php echo esc_attr($this->orderby); ?>' />
364
- <input type="hidden" name="_wpnonce" value="<?php echo ( !empty($_REQUEST['_wpnonce']) ) ? esc_attr($_REQUEST['_wpnonce']):wp_create_nonce('em_bookings_table'); ?>" />
365
- <input type="hidden" name="action" value="em_bookings_table" />
366
- <input type="hidden" name="cols" value="<?php echo esc_attr(implode(',', $this->cols)); ?>" />
367
-
368
- <div class='tablenav'>
369
- <div class="alignleft actions">
370
- <a href="#" class="em-bookings-table-export" id="em-bookings-table-export-trigger" rel="#em-bookings-table-export" title="<?php _e('Export these bookings.','events-manager'); ?>"></a>
371
- <a href="#" class="em-bookings-table-settings" id="em-bookings-table-settings-trigger" rel="#em-bookings-table-settings"></a>
372
- <?php if( $EM_Event === false ): ?>
373
- <select name="scope">
374
- <?php
375
- foreach ( em_get_scopes() as $key => $value ) {
376
- $selected = "";
377
- if ($key == $this->scope)
378
- $selected = "selected='selected'";
379
- echo "<option value='".esc_attr($key)."' $selected>".esc_html($value)."</option> ";
380
- }
381
- ?>
382
- </select>
383
- <?php endif; ?>
384
- <select name="limit">
385
- <option value="<?php echo esc_attr($this->limit) ?>"><?php echo esc_html(sprintf(__('%s Rows','events-manager'),$this->limit)); ?></option>
386
- <option value="5">5</option>
387
- <option value="10">10</option>
388
- <option value="25">25</option>
389
- <option value="50">50</option>
390
- <option value="100">100</option>
391
- </select>
392
- <select name="status">
393
- <?php
394
- foreach ( $this->statuses as $key => $value ) {
395
- $selected = "";
396
- if ($key == $this->status)
397
- $selected = "selected='selected'";
398
- echo "<option value='".esc_attr($key)."' $selected>".esc_html($value['label'])."</option> ";
399
- }
400
- ?>
401
- </select>
402
- <input name="pno" type="hidden" value="1" />
403
- <input id="post-query-submit" class="button-secondary" type="submit" value="<?php esc_attr_e( 'Filter' )?>" />
404
- <?php if( $EM_Event !== false ): ?>
405
- <?php esc_html_e('Displaying Event','events-manager'); ?> : <?php echo esc_html($EM_Event->event_name); ?>
406
- <?php elseif( $EM_Person !== false ): ?>
407
- <?php esc_html_e('Displaying User','events-manager'); echo ' : '.esc_html($EM_Person->get_name()); ?>
408
- <?php endif; ?>
409
- </div>
410
- <?php
411
- if ( $this->bookings_count >= $this->limit ) {
412
- $bookings_nav = em_admin_paginate( $this->bookings_count, $this->limit, $this->page, array(),'#%#%','#');
413
- echo $bookings_nav;
414
- }
415
- ?>
416
- </div>
417
- <div class="clear"></div>
418
- <div class='table-wrap'>
419
- <table id='dbem-bookings-table' class='widefat post '>
420
- <thead>
421
- <tr>
422
- <?php /*
423
- <th class='manage-column column-cb check-column' scope='col'>
424
- <input class='select-all' type="checkbox" value='1' />
425
- </th>
426
- */ ?>
427
- <th class='manage-column' scope='col'><?php echo implode("</th><th class='manage-column' scope='col'>", $this->get_headers()); ?></th>
428
- </tr>
429
- </thead>
430
- <?php if( $this->bookings_count > 0 ): ?>
431
- <tbody>
432
- <?php
433
- $rowno = 0;
434
- $event_count = (!empty($event_count)) ? $event_count:0;
435
- foreach ($this->bookings->bookings as $EM_Booking) {
436
- ?>
437
- <tr>
438
- <?php /*
439
- <th scope="row" class="check-column" style="padding:7px 0px 7px;"><input type='checkbox' value='<?php echo $EM_Booking->booking_id ?>' name='bookings[]'/></th>
440
- */
441
- /* @var $EM_Booking EM_Booking */
442
- /* @var $EM_Ticket_Booking EM_Ticket_Booking */
443
- if( $this->show_tickets ){
444
- foreach($EM_Booking->get_tickets_bookings()->tickets_bookings as $EM_Ticket_Booking){
445
- $row = $this->get_row($EM_Ticket_Booking);
446
- foreach( $row as $row_cell ){
447
- ?><td><?php echo $row_cell; ?></td><?php
448
- }
449
- }
450
- }else{
451
- $row = $this->get_row($EM_Booking);
452
- foreach( $row as $row_cell ){
453
- ?><td><?php echo $row_cell; ?></td><?php
454
- }
455
- }
456
- ?>
457
- </tr>
458
- <?php
459
- }
460
- ?>
461
- </tbody>
462
- <?php else: ?>
463
- <tbody>
464
- <tr><td scope="row" colspan="<?php echo count($this->cols); ?>"><?php esc_html_e('No bookings.', 'events-manager'); ?></td></tr>
465
- </tbody>
466
- <?php endif; ?>
467
- </table>
468
- </div>
469
- <?php if( !empty($bookings_nav) && $this->bookings_count >= $this->limit ) : ?>
470
- <div class='tablenav'>
471
- <?php echo $bookings_nav; ?>
472
- <div class="clear"></div>
473
- </div>
474
- <?php endif; ?>
475
- </form>
476
- </div>
477
- <?php
478
- }
479
-
480
- function get_headers($csv = false){
481
- $headers = array();
482
- foreach($this->cols as $col){
483
- if( $col == 'actions' ){
484
- if( !$csv ) $headers[$col] = '&nbsp;';
485
- }elseif(array_key_exists($col, $this->cols_template)){
486
- /* for later - col ordering!
487
- if($this->orderby == $col){
488
- if($this->order == 'ASC'){
489
- $headers[] = '<a class="em-bookings-orderby" href="#'.$col.'">'.$this->cols_template[$col].' (^)</a>';
490
- }else{
491
- $headers[] = '<a class="em-bookings-orderby" href="#'.$col.'">'.$this->cols_template[$col].' (d)</a>';
492
- }
493
- }else{
494
- $headers[] = '<a class="em-bookings-orderby" href="#'.$col.'">'.$this->cols_template[$col].'</a>';
495
- }
496
- */
497
- $v = $this->cols_template[$col];
498
- if( $csv ){
499
- $v = self::sanitize_spreadsheet_cell($v);
500
- }
501
- $headers[$col] = $v;
502
- }
503
- }
504
- return apply_filters('em_bookings_table_get_headers', $headers, $csv, $this);
505
- }
506
-
507
- function get_table(){
508
-
509
- }
510
-
511
- /**
512
- * @param Object $object
513
- * @return array()
514
- */
515
- function get_row( $object, $format = 'html' ){
516
- /* @var $EM_Ticket EM_Ticket */
517
- /* @var $EM_Ticket_Booking EM_Ticket_Booking */
518
- /* @var $EM_Booking EM_Booking */
519
- if( $format === true ) $format = 'csv'; //backwards compatibility, previously $format was $csv which was a boolean
520
- if( get_class($object) == 'EM_Ticket_Booking' ){
521
- $EM_Ticket_Booking = $object;
522
- $EM_Ticket = $EM_Ticket_Booking->get_ticket();
523
- $EM_Booking = $EM_Ticket_Booking->get_booking();
524
- }else{
525
- $EM_Booking = $object;
526
- }
527
- $cols = array();
528
- foreach($this->cols as $col){
529
- $val = ''; //reset value
530
- //is col a user col or else?
531
- //TODO fix urls so this works in all pages in front as well
532
- if( $col == 'user_email' ){
533
- $val = $EM_Booking->get_person()->user_email;
534
- }elseif($col == 'user_login'){
535
- if( $EM_Booking->is_no_user() ){
536
- $val = esc_html__('Guest User', 'events-manager');
537
- }else{
538
- if( $format == 'csv' ){
539
- $val = $EM_Booking->get_person()->user_login;
540
- }else{
541
- $val = '<a href="'.esc_url(add_query_arg(array('person_id'=>$EM_Booking->person_id, 'event_id'=>null), $EM_Booking->get_event()->get_bookings_url())).'">'. esc_html($EM_Booking->person->user_login) .'</a>';
542
- }
543
- }
544
- }elseif($col == 'dbem_phone'){
545
- $val = $EM_Booking->get_person()->phone;
546
- }elseif($col == 'user_name'){
547
- if( $format == 'csv' ){
548
- $val = $EM_Booking->get_person()->get_name();
549
- }elseif( $EM_Booking->is_no_user() ){
550
- $val = esc_html($EM_Booking->get_person()->get_name());
551
- }else{
552
- $val = '<a href="'.esc_url(add_query_arg(array('person_id'=>$EM_Booking->person_id, 'event_id'=>null), $EM_Booking->get_event()->get_bookings_url())).'">'. esc_html($EM_Booking->person->get_name()) .'</a>';
553
- }
554
- }elseif($col == 'first_name'){
555
- $val = $EM_Booking->get_person()->first_name;
556
- }elseif($col == 'last_name'){
557
- $val = $EM_Booking->get_person()->last_name;
558
- }elseif($col == 'event_name'){
559
- if( $format == 'csv' ){
560
- $val = $EM_Booking->get_event()->event_name;
561
- }else{
562
- $val = '<a href="'.$EM_Booking->get_event()->get_bookings_url().'">'. esc_html($EM_Booking->get_event()->event_name) .'</a>';
563
- }
564
- }elseif($col == 'event_date'){
565
- $val = $EM_Booking->get_event()->output('#_EVENTDATES');
566
- }elseif($col == 'event_time'){
567
- $val = $EM_Booking->get_event()->output('#_EVENTTIMES');
568
- }elseif($col == 'booking_price'){
569
- $val = $EM_Booking->get_price(true);
570
- }elseif($col == 'booking_status'){
571
- $val = $EM_Booking->get_status(true);
572
- }elseif($col == 'booking_date'){
573
- $val = $EM_Booking->date()->i18n( get_option('dbem_date_format').' '. get_option('dbem_time_format') );
574
- }elseif($col == 'actions' ){
575
- if( $format == 'csv' ) continue;
576
- $val = implode(' | ', $this->get_booking_actions($EM_Booking));
577
- }elseif( $col == 'booking_spaces' ){
578
- $val = ($this->show_tickets && !empty($EM_Ticket)) ? $EM_Ticket_Booking->get_spaces() : $EM_Booking->get_spaces();
579
- }elseif( $col == 'booking_id' ){
580
- $val = $EM_Booking->booking_id;
581
- }elseif( $col == 'ticket_name' && $this->show_tickets && !empty($EM_Ticket) ){
582
- $val = $EM_Ticket->$col;
583
- }elseif( $col == 'ticket_description' && $this->show_tickets && !empty($EM_Ticket) ){
584
- $val = $EM_Ticket->$col;
585
- }elseif( $col == 'ticket_price' && $this->show_tickets && !empty($EM_Ticket) ){
586
- $val = $EM_Ticket->get_price(true);
587
- }elseif( $col == 'ticket_total' && $this->show_tickets && !empty($EM_Ticket_Booking) ){
588
- $val = apply_filters('em_bookings_table_row_booking_price_ticket', $EM_Ticket_Booking->get_price(false), $EM_Booking, true);
589
- $val = $EM_Booking->format_price($val * (1 + $EM_Booking->get_tax_rate(true)));
590
- }elseif( $col == 'ticket_id' && $this->show_tickets && !empty($EM_Ticket) ){
591
- $val = $EM_Ticket->ticket_id;
592
- }elseif( $col == 'booking_comment' ){
593
- $val = $EM_Booking->booking_comment;
594
- }
595
- //escape all HTML if destination is HTML or not defined
596
- if( $format == 'html' || empty($format) ){
597
- if( !in_array($col, array('user_login', 'user_name', 'event_name', 'actions')) ) $val = esc_html($val);
598
- }
599
- //use this
600
- $val = apply_filters('em_bookings_table_rows_col_'.$col, $val, $EM_Booking, $this, $format, $object);
601
- $val = apply_filters('em_bookings_table_rows_col', $val, $col, $EM_Booking, $this, $format, $object); //use the above filter instead for better performance
602
- //csv/excel escaping
603
- if( $format == 'csv' || $format == 'xls' || $format == 'xlsx' ){
604
- $val = self::sanitize_spreadsheet_cell($val);
605
- }
606
- //add to cols
607
- $cols[] = $val;
608
- }
609
- return $cols;
610
- }
611
-
612
- function get_row_csv($EM_Booking){
613
- $row = $this->get_row($EM_Booking, 'csv');
614
- foreach($row as $k=>$v){
615
- $row[$k] = html_entity_decode($v);
616
- } //remove things like &amp; which may have been saved to the DB directly
617
- return $row;
618
- }
619
-
620
- public static function sanitize_spreadsheet_cell( $cell ){
621
- return preg_replace('/^([;=@\+\-])/', "'$1", $cell);
622
- }
623
-
624
- /**
625
- * @param EM_Booking $EM_Booking
626
- * @return mixed
627
- */
628
- function get_booking_actions($EM_Booking){
629
- $booking_actions = array();
630
- $url = $EM_Booking->get_event()->get_bookings_url();
631
- switch($EM_Booking->booking_status){
632
- case 0: //pending
633
- if( get_option('dbem_bookings_approval') ){
634
- $booking_actions = array(
635
- 'approve' => '<a class="em-bookings-approve" href="'.em_add_get_params($url, array('action'=>'bookings_approve', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Approve','events-manager').'</a>',
636
- 'reject' => '<a class="em-bookings-reject" href="'.em_add_get_params($url, array('action'=>'bookings_reject', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Reject','events-manager').'</a>',
637
- 'delete' => '<span class="trash"><a class="em-bookings-delete" href="'.em_add_get_params($url, array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Delete','events-manager').'</a></span>',
638
- 'edit' => '<a class="em-bookings-edit" href="'.em_add_get_params($EM_Booking->get_event()->get_bookings_url(), array('booking_id'=>$EM_Booking->booking_id, 'em_ajax'=>null, 'em_obj'=>null)).'">'.__('Edit/View','events-manager').'</a>',
639
- );
640
- break;
641
- }//if approvals are off, treat as a 1
642
- case 1: //approved
643
- $booking_actions = array(
644
- 'unapprove' => '<a class="em-bookings-unapprove" href="'.em_add_get_params($url, array('action'=>'bookings_unapprove', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Unapprove','events-manager').'</a>',
645
- 'reject' => '<a class="em-bookings-reject" href="'.em_add_get_params($url, array('action'=>'bookings_reject', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Reject','events-manager').'</a>',
646
- 'delete' => '<span class="trash"><a class="em-bookings-delete" href="'.em_add_get_params($url, array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Delete','events-manager').'</a></span>',
647
- 'edit' => '<a class="em-bookings-edit" href="'.em_add_get_params($EM_Booking->get_event()->get_bookings_url(), array('booking_id'=>$EM_Booking->booking_id, 'em_ajax'=>null, 'em_obj'=>null)).'">'.__('Edit/View','events-manager').'</a>',
648
- );
649
- break;
650
- case 2: //rejected
651
- $booking_actions = array(
652
- 'approve' => '<a class="em-bookings-approve" href="'.em_add_get_params($url, array('action'=>'bookings_approve', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Approve','events-manager').'</a>',
653
- 'delete' => '<span class="trash"><a class="em-bookings-delete" href="'.em_add_get_params($url, array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Delete','events-manager').'</a></span>',
654
- 'edit' => '<a class="em-bookings-edit" href="'.em_add_get_params($EM_Booking->get_event()->get_bookings_url(), array('booking_id'=>$EM_Booking->booking_id, 'em_ajax'=>null, 'em_obj'=>null)).'">'.__('Edit/View','events-manager').'</a>',
655
- );
656
- break;
657
- case 3: //cancelled
658
- case 4: //awaiting online payment - similar to pending but always needs approval in EM Free
659
- case 5: //awaiting payment - similar to pending but always needs approval in EM Free
660
- $booking_actions = array(
661
- 'approve' => '<a class="em-bookings-approve" href="'.em_add_get_params($url, array('action'=>'bookings_approve', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Approve','events-manager').'</a>',
662
- 'delete' => '<span class="trash"><a class="em-bookings-delete" href="'.em_add_get_params($url, array('action'=>'bookings_delete', 'booking_id'=>$EM_Booking->booking_id)).'">'.__('Delete','events-manager').'</a></span>',
663
- 'edit' => '<a class="em-bookings-edit" href="'.em_add_get_params($EM_Booking->get_event()->get_bookings_url(), array('booking_id'=>$EM_Booking->booking_id, 'em_ajax'=>null, 'em_obj'=>null)).'">'.__('Edit/View','events-manager').'</a>',
664
- );
665
- break;
666
-
667
- }
668
- if( !get_option('dbem_bookings_approval') ) unset($booking_actions['unapprove']);
669
- $booking_actions = apply_filters('em_bookings_table_booking_actions_'.$EM_Booking->booking_status ,$booking_actions, $EM_Booking);
670
- return apply_filters('em_bookings_table_cols_col_action', $booking_actions, $EM_Booking);
671
- }
672
- }
673
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-bookings.php DELETED
@@ -1,835 +0,0 @@
1
- <?php
2
- /**
3
- * Deals with the booking info for an event
4
- * @author marcus
5
- * @property EM_Booking[] $bookings
6
- */
7
- class EM_Bookings extends EM_Object implements Iterator{
8
-
9
- /**
10
- * Array of EM_Booking objects for a specific event
11
- * @var EM_Booking[]
12
- */
13
- protected $bookings;
14
- /**
15
- * @var EM_Tickets
16
- */
17
- var $tickets;
18
- /**
19
- * @var int
20
- */
21
- var $event_id;
22
- /**
23
- * How many spaces this event has
24
- * @var int
25
- */
26
- var $spaces;
27
- /**
28
- * @var boolena Flag for Multilingual functionality, to help prevent unnecessary reloading of this object if already 'translated'
29
- */
30
- var $translated;
31
- /**
32
- * If flag is true, a registration will be attempted when booking whether the user is logged in or not. Used in cases such as manual bookings (a Pro feature) and should only be enabled during manipulation by an event admin.
33
- * @var unknown
34
- */
35
- public static $force_registration;
36
- /**
37
- * If flag is true, bookings and forms will not impose restrictions for roles. Future iterations will remove restrictions on dates, space capacity, etc. This is mainly for use by event admins such as for a manual booking (a Pro feature).
38
- * @var bool
39
- */
40
- public static $disable_restrictions = false;
41
-
42
- protected $booked_spaces;
43
- protected $pending_spaces;
44
- protected $available_spaces;
45
-
46
- /**
47
- * Creates an EM_Bookings instance, currently accepts an EM_Event object (gets all bookings for that event) or array of any EM_Booking objects, which can be manipulated in bulk with helper functions.
48
- * @param EM_Event $event
49
- * @return null
50
- */
51
- function __construct( $data = false ){
52
- if( is_object($data) && get_class($data) == "EM_Event" ){ //Creates a blank bookings object if needed
53
- $this->event_id = $data->event_id;
54
- }elseif( is_array($data) ){
55
- foreach( $data as $EM_Booking ){
56
- if( get_class($EM_Booking) == 'EM_Booking'){
57
- $this->bookings[] = $EM_Booking;
58
- }
59
- }
60
- }
61
- }
62
-
63
- public function __get( $var ){
64
- if( $var == 'bookings' ){
65
- return $this->load();
66
- }
67
- return parent::__get( $var );
68
- }
69
-
70
- public function __set( $var, $val ){
71
- if( $var == 'bookings' ){
72
- if( is_array($val) ){
73
- $this->bookings = $val;
74
- }else{
75
- $this->bookings = null;
76
- }
77
- }
78
- parent::__set( $var, $val );
79
- }
80
-
81
- /**
82
- * Counter-intuitive but __isset works against isset() but for our purpose it's mainly aimed at empty() calls, which also references this function.
83
- * We don't expect nor do we want people using isset on things like the bookings property.
84
- * Assume every property in EM_Bookings isset() == true and avoid it, only use empty() calls to check if there's anything in that property.
85
- * Therefore, we'd return !empty($this->bookings) because if there's bookings, isset() should return true
86
- * @param string $var
87
- * @return boolean
88
- */
89
- public function __isset( $prop ){
90
- //if isset is invoked on $EM_Bookings->bookings then we'll assume it's only set if the bookings property is empty, not if null.
91
- if( $prop == 'bookings' ){
92
- return $this->bookings !== null;
93
- }
94
- return parent::__isset( $prop );
95
- }
96
-
97
- public function load( $refresh = false ){
98
- if( $refresh || $this->bookings === null ){
99
- global $wpdb;
100
- $bookings = $this->bookings = array();
101
- if( $this->event_id > 0 ){
102
- $sql = "SELECT * FROM ". EM_BOOKINGS_TABLE ." WHERE event_id ='{$this->event_id}' ORDER BY booking_date";
103
- $bookings = $wpdb->get_results($sql, ARRAY_A);
104
- }
105
- foreach ($bookings as $booking){
106
- $this->bookings[] = em_get_booking($booking);
107
- }
108
- }
109
- return apply_filters('em_bookings_load', $this->bookings);
110
- }
111
-
112
- /**
113
- * Add a booking into this event (or add spaces if person already booked this). We assume at this point that the booking has already been validated usin $EM_Booking->validate()
114
- * @param EM_Booking $EM_Booking
115
- * @return boolean
116
- */
117
- function add( $EM_Booking ){
118
- global $wpdb,$EM_Mailer;
119
- //Save the booking
120
- $email = false;
121
- //set status depending on approval settings
122
- if( empty($EM_Booking->booking_status) ){ //if status is not set, give 1 or 0 depending on approval settings
123
- $EM_Booking->booking_status = get_option('dbem_bookings_approval') ? 0:1;
124
- }
125
- $result = $EM_Booking->save(false);
126
- if($result){
127
- //Success
128
- do_action('em_bookings_added', $EM_Booking);
129
- if( $this->bookings === null ) $this->bookings = array();
130
- $this->bookings[] = $EM_Booking;
131
- $email = $EM_Booking->email();
132
- if( get_option('dbem_bookings_approval') == 1 && $EM_Booking->booking_status == 0){
133
- $this->feedback_message = get_option('dbem_booking_feedback_pending');
134
- }else{
135
- $this->feedback_message = get_option('dbem_booking_feedback');
136
- }
137
- if(!$email){
138
- $EM_Booking->email_not_sent = true;
139
- $this->feedback_message .= ' '.get_option('dbem_booking_feedback_nomail');
140
- if( current_user_can('activate_plugins') ){
141
- if( count($EM_Booking->get_errors()) > 0 ){
142
- $this->feedback_message .= '<br/><strong>Errors:</strong> (only admins see this message)<br/><ul><li>'. implode('</li><li>', $EM_Booking->get_errors()).'</li></ul>';
143
- }else{
144
- $this->feedback_message .= '<br/><strong>No errors returned by mailer</strong> (only admins see this message)';
145
- }
146
- }
147
- }
148
- return apply_filters('em_bookings_add', true, $EM_Booking);
149
- }else{
150
- //Failure
151
- $this->errors[] = "<strong>".get_option('dbem_booking_feedback_error')."</strong><br />". implode('<br />', $EM_Booking->errors);
152
- }
153
- return apply_filters('em_bookings_add', false, $EM_Booking);
154
- }
155
-
156
- /**
157
- * Get POST data and create a booking for each ticket requested. If successful, a booking object is returned, false if not.
158
- * @return false|object
159
- */
160
- function add_from_post(){
161
- $EM_Booking = new EM_booking();
162
- $result = $EM_Booking->get_post();
163
- if($result){
164
- $result = $this->add($EM_Booking);
165
- if($result){
166
- $result = $EM_Booking;
167
- }
168
- $this->feedback_message = sprintf(__('%s created.','events-manager'),__('Booking','events-manager'));
169
- }else{
170
- $this->errors = array_merge($this->errors, $EM_Booking->errors);
171
- }
172
- return apply_filters('em_bookings_add_from_post',$result,$EM_Booking,$this);
173
- }
174
-
175
- /**
176
- * Smart event locator, saves a database read if possible. Note that if an event doesn't exist, a blank object will be created to prevent duplicates.
177
- */
178
- function get_event(){
179
- global $EM_Event;
180
- if( is_object($EM_Event) && $EM_Event->event_id == $this->event_id ){
181
- return $EM_Event;
182
- }else{
183
- if( is_numeric($this->event_id) && $this->event_id > 0 ){
184
- return em_get_event($this->event_id, 'event_id');
185
- }elseif( is_array($this->bookings) ){
186
- foreach($this->bookings as $EM_Booking){
187
- /* @var $EM_Booking EM_Booking */
188
- return em_get_event($EM_Booking->event_id, 'event_id');
189
- }
190
- }
191
- }
192
- return em_get_event($this->event_id, 'event_id');
193
- }
194
-
195
- /**
196
- * Retrieve and save the bookings belonging to instance. If called again will return cached version, set $force_reload to true to create a new EM_Tickets object.
197
- * @param boolean $force_reload
198
- * @return EM_Tickets
199
- */
200
- function get_tickets( $force_reload = false ){
201
- if( !is_object($this->tickets) || $force_reload ){
202
- $this->tickets = new EM_Tickets($this->event_id);
203
- if( get_option('dbem_bookings_tickets_single') && count($this->tickets->tickets) == 1 ){
204
- //if in single ticket mode, then the event booking cut-off is the ticket end date
205
- $EM_Ticket = $this->tickets->get_first();
206
- $EM_Event = $this->get_event();
207
- //if ticket has cut-off date, that should take precedence as we save the ticket cut-off date/time to the event in single ticket mode
208
- if( !empty($EM_Ticket->ticket_end) ){
209
- //if ticket end dates are set, move to event
210
- $EM_Event->event_rsvp_date = $EM_Ticket->end()->format('Y-m-d');
211
- $EM_Event->event_rsvp_time = $EM_Ticket->end()->format('H:i:00');
212
- if( $EM_Event->is_recurring() && !empty($EM_Ticket->ticket_meta['recurrences']) ){
213
- $EM_Event->recurrence_rsvp_days = $EM_Ticket->ticket_meta['recurrences']['end_days'];
214
- }
215
- }else{
216
- //if no end date is set, use event end date (which will have defaulted to the event start date
217
- if( !$EM_Event->is_recurring() ){
218
- //save if we have a valid rsvp end date
219
- if( $EM_Event->rsvp_end()->valid ){
220
- $EM_Ticket->ticket_end = $EM_Event->rsvp_end()->getDateTime();
221
- }
222
- }else{
223
- if( !isset($EM_Ticket->ticket_meta['recurrences']['end_days']) ){
224
- //for recurrences, we take the recurrence_rsvp_days and feed it into the ticket meta that'll handle recurrences
225
- $EM_Ticket->ticket_meta['recurrences']['end_days'] = !empty($EM_Event->recurrence_rsvp_days) ? $EM_Event->recurrence_rsvp_days : 0;
226
- if( !isset($EM_Ticket->ticket_meta['recurrences']['end_time']) ){
227
- iF( empty($EM_Event->event_rsvp_time) ){
228
- $EM_Ticket->ticket_meta['recurrences']['end_time'] = $EM_Event->start()->getTime();
229
- }else{
230
- $EM_Ticket->ticket_meta['recurrences']['end_time'] = $EM_Event->event_rsvp_time;
231
- }
232
- }
233
- $EM_Ticket->ticket_end = $EM_Event->start()->format('Y-m-d') . $EM_Ticket->ticket_meta['recurrences']['end_time'];
234
- }
235
- }
236
- }
237
- }
238
- }else{
239
- $this->tickets->event_id = $this->event_id;
240
- }
241
- return apply_filters('em_bookings_get_tickets', $this->tickets, $this);
242
- }
243
-
244
- /**
245
- * Returns EM_Tickets object with available tickets
246
- * @param boolean $include_member_tickets - if set to true, member-ony tickets will be considered available even if logged out
247
- * @return EM_Tickets
248
- */
249
- function get_available_tickets( $include_member_tickets = false ){
250
- $tickets = array();
251
- foreach ($this->get_tickets() as $EM_Ticket){
252
- /* @var $EM_Ticket EM_Ticket */
253
- if( $EM_Ticket->is_available($include_member_tickets) ){
254
- //within time range
255
- if( $EM_Ticket->get_available_spaces() > 0 ){
256
- $tickets[] = $EM_Ticket;
257
- }
258
- }
259
- }
260
- $EM_Tickets = new EM_Tickets($tickets);
261
- return apply_filters('em_bookings_get_available_tickets', $EM_Tickets, $this);
262
- }
263
-
264
- /**
265
- * Deprecated - was never used and therefore is deprecated, will always return an array() and will eventually be removed entirely.
266
- * @return array
267
- */
268
- function get_user_list(){
269
- return array();
270
- }
271
-
272
- /**
273
- * Returns a boolean indicating whether this ticket exists in this bookings context.
274
- * @return bool
275
- */
276
- function ticket_exists($ticket_id){
277
- $EM_Tickets = $this->get_tickets();
278
- foreach( $EM_Tickets->tickets as $EM_Ticket){
279
- if($EM_Ticket->ticket_id == $ticket_id){
280
- return apply_filters('em_bookings_ticket_exists',true, $EM_Ticket, $this);
281
- }
282
- }
283
- return apply_filters('em_bookings_ticket_exists',false, false,$this);
284
- }
285
-
286
- function has_space( $include_member_tickets = false ){
287
- return count($this->get_available_tickets( $include_member_tickets )->tickets) > 0;
288
- }
289
-
290
- function has_open_time(){
291
- $return = false;
292
- $EM_Event = $this->get_event();
293
- if( $EM_Event->rsvp_end()->getTimestamp() > time()){
294
- $return = true;
295
- }
296
- return $return;
297
- }
298
-
299
- function is_open($include_member_tickets = false){
300
- //TODO extend booking options
301
- $return = $this->has_open_time() && $this->has_space($include_member_tickets);
302
- return apply_filters('em_bookings_is_open', $return, $this, $include_member_tickets);
303
- }
304
-
305
- /**
306
- * Delete bookings on this id
307
- * @return boolean
308
- */
309
- function delete(){
310
- global $wpdb;
311
- $booking_ids = array();
312
- if( !empty($this->bookings) ){
313
- //get the booking ids tied to this event or preloaded into this object
314
- foreach( $this->bookings as $EM_Booking ){
315
- $booking_ids[] = $EM_Booking->booking_id;
316
- }
317
- $result_tickets = true;
318
- $result = true;
319
- if( count($booking_ids) > 0 ){
320
- //Delete bookings and ticket bookings
321
- $result_tickets = $wpdb->query("DELETE FROM ". EM_TICKETS_BOOKINGS_TABLE ." WHERE booking_id IN (".implode(',',$booking_ids).");");
322
- $result = $wpdb->query("DELETE FROM ".EM_BOOKINGS_TABLE." WHERE booking_id IN (".implode(',',$booking_ids).")");
323
- }
324
- }elseif( !empty($this->event_id) ){
325
- //faster way of deleting bookings for an event circumventing the need to load all bookings if it hasn't been loaded already
326
- $event_id = absint($this->event_id);
327
- $booking_ids = $wpdb->get_col("SELECT booking_id FROM ".EM_BOOKINGS_TABLE." WHERE event_id = '$event_id'");
328
- $result_tickets = $wpdb->query("DELETE FROM ". EM_TICKETS_BOOKINGS_TABLE ." WHERE booking_id IN (SELECT booking_id FROM ".EM_BOOKINGS_TABLE." WHERE event_id = '$event_id')");
329
- $result = $wpdb->query("DELETE FROM ".EM_BOOKINGS_TABLE." WHERE event_id = '$event_id'");
330
- }else{
331
- //we have not bookings loaded to delete, nor an event to delete bookings from, so bookings are considered 'deleted' since there's nothing ot delete
332
- $result = $result_tickets = true;
333
- }
334
- do_action('em_bookings_deleted', $result, $booking_ids);
335
- return apply_filters('em_bookings_delete', $result !== false && $result_tickets !== false, $booking_ids, $this);
336
- }
337
-
338
-
339
- /**
340
- * Will approve all supplied booking ids, which must be in the form of a numeric array or a single number.
341
- * @param array|int $booking_ids
342
- * @return boolean
343
- */
344
- function approve( $booking_ids ){
345
- $this->set_status(1, $booking_ids);
346
- return false;
347
- }
348
-
349
- /**
350
- * Will reject all supplied booking ids, which must be in the form of a numeric array or a single number.
351
- * @param array|int $booking_ids
352
- * @return boolean
353
- */
354
- function reject( $booking_ids ){
355
- return $this->set_status(2, $booking_ids);
356
- }
357
-
358
- /**
359
- * Will unapprove all supplied booking ids, which must be in the form of a numeric array or a single number.
360
- * @param array|int $booking_ids
361
- * @return boolean
362
- */
363
- function unapprove( $booking_ids ){
364
- return $this->set_status(0, $booking_ids);
365
- }
366
-
367
- /**
368
- * @param int $status
369
- * @param array|int $booking_ids
370
- * @param bool $send_email
371
- * @param bool $ignore_spaces
372
- * @return bool
373
- */
374
- function set_status( $status, $booking_ids, $send_email = true, $ignore_spaces = false ){
375
- //FIXME status should work with instantiated object
376
- if( self::array_is_numeric($booking_ids) ){
377
- //Get all the bookings
378
- $results = array();
379
- $mails = array();
380
- foreach( $booking_ids as $booking_id ){
381
- $EM_Booking = em_get_booking($booking_id);
382
- if( !$EM_Booking->can_manage() ){
383
- $this->feedback_message = __('Bookings %s. Mails Sent.', 'events-manager');
384
- return false;
385
- }
386
- $results[] = $EM_Booking->set_status($status, $send_email, $ignore_spaces);
387
- }
388
- if( !in_array('false',$results) ){
389
- $this->feedback_message = __('Bookings %s. Mails Sent.', 'events-manager');
390
- return true;
391
- }else{
392
- //TODO Better error handling needed if some bookings fail approval/failure
393
- $this->feedback_message = __('An error occurred.', 'events-manager');
394
- return false;
395
- }
396
- }elseif( is_numeric($booking_ids) || is_object($booking_ids) ){
397
- $EM_Booking = ( is_object($booking_ids) && get_class($booking_ids) == 'EM_Booking') ? $booking_ids : em_get_booking($booking_ids);
398
- $result = $EM_Booking->set_status($status);
399
- $this->feedback_message = $EM_Booking->feedback_message;
400
- return $result;
401
- }
402
- return false;
403
- }
404
-
405
-
406
- /**
407
- * Get the total number of spaces this event has. This will show the lower value of event global spaces limit or total ticket spaces. Setting $force_refresh to true will recheck spaces, even if previously done so.
408
- * @param boolean $force_refresh
409
- * @return int
410
- */
411
- function get_spaces( $force_refresh=false ){
412
- if($force_refresh || $this->spaces == 0){
413
- $this->spaces = $this->get_tickets()->get_spaces();
414
- }
415
- //check overall events cap
416
- if(!empty($this->get_event()->event_spaces) && $this->get_event()->event_spaces < $this->spaces) $this->spaces = $this->get_event()->event_spaces;
417
- return apply_filters('em_booking_get_spaces',$this->spaces,$this);
418
- }
419
-
420
- /**
421
- * Returns number of available spaces for this event. If approval of bookings is on, will include pending bookings depending on em option.
422
- * @return int
423
- */
424
- function get_available_spaces(){
425
- $spaces = $this->get_spaces();
426
- $available_spaces = $spaces - $this->get_booked_spaces();
427
- if( get_option('dbem_bookings_approval_reserved') ){ //deduct reserved/pending spaces from available spaces
428
- $available_spaces -= $this->get_pending_spaces();
429
- }
430
- return apply_filters('em_booking_get_available_spaces', $available_spaces, $this);
431
- }
432
-
433
- /**
434
- * Returns number of booked spaces for this event. If approval of bookings is on, will return number of booked confirmed spaces.
435
- * @return int
436
- */
437
- function get_booked_spaces($force_refresh = false){
438
- global $wpdb;
439
- if( $this->booked_spaces === null || $force_refresh ){
440
- $status_cond = !get_option('dbem_bookings_approval') ? 'booking_status IN (0,1)' : 'booking_status = 1';
441
- $sql = 'SELECT SUM(booking_spaces) FROM '.EM_BOOKINGS_TABLE. " WHERE $status_cond AND event_id=".absint($this->event_id);
442
- $booked_spaces = $wpdb->get_var($sql);
443
- $this->booked_spaces = $booked_spaces > 0 ? $booked_spaces : 0;
444
- }
445
- return apply_filters('em_bookings_get_booked_spaces', $this->booked_spaces, $this, $force_refresh);
446
- }
447
-
448
- /**
449
- * Gets number of pending spaces awaiting approval. Will return 0 if booking approval is not enabled.
450
- * @return int
451
- */
452
- function get_pending_spaces( $force_refresh = false ){
453
- if( get_option('dbem_bookings_approval') == 0 ){
454
- return apply_filters('em_bookings_get_pending_spaces', 0, $this);
455
- }
456
- global $wpdb;
457
- if( $this->pending_spaces === null || $force_refresh ){
458
- $sql = 'SELECT SUM(booking_spaces) FROM '.EM_BOOKINGS_TABLE. ' WHERE booking_status=0 AND event_id='.absint($this->event_id);
459
- $pending_spaces = $wpdb->get_var($sql);
460
- $this->pending_spaces = $pending_spaces > 0 ? $pending_spaces : 0;
461
- }
462
- return apply_filters('em_bookings_get_pending_spaces', $this->pending_spaces, $this, $force_refresh);
463
- }
464
-
465
- /**
466
- * Gets booking objects (not spaces). If booking approval is enabled, only the number of approved bookings will be shown.
467
- * @param boolean $all_bookings If set to true, then all bookings with any status is returned
468
- * @return EM_Bookings
469
- */
470
- function get_bookings( $all_bookings = false ){
471
- $confirmed = array();
472
- foreach ( $this->load() as $EM_Booking ){
473
- if( $EM_Booking->booking_status == 1 || (get_option('dbem_bookings_approval') == 0 && $EM_Booking->booking_status == 0) || $all_bookings ){
474
- $confirmed[] = $EM_Booking;
475
- }
476
- }
477
- $EM_Bookings = new EM_Bookings($confirmed);
478
- return $EM_Bookings;
479
- }
480
-
481
- /**
482
- * Get pending bookings. If booking approval is disabled, will return no bookings.
483
- * @return EM_Bookings
484
- */
485
- function get_pending_bookings(){
486
- if( get_option('dbem_bookings_approval') == 0 ){
487
- return new EM_Bookings();
488
- }
489
- $pending = array();
490
- foreach ( $this->load() as $EM_Booking ){
491
- if($EM_Booking->booking_status == 0){
492
- $pending[] = $EM_Booking;
493
- }
494
- }
495
- $EM_Bookings = new EM_Bookings($pending);
496
- return $EM_Bookings;
497
- }
498
-
499
- /**
500
- * Get rejected bookings. If booking approval is disabled, will return no bookings.
501
- * @return array EM_Bookings
502
- */
503
- function get_rejected_bookings(){
504
- $rejected = array();
505
- foreach ( $this->load() as $EM_Booking ){
506
- if($EM_Booking->booking_status == 2){
507
- $rejected[] = $EM_Booking;
508
- }
509
- }
510
- $EM_Bookings = new EM_Bookings($rejected);
511
- return $EM_Bookings;
512
- }
513
-
514
- /**
515
- * Get cancelled bookings.
516
- * @return array EM_Booking
517
- */
518
- function get_cancelled_bookings(){
519
- $cancelled = array();
520
- foreach ( $this->load() as $EM_Booking ){
521
- if($EM_Booking->booking_status == 3){
522
- $cancelled[] = $EM_Booking;
523
- }
524
- }
525
- $EM_Bookings = new EM_Bookings($cancelled);
526
- return $EM_Bookings;
527
- }
528
-
529
- /**
530
- * Checks if a person with similar details has booked for this before
531
- * @param $person_id
532
- * @return EM_Booking
533
- */
534
- function find_previous_booking($EM_Booking){
535
- //First see if we have a similar person on record that's making this booking
536
- $EM_Booking->person->load_similar();
537
- //If person exists on record, see if they've booked this event before, if so return the booking.
538
- if( is_numeric($EM_Booking->person->ID) && $EM_Booking->person->ID > 0 ){
539
- $EM_Booking->person_id = $EM_Booking->person->ID;
540
- foreach ($this->load() as $booking){
541
- if( $booking->person_id == $EM_Booking->person->ID ){
542
- return $booking;
543
- }
544
- }
545
- }
546
- return false;
547
- }
548
-
549
- /**
550
- * Checks to see if user has a booking for this event
551
- * @param int $user_id
552
- */
553
- function has_booking( $user_id = false ){
554
- if( $user_id === false ){
555
- $user_id = get_current_user_id();
556
- }
557
- if( is_numeric($user_id) && $user_id > 0 ){
558
- global $wpdb;
559
- // get the first booking ID available and return that
560
- $sql = $wpdb->prepare('SELECT booking_id FROM '.EM_BOOKINGS_TABLE.' WHERE event_id = %d AND person_id = %d AND booking_status NOT IN (2,3)', $this->event_id, $user_id);
561
- $booking_id = $wpdb->get_var($sql);
562
- if( (int) $booking_id > 0 ){
563
- $EM_Booking = em_get_booking($booking_id);
564
- return apply_filters('em_bookings_has_booking', $EM_Booking, $this);
565
- }
566
- }
567
- return apply_filters('em_bookings_has_booking', false, $this);
568
- }
569
-
570
- /**
571
- * Get bookings that match the array of arguments passed.
572
- * @return array
573
- * @static
574
- */
575
- public static function get( $args = array(), $count = false ){
576
- global $wpdb,$current_user;
577
- $bookings_table = EM_BOOKINGS_TABLE;
578
- $events_table = EM_EVENTS_TABLE;
579
- $locations_table = EM_LOCATIONS_TABLE;
580
-
581
- //Quick version, we can accept an array of IDs, which is easy to retrieve
582
- if( self::array_is_numeric($args) ){ //Array of numbers, assume they are event IDs to retreive
583
- //We can just get all the events here and return them
584
- $sql = "
585
- SELECT * FROM $bookings_table b
586
- LEFT JOIN $events_table e ON e.event_id=b.event_id
587
- WHERE booking_id=".implode(" OR booking_id=", $args);
588
- $results = $wpdb->get_results(apply_filters('em_bookings_get_sql',$sql),ARRAY_A);
589
- $bookings = array();
590
- foreach($results as $result){
591
- $bookings[] = em_get_booking($result);
592
- }
593
- return $bookings; //We return all the bookings matched as an EM_Booking array.
594
- }
595
-
596
- //We assume it's either an empty array or array of search arguments to merge with defaults
597
- $args = self::get_default_search($args);
598
- $limit = ( $args['limit'] && is_numeric($args['limit'])) ? "LIMIT {$args['limit']}" : '';
599
- $offset = ( $limit != "" && is_numeric($args['offset']) ) ? "OFFSET {$args['offset']}" : '';
600
-
601
- //Get the default conditions
602
- $conditions = self::build_sql_conditions($args);
603
- //Put it all together
604
- $where = ( count($conditions) > 0 ) ? " WHERE " . implode ( " AND ", $conditions ):'';
605
-
606
- //Get ordering instructions
607
- $EM_Booking = new EM_Booking();
608
- $accepted_fields = $EM_Booking->get_fields(true);
609
- $accepted_fields['date'] = 'booking_date';
610
- $orderby = self::build_sql_orderby($args, $accepted_fields);
611
- //Now, build orderby sql
612
- $orderby_sql = ( count($orderby) > 0 ) ? 'ORDER BY '. implode(', ', $orderby) : 'ORDER BY booking_date';
613
- //Selectors
614
- if( $count ){
615
- $selectors = 'COUNT(*)';
616
- }elseif( is_array($args['array']) ){
617
- $selectors = implode(',', $args['array']);
618
- }else{
619
- $selectors = '*';
620
- }
621
- //Create the SQL statement and execute
622
- $sql = apply_filters('em_bookings_get_sql',"
623
- SELECT $selectors FROM $bookings_table
624
- LEFT JOIN $events_table ON {$events_table}.event_id={$bookings_table}.event_id
625
- LEFT JOIN $locations_table ON {$locations_table}.location_id={$events_table}.location_id
626
- $where
627
- $orderby_sql
628
- $limit $offset
629
- ", $args);
630
-
631
- //If we're only counting results, return the number of results
632
- if( $count ){
633
- return apply_filters('em_bookings_get_count', $wpdb->get_var($sql), $args);
634
- }
635
- $results = $wpdb->get_results($sql, ARRAY_A);
636
-
637
- //If we want results directly in an array, why not have a shortcut here?
638
- if( !empty($args['array']) ){
639
- return $results;
640
- }
641
-
642
- //Make returned results EM_Booking objects
643
- $results = (is_array($results)) ? $results:array();
644
- $bookings = array();
645
- foreach ( $results as $booking ){
646
- $bookings[] = em_get_booking($booking);
647
- }
648
- $EM_Bookings = new EM_Bookings($bookings);
649
- return apply_filters('em_bookings_get', $EM_Bookings);
650
- }
651
-
652
- public static function count( $args = array() ){
653
- return self::get($args, true);
654
- }
655
-
656
-
657
- //List of patients in the patient database, that a user can choose and go on to edit any previous treatment data, or add a new admission.
658
- //Deprecated
659
- //@todo remove in 6.0
660
- function export_csv() {
661
- global $EM_Event;
662
- if($EM_Event->event_id != $this->event_id ){
663
- $event = $this->get_event();
664
- $event_name = $event->name;
665
- }else{
666
- $event_name = $EM_Event->name;
667
- }
668
- // The name of the file on the user's pc
669
- $file_name = sanitize_title($event_name). "-bookings.csv";
670
-
671
- header("Content-Type: application/octet-stream");
672
- header("Content-Disposition: Attachment; filename=$file_name");
673
- em_locate_template('templates/csv-event-bookings.php', true);
674
- exit();
675
- }
676
-
677
- static function enqueue_js(){
678
- if( !defined('EM_BOOKING_JS_LOADED') ){ //request loading of JS file in footer of page load
679
- add_action('wp_footer','EM_Bookings::em_booking_js_footer', 20);
680
- add_action('admin_footer','EM_Bookings::em_booking_js_footer', 20);
681
- define('EM_BOOKING_JS_LOADED',true);
682
- }
683
- }
684
-
685
- static function em_booking_js_footer(){
686
- ?>
687
- <script type="text/javascript">
688
- jQuery(document).ready( function($){
689
- <?php
690
- //we call the segmented JS files and include them here
691
- $include_path = dirname(dirname(__FILE__)); //get path to parent directory
692
- include($include_path.'/includes/js/bookingsform.js');
693
- do_action('em_gateway_js'); //deprecated use em_booking_js below instead
694
- do_action('em_booking_js'); //use this instead
695
- ?>
696
- });
697
- <?php
698
- do_action('em_booking_js_footer');
699
- ?>
700
- </script>
701
- <?php
702
- }
703
-
704
- /**
705
- * Checks whether a booking being made should register user information as a booking from another user whilst an admin is logged in
706
- * @return boolean
707
- */
708
- public static function is_registration_forced(){
709
- return ( defined('EM_FORCE_REGISTRATION') || self::$force_registration );
710
- }
711
-
712
- /* Overrides EM_Object method to apply a filter to result
713
- * @see wp-content/plugins/events-manager/classes/EM_Object#build_sql_conditions()
714
- */
715
- public static function build_sql_conditions( $args = array() ){
716
- $conditions = apply_filters( 'em_bookings_build_sql_conditions', parent::build_sql_conditions($args), $args );
717
- if( is_numeric($args['status']) ){
718
- $conditions['status'] = 'booking_status='.$args['status'];
719
- }elseif( self::array_is_numeric($args['status']) && count($args['status']) > 0 ){
720
- $conditions['status'] = 'booking_status IN ('.implode(',',$args['status']).')';
721
- }elseif( !is_array($args['status']) && preg_match('/^([0-9],?)+$/', $args['status']) ){
722
- $conditions['status'] = 'booking_status IN ('.$args['status'].')';
723
- }
724
- if( is_numeric($args['person']) ){
725
- $conditions['person'] = EM_BOOKINGS_TABLE.'.person_id='.$args['person'];
726
- }
727
- if( EM_MS_GLOBAL && !empty($args['blog']) && is_numeric($args['blog']) ){
728
- if( is_main_site($args['blog']) ){
729
- $conditions['blog'] = "(".EM_EVENTS_TABLE.".blog_id={$args['blog']} OR ".EM_EVENTS_TABLE.".blog_id IS NULL)";
730
- }else{
731
- $conditions['blog'] = "(".EM_EVENTS_TABLE.".blog_id={$args['blog']})";
732
- }
733
- }
734
- if( empty($conditions['event']) && $args['event'] === false ){
735
- $conditions['event'] = EM_BOOKINGS_TABLE.'.event_id != 0';
736
- }
737
- if( is_numeric($args['ticket_id']) ){
738
- $EM_Ticket = new EM_Ticket($args['ticket_id']);
739
- if( $EM_Ticket->can_manage() ){
740
- $conditions['ticket'] = EM_BOOKINGS_TABLE.'.booking_id IN (SELECT booking_id FROM '.EM_TICKETS_BOOKINGS_TABLE." WHERE ticket_id='{$args['ticket_id']}')";
741
- }
742
- }
743
- return apply_filters('em_bookings_build_sql_conditions', $conditions, $args);
744
- }
745
-
746
- /* Overrides EM_Object method to apply a filter to result
747
- * @see wp-content/plugins/events-manager/classes/EM_Object#build_sql_orderby()
748
- */
749
- public static function build_sql_orderby( $args, $accepted_fields, $default_order = 'ASC' ){
750
- return apply_filters( 'em_bookings_build_sql_orderby', parent::build_sql_orderby($args, $accepted_fields, get_option('dbem_bookings_default_order','booking_date')), $args, $accepted_fields, $default_order );
751
- }
752
-
753
- /*
754
- * Adds custom Events search defaults
755
- * @param array $array_or_defaults may be the array to override defaults
756
- * @param array $array
757
- * @return array
758
- * @uses EM_Object#get_default_search()
759
- */
760
- public static function get_default_search( $array_or_defaults = array(), $array = array() ){
761
- $defaults = array(
762
- 'status' => false,
763
- 'person' => true, //to add later, search by person's bookings...
764
- 'blog' => get_current_blog_id(),
765
- 'ticket_id' => false,
766
- 'array' => false //returns an array of results if true, if an array or text it's assumed an array of specific table fields or single field name requested
767
- );
768
- //sort out whether defaults were supplied or just the array of search values
769
- if( empty($array) ){
770
- $array = $array_or_defaults;
771
- }else{
772
- $defaults = array_merge($defaults, $array_or_defaults);
773
- }
774
- //clean up array value
775
- if( !empty($args['array']) ){
776
- $EM_Booking = new EM_Booking();
777
- if( is_array($args['array']) ){
778
- $clean_arg = array();
779
- foreach( $args['array'] as $k => $field ){
780
- if( array_key_exists($field, $EM_Booking->fields) ){
781
- $clean_arg[] = $field;
782
- }
783
- }
784
- $args['array'] = !empty($clean_arg) ? $clean_arg : true; //if invalid args given, just return all fields
785
- }elseif( is_string($args['array']) && array_key_exists($args['array'], $EM_Booking->fields) ){
786
- $args['array'] = array($args['array']);
787
- }else{
788
- $args['array'] = true;
789
- }
790
- }else{
791
- $args['array'] = false;
792
- }
793
- //figure out default owning permissions
794
- if( !current_user_can('edit_others_events') ){
795
- $defaults['owner'] = get_current_user_id();
796
- }else{
797
- $defaults['owner'] = false;
798
- }
799
- if( EM_MS_GLOBAL && !is_admin() ){
800
- if( empty($array['blog']) && is_main_site() && get_site_option('dbem_ms_global_events') ){
801
- $array['blog'] = false;
802
- }
803
- }
804
- return apply_filters('em_bookings_get_default_search', parent::get_default_search($defaults,$array), $array, $defaults);
805
- }
806
-
807
- //Iterator Implementation - if we iterate this object, we automatically invoke the load() function first
808
- //and load up all bookings to go through from the database.
809
- public function rewind(){
810
- $this->load();
811
- reset($this->bookings);
812
- }
813
- public function current(){
814
- $this->load();
815
- $var = current($this->bookings);
816
- return $var;
817
- }
818
- public function key(){
819
- $this->load();
820
- $var = key($this->bookings);
821
- return $var;
822
- }
823
- public function next(){
824
- $this->load();
825
- $var = next($this->bookings);
826
- return $var;
827
- }
828
- public function valid(){
829
- $this->load();
830
- $key = key($this->bookings);
831
- $var = ($key !== NULL && $key !== FALSE);
832
- return $var;
833
- }
834
- }
835
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-calendar.php DELETED
@@ -1,485 +0,0 @@
1
- <?php
2
- class EM_Calendar extends EM_Object {
3
-
4
- public static function init(){
5
- //nothing to init anymore
6
- }
7
-
8
- public static function get( $args ){
9
-
10
- global $wpdb, $wp_rewrite;
11
-
12
- $calendar_array = array();
13
- $calendar_array['cells'] = array();
14
-
15
- $args = apply_filters('em_calendar_get_args', $args);
16
- $original_args = $args;
17
- $args = self::get_default_search($args);
18
- $full = $args['full']; //For ZDE, don't delete pls
19
- //figure out what month to look for, if we need to
20
- if( empty($args['month']) && is_array($args['scope']) ){
21
- //if a scope is supplied, figure out the month/year we're after, which will be between these two dates.
22
- $EM_DateTime = new EM_DateTime($args['scope'][0]);
23
- $scope_start = $EM_DateTime->getTimestamp();
24
- $scope_end = $EM_DateTime->modify($args['scope'][1])->getTimestamp();
25
- $EM_DateTime->setTimestamp( $scope_start + ($scope_end - $scope_start)/2 );
26
- $month = $args['month'] = $EM_DateTime->format('n');
27
- $year = $args['year'] = $EM_DateTime->format('Y');
28
- }else{
29
- //if month/year supplied, we use those or later on default to current month/year
30
- $month = $args['month'];
31
- $year = $args['year'];
32
- }
33
- $long_events = $args['long_events'];
34
- $limit = $args['limit']; //limit arg will be used per day and not for events search
35
-
36
- $start_of_week = get_option('start_of_week');
37
-
38
- if( !(is_numeric($month) && $month <= 12 && $month > 0) ) {
39
- $month = date('m', current_time('timestamp'));
40
- }
41
- if( !( is_numeric($year) ) ){
42
- $year = date('Y', current_time('timestamp'));
43
- }
44
-
45
- // Get the first day of the month
46
- $month_start = mktime(0,0,0,$month, 1, $year);
47
- $calendar_array['month_start'] = $month_start;
48
-
49
- // Get friendly month name
50
- $month_name = date('M',$month_start);
51
- // Figure out which day of the week
52
- // the month starts on.
53
- $month_start_day = date('D', $month_start);
54
-
55
- switch($month_start_day){
56
- case "Sun": $offset = 0; break;
57
- case "Mon": $offset = 1; break;
58
- case "Tue": $offset = 2; break;
59
- case "Wed": $offset = 3; break;
60
- case "Thu": $offset = 4; break;
61
- case "Fri": $offset = 5; break;
62
- case "Sat": $offset = 6; break;
63
- }
64
- //We need to go back to the WP defined day when the week started, in case the event day is near the end
65
- $offset -= $start_of_week;
66
- if($offset<0)
67
- $offset += 7;
68
-
69
- // determine how many days are in the last month.
70
- $month_last = $month-1;
71
- $month_next = $month+1;
72
- $year_last = $year;
73
- $year_next = $year;
74
-
75
- if($month == 1) {
76
- $month_last = 12;
77
- $year_last = $year -1;
78
- }elseif($month == 12){
79
- $month_next = 1;
80
- $year_next = $year + 1;
81
- }
82
- $calendar_array['month_next'] = $month_next;
83
- $calendar_array['month_last'] = $month_last;
84
- $calendar_array['year_last'] = $year_last;
85
- $calendar_array['year_next'] = $year_next;
86
-
87
- $num_days_last = self::days_in_month($month_last, $year_last);
88
-
89
- // determine how many days are in the current month.
90
- $num_days_current = self::days_in_month($month, $year);
91
- // Build an array for the current days
92
- // in the month
93
- for($i = 1; $i <= $num_days_current; $i++){
94
- $num_days_array[] = mktime(0,0,0,$month, $i, $year);
95
- }
96
- // Build an array for the number of days
97
- // in last month
98
- for($i = 1; $i <= $num_days_last; $i++){
99
- $num_days_last_array[] = mktime(0,0,0,$month_last, $i, $year_last);
100
- }
101
- // If the $offset from the starting day of the
102
- // week happens to be Sunday, $offset would be 0,
103
- // so don't need an offset correction.
104
-
105
- if($offset > 0){
106
- $offset_correction = array_slice($num_days_last_array, -$offset, $offset);
107
- $new_count = array_merge($offset_correction, $num_days_array);
108
- $offset_count = count($offset_correction);
109
- } else { // The else statement is to prevent building the $offset array.
110
- $offset_count = 0;
111
- $new_count = $num_days_array;
112
- }
113
- // count how many days we have with the two
114
- // previous arrays merged together
115
- $current_num = count($new_count);
116
-
117
- // Since we will have 5 HTML table rows (TR)
118
- // with 7 table data entries (TD)
119
- // we need to fill in 35 TDs
120
- // so, we will have to figure out
121
- // how many days to appened to the end
122
- // of the final array to make it 35 days.
123
- if( !empty($args['number_of_weeks']) && is_numeric($args['number_of_weeks']) ){
124
- $num_weeks = $args['number_of_weeks'];
125
- }elseif($current_num > 35){
126
- $num_weeks = 6;
127
- }else{
128
- $num_weeks = 5;
129
- }
130
- $outset = ($num_weeks * 7) - $current_num;
131
- // Outset Correction
132
- for($i = 1; $i <= $outset; $i++){
133
- $new_count[] = mktime(0,0,0,$month_next, $i, $year_next);
134
- }
135
- // Now let's "chunk" the $all_days array
136
- // into weeks. Each week has 7 days
137
- // so we will array_chunk it into 7 days.
138
- $weeks = array_chunk($new_count, 7);
139
-
140
- //Get an array of arguments that don't include default valued args
141
- $link_args = self::get_query_args($args);
142
- $link_args['ajaxCalendar'] = 1;
143
- $previous_url = esc_url_raw(add_query_arg( array_merge($link_args, array('mo'=>$month_last, 'yr'=>$year_last)) ));
144
- $next_url = esc_url_raw(add_query_arg( array_merge($link_args, array('mo'=>$month_next, 'yr'=>$year_next)) ));
145
-
146
- $weekdays = array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
147
- if(!empty($args['full'])) {
148
- if( get_option('dbem_full_calendar_abbreviated_weekdays') ) $weekdays = array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
149
- $day_initials_length = get_option('dbem_full_calendar_initials_length');
150
- } else {
151
- if ( get_option('dbem_small_calendar_abbreviated_weekdays') ) $weekdays = array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
152
- $day_initials_length = get_option('dbem_small_calendar_initials_length');
153
- }
154
-
155
- for( $n = 0; $n < $start_of_week; $n++ ) {
156
- $last_day = array_shift($weekdays);
157
- $weekdays[]= $last_day;
158
- }
159
-
160
- $days_initials_array = array();
161
- //translate day names, some languages may have special circumstances
162
- if( $day_initials_length == 1 && in_array(EM_ML::$current_language, array('zh_CN', 'zh_TW')) ){
163
- //Chinese single initial day names are different
164
- $days_initials_array = array('日','一','二','三','四','五','六');
165
- }else{
166
- //all other languages
167
- foreach($weekdays as $weekday) {
168
- $days_initials_array[] = esc_html(self::translate_and_trim($weekday, $day_initials_length));
169
- }
170
- }
171
-
172
- $calendar_array['links'] = array( 'previous_url'=>$previous_url, 'next_url'=>$next_url);
173
- $calendar_array['row_headers'] = $days_initials_array;
174
-
175
- // Now we break each key of the array
176
- // into a week and create a new table row for each
177
- // week with the days of that week in the table data
178
-
179
- $i = 0;
180
- $current_date = date('Y-m-d', current_time('timestamp'));
181
- $week_count = 0;
182
- foreach ( $weeks as $week ) {
183
- foreach ( $week as $d ) {
184
- $date = date('Y-m-d', $d);
185
- $calendar_array['cells'][$date] = array('date'=>$d, 'events'=>array(), 'events_count'=>0); //set it up so we have the exact array of dates to be filled
186
- if ($i < $offset_count) { //if it is PREVIOUS month
187
- $calendar_array['cells'][$date]['type'] = 'pre';
188
- }
189
- if (($i >= $offset_count) && ($i < ($num_weeks * 7) - $outset)) { // if it is THIS month
190
- if ( $current_date == $date ){
191
- $calendar_array['cells'][$date]['type'] = 'today';
192
- }
193
- } elseif (($outset > 0)) { //if it is NEXT month
194
- if (($i >= ($num_weeks * 7) - $outset)) {
195
- $calendar_array['cells'][$date]['type'] = 'post';
196
- }
197
- }
198
- $i ++;
199
- }
200
- $week_count++;
201
- }
202
-
203
- //query the database for events in this time span with $offset days before and $outset days after this month to account for these cells in the calendar
204
- $scope_datetime_start = new EM_DateTime("{$year}-{$month}-1");
205
- $scope_datetime_end = new EM_DateTime($scope_datetime_start->format('Y-m-t'));
206
- $scope_datetime_start->sub('P'.$offset.'D');
207
- $scope_datetime_end->add('P'.$outset.'D');
208
- //we have two methods here, one for high-volume event sites i.e. many thousands of events per month, and another for thousands or less per month.
209
- $args['array'] = true; //we're getting an array first to avoid extra queries during object creation
210
- unset($args['month']);
211
- unset($args['year']);
212
- unset($args['limit']); //limits in the events search won't help
213
- if( defined('EM_CALENDAR_OPT') && EM_CALENDAR_OPT ){
214
- //here we loop through each day, query that specific date, and then compile a list of event objects
215
- //in this mode the count will never be accurate, we're grabing at most (31 + 14 days) * (limit + 1) events to reduce memory loads
216
- $args['limit'] = $limit + 1;
217
- $scope_datetime_loop = $scope_datetime_start->format('U');
218
- $events = array();
219
- while( $scope_datetime_loop <= $scope_datetime_end->format('U') ){
220
- $args['scope'] = date('Y-m-d', $scope_datetime_loop);
221
- foreach( EM_Events::get($args) as $event ){
222
- $events[$event['event_id']] = $event;
223
- }
224
- $scope_datetime_loop += (86400); //add a day
225
- }
226
- }else{
227
- //just load all the events for this time-range
228
- $args['scope'] = array( $scope_datetime_start->format('Y-m-d'), $scope_datetime_end->format('Y-m-d'));
229
- $events = EM_Events::get($args);
230
- }
231
- //back to what it was
232
- $args['month'] = $month;
233
- $args['year'] = $year;
234
- $args['limit'] = $limit;
235
-
236
- $event_format = get_option('dbem_full_calendar_event_format');
237
- $event_title_format = get_option('dbem_small_calendar_event_title_format');
238
- $event_title_separator_format = get_option('dbem_small_calendar_event_title_separator');
239
-
240
- $eventful_days= array();
241
- $eventful_days_count = array();
242
- if($events){
243
- //Go through the events and slot them into the right d-m index
244
- foreach($events as $event) {
245
- $event = apply_filters('em_calendar_output_loop_start', $event);
246
- if( $long_events ){
247
- //If $long_events is set then show a date as eventful if there is an multi-day event which runs during that day
248
- $event_start = new EM_DateTime($event['event_start_date'], $event['event_timezone']);
249
- $event_end = new EM_DateTime($event['event_end_date'], $event['event_timezone']);
250
- if( $event_end->getTimestamp() > $scope_datetime_end->getTimestamp() ) $event_end = $scope_datetime_end;
251
- while( $event_start->getTimestamp() <= $event_end->getTimestamp() ){ //we loop until the last day of our time-range, not the end date of the event, which could be in a year
252
- //Ensure date is within event dates and also within the limits of events to show per day, if so add to eventful days array
253
- $event_eventful_date = $event_start->getDate();
254
- if( empty($eventful_days_count[$event_eventful_date]) || !$limit || $eventful_days_count[$event_eventful_date] < $limit ){
255
- //now we know this is an event that'll be used, convert it to an object
256
- $EM_Event = EM_MS_GLOBAL ? em_get_event($event['post_id'], $event['blog_id']) : $EM_Event = em_get_event($event['post_id'], 'post_id');
257
- if( empty($eventful_days[$event_eventful_date]) || !is_array($eventful_days[$event_eventful_date]) ) $eventful_days[$event_eventful_date] = array();
258
- //add event to array with a corresponding timestamp for sorting of times including long and all-day events
259
- $event_ts_marker = ($EM_Event->event_all_day) ? 0 : (int) $event_start->getTimestamp();
260
- while( !empty($eventful_days[$event_eventful_date][$event_ts_marker]) ){
261
- $event_ts_marker++; //add a second
262
- }
263
- $eventful_days[$event_eventful_date][$event_ts_marker] = $EM_Event;
264
- }
265
- //count events for that day
266
- $eventful_days_count[$event_eventful_date] = empty($eventful_days_count[$event_eventful_date]) ? 1 : $eventful_days_count[$event_eventful_date]+1;
267
- $event_start->add('P1D');
268
- }
269
- }else{
270
- //Only show events on the day that they start
271
- $event_eventful_date = $event['event_start_date'];
272
- if( empty($eventful_days_count[$event_eventful_date]) || !$limit || $eventful_days_count[$event_eventful_date] < $limit ){
273
- $EM_Event = EM_MS_GLOBAL ? em_get_event($event['post_id'], $event['blog_id']) : em_get_event($event['post_id'], 'post_id');
274
- if( empty($eventful_days[$event_eventful_date]) || !is_array($eventful_days[$event_eventful_date]) ) $eventful_days[$event_eventful_date] = array();
275
- //add event to array with a corresponding timestamp for sorting of times including long and all-day events
276
- $event_ts_marker = ($EM_Event->event_all_day) ? 0 : (int) $EM_Event->start()->getTimestamp();
277
- while( !empty($eventful_days[$event_eventful_date][$event_ts_marker]) ){
278
- $event_ts_marker++; //add a second
279
- }
280
- $eventful_days[$event_eventful_date][$event_ts_marker] = $EM_Event;
281
- }
282
- //count events for that day
283
- $eventful_days_count[$event['event_start_date']] = empty($eventful_days_count[$event['event_start_date']]) ? 1 : $eventful_days_count[$event['event_start_date']]+1;
284
- }
285
- }
286
- }
287
- //generate a link argument string containing event search only
288
- $day_link_args = self::get_query_args( array_intersect_key($original_args, EM_Events::get_post_search($args, true) ));
289
- //get event link
290
- if( get_option("dbem_events_page") > 0 ){
291
- $event_page_link = get_permalink(get_option("dbem_events_page")); //PAGE URI OF EM
292
- }else{
293
- if( $wp_rewrite->using_permalinks() ){
294
- $event_page_link = trailingslashit(home_url()).EM_POST_TYPE_EVENT_SLUG.'/'; //don't use EM_URI here, since ajax calls this before EM_URI is defined.
295
- }else{
296
- //not needed atm anyway, but we use esc_url later on, in case you're wondering ;)
297
- $event_page_link = add_query_arg(array('post_type'=>EM_POST_TYPE_EVENT), home_url()); //don't use EM_URI here, since ajax calls this before EM_URI is defined.
298
- }
299
- }
300
- $event_page_link_parts = explode('?', $event_page_link); //in case we have other plugins (e.g. WPML) adding querystring params to the end
301
- foreach($eventful_days as $day_key => $events) {
302
- if( array_key_exists($day_key, $calendar_array['cells']) ){
303
- //Get link title for this date
304
- $events_titles = array();
305
- foreach($events as $event) {
306
- if( !$limit || count($events_titles) < $limit ){
307
- $events_titles[] = $event->output($event_title_format);
308
- }else{
309
- $events_titles[] = get_option('dbem_display_calendar_events_limit_msg');
310
- break;
311
- }
312
- }
313
- $calendar_array['cells'][$day_key]['link_title'] = implode( $event_title_separator_format, $events_titles);
314
-
315
- //Get the link to this calendar day
316
- if( $eventful_days_count[$day_key] > 1 || !get_option('dbem_calendar_direct_links') ){
317
- if( $wp_rewrite->using_permalinks() && !defined('EM_DISABLE_PERMALINKS') ){
318
- $calendar_array['cells'][$day_key]['link'] = trailingslashit($event_page_link_parts[0]).$day_key."/";
319
- if( !empty($event_page_link_parts[1]) ) $calendar_array['cells'][$day_key]['link'] .= '?' . $event_page_link_parts[1];
320
- //add query vars to end of link
321
- if( !empty($day_link_args) ){
322
- $calendar_array['cells'][$day_key]['link'] = esc_url_raw(add_query_arg($day_link_args, $calendar_array['cells'][$day_key]['link']));
323
- }
324
- }else{
325
- $day_link_args['calendar_day'] = $day_key;
326
- $calendar_array['cells'][$day_key]['link'] = esc_url_raw(add_query_arg($day_link_args, $event_page_link));
327
- }
328
- }else{
329
- foreach($events as $EM_Event){
330
- $calendar_array['cells'][$day_key]['link'] = $EM_Event->get_permalink();
331
- }
332
- }
333
- //Add events to array
334
- $calendar_array['cells'][$day_key]['events_count'] = $eventful_days_count[$day_key];
335
- $calendar_array['cells'][$day_key]['events'] = $events;
336
- }
337
- }
338
- return apply_filters('em_calendar_get',$calendar_array, $args);
339
- }
340
-
341
- public static function output($args = array(), $wrapper = true) {
342
- //Let month and year REQUEST override for non-JS users
343
- $args['limit'] = !empty($args['limit']) ? $args['limit'] : get_option('dbem_display_calendar_events_limit'); //limit arg will be used per day and not for events search
344
- if( !empty($_REQUEST['mo']) || !empty($args['mo']) ){
345
- $args['month'] = ($_REQUEST['mo']) ? $_REQUEST['mo']:$args['mo'];
346
- }
347
- if( !empty($_REQUEST['yr']) || !empty($args['yr']) ){
348
- $args['year'] = (!empty($_REQUEST['yr'])) ? $_REQUEST['yr']:$args['yr'];
349
- }
350
- $calendar_array = self::get($args);
351
- $template = (!empty($args['full'])) ? 'templates/calendar-full.php':'templates/calendar-small.php';
352
- ob_start();
353
- em_locate_template($template, true, array('calendar'=>$calendar_array,'args'=>$args));
354
- if($wrapper){
355
- $calendar = '<div id="em-calendar-'.rand(100,200).'" class="em-calendar-wrapper">'.ob_get_clean().'</div>';
356
- }else{
357
- $calendar = ob_get_clean();
358
- }
359
- return apply_filters('em_calendar_output', $calendar, $args);
360
- }
361
-
362
-
363
- public static function days_in_month($month, $year) {
364
- return date('t', mktime(0,0,0,$month,1,$year));
365
- }
366
-
367
- public static function translate_and_trim($string, $length = 1) {
368
- if( $length > 0 ){
369
- if(function_exists('mb_substr')){ //fix for diacritic calendar names
370
- return mb_substr(translate($string), 0, $length, 'UTF-8');
371
- }else{
372
- return substr(translate($string), 0, $length);
373
- }
374
- }
375
- return translate($string);
376
- }
377
-
378
- /**
379
- * Gets all the EM-supported search arguments and removes the ones that aren't the default in the $args array. Returns the arguments that have non-default values.
380
- * @param array $args
381
- * @return array
382
- */
383
- public static function get_query_args( $args ){
384
- unset($args['month']); unset($args['year']);
385
- $default_args = self::get_default_search(array());
386
- foreach($default_args as $arg_key => $arg_value){
387
- if( !isset($args[$arg_key]) ){
388
- unset($args[$arg_key]);
389
- }else{
390
- //check that argument doesn't match default
391
- $arg = array($args[$arg_key], $arg_value);
392
- foreach($arg as $k => $v){
393
- if( is_string($v) || is_numeric($v) ){
394
- //strings must be typecast to avoid false positive for something like 'string' == 0
395
- $arg[$k] = (string) $v;
396
- }elseif( is_bool($v) ){
397
- $arg[$k] = $v ? '1':'0';
398
- }
399
- }
400
- if( $arg[0] == $arg[1] ){
401
- //argument same as default so it's not needed in link
402
- unset($args[$arg_key]);
403
- }
404
- }
405
- }
406
- //clean up post type conflicts in a URL
407
- if( !empty($args['event']) ){
408
- $args['event_id'] = $args['event'];
409
- unset($args['event']);
410
- }
411
- if( !empty($args['location']) ){
412
- $args['location_id'] = $args['location'];
413
- unset($args['location']);
414
- }
415
- return $args;
416
- }
417
-
418
- /**
419
- * DEPRECATED - use EM_Calendar::get_query_args() instead and manipulate the array.
420
- * Left only to prevent 3rd party add-ons from potentially breaking if they use this
421
- * Helper function to create a link querystring from array which contains arguments with only values that aren't defuaults.
422
- */
423
- public static function get_link_args($args = array(), $html_entities=true){
424
- $args = self::get_query_args($args);
425
- $qs_array = array();
426
- foreach($args as $key => $value){
427
- if(is_array($value)){
428
- $value = implode(',',$value);
429
- }
430
- $qs_array[] = "$key=".urlencode($value);
431
- }
432
- return ($html_entities) ? implode('&amp;', $qs_array) : implode('&', $qs_array);
433
- }
434
-
435
-
436
- /*
437
- * Adds custom calendar search defaults
438
- * @param array $array_or_defaults may be the array to override defaults
439
- * @param array $array
440
- * @return array
441
- * @uses EM_Object#get_default_search()
442
- */
443
- public static function get_default_search( $array_or_defaults = array(), $array = array() ){
444
- //These defaults aren't for db queries, but flags for what to display in calendar output
445
- $defaults = array(
446
- 'recurring' => false, //we don't initially look for recurring events only events and recurrences of recurring events
447
- 'full' => 0, //Will display a full calendar with event names
448
- 'long_events' => 0, //Events that last longer than a day
449
- 'scope' => false,
450
- 'status' => 1, //approved events only
451
- 'town' => false,
452
- 'state' => false,
453
- 'country' => false,
454
- 'region' => false,
455
- 'blog' => get_current_blog_id(),
456
- 'orderby' => get_option('dbem_display_calendar_orderby'),
457
- 'order' => get_option('dbem_display_calendar_order'),
458
- 'number_of_weeks' => false, //number of weeks to be displayed in the calendar
459
- 'limit' => get_option('dbem_display_calendar_events_limit'),
460
- 'post_id' => false
461
- );
462
- //sort out whether defaults were supplied or just the array of search values
463
- if( empty($array) ){
464
- $array = $array_or_defaults;
465
- }else{
466
- $defaults = array_merge($defaults, $array_or_defaults);
467
- }
468
- $defaults['long_events'] = !empty($array['full']) ? get_option('dbem_full_calendar_long_events') : get_option('dbem_small_calendar_long_events');
469
- //specific functionality
470
- if(is_multisite()){
471
- global $bp;
472
- if( !is_main_site() && !array_key_exists('blog',$array) ){
473
- //not the main blog, force single blog search
474
- $array['blog'] = get_current_blog_id();
475
- }elseif( empty($array['blog']) && get_site_option('dbem_ms_global_events') ) {
476
- $array['blog'] = false;
477
- }
478
- }
479
- $atts = parent::get_default_search($defaults, $array);
480
- $atts['full'] = ($atts['full']==true) ? 1:0;
481
- $atts['long_events'] = ($atts['long_events']==true) ? 1:0;
482
- return apply_filters('em_calendar_get_default_search', $atts, $array, $defaults);
483
- }
484
- }
485
- add_action('init', array('EM_Calendar', 'init'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-categories-admin.php DELETED
@@ -1,61 +0,0 @@
1
- <?php
2
- /**
3
- * This class extends the EM_Taxonomy_Admin and adds category images and colors to the admin area.
4
- *
5
- * Currently, all functions here serve the purpose of getting around lack of late static binding in PHP < 5.3.
6
- * Eventually when PHP 5.3 is enforced only certain class properties need to be defined for use in the parent class via static::
7
- *
8
- */
9
- class EM_Categories_Admin extends EM_Taxonomy_Admin{
10
-
11
- public static $taxonomy_name = 'EM_TAXONOMY_CATEGORY'; //converted into a constant value during init()
12
- public static $this_class = 'EM_Categories_Admin'; //needed until 5.3 minimum is enforced for late static binding
13
- public static $tax_class = 'EM_Category';
14
- public static $option_name = 'category';
15
- public static $name_singular = 'category';
16
- public static $name_plural = 'categories';
17
- public static $placeholder_image = '#_CATEGORYIMAGE';
18
- public static $placeholder_color = '#_CATEGORYCOLOR';
19
-
20
- public static function init(){
21
- self::$taxonomy_name = EM_TAXONOMY_CATEGORY;
22
- self::static_binding();
23
- parent::init();
24
- }
25
-
26
- public static function form_add(){
27
- self::static_binding();
28
- parent::form_add();
29
- }
30
-
31
- public static function form_edit($tag){
32
- self::static_binding();
33
- parent::form_edit($tag);
34
- }
35
-
36
- public static function save( $term_id, $tt_id ){
37
- self::static_binding();
38
- parent::save( $term_id, $tt_id );
39
- }
40
-
41
- public static function delete( $term_id ){
42
- self::static_binding();
43
- parent::delete( $term_id );
44
- }
45
-
46
- /**
47
- * Temporary function until WP requires PHP 5.3, so that we can make use of late static binding.
48
- * Until then, all functions needing LST should run this function before calling the parent. If all extending classes do this we shouldn't have a problem.
49
- */
50
- public static function static_binding(){
51
- EM_Taxonomy_Admin::$taxonomy_name = self::$taxonomy_name;
52
- EM_Taxonomy_Admin::$this_class = self::$this_class;
53
- EM_Taxonomy_Admin::$tax_class = self::$tax_class;
54
- EM_Taxonomy_Admin::$option_name = self::$option_name;
55
- EM_Taxonomy_Admin::$name_singular = self::$name_singular;
56
- EM_Taxonomy_Admin::$name_plural = self::$name_plural;
57
- EM_Taxonomy_Admin::$placeholder_image = self::$placeholder_image;
58
- EM_Taxonomy_Admin::$placeholder_color = self::$placeholder_color;
59
- }
60
- }
61
- add_action('admin_init',array('EM_Categories_Admin','init'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-categories-frontend.php DELETED
@@ -1,125 +0,0 @@
1
- <?php
2
- class EM_Categories_Frontend extends EM_Taxonomy_Frontend {
3
-
4
- public static $taxonomy_name = 'event-category'; //converted into a constant value during init()
5
- public static $this_class = 'EM_Categories_Frontend'; //needed until 5.3 minimum is enforced for late static binding
6
- public static $tax_class = 'EM_Category';
7
- public static $option_name = 'category';
8
- public static $option_name_plural = 'categories';
9
-
10
- public static function init(){
11
- self::$taxonomy_name = EM_TAXONOMY_CATEGORY; //awaiting LST in PHP 5.3
12
- self::static_binding();
13
- parent::init();
14
- }
15
-
16
- //These following functions can be removed when PHP 5.3 is minimum and LSB is available
17
-
18
- public static function template($template = ''){
19
- self::static_binding();
20
- return parent::template($template);
21
- }
22
-
23
- public static function the_content($content){
24
- self::static_binding();
25
- return parent::the_content($content);
26
- }
27
-
28
- public static function parse_query( $wp_query ){
29
- //we do some double-checking here to prevent running self::static_binding() during the self::template() function when WP_Query is called.
30
- if( !$wp_query->is_main_query() ) return;
31
- if( $wp_query->is_tax(self::$taxonomy_name) || !empty($wp_query->{'em_'.self::$option_name.'_id'}) ){
32
- self::static_binding();
33
- return parent::parse_query( $wp_query );
34
- }
35
- }
36
-
37
- public static function wpseo_breadcrumb_links( $links ){
38
- self::static_binding();
39
- return parent::wpseo_breadcrumb_links( $links );
40
- }
41
-
42
- /**
43
- * Temporary function until WP requires PHP 5.3, so that we can make use of late static binding.
44
- * Until then, all functions needing LST should run this function before calling the parent. If all extending classes do this we shouldn't have a problem.
45
- */
46
- public static function static_binding(){
47
- EM_Taxonomy_Frontend::$taxonomy_name = self::$taxonomy_name;
48
- EM_Taxonomy_Frontend::$this_class = self::$this_class;
49
- EM_Taxonomy_Frontend::$tax_class = self::$tax_class;
50
- EM_Taxonomy_Frontend::$option_name = self::$option_name;
51
- EM_Taxonomy_Frontend::$option_name_plural = self::$option_name_plural;
52
- }
53
- }
54
- class EM_Category_Taxonomy extends EM_Categories_Frontend {} //backwards compatibility
55
-
56
- EM_Categories_Frontend::init();
57
-
58
- //Walker classes allowing for hierarchical display of categories
59
-
60
- /**
61
- * Create an array of Categories. Copied from Walker_CategoryDropdown, but makes it possible for the selected argument to be an array.
62
- *
63
- * @package WordPress
64
- * @since 2.1.0
65
- * @uses Walker
66
- */
67
- class EM_Walker_Category extends Walker {
68
- /**
69
- * @see Walker::$tree_type
70
- * @since 2.1.0
71
- * @var string
72
- */
73
- var $tree_type = 'event-category';
74
-
75
- /**
76
- * @see Walker::$db_fields
77
- * @since 2.1.0
78
- * @todo Decouple this
79
- * @var array
80
- */
81
- var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
82
-
83
- function __construct(){
84
- $tree_type = EM_TAXONOMY_CATEGORY;
85
- }
86
-
87
- /**
88
- * @see Walker::start_el()
89
- */
90
- function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
91
- $pad = str_repeat('&nbsp;', $depth * 3);
92
- $cat_name = $object->name;
93
- $name = !empty($args['name']) ? $args['name']:'event_categories[]';
94
- $output .= !empty($args['before']) ? $args['after']:'';
95
- $output .= $pad."<input type=\"checkbox\" name=\"$name\" class=\"level-$depth\" value=\"".$object->term_id."\"";
96
- if ( (is_array($args['selected']) && in_array($object->term_id, $args['selected'])) || ($object->term_id == $args['selected']) )
97
- $output .= ' checked="checked"';
98
- $output .= ' /> ';
99
- $output .= $cat_name;
100
- $output .= !empty($args['after']) ? $args['after']:'<br />';
101
- }
102
- }
103
-
104
- /**
105
- * Create an array of Categories. Copied from Walker_CategoryDropdown, but makes it possible for the selected argument to be an array.
106
- *
107
- * @package WordPress
108
- * @since 2.1.0
109
- * @uses Walker
110
- */
111
- class EM_Walker_CategoryMultiselect extends EM_Walker_Category {
112
- /**
113
- * @see Walker::start_el()
114
- */
115
- function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
116
- $pad = str_repeat('&nbsp;', $depth * 3);
117
- $cat_name = $object->name;
118
- $output .= "\t<option class=\"level-$depth\" value=\"".$object->term_id."\"";
119
- if ( (is_array($args['selected']) && in_array($object->term_id, $args['selected'])) || ($object->term_id == $args['selected']) )
120
- $output .= ' selected="selected"';
121
- $output .= '>';
122
- $output .= $pad.$cat_name;
123
- $output .= "</option>\n";
124
- }
125
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-categories.php DELETED
@@ -1,72 +0,0 @@
1
- <?php
2
- class EM_Categories extends EM_Taxonomy_Terms {
3
-
4
- //Overridable functions
5
- protected $is_ms_global = true;
6
- protected $taxonomy = 'event-categories';
7
- protected $meta_key = 'event-category';
8
- protected $terms_name = 'categories';
9
- protected $term_class = 'EM_Category';
10
- protected $ajax_search_action = 'search_cats';
11
-
12
- /**
13
- * Creates an EM_Categories instance, currently accepts an EM_Event object (gets all Categories for that event) or array of any EM_Category objects, which can be manipulated in bulk with helper functions.
14
- * @param mixed $data
15
- * @return null
16
- */
17
- function __construct( $data = false ){
18
- $this->taxonomy = EM_TAXONOMY_CATEGORY;
19
- parent::__construct($data);
20
- }
21
-
22
- /**
23
- * Legacy get overload for any use of $EM_Categories->tags
24
- * @param string $var_name
25
- * @return array|NULL
26
- */
27
- function __get( $var_name ){
28
- if( $var_name == 'categories' ){
29
- return $this->terms;
30
- }
31
- return null;
32
- }
33
-
34
- /**
35
- * Legacy overload for use of empty($this->categories)
36
- * @param string $prop
37
- * @return boolean
38
- */
39
- function __isset( $prop ){
40
- if( $prop == 'categories' ){
41
- return !empty($this->terms);
42
- }
43
- return parent::__isset( $prop );
44
- }
45
-
46
- //Functions we won't need when PHP 5.3 minimum allows for use of LSB
47
-
48
- public static function get( $args = array() ){
49
- self::$instance = new EM_Categories();
50
- return parent::get($args);
51
- }
52
-
53
- public static function output( $args = array() ){
54
- self::$instance = new EM_Categories();
55
- return parent::output($args);
56
- }
57
-
58
- public static function get_pagination_links($args, $count, $search_action = 'search_cats', $default_args = array()){
59
- self::$instance = new EM_Categories();
60
- return parent::get_pagination_links($args, $count, $search_action, $default_args);
61
- }
62
-
63
- public static function get_post_search($args = array(), $filter = false, $request = array(), $accepted_args = array()){
64
- self::$instance = new EM_Categories();
65
- return parent::get_post_search($args, $filter, $request, $accepted_args);
66
- }
67
-
68
- public static function get_default_search( $array_or_defaults = array(), $array = array() ){
69
- self::$instance = new EM_Categories();
70
- return parent::get_default_search($defaults,$array);
71
- }
72
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-category.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
- class EM_Category extends EM_Taxonomy_Term {
3
-
4
- //static options for EM_Category, but until PHP 5.3 is the WP minimum requirement we'll make them regular properties due to lack of late static binding
5
- public $option_ms_global = true;
6
- public $option_name = 'category'; //the singular name of this taxonomy which is used in option names consistent across EM taxonomies
7
- public $taxonomy = 'EM_TAXONOMY_CATEGORY';
8
-
9
- /**
10
- * Necessary to supply the $class_name until late static binding is reliably available on all WP sites running PHP 5.3
11
- * @param string $id
12
- * @param string $class_name
13
- * @return EM_Taxonomy
14
- */
15
- public static function get( $id, $class_name = 'EM_Category' ){
16
- return parent::get($id, $class_name);
17
- }
18
-
19
- public function can_manage( $capability_owner = 'edit_event_categories', $capability_admin = false, $user_to_check = false ){
20
- return parent::can_manage($capability_owner, $capability_admin, $user_to_check);
21
- }
22
- }
23
-
24
- /**
25
- * Get an category in a db friendly way, by checking globals and passed variables to avoid extra class instantiations
26
- * @param mixed $id
27
- * @return EM_Category
28
- * @uses EM_Category::get()
29
- */
30
- function em_get_category( $id ) {
31
- return EM_Category::get($id);
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-datetime.php DELETED
@@ -1,339 +0,0 @@
1
- <?php
2
- /**
3
- * Extends DateTime allowing supplied timezone to be a string, which can also be a UTC offset.
4
- * Also prevents an exception being thrown. Some additional shortcuts added so less coding is required for regular tasks.
5
- * By doing this, we support WP's option to manually offset time with a UTC timezone name e.g. UTC+1.5, which isn't supported by PHP (it only supports numerical offsets which represent UTC offsets)
6
- *
7
- * @since 5.8.2
8
- */
9
- class EM_DateTime extends DateTime {
10
-
11
- /**
12
- * The name of this timezone. For example, America/New_York or UTC+3.5
13
- * @var string
14
- */
15
- protected $timezone_name = false;
16
- /**
17
- * @var bool Whether or not string is UTC offset with a UTC+-d timezone name pattern, which isn't supported in PHP normally.
18
- */
19
- protected $timezone_utc = false;
20
- /**
21
- * Flag for validation purposes, so we can still have a real EM_DateTime and extract dates but know if the intended datetime failed validation.
22
- * A completely invalid date and time will become 1970-01-01 00:00:00 in local timezone, however a valid time can still exist with the 1970-01-01 date.
23
- * If the date is invalid, only local timezones should be used since the time will not accurately convert timezone switches.
24
- * @var string
25
- */
26
- public $valid = true;
27
-
28
- /**
29
- * @see DateTime::__construct()
30
- * @param string $time
31
- * @param string|EM_DateTimeZone $timezone Unlike DateTime this also accepts string representation of a valid timezone, as well as UTC offsets in form of 'UTC -3' or just '-3'
32
- */
33
- public function __construct( $time = 'now', $timezone = null ){
34
- //get our EM_DateTimeZone
35
- $timezone = EM_DateTimeZone::create($timezone);
36
- //save timezone name for use in getTimezone()
37
- $this->timezone_name = $timezone->getName();
38
- $this->timezone_utc = $timezone->utc_offset !== false;
39
- //fix DateTime error if a regular timestamp is supplied without prepended @ symbol
40
- if( is_numeric($time) ){
41
- $time = '@'.$time;
42
- }elseif( is_null($time) ){
43
- $time = 'now';
44
- }
45
- //finally, run parent function with our custom timezone
46
- try{
47
- @parent::__construct( (string) $time, $timezone);
48
- if( substr($time,0,1) == '@' || $time == 'now' ) $this->setTimezone($timezone);
49
- $this->valid = true; //if we get this far, supplied time is valid
50
- }catch( Exception $e ){
51
- //get current date/time in relevant timezone and set valid flag to false
52
- try {
53
- parent::__construct('@0');
54
- }catch( Exception $e ){
55
- // do nothing
56
- }finally{
57
- $this->setTimezone($timezone);
58
- $this->setDate(1970,1,1);
59
- $this->setTime(0,0,0);
60
- $this->valid = false;
61
- }
62
- }
63
- }
64
-
65
- /**
66
- * {@inheritDoc}
67
- * @see DateTime::format()
68
- */
69
- public function format( $format = 'Y-m-d H:i:s'){
70
- if( !$this->valid && ($format == 'Y-m-d' || $format == em_get_date_format())) return '';
71
- if( $format !== 'Y-m-d H:i:s' ) $format = $this->formatTimezones($format); // format UTC timezones
72
- return parent::format($format);
73
- }
74
-
75
- /**
76
- * Formats timezone name/abbreviation placeholders when there is a manual offset, which would be passed onto date formatting functions and usually output UTC timezone information.
77
- * @param string $format The format to be parsed.
78
- * @return string
79
- */
80
- public function formatTimezones($format){
81
- if( $this->timezone_utc ){
82
- $timezone_formats = array( 'T', 'e' );
83
- foreach ( $timezone_formats as $timezone_format ) {
84
- if ( false !== strpos( $format, $timezone_format ) ) {
85
- $format = ' '.$format;
86
- $format = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $this->timezone_name ), $format );
87
- $format = substr( $format, 1, strlen( $format ) -1 );
88
- }
89
- }
90
- }
91
- return $format;
92
- }
93
-
94
- /**
95
- * Returns a date and time representation in the format stored in Events Manager settings.
96
- * @param bool $include_hour
97
- * @return string
98
- */
99
- public function formatDefault( $include_hour = true ){
100
- $format = $include_hour ? em_get_date_format() . ' ' . em_get_hour_format() : em_get_date_format();
101
- $format = apply_filters( 'em_datetime_format_default', $format, $include_hour );
102
- return $this->i18n( $format );
103
- }
104
-
105
- /**
106
- * Provides a translated date and time according to the current blog language.
107
- * Useful if using formats that provide date-related names such as 'Monday' or 'January', which should be translated if displayed in another language.
108
- * @param string $format
109
- * @return string
110
- */
111
- public function i18n( $format = 'Y-m-d H:i:s' ){
112
- if( !$this->valid && $format == em_get_date_format()) return '';
113
- // since we use WP's date functions which don't use DateTime (and if so, don't inherit our timezones), we need to preformat timezone related formats, adapted from date_i18n
114
- $format = $this->formatTimezones( $format );
115
- // support for < WP 5.3.0
116
- if( function_exists('wp_date') ){
117
- return wp_date( $format, $this->getTimestamp(), $this->getTimezone() );
118
- }else{
119
- return date_i18n( $format, $this->getTimestampWithOffset(true) );
120
- }
121
- }
122
-
123
- /**
124
- * Outputs a default mysql datetime formatted string.
125
- * @return string
126
- */
127
- public function __toString(){
128
- return $this->format('Y-m-d H:i:s');
129
- }
130
-
131
- /**
132
- * Modifies the time of this object, if a mysql TIME valid format is provided (e.g. 14:30:00).
133
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
134
- * @param string $hour
135
- * @return EM_DateTime Returns object for chaining.
136
- */
137
- public function setTimeString( $hour ){
138
- if( preg_match('/^\d{2}:\d{2}:\d{2}$/', $hour) ){
139
- $time = explode(':', $hour);
140
- $this->setTime($time[0], $time[1], $time[2]);
141
- }else{
142
- $this->valid = false;
143
- }
144
- return $this;
145
- }
146
-
147
- /**
148
- * Sets timestamp and returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
149
- * @param int $timestamp
150
- * @see DateTime::setTimestamp()
151
- * @return EM_DateTime
152
- */
153
- public function setTimestamp( $timestamp ){
154
- $return = parent::setTimestamp( $timestamp );
155
- $this->valid = $return !== false;
156
- return $this;
157
- }
158
-
159
- /**
160
- * Extends DateTime functionality by accepting a false or string value for a timezone. If set to false, default WP timezone will be used.
161
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
162
- * @param string|false $timezone
163
- * @see DateTime::setTimezone()
164
- * @return EM_DateTime Returns object for chaining.
165
- */
166
- public function setTimezone( $timezone = false ){
167
- if( $timezone == $this->getTimezone()->getName() ) return $this;
168
- $timezone = EM_DateTimeZone::create($timezone);
169
- $return = parent::setTimezone($timezone);
170
- $this->timezone_name = $timezone->getName();
171
- $this->timezone_utc = $timezone->utc_offset !== false;
172
- $this->valid = $return !== false;
173
- return $this;
174
- }
175
-
176
- /**
177
- * Sets time along and returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
178
- * {@inheritDoc}
179
- * @see DateTime::setTime()
180
- */
181
- public function setTime( $hour, $minute, $second = NULL, $microseconds = NULL ){
182
- $return = parent::setTime( (int) $hour, (int) $minute, (int) $second );
183
- $this->valid = $return !== false;
184
- return $this;
185
- }
186
-
187
- /**
188
- * Sets date along and returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
189
- * {@inheritDoc}
190
- * @see DateTime::setDate()
191
- */
192
- public function setDate( $year, $month, $day ){
193
- $return = parent::setDate( $year, $month, $day );
194
- $this->valid = $return !== false;
195
- return $this;
196
- }
197
-
198
- /**
199
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
200
- * {@inheritDoc}
201
- * @see DateTime::setISODate()
202
- */
203
- public function setISODate( $year, $week, $day = NULL ){
204
- $return = parent::setISODate( $year, $week, $day );
205
- $this->valid = $return !== false;
206
- return $this;
207
- }
208
-
209
- /**
210
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
211
- * {@inheritDoc}
212
- * @see DateTime::modify()
213
- */
214
- public function modify( $modify ){
215
- $result = parent::modify($modify);
216
- $this->valid = $result !== false;
217
- return $this;
218
- }
219
-
220
- /**
221
- * Extends DateTime function to allow string representation of argument passed to create a new DateInterval object.
222
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
223
- * @see DateTime::add()
224
- * @param string|DateInterval
225
- * @return EM_DateTime Returns object for chaining.
226
- * @throws Exception
227
- */
228
- public function add( $DateInterval ){
229
- if( is_object($DateInterval) ){
230
- $result = parent::add($DateInterval);
231
- }else{
232
- $result = parent::add( new DateInterval($DateInterval) );
233
- }
234
- $this->valid = $result !== false;
235
- return $this;
236
- }
237
-
238
- /**
239
- * Extends DateTime function to allow string representation of argument passed to create a new DateInterval object.
240
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
241
- * @see DateTime::sub()
242
- * @param string|DateInterval
243
- * @return EM_DateTime
244
- * @throws Exception
245
- */
246
- public function sub( $DateInterval ){
247
- if( is_object($DateInterval) ){
248
- $result = parent::sub($DateInterval);
249
- }else{
250
- $result = parent::sub( new DateInterval($DateInterval) );
251
- }
252
- $this->valid = $result !== false;
253
- return $this;
254
- }
255
-
256
- /**
257
- * Easy chainable cloning function, useful for situations where you may want to manipulate the current date,
258
- * such as adding a month and getting the DATETIME string without changing the original value of this object.
259
- * @return EM_DateTime
260
- */
261
- public function copy(){
262
- return clone $this;
263
- }
264
-
265
- /**
266
- * Gets a timestamp with an offset, which will represent the local time equivalent in UTC time.
267
- * If using this to supply to a date() function, set $server_localized to true which will account for any rogue code
268
- * that sets the server default timezone to something other than UTC (which is WP sets it to at the start)
269
- * @param boolean $server_localized
270
- * @return int
271
- */
272
- public function getTimestampWithOffset( $server_localized = false ){
273
- //aside from the actual offset from the timezone, we also have a local server offset we need to deal with here...
274
- $server_offset = $server_localized ? date('Z',$this->getTimestamp()) : 0;
275
- return $this->getOffset() + $this->getTimestamp() - $server_offset;
276
- }
277
-
278
- /**
279
- * Returns an EM_DateTimeZone object instead of the default DateTimeZone object.
280
- * @see DateTime::getTimezone()
281
- * @return EM_DateTimeZone
282
- */
283
- public function getTimezone(){
284
- return new EM_DateTimeZone($this->timezone_name);
285
- }
286
-
287
- /**
288
- * Returns a MySQL TIME formatted string, with the option of providing the UTC equivalent.
289
- * @param bool $utc If set to true a UTC relative time will be provided.
290
- * @return string
291
- */
292
- public function getTime( $utc = false ){
293
- if( $utc ){
294
- $current_timezone = $this->getTimezone()->getName();
295
- $this->setTimezone('UTC');
296
- }
297
- $return = $this->format('H:i:s');
298
- if( $utc ) $this->setTimezone($current_timezone);
299
- return $return;
300
- }
301
-
302
- /**
303
- * Returns a MySQL DATE formatted string.
304
- * @param bool $utc
305
- * @return string
306
- */
307
- public function getDate( $utc = false ){
308
- return $this->format('Y-m-d');
309
- }
310
-
311
- /**
312
- * Returns a MySQL DATETIME formatted string, with the option of providing the UTC equivalent.
313
- * @param bool $utc If set to true a UTC relative time will be provided.
314
- * @return string
315
- */
316
- public function getDateTime( $utc = false ){
317
- if( $utc ){
318
- $current_timezone = $this->getTimezone()->getName();
319
- $this->setTimezone('UTC');
320
- }
321
- $return = $this->format('Y-m-d H:i:s');
322
- if( $utc ) $this->setTimezone($current_timezone);
323
- return $return;
324
- }
325
-
326
- /**
327
- * Extends the DateTime::createFromFormat() function by setting the timezone to the default blog timezone if none is provided.
328
- * @param string $format
329
- * @param string $time
330
- * @param string|EM_DateTimeZone $timezone
331
- * @return boolean|EM_DateTime
332
- */
333
- public static function createFromFormat( $format, $time, $timezone = null ){
334
- $timezone = EM_DateTimeZone::create($timezone);
335
- $DateTime = parent::createFromFormat($format, $time, $timezone);
336
- if( $DateTime === false ) return false;
337
- return new EM_DateTime($DateTime->format('Y-m-d H:i:s'), $timezone);
338
- }
339
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-datetimezone.php DELETED
@@ -1,83 +0,0 @@
1
- <?php
2
- /**
3
- * Extends the native DateTimeZone object by allowing for UTC manual offsets as supported by WordPress, along with eash creation of a DateTimeZone object with the blog's timezone.
4
- * @since 5.8.2
5
- */
6
- class EM_DateTimeZone extends DateTimeZone {
7
-
8
- public $utc_offset = false;
9
-
10
- public function __construct( $timezone ){
11
- //if we're not suppiled a DateTimeZone object, create one from string or implement manual offset
12
- if( $timezone != 'UTC' ){
13
- $timezone = preg_replace('/^UTC ?/', '', $timezone);
14
- if( is_numeric($timezone) ){
15
- if( absint($timezone) == 0 ){
16
- $timezone = 'UTC';
17
- }else{
18
- // convert this to an offset, taken from wp_timezone
19
- $offset = (float) $timezone;
20
- $hours = (int) $offset;
21
- $minutes = ( $offset - $hours );
22
- $sign = ( $offset < 0 ) ? '-' : '+';
23
- $abs_hour = abs( $hours );
24
- $abs_mins = abs( $minutes * 60 );
25
- $timezone = sprintf( '%s%02d%02d', $sign, $abs_hour, $abs_mins );
26
- $this->utc_offset = sprintf( 'UTC%s%d', $sign, abs($offset) );
27
- }
28
- }
29
- }
30
- parent::__construct($timezone);
31
- }
32
-
33
- /**
34
- * Special function which converts a timezone string, UTC offset or DateTimeZone object into a valid EM_DateTimeZone object.
35
- * If no value supplied, a EM_DateTimezone with the default WP environment timezone is created.
36
- * @param mixed $timezone
37
- * @return EM_DateTimeZone
38
- */
39
- public static function create( $timezone = false ){
40
- //if we're not suppiled a DateTimeZone object, create one from string or implement manual offset
41
- if( !empty($timezone) && !is_object($timezone) ){
42
- //create EM_DateTimeZone object if valid, otherwise allow defaults to override later
43
- try {
44
- $timezone = new EM_DateTimeZone($timezone);
45
- }catch( Exception $e ){
46
- $timezone = null;
47
- }
48
- }elseif( is_object($timezone) && get_class($timezone) == 'DateTimeZone'){
49
- //if supplied a regular DateTimeZone, convert it to EM_DateTimeZone
50
- $timezone = new EM_DateTimeZone($timezone->getName());
51
- }
52
- if( !is_object($timezone) ){
53
- //if no valid timezone supplied, get the default timezone in EM environment, otherwise the WP timezone or offset
54
- $timezone = get_option( 'timezone_string' );
55
- if( !$timezone ) $timezone = get_option('gmt_offset');
56
- $timezone = new EM_DateTimeZone($timezone);
57
- }
58
- return $timezone;
59
- }
60
-
61
- /**
62
- * {@inheritDoc}
63
- * @see DateTimeZone::getName()
64
- */
65
- public function getName(){
66
- if( $this->utc_offset !== false ){
67
- return $this->utc_offset;
68
- }
69
- return parent::getName();
70
- }
71
-
72
- /**
73
- * If the timezone has a manual UTC offset, then an empty array of transitions is returned.
74
- * {@inheritDoc}
75
- * @see DateTimeZone::getTransitions()
76
- */
77
- public function getTransitions( $timestamp_begin = null, $timestamp_end = null ){
78
- if( $this->utc_offset !== false ){
79
- return array();
80
- }
81
- return parent::getTransitions($timestamp_begin, $timestamp_end);
82
- }
83
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-event-post-admin.php DELETED
@@ -1,528 +0,0 @@
1
- <?php
2
- /*
3
- * Events Edit Page
4
- */
5
- class EM_Event_Post_Admin{
6
- public static function init(){
7
- global $pagenow;
8
- if($pagenow == 'post.php' || $pagenow == 'post-new.php' ){ //only needed if editing post
9
- add_action('admin_head', array('EM_Event_Post_Admin','admin_head')); //I don't think we need this anymore?
10
- //Meta Boxes
11
- add_action('add_meta_boxes_'.EM_POST_TYPE_EVENT, array('EM_Event_Post_Admin','meta_boxes'), 10, 1);
12
- //Notices
13
- add_action('admin_notices',array('EM_Event_Post_Admin','admin_notices'));
14
- }
15
- //Save/Edit actions
16
- add_filter('wp_insert_post_data',array('EM_Event_Post_Admin','wp_insert_post_data'),100,2); //validate post meta before saving is done
17
- add_action('save_post',array('EM_Event_Post_Admin','save_post'),1,1); //set to 1 so metadata gets saved ASAP
18
- add_action('before_delete_post',array('EM_Event_Post_Admin','before_delete_post'),10,1);
19
- add_action('trashed_post',array('EM_Event_Post_Admin','trashed_post'),10,1);
20
- add_action('untrash_post',array('EM_Event_Post_Admin','untrash_post'),10,1);
21
- add_action('untrashed_post',array('EM_Event_Post_Admin','untrashed_post'),10,1);
22
- //Notices
23
- add_action('post_updated_messages',array('EM_Event_Post_Admin','admin_notices_filter'),1,1);
24
- }
25
-
26
- public static function admin_head(){
27
- global $post, $EM_Event;
28
- if( empty($EM_Event) && !empty($post) && $post->post_type == EM_POST_TYPE_EVENT ){
29
- $EM_Event = em_get_event($post->ID, 'post_id');
30
- }
31
- }
32
-
33
- public static function admin_notices(){
34
- //When editing
35
- global $post, $EM_Event, $pagenow;
36
- if( $pagenow == 'post.php' && ($post->post_type == EM_POST_TYPE_EVENT || $post->post_type == 'event-recurring') ){
37
- if ( $EM_Event->is_recurring() ) {
38
- $warning = "<p><strong>".__( 'WARNING: This is a recurring event.', 'events-manager')."</strong></p>";
39
- $warning .= "<p>". __( 'Modifications to recurring events will be applied to all recurrences and will overwrite any changes made to those individual event recurrences.', 'events-manager') . '</p>';
40
- $warning .= "<p>". __( 'Bookings to individual event recurrences will be preserved if event times and ticket settings are not modified.', 'events-manager') . '</p>';
41
- $warning .= '<p><a href="'. esc_url( add_query_arg(array('scope'=>'all', 'recurrence_id'=>$EM_Event->event_id), em_get_events_admin_url()) ).'">'. esc_html__('You can edit individual recurrences and disassociate them with this recurring event.','events-manager') . '</a></p>';
42
- ?><div class="notice notice-warning is-dismissible"><?php echo $warning; ?></div><?php
43
- } elseif ( $EM_Event->is_recurrence() ) {
44
- $warning = "<p><strong>".__('WARNING: This is a recurrence in a set of recurring events.', 'events-manager')."</strong></p>";
45
- $warning .= "<p>". sprintf(__('If you update this event data and save, it could get overwritten if you edit the recurring event template. To make it an independent, <a href="%s">detach it</a>.', 'events-manager'), $EM_Event->get_detach_url())."</p>";
46
- $warning .= "<p>".sprintf(__('To manage the whole set, <a href="%s">edit the recurring event template</a>.', 'events-manager'),admin_url('post.php?action=edit&amp;post='.$EM_Event->get_event_recurrence()->post_id))."</p>";
47
- ?><div class="notice notice-warning is-dismissible"><?php echo $warning; ?></div><?php
48
- }
49
- if( !empty($EM_Event->group_id) && function_exists('groups_get_group') ){
50
- $group = groups_get_group(array('group_id'=>$EM_Event->group_id));
51
- $warning = sprintf(__('WARNING: This is a event belonging to the group "%s". Other group admins can also modify this event.', 'events-manager'), $group->name);
52
- ?><div class="notice notice-info is-dismissible"><p><?php echo $warning; ?></p></div><?php
53
- }
54
- }
55
- }
56
-
57
- public static function admin_notices_filter($messages){
58
- //When editing
59
- global $post, $EM_Notices; /* @var EM_Notices $EM_Notices */
60
- if( $post->post_type == EM_POST_TYPE_EVENT || $post->post_type == 'event-recurring' ){
61
- if ( $EM_Notices->count_errors() > 0 ) {
62
- unset($_GET['message']);
63
- }
64
- }
65
- return $messages;
66
- }
67
-
68
- /**
69
- * Validate event once BEFORE it goes into the database, because otherwise it could get 'published' between now and save_post,
70
- * allowing other plugins hooking here to perform incorrect actions e.g. tweet a new event.
71
- *
72
- * @param array $data
73
- * @param array $postarr
74
- * @return array
75
- */
76
- public static function wp_insert_post_data( $data, $postarr ){
77
- global $wpdb, $EM_SAVING_EVENT;
78
- if( !empty($EM_SAVING_EVENT) ) return $data; //never proceed with this if using EM_Event::save();
79
- $post_type = $data['post_type'];
80
- $post_ID = !empty($postarr['ID']) ? $postarr['ID'] : false;
81
- $is_post_type = $post_type == EM_POST_TYPE_EVENT || $post_type == 'event-recurring';
82
- $doing_add_meta_ajax = defined('DOING_AJAX') && DOING_AJAX && !empty($_REQUEST['action']) && $_REQUEST['action'] == 'add-meta' && check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta', false ); //we don't need to save anything here, we don't use this action
83
- $saving_status = !in_array($data['post_status'], array('trash','auto-draft')) && !defined('DOING_AUTOSAVE') && !$doing_add_meta_ajax;
84
- $untrashing = $post_ID && defined('UNTRASHING_'.$post_ID);
85
- if( !$untrashing && $is_post_type && $saving_status ){
86
- if( !empty($_REQUEST['_emnonce']) && wp_verify_nonce($_REQUEST['_emnonce'], 'edit_event') ){
87
- //this is only run if we know form data was submitted, hence the nonce
88
- $EM_Event = em_get_event($post_ID, 'post_id');
89
- $EM_Event->post_type = $post_type;
90
- //Handle Errors by making post draft
91
- $get_meta = $EM_Event->get_post_meta();
92
- $validate_meta = $EM_Event->validate_meta();
93
- if( !$get_meta || !$validate_meta ) $data['post_status'] = 'draft';
94
- }
95
- }
96
- return $data;
97
- }
98
-
99
- public static function save_post($post_id, $post = false){
100
- global $wpdb, $EM_Event, $EM_Notices, $EM_SAVING_EVENT, $EM_EVENT_SAVE_POST; /* @var EM_Notices $EM_Notices */
101
- if( !empty($EM_SAVING_EVENT) ) return; //never proceed with this if using EM_Event::save();
102
- if ( isset($_GET['preview_id']) && isset($_GET['preview_nonce']) && wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $post_id ) ) return; //don't proceed with saving when previewing, may cause issues
103
- $post_type = get_post_type($post_id);
104
- $is_post_type = $post_type == EM_POST_TYPE_EVENT || $post_type == 'event-recurring';
105
- $doing_add_meta_ajax = defined('DOING_AJAX') && DOING_AJAX && !empty($_REQUEST['action']) && $_REQUEST['action'] == 'add-meta' && check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta', false ); //we don't need to save anything here, we don't use this action
106
- $saving_status = !in_array(get_post_status($post_id), array('trash','auto-draft')) && !defined('DOING_AUTOSAVE') && !$doing_add_meta_ajax;
107
- $EM_EVENT_SAVE_POST = true; //first filter for save_post in EM for events
108
- if(!defined('UNTRASHING_'.$post_id) && $is_post_type && $saving_status ){
109
- //Reset server timezone to UTC in case other plugins are doing something naughty
110
- $server_timezone = date_default_timezone_get();
111
- date_default_timezone_set('UTC');
112
- //grab event, via post info, reset the $EM_Event variable
113
- $EM_Event = new EM_Event($post_id, 'post_id');
114
- $EM_Event->post_type = $post_type;
115
- //check whether this is a quick save or not, then save accordingly
116
- if( !empty($_REQUEST['_emnonce']) && wp_verify_nonce($_REQUEST['_emnonce'], 'edit_event') ){
117
- //this is only run if we know form data was submitted, hence the nonce
118
- $get_meta = $EM_Event->get_post_meta();
119
- $validate_meta = $EM_Event->validate_meta(); //Handle Errors by making post draft
120
- do_action('em_event_save_pre', $EM_Event); //technically, the event is saved... but the meta isn't. wp doesn't give an pre-intervention action for this (or does it?)
121
- //if we execute a location save here, we will screw up the current save_post $wp_filter pointer executed in do_action()
122
- //therefore, we save the current pointer position (priority) and set it back after saving the location further down
123
- global $wp_filter, $wp_current_filter;
124
- $wp_filter_priority = key($wp_filter['save_post']);
125
- $tag = end($wp_current_filter);
126
- //save the event meta, whether validated or not and which includes saving a location
127
- $save_meta = $EM_Event->save_meta();
128
- //reset save_post pointer in $wp_filter to its original position
129
- reset( $wp_filter[$tag] );
130
- do{
131
- if( key($wp_filter[$tag]) == $wp_filter_priority ) break;
132
- }while ( next($wp_filter[$tag]) !== false );
133
- //save categories in case of default category
134
- if( get_option('dbem_categories_enabled') ) $EM_Event->get_categories()->save();
135
- //continue whether all went well or not
136
- if( !$get_meta || !$validate_meta || !$save_meta ){
137
- //failed somewhere, set to draft, don't publish
138
- $EM_Event->set_status(null, true);
139
- if( $EM_Event->is_recurring() ){
140
- $EM_Notices->add_error( '<strong>'.__('Your event details are incorrect and recurrences cannot be created, please correct these errors first:','events-manager').'</strong>', true); //Always seems to redirect, so we make it static
141
- }else{
142
- $EM_Notices->add_error( '<strong>'.sprintf(__('Your %s details are incorrect and cannot be published, please correct these errors first:','events-manager'),__('event','events-manager')).'</strong>', true); //Always seems to redirect, so we make it static
143
- }
144
- $EM_Notices->add_error($EM_Event->get_errors(), true); //Always seems to redirect, so we make it static
145
- apply_filters('em_event_save', false, $EM_Event);
146
- }else{
147
- //if this is just published, we need to email the user about the publication, or send to pending mode again for review
148
- if( (!$EM_Event->is_recurring() && !current_user_can('publish_events')) || ($EM_Event->is_recurring() && !current_user_can('publish_recurring_events')) ){
149
- if( $EM_Event->is_published() ){ $EM_Event->set_status(0, true); } //no publishing and editing... security threat
150
- }
151
- apply_filters('em_event_save', true, $EM_Event);
152
- //flag a cache refresh if we get here
153
- $EM_Event->refresh_cache = true;
154
- add_filter('save_post', 'EM_Event_Post_Admin::refresh_cache', 100000000);
155
- }
156
- }else{
157
- //we're updating only the quick-edit style information, which is only post info saved into the index
158
- if( $EM_Event->validate() ){
159
- do_action('em_event_save_pre', $EM_Event); //technically, the event is saved... but the meta isn't. wp doesn't give an pre-intervention action for this (or does it?)
160
- //first things first, we must make sure we have an index, if not, reset it to a new one:
161
- $event_truly_exists = $wpdb->get_var('SELECT event_id FROM '.EM_EVENTS_TABLE." WHERE event_id={$EM_Event->event_id}") == $EM_Event->event_id;
162
- if(empty($EM_Event->event_id) || !$event_truly_exists){ $EM_Event->save_meta(); }
163
- //we can save the status now
164
- $EM_Event->get_previous_status(); //before we save anything
165
- $event_status = $EM_Event->get_status(true);
166
- //if this is just published, we need to email the user about the publication, or send to pending mode again for review
167
- if( (!$EM_Event->is_recurring() && !current_user_can('publish_events')) || ($EM_Event->is_recurring() && !current_user_can('publish_recurring_events')) ){
168
- if( $EM_Event->is_published() ){ $EM_Event->set_status(0, true); } //no publishing and editing... security threat
169
- }
170
- //now update the db
171
- $where_array = array($EM_Event->event_name, $EM_Event->event_owner, $EM_Event->event_slug, $EM_Event->event_private, $EM_Event->event_id);
172
- $sql = $wpdb->prepare("UPDATE ".EM_EVENTS_TABLE." SET event_name=%s, event_owner=%d, event_slug=%s, event_status={$event_status}, event_private=%d WHERE event_id=%d", $where_array);
173
- $wpdb->query($sql);
174
- //If we're saving via quick-edit in MS Global mode, then the categories need to be pushed to the ms global index
175
- if( EM_MS_GLOBAL && get_option('dbem_categories_enabled') && is_main_site() ){
176
- $EM_Event->get_categories()->save_index(); //just save to index, WP should have saved the taxonomy data
177
- }
178
- //deal with recurrences
179
- if( $EM_Event->is_recurring() && ($EM_Event->is_published() || (defined('EM_FORCE_RECURRENCES_SAVE') && EM_FORCE_RECURRENCES_SAVE)) ){
180
- //recurrences are (re)saved only if event is published
181
- $EM_Event->save_events();
182
- }
183
- apply_filters('em_event_save', true, $EM_Event);
184
- //flag a cache refresh if we get here
185
- $EM_Event->refresh_cache = true;
186
- add_filter('save_post', 'EM_Event_Post_Admin::refresh_cache', 100000000);
187
- }else{
188
- do_action('em_event_save_pre', $EM_Event); //technically, the event is saved... but the meta isn't. wp doesn't give an pre-intervention action for this (or does it?)
189
- //Event doesn't validate, so set status to null
190
- $EM_Event->set_status(null, true);
191
- apply_filters('em_event_save', false, $EM_Event);
192
- }
193
- }
194
- self::maybe_publish_location($EM_Event);
195
- //Set server timezone back, even though it should be UTC anyway
196
- date_default_timezone_set($server_timezone);
197
- }
198
- }
199
-
200
- /**
201
- * Refreshes the cache of the current global $EM_Event, provided the refresh_cache flag is set to true within the object and the object has a published state
202
- */
203
- public static function refresh_cache(){
204
- global $EM_Event;
205
- //if this is a published event, and the refresh_cache flag was added to this event during save_post, refresh the meta and update the cache
206
- if( !empty($EM_Event->refresh_cache) && !empty($EM_Event->post_id) && $EM_Event->is_published() ){
207
- $post = get_post($EM_Event->post_id);
208
- $EM_Event->load_postdata($post);
209
- unset($EM_Event->refresh_cache);
210
- wp_cache_set($EM_Event->event_id, $EM_Event, 'em_events');
211
- wp_cache_set($EM_Event->post_id, $EM_Event->event_id, 'em_events_ids');
212
- }
213
- }
214
-
215
- /**
216
- * Publish the location if the event has just been approved and the location is pending. We assume an editor published the event and approves the location too.
217
- * @param EM_Event $EM_Event
218
- */
219
- public static function maybe_publish_location($EM_Event){
220
- //do a dirty update for location too if it's not published
221
- if( $EM_Event->is_published() && !empty($EM_Event->location_id) ){
222
- $EM_Location = $EM_Event->get_location();
223
- if( $EM_Location->location_status !== 1 ){
224
- //let's also publish the location
225
- $EM_Location->set_status(1, true);
226
- }
227
- }
228
- }
229
-
230
- public static function before_delete_post($post_id){
231
- if(get_post_type($post_id) == EM_POST_TYPE_EVENT){
232
- $EM_Event = em_get_event($post_id,'post_id');
233
- do_action('em_event_delete_pre ',$EM_Event);
234
- $EM_Event->delete_meta();
235
- }
236
- }
237
-
238
- public static function trashed_post($post_id){
239
- if(get_post_type($post_id) == EM_POST_TYPE_EVENT){
240
- global $EM_Notices;
241
- $EM_Event = em_get_event($post_id,'post_id');
242
- $EM_Event->set_status(-1);
243
- $EM_Notices->remove_all(); //no validation/notices needed
244
- }
245
- }
246
-
247
- public static function untrash_post($post_id){
248
- if(get_post_type($post_id) == EM_POST_TYPE_EVENT){
249
- //set a constant so we know this event doesn't need 'saving'
250
- if(!defined('UNTRASHING_'.$post_id)) define('UNTRASHING_'.$post_id, true);
251
- }
252
- }
253
-
254
- public static function untrashed_post($post_id){
255
- if(get_post_type($post_id) == EM_POST_TYPE_EVENT){
256
- global $EM_Notices, $EM_Event;
257
- $EM_Event = new EM_Event($post_id, 'post_id'); //get a refreshed $EM_Event because otherwise statuses don't get updated by WP
258
- $EM_Event->set_status( $EM_Event->get_status() );
259
- $EM_Notices->remove_all(); //no validation/notices needed
260
- }
261
- }
262
-
263
- public static function meta_boxes( $post ){
264
- global $EM_Event;
265
- //since this is the first point when the admin area loads event stuff, we load our EM_Event here
266
- if( empty($EM_Event) && !empty($post) ){
267
- $EM_Event = em_get_event($post->ID, 'post_id');
268
- }
269
- if( !empty($EM_Event->event_owner_anonymous) ){
270
- add_meta_box('em-event-anonymous', __('Anonymous Submitter Info','events-manager'), array('EM_Event_Post_Admin','meta_box_anonymous'),EM_POST_TYPE_EVENT, 'side','high');
271
- }
272
- add_meta_box('em-event-when', __('When','events-manager'), array('EM_Event_Post_Admin','meta_box_date'),EM_POST_TYPE_EVENT, 'side','high');
273
- if(get_option('dbem_locations_enabled', true)){
274
- add_meta_box('em-event-where', __('Where','events-manager'), array('EM_Event_Post_Admin','meta_box_location'),EM_POST_TYPE_EVENT, 'normal','high');
275
- }
276
- if( defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_DISPLAY') && WP_DEBUG_DISPLAY && (!defined('EM_DEBUG_DISPLAY') || EM_DEBUG_DISPLAY) ){
277
- add_meta_box('em-event-meta', 'Event Meta (debugging only)', array('EM_Event_Post_Admin','meta_box_metadump'),EM_POST_TYPE_EVENT, 'normal','high');
278
- }
279
- if( get_option('dbem_rsvp_enabled', true) && $EM_Event->can_manage('manage_bookings','manage_others_bookings') ){
280
- add_meta_box('em-event-bookings', __('Bookings/Registration','events-manager'), array('EM_Event_Post_Admin','meta_box_bookings'),EM_POST_TYPE_EVENT, 'normal','high');
281
- if( !empty($EM_Event->event_id) && $EM_Event->event_rsvp ){
282
- add_meta_box('em-event-bookings-stats', __('Bookings Stats','events-manager'), array('EM_Event_Post_Admin','meta_box_bookings_stats'),EM_POST_TYPE_EVENT, 'side','core');
283
- }
284
- }
285
- if( get_option('dbem_attributes_enabled', true) ){
286
- add_meta_box('em-event-attributes', __('Attributes','events-manager'), array('EM_Event_Post_Admin','meta_box_attributes'),EM_POST_TYPE_EVENT, 'normal','default');
287
- }
288
- if( EM_MS_GLOBAL && !is_main_site() && get_option('dbem_categories_enabled') ){
289
- add_meta_box('em-event-categories', __('Site Categories','events-manager'), array('EM_Event_Post_Admin','meta_box_ms_categories'),EM_POST_TYPE_EVENT, 'side','low');
290
- }
291
- add_action('post_submitbox_misc_actions', 'EM_Event_Post_Admin::meta_box_action_post_submitbox_start');
292
- }
293
-
294
- public static function meta_box_action_post_submitbox_start(){
295
- global $EM_Event;
296
- ?>
297
- <div class="misc-pub-section misc-pub-post-status misc-event-duplicate-link">
298
- <a href="<?php echo esc_url($EM_Event->duplicate_url()); ?>"><?php echo esc_html(sprintf(__('Duplicate %s','events-manager'), __('Event','events-manager'))); ?></a>
299
- </div>
300
- <?php
301
- }
302
-
303
- public static function meta_box_metadump(){
304
- global $post,$EM_Event;
305
- echo "<pre>"; print_r($EM_Event); echo "</pre>";
306
- }
307
-
308
- public static function meta_box_anonymous(){
309
- global $EM_Event;
310
- ?>
311
- <div class='updated'><p><?php echo sprintf(__('This %s was submitted by a guest. You will find their details in the <em>Anonymous Submitter Info</em> box','events-manager'), __('event', 'events-manager')); ?></p></div>
312
- <p><strong><?php _e('Name','events-manager'); ?> :</strong> <?php echo $EM_Event->event_owner_name; ?></p>
313
- <p><strong><?php _e('Email','events-manager'); ?> :</strong> <?php echo $EM_Event->event_owner_email; ?></p>
314
- <?php
315
- }
316
-
317
- public static function meta_box_date(){
318
- //create meta box check of date nonce
319
- ?><input type="hidden" name="_emnonce" value="<?php echo wp_create_nonce('edit_event'); ?>" /><?php
320
- em_locate_template('forms/event/when.php', true);
321
- }
322
-
323
- public static function meta_box_bookings_stats(){
324
- em_locate_template('forms/event/booking-stats.php',true);
325
- }
326
-
327
- public static function meta_box_bookings(){
328
- em_locate_template('forms/event/bookings.php', true);
329
- add_action('admin_footer',array('EM_Event_Post_Admin','meta_box_bookings_overlay'));
330
- }
331
-
332
- public static function meta_box_bookings_overlay(){
333
- em_locate_template('forms/tickets-form.php', true); //put here as it can't be in the add event form
334
- }
335
-
336
- public static function meta_box_attributes(){
337
- em_locate_template('forms/event/attributes.php',true);
338
- }
339
-
340
- public static function meta_box_location(){
341
- em_locate_template('forms/event/location.php',true);
342
- }
343
-
344
- public static function meta_box_ms_categories(){
345
- global $EM_Event;
346
- EM_Object::ms_global_switch();
347
- $categories = EM_Categories::get(array('hide_empty'=>false));
348
- ?>
349
- <?php if( count($categories) > 0 ): ?>
350
- <p class="ms-global-categories">
351
- <?php $selected = $EM_Event->get_categories()->get_ids(); ?>
352
- <?php $walker = new EM_Walker_Category(); ?>
353
- <?php $args_em = array( 'hide_empty' => 0, 'name' => 'event_categories[]', 'hierarchical' => true, 'id' => EM_TAXONOMY_CATEGORY, 'taxonomy' => EM_TAXONOMY_CATEGORY, 'selected' => $selected, 'walker'=> $walker); ?>
354
- <?php echo walk_category_dropdown_tree($categories, 0, $args_em); ?>
355
- </p>
356
- <?php else: ?>
357
- <p><?php sprintf(__('No categories available, <a href="%s">create one here first</a>','events-manager'), get_bloginfo('wpurl').'/wp-admin/admin.php?page=events-manager-categories'); ?></p>
358
- <?php endif; ?>
359
- <!-- END Categories -->
360
- <?php
361
- EM_Object::ms_global_switch_back();
362
- }
363
- }
364
- add_action('admin_init',array('EM_Event_Post_Admin','init'));
365
-
366
- /*
367
- * Recurring Events
368
- */
369
- class EM_Event_Recurring_Post_Admin{
370
- public static function init(){
371
- global $pagenow;
372
- if($pagenow == 'post.php' || $pagenow == 'post-new.php' ){ //only needed if editing post
373
- add_action('admin_head', array('EM_Event_Recurring_Post_Admin','admin_head'));
374
- //Meta Boxes
375
- add_action('add_meta_boxes_event-recurring', array('EM_Event_Recurring_Post_Admin','meta_boxes'), 10, 1);
376
- //Notices
377
- add_action('admin_notices',array('EM_Event_Post_Admin','admin_notices')); //shared with posts
378
- }
379
- //Save/Edit actions
380
- add_action('save_post',array('EM_Event_Recurring_Post_Admin','save_post'),10000,1); //late priority for checking non-EM meta data added later
381
- add_action('before_delete_post',array('EM_Event_Recurring_Post_Admin','before_delete_post'),10,1);
382
- add_action('trashed_post',array('EM_Event_Recurring_Post_Admin','trashed_post'),10,1);
383
- add_action('untrash_post',array('EM_Event_Recurring_Post_Admin','untrash_post'),10,1);
384
- add_action('untrashed_post',array('EM_Event_Recurring_Post_Admin','untrashed_post'),10,1);
385
- //Notices
386
- add_action('post_updated_messages',array('EM_Event_Post_Admin','admin_notices_filter'),1,1); //shared with posts
387
- }
388
-
389
- public static function admin_head(){
390
- global $post, $EM_Event;
391
- if( !empty($post) && $post->post_type == 'event-recurring' ){
392
- $EM_Event = em_get_event($post->ID, 'post_id');
393
- //quick hacks to make event admin table make more sense for events
394
- ?>
395
- <script type="text/javascript">
396
- jQuery(document).ready( function($){
397
- if(!EM.recurrences_menu){
398
- $('#menu-posts-'+EM.event_post_type+', #menu-posts-'+EM.event_post_type+' > a').addClass('wp-has-current-submenu');
399
- }
400
- });
401
- </script>
402
- <?php
403
- }
404
- }
405
-
406
- /**
407
- * Beacuse in wp admin recurrences get saved early on during save_post, meta added by other plugins to the recurring event template don't get copied over to recurrences
408
- * This re-saves meta late in save_post to correct this issue, in the future when recurrences refer to one post, this shouldn't be an issue
409
- * @param int $post_id
410
- */
411
- public static function save_post($post_id){
412
- global $wpdb, $EM_Notices, $EM_SAVING_EVENT, $EM_EVENT_SAVE_POST;
413
- if( !empty($EM_SAVING_EVENT) ) return; //never proceed with this if using EM_Event::save(); which only gets executed outside wp admin
414
- $post_type = get_post_type($post_id);
415
- $saving_status = !in_array(get_post_status($post_id), array('trash','auto-draft')) && !defined('DOING_AUTOSAVE');
416
- if(!defined('UNTRASHING_'.$post_id) && $post_type == 'event-recurring' && $saving_status && !empty($EM_EVENT_SAVE_POST) ){
417
- $EM_Event = em_get_event($post_id, 'post_id');
418
- $EM_Event->post_type = $post_type;
419
- //get the list post IDs for recurrences this recurrence
420
- if( !$EM_Event->save_events() && ( $EM_Event->is_published() || 'future' == $EM_Event->post_status ) ){
421
- $EM_Event->set_status(null, true);
422
- $EM_Notices->add_error(__ ( 'Something went wrong with the recurrence update...', 'events-manager'). __ ( 'There was a problem saving the recurring events.', 'events-manager'));
423
- }
424
- }
425
- $EM_EVENT_SAVE_POST = false; //last filter of save_post in EM for events
426
- }
427
-
428
- public static function before_delete_post($post_id){
429
- if(get_post_type($post_id) == 'event-recurring'){
430
- $EM_Event = em_get_event($post_id,'post_id');
431
- do_action('em_event_delete_pre ',$EM_Event);
432
- //now delete recurrences
433
- //only delete other events if this isn't a draft-never-published event
434
- if( !empty($EM_Event->event_id) ){
435
- $events_array = EM_Events::get( array('recurrence'=>$EM_Event->event_id, 'scope'=>'all', 'status'=>'everything' ) );
436
- foreach($events_array as $event){
437
- /* @var $event EM_Event */
438
- if($EM_Event->event_id == $event->recurrence_id && !empty($event->recurrence_id) ){ //double check the event is a recurrence of this event
439
- wp_delete_post($event->post_id, true);
440
- }
441
- }
442
- }
443
- $EM_Event->post_type = EM_POST_TYPE_EVENT; //trick it into thinking it's one event.
444
- $EM_Event->delete_meta();
445
- }
446
- }
447
-
448
- public static function trashed_post($post_id){
449
- if(get_post_type($post_id) == 'event-recurring'){
450
- global $EM_Notices, $wpdb;
451
- $EM_Event = em_get_event($post_id,'post_id');
452
- $EM_Event->set_status(null);
453
- //only trash other events if this isn't a draft-never-published event
454
- if( !empty($EM_Event->event_id) ){
455
- //now trash recurrences
456
- $events_array = EM_Events::get( array('recurrence_id'=>$EM_Event->event_id, 'scope'=>'all', 'status'=>'everything' ) );
457
- foreach($events_array as $event){
458
- /* @var $event EM_Event */
459
- if($EM_Event->event_id == $event->recurrence_id ){ //double check the event is a recurrence of this event
460
- wp_trash_post($event->post_id);
461
- }
462
- }
463
- }
464
- $EM_Notices->remove_all(); //no validation/notices needed
465
- }
466
- }
467
-
468
- public static function untrash_post($post_id){
469
- if(get_post_type($post_id) == 'event-recurring'){
470
- global $wpdb;
471
- //set a constant so we know this event doesn't need 'saving'
472
- if(!defined('UNTRASHING_'.$post_id)) define('UNTRASHING_'.$post_id, true);
473
- $EM_Event = em_get_event($post_id,'post_id');
474
- //only untrash other events if this isn't a draft-never-published event, because if so it never had other events to untrash
475
- if( !empty($EM_Event->event_id) ){
476
- $events_array = EM_Events::get( array('recurrence_id'=>$EM_Event->event_id, 'scope'=>'all', 'status'=>'everything' ) );
477
- foreach($events_array as $event){
478
- /* @var $event EM_Event */
479
- if($EM_Event->event_id == $event->recurrence_id){
480
- wp_untrash_post($event->post_id);
481
- }
482
- }
483
- }
484
- }
485
- }
486
-
487
- public static function untrashed_post($post_id){
488
- if(get_post_type($post_id) == 'event-recurring'){
489
- global $EM_Notices,$EM_Event;
490
- $EM_Event->set_status(1);
491
- $EM_Notices->remove_all(); //no validation/notices needed
492
- }
493
- }
494
-
495
- public static function meta_boxes( $post ){
496
- global $EM_Event;
497
- //since this is the first point when the admin area loads event stuff, we load our EM_Event here
498
- if( empty($EM_Event) && !empty($post) ){
499
- $EM_Event = em_get_event($post->ID, 'post_id');
500
- }
501
- if( !empty($EM_Event->event_owner_anonymous) ){
502
- add_meta_box('em-event-anonymous', __('Anonymous Submitter Info','events-manager'), array('EM_Event_Post_Admin','meta_box_anonymous'),'event-recurring', 'side','high');
503
- }
504
- add_meta_box('em-event-recurring', __('Recurrences','events-manager'), array('EM_Event_Recurring_Post_Admin','meta_box_recurrence'),'event-recurring', 'normal','high');
505
- //add_meta_box('em-event-meta', 'Event Meta (debugging only)', array('EM_Event_Post_Admin','meta_box_metadump'),'event-recurring', 'normal','high');
506
- if(get_option('dbem_locations_enabled', true)){
507
- add_meta_box('em-event-where', __('Where','events-manager'), array('EM_Event_Post_Admin','meta_box_location'),'event-recurring', 'normal','high');
508
- }
509
- if( get_option('dbem_rsvp_enabled') && $EM_Event->can_manage('manage_bookings','manage_others_bookings') ){
510
- add_meta_box('em-event-bookings', __('Bookings/Registration','events-manager'), array('EM_Event_Post_Admin','meta_box_bookings'),'event-recurring', 'normal','high');
511
- }
512
- if( get_option('dbem_attributes_enabled') ){
513
- add_meta_box('em-event-attributes', __('Attributes','events-manager'), array('EM_Event_Post_Admin','meta_box_attributes'),'event-recurring', 'normal','default');
514
- }
515
- if( EM_MS_GLOBAL && !is_main_site() && get_option('dbem_categories_enabled') ){
516
- add_meta_box('em-event-categories', __('Site Categories','events-manager'), array('EM_Event_Post_Admin','meta_box_ms_categories'),'event-recurring', 'side','low');
517
- }
518
- if( defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_DISPLAY') && WP_DEBUG_DISPLAY ){
519
- add_meta_box('em-event-meta', 'Event Meta (debugging only)', array('EM_Event_Post_Admin','meta_box_metadump'),'event-recurring', 'normal','high');
520
- }
521
- }
522
-
523
- public static function meta_box_recurrence(){
524
- ?><input type="hidden" name="_emnonce" value="<?php echo wp_create_nonce('edit_event'); ?>" /><?php
525
- em_locate_template('forms/event/recurring-when.php', true);
526
- }
527
- }
528
- add_action('admin_init',array('EM_Event_Recurring_Post_Admin','init'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-event-post.php DELETED
@@ -1,350 +0,0 @@
1
- <?php
2
- /**
3
- * Controls how events are queried and displayed via the WordPress Custom Post APIs
4
- * @author marcus
5
- *
6
- */
7
- class EM_Event_Post {
8
-
9
- public static function init(){
10
- //Front Side Modifiers
11
- if( !is_admin() ){
12
- //override single page with formats?
13
- add_filter('the_content', array('EM_Event_Post','the_content'));
14
- add_filter('the_excerpt_rss', array('EM_Event_Post','the_excerpt_rss'));
15
- //excerpts can trigger the_content which isn't ideal, so we disable the_content between the first and last excerpt calls within WP logic
16
- add_filter('get_the_excerpt', array('EM_Event_Post','disable_the_content'), 1);
17
- add_filter('get_the_excerpt', array('EM_Event_Post','enable_the_content'), 100);
18
- if( get_option('dbem_cp_events_excerpt_formats') ){
19
- //important add this before wp_trim_excerpt hook, as it can screw up things like wp_editor() for WordPress SEO plugin
20
- add_filter('get_the_excerpt', array('EM_Event_Post','get_the_excerpt'));
21
- }
22
- //display as page template?
23
- if( get_option('dbem_cp_events_template') ){
24
- add_filter('single_template',array('EM_Event_Post','single_template'));
25
- }
26
- //add classes to body and post_class()
27
- if( get_option('dbem_cp_events_post_class') != '' ){
28
- add_filter('post_class', array('EM_Event_Post','post_class'), 10, 3);
29
- }
30
- if( get_option('dbem_cp_events_body_class') != '' ){
31
- add_filter('body_class', array('EM_Event_Post','body_class'), 10, 3);
32
- }
33
- //Override post template tags
34
- add_filter('get_the_date',array('EM_Event_Post','the_date'),10,3);
35
- add_filter('get_the_time',array('EM_Event_Post','the_time'),10,3);
36
- add_filter('the_category',array('EM_Event_Post','the_category'),10,3);
37
- }
38
- add_action('parse_query', array('EM_Event_Post','parse_query'));
39
- add_action('publish_future_post',array('EM_Event_Post','publish_future_post'),10,1);
40
- }
41
-
42
- public static function publish_future_post($post_id){
43
- global $EM_Event;
44
- $post_type = get_post_type($post_id);
45
- $is_post_type = $post_type == EM_POST_TYPE_EVENT || $post_type == 'event-recurring';
46
- $saving_status = !in_array(get_post_status($post_id), array('trash','auto-draft')) && !defined('DOING_AUTOSAVE');
47
- if(!defined('UNTRASHING_'.$post_id) && $is_post_type && $saving_status ){
48
- $EM_Event = em_get_event($post_id, 'post_id');
49
- $EM_Event->set_status(1);
50
- }
51
- }
52
-
53
- /**
54
- * Overrides the default post format of an event and can display an event as a page, which uses the page.php template.
55
- * @param string $template
56
- * @return string
57
- */
58
- public static function single_template($template){
59
- global $post;
60
- if( !locate_template('single-'.EM_POST_TYPE_EVENT.'.php') && $post->post_type == EM_POST_TYPE_EVENT ){
61
- //do we have a default template to choose for events?
62
- if( get_option('dbem_cp_events_template') == 'page' ){
63
- $post_templates = array('page.php','index.php');
64
- }else{
65
- $post_templates = array(get_option('dbem_cp_events_template'));
66
- }
67
- if( !empty($post_templates) ){
68
- $post_template = locate_template($post_templates,false);
69
- if( !empty($post_template) ) $template = $post_template;
70
- }
71
- }
72
- return $template;
73
- }
74
-
75
- public static function post_class( $classes, $class, $post_id ){
76
- $post = get_post($post_id);
77
- if( $post->post_type == EM_POST_TYPE_EVENT ){
78
- foreach( explode(' ', get_option('dbem_cp_events_post_class')) as $class ){
79
- $classes[] = esc_attr($class);
80
- }
81
- }
82
- return $classes;
83
- }
84
-
85
- public static function body_class( $classes ){
86
- if( em_is_event_page() ){
87
- foreach( explode(' ', get_option('dbem_cp_events_body_class')) as $class ){
88
- $classes[] = esc_attr($class);
89
- }
90
- }
91
- return $classes;
92
- }
93
-
94
- /**
95
- * Overrides the_excerpt if this is an event post type
96
- */
97
- public static function get_the_excerpt($content){
98
- global $post;
99
- if( $post->post_type == EM_POST_TYPE_EVENT ){
100
- $EM_Event = em_get_event($post);
101
- $output = !empty($EM_Event->post_excerpt) ? get_option('dbem_event_excerpt_format'):get_option('dbem_event_excerpt_alt_format');
102
- $content = $EM_Event->output($output);
103
- }
104
- return $content;
105
- }
106
- public static function the_excerpt($content){ return self::get_the_excerpt($content); }
107
-
108
- public static function the_excerpt_rss( $content ){
109
- global $post;
110
- if( $post->post_type == EM_POST_TYPE_EVENT ){
111
- if( get_option('dbem_cp_events_formats') ){
112
- $EM_Event = em_get_event($post);
113
- $content = $EM_Event->output( get_option ( 'dbem_rss_description_format' ), "rss");
114
- $content = ent2ncr(convert_chars($content)); //Some RSS filtering
115
- }
116
- }
117
- return $content;
118
- }
119
-
120
- public static function enable_the_content( $content ){
121
- add_filter('the_content', array('EM_Event_Post','the_content'));
122
- return $content;
123
- }
124
- public static function disable_the_content( $content ){
125
- remove_filter('the_content', array('EM_Event_Post','the_content'));
126
- return $content;
127
- }
128
-
129
- public static function the_content( $content ){
130
- global $post, $EM_Event;
131
- if( !empty($post) && $post->post_type == EM_POST_TYPE_EVENT ){
132
- if( is_archive() || is_search() ){
133
- if(get_option('dbem_cp_events_archive_formats')){
134
- $EM_Event = em_get_event($post);
135
- $content = $EM_Event->output(get_option('dbem_event_list_item_format'));
136
- }
137
- }else{
138
- if( get_option('dbem_cp_events_formats') && !post_password_required() ){
139
- $EM_Event = em_get_event($post);
140
- //do a little check for preview mode and re-insert content from $post
141
- if( !empty($_REQUEST['preview']) ){
142
- //we don't do extra checks here because WP will have already done the work for us here...
143
- $EM_Event->post_content = $post->post_content;
144
- $EM_Event->post_content_filtered = $post->post_content_filtered;
145
- }
146
- ob_start();
147
- em_locate_template('templates/event-single.php',true);
148
- $content = ob_get_clean();
149
- }elseif( !post_password_required() ){
150
- $EM_Event = em_get_event($post);
151
- if( $EM_Event->event_rsvp && (!defined('EM_DISABLE_AUTO_BOOKINGSFORM') || !EM_DISABLE_AUTO_BOOKINGSFORM) ){
152
- $content .= '<h2>'.esc_html__('Bookings','events-manager').'</h2>';
153
- $content .= $EM_Event->output('#_BOOKINGFORM');
154
- }
155
- }
156
- }
157
- }
158
- return $content;
159
- }
160
-
161
- public static function the_date( $the_date, $d = '', $post = null ){
162
- $post = get_post( $post );
163
- if( $post->post_type == EM_POST_TYPE_EVENT ){
164
- $EM_Event = em_get_event($post);
165
- if ( '' == $d ){
166
- $the_date = $EM_Event->start()->i18n(get_option('date_format'));
167
- }else{
168
- $the_date = $EM_Event->start()->i18n($d);
169
- }
170
- }
171
- return $the_date;
172
- }
173
-
174
- public static function the_time( $the_time, $f = '', $post = null ){
175
- $post = get_post( $post );
176
- if( $post->post_type == EM_POST_TYPE_EVENT ){
177
- $EM_Event = em_get_event($post);
178
- if ( '' == $f ){
179
- $the_time = $EM_Event->start()->i18n(get_option('time_format'));
180
- }else{
181
- $the_time = $EM_Event->start()->i18n($f);
182
- }
183
- }
184
- return $the_time;
185
- }
186
-
187
- public static function the_category( $thelist, $separator = '', $parents='' ){
188
- global $post, $wp_rewrite;
189
- if( $post->post_type == EM_POST_TYPE_EVENT ){
190
- $EM_Event = em_get_event($post);
191
- $categories = $EM_Event->get_categories();
192
- if( empty($categories) ) return '';
193
-
194
- /* Copied from get_the_category_list function, with a few minor edits to make urls work, and removing parent stuff (for now) */
195
- $rel = ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) ? 'rel="category tag"' : 'rel="category"';
196
-
197
- $thelist = '';
198
- if ( '' == $separator ) {
199
- $thelist .= '<ul class="post-categories">';
200
- foreach ( $categories as $category ) {
201
- $thelist .= "\n\t<li>";
202
- switch ( strtolower( $parents ) ) {
203
- case 'multiple':
204
- $thelist .= '<a href="' . $category->get_url() . '" title="' . esc_attr( sprintf( __( "View all posts in %s", 'events-manager'), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a></li>';
205
- break;
206
- case 'single':
207
- $thelist .= '<a href="' . $category->get_url() . '" title="' . esc_attr( sprintf( __( "View all posts in %s", 'events-manager'), $category->name ) ) . '" ' . $rel . '>';
208
- $thelist .= $category->name.'</a></li>';
209
- break;
210
- case '':
211
- default:
212
- $thelist .= '<a href="' . $category->get_url() . '" title="' . esc_attr( sprintf( __( "View all posts in %s", 'events-manager'), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a></li>';
213
- }
214
- }
215
- $thelist .= '</ul>';
216
- } else {
217
- $i = 0;
218
- foreach ( $categories as $category ) {
219
- if ( 0 < $i )
220
- $thelist .= $separator;
221
- switch ( strtolower( $parents ) ) {
222
- case 'multiple':
223
- $thelist .= '<a href="' . $category->get_url() . '" title="' . esc_attr( sprintf( __( "View all posts in %s", 'events-manager'), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a>';
224
- break;
225
- case 'single':
226
- $thelist .= '<a href="' . $category->get_url() . '" title="' . esc_attr( sprintf( __( "View all posts in %s", 'events-manager'), $category->name ) ) . '" ' . $rel . '>';
227
- $thelist .= "$category->name</a>";
228
- break;
229
- case '':
230
- default:
231
- $thelist .= '<a href="' . $category->get_url() . '" title="' . esc_attr( sprintf( __( "View all posts in %s", 'events-manager'), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a>';
232
- }
233
- ++$i;
234
- }
235
- }
236
- /* End copying */
237
- }
238
- return $thelist;
239
- }
240
-
241
- public static function parse_query(){
242
- global $wp_query;
243
- //Search Query Filtering
244
- if( is_admin() ){
245
- if( !empty($wp_query->query_vars[EM_TAXONOMY_CATEGORY]) && is_numeric($wp_query->query_vars[EM_TAXONOMY_CATEGORY]) ){
246
- //sorts out filtering admin-side as it searches by id
247
- $term = get_term_by('id', $wp_query->query_vars[EM_TAXONOMY_CATEGORY], EM_TAXONOMY_CATEGORY);
248
- $wp_query->query_vars[EM_TAXONOMY_CATEGORY] = ( $term !== false && !is_wp_error($term) )? $term->slug:0;
249
- }
250
- }
251
- //Scoping
252
- if( !empty($wp_query->query_vars['post_type']) && ($wp_query->query_vars['post_type'] == EM_POST_TYPE_EVENT || $wp_query->query_vars['post_type'] == 'event-recurring') && (empty($wp_query->query_vars['post_status']) || !in_array($wp_query->query_vars['post_status'],array('trash','pending','draft'))) ) {
253
- $query = array();
254
- //Let's deal with the scope - default is future
255
- if( is_admin() ){
256
- $scope = $wp_query->query_vars['scope'] = (!empty($_REQUEST['scope'])) ? $_REQUEST['scope']:'future';
257
- //TODO limit what a user can see admin side for events/locations/recurring events
258
- if( !empty($wp_query->query_vars['recurrence_id']) && is_numeric($wp_query->query_vars['recurrence_id']) ){
259
- $query[] = array( 'key' => '_recurrence_id', 'value' => $wp_query->query_vars['recurrence_id'], 'compare' => '=' );
260
- }
261
- }else{
262
- if( !empty($wp_query->query_vars['calendar_day']) ) $wp_query->query_vars['scope'] = $wp_query->query_vars['calendar_day'];
263
- if( empty($wp_query->query_vars['scope']) ){
264
- if( is_archive() ){
265
- $scope = $wp_query->query_vars['scope'] = get_option('dbem_events_archive_scope');
266
- }else{
267
- $scope = $wp_query->query_vars['scope'] = 'all'; //otherwise we'll get 404s for past events
268
- }
269
- }else{
270
- $scope = $wp_query->query_vars['scope'];
271
- }
272
- }
273
- if ( $scope == 'today' || $scope == 'tomorrow' || preg_match ( "/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/", $scope ) ) {
274
- $EM_DateTime = new EM_DateTime($scope); //create default time in blog timezone
275
- if( get_option('dbem_events_current_are_past') && $wp_query->query_vars['post_type'] != 'event-recurring' ){
276
- $query[] = array( 'key' => '_event_start_date', 'value' => $EM_DateTime->getDate() );
277
- }else{
278
- $query[] = array( 'key' => '_event_start_date', 'value' => $EM_DateTime->getDate(), 'compare' => '<=', 'type' => 'DATE' );
279
- $query[] = array( 'key' => '_event_end_date', 'value' => $EM_DateTime->getDate(), 'compare' => '>=', 'type' => 'DATE' );
280
- }
281
- }elseif ($scope == "future" || $scope == 'past' ){
282
- $EM_DateTime = new EM_DateTime(); //create default time in blog timezone
283
- $EM_DateTime->setTimezone('UTC');
284
- $compare = $scope == 'future' ? '>=' : '<';
285
- if( get_option('dbem_events_current_are_past') && $wp_query->query_vars['post_type'] != 'event-recurring' ){
286
- $query[] = array( 'key' => '_event_start', 'value' => $EM_DateTime->getDateTime(), 'compare' => $compare, 'type' => 'DATETIME' );
287
- }else{
288
- $query[] = array( 'key' => '_event_end', 'value' => $EM_DateTime->getDateTime(), 'compare' => $compare, 'type' => 'DATETIME' );
289
- }
290
- }elseif ($scope == "month" || $scope == "next-month" ){
291
- $EM_DateTime = new EM_DateTime(); //create default time in blog timezone
292
- if( $scope == 'next-month' ) $EM_DateTime->add('P1M');
293
- $start_month = $EM_DateTime->modify('first day of this month')->getDate();
294
- $end_month = $EM_DateTime->modify('last day of this month')->getDate();
295
- if( get_option('dbem_events_current_are_past') && $wp_query->query_vars['post_type'] != 'event-recurring' ){
296
- $query[] = array( 'key' => '_event_start_date', 'value' => array($start_month,$end_month), 'type' => 'DATE', 'compare' => 'BETWEEN');
297
- }else{
298
- $query[] = array( 'key' => '_event_start_date', 'value' => $end_month, 'compare' => '<=', 'type' => 'DATE' );
299
- $query[] = array( 'key' => '_event_end_date', 'value' => $start_month, 'compare' => '>=', 'type' => 'DATE' );
300
- }
301
- }elseif( preg_match('/(\d\d?)\-months/',$scope,$matches) ){ // next x months means this month (what's left of it), plus the following x months until the end of that month.
302
- $EM_DateTime = new EM_DateTime(); //create default time in blog timezone
303
- $months_to_add = $matches[1];
304
- $start_month = $EM_DateTime->getDate();
305
- $end_month = $EM_DateTime->add('P'.$months_to_add.'M')->format('Y-m-t');
306
- if( get_option('dbem_events_current_are_past') && $wp_query->query_vars['post_type'] != 'event-recurring' ){
307
- $query[] = array( 'key' => '_event_start_date', 'value' => array($start_month,$end_month), 'type' => 'DATE', 'compare' => 'BETWEEN');
308
- }else{
309
- $query[] = array( 'key' => '_event_start_date', 'value' => $end_month, 'compare' => '<=', 'type' => 'DATE' );
310
- $query[] = array( 'key' => '_event_end_date', 'value' => $start_month, 'compare' => '>=', 'type' => 'DATE' );
311
- }
312
- }elseif( !empty($scope) ){
313
- $query = apply_filters('em_event_post_scope_meta_query', $query, $scope);
314
- }
315
- if( !empty($query) && is_array($query) ){
316
- $wp_query->query_vars['meta_query'] = $query;
317
- }
318
- if( is_admin() ){
319
- //admin areas don't need special ordering, so make it simple
320
- if( !empty($_REQUEST['orderby']) && $_REQUEST['orderby'] != 'date-time' ){
321
- $wp_query->query_vars['orderby'] = sanitize_key($_REQUEST['orderby']);
322
- }else{
323
- $wp_query->query_vars['orderby'] = 'meta_value';
324
- $wp_query->query_vars['meta_key'] = '_event_start_local';
325
- $wp_query->query_vars['meta_type'] = 'DATETIME';
326
- }
327
- $wp_query->query_vars['order'] = (!empty($_REQUEST['order']) && preg_match('/^(ASC|DESC)$/i', $_REQUEST['order'])) ? $_REQUEST['order']:'ASC';
328
- }else{
329
- if( get_option('dbem_events_default_archive_orderby') == 'title'){
330
- $wp_query->query_vars['orderby'] = 'title';
331
- $wp_query->query_vars['order'] = get_option('dbem_events_default_archive_order','ASC');
332
- }else{
333
- $wp_query->query_vars['orderby'] = 'meta_value';
334
- $wp_query->query_vars['meta_key'] = '_event_start_local';
335
- $wp_query->query_vars['meta_type'] = 'DATETIME';
336
- }
337
- $wp_query->query_vars['order'] = get_option('dbem_events_default_archive_order','ASC');
338
- }
339
- }elseif( !empty($wp_query->query_vars['post_type']) && $wp_query->query_vars['post_type'] == EM_POST_TYPE_EVENT ){
340
- $wp_query->query_vars['scope'] = 'all';
341
- if( $wp_query->query_vars['post_status'] == 'pending' ){
342
- $wp_query->query_vars['orderby'] = 'meta_value';
343
- $wp_query->query_vars['order'] = 'ASC';
344
- $wp_query->query_vars['meta_key'] = '_event_start_local';
345
- $wp_query->query_vars['meta_type'] = 'DATETIME';
346
- }
347
- }
348
- }
349
- }
350
- EM_Event_Post::init();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-event-posts-admin.php DELETED
@@ -1,421 +0,0 @@
1
- <?php
2
- class EM_Event_Posts_Admin{
3
- public static function init(){
4
- global $pagenow;
5
- if( $pagenow == 'edit.php' && !empty($_REQUEST['post_type']) && $_REQUEST['post_type'] == EM_POST_TYPE_EVENT ){ //only needed for events list
6
- if( !empty($_REQUEST['category_id']) && is_numeric($_REQUEST['category_id']) ){
7
- $term = get_term_by('id', absint($_REQUEST['category_id']), EM_TAXONOMY_CATEGORY);
8
- if( !empty($term->slug) ){
9
- $_REQUEST['category_id'] = $term->slug;
10
- }
11
- }
12
- //admin warnings
13
- add_action('admin_notices', 'EM_Event_Posts_Admin::admin_notices');
14
- //hide some cols by default:
15
- $screen = 'edit-'.EM_POST_TYPE_EVENT;
16
- $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
17
- if( $hidden === false ){
18
- $hidden = array('event-id');
19
- update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
20
- }
21
- //deal with actions
22
- $row_action_type = is_post_type_hierarchical( EM_POST_TYPE_EVENT ) ? 'page_row_actions' : 'post_row_actions';
23
- add_filter($row_action_type, array('EM_Event_Posts_Admin','row_actions'),10,2);
24
- add_action('admin_head', array('EM_Event_Posts_Admin','admin_head'));
25
- }
26
- //collumns
27
- add_filter('manage_'.EM_POST_TYPE_EVENT.'_posts_columns' , array('EM_Event_Posts_Admin','columns_add'));
28
- add_action('manage_'.EM_POST_TYPE_EVENT.'_posts_custom_column' , array('EM_Event_Posts_Admin','columns_output'),10,2 );
29
- add_filter('manage_edit-'.EM_POST_TYPE_EVENT.'_sortable_columns', array('EM_Event_Posts_Admin','sortable_columns') );
30
- //clean up the views in the admin selection area - WIP
31
- //add_filter('views_edit-'.EM_POST_TYPE_EVENT, array('EM_Event_Posts_Admin','restrict_views'),10,2);
32
- //add_filter('views_edit-event-recurring', array('EM_Event_Posts_Admin','restrict_views'),10,2);
33
- //add filters to event post list tables
34
- add_action('restrict_manage_posts', array('EM_Event_Posts_Admin','restrict_manage_posts'));
35
- }
36
-
37
- public static function admin_head(){
38
- //quick hacks to make event admin table make more sense for events
39
- ?>
40
- <script type="text/javascript">
41
- jQuery(document).ready( function($){
42
- $('.inline-edit-date').prev().css('display','none').next().css('display','none').next().css('display','none');
43
- $('.em-detach-link').on('click', function( event ){
44
- if( !confirm(EM.event_detach_warning) ){
45
- event.preventDefault();
46
- return false;
47
- }
48
- });
49
- $('.em-delete-recurrence-link').on('click', function( event ){
50
- if( !confirm(EM.delete_recurrence_warning) ){
51
- event.preventDefault();
52
- return false;
53
- }
54
- });
55
- });
56
- </script>
57
- <style>
58
- table.fixed{ table-layout:auto !important; }
59
- .tablenav select[name="m"] { display:none; }
60
- </style>
61
- <?php
62
- }
63
-
64
- public static function admin_notices(){
65
- if( !empty($_REQUEST['recurrence_id']) && is_numeric($_REQUEST['recurrence_id']) ){
66
- $EM_Event = em_get_event( absint($_REQUEST['recurrence_id']) );
67
- ?>
68
- <div class="notice notice-info">
69
- <p><?php echo sprintf(esc_html__('You are viewing individual recurrences of recurring event %s.', 'events-manager'), '<a href="'.$EM_Event->get_edit_url().'">'.$EM_Event->event_name.'</a>'); ?></p>
70
- <p><?php esc_html_e('You can edit individual recurrences and disassociate them with this recurring event.', 'events-manager'); ?></p>
71
- </div>
72
- <?php
73
- }
74
- }
75
-
76
- /**
77
- * Handles WP_Query filter option in the admin area, which gets executed before EM_Event_Post::parse_query
78
- * Not yet in use
79
- */
80
- public static function parse_query(){
81
- global $wp_query;
82
- //Search Query Filtering
83
- if( !empty($wp_query->query_vars[EM_TAXONOMY_CATEGORY]) && is_numeric($wp_query->query_vars[EM_TAXONOMY_CATEGORY]) ){
84
- //sorts out filtering admin-side as it searches by id
85
- $term = get_term_by('id', $wp_query->query_vars[EM_TAXONOMY_CATEGORY], EM_TAXONOMY_CATEGORY);
86
- $wp_query->query_vars[EM_TAXONOMY_CATEGORY] = ( $term !== false && !is_wp_error($term) )? $term->slug:0;
87
- }
88
- if( !empty($wp_query->query_vars['post_type']) && ($wp_query->query_vars['post_type'] == EM_POST_TYPE_EVENT || $wp_query->query_vars['post_type'] == 'event-recurring') && (empty($wp_query->query_vars['post_status']) || !in_array($wp_query->query_vars['post_status'],array('trash','pending','draft'))) ) {
89
- //Set up Scope for EM_Event_Post
90
- $scope = $wp_query->query_vars['scope'] = (!empty($_REQUEST['scope'])) ? $_REQUEST['scope']:'future';
91
- }
92
- }
93
-
94
- /**
95
- * Adds Future view to make things simpler, and also changes counts if user doesn't have edit_others_events permission
96
- * @param array $views
97
- * @return array
98
- */
99
- public static function restrict_views( $views ){
100
- global $wp_query;
101
- //TODO alter views of locations, events and recurrences, specifically find a good way to alter the wp_count_posts method to force user owned posts only
102
- $post_type = get_current_screen()->post_type;
103
- if( in_array($post_type, array(EM_POST_TYPE_EVENT, 'event-recurring')) ){
104
- //get counts for future events
105
- $num_posts = wp_count_posts( $post_type, 'readable' );
106
- //prepare to alter cache if neccessary
107
- if( !isset($num_posts->em_future) ){
108
- $cache_key = $post_type;
109
- $user = wp_get_current_user();
110
- if ( is_user_logged_in() && !current_user_can('read_private_events') ) {
111
- $cache_key .= '_readable_' . $user->ID; //as seen on wp_count_posts
112
- }
113
- $args = array('scope'=>'future', 'status'=>'all');
114
- if( $post_type == 'event-recurring' ) $args['recurring'] = 1;
115
- $num_posts->em_future = EM_Events::count($args);
116
- wp_cache_set($cache_key, $num_posts, 'counts');
117
- }
118
- $class = '';
119
- //highlight the 'Future' status if necessary
120
- if( empty($_REQUEST['post_status']) && !empty($wp_query->query_vars['scope']) && $wp_query->query_vars['scope'] == 'future'){
121
- $class = ' class="current"';
122
- foreach($views as $key => $view){
123
- $views[$key] = str_replace(' class="current"','', $view);
124
- }
125
- }
126
- //change the 'All' status to have scope=all
127
- $views['all'] = str_replace('edit.php?', 'edit.php?scope=all&', $views['all'] );
128
- //merge new custom status into views
129
- $old_views = $views;
130
- $views = array('em_future' => "<a href='edit.php?post_type=$post_type'$class>" . sprintf( _nx( 'Future <span class="count">(%s)</span>', 'Future <span class="count">(%s)</span>', $num_posts->em_future, 'events', 'events-manager'), number_format_i18n( $num_posts->em_future ) ) . '</a>');
131
- $views = array_merge($views, $old_views);
132
- }
133
-
134
- return $views;
135
- }
136
-
137
- public static function restrict_manage_posts(){
138
- global $wp_query;
139
- if( $wp_query->query_vars['post_type'] == EM_POST_TYPE_EVENT || $wp_query->query_vars['post_type'] == 'event-recurring' ){
140
- ?>
141
- <select name="scope">
142
- <?php
143
- $scope = (!empty($wp_query->query_vars['scope'])) ? $wp_query->query_vars['scope']:'future';
144
- foreach ( em_get_scopes() as $key => $value ) {
145
- $selected = "";
146
- if ($key == $scope)
147
- $selected = "selected='selected'";
148
- echo "<option value='$key' $selected>$value</option> ";
149
- }
150
- ?>
151
- </select>
152
- <?php
153
- if( get_option('dbem_categories_enabled') ){
154
- //Categories
155
- $selected = !empty($_GET['event-categories']) ? $_GET['event-categories'] : 0;
156
- wp_dropdown_categories(array( 'hide_empty' => 1, 'name' => EM_TAXONOMY_CATEGORY,
157
- 'hierarchical' => true, 'orderby'=>'name', 'id' => EM_TAXONOMY_CATEGORY,
158
- 'taxonomy' => EM_TAXONOMY_CATEGORY, 'selected' => $selected,
159
- 'show_option_all' => __('View all categories')));
160
- }
161
- if( !empty($_REQUEST['author']) ){
162
- ?>
163
- <input type="hidden" name="author" value="<?php echo esc_attr($_REQUEST['author']); ?>" />
164
- <?php
165
- }
166
- }
167
- }
168
-
169
- public static function views($views){
170
- if( !current_user_can('edit_others_events') ){
171
- //alter the views to reflect correct numbering
172
-
173
- }
174
- return $views;
175
- }
176
-
177
- public static function columns_add($columns) {
178
- if( array_key_exists('cb', $columns) ){
179
- $cb = $columns['cb'];
180
- unset($columns['cb']);
181
- $id_array = array('cb'=>$cb, 'event-id' => sprintf(__('%s ID','events-manager'),__('Event','events-manager')));
182
- }else{
183
- $id_array = array('event-id' => sprintf(__('%s ID','events-manager'),__('Event','events-manager')));
184
- }
185
- unset($columns['comments']);
186
- unset($columns['date']);
187
- unset($columns['author']);
188
- $columns = array_merge($id_array, $columns, array(
189
- 'location' => __('Location','events-manager'),
190
- 'date-time' => __('Date and Time','events-manager'),
191
- 'author' => __('Owner','events-manager'),
192
- 'extra' => ''
193
- ));
194
- if( !get_option('dbem_locations_enabled') ){
195
- unset($columns['location']);
196
- }
197
- return $columns;
198
- }
199
-
200
- public static function columns_output( $column ) {
201
- global $post, $EM_Event;
202
- $EM_Event = em_get_event($post, 'post_id');
203
- /* @var $post EM_Event */
204
- switch ( $column ) {
205
- case 'event-id':
206
- echo $EM_Event->event_id;
207
- break;
208
- case 'location':
209
- //get meta value to see if post has location, otherwise
210
- $EM_Location = $EM_Event->get_location();
211
- if( $EM_Event->has_location() ){
212
- $actions = array();
213
- $actions[] = "<a href='". esc_url($EM_Location->get_permalink())."'>". esc_html__('View') ."</a>";
214
- if( $EM_Location->can_manage('edit_locations', 'edit_others_locations') ) {
215
- $actions[] = "<a href='". esc_url($EM_Location->get_edit_url())."'>". esc_html__('Edit') ."</a>";
216
- }
217
- echo "<strong><a href='". $EM_Location->get_permalink()."'>" . $EM_Location->location_name . "</a></strong>";
218
- echo "<span class='row-actions'> - ". implode(' | ', $actions) . "</span>";
219
- echo "<br/>" . $EM_Location->location_address . " - " . $EM_Location->location_town;
220
- }elseif( $EM_Event->has_event_location() ) {
221
- echo $EM_Event->get_event_location()->get_admin_column();
222
- }else{
223
- echo __('None','events-manager');
224
- }
225
- break;
226
- case 'date-time':
227
- //get meta value to see if post has location, otherwise
228
- $localised_start_date = $EM_Event->start()->i18n(get_option('date_format'));
229
- $localised_end_date = $EM_Event->end()->i18n(get_option('date_format'));
230
- echo $localised_start_date;
231
- echo ($localised_end_date != $localised_start_date) ? " - $localised_end_date":'';
232
- echo "<br />";
233
- if(!$EM_Event->event_all_day){
234
- echo $EM_Event->start()->i18n(get_option('time_format')) . " - " . $EM_Event->end()->i18n(get_option('time_format'));
235
- }else{
236
- echo get_option('dbem_event_all_day_message');
237
- }
238
- if( $EM_Event->get_timezone()->getName() != EM_DateTimeZone::create()->getName() ) echo '<span class="dashicons dashicons-info" style="font-size:16px; color:#ccc; padding-top:2px;" title="'.esc_attr(str_replace('_', ' ', $EM_Event->event_timezone)).'"></span>';
239
- break;
240
- case 'extra':
241
- if( get_option('dbem_rsvp_enabled') == 1 && !empty($EM_Event->event_rsvp) && $EM_Event->can_manage('manage_bookings','manage_others_bookings')){
242
- ?>
243
- <a href="<?php echo $EM_Event->get_bookings_url(); ?>"><?php echo __("Bookings",'events-manager'); ?></a> &ndash;
244
- <?php _e("Booked",'events-manager'); ?>: <?php echo $EM_Event->get_bookings()->get_booked_spaces()."/".$EM_Event->get_spaces(); ?>
245
- <?php if( get_option('dbem_bookings_approval') == 1 ): ?>
246
- | <?php _e("Pending",'events-manager') ?>: <?php echo $EM_Event->get_bookings()->get_pending_spaces(); ?>
247
- <?php endif;
248
- echo ($EM_Event->is_recurrence()) ? '<br />':'';
249
- }
250
- if ( $EM_Event->is_recurrence() && current_user_can('edit_recurring_events','edit_others_recurring_events') ) {
251
- $actions = array();
252
- if( $EM_Event->get_event_recurrence()->can_manage('edit_recurring_events', 'edit_others_recurring_events') ){
253
- $actions[] = '<a href="'. admin_url() .'post.php?action=edit&amp;post='. $EM_Event->get_event_recurrence()->post_id .'">'. esc_html__( 'Edit Recurring Events', 'events-manager'). '</a>';
254
- $actions[] = '<a class="em-detach-link" href="'. esc_url($EM_Event->get_detach_url()) .'">'. esc_html__('Detach', 'events-manager') .'</a>';
255
- }
256
- if( $EM_Event->get_event_recurrence()->can_manage('delete_recurring_events', 'delete_others_recurring_events') ){
257
- $actions[] = '<span class="trash"><a class="em-delete-recurrence-link" href="'. get_delete_post_link($EM_Event->get_event_recurrence()->post_id) .'">'. esc_html__('Delete','events-manager') .'</a></span>';
258
- }
259
- ?>
260
- <strong>
261
- <?php echo $EM_Event->get_recurrence_description(); ?>
262
- </strong>
263
- <?php if( !empty($actions) ): ?>
264
- <br >
265
- <div class="row-actions">
266
- <?php echo implode(' | ', $actions); ?>
267
- </div>
268
- <?php endif;
269
- }
270
-
271
- break;
272
- }
273
- }
274
-
275
- public static function row_actions($actions, $post){
276
- if($post->post_type == EM_POST_TYPE_EVENT){
277
- global $post, $EM_Event;
278
- $EM_Event = em_get_event($post, 'post_id');
279
- $actions['duplicate'] = '<a href="'.$EM_Event->duplicate_url().'" title="'.sprintf(__('Duplicate %s','events-manager'), __('Event','events-manager')).'">'.__('Duplicate','events-manager').'</a>';
280
- }
281
- return $actions;
282
- }
283
-
284
- public static function sortable_columns( $columns ){
285
- $columns['date-time'] = 'date-time';
286
- return $columns;
287
- }
288
-
289
- }
290
- add_action('admin_init', array('EM_Event_Posts_Admin','init'));
291
-
292
- /*
293
- * Recurring Events
294
- */
295
- class EM_Event_Recurring_Posts_Admin{
296
- public static function init(){
297
- global $pagenow;
298
- if( $pagenow == 'edit.php' && !empty($_REQUEST['post_type']) && $_REQUEST['post_type'] == 'event-recurring' ){
299
- //hide some cols by default:
300
- $screen = 'edit-event-recurring';
301
- $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
302
- if( $hidden === false ){
303
- $hidden = array('event-id');
304
- update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
305
- }
306
- //notices
307
- add_action('admin_notices',array('EM_Event_Recurring_Posts_Admin','admin_notices'));
308
- add_action('admin_head', array('EM_Event_Recurring_Posts_Admin','admin_head'));
309
- //actions
310
- $row_action_type = is_post_type_hierarchical( EM_POST_TYPE_EVENT ) ? 'page_row_actions' : 'post_row_actions';
311
- add_filter($row_action_type, array('EM_Event_Recurring_Posts_Admin','row_actions'),10,2);
312
- }
313
- //collumns
314
- add_filter('manage_event-recurring_posts_columns' , array('EM_Event_Recurring_Posts_Admin','columns_add'));
315
- add_filter('manage_event-recurring_posts_custom_column' , array('EM_Event_Recurring_Posts_Admin','columns_output'),10,1 );
316
- add_action('restrict_manage_posts', array('EM_Event_Posts_Admin','restrict_manage_posts'));
317
- add_filter( 'manage_edit-event-recurring_sortable_columns', array('EM_Event_Posts_Admin','sortable_columns') );
318
- }
319
-
320
- public static function admin_notices(){
321
- ?>
322
- <div class="notice notice-info">
323
- <p><?php esc_html_e( 'Modifications to recurring events will be applied to all recurrences and will overwrite any changes made to those individual event recurrences.', 'events-manager'); ?></p>
324
- <p><?php esc_html_e( 'Bookings to individual event recurrences will be preserved if event times and ticket settings are not modified.', 'events-manager'); ?></p>
325
- <p>
326
- <a href="<?php echo esc_url( em_get_events_admin_url() ); ?>">
327
- <strong><?php esc_html_e('You can edit individual recurrences and disassociate them with a recurring event to prevent getting overwritten.', 'events-manager'); ?></strong>
328
- </a>
329
- </p>
330
- </div>
331
- <?php
332
- }
333
-
334
- public static function admin_head(){
335
- //quick hacks to make event admin table make more sense for events
336
- ?>
337
- <script type="text/javascript">
338
- jQuery(document).ready( function($){
339
- $('.inline-edit-date').prev().css('display','none').next().css('display','none').next().css('display','none');
340
- if(!EM.recurrences_menu){
341
- $('#menu-posts-'+EM.event_post_type+', #menu-posts-'+EM.event_post_type+' > a').addClass('wp-has-current-submenu');
342
- }
343
- });
344
- </script>
345
- <style>
346
- table.fixed{ table-layout:auto !important; }
347
- .tablenav select[name="m"] { display:none; }
348
- </style>
349
- <?php
350
- }
351
-
352
- public static function columns_add($columns) {
353
- if( array_key_exists('cb', $columns) ){
354
- $cb = $columns['cb'];
355
- unset($columns['cb']);
356
- $id_array = array('cb'=>$cb, 'event-id' => sprintf(__('%s ID','events-manager'),__('Event','events-manager')));
357
- }else{
358
- $id_array = array('event-id' => sprintf(__('%s ID','events-manager'),__('Event','events-manager')));
359
- }
360
- unset($columns['comments']);
361
- unset($columns['date']);
362
- unset($columns['author']);
363
- $columns = array_merge($id_array, $columns, array(
364
- 'location' => __('Location','events-manager'),
365
- 'date-time' => __('Date and Time','events-manager'),
366
- 'author' => __('Owner','events-manager'),
367
- ));
368
- if( !get_option('dbem_locations_enabled') ){
369
- unset($columns['location']);
370
- }
371
- return $columns;
372
- }
373
-
374
-
375
- public static function columns_output( $column ) {
376
- global $post, $EM_Event;
377
- if( $post->post_type == 'event-recurring' ){
378
- $post = $EM_Event = em_get_event($post);
379
- /* @var $post EM_Event */
380
- switch ( $column ) {
381
- case 'event-id':
382
- echo $EM_Event->event_id;
383
- break;
384
- case 'location':
385
- //get meta value to see if post has location, otherwise
386
- $EM_Location = $EM_Event->get_location();
387
- if( !empty($EM_Location->location_id) ){
388
- $actions = array();
389
- $actions[] = "<a href='". esc_url($EM_Location->get_permalink())."'>". esc_html__('View') ."</a>";
390
- if( $EM_Location->can_manage('edit_locations', 'edit_others_locations') ) {
391
- $actions[] = "<a href='". esc_url($EM_Location->get_edit_url())."'>". esc_html__('Edit') ."</a>";
392
- }
393
- echo "<strong><a href='". $EM_Location->get_permalink()."'>" . $EM_Location->location_name . "</a></strong>";
394
- echo "<span class='row-actions'> - ". implode(' | ', $actions) . "</span>";
395
- echo "<br/>" . $EM_Location->location_address . " - " . $EM_Location->location_town;
396
- }else{
397
- echo __('None','events-manager');
398
- }
399
- break;
400
- case 'date-time':
401
- echo $EM_Event->get_recurrence_description();
402
- $edit_url = add_query_arg(array('scope'=>'all', 'recurrence_id'=>$EM_Event->event_id), em_get_events_admin_url());
403
- $link_text = sprintf(__('View %s', 'events-manager'), __('Recurrences', 'events-manager'));
404
- echo "<br /><span class='row-actions'>
405
- <a href='". esc_url($edit_url) ."'>". esc_html($link_text) ."</a>
406
- </span>";
407
- break;
408
- }
409
- }
410
- }
411
-
412
- public static function row_actions($actions, $post){
413
- if($post->post_type == 'event-recurring'){
414
- global $post, $EM_Event;
415
- $EM_Event = em_get_event($post, 'post_id');
416
- $actions['duplicate'] = '<a href="'.$EM_Event->duplicate_url().'" title="'.sprintf(__('Duplicate %s','events-manager'), __('Event','events-manager')).'">'.__('Duplicate','events-manager').'</a>';
417
- }
418
- return $actions;
419
- }
420
- }
421
- add_action('admin_init', array('EM_Event_Recurring_Posts_Admin','init'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-event.php DELETED
@@ -1,3547 +0,0 @@
1
- <?php
2
- use EM_Event_Locations\Event_Location, EM_Event_Locations\Event_Locations;
3
- /**
4
- * Get an event in a db friendly way, by checking globals, cache and passed variables to avoid extra class instantiations.
5
- * @param mixed $id can be either a post object, event object, event id or post id
6
- * @param mixed $search_by default is post_id, otherwise it can be by event_id as well. In multisite global mode, a blog id can be supplied to load events from another blog.
7
- * @return EM_Event
8
- */
9
- function em_get_event($id = false, $search_by = 'event_id') {
10
- global $EM_Event;
11
- //check if it's not already global so we don't instantiate again
12
- if( is_object($EM_Event) && get_class($EM_Event) == 'EM_Event' ){
13
- if( is_object($id) && $EM_Event->post_id == $id->ID ){
14
- return apply_filters('em_get_event', $EM_Event);
15
- }elseif( !is_object($id) ){
16
- if( $search_by == 'event_id' && $EM_Event->event_id == $id ){
17
- return apply_filters('em_get_event', $EM_Event);
18
- }elseif( $search_by == 'post_id' && $EM_Event->post_id == $id ){
19
- return apply_filters('em_get_event', $EM_Event);
20
- }
21
- }
22
- }
23
- if( is_object($id) && get_class($id) == 'EM_Event' ){
24
- return apply_filters('em_get_event', $id);
25
- }elseif( !defined('EM_CACHE') || EM_CACHE ){
26
- //check the cache first
27
- $event_id = false;
28
- if( is_numeric($id) ){
29
- if( $search_by == 'event_id' ){
30
- $event_id = absint($id);
31
- }elseif( $search_by == 'post_id' ){
32
- $event_id = wp_cache_get($id, 'em_events_ids');
33
- }
34
- }elseif( !empty($id->ID) && !empty($id->post_type) && ($id->post_type == EM_POST_TYPE_EVENT || $id->post_type == 'event-recurring') ){
35
- $event_id = wp_cache_get($id->ID, 'em_events_ids');
36
- }
37
- if( $event_id ){
38
- $event = wp_cache_get($event_id, 'em_events');
39
- if( is_object($event) && !empty($event->event_id) && $event->event_id){
40
- return apply_filters('em_get_event', $event);
41
- }
42
- }
43
- }
44
- //if we get this far, just create a new event
45
- return apply_filters('em_get_event', new EM_Event($id,$search_by));
46
- }
47
- /**
48
- * Event Object. This holds all the info pertaining to an event, including location and recurrence info.
49
- * An event object can be one of three "types" a recurring event, recurrence of a recurring event, or a single event.
50
- * The single event might be part of a set of recurring events, but if loaded by specific event id then any operations and saves are
51
- * specifically done on this event. However, if you edit the recurring group, any changes made to single events are overwritten.
52
- *
53
- * @property string $language Language of the event, shorthand for event_language
54
- * @property string $translation Whether or not a event is a translation (i.e. it was translated from an original event), shorthand for event_translation
55
- * @property int $parent Event ID of parent event, shorthand for event_parent
56
- * @property int $id The Event ID, case sensitive, shorthand for event_id
57
- * @property string $slug Event slug, shorthand for event_slug
58
- * @property string name Event name, shorthand for event_name
59
- * @property int owner ID of author/owner, shorthand for event_owner
60
- * @property int status ID of post status, shorthand for event_status
61
- * @property string $event_start_time Start time of event
62
- * @property string $event_end_time End time of event
63
- * @property string $event_start_date Start date of event
64
- * @property string $event_end_date End date of event
65
- * @property string $event_start The event start date in local time. represented by a mysql DATE format
66
- * @property string $event_end The event end date in local time. represented by a mysql DATE format
67
- * @property string $event_timezone Timezone representation in PHP string or WP-style UTC offset
68
- * @property string $event_rsvp_date Start rsvo date of event
69
- * @property string $event_rsvp_time End rsvp time of event
70
- *
71
- */
72
- //TODO Can add more recurring functionality such as "also update all future recurring events" or "edit all events" like google calendar does.
73
- //TODO Integrate recurrences into events table
74
- //FIXME If you create a super long recurrence timespan, there could be thousands of events... need an upper limit here.
75
- class EM_Event extends EM_Object{
76
- /* Field Names */
77
- var $event_id;
78
- var $post_id;
79
- var $event_parent;
80
- var $event_slug;
81
- var $event_owner;
82
- var $event_name;
83
- /**
84
- * The event start time in local time, represented by a mysql TIME format or 00:00:00 default.
85
- * Protected so when set in PHP it will reset the EM_Event->start property (EM_DateTime object) so it will have the correct UTC time according to timezone.
86
- * @var string
87
- */
88
- protected $event_start_time = '00:00:00';
89
- /**
90
- * The event end time in local time, represented by a mysql TIME format or 00:00:00 default.
91
- * Protected so when set in PHP it will reset the EM_Event->end property (EM_DateTime object) so it will have the correct UTC time according to timezone.
92
- * @var string
93
- */
94
- protected $event_end_time = '00:00:00';
95
- /**
96
- * The event start date in local time. represented by a mysql DATE format.
97
- * Protected so when set in PHP it will reset the EM_Event->start property (EM_DateTime object) so it will have the correct UTC time according to timezone.
98
- * @var string
99
- */
100
- protected $event_start_date;
101
- /**
102
- * The event end date in local time. represented by a mysql DATE format.
103
- * Protected so when set in PHP it will reset the EM_Event->start property (EM_DateTime object) so it will have the correct UTC time according to timezone.
104
- * @var string
105
- */
106
- protected $event_end_date;
107
- /**
108
- * The event start date/time in UTC timezone, represented as a mysql DATETIME value. Protected non-accessible property.
109
- * Use $EM_Event->start() to obtain the date/time via the returned EM_DateTime object.
110
- * @var string
111
- */
112
- protected $event_start;
113
- /**
114
- * The event end date/time in UTC timezone, represented as a mysql DATETIME value. Protected non-accessible property.
115
- * Use $EM_Event->end() to obtain the date/time via the returned EM_DateTime object.
116
- * @var string
117
- */
118
- protected $event_end;
119
- /**
120
- * Whether an event is all day or at specific start/end times. When set to true, event start/end times are assumed to be 00:00:00 and 11:59:59 respectively.
121
- * @var boolean
122
- */
123
- var $event_all_day;
124
- /**
125
- * Timezone representation in PHP string or WP-style UTC offset.
126
- * @var string
127
- */
128
- protected $event_timezone;
129
- var $post_content;
130
- var $event_rsvp = 0;
131
- protected $event_rsvp_date;
132
- protected $event_rsvp_time;
133
- var $event_rsvp_spaces;
134
- var $event_spaces;
135
- var $event_private;
136
- var $location_id;
137
- /**
138
- * Key name of event location type associated to this event.
139
- *
140
- * Events can have an event-specific location type, such as a url, webinar or another custom type instead of a regular geographical location. If this value is set, then a registered event location type is loaded and relevant saved event meta is used.
141
- *
142
- * @var string
143
- */
144
- public $event_location_type;
145
- var $recurrence_id;
146
- var $event_status;
147
- var $blog_id = 0;
148
- var $group_id;
149
- var $event_language;
150
- var $event_translation = 0;
151
- /**
152
- * Populated with the non-hidden event post custom fields (i.e. not starting with _)
153
- * @var array
154
- */
155
- var $event_attributes = array();
156
- /* Recurring Specific Values */
157
- var $recurrence = 0;
158
- var $recurrence_interval;
159
- var $recurrence_freq;
160
- var $recurrence_byday;
161
- var $recurrence_days = 0;
162
- var $recurrence_byweekno;
163
- var $recurrence_rsvp_days;
164
- /* anonymous submission information */
165
- var $event_owner_anonymous;
166
- var $event_owner_name;
167
- var $event_owner_email;
168
- /**
169
- * Previously used to give this object shorter property names for db values (each key has a name) but this is now deprecated, use the db field names as properties. This propertey provides extra info about the db fields.
170
- * @var array
171
- */
172
- var $fields = array(
173
- 'event_id' => array( 'name'=>'id', 'type'=>'%d' ),
174
- 'post_id' => array( 'name'=>'post_id', 'type'=>'%d' ),
175
- 'event_parent' => array( 'type'=>'%d', 'null'=>true ),
176
- 'event_slug' => array( 'name'=>'slug', 'type'=>'%s', 'null'=>true ),
177
- 'event_owner' => array( 'name'=>'owner', 'type'=>'%d', 'null'=>true ),
178
- 'event_name' => array( 'name'=>'name', 'type'=>'%s', 'null'=>true ),
179
- 'event_timezone' => array('type'=>'%s', 'null'=>true ),
180
- 'event_start_time' => array( 'name'=>'start_time', 'type'=>'%s', 'null'=>true ),
181
- 'event_end_time' => array( 'name'=>'end_time', 'type'=>'%s', 'null'=>true ),
182
- 'event_start' => array('type'=>'%s', 'null'=>true ),
183
- 'event_end' => array('type'=>'%s', 'null'=>true ),
184
- 'event_all_day' => array( 'name'=>'all_day', 'type'=>'%d', 'null'=>true ),
185
- 'event_start_date' => array( 'name'=>'start_date', 'type'=>'%s', 'null'=>true ),
186
- 'event_end_date' => array( 'name'=>'end_date', 'type'=>'%s', 'null'=>true ),
187
- 'post_content' => array( 'name'=>'notes', 'type'=>'%s', 'null'=>true ),
188
- 'event_rsvp' => array( 'name'=>'rsvp', 'type'=>'%d' ),
189
- 'event_rsvp_date' => array( 'name'=>'rsvp_date', 'type'=>'%s', 'null'=>true ),
190
- 'event_rsvp_time' => array( 'name'=>'rsvp_time', 'type'=>'%s', 'null'=>true ),
191
- 'event_rsvp_spaces' => array( 'name'=>'rsvp_spaces', 'type'=>'%d', 'null'=>true ),
192
- 'event_spaces' => array( 'name'=>'spaces', 'type'=>'%d', 'null'=>true),
193
- 'location_id' => array( 'name'=>'location_id', 'type'=>'%d', 'null'=>true ),
194
- 'event_location_type' => array( 'type'=>'%s', 'null'=>true ),
195
- 'recurrence_id' => array( 'name'=>'recurrence_id', 'type'=>'%d', 'null'=>true ),
196
- 'event_status' => array( 'name'=>'status', 'type'=>'%d', 'null'=>true ),
197
- 'event_private' => array( 'name'=>'status', 'type'=>'%d', 'null'=>true ),
198
- 'blog_id' => array( 'name'=>'blog_id', 'type'=>'%d', 'null'=>true ),
199
- 'group_id' => array( 'name'=>'group_id', 'type'=>'%d', 'null'=>true ),
200
- 'event_language' => array( 'type'=>'%s', 'null'=>true ),
201
- 'event_translation' => array( 'type'=>'%d'),
202
- 'recurrence' => array( 'name'=>'recurrence', 'type'=>'%d', 'null'=>false ), //is this a recurring event template
203
- 'recurrence_interval' => array( 'name'=>'interval', 'type'=>'%d', 'null'=>true ), //every x day(s)/week(s)/month(s)
204
- 'recurrence_freq' => array( 'name'=>'freq', 'type'=>'%s', 'null'=>true ), //daily,weekly,monthly?
205
- 'recurrence_days' => array( 'name'=>'days', 'type'=>'%d', 'null'=>true ), //each event spans x days
206
- 'recurrence_byday' => array( 'name'=>'byday', 'type'=>'%s', 'null'=>true ), //if weekly or monthly, what days of the week?
207
- 'recurrence_byweekno' => array( 'name'=>'byweekno', 'type'=>'%d', 'null'=>true ), //if monthly which week (-1 is last)
208
- 'recurrence_rsvp_days' => array( 'name'=>'recurrence_rsvp_days', 'type'=>'%d', 'null'=>true ), //days before or after start date to generat bookings cut-off date
209
- );
210
- var $post_fields = array('event_slug','event_owner','event_name','event_private','event_status','event_attributes','post_id','post_content'); //fields that won't be taken from the em_events table anymore
211
- var $recurrence_fields = array('recurrence', 'recurrence_interval', 'recurrence_freq', 'recurrence_days', 'recurrence_byday', 'recurrence_byweekno', 'recurrence_rsvp_days');
212
-
213
- protected $shortnames = array(
214
- 'language' => 'event_language',
215
- 'translation' => 'event_translation',
216
- 'parent' => 'event_parent',
217
- 'id' => 'event_id',
218
- 'slug' => 'event_slug',
219
- 'name' => 'event_name',
220
- 'status' => 'event_status',
221
- 'owner' => 'event_owner',
222
- );
223
-
224
- var $image_url = '';
225
- /**
226
- * EM_DateTime of start date/time in local timezone.
227
- * As of EM 5.8 this property is protected and accessible via __get(). For backwards compatibility accessing this property directly returns the timestamp as before with an offset to timezone.
228
- * To access the object use EM_Event::start(), do not try to access it directly for better accuracy use EM_Event::start()->getTimestamp();
229
- * @var EM_DateTime
230
- */
231
- protected $start;
232
- /**
233
- * EM_DateTime of end date/time in local timezone.
234
- * As of EM 5.8 this property is protected and accessible via __get(). For backwards compatibility accessing this property directly returns the timestamp as before, with an offset to timezone.
235
- * To access the object use EM_Event::end(), do not try to access it directly for better accuracy use EM_Event::start()->getTimestamp();
236
- * @var EM_DateTime
237
- */
238
- protected $end;
239
- /**
240
- * Timestamp for booking cut-off date/time
241
- * @var EM_DateTime
242
- */
243
- protected $rsvp_end;
244
-
245
- /**
246
- * @var EM_Location
247
- */
248
- var $location;
249
- /**
250
- * @var Event_Location
251
- */
252
- var $event_location;
253
- /**
254
- * If we're switching event location types, previous event location is kept here and deleted upon save()
255
- * @var Event_Location
256
- */
257
- var $event_location_deleted = null;
258
- /**
259
- * @var EM_Bookings
260
- */
261
- var $bookings;
262
- /**
263
- * The contact person for this event
264
- * @var WP_User
265
- */
266
- var $contact;
267
- /**
268
- * The categories object containing the event categories
269
- * @var EM_Categories
270
- */
271
- var $categories;
272
- /**
273
- * The tags object containing the event tags
274
- * @var EM_Tags
275
- */
276
- var $tags;
277
- /**
278
- * If there are any errors, they will be added here.
279
- * @var array
280
- */
281
- var $errors = array();
282
- /**
283
- * If something was successful, a feedback message might be supplied here.
284
- * @var string
285
- */
286
- var $feedback_message;
287
- /**
288
- * Any warnings about an event (e.g. bad data, recurrence, etc.)
289
- * @var string
290
- */
291
- var $warnings;
292
- /**
293
- * Array of dbem_event field names required to create an event
294
- * @var array
295
- */
296
- var $required_fields = array('event_name', 'event_start_date');
297
- var $mime_types = array(1 => 'gif', 2 => 'jpg', 3 => 'png');
298
- /**
299
- * previous status of event when instantiated
300
- * @access protected
301
- * @var mixed
302
- */
303
- var $previous_status = false;
304
- /**
305
- * If set to true, recurring events will delete and recreate recurrences when saved.
306
- * @var boolean
307
- */
308
- var $recurring_reschedule = false;
309
- /**
310
- * If set to true, recurring events will delete bookings and tickets of recurrences and recreate tickets. If set explicitly to false bookings will be ignored when creating recurrences.
311
- * @var boolean
312
- */
313
- var $recurring_recreate_bookings;
314
- /**
315
- * Flag used for when saving a recurring event that previously had bookings enabled and then subsequently disabled.
316
- * If set to true, and $this->recurring_recreate_bookings is false, bookings and tickets of recurrences will be deleted.
317
- * @var boolean
318
- */
319
- var $recurring_delete_bookings = false;
320
- /**
321
- * If the event was just added/created during this execution, value will be true. Useful when running validation or making decisions on taking actions when events are saved/created for the first time.
322
- * @var boolean
323
- */
324
- var $just_added_event = false;
325
-
326
- /* Post Variables - copied out of post object for easy IDE reference */
327
- var $ID;
328
- var $post_author;
329
- var $post_date;
330
- var $post_date_gmt;
331
- var $post_title;
332
- var $post_excerpt = '';
333
- var $post_status;
334
- var $comment_status;
335
- var $ping_status;
336
- var $post_password;
337
- var $post_name;
338
- var $to_ping;
339
- var $pinged;
340
- var $post_modified;
341
- var $post_modified_gmt;
342
- var $post_content_filtered;
343
- var $post_parent;
344
- var $guid;
345
- var $menu_order;
346
- var $post_type;
347
- var $post_mime_type;
348
- var $comment_count;
349
- var $ancestors;
350
- var $filter;
351
-
352
- /**
353
- * Initialize an event. You can provide event data in an associative array (using database table field names), an id number, or false (default) to create empty event.
354
- * @param mixed $id
355
- * @param mixed $search_by default is post_id, otherwise it can be by event_id as well. In multisite global mode, a blog id can be supplied to load events from another blog.
356
- */
357
- function __construct($id = false, $search_by = 'event_id') {
358
- global $wpdb;
359
- if( is_array($id) ){
360
- //deal with the old array style, but we can't supply arrays anymore
361
- $id = (!empty($id['event_id'])) ? absint($id['event_id']) : absint($id['post_id']);
362
- $search_by = (!empty($id['event_id'])) ? 'event_id':'post_id';
363
- }
364
- $is_post = !empty($id->ID) && ($id->post_type == EM_POST_TYPE_EVENT || $id->post_type == 'event-recurring');
365
- if( $is_post ){
366
- $id->ID = absint($id->ID);
367
- }else{
368
- $id = absint($id);
369
- if( $id == 0 ) $id = false;
370
- }
371
- if( is_numeric($id) || $is_post ){ //only load info if $id is a number
372
- $event_post = null;
373
- if($search_by == 'event_id' && !$is_post ){
374
- //search by event_id, get post_id and blog_id (if in ms mode) and load the post
375
- $results = $wpdb->get_row($wpdb->prepare("SELECT post_id, blog_id FROM ".EM_EVENTS_TABLE." WHERE event_id=%d",$id), ARRAY_A);
376
- if( !empty($results['post_id']) ){ $this->post_id = $results['post_id']; $this->event_id = $id; }
377
- if( is_multisite() && (is_numeric($results['blog_id']) || $results['blog_id']=='' ) ){
378
- if( $results['blog_id']=='' ) $results['blog_id'] = get_current_site()->blog_id;
379
- $event_post = get_blog_post($results['blog_id'], $results['post_id']);
380
- $search_by = $this->blog_id = $results['blog_id'];
381
- }elseif( !empty($results['post_id']) ){
382
- $event_post = get_post($results['post_id']);
383
- }
384
- }else{
385
- //if searching specifically by post_id and in MS Global mode, then assume we're looking in the current blog we're in
386
- if( $search_by == 'post_id' && EM_MS_GLOBAL ) $search_by = get_current_blog_id();
387
- //get post data based on ID and search context
388
- if(!$is_post){
389
- if( is_multisite() && (is_numeric($search_by) || $search_by == '') ){
390
- if( $search_by == '' ) $search_by = get_current_site()->blog_id;
391
- //we've been given a blog_id, so we're searching for a post id
392
- $event_post = get_blog_post($search_by, $id);
393
- $this->blog_id = $search_by;
394
- }else{
395
- //search for the post id only
396
- $event_post = get_post($id);
397
- }
398
- }else{
399
- $event_post = $id;
400
- //if we're in MS Global mode, then unless a blog id was specified, we assume the current post object belongs to the current blog
401
- if( EM_MS_GLOBAL && !is_numeric($search_by) ){
402
- $this->blog_id = get_current_blog_id();
403
- }
404
- }
405
- $this->post_id = !empty($id->ID) ? $id->ID : $id;
406
- }
407
- $this->load_postdata($event_post, $search_by);
408
- }
409
- //set default timezone
410
- if( empty($this->event_timezone) ){
411
- if( get_option('dbem_timezone_enabled') ){
412
- //get default timezone for event, and sanitize UTC variations
413
- $this->event_timezone = get_option('dbem_timezone_default');
414
- if( $this->event_timezone == 'UTC+0' || $this->event_timezone == 'UTC +0' ){ $this->event_timezone = 'UTC'; }
415
- }else{
416
- $this->event_timezone = EM_DateTimeZone::create()->getName(); //set a default timezone if none exists
417
- }
418
- }
419
- //set recurrence value already
420
- $this->recurrence = $this->is_recurring() ? 1:0;
421
- //Do it here so things appear in the po file.
422
- $this->status_array = array(
423
- 0 => __('Pending','events-manager'),
424
- 1 => __('Approved','events-manager')
425
- );
426
- //add this event to the cache
427
- if( $this->event_id && $this->post_id ){
428
- wp_cache_set($this->event_id, $this, 'em_events');
429
- wp_cache_set($this->post_id, $this->event_id, 'em_events_ids');
430
- }
431
- do_action('em_event', $this, $id, $search_by);
432
- }
433
-
434
- function __get( $var ){
435
- //get the modified or created date from the DB only if requested, and save to object
436
- if( $var == 'event_date_modified' || $var == 'event_date_created'){
437
- global $wpdb;
438
- $row = $wpdb->get_row($wpdb->prepare("SELECT event_date_created, event_date_modified FROM ".EM_EVENTS_TABLE.' WHERE event_id=%s', $this->event_id));
439
- if( $row ){
440
- $this->event_date_modified = $row->event_date_modified;
441
- $this->event_date_created = $row->event_date_created;
442
- return $this->$var;
443
- }
444
- }elseif( in_array($var, array('event_start_date', 'event_start_time', 'event_end_date', 'event_end_time', 'event_rsvp_date', 'event_rsvp_time')) ){
445
- return $this->$var;
446
- }elseif( $var == 'event_timezone' ){
447
- return $this->get_timezone()->getName();
448
- }
449
- //deprecated properties for external access, use the start(), end() and rsvp_end() functions to access any of this data.
450
- if( $var == 'start' ) return $this->start()->getTimestampWithOffset();
451
- if( $var == 'end' ) return $this->end()->getTimestampWithOffset();
452
- if( $var == 'rsvp_end' ) return $this->rsvp_end()->getTimestampWithOffset();
453
- return parent::__get( $var );
454
- }
455
-
456
- public function __set( $prop, $val ){
457
- if( $prop == 'event_start_date' || $prop == 'event_end_date' || $prop == 'event_rsvp_date' ){
458
- //if date is valid, set it, if not set it to null
459
- $this->$prop = preg_match('/^\d{4}-\d{2}-\d{2}$/', $val) ? $val : null;
460
- if( $prop == 'event_start_date') $this->start = $this->event_start = null;
461
- elseif( $prop == 'event_end_date') $this->end = $this->event_end = null;
462
- elseif( $prop == 'event_rsvp_date') $this->rsvp_end = null;
463
- }elseif( $prop == 'event_start_time' || $prop == 'event_end_time' || $prop == 'event_rsvp_time' ){
464
- //if time is valid, set it, otherwise set it to midnight
465
- $this->$prop = preg_match('/^\d{2}:\d{2}:\d{2}$/', $val) ? $val : '00:00:00';
466
- if( $prop == 'event_start_date') $this->start = null;
467
- elseif( $prop == 'event_end_date') $this->end = null;
468
- elseif( $prop == 'event_rsvp_date') $this->rsvp_end = null;
469
- }
470
- //deprecated properties, use start()->setTimestamp() instead
471
- elseif( $prop == 'start' || $prop == 'end' || $prop == 'rsvp_end' ){
472
- if( is_numeric($val) ){
473
- $this->$prop()->setTimestamp( (int) $val);
474
- }elseif( is_string($val) ){
475
- $this->$val = new EM_DateTime($val, $this->event_timezone);
476
- }
477
- }
478
- //anything else
479
- else{
480
- $this->$prop = $val;
481
- }
482
- parent::__set( $prop, $val );
483
- }
484
-
485
- public function __isset( $prop ){
486
- if( in_array($prop, array('event_start_date', 'event_end_date', 'event_start_time', 'event_end_time', 'event_rsvp_date', 'event_rsvp_time', 'event_start', 'event_end')) ){
487
- return !empty($this->$prop);
488
- }elseif( $prop == 'event_timezone' ){
489
- return true;
490
- }elseif( $prop == 'start' || $prop == 'end' || $prop == 'rsvp_end' ){
491
- return $this->$prop()->valid;
492
- }
493
- return parent::__isset( $prop );
494
- }
495
-
496
- /**
497
- * When cloning this event, we get rid of the bookings and location objects, since they can be retrieved again from the cache instead.
498
- */
499
- public function __clone(){
500
- $this->bookings = null;
501
- $this->location = null;
502
- if( is_object($this->event_location) ){
503
- $this->event_location = clone $this->event_location;
504
- $this->event_location->event = $this;
505
- }
506
- }
507
-
508
- function load_postdata($event_post, $search_by = false){
509
- //load event post object if it's an actual object and also a post type of our event CPT names
510
- if( is_object($event_post) && ($event_post->post_type == 'event-recurring' || $event_post->post_type == EM_POST_TYPE_EVENT) ){
511
- //load post data - regardless
512
- $this->post_id = absint($event_post->ID);
513
- $this->event_name = $event_post->post_title;
514
- $this->event_owner = $event_post->post_author;
515
- $this->post_content = $event_post->post_content;
516
- $this->post_excerpt = $event_post->post_excerpt;
517
- $this->event_slug = $event_post->post_name;
518
- foreach( $event_post as $key => $value ){ //merge post object into this object
519
- $this->$key = $value;
520
- }
521
- $this->recurrence = $this->is_recurring() ? 1:0;
522
- //load meta data and other related information
523
- if( $event_post->post_status != 'auto-draft' ){
524
- $event_meta = $this->get_event_meta($search_by);
525
- if( !empty($event_meta['_event_location_type']) ) $this->event_location_type = $event_meta['_event_location_type']; //load this directly so we know further down whether this has an event location type to load
526
- //Get custom fields and post meta
527
- foreach($event_meta as $event_meta_key => $event_meta_val){
528
- $field_name = substr($event_meta_key, 1);
529
- if($event_meta_key[0] != '_'){
530
- $this->event_attributes[$event_meta_key] = ( is_array($event_meta_val) ) ? $event_meta_val[0]:$event_meta_val;
531
- }elseif( is_string($field_name) && !in_array($field_name, $this->post_fields) ){
532
- if( array_key_exists($field_name, $this->fields) ){
533
- $this->$field_name = $event_meta_val[0];
534
- }elseif( in_array($field_name, array('event_owner_name','event_owner_anonymous','event_owner_email')) ){
535
- $this->$field_name = $event_meta_val[0];
536
- }
537
- }
538
- }
539
- if( $this->has_event_location() ) $this->get_event_location()->load_postdata($event_meta);
540
- //quick compatability fix in case _event_id isn't loaded or somehow got erased in post meta
541
- if( empty($this->event_id) && !$this->is_recurring() ){
542
- global $wpdb;
543
- if( EM_MS_GLOBAL ){
544
- $event_array = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".EM_EVENTS_TABLE." WHERE post_id=%d && blog_id=%d",$this->post_id, $this->blog_id), ARRAY_A);
545
- }else{
546
- $event_array = $wpdb->get_row('SELECT * FROM '.EM_EVENTS_TABLE. ' WHERE post_id='.$this->post_id, ARRAY_A);
547
- }
548
- if( !empty($event_array['event_id']) ){
549
- foreach($event_array as $key => $value){
550
- if( !empty($value) && empty($this->$key) ){
551
- update_post_meta($event_post->ID, '_'.$key, $value);
552
- $this->$key = $value;
553
- }
554
- }
555
- }
556
- }
557
- }
558
- $this->get_status();
559
- $this->compat_keys();
560
- }elseif( !empty($this->post_id) ){
561
- //we have an orphan... show it, so that we can at least remove it on the front-end
562
- global $wpdb;
563
- if( EM_MS_GLOBAL ){ //if MS Global mode enabled, make sure we search by blog too so there's no cross-post confusion
564
- if( !empty($this->event_id) ){
565
- $event_array = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".EM_EVENTS_TABLE." WHERE event_id=%d",$this->event_id), ARRAY_A);
566
- }else{
567
- if( $this->blog_id == get_current_blog_id() || empty($this->blog_id) ){
568
- $event_array = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".EM_EVENTS_TABLE." WHERE post_id=%d AND (blog_id=%d OR blog_id IS NULL)",$this->post_id, $this->blog_id), ARRAY_A);
569
- }else{
570
- $event_array = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".EM_EVENTS_TABLE." WHERE post_id=%d AND blog_id=%d",$this->post_id, $this->blog_id), ARRAY_A);
571
- }
572
- }
573
- }else{
574
- $event_array = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".EM_EVENTS_TABLE." WHERE post_id=%d",$this->post_id), ARRAY_A);
575
- }
576
- if( is_array($event_array) ){
577
- $this->orphaned_event = true;
578
- $this->post_id = $this->ID = $event_array['post_id'] = null; //reset post_id because it doesn't really exist
579
- $this->to_object($event_array);
580
- }
581
- }
582
- if( empty($this->location_id) && !empty($this->event_id) ) $this->location_id = 0; //just set location_id to 0 and avoid any doubt
583
- if( EM_MS_GLOBAL && empty($this->blog_id) ) $this->blog_id = get_current_site()->blog_id; //events created before going multisite may have null values, so we set it to main site id
584
- }
585
-
586
- function get_event_meta($blog_id = false){
587
- if( !empty($this->blog_id) ) $blog_id = $this->blog_id; //if there's a blog id already, there's no doubt where to look for
588
- if( empty($this->post_id) ) return array();
589
- if( is_numeric($blog_id) && $blog_id > 0 && is_multisite() ){
590
- // if in multisite mode, switch blogs quickly to get the right post meta.
591
- switch_to_blog($blog_id);
592
- $event_meta = get_post_meta($this->post_id);
593
- restore_current_blog();
594
- $this->blog_id = $blog_id;
595
- }elseif( EM_MS_GLOBAL ){
596
- // if a blog ID wasn't defined then we'll check the main blog, in case the event was created in the past
597
- $this->ms_global_switch();
598
- $event_meta = get_post_meta($this->post_id);
599
- $this->ms_global_switch_back();
600
- }else{
601
- $event_meta = get_post_meta($this->post_id);
602
- }
603
- if( !is_array($event_meta) ) $event_meta = array();
604
- return apply_filters('em_event_get_event_meta', $event_meta);
605
- }
606
-
607
- /**
608
- * Retrieve event information via POST (only used in situations where posts aren't submitted via WP)
609
- * @return boolean
610
- */
611
- function get_post($validate = true){
612
- global $allowedposttags;
613
- do_action('em_event_get_post_pre', $this);
614
- //we need to get the post/event name and content.... that's it.
615
- $this->post_content = isset($_POST['content']) ? wp_kses( wp_unslash($_POST['content']), $allowedposttags):'';
616
- $this->post_excerpt = !empty($this->post_excerpt) ? $this->post_excerpt:''; //fix null error
617
- $this->event_name = ( !empty($_POST['event_name']) ) ? sanitize_post_field('post_title', $_POST['event_name'], $this->post_id, 'db'):'';
618
- $this->post_type = ($this->is_recurring() || !empty($_POST['recurring'])) ? 'event-recurring':EM_POST_TYPE_EVENT;
619
- //don't forget categories!
620
- if( get_option('dbem_categories_enabled') ) $this->get_categories()->get_post();
621
- //get the rest and validate (optional)
622
- $this->get_post_meta();
623
- //anonymous submissions and guest basic info
624
- if( !is_user_logged_in() && get_option('dbem_events_anonymous_submissions') && empty($this->event_id) ){
625
- $this->event_owner_anonymous = 1;
626
- $this->event_owner_name = !empty($_POST['event_owner_name']) ? wp_kses_data(wp_unslash($_POST['event_owner_name'])):'';
627
- $this->event_owner_email = !empty($_POST['event_owner_email']) ? wp_kses_data($_POST['event_owner_email']):'';
628
- if( empty($this->location_id) && !($this->location_id === 0 && !get_option('dbem_require_location',true)) ){
629
- $this->get_location()->owner_anonymous = 1;
630
- $this->location->owner_email = $this->event_owner_email;
631
- $this->location->owner_name = $this->event_owner_name;
632
- }
633
- }
634
- //validate and return results
635
- $result = $validate ? $this->validate():true; //validate both post and meta, otherwise return true
636
- return apply_filters('em_event_get_post', $result, $this);
637
- }
638
-
639
- /**
640
- * Retrieve event post meta information via POST, which should be always be called when saving the event custom post via WP.
641
- * @return boolean
642
- */
643
- function get_post_meta(){
644
- do_action('em_event_get_post_meta_pre', $this);
645
-
646
- //Check if this is recurring or not early on so we can take appropriate action further down
647
- if( !empty($_POST['recurring']) ){
648
- $this->recurrence = 1;
649
- $this->post_type = 'event-recurring';
650
- }
651
- //Set Event Timezone to supplied value or alternatively use blog timezone value by default.
652
- if( !empty($_REQUEST['event_timezone']) ){
653
- $this->event_timezone = EM_DateTimeZone::create($_REQUEST['event_timezone'])->getName();
654
- }elseif( empty($this->event_timezone ) ){ //if timezone was already set but not supplied, we don't change it
655
- $this->event_timezone = EM_DateTimeZone::create()->getName();
656
- }
657
- //Dates and Times - dates ignored if event is recurring being updated (not new) and not specifically chosen to reschedule event
658
- $this->event_start = $this->event_end = null;
659
- if( !$this->is_recurring() || (empty($this->event_id) || !empty($_REQUEST['event_reschedule'])) ){
660
- //Event Dates
661
- $this->event_start_date = ( !empty($_POST['event_start_date']) ) ? wp_kses_data($_POST['event_start_date']) : null;
662
- $this->event_end_date = ( !empty($_POST['event_end_date']) ) ? wp_kses_data($_POST['event_end_date']) : $this->event_start_date;
663
- }
664
- //Sort out time
665
- $this->event_all_day = ( !empty($_POST['event_all_day']) ) ? 1 : 0;
666
- if( $this->event_all_day ){
667
- $times_array = array('event_rsvp_time');
668
- $this->event_start_time = '00:00:00';
669
- $this->event_end_time = '23:59:59';
670
- }else{
671
- $times_array = array('event_start_time','event_end_time', 'event_rsvp_time');
672
- }
673
- foreach( $times_array as $timeName ){
674
- $match = array();
675
- if( !empty($_POST[$timeName]) && preg_match ( '/^([01]\d|[0-9]|2[0-3])(:([0-5]\d))? ?(AM|PM)?$/', $_POST[$timeName], $match ) ){
676
- if( empty($match[3]) ) $match[3] = '00';
677
- if( strlen($match[1]) == 1 ) $match[1] = '0'.$match[1];
678
- if( !empty($match[4]) && $match[4] == 'PM' && $match[1] != 12 ){
679
- $match[1] = 12+$match[1];
680
- }elseif( !empty($match[4]) && $match[4] == 'AM' && $match[1] == 12 ){
681
- $match[1] = '00';
682
- }
683
- $this->$timeName = $match[1].":".$match[3].":00";
684
- }else{
685
- $this->$timeName = ($timeName == 'event_start_time') ? "00:00:00":$this->event_start_time;
686
- }
687
- }
688
- //reset start and end objects so they are recreated with the new dates/times if and when needed
689
- $this->start = $this->end = null;
690
-
691
- //Get Location Info
692
- if( get_option('dbem_locations_enabled') ){
693
- // determine location type, with backward compatibility considerations for those overriding the location forms
694
- $location_type = isset($_POST['location_type']) ? sanitize_key($_POST['location_type']) : 'location';
695
- if( !empty($_POST['no_location']) ) $location_type = 0; //backwards compat
696
- if( $location_type == 'location' && empty($_POST['location_id']) && get_option('dbem_use_select_for_locations')) $location_type = 0; //backward compat
697
- // assign location data
698
- if( $location_type === 0 || $location_type === '0' ){
699
- // no location
700
- $this->location_id = 0;
701
- $this->event_location_type = null;
702
- }elseif( $location_type == 'location' && EM_Locations::is_enabled() ){
703
- // a physical location, old school
704
- $this->event_location_type = null; // if location resides in locations table, location type is null since we have a location_id table value
705
- if( !empty($_POST['location_id']) && is_numeric($_POST['location_id']) ){
706
- // we're using a previously created location
707
- $this->location_id = absint($_POST['location_id']);
708
- }else{
709
- $this->location_id = null;
710
- //we're adding a new location place, so create an empty location and populate
711
- $this->get_location()->get_post(false);
712
- $this->get_location()->post_content = ''; //reset post content, as it'll grab the event description otherwise
713
- }
714
- }else{
715
- // we're dealing with an event location such as a url or webinar
716
- $this->location_id = null; // no location ID
717
- if( $this->event_id && $this->has_event_location() && $location_type != $this->event_location_type ){
718
- // if we're changing location types, then we'll delete all the previous data upon saving
719
- $this->event_location_deleted = $this->event_location;
720
- }
721
- $this->event_location_type = $location_type;
722
- if( Event_Locations::is_enabled($location_type) ){
723
- $this->get_event_location()->get_post();
724
- }
725
- }
726
- }else{
727
- $this->location_id = 0;
728
- $this->event_location_type = null;
729
- }
730
-
731
- //Bookings
732
- $can_manage_bookings = $this->can_manage('manage_bookings','manage_others_bookings');
733
- $preview_autosave = is_admin() && !empty($_REQUEST['_emnonce']) && !empty($_REQUEST['wp-preview']) && $_REQUEST['wp-preview'] == 'dopreview'; //we shouldn't save new data during a preview auto-save
734
- if( !$preview_autosave && $can_manage_bookings && !empty($_POST['event_rsvp']) && $_POST['event_rsvp'] ){
735
- //get tickets only if event is new, non-recurring, or recurring but specifically allowed to reschedule by user
736
- if( !$this->is_recurring() || (empty($this->event_id) || !empty($_REQUEST['event_recreate_tickets'])) || !$this->event_rsvp ){
737
- $this->get_bookings()->get_tickets()->get_post();
738
- }
739
- $this->event_rsvp = 1;
740
- $this->rsvp_end = null;
741
- //RSVP cuttoff TIME is set up above where start/end times are as well
742
- if( get_option('dbem_bookings_tickets_single') && count($this->get_tickets()->tickets) == 1 ){
743
- //single ticket mode will use the ticket end date/time as cut-off date/time
744
- $EM_Ticket = $this->get_tickets()->get_first();
745
- $this->event_rsvp_date = null;
746
- if( !empty($EM_Ticket->ticket_end) ){
747
- $this->event_rsvp_date = $EM_Ticket->end()->getDate();
748
- $this->event_rsvp_time = $EM_Ticket->end()->getTime();
749
- }else{
750
- //no default ticket end time, so make it default to event start date/time
751
- $this->event_rsvp_date = $this->event_start_date;
752
- $this->event_rsvp_time = $this->event_start_time;
753
- if( $this->event_all_day && empty($_POST['event_rsvp_date']) ){ $this->event_rsvp_time = '00:00:00'; } //all-day events start at 0 hour
754
- }
755
- }else{
756
- //if no rsvp cut-off date supplied, make it the event start date
757
- $this->event_rsvp_date = ( !empty($_POST['event_rsvp_date']) ) ? wp_kses_data($_POST['event_rsvp_date']) : $this->event_start_date;
758
- //if no specificed time, default to event start time
759
- if ( empty($_POST['event_rsvp_time']) ) $this->event_rsvp_time = $this->event_start_time;
760
- }
761
- //reset EM_DateTime object
762
- $this->rsvp_end = null;
763
- $this->event_spaces = ( isset($_POST['event_spaces']) ) ? absint($_POST['event_spaces']):0;
764
- $this->event_rsvp_spaces = ( isset($_POST['event_rsvp_spaces']) ) ? absint($_POST['event_rsvp_spaces']):0;
765
- }elseif( !$preview_autosave && ($can_manage_bookings || !$this->event_rsvp) ){
766
- if( empty($_POST['event_rsvp']) && $this->event_rsvp ) $deleting_bookings = true;
767
- $this->event_rsvp = 0;
768
- $this->event_rsvp_date = $this->event_rsvp_time = $this->rsvp_end = null;
769
- }
770
-
771
- //Sort out event attributes - note that custom post meta now also gets inserted here automatically (and is overwritten by these attributes)
772
- if(get_option('dbem_attributes_enabled')){
773
- global $allowedtags;
774
- if( !is_array($this->event_attributes) ){ $this->event_attributes = array(); }
775
- $event_available_attributes = !empty($event_available_attributes) ? $event_available_attributes : em_get_attributes(); //we use this in locations, no need to repeat if needed
776
- if( !empty($_POST['em_attributes']) && is_array($_POST['em_attributes']) ){
777
- foreach($_POST['em_attributes'] as $att_key => $att_value ){
778
- if( (in_array($att_key, $event_available_attributes['names']) || array_key_exists($att_key, $this->event_attributes) ) ){
779
- $this->event_attributes[$att_key] = '';
780
- $att_vals = isset($event_available_attributes['values'][$att_key]) ? count($event_available_attributes['values'][$att_key]) : 0;
781
- if( $att_value != '' ){
782
- if( $att_vals <= 1 || ($att_vals > 1 && in_array($att_value, $event_available_attributes['values'][$att_key])) ){
783
- $this->event_attributes[$att_key] = wp_unslash($att_value);
784
- }
785
- }
786
- if( $att_value == '' && $att_vals > 1){
787
- $this->event_attributes[$att_key] = wp_unslash(wp_kses($event_available_attributes['values'][$att_key][0], $allowedtags));
788
- }
789
- }
790
- }
791
- }
792
- }
793
-
794
- //group id
795
- $this->group_id = (!empty($_POST['group_id']) && is_numeric($_POST['group_id'])) ? absint($_POST['group_id']):0;
796
-
797
- //Recurrence data
798
- if( $this->is_recurring() ){
799
- $this->recurrence = 1; //just in case
800
-
801
- //If event is new or reschedule is requested, then proceed with new time pattern
802
- if( empty($this->event_id) || !empty($_REQUEST['event_reschedule']) ){
803
- //dates and time schedules of events
804
- $this->recurrence_freq = ( !empty($_POST['recurrence_freq']) && in_array($_POST['recurrence_freq'], array('daily','weekly','monthly','yearly')) ) ? $_POST['recurrence_freq']:'daily';
805
- if( !empty($_POST['recurrence_bydays']) && $this->recurrence_freq == 'weekly' && self::array_is_numeric($_POST['recurrence_bydays']) ){
806
- $this->recurrence_byday = str_replace(' ', '', implode( ",", $_POST['recurrence_bydays'] ));
807
- }elseif( isset($_POST['recurrence_byday']) && $this->recurrence_freq == 'monthly' ){
808
- $this->recurrence_byday = wp_kses_data($_POST['recurrence_byday']);
809
- }else{
810
- $this->recurrence_byday = null;
811
- }
812
- $this->recurrence_interval = ( !empty($_POST['recurrence_interval']) && is_numeric($_POST['recurrence_interval']) ) ? $_POST['recurrence_interval']:1;
813
- $this->recurrence_byweekno = ( !empty($_POST['recurrence_byweekno']) ) ? wp_kses_data($_POST['recurrence_byweekno']):'';
814
- $this->recurrence_days = ( !empty($_POST['recurrence_days']) && is_numeric($_POST['recurrence_days']) ) ? (int) $_POST['recurrence_days']:0;
815
- }
816
-
817
- //here we do a comparison between new and old event data to see if we are to reschedule events or recreate bookings
818
- if( $this->event_id ){ //only needed if this is an existing event needing rescheduling/recreation
819
- //Get original recurring event so we can tell whether event recurrences or bookings will be recreated or just modified
820
- $EM_Event = new EM_Event($this->event_id);
821
-
822
- //first check event times
823
- $recurring_event_dates = array(
824
- 'event_start_date' => $EM_Event->event_start_date,
825
- 'event_end_date' => $EM_Event->event_end_date,
826
- 'recurrence_byday' => $EM_Event->recurrence_byday,
827
- 'recurrence_byweekno' => $EM_Event->recurrence_byweekno,
828
- 'recurrence_days' => $EM_Event->recurrence_days,
829
- 'recurrence_freq' => $EM_Event->recurrence_freq,
830
- 'recurrence_interval' => $EM_Event->recurrence_interval
831
- );
832
- //check previously saved event info compared to current recurrence info to see if we need to reschedule
833
- foreach($recurring_event_dates as $k => $v){
834
- if( $this->$k != $v ){
835
- $this->recurring_reschedule = true; //something changed, so we reschedule
836
- }
837
- }
838
-
839
- //now check tickets if we don't already have to reschedule
840
- if( !$this->recurring_reschedule && $this->event_rsvp ){
841
- //@TODO - ideally tickets could be independent of events, it'd make life easier here for comparison and editing without rescheduling
842
- $EM_Tickets = $EM_Event->get_tickets();
843
- //we compare tickets
844
- foreach( $this->get_tickets()->tickets as $EM_Ticket ){
845
- if( !empty($EM_Ticket->ticket_id) && !empty($EM_Tickets->tickets[$EM_Ticket->ticket_id]) ){
846
- $new_ticket = $EM_Ticket->to_array(true);
847
- foreach( $EM_Tickets->tickets[$EM_Ticket->ticket_id]->to_array() as $k => $v ){
848
- if( !(empty($new_ticket[$k]) && empty($v)) && ((empty($new_ticket[$k]) && $v) || $new_ticket[$k] != $v) ){
849
- if( $k == 'ticket_meta' && is_array($v) && is_array($new_ticket['ticket_meta']) ){
850
- foreach( $v as $k_meta => $v_meta ){
851
- if( (empty($new_ticket['ticket_meta'][$k_meta]) && !empty($v_meta)) || $new_ticket['ticket_meta'][$k_meta] != $v_meta ){
852
- $this->recurring_recreate_bookings = true; //something changed, so we reschedule
853
- }
854
- }
855
- }else{
856
- $this->recurring_recreate_bookings = true; //something changed, so we reschedule
857
- }
858
- }
859
- }
860
- }else{
861
- $this->recurring_recreate_bookings = true; //we have a new ticket
862
- }
863
- }
864
- }elseif( !empty($deleting_bookings) ){
865
- $this->recurring_delete_bookings = true;
866
- }
867
- unset($EM_Event);
868
- }else{
869
- //new event so we create everything from scratch
870
- $this->recurring_reschedule = $this->recurring_recreate_bookings = true;
871
- }
872
- //recurring events may have a cut-off date x days before or after the recurrence start dates
873
- $this->recurrence_rsvp_days = null;
874
- if( get_option('dbem_bookings_tickets_single') && count($this->get_tickets()->tickets) == 1 ){
875
- //if in single ticket mode then ticket cut-off date determines event cut-off date
876
- $EM_Ticket = $this->get_tickets()->get_first();
877
- if( !empty($EM_Ticket->ticket_meta['recurrences']) ){
878
- $this->recurrence_rsvp_days = $EM_Ticket->ticket_meta['recurrences']['end_days'];
879
- $this->event_rsvp_time = $EM_Ticket->ticket_meta['recurrences']['end_time'];
880
- }
881
- }else{
882
- if( array_key_exists('recurrence_rsvp_days', $_POST) ){
883
- if( !empty($_POST['recurrence_rsvp_days_when']) && $_POST['recurrence_rsvp_days_when'] == 'after' ){
884
- $this->recurrence_rsvp_days = absint($_POST['recurrence_rsvp_days']);
885
- }else{ //by default the start date is the point of reference
886
- $this->recurrence_rsvp_days = absint($_POST['recurrence_rsvp_days']) * -1;
887
- }
888
- }
889
- }
890
- //create timestamps and set rsvp date/time for a normal event
891
- if( !is_numeric($this->recurrence_rsvp_days) ){
892
- //falback in case nothing gets set for rsvp cut-off
893
- $this->event_rsvp_date = $this->event_rsvp_time = $this->rsvp_end = null;
894
- }else{
895
- $this->event_rsvp_date = $this->start()->copy()->modify($this->recurrence_rsvp_days.' days')->getDate();
896
- }
897
- }else{
898
- foreach( $this->recurrence_fields as $recurrence_field ){
899
- $this->$recurrence_field = null;
900
- }
901
- $this->recurrence = 0; // to avoid any doubt
902
- }
903
- //event language
904
- if( EM_ML::$is_ml && !empty($_POST['event_language']) && array_key_exists($_POST['event_language'], EM_ML::$langs) ){
905
- $this->event_language = $_POST['event_language'];
906
- }
907
- //categories in MS GLobal
908
- if(EM_MS_GLOBAL && !is_main_site() && get_option('dbem_categories_enabled') ){
909
- $this->get_categories()->get_post(); //it'll know what to do
910
- }
911
- $this->compat_keys(); //compatability
912
- return apply_filters('em_event_get_post_meta', count($this->errors) == 0, $this);
913
- }
914
-
915
- function validate(){
916
- $validate_post = true;
917
- if( empty($this->event_name) ){
918
- $validate_post = false;
919
- $this->add_error( sprintf(__("%s is required.", 'events-manager'), __('Event name','events-manager')) );
920
- }
921
- //anonymous submissions and guest basic info
922
- if( !empty($this->event_owner_anonymous) ){
923
- if( !is_email($this->event_owner_email) ){
924
- $this->add_error( sprintf(__("%s is required.", 'events-manager'), __('A valid email','events-manager')) );
925
- }
926
- if( empty($this->event_owner_name) ){
927
- $this->add_error( sprintf(__("%s is required.", 'events-manager'), __('Your name','events-manager')) );
928
- }
929
- }
930
- $validate_tickets = true; //must pass if we can't validate bookings
931
- if( $this->can_manage('manage_bookings','manage_others_bookings') ){
932
- $validate_tickets = $this->get_bookings()->get_tickets()->validate();
933
- }
934
- $validate_image = $this->image_validate();
935
- $validate_meta = $this->validate_meta();
936
- return apply_filters('em_event_validate', $validate_post && $validate_image && $validate_meta && $validate_tickets, $this );
937
- }
938
-
939
- function validate_meta(){
940
- $missing_fields = Array ();
941
- foreach ( array('event_start_date') as $field ) {
942
- if ( $this->$field == "") {
943
- $missing_fields[$field] = $field;
944
- }
945
- }
946
- if( preg_match('/\d{4}-\d{2}-\d{2}/', $this->event_start_date) && preg_match('/\d{4}-\d{2}-\d{2}/', $this->event_end_date) ){
947
- if( $this->start()->getTimestamp() > $this->end()->getTimestamp() ){
948
- $this->add_error(__('Events cannot start after they end.','events-manager'));
949
- }elseif( $this->is_recurring() && $this->recurrence_days == 0 && $this->start()->getTimestamp() > $this->end()->getTimestamp() ){
950
- $this->add_error(__('Events cannot start after they end.','events-manager').' '.__('For recurring events that end the following day, ensure you make your event last 1 or more days.'));
951
- }
952
- }else{
953
- if( !empty($missing_fields['event_start_date']) ) { unset($missing_fields['event_start_date']); }
954
- if( !empty($missing_fields['event_end_date']) ) { unset($missing_fields['event_end_date']); }
955
- $this->add_error(__('Dates must have correct formatting. Please use the date picker provided.','events-manager'));
956
- }
957
- if( $this->event_rsvp ){
958
- if( !$this->get_bookings()->get_tickets()->validate() ){
959
- $this->add_error($this->get_bookings()->get_tickets()->get_errors());
960
- }
961
- if( !empty($this->event_rsvp_date) && !preg_match('/\d{4}-\d{2}-\d{2}/', $this->event_rsvp_date) ){
962
- $this->add_error(__('Dates must have correct formatting. Please use the date picker provided.','events-manager'));
963
- }
964
- }
965
- if( get_option('dbem_locations_enabled') ){
966
- if( $this->location_id === 0 && get_option('dbem_require_location',true) ){
967
- // no location chosen, yet we require a location
968
- $this->add_error(__('No location associated with this event.', 'events-manager'));
969
- }elseif( $this->has_location() ){
970
- // physical location
971
- if( empty($this->location_id) && !$this->get_location()->validate() ){
972
- // new location doesn't validate
973
- $this->add_error($this->get_location()->get_errors());
974
- }elseif( !empty($this->location_id) && !$this->get_location()->location_id ){
975
- // non-existent location selected
976
- $this->add_error( __('Please select a valid location.', 'events-manager') );
977
- }
978
- }elseif( $this->has_event_location() ){
979
- // event location, validation applies errors directly to $this
980
- $this->get_event_location()->validate();
981
- }
982
- }
983
- if ( count($missing_fields) > 0){
984
- // TODO Create friendly equivelant names for missing fields notice in validation
985
- $this->add_error( __( 'Missing fields: ', 'events-manager') . implode ( ", ", $missing_fields ) . ". " );
986
- }
987
- if ( $this->is_recurring() ){
988
- if( $this->event_end_date == "" || $this->event_end_date == $this->event_start_date){
989
- $this->add_error( __( 'Since the event is repeated, you must specify an event end date greater than the start date.', 'events-manager'));
990
- }
991
- if( $this->recurrence_freq == 'weekly' && !preg_match('/^[0-9](,[0-9])*$/',$this->recurrence_byday) ){
992
- $this->add_error( __( 'Please specify what days of the week this event should occur on.', 'events-manager'));
993
- }
994
- }
995
- return apply_filters('em_event_validate_meta', count($this->errors) == 0, $this );
996
- }
997
-
998
- /**
999
- * Will save the current instance into the database, along with location information if a new one was created and return true if successful, false if not.
1000
- * Will automatically detect whether it's a new or existing event.
1001
- * @return boolean
1002
- */
1003
- function save(){
1004
- global $wpdb, $current_user, $blog_id, $EM_SAVING_EVENT;
1005
- $EM_SAVING_EVENT = true; //this flag prevents our dashboard save_post hooks from going further
1006
- if( !$this->can_manage('edit_events', 'edit_others_events') && !( get_option('dbem_events_anonymous_submissions') && empty($this->event_id)) ){
1007
- //unless events can be submitted by an anonymous user (and this is a new event), user must have permissions.
1008
- return apply_filters('em_event_save', false, $this);
1009
- }
1010
- //start saving process
1011
- do_action('em_event_save_pre', $this);
1012
- $post_array = array();
1013
- //Deal with updates to an event
1014
- if( !empty($this->post_id) ){
1015
- //get the full array of post data so we don't overwrite anything.
1016
- if( !empty($this->blog_id) && is_multisite() ){
1017
- $post_array = (array) get_blog_post($this->blog_id, $this->post_id);
1018
- }else{
1019
- $post_array = (array) get_post($this->post_id);
1020
- }
1021
- }
1022
- //Overwrite new post info
1023
- $post_array['post_type'] = ($this->recurrence && get_option('dbem_recurrence_enabled')) ? 'event-recurring':EM_POST_TYPE_EVENT;
1024
- $post_array['post_title'] = $this->event_name;
1025
- $post_array['post_content'] = !empty($this->post_content) ? $this->post_content : '';
1026
- $post_array['post_excerpt'] = $this->post_excerpt;
1027
- //decide on post status
1028
- if( empty($this->force_status) ){
1029
- if( count($this->errors) == 0 ){
1030
- $post_array['post_status'] = ( $this->can_manage('publish_events','publish_events') ) ? 'publish':'pending';
1031
- }else{
1032
- $post_array['post_status'] = 'draft';
1033
- }
1034
- }else{
1035
- $post_array['post_status'] = $this->force_status;
1036
- }
1037
- //anonymous submission only
1038
- if( !is_user_logged_in() && get_option('dbem_events_anonymous_submissions') && empty($this->event_id) ){
1039
- $post_array['post_author'] = get_option('dbem_events_anonymous_user');
1040
- if( !is_numeric($post_array['post_author']) ) $post_array['post_author'] = 0;
1041
- }
1042
- //Save post and continue with meta
1043
- $post_id = wp_insert_post($post_array);
1044
- $post_save = false;
1045
- $meta_save = false;
1046
- if( !is_wp_error($post_id) && !empty($post_id) ){
1047
- $post_save = true;
1048
- //refresh this event with wp post info we'll put into the db
1049
- $post_data = get_post($post_id);
1050
- $this->post_id = $this->ID = $post_id;
1051
- $this->post_type = $post_data->post_type;
1052
- $this->event_slug = $post_data->post_name;
1053
- $this->event_owner = $post_data->post_author;
1054
- $this->post_status = $post_data->post_status;
1055
- $this->get_status();
1056
- //Categories
1057
- if( get_option('dbem_categories_enabled') ){
1058
- $this->get_categories()->event_id = $this->event_id;
1059
- $this->categories->post_id = $this->post_id;
1060
- $this->categories->save();
1061
- }
1062
- //anonymous submissions should save this information
1063
- if( !empty($this->event_owner_anonymous) ){
1064
- update_post_meta($this->post_id, '_event_owner_anonymous', 1);
1065
- update_post_meta($this->post_id, '_event_owner_name', $this->event_owner_name);
1066
- update_post_meta($this->post_id, '_event_owner_email', $this->event_owner_email);
1067
- }
1068
- //save the image, errors here will surface during $this->save_meta()
1069
- $this->image_upload();
1070
- //now save the meta
1071
- $meta_save = $this->save_meta();
1072
- }
1073
- $result = $meta_save && $post_save;
1074
- if($result) $this->load_postdata($post_data, $blog_id); //reload post info
1075
- //do a dirty update for location too if it's not published
1076
- if( $this->is_published() && !empty($this->location_id) ){
1077
- $EM_Location = $this->get_location();
1078
- if( $EM_Location->location_status !== 1 ){
1079
- //let's also publish the location
1080
- $EM_Location->set_status(1, true);
1081
- }
1082
- }
1083
- $return = apply_filters('em_event_save', $result, $this);
1084
- $EM_SAVING_EVENT = false;
1085
- //reload post data and add this event to the cache, after any other hooks have done their thing
1086
- //cache refresh when saving via admin area is handled in EM_Event_Post_Admin::save_post/refresh_cache
1087
- if( $result && $this->is_published() ){
1088
- //we won't depend on hooks, if we saved the event and it's still published in its saved state, refresh the cache regardless
1089
- $this->load_postdata($this);
1090
- wp_cache_set($this->event_id, $this, 'em_events');
1091
- wp_cache_set($this->post_id, $this->event_id, 'em_events_ids');
1092
- }
1093
- return $return;
1094
- }
1095
-
1096
- function save_meta(){
1097
- global $wpdb, $EM_SAVING_EVENT;
1098
- $EM_SAVING_EVENT = true;
1099
- //sort out multisite blog id if appliable
1100
- if( is_multisite() && empty($this->blog_id) ){
1101
- $this->blog_id = get_current_blog_id();
1102
- }
1103
- //trigger setting of event_end and event_start in case it hasn't been set already
1104
- $this->start();
1105
- $this->end();
1106
- //continue with saving if permissions allow
1107
- if( ( get_option('dbem_events_anonymous_submissions') && empty($this->event_id)) || $this->can_manage('edit_events', 'edit_others_events') ){
1108
- do_action('em_event_save_meta_pre', $this);
1109
- //language default
1110
- if( !$this->event_language ) $this->event_language = EM_ML::$current_language;
1111
- //first save location
1112
- if( empty($this->location_id) && !($this->location_id === 0 && !get_option('dbem_require_location',true)) ){
1113
- //pass language on
1114
- $this->get_location()->location_language = $this->event_language;
1115
- //proceed with location save
1116
- if( !$this->get_location()->save() ){ //soft fail
1117
- global $EM_Notices;
1118
- if( !empty($this->get_location()->location_id) ){
1119
- $EM_Notices->add_error( __('There were some errors saving your location.','events-manager').' '.sprintf(__('It will not be displayed on the website listings, to correct this you must <a href="%s">edit your location</a> directly.'),$this->get_location()->output('#_LOCATIONEDITURL')), true);
1120
- }
1121
- }
1122
- if( !empty($this->location->location_id) ){ //only case we don't use get_location(), since it will fail as location has an id, whereas location_id isn't set in this object
1123
- $this->location_id = $this->location->location_id;
1124
- }
1125
- }
1126
- //Update Post Meta
1127
- $current_meta_values = $this->get_event_meta();
1128
- foreach( $this->fields as $key => $field_info ){
1129
- //certain keys will not be saved if not needed, including flags with a 0 value. Older databases using custom WP_Query calls will need to use an array of meta_query items using NOT EXISTS - OR - value=0
1130
- if( !in_array($key, $this->post_fields) && $key != 'event_attributes' ){
1131
- //ignore certain fields and delete if not new
1132
- $save_meta_key = true;
1133
- if( !$this->is_recurring() && in_array($key, $this->recurrence_fields) ) $save_meta_key = false;
1134
- if( !$this->is_recurrence() && $key == 'recurrence_id' ) $save_meta_key = false;
1135
- if( !EM_ML::$is_ml && $key == 'event_language' ) $save_meta_key = false;
1136
- $ignore_zero_keys = array('location_id', 'group_id', 'event_all_day', 'event_parent', 'event_translation');
1137
- if( in_array($key, $ignore_zero_keys) && empty($this->$key) ) $save_meta_key = false;
1138
- if( $key == 'blog_id' ) $save_meta_key = false; //not needed, given postmeta is stored on the actual blog table in MultiSite
1139
- //we don't need rsvp info if rsvp is not set, including the RSVP flag too
1140
- if( empty($this->event_rsvp) && in_array($key, array('event_rsvp','event_rsvp_date', 'event_rsvp_time', 'event_rsvp_spaces', 'event_spaces')) ) $save_meta_key = false;
1141
- //save key or ignore/delete key
1142
- if( $save_meta_key ){
1143
- update_post_meta($this->post_id, '_'.$key, $this->$key);
1144
- }elseif( array_key_exists('_'.$key, $current_meta_values) ){
1145
- //delete if this event already existed, in case this event already had the values before
1146
- delete_post_meta($this->post_id, '_'.$key);
1147
- }
1148
- }elseif( array_key_exists('_'.$key, $current_meta_values) && $key != 'event_attributes' ){ //we should delete event_attributes, but maybe something else uses it without us knowing
1149
- delete_post_meta($this->post_id, '_'.$key);
1150
- }
1151
- }
1152
- if( get_option('dbem_attributes_enabled') ){
1153
- //attributes get saved as individual keys
1154
- $atts = em_get_attributes(); //get available attributes that EM manages
1155
- $this->event_attributes = maybe_unserialize($this->event_attributes);
1156
- foreach( $atts['names'] as $event_attribute_key ){
1157
- if( array_key_exists($event_attribute_key, $this->event_attributes) && $this->event_attributes[$event_attribute_key] != '' ){
1158
- update_post_meta($this->post_id, $event_attribute_key, $this->event_attributes[$event_attribute_key]);
1159
- }else{
1160
- delete_post_meta($this->post_id, $event_attribute_key);
1161
- }
1162
- }
1163
- }
1164
- //update timestamps, dates and times
1165
- update_post_meta($this->post_id, '_event_start_local', $this->start()->getDateTime());
1166
- update_post_meta($this->post_id, '_event_end_local', $this->end()->getDateTime());
1167
- //Deprecated, only for backwards compatibility, these meta fields will eventually be deleted!
1168
- $site_data = get_site_option('dbem_data');
1169
- if( !empty($site_data['updates']['timezone-backcompat']) ){
1170
- update_post_meta($this->post_id, '_start_ts', str_pad($this->start()->getTimestamp(), 10, 0, STR_PAD_LEFT));
1171
- update_post_meta($this->post_id, '_end_ts', str_pad($this->end()->getTimestamp(), 10, 0, STR_PAD_LEFT));
1172
- }
1173
- //sort out event status
1174
- $result = count($this->errors) == 0;
1175
- $this->get_status();
1176
- $this->event_status = ($result) ? $this->event_status:null; //set status at this point, it's either the current status, or if validation fails, null
1177
- //Save to em_event table
1178
- $event_array = $this->to_array(true);
1179
- unset($event_array['event_id']);
1180
- //decide whether or not event is private at this point
1181
- $event_array['event_private'] = ( $this->post_status == 'private' ) ? 1:0;
1182
- //check if event truly exists, meaning the event_id is actually a valid event id
1183
- if( !empty($this->event_id) ){
1184
- $blog_condition = '';
1185
- if( !empty($this->orphaned_event ) && !empty($this->post_id) ){
1186
- //we're dealing with an orphaned event in wp_em_events table, so we want to update the post_id and give it a post parent
1187
- $event_truly_exists = true;
1188
- }else{
1189
- if( EM_MS_GLOBAL ){
1190
- if( is_main_site() ){
1191
- $blog_condition = " AND (blog_id='".get_current_blog_id()."' OR blog_id IS NULL)";
1192
- }else{
1193
- $blog_condition = " AND blog_id='".get_current_blog_id()."' ";
1194
- }
1195
- }
1196
- $event_truly_exists = $wpdb->get_var('SELECT post_id FROM '.EM_EVENTS_TABLE." WHERE event_id={$this->event_id}".$blog_condition) == $this->post_id;
1197
- }
1198
- }else{
1199
- $event_truly_exists = false;
1200
- }
1201
- //save all the meta
1202
- if( empty($this->event_id) || !$event_truly_exists ){
1203
- $this->previous_status = 0; //for sure this was previously status 0
1204
- $this->event_date_created = $event_array['event_date_created'] = current_time('mysql');
1205
- if ( !$wpdb->insert(EM_EVENTS_TABLE, $event_array) ){
1206
- $this->add_error( sprintf(__('Something went wrong saving your %s to the index table. Please inform a site administrator about this.','events-manager'),__('event','events-manager')));
1207
- }else{
1208
- //success, so link the event with the post via an event id meta value for easy retrieval
1209
- $this->event_id = $wpdb->insert_id;
1210
- update_post_meta($this->post_id, '_event_id', $this->event_id);
1211
- $this->feedback_message = sprintf(__('Successfully saved %s','events-manager'),__('Event','events-manager'));
1212
- $this->just_added_event = true; //make an easy hook
1213
- $this->get_bookings()->bookings = array(); //set bookings array to 0 to avoid an extra DB query
1214
- do_action('em_event_save_new', $this);
1215
- }
1216
- }else{
1217
- $event_array['post_content'] = $this->post_content; //in case the content was removed, which is acceptable
1218
- $this->get_previous_status();
1219
- $this->event_date_modified = $event_array['event_date_modified'] = current_time('mysql');
1220
- if ( $wpdb->update(EM_EVENTS_TABLE, $event_array, array('event_id'=>$this->event_id) ) === false ){
1221
- $this->add_error( sprintf(__('Something went wrong updating your %s to the index table. Please inform a site administrator about this.','events-manager'),__('event','events-manager')));
1222
- }else{
1223
- //Also set the status here if status != previous status
1224
- if( $this->previous_status != $this->get_status() ) $this->set_status($this->get_status());
1225
- $this->feedback_message = sprintf(__('Successfully saved %s','events-manager'),__('Event','events-manager'));
1226
- }
1227
- //check anonymous submission information
1228
- if( !empty($this->event_owner_anonymous) && get_option('dbem_events_anonymous_user') != $this->event_owner ){
1229
- //anonymous user owner has been replaced with a valid wp user account, so we remove anonymous status flag but leave email and name for future reference
1230
- update_post_meta($this->post_id, '_event_owner_anonymous', 0);
1231
- }elseif( get_option('dbem_events_anonymous_submissions') && get_option('dbem_events_anonymous_user') == $this->event_owner && is_email($this->event_owner_email) && !empty($this->event_owner_name) ){
1232
- //anonymous user account has been reinstated as the owner, so we can restore anonymous submission status
1233
- update_post_meta($this->post_id, '_event_owner_anonymous', 1);
1234
- }
1235
- }
1236
- //update event location via post meta
1237
- if( $this->has_event_location() ){
1238
- $this->get_event_location()->save();
1239
- }elseif( !empty($this->event_location) ){
1240
- // we previously had an event location and then switched to no location or a physical location
1241
- $this->event_location->delete();
1242
- }
1243
- if( !empty($this->event_location_deleted) ){
1244
- // we've switched event location types
1245
- $this->event_location_deleted->delete();
1246
- }
1247
- //Add/Delete Tickets
1248
- if($this->event_rsvp == 0){
1249
- if( !$this->just_added_event ){
1250
- $this->get_bookings()->delete();
1251
- $this->get_tickets()->delete();
1252
- }
1253
- }elseif( $this->can_manage('manage_bookings','manage_others_bookings') ){
1254
- if( !$this->get_bookings()->get_tickets()->save() ){
1255
- $this->add_error( $this->get_bookings()->get_tickets()->get_errors() );
1256
- }
1257
- }
1258
- $result = count($this->errors) == 0;
1259
- //deal with categories
1260
- if( get_option('dbem_categories_enabled') ){
1261
- if( EM_MS_GLOBAL ){ //EM_MS_Globals should look up original blog
1262
- //If we're saving event categories in MS Global mode, we'll add them here, saving by term id (cat ids are gone now)
1263
- if( !is_main_site() ){
1264
- $this->get_categories()->save(); //it'll know what to do
1265
- }else{
1266
- $this->get_categories()->save_index(); //just save to index, we assume cats are saved in $this->save();
1267
- }
1268
- }elseif( get_option('dbem_default_category') > 0 ){
1269
- //double-check for default category in other instances
1270
- if( count($this->get_categories()) == 0 ){
1271
- $this->get_categories()->save(); //let the object deal with this...
1272
- }
1273
- }
1274
- }
1275
- $this->compat_keys(); //compatability keys, loaded before saving recurrences
1276
- //build recurrences if needed
1277
- if( $this->is_recurring() && $result && ($this->is_published() || $this->post_status == 'future' || (defined('EM_FORCE_RECURRENCES_SAVE') && EM_FORCE_RECURRENCES_SAVE)) ){ //only save events if recurring event validates and is published or set for future
1278
- global $EM_EVENT_SAVE_POST;
1279
- //If we're in WP Admin and this was called by EM_Event_Post_Admin::save_post, don't save here, it'll be done later in EM_Event_Recurring_Post_Admin::save_post
1280
- if( empty($EM_EVENT_SAVE_POST) ){
1281
- if( $this->just_added_event ) $this->recurring_reschedule = true;
1282
- if( !$this->save_events() ){
1283
- $this->add_error(__ ( 'Something went wrong with the recurrence update...', 'events-manager'). __ ( 'There was a problem saving the recurring events.', 'events-manager'));
1284
- }
1285
- }
1286
- }
1287
- if( !empty($this->just_added_event) ){
1288
- do_action('em_event_added', $this);
1289
- }
1290
- }
1291
- $EM_SAVING_EVENT = false;
1292
- return apply_filters('em_event_save_meta', count($this->errors) == 0, $this);
1293
- }
1294
-
1295
- /**
1296
- * Duplicates this event and returns the duplicated event. Will return false if there is a problem with duplication.
1297
- * @return EM_Event
1298
- */
1299
- function duplicate(){
1300
- global $wpdb;
1301
- //First, duplicate.
1302
- if( $this->can_manage('edit_events','edit_others_events') ){
1303
- $EM_Event = clone $this;
1304
- if( get_option('dbem_categories_enabled') ) $EM_Event->get_categories(); //before we remove event/post ids
1305
- $EM_Event->get_bookings()->get_tickets(); //in case this wasn't loaded and before we reset ids
1306
- $EM_Event->event_id = null;
1307
- $EM_Event->post_id = null;
1308
- $EM_Event->ID = null;
1309
- $EM_Event->post_name = '';
1310
- $EM_Event->location_id = (empty($EM_Event->location_id) && !get_option('dbem_require_location')) ? 0:$EM_Event->location_id;
1311
- $EM_Event->get_bookings()->event_id = null;
1312
- $EM_Event->get_bookings()->get_tickets()->event_id = null;
1313
- //if bookings reset ticket ids and duplicate tickets
1314
- foreach($EM_Event->get_bookings()->get_tickets()->tickets as $EM_Ticket){
1315
- $EM_Ticket->ticket_id = null;
1316
- $EM_Ticket->event_id = null;
1317
- }
1318
- do_action('em_event_duplicate_pre', $EM_Event, $this);
1319
- $EM_Event->duplicated = true;
1320
- $EM_Event->force_status = 'draft';
1321
- if( $EM_Event->save() ){
1322
- $EM_Event->feedback_message = sprintf(__("%s successfully duplicated.", 'events-manager'), __('Event','events-manager'));
1323
- //save tags here - eventually will be moved into part of $this->save();
1324
- if( get_option('dbem_tags_enabled') ){
1325
- $EM_Tags = new EM_Tags($this);
1326
- $EM_Tags->event_id = $EM_Event->event_id;
1327
- $EM_Tags->post_id = $EM_Event->post_id;
1328
- $EM_Tags->save();
1329
- }
1330
- //other non-EM post meta inc. featured image
1331
- $event_meta = $this->get_event_meta($this->blog_id);
1332
- $new_event_meta = $EM_Event->get_event_meta($EM_Event->blog_id);
1333
- $event_meta_inserts = array();
1334
- //Get custom fields and post meta - adapted from $this->load_post_meta()
1335
- foreach($event_meta as $event_meta_key => $event_meta_vals){
1336
- if( $event_meta_key == '_wpas_' ) continue; //allow JetPack Publicize to detect this as a new post when published
1337
- if( is_array($event_meta_vals) ){
1338
- if( !array_key_exists($event_meta_key, $new_event_meta) && !in_array($event_meta_key, array('_event_attributes', '_edit_last', '_edit_lock', '_event_owner_name','_event_owner_anonymous','_event_owner_email')) ){
1339
- foreach($event_meta_vals as $event_meta_val){
1340
- $event_meta_inserts[] = "({$EM_Event->post_id}, '{$event_meta_key}', '{$event_meta_val}')";
1341
- }
1342
- }
1343
- }
1344
- }
1345
- //save in one SQL statement
1346
- if( !empty($event_meta_inserts) ){
1347
- $wpdb->query('INSERT INTO '.$wpdb->postmeta." (post_id, meta_key, meta_value) VALUES ".implode(', ', $event_meta_inserts));
1348
- }
1349
- if( array_key_exists('_event_approvals_count', $event_meta) ) update_post_meta($EM_Event->post_id, '_event_approvals_count', 0);
1350
- //copy anything from the em_meta table too
1351
- $wpdb->query('INSERT INTO '.EM_META_TABLE." (object_id, meta_key, meta_value) SELECT '{$EM_Event->event_id}', meta_key, meta_value FROM ".EM_META_TABLE." WHERE object_id='{$this->event_id}'");
1352
- //set event to draft status
1353
- return apply_filters('em_event_duplicate', $EM_Event, $this);
1354
- }
1355
- }
1356
- //TODO add error notifications for duplication failures.
1357
- return apply_filters('em_event_duplicate', false, $this);;
1358
- }
1359
-
1360
- function duplicate_url($raw = false){
1361
- $url = add_query_arg(array('action'=>'event_duplicate', 'event_id'=>$this->event_id, '_wpnonce'=> wp_create_nonce('event_duplicate_'.$this->event_id)));
1362
- $url = apply_filters('em_event_duplicate_url', $url, $this);
1363
- $url = $raw ? esc_url_raw($url):esc_url($url);
1364
- return $url;
1365
- }
1366
-
1367
- /**
1368
- * Delete whole event, including bookings, tickets, etc.
1369
- * @param boolean $force_delete
1370
- * @return boolean
1371
- */
1372
- function delete( $force_delete = false ){
1373
- if( $this->can_manage('delete_events', 'delete_others_events') ){
1374
- if( !is_admin() ){
1375
- include_once('em-event-post-admin.php');
1376
- if( !defined('EM_EVENT_DELETE_INCLUDE') ){
1377
- EM_Event_Post_Admin::init();
1378
- EM_Event_Recurring_Post_Admin::init();
1379
- define('EM_EVENT_DELETE_INCLUDE',true);
1380
- }
1381
- }
1382
- do_action('em_event_delete_pre', $this);
1383
- if( $force_delete ){
1384
- $result = wp_delete_post($this->post_id,$force_delete);
1385
- }else{
1386
- $result = wp_trash_post($this->post_id);
1387
- if( !$result && $this->post_status == 'trash' ){
1388
- //we're probably dealing with a trashed post already, but the event_status is null from < v5.4.1
1389
- $this->set_status(-1);
1390
- $result = true;
1391
- }
1392
- }
1393
- if( !$result && !empty($this->orphaned_event) ){
1394
- //this is an orphaned event, so the wp delete posts would have never worked, so we just delete the row in our events table
1395
- $result = $this->delete_meta();
1396
- }
1397
- }else{
1398
- $result = false;
1399
- }
1400
- return apply_filters('em_event_delete', $result != false, $this);
1401
- }
1402
-
1403
- function delete_meta(){
1404
- global $wpdb;
1405
- $result = false;
1406
- if( $this->can_manage('delete_events', 'delete_others_events') ){
1407
- do_action('em_event_delete_meta_event_pre', $this);
1408
- $result = $wpdb->query ( $wpdb->prepare("DELETE FROM ". EM_EVENTS_TABLE ." WHERE event_id=%d", $this->event_id) );
1409
- if( $result !== false ){
1410
- $this->get_bookings()->delete();
1411
- $this->get_tickets()->delete();
1412
- if( $this->has_event_location() ) {
1413
- $this->get_event_location()->delete();
1414
- }
1415
- //Delete the recurrences then this recurrence event
1416
- if( $this->is_recurring() ){
1417
- $result = $this->delete_events(); //was true at this point, so false if fails
1418
- }
1419
- //Delete categories from meta if in MS global mode
1420
- if( EM_MS_GLOBAL ){
1421
- $wpdb->query('DELETE FROM '.EM_META_TABLE.' WHERE object_id='.$this->event_id." AND meta_key='event-category'");
1422
- }
1423
- }
1424
- }
1425
- return apply_filters('em_event_delete_meta', $result !== false, $this);
1426
- }
1427
-
1428
- /**
1429
- * Deprecated, use $this->get_bookings->delete() instead.
1430
- * Shortcut function for $this->get_bookings()->delete(), because using the EM_Bookings requires loading previous bookings, which isn't neceesary.
1431
- */
1432
- function delete_bookings(){
1433
- global $wpdb;
1434
- do_action('em_event_delete_bookings_pre', $this);
1435
- $result = false;
1436
- if( $this->can_manage('manage_bookings','manage_others_bookings') ){
1437
- $result_bt = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE booking_id IN (SELECT booking_id FROM ".EM_BOOKINGS_TABLE." WHERE event_id=%d)", $this->event_id) );
1438
- $result = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_BOOKINGS_TABLE." WHERE event_id=%d", $this->event_id) );
1439
- }
1440
- return apply_filters('em_event_delete_bookings', $result !== false && $result_bt !== false, $this);
1441
- }
1442
-
1443
- /**
1444
- * Deprecated, use $this->get_bookings->delete() instead.
1445
- * Shortcut function for $this->get_bookings()->delete(), because using the EM_Bookings requires loading previous bookings, which isn't neceesary.
1446
- */
1447
- function delete_tickets(){
1448
- global $wpdb;
1449
- do_action('em_event_delete_tickets_pre', $this);
1450
- $result = false;
1451
- if( $this->can_manage('manage_bookings','manage_others_bookings') ){
1452
- $result_bt = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE ticket_id IN (SELECT ticket_id FROM ".EM_TICKETS_TABLE." WHERE event_id=%d)", $this->event_id) );
1453
- $result = $wpdb->query( $wpdb->prepare("DELETE FROM ".EM_TICKETS_TABLE." WHERE event_id=%d", $this->event_id) );
1454
- }
1455
- return apply_filters('em_event_delete_tickets', $result, $this);
1456
- }
1457
-
1458
- /**
1459
- * Change the status of the event. This will save to the Database too.
1460
- * @param int $status A number to change the status to, which may be -1 for trash, 1 for publish, 0 for pending or null if draft.
1461
- * @param boolean $set_post_status If set to true the wp_posts table status will also be changed to the new corresponding status.
1462
- * @return string
1463
- */
1464
- function set_status($status, $set_post_status = false){
1465
- global $wpdb;
1466
- //decide on what status to set and update wp_posts in the process
1467
- if($status === null){
1468
- $set_status='NULL'; //draft post
1469
- if($set_post_status){
1470
- //if the post is trash, don't untrash it!
1471
- $wpdb->update( $wpdb->posts, array( 'post_status' => 'draft' ), array( 'ID' => $this->post_id ) );
1472
- }
1473
- $this->post_status = 'draft'; //set post status in this instance
1474
- }elseif( $status == -1 ){ //trashed post
1475
- $set_status = -1;
1476
- if($set_post_status){
1477
- //set the post status of the location in wp_posts too
1478
- $wpdb->update( $wpdb->posts, array( 'post_status' => $this->post_status ), array( 'ID' => $this->post_id ) );
1479
- }
1480
- $this->post_status = 'trash'; //set post status in this instance
1481
- }else{
1482
- $set_status = $status ? 1:0; //published or pending post
1483
- $post_status = $set_status ? 'publish':'pending';
1484
- if( empty($this->post_name) ){
1485
- //published or pending posts should have a valid post slug
1486
- $slug = sanitize_title($this->post_title);
1487
- $this->post_name = wp_unique_post_slug( $slug, $this->post_id, $post_status, EM_POST_TYPE_EVENT, 0);
1488
- $set_post_name = true;
1489
- }
1490
- if($set_post_status){
1491
- $wpdb->update( $wpdb->posts, array( 'post_status' => $post_status, 'post_name' => $this->post_name ), array( 'ID' => $this->post_id ) );
1492
- }elseif( !empty($set_post_name) ){
1493
- //if we've added a post slug then update wp_posts anyway
1494
- $wpdb->update( $wpdb->posts, array( 'post_name' => $this->post_name ), array( 'ID' => $this->post_id ) );
1495
- }
1496
- $this->post_status = $post_status;
1497
- }
1498
- //save in the wp_em_locations table
1499
- $this->get_previous_status();
1500
- $result = $wpdb->query( $wpdb->prepare("UPDATE ".EM_EVENTS_TABLE." SET event_status=$set_status, event_slug=%s WHERE event_id=%d", array($this->post_name, $this->event_id)) );
1501
- $this->get_status(); //reload status
1502
- return apply_filters('em_event_set_status', $result !== false, $status, $this);
1503
- }
1504
-
1505
- public function set_timezone( $timezone = false ){
1506
- //reset UTC times and objects so they're recreated with local time and new timezone
1507
- $this->event_start = $this->event_end = $this->start = $this->end = $this->rsvp_end = null;
1508
- $EM_DateTimeZone = EM_DateTimeZone::create($timezone);
1509
- //modify the timezone string name itself
1510
- $this->event_timezone = $EM_DateTimeZone->getName();
1511
- }
1512
-
1513
- public function get_timezone(){
1514
- return $this->start()->getTimezone();
1515
- }
1516
-
1517
- function is_published(){
1518
- return apply_filters('em_event_is_published', ($this->post_status == 'publish' || $this->post_status == 'private'), $this);
1519
- }
1520
-
1521
- /**
1522
- * Returns an EM_DateTime object of the event start date/time in local timezone of event.
1523
- * @param bool $utc_timezone Returns EM_DateTime with UTC timezone if set to true, returns local timezone by default.
1524
- * @return EM_DateTime
1525
- * @see EM_Event::get_datetime()
1526
- */
1527
- public function start( $utc_timezone = false ){
1528
- return apply_filters('em_event_start', $this->get_datetime('start', $utc_timezone), $this);
1529
- }
1530
-
1531
- /**
1532
- * Returns an EM_DateTime object of the event end date/time in local timezone of event
1533
- * @param bool $utc_timezone Returns EM_DateTime with UTC timezone if set to true, returns local timezone by default.
1534
- * @return EM_DateTime
1535
- * @see EM_Event::get_datetime()
1536
- */
1537
- public function end( $utc_timezone = false ){
1538
- return apply_filters('em_event_end', $this->get_datetime('end', $utc_timezone), $this);
1539
- }
1540
-
1541
- /**
1542
- * Returns an EM_DateTime representation of when bookings close in local event timezone. If no valid date defined, event start date/time will be used.
1543
- * @param bool $utc_timezone Returns EM_DateTime with UTC timezone if set to true, returns local timezone by default.
1544
- * @return EM_DateTime
1545
- */
1546
- public function rsvp_end( $utc_timezone = false ){
1547
- if( empty($this->rsvp_end) || !$this->rsvp_end->valid ){
1548
- if( !empty($this->event_rsvp_date ) ){
1549
- $rsvp_time = !empty($this->event_rsvp_time) ? $this->event_rsvp_time : $this->event_start_time;
1550
- $this->rsvp_end = new EM_DateTime($this->event_rsvp_date." ".$rsvp_time, $this->event_timezone);
1551
- if( !$this->rsvp_end->valid ){
1552
- //invalid date will revert to start time
1553
- $this->rsvp_end = $this->start()->copy();
1554
- }
1555
- }else{
1556
- //no date defined means event start date/time is used
1557
- $this->rsvp_end = $this->start()->copy();
1558
- }
1559
- }
1560
- //Set to UTC timezone if requested, local by default
1561
- $tz = $utc_timezone ? 'UTC' : $this->event_timezone;
1562
- $this->rsvp_end->setTimezone($tz);
1563
- return $this->rsvp_end;
1564
- }
1565
-
1566
- /**
1567
- * Generates an EM_DateTime for the the start/end date/times of the event in local timezone, as well as setting a valid flag if dates and times are valid.
1568
- * The generated object will be derived from the local date and time values. If no date exists, then 1970-01-01 will be used, and 00:00:00 if no valid time exists.
1569
- * If date is invalid but time is, only use local timezones since a UTC conversion will provide inaccurate timezone differences due to unknown DST status. *
1570
- * @param string $when 'start' or 'end' date/time
1571
- * @param bool $utc_timezone Returns EM_DateTime with UTC timezone if set to true, returns local timezone by default. Do not use if EM_DateTime->valid is false.
1572
- * @return EM_DateTime
1573
- */
1574
- public function get_datetime( $when = 'start', $utc_timezone = false ){
1575
- if( $when != 'start' && $when != 'end') return new EM_DateTime(); //currently only start/end dates are relevant
1576
- //Initialize EM_DateTime if not already initialized, or if previously initialized object is invalid (e.g. draft event with invalid dates being resubmitted)
1577
- $when_date = 'event_'.$when.'_date';
1578
- $when_time = 'event_'.$when.'_time';
1579
- //we take a pass at creating a new datetime object if it's empty, invalid or a different time to the current start date
1580
- if( empty($this->$when) || !$this->$when->valid ){
1581
- $when_utc = 'event_'.$when;
1582
- $date_regex = '/^\d{4}-\d{2}-\d{2}$/';
1583
- $valid_time = !empty($this->$when_time) && preg_match('/^\d{2}:\d{2}:\d{2}$/', $this->$when_time);
1584
- //If there now is a valid date string for local or UTC timezones, create a new object which will set the valid flag to true by default
1585
- if( !empty($this->$when_date) && preg_match($date_regex, $this->$when_date) && $valid_time ){
1586
- $EM_DateTime = new EM_DateTime(trim($this->$when_date.' '.$this->$when_time), $this->event_timezone);
1587
- if( $EM_DateTime->valid && empty($this->$when_utc) ){
1588
- $EM_DateTime->setTimezone('UTC');
1589
- $this->$when_utc = $EM_DateTime->format();
1590
- }
1591
- }
1592
- //If we didn't attempt to create a date above, or it didn't work out, create an invalid date based on time.
1593
- if( empty($EM_DateTime) || !$EM_DateTime->valid ){
1594
- //create a new datetime just with the time (if set), fake date and set the valid flag to false
1595
- $time = $valid_time ? $this->$when_time : '00:00:00';
1596
- $EM_DateTime = new EM_DateTime('1970-01-01 '.$time, $this->event_timezone);
1597
- $EM_DateTime->valid = false;
1598
- }
1599
- //set new datetime
1600
- $this->$when = $EM_DateTime;
1601
- }else{
1602
- /* @var EM_DateTime $EM_DateTime */
1603
- $EM_DateTime = $this->$when;
1604
- }
1605
- //Set to UTC timezone if requested, local by default
1606
- $tz = $utc_timezone ? 'UTC' : $this->event_timezone;
1607
- $EM_DateTime->setTimezone($tz);
1608
- return $EM_DateTime;
1609
- }
1610
-
1611
- function get_status($db = false){
1612
- switch( $this->post_status ){
1613
- case 'private':
1614
- $this->event_private = 1;
1615
- $this->event_status = $status = 1;
1616
- break;
1617
- case 'publish':
1618
- $this->event_private = 0;
1619
- $this->event_status = $status = 1;
1620
- break;
1621
- case 'pending':
1622
- $this->event_private = 0;
1623
- $this->event_status = $status = 0;
1624
- break;
1625
- case 'trash':
1626
- $this->event_private = 0;
1627
- $this->event_status = $status = -1;
1628
- break;
1629
- default: //draft or unknown
1630
- $this->event_private = 0;
1631
- $status = $db ? 'NULL':null;
1632
- $this->event_status = null;
1633
- break;
1634
- }
1635
- return $status;
1636
- }
1637
-
1638
- function get_previous_status( $force = false ){
1639
- global $wpdb;
1640
- if( $this->event_id > 0 && ($this->previous_status === false || $force) ){
1641
- $this->previous_status = $wpdb->get_var('SELECT event_status FROM '.EM_EVENTS_TABLE.' WHERE event_id='.$this->event_id); //get status from db, not post_status, as posts get saved quickly
1642
- }
1643
- return $this->previous_status;
1644
- }
1645
-
1646
- /**
1647
- * Returns an EM_Categories object of the EM_Event instance.
1648
- * @return EM_Categories
1649
- */
1650
- function get_categories() {
1651
- if( empty($this->categories) ){
1652
- $this->categories = new EM_Categories($this);
1653
- }elseif(empty($this->categories->event_id)){
1654
- $this->categories->event_id = $this->event_id;
1655
- $this->categories->post_id = $this->post_id;
1656
- }
1657
- return apply_filters('em_event_get_categories', $this->categories, $this);
1658
- }
1659
-
1660
- /**
1661
- * Gets the parent of this event, if none exists, null is returned.
1662
- * @return EM_Event|null
1663
- */
1664
- public function get_parent(){
1665
- if( $this->event_parent ){
1666
- return em_get_event( $this->event_parent );
1667
- }
1668
- return null;
1669
- }
1670
-
1671
- /**
1672
- * Returns the physical location object this event belongs to.
1673
- * @return EM_Location
1674
- */
1675
- function get_location() {
1676
- global $EM_Location;
1677
- if( is_object($EM_Location) && $EM_Location->location_id == $this->location_id ){
1678
- $this->location = $EM_Location;
1679
- }else{
1680
- if( !is_object($this->location) || $this->location->location_id != $this->location_id ){
1681
- $this->location = apply_filters('em_event_get_location', em_get_location($this->location_id), $this);
1682
- }
1683
- }
1684
- return $this->location;
1685
- }
1686
-
1687
- /**
1688
- * Returns whether this event has a phyisical location assigned to it.
1689
- * @return bool
1690
- */
1691
- public function has_location(){
1692
- return !empty($this->location_id) || (!empty($this->location) && !empty($this->location->location_name));
1693
- }
1694
-
1695
- /**
1696
- * Gets the event's event location (note, different from a regular event location, which uses get_location())
1697
- * Returns implementation of Event_Location or false if no event location assigned.
1698
- * @return EM_Event_Locations\URL|Event_Location|false
1699
- */
1700
- public function get_event_location(){
1701
- if( is_object($this->event_location) && $this->event_location->type == $this->event_location_type ) return $this->event_location;
1702
- $Event_Location = false;
1703
- if( $this->has_event_location() ){
1704
- $this->event_location = $Event_Location = Event_Locations::get( $this->event_location_type, $this );
1705
- }
1706
- return apply_filters('em_event_get_event_location', $Event_Location, $this);
1707
- }
1708
-
1709
- /**
1710
- * Returns whether the event has an event location associated with it (different from a physical location). If supplied, can check against a specific type.
1711
- * @param string $event_location_type
1712
- * @return bool
1713
- */
1714
- public function has_event_location( $event_location_type = null ){
1715
- if( $event_location_type !== null ){
1716
- return !empty($this->event_location_type) && $this->event_location_type === $event_location_type && Event_Locations::is_enabled($event_location_type);
1717
- }
1718
- return !empty($this->event_location_type) && Event_Locations::is_enabled($this->event_location_type);
1719
- }
1720
-
1721
- /**
1722
- * Returns the location object this event belongs to.
1723
- * @return EM_Person
1724
- */
1725
- function get_contact(){
1726
- if( !is_object($this->contact) ){
1727
- $this->contact = new EM_Person($this->event_owner);
1728
- //if this is anonymous submission, change contact email and name
1729
- if( $this->event_owner_anonymous ){
1730
- $this->contact->user_email = $this->event_owner_email;
1731
- $name = explode(' ',$this->event_owner_name);
1732
- $first_name = array_shift($name);
1733
- $last_name = (count($name) > 0) ? implode(' ',$name):'';
1734
- $this->contact->user_firstname = $this->contact->first_name = $first_name;
1735
- $this->contact->user_lastname = $this->contact->last_name = $last_name;
1736
- $this->contact->display_name = $this->event_owner_name;
1737
- }
1738
- }
1739
- return $this->contact;
1740
- }
1741
-
1742
- /**
1743
- * Retrieve and save the bookings belonging to instance. If called again will return cached version, set $force_reload to true to create a new EM_Bookings object.
1744
- * @param boolean $force_reload
1745
- * @return EM_Bookings
1746
- */
1747
- function get_bookings( $force_reload = false ){
1748
- if( get_option('dbem_rsvp_enabled') ){
1749
- if( (!$this->bookings || $force_reload) ){
1750
- $this->bookings = new EM_Bookings($this);
1751
- }
1752
- $this->bookings->event_id = $this->event_id; //always refresh event_id
1753
- $this->bookings = apply_filters('em_event_get_bookings', $this->bookings, $this);
1754
- }else{
1755
- return new EM_Bookings();
1756
- }
1757
- //TODO for some reason this returned instance doesn't modify the original, e.g. try $this->get_bookings()->add($EM_Booking) and see how $this->bookings->feedback_message doesn't change
1758
- return $this->bookings;
1759
- }
1760
-
1761
- /**
1762
- * Get the tickets related to this event.
1763
- * @param boolean $force_reload
1764
- * @return EM_Tickets
1765
- */
1766
- function get_tickets( $force_reload = false ){
1767
- return $this->get_bookings($force_reload)->get_tickets();
1768
- }
1769
-
1770
- /* Provides the tax rate for this event.
1771
- * @see EM_Object::get_tax_rate()
1772
- */
1773
- function get_tax_rate( $decimal = false ){
1774
- $tax_rate = apply_filters('em_event_get_tax_rate', parent::get_tax_rate( false ), $this); //we get tax rate but without decimal
1775
- $tax_rate = ( $tax_rate > 0 ) ? $tax_rate : 0;
1776
- if( $decimal && $tax_rate > 0 ) $tax_rate = $tax_rate / 100;
1777
- return $tax_rate;
1778
- }
1779
-
1780
- /**
1781
- * Deprecated - use $this->get_bookings()->get_spaces() instead.
1782
- * Gets number of spaces in this event, dependent on ticket spaces or hard limit, whichever is smaller.
1783
- * @param boolean $force_refresh
1784
- * @return int
1785
- */
1786
- function get_spaces($force_refresh=false){
1787
- return $this->get_bookings()->get_spaces($force_refresh);
1788
- }
1789
-
1790
- /*
1791
- * Extends the default EM_Object function by switching blogs as needed if in MS Global mode
1792
- * @param string $size
1793
- * @return string
1794
- * @see EM_Object::get_image_url()
1795
- */
1796
- function get_image_url($size = 'full'){
1797
- if( EM_MS_GLOBAL && get_current_blog_id() != $this->blog_id ){
1798
- switch_to_blog($this->blog_id);
1799
- $switch_back = true;
1800
- }
1801
- $return = parent::get_image_url($size);
1802
- if( !empty($switch_back) ){ restore_current_blog(); }
1803
- return $return;
1804
- }
1805
-
1806
- function get_edit_reschedule_url(){
1807
- if( $this->is_recurrence() ){
1808
- $EM_Event = em_get_event($this->recurrence_id);
1809
- return $EM_Event->get_edit_url();
1810
- }
1811
- }
1812
-
1813
- function get_edit_url(){
1814
- if( $this->can_manage('edit_events','edit_others_events') ){
1815
- if( EM_MS_GLOBAL && get_site_option('dbem_ms_global_events_links') && !empty($this->blog_id) && is_main_site() && $this->blog_id != get_current_blog_id() ){
1816
- if( get_blog_option($this->blog_id, 'dbem_edit_events_page') ){
1817
- $link = em_add_get_params(get_permalink(get_blog_option($this->blog_id, 'dbem_edit_events_page')), array('action'=>'edit','event_id'=>$this->event_id), false);
1818
- }
1819
- if( empty($link))
1820
- $link = get_admin_url($this->blog_id, "post.php?post={$this->post_id}&action=edit");
1821
- }else{
1822
- if( get_option('dbem_edit_events_page') && !is_admin() ){
1823
- $link = em_add_get_params(get_permalink(get_option('dbem_edit_events_page')), array('action'=>'edit','event_id'=>$this->event_id), false);
1824
- }
1825
- if( empty($link))
1826
- $link = admin_url()."post.php?post={$this->post_id}&action=edit";
1827
- }
1828
- return apply_filters('em_event_get_edit_url', $link, $this);
1829
- }
1830
- }
1831
-
1832
- function get_bookings_url(){
1833
- if( get_option('dbem_edit_bookings_page') && (!is_admin() || !empty($_REQUEST['is_public'])) ){
1834
- $my_bookings_page = get_permalink(get_option('dbem_edit_bookings_page'));
1835
- $bookings_link = em_add_get_params($my_bookings_page, array('event_id'=>$this->event_id), false);
1836
- }else{
1837
- if( is_multisite() && $this->blog_id != get_current_blog_id() ){
1838
- $bookings_link = get_admin_url($this->blog_id, 'edit.php?post_type='.EM_POST_TYPE_EVENT."&page=events-manager-bookings&event_id=".$this->event_id);
1839
- }else{
1840
- $bookings_link = EM_ADMIN_URL. "&page=events-manager-bookings&event_id=".$this->event_id;
1841
- }
1842
- }
1843
- return apply_filters('em_event_get_bookings_url', $bookings_link, $this);
1844
- }
1845
-
1846
- function get_permalink(){
1847
- if( EM_MS_GLOBAL ){
1848
- //if no blog id defined, assume it's the main blog
1849
- $blog_id = empty($this->blog_id) ? get_current_site()->blog_id:$this->blog_id;
1850
- //if we're not on the same blog as this event then decide whether to link to main blog or to source blog
1851
- if( $blog_id != get_current_blog_id() ){
1852
- if( !get_site_option('dbem_ms_global_events_links') && is_main_site() && get_option('dbem_events_page') ){
1853
- //if on main site, and events page exists and direct links are disabled then show link to main site
1854
- $event_link = trailingslashit(get_permalink(get_option('dbem_events_page')).get_site_option('dbem_ms_events_slug',EM_EVENT_SLUG).'/'.$this->event_slug.'-'.$this->event_id);
1855
- }else{
1856
- //linking directly to the source blog by default
1857
- $event_link = get_blog_permalink( $blog_id, $this->post_id);
1858
- }
1859
- }
1860
- }
1861
- if( empty($event_link) ){
1862
- $event_link = get_post_permalink($this->post_id);
1863
- }
1864
- return apply_filters('em_event_get_permalink', $event_link, $this);
1865
- }
1866
-
1867
- function get_ical_url(){
1868
- global $wp_rewrite;
1869
- if( !empty($wp_rewrite) && $wp_rewrite->using_permalinks() ){
1870
- $return = trailingslashit($this->get_permalink()).'ical/';
1871
- }else{
1872
- $return = em_add_get_params($this->get_permalink(), array('ical'=>1));
1873
- }
1874
- return apply_filters('em_event_get_ical_url', $return);
1875
- }
1876
-
1877
- function is_free( $now = false ){
1878
- $free = true;
1879
- foreach($this->get_tickets() as $EM_Ticket){
1880
- /* @var $EM_Ticket EM_Ticket */
1881
- if( $EM_Ticket->get_price() > 0 ){
1882
- if( !$now || $EM_Ticket->is_available() ){
1883
- $free = false;
1884
- }
1885
- }
1886
- }
1887
- return apply_filters('em_event_is_free',$free, $this, $now);
1888
- }
1889
-
1890
- /**
1891
- * Will output a single event format of this event.
1892
- * Equivalent of calling EM_Event::output( get_option ( 'dbem_single_event_format' ) )
1893
- * @param string $target
1894
- * @return string
1895
- */
1896
- function output_single($target='html'){
1897
- $format = get_option ( 'dbem_single_event_format' );
1898
- return apply_filters('em_event_output_single', $this->output($format, $target), $this, $target);
1899
- }
1900
-
1901
- /**
1902
- * Will output a event in the format passed in $format by replacing placeholders within the format.
1903
- * @param string $format
1904
- * @param string $target
1905
- * @return string
1906
- */
1907
- function output($format, $target="html") {
1908
- global $wpdb;
1909
- //$format = do_shortcode($format); //parse shortcode first, so that formats within shortcodes are parsed properly, however uncommenting this will break shortcode containing placeholders for arguments
1910
- $event_string = $format;
1911
- //Time place holder that doesn't show if empty.
1912
- preg_match_all('/#@?__?\{[^}]+\}/', $format, $results);
1913
- foreach($results[0] as $result) {
1914
- if(substr($result, 0, 3 ) == "#@_"){
1915
- $date = 'end';
1916
- if( substr($result, 0, 4 ) == "#@__" ){
1917
- $offset = 5;
1918
- $show_site_timezone = true;
1919
- }else{
1920
- $offset = 4;
1921
- }
1922
- }else{
1923
- $date = 'start';
1924
- if( substr($result, 0, 3) == "#__" ){
1925
- $offset = 4;
1926
- $show_site_timezone = true;
1927
- }else{
1928
- $offset = 3;
1929
- }
1930
- }
1931
- if( $date == 'end' && $this->event_end == $this->event_start ){
1932
- $replace = __( apply_filters('em_event_output_placeholder', '', $this, $result, $target, array($result)) );
1933
- }else{
1934
- $date_format = substr( $result, $offset, (strlen($result)-($offset+1)) );
1935
- if( !empty($show_site_timezone) ){
1936
- $date_formatted = $this->$date()->copy()->setTimezone()->i18n($date_format);
1937
- }else{
1938
- $date_formatted = $this->$date()->i18n($date_format);
1939
- }
1940
- $replace = apply_filters('em_event_output_placeholder', $date_formatted, $this, $result, $target, array($result));
1941
- }
1942
- $event_string = str_replace($result,$replace,$event_string );
1943
- }
1944
- //This is for the custom attributes
1945
- preg_match_all('/#_ATT\{([^}]+)\}(\{([^}]+\}?)\})?/', $event_string, $results);
1946
- $attributes = em_get_attributes();
1947
- foreach($results[0] as $resultKey => $result) {
1948
- //check that we haven't mistakenly captured a closing bracket in second bracket set
1949
- if( !empty($results[3][$resultKey]) && $results[3][$resultKey][0] == '/' ){
1950
- $result = $results[0][$resultKey] = str_replace($results[2][$resultKey], '', $result);
1951
- $results[3][$resultKey] = $results[2][$resultKey] = '';
1952
- }
1953
- //Strip string of placeholder and just leave the reference
1954
- $attRef = substr( substr($result, 0, strpos($result, '}')), 6 );
1955
- $attString = '';
1956
- $placeholder_atts = array('#_ATT', $results[1][$resultKey]);
1957
- if( is_array($this->event_attributes) && array_key_exists($attRef, $this->event_attributes) ){
1958
- $attString = $this->event_attributes[$attRef];
1959
- }elseif( !empty($results[3][$resultKey]) ){
1960
- //Check to see if we have a second set of braces;
1961
- $placeholder_atts[] = $results[3][$resultKey];
1962
- $attStringArray = explode('|', $results[3][$resultKey]);
1963
- $attString = $attStringArray[0];
1964
- }elseif( !empty($attributes['values'][$attRef][0]) ){
1965
- $attString = $attributes['values'][$attRef][0];
1966
- }
1967
- $attString = apply_filters('em_event_output_placeholder', $attString, $this, $result, $target, $placeholder_atts);
1968
- $event_string = str_replace($result, $attString ,$event_string );
1969
- }
1970
- //First let's do some conditional placeholder removals
1971
- for ($i = 0 ; $i < EM_CONDITIONAL_RECURSIONS; $i++){ //you can add nested recursions by modifying this setting in your wp_options table
1972
- preg_match_all('/\{([a-zA-Z0-9_\-,]+)\}(.+?)\{\/\1\}/s', $event_string, $conditionals);
1973
- if( count($conditionals[0]) > 0 ){
1974
- //Check if the language we want exists, if not we take the first language there
1975
- foreach($conditionals[1] as $key => $condition){
1976
- $show_condition = false;
1977
- if ($condition == 'has_bookings') {
1978
- //check if there's a booking, if not, remove this section of code.
1979
- $show_condition = ($this->event_rsvp && get_option('dbem_rsvp_enabled'));
1980
- }elseif ($condition == 'no_bookings') {
1981
- //check if there's a booking, if not, remove this section of code.
1982
- $show_condition = (!$this->event_rsvp && get_option('dbem_rsvp_enabled'));
1983
- }elseif ($condition == 'no_location'){
1984
- //does this event have a valid location?
1985
- $show_condition = !$this->has_event_location() && !$this->has_location();
1986
- }elseif ($condition == 'has_location'){
1987
- //does this event have a valid location?
1988
- $show_condition = ( $this->has_location() && $this->get_location()->location_status ) || $this->has_event_location();
1989
- }elseif ($condition == 'has_location_venue'){
1990
- //does this event have a valid physical location?
1991
- $show_condition = ( $this->has_location() && $this->get_location()->location_status ) || $this->has_event_location();
1992
- }elseif ($condition == 'no_location_venue'){
1993
- //does this event NOT have a valid physical location?
1994
- $show_condition = !$this->has_location();
1995
- }elseif ($condition == 'has_event_location'){
1996
- //does this event have a valid event location?
1997
- $show_condition = $this->has_event_location();
1998
- }elseif ( preg_match('/^has_event_location_([a-zA-Z0-9_\-]+)$/', $condition, $type_match)){
1999
- //event has a specific category
2000
- $show_condition = $this->has_event_location($type_match[1]);
2001
- }elseif ($condition == 'no_event_location'){
2002
- //does this event not have a valid event location?
2003
- $show_condition = !$this->has_event_location();
2004
- }elseif ( preg_match('/^no_event_location_([a-zA-Z0-9_\-]+)$/', $condition, $type_match)){
2005
- //does this event NOT have a specific event location?
2006
- $show_condition = !$this->has_event_location($type_match[1]);
2007
- }elseif ($condition == 'has_image'){
2008
- //does this event have an image?
2009
- $show_condition = ( $this->get_image_url() != '' );
2010
- }elseif ($condition == 'no_image'){
2011
- //does this event have an image?
2012
- $show_condition = ( $this->get_image_url() == '' );
2013
- }elseif ($condition == 'has_time'){
2014
- //are the booking times different and not an all-day event
2015
- $show_condition = ( $this->event_start_time != $this->event_end_time && !$this->event_all_day );
2016
- }elseif ($condition == 'no_time'){
2017
- //are the booking times exactly the same and it's not an all-day event.
2018
- $show_condition = ( $this->event_start_time == $this->event_end_time && !$this->event_all_day );
2019
- }elseif ($condition == 'different_timezone'){
2020
- //current event timezone is different to blog timezone
2021
- $show_condition = $this->event_timezone != EM_DateTimeZone::create()->getName();
2022
- }elseif ($condition == 'same_timezone'){
2023
- //current event timezone is different to blog timezone
2024
- $show_condition = $this->event_timezone == EM_DateTimeZone::create()->getName();
2025
- }elseif ($condition == 'all_day'){
2026
- //is it an all day event
2027
- $show_condition = !empty($this->event_all_day);
2028
- }elseif ($condition == 'not_all_day'){
2029
- //is not an all day event
2030
- $show_condition = !empty($this->event_all_day);
2031
- }elseif ($condition == 'logged_in'){
2032
- //user is logged in
2033
- $show_condition = is_user_logged_in();
2034
- }elseif ($condition == 'not_logged_in'){
2035
- //not logged in
2036
- $show_condition = !is_user_logged_in();
2037
- }elseif ($condition == 'has_spaces'){
2038
- //there are still empty spaces
2039
- $show_condition = $this->event_rsvp && $this->get_bookings()->get_available_spaces() > 0;
2040
- }elseif ($condition == 'fully_booked'){
2041
- //event is fully booked
2042
- $show_condition = $this->event_rsvp && $this->get_bookings()->get_available_spaces() <= 0;
2043
- }elseif ($condition == 'bookings_open'){
2044
- //bookings are still open
2045
- $show_condition = $this->event_rsvp && $this->get_bookings()->is_open();
2046
- }elseif ($condition == 'bookings_closed'){
2047
- //bookings are still closed
2048
- $show_condition = $this->event_rsvp && !$this->get_bookings()->is_open();
2049
- }elseif ($condition == 'is_free' || $condition == 'is_free_now'){
2050
- //is it a free day event, if _now then free right now
2051
- $show_condition = !$this->event_rsvp || $this->is_free( $condition == 'is_free_now' );
2052
- }elseif ($condition == 'not_free' || $condition == 'not_free_now'){
2053
- //is it a paid event, if _now then paid right now
2054
- $show_condition = $this->event_rsvp && !$this->is_free( $condition == 'not_free_now' );
2055
- }elseif ($condition == 'is_long'){
2056
- //is it an all day event
2057
- $show_condition = $this->event_start_date != $this->event_end_date;
2058
- }elseif ($condition == 'not_long'){
2059
- //is it an all day event
2060
- $show_condition = $this->event_start_date == $this->event_end_date;
2061
- }elseif ($condition == 'is_past'){
2062
- //if event is past
2063
- if( get_option('dbem_events_current_are_past') ){
2064
- $show_condition = $this->start()->getTimestamp() <= time();
2065
- }else{
2066
- $show_condition = $this->end()->getTimestamp() <= time();
2067
- }
2068
- }elseif ($condition == 'is_future'){
2069
- //if event is upcoming
2070
- $show_condition = $this->start()->getTimestamp() > time();
2071
- }elseif ($condition == 'is_current'){
2072
- //if event is currently happening
2073
- $show_condition = $this->start()->getTimestamp() <= time() && $this->end()->getTimestamp() >= time();
2074
- }elseif ($condition == 'is_recurrence'){
2075
- //if event is a recurrence
2076
- $show_condition = $this->is_recurrence();
2077
- }elseif ($condition == 'not_recurrence'){
2078
- //if event is not a recurrence
2079
- $show_condition = !$this->is_recurrence();
2080
- }elseif ($condition == 'is_private'){
2081
- //if event is a recurrence
2082
- $show_condition = $this->event_private == 1;
2083
- }elseif ($condition == 'not_private'){
2084
- //if event is not a recurrence
2085
- $show_condition = $this->event_private == 0;
2086
- }elseif ( strpos($condition, 'is_user_attendee') !== false || strpos($condition, 'not_user_attendee') !== false ){
2087
- //if current user has a booking at this event
2088
- $show_condition = false;
2089
- if( is_user_logged_in() ){
2090
- //we only need a user id, booking id and booking status so we do a direct SQL lookup and once for the loop
2091
- if( !isset($user_bookings) || !is_array($user_bookings) ){
2092
- $sql = $wpdb->prepare('SELECT booking_status FROM '.EM_BOOKINGS_TABLE.' WHERE person_id=%d AND event_id=%d', array(get_current_user_id(), $this->event_id));
2093
- $user_bookings = $wpdb->get_col($sql);
2094
- }
2095
- if( $condition == 'is_user_attendee' && count($user_bookings) > 0 ){
2096
- //user has a booking for this event, could be any booking status
2097
- $show_condition = true;
2098
- }elseif( $condition == 'not_user_attendee' && count($user_bookings) == 0 ){
2099
- //user has no bookings to this event
2100
- $show_condition = true;
2101
- }elseif( strpos($condition, 'is_user_attendee_') !== false ){
2102
- //user has a booking for this event, and we'll now look for a specific status
2103
- $attendee_booking_status = str_replace('is_user_attendee_', '', $condition);
2104
- $show_condition = in_array($attendee_booking_status, $user_bookings);
2105
- }elseif( strpos($condition, 'not_user_attendee_') !== false ){
2106
- //user has a booking for this event, and we'll now look for a specific status
2107
- $attendee_booking_status = str_replace('not_user_attendee_', '', $condition);
2108
- $show_condition = !in_array($attendee_booking_status, $user_bookings);
2109
- }
2110
- }
2111
- }elseif ( preg_match('/^has_category_([a-zA-Z0-9_\-,]+)$/', $condition, $category_match)){
2112
- //event is in this category
2113
- $show_condition = has_term(explode(',', $category_match[1]), EM_TAXONOMY_CATEGORY, $this->post_id);
2114
- }elseif ( preg_match('/^no_category_([a-zA-Z0-9_\-,]+)$/', $condition, $category_match)){
2115
- //event is NOT in this category
2116
- $show_condition = !has_term(explode(',', $category_match[1]), EM_TAXONOMY_CATEGORY, $this->post_id);
2117
- }elseif ( preg_match('/^has_tag_([a-zA-Z0-9_\-,]+)$/', $condition, $tag_match)){
2118
- //event has this tag
2119
- $show_condition = has_term(explode(',', $tag_match[1]), EM_TAXONOMY_TAG, $this->post_id);
2120
- }elseif ( preg_match('/^no_tag_([a-zA-Z0-9_\-,]+)$/', $condition, $tag_match)){
2121
- //event doesn't have this tag
2122
- $show_condition = !has_term(explode(',', $tag_match[1]), EM_TAXONOMY_TAG, $this->post_id);
2123
- }elseif ( preg_match('/^has_att_([a-zA-Z0-9_\-,]+)$/', $condition, $att_match)){
2124
- //event has a specific custom field
2125
- $show_condition = !empty($this->event_attributes[$att_match[1]]) || !empty($this->event_attributes[str_replace('_', ' ', $att_match[1])]);
2126
- }elseif ( preg_match('/^no_att_([a-zA-Z0-9_\-,]+)$/', $condition, $att_match)){
2127
- //event has a specific custom field
2128
- $show_condition = empty($this->event_attributes[$att_match[1]]) && empty($this->event_attributes[str_replace('_', ' ', $att_match[1])]);
2129
- }
2130
- //other potential ones - has_attribute_... no_attribute_... has_categories_...
2131
- $show_condition = apply_filters('em_event_output_show_condition', $show_condition, $condition, $conditionals[0][$key], $this);
2132
- if($show_condition){
2133
- //calculate lengths to delete placeholders
2134
- $placeholder_length = strlen($condition)+2;
2135
- $replacement = substr($conditionals[0][$key], $placeholder_length, strlen($conditionals[0][$key])-($placeholder_length *2 +1));
2136
- }else{
2137
- $replacement = '';
2138
- }
2139
- $event_string = str_replace($conditionals[0][$key], apply_filters('em_event_output_condition', $replacement, $condition, $conditionals[0][$key], $this), $event_string);
2140
- }
2141
- }
2142
- }
2143
- //Now let's check out the placeholders.
2144
- preg_match_all("/(#@?_?[A-Za-z0-9_]+)({([^}]+)})?/", $event_string, $placeholders);
2145
- $replaces = array();
2146
- foreach($placeholders[1] as $key => $result) {
2147
- $match = true;
2148
- $replace = '';
2149
- $full_result = $placeholders[0][$key];
2150
- $placeholder_atts = array($result);
2151
- if( !empty($placeholders[3][$key]) ) $placeholder_atts[] = $placeholders[3][$key];
2152
- switch( $result ){
2153
- //Event Details
2154
- case '#_EVENTID':
2155
- $replace = $this->event_id;
2156
- break;
2157
- case '#_EVENTPOSTID':
2158
- $replace = $this->post_id;
2159
- break;
2160
- case '#_NAME': //deprecated
2161
- case '#_EVENTNAME':
2162
- $replace = $this->event_name;
2163
- break;
2164
- case '#_NOTES': //deprecated
2165
- case '#_EVENTNOTES':
2166
- $replace = $this->post_content;
2167
- break;
2168
- case '#_EXCERPT': //deprecated
2169
- case '#_EVENTEXCERPT':
2170
- case '#_EVENTEXCERPTCUT':
2171
- if( !empty($this->post_excerpt) && $result != "#_EVENTEXCERPTCUT" ){
2172
- $replace = $this->post_excerpt;
2173
- }else{
2174
- $excerpt_length = ( $result == "#_EVENTEXCERPTCUT" ) ? 55:false;
2175
- $excerpt_more = apply_filters('em_excerpt_more', ' ' . '[...]');
2176
- if( !empty($placeholders[3][$key]) ){
2177
- $ph_args = explode(',', $placeholders[3][$key]);
2178
- if( is_numeric($ph_args[0]) || empty($ph_args[0]) ) $excerpt_length = $ph_args[0];
2179
- if( !empty($ph_args[1]) ) $excerpt_more = $ph_args[1];
2180
- }
2181
- $replace = $this->output_excerpt($excerpt_length, $excerpt_more, $result == "#_EVENTEXCERPTCUT");
2182
- }
2183
- break;
2184
- case '#_EVENTIMAGEURL':
2185
- case '#_EVENTIMAGE':
2186
- if($this->get_image_url() != ''){
2187
- if($result == '#_EVENTIMAGEURL'){
2188
- $replace = esc_url($this->image_url);
2189
- }else{
2190
- if( empty($placeholders[3][$key]) ){
2191
- $replace = "<img src='".esc_url($this->image_url)."' alt='".esc_attr($this->event_name)."'/>";
2192
- }else{
2193
- $image_size = explode(',', $placeholders[3][$key]);
2194
- $image_url = $this->image_url;
2195
- if( self::array_is_numeric($image_size) && count($image_size) > 1 ){
2196
- //get a thumbnail
2197
- if( get_option('dbem_disable_thumbnails') ){
2198
- $image_attr = '';
2199
- $image_args = array();
2200
- if( empty($image_size[1]) && !empty($image_size[0]) ){
2201
- $image_attr = 'width="'.$image_size[0].'"';
2202
- $image_args['w'] = $image_size[0];
2203
- }elseif( empty($image_size[0]) && !empty($image_size[1]) ){
2204
- $image_attr = 'height="'.$image_size[1].'"';
2205
- $image_args['h'] = $image_size[1];
2206
- }elseif( !empty($image_size[0]) && !empty($image_size[1]) ){
2207
- $image_attr = 'width="'.$image_size[0].'" height="'.$image_size[1].'"';
2208
- $image_args = array('w'=>$image_size[0], 'h'=>$image_size[1]);
2209
- }
2210
- $replace = "<img src='".esc_url(em_add_get_params($image_url, $image_args))."' alt='".esc_attr($this->event_name)."' $image_attr />";
2211
- }else{
2212
- if( EM_MS_GLOBAL && get_current_blog_id() != $this->blog_id ){
2213
- switch_to_blog($this->blog_id);
2214
- $switch_back = true;
2215
- }
2216
- $replace = get_the_post_thumbnail($this->ID, $image_size, array('alt' => esc_attr($this->event_name)) );
2217
- if( !empty($switch_back) ){ restore_current_blog(); }
2218
- }
2219
- }else{
2220
- $replace = "<img src='".esc_url($image_url)."' alt='".esc_attr($this->event_name)."'/>";
2221
- }
2222
- }
2223
- }
2224
- }
2225
- break;
2226
- //Times & Dates
2227
- case '#_24HSTARTTIME':
2228
- case '#_24HENDTIME':
2229
- $replace = ($result == '#_24HSTARTTIME') ? $this->start()->format('H:i'):$this->end()->format('H:i');
2230
- break;
2231
- case '#_24HSTARTTIME_SITE':
2232
- case '#_24HENDTIME_SITE':
2233
- $replace = ($result == '#_24HSTARTTIME_SITE') ? $this->start()->copy()->setTimezone(false)->format('H:i'):$this->end()->copy()->setTimezone(false)->format('H:i');
2234
- break;
2235
- case '#_24HSTARTTIME_LOCAL':
2236
- case '#_24HENDTIME_LOCAL':
2237
- case '#_24HTIMES_LOCAL':
2238
- $ts = ($result == '#_24HENDTIME_LOCAL') ? $this->end()->getTimestamp():$this->start()->getTimestamp();
2239
- $date_end = ($result == '#_24HTIMES_LOCAL' && $this->end()->getTimestamp() !== $ts) ? 'data-time-end="'. esc_attr($this->end()->getTimestamp()) .'" data-separator="'. esc_attr(get_option('dbem_times_separator')) . '"' : '';
2240
- $replace = '<span class="em-time-localjs" data-time-format="24" data-time="'. esc_attr($ts) .'" '. $date_end .'>JavaScript Disabled</span>';
2241
- break;
2242
- case '#_12HSTARTTIME':
2243
- case '#_12HENDTIME':
2244
- $replace = ($result == '#_12HSTARTTIME') ? $this->start()->format('g:i A'):$this->end()->format('g:i A');
2245
- break;
2246
- case '#_12HSTARTTIME_SITE':
2247
- case '#_12HENDTIME_SITE':
2248
- $replace = ($result == '#_12HSTARTTIME_SITE') ? $this->start()->copy()->setTimezone(false)->format('g:i A'):$this->end()->copy()->setTimezone(false)->format('g:i A');
2249
- break;
2250
- case '#_12HSTARTTIME_LOCAL':
2251
- case '#_12HENDTIME_LOCAL':
2252
- case '#_12HTIMES_LOCAL':
2253
- $ts = ($result == '#_12HENDTIME_LOCAL') ? $this->end()->getTimestamp():$this->start()->getTimestamp();
2254
- $date_end = ($result == '#_24HTIMES_LOCAL' && $this->end()->getTimestamp() !== $ts) ? 'data-time-end="'. esc_attr($this->end()->getTimestamp()) .'" data-separator="'. esc_attr(get_option('dbem_times_separator')) . '"' : '';
2255
- $replace = '<span class="em-time-localjs" data-time-format="12" data-time="'. esc_attr($ts) .'" '. $date_end .'>JavaScript Disabled</span>';
2256
- break;
2257
- case '#_EVENTTIMES':
2258
- //get format of time to show
2259
- $replace = $this->output_times();
2260
- break;
2261
- case '#_EVENTTIMES_SITE':
2262
- //get format of time to show but show timezone of site rather than local time
2263
- $replace = $this->output_times(false, false, false, true);
2264
- break;
2265
- case '#_EVENTTIMES_LOCAL':
2266
- case '#_EVENTDATES_LOCAL':
2267
- if( !defined('EM_JS_MOMENTJS_PH') || EM_JS_MOMENTJS_PH ){
2268
- // check for passed parameters, in which case we skip replacements entirely and use pure moment formats
2269
- $time_format = $separator = null;
2270
- if( !empty($placeholder_atts[1]) ){
2271
- $params = explode(',', $placeholder_atts[1]);
2272
- if( !empty($params[0]) ) $time_format = $params[0];
2273
- if( !empty($params[1]) ) $separator = $params[1];
2274
- }
2275
- if( empty($separator) ) $separator = get_option('dbem_times_separator');
2276
- // if no moment format provided, we convert the one stored for times in php
2277
- if( empty($time_format) ){
2278
- // convert EM format setting to moment formatting, adapted from https://stackoverflow.com/questions/30186611/php-dateformat-to-moment-js-format
2279
- $replacements = array(
2280
- /* Day */ 'jS' => 'Do', /*o doesn't exist on its own, so we find/replase jS only*/ 'd' => 'DD', 'D' => 'ddd', 'j' => 'D', 'l' => 'dddd', 'N' => 'E', /*'S' => 'o' - see jS*/ 'w' => 'e', 'z' => 'DDD',
2281
- /* Week */ 'W' => 'W',
2282
- /* Month */ 'F' => 'MMMM', 'm' => 'MM', 'M' => 'MMM', 'n' => 'M', 't' => '#t', /* days in the month => moment().daysInMonth(); */
2283
- /* Year */ 'L' => '#L', /* Leap year? => moment().isLeapYear(); */ 'o' => 'YYYY', 'Y' => 'YYYY', 'y' => 'YY',
2284
- /* Time */ 'a' => 'a', 'A' => 'A', 'B' => '', /* Swatch internet time (.beats), no equivalent */ 'g' => 'h', 'G' => 'H', 'h' => 'hh', 'H' => 'HH', 'i' => 'mm', 's' => 'ss', 'u' => 'SSSSSS', /* microseconds */ 'v' => 'SSS', /* milliseconds (from PHP 7.0.0) */
2285
- /* Timezone */ 'e' => '##T', /* Timezone - deprecated since version 1.6.0 of moment.js, we'll use Intl.DateTimeFromat().resolvedOptions().timeZone instead. */ 'I' => '##t', /* Daylight Saving Time? => moment().isDST(); */ 'O' => 'ZZ', 'P' => 'Z', 'T' => '#T', /* deprecated since version 1.6.0 of moment.js, using GMT difference with colon to keep it shorter than full timezone */ 'Z' => '###t', /* time zone offset in seconds => moment().zone() * -60 : the negative is because moment flips that around; */
2286
- /* Full Date/Time */ 'c' => 'YYYY-MM-DD[T]HH:mm:ssZ', /* ISO 8601 */ 'r' => 'ddd, DD MMM YYYY HH:mm:ss ZZ', /* RFC 2822 */ 'U' => 'X',
2287
- );
2288
- // Converts escaped characters.
2289
- foreach ($replacements as $from => $to) {
2290
- $replacements['\\' . $from] = '[' . $from . ']';
2291
- }
2292
- if( $result === '#_EVENTDATES_LOCAL' ){
2293
- $time_format = ( get_option('dbem_date_format') ) ? get_option('dbem_date_format'):get_option('date_format');
2294
- if( empty($separator) ) $separator = get_option('dbem_dates_separator');
2295
- }else{
2296
- $time_format = ( get_option('dbem_time_format') ) ? get_option('dbem_time_format'):get_option('time_format');
2297
- if( empty($separator) ) $separator = get_option('dbem_times_separator');
2298
- }
2299
- $time_format = strtr($time_format, $replacements);
2300
- }
2301
- wp_enqueue_script('moment', '', array(), false, true); //add to footer if not already
2302
- // start output
2303
- ob_start();
2304
- ?>
2305
- <span class="em-date-momentjs" data-date-format="<?php echo esc_attr($time_format); ?>" data-date-start="<?php echo $this->start()->getTimestamp() ?>" data-date-end="<?php echo $this->end()->getTimestamp() ?>" data-date-separator="<?php echo esc_attr($separator); ?>">JavaScript Disabled</span>
2306
- <?php
2307
- $replace = ob_get_clean();
2308
- }
2309
- break;
2310
- case '#_EVENTDATES':
2311
- //get format of time to show
2312
- $replace = $this->output_dates();
2313
- break;
2314
- case '#_EVENTDATES_SITE':
2315
- //get format of time to show but use timezone of site rather than event
2316
- $replace = $this->output_dates(false, false, true);
2317
- break;
2318
- case '#_EVENTTIMEZONE':
2319
- $replace = str_replace('_', ' ', $this->event_timezone);
2320
- break;
2321
- case '#_EVENTTIMEZONERAW':
2322
- $replace = $this->event_timezone;
2323
- break;
2324
- case '#_EVENTTIMEZONE_LOCAL':
2325
- $rand = rand();
2326
- ob_start();
2327
- ?>
2328
- <span id="em-start-local-timezone-<?php echo $rand ?>">JavaScript Disabled</span>
2329
- <script>
2330
- document.getElementById("em-start-local-timezone-<?php echo $rand ?>").innerHTML = Intl.DateTimeFormat().resolvedOptions().timeZone;
2331
- </script>
2332
- <?php
2333
- $replace = ob_get_clean();
2334
- break;
2335
- //Recurring Placeholders
2336
- case '#_RECURRINGDATERANGE': //Outputs the #_EVENTDATES equivalent of the recurring event template pattern.
2337
- $replace = $this->get_event_recurrence()->output_dates(); //if not a recurrence, we're running output_dates on $this
2338
- break;
2339
- case '#_RECURRINGPATTERN':
2340
- $replace = '';
2341
- if( $this->is_recurrence() || $this->is_recurring() ){
2342
- $replace = $this->get_event_recurrence()->get_recurrence_description();
2343
- }
2344
- break;
2345
- case '#_RECURRINGID':
2346
- $replace = $this->recurrence_id;
2347
- break;
2348
- //Links
2349
- case '#_EVENTPAGEURL': //deprecated
2350
- case '#_LINKEDNAME': //deprecated
2351
- case '#_EVENTURL': //Just the URL
2352
- case '#_EVENTLINK': //HTML Link
2353
- $event_link = esc_url($this->get_permalink());
2354
- if($result == '#_LINKEDNAME' || $result == '#_EVENTLINK'){
2355
- $replace = '<a href="'.$event_link.'">'.esc_attr($this->event_name).'</a>';
2356
- }else{
2357
- $replace = $event_link;
2358
- }
2359
- break;
2360
- case '#_EDITEVENTURL':
2361
- case '#_EDITEVENTLINK':
2362
- if( $this->can_manage('edit_events','edit_others_events') ){
2363
- $link = esc_url($this->get_edit_url());
2364
- if( $result == '#_EDITEVENTLINK'){
2365
- $replace = '<a href="'.$link.'">'.esc_html(sprintf(__('Edit Event','events-manager'))).'</a>';
2366
- }else{
2367
- $replace = $link;
2368
- }
2369
- }
2370
- break;
2371
- //Bookings
2372
- case '#_ADDBOOKINGFORM': //deprecated
2373
- case '#_REMOVEBOOKINGFORM': //deprecated
2374
- case '#_BOOKINGFORM':
2375
- if( get_option('dbem_rsvp_enabled')){
2376
- if( !defined('EM_XSS_BOOKINGFORM_FILTER') && locate_template('plugins/events-manager/placeholders/bookingform.php') ){
2377
- //xss fix for old overridden booking forms
2378
- add_filter('em_booking_form_action_url','esc_url');
2379
- define('EM_XSS_BOOKINGFORM_FILTER',true);
2380
- }
2381
- ob_start();
2382
- $template = em_locate_template('placeholders/bookingform.php', true, array('EM_Event'=>$this));
2383
- EM_Bookings::enqueue_js();
2384
- $replace = ob_get_clean();
2385
- }
2386
- break;
2387
- case '#_BOOKINGBUTTON':
2388
- if( get_option('dbem_rsvp_enabled') && $this->event_rsvp ){
2389
- ob_start();
2390
- $template = em_locate_template('placeholders/bookingbutton.php', true, array('EM_Event'=>$this));
2391
- $replace = ob_get_clean();
2392
- }
2393
- break;
2394
- case '#_EVENTPRICERANGEALL':
2395
- $show_all_ticket_prices = true; //continues below
2396
- case '#_EVENTPRICERANGE':
2397
- //get the range of prices
2398
- $min = false;
2399
- $max = 0;
2400
- if( $this->get_bookings()->is_open() || !empty($show_all_ticket_prices) ){
2401
- foreach( $this->get_tickets()->tickets as $EM_Ticket ){
2402
- /* @var $EM_Ticket EM_Ticket */
2403
- if( $EM_Ticket->is_available() || get_option('dbem_bookings_tickets_show_unavailable') || !empty($show_all_ticket_prices) ){
2404
- if($EM_Ticket->get_price() > $max ){
2405
- $max = $EM_Ticket->get_price();
2406
- }
2407
- if($EM_Ticket->get_price() < $min || $min === false){
2408
- $min = $EM_Ticket->get_price();
2409
- }
2410
- }
2411
- }
2412
- }
2413
- if( $min === false ) $min = 0;
2414
- if( $min != $max ){
2415
- $replace = em_get_currency_formatted($min).' - '.em_get_currency_formatted($max);
2416
- }else{
2417
- $replace = em_get_currency_formatted($min);
2418
- }
2419
- break;
2420
- case '#_EVENTPRICEMIN':
2421
- case '#_EVENTPRICEMINALL':
2422
- //get the range of prices
2423
- $min = false;
2424
- foreach( $this->get_tickets()->tickets as $EM_Ticket ){
2425
- /* @var $EM_Ticket EM_Ticket */
2426
- if( $EM_Ticket->is_available() || $result == '#_EVENTPRICEMINALL'){
2427
- if( $EM_Ticket->get_price() < $min || $min === false){
2428
- $min = $EM_Ticket->get_price();
2429
- }
2430
- }
2431
- }
2432
- if( $min === false ) $min = 0;
2433
- $replace = em_get_currency_formatted($min);
2434
- break;
2435
- case '#_EVENTPRICEMAX':
2436
- case '#_EVENTPRICEMAXALL':
2437
- //get the range of prices
2438
- $max = 0;
2439
- foreach( $this->get_tickets()->tickets as $EM_Ticket ){
2440
- /* @var $EM_Ticket EM_Ticket */
2441
- if( $EM_Ticket->is_available() || $result == '#_EVENTPRICEMAXALL'){
2442
- if( $EM_Ticket->get_price() > $max ){
2443
- $max = $EM_Ticket->get_price();
2444
- }
2445
- }
2446
- }
2447
- $replace = em_get_currency_formatted($max);
2448
- break;
2449
- case '#_AVAILABLESEATS': //deprecated
2450
- case '#_AVAILABLESPACES':
2451
- if ($this->event_rsvp && get_option('dbem_rsvp_enabled')) {
2452
- $replace = $this->get_bookings()->get_available_spaces();
2453
- } else {
2454
- $replace = "0";
2455
- }
2456
- break;
2457
- case '#_BOOKEDSEATS': //deprecated
2458
- case '#_BOOKEDSPACES':
2459
- //This placeholder is actually a little misleading, as it'll consider reserved (i.e. pending) bookings as 'booked'
2460
- if ($this->event_rsvp && get_option('dbem_rsvp_enabled')) {
2461
- $replace = $this->get_bookings()->get_booked_spaces();
2462
- if( get_option('dbem_bookings_approval_reserved') ){
2463
- $replace += $this->get_bookings()->get_pending_spaces();
2464
- }
2465
- } else {
2466
- $replace = "0";
2467
- }
2468
- break;
2469
- case '#_PENDINGSPACES':
2470
- if ($this->event_rsvp && get_option('dbem_rsvp_enabled')) {
2471
- $replace = $this->get_bookings()->get_pending_spaces();
2472
- } else {
2473
- $replace = "0";
2474
- }
2475
- break;
2476
- case '#_SEATS': //deprecated
2477
- case '#_SPACES':
2478
- $replace = $this->get_spaces();
2479
- break;
2480
- case '#_BOOKINGSURL':
2481
- case '#_BOOKINGSLINK':
2482
- if( $this->can_manage('manage_bookings','manage_others_bookings') ){
2483
- $bookings_link = esc_url($this->get_bookings_url());
2484
- if($result == '#_BOOKINGSLINK'){
2485
- $replace = '<a href="'.$bookings_link.'" title="'.esc_attr($this->event_name).'">'.esc_html($this->event_name).'</a>';
2486
- }else{
2487
- $replace = $bookings_link;
2488
- }
2489
- }
2490
- break;
2491
- case '#_BOOKINGSCUTOFF':
2492
- case '#_BOOKINGSCUTOFFDATE':
2493
- case '#_BOOKINGSCUTOFFTIME':
2494
- $replace = '';
2495
- if ($this->event_rsvp && get_option('dbem_rsvp_enabled') ) {
2496
- $replace_format = em_get_date_format() .' '. em_get_hour_format();
2497
- if( $result == '#_BOOKINGSCUTOFFDATE' ) $replace_format = em_get_date_format();
2498
- if( $result == '#_BOOKINGSCUTOFFTIME' ) $replace_format = em_get_hour_format();
2499
- $replace = $this->rsvp_end()->i18n($replace_format);
2500
- }
2501
- break;
2502
- //Contact Person
2503
- case '#_CONTACTNAME':
2504
- case '#_CONTACTPERSON': //deprecated (your call, I think name is better)
2505
- $replace = $this->get_contact()->display_name;
2506
- break;
2507
- case '#_CONTACTUSERNAME':
2508
- $replace = $this->get_contact()->user_login;
2509
- break;
2510
- case '#_CONTACTEMAIL':
2511
- case '#_CONTACTMAIL': //deprecated
2512
- $replace = $this->get_contact()->user_email;
2513
- break;
2514
- case '#_CONTACTURL':
2515
- $replace = $this->get_contact()->user_url;
2516
- break;
2517
- case '#_CONTACTID':
2518
- $replace = $this->get_contact()->ID;
2519
- break;
2520
- case '#_CONTACTPHONE':
2521
- $replace = ( $this->get_contact()->phone != '') ? $this->get_contact()->phone : __('N/A', 'events-manager');
2522
- break;
2523
- case '#_CONTACTAVATAR':
2524
- $replace = get_avatar( $this->get_contact()->ID, $size = '50' );
2525
- break;
2526
- case '#_CONTACTPROFILELINK':
2527
- case '#_CONTACTPROFILEURL':
2528
- if( function_exists('bp_core_get_user_domain') ){
2529
- $replace = bp_core_get_user_domain($this->get_contact()->ID);
2530
- if( $result == '#_CONTACTPROFILELINK' ){
2531
- $replace = '<a href="'.esc_url($replace).'">'.__('Profile', 'events-manager').'</a>';
2532
- }
2533
- }
2534
- break;
2535
- case '#_CONTACTMETA':
2536
- if( !empty($placeholders[3][$key]) ){
2537
- $replace = get_user_meta($this->event_owner, $placeholders[3][$key], true);
2538
- }
2539
- break;
2540
- case '#_ATTENDEES':
2541
- ob_start();
2542
- $template = em_locate_template('placeholders/attendees.php', true, array('EM_Event'=>$this));
2543
- $replace = ob_get_clean();
2544
- break;
2545
- case '#_ATTENDEESLIST':
2546
- ob_start();
2547
- $template = em_locate_template('placeholders/attendeeslist.php', true, array('EM_Event'=>$this));
2548
- $replace = ob_get_clean();
2549
- break;
2550
- case '#_ATTENDEESPENDINGLIST':
2551
- ob_start();
2552
- $template = em_locate_template('placeholders/attendeespendinglist.php', true, array('EM_Event'=>$this));
2553
- $replace = ob_get_clean();
2554
- break;
2555
- //Categories and Tags
2556
- case '#_EVENTCATEGORIESIMAGES':
2557
- $replace = '';
2558
- if( get_option('dbem_categories_enabled') ){
2559
- ob_start();
2560
- $template = em_locate_template('placeholders/eventcategoriesimages.php', true, array('EM_Event'=>$this));
2561
- $replace = ob_get_clean();
2562
- }
2563
- break;
2564
- case '#_EVENTTAGS':
2565
- $replace = '';
2566
- if( get_option('dbem_tags_enabled') ){
2567
- ob_start();
2568
- $template = em_locate_template('placeholders/eventtags.php', true, array('EM_Event'=>$this));
2569
- $replace = ob_get_clean();
2570
- }
2571
- break;
2572
- case '#_CATEGORIES': //deprecated
2573
- case '#_EVENTCATEGORIES':
2574
- $replace = '';
2575
- if( get_option('dbem_categories_enabled') ){
2576
- ob_start();
2577
- $template = em_locate_template('placeholders/categories.php', true, array('EM_Event'=>$this));
2578
- $replace = ob_get_clean();
2579
- }
2580
- break;
2581
- //Ical Stuff
2582
- case '#_EVENTICALURL':
2583
- case '#_EVENTICALLINK':
2584
- $replace = $this->get_ical_url();
2585
- if( $result == '#_EVENTICALLINK' ){
2586
- $replace = '<a href="'.esc_url($replace).'">iCal</a>';
2587
- }
2588
- break;
2589
- case '#_EVENTWEBCALURL':
2590
- case '#_EVENTWEBCALLINK':
2591
- $replace = $this->get_ical_url();
2592
- $replace = str_replace(array('http://','https://'), 'webcal://', $replace);
2593
- if( $result == '#_EVENTWEBCALLINK' ){
2594
- $replace = '<a href="'.esc_url($replace).'">webcal</a>';
2595
- }
2596
- break;
2597
- case '#_EVENTGCALURL':
2598
- case '#_EVENTGCALLINK':
2599
- //get dates in UTC/GMT time
2600
- if($this->event_all_day && $this->event_start_date == $this->event_end_date){
2601
- $dateStart = $this->start()->format('Ymd');
2602
- $dateEnd = $this->end()->copy()->add('P1D')->format('Ymd');
2603
- }else{
2604
- $dateStart = $this->start()->format('Ymd\THis');
2605
- $dateEnd = $this->end()->format('Ymd\THis');
2606
- }
2607
- //build url
2608
- $gcal_url = 'http://www.google.com/calendar/event?action=TEMPLATE&text=event_name&dates=start_date/end_date&details=post_content&location=location_name&trp=false&sprop=event_url&sprop=name:blog_name&ctz=event_timezone';
2609
- $gcal_url = str_replace('event_name', urlencode($this->event_name), $gcal_url);
2610
- $gcal_url = str_replace('start_date', urlencode($dateStart), $gcal_url);
2611
- $gcal_url = str_replace('end_date', urlencode($dateEnd), $gcal_url);
2612
- $gcal_url = str_replace('location_name', urlencode($this->get_location()->get_full_address(', ', true)), $gcal_url);
2613
- $gcal_url = str_replace('blog_name', urlencode(get_bloginfo()), $gcal_url);
2614
- $gcal_url = str_replace('event_url', urlencode($this->get_permalink()), $gcal_url);
2615
- $gcal_url = str_replace('event_timezone', urlencode($this->event_timezone), $gcal_url);
2616
- //calculate URL length so we know how much we can work with to make a description.
2617
- if( !empty($this->post_excerpt) ){
2618
- $gcal_url_description = $this->post_excerpt;
2619
- }else{
2620
- $matches = explode('<!--more', $this->post_content);
2621
- $gcal_url_description = wp_kses_data($matches[0]);
2622
- }
2623
- $gcal_url_length = strlen($gcal_url) - 9;
2624
- if( strlen($gcal_url_description) + $gcal_url_length > 1350 ){
2625
- $gcal_url_description = substr($gcal_url_description, 0, 1380 - $gcal_url_length - 3 ).'...';
2626
- }
2627
- $gcal_url = str_replace('post_content', urlencode($gcal_url_description), $gcal_url);
2628
- //get the final url
2629
- $replace = $gcal_url;
2630
- if( $result == '#_EVENTGCALLINK' ){
2631
- $img_url = 'www.google.com/calendar/images/ext/gc_button2.gif';
2632
- $img_url = is_ssl() ? 'https://'.$img_url:'http://'.$img_url;
2633
- $replace = '<a href="'.esc_url($replace).'" target="_blank"><img src="'.esc_url($img_url).'" alt="0" border="0"></a>';
2634
- }
2635
- break;
2636
- //Event location (not physical location)
2637
- case '#_EVENTLOCATION':
2638
- if( $this->has_event_location() ) {
2639
- if (!empty($placeholders[3][$key])) {
2640
- $replace = $this->get_event_location()->output( $placeholders[3][$key], $target );
2641
- } else {
2642
- $replace = $this->get_event_location()->output( null, $target );
2643
- }
2644
- }
2645
- break;
2646
- default:
2647
- $replace = $full_result;
2648
- break;
2649
- }
2650
- $replaces[$full_result] = apply_filters('em_event_output_placeholder', $replace, $this, $full_result, $target, $placeholder_atts);
2651
- }
2652
- //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
2653
- krsort($replaces);
2654
- foreach($replaces as $full_result => $replacement){
2655
- if( !in_array($full_result, array('#_NOTES','#_EVENTNOTES')) ){
2656
- $event_string = str_replace($full_result, $replacement , $event_string );
2657
- }else{
2658
- $new_placeholder = str_replace('#_', '__#', $full_result); //this will avoid repeated filters when locations/categories are parsed
2659
- $event_string = str_replace($full_result, $new_placeholder , $event_string );
2660
- $desc_replace[$new_placeholder] = $replacement;
2661
- }
2662
- }
2663
- //Time placeholders
2664
- foreach($placeholders[1] as $result) {
2665
- // matches all PHP START date and time placeholders
2666
- if (preg_match('/^#[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
2667
- $replace = $this->start()->i18n(ltrim($result, "#"));
2668
- $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target, array($result));
2669
- $event_string = str_replace($result, $replace, $event_string );
2670
- }
2671
- // matches all PHP END time placeholders for endtime
2672
- if (preg_match('/^#@[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
2673
- $replace = $this->end()->i18n(ltrim($result, "#@"));
2674
- $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target, array($result));
2675
- $event_string = str_replace($result, $replace, $event_string );
2676
- }
2677
- }
2678
- //Now do dependent objects
2679
- if( get_option('dbem_locations_enabled') ){
2680
- if( !empty($this->location_id) && $this->get_location()->location_status ){
2681
- $event_string = $this->get_location()->output($event_string, $target);
2682
- }else{
2683
- $EM_Location = new EM_Location();
2684
- $event_string = $EM_Location->output($event_string, $target);
2685
- }
2686
- }
2687
-
2688
- if( get_option('dbem_categories_enabled') ){
2689
- //for backwards compat and easy use, take over the individual category placeholders with the frirst cat in th elist.
2690
- if( count($this->get_categories()) > 0 ){
2691
- $EM_Category = $this->get_categories()->get_first();
2692
- }
2693
- if( empty($EM_Category) ) $EM_Category = new EM_Category();
2694
- $event_string = $EM_Category->output($event_string, $target);
2695
- }
2696
-
2697
- if( get_option('dbem_tags_enabled') ){
2698
- $EM_Tags = new EM_Tags($this);
2699
- if( count($EM_Tags) > 0 ){
2700
- $EM_Tag = $EM_Tags->get_first();
2701
- }
2702
- if( empty($EM_Tag) ) $EM_Tag = new EM_Tag();
2703
- $event_string = $EM_Tag->output($event_string, $target);
2704
- }
2705
-
2706
- //Finally, do the event notes, so that previous placeholders don't get replaced within the content, which may use shortcodes
2707
- if( !empty($desc_replace) ){
2708
- foreach($desc_replace as $full_result => $replacement){
2709
- $event_string = str_replace($full_result, $replacement , $event_string );
2710
- }
2711
- }
2712
-
2713
- //do some specific formatting
2714
- //TODO apply this sort of formatting to any output() function
2715
- if( $target == 'ical' ){
2716
- //strip html and escape characters
2717
- $event_string = str_replace('\\','\\\\',strip_tags($event_string));
2718
- $event_string = str_replace(';','\;',$event_string);
2719
- $event_string = str_replace(',','\,',$event_string);
2720
- //remove and define line breaks in ical format
2721
- $event_string = str_replace('\\\\n','\n',$event_string);
2722
- $event_string = str_replace("\r\n",'\n',$event_string);
2723
- $event_string = str_replace("\n",'\n',$event_string);
2724
- }
2725
- return apply_filters('em_event_output', $event_string, $this, $format, $target);
2726
- }
2727
-
2728
- function output_times( $time_format = false, $time_separator = false , $all_day_message = false, $use_site_timezone = false ){
2729
- if( !$this->event_all_day ){
2730
- if( empty($time_format) ) $time_format = ( get_option('dbem_time_format') ) ? get_option('dbem_time_format'):get_option('time_format');
2731
- if( empty($time_separator) ) $time_separator = get_option('dbem_times_separator');
2732
- if( $this->event_start_time != $this->event_end_time ){
2733
- if( $use_site_timezone ){
2734
- $replace = $this->start()->copy()->setTimezone()->i18n($time_format). $time_separator . $this->end()->copy()->setTimezone()->i18n($time_format);
2735
- }else{
2736
- $replace = $this->start()->i18n($time_format). $time_separator . $this->end()->i18n($time_format);
2737
- }
2738
- }else{
2739
- if( $use_site_timezone ){
2740
- $replace = $this->start()->copy()->setTimezone()->i18n($time_format);
2741
- }else{
2742
- $replace = $this->start()->i18n($time_format);
2743
- }
2744
- }
2745
- }else{
2746
- $replace = $all_day_message ? $all_day_message : get_option('dbem_event_all_day_message');
2747
- }
2748
- return $replace;
2749
- }
2750
-
2751
- function output_dates( $date_format = false, $date_separator = false, $use_site_timezone = false ){
2752
- if( empty($date_format) ) $date_format = ( get_option('dbem_date_format') ) ? get_option('dbem_date_format'):get_option('date_format');
2753
- if( empty($date_separator) ) $date_separator = get_option('dbem_dates_separator');
2754
- if( $this->event_start_date != $this->event_end_date){
2755
- if( $use_site_timezone ){
2756
- $replace = $this->start()->copy()->setTimezone()->i18n($date_format). $date_separator . $this->end()->copy()->setTimezone()->i18n($date_format);
2757
- }else{
2758
- $replace = $this->start()->i18n($date_format). $date_separator . $this->end()->i18n($date_format);
2759
- }
2760
- }else{
2761
- if( $use_site_timezone ){
2762
- $replace = $this->start()->copy()->setTimezone()->i18n($date_format);
2763
- }else{
2764
- $replace = $this->start()->i18n($date_format);
2765
- }
2766
- }
2767
- return $replace;
2768
- }
2769
-
2770
- /**********************************************************
2771
- * RECURRENCE METHODS
2772
- ***********************************************************/
2773
-
2774
- /**
2775
- * Returns true if this is a recurring event.
2776
- * @return boolean
2777
- */
2778
- function is_recurring(){
2779
- return $this->post_type == 'event-recurring' && get_option('dbem_recurrence_enabled');
2780
- }
2781
- /**
2782
- * Will return true if this individual event is part of a set of events that recur
2783
- * @return boolean
2784
- */
2785
- function is_recurrence(){
2786
- return ( $this->recurrence_id > 0 && get_option('dbem_recurrence_enabled') );
2787
- }
2788
- /**
2789
- * Returns if this is an individual event and is not a recurrence
2790
- * @return boolean
2791
- */
2792
- function is_individual(){
2793
- return ( !$this->is_recurring() && !$this->is_recurrence() );
2794
- }
2795
-
2796
- /**
2797
- * Gets the event recurrence template, which is an EM_Event object (based off an event-recurring post)
2798
- * @return EM_Event
2799
- */
2800
- function get_event_recurrence(){
2801
- if(!$this->is_recurring()){
2802
- return em_get_event($this->recurrence_id, 'event_id');
2803
- }else{
2804
- return $this;
2805
- }
2806
- }
2807
-
2808
- function get_detach_url(){
2809
- return admin_url().'admin.php?event_id='.$this->event_id.'&amp;action=event_detach&amp;_wpnonce='.wp_create_nonce('event_detach_'.get_current_user_id().'_'.$this->event_id);
2810
- }
2811
-
2812
- function get_attach_url($recurrence_id){
2813
- return admin_url().'admin.php?undo_id='.$recurrence_id.'&amp;event_id='.$this->event_id.'&amp;action=event_attach&amp;_wpnonce='.wp_create_nonce('event_attach_'.get_current_user_id().'_'.$this->event_id);
2814
- }
2815
-
2816
- /**
2817
- * Returns if this is an individual event and is not recurring or a recurrence
2818
- * @return boolean
2819
- */
2820
- function detach(){
2821
- global $wpdb;
2822
- if( $this->is_recurrence() && !$this->is_recurring() && $this->can_manage('edit_recurring_events','edit_others_recurring_events') ){
2823
- //remove recurrence id from post meta and index table
2824
- $url = $this->get_attach_url($this->recurrence_id);
2825
- $wpdb->update(EM_EVENTS_TABLE, array('recurrence_id'=>null), array('event_id' => $this->event_id));
2826
- delete_post_meta($this->post_id, '_recurrence_id');
2827
- $this->feedback_message = __('Event detached.','events-manager') . ' <a href="'.$url.'">'.__('Undo','events-manager').'</a>';
2828
- $this->recurrence_id = 0;
2829
- return apply_filters('em_event_detach', true, $this);
2830
- }
2831
- $this->add_error(__('Event could not be detached.','events-manager'));
2832
- return apply_filters('em_event_detach', false, $this);
2833
- }
2834
-
2835
- /**
2836
- * Returns if this is an individual event and is not recurring or a recurrence
2837
- * @return boolean
2838
- */
2839
- function attach($recurrence_id){
2840
- global $wpdb;
2841
- if( !$this->is_recurrence() && !$this->is_recurring() && is_numeric($recurrence_id) && $this->can_manage('edit_recurring_events','edit_others_recurring_events') ){
2842
- //add recurrence id to post meta and index table
2843
- $wpdb->update(EM_EVENTS_TABLE, array('recurrence_id'=>$recurrence_id), array('event_id' => $this->event_id));
2844
- update_post_meta($this->post_id, '_recurrence_id', $recurrence_id);
2845
- $this->feedback_message = __('Event re-attached to recurrence.','events-manager');
2846
- return apply_filters('em_event_attach', true, $recurrence_id, $this);
2847
- }
2848
- $this->add_error(__('Event could not be attached.','events-manager'));
2849
- return apply_filters('em_event_attach', false, $recurrence_id, $this);
2850
- }
2851
-
2852
- /**
2853
- * Saves events and replaces old ones. Returns true if sucecssful or false if not.
2854
- * @return boolean
2855
- */
2856
- function save_events() {
2857
- global $wpdb;
2858
- if( !$this->can_manage('edit_events','edit_others_events') ) return apply_filters('em_event_save_events', false, $this, array(), array());
2859
- $event_ids = $post_ids = $event_dates = $events = array();
2860
- if( $this->is_published() || 'future' == $this->post_status ){
2861
- $result = false;
2862
- //check if there's any events already created, if not (such as when an event is first submitted for approval and then published), force a reschedule.
2863
- if( $wpdb->get_var('SELECT COUNT(event_id) FROM '.EM_EVENTS_TABLE.' WHERE recurrence_id='. absint($this->event_id)) == 0 ){
2864
- $this->recurring_reschedule = true;
2865
- }
2866
- do_action('em_event_save_events_pre', $this); //actions/filters only run if event is recurring
2867
- //Make template event index, post, and meta (we change event dates, timestamps, rsvp dates and other recurrence-relative info whilst saving each event recurrence)
2868
- $event = $this->to_array(true); //event template - for index
2869
- if( !empty($event['event_attributes']) ) $event['event_attributes'] = serialize($event['event_attributes']);
2870
- $post_fields = $wpdb->get_row('SELECT * FROM '.$wpdb->posts.' WHERE ID='.$this->post_id, ARRAY_A); //post to copy
2871
- $post_fields['post_type'] = 'event'; //make sure we'll save events, not recurrence templates
2872
- $meta_fields_map = $wpdb->get_results('SELECT meta_key,meta_value FROM '.$wpdb->postmeta.' WHERE post_id='.$this->post_id, ARRAY_A);
2873
- $meta_fields = array();
2874
- //convert meta_fields into a cleaner array
2875
- foreach($meta_fields_map as $meta_data){
2876
- $meta_fields[$meta_data['meta_key']] = $meta_data['meta_value'];
2877
- }
2878
- if( isset($meta_fields['_edit_last']) ) unset($meta_fields['_edit_last']);
2879
- if( isset($meta_fields['_edit_lock']) ) unset($meta_fields['_edit_lock']);
2880
- //remove id and we have a event template to feed to wpdb insert
2881
- unset($event['event_id'], $event['post_id']);
2882
- unset($post_fields['ID']);
2883
- unset($meta_fields['_event_id']);
2884
- if( isset($meta_fields['_post_id']) ) unset($meta_fields['_post_id']); //legacy bugfix, post_id was never needed in meta table
2885
- //remove recurrence meta info we won't need in events
2886
- foreach( $this->recurrence_fields as $recurrence_field){
2887
- $event[$recurrence_field] = null;
2888
- if( isset($meta_fields['_'.$recurrence_field]) ) unset($meta_fields['_'.$recurrence_field]);
2889
- }
2890
- //Set the recurrence ID
2891
- $event['recurrence_id'] = $meta_fields['_recurrence_id'] = $this->event_id;
2892
- $event['recurrence'] = 0;
2893
-
2894
- //Let's start saving!
2895
- $event_saves = $meta_inserts = array();
2896
- $recurring_date_format = apply_filters('em_event_save_events_format', 'Y-m-d');
2897
- $post_name = $this->sanitize_recurrence_slug( $post_fields['post_name'], $this->start()->format($recurring_date_format)); //template sanitized post slug since we'll be using this
2898
- //First thing - times. If we're changing event times, we need to delete all events and recreate them with the right times, no other way
2899
-
2900
- if( $this->recurring_reschedule ){
2901
- $this->delete_events(); //Delete old events beforehand, this will change soon
2902
- $matching_days = $this->get_recurrence_days(); //Get days where events recur
2903
- $event['event_date_created'] = current_time('mysql'); //since the recurrences are recreated
2904
- unset($event['event_date_modified']);
2905
- if( count($matching_days) > 0 ){
2906
- //first save event post data
2907
- $EM_DateTime = $this->start()->copy();
2908
- foreach( $matching_days as $day ) {
2909
- //set start date/time to $EM_DateTime for relative use further on
2910
- $EM_DateTime->setTimestamp($day)->setTimeString($event['event_start_time']);
2911
- $start_timestamp = $EM_DateTime->getTimestamp(); //for quick access later
2912
- //rewrite post fields if needed
2913
- //set post slug, which may need to be sanitized for length as we pre/postfix a date for uniqueness
2914
- $event_slug_date = $EM_DateTime->format( $recurring_date_format );
2915
- $event_slug = $this->sanitize_recurrence_slug($post_name, $event_slug_date);
2916
- $event_slug = apply_filters('em_event_save_events_recurrence_slug', $event_slug.'-'.$event_slug_date, $event_slug, $event_slug_date, $day, $this); //use this instead
2917
- $post_fields['post_name'] = $event['event_slug'] = apply_filters('em_event_save_events_slug', $event_slug, $post_fields, $day, $matching_days, $this); //deprecated filter
2918
- //set start date
2919
- $event['event_start_date'] = $meta_fields['_event_start_date'] = $EM_DateTime->getDate();
2920
- $event['event_start'] = $meta_fields['_event_start'] = $EM_DateTime->getDateTime(true);
2921
- //add rsvp date/time restrictions
2922
- if( !empty($this->recurrence_rsvp_days) && is_numeric($this->recurrence_rsvp_days) ){
2923
- if( $this->recurrence_rsvp_days > 0 ){
2924
- $event_rsvp_date = $EM_DateTime->copy()->add('P'.absint($this->recurrence_rsvp_days).'D')->getDate(); //cloned so original object isn't modified
2925
- }elseif($this->recurrence_rsvp_days < 0 ){
2926
- $event_rsvp_date = $EM_DateTime->copy()->sub('P'.absint($this->recurrence_rsvp_days).'D')->getDate(); //cloned so original object isn't modified
2927
- }else{
2928
- $event_rsvp_date = $EM_DateTime->getDate();
2929
- }
2930
- $event['event_rsvp_date'] = $meta_fields['_event_rsvp_date'] = $event_rsvp_date;
2931
- }else{
2932
- $event['event_rsvp_date'] = $meta_fields['_event_rsvp_date'] = $event['event_start_date'];
2933
- }
2934
- $event['event_rsvp_time'] = $meta_fields['_event_rsvp_time'] = $event['event_rsvp_time'];
2935
- //set end date
2936
- $EM_DateTime->setTimeString($event['event_end_time']);
2937
- if($this->recurrence_days > 0){
2938
- //$EM_DateTime modified here, and used further down for UTC end date
2939
- $event['event_end_date'] = $meta_fields['_event_end_date'] = $EM_DateTime->add('P'.$this->recurrence_days.'D')->getDate();
2940
- }else{
2941
- $event['event_end_date'] = $meta_fields['_event_end_date'] = $event['event_start_date'];
2942
- }
2943
- $end_timestamp = $EM_DateTime->getTimestamp(); //for quick access later
2944
- $event['event_end'] = $meta_fields['_event_end'] = $EM_DateTime->getDateTime(true);
2945
- //add extra date/time post meta
2946
- $meta_fields['_event_start_local'] = $event['event_start_date'].' '.$event['event_start_time'];
2947
- $meta_fields['_event_end_local'] = $event['event_end_date'].' '.$event['event_end_time'];
2948
- //Deprecated meta fields
2949
- $site_data = get_site_option('dbem_data');
2950
- if( !empty($site_data['updates']['timezone-backcompat']) ){
2951
- $meta_fields['_start_ts'] = $start_timestamp;
2952
- $meta_fields['_end_ts'] = $end_timestamp;
2953
- }
2954
- //create the event
2955
- if( $wpdb->insert($wpdb->posts, $post_fields ) ){
2956
- $event['post_id'] = $post_id = $post_ids[$start_timestamp] = $wpdb->insert_id; //post id saved into event and also as a var for later user
2957
- // Set GUID and event slug as per wp_insert_post
2958
- $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_id ) ), array('ID'=>$post_id) );
2959
- //insert into events index table
2960
- $event_saves[] = $wpdb->insert(EM_EVENTS_TABLE, $event);
2961
- $event_ids[$post_id] = $event_id = $wpdb->insert_id;
2962
- $event_dates[$event_id] = $start_timestamp;
2963
- //create the meta inserts for each event
2964
- $meta_fields['_event_id'] = $event_id;
2965
- foreach($meta_fields as $meta_key => $meta_val){
2966
- $meta_inserts[] = $wpdb->prepare("(%d, %s, %s)", array($post_id, $meta_key, $meta_val));
2967
- }
2968
- }else{
2969
- $event_saves[] = false;
2970
- }
2971
- //if( EM_DEBUG ){ echo "Entering recurrence " . date("D d M Y", $day)."<br/>"; }
2972
- }
2973
- //insert the metas in one go, faster than one by one
2974
- if( count($meta_inserts) > 0 ){
2975
- $result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
2976
- if($result === false){
2977
- $this->add_error(esc_html__('There was a problem adding custom fields to your recurring events.','events-manager'));
2978
- }
2979
- }
2980
- }else{
2981
- $this->add_error(esc_html__('You have not defined a date range long enough to create a recurrence.','events-manager'));
2982
- $result = false;
2983
- }
2984
- }else{
2985
- //we go through all event main data and meta data, we delete and recreate all meta data
2986
- //now unset some vars we don't need to deal with since we're just updating data in the wp_em_events and posts table
2987
- unset( $event['event_date_created'], $event['recurrence_id'], $event['recurrence'], $event['event_start_date'], $event['event_end_date'], $event['event_parent'] );
2988
- $event['event_date_modified'] = current_time('mysql'); //since the recurrences are modified but not recreated
2989
- unset( $post_fields['comment_count'], $post_fields['guid'], $post_fields['menu_order']);
2990
- unset( $meta_fields['_event_parent'] ); // we'll ignore this and add it manually
2991
- // clean the meta fields array to contain only the fields we actually need to overwrite i.e. delete and recreate, to avoid deleting unecessary individula recurrence data
2992
- $exclude_meta_update_keys = apply_filters('em_event_save_events_exclude_update_meta_keys', array('_parent_id'), $this);
2993
- //now we go through the recurrences and check whether things relative to dates need to be changed
2994
- $events = EM_Events::get( array('recurrence'=>$this->event_id, 'scope'=>'all', 'status'=>'everything', 'array' => true ) );
2995
- foreach($events as $event_array){ /* @var $EM_Event EM_Event */
2996
- //set new start/end times to obtain accurate timestamp according to timezone and DST
2997
- $EM_DateTime = $this->start()->copy()->modify($event_array['event_start_date']. ' ' . $event_array['event_start_time']);
2998
- $start_timestamp = $EM_DateTime->getTimestamp();
2999
- $event['event_start'] = $meta_fields['_event_start'] = $EM_DateTime->getDateTime(true);
3000
- $end_timestamp = $EM_DateTime->modify($event_array['event_end_date']. ' ' . $event_array['event_end_time'])->getTimestamp();
3001
- $event['event_end'] = $meta_fields['_event_end'] = $EM_DateTime->getDateTime(true);
3002
- //set indexes for reference further down
3003
- $event_ids[$event_array['post_id']] = $event_array['event_id'];
3004
- $event_dates[$event_array['event_id']] = $start_timestamp;
3005
- $post_ids[$start_timestamp] = $event_array['post_id'];
3006
- //do we need to change the slugs?
3007
- //(re)set post slug, which may need to be sanitized for length as we pre/postfix a date for uniqueness
3008
- $EM_DateTime->setTimestamp($start_timestamp);
3009
- $event_slug_date = $EM_DateTime->format( $recurring_date_format );
3010
- $event_slug = $this->sanitize_recurrence_slug($post_name, $event_slug_date);
3011
- $event_slug = apply_filters('em_event_save_events_recurrence_slug', $event_slug.'-'.$event_slug_date, $event_slug, $event_slug_date, $start_timestamp, $this); //use this instead
3012
- $post_fields['post_name'] = $event['event_slug'] = apply_filters('em_event_save_events_slug', $event_slug, $post_fields, $start_timestamp, array(), $this); //deprecated filter
3013
- //adjust certain meta information relative to dates and times
3014
- if( !empty($this->recurrence_rsvp_days) && is_numeric($this->recurrence_rsvp_days) ){
3015
- $event_rsvp_days = $this->recurrence_rsvp_days >= 0 ? '+'. $this->recurrence_rsvp_days: $this->recurrence_rsvp_days;
3016
- $event_rsvp_date = $EM_DateTime->setTimestamp($start_timestamp)->modify($event_rsvp_days.' days')->getDate();
3017
- $event['event_rsvp_date'] = $meta_fields['_event_rsvp_date'] = $event_rsvp_date;
3018
- }else{
3019
- $event['event_rsvp_date'] = $meta_fields['_event_rsvp_date'] = $event_array['event_start_date'];
3020
- }
3021
- $event['event_rsvp_time'] = $meta_fields['_event_rsvp_time'] = $event['event_rsvp_time'];
3022
- //add meta fields we deleted and are specific to this event
3023
- $meta_fields['_event_start_date'] = $event_array['event_start_date'];
3024
- $meta_fields['_event_start_local'] = $event_array['event_start_date']. ' ' . $event_array['event_start_time'];
3025
- $meta_fields['_event_end_date'] = $event_array['event_end_date'];
3026
- $meta_fields['_event_end_local'] = $event_array['event_end_date']. ' ' . $event_array['event_end_time'];
3027
- $site_data = get_site_option('dbem_data');
3028
- if( !empty($site_data['updates']['timezone-backcompat']) ){
3029
- $meta_fields['_start_ts'] = $start_timestamp;
3030
- $meta_fields['_end_ts'] = $end_timestamp;
3031
- }
3032
- //overwrite event and post tables
3033
- $wpdb->update(EM_EVENTS_TABLE, $event, array('event_id' => $event_array['event_id']));
3034
- $wpdb->update($wpdb->posts, $post_fields, array('ID' => $event_array['post_id']));
3035
- //save meta field data for insertion in one go
3036
- foreach($meta_fields as $meta_key => $meta_val){
3037
- $meta_inserts[] = $wpdb->prepare("(%d, %s, %s)", array($event_array['post_id'], $meta_key, $meta_val));
3038
- }
3039
- }
3040
- // delete all meta we'll be updating
3041
- if( !empty($post_ids) ){
3042
- $sql = "DELETE FROM {$wpdb->postmeta} WHERE post_id IN (".implode(',', $post_ids).")";
3043
- if( !empty($exclude_meta_update_keys) ){
3044
- $sql .= " AND meta_key NOT IN (";
3045
- $i = 0;
3046
- foreach( $exclude_meta_update_keys as $k ){
3047
- $sql.= ( $i > 0 ) ? ',%s' : '%s';
3048
- $i++;
3049
- }
3050
- $sql .= ")";
3051
- $sql = $wpdb->prepare($sql, $exclude_meta_update_keys);
3052
- }
3053
- $wpdb->query($sql);
3054
- }
3055
- // insert the metas in one go, faster than one by one
3056
- if( count($meta_inserts) > 0 ){
3057
- $result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
3058
- if($result === false){
3059
- $this->add_error(esc_html__('There was a problem adding custom fields to your recurring events.','events-manager'));
3060
- }
3061
- }
3062
- }
3063
- //Next - Bookings. If we're completely rescheduling or just recreating bookings, we're deleting them and starting again
3064
- if( ($this->recurring_reschedule || $this->recurring_recreate_bookings) && $this->recurring_recreate_bookings !== false && EM_ML::is_original($this) ){ //if set specifically to false, we skip bookings entirely (ML translations for example)
3065
- //first, delete all bookings & tickets if we haven't done so during the reschedule above - something we'll want to change later if possible so bookings can be modified without losing all data
3066
- if( !$this->recurring_reschedule ){
3067
- //create empty EM_Bookings and EM_Tickets objects to circumvent extra loading of data and SQL queries
3068
- $EM_Bookings = new EM_Bookings();
3069
- $EM_Tickets = new EM_Tickets();
3070
- foreach($events as $event){ //$events was defined in the else statement above so we reuse it
3071
- if($event['recurrence_id'] == $this->event_id){
3072
- //trick EM_Bookings and EM_Tickets to think it was loaded, and make use of optimized delete functions since 5.7.3.4
3073
- $EM_Bookings->event_id = $EM_Tickets->event_id = $event['event_id'];
3074
- $EM_Bookings->delete();
3075
- $EM_Tickets->delete();
3076
- }
3077
- }
3078
- }
3079
- //if bookings hasn't been disabled, delete it all
3080
- if( $this->event_rsvp ){
3081
- $meta_inserts = array();
3082
- foreach($this->get_tickets() as $EM_Ticket){
3083
- /* @var $EM_Ticket EM_Ticket */
3084
- //get array, modify event id and insert
3085
- $ticket = $EM_Ticket->to_array();
3086
- //empty cut-off dates of ticket, add them at per-event level
3087
- unset($ticket['ticket_start']); unset($ticket['ticket_end']);
3088
- if( !empty($ticket['ticket_meta']['recurrences']) ){
3089
- $ticket_meta_recurrences = $ticket['ticket_meta']['recurrences'];
3090
- unset($ticket['ticket_meta']['recurrences']);
3091
- }
3092
- //unset id
3093
- unset($ticket['ticket_id']);
3094
- $ticket['ticket_parent'] = $EM_Ticket->ticket_id;
3095
- //clean up ticket values
3096
- foreach($ticket as $k => $v){
3097
- if( empty($v) && $k != 'ticket_name' ){
3098
- $ticket[$k] = 'NULL';
3099
- }else{
3100
- $data_type = !empty($EM_Ticket->fields[$k]['type']) ? $EM_Ticket->fields[$k]['type']:'%s';
3101
- if(is_array($ticket[$k])) $v = serialize($ticket[$k]);
3102
- $ticket[$k] = $wpdb->prepare($data_type,$v);
3103
- }
3104
- }
3105
- //prep ticket meta for insertion with relative info for each event date
3106
- $EM_DateTime = $this->start()->copy();
3107
- foreach($event_ids as $event_id){
3108
- $ticket['event_id'] = $event_id;
3109
- $ticket['ticket_start'] = $ticket['ticket_end'] = 'NULL';
3110
- //sort out cut-of dates
3111
- if( !empty($ticket_meta_recurrences) ){
3112
- $EM_DateTime->setTimestamp($event_dates[$event_id]); //by using EM_DateTime we'll generate timezone aware dates
3113
- if( array_key_exists('start_days', $ticket_meta_recurrences) && $ticket_meta_recurrences['start_days'] !== false && $ticket_meta_recurrences['start_days'] !== null ){
3114
- $ticket_start_days = $ticket_meta_recurrences['start_days'] >= 0 ? '+'. $ticket_meta_recurrences['start_days']: $ticket_meta_recurrences['start_days'];
3115
- $ticket_start_date = $EM_DateTime->modify($ticket_start_days.' days')->getDate();
3116
- $ticket['ticket_start'] = "'". $ticket_start_date . ' '. $ticket_meta_recurrences['start_time'] ."'";
3117
- }
3118
- if( array_key_exists('end_days', $ticket_meta_recurrences) && $ticket_meta_recurrences['end_days'] !== false && $ticket_meta_recurrences['end_days'] !== null ){
3119
- $ticket_end_days = $ticket_meta_recurrences['end_days'] >= 0 ? '+'. $ticket_meta_recurrences['end_days']: $ticket_meta_recurrences['end_days'];
3120
- $EM_DateTime->setTimestamp($event_dates[$event_id]);
3121
- $ticket_end_date = $EM_DateTime->modify($ticket_end_days.' days')->getDate();
3122
- $ticket['ticket_end'] = "'". $ticket_end_date . ' '. $ticket_meta_recurrences['end_time'] . "'";
3123
- }
3124
- }
3125
- //add insert data
3126
- $meta_inserts[] = "(".implode(",",$ticket).")";
3127
- }
3128
- }
3129
- $keys = "(".implode(",",array_keys($ticket)).")";
3130
- $values = implode(',',$meta_inserts);
3131
- $sql = "INSERT INTO ".EM_TICKETS_TABLE." $keys VALUES $values";
3132
- $result = $wpdb->query($sql);
3133
- }
3134
- }elseif( $this->recurring_delete_bookings ){
3135
- //create empty EM_Bookings and EM_Tickets objects to circumvent extra loading of data and SQL queries
3136
- $EM_Bookings = new EM_Bookings();
3137
- $EM_Tickets = new EM_Tickets();
3138
- foreach($events as $event){ //$events was defined in the else statement above so we reuse it
3139
- if($event['recurrence_id'] == $this->event_id){
3140
- //trick EM_Bookings and EM_Tickets to think it was loaded, and make use of optimized delete functions since 5.7.3.4
3141
- $EM_Bookings->event_id = $EM_Tickets->event_id = $event['event_id'];
3142
- $EM_Bookings->delete();
3143
- $EM_Tickets->delete();
3144
- }
3145
- }
3146
- }
3147
- //copy the event tags and categories, which are automatically deleted/recreated by WP and EM_Categories
3148
- foreach( self::get_taxonomies() as $tax_name => $tax_data ){
3149
- //In MS Global mode, we also save category meta information for global lookups so we use our objects
3150
- if( $tax_name == 'category' ){
3151
- //we save index data for each category in in MS Global mode
3152
- foreach($event_ids as $post_id => $event_id){
3153
- //set and trick category event and post ids so it saves to the right place
3154
- $this->get_categories()->event_id = $event_id;
3155
- $this->get_categories()->post_id = $post_id;
3156
- $this->get_categories()->save();
3157
- }
3158
- $this->get_categories()->event_id = $this->event_id;
3159
- $this->get_categories()->post_id = $this->post_id;
3160
- }else{
3161
- //general taxonomies including event tags
3162
- $terms = get_the_terms( $this->post_id, $tax_data['name']);
3163
- $term_slugs = array();
3164
- if( is_array($terms) ){
3165
- foreach($terms as $term){
3166
- if( !empty($term->slug) ) $term_slugs[] = $term->slug; //save of category will soft-fail if slug is empty
3167
- }
3168
- }
3169
- foreach($post_ids as $post_id){
3170
- wp_set_object_terms($post_id, $term_slugs, $tax_data['name']);
3171
- }
3172
- }
3173
- }
3174
- if( 'future' == $this->post_status ){
3175
- $time = strtotime( $this->post_date_gmt . ' GMT' );
3176
- foreach( $post_ids as $post_id ){
3177
- if( !$this->recurring_reschedule ){
3178
- wp_clear_scheduled_hook( 'publish_future_post', array( $post_id ) ); // clear anything else in the system
3179
- }
3180
- wp_schedule_single_event( $time, 'publish_future_post', array( $post_id ) );
3181
- }
3182
- }
3183
- return apply_filters('em_event_save_events', !in_array(false, $event_saves) && $result !== false, $this, $event_ids, $post_ids);
3184
- }elseif( !$this->is_published() && $this->get_previous_status() != $this->get_status() && defined('EM_FORCE_RECURRENCES_SAVE') && EM_FORCE_RECURRENCES_SAVE ){
3185
- $this->set_status_events($this->get_status());
3186
- }
3187
- return apply_filters('em_event_save_events', false, $this, $event_ids, $post_ids);
3188
- }
3189
-
3190
- /**
3191
- * Ensures a post slug is the correct length when the date postfix is added, which takes into account multibyte and url-encoded characters and WP unique suffixes.
3192
- * If a url-encoded slug is nearing 200 characters (the data character limit in the db table), adding a date to the end will cause issues when saving to the db.
3193
- * This function checks if the final slug is longer than 200 characters and removes one entire character rather than part of a hex-encoded character, until the right size is met.
3194
- * @param string $post_name
3195
- * @param string $post_slug_postfix
3196
- * @return string
3197
- */
3198
- public function sanitize_recurrence_slug( $post_name, $post_slug_postfix ){
3199
- if( strlen($post_name.'-'.$post_slug_postfix) > 200 ){
3200
- if( preg_match('/^(.+)(\-[0-9]+)$/', $post_name, $post_name_parts) ){
3201
- $post_name_decoded = urldecode($post_name_parts[1]);
3202
- $post_name_suffix = $post_name_parts[2];
3203
- }else{
3204
- $post_name_decoded = urldecode($post_name);
3205
- $post_name_suffix = '';
3206
- }
3207
- $post_name_maxlength = 200 - strlen( $post_name_suffix . '-' . $post_slug_postfix);
3208
- if ( $post_name_parts[0] === $post_name_decoded.$post_name_suffix ){
3209
- $post_name = substr( $post_name_decoded, 0, $post_name_maxlength );
3210
- }else{
3211
- $post_name = utf8_uri_encode( $post_name_decoded, $post_name_maxlength );
3212
- }
3213
- $post_name = rtrim( $post_name, '-' ). $post_name_suffix;
3214
- }
3215
- return apply_filters('em_event_sanitize_recurrence_slug', $post_name, $post_slug_postfix, $this);
3216
- }
3217
-
3218
- /**
3219
- * Removes all recurrences of a recurring event.
3220
- * @return null
3221
- */
3222
- function delete_events(){
3223
- global $wpdb;
3224
- do_action('em_event_delete_events_pre', $this);
3225
- //So we don't do something we'll regret later, we could just supply the get directly into the delete, but this is safer
3226
- $result = false;
3227
- $events_array = array();
3228
- if( $this->can_manage('delete_events', 'delete_others_events') ){
3229
- //delete events from em_events table
3230
- $sql = $wpdb->prepare('SELECT event_id FROM '.EM_EVENTS_TABLE.' WHERE (recurrence!=1 OR recurrence IS NULL) AND recurrence_id=%d', $this->event_id);
3231
- $event_ids = $wpdb->get_col( $sql );
3232
- // go through each event and delete individually so individual hooks are fired appropriately
3233
- foreach($event_ids as $event_id){
3234
- $EM_Event = em_get_event( $event_id );
3235
- if($EM_Event->recurrence_id == $this->event_id){
3236
- $EM_Event->delete(true);
3237
- $events_array[] = $EM_Event;
3238
- }
3239
- }
3240
- $result = !empty($events_array) || (is_array($event_ids) && empty($event_ids)); // success if we deleted something, or if there was nothing to delete in the first place
3241
- }
3242
- $result = apply_filters('delete_events', $result, $this, $events_array); //Deprecated, use em_event_delete_events
3243
- return apply_filters('em_event_delete_events', $result, $this, $events_array);
3244
- }
3245
-
3246
- /**
3247
- * Returns the days that match the recurrance array passed (unix timestamps)
3248
- * @param array $recurrence
3249
- * @return array
3250
- */
3251
- function get_recurrence_days(){
3252
- //get timestampes for start and end dates, both at 12AM
3253
- $start_date = $this->start()->copy()->setTime(0,0,0)->getTimestamp();
3254
- $end_date = $this->end()->copy()->setTime(0,0,0)->getTimestamp();
3255
-
3256
- $weekdays = explode(",", $this->recurrence_byday); //what days of the week (or if monthly, one value at index 0)
3257
- $matching_days = array(); //the days we'll be returning in timestamps
3258
-
3259
- //generate matching dates based on frequency type
3260
- switch ( $this->recurrence_freq ){ /* @var EM_DateTime $current_date */
3261
- case 'daily':
3262
- //If daily, it's simple. Get start date, add interval timestamps to that and create matching day for each interval until end date.
3263
- $current_date = $this->start()->copy()->setTime(0,0,0);
3264
- while( $current_date->getTimestamp() <= $end_date ){
3265
- $matching_days[] = $current_date->getTimestamp();
3266
- $current_date->add('P'. $this->recurrence_interval .'D');
3267
- }
3268
- break;
3269
- case 'weekly':
3270
- //sort out week one, get starting days and then days that match time span of event (i.e. remove past events in week 1)
3271
- $current_date = $this->start()->copy()->setTime(0,0,0);
3272
- $start_of_week = get_option('start_of_week'); //Start of week depends on WordPress
3273
- //then get the timestamps of weekdays during this first week, regardless if within event range
3274
- $start_weekday_dates = array(); //Days in week 1 where there would events, regardless of event date range
3275
- for($i = 0; $i < 7; $i++){
3276
- if( in_array( $current_date->format('w'), $weekdays) ){
3277
- $start_weekday_dates[] = $current_date->getTimestamp(); //it's in our starting week day, so add it
3278
- }
3279
- $current_date->add('P1D'); //add a day
3280
- }
3281
- //for each day of eventful days in week 1, add 7 days * weekly intervals
3282
- foreach ($start_weekday_dates as $weekday_date){
3283
- //Loop weeks by interval until we reach or surpass end date
3284
- $current_date->setTimestamp($weekday_date);
3285
- while($current_date->getTimestamp() <= $end_date){
3286
- if( $current_date->getTimestamp() >= $start_date && $current_date->getTimestamp() <= $end_date ){
3287
- $matching_days[] = $current_date->getTimestamp();
3288
- }
3289
- $current_date->add('P'. ($this->recurrence_interval * 7 ) .'D');
3290
- }
3291
- }//done!
3292
- break;
3293
- case 'monthly':
3294
- //loop months starting this month by intervals
3295
- $current_date = $this->start()->copy();
3296
- $current_date->modify($current_date->format('Y-m-01 00:00:00')); //Start date on first day of month, done this way to avoid 'first day of' issues in PHP < 5.6
3297
- while( $current_date->getTimestamp() <= $this->end()->getTimestamp() ){
3298
- $last_day_of_month = $current_date->format('t');
3299
- //Now find which day we're talking about
3300
- $current_week_day = $current_date->format('w');
3301
- $matching_month_days = array();
3302
- //Loop through days of this years month and save matching days to temp array
3303
- for($day = 1; $day <= $last_day_of_month; $day++){
3304
- if((int) $current_week_day == $this->recurrence_byday){
3305
- $matching_month_days[] = $day;
3306
- }
3307
- $current_week_day = ($current_week_day < 6) ? $current_week_day+1 : 0;
3308
- }
3309
- //Now grab from the array the x day of the month
3310
- $matching_day = false;
3311
- if( $this->recurrence_byweekno > 0 ){
3312
- //date might not exist (e.g. fifth Sunday of a month) so only add if it exists
3313
- if( !empty($matching_month_days[$this->recurrence_byweekno-1]) ){
3314
- $matching_day = $matching_month_days[$this->recurrence_byweekno-1];
3315
- }
3316
- }else{
3317
- //last day of month, so we pop the last matching day
3318
- $matching_day = array_pop($matching_month_days);
3319
- }
3320
- //if we have a matching day, get the timestamp, make sure it's within our start/end dates for the event, and add to array if it is
3321
- if( !empty($matching_day) ){
3322
- $matching_date = $current_date->setDate( $current_date->format('Y'), $current_date->format('m'), $matching_day )->getTimestamp();
3323
- if($matching_date >= $start_date && $matching_date <= $end_date){
3324
- $matching_days[] = $matching_date;
3325
- }
3326
- }
3327
- //add the monthly interval to the current date, but set to 1st of current month first so we don't jump months where $current_date is 31st and next month there's no 31st (so a month is skipped)
3328
- $current_date->modify($current_date->format('Y-m-01')); //done this way to avoid 'first day of ' PHP < 5.6 issues
3329
- $current_date->add('P'.$this->recurrence_interval.'M');
3330
- }
3331
- break;
3332
- case 'yearly':
3333
- //Yearly is easy, we get the start date as a cloned EM_DateTime and keep adding a year until it surpasses the end EM_DateTime value.
3334
- $EM_DateTime = $this->start()->copy();
3335
- while( $EM_DateTime <= $this->end() ){
3336
- $matching_days[] = $EM_DateTime->getTimestamp();
3337
- $EM_DateTime->add('P'.absint($this->recurrence_interval).'Y');
3338
- }
3339
- break;
3340
- }
3341
- sort($matching_days);
3342
- return apply_filters('em_events_get_recurrence_days', $matching_days, $this);
3343
- }
3344
-
3345
- /**
3346
- * If event is recurring, set recurrences to same status as template
3347
- * @param $status
3348
- */
3349
- function set_status_events($status){
3350
- //give sub events same status
3351
- global $wpdb;
3352
- //get post and event ids of recurrences
3353
- $post_ids = $event_ids = array();
3354
- $events_array = EM_Events::get( array('recurrence'=>$this->event_id, 'scope'=>'all', 'status'=>false, 'array'=>true) ); //only get recurrences that aren't trashed or drafted
3355
- foreach( $events_array as $event_array ){
3356
- $post_ids[] = absint($event_array['post_id']);
3357
- $event_ids[] = absint($event_array['event_id']);
3358
- }
3359
- if( !empty($post_ids) ){
3360
- //decide on what status to set and update wp_posts in the process
3361
- if($status === null){
3362
- $set_status='NULL'; //draft post
3363
- $post_status = 'draft'; //set post status in this instance
3364
- }elseif( $status == -1 ){ //trashed post
3365
- $set_status = -1;
3366
- $post_status = 'trash'; //set post status in this instance
3367
- }else{
3368
- $set_status = $status ? 1:0; //published or pending post
3369
- $post_status = $set_status ? 'publish':'pending';
3370
- }
3371
- if( EM_MS_GLOBAL ) switch_to_blog( $this->blog_id );
3372
- $result = $wpdb->query( $wpdb->prepare("UPDATE ".$wpdb->posts." SET post_status=%s WHERE ID IN (". implode(',', $post_ids) .')', array($post_status)) );
3373
- restore_current_blog();
3374
- $result = $result && $wpdb->query( $wpdb->prepare("UPDATE ".EM_EVENTS_TABLE." SET event_status=%s WHERE event_id IN (". implode(',', $event_ids) .')', array($set_status)) );
3375
- }
3376
- return apply_filters('em_event_set_status_events', $result !== false, $status, $this, $event_ids, $post_ids);
3377
- }
3378
-
3379
- /**
3380
- * Returns a string representation of this recurrence. Will return false if not a recurrence
3381
- * @return string
3382
- */
3383
- function get_recurrence_description() {
3384
- $EM_Event_Recurring = $this->get_event_recurrence();
3385
- $recurrence = $this->to_array();
3386
- $weekdays_name = array( translate('Sunday'),translate('Monday'),translate('Tuesday'),translate('Wednesday'),translate('Thursday'),translate('Friday'),translate('Saturday'));
3387
- $monthweek_name = array('1' => __('the first %s of the month', 'events-manager'),'2' => __('the second %s of the month', 'events-manager'), '3' => __('the third %s of the month', 'events-manager'), '4' => __('the fourth %s of the month', 'events-manager'), '5' => __('the fifth %s of the month', 'events-manager'), '-1' => __('the last %s of the month', 'events-manager'));
3388
- $output = sprintf (__('From %1$s to %2$s', 'events-manager'), $EM_Event_Recurring->event_start_date, $EM_Event_Recurring->event_end_date).", ";
3389
- if ($EM_Event_Recurring->recurrence_freq == 'daily') {
3390
- $freq_desc =__('everyday', 'events-manager');
3391
- if ($EM_Event_Recurring->recurrence_interval > 1 ) {
3392
- $freq_desc = sprintf (__("every %s days", 'events-manager'), $EM_Event_Recurring->recurrence_interval);
3393
- }
3394
- }elseif ($EM_Event_Recurring->recurrence_freq == 'weekly') {
3395
- $weekday_array = explode(",", $EM_Event_Recurring->recurrence_byday);
3396
- $natural_days = array();
3397
- foreach($weekday_array as $day){
3398
- array_push($natural_days, $weekdays_name[$day]);
3399
- }
3400
- $output .= implode(", ", $natural_days);
3401
- $freq_desc = " " . __("every week", 'events-manager');
3402
- if ($EM_Event_Recurring->recurrence_interval > 1 ) {
3403
- $freq_desc = " ".sprintf (__("every %s weeks", 'events-manager'), $EM_Event_Recurring->recurrence_interval);
3404
- }
3405
-
3406
- }elseif ($EM_Event_Recurring->recurrence_freq == 'monthly') {
3407
- $weekday_array = explode(",", $EM_Event_Recurring->recurrence_byday);
3408
- $natural_days = array();
3409
- foreach($weekday_array as $day){
3410
- if( is_numeric($day) ){
3411
- array_push($natural_days, $weekdays_name[$day]);
3412
- }
3413
- }
3414
- $freq_desc = sprintf (($monthweek_name[$EM_Event_Recurring->recurrence_byweekno]), implode(" and ", $natural_days));
3415
- if ($EM_Event_Recurring->recurrence_interval > 1 ) {
3416
- $freq_desc .= ", ".sprintf (__("every %s months",'events-manager'), $EM_Event_Recurring->recurrence_interval);
3417
- }
3418
- }elseif ($EM_Event_Recurring->recurrence_freq == 'yearly') {
3419
- $freq_desc = __("every year", 'events-manager');
3420
- if ($EM_Event_Recurring->recurrence_interval > 1 ) {
3421
- $freq_desc .= sprintf (__("every %s years",'events-manager'), $EM_Event_Recurring->recurrence_interval);
3422
- }
3423
- }else{
3424
- $freq_desc = "[ERROR: corrupted database record]";
3425
- }
3426
- $output .= $freq_desc;
3427
- return $output;
3428
- }
3429
-
3430
- /**********************************************************
3431
- * UTILITIES
3432
- ***********************************************************/
3433
- function to_array( $db = false ){
3434
- $event_array = parent::to_array($db);
3435
- //we reset start/end datetimes here, based on the EM_DateTime objects if they are valid
3436
- $event_array['event_start'] = $this->start()->valid ? $this->start(true)->format('Y-m-d H:i:s') : null;
3437
- $event_array['event_end'] = $this->end()->valid ? $this->end(true)->format('Y-m-d H:i:s') : null;
3438
- return apply_filters('em_event_to_array', $event_array, $this);
3439
- }
3440
-
3441
- /**
3442
- * Can the user manage this?
3443
- */
3444
- function can_manage( $owner_capability = false, $admin_capability = false, $user_to_check = false ){
3445
- if( ($this->just_added_event || $this->event_id == '') && !is_user_logged_in() && get_option('dbem_events_anonymous_submissions') ){
3446
- $user_to_check = get_option('dbem_events_anonymous_user');
3447
- }
3448
- return apply_filters('em_event_can_manage', parent::can_manage($owner_capability, $admin_capability, $user_to_check), $this, $owner_capability, $admin_capability, $user_to_check);
3449
- }
3450
- }
3451
-
3452
- //TODO placeholder targets filtering could be streamlined better
3453
- /**
3454
- * This is a temporary filter function which mimicks the old filters in the old 2.x placeholders function
3455
- * @param string $result
3456
- * @param EM_Event $event
3457
- * @param string $placeholder
3458
- * @param string $target
3459
- * @return mixed
3460
- */
3461
- function em_event_output_placeholder($result,$event,$placeholder,$target='html'){
3462
- if( $target == 'raw' ) return $result;
3463
- if( in_array($placeholder, array("#_EXCERPT",'#_EVENTEXCERPT','#_EVENTEXCERPTCUT', "#_LOCATIONEXCERPT")) && $target == 'html' ){
3464
- $result = apply_filters('dbem_notes_excerpt', $result);
3465
- }elseif( $placeholder == '#_CONTACTEMAIL' && $target == 'html' ){
3466
- $result = em_ascii_encode($event->get_contact()->user_email);
3467
- }elseif( in_array($placeholder, array('#_EVENTNOTES','#_NOTES','#_DESCRIPTION','#_LOCATIONNOTES','#_CATEGORYNOTES','#_CATEGORYDESCRIPTION')) ){
3468
- if($target == 'rss'){
3469
- $result = apply_filters('dbem_notes_rss', $result);
3470
- $result = apply_filters('the_content_rss', $result);
3471
- }elseif($target == 'map'){
3472
- $result = apply_filters('dbem_notes_map', $result);
3473
- }elseif($target == 'ical'){
3474
- $result = apply_filters('dbem_notes_ical', $result);
3475
- }elseif ($target == "email"){
3476
- $result = apply_filters('dbem_notes_email', $result);
3477
- }else{ //html
3478
- $result = apply_filters('dbem_notes', $result);
3479
- }
3480
- }elseif( in_array($placeholder, array("#_NAME",'#_LOCATION','#_TOWN','#_ADDRESS','#_LOCATIONNAME',"#_EVENTNAME","#_LOCATIONNAME",'#_CATEGORY')) ){
3481
- if ($target == "rss"){
3482
- $result = apply_filters('dbem_general_rss', $result);
3483
- }elseif ($target == "ical"){
3484
- $result = apply_filters('dbem_general_ical', $result);
3485
- }elseif ($target == "email"){
3486
- $result = apply_filters('dbem_general_email', $result);
3487
- }else{ //html
3488
- $result = apply_filters('dbem_general', $result);
3489
- }
3490
- }
3491
- return $result;
3492
- }
3493
- add_filter('em_category_output_placeholder','em_event_output_placeholder',1,4);
3494
- add_filter('em_event_output_placeholder','em_event_output_placeholder',1,4);
3495
- add_filter('em_location_output_placeholder','em_event_output_placeholder',1,4);
3496
- // FILTERS
3497
- // filters for general events field (corresponding to those of "the _title")
3498
- add_filter('dbem_general', 'wptexturize');
3499
- add_filter('dbem_general', 'convert_chars');
3500
- add_filter('dbem_general', 'trim');
3501
- // filters for the notes field in html (corresponding to those of "the _content")
3502
- add_filter('dbem_notes', 'wptexturize');
3503
- add_filter('dbem_notes', 'convert_smilies');
3504
- add_filter('dbem_notes', 'convert_chars');
3505
- add_filter('dbem_notes', 'wpautop');
3506
- add_filter('dbem_notes', 'prepend_attachment');
3507
- add_filter('dbem_notes', 'do_shortcode');
3508
- // filters for the notes field in html (corresponding to those of "the _content")
3509
- add_filter('dbem_notes_excerpt', 'wptexturize');
3510
- add_filter('dbem_notes_excerpt', 'convert_smilies');
3511
- add_filter('dbem_notes_excerpt', 'convert_chars');
3512
- add_filter('dbem_notes_excerpt', 'wpautop');
3513
- add_filter('dbem_notes_excerpt', 'prepend_attachment');
3514
- add_filter('dbem_notes_excerpt', 'do_shortcode');
3515
- // RSS content filter
3516
- add_filter('dbem_notes_rss', 'convert_chars', 8);
3517
- add_filter('dbem_general_rss', 'esc_html', 8);
3518
- // Notes map filters
3519
- add_filter('dbem_notes_map', 'convert_chars', 8);
3520
- add_filter('dbem_notes_map', 'js_escape');
3521
- //embeds support if using placeholders
3522
- if ( is_object($GLOBALS['wp_embed']) ){
3523
- add_filter( 'dbem_notes', array( $GLOBALS['wp_embed'], 'run_shortcode' ), 8 );
3524
- add_filter( 'dbem_notes', array( $GLOBALS['wp_embed'], 'autoembed' ), 8 );
3525
- }
3526
-
3527
- /**
3528
- * This function replaces the default gallery shortcode, so it can check if this is a recurring event recurrence and pass on the parent post id as the default post.
3529
- * @param array $attr
3530
- */
3531
- function em_event_gallery_override( $attr = array() ){
3532
- global $post;
3533
- if( !empty($post->post_type) && $post->post_type == EM_POST_TYPE_EVENT && empty($attr['id']) && empty($attr['ids']) ){
3534
- //no id specified, so check if it's recurring and override id with recurrence template post id
3535
- $EM_Event = em_get_event($post->ID, 'post_id');
3536
- if( $EM_Event->is_recurrence() ){
3537
- $attr['id'] = $EM_Event->get_event_recurrence()->post_id;
3538
- }
3539
- }
3540
- return gallery_shortcode($attr);
3541
- }
3542
- function em_event_gallery_override_init(){
3543
- remove_shortcode('gallery');
3544
- add_shortcode('gallery', 'em_event_gallery_override');
3545
- }
3546
- add_action('init','em_event_gallery_override_init', 1000); //so that plugins like JetPack don't think we're overriding gallery, we're not i swear!
3547
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-events.php DELETED
@@ -1,740 +0,0 @@
1
- <?php
2
- use EM_Event_Locations\Event_Locations;
3
- //TODO EM_Events is currently static, better we make this non-static so we can loop sets of events, and standardize with other objects.
4
- /**
5
- * Use this class to query and manipulate sets of events. If dealing with more than one event, you probably want to use this class in some way.
6
- *
7
- */
8
- class EM_Events extends EM_Object {
9
-
10
- /**
11
- * Like WPDB->num_rows it holds the number of results found on the last query.
12
- * @var int
13
- */
14
- public static $num_rows;
15
-
16
- /**
17
- * If $args['pagination'] is true or $args['offset'] or $args['page'] is greater than one, and a limit is imposed when using a get() query,
18
- * this will contain the total records found without a limit for the last query.
19
- * If no limit was used or pagination was not enabled, this will be the same as self::$num_rows
20
- * @var int
21
- */
22
- public static $num_rows_found;
23
-
24
- protected static $context = 'event';
25
-
26
- /**
27
- * Returns an array of EM_Events that match the given specs in the argument, or returns a list of future evetnts in future
28
- * (see EM_Events::get_default_search() ) for explanation of possible search array values. You can also supply a numeric array
29
- * containing the ids of the events you'd like to obtain
30
- *
31
- * @param array $args
32
- * @return EM_Event[]
33
- */
34
- public static function get( $args = array(), $count=false ) {
35
- global $wpdb;
36
- $events_table = EM_EVENTS_TABLE;
37
- $locations_table = EM_LOCATIONS_TABLE;
38
-
39
- //Quick version, we can accept an array of IDs, which is easy to retrieve
40
- if( self::array_is_numeric($args) ){ //Array of numbers, assume they are event IDs to retreive
41
- //We can just get all the events here and return them
42
- $events = array();
43
- foreach($args as $event_id){
44
- $events[$event_id] = em_get_event($event_id);
45
- }
46
- return apply_filters('em_events_get', $events, $args);
47
- }
48
-
49
- //We assume it's either an empty array or array of search arguments to merge with defaults
50
- $args = self::get_default_search($args);
51
- $limit = ( $args['limit'] && is_numeric($args['limit'])) ? "LIMIT {$args['limit']}" : '';
52
- $offset = ( $limit != "" && is_numeric($args['offset']) ) ? "OFFSET {$args['offset']}" : '';
53
-
54
- //Get fields that we can use in ordering and grouping, which can be event and location (excluding ambiguous) fields
55
- $EM_Event = new EM_Event();
56
- $EM_Location = new EM_Location();
57
- $event_fields = array_keys($EM_Event->fields);
58
- $location_fields = array(); //will contain location-specific fields, not ambiguous ones
59
- foreach( array_keys($EM_Location->fields) as $field_name ){
60
- if( !in_array($field_name, $event_fields) ) $location_fields[] = $field_name;
61
- }
62
- if( get_option('dbem_locations_enabled') ){
63
- $accepted_fields = array_merge($event_fields, $location_fields);
64
- }else{
65
- //if locations disabled then we don't accept location-specific fields
66
- $accepted_fields = $event_fields;
67
- }
68
-
69
- //Start SQL statement
70
-
71
- //Create the SQL statement selectors
72
- $calc_found_rows = $limit && ( $args['pagination'] || $args['offset'] > 0 || $args['page'] > 0 );
73
- if( $count ){
74
- $selectors = 'COUNT(DISTINCT '.$events_table . '.event_id)';
75
- $limit = 'LIMIT 1';
76
- $offset = 'OFFSET 0';
77
- }else{
78
- if( $args['array'] ){
79
- //get all fields from table, add events table prefix to avoid ambiguous fields from location
80
- $selectors = $events_table . '.*';
81
- }elseif( EM_MS_GLOBAL ){
82
- $selectors = $events_table.'.post_id, '.$events_table.'.blog_id';
83
- }else{
84
- $selectors = $events_table.'.post_id';
85
- }
86
- if( $calc_found_rows ) $selectors = 'SQL_CALC_FOUND_ROWS ' . $selectors; //for storing total rows found
87
- $selectors = 'DISTINCT ' . $selectors; //duplicate avoidance
88
- }
89
-
90
- //check if we need to join a location table for this search, which is necessary if any location-specific are supplied, or if certain arguments such as orderby contain location fields
91
- if( !empty($args['groupby']) || (defined('EM_DISABLE_OPTIONAL_JOINS') && EM_DISABLE_OPTIONAL_JOINS) ){
92
- $location_specific_args = array('town', 'state', 'country', 'region', 'near', 'geo', 'search');
93
- $join_locations = false;
94
- foreach( $location_specific_args as $arg ) if( !empty($args[$arg]) ) $join_locations = true;
95
- //if set to false the following would provide a false negative in the line above
96
- if( $args['location_status'] !== false ){ $join_locations = true; }
97
- //check ordering and grouping arguments for precense of location fields requiring a join
98
- if( !$join_locations ){
99
- foreach( array('groupby', 'orderby', 'groupby_orderby') as $arg ){
100
- if( !is_array($args[$arg]) ) continue; //ignore this argument if set to false
101
- //we assume all these arguments are now array thanks to self::get_search_defaults() cleaning it up
102
- foreach( $args[$arg] as $field_name ){
103
- if( in_array($field_name, $location_fields) ){
104
- $join_locations = true;
105
- break; //we join, no need to keep searching
106
- }
107
- }
108
- }
109
- }
110
- }else{ $join_locations = true; }//end temporary if( !empty($args['groupby']).... wrapper
111
- //plugins can override this optional joining behaviour here in case they add custom WHERE conditions or something like that
112
- $join_locations = apply_filters('em_events_get_join_locations_table', $join_locations, $args, $count);
113
- //depending on whether to join we do certain things like add a join SQL, change specific values like status search
114
- $location_optional_join = $join_locations ? "LEFT JOIN $locations_table ON {$locations_table}.location_id={$events_table}.location_id" : '';
115
-
116
- //Build ORDER BY and WHERE SQL statements here, after we've done all the pre-processing necessary
117
- $conditions = self::build_sql_conditions($args);
118
- $where = ( count($conditions) > 0 ) ? " WHERE " . implode ( " AND ", $conditions ):'';
119
- $orderby = self::build_sql_orderby($args, $accepted_fields, get_option('dbem_events_default_order'));
120
- $orderby_sql = ( count($orderby) > 0 ) ? 'ORDER BY '. implode(', ', $orderby) : '';
121
-
122
- //Build GROUP BY SQL statement, which will be very different if we group things due to how we need to filter out by event date
123
- if( !empty($args['groupby']) ){
124
- //get groupby field(s)
125
- $groupby_fields = self::build_sql_groupby($args, $accepted_fields);
126
- if( !empty($groupby_fields[0]) ){
127
- //we can safely assume we've been passed at least one array item with index of 0 containing a valid field due to build_sql_groupby()
128
- $groupby_field = $groupby_fields[0]; //we only support one field for events
129
- $groupby_orderby = self::build_sql_groupby_orderby($args, $accepted_fields);
130
- $groupby_orderby_sql = !empty($groupby_orderby) ? ', '. implode(', ', $groupby_orderby) : '';
131
- //get minimum required selectors within the inner query to shorten query length as much as possible
132
- $inner_selectors = $events_table . '.*';
133
- if( $location_optional_join ){
134
- //we're selecting all fields from events table so add only location fields required in the outer ORDER BY statement
135
- foreach( $args['orderby'] as $orderby_field ){
136
- if( in_array($orderby_field, $location_fields) ){
137
- $inner_selectors .= ', '. $locations_table .'.'. $orderby_field;
138
- }
139
- }
140
- }
141
-
142
- //THE Query - Grouped
143
- if( in_array($groupby_field, $location_fields) || count(array_intersect($location_fields, $args['groupby_orderby'])) || defined('EM_FORCE_GROUPED_DATASET_SQL') ){
144
- //if we're grouping by any fields in the locations table, we run a different (slightly slower) query to provide reliable results
145
- if( in_array($groupby_field, $location_fields) && !in_array($groupby_field, $args['orderby']) ){
146
- //we may not have included the grouped field if it's not in the outer ORDER BY clause, so we add it for this specific query
147
- $inner_selectors .= ', '. $locations_table .'.'. $groupby_field;
148
- }
149
- $sql = "
150
- SELECT $selectors
151
- FROM (
152
- SELECT *,
153
- @cur := IF($groupby_field = @id, @cur+1, 1) AS RowNumber,
154
- @id := $groupby_field AS IdCache
155
- FROM (
156
- SELECT {$inner_selectors} FROM {$events_table}
157
- $location_optional_join
158
- $where
159
- ORDER BY $groupby_field $groupby_orderby_sql
160
- ) {$events_table}
161
- INNER JOIN (
162
- SELECT @id:=0, @cur:=0
163
- ) AS lookup
164
- ) {$events_table}
165
- WHERE RowNumber = 1
166
- $orderby_sql
167
- $limit $offset";
168
- }else{
169
- //we'll keep this query simply because it's a little faster and still seems reliable when not grouping or group-sorting any fields in the locations table
170
- $sql = "
171
- SELECT $selectors
172
- FROM (
173
- SELECT {$inner_selectors},
174
- @cur := IF($groupby_field = @id, @cur+1, 1) AS RowNumber,
175
- @id := $groupby_field AS IdCache
176
- FROM {$events_table}
177
- INNER JOIN (
178
- SELECT @id:=0, @cur:=0
179
- ) AS lookup
180
- $location_optional_join
181
- $where
182
- ORDER BY {$groupby_field} $groupby_orderby_sql
183
- ) {$events_table}
184
- WHERE RowNumber = 1
185
- $orderby_sql
186
- $limit $offset";
187
- }
188
- }
189
- }
190
-
191
- //Build THE Query SQL statement if not already built for a grouped query
192
- if( empty($sql) ){
193
- //THE Query
194
- $sql = "
195
- SELECT $selectors FROM $events_table
196
- $location_optional_join
197
- $where
198
- $orderby_sql
199
- $limit $offset";
200
- }
201
-
202
- //THE Query filter
203
- $sql = apply_filters('em_events_get_sql', $sql, $args);
204
- //if( em_wp_is_super_admin() && WP_DEBUG_DISPLAY ){ echo "<pre>"; print_r($sql); echo '</pre>'; }
205
-
206
- //If we're only counting results, return the number of results and go no further
207
- if( $count ){
208
- self::$num_rows_found = self::$num_rows = $wpdb->get_var($sql);
209
- return apply_filters('em_events_get_count', self::$num_rows, $args);
210
- }
211
-
212
- //get the result and count results
213
- $results = $wpdb->get_results( $sql, ARRAY_A);
214
- self::$num_rows = $wpdb->num_rows;
215
- if( $calc_found_rows ){
216
- self::$num_rows_found = $wpdb->get_var('SELECT FOUND_ROWS()');
217
- }else{
218
- self::$num_rows_found = self::$num_rows;
219
- }
220
-
221
- //If we want results directly in an array, why not have a shortcut here?
222
- if( $args['array'] == true ){
223
- return apply_filters('em_events_get_array',$results, $args);
224
- }
225
-
226
- //Make returned results EM_Event objects
227
- $results = (is_array($results)) ? $results:array();
228
- $events = array();
229
-
230
- if( EM_MS_GLOBAL ){
231
- foreach ( $results as $event ){
232
- $events[] = em_get_event($event['post_id'], $event['blog_id']);
233
- }
234
- }else{
235
- foreach ( $results as $event ){
236
- $events[] = em_get_event($event['post_id'], 'post_id');
237
- }
238
- }
239
-
240
- return apply_filters('em_events_get', $events, $args);
241
- }
242
-
243
- /**
244
- * Returns the number of events on a given date
245
- * @param $date
246
- * @return int
247
- */
248
- public static function count_date($date){
249
- global $wpdb;
250
- $table_name = EM_EVENTS_TABLE;
251
- $sql = "SELECT COUNT(*) FROM $table_name WHERE (event_start_date like '$date') OR (event_start_date <= '$date' AND event_end_date >= '$date');";
252
- return apply_filters('em_events_count_date', $wpdb->get_var($sql));
253
- }
254
-
255
- public static function count( $args = array() ){
256
- return apply_filters('em_events_count', self::get($args, true), $args);
257
- }
258
-
259
- /**
260
- * Will delete given an array of event_ids or EM_Event objects
261
- * @param unknown_type $id_array
262
- */
263
- public static function delete( $array ){
264
- global $wpdb;
265
- //Detect array type and generate SQL for event IDs
266
- $results = array();
267
- if( !empty($array) && @get_class(current($array)) != 'EM_Event' ){
268
- $events = self::get($array);
269
- }else{
270
- $events = $array;
271
- }
272
- $event_ids = array();
273
- foreach ($events as $EM_Event){
274
- $event_ids[] = $EM_Event->event_id;
275
- $results[] = $EM_Event->delete();
276
- }
277
- //TODO add better error feedback on events delete fails
278
- return apply_filters('em_events_delete', in_array(false, $results), $event_ids);
279
- }
280
-
281
-
282
- /**
283
- * Output a set of matched of events. You can pass on an array of EM_Events as well, in this event you can pass args in second param.
284
- * Note that you can pass a 'pagination' boolean attribute to enable pagination, default is enabled (true).
285
- * @param array $args
286
- * @param array $secondary_args
287
- * @return string
288
- */
289
- public static function output( $args ){
290
- global $EM_Event;
291
- $EM_Event_old = $EM_Event; //When looping, we can replace EM_Event global with the current event in the loop
292
- //get page number if passed on by request (still needs pagination enabled to have effect)
293
- $page_queryvar = !empty($args['page_queryvar']) ? $args['page_queryvar'] : 'pno';
294
- if( !empty($args['pagination']) && !array_key_exists('page',$args) && !empty($_REQUEST[$page_queryvar]) && is_numeric($_REQUEST[$page_queryvar]) ){
295
- $args['page'] = $_REQUEST[$page_queryvar];
296
- }
297
- //Can be either an array for the get search or an array of EM_Event objects
298
- if( is_object(current($args)) && get_class((current($args))) == 'EM_Event' ){
299
- $func_args = func_get_args();
300
- $events = $func_args[0];
301
- $args = (!empty($func_args[1]) && is_array($func_args[1])) ? $func_args[1] : array();
302
- $args = apply_filters('em_events_output_args', self::get_default_search($args), $events);
303
- $limit = ( !empty($args['limit']) && is_numeric($args['limit']) ) ? $args['limit']:false;
304
- $events_count = count($events);
305
- }else{
306
- //Firstly, let's check for a limit/offset here, because if there is we need to remove it and manually do this
307
- $args = apply_filters('em_events_output_args', self::get_default_search($args));
308
- $limit = ( !empty($args['limit']) && is_numeric($args['limit']) ) ? $args['limit']:false;
309
- $events = self::get( $args );
310
- $events_count = self::$num_rows_found;
311
- }
312
- //What format shall we output this to, or use default
313
- $format = ( empty($args['format']) ) ? get_option( 'dbem_event_list_item_format' ) : $args['format'] ;
314
-
315
- $output = "";
316
-
317
- if ( $events_count > 0 ) {
318
- $events = apply_filters('em_events_output_events', $events);
319
- foreach ( $events as $EM_Event ) {
320
- $output .= $EM_Event->output($format);
321
- }
322
- //Add headers and footers to output
323
- if( $format == get_option( 'dbem_event_list_item_format' ) ){
324
- //we're using the default format, so if a custom format header or footer is supplied, we can override it, if not use the default
325
- $format_header = empty($args['format_header']) ? get_option('dbem_event_list_item_format_header') : $args['format_header'];
326
- $format_footer = empty($args['format_footer']) ? get_option('dbem_event_list_item_format_footer') : $args['format_footer'];
327
- }else{
328
- //we're using a custom format, so if a header or footer isn't specifically supplied we assume it's blank
329
- $format_header = !empty($args['format_header']) ? $args['format_header'] : '' ;
330
- $format_footer = !empty($args['format_footer']) ? $args['format_footer'] : '' ;
331
- }
332
- $output = $format_header . $output . $format_footer;
333
- //Pagination (if needed/requested)
334
- if( !empty($args['pagination']) && !empty($limit) && $events_count > $limit ){
335
- $output .= self::get_pagination_links($args, $events_count);
336
- }
337
- }elseif( $args['no_results_msg'] !== false ){
338
- $output = !empty($args['no_results_msg']) ? $args['no_results_msg'] : get_option('dbem_no_events_message');
339
- }
340
-
341
- //TODO check if reference is ok when restoring object, due to changes in php5 v 4
342
- $EM_Event = $EM_Event_old;
343
- $output = apply_filters('em_events_output', $output, $events, $args);
344
- return $output;
345
- }
346
-
347
- /**
348
- * Generate a grouped list of events by year, month, week or day.
349
- *
350
- * There is a nuance with this function, long_events won't work unless you add a limit of 0. The reason is because this won't work with pagination, due to the fact
351
- * that you need to alter the event total count to reflect each time an event is displayed in a time range. e.g. if an event lasts 2 days and it's daily grouping,
352
- * then that event would count as 2 events for pagination purposes. For that you need to count every single event and calculate date range etc. which is too resource
353
- * heavy and not scalabale, therefore we've added this limitation.
354
- *
355
- * @since 5.4.4.2
356
- * @param array $args
357
- * @return string
358
- */
359
- public static function output_grouped( $args = array() ){
360
- //Reset some args to include pagination for if pagination is requested.
361
- $args['limit'] = isset($args['limit']) ? $args['limit'] : get_option('dbem_events_default_limit');
362
- $args['page'] = (!empty($args['page']) && is_numeric($args['page']) )? $args['page'] : 1;
363
- $args['page'] = (!empty($args['pagination']) && !empty($_REQUEST['pno']) && is_numeric($_REQUEST['pno']) )? $_REQUEST['pno'] : $args['page'];
364
- $args['offset'] = ($args['page']-1) * $args['limit'];
365
- $args['orderby'] = 'event_start_date,event_start_time,event_name'; // must override this to display events in right cronology.
366
- $long_events = !empty($args['long_events']);
367
-
368
- $args['mode'] = !empty($args['mode']) ? $args['mode'] : get_option('dbem_event_list_groupby');
369
- $args['header_format'] = !empty($args['header_format']) ? $args['header_format'] : get_option('dbem_event_list_groupby_header_format', '<h2>#s</h2>');
370
- $args['date_format'] = !empty($args['date_format']) ? $args['date_format'] : get_option('dbem_event_list_groupby_format','');
371
- $args = apply_filters('em_events_output_grouped_args', self::get_default_search($args));
372
- //Reset some vars for counting events and displaying set arrays of events
373
- $atts = (array) $args;
374
- $atts['pagination'] = $atts['limit'] = $atts['page'] = $atts['offset'] = false;
375
- //decide what form of dates to show
376
- $EM_Events = self::get( $args );
377
- $events_count = self::$num_rows_found;
378
- ob_start();
379
- if( $events_count > 0 ){
380
- switch ( $args['mode'] ){
381
- case 'yearly':
382
- //go through the events and put them into a monthly array
383
- $format = (!empty($args['date_format'])) ? $args['date_format']:'Y';
384
- $events_dates = array();
385
- foreach($EM_Events as $EM_Event){ /* @var $EM_Event EM_Event */
386
- $year = $EM_Event->start()->format('Y');
387
- $events_dates[$year][] = $EM_Event;
388
- //if long events requested, add event to other dates too
389
- if( empty($args['limit']) && $long_events && $EM_Event->end()->getDate() != $EM_Event->start()->getDate() ) {
390
- $next_year = $year + 1;
391
- $year_end = $EM_Event->end()->format('Y');
392
- while( $next_year <= $year_end ){
393
- $events_dates[$next_year][] = $EM_Event;
394
- $next_year = $next_year + 1;
395
- }
396
- }
397
- }
398
- foreach ($events_dates as $year => $events){
399
- $EM_DateTime = new EM_DateTime($year.'-01-01');
400
- echo str_replace('#s', $EM_DateTime->i18n($format), $args['header_format']);
401
- echo self::output($events, $atts);
402
- }
403
- break;
404
- case 'monthly':
405
- //go through the events and put them into a monthly array
406
- $format = (!empty($args['date_format'])) ? $args['date_format']:'M Y';
407
- $events_dates = array();
408
- foreach($EM_Events as $EM_Event){
409
- $events_dates[$EM_Event->start()->format('Y-m-01')][] = $EM_Event;
410
- //if long events requested, add event to other dates too
411
- if( empty($args['limit']) && $long_events && $EM_Event->end()->getDate() != $EM_Event->start()->getDate() ) {
412
- ///$EM_DateTime is synoymous with the next month here
413
- $EM_DateTime = $EM_Event->start()->copy()->add('P1M');
414
- while( $EM_DateTime <= $EM_Event->end() ){
415
- $events_dates[$EM_DateTime->format('Y-m-01')][] = $EM_Event;
416
- $EM_DateTime = $EM_DateTime->add('P1M');
417
- }
418
- }
419
- }
420
- foreach ($events_dates as $month => $events){
421
- $EM_DateTime = new EM_DateTime($month);
422
- echo str_replace('#s', $EM_DateTime->i18n($format), $args['header_format']);
423
- echo self::output($events, $atts);
424
- }
425
- break;
426
- case 'weekly':
427
- $format = (!empty($args['date_format'])) ? $args['date_format']:get_option('date_format');
428
- $events_dates = array();
429
- foreach($EM_Events as $EM_Event){
430
- //obtain start of the week as per WordPress general settings
431
- $start_of_week = get_option('start_of_week');
432
- $day_of_week = $EM_Event->start()->format('w');
433
- $offset = $day_of_week - $start_of_week;
434
- if($offset<0){ $offset += 7; }
435
- $EM_DateTime = $EM_Event->start()->copy()->sub('P'.$offset.'D');
436
- //save event to date representing start of week for this WP install based on general settings
437
- $events_dates[$EM_DateTime->getDate()][] = $EM_Event;
438
- //if long events requested, add event to other dates too
439
- if( empty($args['limit']) && $long_events && $EM_Event->end()->getDate() != $EM_Event->start()->getDate() ) {
440
- do{
441
- $EM_DateTime->add('P1W');
442
- $events_dates[$EM_DateTime->getDate()][] = $EM_Event;
443
- }while( $EM_DateTime <= $EM_Event->end() );
444
- }
445
- }
446
- foreach ($events_dates as $date => $events){
447
- $dates_formatted = $EM_DateTime->modify($date)->i18n($format). get_option('dbem_dates_separator') . $EM_DateTime->add('P6D')->i18n($format);
448
- echo str_replace('#s', $dates_formatted, $args['header_format']);
449
- echo self::output($events, $atts);
450
- }
451
- break;
452
- default: //daily
453
- //go through the events and put them into a daily array
454
- $format = (!empty($args['date_format'])) ? $args['date_format']:get_option('date_format');
455
- $events_dates = array();
456
- foreach($EM_Events as $EM_Event){
457
- $EM_DateTime = $EM_Event->start()->copy()->setTime(0,0,0); /* @var EM_DateTime $EM_DateTime */
458
- $events_dates[$EM_DateTime->getDate()][] = $EM_Event;
459
- //if long events requested, add event to other dates too
460
- if( empty($args['limit']) && $long_events && $EM_Event->end()->getDate() != $EM_Event->start()->getDate() ) {
461
- do{
462
- $EM_DateTime->add('P1D');
463
- //store indexes as Y-m-d format so we become timezone independent
464
- $events_dates[$EM_DateTime->getDate()][] = $EM_Event;
465
- }while( $EM_DateTime <= $EM_Event->end() );
466
- }
467
- }
468
- foreach ($events_dates as $date => $events){
469
- echo str_replace('#s', $EM_DateTime->modify($date)->i18n($format), $args['header_format']);
470
- echo self::output($events, $atts);
471
- }
472
- break;
473
- }
474
- //Show the pagination links (unless there's less than $limit events)
475
- if( !empty($args['pagination']) && !empty($args['limit']) && $events_count > $args['limit'] ){
476
- echo self::get_pagination_links($args, $events_count, 'search_events_grouped');
477
- }
478
- }elseif( $args['no_results_msg'] !== false ){
479
- echo !empty($args['no_results_msg']) ? $args['no_results_msg'] : get_option('dbem_no_events_message');
480
- }
481
- return ob_get_clean();
482
- }
483
-
484
- public static function get_pagination_links($args, $count, $search_action = 'search_events', $default_args = array()){
485
- //get default args if we're in a search, supply to parent since we can't depend on late static binding until WP requires PHP 5.3 or later
486
- if( empty($default_args) && (!empty($args['ajax']) || !empty($_REQUEST['action']) && $_REQUEST['action'] == $search_action) ){
487
- $default_args = self::get_default_search();
488
- $default_args['limit'] = get_option('dbem_events_default_limit');
489
- }
490
- return parent::get_pagination_links($args, $count, $search_action, $default_args);
491
- }
492
-
493
- /* (non-PHPdoc)
494
- * DEPRECATED - this class should just contain static classes,
495
- * @see EM_Object::can_manage()
496
- */
497
- function can_manage($event_ids = false , $admin_capability = false, $user_to_check = false ){
498
- global $wpdb;
499
- if( current_user_can('edit_others_events') ){
500
- return apply_filters('em_events_can_manage', true, $event_ids);
501
- }
502
- if( EM_Object::array_is_numeric($event_ids) ){
503
- $condition = implode(" OR event_id=", $event_ids);
504
- //we try to find any of these events that don't belong to this user
505
- $results = $wpdb->get_var("SELECT COUNT(*) FROM ". EM_EVENTS_TABLE ." WHERE event_owner != '". get_current_user_id() ."' event_id=$condition;");
506
- return apply_filters('em_events_can_manage', ($results == 0), $event_ids);
507
- }
508
- return apply_filters('em_events_can_manage', false, $event_ids);
509
- }
510
-
511
- public static function get_post_search($args = array(), $filter = false, $request = array(), $accepted_args = array()){
512
- //supply $accepted_args to parent argument since we can't depend on late static binding until WP requires PHP 5.3 or later
513
- $accepted_args = !empty($accepted_args) ? $accepted_args : array_keys(self::get_default_search());
514
- return apply_filters('em_events_get_post_search', parent::get_post_search($args, $filter, $request, $accepted_args));
515
- }
516
-
517
- /* Overrides EM_Object method to apply a filter to result
518
- * @see wp-content/plugins/events-manager/classes/EM_Object#build_sql_conditions()
519
- */
520
- public static function build_sql_conditions( $args = array() ){
521
- global $wpdb;
522
- //continue with conditions
523
- $conditions = parent::build_sql_conditions($args);
524
- //specific location query conditions if locations are enabled
525
- if( get_option('dbem_locations_enabled') ){
526
- //events with or without locations
527
- if( !empty($args['has_location']) ){
528
- $conditions['has_location'] = '('.EM_EVENTS_TABLE.'.location_id IS NOT NULL AND '.EM_EVENTS_TABLE.'.location_id != 0)';
529
- }elseif( !empty($args['no_location']) ){
530
- $conditions['no_location'] = '('.EM_EVENTS_TABLE.'.location_id IS NULL OR '.EM_EVENTS_TABLE.'.location_id = 0)';
531
- }elseif( !empty($conditions['location_status']) ){
532
- $location_specific_args = array('town', 'state', 'country', 'region', 'near', 'geo', 'search');
533
- foreach( $location_specific_args as $location_arg ){
534
- if( !empty($args[$location_arg]) ) $skip_location_null_condition = true;
535
- }
536
- if( empty($skip_location_null_condition) ){
537
- $conditions['location_status'] = '('.$conditions['location_status'].' OR '.EM_LOCATIONS_TABLE.'.location_id IS NULL)';
538
- }
539
- }
540
- }
541
- //search conditions
542
- if( !empty($args['search']) ){
543
- if( get_option('dbem_locations_enabled') ){
544
- $like_search = array('event_name',EM_EVENTS_TABLE.'.post_content','location_name','location_address','location_town','location_postcode','location_state','location_country','location_region');
545
- }else{
546
- $like_search = array('event_name',EM_EVENTS_TABLE.'.post_content');
547
- }
548
- $like_search_string = '%'.$wpdb->esc_like($args['search']).'%';
549
- $like_search_strings = array();
550
- foreach( $like_search as $v ) $like_search_strings[] = $like_search_string;
551
- $like_search_sql = "(".implode(" LIKE %s OR ", $like_search). " LIKE %s)";
552
- $conditions['search'] = $wpdb->prepare($like_search_sql, $like_search_strings);
553
- }
554
- //private events
555
- if( empty($args['private']) ){
556
- $conditions['private'] = "(`event_private`=0)";
557
- }elseif( !empty($args['private_only']) ){
558
- $conditions['private_only'] = "(`event_private`=1)";
559
- }
560
- if( EM_MS_GLOBAL && !empty($args['blog']) ){
561
- if( is_numeric($args['blog']) ){
562
- if( is_main_site($args['blog']) ){
563
- $conditions['blog'] = "(".EM_EVENTS_TABLE.".blog_id={$args['blog']} OR ".EM_EVENTS_TABLE.".blog_id IS NULL)";
564
- }else{
565
- $conditions['blog'] = "(".EM_EVENTS_TABLE.".blog_id={$args['blog']})";
566
- }
567
- }else{
568
- if( !is_array($args['blog']) && preg_match('/^([\-0-9],?)+$/', $args['blog']) ){
569
- $conditions['blog'] = "(".EM_EVENTS_TABLE.".blog_id IN ({$args['blog']}) )";
570
- }elseif( is_array($args['blog']) && self::array_is_numeric($args['blog']) ){
571
- $conditions['blog'] = "(".EM_EVENTS_TABLE.".blog_id IN (".implode(',',$args['blog']).") )";
572
- }
573
- }
574
- }
575
- //post search
576
- if( !empty($args['post_id'])){
577
- if( is_array($args['post_id']) ){
578
- $conditions['post_id'] = "(".EM_EVENTS_TABLE.".post_id IN (".implode(',',$args['post_id'])."))";
579
- }else{
580
- $conditions['post_id'] = "(".EM_EVENTS_TABLE.".post_id={$args['post_id']})";
581
- }
582
- }
583
- // event locations
584
- if( !empty($args['event_location_type']) ){
585
- $event_location_types = explode(',', $args['event_location_type']);
586
- $event_locations_search = array();
587
- // generate array of clean and enabled event location types
588
- foreach( $event_location_types as $event_location_type ){
589
- $event_location_type = trim($event_location_type);
590
- if( Event_Locations::is_enabled($event_location_type) ){
591
- $event_locations_search[] = $event_location_type;
592
- }
593
- }
594
- // add condition if at least one valid/clean type supplied
595
- if( !empty($event_locations_search) ){
596
- if( count($event_locations_search) === 1 ){
597
- $event_location = current($event_locations_search);
598
- $conditions['event_location'] = "event_location_type='$event_location'";
599
- }else{
600
- $conditions['event_location'] = "event_location_type IN ('". implode("','", $event_locations_search) ."')";
601
- }
602
- }
603
- }
604
- if( isset($args['has_event_location']) && $args['has_event_location'] !== false ){
605
- if( $args['has_event_location'] ){
606
- $conditions['has_event_location'] = "event_location_type IS NOT NULL";
607
- }else{
608
- $conditions['has_event_location'] = "event_location_type IS NULL";
609
- }
610
- }
611
- return apply_filters( 'em_events_build_sql_conditions', $conditions, $args );
612
- }
613
-
614
- /**
615
- * Overrides EM_Object method to clean ambiguous fields and apply a filter to result.
616
- * @see EM_Object::build_sql_orderby()
617
- */
618
- public static function build_sql_orderby( $args, $accepted_fields, $default_order = 'ASC' ){
619
- $accepted_fields[] = 'event_date_modified';
620
- $accepted_fields[] = 'event_date_created';
621
- $orderby = parent::build_sql_orderby($args, $accepted_fields, get_option('dbem_events_default_order'));
622
- $orderby = self::build_sql_ambiguous_fields_helper($orderby); //fix ambiguous fields
623
- return apply_filters( 'em_events_build_sql_orderby', $orderby, $args, $accepted_fields, $default_order );
624
- }
625
-
626
- /**
627
- * Overrides EM_Object method to clean ambiguous fields and apply a filter to result.
628
- * @see EM_Object::build_sql_groupby()
629
- */
630
- public static function build_sql_groupby( $args, $accepted_fields, $groupby_order = false, $default_order = 'ASC' ){
631
- $accepted_fields[] = 'event_date_modified';
632
- $accepted_fields[] = 'event_date_created';
633
- $groupby = parent::build_sql_groupby($args, $accepted_fields);
634
- //fix ambiguous fields and give them scope of events table
635
- $groupby = self::build_sql_ambiguous_fields_helper($groupby);
636
- return apply_filters( 'em_events_build_sql_groupby', $groupby, $args, $accepted_fields );
637
- }
638
-
639
- /**
640
- * Overrides EM_Object method to clean ambiguous fields and apply a filter to result.
641
- * @see EM_Object::build_sql_groupby_orderby()
642
- */
643
- public static function build_sql_groupby_orderby($args, $accepted_fields, $default_order = 'ASC' ){
644
- $accepted_fields[] = 'event_date_modified';
645
- $accepted_fields[] = 'event_date_created';
646
- $group_orderby = parent::build_sql_groupby_orderby($args, $accepted_fields, get_option('dbem_events_default_order'));
647
- //fix ambiguous fields and give them scope of events table
648
- $group_orderby = self::build_sql_ambiguous_fields_helper($group_orderby);
649
- return apply_filters( 'em_events_build_sql_groupby_orderby', $group_orderby, $args, $accepted_fields, $default_order );
650
- }
651
-
652
- /**
653
- * Overrides EM_Object method to provide specific reserved fields and events table.
654
- * @see EM_Object::build_sql_ambiguous_fields_helper()
655
- */
656
- protected static function build_sql_ambiguous_fields_helper( $fields, $reserved_fields = array(), $prefix = 'table_name' ){
657
- //This will likely be removed when PHP 5.3 is the minimum and LSB is a given
658
- return parent::build_sql_ambiguous_fields_helper($fields, array('post_id', 'location_id', 'blog_id'), EM_EVENTS_TABLE);
659
- }
660
-
661
- /*
662
- * Adds custom Events search defaults
663
- * @param array $array_or_defaults may be the array to override defaults
664
- * @param array $array
665
- * @return array
666
- * @uses EM_Object#get_default_search()
667
- */
668
- public static function get_default_search( $array_or_defaults = array(), $array = array() ){
669
- $defaults = array(
670
- 'recurring' => false, //we don't initially look for recurring events only events and recurrences of recurring events
671
- 'orderby' => get_option('dbem_events_default_orderby'),
672
- 'order' => get_option('dbem_events_default_order'),
673
- 'groupby' => false,
674
- 'groupby_orderby' => 'event_start_date, event_start_time', //groups according to event start time, i.e. by default shows earliest event in a scope
675
- 'groupby_order' => 'ASC', //groups according to event start time, i.e. by default shows earliest event in a scope
676
- 'status' => 1, //approved events only
677
- 'town' => false,
678
- 'state' => false,
679
- 'country' => false,
680
- 'region' => false,
681
- 'postcode' => false,
682
- 'blog' => get_current_blog_id(),
683
- 'private' => current_user_can('read_private_events'),
684
- 'private_only' => false,
685
- 'post_id' => false,
686
- //ouput_grouped specific arguments
687
- 'mode' => false,
688
- 'header_format' => false,
689
- 'date_format' => false,
690
- //event-specific search attributes
691
- 'has_location' => false, //search events with a location
692
- 'no_location' => false, //search events without a location
693
- 'location_status' => false, //search events with locations of a specific publish status
694
- 'event_location_type' => false,
695
- 'has_event_location' => false,
696
- );
697
- //sort out whether defaults were supplied or just the array of search values
698
- if( empty($array) ){
699
- $array = $array_or_defaults;
700
- }else{
701
- $defaults = array_merge($defaults, $array_or_defaults);
702
- }
703
- //specific functionality
704
- if( EM_MS_GLOBAL && (!is_admin() || defined('DOING_AJAX')) ){
705
- if( empty($array['blog']) && is_main_site() && get_site_option('dbem_ms_global_events') ){
706
- $array['blog'] = false;
707
- }
708
- }
709
- //admin-area specific modifiers
710
- if( is_admin() && !defined('DOING_AJAX') ){
711
- //figure out default owning permissions
712
- $defaults['owner'] = !current_user_can('edit_others_events') ? get_current_user_id() : false;
713
- if( !array_key_exists('status', $array) && current_user_can('edit_others_events') ){
714
- $defaults['status'] = false; //by default, admins see pending and live events
715
- }
716
- }
717
- //check if we're doing any location-specific searching, if so then we (by default) want to match the status of events
718
- if( !empty($array['has_location']) ){
719
- //we're looking for events with locations, so we match the status we're searching for events unless there's an argument passed on for something different
720
- $defaults['location_status'] = true;
721
- }elseif( !empty($array['no_location']) ){
722
- //if no location is being searched for, we should ignore any status searches for location
723
- $defaults['location_status'] = $array['location_status'] = false;
724
- }else{
725
- $location_specific_args = array('town', 'state', 'country', 'region', 'near', 'geo');
726
- foreach( $location_specific_args as $location_arg ){
727
- if( !empty($array[$location_arg]) ) $defaults['location_status'] = true;
728
- }
729
- }
730
- $args = parent::get_default_search($defaults,$array);
731
- //do some post-parnet cleaning up here if locations are enabled or disabled
732
- if( !get_option('dbem_locations_enabled') ){
733
- //locations disabled, wipe any args to do with locations so they're ignored
734
- $location_args = array('town', 'state', 'country', 'region', 'has_location', 'no_location', 'location_status', 'location', 'geo', 'near', 'location_id');
735
- foreach( $location_args as $arg ) $args[$arg] = false;
736
- }
737
- return apply_filters('em_events_get_default_search', $args, $array, $defaults);
738
- }
739
- }
740
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/classes/em-exception.php DELETED
@@ -1,107 +0,0 @@
1
- <?php
2
- //in case we include it in EM core code
3
- if( !class_exists('EM_Exception') ){
4
- /**
5
- * Extended Exception class that allows for creating multiple error messages in an exception as an array and outputting them together at once.
6
- * Class Exception
7
- */
8
- class EM_Exception extends Exception {
9
-
10
- /**
11
- * @var WP_Error
12
- */
13
- public $wp_error;
14
- /**
15
- * @var array
16
- */
17
- public $error_messages = array();
18
- /**
19
- * @var int|string Allows for a custom code to be used rather than an integer.
20
- */
21
- public $error_code;
22
-
23
- /**
24
- * Exception constructor.
25
- * @param string $error
26
- * @param int $code
27
- * @param null $previous
28
- */
29
- public function __construct($error = '', $code = 0, $previous = null ){
30
- if( is_array($error) ) {
31
- $this->error_messages = $error;
32
- $message = $this->get_message();
33
- }elseif( is_wp_error($error) ){ /* @var WP_Error $error */
34
- $this->wp_error = $error;
35
- $code = $error->get_error_code();
36
- $message = $error->get_error_message();
37
- }else{
38
- $message = $error;
39
- }
40
- if( !is_numeric($code) ){
41
- $this->error_code = $code;
42
- $code = 0;
43
- }
44
- parent::__construct($message, $code, $previous);
45
- }
46
-
47
- /**
48
- * Returns either a string code reference, or a regular Exception code number.
49
- * @return int|string
50
- */
51
- public function get_error_code(){
52
- if( $this->error_code ){
53
- return $this->error_code;
54
- }
55
- return $this->getCode();
56
- }
57
-
58
- /**
59
- * Provides a paragraph-formatted message which may contain multiple paragraphs for multiple errors.
60
- * @return string
61
- */
62
- public function get_message(){
63
- if( $this->is_wp_error() ){
64
- $message = '<p>' . implode('</p><p>', $this->wp_error->get_error_messages()) . '</p>';
65
- }elseif( !empty($this->error_messages) ){
66
- $message = '<p>' . implode('</p><p>', $this->error_messages) . '</p>';
67
- }else{
68
- $message = '<p>' . $this->g