Version Description
- fixed CSV injection vulnerability which can allow malicious text to be exported to CSV files and parsed by Spreadsheet
- fixed #_BOOKINGCUTOFF text date formats not getting translated correctly
- added ability to programatically add attachments to booking emails for future features
- fixed/updated casing of functions in phpMailer function calls (prefiously backward compatible),
- added reply-to headers for wp_mail emails circumventing some plugins forcing from email address fields,
- fixed email testing function ignoring sender name, encryption and autotls options
- fixed ical apple structure breaking parsing in google (and possible others)
- updated events-manager.js to replace deprecated use of delegate/bind with on/off equivalents
- added ticket ordering
- fixed editing booking tickets in admin causing validation errors on 0 values
- fixed PHP Warning generated when adding Booking Notes which prevent a redirect with WP_DEBUG enabled
- fixed Events tab on profile pages stripping last character with the BuddyPress Nouveau theme
- changed blank value to 'no location' when viewing the event bookings admin page for locationless events
- changed EM_Notices by making them JsonSerializable
- fixed (hopefully!) the elusive and hard to reproduce "variable mismatch" error when submitting new form in some rare circumstances
Download this release
Release Info
Developer | netweblogic |
Plugin | Events Manager |
Version | 5.9.7.2 |
Comparing to | |
See all releases |
Code changes from version 5.9.7.1 to 5.9.7.2
- admin/em-bookings.php +5 -1
- admin/em-options.php +5 -1
- admin/settings/tabs/bookings.php +4 -3
- admin/settings/tabs/emails.php +1 -0
- buddypress/bp-em-core.php +2 -1
- classes/em-booking.php +12 -4
- classes/em-bookings-table.php +20 -4
- classes/em-event.php +1 -1
- classes/em-mailer.php +114 -24
- classes/em-notices.php +15 -4
- classes/em-object.php +3 -2
- classes/em-ticket-booking.php +12 -2
- classes/em-ticket.php +3 -1
- classes/em-tickets-bookings.php +25 -6
- classes/em-tickets.php +18 -2
- em-install.php +2 -0
- em-template-tags.php +2 -0
- events-manager.php +4 -4
- includes/css/events_manager.css +10 -4
- includes/css/events_manager_admin.css +10 -4
- includes/js/events-manager.js +44 -19
- readme.txt +18 -1
- templates/forms/event-editor.php +1 -1
- templates/forms/event/bookings.php +12 -7
- templates/templates/ical.php +2 -2
admin/em-bookings.php
CHANGED
@@ -108,7 +108,11 @@ function em_bookings_event(){
|
|
108 |
</p>
|
109 |
<p>
|
110 |
<strong><?php esc_html_e('Location','events-manager'); ?></strong> :
|
111 |
-
|
|
|
|
|
|
|
|
|
112 |
</p>
|
113 |
</div>
|
114 |
<h2><?php esc_html_e('Bookings','events-manager'); ?></h2>
|
108 |
</p>
|
109 |
<p>
|
110 |
<strong><?php esc_html_e('Location','events-manager'); ?></strong> :
|
111 |
+
<?php if( $EM_Event->location_id == 0 ): ?>
|
112 |
+
<em><?php esc_html_e('No Location', 'events-manager'); ?></em>
|
113 |
+
<?php else: ?>
|
114 |
+
<a class="row-title" href="<?php echo admin_url(); ?>post.php?action=edit&post=<?php echo $EM_Event->get_location()->post_id ?>"><?php echo ($EM_Event->get_location()->location_name); ?></a>
|
115 |
+
<?php endif; ?>
|
116 |
</p>
|
117 |
</div>
|
118 |
<h2><?php esc_html_e('Bookings','events-manager'); ?></h2>
|
admin/em-options.php
CHANGED
@@ -345,7 +345,7 @@ function em_admin_email_test_ajax(){
|
|
345 |
$current_user = get_user_by('id', get_current_user_id());
|
346 |
//add filters for options used in EM_Mailer so the current supplied ones are used
|
347 |
ob_start();
|
348 |
-
function pre_option_dbem_mail_sender_name(){ return
|
349 |
add_filter('pre_option_dbem_mail_sender_name', 'pre_option_dbem_mail_sender_name');
|
350 |
function pre_option_dbem_mail_sender_address(){ return sanitize_text_field($_REQUEST['dbem_mail_sender_address']); }
|
351 |
add_filter('pre_option_dbem_mail_sender_address', 'pre_option_dbem_mail_sender_address');
|
@@ -353,6 +353,10 @@ function em_admin_email_test_ajax(){
|
|
353 |
add_filter('pre_option_dbem_rsvp_mail_send_method', 'pre_option_dbem_rsvp_mail_send_method');
|
354 |
function pre_option_dbem_rsvp_mail_port(){ return sanitize_text_field($_REQUEST['dbem_rsvp_mail_port']); }
|
355 |
add_filter('pre_option_dbem_rsvp_mail_port', 'pre_option_dbem_rsvp_mail_port');
|
|
|
|
|
|
|
|
|
356 |
function pre_option_dbem_rsvp_mail_SMTPAuth(){ return sanitize_text_field($_REQUEST['dbem_rsvp_mail_SMTPAuth']); }
|
357 |
add_filter('pre_option_dbem_rsvp_mail_SMTPAuth', 'pre_option_dbem_rsvp_mail_SMTPAuth');
|
358 |
function pre_option_dbem_smtp_host(){ return sanitize_text_field($_REQUEST['dbem_smtp_host']); }
|
345 |
$current_user = get_user_by('id', get_current_user_id());
|
346 |
//add filters for options used in EM_Mailer so the current supplied ones are used
|
347 |
ob_start();
|
348 |
+
function pre_option_dbem_mail_sender_name(){ return sanitize_text_field($_REQUEST['dbem_mail_sender_name']); }
|
349 |
add_filter('pre_option_dbem_mail_sender_name', 'pre_option_dbem_mail_sender_name');
|
350 |
function pre_option_dbem_mail_sender_address(){ return sanitize_text_field($_REQUEST['dbem_mail_sender_address']); }
|
351 |
add_filter('pre_option_dbem_mail_sender_address', 'pre_option_dbem_mail_sender_address');
|
353 |
add_filter('pre_option_dbem_rsvp_mail_send_method', 'pre_option_dbem_rsvp_mail_send_method');
|
354 |
function pre_option_dbem_rsvp_mail_port(){ return sanitize_text_field($_REQUEST['dbem_rsvp_mail_port']); }
|
355 |
add_filter('pre_option_dbem_rsvp_mail_port', 'pre_option_dbem_rsvp_mail_port');
|
356 |
+
function pre_option_dbem_smtp_encryption(){ return sanitize_text_field($_REQUEST['dbem_smtp_encryption']); }
|
357 |
+
add_filter('pre_option_dbem_smtp_encryption', 'pre_option_dbem_smtp_encryption');
|
358 |
+
function pre_option_dbem_smtp_autotls(){ return sanitize_text_field($_REQUEST['dbem_smtp_autotls']); }
|
359 |
+
add_filter('pre_option_dbem_smtp_autotls', 'pre_option_dbem_smtp_autotls');
|
360 |
function pre_option_dbem_rsvp_mail_SMTPAuth(){ return sanitize_text_field($_REQUEST['dbem_rsvp_mail_SMTPAuth']); }
|
361 |
add_filter('pre_option_dbem_rsvp_mail_SMTPAuth', 'pre_option_dbem_rsvp_mail_SMTPAuth');
|
362 |
function pre_option_dbem_smtp_host(){ return sanitize_text_field($_REQUEST['dbem_smtp_host']); }
|
admin/settings/tabs/bookings.php
CHANGED
@@ -102,7 +102,7 @@
|
|
102 |
?>
|
103 |
</table>
|
104 |
</div> <!-- . inside -->
|
105 |
-
</div> <!-- .postbox -->
|
106 |
|
107 |
<div class="postbox " id="em-opt-ticket-options" >
|
108 |
<div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__( '%s Options', 'events-manager'),__('Ticket','events-manager')); ?> </span></h3>
|
@@ -115,12 +115,13 @@
|
|
115 |
em_options_radio_binary ( __( 'Show member-only tickets?', 'events-manager'), 'dbem_bookings_tickets_show_member_tickets', sprintf(__('%s must be set to yes for this to work.', 'events-manager'), '<strong>'.__( 'Show unavailable tickets?', 'events-manager').'</strong>').' '.__( 'If there are member-only tickets, you can choose whether or not to show these tickets to guests.','events-manager') );
|
116 |
|
117 |
em_options_radio_binary ( __( 'Show multiple tickets if logged out?', 'events-manager'), 'dbem_bookings_tickets_show_loggedout', __( 'If guests cannot make bookings, they will be asked to register in order to book. However, enabling this will still show available tickets.', 'events-manager') );
|
118 |
-
|
|
|
119 |
'ticket_price DESC, ticket_name ASC'=>__('Ticket Price (Descending)','events-manager'),
|
120 |
'ticket_price ASC, ticket_name ASC'=>__('Ticket Price (Ascending)','events-manager'),
|
121 |
'ticket_name ASC, ticket_price DESC'=>__('Ticket Name (Ascending)','events-manager'),
|
122 |
'ticket_name DESC, ticket_price DESC'=>__('Ticket Name (Descending)','events-manager')
|
123 |
-
);
|
124 |
em_options_select ( __( 'Order Tickets By', 'events-manager'), 'dbem_bookings_tickets_orderby', $ticket_orders, __( 'Choose which order your tickets appear.', 'events-manager') );
|
125 |
echo $save_button;
|
126 |
?>
|
102 |
?>
|
103 |
</table>
|
104 |
</div> <!-- . inside -->
|
105 |
+
</div> <!-- .postbox -->
|
106 |
|
107 |
<div class="postbox " id="em-opt-ticket-options" >
|
108 |
<div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php echo sprintf(__( '%s Options', 'events-manager'),__('Ticket','events-manager')); ?> </span></h3>
|
115 |
em_options_radio_binary ( __( 'Show member-only tickets?', 'events-manager'), 'dbem_bookings_tickets_show_member_tickets', sprintf(__('%s must be set to yes for this to work.', 'events-manager'), '<strong>'.__( 'Show unavailable tickets?', 'events-manager').'</strong>').' '.__( 'If there are member-only tickets, you can choose whether or not to show these tickets to guests.','events-manager') );
|
116 |
|
117 |
em_options_radio_binary ( __( 'Show multiple tickets if logged out?', 'events-manager'), 'dbem_bookings_tickets_show_loggedout', __( 'If guests cannot make bookings, they will be asked to register in order to book. However, enabling this will still show available tickets.', 'events-manager') );
|
118 |
+
em_options_radio_binary ( __( 'Enable custom ticket ordering?', 'events-manager'), 'dbem_bookings_tickets_ordering', __( 'When enabled, users can custom-order their tickets using drag and drop. If enabled, saved ordering supercedes the default ticket ordering below.', 'events-manager') );
|
119 |
+
$ticket_orders = apply_filters('em_tickets_orderby_options', array(
|
120 |
'ticket_price DESC, ticket_name ASC'=>__('Ticket Price (Descending)','events-manager'),
|
121 |
'ticket_price ASC, ticket_name ASC'=>__('Ticket Price (Ascending)','events-manager'),
|
122 |
'ticket_name ASC, ticket_price DESC'=>__('Ticket Name (Ascending)','events-manager'),
|
123 |
'ticket_name DESC, ticket_price DESC'=>__('Ticket Name (Descending)','events-manager')
|
124 |
+
));
|
125 |
em_options_select ( __( 'Order Tickets By', 'events-manager'), 'dbem_bookings_tickets_orderby', $ticket_orders, __( 'Choose which order your tickets appear.', 'events-manager') );
|
126 |
echo $save_button;
|
127 |
?>
|
admin/settings/tabs/emails.php
CHANGED
@@ -14,6 +14,7 @@
|
|
14 |
$email_subject_tip = __('You can disable this email by leaving the subject blank.','events-manager');
|
15 |
em_options_input_text ( __( 'Email events admin?', 'events-manager'), 'dbem_bookings_notify_admin', __( "If you would like every event booking confirmation email sent to an administrator write their email here (leave blank to not send an email).", 'events-manager').' '.__('For multiple emails, separate by commas (e.g. email1@test.com,email2@test.com,etc.)','events-manager') );
|
16 |
em_options_radio_binary ( __( 'Email event owner?', 'events-manager'), 'dbem_bookings_contact_email', __( 'Check this option if you want the event contact to receive an email when someone books places. An email will be sent when a booking is first made (regardless if confirmed or pending)', 'events-manager') );
|
|
|
17 |
?>
|
18 |
<tr class="em-header"><td colspan='2'><h4><?php _e('Event Admin/Owner Emails', 'events-manager'); ?></h4></td></tr>
|
19 |
<tbody class="em-subsection">
|
14 |
$email_subject_tip = __('You can disable this email by leaving the subject blank.','events-manager');
|
15 |
em_options_input_text ( __( 'Email events admin?', 'events-manager'), 'dbem_bookings_notify_admin', __( "If you would like every event booking confirmation email sent to an administrator write their email here (leave blank to not send an email).", 'events-manager').' '.__('For multiple emails, separate by commas (e.g. email1@test.com,email2@test.com,etc.)','events-manager') );
|
16 |
em_options_radio_binary ( __( 'Email event owner?', 'events-manager'), 'dbem_bookings_contact_email', __( 'Check this option if you want the event contact to receive an email when someone books places. An email will be sent when a booking is first made (regardless if confirmed or pending)', 'events-manager') );
|
17 |
+
do_action('em_options_page_booking_email_templates_options_subtop');
|
18 |
?>
|
19 |
<tr class="em-header"><td colspan='2'><h4><?php _e('Event Admin/Owner Emails', 'events-manager'); ?></h4></td></tr>
|
20 |
<tbody class="em-subsection">
|
buddypress/bp-em-core.php
CHANGED
@@ -78,8 +78,9 @@ class BP_EM_Component extends BP_Component {
|
|
78 |
/* Add 'Events' to the main user profile navigation */
|
79 |
$event_count = EM_Events::count( array( 'scope'=>'future', 'owner'=> bp_displayed_user_id() ));
|
80 |
if( empty($event_count) ) $event_count = 0;
|
|
|
81 |
$main_nav = array(
|
82 |
-
'name' => __( 'Events', 'events-manager').
|
83 |
'slug' => em_bp_get_slug(),
|
84 |
'position' => 80,
|
85 |
'screen_function' => 'bp_em_events',
|
78 |
/* Add 'Events' to the main user profile navigation */
|
79 |
$event_count = EM_Events::count( array( 'scope'=>'future', 'owner'=> bp_displayed_user_id() ));
|
80 |
if( empty($event_count) ) $event_count = 0;
|
81 |
+
$event_count_span = $event_count > 0 ? ' <span class="count">'.esc_html($event_count).'</span>':'';
|
82 |
$main_nav = array(
|
83 |
+
'name' => __( 'Events', 'events-manager'). $event_count_span,
|
84 |
'slug' => em_bp_get_slug(),
|
85 |
'position' => 80,
|
86 |
'screen_function' => 'bp_em_events',
|
classes/em-booking.php
CHANGED
@@ -1007,8 +1007,8 @@ class EM_Booking extends EM_Object{
|
|
1007 |
global $wpdb;
|
1008 |
if( $this->can_manage() ){
|
1009 |
$this->get_notes();
|
1010 |
-
$note = array('author'=>get_current_user_id(),'note'
|
1011 |
-
$this->notes[] =
|
1012 |
$this->feedback_message = __('Booking note successfully added.','events-manager');
|
1013 |
return $wpdb->insert(EM_META_TABLE, array('object_id'=>$this->booking_id, 'meta_key'=>'booking-note', 'meta_value'=> serialize($note)),array('%d','%s','%s'));
|
1014 |
}
|
@@ -1152,8 +1152,12 @@ class EM_Booking extends EM_Object{
|
|
1152 |
if( !empty($msg['user']['subject']) && $email_attendee ){
|
1153 |
$msg['user']['subject'] = $this->output($msg['user']['subject'], 'raw');
|
1154 |
$msg['user']['body'] = $this->output($msg['user']['body'], 'email');
|
|
|
|
|
|
|
|
|
1155 |
//Send to the person booking
|
1156 |
-
if( !$this->email_send( $msg['user']['subject'], $msg['user']['body'], $this->get_person()->user_email) ){
|
1157 |
$result = false;
|
1158 |
}else{
|
1159 |
$this->mails_sent++;
|
@@ -1175,8 +1179,12 @@ class EM_Booking extends EM_Object{
|
|
1175 |
//Only gets sent if this is a pending booking, unless approvals are disabled.
|
1176 |
$msg['admin']['subject'] = $this->output($msg['admin']['subject'],'raw');
|
1177 |
$msg['admin']['body'] = $this->output($msg['admin']['body'], 'email');
|
|
|
|
|
|
|
|
|
1178 |
//email admins
|
1179 |
-
if( !$this->email_send( $msg['admin']['subject'], $msg['admin']['body'], $admin_emails) && current_user_can('manage_options') ){
|
1180 |
$this->errors[] = __('Confirmation email could not be sent to admin. Registrant should have gotten their email (only admin see this warning).','events-manager');
|
1181 |
$result = false;
|
1182 |
}else{
|
1007 |
global $wpdb;
|
1008 |
if( $this->can_manage() ){
|
1009 |
$this->get_notes();
|
1010 |
+
$note = array('author'=>get_current_user_id(),'note'=>wp_kses_data($note_text),'timestamp'=>time());
|
1011 |
+
$this->notes[] = $note;
|
1012 |
$this->feedback_message = __('Booking note successfully added.','events-manager');
|
1013 |
return $wpdb->insert(EM_META_TABLE, array('object_id'=>$this->booking_id, 'meta_key'=>'booking-note', 'meta_value'=> serialize($note)),array('%d','%s','%s'));
|
1014 |
}
|
1152 |
if( !empty($msg['user']['subject']) && $email_attendee ){
|
1153 |
$msg['user']['subject'] = $this->output($msg['user']['subject'], 'raw');
|
1154 |
$msg['user']['body'] = $this->output($msg['user']['body'], 'email');
|
1155 |
+
$attachments = array();
|
1156 |
+
if( !empty($msg['user']['attachments']) && is_array($msg['user']['attachments']) ){
|
1157 |
+
$attachments = $msg['user']['attachments'];
|
1158 |
+
}
|
1159 |
//Send to the person booking
|
1160 |
+
if( !$this->email_send( $msg['user']['subject'], $msg['user']['body'], $this->get_person()->user_email, $attachments) ){
|
1161 |
$result = false;
|
1162 |
}else{
|
1163 |
$this->mails_sent++;
|
1179 |
//Only gets sent if this is a pending booking, unless approvals are disabled.
|
1180 |
$msg['admin']['subject'] = $this->output($msg['admin']['subject'],'raw');
|
1181 |
$msg['admin']['body'] = $this->output($msg['admin']['body'], 'email');
|
1182 |
+
$attachments = array();
|
1183 |
+
if( !empty($msg['admin']['attachments']) && is_array($msg['admin']['attachments']) ){
|
1184 |
+
$attachments = $msg['admin']['attachments'];
|
1185 |
+
}
|
1186 |
//email admins
|
1187 |
+
if( !$this->email_send( $msg['admin']['subject'], $msg['admin']['body'], $admin_emails, $attachments) && current_user_can('manage_options') ){
|
1188 |
$this->errors[] = __('Confirmation email could not be sent to admin. Registrant should have gotten their email (only admin see this warning).','events-manager');
|
1189 |
$result = false;
|
1190 |
}else{
|
classes/em-bookings-table.php
CHANGED
@@ -490,7 +490,11 @@ class EM_Bookings_Table{
|
|
490 |
$headers[] = '<a class="em-bookings-orderby" href="#'.$col.'">'.$this->cols_template[$col].'</a>';
|
491 |
}
|
492 |
*/
|
493 |
-
$
|
|
|
|
|
|
|
|
|
494 |
}
|
495 |
}
|
496 |
return apply_filters('em_bookings_table_get_headers', $headers, $csv, $this);
|
@@ -588,19 +592,31 @@ class EM_Bookings_Table{
|
|
588 |
if( $format == 'html' || empty($format) ){
|
589 |
if( !in_array($col, array('user_login', 'user_name', 'event_name', 'actions')) ) $val = esc_html($val);
|
590 |
}
|
591 |
-
//use this
|
592 |
$val = apply_filters('em_bookings_table_rows_col_'.$col, $val, $EM_Booking, $this, $format, $object);
|
593 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
594 |
}
|
595 |
return $cols;
|
596 |
}
|
597 |
|
598 |
function get_row_csv($EM_Booking){
|
599 |
$row = $this->get_row($EM_Booking, 'csv');
|
600 |
-
foreach($row as $k=>$v)
|
|
|
|
|
601 |
return $row;
|
602 |
}
|
603 |
|
|
|
|
|
|
|
|
|
604 |
/**
|
605 |
* @param EM_Booking $EM_Booking
|
606 |
* @return mixed
|
490 |
$headers[] = '<a class="em-bookings-orderby" href="#'.$col.'">'.$this->cols_template[$col].'</a>';
|
491 |
}
|
492 |
*/
|
493 |
+
$v = $this->cols_template[$col];
|
494 |
+
if( $csv ){
|
495 |
+
$v = self::sanitize_spreadsheet_cell($v);
|
496 |
+
}
|
497 |
+
$headers[$col] = $v;
|
498 |
}
|
499 |
}
|
500 |
return apply_filters('em_bookings_table_get_headers', $headers, $csv, $this);
|
592 |
if( $format == 'html' || empty($format) ){
|
593 |
if( !in_array($col, array('user_login', 'user_name', 'event_name', 'actions')) ) $val = esc_html($val);
|
594 |
}
|
595 |
+
//use this
|
596 |
$val = apply_filters('em_bookings_table_rows_col_'.$col, $val, $EM_Booking, $this, $format, $object);
|
597 |
+
$val = apply_filters('em_bookings_table_rows_col', $val, $col, $EM_Booking, $this, $format, $object); //use the above filter instead for better performance
|
598 |
+
//csv/excel escaping
|
599 |
+
if( $format == 'csv' || $format == 'xls' || $format == 'xlsx' ){
|
600 |
+
$val = self::sanitize_spreadsheet_cell($val);
|
601 |
+
}
|
602 |
+
//add to cols
|
603 |
+
$cols[] = $val;
|
604 |
}
|
605 |
return $cols;
|
606 |
}
|
607 |
|
608 |
function get_row_csv($EM_Booking){
|
609 |
$row = $this->get_row($EM_Booking, 'csv');
|
610 |
+
foreach($row as $k=>$v){
|
611 |
+
$row[$k] = html_entity_decode($v);
|
612 |
+
} //remove things like & which may have been saved to the DB directly
|
613 |
return $row;
|
614 |
}
|
615 |
|
616 |
+
public static function sanitize_spreadsheet_cell( $cell ){
|
617 |
+
return preg_replace('/^([;=@\+\-])/', "'$1", $cell);
|
618 |
+
}
|
619 |
+
|
620 |
/**
|
621 |
* @param EM_Booking $EM_Booking
|
622 |
* @return mixed
|
classes/em-event.php
CHANGED
@@ -2243,7 +2243,7 @@ class EM_Event extends EM_Object{
|
|
2243 |
$replace_format = em_get_date_format() .' '. em_get_hour_format();
|
2244 |
if( $result == '#_BOOKINGSCUTOFFDATE' ) $replace_format = em_get_date_format();
|
2245 |
if( $result == '#_BOOKINGSCUTOFFTIME' ) $replace_format = em_get_hour_format();
|
2246 |
-
$replace = $this->rsvp_end()->
|
2247 |
}
|
2248 |
break;
|
2249 |
//Contact Person
|
2243 |
$replace_format = em_get_date_format() .' '. em_get_hour_format();
|
2244 |
if( $result == '#_BOOKINGSCUTOFFDATE' ) $replace_format = em_get_date_format();
|
2245 |
if( $result == '#_BOOKINGSCUTOFFTIME' ) $replace_format = em_get_hour_format();
|
2246 |
+
$replace = $this->rsvp_end()->i18n($replace_format);
|
2247 |
}
|
2248 |
break;
|
2249 |
//Contact Person
|
classes/em-mailer.php
CHANGED
@@ -10,6 +10,11 @@ class EM_Mailer {
|
|
10 |
* @var array
|
11 |
*/
|
12 |
public $errors = array();
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
/**
|
15 |
* Send an email via the EM-saved settings.
|
@@ -36,21 +41,26 @@ class EM_Mailer {
|
|
36 |
}
|
37 |
if ( $emails_ok && get_option('dbem_rsvp_mail_send_method') == 'wp_mail' ){
|
38 |
$from = get_option('dbem_mail_sender_address');
|
39 |
-
$headers =
|
|
|
|
|
40 |
if( get_option('dbem_smtp_html') ){ //create filter to change content type to html in wp_mail
|
41 |
add_filter('wp_mail_content_type','EM_Mailer::return_texthtml');
|
42 |
}
|
43 |
//prep attachments for WP Mail, which only accept a path
|
44 |
-
|
45 |
-
|
46 |
-
$wp_mail_attachments[] = $attachment['path'];
|
47 |
-
}
|
48 |
//send and handle errors
|
49 |
-
$send = wp_mail($receiver, $subject, $body, $headers
|
|
|
|
|
|
|
50 |
if(!$send){
|
51 |
global $phpmailer;
|
52 |
$this->errors[] = $phpmailer->ErrorInfo;
|
53 |
}
|
|
|
|
|
54 |
return $send;
|
55 |
}elseif( $emails_ok ){
|
56 |
$this->load_phpmailer();
|
@@ -60,11 +70,13 @@ class EM_Mailer {
|
|
60 |
if( get_option('dbem_smtp_html') ){
|
61 |
$mail->isHTML();
|
62 |
}
|
63 |
-
$mail->
|
64 |
-
$mail->
|
65 |
-
$mail->
|
|
|
|
|
66 |
$mail->CharSet = 'utf-8';
|
67 |
-
$mail->
|
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
|
@@ -87,23 +99,13 @@ class EM_Mailer {
|
|
87 |
}
|
88 |
$mail->SMTPAutoTLS = get_option('dbem_smtp_autotls') == 1;
|
89 |
//add attachments
|
90 |
-
|
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->
|
104 |
}
|
105 |
}else{
|
106 |
-
$mail->
|
107 |
}
|
108 |
do_action('em_mailer', $mail); //$mail will still be modified
|
109 |
|
@@ -119,18 +121,21 @@ class EM_Mailer {
|
|
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->
|
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;
|
135 |
}
|
136 |
}
|
@@ -143,8 +148,93 @@ class EM_Mailer {
|
|
143 |
require_once ABSPATH . WPINC . '/class-smtp.php';
|
144 |
}
|
145 |
|
|
|
|
|
|
|
|
|
146 |
public static function return_texthtml(){
|
147 |
return "text/html";
|
148 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
}
|
150 |
?>
|
10 |
* @var array
|
11 |
*/
|
12 |
public $errors = array();
|
13 |
+
/**
|
14 |
+
* Array of attachments which will be added to WP_Mail's phpmailer just before sending, and subsequently emptied.
|
15 |
+
* @var array
|
16 |
+
*/
|
17 |
+
public static $attachments = array();
|
18 |
|
19 |
/**
|
20 |
* Send an email via the EM-saved settings.
|
41 |
}
|
42 |
if ( $emails_ok && get_option('dbem_rsvp_mail_send_method') == 'wp_mail' ){
|
43 |
$from = get_option('dbem_mail_sender_address');
|
44 |
+
$headers = array();
|
45 |
+
$headers[] = get_option('dbem_mail_sender_name') ? 'From: '.get_option('dbem_mail_sender_name').' <'.$from.'>':'From: '.$from;
|
46 |
+
$headers[] = get_option('dbem_mail_sender_name') ? 'Reply-To: '.get_option('dbem_mail_sender_name').' <'.$from.'>':'From: '.$from;
|
47 |
if( get_option('dbem_smtp_html') ){ //create filter to change content type to html in wp_mail
|
48 |
add_filter('wp_mail_content_type','EM_Mailer::return_texthtml');
|
49 |
}
|
50 |
//prep attachments for WP Mail, which only accept a path
|
51 |
+
self::$attachments = $attachments;
|
52 |
+
add_action('phpmailer_init', 'EM_Mailer::add_attachments_to_mailer', 9999, 1);
|
|
|
|
|
53 |
//send and handle errors
|
54 |
+
$send = wp_mail($receiver, $subject, $body, $headers);
|
55 |
+
//unload attachments hook
|
56 |
+
remove_action('phpmailer_init', 'EM_Mailer::add_attachments_to_mailer', 9999);
|
57 |
+
//send email
|
58 |
if(!$send){
|
59 |
global $phpmailer;
|
60 |
$this->errors[] = $phpmailer->ErrorInfo;
|
61 |
}
|
62 |
+
//cleanup
|
63 |
+
self::delete_email_attachments($attachments);
|
64 |
return $send;
|
65 |
}elseif( $emails_ok ){
|
66 |
$this->load_phpmailer();
|
70 |
if( get_option('dbem_smtp_html') ){
|
71 |
$mail->isHTML();
|
72 |
}
|
73 |
+
$mail->clearAllRecipients();
|
74 |
+
$mail->clearAddresses();
|
75 |
+
$mail->clearAttachments();
|
76 |
+
$mail->clearCustomHeaders();
|
77 |
+
$mail->clearReplyTos();
|
78 |
$mail->CharSet = 'utf-8';
|
79 |
+
$mail->setLanguage('en', dirname(__FILE__).'/');
|
80 |
$mail->PluginDir = dirname(__FILE__).'/phpmailer/';
|
81 |
$host = get_option('dbem_smtp_host');
|
82 |
//if port is supplied via the host address, give that precedence over the port setting
|
99 |
}
|
100 |
$mail->SMTPAutoTLS = get_option('dbem_smtp_autotls') == 1;
|
101 |
//add attachments
|
102 |
+
self::add_attachments_to_mailer($mail, $attachments);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
if(is_array($receiver)){
|
104 |
foreach($receiver as $receiver_email){
|
105 |
+
$mail->addAddress($receiver_email);
|
106 |
}
|
107 |
}else{
|
108 |
+
$mail->addAddress($receiver);
|
109 |
}
|
110 |
do_action('em_mailer', $mail); //$mail will still be modified
|
111 |
|
121 |
$mail->SMTPAuth = TRUE;
|
122 |
}
|
123 |
do_action('em_mailer_before_send', $mail, $subject, $body, $receiver, $attachments); //$mail can still be modified
|
124 |
+
$send = $mail->send();
|
125 |
if(!$send){
|
126 |
$this->errors[] = $mail->ErrorInfo;
|
127 |
}
|
128 |
do_action('em_mailer_sent', $mail, $send); //$mail can still be modified
|
129 |
+
self::delete_email_attachments($attachments);
|
130 |
return $send;
|
131 |
}catch( phpmailerException $ex ){
|
132 |
$this->errors[] = $mail->ErrorInfo;
|
133 |
+
self::delete_email_attachments($attachments);
|
134 |
return false;
|
135 |
}
|
136 |
}else{
|
137 |
$this->errors[] = __('Please supply a valid email format.', 'events-manager');
|
138 |
+
self::delete_email_attachments($attachments);
|
139 |
return false;
|
140 |
}
|
141 |
}
|
148 |
require_once ABSPATH . WPINC . '/class-smtp.php';
|
149 |
}
|
150 |
|
151 |
+
/**
|
152 |
+
* Shorthand function for filters to return 'text/html' string.
|
153 |
+
* @return string 'text/html'
|
154 |
+
*/
|
155 |
public static function return_texthtml(){
|
156 |
return "text/html";
|
157 |
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* WP_Mail doesn't accept attachment meta, only an array of paths, this function post-fixes attachments to the PHPMailer object.
|
161 |
+
* @param PHPMailer $phpmailer
|
162 |
+
* @param array $attachments
|
163 |
+
*/
|
164 |
+
public static function add_attachments_to_mailer( $phpmailer, $attachments = array() ){
|
165 |
+
//add attachments
|
166 |
+
$attachments = !empty($attachments) ? $attachments : self::$attachments;
|
167 |
+
if( !empty($attachments) ){
|
168 |
+
foreach($attachments as $attachment){
|
169 |
+
$att = array('name'=> '', 'encoding' => 'base64', 'type' => 'application/octet-stream');
|
170 |
+
if( is_array($attachment) ){
|
171 |
+
$att = array_merge($att, $attachment);
|
172 |
+
}else{
|
173 |
+
$att['path'] = $attachment;
|
174 |
+
}
|
175 |
+
try{
|
176 |
+
$phpmailer->addAttachment($att['path'], $att['name'], $att['encoding'], $att['type']);
|
177 |
+
}catch( phpmailerException $ex ){
|
178 |
+
//do nothing
|
179 |
+
}
|
180 |
+
}
|
181 |
+
}
|
182 |
+
self::$attachments = array();
|
183 |
+
}
|
184 |
+
|
185 |
+
public static function delete_email_attachments( $attachments ){
|
186 |
+
foreach( $attachments as $attachment ){
|
187 |
+
if( !empty($attachment['delete']) ){
|
188 |
+
@unlink( $attachment['path']);
|
189 |
+
}
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Returns the path of the attachments folder, creating it if non-existent. Returns false if folder could not be created.
|
195 |
+
* A .htaccess file is also attempted to be created, although this will still return as true even if it cannot be created.
|
196 |
+
* @return bool|string
|
197 |
+
*/
|
198 |
+
public static function get_attachments_dir(){
|
199 |
+
//get and possibly create attachment directory path
|
200 |
+
$upload_dir = wp_upload_dir();
|
201 |
+
$attachments_dir = trailingslashit($upload_dir['basedir'])."em-email-attachments/";
|
202 |
+
if( !is_dir($attachments_dir) ){
|
203 |
+
//try to make a directory and create an .htaccess file
|
204 |
+
if( @mkdir($attachments_dir, 0755) ){
|
205 |
+
return $attachments_dir;
|
206 |
+
}
|
207 |
+
//could not create directory
|
208 |
+
return false;
|
209 |
+
}
|
210 |
+
//add .htaccess file to prevent access to folder by guessing filenames
|
211 |
+
if( !file_exists($attachments_dir.'.htaccess') ){
|
212 |
+
$file = @fopen($attachments_dir.'.htaccess','w');
|
213 |
+
if( $file ){
|
214 |
+
fwrite($file, 'deny from all');
|
215 |
+
fclose($file);
|
216 |
+
}
|
217 |
+
}
|
218 |
+
return $attachments_dir;
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Adds file to email attachments folder, which defaults to wp-content/uploads/em-email-attachments/ and returns the location of said file, false if file could not be created.
|
223 |
+
* @param $file_name
|
224 |
+
* @param $file_content
|
225 |
+
* @return bool|string
|
226 |
+
*/
|
227 |
+
public static function add_email_attachment( $file_name, $file_content ){
|
228 |
+
$attachment_dir = self::get_attachments_dir();
|
229 |
+
if( $attachment_dir ){
|
230 |
+
$file = fopen($attachment_dir.$file_name,'w+');
|
231 |
+
if( $file ){
|
232 |
+
fwrite($file, $file_content);
|
233 |
+
fclose($file);
|
234 |
+
return $attachment_dir . $file_name;
|
235 |
+
}
|
236 |
+
}
|
237 |
+
return false;
|
238 |
+
}
|
239 |
}
|
240 |
?>
|
classes/em-notices.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
* @author marcus
|
5 |
*
|
6 |
*/
|
7 |
-
class EM_Notices implements Iterator {
|
8 |
/**
|
9 |
* If object has been displayed, this gets set to true, can be checked to avoid duplicates.
|
10 |
* @var boolean
|
@@ -222,7 +222,18 @@
|
|
222 |
}
|
223 |
function count_confirms(){
|
224 |
return $this->count('confirms');
|
225 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
|
227 |
//Iterator Implementation
|
228 |
function rewind(){
|
@@ -244,8 +255,8 @@
|
|
244 |
$key = key($this->bookings);
|
245 |
$var = ($key !== NULL && $key !== FALSE);
|
246 |
return $var;
|
247 |
-
}
|
248 |
-
|
249 |
}
|
250 |
function em_notices_init(){
|
251 |
global $EM_Notices;
|
4 |
* @author marcus
|
5 |
*
|
6 |
*/
|
7 |
+
class EM_Notices implements Iterator, JsonSerializable {
|
8 |
/**
|
9 |
* If object has been displayed, this gets set to true, can be checked to avoid duplicates.
|
10 |
* @var boolean
|
222 |
}
|
223 |
function count_confirms(){
|
224 |
return $this->count('confirms');
|
225 |
+
}
|
226 |
+
|
227 |
+
// Encoiding in JsonSerializable
|
228 |
+
function jsonSerialize(){
|
229 |
+
$notices = array();
|
230 |
+
foreach( $notices as $k => $v ){
|
231 |
+
if( !empty($v) ){
|
232 |
+
$notices[$k] = $v;
|
233 |
+
}
|
234 |
+
}
|
235 |
+
return $notices;
|
236 |
+
}
|
237 |
|
238 |
//Iterator Implementation
|
239 |
function rewind(){
|
255 |
$key = key($this->bookings);
|
256 |
$var = ($key !== NULL && $key !== FALSE);
|
257 |
return $var;
|
258 |
+
}
|
259 |
+
|
260 |
}
|
261 |
function em_notices_init(){
|
262 |
global $EM_Notices;
|
classes/em-object.php
CHANGED
@@ -1362,15 +1362,16 @@ class EM_Object {
|
|
1362 |
* @param string $subject
|
1363 |
* @param string $body
|
1364 |
* @param string $email
|
|
|
1365 |
* @return string
|
1366 |
*/
|
1367 |
-
function email_send($subject, $body, $email){
|
1368 |
global $EM_Mailer;
|
1369 |
if( !empty($subject) ){
|
1370 |
if( !is_object($EM_Mailer) ){
|
1371 |
$EM_Mailer = new EM_Mailer();
|
1372 |
}
|
1373 |
-
if( !$EM_Mailer->send($subject,$body,$email) ){
|
1374 |
if( is_array($EM_Mailer->errors) ){
|
1375 |
foreach($EM_Mailer->errors as $error){
|
1376 |
$this->errors[] = $error;
|
1362 |
* @param string $subject
|
1363 |
* @param string $body
|
1364 |
* @param string $email
|
1365 |
+
* @param array $attachments
|
1366 |
* @return string
|
1367 |
*/
|
1368 |
+
function email_send($subject, $body, $email, $attachments = array()){
|
1369 |
global $EM_Mailer;
|
1370 |
if( !empty($subject) ){
|
1371 |
if( !is_object($EM_Mailer) ){
|
1372 |
$EM_Mailer = new EM_Mailer();
|
1373 |
}
|
1374 |
+
if( !$EM_Mailer->send($subject,$body,$email, $attachments) ){
|
1375 |
if( is_array($EM_Mailer->errors) ){
|
1376 |
foreach($EM_Mailer->errors as $error){
|
1377 |
$this->errors[] = $error;
|
classes/em-ticket-booking.php
CHANGED
@@ -215,8 +215,18 @@ class EM_Ticket_Booking extends EM_Object{
|
|
215 |
*/
|
216 |
function delete(){
|
217 |
global $wpdb;
|
218 |
-
|
219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
return apply_filters('em_ticket_booking_delete', ($result !== false ), $this);
|
221 |
}
|
222 |
|
215 |
*/
|
216 |
function delete(){
|
217 |
global $wpdb;
|
218 |
+
if( $this->ticket_booking_id ){
|
219 |
+
$sql = $wpdb->prepare("DELETE FROM ". EM_TICKETS_BOOKINGS_TABLE . " WHERE ticket_booking_id=%d LIMIT 1", $this->ticket_booking_id);
|
220 |
+
}elseif( !empty($this->ticket_id) && !empty($this->booking_id) ){
|
221 |
+
//in the event a ticket_booking_id isn't available we can delete via the booking and ticket id
|
222 |
+
$sql = $wpdb->prepare("DELETE FROM ". EM_TICKETS_BOOKINGS_TABLE . " WHERE ticket_id=%d AND booking_id=%d LIMIT 1", $this->ticket_id, $this->booking_id);
|
223 |
+
}else{
|
224 |
+
//cannot delete ticket
|
225 |
+
$result = false;
|
226 |
+
}
|
227 |
+
if( !empty($sql) ){
|
228 |
+
$result = $wpdb->query( $sql );
|
229 |
+
}
|
230 |
return apply_filters('em_ticket_booking_delete', ($result !== false ), $this);
|
231 |
}
|
232 |
|
classes/em-ticket.php
CHANGED
@@ -17,6 +17,7 @@ class EM_Ticket extends EM_Object{
|
|
17 |
var $ticket_required = false;
|
18 |
var $ticket_parent;
|
19 |
var $ticket_meta = array();
|
|
|
20 |
var $fields = array(
|
21 |
'ticket_id' => array('name'=>'id','type'=>'%d'),
|
22 |
'event_id' => array('name'=>'event_id','type'=>'%d'),
|
@@ -33,7 +34,8 @@ class EM_Ticket extends EM_Object{
|
|
33 |
'ticket_guests' => array('name'=>'guests','type'=>'%d','null'=>1),
|
34 |
'ticket_required' => array('name'=>'required','type'=>'%d','null'=>1),
|
35 |
'ticket_parent' => array('type'=>'%d','null'=>1),
|
36 |
-
'ticket_meta' => array('name'=>'ticket_meta','type'=>'%s','null'=>1)
|
|
|
37 |
);
|
38 |
//Other Vars
|
39 |
/**
|
17 |
var $ticket_required = false;
|
18 |
var $ticket_parent;
|
19 |
var $ticket_meta = array();
|
20 |
+
var $ticket_order;
|
21 |
var $fields = array(
|
22 |
'ticket_id' => array('name'=>'id','type'=>'%d'),
|
23 |
'event_id' => array('name'=>'event_id','type'=>'%d'),
|
34 |
'ticket_guests' => array('name'=>'guests','type'=>'%d','null'=>1),
|
35 |
'ticket_required' => array('name'=>'required','type'=>'%d','null'=>1),
|
36 |
'ticket_parent' => array('type'=>'%d','null'=>1),
|
37 |
+
'ticket_meta' => array('name'=>'ticket_meta','type'=>'%s','null'=>1),
|
38 |
+
'ticket_order' => array('type'=>'%d','null'=>1),
|
39 |
);
|
40 |
//Other Vars
|
41 |
/**
|
classes/em-tickets-bookings.php
CHANGED
@@ -8,9 +8,14 @@ class EM_Tickets_Bookings extends EM_Object implements Iterator, Countable {
|
|
8 |
|
9 |
/**
|
10 |
* Array of EM_Ticket_Booking objects for a specific event
|
11 |
-
* @var array
|
12 |
*/
|
13 |
var $tickets_bookings = array();
|
|
|
|
|
|
|
|
|
|
|
14 |
/**
|
15 |
* This object belongs to this booking object
|
16 |
* @var EM_Booking
|
@@ -57,14 +62,22 @@ class EM_Tickets_Bookings extends EM_Object implements Iterator, Countable {
|
|
57 |
* @return boolean
|
58 |
*/
|
59 |
function save(){
|
60 |
-
global $wpdb;
|
61 |
do_action('em_tickets_bookings_save_pre',$this);
|
62 |
-
|
|
|
63 |
$result = $EM_Ticket_Booking->save();
|
64 |
if(!$result){
|
65 |
$this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
|
66 |
}
|
67 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
if( count($this->errors) > 0 ){
|
69 |
$this->feedback_message = __('There was a problem saving the booking.', 'events-manager');
|
70 |
$this->errors[] = __('There was a problem saving the booking.', 'events-manager');
|
@@ -85,9 +98,15 @@ class EM_Tickets_Bookings extends EM_Object implements Iterator, Countable {
|
|
85 |
$ticket_booking_key = $this->has_ticket($EM_Ticket_Booking->ticket_id);
|
86 |
$this->price = 0; //so price calculations are reset
|
87 |
if( $ticket_booking_key !== false && is_object($this->tickets_bookings[$EM_Ticket_Booking->ticket_id]) ){
|
88 |
-
|
89 |
-
|
90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
return apply_filters('em_tickets_bookings_add', true, $this, $EM_Ticket_Booking);
|
92 |
}elseif( $EM_Ticket_Booking->get_spaces() > 0 ){
|
93 |
//new ticket in booking
|
8 |
|
9 |
/**
|
10 |
* Array of EM_Ticket_Booking objects for a specific event
|
11 |
+
* @var array[EM_Ticket_Booking]
|
12 |
*/
|
13 |
var $tickets_bookings = array();
|
14 |
+
/**
|
15 |
+
* When adding existing booked tickets via add() with 0 spaces, they get slotted here for deletion during save() so they circumvent validation.
|
16 |
+
* @var array[EM_Ticket_Booking]
|
17 |
+
*/
|
18 |
+
var $tickets_bookings_deleted = array();
|
19 |
/**
|
20 |
* This object belongs to this booking object
|
21 |
* @var EM_Booking
|
62 |
* @return boolean
|
63 |
*/
|
64 |
function save(){
|
|
|
65 |
do_action('em_tickets_bookings_save_pre',$this);
|
66 |
+
//save/update tickets
|
67 |
+
foreach( $this->tickets_bookings as $EM_Ticket_Booking ){
|
68 |
$result = $EM_Ticket_Booking->save();
|
69 |
if(!$result){
|
70 |
$this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
|
71 |
}
|
72 |
}
|
73 |
+
//delete old tickets if set to 0 in an update
|
74 |
+
foreach($this->tickets_bookings_deleted as $EM_Ticket_Booking ){
|
75 |
+
$result = $EM_Ticket_Booking->delete();
|
76 |
+
if(!$result){
|
77 |
+
$this->errors = array_merge($this->errors, $EM_Ticket_Booking->get_errors());
|
78 |
+
}
|
79 |
+
}
|
80 |
+
//return result
|
81 |
if( count($this->errors) > 0 ){
|
82 |
$this->feedback_message = __('There was a problem saving the booking.', 'events-manager');
|
83 |
$this->errors[] = __('There was a problem saving the booking.', 'events-manager');
|
98 |
$ticket_booking_key = $this->has_ticket($EM_Ticket_Booking->ticket_id);
|
99 |
$this->price = 0; //so price calculations are reset
|
100 |
if( $ticket_booking_key !== false && is_object($this->tickets_bookings[$EM_Ticket_Booking->ticket_id]) ){
|
101 |
+
if( $EM_Ticket_Booking->get_spaces() > 0 ){
|
102 |
+
//previously booked ticket, so let's just reset spaces/prices and replace it
|
103 |
+
$this->tickets_bookings[$EM_Ticket_Booking->ticket_id]->ticket_booking_spaces = $EM_Ticket_Booking->get_spaces();
|
104 |
+
$this->tickets_bookings[$EM_Ticket_Booking->ticket_id]->ticket_booking_price = $EM_Ticket_Booking->get_price();
|
105 |
+
}else{
|
106 |
+
//remove ticket from bookings and set for deletion if this is saved
|
107 |
+
unset($this->tickets_bookings[$EM_Ticket_Booking->ticket_id]);
|
108 |
+
$this->tickets_bookings_deleted[$EM_Ticket_Booking->ticket_id] = $EM_Ticket_Booking;
|
109 |
+
}
|
110 |
return apply_filters('em_tickets_bookings_add', true, $this, $EM_Ticket_Booking);
|
111 |
}elseif( $EM_Ticket_Booking->get_spaces() > 0 ){
|
112 |
//new ticket in booking
|
classes/em-tickets.php
CHANGED
@@ -30,10 +30,23 @@ class EM_Tickets extends EM_Object implements Iterator, Countable {
|
|
30 |
global $wpdb;
|
31 |
if( is_numeric($object) || (is_object($object) && in_array(get_class($object), array("EM_Event","EM_Booking"))) ){
|
32 |
$this->event_id = (is_object($object)) ? $object->event_id:$object;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
if( is_object($object) && get_class($object) == 'EM_Booking' ){
|
34 |
-
$sql = "SELECT * FROM ". EM_TICKETS_TABLE ." WHERE ticket_id IN (SELECT ticket_id FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE booking_id='{$object->booking_id}') ORDER BY ".
|
35 |
}else{
|
36 |
-
$sql = "SELECT * FROM ". EM_TICKETS_TABLE ." WHERE event_id ='{$this->event_id}' ORDER BY ".
|
37 |
}
|
38 |
$tickets = $wpdb->get_results($sql, ARRAY_A);
|
39 |
foreach ($tickets as $ticket){
|
@@ -147,6 +160,7 @@ class EM_Tickets extends EM_Object implements Iterator, Countable {
|
|
147 |
if( !empty($_POST['em_tickets']) && is_array($_POST['em_tickets']) ){
|
148 |
//get all ticket data and create objects
|
149 |
global $allowedposttags;
|
|
|
150 |
foreach($_POST['em_tickets'] as $row => $ticket_data){
|
151 |
if( $row > 0 ){
|
152 |
if( !empty($ticket_data['ticket_id']) && !empty($current_tickets[$ticket_data['ticket_id']]) ){
|
@@ -156,11 +170,13 @@ class EM_Tickets extends EM_Object implements Iterator, Countable {
|
|
156 |
}
|
157 |
$ticket_data['event_id'] = $this->event_id;
|
158 |
$EM_Ticket->get_post($ticket_data);
|
|
|
159 |
if( $EM_Ticket->ticket_id ){
|
160 |
$this->tickets[$EM_Ticket->ticket_id] = $EM_Ticket;
|
161 |
}else{
|
162 |
$this->tickets[] = $EM_Ticket;
|
163 |
}
|
|
|
164 |
}
|
165 |
}
|
166 |
}else{
|
30 |
global $wpdb;
|
31 |
if( is_numeric($object) || (is_object($object) && in_array(get_class($object), array("EM_Event","EM_Booking"))) ){
|
32 |
$this->event_id = (is_object($object)) ? $object->event_id:$object;
|
33 |
+
$orderby_option = get_option('dbem_bookings_tickets_orderby');
|
34 |
+
$order_by = get_option('dbem_bookings_tickets_ordering') ? array('ticket_order ASC') : array();
|
35 |
+
$ticket_orderby_options = apply_filters('em_tickets_orderby_options', array(
|
36 |
+
'ticket_price DESC, ticket_name ASC'=>__('Ticket Price (Descending)','events-manager'),
|
37 |
+
'ticket_price ASC, ticket_name ASC'=>__('Ticket Price (Ascending)','events-manager'),
|
38 |
+
'ticket_name ASC, ticket_price DESC'=>__('Ticket Name (Ascending)','events-manager'),
|
39 |
+
'ticket_name DESC, ticket_price DESC'=>__('Ticket Name (Descending)','events-manager')
|
40 |
+
));
|
41 |
+
if( array_key_exists($orderby_option, $ticket_orderby_options) ){
|
42 |
+
$order_by[] = $orderby_option;
|
43 |
+
}else{
|
44 |
+
$order_by[] = 'ticket_price DESC, ticket_name ASC';
|
45 |
+
}
|
46 |
if( is_object($object) && get_class($object) == 'EM_Booking' ){
|
47 |
+
$sql = "SELECT * FROM ". EM_TICKETS_TABLE ." WHERE ticket_id IN (SELECT ticket_id FROM ".EM_TICKETS_BOOKINGS_TABLE." WHERE booking_id='{$object->booking_id}') ORDER BY ".implode(',', $order_by);
|
48 |
}else{
|
49 |
+
$sql = "SELECT * FROM ". EM_TICKETS_TABLE ." WHERE event_id ='{$this->event_id}' ORDER BY ".implode(',', $order_by);
|
50 |
}
|
51 |
$tickets = $wpdb->get_results($sql, ARRAY_A);
|
52 |
foreach ($tickets as $ticket){
|
160 |
if( !empty($_POST['em_tickets']) && is_array($_POST['em_tickets']) ){
|
161 |
//get all ticket data and create objects
|
162 |
global $allowedposttags;
|
163 |
+
$order = 1;
|
164 |
foreach($_POST['em_tickets'] as $row => $ticket_data){
|
165 |
if( $row > 0 ){
|
166 |
if( !empty($ticket_data['ticket_id']) && !empty($current_tickets[$ticket_data['ticket_id']]) ){
|
170 |
}
|
171 |
$ticket_data['event_id'] = $this->event_id;
|
172 |
$EM_Ticket->get_post($ticket_data);
|
173 |
+
$EM_Ticket->ticket_order = $order;
|
174 |
if( $EM_Ticket->ticket_id ){
|
175 |
$this->tickets[$EM_Ticket->ticket_id] = $EM_Ticket;
|
176 |
}else{
|
177 |
$this->tickets[] = $EM_Ticket;
|
178 |
}
|
179 |
+
$order++;
|
180 |
}
|
181 |
}
|
182 |
}else{
|
em-install.php
CHANGED
@@ -333,6 +333,7 @@ function em_create_tickets_table() {
|
|
333 |
ticket_guests INT( 1 ) NULL ,
|
334 |
ticket_required INT( 1 ) NULL ,
|
335 |
ticket_parent BIGINT( 20 ) UNSIGNED NULL,
|
|
|
336 |
ticket_meta LONGTEXT NULL,
|
337 |
PRIMARY KEY (ticket_id)
|
338 |
) DEFAULT CHARSET=utf8 ;";
|
@@ -759,6 +760,7 @@ function em_add_options() {
|
|
759 |
'dbem_bookings_email_registration_subject' => $booking_registration_email_subject,
|
760 |
'dbem_bookings_email_registration_body' => str_replace("<br/>", "\n\r", $booking_registration_email_body),
|
761 |
//Ticket Specific Options
|
|
|
762 |
'dbem_bookings_tickets_orderby' => 'ticket_price DESC, ticket_name ASC',
|
763 |
'dbem_bookings_tickets_priority' => 0,
|
764 |
'dbem_bookings_tickets_show_unavailable' => 0,
|
333 |
ticket_guests INT( 1 ) NULL ,
|
334 |
ticket_required INT( 1 ) NULL ,
|
335 |
ticket_parent BIGINT( 20 ) UNSIGNED NULL,
|
336 |
+
ticket_order INT( 2 ) UNSIGNED NULL,
|
337 |
ticket_meta LONGTEXT NULL,
|
338 |
PRIMARY KEY (ticket_id)
|
339 |
) DEFAULT CHARSET=utf8 ;";
|
760 |
'dbem_bookings_email_registration_subject' => $booking_registration_email_subject,
|
761 |
'dbem_bookings_email_registration_body' => str_replace("<br/>", "\n\r", $booking_registration_email_body),
|
762 |
//Ticket Specific Options
|
763 |
+
'dbem_bookings_tickets_ordering' => 1,
|
764 |
'dbem_bookings_tickets_orderby' => 'ticket_price DESC, ticket_name ASC',
|
765 |
'dbem_bookings_tickets_priority' => 0,
|
766 |
'dbem_bookings_tickets_show_unavailable' => 0,
|
em-template-tags.php
CHANGED
@@ -201,7 +201,9 @@ function em_event_form($args = array()){
|
|
201 |
em_locate_template('forms/event-editor.php',true, array('args'=>$args));
|
202 |
}
|
203 |
if( get_option('dbem_css_editors') ) echo '</div>';
|
|
|
204 |
}
|
|
|
205 |
/**
|
206 |
* Retreives the event submission form for guests and members.
|
207 |
* @param array $args
|
201 |
em_locate_template('forms/event-editor.php',true, array('args'=>$args));
|
202 |
}
|
203 |
if( get_option('dbem_css_editors') ) echo '</div>';
|
204 |
+
wp_enqueue_style('dashicons');
|
205 |
}
|
206 |
+
|
207 |
/**
|
208 |
* Retreives the event submission form for guests and members.
|
209 |
* @param array $args
|
events-manager.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Events Manager
|
4 |
-
Version: 5.9.7.
|
5 |
Plugin URI: http://wp-events-plugin.com
|
6 |
Description: Event registration and booking management for WordPress. Recurring events, locations, google maps, rss, ical, booking registration and more!
|
7 |
Author: Marcus Sykes
|
@@ -10,7 +10,7 @@ Text Domain: events-manager
|
|
10 |
*/
|
11 |
|
12 |
/*
|
13 |
-
Copyright (c)
|
14 |
|
15 |
This program is free software; you can redistribute it and/or
|
16 |
modify it under the terms of the GNU General Public License
|
@@ -28,8 +28,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
28 |
*/
|
29 |
|
30 |
// Setting constants
|
31 |
-
define('EM_VERSION', 5.
|
32 |
-
define('EM_PRO_MIN_VERSION', 2.
|
33 |
define('EM_PRO_MIN_VERSION_CRITICAL', 2.377); //self expanatory
|
34 |
define('EM_DIR', dirname( __FILE__ )); //an absolute path to this directory
|
35 |
define('EM_DIR_URI', trailingslashit(plugins_url('',__FILE__))); //an absolute path to this directory
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Events Manager
|
4 |
+
Version: 5.9.7.2
|
5 |
Plugin URI: http://wp-events-plugin.com
|
6 |
Description: Event registration and booking management for WordPress. Recurring events, locations, google maps, rss, ical, booking registration and more!
|
7 |
Author: Marcus Sykes
|
10 |
*/
|
11 |
|
12 |
/*
|
13 |
+
Copyright (c) 2020, Marcus Sykes
|
14 |
|
15 |
This program is free software; you can redistribute it and/or
|
16 |
modify it under the terms of the GNU General Public License
|
28 |
*/
|
29 |
|
30 |
// Setting constants
|
31 |
+
define('EM_VERSION', 5.972); //self expanatory
|
32 |
+
define('EM_PRO_MIN_VERSION', 2.6712); //self expanatory
|
33 |
define('EM_PRO_MIN_VERSION_CRITICAL', 2.377); //self expanatory
|
34 |
define('EM_DIR', dirname( __FILE__ )); //an absolute path to this directory
|
35 |
define('EM_DIR_URI', trailingslashit(plugins_url('',__FILE__))); //an absolute path to this directory
|
includes/css/events_manager.css
CHANGED
@@ -135,11 +135,17 @@ div#em-loading { position:absolute; width:100%; height:100%; background:#FFFFFF
|
|
135 |
#event-rsvp-box { margin:10px; }
|
136 |
#event-rsvp-options label { font-weight:bold; }
|
137 |
/*Tickets*/
|
138 |
-
|
139 |
-
.em-tickets-row .ticket-status span.ticket_off { display:block; width:10px; height:10px; background:red; }
|
140 |
-
.em-tickets-row .ticket-status span.ticket_new { display:block; width:10px; height:10px; background:grey; }
|
141 |
#em-tickets-form th { width:auto; }
|
142 |
-
#em-tickets-form th.ticket-status { width:20px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
/* Ticket Forms */
|
144 |
.em-ticket-form .ticket-options { margin-top:10px; }
|
145 |
.em-ticket-form > div > div, #em-tickets-form .ticket-dates > div { clear:both; padding-top:4px; }
|
135 |
#event-rsvp-box { margin:10px; }
|
136 |
#event-rsvp-options label { font-weight:bold; }
|
137 |
/*Tickets*/
|
138 |
+
#em-tickets-form tbody.em-ticket-template { display:none; }
|
|
|
|
|
139 |
#em-tickets-form th { width:auto; }
|
140 |
+
#em-tickets-form th.ticket-status, .em-tickets-row .ticket-status { width:20px; }
|
141 |
+
#em-tickets-form .em-tickets-row .ticket-status span.dashicons { display:block; width:16px; height:16px; line-height:16px; font-size:16px; font-weight: bolder; }
|
142 |
+
#em-tickets-form .em-tickets-row .ticket-status.single span.dashicons { cursor:auto; }
|
143 |
+
#em-tickets-form .em-tickets-row .ticket-status span.ticket-on { color: #008000; }
|
144 |
+
#em-tickets-form .em-tickets-row .ticket-status span.ticket-off { color: #ff0000; }
|
145 |
+
#em-tickets-form .em-tickets-row .ticket-status span.ticket_new { color: #808080; }
|
146 |
+
#em-tickets-form.em-tickets-sortable .em-tickets-row .ticket-status span.dashicons { cursor:move; }
|
147 |
+
#em-tickets-form .em-ticket-sortable-placeholder { border:2px dashed #dedede; background:#efefef; }
|
148 |
+
#em-tickets-form .ui-sortable-helper { cursor:move; }
|
149 |
/* Ticket Forms */
|
150 |
.em-ticket-form .ticket-options { margin-top:10px; }
|
151 |
.em-ticket-form > div > div, #em-tickets-form .ticket-dates > div { clear:both; padding-top:4px; }
|
includes/css/events_manager_admin.css
CHANGED
@@ -45,11 +45,17 @@ div.em-location-data .em-location-map-404 { vertical-align:middle; text-align: c
|
|
45 |
#event-rsvp-options h4 { font-size:14px; }
|
46 |
#event-rsvp-options label { font-weight:bold; }
|
47 |
/*Tickets*/
|
48 |
-
|
49 |
-
.em-tickets-row .ticket-status span.ticket_off { display:block; width:10px; height:10px; background:red; }
|
50 |
-
.em-tickets-row .ticket-status span.ticket_new { display:block; width:10px; height:10px; background:grey; }
|
51 |
#em-tickets-form th { width:auto; }
|
52 |
-
#em-tickets-form th.ticket-status { width:20px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
/* Ticket Forms */
|
54 |
.em-ticket-form .ticket-options { margin-top:10px; }
|
55 |
.em-ticket-form > div > div, #em-tickets-form .ticket-dates > div { clear:both; padding-top:4px; }
|
45 |
#event-rsvp-options h4 { font-size:14px; }
|
46 |
#event-rsvp-options label { font-weight:bold; }
|
47 |
/*Tickets*/
|
48 |
+
#em-tickets-form tbody.em-ticket-template { display:none; }
|
|
|
|
|
49 |
#em-tickets-form th { width:auto; }
|
50 |
+
#em-tickets-form th.ticket-status, .em-tickets-row .ticket-status { width:20px; }
|
51 |
+
#em-tickets-form .em-tickets-row .ticket-status span.dashicons { display:block; width:16px; height:16px; line-height:16px; font-size:16px; font-weight: bolder; }
|
52 |
+
#em-tickets-form .em-tickets-row .ticket-status.single span.dashicons { cursor:auto; }
|
53 |
+
#em-tickets-form .em-tickets-row .ticket-status span.ticket-on { color: #008000; }
|
54 |
+
#em-tickets-form .em-tickets-row .ticket-status span.ticket-off { color: #ff0000; }
|
55 |
+
#em-tickets-form .em-tickets-row .ticket-status span.ticket_new { color: #808080; }
|
56 |
+
#em-tickets-form.em-tickets-sortable .em-tickets-row .ticket-status span.dashicons { cursor:move; }
|
57 |
+
#em-tickets-form .em-ticket-sortable-placeholder { border:2px dashed #dedede; background:#efefef; }
|
58 |
+
#em-tickets-form .ui-sortable-helper { cursor:move; }
|
59 |
/* Ticket Forms */
|
60 |
.em-ticket-form .ticket-options { margin-top:10px; }
|
61 |
.em-ticket-form > div > div, #em-tickets-form .ticket-dates > div { clear:both; padding-top:4px; }
|
includes/js/events-manager.js
CHANGED
@@ -8,9 +8,8 @@ jQuery(document).ready( function($){
|
|
8 |
em_setup_timepicker('body');
|
9 |
}
|
10 |
/* Calendar AJAX */
|
11 |
-
$('.em-calendar-wrapper a').
|
12 |
-
$('.em-calendar-wrapper
|
13 |
-
$('.em-calendar-wrapper').delegate('a.em-calnav, a.em-calnav', 'click', function(e){
|
14 |
e.preventDefault();
|
15 |
$(this).closest('.em-calendar-wrapper').prepend('<div class="loading" id="em-loading"></div>');
|
16 |
var url = em_ajaxify($(this).attr('href'));
|
@@ -18,7 +17,7 @@ jQuery(document).ready( function($){
|
|
18 |
} );
|
19 |
|
20 |
//Events Search
|
21 |
-
$(document).
|
22 |
e.preventDefault();
|
23 |
//show or hide advanced tickets, hidden by default
|
24 |
var el = $(this);
|
@@ -98,7 +97,7 @@ jQuery(document).ready( function($){
|
|
98 |
});
|
99 |
|
100 |
//in order for this to work, you need the above classes to be present in your templates
|
101 |
-
$(document).
|
102 |
var form = $(this);
|
103 |
if( this.em_search && this.em_search.value == EM.txt_search){ this.em_search.value = ''; }
|
104 |
var results_wrapper = form.closest('.em-search-wrapper').find('.em-search-ajax');
|
@@ -130,7 +129,7 @@ jQuery(document).ready( function($){
|
|
130 |
}
|
131 |
});
|
132 |
if( $('.em-search-ajax').length > 0 ){
|
133 |
-
$(document).
|
134 |
var a = $(this);
|
135 |
var data = a.closest('.em-pagination').attr('data-em-ajax');
|
136 |
var wrapper = a.closest('.em-search-ajax');
|
@@ -255,7 +254,7 @@ jQuery(document).ready( function($){
|
|
255 |
//create copy of template slot, insert so ready for population
|
256 |
var tickets = $('#em-tickets-form table tbody');
|
257 |
var rowNo = tickets.length+1;
|
258 |
-
var slot = tickets.first().clone(true).attr('id','em-ticket-'+ rowNo).appendTo($('#em-tickets-form table'));
|
259 |
//change the index of the form element names
|
260 |
slot.find('*[name]').each( function(index,el){
|
261 |
el = $(el);
|
@@ -269,9 +268,10 @@ jQuery(document).ready( function($){
|
|
269 |
em_setup_datepicker(slot);
|
270 |
em_setup_timepicker(slot);
|
271 |
$('html, body').animate({ scrollTop: slot.offset().top - 30 }); //sends user to form
|
|
|
272 |
});
|
273 |
//Edit a Ticket
|
274 |
-
$(document).
|
275 |
e.preventDefault();
|
276 |
reset_ticket_forms();
|
277 |
var tbody = $(this).closest('tbody');
|
@@ -279,7 +279,7 @@ jQuery(document).ready( function($){
|
|
279 |
tbody.find('tr.em-tickets-row-form').fadeIn();
|
280 |
return false;
|
281 |
});
|
282 |
-
$(document).
|
283 |
e.preventDefault();
|
284 |
var tbody = $(this).closest('tbody');
|
285 |
var rowNo = tbody.attr('id').replace('em-ticket-','');
|
@@ -322,7 +322,7 @@ jQuery(document).ready( function($){
|
|
322 |
$('html, body').animate({ scrollTop: tbody.parent().offset().top - 30 }); //sends user back to top of form
|
323 |
return false;
|
324 |
});
|
325 |
-
$(document).
|
326 |
//check if ticket is for all users or members, if members, show roles to limit the ticket to
|
327 |
var el = $(this);
|
328 |
if( el.find('option:selected').val() == 'members' ){
|
@@ -331,7 +331,7 @@ jQuery(document).ready( function($){
|
|
331 |
el.closest('.em-ticket-form').find('.ticket-roles').hide();
|
332 |
}
|
333 |
});
|
334 |
-
$(document).
|
335 |
//show or hide advanced tickets, hidden by default
|
336 |
e.preventDefault();
|
337 |
var el = $(this);
|
@@ -356,7 +356,7 @@ jQuery(document).ready( function($){
|
|
356 |
if( show_advanced ) el.find('.ticket-options-advanced').trigger('click');
|
357 |
});
|
358 |
//Delete a ticket
|
359 |
-
$(document).
|
360 |
e.preventDefault();
|
361 |
var el = $(this);
|
362 |
var tbody = el.closest('tbody');
|
@@ -375,13 +375,38 @@ jQuery(document).ready( function($){
|
|
375 |
//not saved to db yet, so just remove
|
376 |
tbody.remove();
|
377 |
}
|
|
|
378 |
return false;
|
379 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
380 |
}
|
381 |
//Manageing Bookings
|
382 |
if( $('#em-bookings-table').length > 0 ){
|
383 |
//Pagination link clicks
|
384 |
-
$(document).
|
385 |
var el = $(this);
|
386 |
var form = el.parents('#em-bookings-table form.bookings-filter');
|
387 |
//get page no from url, change page, submit form
|
@@ -441,10 +466,10 @@ jQuery(document).ready( function($){
|
|
441 |
if( $("#em-bookings-table-settings").length > 0 ){
|
442 |
//Settings Overlay
|
443 |
$("#em-bookings-table-settings").dialog(em_bookings_settings_dialog);
|
444 |
-
$(document).
|
445 |
//Export Overlay
|
446 |
$("#em-bookings-table-export").dialog(em_bookings_export_dialog);
|
447 |
-
$(document).
|
448 |
var export_overlay_show_tickets = function(){
|
449 |
if( $('#em-bookings-table-export-form input[name=show_tickets]').is(':checked') ){
|
450 |
$('#em-bookings-table-export-form .em-bookings-col-item-ticket').show();
|
@@ -479,7 +504,7 @@ jQuery(document).ready( function($){
|
|
479 |
load_ui_css = true;
|
480 |
}
|
481 |
//Widgets and filter submissions
|
482 |
-
$(document).
|
483 |
var el = $(this);
|
484 |
//append loading spinner
|
485 |
el.parents('#em-bookings-table').find('.table-wrap').first().append('<div id="em-loading" />');
|
@@ -495,7 +520,7 @@ jQuery(document).ready( function($){
|
|
495 |
return false;
|
496 |
});
|
497 |
//Approve/Reject Links
|
498 |
-
$(document).
|
499 |
var el = $(this);
|
500 |
if( el.hasClass('em-bookings-delete') ){
|
501 |
if( !confirm(EM.booking_delete) ){ return false; }
|
@@ -510,7 +535,7 @@ jQuery(document).ready( function($){
|
|
510 |
//Old Bookings Table - depreciating soon
|
511 |
if( $('.em_bookings_events_table').length > 0 ){
|
512 |
//Widgets and filter submissions
|
513 |
-
$(document).
|
514 |
var el = $(this);
|
515 |
var url = em_ajaxify( el.attr('action') );
|
516 |
el.parents('.em_bookings_events_table').find('.table-wrap').first().append('<div id="em-loading" />');
|
@@ -520,7 +545,7 @@ jQuery(document).ready( function($){
|
|
520 |
return false;
|
521 |
});
|
522 |
//Pagination link clicks
|
523 |
-
$(document).
|
524 |
var el = $(this);
|
525 |
var url = em_ajaxify( el.attr('href') );
|
526 |
el.parents('.em_bookings_events_table').find('.table-wrap').first().append('<div id="em-loading" />');
|
8 |
em_setup_timepicker('body');
|
9 |
}
|
10 |
/* Calendar AJAX */
|
11 |
+
$('.em-calendar-wrapper a').off("click");
|
12 |
+
$('.em-calendar-wrapper').on('click', 'a.em-calnav, a.em-calnav', function(e){
|
|
|
13 |
e.preventDefault();
|
14 |
$(this).closest('.em-calendar-wrapper').prepend('<div class="loading" id="em-loading"></div>');
|
15 |
var url = em_ajaxify($(this).attr('href'));
|
17 |
} );
|
18 |
|
19 |
//Events Search
|
20 |
+
$(document).on('click change', '.em-toggle', function(e){
|
21 |
e.preventDefault();
|
22 |
//show or hide advanced tickets, hidden by default
|
23 |
var el = $(this);
|
97 |
});
|
98 |
|
99 |
//in order for this to work, you need the above classes to be present in your templates
|
100 |
+
$(document).on('submit', '.em-search-form, .em-events-search-form', function(e){
|
101 |
var form = $(this);
|
102 |
if( this.em_search && this.em_search.value == EM.txt_search){ this.em_search.value = ''; }
|
103 |
var results_wrapper = form.closest('.em-search-wrapper').find('.em-search-ajax');
|
129 |
}
|
130 |
});
|
131 |
if( $('.em-search-ajax').length > 0 ){
|
132 |
+
$(document).on('click', '.em-search-ajax a.page-numbers', function(e){
|
133 |
var a = $(this);
|
134 |
var data = a.closest('.em-pagination').attr('data-em-ajax');
|
135 |
var wrapper = a.closest('.em-search-ajax');
|
254 |
//create copy of template slot, insert so ready for population
|
255 |
var tickets = $('#em-tickets-form table tbody');
|
256 |
var rowNo = tickets.length+1;
|
257 |
+
var slot = tickets.first('.em-ticket-template').clone(true).attr('id','em-ticket-'+ rowNo).removeClass('em-ticket-template').addClass('em-ticket').appendTo($('#em-tickets-form table'));
|
258 |
//change the index of the form element names
|
259 |
slot.find('*[name]').each( function(index,el){
|
260 |
el = $(el);
|
268 |
em_setup_datepicker(slot);
|
269 |
em_setup_timepicker(slot);
|
270 |
$('html, body').animate({ scrollTop: slot.offset().top - 30 }); //sends user to form
|
271 |
+
check_ticket_sortability();
|
272 |
});
|
273 |
//Edit a Ticket
|
274 |
+
$(document).on('click', '.ticket-actions-edit', function(e){
|
275 |
e.preventDefault();
|
276 |
reset_ticket_forms();
|
277 |
var tbody = $(this).closest('tbody');
|
279 |
tbody.find('tr.em-tickets-row-form').fadeIn();
|
280 |
return false;
|
281 |
});
|
282 |
+
$(document).on('click', '.ticket-actions-edited', function(e){
|
283 |
e.preventDefault();
|
284 |
var tbody = $(this).closest('tbody');
|
285 |
var rowNo = tbody.attr('id').replace('em-ticket-','');
|
322 |
$('html, body').animate({ scrollTop: tbody.parent().offset().top - 30 }); //sends user back to top of form
|
323 |
return false;
|
324 |
});
|
325 |
+
$(document).on('change', '.em-ticket-form select.ticket_type', function(e){
|
326 |
//check if ticket is for all users or members, if members, show roles to limit the ticket to
|
327 |
var el = $(this);
|
328 |
if( el.find('option:selected').val() == 'members' ){
|
331 |
el.closest('.em-ticket-form').find('.ticket-roles').hide();
|
332 |
}
|
333 |
});
|
334 |
+
$(document).on('click', '.em-ticket-form .ticket-options-advanced', function(e){
|
335 |
//show or hide advanced tickets, hidden by default
|
336 |
e.preventDefault();
|
337 |
var el = $(this);
|
356 |
if( show_advanced ) el.find('.ticket-options-advanced').trigger('click');
|
357 |
});
|
358 |
//Delete a ticket
|
359 |
+
$(document).on('click', '.ticket-actions-delete', function(e){
|
360 |
e.preventDefault();
|
361 |
var el = $(this);
|
362 |
var tbody = el.closest('tbody');
|
375 |
//not saved to db yet, so just remove
|
376 |
tbody.remove();
|
377 |
}
|
378 |
+
check_ticket_sortability();
|
379 |
return false;
|
380 |
});
|
381 |
+
//Sort Tickets
|
382 |
+
$('#em-tickets-form.em-tickets-sortable table').sortable({
|
383 |
+
items: '> tbody',
|
384 |
+
placeholder: "em-ticket-sortable-placeholder",
|
385 |
+
handle:'.ticket-status',
|
386 |
+
helper: function( event, el ){
|
387 |
+
var helper = $(el).clone().addClass('em-ticket-sortable-helper');
|
388 |
+
var tds = helper.find('.em-tickets-row td').length;
|
389 |
+
helper.children().remove();
|
390 |
+
helper.append('<tr class="em-tickets-row"><td colspan="'+tds+'" style="text-align:left; padding-left:15px;"><span class="dashicons dashicons-tickets-alt"></span></td></tr>');
|
391 |
+
return helper;
|
392 |
+
},
|
393 |
+
});
|
394 |
+
var check_ticket_sortability = function(){
|
395 |
+
var em_tickets = $('#em-tickets-form table tbody.em-ticket');
|
396 |
+
if( em_tickets.length == 1 ){
|
397 |
+
em_tickets.find('.ticket-status').addClass('single');
|
398 |
+
$('#em-tickets-form table').sortable( "option", "disabled", true );
|
399 |
+
}else{
|
400 |
+
em_tickets.find('.ticket-status').removeClass('single');
|
401 |
+
$('#em-tickets-form table').sortable( "option", "disabled", false );
|
402 |
+
}
|
403 |
+
};
|
404 |
+
check_ticket_sortability();
|
405 |
}
|
406 |
//Manageing Bookings
|
407 |
if( $('#em-bookings-table').length > 0 ){
|
408 |
//Pagination link clicks
|
409 |
+
$(document).on('click', '#em-bookings-table .tablenav-pages a', function(){
|
410 |
var el = $(this);
|
411 |
var form = el.parents('#em-bookings-table form.bookings-filter');
|
412 |
//get page no from url, change page, submit form
|
466 |
if( $("#em-bookings-table-settings").length > 0 ){
|
467 |
//Settings Overlay
|
468 |
$("#em-bookings-table-settings").dialog(em_bookings_settings_dialog);
|
469 |
+
$(document).on('click', '#em-bookings-table-settings-trigger', function(e){ e.preventDefault(); $("#em-bookings-table-settings").dialog('open'); });
|
470 |
//Export Overlay
|
471 |
$("#em-bookings-table-export").dialog(em_bookings_export_dialog);
|
472 |
+
$(document).on('click', '#em-bookings-table-export-trigger', function(e){ e.preventDefault(); $("#em-bookings-table-export").dialog('open'); });
|
473 |
var export_overlay_show_tickets = function(){
|
474 |
if( $('#em-bookings-table-export-form input[name=show_tickets]').is(':checked') ){
|
475 |
$('#em-bookings-table-export-form .em-bookings-col-item-ticket').show();
|
504 |
load_ui_css = true;
|
505 |
}
|
506 |
//Widgets and filter submissions
|
507 |
+
$(document).on('submit', '#em-bookings-table form.bookings-filter', function(e){
|
508 |
var el = $(this);
|
509 |
//append loading spinner
|
510 |
el.parents('#em-bookings-table').find('.table-wrap').first().append('<div id="em-loading" />');
|
520 |
return false;
|
521 |
});
|
522 |
//Approve/Reject Links
|
523 |
+
$(document).on('click', '.em-bookings-approve,.em-bookings-reject,.em-bookings-unapprove,.em-bookings-delete', function(){
|
524 |
var el = $(this);
|
525 |
if( el.hasClass('em-bookings-delete') ){
|
526 |
if( !confirm(EM.booking_delete) ){ return false; }
|
535 |
//Old Bookings Table - depreciating soon
|
536 |
if( $('.em_bookings_events_table').length > 0 ){
|
537 |
//Widgets and filter submissions
|
538 |
+
$(document).on('submit', '.em_bookings_events_table form', function(e){
|
539 |
var el = $(this);
|
540 |
var url = em_ajaxify( el.attr('action') );
|
541 |
el.parents('.em_bookings_events_table').find('.table-wrap').first().append('<div id="em-loading" />');
|
545 |
return false;
|
546 |
});
|
547 |
//Pagination link clicks
|
548 |
+
$(document).on('click', '.em_bookings_events_table .tablenav-pages a', function(){
|
549 |
var el = $(this);
|
550 |
var url = em_ajaxify( el.attr('href') );
|
551 |
el.parents('.em_bookings_events_table').find('.table-wrap').first().append('<div id="em-loading" />');
|
readme.txt
CHANGED
@@ -5,7 +5,7 @@ Tags: bookings, calendar, tickets, events, buddypress, event management, google
|
|
5 |
Text Domain: events-manager
|
6 |
Requires at least: 4.8
|
7 |
Tested up to: 5.3
|
8 |
-
Stable tag: 5.9.7.
|
9 |
Requires PHP: 5.3
|
10 |
|
11 |
Fully featured event registration management including recurring events, locations management, calendar, Google map integration, booking management
|
@@ -111,6 +111,23 @@ See our [FAQ](http://wp-events-plugin.com/documentation/faq/) page, which is upd
|
|
111 |
6. Manage attendees with various booking reports
|
112 |
|
113 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
= 5.9.7.1 =
|
115 |
* fixed minor typo in new email setting description
|
116 |
* fixed CSV booking export files turning out blank due to change in EM_Bookings::__isset() in 5.9.7
|
5 |
Text Domain: events-manager
|
6 |
Requires at least: 4.8
|
7 |
Tested up to: 5.3
|
8 |
+
Stable tag: 5.9.7.2
|
9 |
Requires PHP: 5.3
|
10 |
|
11 |
Fully featured event registration management including recurring events, locations management, calendar, Google map integration, booking management
|
111 |
6. Manage attendees with various booking reports
|
112 |
|
113 |
== Changelog ==
|
114 |
+
= 5.9.7.2 =
|
115 |
+
* fixed CSV injection vulnerability which can allow malicious text to be exported to CSV files and parsed by Spreadsheet
|
116 |
+
* fixed #_BOOKINGCUTOFF text date formats not getting translated correctly
|
117 |
+
* added ability to programatically add attachments to booking emails for future features
|
118 |
+
* fixed/updated casing of functions in phpMailer function calls (prefiously backward compatible),
|
119 |
+
* added reply-to headers for wp_mail emails circumventing some plugins forcing from email address fields,
|
120 |
+
* fixed email testing function ignoring sender name, encryption and autotls options
|
121 |
+
* fixed ical apple structure breaking parsing in google (and possible others)
|
122 |
+
* updated events-manager.js to replace deprecated use of delegate/bind with on/off equivalents
|
123 |
+
* added ticket ordering
|
124 |
+
* fixed editing booking tickets in admin causing validation errors on 0 values
|
125 |
+
* fixed PHP Warning generated when adding Booking Notes which prevent a redirect with WP_DEBUG enabled
|
126 |
+
* fixed Events tab on profile pages stripping last character with the BuddyPress Nouveau theme
|
127 |
+
* changed blank value to 'no location' when viewing the event bookings admin page for locationless events
|
128 |
+
* changed EM_Notices by making them JsonSerializable
|
129 |
+
* fixed (hopefully!) the elusive and hard to reproduce "variable mismatch" error when submitting new form in some rare circumstances
|
130 |
+
|
131 |
= 5.9.7.1 =
|
132 |
* fixed minor typo in new email setting description
|
133 |
* fixed CSV booking export files turning out blank due to change in EM_Bookings::__isset() in 5.9.7
|
templates/forms/event-editor.php
CHANGED
@@ -23,7 +23,7 @@ if( !empty($_REQUEST['success']) ){
|
|
23 |
if(!get_option('dbem_events_form_reshow')) return false;
|
24 |
}
|
25 |
?>
|
26 |
-
<form enctype='multipart/form-data' id="event-form" class="em-event-admin-editor <?php if( $EM_Event->is_recurring() ) echo 'em-event-admin-recurring' ?>" method="post" action="<?php echo esc_url(add_query_arg(array('success'=>null))); ?>">
|
27 |
<div class="wrap">
|
28 |
<?php do_action('em_front_event_form_header', $EM_Event); ?>
|
29 |
<?php if(get_option('dbem_events_anonymous_submissions') && !is_user_logged_in()): ?>
|
23 |
if(!get_option('dbem_events_form_reshow')) return false;
|
24 |
}
|
25 |
?>
|
26 |
+
<form enctype='multipart/form-data' id="event-form" class="em-event-admin-editor <?php if( $EM_Event->is_recurring() ) echo 'em-event-admin-recurring' ?>" method="post" action="<?php echo esc_url(add_query_arg(array('success'=>null, 'action'=>null))); ?>">
|
27 |
<div class="wrap">
|
28 |
<?php do_action('em_front_event_form_header', $EM_Event); ?>
|
29 |
<?php if(get_option('dbem_events_anonymous_submissions') && !is_user_logged_in()): ?>
|
templates/forms/event/bookings.php
CHANGED
@@ -42,8 +42,11 @@ $reschedule_warnings = !empty($EM_Event->event_id) && $EM_Event->is_recurring()
|
|
42 |
</div>
|
43 |
<?php
|
44 |
}
|
|
|
|
|
|
|
45 |
?>
|
46 |
-
<div id="em-tickets-form" class="em-tickets-form<?php
|
47 |
<?php
|
48 |
//output ticket options
|
49 |
if( get_option('dbem_bookings_tickets_single') && count($EM_Tickets->tickets) == 1 ){
|
@@ -62,12 +65,11 @@ $reschedule_warnings = !empty($EM_Event->event_id) && $EM_Event->is_recurring()
|
|
62 |
<th><?php esc_html_e('Start/End','events-manager'); ?></th>
|
63 |
<th><?php esc_html_e('Avail. Spaces','events-manager'); ?></th>
|
64 |
<th><?php esc_html_e('Booked Spaces','events-manager'); ?></th>
|
65 |
-
<th> </th>
|
66 |
</tr>
|
67 |
</thead>
|
68 |
<tfoot>
|
69 |
<tr valign="top">
|
70 |
-
<td colspan="
|
71 |
<a href="#" id="em-tickets-add"><?php esc_html_e('Add new ticket','events-manager'); ?></a>
|
72 |
</td>
|
73 |
</tr>
|
@@ -79,15 +81,18 @@ $reschedule_warnings = !empty($EM_Event->event_id) && $EM_Event->is_recurring()
|
|
79 |
$col_count = 0;
|
80 |
foreach( $EM_Tickets->tickets as $EM_Ticket){
|
81 |
/* @var $EM_Ticket EM_Ticket */
|
|
|
82 |
?>
|
83 |
-
<tbody id="em-ticket-<?php echo $col_count ?>" <?php
|
84 |
<tr class="em-tickets-row">
|
85 |
-
<td class="ticket-status"
|
|
|
|
|
86 |
<td class="ticket-name">
|
87 |
<span class="ticket_name"><?php if($EM_Ticket->ticket_members) echo '* ';?><?php echo wp_kses_data($EM_Ticket->ticket_name); ?></span>
|
88 |
<div class="ticket_description"><?php echo wp_kses($EM_Ticket->ticket_description,$allowedposttags); ?></div>
|
89 |
<div class="ticket-actions">
|
90 |
-
<a href="#" class="ticket-actions-edit"><?php esc_html_e('Edit','events-manager'); ?></a>
|
91 |
<?php if( $EM_Ticket->get_bookings_count() == 0 ): ?>
|
92 |
| <a href="<?php bloginfo('wpurl'); ?>/wp-load.php" class="ticket-actions-delete"><?php esc_html_e('Delete','events-manager'); ?></a>
|
93 |
<?php else: ?>
|
@@ -101,7 +106,7 @@ $reschedule_warnings = !empty($EM_Event->event_id) && $EM_Event->is_recurring()
|
|
101 |
<td class="ticket-limit">
|
102 |
<span class="ticket_min">
|
103 |
<?php echo ( !empty($EM_Ticket->ticket_min) ) ? esc_html($EM_Ticket->ticket_min):'-'; ?>
|
104 |
-
</span> /
|
105 |
<span class="ticket_max"><?php echo ( !empty($EM_Ticket->ticket_max) ) ? esc_html($EM_Ticket->ticket_max):'-'; ?></span>
|
106 |
</td>
|
107 |
<td class="ticket-time">
|
42 |
</div>
|
43 |
<?php
|
44 |
}
|
45 |
+
$container_classes = array();
|
46 |
+
if( $reschedule_warnings && empty($_REQUEST['recreate_tickets']) ) $container_classes[] = 'reschedule-hidden';
|
47 |
+
if( get_option('dbem_bookings_tickets_ordering') ) $container_classes[] = 'em-tickets-sortable';
|
48 |
?>
|
49 |
+
<div id="em-tickets-form" class="em-tickets-form <?php echo implode(' ', $container_classes); ?>">
|
50 |
<?php
|
51 |
//output ticket options
|
52 |
if( get_option('dbem_bookings_tickets_single') && count($EM_Tickets->tickets) == 1 ){
|
65 |
<th><?php esc_html_e('Start/End','events-manager'); ?></th>
|
66 |
<th><?php esc_html_e('Avail. Spaces','events-manager'); ?></th>
|
67 |
<th><?php esc_html_e('Booked Spaces','events-manager'); ?></th>
|
|
|
68 |
</tr>
|
69 |
</thead>
|
70 |
<tfoot>
|
71 |
<tr valign="top">
|
72 |
+
<td colspan="7">
|
73 |
<a href="#" id="em-tickets-add"><?php esc_html_e('Add new ticket','events-manager'); ?></a>
|
74 |
</td>
|
75 |
</tr>
|
81 |
$col_count = 0;
|
82 |
foreach( $EM_Tickets->tickets as $EM_Ticket){
|
83 |
/* @var $EM_Ticket EM_Ticket */
|
84 |
+
$class_name = $col_count == 0 ? 'em-ticket-template':'em-ticket';
|
85 |
?>
|
86 |
+
<tbody id="em-ticket-<?php echo $col_count ?>" class="<?php echo $class_name; ?>">
|
87 |
<tr class="em-tickets-row">
|
88 |
+
<td class="ticket-status">
|
89 |
+
<span class="dashicons dashicons-menu <?php if($EM_Ticket->ticket_id && $EM_Ticket->is_available(true, true)){ echo 'ticket-on'; }elseif($EM_Ticket->ticket_id > 0){ echo 'ticket-off'; }else{ echo 'ticket-new'; } ?>"></span>
|
90 |
+
</td>
|
91 |
<td class="ticket-name">
|
92 |
<span class="ticket_name"><?php if($EM_Ticket->ticket_members) echo '* ';?><?php echo wp_kses_data($EM_Ticket->ticket_name); ?></span>
|
93 |
<div class="ticket_description"><?php echo wp_kses($EM_Ticket->ticket_description,$allowedposttags); ?></div>
|
94 |
<div class="ticket-actions">
|
95 |
+
<a href="#" class="ticket-actions-edit"><?php esc_html_e('Edit','events-manager'); ?></a>
|
96 |
<?php if( $EM_Ticket->get_bookings_count() == 0 ): ?>
|
97 |
| <a href="<?php bloginfo('wpurl'); ?>/wp-load.php" class="ticket-actions-delete"><?php esc_html_e('Delete','events-manager'); ?></a>
|
98 |
<?php else: ?>
|
106 |
<td class="ticket-limit">
|
107 |
<span class="ticket_min">
|
108 |
<?php echo ( !empty($EM_Ticket->ticket_min) ) ? esc_html($EM_Ticket->ticket_min):'-'; ?>
|
109 |
+
</span> /
|
110 |
<span class="ticket_max"><?php echo ( !empty($EM_Ticket->ticket_max) ) ? esc_html($EM_Ticket->ticket_max):'-'; ?></span>
|
111 |
</td>
|
112 |
<td class="ticket-time">
|
templates/templates/ical.php
CHANGED
@@ -92,8 +92,8 @@ while ( count($EM_Events) > 0 ){
|
|
92 |
$geo = 'GEO:'.$EM_Event->get_location()->location_latitude.";".$EM_Event->get_location()->location_longitude;
|
93 |
}
|
94 |
if( !defined('EM_ICAL_APPLE_STRUCT') || !EM_ICAL_APPLE_STRUCT ){
|
95 |
-
$apple_location = $EM_Event->output('#_LOCATIONFULLLINE, #_LOCATIONCOUNTRY', 'ical');
|
96 |
-
$apple_location_title = $EM_Event->output('#_LOCATIONNAME', 'ical');
|
97 |
$apple_geo = !empty($geo) ? $EM_Event->get_location()->location_latitude.",".$EM_Event->get_location()->location_longitude:'0,0';
|
98 |
$apple_structured_location = "X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS={$apple_location};X-APPLE-RADIUS=100;X-TITLE={$apple_location_title}:geo:{$apple_geo}";
|
99 |
$apple_structured_location = str_replace('"', '\"', $apple_structured_location); //google chucks a wobbly with these on this line
|
92 |
$geo = 'GEO:'.$EM_Event->get_location()->location_latitude.";".$EM_Event->get_location()->location_longitude;
|
93 |
}
|
94 |
if( !defined('EM_ICAL_APPLE_STRUCT') || !EM_ICAL_APPLE_STRUCT ){
|
95 |
+
$apple_location = str_replace(';', '', html_entity_decode(str_replace('\;', ';', $EM_Event->output('#_LOCATIONFULLLINE, #_LOCATIONCOUNTRY', 'ical'))));
|
96 |
+
$apple_location_title = str_replace('\;', '', html_entity_decode(str_replace('\;', ';', $EM_Event->output('#_LOCATIONNAME', 'ical'))));
|
97 |
$apple_geo = !empty($geo) ? $EM_Event->get_location()->location_latitude.",".$EM_Event->get_location()->location_longitude:'0,0';
|
98 |
$apple_structured_location = "X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS={$apple_location};X-APPLE-RADIUS=100;X-TITLE={$apple_location_title}:geo:{$apple_geo}";
|
99 |
$apple_structured_location = str_replace('"', '\"', $apple_structured_location); //google chucks a wobbly with these on this line
|