Grunion_Contact_Form

Class for the contact-form shortcode.

Defined (1)

The class is defined in the following location(s).

/modules/contact-form/grunion-contact-form.php  
  1. class Grunion_Contact_Form extends Crunion_Contact_Form_Shortcode { 
  2. public $shortcode_name = 'contact-form'; 
  3.  
  4. /** 
  5. * @var WP_Error stores form submission errors 
  6. */ 
  7. public $errors; 
  8.  
  9. /** 
  10. * @var Grunion_Contact_Form The most recent (inclusive) contact-form shortcode processed 
  11. */ 
  12. static $last; 
  13.  
  14. /** 
  15. * @var Whatever form we are currently looking at. If processed, will become $last 
  16. */ 
  17. static $current_form; 
  18.  
  19. /** 
  20. * @var bool Whether to print the grunion.css style when processing the contact-form shortcode 
  21. */ 
  22. static $style = false; 
  23.  
  24. function __construct( $attributes, $content = null ) { 
  25. global $post; 
  26.  
  27. // Set up the default subject and recipient for this form 
  28. $default_to = ''; 
  29. $default_subject = "[" . get_option( 'blogname' ) . "]"; 
  30.  
  31. if ( !empty( $attributes['widget'] ) && $attributes['widget'] ) { 
  32. $default_to .= get_option( 'admin_email' ); 
  33. $attributes['id'] = 'widget-' . $attributes['widget']; 
  34. $default_subject = sprintf( _x( '%1$s Sidebar', '%1$s = blog name', 'jetpack' ), $default_subject ); 
  35. } else if ( $post ) { 
  36. $attributes['id'] = $post->ID; 
  37. $default_subject = sprintf( _x( '%1$s %2$s', '%1$s = blog name, %2$s = post title', 'jetpack' ), $default_subject, Grunion_Contact_Form_Plugin::strip_tags( $post->post_title ) ); 
  38. $post_author = get_userdata( $post->post_author ); 
  39. $default_to .= $post_author->user_email; 
  40.  
  41. // Keep reference to $this for parsing form fields 
  42. self::$current_form = $this; 
  43.  
  44. $this->defaults = array( 
  45. 'to' => $default_to,  
  46. 'subject' => $default_subject,  
  47. 'show_subject' => 'no', // only used in back-compat mode 
  48. 'widget' => 0, // Not exposed to the user. Works with Grunion_Contact_Form_Plugin::widget_atts() 
  49. 'id' => null, // Not exposed to the user. Set above. 
  50. 'submit_button_text' => __( 'Submit »', 'jetpack' ),  
  51. ); 
  52.  
  53. $attributes = shortcode_atts( $this->defaults, $attributes, 'contact-form' ); 
  54.  
  55. // We only enable the contact-field shortcode temporarily while processing the contact-form shortcode 
  56. Grunion_Contact_Form_Plugin::$using_contact_form_field = true; 
  57.  
  58. parent::__construct( $attributes, $content ); 
  59.  
  60. // There were no fields in the contact form. The form was probably just [contact-form /]. Build a default form. 
  61. if ( empty( $this->fields ) ) { 
  62. // same as the original Grunion v1 form 
  63. $default_form = ' 
  64. [contact-field label="' . __( 'Name', 'jetpack' ) . '" type="name" required="true" /] 
  65. [contact-field label="' . __( 'Email', 'jetpack' ) . '" type="email" required="true" /] 
  66. [contact-field label="' . __( 'Website', 'jetpack' ) . '" type="url" /]'; 
  67.  
  68. if ( 'yes' == strtolower( $this->get_attribute( 'show_subject' ) ) ) { 
  69. $default_form .= ' 
  70. [contact-field label="' . __( 'Subject', 'jetpack' ) . '" type="subject" /]'; 
  71.  
  72. $default_form .= ' 
  73. [contact-field label="' . __( 'Message', 'jetpack' ) . '" type="textarea" /]'; 
  74.  
  75. $this->parse_content( $default_form ); 
  76.  
  77. // Store the shortcode 
  78. $this->store_shortcode( $default_form, $attributes ); 
  79. } else { 
  80. // Store the shortcode 
  81. $this->store_shortcode( $content, $attributes ); 
  82.  
  83. // $this->body and $this->fields have been setup. We no longer need the contact-field shortcode. 
  84. Grunion_Contact_Form_Plugin::$using_contact_form_field = false; 
  85.  
  86. /** 
  87. * Store shortcode content for recall later 
  88. * - used to receate shortcode when user uses do_shortcode 
  89. * @param string $content 
  90. */ 
  91. static function store_shortcode( $content = null, $attributes = null ) { 
  92.  
  93. if ( $content != null and isset( $attributes['id'] ) ) { 
  94.  
  95. $shortcode_meta = get_post_meta( $attributes['id'], '_g_feedback_shortcode', true ); 
  96.  
  97. if ( $shortcode_meta != '' or $shortcode_meta != $content ) { 
  98. update_post_meta( $attributes['id'], '_g_feedback_shortcode', $content ); 
  99.  
  100.  
  101. /** 
  102. * Toggle for printing the grunion.css stylesheet 
  103. * @param bool $style 
  104. */ 
  105. static function style( $style ) { 
  106. $previous_style = self::$style; 
  107. self::$style = (bool) $style; 
  108. return $previous_style; 
  109.  
  110. /** 
  111. * Turn on printing of grunion.css stylesheet 
  112. * @see ::style() 
  113. * @internal 
  114. * @param bool $style 
  115. */ 
  116. static function _style_on() { 
  117. return self::style( true ); 
  118.  
  119. /** 
  120. * The contact-form shortcode processor 
  121. * @param array $attributes Key => Value pairs as parsed by shortcode_parse_atts() 
  122. * @param string|null $content The shortcode's inner content: [contact-form]$content[/contact-form] 
  123. * @return string HTML for the concat form. 
  124. */ 
  125. static function parse( $attributes, $content ) { 
  126. // Create a new Grunion_Contact_Form object (this class) 
  127. $form = new Grunion_Contact_Form( $attributes, $content ); 
  128.  
  129. $id = $form->get_attribute( 'id' ); 
  130.  
  131. if ( !$id ) { // something terrible has happened 
  132. return '[contact-form]'; 
  133.  
  134. if ( is_feed() ) { 
  135. return '[contact-form]'; 
  136.  
  137. // Only allow one contact form per post/widget 
  138. if ( self::$last && $id == self::$last->get_attribute( 'id' ) ) { 
  139. // We're processing the same post 
  140.  
  141. if ( self::$last->attributes != $form->attributes || self::$last->content != $form->content ) { 
  142. // And we're processing a different shortcode; 
  143. return ''; 
  144. } // else, we're processing the same shortcode - probably a separate run of do_shortcode() - let it through 
  145.  
  146. } else { 
  147. self::$last = $form; 
  148.  
  149. // Enqueue the grunion.css stylesheet if self::$style allows it 
  150. if ( self::$style && ( empty( $_REQUEST['action'] ) || $_REQUEST['action'] != 'grunion_shortcode_to_json' ) ) { 
  151. // Enqueue the style here instead of printing it, because if some other plugin has run the_post()+rewind_posts(),  
  152. // (like VideoPress does), the style tag gets "printed" the first time and discarded, leaving the contact form unstyled. 
  153. // when WordPress does the real loop. 
  154. wp_enqueue_style( 'grunion.css' ); 
  155.  
  156. $r = ''; 
  157. $r .= "<div id='contact-form-$id'>\n"; 
  158.  
  159. if ( is_wp_error( $form->errors ) && $form->errors->get_error_codes() ) { 
  160. // There are errors. Display them 
  161. $r .= "<div class='form-error'>\n<h3>" . __( 'Error!', 'jetpack' ) . "</h3>\n<ul class='form-errors'>\n"; 
  162. foreach ( $form->errors->get_error_messages() as $message ) 
  163. $r .= "\t<li class='form-error-message'>" . esc_html( $message ) . "</li>\n"; 
  164. $r .= "</ul>\n</div>\n\n"; 
  165.  
  166. if ( isset( $_GET['contact-form-id'] ) && $_GET['contact-form-id'] == self::$last->get_attribute( 'id' ) && isset( $_GET['contact-form-sent'] ) ) { 
  167. // The contact form was submitted. Show the success message/results 
  168.  
  169. $feedback_id = (int) $_GET['contact-form-sent']; 
  170.  
  171. $back_url = remove_query_arg( array( 'contact-form-id', 'contact-form-sent', '_wpnonce' ) ); 
  172.  
  173. $r_success_message = 
  174. "<h3>" . __( 'Message Sent', 'jetpack' ) . 
  175. ' (<a href="' . esc_url( $back_url ) . '">' . esc_html__( 'go back', 'jetpack' ) . '</a>)' . 
  176. "</h3>\n\n"; 
  177.  
  178. // Don't show the feedback details unless the nonce matches 
  179. if ( $feedback_id && wp_verify_nonce( stripslashes( $_GET['_wpnonce'] ), "contact-form-sent-{$feedback_id}" ) ) { 
  180. $r_success_message .= self::success_message( $feedback_id, $form ); 
  181.  
  182. /** 
  183. * Filter the message returned after a successfull contact form submission. 
  184. * @module contact-form 
  185. * @since 1.3.1 
  186. * @param string $r_success_message Success message. 
  187. */ 
  188. $r .= apply_filters( 'grunion_contact_form_success_message', $r_success_message ); 
  189. } else { 
  190. // Nothing special - show the normal contact form 
  191.  
  192. if ( $form->get_attribute( 'widget' ) ) { 
  193. // Submit form to the current URL 
  194. $url = remove_query_arg( array( 'contact-form-id', 'contact-form-sent', 'action', '_wpnonce' ) ); 
  195. } else { 
  196. // Submit form to the post permalink 
  197. $url = get_permalink(); 
  198.  
  199. // For SSL/TLS page. See RFC 3986 Section 4.2 
  200. $url = set_url_scheme( $url ); 
  201.  
  202. // May eventually want to send this to admin-post.php... 
  203. /** 
  204. * Filter the contact form action URL. 
  205. * @module contact-form 
  206. * @since 1.3.1 
  207. * @param string $contact_form_id Contact form post URL. 
  208. * @param $post $GLOBALS['post'] Post global variable. 
  209. * @param int $id Contact Form ID. 
  210. */ 
  211. $url = apply_filters( 'grunion_contact_form_form_action', "{$url}#contact-form-{$id}", $GLOBALS['post'], $id ); 
  212.  
  213. $r .= "<form action='" . esc_url( $url ) . "' method='post' class='contact-form commentsblock'>\n"; 
  214. $r .= $form->body; 
  215. $r .= "\t<p class='contact-submit'>\n"; 
  216. $r .= "\t\t<input type='submit' value='" . esc_attr( $form->get_attribute( 'submit_button_text' ) ) . "' class='pushbutton-wide'/>\n"; 
  217. if ( is_user_logged_in() ) { 
  218. $r .= "\t\t" . wp_nonce_field( 'contact-form_' . $id, '_wpnonce', true, false ) . "\n"; // nonce and referer 
  219. $r .= "\t\t<input type='hidden' name='contact-form-id' value='$id' />\n"; 
  220. $r .= "\t\t<input type='hidden' name='action' value='grunion-contact-form' />\n"; 
  221. $r .= "\t</p>\n"; 
  222. $r .= "</form>\n"; 
  223.  
  224. $r .= "</div>"; 
  225.  
  226. return $r; 
  227.  
  228. /** 
  229. * Returns a success message to be returned if the form is sent via AJAX. 
  230. * @param int $feedback_id 
  231. * @param object Grunion_Contact_Form $form 
  232. * @return string $message 
  233. */ 
  234. static function success_message( $feedback_id, $form ) { 
  235. return wp_kses( 
  236. '<blockquote class="contact-form-submission">' 
  237. . '<p>' . join( self::get_compiled_form( $feedback_id, $form ), '</p><p>' ) . '</p>' 
  238. . '</blockquote>',  
  239. array( 'br' => array(), 'blockquote' => array( 'class' => array() ), 'p' => array() ) 
  240. ); 
  241.  
  242. /** 
  243. * Returns a compiled form with labels and values in a form of an array 
  244. * of lines. 
  245. * @param int $feedback_id 
  246. * @param object Grunion_Contact_Form $form 
  247. * @return array $lines 
  248. */ 
  249. static function get_compiled_form( $feedback_id, $form ) { 
  250. $feedback = get_post( $feedback_id ); 
  251. $field_ids = $form->get_field_ids(); 
  252. $content_fields = Grunion_Contact_Form_Plugin::parse_fields_from_content( $feedback_id ); 
  253.  
  254. // Maps field_ids to post_meta keys 
  255. $field_value_map = array( 
  256. 'name' => 'author',  
  257. 'email' => 'author_email',  
  258. 'url' => 'author_url',  
  259. 'subject' => 'subject',  
  260. 'textarea' => false, // not a post_meta key. This is stored in post_content 
  261. ); 
  262.  
  263. $compiled_form = array(); 
  264.  
  265. // "Standard" field whitelist 
  266. foreach ( $field_value_map as $type => $meta_key ) { 
  267. if ( isset( $field_ids[$type] ) ) { 
  268. $field = $form->fields[$field_ids[$type]]; 
  269.  
  270. if ( $meta_key ) { 
  271. if ( isset( $content_fields["_feedback_{$meta_key}"] ) ) 
  272. $value = $content_fields["_feedback_{$meta_key}"]; 
  273. } else { 
  274. // The feedback content is stored as the first "half" of post_content 
  275. $value = $feedback->post_content; 
  276. list( $value ) = explode( '<!--more-->', $value ); 
  277. $value = trim( $value ); 
  278.  
  279. $field_index = array_search( $field_ids[ $type ], $field_ids['all'] ); 
  280. $compiled_form[ $field_index ] = sprintf( 
  281. '<b>%1$s:</b> %2$s<br /><br />',  
  282. wp_kses( $field->get_attribute( 'label' ), array() ),  
  283. nl2br( wp_kses( $value, array() ) ) 
  284. ); 
  285.  
  286. // "Non-standard" fields 
  287. if ( $field_ids['extra'] ) { 
  288. // array indexed by field label (not field id) 
  289. $extra_fields = get_post_meta( $feedback_id, '_feedback_extra_fields', true ); 
  290. $extra_field_keys = array_keys( $extra_fields ); 
  291.  
  292. $i = 0; 
  293. foreach ( $field_ids['extra'] as $field_id ) { 
  294. $field = $form->fields[$field_id]; 
  295. $field_index = array_search( $field_id, $field_ids['all'] ); 
  296.  
  297. $label = $field->get_attribute( 'label' ); 
  298.  
  299. $compiled_form[ $field_index ] = sprintf( 
  300. '<b>%1$s:</b> %2$s<br /><br />',  
  301. wp_kses( $label, array() ),  
  302. nl2br( wp_kses( $extra_fields[$extra_field_keys[$i]], array() ) ) 
  303. ); 
  304.  
  305. $i++; 
  306.  
  307. // Sorting lines by the field index 
  308. ksort( $compiled_form ); 
  309.  
  310. return $compiled_form; 
  311.  
  312. /** 
  313. * The contact-field shortcode processor 
  314. * We use an object method here instead of a static Grunion_Contact_Form_Field class method to parse contact-field shortcodes so that we can tie them to the contact-form object. 
  315. * @param array $attributes Key => Value pairs as parsed by shortcode_parse_atts() 
  316. * @param string|null $content The shortcode's inner content: [contact-field]$content[/contact-field] 
  317. * @return HTML for the contact form field 
  318. */ 
  319. static function parse_contact_field( $attributes, $content ) { 
  320. // Don't try to parse contact form fields if not inside a contact form 
  321. if ( ! Grunion_Contact_Form_Plugin::$using_contact_form_field ) { 
  322. $att_strs = array(); 
  323. foreach ( $attributes as $att => $val ) { 
  324. if ( is_numeric( $att ) ) { // Is a valueless attribute 
  325. $att_strs[] = esc_html( $val ); 
  326. } else if ( isset( $val ) ) { // A regular attr - value pair 
  327. $att_strs[] = esc_html( $att ) . '=\'' . esc_html( $val ) . '\''; 
  328.  
  329. $html = '[contact-field ' . implode( ' ', $att_strs ); 
  330.  
  331. if ( isset( $content ) && ! empty( $content ) ) { // If there is content, let's add a closing tag 
  332. $html .= ']' . esc_html( $content ) . '[/contact-field]'; 
  333. } else { // Otherwise let's add a closing slash in the first tag 
  334. $html .= '/]'; 
  335.  
  336. return $html; 
  337.  
  338. $form = Grunion_Contact_Form::$current_form; 
  339.  
  340. $field = new Grunion_Contact_Form_Field( $attributes, $content, $form ); 
  341.  
  342. $field_id = $field->get_attribute( 'id' ); 
  343. if ( $field_id ) { 
  344. $form->fields[$field_id] = $field; 
  345. } else { 
  346. $form->fields[] = $field; 
  347.  
  348. if ( 
  349. isset( $_POST['action'] ) && 'grunion-contact-form' === $_POST['action'] 
  350. && 
  351. isset( $_POST['contact-form-id'] ) && $form->get_attribute( 'id' ) == $_POST['contact-form-id'] 
  352. ) { 
  353. // If we're processing a POST submission for this contact form, validate the field value so we can show errors as necessary. 
  354. $field->validate(); 
  355.  
  356. // Output HTML 
  357. return $field->render(); 
  358.  
  359. /** 
  360. * Loops through $this->fields to generate a (structured) list of field IDs 
  361. * @return array 
  362. */ 
  363. function get_field_ids() { 
  364. $field_ids = array( 
  365. 'all' => array(), // array of all field_ids 
  366. 'extra' => array(), // array of all non-whitelisted field IDs 
  367.  
  368. // Whitelisted "standard" field IDs: 
  369. // 'email' => field_id,  
  370. // 'name' => field_id,  
  371. // 'url' => field_id,  
  372. // 'subject' => field_id,  
  373. // 'textarea' => field_id,  
  374. ); 
  375.  
  376. foreach ( $this->fields as $id => $field ) { 
  377. $field_ids['all'][] = $id; 
  378.  
  379. $type = $field->get_attribute( 'type' ); 
  380. if ( isset( $field_ids[$type] ) ) { 
  381. // This type of field is already present in our whitelist of "standard" fields for this form 
  382. // Put it in extra 
  383. $field_ids['extra'][] = $id; 
  384. continue; 
  385.  
  386. switch ( $type ) { 
  387. case 'email' : 
  388. case 'telephone' : 
  389. case 'name' : 
  390. case 'url' : 
  391. case 'subject' : 
  392. case 'textarea' : 
  393. $field_ids[$type] = $id; 
  394. break; 
  395. default : 
  396. // Put everything else in extra 
  397. $field_ids['extra'][] = $id; 
  398.  
  399. return $field_ids; 
  400.  
  401. /** 
  402. * Process the contact form's POST submission 
  403. * Stores feedback. Sends email. 
  404. */ 
  405. function process_submission() { 
  406. global $post; 
  407.  
  408. $plugin = Grunion_Contact_Form_Plugin::init(); 
  409.  
  410. $id = $this->get_attribute( 'id' ); 
  411. $to = $this->get_attribute( 'to' ); 
  412. $widget = $this->get_attribute( 'widget' ); 
  413.  
  414. $contact_form_subject = $this->get_attribute( 'subject' ); 
  415.  
  416. $to = str_replace( ' ', '', $to ); 
  417. $emails = explode( ', ', $to ); 
  418.  
  419. $valid_emails = array(); 
  420.  
  421. foreach ( (array) $emails as $email ) { 
  422. if ( !is_email( $email ) ) { 
  423. continue; 
  424.  
  425. if ( function_exists( 'is_email_address_unsafe' ) && is_email_address_unsafe( $email ) ) { 
  426. continue; 
  427.  
  428. $valid_emails[] = $email; 
  429.  
  430. // No one to send it to, which means none of the "to" attributes are valid emails. 
  431. // Use default email instead. 
  432. if ( !$valid_emails ) { 
  433. $valid_emails = $this->defaults['to']; 
  434.  
  435. $to = $valid_emails; 
  436.  
  437. // Last ditch effort to set a recipient if somehow none have been set. 
  438. if ( empty( $to ) ) { 
  439. $to = get_option( 'admin_email' ); 
  440.  
  441. // Make sure we're processing the form we think we're processing... probably a redundant check. 
  442. if ( $widget ) { 
  443. if ( 'widget-' . $widget != $_POST['contact-form-id'] ) { 
  444. return false; 
  445. } else { 
  446. if ( $post->ID != $_POST['contact-form-id'] ) { 
  447. return false; 
  448.  
  449. $field_ids = $this->get_field_ids(); 
  450.  
  451. // Initialize all these "standard" fields to null 
  452. $comment_author_email = $comment_author_email_label = // v 
  453. $comment_author = $comment_author_label = // v 
  454. $comment_author_url = $comment_author_url_label = // v 
  455. $comment_content = $comment_content_label = null; 
  456.  
  457. // For each of the "standard" fields, grab their field label and value. 
  458.  
  459. if ( isset( $field_ids['name'] ) ) { 
  460. $field = $this->fields[$field_ids['name']]; 
  461. $comment_author = Grunion_Contact_Form_Plugin::strip_tags( 
  462. stripslashes( 
  463. /** This filter is already documented in core/wp-includes/comment-functions.php */ 
  464. apply_filters( 'pre_comment_author_name', addslashes( $field->value ) ) 
  465. ); 
  466. $comment_author_label = Grunion_Contact_Form_Plugin::strip_tags( $field->get_attribute( 'label' ) ); 
  467.  
  468. if ( isset( $field_ids['email'] ) ) { 
  469. $field = $this->fields[$field_ids['email']]; 
  470. $comment_author_email = Grunion_Contact_Form_Plugin::strip_tags( 
  471. stripslashes( 
  472. /** This filter is already documented in core/wp-includes/comment-functions.php */ 
  473. apply_filters( 'pre_comment_author_email', addslashes( $field->value ) ) 
  474. ); 
  475. $comment_author_email_label = Grunion_Contact_Form_Plugin::strip_tags( $field->get_attribute( 'label' ) ); 
  476.  
  477. if ( isset( $field_ids['url'] ) ) { 
  478. $field = $this->fields[$field_ids['url']]; 
  479. $comment_author_url = Grunion_Contact_Form_Plugin::strip_tags( 
  480. stripslashes( 
  481. /** This filter is already documented in core/wp-includes/comment-functions.php */ 
  482. apply_filters( 'pre_comment_author_url', addslashes( $field->value ) ) 
  483. ); 
  484. if ( 'http://' == $comment_author_url ) { 
  485. $comment_author_url = ''; 
  486. $comment_author_url_label = Grunion_Contact_Form_Plugin::strip_tags( $field->get_attribute( 'label' ) ); 
  487.  
  488. if ( isset( $field_ids['textarea'] ) ) { 
  489. $field = $this->fields[$field_ids['textarea']]; 
  490. $comment_content = trim( Grunion_Contact_Form_Plugin::strip_tags( $field->value ) ); 
  491. $comment_content_label = Grunion_Contact_Form_Plugin::strip_tags( $field->get_attribute( 'label' ) ); 
  492.  
  493. if ( isset( $field_ids['subject'] ) ) { 
  494. $field = $this->fields[$field_ids['subject']]; 
  495. if ( $field->value ) { 
  496. $contact_form_subject = Grunion_Contact_Form_Plugin::strip_tags( $field->value ); 
  497.  
  498. $all_values = $extra_values = array(); 
  499. $i = 1; // Prefix counter for stored metadata 
  500.  
  501. // For all fields, grab label and value 
  502. foreach ( $field_ids['all'] as $field_id ) { 
  503. $field = $this->fields[$field_id]; 
  504. $label = $i . '_' . $field->get_attribute( 'label' ); 
  505. $value = $field->value; 
  506.  
  507. $all_values[$label] = $value; 
  508. $i++; // Increment prefix counter for the next field 
  509.  
  510. // For the "non-standard" fields, grab label and value 
  511. // Extra fields have their prefix starting from count( $all_values ) + 1 
  512. foreach ( $field_ids['extra'] as $field_id ) { 
  513. $field = $this->fields[$field_id]; 
  514. $label = $i . '_' . $field->get_attribute( 'label' ); 
  515. $value = $field->value; 
  516.  
  517. if ( is_array( $value ) ) { 
  518. $value = implode( ', ', $value ); 
  519.  
  520. $extra_values[$label] = $value; 
  521. $i++; // Increment prefix counter for the next extra field 
  522.  
  523. $contact_form_subject = trim( $contact_form_subject ); 
  524.  
  525. $comment_author_IP = Grunion_Contact_Form_Plugin::get_ip_address(); 
  526.  
  527. $vars = array( 'comment_author', 'comment_author_email', 'comment_author_url', 'contact_form_subject', 'comment_author_IP' ); 
  528. foreach ( $vars as $var ) 
  529. $$var = str_replace( array( "\n", "\r" ), '', $$var ); 
  530.  
  531. // Ensure that Akismet gets all of the relevant information from the contact form,  
  532. // not just the textarea field and predetermined subject. 
  533. $akismet_vars = compact( $vars ); 
  534. $akismet_vars['comment_content'] = $comment_content; 
  535.  
  536. foreach ( array_merge( $field_ids['all'], $field_ids['extra'] ) as $field_id ) { 
  537. $field = $this->fields[$field_id]; 
  538.  
  539. // Normalize the label into a slug. 
  540. $field_slug = trim( // Strip all leading/trailing dashes. 
  541. preg_replace( // Normalize everything to a-z0-9_- 
  542. '/[^a-z0-9_]+/',  
  543. '-',  
  544. strtolower( $field->get_attribute( 'label' ) ) // Lowercase 
  545. ),  
  546. '-' 
  547. ); 
  548.  
  549. $field_value = ( is_array( $field->value ) ) ? trim( implode( ', ', $field->value ) ) : trim( $field->value ); 
  550.  
  551. // Skip any values that are already in the array we're sending. 
  552. if ( $field_value && in_array( $field_value, $akismet_vars ) ) { 
  553. continue; 
  554.  
  555. $akismet_vars[ 'contact_form_field_' . $field_slug ] = $field_value; 
  556.  
  557. $spam = ''; 
  558. $akismet_values = $plugin->prepare_for_akismet( $akismet_vars ); 
  559.  
  560. // Is it spam? 
  561. /** This filter is already documented in modules/contact-form/admin.php */ 
  562. $is_spam = apply_filters( 'jetpack_contact_form_is_spam', false, $akismet_values ); 
  563. if ( is_wp_error( $is_spam ) ) // WP_Error to abort 
  564. return $is_spam; // abort 
  565. elseif ( $is_spam === TRUE ) // TRUE to flag a spam 
  566. $spam = '***SPAM*** '; 
  567.  
  568. if ( !$comment_author ) 
  569. $comment_author = $comment_author_email; 
  570.  
  571. /** 
  572. * Filter the email where a submitted feedback is sent. 
  573. * @module contact-form 
  574. * @since 1.3.1 
  575. * @param string|array $to Array of valid email addresses, or single email address. 
  576. */ 
  577. $to = (array) apply_filters( 'contact_form_to', $to ); 
  578. foreach ( $to as $to_key => $to_value ) { 
  579. $to[$to_key] = Grunion_Contact_Form_Plugin::strip_tags( $to_value ); 
  580.  
  581. $blog_url = parse_url( site_url() ); 
  582. $from_email_addr = 'wordpress@' . $blog_url['host']; 
  583.  
  584. $reply_to_addr = $to[0]; 
  585. if ( ! empty( $comment_author_email ) ) { 
  586. $reply_to_addr = $comment_author_email; 
  587.  
  588. $headers = 'From: "' . $comment_author .'" <' . $from_email_addr . ">\r\n" . 
  589. 'Reply-To: "' . $comment_author . '" <' . $reply_to_addr . ">\r\n" . 
  590. "Content-Type: text/html; charset=\"" . get_option('blog_charset') . "\""; 
  591.  
  592. /** This filter is already documented in modules/contact-form/admin.php */ 
  593. $subject = apply_filters( 'contact_form_subject', $contact_form_subject, $all_values ); 
  594. $url = $widget ? home_url( '/' ) : get_permalink( $post->ID ); 
  595.  
  596. $date_time_format = _x( '%1$s \a\t %2$s', '{$date_format} \a\t {$time_format}', 'jetpack' ); 
  597. $date_time_format = sprintf( $date_time_format, get_option( 'date_format' ), get_option( 'time_format' ) ); 
  598. $time = date_i18n( $date_time_format, current_time( 'timestamp' ) ); 
  599.  
  600. // keep a copy of the feedback as a custom post type 
  601. $feedback_time = current_time( 'mysql' ); 
  602. $feedback_title = "{$comment_author} - {$feedback_time}"; 
  603. $feedback_status = $is_spam === TRUE ? 'spam' : 'publish'; 
  604.  
  605. foreach ( (array) $akismet_values as $av_key => $av_value ) { 
  606. $akismet_values[$av_key] = Grunion_Contact_Form_Plugin::strip_tags( $av_value ); 
  607.  
  608. foreach ( (array) $all_values as $all_key => $all_value ) { 
  609. $all_values[$all_key] = Grunion_Contact_Form_Plugin::strip_tags( $all_value ); 
  610.  
  611. foreach ( (array) $extra_values as $ev_key => $ev_value ) { 
  612. $extra_values[$ev_key] = Grunion_Contact_Form_Plugin::strip_tags( $ev_value ); 
  613.  
  614. /** We need to make sure that the post author is always zero for contact 
  615. * form submissions. This prevents export/import from trying to create 
  616. * new users based on form submissions from people who were logged in 
  617. * at the time. 
  618. * Unfortunately wp_insert_post() tries very hard to make sure the post 
  619. * author gets the currently logged in user id. That is how we ended up 
  620. * with this work around. */ 
  621. add_filter( 'wp_insert_post_data', array( $plugin, 'insert_feedback_filter' ), 10, 2 ); 
  622.  
  623. $post_id = wp_insert_post( array( 
  624. 'post_date' => addslashes( $feedback_time ),  
  625. 'post_type' => 'feedback',  
  626. 'post_status' => addslashes( $feedback_status ),  
  627. 'post_parent' => (int) $post->ID,  
  628. 'post_title' => addslashes( wp_kses( $feedback_title, array() ) ),  
  629. 'post_content' => addslashes( wp_kses( $comment_content . "\n<!--more-->\n" . "AUTHOR: {$comment_author}\nAUTHOR EMAIL: {$comment_author_email}\nAUTHOR URL: {$comment_author_url}\nSUBJECT: {$subject}\nIP: {$comment_author_IP}\n" . print_r( $all_values, TRUE ), array() ) ), // so that search will pick up this data 
  630. 'post_name' => md5( $feedback_title ),  
  631. ) ); 
  632.  
  633. // once insert has finished we don't need this filter any more 
  634. remove_filter( 'wp_insert_post_data', array( $plugin, 'insert_feedback_filter' ), 10, 2 ); 
  635.  
  636. update_post_meta( $post_id, '_feedback_extra_fields', $this->addslashes_deep( $extra_values ) ); 
  637. update_post_meta( $post_id, '_feedback_akismet_values', $this->addslashes_deep( $akismet_values ) ); 
  638.  
  639. $message = self::get_compiled_form( $post_id, $this ); 
  640.  
  641. array_push( 
  642. $message,  
  643. "", // Empty line left intentionally 
  644. __( 'Time:', 'jetpack' ) . ' ' . $time . '<br />',  
  645. __( 'IP Address:', 'jetpack' ) . ' ' . $comment_author_IP . '<br />',  
  646. __( 'Contact Form URL:', 'jetpack' ) . " " . $url . '<br />' 
  647. ); 
  648.  
  649. if ( is_user_logged_in() ) { 
  650. array_push( 
  651. $message,  
  652. "",  
  653. sprintf( 
  654. __( 'Sent by a verified %s user.', 'jetpack' ),  
  655. isset( $GLOBALS['current_site']->site_name ) && $GLOBALS['current_site']->site_name ? 
  656. $GLOBALS['current_site']->site_name : '"' . get_option( 'blogname' ) . '"' 
  657. ); 
  658. } else { 
  659. array_push( $message, __( 'Sent by an unverified visitor to your site.', 'jetpack' ) ); 
  660.  
  661. $message = join( $message, "" ); 
  662. /** 
  663. * Filters the message sent via email after a successfull form submission. 
  664. * @module contact-form 
  665. * @since 1.3.1 
  666. * @param string $message Feedback email message. 
  667. */ 
  668. $message = apply_filters( 'contact_form_message', $message ); 
  669.  
  670. update_post_meta( $post_id, '_feedback_email', $this->addslashes_deep( compact( 'to', 'message' ) ) ); 
  671.  
  672. /** 
  673. * Fires right before the contact form message is sent via email to 
  674. * the recipient specified in the contact form. 
  675. * @module contact-form 
  676. * @since 1.3.1 
  677. * @param integer $post_id Post contact form lives on 
  678. * @param array $all_values Contact form fields 
  679. * @param array $extra_values Contact form fields not included in $all_values 
  680. */ 
  681. do_action( 'grunion_pre_message_sent', $post_id, $all_values, $extra_values ); 
  682.  
  683. // schedule deletes of old spam feedbacks 
  684. if ( ! wp_next_scheduled( 'grunion_scheduled_delete' ) ) { 
  685. wp_schedule_event( time() + 250, 'daily', 'grunion_scheduled_delete' ); 
  686.  
  687. if ( 
  688. $is_spam !== TRUE && 
  689. /** 
  690. * Filter to choose whether an email should be sent after each successfull contact form submission. 
  691. * @module contact-form 
  692. * @since 2.6.0 
  693. * @param bool true Should an email be sent after a form submission. Default to true. 
  694. * @param int $post_id Post ID. 
  695. */ 
  696. true === apply_filters( 'grunion_should_send_email', true, $post_id ) 
  697. ) { 
  698. wp_mail( $to, "{$spam}{$subject}", $message, $headers ); 
  699. } elseif ( 
  700. true === $is_spam && 
  701. /** 
  702. * Choose whether an email should be sent for each spam contact form submission. 
  703. * @module contact-form 
  704. * @since 1.3.1 
  705. * @param bool false Should an email be sent after a spam form submission. Default to false. 
  706. */ 
  707. apply_filters( 'grunion_still_email_spam', FALSE ) == TRUE 
  708. ) { // don't send spam by default. Filterable. 
  709. wp_mail( $to, "{$spam}{$subject}", $message, $headers ); 
  710.  
  711. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { 
  712. return self::success_message( $post_id, $this ); 
  713.  
  714. $redirect = wp_get_referer(); 
  715. if ( !$redirect ) { // wp_get_referer() returns false if the referer is the same as the current page 
  716. $redirect = $_SERVER['REQUEST_URI']; 
  717.  
  718. $redirect = add_query_arg( urlencode_deep( array( 
  719. 'contact-form-id' => $id,  
  720. 'contact-form-sent' => $post_id,  
  721. '_wpnonce' => wp_create_nonce( "contact-form-sent-{$post_id}" ), // wp_nonce_url HTMLencodes :( 
  722. ) ), $redirect ); 
  723.  
  724. /** 
  725. * Filter the URL where the reader is redirected after submitting a form. 
  726. * @module contact-form 
  727. * @since 1.9.0 
  728. * @param string $redirect Post submission URL. 
  729. * @param int $id Contact Form ID. 
  730. * @param int $post_id Post ID. 
  731. */ 
  732. $redirect = apply_filters( 'grunion_contact_form_redirect_url', $redirect, $id, $post_id ); 
  733.  
  734. wp_safe_redirect( $redirect ); 
  735. exit; 
  736.  
  737. function addslashes_deep( $value ) { 
  738. if ( is_array( $value ) ) { 
  739. return array_map( array( $this, 'addslashes_deep' ), $value ); 
  740. } elseif ( is_object( $value ) ) { 
  741. $vars = get_object_vars( $value ); 
  742. foreach ( $vars as $key => $data ) { 
  743. $value->{$key} = $this->addslashes_deep( $data ); 
  744. return $value; 
  745.  
  746. return addslashes( $value );