Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/supportcandy/class-wpsc-installation.php
+++ b/supportcandy/class-wpsc-installation.php
@@ -1539,6 +1539,7 @@
// ticket widgets.
$labels = array(
+ 'agent-collision' => __( 'Currently viewing', 'supportcandy' ),
'change-status' => __( 'Ticket status', 'supportcandy' ),
'raised-by' => __( 'Customer', 'supportcandy' ),
'ticket-info' => __( 'Ticket info', 'supportcandy' ),
@@ -1555,14 +1556,22 @@
update_option(
'wpsc-ticket-widget',
array(
- 'change-status' => array(
- 'title' => $labels['change-status'],
+ 'agent-collision' => array(
+ 'title' => $labels['agent-collision'],
'is_enable' => 1,
- 'allow-customer' => 1,
+ 'allow-customer' => 0,
'allowed-agent-roles' => array( 1, 2 ),
'show-priority-to-customer' => 0,
- 'callback' => 'wpsc_get_tw_ticket_status()',
- 'class' => 'WPSC_ITW_Change_Status',
+ 'callback' => 'wpsc_get_tw_agent_collision()',
+ 'class' => 'WPSC_ITW_Agent_Collision',
+ ),
+ 'change-status' => array(
+ 'title' => $labels['change-status'],
+ 'is_enable' => 1,
+ 'allow-customer' => 1,
+ 'allowed-agent-roles' => array( 1, 2 ),
+ 'callback' => 'wpsc_get_tw_ticket_status()',
+ 'class' => 'WPSC_ITW_Change_Status',
),
'raised-by' => array(
'title' => $labels['raised-by'],
@@ -2252,7 +2261,7 @@
if ( version_compare( self::$current_version, '3.2.4', '<' ) ) {
// add default true to admin and agent dashboard access.
- $roles = get_option( 'wpsc-agent-roles' );
+ $roles = get_option( 'wpsc-agent-roles', array() );
$role_keys = array();
foreach ( $roles as $key => $role ) {
$role['caps']['dash-access'] = true;
@@ -2652,6 +2661,41 @@
wp_clear_scheduled_hook( 'wpsc_auto_archive_closed_tickets' );
}
+ if ( version_compare( self::$current_version, '3.4.7', '<' ) ) {
+
+ $widgets = get_option( 'wpsc-ticket-widget', array() );
+ if ( ! isset( $widgets['agent-collision'] ) ) {
+
+ $roles = get_option( 'wpsc-agent-roles', array() );
+ $role_keys = array();
+ foreach ( $roles as $key => $role ) {
+ $role_keys[] = $key;
+ }
+
+ $label = esc_attr__( 'Currently viewing', 'supportcandy' );
+ $agent_collision = array(
+ 'agent-collision' => array(
+ 'title' => $label,
+ 'is_enable' => 1,
+ 'allow-customer' => 0,
+ 'allowed-agent-roles' => $role_keys,
+ 'show-priority-to-customer' => 0,
+ 'callback' => 'wpsc_get_tw_agent_collision()',
+ 'class' => 'WPSC_ITW_Agent_Collision',
+ ),
+ );
+
+ // append the widget on the top.
+ $widgets = array_merge( $agent_collision, $widgets );
+ update_option( 'wpsc-ticket-widget', $widgets );
+
+ // string translations.
+ $string_translations = get_option( 'wpsc-string-translation' );
+ $string_translations['wpsc-twt-agent-collision'] = $label;
+ update_option( 'wpsc-string-translation', $string_translations );
+ }
+ }
+
update_option( 'wpsc-string-translation', $string_translations );
self::set_upgrade_complete();
}
--- a/supportcandy/framework/class-wpsc-framework.php
+++ b/supportcandy/framework/class-wpsc-framework.php
@@ -430,6 +430,8 @@
$localizations['translations']['req_term_cond'] = esc_attr__( 'Please accept terms and conditions!', 'supportcandy' );
$localizations['translations']['req_gdpr'] = esc_attr__( 'Please accept GDPR policy!', 'supportcandy' );
$localizations['translations']['delete_permanently'] = esc_attr__( 'Deleting a ticket will permanently remove all associated information and cannot be undone!', 'supportcandy' );
+ $localizations['translations']['block_notifications'] = esc_attr__( 'Blocking notifications will stop all email alerts for this ticket.', 'supportcandy' );
+ $localizations['translations']['unblock_notifications'] = esc_attr__( 'Unblocking notifications will resume email alerts for this ticket.', 'supportcandy' );
return $localizations;
}
--- a/supportcandy/includes/admin/custom-fields/class-wpsc-aof.php
+++ b/supportcandy/includes/admin/custom-fields/class-wpsc-aof.php
@@ -63,7 +63,9 @@
if ( ! WPSC_Functions::is_site_admin() ) {
wp_send_json_error( __( 'Unauthorized access!', 'supportcandy' ), 401 );
- }?>
+ }
+ $custom_fields_types = array_merge( WPSC_Custom_Field::$cf_types, WPSC_Custom_Field::$default_cf_types );
+ ?>
<div class="wpsc-setting-header">
<h2><?php esc_attr_e( 'Agent Only Fields', 'supportcandy' ); ?></h2>
@@ -83,6 +85,8 @@
<tr>
<th><?php esc_attr_e( 'Field', 'supportcandy' ); ?></th>
<th><?php esc_attr_e( 'Extra info', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Type', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Personal Info', 'supportcandy' ); ?></th>
<th><?php esc_attr_e( 'Actions', 'supportcandy' ); ?></th>
</tr>
</thead>
@@ -96,6 +100,8 @@
<tr>
<td><?php echo esc_attr( $cf->name ); ?></td>
<td><?php echo esc_attr( $cf->extra_info ); ?></td>
+ <td><?php echo esc_attr( $custom_fields_types[ $cf->type::$slug ]['label'] ); ?></td>
+ <td><?php echo esc_attr( $cf->is_personal_info ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
<td>
<span class="wpsc-link" onclick="wpsc_get_edit_custom_field(<?php echo esc_attr( $cf->id ); ?>, '<?php echo esc_attr( wp_create_nonce( 'wpsc_get_edit_custom_field' ) ); ?>');"><?php esc_attr_e( 'Edit', 'supportcandy' ); ?></span>
<?php
--- a/supportcandy/includes/admin/custom-fields/class-wpsc-cf.php
+++ b/supportcandy/includes/admin/custom-fields/class-wpsc-cf.php
@@ -64,7 +64,9 @@
if ( ! WPSC_Functions::is_site_admin() ) {
wp_send_json_error( __( 'Unauthorized access!', 'supportcandy' ), 401 );
- }?>
+ }
+ $custom_fields_types = array_merge( WPSC_Custom_Field::$cf_types, WPSC_Custom_Field::$default_cf_types );
+ ?>
<div class="wpsc-setting-header">
<h2><?php esc_attr_e( 'Customer Fields', 'supportcandy' ); ?></h2>
@@ -84,6 +86,11 @@
<tr>
<th><?php esc_attr_e( 'Field', 'supportcandy' ); ?></th>
<th><?php esc_attr_e( 'Extra info', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Type', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Auto Fill', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Personal Info', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Allow in My Profile', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Allow in Ticket Form', 'supportcandy' ); ?></th>
<th><?php esc_attr_e( 'Actions', 'supportcandy' ); ?></th>
</tr>
</thead>
@@ -97,6 +104,11 @@
<tr>
<td><?php echo esc_attr( $cf->name ); ?></td>
<td><?php echo esc_attr( $cf->extra_info ); ?></td>
+ <td><?php echo esc_attr( $custom_fields_types[ $cf->type::$slug ]['label'] ); ?></td>
+ <td><?php echo esc_attr( $cf->is_auto_fill ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
+ <td><?php echo esc_attr( $cf->is_personal_info ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
+ <td><?php echo esc_attr( $cf->allow_my_profile ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
+ <td><?php echo esc_attr( $cf->allow_ticket_form ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
<td>
<span class="wpsc-link" onclick="wpsc_get_edit_custom_field(<?php echo esc_attr( $cf->id ); ?>, '<?php echo esc_attr( wp_create_nonce( 'wpsc_get_edit_custom_field' ) ); ?>');"><?php esc_attr_e( 'Edit', 'supportcandy' ); ?></span>
<?php
--- a/supportcandy/includes/admin/custom-fields/class-wpsc-tf.php
+++ b/supportcandy/includes/admin/custom-fields/class-wpsc-tf.php
@@ -59,7 +59,9 @@
if ( ! WPSC_Functions::is_site_admin() ) {
wp_send_json_error( __( 'Unauthorized access!', 'supportcandy' ), 401 );
- }?>
+ }
+ $custom_fields_types = array_merge( WPSC_Custom_Field::$cf_types, WPSC_Custom_Field::$default_cf_types );
+ ?>
<div class="wpsc-setting-header">
<h2><?php esc_attr_e( 'Ticket Fields', 'supportcandy' ); ?></h2>
@@ -80,6 +82,9 @@
<tr>
<th><?php esc_attr_e( 'Field', 'supportcandy' ); ?></th>
<th><?php esc_attr_e( 'Extra info', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Type', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Auto Fill', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Personal Info', 'supportcandy' ); ?></th>
<th><?php esc_attr_e( 'Actions', 'supportcandy' ); ?></th>
</tr>
</thead>
@@ -93,6 +98,9 @@
<tr>
<td><?php echo esc_attr( $cf->name ); ?></td>
<td><?php echo esc_attr( $cf->extra_info ); ?></td>
+ <td><?php echo esc_attr( $custom_fields_types[ $cf->type::$slug ]['label'] ); ?></td>
+ <td><?php echo esc_attr( $cf->is_auto_fill ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
+ <td><?php echo esc_attr( $cf->is_personal_info ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
<td>
<span class="wpsc-link" onclick="wpsc_get_edit_custom_field(<?php echo esc_attr( $cf->id ); ?>, '<?php echo esc_attr( wp_create_nonce( 'wpsc_get_edit_custom_field' ) ); ?>');"><?php esc_attr_e( 'Edit', 'supportcandy' ); ?></span>
<?php
--- a/supportcandy/includes/admin/custom-fields/class-wpsc-tff.php
+++ b/supportcandy/includes/admin/custom-fields/class-wpsc-tff.php
@@ -52,6 +52,11 @@
}
$tff = get_option( 'wpsc-tff', array() );
+ $width = array(
+ '1/3' => __( '1/3rd of row', 'supportcandy' ),
+ 'half' => __( 'Half width', 'supportcandy' ),
+ 'full' => __( 'Full width', 'supportcandy' ),
+ );
?>
<div class="wpsc-setting-header">
@@ -71,6 +76,9 @@
<thead>
<tr>
<th><?php esc_attr_e( 'Field', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Required', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Visibility Conditions', 'supportcandy' ); ?></th>
+ <th><?php esc_attr_e( 'Width', 'supportcandy' ); ?></th>
<th><?php esc_attr_e( 'Actions', 'supportcandy' ); ?></th>
</tr>
</thead>
@@ -81,9 +89,14 @@
if ( ! $cf ) {
continue;
}
+ $vis_decoded = is_string( $settings['visibility'] ) ? json_decode( $settings['visibility'], true ) : $settings['visibility'];
+ $visibility = ( ! empty( $vis_decoded ) ) ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' );
?>
<tr>
<td><?php echo esc_attr( $cf->name ); ?></td>
+ <td><?php echo esc_attr( $settings['is-required'] ? __( 'Yes', 'supportcandy' ) : __( 'No', 'supportcandy' ) ); ?></td>
+ <td><?php echo esc_attr( $visibility ); ?></td>
+ <td><?php echo esc_attr( isset( $width[ $settings['width'] ] ) ? $width[ $settings['width'] ] : $settings['width'] ); ?></td>
<td>
<span class="wpsc-link" onclick="wpsc_get_edit_tff(<?php echo esc_attr( $cf->id ); ?>, '<?php echo esc_attr( wp_create_nonce( 'wpsc_get_edit_tff' ) ); ?>');"><?php esc_attr_e( 'Edit', 'supportcandy' ); ?></span>
<?php
--- a/supportcandy/includes/admin/customers/class-wpsc-customers.php
+++ b/supportcandy/includes/admin/customers/class-wpsc-customers.php
@@ -31,14 +31,14 @@
add_action( 'wp_ajax_wpsc_delete_customer', array( __CLASS__, 'delete_customer_info' ) );
// calculate customer ticket count.
- add_action( 'wpsc_create_new_ticket', array( __CLASS__, 'customer_ticket_count' ) );
- add_action( 'wpsc_delete_ticket', array( __CLASS__, 'customer_ticket_count' ) );
- add_action( 'wpsc_ticket_restore', array( __CLASS__, 'customer_ticket_count' ) );
- add_action( 'wpsc_ticket_delete_permanently', array( __CLASS__, 'customer_ticket_count' ) );
- add_action( 'wpsc_change_raised_by', array( __CLASS__, 'customer_ticket_count_after_change_raised_by' ), 200, 4 );
- add_action( 'wpsc_ticket_archive', array( __CLASS__, 'reset_customer_ticket_count' ), 200, 2 );
- add_action( 'wpsc_archive_ticket_restore', array( __CLASS__, 'reset_customer_ticket_count' ), 200, 2 );
- add_action( 'wpsc_after_ticket_merge', array( __CLASS__, 'customer_ticket_count_after_ticket_merge' ), 200, 2 );
+ add_action( 'wpsc_create_new_ticket', array( __CLASS__, 'customer_ticket_count' ), 500 );
+ add_action( 'wpsc_delete_ticket', array( __CLASS__, 'customer_ticket_count' ), 500 );
+ add_action( 'wpsc_ticket_restore', array( __CLASS__, 'customer_ticket_count' ), 500 );
+ add_action( 'wpsc_ticket_delete_permanently', array( __CLASS__, 'customer_ticket_count' ), 500 );
+ add_action( 'wpsc_change_raised_by', array( __CLASS__, 'customer_ticket_count_after_change_raised_by' ), 500, 4 );
+ add_action( 'wpsc_ticket_archive', array( __CLASS__, 'reset_customer_ticket_count' ), 500, 2 );
+ add_action( 'wpsc_archive_ticket_restore', array( __CLASS__, 'reset_customer_ticket_count' ), 500, 2 );
+ add_action( 'wpsc_after_ticket_merge', array( __CLASS__, 'customer_ticket_count_after_ticket_merge' ), 500, 2 );
// view customer profile info.
add_action( 'wp_ajax_wpsc_view_customer_detailed_info', array( __CLASS__, 'view_customer_detailed_info' ) );
@@ -684,7 +684,19 @@
*/
public static function customer_ticket_count_after_ticket_merge( $prev_ticket, $new_ticket ) {
- $prev_ticket->customer->update_ticket_count();
+ if ( empty( $prev_ticket->customer ) ) {
+ return;
+ }
+
+ $customer = $prev_ticket->customer;
+
+ if ( ! is_object( $customer ) ) {
+ $customer = new WPSC_Customer( $customer );
+ }
+
+ if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) {
+ $customer->update_ticket_count();
+ }
}
/**
@@ -698,7 +710,19 @@
*/
public static function customer_ticket_count_after_change_raised_by( $ticket, $prev, $new, $customer_id ) {
- $ticket->customer->update_ticket_count();
+ if ( empty( $ticket->customer ) ) {
+ return;
+ }
+
+ $customer = $ticket->customer;
+
+ if ( ! is_object( $customer ) ) {
+ $customer = new WPSC_Customer( $customer );
+ }
+
+ if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) {
+ $customer->update_ticket_count();
+ }
}
/**
@@ -710,7 +734,19 @@
*/
public static function reset_customer_ticket_count( $ticket, $ar_ticket ) {
- $ticket->customer->update_ticket_count();
+ if ( empty( $ticket->customer ) ) {
+ return;
+ }
+
+ $customer = $ticket->customer;
+
+ if ( ! is_object( $customer ) ) {
+ $customer = new WPSC_Customer( $customer );
+ }
+
+ if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) {
+ $customer->update_ticket_count();
+ }
}
/**
@@ -721,7 +757,19 @@
*/
public static function customer_ticket_count( $ticket ) {
- $ticket->customer->update_ticket_count();
+ if ( empty( $ticket->customer ) ) {
+ return;
+ }
+
+ $customer = $ticket->customer;
+
+ if ( ! is_object( $customer ) ) {
+ $customer = new WPSC_Customer( $customer );
+ }
+
+ if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) {
+ $customer->update_ticket_count();
+ }
}
/**
--- a/supportcandy/includes/admin/settings/miscellaneous-settings/class-wpsc-ms-gdpr.php
+++ b/supportcandy/includes/admin/settings/miscellaneous-settings/class-wpsc-ms-gdpr.php
@@ -332,10 +332,9 @@
?>
case 'gdpr':
- var checkbox = customField.find('input:checked');
- if (checkbox.length === 0) {
+ if (customField.find('input:checked').length === 0) {
+ showFieldError(customField, supportcandy.translations.req_gdpr);
isValid = false;
- alert(supportcandy.translations.req_gdpr);
}
break;
<?php
--- a/supportcandy/includes/admin/settings/miscellaneous-settings/class-wpsc-ms-recaptcha.php
+++ b/supportcandy/includes/admin/settings/miscellaneous-settings/class-wpsc-ms-recaptcha.php
@@ -199,7 +199,6 @@
var recaptcha = jQuery("#g-recaptcha-response").val();
if (recaptcha === "") {
isValid = false;
- alert("<?php esc_attr_e( 'Captcha not set!', 'supportcandy' ); ?>");
}
break;
<?php
--- a/supportcandy/includes/admin/settings/miscellaneous-settings/class-wpsc-ms-tac.php
+++ b/supportcandy/includes/admin/settings/miscellaneous-settings/class-wpsc-ms-tac.php
@@ -296,10 +296,9 @@
?>
case 'term-and-conditions':
- var checkbox = customField.find('input:checked');
- if (checkbox.length === 0) {
+ if (customField.find('input:checked').length === 0) {
+ showFieldError(customField, supportcandy.translations.req_term_cond);
isValid = false;
- alert(supportcandy.translations.req_term_cond);
}
break;
<?php
--- a/supportcandy/includes/admin/settings/text-editor-settings/class-wpsc-text-editor.php
+++ b/supportcandy/includes/admin/settings/text-editor-settings/class-wpsc-text-editor.php
@@ -331,6 +331,16 @@
wpsc_clear_saved_draft_reply( ticket_id );
}
});
+ editor.on('keyup change input', function () {
+ var field = jQuery('#' + editor.id).closest('.wpsc-tff');
+
+ // Check if editor actually has content
+ var content = editor.getContent({ format: 'text' }).trim();
+
+ if (content !== '') {
+ field.find('.wpsc-error-msg').remove();
+ }
+ });
}
});
<?php
--- a/supportcandy/includes/admin/tickets/class-wpsc-individual-ticket.php
+++ b/supportcandy/includes/admin/tickets/class-wpsc-individual-ticket.php
@@ -108,6 +108,8 @@
add_action( 'wp_ajax_nopriv_wpsc_it_ticket_restore', array( __CLASS__, 'ticket_restore' ) );
add_action( 'wp_ajax_wpsc_it_delete_permanently', array( __CLASS__, 'set_delete_ticket_permanently' ) );
add_action( 'wp_ajax_nopriv_wpsc_it_delete_permanently', array( __CLASS__, 'set_delete_ticket_permanently' ) );
+ add_action( 'wp_ajax_wpsc_it_block_unblock_notifications', array( __CLASS__, 'set_block_unblock_notifications' ) );
+ add_action( 'wp_ajax_nopriv_wpsc_it_block_unblock_notifications', array( __CLASS__, 'set_block_unblock_notifications' ) );
// Thread actions.
add_action( 'wp_ajax_wpsc_it_thread_info', array( __CLASS__, 'it_thread_info' ) );
@@ -136,10 +138,6 @@
// Load older threads.
add_action( 'wp_ajax_wpsc_load_older_threads', array( __CLASS__, 'load_older_threads' ) );
add_action( 'wp_ajax_nopriv_wpsc_load_older_threads', array( __CLASS__, 'load_older_threads' ) );
-
- // agent collision.
- add_filter( 'wp_ajax_wpsc_check_live_agents', array( __CLASS__, 'check_live_agents' ) );
- add_action( 'wp_ajax_nopriv_wpsc_check_live_agents', array( __CLASS__, 'check_live_agents' ) );
}
/**
@@ -160,7 +158,6 @@
<?php
self::get_actions();
self::get_subject();
- self::get_live_agents();
self::get_mobile_widgets();
if ( $gs['reply-form-position'] == 'top' ) {
self::get_reply_section();
@@ -382,6 +379,25 @@
);
}
+ // Block Notifications.
+ $misc = is_array( self::$ticket->misc ) ? self::$ticket->misc : array();
+ $is_blocked = ! empty( $misc['block_notifications'] );
+ $action_label = $is_blocked
+ ? esc_html__( 'Unblock Notifications', 'supportcandy' )
+ : esc_html__( 'Block Notifications', 'supportcandy' );
+
+ if ( $current_user->is_agent && WPSC_Functions::is_site_admin() && self::$ticket->is_active ) {
+ $actions['block-notifications'] = array(
+ 'label' => $action_label,
+ 'callback' => sprintf(
+ "wpsc_it_block_unblock_notifications(%d, %s, '%s');",
+ (int) self::$ticket->id,
+ $is_blocked ? 'false' : 'true',
+ wp_create_nonce( 'wpsc_it_block_unblock_notifications' )
+ ),
+ );
+ }
+
self::$actions = apply_filters( 'wpsc_individual_ticket_actions', $actions, self::$ticket );
if ( self::$view_profile == 'agent' ) {
@@ -2450,6 +2466,43 @@
}
/**
+ * Block/Unblock ticket notifications ajax request
+ *
+ * @return void
+ */
+ public static function set_block_unblock_notifications() {
+
+ if ( ! check_ajax_referer( 'wpsc_it_block_unblock_notifications', '_ajax_nonce', false ) ) {
+ wp_send_json_error( __( 'Unauthorized request.', 'supportcandy' ), 401 );
+ }
+
+ $current_user = WPSC_Current_User::$current_user;
+ if ( ! $current_user || ! $current_user->is_agent ) {
+ wp_send_json_error( __( 'Unauthorized request.', 'supportcandy' ), 401 );
+ }
+
+ self::load_current_ticket();
+ if ( self::$is_restricted || ! self::$ticket ) {
+ wp_send_json_error( __( 'Unauthorized request.', 'supportcandy' ), 401 );
+ }
+
+ $is_block = isset( $_POST['is_block'] ) ? (int) $_POST['is_block'] : 0;
+ $is_block = $is_block === 1 ? 1 : 0;
+
+ $misc = is_array( self::$ticket->misc ) ? self::$ticket->misc : array();
+ if ( $is_block ) {
+ $misc['block_notifications'] = 1;
+ } else {
+ unset( $misc['block_notifications'] );
+ }
+
+ self::$ticket->misc = $misc;
+ self::$ticket->save();
+ do_action( 'wpsc_ticket_block_notifications', self::$ticket, $is_block );
+ wp_die();
+ }
+
+ /**
* Permanently delete current ticket
*
* @return void
@@ -3560,193 +3613,6 @@
wp_send_json( $html_response );
wp_die();
}
-
- /**
- * Show the list of live agents.
- *
- * @return void
- */
- public static function get_live_agents() {
-
- $current_user = WPSC_Current_User::$current_user;
- $ms_advanced = get_option( 'wpsc-ms-advanced-settings' );
- if ( ! ( $current_user->is_agent && $ms_advanced['agent-collision'] ) ) {
- return;
- }
- ?>
- <div class="wpsc-it-body-item wpsc-agent-collision wpsc-it-widget">
- <div class="wpsc-widget-header">
- <h2><?php esc_attr_e( 'Currently viewing', 'supportcandy' ); ?></h2>
- </div>
- <div class="wpsc-widget-body wpsc-live-agents">
- </div>
- </div>
-
- <script>
- supportcandy.agent_collision = true;
- wpsc_get_live_agents(<?php echo intval( $current_user->agent->id ); ?>, <?php echo intval( self::$ticket->id ); ?>);
- function wpsc_get_live_agents( agent_id, ticket_id ){
-
- jQuery('.wpsc-live-agents').html('');
- jQuery('.wpsc-agent-collision').hide();
- var current_tid = jQuery('#wpsc-current-ticket').val();
- if( current_tid != ticket_id ){
- return;
- }
- const urlParams = new URLSearchParams(window.location.search);
- if( supportcandy.is_frontend === '0' ) {
- section = urlParams.get('section');
- }else{
- section = urlParams.get('wpsc-section');
- }
- if( ! ( section == 'ticket-list' && ( urlParams.has('id') || urlParams.has('ticket-id')) ) ){
- return;
- }
- var data = { action: 'wpsc_check_live_agents', agent_id, ticket_id, operation: 'check', _ajax_nonce: supportcandy.nonce };
- jQuery.post(
- supportcandy.ajax_url,
- data,
- function (response) {
- if ( response.agents ) {
- jQuery('.wpsc-live-agents').html(response.agents);
- jQuery('.wpsc-agent-collision').show();
- } else {
- jQuery('.wpsc-live-agents').html('');
- jQuery('.wpsc-agent-collision').hide();
- }
- }
- );
- setTimeout(
- function () {
- wpsc_get_live_agents( agent_id, ticket_id );
- },
- 60000
- );
- }
-
- jQuery(document).ready(function(){
- window.addEventListener('beforeunload', function () {
- const urlParams = new URLSearchParams(window.location.search);
-
- // Determine section
- let section = supportcandy.is_frontend === '0'
- ? urlParams.get('section')
- : urlParams.get('wpsc-section');
-
- // Only trigger if we are on the ticket detail page
- if (!(section === 'ticket-list' && (urlParams.has('id') || urlParams.has('ticket-id')))) {
- return;
- }
-
- // Prepare data
- const data = new FormData();
- data.append('action', 'wpsc_check_live_agents');
- data.append('agent_id', '<?php echo intval( $current_user->agent->id ); ?>');
- data.append('ticket_id', '<?php echo intval( self::$ticket->id ); ?>');
- data.append('operation', 'leave');
- data.append('_ajax_nonce', supportcandy.nonce);
-
- // Send reliably on tab close
- navigator.sendBeacon(supportcandy.ajax_url, data);
- });
- });
- </script>
- <?php
- }
-
- /**
- * Get list of live agents.
- *
- * @return void
- */
- public static function check_live_agents() {
-
- if ( check_ajax_referer( 'general', '_ajax_nonce', false ) != 1 ) {
- wp_send_json_error( 'Unauthorized request!', 401 );
- }
-
- $current_user = WPSC_Current_User::$current_user;
- $ms_advanced = get_option( 'wpsc-ms-advanced-settings' );
- if ( ! ( $current_user->is_agent && $ms_advanced['agent-collision'] ) ) {
- wp_send_json_error( new WP_Error( '001', 'Unauthorized!' ), 401 );
- }
-
- $id = isset( $_POST['ticket_id'] ) ? intval( $_POST['ticket_id'] ) : 0; // phpcs:ignore
- if ( ! $id ) {
- wp_send_json_error( new WP_Error( '001', 'Unauthorized!' ), 401 );
- }
-
- $ticket = new WPSC_Ticket( $id );
- if ( ! $ticket->id ) {
- wp_send_json_error( new WP_Error( '002', 'Something went wrong!' ), 400 );
- }
-
- self::$ticket = $ticket;
- if ( ! self::has_ticket_cap( 'view' ) ) {
- wp_send_json_error( new WP_Error( '003', 'Unauthorized!' ), 401 );
- }
-
- $agent_id = isset( $_POST['agent_id'] ) ? intval( $_POST['agent_id'] ) : 0; // phpcs:ignore
- if ( ! $agent_id ) {
- wp_send_json_error( new WP_Error( '001', 'Unauthorized!' ), 401 );
- }
-
- $agent = new WPSC_Agent( $agent_id );
- if ( ! $agent->id ) {
- wp_send_json_error( new WP_Error( '002', 'Something went wrong!' ), 400 );
- }
-
- $operation = isset( $_POST['operation'] ) ? esc_attr( $_POST['operation'] ) : 'check'; // phpcs:ignore
-
- $agents = json_decode( $ticket->live_agents, true );
- $agents = $agents ? $agents : array();
-
- if ( $operation == 'leave' ) {
-
- if ( array_key_exists( $agent->id, $agents ) ) {
- unset( $agents[ $agent->id ] );
- $agents = wp_json_encode( $agents );
- $ticket->live_agents = $agents;
- $ticket->save();
- }
- wp_die();
- }
- // check inactive agents.
- foreach ( $agents as $key => $tm ) {
- if ( $key == $agent->id ) {
- continue;
- }
-
- $time = DateTime::createFromFormat( 'Y-m-d H:i:s', $tm );
- $now = new DateTime();
- $interval = $now->diff( $time );
- if ( $interval->i >= 1 && $interval->s > 1 ) {
- unset( $agents[ $key ] );
- }
- }
-
- $agents[ $agent->id ] = ( new DateTime() )->format( 'Y-m-d H:i:s' );
-
- $html = '';
- foreach ( $agents as $ag_id => $tmp ) {
- if ( $ag_id == $agent->id ) {
- continue;
- }
- $agt = new WPSC_Agent( $ag_id );
-
- $html .= '<div class="wpsc-ac-agent"> ' .
- get_avatar( $agt->customer->email, 20 ) .
- '<span class="ac-name">' . $agt->name . '</span></div>';
- }
-
- $agents = wp_json_encode( $agents );
- $ticket->live_agents = $agents;
- $ticket->save();
- $response = array(
- 'agents' => $html,
- );
- wp_send_json( $response );
- }
}
endif;
--- a/supportcandy/includes/admin/tickets/class-wpsc-new-ticket.php
+++ b/supportcandy/includes/admin/tickets/class-wpsc-new-ticket.php
@@ -322,22 +322,58 @@
var customFields = jQuery('.wpsc-tff.wpsc-visible');
var flag = true;
+ var firstInvalidField = null;
+
+ // Remove old errors
+ clearAllFieldErrors();
jQuery.each(customFields, function(index, customField){
customField = jQuery(customField);
var customFieldType = customField.data('cft');
var isValid = true;
+ var isRequired = customField.hasClass('required');
+
+ var fieldLabel = customField.find('.wpsc-tff-label .name').text().trim() || 'This field';
switch (customFieldType) {
<?php do_action( 'wpsc_js_validate_ticket_form' ); ?>
}
+ //Common error handling
if (!isValid) {
+
flag = false;
- return false;
+
+ // Show error message
+ showFieldError(customField, fieldLabel + ' is required');
+
+ // Track first invalid field
+ if (!firstInvalidField) {
+ firstInvalidField = customField;
+ }
}
});
+
+ // Scroll to first error
+ if (firstInvalidField) {
+ firstInvalidField[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }
return flag;
}
+ function showFieldError(field, message) {
+ if (field.find('.wpsc-error-msg').length === 0) {
+ field.append('<div class="wpsc-error-msg">' + message + '</div>');
+ }
+ }
+
+ function clearAllFieldErrors() {
+ jQuery('.wpsc-error-msg').remove();
+ }
+
+ jQuery(document).on('input change', '.wpsc-tff input, .wpsc-tff textarea, .wpsc-tff select', function(){
+ var field = jQuery(this).closest('.wpsc-tff');
+ field.find('.wpsc-error-msg').remove();
+ });
+
function wpsc_clear_hidden_fields() {
var customFields = jQuery('.wpsc-tff.wpsc-hidden');
jQuery.each(customFields, function(index, customField){
--- a/supportcandy/includes/admin/tickets/widgets/class-wpsc-itw-agent-collision.php
+++ b/supportcandy/includes/admin/tickets/widgets/class-wpsc-itw-agent-collision.php
@@ -0,0 +1,347 @@
+<?php
+
+if ( ! defined( 'ABSPATH' ) ) {
+ exit; // Exit if accessed directly!
+}
+
+if ( ! class_exists( 'WPSC_ITW_Agent_Collision' ) ) :
+
+ final class WPSC_ITW_Agent_Collision {
+
+ /**
+ * Initialization
+ *
+ * @return void
+ */
+ public static function init() {
+
+ // agent collision.
+ add_action( 'wp_ajax_wpsc_check_live_agents', array( __CLASS__, 'check_live_agents' ) );
+ add_action( 'wp_ajax_nopriv_wpsc_check_live_agents', array( __CLASS__, 'check_live_agents' ) );
+
+ // edit widget settings.
+ add_action( 'wp_ajax_wpsc_get_tw_agent_collision', array( __CLASS__, 'get_tw_agent_collision' ) );
+ add_action( 'wp_ajax_wpsc_set_tw_agent_collision', array( __CLASS__, 'set_tw_agent_collision' ) );
+
+ add_action( 'wpsc_it_layout_section', array( __CLASS__, 'print_agent_collision_scripts' ) );
+ }
+
+ /**
+ * Print body of current widget
+ *
+ * @param WPSC_Ticket $ticket - ticket object.
+ * @param array $settings - setting array.
+ * @return void
+ */
+ public static function print_widget( $ticket, $settings ) {
+
+ $current_user = WPSC_Current_User::$current_user;
+ $ms_advanced = get_option( 'wpsc-ms-advanced-settings' );
+
+ if (
+ ! $current_user->is_agent ||
+ ! $ms_advanced['agent-collision'] ||
+ WPSC_Individual_Ticket::$view_profile !== 'agent'
+ ) {
+ return;
+ }
+
+ WPSC_Individual_Ticket::$ticket = $ticket;
+ if ( WPSC_Individual_Ticket::$is_restricted ) {
+ return;
+ }
+
+ $title = $settings['title']
+ ? WPSC_Translations::get( 'wpsc-twt-agent-collision', stripslashes( $settings['title'] ) )
+ : stripslashes( $settings['title'] );
+ $no_agent_html = '<div class="wpsc-no-agents">No live agent found</div>';
+ ?>
+ <div class="wpsc-it-widget wpsc-itw-ac">
+ <div class="wpsc-widget-header">
+ <h2><?php echo esc_html( $title ); ?></h2>
+ <span class="wpsc-itw-toggle" data-widget="wpsc-itw-ac"><?php WPSC_Icons::get( 'chevron-up' ); ?></span>
+ </div>
+ <div class="wpsc-widget-body" style="max-height: 100px;">
+ <div class="wpsc-widget-default">
+ <div class="wpsc-agent-collision">
+ <div class="wpsc-live-agents"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <?php
+ }
+
+ /**
+ * Print necessary scripts for agent collision widget
+ *
+ * @param WPSC_Ticket $ticket - ticket object.
+ * @return void
+ */
+ public static function print_agent_collision_scripts( $ticket ) {
+ $current_user = WPSC_Current_User::$current_user;
+ ?>
+ <script>
+ supportcandy.agent_collision = true;
+ wpsc_get_live_agents(<?php echo intval( $current_user->agent->id ); ?>, <?php echo intval( $ticket->id ); ?>);
+ function wpsc_get_live_agents(agent_id, ticket_id){
+
+ // ALWAYS re-select DOM (important)
+ let container = jQuery('.wpsc-live-agents');
+ let parent = jQuery('.wpsc-agent-collision');
+
+ var current_tid = jQuery('#wpsc-current-ticket').val();
+ if (current_tid != ticket_id){
+ schedule_next(agent_id, ticket_id);
+ return;
+ }
+
+ const urlParams = new URLSearchParams(window.location.search);
+ let section = supportcandy.is_frontend === '0'
+ ? urlParams.get('section')
+ : urlParams.get('wpsc-section');
+
+ if (!(section == 'ticket-list' && (urlParams.has('id') || urlParams.has('ticket-id')))){
+ schedule_next(agent_id, ticket_id);
+ return;
+ }
+
+ var data = {
+ action: 'wpsc_check_live_agents',
+ agent_id,
+ ticket_id,
+ operation: 'check',
+ _ajax_nonce: supportcandy.nonce
+ };
+
+ jQuery.post(supportcandy.ajax_url, data, function (response) {
+ if (response && response.agents){
+ if (container.html() !== response.agents){
+ container.html(response.agents);
+ }
+ parent.stop(true, true).fadeIn(200);
+ } else {
+
+ let noAgentHTML = '<div class="wpsc-no-agents"><?php echo esc_attr__( 'No live agent found', 'supportcandy' ); ?></div>';
+ if (container.html() !== noAgentHTML){
+ container.html(noAgentHTML);
+ }
+ parent.stop(true, true).fadeIn(200);
+ }
+ });
+ schedule_next(agent_id, ticket_id);
+ }
+
+ // Keep polling simple & reliable
+ function schedule_next(agent_id, ticket_id){
+ setTimeout(function(){
+ wpsc_get_live_agents(agent_id, ticket_id);
+ }, 60000);
+ }
+
+ jQuery(document).ready(function(){
+ window.addEventListener('beforeunload', function () {
+ const urlParams = new URLSearchParams(window.location.search);
+
+ // Determine section
+ let section = supportcandy.is_frontend === '0'
+ ? urlParams.get('section')
+ : urlParams.get('wpsc-section');
+
+ // Only trigger if we are on the ticket detail page
+ if (!(section === 'ticket-list' && (urlParams.has('id') || urlParams.has('ticket-id')))) {
+ return;
+ }
+
+ // Prepare data
+ const data = new FormData();
+ data.append('action', 'wpsc_check_live_agents');
+ data.append('agent_id', '<?php echo intval( $current_user->agent->id ); ?>');
+ data.append('ticket_id', '<?php echo intval( $ticket->id ); ?>');
+ data.append('operation', 'leave');
+ data.append('_ajax_nonce', supportcandy.nonce);
+
+ // Send reliably on tab close
+ navigator.sendBeacon(supportcandy.ajax_url, data);
+ });
+ });
+ </script>
+ <?php
+ }
+
+ /**
+ * Get list of live agents.
+ *
+ * @return void
+ */
+ public static function check_live_agents() {
+
+ if ( check_ajax_referer( 'general', '_ajax_nonce', false ) != 1 ) {
+ wp_send_json_error( 'Unauthorized request!', 401 );
+ }
+
+ $current_user = WPSC_Current_User::$current_user;
+ $ms_advanced = get_option( 'wpsc-ms-advanced-settings' );
+ if ( ! ( $current_user->is_agent && $ms_advanced['agent-collision'] ) ) {
+ wp_send_json_error( new WP_Error( '001', 'Unauthorized!' ), 401 );
+ }
+
+ $id = isset( $_POST['ticket_id'] ) ? intval( $_POST['ticket_id'] ) : 0; // phpcs:ignore
+ if ( ! $id ) {
+ wp_send_json_error( new WP_Error( '001', 'Unauthorized!' ), 401 );
+ }
+
+ // Always use the authenticated user's agent ID, not the request's agent_id.
+ if ( ! isset( $current_user->agent ) || ! $current_user->agent->id ) {
+ wp_send_json_error( new WP_Error( '001', 'Unauthorized!' ), 401 );
+ }
+
+ // If agent_id is present in the request, it must match the authenticated user's agent ID.
+ if ( isset( $_POST['agent_id'] ) && intval( $_POST['agent_id'] ) !== intval( $current_user->agent->id ) ) {
+ wp_send_json_error( new WP_Error( '004', 'Agent ID mismatch!' ), 401 );
+ }
+
+ $agent_id = intval( $current_user->agent->id );
+ $agent = new WPSC_Agent( $agent_id );
+ if ( ! $agent->id ) {
+ wp_send_json_error( new WP_Error( '002', 'Something went wrong!' ), 400 );
+ }
+
+ $ticket = new WPSC_Ticket( $id );
+ if ( ! $ticket->id ) {
+ wp_send_json_error( new WP_Error( '002', 'Something went wrong!' ), 400 );
+ }
+
+ WPSC_Individual_Ticket::$ticket = $ticket;
+ if ( ! WPSC_Individual_Ticket::has_ticket_cap( 'view' ) ) {
+ wp_send_json_error( new WP_Error( '003', 'Unauthorized!' ), 401 );
+ }
+
+ $operation = isset( $_POST['operation'] ) ? esc_attr( $_POST['operation'] ) : 'check'; // phpcs:ignore
+
+ $agents = json_decode( $ticket->live_agents, true );
+ $agents = $agents ? $agents : array();
+
+ if ( $operation == 'leave' ) {
+
+ if ( array_key_exists( $agent->id, $agents ) ) {
+ unset( $agents[ $agent->id ] );
+ $agents = wp_json_encode( $agents );
+ $ticket->live_agents = $agents;
+ $ticket->save();
+ }
+ wp_die();
+ }
+ // check inactive agents using timestamp comparison; remove if parsing fails or inactive > 60s.
+ foreach ( $agents as $key => $tm ) {
+ if ( $key == $agent->id ) {
+ continue;
+ }
+ $timestamp = strtotime( $tm );
+ if ( $timestamp === false || $timestamp < ( time() - 60 ) ) {
+ unset( $agents[ $key ] );
+ }
+ }
+
+ $agents[ $agent->id ] = ( new DateTime() )->format( 'Y-m-d H:i:s' );
+
+ $html = '';
+ foreach ( $agents as $ag_id => $tmp ) {
+ if ( $ag_id == $agent->id ) {
+ continue;
+ }
+ $agt = new WPSC_Agent( $ag_id );
+
+ $html .= '<div class="wpsc-agent-avatar" title="' . esc_attr( $agt->name ) . '">' .
+ get_avatar( $agt->customer->email, 28 ) .
+ '</div>';
+ }
+
+ $agents = wp_json_encode( $agents );
+ $ticket->live_agents = $agents;
+ $ticket->save();
+ $response = array(
+ 'agents' => $html,
+ );
+ wp_send_json( $response );
+ }
+
+ /**
+ * Add/edit Agent Collision title
+ *
+ * @return void
+ */
+ public static function get_tw_agent_collision() {
+
+ if ( ! WPSC_Functions::is_site_admin() ) {
+ wp_send_json_error( __( 'Unauthorized access!', 'supportcandy' ), 401 );
+ }
+
+ $ticket_widgets = get_option( 'wpsc-ticket-widget', array() );
+ $agent_collision = $ticket_widgets['agent-collision'];
+ $title = $agent_collision['title'];
+ ob_start();
+ ?>
+ <form action="#" onsubmit="return false;" class="wpsc-frm-edit-ac">
+ <div class="wpsc-input-group">
+ <div class="label-container">
+ <label for=""><?php echo esc_attr( wpsc__( 'Title', 'supportcandy' ) ); ?></label>
+ </div>
+ <input name="label" type="text" value="<?php echo esc_attr( $agent_collision['title'] ); ?>" autocomplete="off">
+ </div>
+ <input type="hidden" name="action" value="wpsc_set_tw_agent_collision">
+ <input type="hidden" name="_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wpsc_set_tw_agent_collision' ) ); ?>">
+ </form>
+ <?php
+ $body = ob_get_clean();
+ ob_start();
+ ?>
+ <button class="wpsc-button small primary" onclick="wpsc_set_tw_agent_collision(this);">
+ <?php echo esc_attr( wpsc__( 'Submit', 'supportcandy' ) ); ?>
+ </button>
+ <button class="wpsc-button small secondary" onclick="wpsc_close_modal();">
+ <?php echo esc_attr( wpsc__( 'Cancel', 'supportcandy' ) ); ?>
+ </button>
+ <?php
+ $footer = ob_get_clean();
+ $response = array(
+ 'title' => $title,
+ 'body' => $body,
+ 'footer' => $footer,
+ );
+ wp_send_json( $response );
+ }
+
+ /**
+ * Save Agent Collision label
+ *
+ * @return void
+ */
+ public static function set_tw_agent_collision() {
+
+ if ( check_ajax_referer( 'wpsc_set_tw_agent_collision', '_ajax_nonce', false ) != 1 ) {
+ wp_send_json_error( 'Unauthorized request!', 400 );
+ }
+
+ if ( ! WPSC_Functions::is_site_admin() ) {
+ wp_send_json_error( __( 'Unauthorized access!', 'supportcandy' ), 401 );
+ }
+
+ $label = isset( $_POST['label'] ) ? sanitize_text_field( wp_unslash( $_POST['label'] ) ) : '';
+ if ( ! $label ) {
+ wp_send_json_error( 'Bad Request', 400 );
+ }
+
+ $ticket_widgets = get_option( 'wpsc-ticket-widget', array() );
+ $ticket_widgets['agent-collision']['title'] = $label;
+ update_option( 'wpsc-ticket-widget', $ticket_widgets );
+
+ // remove string translations.
+ WPSC_Translations::remove( 'wpsc-twt-agent-collision' );
+ WPSC_Translations::add( 'wpsc-twt-agent-collision', stripslashes( $label ) );
+ wp_die();
+ }
+ }
+endif;
+
+WPSC_ITW_Agent_Collision::init();
--- a/supportcandy/includes/class-wpsc-email-notifications.php
+++ b/supportcandy/includes/class-wpsc-email-notifications.php
@@ -249,6 +249,12 @@
return false;
}
+ // check block notification flag in misc to skip notifications if it is set for the ticket.
+ $misc_array = $this->ticket->misc ? $this->ticket->misc : array();
+ if ( ! empty( $misc_array['block_notifications'] ) ) {
+ return false;
+ }
+
// from name & email.
$en_general = get_option( 'wpsc-en-general' );
if ( ! $en_general['from-name'] || ! $en_general['from-email'] ) {
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-checkbox.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-checkbox.php
@@ -512,10 +512,8 @@
?>
case '<?php echo esc_attr( self::$slug ); ?>':
- var checkbox = customField.find('input:checked');
- if (customField.hasClass('required') && checkbox.length === 0) {
+ if (isRequired && customField.find('input:checked').length === 0) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-date.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-date.php
@@ -618,9 +618,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-datetime.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-datetime.php
@@ -580,9 +580,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-email.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-email.php
@@ -575,15 +575,11 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
- break;
- }
- if (val && !validateEmail(val)) {
+ } else if (val && !validateEmail(val)) {
+ showFieldError(customField, 'Invalid email address');
isValid = false;
- alert('<?php esc_attr_e( 'Invalid email address!', 'supportcandy' ); ?>');
- break;
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-file-attachment-multiple.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-file-attachment-multiple.php
@@ -279,10 +279,8 @@
?>
case '<?php echo esc_attr( self::$slug ); ?>':
- var count = customField.find('input[type=hidden]').length;
- if (customField.hasClass('required') && count === 0) {
+ if (isRequired && customField.find('input[type=hidden]').length === 0) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-file-attachment-single.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-file-attachment-single.php
@@ -285,10 +285,8 @@
?>
case '<?php echo esc_attr( self::$slug ); ?>':
- var count = customField.find('input[type=hidden]').length;
- if (customField.hasClass('required') && count === 0) {
+ if (isRequired && customField.find('input[type=hidden]').length === 0) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-multi-select.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-multi-select.php
@@ -526,9 +526,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('select').first().val();
- if (customField.hasClass('required') && val.length === 0) {
+ if (isRequired && (!val || val.length === 0)) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-number.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-number.php
@@ -670,10 +670,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
- break;
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-radio-button.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-radio-button.php
@@ -476,10 +476,8 @@
?>
case '<?php echo esc_attr( self::$slug ); ?>':
- var rb = customField.find('input:checked');
- if (customField.hasClass('required') && rb.length === 0) {
+ if (isRequired && customField.find('input:checked').length === 0) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-single-select.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-single-select.php
@@ -488,9 +488,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('select').first().val();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-text-field.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-text-field.php
@@ -569,9 +569,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-textarea.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-textarea.php
@@ -542,9 +542,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('textarea').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-time.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-time.php
@@ -272,9 +272,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-cf-url.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-cf-url.php
@@ -555,15 +555,11 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
- break;
- }
- if (val && !validateURL(val)) {
+ } else if (val && !validateURL(val)) {
+ showFieldError(customField, 'Invalid URL');
isValid = false;
- alert('<?php esc_attr_e( 'Invalid URL!', 'supportcandy' ); ?>');
- break;
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-additional-recipients.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-additional-recipients.php
@@ -175,6 +175,9 @@
// create ticket data for rest api.
add_filter( 'wpsc_rest_create_ticket', array( __CLASS__, 'set_rest_ticket_data' ), 10, 3 );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -193,6 +196,21 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Additional Recipients', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Add ticket search compatibility for fields of this custom field type.
*
* @param array $sql - Array of sql peices that can be joined later.
@@ -258,9 +276,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('textarea').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-agent-created.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-agent-created.php
@@ -176,6 +176,9 @@
// rest api.
add_filter( 'wpsc_rest_prevent_ticket_data', array( __CLASS__, 'rest_prevent_ticket_data' ) );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -194,6 +197,20 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Agent Created', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Print operators for ticket form filter
*
* @param WPSC_Custom_Field $cf - custom field object.
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-assigned-agent.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-assigned-agent.php
@@ -196,6 +196,9 @@
// Agent assign ticket to self.
add_action( 'wp_ajax_wpsc_self_assign_ticket', array( __CLASS__, 'self_assign_ticket' ) );
add_action( 'wp_ajax_nopriv_wpsc_self_assign_ticket', array( __CLASS__, 'self_assign_ticket' ) );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -214,6 +217,20 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Assigned Agent', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Print operators for ticket form filter
*
* @param WPSC_Custom_Field $cf - custom field object.
@@ -656,9 +673,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('select').first().val();
- if (customField.hasClass('required') && val.length === 0) {
+ if (isRequired && (!val || val.length === 0)) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-browser.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-browser.php
@@ -166,6 +166,9 @@
// TFF!
add_action( 'wpsc_create_ticket_data', array( __CLASS__, 'set_create_ticket_data' ), 10, 3 );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -184,6 +187,20 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Browser', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Print operators for ticket form filter
*
* @param WPSC_Custom_Field $cf - custom field object.
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-category.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-category.php
@@ -175,6 +175,9 @@
// Ticket model.
add_filter( 'wpsc_ticket_joins', array( __CLASS__, 'ticket_join' ), 10, 2 );
add_filter( 'wpsc_archive_ticket_joins', array( __CLASS__, 'ticket_join' ), 10, 2 );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -193,6 +196,20 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Category', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Print operators for ticket form filter
*
* @param WPSC_Custom_Field $cf - custom field object.
@@ -451,9 +468,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('select').first().val();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-customer-email.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-customer-email.php
@@ -167,6 +167,9 @@
// TFF!
add_action( 'wpsc_js_validate_ticket_form', array( __CLASS__, 'js_validate_ticket_form' ) );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -185,6 +188,21 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Customer Email', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Print ticket form field
*
* @param WPSC_Custom_Field $cf - Custom field object.
@@ -243,15 +261,11 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
- break;
- }
- if (val && !validateEmail(val)) {
+ } else if (val && !validateEmail(val)) {
+ showFieldError(customField, '<?php esc_attr_e( 'Invalid email address!', 'supportcandy' ); ?>');
isValid = false;
- alert('<?php esc_attr_e( 'Invalid email address!', 'supportcandy' ); ?>');
- break;
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-customer-name.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-customer-name.php
@@ -166,6 +166,9 @@
// TFF!
add_action( 'wpsc_js_validate_ticket_form', array( __CLASS__, 'js_validate_ticket_form' ) );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -184,6 +187,20 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Customer Name', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Print ticket form field
*
* @param WPSC_Custom_Field $cf - Custom field object.
@@ -240,9 +257,8 @@
case '<?php echo esc_attr( self::$slug ); ?>':
var val = customField.find('input').first().val().trim();
- if (customField.hasClass('required') && !val) {
+ if (isRequired && !val) {
isValid = false;
- alert(supportcandy.translations.req_fields_missing);
}
break;
<?php
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-customer.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-customer.php
@@ -190,6 +190,9 @@
// Customer filter autocomplete.
add_action( 'wp_ajax_wpsc_customer_filter_autocomplete', array( __CLASS__, 'customer_filter_autocomplete' ) );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -208,6 +211,20 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array
+ */
+ public static function default_cf_types( $default_cf_types ) {
+ $default_cf_types[ self::$slug ] = array(
+ 'label' => esc_attr__( 'Customer', 'supportcandy' ),
+ 'class' => __CLASS__,
+ );
+ return $default_cf_types;
+ }
+
+ /**
* Print operators for ticket form filter
*
* @param WPSC_Custom_Field $cf - custom field object.
--- a/supportcandy/includes/custom-field-types/class-wpsc-df-date-closed.php
+++ b/supportcandy/includes/custom-field-types/class-wpsc-df-date-closed.php
@@ -163,6 +163,9 @@
// Get object of this class.
add_filter( 'wpsc_load_ref_classes', array( __CLASS__, 'load_ref_class' ) );
+
+ // Set custom field type.
+ add_filter( 'wpsc_default_cf_types', array( __CLASS__, 'default_cf_types' ), 4 );
}
/**
@@ -181,6 +184,20 @@
}
/**
+ * Add default custom field type to list
+ *
+ * @param array $default_cf_types - default custom field types array.
+ * @return array