'' . esc_html__('View Changelogs', 'themify') . ''
);
return array_merge($links, $row_meta);
}
return (array)$links;
}
public static function action_links(array $links):array{
if (is_plugin_active('themify-updater/themify-updater.php')) {
$tlinks = array(
'' . __('Themify License', 'themify') . '',
);
} else {
$tlinks = array(
'' . __('Themify Updater', 'themify') . '',
);
}
return array_merge($links, $tlinks);
}
public static function i18n(){
load_plugin_textdomain( 'builder-contact', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
self::create_post_type();
}
public static function register_module() {
$dir=trailingslashit(plugin_dir_path(__FILE__));
if(method_exists('Themify_Builder_Model', 'add_module')){
Themify_Builder_Model::add_module($dir . 'modules/module-contact.php' );
}
else{
Themify_Builder_Model::register_directory('templates', $dir . 'templates');
Themify_Builder_Model::register_directory('modules', $dir . 'modules');
}
}
/**
* Retrieve saved settings for a module
*
* @deprecated since Builder v7, @2024
* @return array
*/
private static function get_element_settings( $post_id, $element_id ) : array {
global $ThemifyBuilder;
$data = $ThemifyBuilder->get_flat_modules_list( $post_id );
if ( ! empty( $data ) ) {
foreach ( $data as $module ) {
if ( isset( $module['element_id'], $module['mod_settings'] ) && $module['element_id'] === $element_id ) {
return $module['mod_settings'];
}
}
}
return [];
}
public static function contact_get_nonce() {
wp_send_json_success( array( 'nonce' => wp_create_nonce( 'builder_contact_send' ) ) );
}
public static function contact_send() {
if ( ! isset( $_POST['post_id'], $_POST['element_id'] ) ) {
return;
}
// CSRF protection: verify nonce
if ( ! isset( $_POST['bc_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['bc_nonce'] ) ), 'builder_contact_send' ) ) {
wp_send_json_error( array( 'error' => __( 'Security check failed. Please reload the page and try again.', 'builder-contact' ) ) );
return;
}
global $post;
$post = get_post((int) $_POST['orig_id']);
if ( $post ) {
setup_postdata( $post );
}
$post_id = (int) $_POST['post_id'];
$element_id = sanitize_text_field( $_POST['element_id'] );
if ( method_exists( 'Themify_Builder_Component_Module', 'get_element_settings' ) ) { /* v7 */
$module_settings = Themify_Builder_Component_Module::get_element_settings( $post_id, $element_id );
} else {
$module_settings = self::get_element_settings( $post_id, $element_id );
}
// WPML translates the TBP template post to a language-specific stub post that
// carries no builder data of its own — the data lives on the original-language
// template post. When the lookup above returns empty, resolve the original post
// via the wpml_object_id filter and retry once.
if ( empty( $module_settings ) && defined( 'ICL_SITEPRESS_VERSION' ) ) {
$original_post_id = apply_filters( 'wpml_object_id', $post_id, get_post_type( $post_id ), true, apply_filters( 'wpml_default_language', null ) );
if ( $original_post_id && $original_post_id !== $post_id ) {
if ( method_exists( 'Themify_Builder_Component_Module', 'get_element_settings' ) ) {
$module_settings = Themify_Builder_Component_Module::get_element_settings( $original_post_id, $element_id );
} else {
$module_settings = self::get_element_settings( $original_post_id, $element_id );
}
}
}
if ( empty( $module_settings ) ) {
wp_send_json_error( array( 'error' => __( 'Form configuration could not be loaded. Please reload the page and try again.', 'builder-contact' ) ) );
return;
}
/* parse Dynamic Content on the module if applicable */
if ( is_callable( [ 'Tbp_Dynamic_Content', 'do_replace' ] ) ) {
$module_settings = Tbp_Dynamic_Content::do_replace( $module_settings );
}
$module_settings+= array(
'mail_contact' => get_option('admin_email'),
'specify_from_address' => '',
'specify_email_address' => '',
'bcc_mail_contact' => '',
'bcc_mail' => '',
'default_subject' => '',
'success_url' => '',
'post_type' => '',
'post_author' => '',
'success_message_text' => __('Message sent. Thank you.', 'builder-contact'),
'contact_sent_from' => 'enable',
'field_sendcopy_subject' => '',
'field_name_active' => 'yes',
'field_name_require' => 'yes',
'field_email_active' => 'yes',
'field_email_require' => 'yes',
'field_subject_active' => 'yes',
'field_subject_require' => 'yes',
'field_message_active'=>'yes',
'field_message_require'=>'',
'field_captcha_active' => '',
'field_sendcopy_active' => '',
'field_optin_active' => '',
'auto_respond' => '',
'auto_respond_subject' => __( 'Message sent. Thank you.', 'builder-contact' ),
'auto_respond_message' => '',
'user_role' => '',
'field_extra' => '{ "fields": [] }',
'custom_template' => 'off',
'include_name_mail' => '',
);
foreach ( array( 'name', 'email', 'subject', 'message' ) as $field ) {
if ( (isset($module_settings["field_{$field}_active"]) && $module_settings["field_{$field}_active"] === 'yes') && (isset($module_settings["field_{$field}_require"]) && $module_settings["field_{$field}_require"] === 'yes') ) {
if ( empty( $_POST["contact-{$field}"] ) ) {
wp_send_json_error( array( 'error' => __( 'Please fill in the required data.', 'builder-contact' ) ) );
}
}
}
$name = isset( $_POST['contact-name'] ) ? sanitize_text_field( stripslashes($_POST['contact-name']) ) : '';
$email = isset( $_POST['contact-email'] ) ? sanitize_email( $_POST['contact-email'] ) : '';
$subject = ! empty( $_POST['contact-subject'] ) ? sanitize_text_field( stripslashes($_POST['contact-subject']) ) : $module_settings['default_subject'];
if ( $module_settings['field_email_active'] === 'yes' && ! empty( $_POST['contact-email'] ) && ! is_email( $email ) ) {
wp_send_json_error( array( 'error' => __( 'Invalid Email address!', 'builder-contact' ) ) );
}
$extra_fields = is_string($module_settings['field_extra'])?json_decode( $module_settings['field_extra'], true ):$module_settings['field_extra'];
if ( ! is_array( $extra_fields ) || ! isset( $extra_fields['fields'] ) || ! is_array( $extra_fields['fields'] ) ) {
$extra_fields = array( 'fields' => array() );
}
// ensure "required" extra fields are submitted
foreach ( $extra_fields['fields'] as $key => $field ) {
if ( isset( $field['required'] ) && $field['required'] ) {
if (( $field['type'] === 'upload' && empty( $_FILES["field_extra_{$key}"] ) )|| ( $field['type'] !== 'upload' && empty( $_POST["field_extra_{$key}"] ) )) {
wp_send_json_error( array( 'error' => __( 'Please fill in the required data.', 'builder-contact' ) ) );
}
}
if ( $field['type'] === 'email' && ! empty( $_POST["field_extra_{$key}"] ) && ! sanitize_email( $_POST["field_extra_{$key}"] ) ) {
wp_send_json_error( array( 'error' => __( 'Invalid Email address is sent.', 'builder-contact' ) ) );
}
}
/* GDPR consent validation */
if ( isset( $module_settings['gdpr'] ) && $module_settings['gdpr'] === 'accept' ) {
if ( empty( $_POST['gdpr'] ) || $_POST['gdpr'] !== '1' ) {
wp_send_json_error( array( 'error' => __( 'You must accept the privacy policy to continue.', 'builder-contact' ) ) );
}
}
/* reCAPTCHA validation */
if ( $module_settings['field_captcha_active'] === 'yes' ) {
if ( ! method_exists( 'Themify_Builder_Model', 'get_captcha_field' ) ) {
wp_send_json_error( array( 'error' => __( 'Themify Builder update is required.', 'builder-contact' ) ) );
}
$provider = 'recaptcha';
if ( isset( $module_settings['captcha_provider'] ) && 'r' !== $module_settings['captcha_provider'] ) {
$provider = $module_settings['captcha_provider'] === 'h' ? 'hcaptcha' : $module_settings['captcha_provider'];
}
$response = null;
if ( $provider === 'recaptcha' && ! empty( $_POST['g-recaptcha-response'] ) ) {
$response = $_POST['g-recaptcha-response'];
} else if ( $provider === 'hcaptcha' && ! empty( $_POST['h-captcha-response'] ) ) {
$response = $_POST['h-captcha-response'];
} else if ( $provider === 'turnstile' && ! empty( $_POST['cf-turnstile-response'] ) ) {
$response = $_POST['cf-turnstile-response'];
}
if ( $response ) {
$result = Themify_Builder_Model::validate_captcha( $provider, $response );
if ( is_wp_error( $result ) ) {
wp_send_json_error( array( 'error' => $result->get_error_message() ) );
}
} else {
wp_send_json_error( array( 'error' => __( 'Empty Captcha response.', 'builder-contact' ) ) );
}
}
if(!isset($module_settings['send_to_admins']) || $module_settings['send_to_admins']==='true'){//old backward
if ( 'sr' === $module_settings['user_role'] ) {
// Index of the chosen recipient, posted by the radio/select field.
$selected_recipient = isset( $_POST['contact-recipients'] ) ? (int) $_POST['contact-recipients'] : 0;
if ( ! empty( $module_settings['sr'][ $selected_recipient ]['email'] ) ) {
$recipients = [ $module_settings['sr'][ $selected_recipient ]['email'] ];
} else {
// No valid recipient found, fall back to admin email.
$recipients = array( get_option( 'admin_email' ) );
}
}
elseif ( 'author' === $module_settings['user_role'] ) {
// orig_id is the actual viewed page; post_id may point to a builder template.
$author_id = get_post_field( 'post_author', (int) $_POST['orig_id'] );
$authors_email = get_the_author_meta( 'user_email', $author_id );
$recipients = ( is_email( $authors_email ) ) ? array( $authors_email ) : array( get_option( 'admin_email' ) );
}
elseif($module_settings['user_role']==='admin' || (isset($module_settings['send_to_admins']) && $module_settings['send_to_admins'] === 'true')) {
$recipients = array(get_option('admin_email'));
}
else{
$recipients = self::filter_valid_emails( array_map( 'trim', explode( ',', $module_settings['mail_contact'] ) ) );
}
}
else{
$recipients = self::filter_valid_emails( array_map( 'trim', explode( ',', $module_settings['mail_contact'] ) ) );
}
$recipients = self::filter_valid_emails( (array) $recipients );
if ( empty( $recipients ) ) {
$fallback_email = sanitize_email( (string) get_option( 'admin_email' ) );
if ( ! is_email( $fallback_email ) ) {
$fallback_email = self::get_site_from_email();
}
$recipients = array( $fallback_email );
}
// Current builder saves 'en'/'dis'; older data used 'true'/'enable'.
// Whitelist all known on-values so stale DB data doesn't activate a disabled toggle.
$toggle_on_values = [ 'en', 'enable', 'true' ];
$active_bcc = in_array( $module_settings['bcc_mail'], $toggle_on_values, true );
$active_specify_from_address = in_array( $module_settings['specify_from_address'], $toggle_on_values, true );
$active_post_type = in_array( $module_settings['post_type'], $toggle_on_values, true );
$bcc_recipients = self::filter_valid_emails( array_map( 'trim', explode( ',', $module_settings['bcc_mail_contact'] ) ) );
$specify_email_address = trim( $module_settings['specify_email_address'] );
$subject = apply_filters('builder_contact_subject', $subject);
if ( empty( $subject ) ) {
$subject = get_bloginfo( 'name' );
}
$headers = array();
$reply_to_email = '';
if ( '' !== $email ) {
$reply_to_email = $email;
}
// add the email address to message body
// Same on-value whitelist as the other toggle fields above.
$custom_template = in_array( $module_settings['custom_template'], $toggle_on_values, true );
$message = isset( $_POST['contact-message'] ) ? wpautop( sanitize_textarea_field( stripslashes($_POST['contact-message']) ) ) : '';
if ( isset( $_SERVER['HTTP_REFERER'] ) && $_SERVER['HTTP_REFERER'] != '' ) {
$referer = esc_url( wp_unslash( $_SERVER['HTTP_REFERER'] ) );
} else {
$referer = get_site_url();
}
if ( $custom_template ) {
$template_vars = array(
'%name%' => $name,
'%email%' => $email,
'%subject%' => $subject,
'%message%' => $message,
'%referer%' => $referer,
);
if ( empty( $module_settings['template'] ) ) {
$template = self::get_default_template();
} else {
// WP adds slashes on save; strip them, then convert newlines to
for HTML email.
$template = stripslashes( $module_settings['template'] );
$template = preg_replace( '/
\n/i', '
', $template );
$template = nl2br( $template, false );
}
} else {
$body = '';
if ( '' !== $name && '' === $email ) {
$body = __('From:', 'builder-contact') . ' ' . $name ;
} elseif ( '' === $name && '' !== $email ) {
$body .= __('From:', 'builder-contact') . ' '. ' <' . $email . '>' . "
" ;
} elseif ( '' !== $name && '' !== $email ) {
$body .= __('From:', 'builder-contact') . ' ' . $name . ' <' . $email . '>' . "
";
}
if ( 'enable' === $module_settings['include_name_mail'] ) {
$body .= "
" . __('Name:', 'builder-contact').' ' . $name .'
';
$body .= "" . __('Email:', 'builder-contact').' ' . $email .'
';
$body .= "" . __('Subject:', 'builder-contact').' ' . $subject .'
';
}
$body .= $message;
}
if ( ! empty( $module_settings['upload_dir'] ) ) {
$safe_dir = sanitize_file_name( basename( $module_settings['upload_dir'] ) );
if ( $safe_dir !== '' && $safe_dir === $module_settings['upload_dir'] ) {
self::$upload_dir = $safe_dir;
add_filter( 'upload_dir', [ __CLASS__, 'upload_dir' ] );
}
}
$uploaded_files_path = $uploaded_files_url = array();
$extra_field_values = array(); // Collect extra field label => value pairs for appending to email body.
foreach ( $extra_fields['fields'] as $key => $field ) {
if ( $field['type'] === 'static' ) {
// Display-only field — no submitted value, skip entirely.
continue;
}
$field_label = isset( $field['label'] ) ? $field['label'] : '';
if ( $field['type'] === 'upload' ) {
if ( isset( $_FILES[ "field_extra_{$key}" ] ) && 0 !== $_FILES["field_extra_{$key}"]['size'] ) {
$file_info = $_FILES["field_extra_{$key}"];
$upload_file = self::upload_attachment( $file_info, $field );
if ( is_wp_error( $upload_file ) ) {
wp_send_json_error( array( 'error' => $upload_file->get_error_message() ) );
} elseif ( $upload_file ) {
$uploaded_files_url[ $key ] = $upload_file['url'];
$uploaded_files_path[ $key ] = $upload_file['file'];
// Make uploaded file URL available as a template variable.
if ( $custom_template && $field_label !== '' ) {
$template_key = html_entity_decode( $field_label, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
$template_vars[ '%' . $template_key . '%' ] = $upload_file['url'];
}
}
} elseif ( $custom_template && $field_label !== '' ) {
// No file — leave placeholder empty.
$template_key = html_entity_decode( $field_label, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
$template_vars[ '%' . $template_key . '%' ] = '';
}
continue;
}
// Checkboxes post as an array when checked, and are absent from $_POST when not.
if ( $field['type'] === 'checkbox' ) {
if ( isset( $_POST[ "field_extra_{$key}" ] ) && is_array( $_POST[ "field_extra_{$key}" ] ) ) {
$value = '';
foreach ( $_POST[ "field_extra_{$key}" ] as $val ) {
$value .= sanitize_text_field( stripslashes( $val ) ) . ', ';
}
$value = rtrim( $value, ', ' );
} else {
// Nothing checked.
$value = '';
}
} elseif ( ! isset( $_POST[ "field_extra_{$key}" ] ) ) {
continue;
} elseif ( is_array( $_POST[ "field_extra_{$key}" ] ) ) {
// Other array-type fields.
$value = '';
foreach ( $_POST[ "field_extra_{$key}" ] as $val ) {
$value .= sanitize_text_field( stripslashes( $val ) ) . ', ';
}
$value = rtrim( $value, ', ' );
} else {
if ( $field['type'] === 'textarea' ) {
$value = sanitize_textarea_field( stripslashes( $_POST[ "field_extra_{$key}" ] ) );
} elseif ( $field['type'] === 'email' ) {
$value = sanitize_email( stripslashes( $_POST[ "field_extra_{$key}" ] ) );
} elseif ( $field['type'] === 'date' ) {
if ( empty( $field['show'] ) ) {
$separator = _x( ' @ ', 'Separator between date and time', 'builder-contact' );
$format = get_option( 'date_format' ) . $separator . get_option( 'time_format' );
} else {
$format = get_option( "{$field['show']}_format" );
}
$value = date_i18n( $format, strtotime( stripslashes( $_POST[ "field_extra_{$key}" ] ) ) );
} else {
// text, number, tel, radio, select
$value = sanitize_text_field( stripslashes( $_POST[ "field_extra_{$key}" ] ) );
}
}
$value_display = $field['type'] === 'textarea'
? nl2br( esc_html( $value ), false )
: esc_html( $value );
if ( $custom_template ) {
if ( $field_label !== '' ) {
// Labels may contain HTML entities; decode so the key matches the template placeholder.
$template_key = html_entity_decode( $field_label, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
$template_vars[ '%' . $template_key . '%' ] = $value_display;
}
// Always track extra field values so they can be appended when the template lacks a matching placeholder.
$extra_field_values[] = array( 'label' => $field_label, 'display' => $value_display );
} else {
$body .= '
';
$body .= '' . wp_kses_post( $field_label ) . " :
" . $value_display . "
";
}
}
if ( $custom_template ) {
// Finalize body by replacing all template vars including any from extra fields
$body = strtr( $template, $template_vars );
// Append extra fields whose placeholders were not present in the template,
// so custom fields always appear in the email even when the template does not
// explicitly include them.
$extra_append = '';
foreach ( $extra_field_values as $ef ) {
$placeholder = '%' . html_entity_decode( $ef['label'], ENT_QUOTES | ENT_HTML5, 'UTF-8' ) . '%';
if ( $ef['label'] === '' || strpos( $template, $placeholder ) === false ) {
$extra_append .= '
';
$extra_append .= '' . wp_kses_post( $ef['label'] ) . " :
" . $ef['display'] . "
";
}
}
if ( $extra_append !== '' ) {
$body .= $extra_append;
}
} elseif ( 'enable' === $module_settings['contact_sent_from'] ) {
$body .= '
' . __( 'Sent from:', 'builder-contact' ) . ' ' . $referer . '
';
}
if ( $module_settings['field_sendcopy_active'] === 'yes' && isset( $_POST['contact-sendcopy'] ) && $_POST['contact-sendcopy'] == '1' ) {
if ( ! empty( $email ) && is_email( $email ) ) {
$sendcopy_headers = array();
if ( ! empty( $recipients[0] ) && is_email( $recipients[0] ) ) {
$sendcopy_headers[] = 'Reply-To: ' . $recipients[0];
}
$sendcopy_subject = self::build_sendcopy_subject( $subject, (string) $module_settings['field_sendcopy_subject'] );
self::send_mail( $email, $sendcopy_subject, $body, $sendcopy_headers );
}
}
if ( $module_settings['field_optin_active'] && isset( $_POST['contact-optin'] ) && $_POST['contact-optin'] == '1' ) {
if ( ! class_exists( 'Builder_Optin_Service',false ) ){
include_once( THEMIFY_BUILDER_INCLUDES_DIR. '/optin-services/base.php' );
}
$provider=sanitize_text_field($_POST['contact-optin-provider']);
$optin_instance = method_exists('Builder_Optin_Service', 'get_settings')?Builder_Optin_Service::get_providers( $provider,true ):Builder_Optin_Service::get_providers( $provider );
if ( $optin_instance ) {
// collect the data for optin service
$data = array(
'email' => $email,
'fname' => $name,
'lname' => '',
);
foreach ( $_POST as $key => $value ) {
if ( preg_match( '/^contact-optin-/', $key ) ) {
$key = preg_replace( '/^contact-optin-/', '', $key );
$data[ $key ] = sanitize_text_field( trim( stripslashes($value) ) );
}
}
if(is_string($optin_instance)){
$optin_instance::subscribe( $data );
}
else{
$optin_instance->subscribe( $data );
}
}
unset($optin_instance);
}
if ( $active_post_type ) {
$files_links = '';// for add file link to the post
if ( ! empty( $uploaded_files_url ) ) {
$files_links .= '
' . __( 'Attachments : ', 'builder-contact' );
foreach ( $uploaded_files_url as $link ) {
$files_links .= "
" . $link . "
";
}
}
$post_author_id=false;
if ( $module_settings['post_author'] === 'add' ) {
$post_author_email = $recipients[0];
$post_author_id = self::create_new_author( $post_author_email );
}
self::send_via_post_type( $subject, $body . $files_links, $post_author_id );
}
$auto_respond_sent = false;
$headerStr = $headers;
$cc_recipients = $recipients;
unset( $cc_recipients[0] );
$cc_recipients = self::filter_valid_emails( $cc_recipients );
if ( ! empty( $cc_recipients ) ) {
$headerStr[] = 'Cc: ' . implode( ',', $cc_recipients );
}
if ( $active_bcc && ! empty( $bcc_recipients ) ) {
$headerStr[] = 'Bcc: ' . implode( ',', $bcc_recipients );
}
$sent = self::send_mail( $recipients[0], $subject, $body, $headerStr, $uploaded_files_path, $reply_to_email );
if ( ! $sent ) {
// Retrieve the PHPMailer error if available.
$mailer_error = '';
global $phpmailer;
if ( isset( $phpmailer ) && ! empty( $phpmailer->ErrorInfo ) ) {
$mailer_error = $phpmailer->ErrorInfo;
}
$failed_hook_error = self::$last_mail_error;
$log_detail = $mailer_error ?: $failed_hook_error;
error_log( 'Builder Contact: wp_mail() failed.' . ( $log_detail !== '' ? ' Error: ' . $log_detail : '' ) );
$error_message = __( 'There was an error. Please try again.', 'builder-contact' );
if ( current_user_can( 'manage_options' ) && $log_detail !== '' ) {
$error_message .= ' ' . __( 'Error:', 'builder-contact' ) . ' ' . esc_html( $log_detail );
}
// Clean up any uploaded files before exiting.
if ( $uploaded_files_path && ! $active_post_type ) {
foreach ( $uploaded_files_path as $attachment ) {
if ( file_exists( $attachment ) ) {
wp_delete_file( $attachment );
}
}
}
wp_send_json_error( array( 'error' => $error_message ) );
return;
}
// Mail accepted — send auto-response if configured.
if ( ! empty( $module_settings['auto_respond'] ) && ! empty( $module_settings['auto_respond_message'] ) ) {
$ar_subject = trim( stripslashes( $module_settings['auto_respond_subject'] ) );
$ar_message = wpautop( trim( stripslashes( $module_settings['auto_respond_message'] ) ) );
if ( $custom_template ) {
$ar_message = strtr( $ar_message, $template_vars );
}
$ar_headers = array();
self::send_mail( $email, $ar_subject, $ar_message, $ar_headers );
}
do_action( 'builder_contact_mail_sent' );
if ( $uploaded_files_path && ! $active_post_type ) {
foreach ( $uploaded_files_path as $attachment ) {
if ( file_exists( $attachment ) ) {
wp_delete_file( $attachment );
}
}
}
wp_send_json_success( array(
'msg' => $module_settings['success_message_text'],
'redirect_url' => $module_settings['success_url'],
'nw' => ! empty( $module_settings['nw'] ) ? 1 : '',
) );
}
private static function upload_attachment( $file_info, $field ) {
if ( ! empty( $file_info ) ) {
if ( ! $file_info['error'] && $file_info['size'] <= wp_max_upload_size() ) {
$allowed_types = ! empty( $field['allowed'] ) ? self::get_allowed_mime_types( $field['allowed'] ) : null;
$movefile = wp_handle_upload( $file_info, array(
'test_form' => false,
'mimes' => $allowed_types
) );
if ( $movefile && ! isset( $movefile['error'] ) ) {
return $movefile;
}
return new WP_Error( 'error_filetype', __('WordPress doesn\'t allow this type of uploads.', 'builder-contact' ) );
}
return new WP_Error( 'error_filesize', __('The selected file size is larger than the limit.', 'builder-contact') );
}
return false;
}
public static function upload_dir( $dir ) {
$new_path = trailingslashit( $dir['basedir'] ) . self::$upload_dir;
if ( wp_mkdir_p( $new_path ) ) {
$dir['path'] = $new_path;
$dir['url'] = trailingslashit( $dir['baseurl'] ) . self::$upload_dir;
}
return $dir;
}
/**
* Return a list of $extension => $mime_type from a comma-separated list
*
*/
private static function get_allowed_mime_types(string $allowed ):array {
$output = [];
$mime_types = wp_get_mime_types();
foreach ( explode( ',', $allowed ) as $allowed_ext ) {
foreach ( $mime_types as $exts => $mime ) {
if ( preg_match( '!^(' . $exts . ')$!i', $allowed_ext ) ) {
$output[ $exts ] = $mime;
}
}
}
return $output;
}
/**
* Returns the HTML-friendly list of acceptable types for "file" input
*
*/
public static function get_allowed_types_attr(string $allowed ):string {
$types = self::get_allowed_mime_types( $allowed );
$output = [];
foreach ( $types as $ext => $mime_type ) {
if ( strpos( $ext, '|' ) !== false ) {
$ext = join( ',.', explode( '|', $ext ) );
}
$output[] = ".{$ext},{$mime_type}";
}
return implode( ',', $output );
}
private static function filter_valid_emails( array $emails ): array {
$valid = array();
foreach ( $emails as $email ) {
$email = sanitize_email( trim( (string) $email ) );
if ( $email !== '' && is_email( $email ) ) {
$valid[] = $email;
}
}
return array_values( array_unique( $valid ) );
}
private static function build_sendcopy_subject( string $subject, string $append_text ): string {
$subject = trim( $subject );
$append_text = trim( stripslashes( $append_text ) );
if ( $append_text === '' ) {
return $subject;
}
// If the configured text contains %subject%, replace it with the real subject.
// e.g. "COPY: %subject%" → "COPY: My Subject"
if ( strpos( $append_text, '%subject%' ) !== false ) {
return trim( str_replace( '%subject%', $subject, $append_text ) );
}
// No placeholder — treat the configured text as a prefix.
// e.g. "COPY:" → "COPY: My Subject"
return trim( $append_text . ' ' . $subject );
}
private static $last_mail_error = '';
/**
* Turn stored HTML email body into readable plain text (for wp_mail message + text/plain part).
* Hosts that ignore PHPMailer and send only the wp_mail() body string then deliver readable mail.
*/
private static function html_email_to_plain( string $html ): string {
if ( $html === '' ) {
return '';
}
$s = preg_replace( '~
~i', "\n", $html );
$s = preg_replace( '~