You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

925 lines
38 KiB
PHP

<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class AWSM_Job_Openings_Form {
private static $instance = null;
protected $cpath = null;
public $form_fields_order = array( 'awsm_applicant_name', 'awsm_applicant_email', 'awsm_applicant_phone', 'awsm_applicant_letter', 'awsm_file' );
public static $allowed_html = array(
'a' => array(
'href' => array(),
'title' => array(),
),
'br' => array(),
'em' => array(),
'span' => array(),
'strong' => array(),
'small' => array(),
);
public function __construct() {
$this->cpath = untrailingslashit( plugin_dir_path( __FILE__ ) );
add_action( 'awsm_application_form_init', array( $this, 'application_form' ) );
add_action( 'awsm_application_form_field_init', array( $this, 'form_field_init' ) );
add_action( 'awsm_application_form_field_init', array( $this, 'form_language_field' ), 100 );
add_action( 'awsm_job_application_submitting', array( $this, 'set_form_language' ) );
add_action( 'before_awsm_job_details', array( $this, 'insert_application' ) );
add_action( 'wp_ajax_awsm_applicant_form_submission', array( $this, 'ajax_handle' ) );
add_action( 'wp_ajax_nopriv_awsm_applicant_form_submission', array( $this, 'ajax_handle' ) );
add_filter( 'wp_check_filetype_and_ext', array( $this, 'check_filetype_and_ext' ), 10, 5 );
}
public static function init() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
public static function get_allowed_html() {
/**
* Filters the allowed HTML elements and attributes for the form.
*
* @since 3.0.0
*
* @param array|string $allowed_html An array of allowed HTML elements and attributes or a context name.
*/
return apply_filters( 'awsm_application_form_allowed_html', self::$allowed_html );
}
public function dynamic_form_fields( $form_attrs ) {
$allowed_file_types = get_option( 'awsm_jobs_admin_upload_file_ext' );
$allowed_file_content = '';
if ( is_array( $allowed_file_types ) && ! empty( $allowed_file_types ) ) {
$allowed_file_types = '.' . join( ', .', $allowed_file_types );
/* translators: %1$s: comma-separated list of allowed file types */
$allowed_file_content = '<small>' . sprintf( esc_html__( 'Allowed Type(s): %1$s', 'wp-job-openings' ), $allowed_file_types ) . '</small>';
}
$default_form_fields = array(
'awsm_applicant_name' => array(
'label' => __( 'Full Name', 'wp-job-openings' ),
'id' => 'awsm-applicant-name',
'class' => array( 'awsm-job-form-control' ),
),
'awsm_applicant_email' => array(
'label' => __( 'Email', 'wp-job-openings' ),
'field_type' => array(
'tag' => 'input',
'type' => 'email',
),
'id' => 'awsm-applicant-email',
'class' => array( 'awsm-job-form-control' ),
'error' => array(
'error_rule' => 'email',
'error_msg' => __( 'Please enter a valid email address.', 'wp-job-openings' ),
),
),
'awsm_applicant_phone' => array(
'label' => __( 'Phone', 'wp-job-openings' ),
'field_type' => array(
'tag' => 'input',
'type' => 'tel',
),
'id' => 'awsm-applicant-phone',
'class' => array( 'awsm-job-form-control' ),
'error' => array(
'error_msg' => __( 'Please enter a valid phone number.', 'wp-job-openings' ),
),
),
'awsm_applicant_letter' => array(
'label' => __( 'Cover Letter', 'wp-job-openings' ),
'field_type' => array(
'tag' => 'textarea',
),
'id' => 'awsm-cover-letter',
'class' => array( 'awsm-job-form-control' ),
),
'awsm_file' => array(
'label' => __( 'Upload CV/Resume', 'wp-job-openings' ),
'field_type' => array(
'tag' => 'input',
'type' => 'file',
'accept' => $allowed_file_types,
),
'id' => 'awsm-application-file',
'class' => array( 'awsm-resume-file-control', 'awsm-job-form-control', 'awsm-form-file-control' ),
'content' => $allowed_file_content,
),
);
/**
* Filters the job application form fields.
*
* @since 1.0.0
* @since 2.2.1 The `$form_attrs` parameter was added.
*
* @param array $form_fields Form fields array.
* @param array $form_attrs Attributes array for the form.
*/
$form_fields = apply_filters( 'awsm_application_form_fields', $default_form_fields, $form_attrs );
return $form_fields;
}
public function display_dynamic_fields( $form_attrs ) {
$dynamic_form_fields = $this->dynamic_form_fields( $form_attrs );
if ( ! empty( $dynamic_form_fields ) ) {
$ordered_form_fields = array();
/**
* Filters the job application form fields order.
*
* @since 1.2.0
* @since 2.2.1 The `$form_attrs` parameter was added.
*
* @param array $form_fields_order Form fields array.
* @param array $form_attrs Attributes array for the form.
*/
$form_fields_order = apply_filters( 'awsm_application_form_fields_order', $this->form_fields_order, $form_attrs );
foreach ( $form_fields_order as $form_field_order ) {
$ordered_form_fields[ $form_field_order ] = $dynamic_form_fields[ $form_field_order ];
}
$dynamic_form_fields = $ordered_form_fields;
$allowed_html = self::get_allowed_html();
$required_msg = esc_attr__( 'This field is required.', 'wp-job-openings' );
$form_output = '';
foreach ( $dynamic_form_fields as $field_name => $field_args ) {
$show_field = ( isset( $field_args['show_field'] ) ) ? $field_args['show_field'] : true;
if ( $show_field ) {
$label = ( isset( $field_args['label'] ) ) ? $field_args['label'] : '';
$tag = ( isset( $field_args['field_type'] ) ) ? ( ( isset( $field_args['field_type']['tag'] ) ) ? $field_args['field_type']['tag'] : 'input' ) : 'input';
$input_type = ( isset( $field_args['field_type'] ) ) ? ( ( isset( $field_args['field_type']['type'] ) ) ? $field_args['field_type']['type'] : 'text' ) : 'text';
$field_id = ( isset( $field_args['id'] ) ) ? $field_args['id'] : $field_name;
$field_class = 'awsm-job-form-field';
$field_class = ( isset( $field_args['class'] ) && is_array( $field_args['class'] ) ) ? $field_class . ' ' . join( ' ', $field_args['class'] ) : $field_class;
$required = ( isset( $field_args['required'] ) ) ? $field_args['required'] : true;
$required_attr = ( $required ) ? ' required' : '';
$data_required = ( $required ) ? ' data-msg-required="' . $required_msg . '"' : '';
$required_label = ( $required ) ? ' <span class="awsm-job-form-error">*</span>' : '';
$form_group_class = 'awsm-job-form-group';
$form_group_class = ( isset( $field_args['label_inline'] ) ) ? $form_group_class . ' awsm-job-inline-group' : $form_group_class;
$extra_content = ( isset( $field_args['content'] ) ) ? $field_args['content'] : '';
// Validation
$data_error_msg = ( isset( $field_args['error'] ) && ! empty( $field_args['error'] ) ) ? ( ( isset( $field_args['error']['error_msg'], $field_args['error']['error_rule'] ) && ! empty( $field_args['error']['error_msg'] ) && ! empty( $field_args['error']['error_rule'] ) ) ? ( ' data-rule-' . $field_args['error']['error_rule'] . '="true" data-msg-' . $field_args['error']['error_rule'] . '="' . esc_attr( $field_args['error']['error_msg'] ) . '"' ) : '' ) : '';
// Common attributes for tags
$common_attrs = sprintf( 'name="%1$s" class="%2$s" id="%3$s"%4$s', esc_attr( $field_name ), esc_attr( $field_class ), esc_attr( $field_id ), $required_attr . $data_required . $data_error_msg );
if ( $input_type === 'file' ) {
$common_attrs .= isset( $field_args['field_type']['accept'] ) ? sprintf( ' accept="%s"', esc_attr( $field_args['field_type']['accept'] ) ) : '';
} else {
if ( $tag !== 'textarea' && $tag !== 'select' ) {
$common_attrs .= isset( $field_args['field_type']['value'] ) ? sprintf( ' value="%s"', esc_attr( $field_args['field_type']['value'] ) ) : '';
}
}
$field_content = $label_content = ''; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
if ( ! empty( $label ) ) {
$label_content = sprintf( '<label for="%2$s">%1$s</label>', wp_kses( $label, $allowed_html ) . $required_label, esc_attr( $field_id ) );
}
if ( $tag === 'input' || $tag === 'select' ) {
if ( $tag === 'select' || $input_type === 'checkbox' || $input_type === 'radio' ) {
$options = isset( $field_args['field_type']['options'] ) ? $field_args['field_type']['options'] : '';
if ( ! empty( $options ) && is_array( $options ) ) {
$options_content = '';
if ( $tag === 'select' ) {
if ( ! $required ) {
$options_content .= sprintf( '<option value="">%s</option>', esc_html__( '--Please Choose an Option--', 'wp-job-openings' ) );
}
foreach ( $options as $option ) {
$options_content .= sprintf( '<option value="%s">%s</option>', esc_attr( $option ), esc_html( $option ) );
}
$field_content .= sprintf( '<select %2$s>%1$s</select>', $options_content, $common_attrs );
} else {
$id_suffix = 1;
foreach ( $options as $option ) {
$name_suffix = ( $input_type === 'checkbox' ) ? '[]' : '';
$current_field_id = esc_attr( $field_id . '_' . $id_suffix );
$common_attrs = sprintf( 'name="%1$s" class="%2$s" id="%3$s"%4$s', esc_attr( $field_name . $name_suffix ), esc_attr( $field_class ), $current_field_id, $required_attr . $data_required . $data_error_msg );
$options_content .= sprintf( '<span><input type="%s" value="%s" %s /> <label for="%s">%s</label></span>', esc_attr( $input_type ), esc_attr( $option ), $common_attrs, $current_field_id, esc_html( $option ) );
$id_suffix ++;
}
$field_content .= sprintf( '<div class="awsm-job-form-options-container">%s</div>', $options_content );
}
}
} else {
$field_content .= sprintf( '<input type="%1$s" %2$s />', esc_attr( $input_type ), $common_attrs );
}
} elseif ( $tag === 'textarea' ) {
$field_content .= sprintf( '<textarea %1$s rows="5" cols="50"></textarea>', $common_attrs );
}
if ( isset( $field_args['label_inline'] ) && $field_args['label_inline'] === 'right' ) {
$field_content .= $label_content;
} else {
$field_content = $label_content . $field_content;
}
$field_type = $tag === 'input' ? $input_type : $tag;
/**
* Filters the field content of a specific field type of the job application form.
*
* @since 2.0.0
* @since 2.2.1 The `$form_attrs` parameter was added.
*
* @param string $field_content The content.
* @param array $field_args Form field options.
* @param array $form_attrs Attributes array for the form.
*/
$field_content = apply_filters( "awsm_application_dynamic_form_{$field_type}_field_content", $field_content, $field_args, $form_attrs );
$field_output = sprintf( '<div class="%2$s">%1$s</div>', $field_content . wp_kses( $extra_content, $allowed_html ), esc_attr( $form_group_class ) );
/**
* Filters the form field content of the job application form.
*
* @since 2.0.0
* @since 2.2.1 The `$form_attrs` parameter was added.
*
* @param string $field_output The content.
* @param string $field_type The field type.
* @param array $field_args Form field options.
* @param array $form_attrs Attributes array for the form.
*/
$form_output .= apply_filters( 'awsm_application_dynamic_form_field_content', $field_output, $field_type, $field_args, $form_attrs );
}
}
/**
* Filters the dynamic form fields content of the job application form.
*
* @since 1.3.0
* @since 2.2.1 The `$form_attrs` parameter was added.
*
* @param string $form_output The content.
* @param array $dynamic_form_fields Dynamic form fields.
* @param array $form_attrs Attributes array for the form.
*/
echo apply_filters( 'awsm_application_dynamic_form_fields_content', $form_output, $dynamic_form_fields, $form_attrs ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
public function get_gdpr_field_label() {
$gdpr_enable = get_option( 'awsm_enable_gdpr_cb' );
$gdpr_cb_text = get_option( 'awsm_gdpr_cb_text' );
if ( ! empty( $gdpr_enable ) && ! empty( $gdpr_cb_text ) ) {
return $gdpr_cb_text;
} else {
return false;
}
}
public function display_gdpr_field( $form_attrs ) {
$label = $this->get_gdpr_field_label();
if ( ! empty( $label ) ) {
$field_id = $form_attrs['single_form'] ? 'awsm_form_privacy_policy' : esc_attr( 'awsm_form_privacy_policy-' . $form_attrs['job_id'] );
$field_content = sprintf( '<div class="awsm-job-form-group awsm-job-inline-group"><input name="awsm_form_privacy_policy" class="awsm-job-form-field" id="%1$s" value="yes" type="checkbox" data-msg-required="%3$s" aria-required="true" required><label for="%1$s">%2$s <span class="awsm-job-form-error">*</span></label></div>', esc_attr( $field_id ), wp_kses( $label, self::get_allowed_html() ), esc_attr__( 'This field is required.', 'wp-job-openings' ) );
/**
* Filters the privacy policy checkbox field content.
*
* @since 3.0.0
*
* @param string $field_content Field HTML content.
* @param array $form_attrs Attributes array for the form.
*/
echo apply_filters( 'awsm_application_form_gdpr_field_content', $field_content, $form_attrs ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
public function display_recaptcha_field( $form_attrs ) {
if ( $this->is_recaptcha_set() ) :
/**
* Filters the reCAPTCHA visibility in the application form.
*
* @since 2.2.0
* @since 2.2.1 The `$form_attrs` parameter was added.
*
* @param bool $is_visible Whether the reCAPTCHA is visible or not in the form.
* @param array $form_attrs Attributes array for the form.
*/
$is_visible = apply_filters( 'awsm_application_form_is_recaptcha_visible', true, $form_attrs );
if ( $is_visible ) :
$site_key = get_option( 'awsm_jobs_recaptcha_site_key' );
$fallback_url = add_query_arg( 'k', $site_key, 'https://www.google.com/recaptcha/api/fallback' );
?>
<div class="awsm-job-form-group awsm-job-g-recaptcha-group">
<div class="g-recaptcha" data-sitekey="<?php echo esc_attr( $site_key ); ?>"></div>
<noscript>
<div style="width: 302px; height: 422px; position: relative;">
<div style="width: 302px; height: 422px; position: absolute;">
<iframe src="<?php echo esc_url( $fallback_url ); ?>" frameborder="0" scrolling="no" style="width: 302px; height:422px; border-style: none;"></iframe>
</div>
<div style="width: 300px; height: 60px; border-style: none; bottom: 12px; left: 25px; margin: 0px; padding: 0px; right: 25px; background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;">
<textarea id="g-recaptcha-response" name="g-recaptcha-response" class="g-recaptcha-response" style="width: 250px; height: 40px; border: 1px solid #c1c1c1; margin: 10px 25px; padding: 0px; resize: none;" ></textarea>
</div>
</div>
</noscript>
</div>
<?php
endif;
endif;
}
public function application_form() {
$form_attrs = array(
'single_form' => true,
'job_id' => get_the_ID(),
);
include AWSM_Job_Openings::get_template_path( 'form.php', 'single-job' );
}
public function form_field_init( $form_attrs ) {
$this->display_dynamic_fields( $form_attrs );
$this->display_gdpr_field( $form_attrs );
$this->display_recaptcha_field( $form_attrs );
}
public function check_filetype_and_ext( $wp_filetype, $file, $filename, $mimes, $real_mime = '' ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( ! empty( $real_mime ) && isset( $_POST['action'] ) && $_POST['action'] === 'awsm_applicant_form_submission' && empty( $wp_filetype['type'] ) && ! empty( $mimes ) ) {
$filetype = wp_check_filetype( $filename, $mimes );
// fix issue with application/vnd.openxmlformats-officedocument.* mime types in some PHP versions.
$extensions = array( 'docx', 'dotx', 'xlsx', 'xltx', 'pptx', 'ppsx', 'potx', 'sldx' );
if ( $filetype['ext'] && in_array( $filetype['ext'], $extensions, true ) && $real_mime === $filetype['type'] . $filetype['type'] ) {
$wp_filetype['ext'] = $filetype['ext'];
$wp_filetype['type'] = $filetype['type'];
}
}
return $wp_filetype;
}
public function upload_dir( $param ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( isset( $_POST['action'] ) && $_POST['action'] === 'awsm_applicant_form_submission' ) {
$subdir = '/' . AWSM_JOBS_UPLOAD_DIR_NAME;
if ( empty( $param['subdir'] ) ) {
$param['path'] = $param['path'] . $subdir;
$param['url'] = $param['url'] . $subdir;
$param['subdir'] = $subdir;
} else {
$subdir .= $param['subdir'];
$param['path'] = str_replace( $param['subdir'], $subdir, $param['path'] );
$param['url'] = str_replace( $param['subdir'], $subdir, $param['url'] );
$param['subdir'] = str_replace( $param['subdir'], $subdir, $param['subdir'] );
}
}
return $param;
}
public function hashed_file_name( $dir, $name, $ext ) {
$file_name = hash( 'sha1', ( $name . uniqid( (string) rand(), true ) ) ) . time();
return sanitize_file_name( $file_name . $ext );
}
public function form_language_field() {
$current_lang = AWSM_Job_Openings::get_current_language();
if ( ! empty( $current_lang ) ) {
printf( '<input type="hidden" name="lang" value="%s">', esc_attr( $current_lang ) );
}
}
public function set_form_language() {
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( isset( $_POST['lang'] ) ) {
AWSM_Job_Openings::set_current_language( $_POST['lang'] );
}
// phpcs:enable
}
public function insert_application() {
// phpcs:disable WordPress.Security.NonceVerification.Missing
global $awsm_response;
$awsm_response = array(
'success' => array(),
'error' => array(),
);
if ( $_SERVER['REQUEST_METHOD'] === 'POST' && ! empty( $_POST['action'] ) && $_POST['action'] === 'awsm_applicant_form_submission' ) {
$job_id = intval( $_POST['awsm_job_id'] );
$applicant_name = sanitize_text_field( wp_unslash( $_POST['awsm_applicant_name'] ) );
$applicant_email = sanitize_email( wp_unslash( $_POST['awsm_applicant_email'] ) );
$applicant_phone = sanitize_text_field( wp_unslash( $_POST['awsm_applicant_phone'] ) );
$applicant_letter = awsm_jobs_sanitize_textarea( wp_unslash( $_POST['awsm_applicant_letter'] ) );
$attachment = isset( $_FILES['awsm_file'] ) ? $_FILES['awsm_file'] : '';
$agree_privacy_policy = false;
$generic_err_msg = esc_html__( 'Error in submitting your application. Please refresh the page and retry.', 'wp-job-openings' );
if ( $this->is_recaptcha_set() ) {
$is_human = false;
if ( isset( $_POST['g-recaptcha-response'] ) ) {
$is_human = $this->validate_captcha_field( $_POST['g-recaptcha-response'] );
}
if ( ! $is_human ) {
$awsm_response['error'][] = esc_html__( 'Please verify that you are not a robot.', 'wp-job-openings' );
}
}
if ( $this->get_gdpr_field_label() !== false ) {
if ( ! isset( $_POST['awsm_form_privacy_policy'] ) || $_POST['awsm_form_privacy_policy'] !== 'yes' ) {
$awsm_response['error'][] = esc_html__( 'Please agree to our privacy policy.', 'wp-job-openings' );
} else {
$agree_privacy_policy = sanitize_text_field( $_POST['awsm_form_privacy_policy'] );
}
}
if ( get_post_type( $job_id ) !== 'awsm_job_openings' ) {
$awsm_response['error'][] = esc_html__( 'Error occurred: Invalid Job.', 'wp-job-openings' );
}
if ( get_post_status( $job_id ) === 'expired' ) {
$awsm_response['error'][] = esc_html__( 'Sorry! This job has expired.', 'wp-job-openings' );
}
if ( empty( $applicant_name ) ) {
$awsm_response['error'][] = esc_html__( 'Name is required.', 'wp-job-openings' );
}
if ( empty( $applicant_email ) ) {
$awsm_response['error'][] = esc_html__( 'Email is required.', 'wp-job-openings' );
} else {
if ( ! filter_var( $applicant_email, FILTER_VALIDATE_EMAIL ) ) {
$awsm_response['error'][] = esc_html__( 'Invalid email format.', 'wp-job-openings' );
}
}
if ( empty( $applicant_phone ) ) {
$awsm_response['error'][] = esc_html__( 'Contact number is required.', 'wp-job-openings' );
} else {
if ( ! preg_match( '%^[+]?[0-9()/ -]*$%', trim( $applicant_phone ) ) ) {
$awsm_response['error'][] = esc_html__( 'Invalid phone number.', 'wp-job-openings' );
}
}
if ( empty( $applicant_letter ) ) {
$awsm_response['error'][] = esc_html__( 'Cover Letter cannot be empty.', 'wp-job-openings' );
}
if ( empty( $attachment ) || ! isset( $attachment['error'] ) || $attachment['error'] > 0 ) {
$awsm_response['error'][] = esc_html__( 'Please select your cv/resume.', 'wp-job-openings' );
}
/**
* Fires before job application submission
*
* @since 1.2
*/
do_action( 'awsm_job_application_submitting' );
if ( count( $awsm_response['error'] ) === 0 ) {
if ( ! function_exists( 'wp_handle_upload' ) ) {
include ABSPATH . 'wp-admin/includes/file.php';
}
if ( ! function_exists( 'wp_crop_image' ) ) {
include ABSPATH . 'wp-admin/includes/image.php';
}
$mimes = array();
$allowed_mime_types = get_allowed_mime_types();
$alowed_types = get_option( 'awsm_jobs_admin_upload_file_ext' );
foreach ( $alowed_types as $allowed_type ) {
if ( isset( $allowed_mime_types[ $allowed_type ] ) ) {
$mimes[ $allowed_type ] = $allowed_mime_types[ $allowed_type ];
}
}
$override = array(
'test_form' => false,
'mimes' => $mimes,
'unique_filename_callback' => array( $this, 'hashed_file_name' ),
);
add_filter( 'upload_dir', array( $this, 'upload_dir' ) );
$movefile = wp_handle_upload( $attachment, $override );
remove_filter( 'upload_dir', array( $this, 'upload_dir' ) );
if ( $movefile && ! isset( $movefile['error'] ) ) {
$post_base_data = array(
'post_title' => $applicant_name,
'post_content' => '',
'post_status' => 'publish',
'comment_status' => 'closed',
);
$application_data = array_merge(
$post_base_data,
array(
'post_type' => 'awsm_job_application',
'post_parent' => $job_id,
)
);
$application_id = wp_insert_post( $application_data, true );
if ( ! is_wp_error( $application_id ) ) {
$attachment_data = array_merge(
$post_base_data,
array(
'post_mime_type' => $movefile['type'],
'guid' => $movefile['url'],
)
);
$attach_id = wp_insert_attachment( $attachment_data, $movefile['file'], $application_id, true );
if ( ! is_wp_error( $attach_id ) ) {
$attach_data = wp_generate_attachment_metadata( $attach_id, $movefile['file'] );
wp_update_attachment_metadata( $attach_id, $attach_data );
$applicant_details = array(
'awsm_job_id' => $job_id,
'awsm_apply_for' => esc_html( get_the_title( $job_id ) ),
'awsm_applicant_ip' => isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : '',
'awsm_applicant_name' => $applicant_name,
'awsm_applicant_email' => $applicant_email,
'awsm_applicant_phone' => $applicant_phone,
'awsm_applicant_letter' => $applicant_letter,
'awsm_attachment_id' => $attach_id,
);
if ( ! empty( $agree_privacy_policy ) ) {
$applicant_details['awsm_agree_privacy_policy'] = $agree_privacy_policy;
}
foreach ( $applicant_details as $meta_key => $meta_value ) {
update_post_meta( $application_id, $meta_key, $meta_value );
}
// Now, send notification email
$applicant_details['application_id'] = $application_id;
$this->notification_email( $applicant_details );
$awsm_response['success'][] = esc_html__( 'Your application has been submitted.', 'wp-job-openings' );
/**
* Fires after successful job application submission
*
* @since 1.2
*
* @param int $application_id Application ID
*/
do_action( 'awsm_job_application_submitted', $application_id );
} else {
AWSM_Job_Openings::log( $attach_id );
$awsm_response['error'][] = $generic_err_msg;
}
} else {
AWSM_Job_Openings::log( $application_id );
$awsm_response['error'][] = $generic_err_msg;
}
} else {
AWSM_Job_Openings::log( $movefile );
$awsm_response['error'][] = $movefile['error'];
}
}
add_action( 'awsm_application_form_notices', array( $this, 'awsm_form_submit_notices' ) );
}
return $awsm_response;
// phpcs:enable
}
public function is_recaptcha_set() {
$is_set = false;
$enable_recaptcha = get_option( 'awsm_jobs_enable_recaptcha' );
$site_key = get_option( 'awsm_jobs_recaptcha_site_key' );
$secret_key = get_option( 'awsm_jobs_recaptcha_secret_key' );
if ( $enable_recaptcha === 'enable' && ! empty( $site_key ) && ! empty( $secret_key ) ) {
$is_set = true;
}
return $is_set;
}
public function get_recaptcha_response( $token ) {
$result = array();
$secret_key = get_option( 'awsm_jobs_recaptcha_secret_key' );
$response = wp_safe_remote_post(
'https://www.google.com/recaptcha/api/siteverify',
array(
'body' => array(
'secret' => $secret_key,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'],
),
)
);
if ( ! is_wp_error( $response ) ) {
$response_body = wp_remote_retrieve_body( $response );
if ( '' !== $response_body ) {
if ( wp_remote_retrieve_response_code( $response ) === 200 ) {
$result = json_decode( $response_body, true );
}
}
}
return $result;
}
public function validate_captcha_field( $token ) {
$is_valid = false;
if ( ! empty( $token ) ) {
$result = $this->get_recaptcha_response( $token );
if ( ! empty( $result ) ) {
$is_valid = isset( $result['success'] ) && $result['success'] === true;
}
}
return $is_valid;
}
public function ajax_handle() {
$response = $this->insert_application();
wp_send_json( $response );
}
public function awsm_form_submit_notices() {
global $awsm_response;
$msg_array = array();
$class_name = 'awsm-default-message';
$content = '';
if ( ! empty( $awsm_response['success'] ) ) {
$msg_array = $awsm_response['success'];
$class_name = 'awsm-success-message';
} else {
if ( ! empty( $awsm_response['error'] ) ) {
$msg_array = $awsm_response['error'];
$class_name = 'awsm-error-message';
$content .= '<p>' . esc_html__( 'The following errors have occurred:', 'wp-job-openings' ) . '</p>';
}
}
foreach ( $msg_array as $msg ) {
$content .= '<li>' . esc_html( $msg ) . '</li>';
}
printf( '<ul class="%1$s">%2$s</ul>', esc_attr( $class_name ), $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
public function get_mail_template_tags( $applicant_details, $options = array() ) {
$job_expiry = get_post_meta( $applicant_details['awsm_job_id'], 'awsm_job_expiry', true );
$job_expiry = ( ! empty( $job_expiry ) ) ? date_i18n( get_awsm_jobs_date_format( 'expiry-mail' ), strtotime( $job_expiry ) ) : '';
$attachment_url = isset( $applicant_details['awsm_attachment_id'] ) ? wp_get_attachment_url( $applicant_details['awsm_attachment_id'] ) : '';
if ( ! empty( $attachment_url ) && get_option( 'awsm_hide_uploaded_files' ) === 'hide_files' ) {
$attachment_url = AWSM_Job_Openings::get_application_edit_link( $applicant_details['application_id'] );
}
$tags = array(
'{applicant}' => $applicant_details['awsm_applicant_name'],
'{application-id}' => $applicant_details['application_id'],
'{applicant-email}' => $applicant_details['awsm_applicant_email'],
'{applicant-phone}' => isset( $applicant_details['awsm_applicant_phone'] ) ? $applicant_details['awsm_applicant_phone'] : '',
'{job-id}' => $applicant_details['awsm_job_id'],
'{job-expiry}' => $job_expiry,
'{job-title}' => $applicant_details['awsm_apply_for'],
'{applicant-cover}' => isset( $applicant_details['awsm_applicant_letter'] ) ? nl2br( $applicant_details['awsm_applicant_letter'] ) : '',
'{applicant-resume}' => ( ! empty( $attachment_url ) ) ? esc_url( $attachment_url ) : '',
);
$tags = array_merge( $tags, AWSM_Job_Openings::get_mail_generic_template_tags( $options ) );
/**
* Filters the mail template tags.
*
* @since 1.4
*
* @param array $tags Mail template tags
* @param array $applicant_details Applicant Details
* @param array $options Settings values
*/
return apply_filters( 'awsm_jobs_mail_template_tags', $tags, $applicant_details, $options );
}
/**
* Get the notification options.
*
* @since 3.0.0
*
* @param string $type Notification type - applicant or admin
* @return array
*/
public static function get_notification_options( $type ) {
$options = array();
$admin_email = get_option( 'admin_email' );
$hr_email = get_option( 'awsm_hr_email_address' );
if ( $type === 'applicant' ) {
$options = array(
'acknowledgement' => get_option( 'awsm_jobs_acknowledgement' ),
'from' => get_option( 'awsm_jobs_from_email_notification', $admin_email ),
'reply_to' => get_option( 'awsm_jobs_reply_to_notification' ),
'cc' => get_option( 'awsm_jobs_hr_notification', $hr_email ),
'subject' => get_option( 'awsm_jobs_notification_subject', '' ),
'content' => get_option( 'awsm_jobs_notification_content', '' ),
'html_template' => get_option( 'awsm_jobs_notification_mail_template' ),
);
} elseif ( $type === 'admin' ) {
$options = array(
'enable' => get_option( 'awsm_jobs_enable_admin_notification' ),
'from' => get_option( 'awsm_jobs_admin_from_email_notification', $admin_email ),
'reply_to' => get_option( 'awsm_jobs_admin_reply_to_notification', '{applicant-email}' ),
'to' => get_option( 'awsm_jobs_admin_to_notification', $hr_email ),
'cc' => get_option( 'awsm_jobs_admin_hr_notification' ),
'subject' => get_option( 'awsm_jobs_admin_notification_subject', '' ),
'content' => get_option( 'awsm_jobs_admin_notification_content', '' ),
'html_template' => get_option( 'awsm_jobs_notification_admin_mail_template' ),
);
}
return $options;
}
/**
* Handle applicant and admin notification emails.
*
* @since 3.0.0 The `$data` parameter was added.
*
* @param array $applicant_details Applicant details.
* @param array $data Notification data if provided will override the default.
*/
protected function notification_email( $applicant_details, $data = array() ) {
/**
* Filters the default notifications types - applicant or admin.
*
* @since 3.2.0
*
* @param array $types Notification types.
* @param array $applicant_details Applicant details.
* @param array $data Notification data.
*/
$types = apply_filters(
'awsm_jobs_default_notifications_types',
array( 'applicant', 'admin' ),
$applicant_details,
$data
);
foreach ( $types as $type ) {
if ( ! isset( $data[ $type ] ) ) {
$data[ $type ] = self::get_notification_options( $type );
}
$options = $data[ $type ];
// Check if the notification is enabled or not.
$enable = false;
if ( $type === 'applicant' ) {
$enable = $options['acknowledgement'] === 'acknowledgement';
} elseif ( $type === 'admin' ) {
$enable = $options['enable'] === 'enable';
}
if ( $enable ) {
$admin_email = get_option( 'admin_email' );
$hr_mail = get_option( 'awsm_hr_email_address' );
$applicant_email = $applicant_details['awsm_applicant_email'];
$company_name = get_option( 'awsm_job_company_name' );
$from = ( ! empty( $company_name ) ) ? $company_name : get_option( 'blogname' );
$tags = $this->get_mail_template_tags(
$applicant_details,
array(
'admin_email' => $admin_email,
'hr_email' => $hr_mail,
'company_name' => $company_name,
)
);
$tag_names = array_keys( $tags );
$tag_values = array_values( $tags );
$email_tag_names = array( '{admin-email}', '{hr-email}', '{applicant-email}' );
$email_tag_values = array( $admin_email, $hr_mail, $applicant_email );
if ( ! empty( $options['subject'] ) && ! empty( $options['content'] ) ) {
$subject = str_replace( $tag_names, $tag_values, $options['subject'] );
$reply_to = str_replace( $email_tag_names, $email_tag_values, $options['reply_to'] );
$cc = str_replace( $email_tag_names, $email_tag_values, $options['cc'] );
/**
* Filters the applicant or admin notification mail headers.
*
* @since 1.4
*
* @param array $headers Additional headers.
* @param array $applicant_details Applicant details.
*/
$headers = apply_filters(
"awsm_jobs_{$type}_notification_mail_headers",
array(
'content_type' => 'Content-Type: text/html; charset=UTF-8',
'from' => sprintf( 'From: %1$s <%2$s>', $from, $options['from'] ),
'reply_to' => 'Reply-To: ' . $reply_to,
'cc' => 'Cc: ' . $cc,
),
$applicant_details
);
$reply_to = trim( str_replace( 'Reply-To:', '', $headers['reply_to'] ) );
if ( empty( $reply_to ) ) {
unset( $headers['reply_to'] );
}
$mail_cc = trim( str_replace( 'Cc:', '', $headers['cc'] ) );
if ( empty( $mail_cc ) ) {
unset( $headers['cc'] );
}
/**
* Filters the applicant or admin notification mail attachments.
*
* @since 1.4
*
* @param array $attachments Mail attachments.
* @param array $applicant_details Applicant details.
*/
$attachments = apply_filters( "awsm_jobs_{$type}_notification_mail_attachments", array(), $applicant_details );
$admin_attachments = $attachments;
if ( $type === 'admin' ) {
$attachments = ! empty( $attachments ) ? wp_list_pluck( $attachments, 'file' ) : array();
}
$mail_content = nl2br( AWSM_Job_Openings_Mail_Customizer::sanitize_content( $options['content'] ) );
if ( $options['html_template'] === 'enable' ) {
// Header mail template.
ob_start();
include AWSM_Job_Openings::get_template_path( 'header.php', 'mail' );
$header_template = ob_get_clean();
$header_template .= '<div style="padding: 0 15px; font-size: 16px; max-width: 512px; margin: 0 auto;">';
// Footer mail template.
ob_start();
include AWSM_Job_Openings::get_template_path( 'footer.php', 'mail' );
$footer_template = ob_get_clean();
$footer_template = '</div>' . $footer_template;
$template = $header_template . $mail_content . $footer_template;
/**
* Filters the applicant or admin notification mail template.
*
* @since 2.0.0
*
* @param string $template Mail template.
* @param array $template_data Mail template data.
* @param array $applicant_details Applicant details.
*/
$mail_content = apply_filters(
"awsm_jobs_{$type}_notification_mail_template",
$template,
array(
'header' => $header_template,
'main' => $mail_content,
'footer' => $footer_template,
),
$applicant_details
);
} else {
// Basic mail template.
ob_start();
include AWSM_Job_Openings::get_template_path( 'basic.php', 'mail' );
$basic_template = ob_get_clean();
$mail_content = str_replace( '{mail-content}', $mail_content, $basic_template );
}
$tag_names[] = '{mail-subject}';
$tag_values[] = $subject;
$mail_content = str_replace( $tag_names, $tag_values, $mail_content );
$to = $applicant_email;
if ( $type !== 'applicant' ) {
$to = str_replace( $email_tag_names, $email_tag_values, $options['to'] );
}
AWSM_Job_Openings::log(
array(
'to' => $to,
'subject' => $subject,
'mail_content' => $mail_content,
'headers' => $headers,
'attachments' => $attachments,
)
);
add_filter( 'wp_mail_content_type', 'awsm_jobs_mail_content_type' );
// Now, send the mail.
$is_mail_send = wp_mail( $to, $subject, $mail_content, array_values( $headers ), $attachments );
remove_filter( 'wp_mail_content_type', 'awsm_jobs_mail_content_type' );
if ( $is_mail_send ) {
if ( $type === 'applicant' ) {
// Save the applicant notification details.
$current_time = current_time( 'mysql' );
$mails_data = array(
array(
'send_by' => 0,
'mail_date' => $current_time,
'cc' => $cc,
'subject' => $subject,
'mail_content' => str_replace( $tag_names, $tag_values, nl2br( $options['content'] ) ),
),
);
update_post_meta( $applicant_details['application_id'], 'awsm_application_mails', $mails_data );
} elseif ( $type === 'admin' ) {
// Remove the admin notification attachments after the mail is sent (requires a specific structure for each attachment).
if ( ! empty( $admin_attachments ) ) {
foreach ( $admin_attachments as $admin_attachment ) {
if ( isset( $admin_attachment['temp'] ) && $admin_attachment['temp'] === true ) {
unlink( $admin_attachment['file'] );
}
}
}
}
/**
* Fires when applicant or admin notification mail is successfully sent.
*
* @since 1.4
*
* @param array $applicant_details Applicant details.
*/
do_action( "awsm_job_{$type}_mail_sent", $applicant_details );
} else {
/**
* Fires when applicant or admin notification mail is failed to send.
*
* @since 1.4
*
* @param array $applicant_details Applicant details.
*/
do_action( "awsm_job_{$type}_mail_failed", $applicant_details );
}
}
}
}
}
}