| @@ -1,36 +1,19 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | - * Email functions. | |
| 3 | + * Email functions | |
| 4 | 4 | * |
| 5 | - * Helper wrappers around wp_mail() used by the theme, plus the AJAX handler | |
| 6 | - * that backs the front-end contact form (both the classic and Elementor | |
| 7 | - * contact widgets). Provides the default "From"/"Reply-To" identity and a | |
| 8 | - * single send routine that switches between plain-text and HTML headers. | |
| 9 | - * | |
| 10 | 5 | * @package wpstream-theme |
| 11 | 6 | */ |
| 12 | 7 | |
| 13 | - | |
| 14 | -// Exit if accessed directly. | |
| 15 | -if ( ! defined( 'ABSPATH' ) ) { | |
| 16 | - exit; | |
| 17 | -} | |
| 18 | - | |
| 19 | -// Only define once; guards against redeclaration when the theme/plugin overlap. | |
| 20 | 8 | if ( ! function_exists( 'wpstream_theme_return_sending_email' ) ) { |
| 21 | 9 | /** |
| 22 | - * Build the default "From" identity used for outgoing theme emails. | |
| 23 | - * | |
| 24 | - * @return string A formatted "Name <email>" sender string. | |
| 10 | + * Return sending email | |
| 25 | 11 | */ |
| 26 | 12 | function wpstream_theme_return_sending_email() { |
| 27 | - // Placeholder sender address; intended to be customised per install. | |
| 28 | 13 | $from_email = 'noreply@changeme.net'; |
| 29 | - // Placeholder display name shown as the sender. | |
| 30 | 14 | $name_email = 'changeME'; |
| 31 | 15 | |
| 32 | - // Assemble the RFC-style "Name <email>" header value. | |
| 33 | 16 | return $name_email . ' <' . $from_email . '>'; |
| 34 | 17 | } |
| 35 | 18 | } |
| 36 | 19 | |
| @@ -46,14 +29,12 @@ | ||
| 46 | 29 | * @param string $reply_to The reply-to email address. |
| 47 | 30 | * @param string|array $extra_headers Extra headers to include in the email. |
| 48 | 31 | */ |
| 49 | 32 | function wpstream_theme_send_emails( $user_email, $subject, $message, $email_type, $reply_to = '', $extra_headers = '' ) { |
| 50 | - // When no explicit reply-to is passed, reply-to defaults to the sender identity. | |
| 51 | 33 | if ( '' === $reply_to ) { |
| 52 | 34 | $reply_to = wpstream_theme_return_sending_email(); |
| 53 | 35 | } |
| 54 | 36 | |
| 55 | - // Default headers: HTML body with UTF-8 encoding. | |
| 56 | 37 | $headers = 'From: ' . wpstream_theme_return_sending_email() . "\r\n" . |
| 57 | 38 | 'Reply-To:' . $reply_to . "\r\n" . |
| 58 | 39 | 'Content-Type: text/html; charset="UTF-8"' . "\r\n" . |
| 59 | 40 | 'Content-Transfer-Encoding: 8bit' . "\r\n" . |
| @@ -59,9 +40,8 @@ | ||
| 59 | 40 | 'Content-Transfer-Encoding: 8bit' . "\r\n" . |
| 60 | 41 | 'MIME-Version: 1.0' . "\r\n" . |
| 61 | 42 | 'X-Mailer: PHP/' . phpversion(); |
| 62 | 43 | |
| 63 | - // Override the Content-Type with a plain-text variant when requested. | |
| 64 | 44 | if ( 'text' === $email_type ) { |
| 65 | 45 | $headers = 'From: ' . wpstream_theme_return_sending_email() . "\r\n" . |
| 66 | 46 | 'Reply-To:' . $reply_to . "\r\n" . |
| 67 | 47 | 'Content-Type: text/plain ; charset="UTF-8"' . "\r\n" . |
| @@ -69,12 +49,10 @@ | ||
| 69 | 49 | 'MIME-Version: 1.0' . "\r\n" . |
| 70 | 50 | 'X-Mailer: PHP/' . phpversion(); |
| 71 | 51 | } |
| 72 | 52 | |
| 73 | - // Append any caller-supplied extra headers to the base header block. | |
| 74 | 53 | $headers = $headers . $extra_headers; |
| 75 | 54 | |
| 76 | - // Dispatch the email; stripslashes undoes any slashes added by WP on input. | |
| 77 | 55 | $sent = wp_mail( |
| 78 | 56 | $user_email, |
| 79 | 57 | stripslashes( $subject ), |
| 80 | 58 | stripslashes( $message ), |
| @@ -80,9 +58,8 @@ | ||
| 80 | 58 | stripslashes( $message ), |
| 81 | 59 | $headers |
| 82 | 60 | ); |
| 83 | 61 | |
| 84 | - // Log a failure so delivery problems are visible in the error log. | |
| 85 | 62 | if ( ! $sent ) { |
| 86 | 63 | error_log( 'Failed to send email to ' . $user_email ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log |
| 87 | 64 | } |
| 88 | 65 | } |
| @@ -94,141 +71,87 @@ | ||
| 94 | 71 | * |
| 95 | 72 | */ |
| 96 | 73 | |
| 97 | 74 | |
| 98 | -if ( ! function_exists( 'wpstream_theme_post_text' ) ) { | |
| 99 | - /** | |
| 100 | - * Read a POST field as trimmed text. | |
| 101 | - * | |
| 102 | - * Missing fields and non-scalar payloads (name[]=x style) both come back | |
| 103 | - * as '', so callers can validate "empty" without type juggling warnings. | |
| 104 | - * | |
| 105 | - * @param string $key POST field name. | |
| 106 | - * @return string Trimmed scalar value, or '' when absent/non-scalar. | |
| 107 | - */ | |
| 108 | - function wpstream_theme_post_text( $key ) { | |
| 109 | - return ( isset( $_POST[ $key ] ) && is_scalar( $_POST[ $key ] ) ) ? trim( (string) $_POST[ $key ] ) : ''; | |
| 110 | - } | |
| 111 | -} | |
| 112 | - | |
| 113 | -// Register the contact-form AJAX handler for both logged-out and logged-in users. | |
| 114 | 75 | add_action( 'wp_ajax_nopriv_wpstream_ajax_contact_function', 'wpstream_ajax_contact_function' ); |
| 115 | 76 | add_action( 'wp_ajax_wpstream_ajax_contact_function', 'wpstream_ajax_contact_function' ); |
| 116 | 77 | |
| 117 | -// Guard against redeclaration before defining the handler. | |
| 118 | 78 | if( !function_exists('wpstream_ajax_contact_function') ): |
| 119 | 79 | |
| 120 | - /** | |
| 121 | - * AJAX handler for the front-end contact form. | |
| 122 | - * | |
| 123 | - * Validates the submitted fields, builds a plain message body, and emails it | |
| 124 | - * to the site admin. Handles both the classic contact form and the Elementor | |
| 125 | - * contact-form builder (which sends a pre-composed comment only). | |
| 126 | - * Echoes a JSON payload describing success/failure and exits. | |
| 127 | - * | |
| 128 | - * @return void | |
| 129 | - */ | |
| 130 | 80 | function wpstream_ajax_contact_function(){ |
| 131 | 81 | |
| 132 | 82 | |
| 133 | 83 | // check for POST vars |
| 134 | - // Accumulator for the outgoing message body. | |
| 135 | 84 | $message = ''; |
| 136 | - // Error flag (declared but not actively used below). | |
| 137 | 85 | $hasError = false; |
| 138 | - // Empty allowlist means wp_kses strips all HTML from user input. | |
| 139 | 86 | $allowed_html = array(); |
| 140 | - // Scratch output buffer (declared but not actively used below). | |
| 141 | 87 | $to_print = ''; |
| 142 | - // Sanitized message body; stays '' when the Elementor branch gets | |
| 143 | - // no comment field ($name/$email are always set before use). | |
| 144 | - $comment = ''; | |
| 145 | - // Reject the request unless the contact-form nonce is valid. | |
| 146 | - if ( !wp_verify_nonce( $_POST['nonce'] ?? '', 'ajax-property-contact')) { | |
| 88 | + if ( !wp_verify_nonce( $_POST['nonce'], 'ajax-property-contact')) { | |
| 147 | 89 | exit("No naughty business please"); |
| 148 | 90 | } |
| 91 | + | |
| 92 | + $is_elementor_contact_builder = intval($_POST['is_elementor']); | |
| 149 | 93 | |
| 150 | - // Flag: 1 when the submission comes from the Elementor contact widget. | |
| 151 | - $is_elementor_contact_builder = intval($_POST['is_elementor'] ?? 0); | |
| 152 | - | |
| 153 | - // Classic contact form path: validate name/email/comment individually | |
| 154 | - // (each read defaults to '' so a missing field is just an empty one). | |
| 155 | 94 | if($is_elementor_contact_builder==0){ |
| 156 | - // Validate the name field. | |
| 157 | - $posted_name = wpstream_theme_post_text('name'); | |
| 158 | - // Empty name (or the untouched placeholder) is treated as invalid. | |
| 159 | - if( $posted_name =='' || $posted_name ==esc_html__( 'Your Name','hello-wpstream') ){ | |
| 160 | - echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'The name field is empty !','hello-wpstream') )); | |
| 161 | - exit(); | |
| 162 | - }else { | |
| 163 | - // Sanitize the name (strips all HTML). | |
| 164 | - $name = wp_kses( $posted_name,$allowed_html ); | |
| 95 | + if ( isset($_POST['name']) ) { | |
| 96 | + if( trim($_POST['name']) =='' || trim($_POST['name']) ==esc_html__( 'Your Name','hello-wpstream') ){ | |
| 97 | + echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'The name field is empty !','hello-wpstream') )); | |
| 98 | + exit(); | |
| 99 | + }else { | |
| 100 | + $name = wp_kses( trim($_POST['name']),$allowed_html ); | |
| 101 | + } | |
| 165 | 102 | } |
| 166 | 103 | |
| 167 | 104 | |
| 168 | 105 | //Check email |
| 169 | - $posted_email = wpstream_theme_post_text('email'); | |
| 170 | - // Empty email is invalid. | |
| 171 | - if( $posted_email ==''){ | |
| 172 | - echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'The email field is empty','hello-wpstream' ) ) ); | |
| 173 | - exit(); | |
| 174 | - // Reject malformed email addresses. | |
| 175 | - } else if( filter_var($posted_email,FILTER_VALIDATE_EMAIL) === false) { | |
| 176 | - echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'The email doesn\'t look right !','hello-wpstream') ) ); | |
| 177 | - exit(); | |
| 178 | - } else { | |
| 179 | - // Sanitize the accepted email address. | |
| 180 | - $email = wp_kses( $posted_email,$allowed_html ); | |
| 106 | + if ( isset($_POST['email']) || trim($_POST['email']) ==esc_html__( 'Your Email','hello-wpstream') ) { | |
| 107 | + if( trim($_POST['email']) ==''){ | |
| 108 | + echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'The email field is empty','hello-wpstream' ) ) ); | |
| 109 | + exit(); | |
| 110 | + } else if( filter_var($_POST['email'],FILTER_VALIDATE_EMAIL) === false) { | |
| 111 | + echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'The email doesn\'t look right !','hello-wpstream') ) ); | |
| 112 | + exit(); | |
| 113 | + } else { | |
| 114 | + $email = wp_kses( trim($_POST['email']),$allowed_html ); | |
| 115 | + } | |
| 181 | 116 | } |
| 182 | 117 | |
| 183 | 118 | //Check comments |
| 184 | - $posted_comment = wpstream_theme_post_text('comment'); | |
| 185 | - // Empty message (or the untouched placeholder) is invalid. | |
| 186 | - if( $posted_comment =='' || $posted_comment ==esc_html__( 'Your Message','hello-wpstream')){ | |
| 187 | - echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'Your message is empty !','hello-wpstream') ) ); | |
| 188 | - exit(); | |
| 189 | - }else { | |
| 190 | - // Sanitize the message body. | |
| 191 | - $comment = wp_kses($posted_comment ,$allowed_html ); | |
| 119 | + if ( isset($_POST['comment']) ) { | |
| 120 | + if( trim($_POST['comment']) =='' || trim($_POST['comment']) ==esc_html__( 'Your Message','hello-wpstream')){ | |
| 121 | + echo json_encode(array('sent'=>false, 'response'=>esc_html__( 'Your message is empty !','hello-wpstream') ) ); | |
| 122 | + exit(); | |
| 123 | + }else { | |
| 124 | + $comment = wp_kses($_POST['comment'] ,$allowed_html ); | |
| 125 | + } | |
| 192 | 126 | } |
| 193 | 127 | |
| 194 | 128 | |
| 195 | - // Prepend the collected name and email to the message body. | |
| 196 | 129 | $message .= esc_html__('Client Name','hello-wpstream').": " . $name . PHP_EOL; |
| 197 | 130 | $message .= esc_html__('Email','hello-wpstream').": " . $email . PHP_EOL; |
| 198 | - // Optional website field, when supplied. | |
| 199 | - $posted_website = wpstream_theme_post_text('website'); | |
| 200 | - if( $posted_website !== '' ){ | |
| 201 | - $website = wp_kses( $posted_website,$allowed_html ); | |
| 131 | + if(isset($_POST['website'])){ | |
| 132 | + $website = wp_kses( trim($_POST['website']),$allowed_html ); | |
| 202 | 133 | $message .= esc_html__('Website','hello-wpstream').": " . $website . PHP_EOL; |
| 203 | 134 | } |
| 204 | 135 | |
| 205 | 136 | }else{ |
| 206 | - // Elementor contact-builder path: use its pre-composed comment only. | |
| 207 | - $posted_comment = wpstream_theme_post_text('comment'); | |
| 208 | - if ( $posted_comment !== '' ) { | |
| 209 | - $comment = wp_kses($posted_comment ,$allowed_html ); | |
| 210 | - // Convert literal "/n" tokens into real line breaks. | |
| 137 | + if ( isset($_POST['comment']) ) { | |
| 138 | + $comment = wp_kses($_POST['comment'] ,$allowed_html ); | |
| 211 | 139 | $comment = str_replace('/n',PHP_EOL,$comment); |
| 212 | - | |
| 140 | + | |
| 213 | 141 | } |
| 214 | 142 | } |
| 215 | 143 | |
| 216 | 144 | |
| 217 | - // Default subject line records the site the form was submitted from. | |
| 218 | 145 | $subject =esc_html__( 'Contact form from ','hello-wpstream') . esc_url( home_url('/') ) ; |
| 219 | - // Deliver to the site's configured admin email. | |
| 220 | 146 | $receiver_email = esc_html(get_option('admin_email') ); |
| 221 | - // Append the message body and a provenance note. | |
| 222 | 147 | $message .= esc_html__('Message','hello-wpstream').": ".PHP_EOL." " . $comment. PHP_EOL; |
| 223 | 148 | $message .= esc_html__('Message sent from contact page','hello-wpstream'). PHP_EOL; |
| 224 | 149 | |
| 225 | 150 | |
| 226 | - // Derive the host for a fallback From header (note: unused by the send call below). | |
| 227 | 151 | $site_web_url = parse_url(home_url(), PHP_URL_HOST); |
| 228 | 152 | $headers = 'From: No Reply <noreply@' . $site_web_url . '>' . "\r\n"; |
| 229 | 153 | |
| 230 | - // Elementor widgets may supply their own subject line. | |
| 231 | 154 | if(isset($_POST['elementor_email_subject'])){ |
| 232 | 155 | $subject = sanitize_text_field( $_POST['elementor_email_subject']); |
| 233 | 156 | } |
| 234 | 157 | |
| @@ -234,13 +157,11 @@ | ||
| 234 | 157 | |
| 235 | 158 | |
| 236 | 159 | |
| 237 | 160 | |
| 238 | - // Send the composed contact email to the site admin. | |
| 239 | 161 | wpstream_theme_send_emails( $receiver_email, $subject, $message, '' ); |
| 240 | 162 | |
| 241 | 163 | |
| 242 | - // Report success back to the AJAX caller and stop execution. | |
| 243 | 164 | echo json_encode(array('sent'=>true,'data'=>true, 'response'=>esc_html__( 'The message was sent !','hello-wpstream') ) ); |
| 244 | 165 | die(); |
| 245 | 166 | } |
| 246 | 167 | |