__CLASS__,
'save-key' => 'id',
);
return $classes;
}
/**
* Add custom field type to list
*
* @param array $cf_types - custom field types array.
* @return array
*/
public static function add_cf_type( $cf_types ) {
$cf_types[ self::$slug ] = array(
'label' => esc_attr__( 'Dropdown (multi-select)', 'supportcandy' ),
'class' => __CLASS__,
);
return $cf_types;
}
/**
* Print operators for ticket form filter
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param array $filter - Existing filters (if any).
* @return void
*/
public static function get_operators( $cf, $filter = array() ) {
?>
get_options();
$unique_id = uniqid( 'wpsc_' );
?>
$value ) {
if ( $value == '' ) {
$val[ $index ] = '^$';
}
}
$str = self::get_sql_slug( $cf ) . ' RLIKE \'(^|[|])(' . implode( '|', esc_sql( $val ) ) . ')($|[|])\'';
break;
case 'NOT IN':
foreach ( $val as $index => $value ) {
if ( $value == '' ) {
$val[ $index ] = '^$';
}
}
$str = self::get_sql_slug( $cf ) . ' NOT RLIKE \'(^|[|])(' . implode( '|', esc_sql( $val ) ) . ')($|[|])\'';
break;
default:
$str = '1=1';
}
return $str;
}
/**
* Check ticket condition
*
* @param array $condition - array with condition data.
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Ticket $ticket - ticket object.
* @return boolean
*/
public static function is_valid_ticket_condition( $condition, $cf, $ticket ) {
$flag = true;
$cf_ids = array_map( fn( $option ) => $option->id, $ticket->{$cf->slug} );
switch ( $condition['operator'] ) {
case '=':
$flag = in_array( $condition['operand_val_1'], $cf_ids );
break;
case 'IN':
$flag = false;
foreach ( $cf_ids as $id ) {
if ( in_array( $id, $condition['operand_val_1'] ) ) {
$flag = true;
break;
}
}
break;
case 'NOT IN':
foreach ( $cf_ids as $id ) {
if ( in_array( $id, $condition['operand_val_1'] ) ) {
$flag = false;
break;
}
}
break;
default:
$flag = true;
}
return $flag;
}
/**
* Check customer condition
*
* @param array $condition - array with condition data.
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Customer $customer - customer object.
* @return boolean
*/
public static function is_valid_customer_condition( $condition, $cf, $customer ) {
$flag = true;
$cf_ids = array_map( fn( $option ) => $option->id, $customer->{$cf->slug} );
switch ( $condition['operator'] ) {
case '=':
$flag = in_array( $condition['operand_val_1'], $cf_ids );
break;
case 'IN':
$flag = false;
foreach ( $cf_ids as $id ) {
if ( in_array( $id, $condition['operand_val_1'] ) ) {
$flag = true;
break;
}
}
break;
case 'NOT IN':
foreach ( $cf_ids as $id ) {
if ( in_array( $id, $condition['operand_val_1'] ) ) {
$flag = false;
break;
}
}
break;
default:
$flag = true;
}
return $flag;
}
/**
* Print ticket form field
*
* @param WPSC_Custom_Field $cf - Custom field object.
* @param array $tff - Array of ticket form field settings for this field.
* @return string
*/
public static function print_tff( $cf, $tff ) {
$options = $cf->get_options();
$val = array();
if ( $cf->field == 'ticket' ) {
$val = $cf->is_auto_fill && $cf->default_value ? $cf->default_value : array();
} else {
$current_user = WPSC_Current_User::$current_user;
if ( $current_user->is_customer && $current_user->customer->{$cf->slug} ) {
$val = array_map( fn( $option )=>$option->id, $current_user->customer->{$cf->slug} );
}
}
$unique_id = uniqid( 'wpsc_' );
ob_start();
?>
name ); ?>
*
case '':
var val = customField.find('select').first().val();
if (customField.hasClass('required') && val.length === 0) {
isValid = false;
alert(supportcandy.translations.req_fields_missing);
}
break;
default_value ? implode( '|', $cf->default_value ) : '';
}
/**
* Check and return custom field value for new ticket to be created.
* This function is used by filter for set create ticket form and called directly by my-profile for each applicable custom fields.
* Ignore phpcs nonce issue as we already checked where it is called from.
*
* @param array $data - Array of values to to stored in ticket in an insert function.
* @param array $custom_fields - Array containing all applicable custom fields indexed by unique custom field types.
* @param boolean $is_my_profile - Whether it or not it is created from my-profile. This function is used by create ticket as well as my-profile. Due to customer fields handling is done same way, this flag gives apportunity to identify where it being called.
* @return array
*/
public static function set_create_ticket_data( $data, $custom_fields, $is_my_profile ) {
if ( isset( $custom_fields[ self::$slug ] ) ) {
foreach ( $custom_fields[ self::$slug ] as $cf ) {
$value = self::get_tff_value( $cf->slug );
if ( $cf->field == 'ticket' ) {
$default_val = self::get_default_value( $cf );
$data[ $cf->slug ] = $value ? implode( '|', $value ) : $default_val;
} elseif ( $cf->field == 'agentonly' ) {
$data[ $cf->slug ] = self::get_default_value( $cf );
} elseif ( $cf->field == 'customer' && $data['customer'] != 0 ) {
$tff = get_option( 'wpsc-tff' );
if ( ! $is_my_profile && ! isset( $tff[ $cf->slug ] ) ) {
continue;
}
$customer = new WPSC_Customer( $data['customer'] );
$existing_val = array_map( fn( $option )=>$option->id, $customer->{$cf->slug} );
if ( array_diff( $existing_val, $value ) || array_diff( $value, $existing_val ) ) {
$customer->{$cf->slug} = $value;
$customer->save();
$prev_val = $existing_val ? implode( '|', $existing_val ) : '';
$new_val = $value ? implode( '|', $value ) : '';
// Set log for this change.
WPSC_Log::insert(
array(
'type' => 'customer',
'ref_id' => $customer->id,
'modified_by' => WPSC_Current_User::$current_user->customer->id,
'body' => wp_json_encode(
array(
'slug' => $cf->slug,
'prev' => $prev_val,
'new' => $new_val,
)
),
'date_created' => ( new DateTime() )->format( 'Y-m-d H:i:s' ),
)
);
}
}
}
}
return $data;
}
/**
* Set create ticket data for rest api request
*
* @param array $data - create ticket data array.
* @param WP_REST_Request $request - rest request object.
* @param array $custom_fields - custom field objects indexed by unique custom field types.
* @return array
*/
public static function set_rest_ticket_data( $data, $request, $custom_fields ) {
$current_user = WPSC_Current_User::$current_user;
$tff = get_option( 'wpsc-tff' );
if ( isset( $custom_fields[ self::$slug ] ) ) {
foreach ( $custom_fields[ self::$slug ] as $cf ) {
if (
! in_array( $cf->field, array( 'ticket', 'agentonly', 'customer' ) ) ||
( $cf->field == 'customer' && ! isset( $tff[ $cf->slug ] ) )
) {
continue;
}
$value = sanitize_text_field( $request->get_param( $cf->slug ) );
if ( $value ) {
$value = implode(
'|',
array_filter(
array_map(
function ( $id ) {
$option = new WPSC_Option( intval( $id ) );
return $option->id ? $option->id : false;
},
explode( ',', $value )
)
)
);
}
if ( in_array( $cf->field, array( 'ticket', 'agentonly' ) ) ) {
$data[ $cf->slug ] = $cf->field == 'ticket' && $value ? $value : self::get_default_value( $cf );
} else {
$customer = new WPSC_Customer( $data['customer'] );
$existing_val = array_filter(
array_map(
fn( $option ) => $option->id ? $option->id : false,
$customer->{$cf->slug}
)
);
$new_val = array_filter( explode( '|', $value ) );
if ( $new_val && ( array_diff( $existing_val, $new_val ) || array_diff( $new_val, $existing_val ) ) ) {
$customer->{$cf->slug} = $new_val;
$customer->save();
// Set log for this change..
WPSC_Log::insert(
array(
'type' => 'customer',
'ref_id' => $customer->id,
'modified_by' => $current_user->customer->id,
'body' => wp_json_encode(
array(
'slug' => $cf->slug,
'prev' => implode( '|', $existing_val ),
'new' => $value,
)
),
'date_created' => ( new DateTime() )->format( 'Y-m-d H:i:s' ),
)
);
}
}
}
}
return $data;
}
/**
* Return slug string to be used in where condition of ticket model for this type of field
*
* @param WPSC_Custom_Field $cf - custom field object.
* @return string
*/
public static function get_sql_slug( $cf ) {
$join_char = in_array( $cf->field, array( 'ticket', 'agentonly' ) ) ? 't.' : 'c.';
return $join_char . $cf->slug;
}
/**
* Add ticket search compatibility for fields of this custom field type.
*
* @param array $sql - Array of sql peices that can be joined later.
* @param array $filter - User filter.
* @param array $custom_fields - Custom fields array applicable for search.
* @param string $search - search string.
* @param array $allowed_search_fields - Allowed search fields.
* @return array
*/
public static function ticket_search( $sql, $filter, $custom_fields, $search, $allowed_search_fields ) {
if ( isset( $custom_fields[ self::$slug ] ) ) {
$search_items = false;
foreach ( $custom_fields[ self::$slug ] as $cf ) {
if ( in_array( $cf->slug, $allowed_search_fields ) ) {
if ( ! $search_items ) {
$search_items = WPSC_Option::get_tl_search_string( $search );
if ( ! $search_items ) {
break;
}
}
$join_char = in_array( $cf->field, array( 'ticket', 'agentonly' ) ) ? 't.' : 'c.';
$sql[] = $join_char . $cf->slug . ' RLIKE \'(^|[|])(' . implode( '|', $search_items ) . ')($|[|])\'';
}
}
}
return $sql;
}
/**
* Return val field for meta query of this type of custom field
*
* @param array $condition - condition data.
* @return mixed
*/
public static function get_meta_value( $condition ) {
$operator = $condition['operator'];
switch ( $operator ) {
case '=':
case 'IN':
case 'NOT IN':
return $condition['operand_val_1'];
}
return false;
}
/**
* Print generic input field for this type.
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param mixed $value - optional. Input field will be printed with given value.
* @return void
*/
public static function print_cf_input( $cf, $value = array() ) {
if ( ! is_array( $value ) ) {
$value = array_filter(
array_map(
function ( $val ) {
$option = new WPSC_Option( $val );
return $option->id ? $option : '';
},
explode( '|', $value )
)
);
}
$options = $cf->get_options();
$unique_id = uniqid( 'wpsc_' );
?>
name ); ?>
extra_info );
if ( $extra_info ) :
?>
slug ] ) ? array_filter( array_map( 'intval', $_POST[ $cf->slug ] ) ) : array(); // phpcs:ignore
return $value ? implode( '|', $value ) : '';
}
/**
* Print edit ticket custom field in individual ticket
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Ticket $ticket - ticket object.
* @return void
*/
public static function print_edit_ticket_cf( $cf, $ticket ) {
$options = $cf->get_options();
$unique_id = uniqid( 'wpsc_' );
?>
name ); ?>
extra_info );
if ( $extra_info ) :
?>
{$cf->slug} ? $ticket->{$cf->slug} : array();
$prev_ids = array_filter( array_map( fn( $option ) => $option->id ? $option->id : '', $prev ) );
$new_ids = isset( $_POST[ $cf->slug ] ) ? array_filter( array_map( 'intval', $_POST[ $cf->slug ] ) ) : array(); // phpcs:ignore
// Exit if there is no change.
if ( ! ( array_diff( $prev_ids, $new_ids ) || array_diff( $new_ids, $prev_ids ) ) ) {
return $ticket;
}
// Create wpsc_option objects.
$new = array_filter(
array_map(
function ( $id ) {
$option = new WPSC_Option( $id );
return $option->id ? $option : '';
},
$new_ids
)
);
// Change value.
$ticket->{$cf->slug} = $new;
$ticket->save();
return $ticket;
}
/**
* Modify ticket field value of this custom field type using rest api
*
* @param WPSC_Ticket $ticket - ticket object.
* @param WPSC_Custom_Field $cf - custom field.
* @param mixed $value - value to be set.
* @return void
*/
public static function set_rest_edit_ticket_cf( $ticket, $cf, $value ) {
$new = array_unique(
array_filter(
array_map(
function ( $id ) {
$option = new WPSC_Option( intval( $id ) );
return $option->id ? $option->id : false;
},
explode( ',', sanitize_text_field( $value ) )
)
)
);
$prev = is_array( $ticket->{$cf->slug} ) ? $ticket->{$cf->slug} : array();
$prev = array_filter(
array_map(
fn( $option ) => $option->id ? $option->id : false,
$prev
)
);
if ( array_diff( $prev, $new ) || array_diff( $new, $prev ) ) {
$ticket->{$cf->slug} = $new;
}
}
/**
* Insert log thread for this custom field type change
*
* @param WPSC_Custom_Field $cf - current custom field of this type.
* @param WPSC_Ticket $prev - ticket object before making any changes.
* @param WPSC_Ticket $new - ticket object after making changes.
* @param string $current_date - date string to be stored as create time.
* @param int $customer_id - current user customer id for blame.
* @return void
*/
public static function insert_ticket_log( $cf, $prev, $new, $current_date, $customer_id ) {
$prev_ids = array_filter( array_map( fn( $option ) => $option->id ? $option->id : '', $prev->{$cf->slug} ) );
$new_ids = array_filter( array_map( fn( $option )=>$option->id ? $option->id : '', $new->{$cf->slug} ) );
// Exit if there is no change.
if ( ! ( array_diff( $prev_ids, $new_ids ) || array_diff( $new_ids, $prev_ids ) ) ) {
return;
}
$prev_val = $prev_ids ? implode( '|', $prev_ids ) : '';
$new_val = $new_ids ? implode( '|', $new_ids ) : '';
$thread = WPSC_Thread::insert(
array(
'ticket' => $prev->id,
'customer' => $customer_id,
'type' => 'log',
'body' => wp_json_encode(
array(
'slug' => $cf->slug,
'prev' => $prev_val,
'new' => $new_val,
)
),
'date_created' => $current_date,
'date_updated' => $current_date,
)
);
}
/**
* Return data for this custom field while creating duplicate ticket
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Ticket $ticket - ticket object.
* @return mixed
*/
public static function get_duplicate_ticket_data( $cf, $ticket ) {
$val = $ticket->{$cf->slug};
$response = array();
foreach ( $val as $option ) {
$response[] = $option->id;
}
return $response ? implode( '|', $response ) : '';
}
/**
* Print edit field for this type in edit customer info
*
* @param WPSC_Custom_field $cf - custom field object.
* @param WPSC_Customer $customer - customer object.
* @param array $tff - ticket form field data.
* @return string
*/
public static function print_edit_customer_info( $cf, $customer, $tff ) {
$options = $cf->get_options();
$val = array();
if ( $customer->id && $customer->{$cf->slug} ) {
foreach ( $customer->{$cf->slug} as $option ) {
$val[] = $option->id;
}
}
$unique_id = uniqid( 'wpsc_' );
ob_start();
?>
name ); ?>
extra_info = isset( $_POST['extra_info'] ) ? sanitize_text_field( wp_unslash( $_POST['extra_info'] ) ) : ''; // phpcs:ignore
}
// options.
$options = isset( $_POST['options'] ) ? array_filter( array_map( 'sanitize_text_field', wp_unslash($_POST['options']) ) ) : array(); // phpcs:ignore
if ( ! $options ) {
wp_send_json_error( new WP_Error( '001', 'Bad request!' ), 400 );
}
// default value.
if ( in_array( 'default_value', $field_class::$allowed_properties ) ) {
$cf->default_value = isset( $_POST['default-val-option-multi'] ) ? array_filter( array_map( 'intval', $_POST['default-val-option-multi'] ) ) : array(); // phpcs:ignore
}
// auto fill.
if ( in_array( 'is_auto_fill', $field_class::$allowed_properties ) ) {
$cf->is_auto_fill = isset( $_POST['is_auto_fill'] ) ? sanitize_text_field( wp_unslash( $_POST['is_auto_fill'] ) ) : ''; // phpcs:ignore
}
// placeholder!
if ( in_array( 'placeholder_text', $field_class::$allowed_properties ) ) {
$cf->placeholder_text = isset( $_POST['placeholder_text'] ) ? sanitize_text_field( wp_unslash( $_POST['placeholder_text'] ) ) : ''; // phpcs:ignore
}
// personal info.
if ( in_array( 'is_personal_info', $field_class::$allowed_properties ) ) {
$cf->is_personal_info = isset( $_POST['is_personal_info'] ) ? intval( $_POST['is_personal_info'] ) : 0; // phpcs:ignore
}
// my-profile.
if ( in_array( 'allow_my_profile', $field_class::$allowed_properties ) ) {
$cf->allow_my_profile = isset( $_POST['allow_my_profile'] ) ? intval( $_POST['allow_my_profile'] ) : 0; // phpcs:ignore
}
// ticket form.
if ( in_array( 'allow_ticket_form', $field_class::$allowed_properties ) ) {
$cf->allow_ticket_form = isset( $_POST['allow_ticket_form'] ) ? intval( $_POST['allow_ticket_form'] ) : 0; // phpcs:ignore
}
// tl_width!
if ( in_array( 'tl_width', $field_class::$allowed_properties ) ) {
$tl_width = isset( $_POST['tl_width'] ) ? intval( $_POST['tl_width'] ) : 0; // phpcs:ignore
$cf->tl_width = $tl_width ? $tl_width : 100;
}
// save!
$cf->save();
$cf->set_options( $options, true );
}
/**
* Returns printable ticket value for custom field. Can be used in export tickets, replace macros etc.
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Ticket $ticket - ticket object.
* @param string $module - module name.
* @return string
*/
public static function get_ticket_field_val( $cf, $ticket, $module = '' ) {
$names = array_filter(
array_map(
fn( $option ) => $option->id ? $option->name : '',
$ticket->{$cf->slug}
)
);
$value = $names ? implode( ', ', $names ) : '';
return apply_filters( 'wpsc_ticket_field_val_multi_select', $value, $cf, $ticket, $module );
}
/**
* Print ticket value for given custom field on ticket list
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Ticket $ticket - ticket object.
* @return void
*/
public static function print_tl_ticket_field_val( $cf, $ticket ) {
echo esc_attr( self::get_ticket_field_val( $cf, $ticket ) );
}
/**
* Print ticket value for given custom field on widget
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Ticket $ticket - ticket object.
* @return void
*/
public static function print_widget_ticket_field_val( $cf, $ticket ) {
echo esc_attr( self::get_ticket_field_val( $cf, $ticket ) );
}
/**
* Returns printable customer value for custom field. Can be used in export tickets, replace macros etc.
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Customer $customer - customer object.
* @return string
*/
public static function get_customer_field_val( $cf, $customer ) {
$names = array_filter(
array_map(
fn( $option ) => $option->id ? $option->name : '',
$customer->{$cf->slug}
)
);
return $names ? implode( ', ', $names ) : '';
}
/**
* Print customer value for given custom field on ticket list
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Customer $customer - customer object.
* @return void
*/
public static function print_tl_customer_field_val( $cf, $customer ) {
echo esc_attr( self::get_customer_field_val( $cf, $customer ) );
}
/**
* Print customer value for given custom field on widget
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param WPSC_Customer $customer - customer object.
* @return void
*/
public static function print_widget_customer_field_val( $cf, $customer ) {
echo esc_attr( self::get_customer_field_val( $cf, $customer ) );
}
/**
* Print given value for custom field
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param mixed $val - value to convert and print.
* @return void
*/
public static function print_val( $cf, $val ) {
$val = is_array( $val ) ? $val : array_filter( explode( '|', $val ) );
$options = array_filter(
array_map(
function ( $option ) {
if ( is_object( $option ) ) {
return $option;
} elseif ( $option ) {
$option = new WPSC_Option( $option );
return $option->id ? $option : '';
} else {
return '';
}
},
$val
)
);
$option_names = array_map( fn( $option ) => $option->name, $options );
echo $option_names ? esc_attr( implode( ', ', $option_names ) ) : esc_attr__( 'None', 'supportcandy' );
}
/**
* Return printable value for history log macro
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param mixed $val - value to convert and return.
* @return string
*/
public static function get_history_log_val( $cf, $val ) {
ob_start();
self::print_val( $cf, $val );
return ob_get_clean();
}
/**
* Print dashboard activity function
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param array $recent_logs - recent_logs object.
* @param array $body - body object.
* @param int $view - check if frontend.
* @return string
*/
public static function print_activity( $cf, $recent_logs, $body, $view ) {
$url = WPSC_Functions::get_ticket_url( $recent_logs->ticket->id, $view );
$ms_values = explode( '|', $body->new );
foreach ( $ms_values as $ms_value ) {
$new_ms = new WPSC_Option( $ms_value );
if ( $new_ms->id ) {
$new_ms_values[] = esc_attr( $new_ms->name );
}
}
if ( ! empty( $new_ms_values ) ) {
$ms_names = implode( ', ', $new_ms_values );
} else {
$ms_names = 'None';
}
return esc_attr( $recent_logs->customer->name ) . ' updated the ' . esc_attr( $cf->name ) . ' value of #' . esc_attr( $recent_logs->ticket->id ) . ' to ' . esc_attr( $ms_names );
}
/**
* Return given value for custom field
*
* @param WPSC_Custom_Field $cf - custom field object.
* @param mixed $val - value to convert and print.
* @return string
*/
public static function get_field_value( $cf, $val ) {
$val = is_array( $val ) ? $val : array_filter( explode( '|', $val ) );
$options = array_filter(
array_map(
function ( $option ) {
if ( is_object( $option ) ) {
return $option;
} elseif ( $option ) {
$option = new WPSC_Option( $option );
return $option->id ? $option : '';
} else {
return '';
}
},
$val
)
);
$option_names = array_map( fn( $option ) => $option->name, $options );
return $option_names ? esc_attr( implode( ', ', $option_names ) ) : esc_attr__( 'None', 'supportcandy' );
}
/**
* Clear value of hidden fields
*
* @return void
*/
public static function js_clear_value_hidden_fields() {
?>
case '':
customField.find('select').first().val('');
break;