Events Manager - Version 5.9.7

Version Description

  • fixed google calendar add-to link not including location town/zip/state
  • fixed minor PHP warnings
  • added timestamps for keys to $post_ids array in em_event_save_events filter
  • tweaked deleting of recurrences to reduce possibility of mistken circumvention by other filters
  • added parameter option to include country to EM_Location->get_full_address()
  • added em_ticket_delete and em_tickets_delete filters
  • added language definition for events and locations allowing for faster multilingual searches where supported
  • added parent definition for events, tickets and locations paving the way for various hierarchical applications
  • added language search attribute for events and locations
  • fixed potential search inconsistencies when using 'recurrence' search attribute for finding recurrences by recurring event ID
  • added multilingual support for recurring events (requires update to any compatibility plugins)
  • added ability for event recurrences to assign corresponding parent ticket ids to recurrence tickets via ticket_parent db field
  • fixed potentially conflict-causing permalink rules for the calendar page (fixes WPML-EM conflict on these pages)
  • added support for location address translation in multilingual environments
  • removed filter pointer (previously used to fix ACF conflicts) in EM_ML_IO::event_save_meta() since WP now has fixed pointer issues for nested filter triggers
  • fixed EM_Event::is_recurrence() returning false when event not saved for first time
  • fixed delete_events not returning true to filter when events are actually deleted
  • fixed JS warning preventing address update on map when updating locations
  • added various precautionary data sanitization for security enhancement
  • replaced all uses of wp_redirect() with wp_safe_redirect() as a security precaution
  • added encryption and autotls options to email settings
  • added em_is_event() and em_is_location() object checking functions
  • added native primary handling of finding translations of events and locations before passing it onto filters where translation plugins can intervene
  • added native searching of events and locations based on new language/parent fields
  • added native support for searching eventful and eventless arguments in multilingual context
  • added native support for listing untranslated events and locations in original language when listing a second language in multilingual context
  • changed EM_Event and EM_Location blog_id to default to 0 rather than null
  • added shortname property names for common EM_Event and EM_Location fields language, parent, translation, id (event/location id), slug, status, name and owner
  • added get_parent() function for EM_Event and EM_Location classes
  • added $context peroperty to EM_Events and EM_Locations classes which leverage late static binding in PHP 5.3
  • added 'language' search argument for events and locations which can be used in multilingual contexts
  • moved table joining decision logic in EM_Locations into its own function, enabling overriding via filters
  • added em_booking_email_before_send, em_booking_email_after_send and em_booking_output_pre actions in EM_Booking
  • added em_booking_email filter in EM_Booking
  • added name/description shortname properties and modified ticket_name/description access in EM_Ticket to enable dynamic translation of ticket names
  • added price,id,spaces shortnames for EM_Ticket_Booking
  • added em_ticket_booking_get_ticket filter in EM_Ticket_Booking
  • added locale switching/restoring functions in EM_ML as well as syncing with the WP locale switcher
  • fixed booking emails not getting correctly translated in ML modes
  • fixed data privacy consent validation errors when booking in custom modes under certain setting configurations
  • removed load_plugin_textdomain call in favour of letting WordPress.org automatically handle language translation files
  • changed boolean database fields into tinyint(1) unsigned types
Download this release

Release Info

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

Code changes from version 5.9.6 to 5.9.7

Files changed (104) hide show
  1. admin/em-admin.php +5 -5
  2. admin/em-data-privacy.php +6 -6
  3. admin/em-ms-options.php +1 -1
  4. admin/em-options.php +13 -11
  5. admin/settings/tabs/general.php +2 -2
  6. admin/settings/updates/timezone-backcompat.php +2 -2
  7. buddypress/bp-em-groups.php +2 -2
  8. buddypress/screens/my-events.php +1 -1
  9. buddypress/screens/my-locations.php +1 -1
  10. classes/em-booking.php +29 -16
  11. classes/em-bookings.php +4 -2
  12. classes/em-event-post-admin.php +4 -2
  13. classes/em-event-posts-admin.php +2 -2
  14. classes/em-event.php +107 -40
  15. classes/em-events.php +2 -2
  16. classes/em-location-post-admin.php +4 -2
  17. classes/em-location.php +61 -8
  18. classes/em-locations.php +44 -33
  19. classes/em-mailer.php +72 -53
  20. classes/em-object.php +62 -13
  21. classes/em-permalinks.php +9 -9
  22. classes/em-taxonomy-term.php +4 -3
  23. classes/em-ticket-booking.php +6 -1
  24. classes/em-ticket.php +66 -8
  25. classes/em-tickets.php +4 -3
  26. em-actions.php +38 -31
  27. em-data-privacy.php +2 -2
  28. em-ical.php +2 -3
  29. em-install.php +38 -8
  30. em-shortcode.php +2 -2
  31. em-template-tags.php +56 -2
  32. em-wpfc.php +1 -1
  33. events-manager.php +9 -11
  34. includes/js/events-manager.js +1 -1
  35. includes/langs/events-manager-ar.mo +0 -0
  36. includes/langs/events-manager-ar.po +0 -5988
  37. includes/langs/events-manager-ca.mo +0 -0
  38. includes/langs/events-manager-ca.po +0 -5984
  39. includes/langs/events-manager-cs_CZ.mo +0 -0
  40. includes/langs/events-manager-cs_CZ.po +0 -5985
  41. includes/langs/events-manager-da_DK.mo +0 -0
  42. includes/langs/events-manager-da_DK.po +0 -5984
  43. includes/langs/events-manager-de_DE.mo +0 -0
  44. includes/langs/events-manager-de_DE.po +0 -5984
  45. includes/langs/events-manager-el.mo +0 -0
  46. includes/langs/events-manager-el.po +0 -5984
  47. includes/langs/events-manager-en_AU.mo +0 -0
  48. includes/langs/events-manager-en_AU.po +0 -5984
  49. includes/langs/events-manager-en_CA.mo +0 -0
  50. includes/langs/events-manager-en_CA.po +0 -5984
  51. includes/langs/events-manager-en_GB.mo +0 -0
  52. includes/langs/events-manager-en_GB.po +0 -5980
  53. includes/langs/events-manager-es_ES.mo +0 -0
  54. includes/langs/events-manager-es_ES.po +0 -5984
  55. includes/langs/events-manager-et.mo +0 -0
  56. includes/langs/events-manager-et.po +0 -5984
  57. includes/langs/events-manager-fa_IR.mo +0 -0
  58. includes/langs/events-manager-fa_IR.po +0 -5983
  59. includes/langs/events-manager-fi.mo +0 -0
  60. includes/langs/events-manager-fi.po +0 -5986
  61. includes/langs/events-manager-fr_FR.mo +0 -0
  62. includes/langs/events-manager-fr_FR.po +0 -5984
  63. includes/langs/events-manager-he_IL.mo +0 -0
  64. includes/langs/events-manager-he_IL.po +0 -5984
  65. includes/langs/events-manager-hu_HU.mo +0 -0
  66. includes/langs/events-manager-hu_HU.po +0 -5984
  67. includes/langs/events-manager-it_IT.mo +0 -0
  68. includes/langs/events-manager-it_IT.po +0 -5984
  69. includes/langs/events-manager-ja.mo +0 -0
  70. includes/langs/events-manager-ja.po +0 -5983
  71. includes/langs/events-manager-nb_NO.mo +0 -0
  72. includes/langs/events-manager-nb_NO.po +0 -5984
  73. includes/langs/events-manager-nl_NL.mo +0 -0
  74. includes/langs/events-manager-nl_NL.po +0 -5984
  75. includes/langs/events-manager-no_NO.mo +0 -0
  76. includes/langs/events-manager-no_NO.po +0 -5984
  77. includes/langs/events-manager-pl_PL.mo +0 -0
  78. includes/langs/events-manager-pl_PL.po +0 -5985
  79. includes/langs/events-manager-pt_BR.mo +0 -0
  80. includes/langs/events-manager-pt_BR.po +0 -5984
  81. includes/langs/events-manager-pt_PT.mo +0 -0
  82. includes/langs/events-manager-pt_PT.po +0 -5984
  83. includes/langs/events-manager-ru_RU.mo +0 -0
  84. includes/langs/events-manager-ru_RU.po +0 -5987
  85. includes/langs/events-manager-sk_SK.mo +0 -0
  86. includes/langs/events-manager-sk_SK.po +0 -5985
  87. includes/langs/events-manager-sl_SI.mo +0 -0
  88. includes/langs/events-manager-sl_SI.po +0 -5986
  89. includes/langs/events-manager-sv_SE.mo +0 -0
  90. includes/langs/events-manager-sv_SE.po +0 -5984
  91. includes/langs/events-manager-tr_TR.mo +0 -0
  92. includes/langs/events-manager-tr_TR.po +0 -5984
  93. includes/langs/events-manager-zh_CN.mo +0 -0
  94. includes/langs/events-manager-zh_CN.po +0 -5983
  95. includes/langs/events-manager-zh_TW.mo +0 -0
  96. includes/langs/events-manager-zh_TW.po +0 -5983
  97. includes/langs/events-manager.pot +0 -8288
  98. multilingual/em-ml-admin.php +54 -3
  99. multilingual/em-ml-bookings.php +81 -30
  100. multilingual/em-ml-io-locations.php +139 -0
  101. multilingual/em-ml-io.php +284 -132
  102. multilingual/em-ml-search.php +113 -3
  103. multilingual/em-ml.php +347 -59
  104. readme.txt +45 -1
admin/em-admin.php CHANGED
@@ -111,7 +111,7 @@ 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
@@ -144,7 +144,7 @@ function em_admin_warnings() {
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', $_SERVER['REQUEST_URI'].$dismiss_link_joiner.'disable_hello_to_user=true');
148
?>
149
<div id="message" class="updated">
150
<?php echo $advice; ?>
@@ -159,9 +159,9 @@ function em_admin_warnings() {
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', $_SERVER['REQUEST_URI'].$dismiss_link_joiner.'em_dismiss_events_page=1' ); ?></p>
163
</div>
164
- <?php
165
}
166
}
167
@@ -179,7 +179,7 @@ function em_admin_warnings() {
179
}else{
180
?>
181
<div id="em_page_error" class="updated">
182
- <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', $_SERVER['REQUEST_URI'].'&amp;disable_dbem_ms_update_nag=1'); ?></p>
183
</div>
184
<?php
185
}
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
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; ?>
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
179
}else{
180
?>
181
<div id="em_page_error" class="updated">
182
+ <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>
183
</div>
184
<?php
185
}
admin/em-data-privacy.php CHANGED
@@ -210,8 +210,8 @@ class EM_Data_Privacy {
210
}
211
212
public static function export_cleanup(){
213
- delete_post_meta($_REQUEST['id'], '_em_locations_exported');
214
- delete_post_meta($_REQUEST['id'], '_em_bookings_exported');
215
}
216
217
public static function export_user( $email_address ){
@@ -345,7 +345,7 @@ class EM_Data_Privacy {
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( $_REQUEST['id'], '_em_locations_exported', true);
349
if( empty($locations_exported) ) $locations_exported = array();
350
351
//EVENTS
@@ -423,7 +423,7 @@ class EM_Data_Privacy {
423
}
424
425
$done = $items_count < $limit; //if we didn't reach limit of bookings then we must be done
426
- update_post_meta( $_REQUEST['id'], '_em_locations_exported', $locations_exported);
427
return array(
428
'data' => $export_items,
429
'done' => $done,
@@ -446,7 +446,7 @@ class EM_Data_Privacy {
446
);
447
448
//Locations - previous to 5.9.4 locations submitted anonymously did nint include
449
- $locations_exported = get_post_meta( $_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);
@@ -473,7 +473,7 @@ class EM_Data_Privacy {
473
if( $items_count == $limit ) break;
474
}
475
}
476
- update_post_meta( $_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,
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 ){
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
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,
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);
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,
admin/em-ms-options.php CHANGED
@@ -65,6 +65,7 @@ function em_ms_admin_options_page() {
65
return;
66
}
67
//TODO place all options into an array
68
$events_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#event-placeholders">'. __('Event Related Placeholders','events-manager') .'</a>';
69
$locations_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#location-placeholders">'. __('Location Related Placeholders','events-manager') .'</a>';
70
$bookings_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#booking-placeholders">'. __('Booking Related Placeholders','events-manager') .'</a>';
@@ -137,7 +138,6 @@ function em_ms_admin_options_page() {
137
<h1 id="em-options-title"><?php _e ( 'Event Manager Options', 'events-manager'); ?></h1>
138
<h2 class="nav-tab-wrapper">
139
<?php
140
- $tabs_enabled = defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS;
141
if( $tabs_enabled ){
142
$general_tab_link = esc_url(add_query_arg( array('em_tab'=>'general')));
143
}else{
65
return;
66
}
67
//TODO place all options into an array
68
+ $tabs_enabled = defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS;
69
$events_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#event-placeholders">'. __('Event Related Placeholders','events-manager') .'</a>';
70
$locations_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#location-placeholders">'. __('Location Related Placeholders','events-manager') .'</a>';
71
$bookings_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#booking-placeholders">'. __('Booking Related Placeholders','events-manager') .'</a>';
138
<h1 id="em-options-title"><?php _e ( 'Event Manager Options', 'events-manager'); ?></h1>
139
<h2 class="nav-tab-wrapper">
140
<?php
141
if( $tabs_enabled ){
142
$general_tab_link = esc_url(add_query_arg( array('em_tab'=>'general')));
143
}else{
admin/em-options.php CHANGED
@@ -83,7 +83,7 @@ function em_options_save(){
83
$referrer_array = explode('#', $referrer);
84
$referrer = esc_url_raw($referrer_array[0] . '#' . $_REQUEST['tab_path']);
85
}
86
- wp_redirect($referrer);
87
exit();
88
}
89
//Migration
@@ -94,7 +94,7 @@ function em_options_save(){
94
$failed = ( $result['fail'] > 0 ) ? $result['fail'] . ' images failed to migrate.' : '';
95
$EM_Notices->add_confirm('<strong>'.$result['success'].' images migrated successfully. '.$failed.'</strong>');
96
}
97
- wp_redirect(admin_url().'edit.php?post_type=event&page=events-manager-options&em_migrate_images');
98
}elseif( !empty($_GET['em_not_migrate_images']) && check_admin_referer('em_not_migrate_images','_wpnonce') ){
99
delete_option('dbem_migrate_images_nag');
100
delete_option('dbem_migrate_images');
@@ -134,7 +134,7 @@ function em_options_save(){
134
$wpdb->query('DELETE FROM '.$wpdb->options.' WHERE option_name LIKE \'em_%\' OR option_name LIKE \'dbem_%\'');
135
//deactivate and go!
136
deactivate_plugins(array('events-manager/events-manager.php','events-manager-pro/events-manager-pro.php'), true);
137
- wp_redirect(admin_url('plugins.php?deactivate=true'));
138
exit();
139
}
140
}
@@ -154,7 +154,7 @@ function em_options_save(){
154
}
155
//go back to plugin options page
156
$EM_Notices->add_confirm(__('Settings have been reset back to default. Your events, locations and categories have not been modified.','events-manager'), true);
157
- wp_redirect(em_wp_get_referer());
158
exit();
159
}
160
}
@@ -180,7 +180,7 @@ function em_options_save(){
180
}
181
//go back to plugin options page
182
$EM_Notices->add_confirm(sprintf(__('Found %d orphaned events, deleted %d successfully','events-manager'), count($results), $deleted_events), true);
183
- wp_redirect(em_wp_get_referer());
184
exit();
185
}
186
//Force Update Recheck - Workaround for now
@@ -189,7 +189,7 @@ function em_options_save(){
189
delete_transient('update_plugins');
190
delete_site_transient('update_plugins');
191
$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);
192
- wp_redirect(em_wp_get_referer());
193
exit();
194
}
195
//Flag version checking to look at trunk, not tag
@@ -199,7 +199,7 @@ function em_options_save(){
199
delete_site_transient('update_plugins');
200
update_option('em_check_dev_version', true);
201
$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);
202
- wp_redirect(em_wp_get_referer());
203
exit();
204
}
205
//import EM settings
@@ -223,12 +223,12 @@ function em_options_save(){
223
}
224
}
225
$EM_Notices->add_confirm(__('Settings imported.','events-manager'), true);
226
- wp_redirect(em_wp_get_referer());
227
exit();
228
}
229
}
230
$EM_Notices->add_error(__('Please upload a valid txt file containing Events Manager import settings.','events-manager'), true);
231
- wp_redirect(em_wp_get_referer());
232
exit();
233
}
234
//export EM settings
@@ -320,7 +320,7 @@ function em_options_save(){
320
$EM_Notices->add_confirm(sprintf(__('Event timezones have been reset to %s.','events-manager'), '<code>'.$timezone.'</code>'), true);
321
}
322
}
323
- wp_redirect(em_wp_get_referer());
324
exit();
325
}
326
@@ -606,7 +606,9 @@ function em_admin_option_box_email(){
606
<?php
607
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') );
608
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') );
609
- 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 'ssl://smtp.gmail.com:465'.", 'events-manager') );
610
em_options_input_text ( __( 'SMTP username', 'events-manager'), 'dbem_smtp_username', __( "Insert the username to be used to access your SMTP server.", 'events-manager') );
611
em_options_input_password ( __( 'SMTP password', 'events-manager'), "dbem_smtp_password", __( "Insert the password to be used to access your SMTP server", 'events-manager') );
612
?>
83
$referrer_array = explode('#', $referrer);
84
$referrer = esc_url_raw($referrer_array[0] . '#' . $_REQUEST['tab_path']);
85
}
86
+ wp_safe_redirect($referrer);
87
exit();
88
}
89
//Migration
94
$failed = ( $result['fail'] > 0 ) ? $result['fail'] . ' images failed to migrate.' : '';
95
$EM_Notices->add_confirm('<strong>'.$result['success'].' images migrated successfully. '.$failed.'</strong>');
96
}
97
+ wp_safe_redirect(admin_url().'edit.php?post_type=event&page=events-manager-options&em_migrate_images');
98
}elseif( !empty($_GET['em_not_migrate_images']) && check_admin_referer('em_not_migrate_images','_wpnonce') ){
99
delete_option('dbem_migrate_images_nag');
100
delete_option('dbem_migrate_images');
134
$wpdb->query('DELETE FROM '.$wpdb->options.' WHERE option_name LIKE \'em_%\' OR option_name LIKE \'dbem_%\'');
135
//deactivate and go!
136
deactivate_plugins(array('events-manager/events-manager.php','events-manager-pro/events-manager-pro.php'), true);
137
+ wp_safe_redirect(admin_url('plugins.php?deactivate=true'));
138
exit();
139
}
140
}
154
}
155
//go back to plugin options page
156
$EM_Notices->add_confirm(__('Settings have been reset back to default. Your events, locations and categories have not been modified.','events-manager'), true);
157
+ wp_safe_redirect(em_wp_get_referer());
158
exit();
159
}
160
}
180
}
181
//go back to plugin options page
182
$EM_Notices->add_confirm(sprintf(__('Found %d orphaned events, deleted %d successfully','events-manager'), count($results), $deleted_events), true);
183
+ wp_safe_redirect(em_wp_get_referer());
184
exit();
185
}
186
//Force Update Recheck - Workaround for now
189
delete_transient('update_plugins');
190
delete_site_transient('update_plugins');
191
$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);
192
+ wp_safe_redirect(em_wp_get_referer());
193
exit();
194
}
195
//Flag version checking to look at trunk, not tag
199
delete_site_transient('update_plugins');
200
update_option('em_check_dev_version', true);
201
$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);
202
+ wp_safe_redirect(em_wp_get_referer());
203
exit();
204
}
205
//import EM settings
223
}
224
}
225
$EM_Notices->add_confirm(__('Settings imported.','events-manager'), true);
226
+ wp_safe_redirect(em_wp_get_referer());
227
exit();
228
}
229
}
230
$EM_Notices->add_error(__('Please upload a valid txt file containing Events Manager import settings.','events-manager'), true);
231
+ wp_safe_redirect(em_wp_get_referer());
232
exit();
233
}
234
//export EM settings
320
$EM_Notices->add_confirm(sprintf(__('Event timezones have been reset to %s.','events-manager'), '<code>'.$timezone.'</code>'), true);
321
}
322
}
323
+ wp_safe_redirect(em_wp_get_referer());
324
exit();
325
}
326
606
<?php
607
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') );
608
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') );
609
+ 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') );
610
+ em_options_radio_binary ( __( 'AutoTLS', 'events-manager'), 'dbem_smtp_autotls', __( 'We recommend leaving this on unless you are experiencing issues configuring your eamil.', 'events-manager') );
611
+ 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') );
612
em_options_input_text ( __( 'SMTP username', 'events-manager'), 'dbem_smtp_username', __( "Insert the username to be used to access your SMTP server.", 'events-manager') );
613
em_options_input_password ( __( 'SMTP password', 'events-manager'), "dbem_smtp_password", __( "Insert the password to be used to access your SMTP server", 'events-manager') );
614
?>
admin/settings/tabs/general.php CHANGED
@@ -315,8 +315,8 @@
315
<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>
316
<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>
317
<p>
318
- <a href="<?php echo $_SERVER['REQUEST_URI'] ?>&amp;em_migrate_images=1&amp;_wpnonce=<?php echo wp_create_nonce('em_migrate_images'); ?>" />Migrate Images</a><br />
319
- <a href="<?php echo $_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>
320
</p>
321
</div> <!-- . inside -->
322
</div> <!-- .postbox -->
315
<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>
316
<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>
317
<p>
318
+ <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 />
319
+ <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>
320
</p>
321
</div> <!-- . inside -->
322
</div> <!-- .postbox -->
admin/settings/updates/timezone-backcompat.php CHANGED
@@ -19,12 +19,12 @@ function em_admin_update_timezone_backcompat(){
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_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_redirect($redirect);
28
exit();
29
}
30
}
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
}
buddypress/bp-em-groups.php CHANGED
@@ -9,8 +9,8 @@ function bp_em_group_event_save($result, $EM_Event){
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(), $_REQUEST['group_id']) ){
13
- $EM_Event->group_id = $_REQUEST['group_id'];
14
}
15
if( !empty($EM_Event->group_id) ){
16
//if group is private, make it private
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
buddypress/screens/my-events.php CHANGED
@@ -5,7 +5,7 @@
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($_REQUEST['event_id']);
9
}
10
11
do_action( 'bp_em_my_events' );
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' );
buddypress/screens/my-locations.php CHANGED
@@ -5,7 +5,7 @@
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($_REQUEST['location_id']);
9
}
10
11
do_action( 'bp_em_my_locations' );
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' );
classes/em-booking.php CHANGED
@@ -27,6 +27,7 @@ function em_get_booking($id = false) {
27
}
28
/**
29
* Contains all information and relevant functions surrounding a single booking made with Events Manager
30
*/
31
class EM_Booking extends EM_Object{
32
//DB Fields
@@ -97,7 +98,7 @@ class EM_Booking extends EM_Object{
97
var $previous_status = false;
98
/**
99
* The booking approval status number corresponds to a state in this array.
100
- * @var unknown_type
101
*/
102
var $status_array = array();
103
/**
@@ -133,7 +134,7 @@ class EM_Booking extends EM_Object{
133
$booking = $booking_data;
134
}elseif( is_numeric($booking_data) ){
135
//Retrieving from the database
136
- $sql = "SELECT * FROM ". EM_BOOKINGS_TABLE ." WHERE booking_id ='$booking_data'";
137
$booking = $wpdb->get_row($sql, ARRAY_A);
138
}
139
//booking meta
@@ -169,14 +170,19 @@ class EM_Booking extends EM_Object{
169
if( $var == 'timestamp' ){
170
if( $this->date() === false ) return 0;
171
return $this->date()->getTimestampWithOffset();
172
}
173
return null;
174
}
175
176
public function __set( $prop, $val ){
177
if( $prop == 'timestamp' ){
178
- if( $this->date() !== false );
179
- $this->date()->setTimestamp($val);
180
}else{
181
$this->$prop = $val;
182
}
@@ -184,6 +190,7 @@ class EM_Booking extends EM_Object{
184
185
public function __isset( $prop ){
186
if( $prop == 'timestamp' ) return $this->date()->getTimestamp() > 0;
187
}
188
189
function get_notes(){
@@ -264,7 +271,7 @@ class EM_Booking extends EM_Object{
264
}
265
266
/**
267
- * Load an record into this object by passing an associative array of table criteria to search for.
268
* Returns boolean depending on whether a record is found or not.
269
* @param $search
270
* @return boolean
@@ -278,12 +285,12 @@ class EM_Booking extends EM_Object{
278
$conds[] = "`$key`='$value'";
279
}
280
}
281
- $sql = "SELECT * FROM ". $wpdb->EM_BOOKINGS_TABLE ." WHERE " . implode(' AND ', $conds) ;
282
$result = $wpdb->get_row($sql, ARRAY_A);
283
if($result){
284
$this->to_object($result);
285
$this->person = new EM_Person($this->person_id);
286
- return true;
287
}else{
288
return false;
289
}
@@ -297,12 +304,13 @@ class EM_Booking extends EM_Object{
297
$this->tickets_bookings = new EM_Tickets_Bookings($this->booking_id);
298
do_action('em_booking_get_post_pre',$this);
299
$result = array();
300
- $this->event_id = $_REQUEST['event_id'];
301
if( isset($_REQUEST['em_tickets']) && is_array($_REQUEST['em_tickets']) && ($_REQUEST['em_tickets'] || $override_availability) ){
302
foreach( $_REQUEST['em_tickets'] as $ticket_id => $values){
303
//make sure ticket exists
304
if( !empty($values['spaces']) || $override_availability ){
305
- $args = array('ticket_id'=>$ticket_id, 'ticket_booking_spaces'=>$values['spaces'], 'booking_id'=>$this->booking_id);
306
if($this->get_event()->get_bookings()->ticket_exists($ticket_id)){
307
$EM_Ticket_Booking = new EM_Ticket_Booking($args);
308
$EM_Ticket_Booking->booking = $this;
@@ -1021,6 +1029,7 @@ class EM_Booking extends EM_Object{
1021
}
1022
1023
function output($format, $target="html") {
1024
preg_match_all("/(#@?_?[A-Za-z0-9]+)({([^}]+)})?/", $format, $placeholders);
1025
foreach( $this->get_tickets() as $EM_Ticket){ /* @var $EM_Ticket EM_Ticket */ break; } //Get first ticket for single ticket placeholders
1026
$output_string = $format;
@@ -1119,21 +1128,22 @@ class EM_Booking extends EM_Object{
1119
}
1120
1121
/**
1122
- * @param EM_Booking $EM_Booking
1123
- * @param EM_Event $event
1124
* @return boolean
1125
*/
1126
function email( $email_admin = true, $force_resend = false, $email_attendee = true ){
1127
- global $EM_Mailer;
1128
$result = true;
1129
$this->mails_sent = 0;
1130
1131
- //FIXME ticket logic needed
1132
- $EM_Event = $this->get_event(); //We NEED event details here.
1133
- $EM_Event->get_bookings(true); //refresh all bookings
1134
1135
//Make sure event matches booking, and that booking used to be approved.
1136
if( $this->booking_status !== $this->previous_status || $force_resend ){
1137
//messages can be overridden just before being sent
1138
$msg = $this->email_messages();
1139
@@ -1173,8 +1183,9 @@ class EM_Booking extends EM_Object{
1173
}
1174
}
1175
}
1176
}
1177
- return $result;
1178
//TODO need error checking for booking mail send
1179
}
1180
@@ -1217,7 +1228,9 @@ class EM_Booking extends EM_Object{
1217
1218
/**
1219
* Returns an EM_DateTime representation of when booking was made in UTC timezone. If no valid date defined, false will be returned
1220
* @return EM_DateTime
1221
*/
1222
public function date( $utc_timezone = false ){
1223
if( empty($this->date) || !$this->date->valid ){
27
}
28
/**
29
* Contains all information and relevant functions surrounding a single booking made with Events Manager
30
+ * @property string $language
31
*/
32
class EM_Booking extends EM_Object{
33
//DB Fields
98
var $previous_status = false;
99
/**
100
* The booking approval status number corresponds to a state in this array.
101
+ * @var array
102
*/
103
var $status_array = array();
104
/**
134
$booking = $booking_data;
135
}elseif( is_numeric($booking_data) ){
136
//Retrieving from the database
137
+ $sql = $wpdb->prepare("SELECT * FROM ". EM_BOOKINGS_TABLE ." WHERE booking_id =%d", $booking_data);
138
$booking = $wpdb->get_row($sql, ARRAY_A);
139
}
140
//booking meta
170
if( $var == 'timestamp' ){
171
if( $this->date() === false ) return 0;
172
return $this->date()->getTimestampWithOffset();
173
+ }elseif( $var == 'language' ){
174
+ if( !empty($this->booking_meta['lang']) ){
175
+ return $this->booking_meta['lang'];
176
+ }
177
}
178
return null;
179
}
180
181
public function __set( $prop, $val ){
182
if( $prop == 'timestamp' ){
183
+ if( $this->date() !== false ) $this->date()->setTimestamp($val);
184
+ }elseif( $prop == 'language' ){
185
+ $this->booking_meta['lang'] = $val;
186
}else{
187
$this->$prop = $val;
188
}
190
191
public function __isset( $prop ){
192
if( $prop == 'timestamp' ) return $this->date()->getTimestamp() > 0;
193
+ if( $prop == 'language' ) return !empty($this->booking_meta['lang']);
194
}
195
196
function get_notes(){
271
}
272
273
/**
274
+ * Load a record into this object by passing an associative array of table criteria to search for.
275
* Returns boolean depending on whether a record is found or not.
276
* @param $search
277
* @return boolean
285
$conds[] = "`$key`='$value'";
286
}
287
}
288
+ $sql = "SELECT * FROM ". EM_BOOKINGS_TABLE ." WHERE " . implode(' AND ', $conds) ;
289
$result = $wpdb->get_row($sql, ARRAY_A);
290
if($result){
291
$this->to_object($result);
292
$this->person = new EM_Person($this->person_id);
293
+ return true;
294
}else{
295
return false;
296
}
304
$this->tickets_bookings = new EM_Tickets_Bookings($this->booking_id);
305
do_action('em_booking_get_post_pre',$this);
306
$result = array();
307
+ $this->event_id = absint($_REQUEST['event_id']);
308
if( isset($_REQUEST['em_tickets']) && is_array($_REQUEST['em_tickets']) && ($_REQUEST['em_tickets'] || $override_availability) ){
309
foreach( $_REQUEST['em_tickets'] as $ticket_id => $values){
310
//make sure ticket exists
311
+ $ticket_id = absint($ticket_id);
312
if( !empty($values['spaces']) || $override_availability ){
313
+ $args = array('ticket_id'=>$ticket_id, 'ticket_booking_spaces'=> absint($values['spaces']), 'booking_id'=>$this->booking_id);
314
if($this->get_event()->get_bookings()->ticket_exists($ticket_id)){
315
$EM_Ticket_Booking = new EM_Ticket_Booking($args);
316
$EM_Ticket_Booking->booking = $this;
1029
}
1030
1031
function output($format, $target="html") {
1032
+ do_action('em_booking_output_pre', $this, $format, $target);
1033
preg_match_all("/(#@?_?[A-Za-z0-9]+)({([^}]+)})?/", $format, $placeholders);
1034
foreach( $this->get_tickets() as $EM_Ticket){ /* @var $EM_Ticket EM_Ticket */ break; } //Get first ticket for single ticket placeholders
1035
$output_string = $format;
1128
}
1129
1130
/**
1131
+ * @param boolean $email_admin
1132
+ * @param boolean $force_resend
1133
+ * @param boolean $email_attendee
1134
* @return boolean
1135
*/
1136
function email( $email_admin = true, $force_resend = false, $email_attendee = true ){
1137
$result = true;
1138
$this->mails_sent = 0;
1139
1140
1141
//Make sure event matches booking, and that booking used to be approved.
1142
if( $this->booking_status !== $this->previous_status || $force_resend ){
1143
+ do_action('em_booking_email_before_send', $this);
1144
+ //get event info and refresh all bookings
1145
+ $EM_Event = $this->get_event(); //We NEED event details here.
1146
+ $EM_Event->get_bookings(true); //refresh all bookings
1147
//messages can be overridden just before being sent
1148
$msg = $this->email_messages();
1149
1183
}
1184
}
1185
}
1186
+ do_action('em_booking_email_after_send', $this);
1187
}
1188
+ return apply_filters('em_booking_email', $result, $this, $email_admin, $force_resend, $email_attendee);
1189
//TODO need error checking for booking mail send
1190
}
1191
1228
1229
/**
1230
* Returns an EM_DateTime representation of when booking was made in UTC timezone. If no valid date defined, false will be returned
1231
+ * @param boolean $utc_timezone
1232
* @return EM_DateTime
1233
+ * @throws Exception
1234
*/
1235
public function date( $utc_timezone = false ){
1236
if( empty($this->date) || !$this->date->valid ){
classes/em-bookings.php CHANGED
@@ -64,6 +64,7 @@ class EM_Bookings extends EM_Object implements Iterator{
64
if( $var == 'bookings' ){
65
return $this->load();
66
}
67
}
68
69
public function __set( $var, $val ){
@@ -74,6 +75,7 @@ class EM_Bookings extends EM_Object implements Iterator{
74
$this->bookings = null;
75
}
76
}
77
}
78
79
/**
@@ -90,7 +92,7 @@ class EM_Bookings extends EM_Object implements Iterator{
90
if( $var == 'bookings' ){
91
$result = $this->bookings !== null;
92
}
93
- return $result;
94
}
95
96
public function load( $refresh = false ){
@@ -598,7 +600,7 @@ class EM_Bookings extends EM_Object implements Iterator{
598
$where = ( count($conditions) > 0 ) ? " WHERE " . implode ( " AND ", $conditions ):'';
599
600
//Get ordering instructions
601
- $EM_Booking = em_get_booking();
602
$accepted_fields = $EM_Booking->get_fields(true);
603
$accepted_fields['date'] = 'booking_date';
604
$orderby = self::build_sql_orderby($args, $accepted_fields);
64
if( $var == 'bookings' ){
65
return $this->load();
66
}
67
+ return parent::__get( $var );
68
}
69
70
public function __set( $var, $val ){
75
$this->bookings = null;
76
}
77
}
78
+ parent::__set( $var, $val );
79
}
80
81
/**
92
if( $var == 'bookings' ){
93
$result = $this->bookings !== null;
94
}
95
+ return parent::__isset( $var );
96
}
97
98
public function load( $refresh = false ){
600
$where = ( count($conditions) > 0 ) ? " WHERE " . implode ( " AND ", $conditions ):'';
601
602
//Get ordering instructions
603
+ $EM_Booking = new EM_Booking();
604
$accepted_fields = $EM_Booking->get_fields(true);
605
$accepted_fields['date'] = 'booking_date';
606
$orderby = self::build_sql_orderby($args, $accepted_fields);
classes/em-event-post-admin.php CHANGED
@@ -79,7 +79,8 @@ class EM_Event_Post_Admin{
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
- $saving_status = !in_array($data['post_status'], array('trash','auto-draft')) && !defined('DOING_AUTOSAVE');
83
$untrashing = $post_ID && defined('UNTRASHING_'.$post_ID);
84
if( !$untrashing && $is_post_type && $saving_status ){
85
if( !empty($_REQUEST['_emnonce']) && wp_verify_nonce($_REQUEST['_emnonce'], 'edit_event') ){
@@ -101,7 +102,8 @@ class EM_Event_Post_Admin{
101
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
102
$post_type = get_post_type($post_id);
103
$is_post_type = $post_type == EM_POST_TYPE_EVENT || $post_type == 'event-recurring';
104
- $saving_status = !in_array(get_post_status($post_id), array('trash','auto-draft')) && !defined('DOING_AUTOSAVE');
105
$EM_EVENT_SAVE_POST = true; //first filter for save_post in EM for events
106
if(!defined('UNTRASHING_'.$post_id) && $is_post_type && $saving_status ){
107
//Reset server timezone to UTC in case other plugins are doing something naughty
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') ){
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
classes/em-event-posts-admin.php CHANGED
@@ -4,7 +4,7 @@ class EM_Event_Posts_Admin{
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', $_REQUEST['category_id'], EM_TAXONOMY_CATEGORY);
8
if( !empty($term->slug) ){
9
$_REQUEST['category_id'] = $term->slug;
10
}
@@ -63,7 +63,7 @@ class EM_Event_Posts_Admin{
63
64
public static function admin_notices(){
65
if( !empty($_REQUEST['recurrence_id']) && is_numeric($_REQUEST['recurrence_id']) ){
66
- $EM_Event = em_get_event($_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>
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
}
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>
classes/em-event.php CHANGED
@@ -26,7 +26,7 @@ function em_get_event($id = false, $search_by = 'event_id') {
26
$event_id = false;
27
if( is_numeric($id) ){
28
if( $search_by == 'event_id' ){
29
- $event_id = $id;
30
}elseif( $search_by == 'post_id' ){
31
$event_id = wp_cache_get($id, 'em_events_ids');
32
}
@@ -48,8 +48,16 @@ function em_get_event($id = false, $search_by = 'event_id') {
48
* An event object can be one of three "types" a recurring event, recurrence of a recurring event, or a single event.
49
* 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
50
* specifically done on this event. However, if you edit the recurring group, any changes made to single events are overwritten.
51
- *
52
- * @author marcus
53
*/
54
//TODO Can add more recurring functionality such as "also update all future recurring events" or "edit all events" like google calendar does.
55
//TODO Integrate recurrences into events table
@@ -58,6 +66,7 @@ class EM_Event extends EM_Object{
58
/* Field Names */
59
var $event_id;
60
var $post_id;
61
var $event_slug;
62
var $event_owner;
63
var $event_name;
@@ -117,8 +126,10 @@ class EM_Event extends EM_Object{
117
var $location_id;
118
var $recurrence_id;
119
var $event_status;
120
- var $blog_id;
121
- var $group_id;
122
/**
123
* Populated with the non-hidden event post custom fields (i.e. not starting with _)
124
* @var array
@@ -143,6 +154,7 @@ class EM_Event extends EM_Object{
143
var $fields = array(
144
'event_id' => array( 'name'=>'id', 'type'=>'%d' ),
145
'post_id' => array( 'name'=>'post_id', 'type'=>'%d' ),
146
'event_slug' => array( 'name'=>'slug', 'type'=>'%s', 'null'=>true ),
147
'event_owner' => array( 'name'=>'owner', 'type'=>'%d', 'null'=>true ),
148
'event_name' => array( 'name'=>'name', 'type'=>'%s', 'null'=>true ),
@@ -166,6 +178,8 @@ class EM_Event extends EM_Object{
166
'event_private' => array( 'name'=>'status', 'type'=>'%d', 'null'=>true ),
167
'blog_id' => array( 'name'=>'blog_id', 'type'=>'%d', 'null'=>true ),
168
'group_id' => array( 'name'=>'group_id', 'type'=>'%d', 'null'=>true ),
169
'recurrence' => array( 'name'=>'recurrence', 'type'=>'%d', 'null'=>true ), //is this a recurring event template
170
'recurrence_interval' => array( 'name'=>'interval', 'type'=>'%d', 'null'=>true ), //every x day(s)/week(s)/month(s)
171
'recurrence_freq' => array( 'name'=>'freq', 'type'=>'%s', 'null'=>true ), //daily,weekly,monthly?
@@ -177,6 +191,17 @@ class EM_Event extends EM_Object{
177
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
178
var $recurrence_fields = array('recurrence', 'recurrence_interval', 'recurrence_freq', 'recurrence_days', 'recurrence_byday', 'recurrence_byweekno', 'recurrence_rsvp_days');
179
180
var $image_url = '';
181
/**
182
* EM_DateTime of start date/time in local timezone.
@@ -225,7 +250,7 @@ class EM_Event extends EM_Object{
225
* If there are any errors, they will be added here.
226
* @var array
227
*/
228
- var $errors = array();
229
/**
230
* If something was successful, a feedback message might be supplied here.
231
* @var string
@@ -254,10 +279,10 @@ class EM_Event extends EM_Object{
254
*/
255
var $recurring_reschedule = false;
256
/**
257
- * If set to true, recurring events will delete bookings and tickets of recurrences and recreate tickets.
258
* @var boolean
259
*/
260
- var $recurring_recreate_bookings = false;
261
/**
262
* Flag used for when saving a recurring event that previously had bookings enabled and then subsequently disabled.
263
* If set to true, and $this->recurring_recreate_bookings is false, bookings and tickets of recurrences will be deleted.
@@ -298,18 +323,23 @@ class EM_Event extends EM_Object{
298
299
/**
300
* 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.
301
- * @param mixed $event_data
302
* @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.
303
- * @return null
304
*/
305
function __construct($id = false, $search_by = 'event_id') {
306
global $wpdb;
307
if( is_array($id) ){
308
//deal with the old array style, but we can't supply arrays anymore
309
- $id = (!empty($id['event_id'])) ? $id['event_id'] : $id['post_id'];
310
$search_by = (!empty($id['event_id'])) ? 'event_id':'post_id';
311
}
312
$is_post = !empty($id->ID) && ($id->post_type == EM_POST_TYPE_EVENT || $id->post_type == 'event-recurring');
313
if( is_numeric($id) || $is_post ){ //only load info if $id is a number
314
if($search_by == 'event_id' && !$is_post ){
315
//search by event_id, get post_id and blog_id (if in ms mode) and load the post
@@ -391,7 +421,7 @@ class EM_Event extends EM_Object{
391
if( $var == 'start' ) return $this->start()->getTimestampWithOffset();
392
if( $var == 'end' ) return $this->end()->getTimestampWithOffset();
393
if( $var == 'rsvp_end' ) return $this->rsvp_end()->getTimestampWithOffset();
394
- return null;
395
}
396
397
public function __set( $prop, $val ){
@@ -420,6 +450,7 @@ class EM_Event extends EM_Object{
420
else{
421
$this->$prop = $val;
422
}
423
}
424
425
public function __isset( $prop ){
@@ -430,6 +461,7 @@ class EM_Event extends EM_Object{
430
}elseif( $prop == 'start' || $prop == 'end' || $prop == 'rsvp_end' ){
431
return $this->$prop()->valid;
432
}
433
}
434
435
/**
@@ -444,7 +476,7 @@ class EM_Event extends EM_Object{
444
//load event post object if it's an actual object and also a post type of our event CPT names
445
if( is_object($event_post) && ($event_post->post_type == 'event-recurring' || $event_post->post_type == EM_POST_TYPE_EVENT) ){
446
//load post data - regardless
447
- $this->post_id = $event_post->ID;
448
$this->event_name = $event_post->post_title;
449
$this->event_owner = $event_post->post_author;
450
$this->post_content = $event_post->post_content;
@@ -518,6 +550,7 @@ class EM_Event extends EM_Object{
518
519
function get_event_meta($blog_id = false){
520
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
521
if( is_numeric($blog_id) && $blog_id > 0 && is_multisite() ){
522
// if in multisite mode, switch blogs quickly to get the right post meta.
523
switch_to_blog($blog_id);
@@ -532,7 +565,8 @@ class EM_Event extends EM_Object{
532
}else{
533
$event_meta = get_post_meta($this->post_id);
534
}
535
- return $event_meta;
536
}
537
538
/**
@@ -623,7 +657,7 @@ class EM_Event extends EM_Object{
623
if( !get_option('dbem_locations_enabled') || (!empty($_POST['no_location']) && !get_option('dbem_require_location',true)) || (empty($_POST['location_id']) && !get_option('dbem_require_location',true) && get_option('dbem_use_select_for_locations')) ){
624
$this->location_id = 0;
625
}elseif( !empty($_POST['location_id']) && is_numeric($_POST['location_id']) ){
626
- $this->location_id = $_POST['location_id'];
627
}else{
628
//we're adding a new location, so create an empty location and populate
629
$this->location_id = null;
@@ -695,7 +729,7 @@ class EM_Event extends EM_Object{
695
}
696
697
//group id
698
- $this->group_id = (!empty($_POST['group_id']) && is_numeric($_POST['group_id'])) ? $_POST['group_id']:0;
699
700
//Recurrence data
701
if( $this->is_recurring() ){
@@ -802,6 +836,10 @@ class EM_Event extends EM_Object{
802
$this->$recurrence_field = null;
803
}
804
}
805
//categories in MS GLobal
806
if(EM_MS_GLOBAL && !is_main_site() && get_option('dbem_categories_enabled') ){
807
$this->get_categories()->get_post(); //it'll know what to do
@@ -934,7 +972,8 @@ class EM_Event extends EM_Object{
934
$post_save = true;
935
//refresh this event with wp post info we'll put into the db
936
$post_data = get_post($post_id);
937
- $this->post_id = $post_id;
938
$this->event_slug = $post_data->post_name;
939
$this->event_owner = $post_data->post_author;
940
$this->post_status = $post_data->post_status;
@@ -980,16 +1019,24 @@ class EM_Event extends EM_Object{
980
}
981
982
function save_meta(){
983
- global $wpdb;
984
//sort out multisite blog id if appliable
985
if( is_multisite() && empty($this->blog_id) ){
986
$this->blog_id = get_current_blog_id();
987
}
988
//continue with saving if permissions allow
989
if( ( get_option('dbem_events_anonymous_submissions') && empty($this->event_id)) || $this->can_manage('edit_events', 'edit_others_events') ){
990
do_action('em_event_save_meta_pre', $this);
991
//first save location
992
if( empty($this->location_id) && !($this->location_id === 0 && !get_option('dbem_require_location',true)) ){
993
//proceed with location save
994
if( !$this->get_location()->save() ){ //soft fail
995
global $EM_Notices;
@@ -1010,7 +1057,8 @@ class EM_Event extends EM_Object{
1010
$save_meta_key = true;
1011
if( !$this->is_recurring() && in_array($key, $this->recurrence_fields) ) $save_meta_key = false;
1012
if( !$this->is_recurrence() && $key == 'recurrence_id' ) $save_meta_key = false;
1013
- $ignore_zero_keys = array('location_id', 'group_id', 'event_all_day' );
1014
if( in_array($key, $ignore_zero_keys) && empty($this->$key) ) $save_meta_key = false;
1015
if( $key == 'blog_id' ) $save_meta_key = false; //not needed, given postmeta is stored on the actual blog table in MultiSite
1016
//we don't need rsvp info if rsvp is not set, including the RSVP flag too
@@ -1154,6 +1202,7 @@ class EM_Event extends EM_Object{
1154
do_action('em_event_added', $this);
1155
}
1156
}
1157
return apply_filters('em_event_save_meta', count($this->errors) == 0, $this);
1158
}
1159
@@ -1518,6 +1567,17 @@ class EM_Event extends EM_Object{
1518
return apply_filters('em_event_get_categories', $this->categories, $this);
1519
}
1520
1521
/**
1522
* Returns the location object this event belongs to.
1523
* @return EM_Location
@@ -2296,7 +2356,7 @@ class EM_Event extends EM_Object{
2296
$gcal_url = str_replace('event_name', urlencode($this->event_name), $gcal_url);
2297
$gcal_url = str_replace('start_date', urlencode($dateStart), $gcal_url);
2298
$gcal_url = str_replace('end_date', urlencode($dateEnd), $gcal_url);
2299
- $gcal_url = str_replace('location_name', urlencode($this->output('#_LOCATION, #_LOCATIONADDRESS, #_LOCATIONCOUNTRY')), $gcal_url);
2300
$gcal_url = str_replace('blog_name', urlencode(get_bloginfo()), $gcal_url);
2301
$gcal_url = str_replace('event_url', urlencode($this->get_permalink()), $gcal_url);
2302
$gcal_url = str_replace('event_timezone', urlencode($this->event_timezone), $gcal_url);
@@ -2444,7 +2504,7 @@ class EM_Event extends EM_Object{
2444
* @return boolean
2445
*/
2446
function is_recurrence(){
2447
- return ( $this->event_id > 0 && $this->recurrence_id > 0 && get_option('dbem_recurrence_enabled') );
2448
}
2449
/**
2450
* Returns if this is an individual event and is not a recurrence
@@ -2516,9 +2576,10 @@ class EM_Event extends EM_Object{
2516
*/
2517
function save_events() {
2518
global $wpdb;
2519
- if( !$this->can_manage('edit_events','edit_others_events') ) return apply_filters('em_event_save_events', false, $this, $event_ids, $post_ids);
2520
- $event_ids = $post_ids = $event_dates = array();
2521
if( $this->is_published() || 'future' == $this->post_status ){
2522
//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.
2523
if( $wpdb->get_var('SELECT COUNT(event_id) FROM '.EM_EVENTS_TABLE.' WHERE recurrence_id='. absint($this->event_id)) == 0 ){
2524
$this->recurring_reschedule = true;
@@ -2613,7 +2674,7 @@ class EM_Event extends EM_Object{
2613
}
2614
//create the event
2615
if( $wpdb->insert($wpdb->posts, $post_fields ) ){
2616
- $event['post_id'] = $post_id = $post_ids[] = $wpdb->insert_id; //post id saved into event and also as a var for later user
2617
// Set GUID and event slug as per wp_insert_post
2618
$wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_id ) ), array('ID'=>$post_id) );
2619
//insert into events index table
@@ -2634,17 +2695,17 @@ class EM_Event extends EM_Object{
2634
if( count($meta_inserts) > 0 ){
2635
$result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
2636
if($result === false){
2637
- $this->add_error('There was a problem adding custom fields to your recurring events.','events-manager');
2638
}
2639
}
2640
}else{
2641
- $this->add_error('You have not defined a date range long enough to create a recurrence.','events-manager');
2642
$result = false;
2643
}
2644
}else{
2645
//we go through all event main data and meta data, we delete and recreate all meta data
2646
//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
2647
- unset( $event['event_date_created'], $event['recurrence_id'], $event['recurrence'], $event['event_start_date'], $event['event_end_date'] );
2648
$event['event_date_modified'] = current_time('mysql'); //since the recurrences are modified but not recreated
2649
unset( $post_fields['comment_count'], $post_fields['guid'], $post_fields['menu_order']);
2650
//now we go through the recurrences and check whether things relative to dates need to be changed
@@ -2659,7 +2720,7 @@ class EM_Event extends EM_Object{
2659
//set indexes for reference further down
2660
$event_ids[$event_array['post_id']] = $event_array['event_id'];
2661
$event_dates[$event_array['event_id']] = $start_timestamp;
2662
- $post_ids[] = $event_array['post_id'];
2663
//do we need to change the slugs?
2664
//(re)set post slug, which may need to be sanitized for length as we pre/postfix a date for uniqueness
2665
$EM_DateTime->setTimestamp($start_timestamp);
@@ -2702,12 +2763,12 @@ class EM_Event extends EM_Object{
2702
if( count($meta_inserts) > 0 ){
2703
$result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
2704
if($result === false){
2705
- $this->add_error('There was a problem adding custom fields to your recurring events.','events-manager');
2706
}
2707
}
2708
}
2709
//Next - Bookings. If we're completely rescheduling or just recreating bookings, we're deleting them and starting again
2710
- if( $this->recurring_reschedule || $this->recurring_recreate_bookings ){
2711
//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
2712
if( !$this->recurring_reschedule ){
2713
//create empty EM_Bookings and EM_Tickets objects to circumvent extra loading of data and SQL queries
@@ -2737,7 +2798,8 @@ class EM_Event extends EM_Object{
2737
}
2738
//unset id
2739
unset($ticket['ticket_id']);
2740
- //clean up ticket values
2741
foreach($ticket as $k => $v){
2742
if( empty($v) && $k != 'ticket_name' ){
2743
$ticket[$k] = 'NULL';
@@ -2755,12 +2817,12 @@ class EM_Event extends EM_Object{
2755
//sort out cut-of dates
2756
if( !empty($ticket_meta_recurrences) ){
2757
$EM_DateTime->setTimestamp($event_dates[$event_id]); //by using EM_DateTime we'll generate timezone aware dates
2758
- if( array_key_exists('start_days', $ticket_meta_recurrences) && $ticket_meta_recurrences['start_days'] !== false ){
2759
$ticket_start_days = $ticket_meta_recurrences['start_days'] >= 0 ? '+'. $ticket_meta_recurrences['start_days']: $ticket_meta_recurrences['start_days'];
2760
$ticket_start_date = $EM_DateTime->modify($ticket_start_days.' days')->getDate();
2761
$ticket['ticket_start'] = "'". $ticket_start_date . ' '. $ticket_meta_recurrences['start_time'] ."'";
2762
}
2763
- if( array_key_exists('end_days', $ticket_meta_recurrences) && $ticket_meta_recurrences['end_days'] !== false ){
2764
$ticket_end_days = $ticket_meta_recurrences['end_days'] >= 0 ? '+'. $ticket_meta_recurrences['end_days']: $ticket_meta_recurrences['end_days'];
2765
$EM_DateTime->setTimestamp($event_dates[$event_id]);
2766
$ticket_end_date = $EM_DateTime->modify($ticket_end_days.' days')->getDate();
@@ -2861,8 +2923,7 @@ class EM_Event extends EM_Object{
2861
}
2862
2863
/**
2864
- * Removes all reoccurring events.
2865
- * @param $recurrence_id
2866
* @return null
2867
*/
2868
function delete_events(){
@@ -2870,17 +2931,23 @@ class EM_Event extends EM_Object{
2870
do_action('em_event_delete_events_pre', $this);
2871
//So we don't do something we'll regret later, we could just supply the get directly into the delete, but this is safer
2872
$result = false;
2873
if( $this->can_manage('delete_events', 'delete_others_events') ){
2874
//delete events from em_events table
2875
- $events_array = EM_Events::get( array('recurrence_id'=>$this->event_id, 'scope'=>'all', 'status'=>'everything' ) );
2876
- foreach($events_array as $EM_Event){
2877
- /* @var $EM_Event EM_Event */
2878
if($EM_Event->recurrence_id == $this->event_id){
2879
$EM_Event->delete(true);
2880
}
2881
- }
2882
}
2883
- return apply_filters('delete_events', $result, $this, $events_array);
2884
}
2885
2886
/**
26
$event_id = false;
27
if( is_numeric($id) ){
28
if( $search_by == 'event_id' ){
29
+ $event_id = absint($id);
30
}elseif( $search_by == 'post_id' ){
31
$event_id = wp_cache_get($id, 'em_events_ids');
32
}
48
* An event object can be one of three "types" a recurring event, recurrence of a recurring event, or a single event.
49
* 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
50
* specifically done on this event. However, if you edit the recurring group, any changes made to single events are overwritten.
51
+ *
52
+ * @property string $language Language of the event, shorthand for event_language
53
+ * @property string $translation Whether or not a event is a translation (i.e. it was translated from an original event), shorthand for event_translation
54
+ * @property int $parent Event ID of parent event, shorthand for event_parent
55
+ * @property int $id The Event ID, case sensitive, shorthand for event_id
56
+ * @property string $slug Event slug, shorthand for event_slug
57
+ * @property string name Event name, shorthand for event_name
58
+ * @property int owner ID of author/owner, shorthand for event_owner
59
+ * @property int status ID of post status, shorthand for event_status
60
+ *
61
*/
62
//TODO Can add more recurring functionality such as "also update all future recurring events" or "edit all events" like google calendar does.
63
//TODO Integrate recurrences into events table
66
/* Field Names */
67
var $event_id;
68
var $post_id;
69
+ var $event_parent;
70
var $event_slug;
71
var $event_owner;
72
var $event_name;
126
var $location_id;
127
var $recurrence_id;
128
var $event_status;
129
+ var $blog_id = 0;
130
+ var $group_id;
131
+ var $event_language;
132
+ var $event_translation = 0;
133
/**
134
* Populated with the non-hidden event post custom fields (i.e. not starting with _)
135
* @var array
154
var $fields = array(
155
'event_id' => array( 'name'=>'id', 'type'=>'%d' ),
156
'post_id' => array( 'name'=>'post_id', 'type'=>'%d' ),
157
+ 'event_parent' => array( 'type'=>'%d', 'null'=>true ),
158
'event_slug' => array( 'name'=>'slug', 'type'=>'%s', 'null'=>true ),
159
'event_owner' => array( 'name'=>'owner', 'type'=>'%d', 'null'=>true ),
160
'event_name' => array( 'name'=>'name', 'type'=>'%s', 'null'=>true ),
178
'event_private' => array( 'name'=>'status', 'type'=>'%d', 'null'=>true ),
179
'blog_id' => array( 'name'=>'blog_id', 'type'=>'%d', 'null'=>true ),
180
'group_id' => array( 'name'=>'group_id', 'type'=>'%d', 'null'=>true ),
181
+ 'event_language' => array( 'type'=>'%s', 'null'=>true ),
182
+ 'event_translation' => array( 'type'=>'%d'),
183
'recurrence' => array( 'name'=>'recurrence', 'type'=>'%d', 'null'=>true ), //is this a recurring event template
184
'recurrence_interval' => array( 'name'=>'interval', 'type'=>'%d', 'null'=>true ), //every x day(s)/week(s)/month(s)
185
'recurrence_freq' => array( 'name'=>'freq', 'type'=>'%s', 'null'=>true ), //daily,weekly,monthly?
191
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
192
var $recurrence_fields = array('recurrence', 'recurrence_interval', 'recurrence_freq', 'recurrence_days', 'recurrence_byday', 'recurrence_byweekno', 'recurrence_rsvp_days');
193
194
+ protected $shortnames = array(
195
+ 'language' => 'event_language',
196
+ 'translation' => 'event_translation',
197
+ 'parent' => 'event_parent',
198
+ 'id' => 'event_id',
199
+ 'slug' => 'event_slug',
200
+ 'name' => 'event_name',
201
+ 'status' => 'event_status',
202
+ 'owner' => 'event_owner',
203
+ );
204
+
205
var $image_url = '';
206
/**
207
* EM_DateTime of start date/time in local timezone.
250
* If there are any errors, they will be added here.
251
* @var array
252
*/
253
+ var $errors = array();
254
/**
255
* If something was successful, a feedback message might be supplied here.
256
* @var string
279
*/
280
var $recurring_reschedule = false;
281
/**
282
+ * 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.
283
* @var boolean
284
*/
285
+ var $recurring_recreate_bookings;
286
/**
287
* Flag used for when saving a recurring event that previously had bookings enabled and then subsequently disabled.
288
* If set to true, and $this->recurring_recreate_bookings is false, bookings and tickets of recurrences will be deleted.
323
324
/**
325
* 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.
326
+ * @param mixed $id
327
* @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.
328
*/
329
function __construct($id = false, $search_by = 'event_id') {
330
global $wpdb;
331
if( is_array($id) ){
332
//deal with the old array style, but we can't supply arrays anymore
333
+ $id = (!empty($id['event_id'])) ? absint($id['event_id']) : absint($id['post_id']);
334
$search_by = (!empty($id['event_id'])) ? 'event_id':'post_id';
335
}
336
$is_post = !empty($id->ID) && ($id->post_type == EM_POST_TYPE_EVENT || $id->post_type == 'event-recurring');
337
+ if( $is_post ){
338
+ $id->ID = absint($id->ID);
339
+ }else{
340
+ $id = absint($id);
341
+ if( $id == 0 ) $id = false;
342
+ }
343
if( is_numeric($id) || $is_post ){ //only load info if $id is a number
344
if($search_by == 'event_id' && !$is_post ){
345
//search by event_id, get post_id and blog_id (if in ms mode) and load the post
421
if( $var == 'start' ) return $this->start()->getTimestampWithOffset();
422
if( $var == 'end' ) return $this->end()->getTimestampWithOffset();
423
if( $var == 'rsvp_end' ) return $this->rsvp_end()->getTimestampWithOffset();
424
+ return parent::__get( $var );
425
}
426
427
public function __set( $prop, $val ){
450
else{
451
$this->$prop = $val;
452
}
453
+ parent::__set( $prop, $val );
454
}
455
456
public function __isset( $prop ){
461
}elseif( $prop == 'start' || $prop == 'end' || $prop == 'rsvp_end' ){
462
return $this->$prop()->valid;
463
}
464
+ return parent::__isset( $prop );
465
}
466
467
/**
476
//load event post object if it's an actual object and also a post type of our event CPT names
477
if( is_object($event_post) && ($event_post->post_type == 'event-recurring' || $event_post->post_type == EM_POST_TYPE_EVENT) ){
478
//load post data - regardless
479
+ $this->post_id = absint($event_post->ID);
480
$this->event_name = $event_post->post_title;
481
$this->event_owner = $event_post->post_author;
482
$this->post_content = $event_post->post_content;
550
551
function get_event_meta($blog_id = false){
552
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
553
+ if( empty($this->post_id) ) return array();
554
if( is_numeric($blog_id) && $blog_id > 0 && is_multisite() ){
555
// if in multisite mode, switch blogs quickly to get the right post meta.
556
switch_to_blog($blog_id);
565
}else{
566
$event_meta = get_post_meta($this->post_id);
567
}
568
+ if( !is_array($event_meta) ) $event_meta = array();
569
+ return apply_filters('em_event_get_event_meta', $event_meta);
570
}
571
572
/**
657
if( !get_option('dbem_locations_enabled') || (!empty($_POST['no_location']) && !get_option('dbem_require_location',true)) || (empty($_POST['location_id']) && !get_option('dbem_require_location',true) && get_option('dbem_use_select_for_locations')) ){
658
$this->location_id = 0;
659
}elseif( !empty($_POST['location_id']) && is_numeric($_POST['location_id']) ){
660
+ $this->location_id = absint($_POST['location_id']);
661
}else{
662
//we're adding a new location, so create an empty location and populate
663
$this->location_id = null;
729
}
730
731
//group id
732
+ $this->group_id = (!empty($_POST['group_id']) && is_numeric($_POST['group_id'])) ? absint($_POST['group_id']):0;
733
734
//Recurrence data
735
if( $this->is_recurring() ){
836
$this->$recurrence_field = null;
837
}
838
}
839
+ //event language
840
+ if( EM_ML::$is_ml && !empty($_POST['event_language']) && array_key_exists($_POST['event_language'], EM_ML::$langs) ){
841
+ $this->event_language = $_POST['event_language'];
842
+ }
843
//categories in MS GLobal
844
if(EM_MS_GLOBAL && !is_main_site() && get_option('dbem_categories_enabled') ){
845
$this->get_categories()->get_post(); //it'll know what to do
972
$post_save = true;
973
//refresh this event with wp post info we'll put into the db
974
$post_data = get_post($post_id);
975
+ $this->post_id = $this->ID = $post_id;
976
+ $this->post_type = $post_data->post_type;
977
$this->event_slug = $post_data->post_name;
978
$this->event_owner = $post_data->post_author;
979
$this->post_status = $post_data->post_status;
1019
}
1020
1021
function save_meta(){
1022
+ global $wpdb, $EM_SAVING_EVENT;
1023
+ $EM_SAVING_EVENT = true;
1024
//sort out multisite blog id if appliable
1025
if( is_multisite() && empty($this->blog_id) ){
1026
$this->blog_id = get_current_blog_id();
1027
}
1028
+ //trigger setting of event_end and event_start in case it hasn't been set already
1029
+ $this->start();
1030
+ $this->end();
1031
//continue with saving if permissions allow
1032
if( ( get_option('dbem_events_anonymous_submissions') && empty($this->event_id)) || $this->can_manage('edit_events', 'edit_others_events') ){
1033
do_action('em_event_save_meta_pre', $this);
1034
+ //language default
1035
+ if( !$this->event_language ) $this->event_language = EM_ML::$current_language;
1036
//first save location
1037
if( empty($this->location_id) && !($this->location_id === 0 && !get_option('dbem_require_location',true)) ){
1038
+ //pass language on
1039
+ $this->get_location()->location_language = $this->event_language;
1040
//proceed with location save
1041
if( !$this->get_location()->save() ){ //soft fail
1042
global $EM_Notices;
1057
$save_meta_key = true;
1058
if( !$this->is_recurring() && in_array($key, $this->recurrence_fields) ) $save_meta_key = false;
1059
if( !$this->is_recurrence() && $key == 'recurrence_id' ) $save_meta_key = false;
1060
+ if( !EM_ML::$is_ml && $key == 'event_language' ) $save_meta_key = false;
1061
+ $ignore_zero_keys = array('location_id', 'group_id', 'event_all_day', 'event_parent', 'event_translation');
1062
if( in_array($key, $ignore_zero_keys) && empty($this->$key) ) $save_meta_key = false;
1063
if( $key == 'blog_id' ) $save_meta_key = false; //not needed, given postmeta is stored on the actual blog table in MultiSite
1064
//we don't need rsvp info if rsvp is not set, including the RSVP flag too
1202
do_action('em_event_added', $this);
1203
}
1204
}
1205
+ $EM_SAVING_EVENT = false;
1206
return apply_filters('em_event_save_meta', count($this->errors) == 0, $this);
1207
}
1208
1567
return apply_filters('em_event_get_categories', $this->categories, $this);
1568
}
1569
1570
+ /**
1571
+ * Gets the parent of this event, if none exists, null is returned.
1572
+ * @return EM_Event|null
1573
+ */
1574
+ public function get_parent(){
1575
+ if( $this->event_parent ){
1576
+ return em_get_event( $this->event_parent );
1577
+ }
1578
+ return null;
1579
+ }
1580
+
1581
/**
1582
* Returns the location object this event belongs to.
1583
* @return EM_Location
2356
$gcal_url = str_replace('event_name', urlencode($this->event_name), $gcal_url);
2357
$gcal_url = str_replace('start_date', urlencode($dateStart), $gcal_url);
2358
$gcal_url = str_replace('end_date', urlencode($dateEnd), $gcal_url);
2359
+ $gcal_url = str_replace('location_name', urlencode($this->get_location()->get_full_address(', ', true)), $gcal_url);
2360
$gcal_url = str_replace('blog_name', urlencode(get_bloginfo()), $gcal_url);
2361
$gcal_url = str_replace('event_url', urlencode($this->get_permalink()), $gcal_url);
2362
$gcal_url = str_replace('event_timezone', urlencode($this->event_timezone), $gcal_url);
2504
* @return boolean
2505
*/
2506
function is_recurrence(){
2507
+ return ( $this->recurrence_id > 0 && get_option('dbem_recurrence_enabled') );
2508
}
2509
/**
2510
* Returns if this is an individual event and is not a recurrence
2576
*/
2577
function save_events() {
2578
global $wpdb;
2579
+ if( !$this->can_manage('edit_events','edit_others_events') ) return apply_filters('em_event_save_events', false, $this, array(), array());
2580
+ $event_ids = $post_ids = $event_dates = $events = array();
2581
if( $this->is_published() || 'future' == $this->post_status ){
2582
+ $result = false;
2583
//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.
2584
if( $wpdb->get_var('SELECT COUNT(event_id) FROM '.EM_EVENTS_TABLE.' WHERE recurrence_id='. absint($this->event_id)) == 0 ){
2585
$this->recurring_reschedule = true;
2674
}
2675
//create the event
2676
if( $wpdb->insert($wpdb->posts, $post_fields ) ){
2677
+ $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
2678
// Set GUID and event slug as per wp_insert_post
2679
$wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_id ) ), array('ID'=>$post_id) );
2680
//insert into events index table
2695
if( count($meta_inserts) > 0 ){
2696
$result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
2697
if($result === false){
2698
+ $this->add_error(esc_html__('There was a problem adding custom fields to your recurring events.','events-manager'));
2699
}
2700
}
2701
}else{
2702
+ $this->add_error(esc_html__('You have not defined a date range long enough to create a recurrence.','events-manager'));
2703
$result = false;
2704
}
2705
}else{
2706
//we go through all event main data and meta data, we delete and recreate all meta data
2707
//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
2708
+ unset( $event['event_date_created'], $event['recurrence_id'], $event['recurrence'], $event['event_start_date'], $event['event_end_date'], $event['event_parent'] );
2709
$event['event_date_modified'] = current_time('mysql'); //since the recurrences are modified but not recreated
2710
unset( $post_fields['comment_count'], $post_fields['guid'], $post_fields['menu_order']);
2711
//now we go through the recurrences and check whether things relative to dates need to be changed
2720
//set indexes for reference further down
2721
$event_ids[$event_array['post_id']] = $event_array['event_id'];
2722
$event_dates[$event_array['event_id']] = $start_timestamp;
2723
+ $post_ids[$start_timestamp] = $event_array['post_id'];
2724
//do we need to change the slugs?
2725
//(re)set post slug, which may need to be sanitized for length as we pre/postfix a date for uniqueness
2726
$EM_DateTime->setTimestamp($start_timestamp);
2763
if( count($meta_inserts) > 0 ){
2764
$result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
2765
if($result === false){
2766
+ $this->add_error(esc_html__('There was a problem adding custom fields to your recurring events.','events-manager'));
2767
}
2768
}
2769
}
2770
//Next - Bookings. If we're completely rescheduling or just recreating bookings, we're deleting them and starting again
2771
+ 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)
2772
//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
2773
if( !$this->recurring_reschedule ){
2774
//create empty EM_Bookings and EM_Tickets objects to circumvent extra loading of data and SQL queries
2798
}
2799
//unset id
2800
unset($ticket['ticket_id']);
2801
+ $ticket['ticket_parent'] = $EM_Ticket->ticket_id;
2802
+ //clean up ticket values
2803
foreach($ticket as $k => $v){
2804
if( empty($v) && $k != 'ticket_name' ){
2805
$ticket[$k] = 'NULL';
2817
//sort out cut-of dates
2818
if( !empty($ticket_meta_recurrences) ){
2819
$EM_DateTime->setTimestamp($event_dates[$event_id]); //by using EM_DateTime we'll generate timezone aware dates
2820
+ if( array_key_exists('start_days', $ticket_meta_recurrences) && $ticket_meta_recurrences['start_days'] !== false && $ticket_meta_recurrences['start_days'] !== null ){
2821
$ticket_start_days = $ticket_meta_recurrences['start_days'] >= 0 ? '+'. $ticket_meta_recurrences['start_days']: $ticket_meta_recurrences['start_days'];
2822
$ticket_start_date = $EM_DateTime->modify($ticket_start_days.' days')->getDate();
2823
$ticket['ticket_start'] = "'". $ticket_start_date . ' '. $ticket_meta_recurrences['start_time'] ."'";
2824
}
2825
+ if( array_key_exists('end_days', $ticket_meta_recurrences) && $ticket_meta_recurrences['end_days'] !== false && $ticket_meta_recurrences['end_days'] !== null ){
2826
$ticket_end_days = $ticket_meta_recurrences['end_days'] >= 0 ? '+'. $ticket_meta_recurrences['end_days']: $ticket_meta_recurrences['end_days'];
2827
$EM_DateTime->setTimestamp($event_dates[$event_id]);
2828
$ticket_end_date = $EM_DateTime->modify($ticket_end_days.' days')->getDate();
2923
}
2924
2925
/**
2926
+ * Removes all recurrences of a recurring event.
2927
* @return null
2928
*/
2929
function delete_events(){
2931
do_action('em_event_delete_events_pre', $this);
2932
//So we don't do something we'll regret later, we could just supply the get directly into the delete, but this is safer
2933
$result = false;
2934
+ $events_array = array();
2935
if( $this->can_manage('delete_events', 'delete_others_events') ){
2936
//delete events from em_events table
2937
+ $sql = $wpdb->prepare('SELECT event_id FROM '.EM_EVENTS_TABLE.' WHERE (recurrence!=1 OR recurrence IS NULL) AND recurrence_id=%d', $this->event_id);
2938
+ $event_ids = $wpdb->get_col( $sql );
2939
+ // go through each event and delete individually so individual hooks are fired appropriately
2940
+ foreach($event_ids as $event_id){
2941
+ $EM_Event = em_get_event( $event_id );
2942
if($EM_Event->recurrence_id == $this->event_id){
2943
$EM_Event->delete(true);
2944
+ $events_array[] = $EM_Event;
2945
}
2946
+ }
2947
+ $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
2948
}
2949
+ $result = apply_filters('delete_events', $result, $this, $events_array); //Deprecated, use em_event_delete_events
2950
+ return apply_filters('em_event_delete_events', $result, $this, $events_array);
2951
}
2952
2953
/**
classes/em-events.php CHANGED
@@ -20,6 +20,8 @@ class EM_Events extends EM_Object {
20
*/
21
public static $num_rows_found;
22
23
/**
24
* Returns an array of EM_Events that match the given specs in the argument, or returns a list of future evetnts in future
25
* (see EM_Events::get_default_search() ) for explanation of possible search array values. You can also supply a numeric array
@@ -515,7 +517,6 @@ $limit $offset";
515
* @see wp-content/plugins/events-manager/classes/EM_Object#build_sql_conditions()
516
*/
517
public static function build_sql_conditions( $args = array() ){
518
- self::$context = EM_POST_TYPE_EVENT;
519
global $wpdb;
520
//continue with conditions
521
$conditions = parent::build_sql_conditions($args);
@@ -636,7 +637,6 @@ $limit $offset";
636
* @uses EM_Object#get_default_search()
637
*/
638
public static function get_default_search( $array_or_defaults = array(), $array = array() ){
639
- self::$context = EM_POST_TYPE_EVENT;
640
$defaults = array(
641
'recurring' => false, //we don't initially look for recurring events only events and recurrences of recurring events
642
'orderby' => get_option('dbem_events_default_orderby'),
20
*/
21
public static $num_rows_found;
22
23
+ protected static $context = 'event';
24
+
25
/**
26
* Returns an array of EM_Events that match the given specs in the argument, or returns a list of future evetnts in future
27
* (see EM_Events::get_default_search() ) for explanation of possible search array values. You can also supply a numeric array
517
* @see wp-content/plugins/events-manager/classes/EM_Object#build_sql_conditions()
518
*/
519
public static function build_sql_conditions( $args = array() ){
520
global $wpdb;
521
//continue with conditions
522
$conditions = parent::build_sql_conditions($args);
637
* @uses EM_Object#get_default_search()
638
*/
639
public static function get_default_search( $array_or_defaults = array(), $array = array() ){
640
$defaults = array(
641
'recurring' => false, //we don't initially look for recurring events only events and recurrences of recurring events
642
'orderby' => get_option('dbem_events_default_orderby'),
classes/em-location-post-admin.php CHANGED
@@ -57,7 +57,8 @@ class EM_Location_Post_Admin{
57
$post_type = $data['post_type'];
58
$post_ID = !empty($postarr['ID']) ? $postarr['ID'] : false;
59
$is_post_type = $post_type == EM_POST_TYPE_LOCATION;
60
- $saving_status = !in_array($data['post_status'], array('trash','auto-draft')) && !defined('DOING_AUTOSAVE');
61
$untrashing = $post_ID && defined('UNTRASHING_'.$post_ID);
62
if( !$untrashing && $is_post_type && $saving_status ){
63
if( !empty($_REQUEST['_emnonce']) && wp_verify_nonce($_REQUEST['_emnonce'], 'edit_location') ){
@@ -80,7 +81,8 @@ class EM_Location_Post_Admin{
80
public static function save_post($post_id){
81
global $wpdb, $EM_Location, $EM_Notices, $EM_SAVING_LOCATION;
82
if( !empty($EM_SAVING_LOCATION) ) return; //If we're saving a location via EM_Location::save() we should never run the below
83
- $saving_status = !in_array(get_post_status($post_id), array('trash','auto-draft')) && !defined('DOING_AUTOSAVE');
84
$is_post_type = get_post_type($post_id) == EM_POST_TYPE_LOCATION;
85
if(!defined('UNTRASHING_'.$post_id) && $is_post_type && $saving_status){
86
if( !empty($_REQUEST['_emnonce']) && wp_verify_nonce($_REQUEST['_emnonce'], 'edit_location')){
57
$post_type = $data['post_type'];
58
$post_ID = !empty($postarr['ID']) ? $postarr['ID'] : false;
59
$is_post_type = $post_type == EM_POST_TYPE_LOCATION;
60
+ $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
61
+ $saving_status = !in_array($data['post_status'], array('trash','auto-draft')) && !defined('DOING_AUTOSAVE') && !$doing_add_meta_ajax;
62
$untrashing = $post_ID && defined('UNTRASHING_'.$post_ID);
63
if( !$untrashing && $is_post_type && $saving_status ){
64
if( !empty($_REQUEST['_emnonce']) && wp_verify_nonce($_REQUEST['_emnonce'], 'edit_location') ){
81
public static function save_post($post_id){
82
global $wpdb, $EM_Location, $EM_Notices, $EM_SAVING_LOCATION;
83
if( !empty($EM_SAVING_LOCATION) ) return; //If we're saving a location via EM_Location::save() we should never run the below
84
+ $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
85
+ $saving_status = !in_array(get_post_status($post_id), array('trash','auto-draft')) && !defined('DOING_AUTOSAVE') && !$doing_add_meta_ajax;
86
$is_post_type = get_post_type($post_id) == EM_POST_TYPE_LOCATION;
87
if(!defined('UNTRASHING_'.$post_id) && $is_post_type && $saving_status){
88
if( !empty($_REQUEST['_emnonce']) && wp_verify_nonce($_REQUEST['_emnonce'], 'edit_location')){
classes/em-location.php CHANGED
@@ -1,6 +1,6 @@
1
<?php
2
/**
3
- * Get an event in a db friendly way, by checking globals, cache and passed variables to avoid extra class instantiations.
4
* @param mixed $id
5
* @param mixed $search_by
6
* @return EM_Location
@@ -44,13 +44,22 @@ function em_get_location($id = false, $search_by = 'location_id') {
44
}
45
/**
46
* Object that holds location info and related functions
47
- * @author marcus
48
*/
49
class EM_Location extends EM_Object {
50
//DB Fields
51
var $location_id = '';
52
var $post_id = '';
53
- var $blog_id = '';
54
var $location_slug = '';
55
var $location_name = '';
56
var $location_address = '';
@@ -64,6 +73,8 @@ class EM_Location extends EM_Object {
64
var $post_content = '';
65
var $location_owner = '';
66
var $location_status = 0;
67
/* anonymous submission information */
68
var $owner_anonymous;
69
var $owner_name;
@@ -73,6 +84,7 @@ class EM_Location extends EM_Object {
73
'location_id' => array('name'=>'id','type'=>'%d'),
74
'post_id' => array('name'=>'post_id','type'=>'%d'),
75
'blog_id' => array('name'=>'blog_id','type'=>'%d'),
76
'location_slug' => array('name'=>'slug','type'=>'%s', 'null'=>true),
77
'location_name' => array('name'=>'name','type'=>'%s', 'null'=>true),
78
'location_address' => array('name'=>'address','type'=>'%s','null'=>true),
@@ -85,7 +97,24 @@ class EM_Location extends EM_Object {
85
'location_longitude' => array('name'=>'longitude','type'=>'%f','null'=>true),
86
'post_content' => array('name'=>'description','type'=>'%s', 'null'=>true),
87
'location_owner' => array('name'=>'owner','type'=>'%d', 'null'=>true),
88
- 'location_status' => array('name'=>'status','type'=>'%d', 'null'=>true)
89
);
90
var $post_fields = array('post_id','location_slug','location_status', 'location_name','post_content','location_owner');
91
var $location_attributes = array();
@@ -132,7 +161,6 @@ class EM_Location extends EM_Object {
132
* Gets data from POST (default), supplied array, or from the database if an ID is supplied
133
* @param WP_Post|int|false $id
134
* @param $search_by - Can be post_id or a number for a blog id if in ms mode with global tables, default is location_id
135
- * @return null
136
*/
137
function __construct($id = false, $search_by = 'location_id' ) {
138
global $wpdb;
@@ -140,6 +168,11 @@ class EM_Location extends EM_Object {
140
$this->required_fields = array("location_address" => __('The location address', 'events-manager'), "location_town" => __('The location town', 'events-manager'), "location_country" => __('The country', 'events-manager'));
141
//Get the post_id/location_id
142
$is_post = !empty($id->ID) && $id->post_type == EM_POST_TYPE_LOCATION;
143
if( $is_post || absint($id) > 0 ){ //only load info if $id is a number
144
$location_post = false;
145
if($search_by == 'location_id' && !$is_post){
@@ -292,6 +325,10 @@ class EM_Location extends EM_Object {
292
}
293
}
294
}
295
//the line below should be deleted one day and we move validation out of this function, when that happens check otherfunctions like EM_ML_IO::get_post_meta function which force validation again
296
$result = $validate ? $this->validate_meta():true; //post returns null
297
$this->compat_keys();
@@ -391,7 +428,8 @@ class EM_Location extends EM_Object {
391
$post_save = true;
392
//refresh this event with wp post
393
$post_data = get_post($post_id);
394
- $this->post_id = $post_id;
395
$this->location_slug = $post_data->post_name;
396
$this->location_owner = $post_data->post_author;
397
$this->post_status = $post_data->post_status;
@@ -431,6 +469,8 @@ class EM_Location extends EM_Object {
431
global $wpdb;
432
if( $this->can_manage('edit_locations','edit_others_locations') || ( get_option('dbem_events_anonymous_submissions') && empty($this->location_id)) ){
433
do_action('em_location_save_meta_pre', $this);
434
//Set Blog ID if in multisite mode
435
if( EM_MS_GLOBAL && get_site_option('dbem_ms_mainblog_locations') ){
436
$this->blog_id = get_current_site()->blog_id; //global locations restricted to main blog must have main site id
@@ -440,6 +480,7 @@ class EM_Location extends EM_Object {
440
//Update Post Meta
441
$current_meta_values = get_post_meta($this->post_id);
442
foreach( array_keys($this->fields) as $key ){
443
if( !in_array($key, $this->post_fields) && $key != 'blog_id' && $this->$key != '' ){
444
update_post_meta($this->post_id, '_'.$key, $this->$key);
445
}elseif( array_key_exists('_'.$key, $current_meta_values) ){ //we should delete event_attributes, but maybe something else uses it without us knowing
@@ -603,7 +644,18 @@ class EM_Location extends EM_Object {
603
$result = $wpdb->query($wpdb->prepare("UPDATE ".EM_LOCATIONS_TABLE." SET location_status=$set_status, location_slug=%s WHERE location_id=%d", array($this->post_name, $this->location_id)));
604
$this->get_status(); //reload status
605
return apply_filters('em_location_set_status', $result !== false, $status, $this);
606
- }
607
608
function get_status($db = false){
609
switch( $this->post_status ){
@@ -1080,13 +1132,14 @@ class EM_Location extends EM_Object {
1080
1081
}
1082
1083
- function get_full_address($glue = ', '){
1084
$location_array = array();
1085
if( !empty($this->location_address) ) $location_array[] = $this->location_address;
1086
if( !empty($this->location_town) ) $location_array[] = $this->location_town;
1087
if( !empty($this->location_state) ) $location_array[] = $this->location_state;
1088
if( !empty($this->location_postcode) ) $location_array[] = $this->location_postcode;
1089
if( !empty($this->location_region) ) $location_array[] = $this->location_region;
1090
return implode($glue, $location_array);
1091
}
1092
1
<?php
2
/**
3
+ * Get a location in a db friendly way, by checking globals, cache and passed variables to avoid extra class instantiations.
4
* @param mixed $id
5
* @param mixed $search_by
6
* @return EM_Location
44
}
45
/**
46
* Object that holds location info and related functions
47
+ *
48
+ * @property string $language Language of the location, shorthand for location_language
49
+ * @property string $translation Whether or not a location is a translation (i.e. it was translated from an original location), shorthand for location_translation
50
+ * @property int $parent Location ID of parent location, shorthand for location_parent
51
+ * @property int $id The Location ID, case sensitive, shorthand for location_id
52
+ * @property string $slug Location slug, shorthand for location_slug
53
+ * @property string name Location name, shorthand for location_name
54
+ * @property int owner ID of author/owner, shorthand for location_owner
55
+ * @property int status ID of post status, shorthand for location_status
56
*/
57
class EM_Location extends EM_Object {
58
//DB Fields
59
var $location_id = '';
60
var $post_id = '';
61
+ var $blog_id = 0;
62
+ var $location_parent;
63
var $location_slug = '';
64
var $location_name = '';
65
var $location_address = '';
73
var $post_content = '';
74
var $location_owner = '';
75
var $location_status = 0;
76
+ var $location_language;
77
+ var $location_translation = 0;
78
/* anonymous submission information */
79
var $owner_anonymous;
80
var $owner_name;
84
'location_id' => array('name'=>'id','type'=>'%d'),
85
'post_id' => array('name'=>'post_id','type'=>'%d'),
86
'blog_id' => array('name'=>'blog_id','type'=>'%d'),
87
+ 'location_parent' => array('type'=>'%d', 'null'=>true),
88
'location_slug' => array('name'=>'slug','type'=>'%s', 'null'=>true),
89
'location_name' => array('name'=>'name','type'=>'%s', 'null'=>true),
90
'location_address' => array('name'=>'address','type'=>'%s','null'=>true),
97
'location_longitude' => array('name'=>'longitude','type'=>'%f','null'=>true),
98
'post_content' => array('name'=>'description','type'=>'%s', 'null'=>true),
99
'location_owner' => array('name'=>'owner','type'=>'%d', 'null'=>true),
100
+ 'location_status' => array('name'=>'status','type'=>'%d', 'null'=>true),
101
+ 'location_language' => array( 'type'=>'%s', 'null'=>true ),
102
+ 'location_translation' => array( 'type'=>'%d' ),
103
+ );
104
+ /**
105
+ * Associative array mapping shorter to full property names in this class, used in EM_Object magic access methods, allowing for interchangeable use when dealing with different object types such as locations and events.
106
+ * @var array
107
+ */
108
+ protected $shortnames = array(
109
+ // common EM CPT object variables
110
+ 'language' => 'location_language',
111
+ 'translation' => 'location_translation',
112
+ 'parent' => 'location_parent',
113
+ 'id' => 'location_id',
114
+ 'slug' => 'locatoin_slug',
115
+ 'name' => 'locatoin_name',
116
+ 'status' => 'location_status',
117
+ 'owner' => 'location_owner',
118
);
119
var $post_fields = array('post_id','location_slug','location_status', 'location_name','post_content','location_owner');
120
var $location_attributes = array();
161
* Gets data from POST (default), supplied array, or from the database if an ID is supplied
162
* @param WP_Post|int|false $id
163
* @param $search_by - Can be post_id or a number for a blog id if in ms mode with global tables, default is location_id
164
*/
165
function __construct($id = false, $search_by = 'location_id' ) {
166
global $wpdb;
168
$this->required_fields = array("location_address" => __('The location address', 'events-manager'), "location_town" => __('The location town', 'events-manager'), "location_country" => __('The country', 'events-manager'));
169
//Get the post_id/location_id
170
$is_post = !empty($id->ID) && $id->post_type == EM_POST_TYPE_LOCATION;
171
+ if( $is_post ){
172
+ $id->ID = absint($id->ID);
173
+ }else{
174
+ $id = absint($id);
175
+ }
176
if( $is_post || absint($id) > 0 ){ //only load info if $id is a number
177
$location_post = false;
178
if($search_by == 'location_id' && !$is_post){
325
}
326
}
327
}
328
+ //location language
329
+ if( EM_ML::$is_ml && !empty($_POST['location_language']) && array_key_exists($_POST['location_language'], EM_ML::$langs) ){
330
+ $this->location_language = $_POST['location_language'];
331
+ }
332
//the line below should be deleted one day and we move validation out of this function, when that happens check otherfunctions like EM_ML_IO::get_post_meta function which force validation again
333
$result = $validate ? $this->validate_meta():true; //post returns null
334
$this->compat_keys();
428
$post_save = true;
429
//refresh this event with wp post
430
$post_data = get_post($post_id);
431
+ $this->post_id = $this->ID = $post_id;
432
+ $this->post_type = $post_data->post_type;
433
$this->location_slug = $post_data->post_name;
434
$this->location_owner = $post_data->post_author;
435
$this->post_status = $post_data->post_status;
469
global $wpdb;
470
if( $this->can_manage('edit_locations','edit_others_locations') || ( get_option('dbem_events_anonymous_submissions') && empty($this->location_id)) ){
471
do_action('em_location_save_meta_pre', $this);
472
+ //language default
473
+ if( !$this->location_language ) $this->location_language = EM_ML::$current_language;
474
//Set Blog ID if in multisite mode
475
if( EM_MS_GLOBAL && get_site_option('dbem_ms_mainblog_locations') ){
476
$this->blog_id = get_current_site()->blog_id; //global locations restricted to main blog must have main site id
480
//Update Post Meta
481
$current_meta_values = get_post_meta($this->post_id);
482
foreach( array_keys($this->fields) as $key ){
483
+ if( !EM_ML::$is_ml && ($key == 'location_language' || $key == 'location_translation') ) continue;
484
if( !in_array($key, $this->post_fields) && $key != 'blog_id' && $this->$key != '' ){
485
update_post_meta($this->post_id, '_'.$key, $this->$key);
486
}elseif( array_key_exists('_'.$key, $current_meta_values) ){ //we should delete event_attributes, but maybe something else uses it without us knowing
644
$result = $wpdb->query($wpdb->prepare("UPDATE ".EM_LOCATIONS_TABLE." SET location_status=$set_status, location_slug=%s WHERE location_id=%d", array($this->post_name, $this->location_id)));
645
$this->get_status(); //reload status
646
return apply_filters('em_location_set_status', $result !== false, $status, $this);
647
+ }
648
+
649
+ /**
650
+ * Gets the parent of this location, if none exists, null is returned.
651
+ * @return EM_Location|null
652
+ */
653
+ public function get_parent(){
654
+ if( $this->location_parent ){
655
+ return em_get_location( $this->location_parent );
656
+ }
657
+ return null;
658
+ }
659
660
function get_status($db = false){
661
switch( $this->post_status ){
1132
1133
}
1134
1135
+ function get_full_address($glue = ', ', $include_country = false){
1136
$location_array = array();
1137
if( !empty($this->location_address) ) $location_array[] = $this->location_address;
1138
if( !empty($this->location_town) ) $location_array[] = $this->location_town;
1139
if( !empty($this->location_state) ) $location_array[] = $this->location_state;
1140
if( !empty($this->location_postcode) ) $location_array[] = $this->location_postcode;
1141
if( !empty($this->location_region) ) $location_array[] = $this->location_region;
1142
+ if( $include_country ) $location_array[] = $this->get_country();
1143
return implode($glue, $location_array);
1144
}
1145
classes/em-locations.php CHANGED
@@ -20,10 +20,12 @@ class EM_Locations extends EM_Object {
20
*/
21
public static $num_rows_found;
22
23
/**
24
* Returns an array of EM_Location objects
25
- * @param boolean $eventful
26
- * @param boolean $return_objects
27
* @return array
28
*/
29
public static function get( $args = array(), $count=false ){
@@ -80,37 +82,11 @@ class EM_Locations extends EM_Object {
80
$selectors = $locations_table.'.post_id';
81
}
82
if( $calc_found_rows ) $selectors = 'SQL_CALC_FOUND_ROWS ' . $selectors; //for storing total rows found
83
- $selectors = 'DISTINCT ' . $selectors; //duplicate avoidance
84
}
85
86
- //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
87
- $join_events_table = false;
88
- //for we only will check optional joining by default for groupby searches, and for the original searches if EM_DISABLE_OPTIONAL_JOINS is set to true in wp-config.php
89
- if( !empty($args['groupby']) || (defined('EM_DISABLE_OPTIONAL_JOINS') && EM_DISABLE_OPTIONAL_JOINS) ){
90
- $event_specific_args = array('eventful', 'eventless', 'tag', 'category', 'event', 'recurrence', 'month', 'year', 'rsvp', 'bookings');
91
- $join_events_table = $args['scope'] != 'all'; //only value where false is not default so we check that first
92
- foreach( $event_specific_args as $arg ) if( !empty($args[$arg]) ) $join_events_table = true;
93
- //if set to false the following would provide a false negative in the line above
94
- if( $args['recurrences'] !== null ) $join_events_table = true;
95
- if( $args['recurring'] !== null ) $join_events_table = true;
96
- if( $args['event_status'] !== false ){ $join_events_table = true; }
97
- //check ordering and grouping arguments for precense of event fields requiring a join
98
- if( !$join_events_table ){
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, $event_fields) ){
104
- $join_events_table = true;
105
- break; //we join, no need to keep searching
106
- }
107
- }
108
- }
109
- }
110
- //EM_Events has a special argument for recurring events (the template), where it automatically omits recurring event templates. If we are searching events, and recurring was not explicitly set, we set it to the same as in EM_Events default
111
- if( $join_events_table && $args['recurring'] === null ) $args['recurring'] = false;
112
- }else{ $join_events_table = true; }//end temporary if( !empty($args['groupby']).... wrapper
113
- //plugins can override this optional joining behaviour here in case they add custom WHERE conditions or something like that
114
$join_events_table = apply_filters('em_locations_get_join_events_table', $join_events_table, $args, $count);
115
//depending on whether to join we do certain things like add a join SQL, change specific values like status search
116
$event_optional_join = $join_events_table ? "LEFT JOIN $events_table ON {$locations_table}.location_id={$events_table}.location_id" : '';
@@ -316,13 +292,49 @@ $limit $offset
316
return apply_filters('em_locations_get_post_search', $return);
317
}
318
319
/**
320
* Builds an array of SQL query conditions based on regularly used arguments
321
* @param array $args
322
* @return array
323
*/
324
public static function build_sql_conditions( $args = array(), $count=false ){
325
- self::$context = EM_POST_TYPE_LOCATION;
326
global $wpdb;
327
$events_table = EM_EVENTS_TABLE;
328
$locations_table = EM_LOCATIONS_TABLE;
@@ -434,7 +446,6 @@ $limit $offset
434
* @uses EM_Object#get_default_search()
435
*/
436
public static function get_default_search( $array_or_defaults = array(), $array = array() ){
437
- self::$context = EM_POST_TYPE_LOCATION;
438
$defaults = array(
439
'orderby' => 'location_name',
440
'groupby' => false,
20
*/
21
public static $num_rows_found;
22
23
+ protected static $context = 'location';
24
+
25
/**
26
* Returns an array of EM_Location objects
27
+ * @param array $args
28
+ * @param boolean $count
29
* @return array
30
*/
31
public static function get( $args = array(), $count=false ){
82
$selectors = $locations_table.'.post_id';
83
}
84
if( $calc_found_rows ) $selectors = 'SQL_CALC_FOUND_ROWS ' . $selectors; //for storing total rows found
85
+ $selectors = $selectors; //duplicate avoidance
86
}
87
88
+ $join_events_table = self::check_events_table_join( $args, $event_fields );
89
+ // Deprecated, use em_locations_check_events_table_join instead, $count is unecessary
90
$join_events_table = apply_filters('em_locations_get_join_events_table', $join_events_table, $args, $count);
91
//depending on whether to join we do certain things like add a join SQL, change specific values like status search
92
$event_optional_join = $join_events_table ? "LEFT JOIN $events_table ON {$locations_table}.location_id={$events_table}.location_id" : '';
292
return apply_filters('em_locations_get_post_search', $return);
293
}
294
295
+ /**
296
+ * Checks if we need to join an events table for this search, which is necessary if any event-specific arguments are supplied, or if certain arguments such as orderby contain location fields
297
+ * @param array $args
298
+ * @param array $event_fields
299
+ * @return boolean
300
+ */
301
+ public static function check_events_table_join( $args, $event_fields ){
302
+ //for we only will check optional joining by default for groupby searches, and for the original searches if EM_DISABLE_OPTIONAL_JOINS is set to true in wp-config.php
303
+ if( !empty($args['groupby']) || (defined('EM_DISABLE_OPTIONAL_JOINS') && EM_DISABLE_OPTIONAL_JOINS) ){
304
+ $event_specific_args = array('eventful', 'eventless', 'tag', 'category', 'event', 'recurrence', 'month', 'year', 'rsvp', 'bookings');
305
+ $event_specific_args = apply_filters('em_locations_event_specific_args', $event_specific_args);
306
+ $join_events_table = $args['scope'] != 'all'; //only value where false is not default so we check that first
307
+ foreach( $event_specific_args as $arg ) if( !empty($args[$arg]) ) $join_events_table = true;
308
+ //if set to false the following would provide a false negative in the line above
309
+ if( $args['recurrences'] !== null ) $join_events_table = true;
310
+ if( $args['recurring'] !== null ) $join_events_table = true;
311
+ if( $args['event_status'] !== false ){ $join_events_table = true; }
312
+ //check ordering and grouping arguments for precense of event fields requiring a join
313
+ if( !$join_events_table ){
314
+ foreach( array('groupby', 'orderby', 'groupby_orderby') as $arg ){
315
+ if( !is_array($args[$arg]) ) continue; //ignore this argument if set to false
316
+ //we assume all these arguments are now array thanks to self::get_search_defaults() cleaning it up
317
+ foreach( $args[$arg] as $field_name ){
318
+ if( in_array($field_name, $event_fields) ){
319
+ $join_events_table = true;
320
+ break; //we join, no need to keep searching
321
+ }
322
+ }
323
+ }
324
+ }
325
+ //EM_Events has a special argument for recurring events (the template), where it automatically omits recurring event templates. If we are searching events, and recurring was not explicitly set, we set it to the same as in EM_Events default
326
+ if( $join_events_table && $args['recurring'] === null ) $args['recurring'] = false;
327
+ }else{ $join_events_table = true; }//end temporary if( !empty($args['groupby']).... wrapper
328
+ //plugins can override this optional joining behaviour here in case they add custom WHERE conditions or something like that
329
+ return apply_filters('em_locations_check_events_table_join', $join_events_table, $args, $event_fields);
330
+ }
331
+
332
/**
333
* Builds an array of SQL query conditions based on regularly used arguments
334
* @param array $args
335
* @return array
336
*/
337
public static function build_sql_conditions( $args = array(), $count=false ){
338
global $wpdb;
339
$events_table = EM_EVENTS_TABLE;
340
$locations_table = EM_LOCATIONS_TABLE;
446
* @uses EM_Object#get_default_search()
447
*/
448
public static function get_default_search( $array_or_defaults = array(), $array = array() ){
449
$defaults = array(
450
'orderby' => 'location_name',
451
'groupby' => false,
classes/em-mailer.php CHANGED
@@ -12,10 +12,12 @@ class EM_Mailer {
12
public $errors = array();
13
14
/**
15
* @param $subject
16
* @param $body
17
* @param $receiver
18
* @param $attachments
19
*/
20
public function send($subject="no title",$body="No message specified", $receiver='', $attachments = array() ) {
21
//TODO add an EM_Error global object, for this sort of error reporting. (@marcus like StatusNotice)
@@ -53,63 +55,80 @@ class EM_Mailer {
53
}elseif( $emails_ok ){
54
$this->load_phpmailer();
55
$mail = new PHPMailer();
56
- //$mail->SMTPDebug = true;
57
- if( get_option('dbem_smtp_html') ){
58
- $mail->isHTML();
59
- }
60
- $mail->ClearAllRecipients();
61
- $mail->ClearAddresses();
62
- $mail->ClearAttachments();
63
- $mail->CharSet = 'utf-8';
64
- $mail->SetLanguage('en', dirname(__FILE__).'/');
65
- $mail->PluginDir = dirname(__FILE__).'/phpmailer/';
66
- $mail->Host = get_option('dbem_smtp_host');
67
- $mail->Port = get_option('dbem_rsvp_mail_port');
68
- $mail->Username = get_option('dbem_smtp_username');
69
- $mail->Password = get_option('dbem_smtp_password');
70
- $mail->From = get_option('dbem_mail_sender_address');
71
- $mail->FromName = get_option('dbem_mail_sender_name'); // This is the from name in the email, you can put anything you like here
72
- $mail->Body = $body;
73
- $mail->Subject = $subject;
74
- //add attachments
75
- if( is_array($attachments) ){
76
- foreach($attachments as $attachment){
77
- $att = array('name'=> '', 'encoding' => 'base64', 'type' => 'application/octet-stream');
78
- if( is_array($attachment) ){
79
- $att = array_merge($att, $attachment);
80
- }else{
81
- $att['path'] = $attachment;
82
- }
83
- $mail->AddAttachment($att['path'], $att['name'], $att['encoding'], $att['type']);
84
}
85
- }
86
- do_action('em_mailer', $mail); //$mail will still be modified
87
- if(is_array($receiver)){
88
- foreach($receiver as $receiver_email){
89
- $mail->AddAddress($receiver_email);
90
}
91
- }else{
92
- $mail->AddAddress($receiver);
93
- }
94
-
95
- //Protocols
96
- if( get_option('dbem_rsvp_mail_send_method') == 'qmail' ){
97
- $mail->isQmail();
98
- }elseif( get_option('dbem_rsvp_mail_send_method') == 'sendmail' ){
99
- $mail->isSendmail();
100
- }else {
101
- $mail->Mailer = get_option('dbem_rsvp_mail_send_method');
102
- }
103
- if(get_option('dbem_rsvp_mail_SMTPAuth') == '1'){
104
- $mail->SMTPAuth = TRUE;
105
- }
106
- do_action('em_mailer_before_send', $mail, $subject, $body, $receiver, $attachments); //$mail can still be modified
107
- $send = $mail->Send();
108
- if(!$send){
109
$this->errors[] = $mail->ErrorInfo;
110
}
111
- do_action('em_mailer_sent', $mail, $send); //$mail can still be modified
112
- return $send;
113
}else{
114
$this->errors[] = __('Please supply a valid email format.', 'events-manager');
115
return false;
12
public $errors = array();
13
14
/**
15
+ * Send an email via the EM-saved settings.
16
* @param $subject
17
* @param $body
18
* @param $receiver
19
* @param $attachments
20
+ * @return boolean
21
*/
22
public function send($subject="no title",$body="No message specified", $receiver='', $attachments = array() ) {
23
//TODO add an EM_Error global object, for this sort of error reporting. (@marcus like StatusNotice)
55
}elseif( $emails_ok ){
56
$this->load_phpmailer();
57
$mail = new PHPMailer();
58
+ try{
59
+ //$mail->SMTPDebug = true;
60
+ if( get_option('dbem_smtp_html') ){
61
+ $mail->isHTML();
62
}
63
+ $mail->ClearAllRecipients();
64
+ $mail->ClearAddresses();
65
+ $mail->ClearAttachments();
66
+ $mail->CharSet = 'utf-8';
67
+ $mail->SetLanguage('en', dirname(__FILE__).'/');
68
+ $mail->PluginDir = dirname(__FILE__).'/phpmailer/';
69
+ $host = get_option('dbem_smtp_host');
70
+ //if port is supplied via the host address, give that precedence over the port setting
71
+ if( preg_match('/^(.+):([0-9]+)#x2F;', $host, $host_port_matches) ){
72
+ $mail->Host = $host_port_matches[1];
73
+ $mail->Port = $host_port_matches[2];
74
+ }else{
75
+ $mail->Host = $host;
76
+ $mail->Port = get_option('dbem_rsvp_mail_port');
77
}
78
+ $mail->Username = get_option('dbem_smtp_username');
79
+ $mail->Password = get_option('dbem_smtp_password');
80
+ $mail->From = get_option('dbem_mail_sender_address');
81
+ $mail->FromName = get_option('dbem_mail_sender_name'); // This is the from name in the email, you can put anything you like here
82
+ $mail->Body = $body;
83
+ $mail->Subject = $subject;
84
+ //SSL/TLS
85
+ if( get_option('dbem_smtp_encryption') ){
86
+ $mail->SMTPSecure = get_option('dbem_smtp_encryption');
87
+ }
88
+ $mail->SMTPAutoTLS = get_option('dbem_smtp_autotls') == 1;
89
+ //add attachments
90
+ if( is_array($attachments) ){
91
+ foreach($attachments as $attachment){
92
+ $att = array('name'=> '', 'encoding' => 'base64', 'type' => 'application/octet-stream');
93
+ if( is_array($attachment) ){
94
+ $att = array_merge($att, $attachment);
95
+ }else{
96
+ $att['path'] = $attachment;
97
+ }
98
+ $mail->AddAttachment($att['path'], $att['name'], $att['encoding'], $att['type']);
99
+ }
100
+ }
101
+ if(is_array($receiver)){
102
+ foreach($receiver as $receiver_email){
103
+ $mail->AddAddress($receiver_email);
104
+ }
105
+ }else{
106
+ $mail->AddAddress($receiver);
107
+ }
108
+ do_action('em_mailer', $mail); //$mail will still be modified
109
+
110
+ //Protocols
111
+ if( get_option('dbem_rsvp_mail_send_method') == 'qmail' ){
112
+ $mail->isQmail();
113
+ }elseif( get_option('dbem_rsvp_mail_send_method') == 'sendmail' ){
114
+ $mail->isSendmail();
115
+ }else {
116
+ $mail->Mailer = get_option('dbem_rsvp_mail_send_method');
117
+ }
118
+ if(get_option('dbem_rsvp_mail_SMTPAuth') == '1'){
119
+ $mail->SMTPAuth = TRUE;
120
+ }
121
+ do_action('em_mailer_before_send', $mail, $subject, $body, $receiver, $attachments); //$mail can still be modified
122
+ $send = $mail->Send();
123
+ if(!$send){
124
+ $this->errors[] = $mail->ErrorInfo;
125
+ }
126
+ do_action('em_mailer_sent', $mail, $send); //$mail can still be modified
127
+ return $send;
128
+ }catch( phpmailerException $ex ){
129
$this->errors[] = $mail->ErrorInfo;
130
+ return false;
131
}
132
}else{
133
$this->errors[] = __('Please supply a valid email format.', 'events-manager');
134
return false;
classes/em-object.php CHANGED
@@ -5,13 +5,24 @@
5
*/
6
class EM_Object {
7
var $fields = array();
8
var $required_fields = array();
9
var $feedback_message = "";
10
var $errors = array();
11
var $mime_types = array(1 => 'gif', 2 => 'jpg', 3 => 'png');
12
13
private static $taxonomies_array; //see self::get_taxonomies()
14
- protected static $context = 'event'; //this should be overridden to the db table name for deciding on ambiguous fields to look up
15
16
/**
17
* Takes the array and provides a clean array of search parameters, along with details
@@ -60,7 +71,8 @@ class EM_Object {
60
'near'=>false, //lat,lng coordinates in array or comma-separated format
61
'near_unit'=>get_option('dbem_search_form_geo_unit_default'), //mi or km
62
'near_distance'=>get_option('dbem_search_form_geo_distance_default'), //distance from near coordinates - currently the default is the same as for the search form
63
- 'ajax'=> (defined('EM_AJAX') && EM_AJAX) //considered during pagination
64
);
65
//auto-add taxonomies to defaults
66
foreach( self::get_taxonomies() as $item => $item_data ){ $super_defaults[$item] = false; }
@@ -121,6 +133,12 @@ class EM_Object {
121
$array['timezone'] = explode(',', $array['timezone']);
122
}
123
}
124
//return clean array
125
$defaults = array_merge ( $defaults, $array ); //No point using WP's cleaning function, we're doing it already.
126
}
@@ -188,8 +206,6 @@ class EM_Object {
188
}else{
189
$defaults['page'] = ($defaults['limit'] > 0 ) ? floor($defaults['offset']/$defaults['limit']) + 1 : 1;
190
}
191
- //reset the context
192
- self::$context = EM_POST_TYPE_EVENT;
193
//return values
194
return apply_filters('em_object_get_default_search', $defaults, $array, $super_defaults);
195
}
@@ -229,8 +245,8 @@ class EM_Object {
229
// e.g. if in events, search for 'publish' events and 0 location_status, it'll find events with a location pending review.
230
foreach( array('event_status', 'location_status') as $status_type ){
231
//find out whether the main status context we're after is an event or location i.e. are we running an events or location query
232
- $is_location_status = $status_type == "location_status" && self::$context == EM_POST_TYPE_LOCATION;
233
- $is_event_status = $status_type == "event_status" && self::$context == EM_POST_TYPE_EVENT;
234
//$is_joined_status decides whether this status we're dealing with is part of a joined table or the main table
235
$is_joined_status = (!$is_location_status || !$is_event_status) && $args[$status_type] !== false;
236
//we add a status condition if this is the main status context or if joining a table and joined status arg is not exactly false
@@ -266,7 +282,7 @@ class EM_Object {
266
$conditions['recurring'] = "`recurrence`=1";
267
}
268
}elseif( $recurrence > 0 ){
269
- $conditions['recurrence'] = $wpdb->prepare("`recurrence_id`=%d", $recurrence);
270
}else{
271
//we choose to either exclusively show or completely omit recurrences, if not set then both are shown
272
if( $recurrences !== null ){
@@ -390,7 +406,7 @@ class EM_Object {
390
}
391
392
//Filter by Location - can be object, array, or id
393
- $location_id_table = self::$context == EM_POST_TYPE_EVENT ? $events_table:$locations_table;
394
if ( is_numeric($location) && $location > 0 ) { //Location ID takes precedence
395
$conditions['location'] = " {$location_id_table}.location_id = $location";
396
}elseif ( $location === 0 ) { //only helpful is searching events
@@ -526,7 +542,7 @@ class EM_Object {
526
//figure out context - what table/field to search
527
$post_context = EM_EVENTS_TABLE.".post_id";
528
$ms_context = EM_EVENTS_TABLE.".event_id";
529
- if( !empty($tax_data['context']) && self::$context == EM_POST_TYPE_LOCATION && in_array( self::$context, $tax_data['context']) ){
530
//context can be either locations or events, since those are the only two CPTs we deal with
531
$post_context = EM_LOCATIONS_TABLE.".post_id";
532
$ms_context = EM_LOCATIONS_TABLE.".event_id";
@@ -585,8 +601,15 @@ class EM_Object {
585
}elseif( self::array_is_numeric($owner) ){
586
$conditions['owner'] = 'event_owner IN ('.implode(',',$owner).')';
587
}
588
- //reset the context
589
- self::$context = EM_POST_TYPE_EVENT;
590
//return values
591
return apply_filters('em_object_build_sql_conditions', $conditions);
592
}
@@ -1089,6 +1112,34 @@ class EM_Object {
1089
return $return;
1090
}
1091
1092
/**
1093
* Returns the id of a particular object in the table it is stored, be it Event (event_id), Location (location_id), Tag, Booking etc.
1094
* @return int
@@ -1107,8 +1158,6 @@ class EM_Object {
1107
return $this->ticket_id;
1108
case 'EM_Ticket_Booking':
1109
return $this->ticket_booking_id;
1110
- case 'EM_Ticket_Booking':
1111
- return $this->ticket_booking_id;
1112
}
1113
return 0;
1114
}
5
*/
6
class EM_Object {
7
var $fields = array();
8
+ /**
9
+ * @var array Associative array of shortname => property names for this object. For example, an EM_Event object will have a 'language' key to 'event_language' value.
10
+ */
11
+ protected $shortnames = array();
12
var $required_fields = array();
13
var $feedback_message = "";
14
var $errors = array();
15
var $mime_types = array(1 => 'gif', 2 => 'jpg', 3 => 'png');
16
17
private static $taxonomies_array; //see self::get_taxonomies()
18
+
19
+ /**
20
+ * Provides context in searches where ambiguous field names may coincide between event and location database searches requiring a specific field name for each type.
21
+ * For example, status, location, taxonomy and language arguments are used interchangeably in event and location searches but both have different field names.
22
+ * Child classes such as EM_Events and EM_Locations will override this field with 'event' or 'location' respectively to determine context.
23
+ * @var string
24
+ */
25
+ protected static $context = 'object_type';
26
27
/**
28
* Takes the array and provides a clean array of search parameters, along with details
71
'near'=>false, //lat,lng coordinates in array or comma-separated format
72
'near_unit'=>get_option('dbem_search_form_geo_unit_default'), //mi or km
73
'near_distance'=>get_option('dbem_search_form_geo_distance_default'), //distance from near coordinates - currently the default is the same as for the search form
74
+ 'ajax'=> (defined('EM_AJAX') && EM_AJAX), //considered during pagination
75
+ 'language' => null, //for language searches in ML mode
76
);
77
//auto-add taxonomies to defaults
78
foreach( self::get_taxonomies() as $item => $item_data ){ $super_defaults[$item] = false; }
133
$array['timezone'] = explode(',', $array['timezone']);
134
}
135
}
136
+ // Language
137
+ if( isset($array['language']) ){
138
+ if( $array['language'] !== false && !in_array($array['language'], EM_ML::$langs) ){
139
+ unset($array['language']);
140
+ }
141
+ }
142
//return clean array
143
$defaults = array_merge ( $defaults, $array ); //No point using WP's cleaning function, we're doing it already.
144
}
206
}else{
207
$defaults['page'] = ($defaults['limit'] > 0 ) ? floor($defaults['offset']/$defaults['limit']) + 1 : 1;
208
}
209
//return values
210
return apply_filters('em_object_get_default_search', $defaults, $array, $super_defaults);
211
}
245
// e.g. if in events, search for 'publish' events and 0 location_status, it'll find events with a location pending review.
246
foreach( array('event_status', 'location_status') as $status_type ){
247
//find out whether the main status context we're after is an event or location i.e. are we running an events or location query
248
+ $is_location_status = $status_type == "location_status" && static::$context == 'location';
249
+ $is_event_status = $status_type == "event_status" && static::$context == 'event';
250
//$is_joined_status decides whether this status we're dealing with is part of a joined table or the main table
251
$is_joined_status = (!$is_location_status || !$is_event_status) && $args[$status_type] !== false;
252
//we add a status condition if this is the main status context or if joining a table and joined status arg is not exactly false
282
$conditions['recurring'] = "`recurrence`=1";
283
}
284
}elseif( $recurrence > 0 ){
285
+ $conditions['recurrence'] = $wpdb->prepare("(`recurrence_id`=%d AND `recurrence`!=1)", $recurrence);
286
}else{
287
//we choose to either exclusively show or completely omit recurrences, if not set then both are shown
288
if( $recurrences !== null ){
406
}
407
408
//Filter by Location - can be object, array, or id
409
+ $location_id_table = static::$context == 'event' ? $events_table:$locations_table;
410
if ( is_numeric($location) && $location > 0 ) { //Location ID takes precedence
411
$conditions['location'] = " {$location_id_table}.location_id = $location";
412
}elseif ( $location === 0 ) { //only helpful is searching events
542
//figure out context - what table/field to search
543
$post_context = EM_EVENTS_TABLE.".post_id";
544
$ms_context = EM_EVENTS_TABLE.".event_id";
545
+ if( !empty($tax_data['context']) && static::$context == 'location' && in_array( static::$context, $tax_data['context']) ){
546
//context can be either locations or events, since those are the only two CPTs we deal with
547
$post_context = EM_LOCATIONS_TABLE.".post_id";
548
$ms_context = EM_LOCATIONS_TABLE.".event_id";
601
}elseif( self::array_is_numeric($owner) ){
602
$conditions['owner'] = 'event_owner IN ('.implode(',',$owner).')';
603
}
604
+
605
+ // Language searches, only relevant if ML is activated via a third party plugin
606
+ if( EM_ML::$is_ml && $args['language'] ){ // language ignored if null or false
607
+ if( static::$context == 'event'){
608
+ $conditions['language'] = $wpdb->prepare('event_language = %s', EM_ML::$current_language);
609
+ }elseif( static::$context == 'location'){
610
+ $conditions['language'] = $wpdb->prepare('location_language = %s', EM_ML::$current_language);
611
+ }
612
+ }
613
//return values
614
return apply_filters('em_object_build_sql_conditions', $conditions);
615
}
1112
return $return;
1113
}
1114
1115
+ public function __get( $shortname ){
1116
+ if( !empty($this->shortnames[$shortname]) ){
1117
+ $property = $this->shortnames[$shortname];
1118
+ return $this->{$property};
1119
+ }
1120
+ return null;
1121
+ }
1122
+
1123
+ public function __set($prop, $val ){
1124
+ if( !empty($this->shortnames[$prop]) ){
1125
+ $property = $this->shortnames[$prop];
1126
+ if( !empty($this->fields[$property]['type']) && $this->fields[$property]['type'] == '%d' ){
1127
+ $val = absint($val);
1128
+ }
1129
+ $this->{$property} = $val;
1130
+ }else{
1131
+ $this->{$prop} = $val;
1132
+ }
1133
+ }
1134
+
1135
+ public function __isset( $shortname ){
1136
+ if( !empty($this->shortnames[$shortname]) ){
1137
+ $property = $this->shortnames[$shortname];
1138
+ return !empty($this->{$property});
1139
+ }
1140
+ return false;
1141
+ }
1142
+
1143
/**
1144
* Returns the id of a particular object in the table it is stored, be it Event (event_id), Location (location_id), Tag, Booking etc.
1145
* @return int
1158
return $this->ticket_id;
1159
case 'EM_Ticket_Booking':
1160
return $this->ticket_booking_id;
1161
}
1162
return 0;
1163
}
classes/em-permalinks.php CHANGED
@@ -77,7 +77,7 @@ if( !class_exists('EM_Permalinks') ){
77
$url = get_term_link($wp_query->get('category_slug'), EM_TAXONOMY_CATEGORY);
78
}
79
if(!empty($url)){
80
- wp_redirect($url,301);
81
exit();
82
}
83
}
@@ -93,7 +93,8 @@ if( !class_exists('EM_Permalinks') ){
93
if( is_object($events_page) ){
94
$events_slug = urldecode(preg_replace('/\/#x2F;', '', str_replace( trailingslashit(home_url()), '', get_permalink($events_page_id)) ));
95
$events_slug = ( !empty($events_slug) ) ? trailingslashit($events_slug) : $events_slug;
96
- $em_rules[$events_slug.'(\d{4}-\d{2}-\d{2})#x27;] = 'index.php?pagename='.$events_slug.'&calendar_day=$matches[1]'; //event calendar date search
97
if( $events_page_id != get_option('page_on_front') && EM_POST_TYPE_EVENT_SLUG != $events_slug ){ //ignore this rule if events page is the home page
98
$em_rules[$events_slug.'rss/?#x27;] = 'index.php?post_type='.EM_POST_TYPE_EVENT.'&feed=feed'; //rss page
99
$em_rules[$events_slug.'feed/?#x27;] = 'index.php?post_type='.EM_POST_TYPE_EVENT.'&feed=feed'; //compatible rss page
@@ -125,14 +126,14 @@ if( !class_exists('EM_Permalinks') ){
125
//global links hard-coded
126
if( EM_MS_GLOBAL && !get_site_option('dbem_ms_global_events_links', true) ){
127
//MS Mode has slug also for global links
128
- $em_rules[$events_slug.get_site_option('dbem_ms_events_slug',EM_EVENT_SLUG).'/(.+)#x27;] = 'index.php?pagename='.$events_slug.'&em_redirect=1&event_slug=$matches[1]'; //single event from subsite
129
}
130
//add redirection for backwards compatability
131
- $em_rules[$events_slug.EM_EVENT_SLUG.'/(.+)#x27;] = 'index.php?pagename='.$events_slug.'&em_redirect=1&event_slug=$matches[1]'; //single event
132
- $em_rules[$events_slug.EM_LOCATION_SLUG.'/(.+)#x27;] = 'index.php?pagename='.$events_slug.'&em_redirect=1&location_slug=$matches[1]'; //single location page
133
- $em_rules[$events_slug.EM_CATEGORY_SLUG.'/(.+)#x27;] = 'index.php?pagename='.$events_slug.'&em_redirect=1&category_slug=$matches[1]'; //single category page slug