/** * Helpers for Jetpack form values + debug */ function ecb_mask_email( $email ) { $email = sanitize_email( (string) $email ); if ( ! $email || false === strpos( $email, '@' ) ) { return ''; } list( $local, $domain ) = explode( '@', $email, 2 ); $local = substr( $local, 0, 2 ) . '***'; return $local . '@' . $domain; } function ecb_debug( $message, $context = array() ) { if ( ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) { return; } $clean = array(); foreach ( (array) $context as $key => $value ) { if ( is_scalar( $value ) || null === $value ) { $clean[ $key ] = $value; } elseif ( is_array( $value ) ) { $clean[ $key ] = array_map( function ( $item ) { return is_scalar( $item ) || null === $item ? $item : gettype( $item ); }, $value ); } else { $clean[ $key ] = gettype( $value ); } } error_log( '[ECB] ' . $message . ' | ' . wp_json_encode( $clean ) ); } function ecb_extract_values_map( $all_values, $extra_values = array() ) { $map = array(); $source = array_merge( is_array( $all_values ) ? $all_values : array(), is_array( $extra_values ) ? $extra_values : array() ); foreach ( $source as $key => $value ) { if ( is_array( $value ) ) { $flat = implode( ', ', array_map( 'sanitize_text_field', $value ) ); } else { $flat = sanitize_text_field( (string) $value ); } $map[ (string) $key ] = $flat; } return $map; } function ecb_find_email_in_values_map( $values_map ) { foreach ( (array) $values_map as $value ) { if ( is_email( $value ) ) { return sanitize_email( $value ); } } return ''; } function ecb_find_author_in_values_map( $values_map ) { foreach ( (array) $values_map as $key => $value ) { $key_l = strtolower( (string) $key ); if ( false !== strpos( $key_l, 'naam' ) || false !== strpos( $key_l, 'name' ) || false !== strpos( $key_l, 'achternaam' ) ) { return sanitize_text_field( (string) $value ); } } return ''; } function ecb_build_trello_message_from_map( $values_map, $email, $author, $submitted_url = '', $submitted_time = '' ) { $message = ''; foreach ( (array) $values_map as $label => $value ) { $message .= sanitize_text_field( (string) $label ) . ': ' . sanitize_text_field( (string) $value ) . PHP_EOL . PHP_EOL; } if ( $email ) { $message .= 'E-mail adres: ' . sanitize_email( $email ) . PHP_EOL . PHP_EOL; } if ( $author ) { $message .= 'Naam: ' . sanitize_text_field( $author ) . PHP_EOL . PHP_EOL; } if ( $submitted_time ) { $message .= 'Tijd: ' . sanitize_text_field( $submitted_time ) . PHP_EOL . PHP_EOL; } if ( $submitted_url ) { $message .= 'Contactformulier-URL: ' . esc_url_raw( $submitted_url ) . PHP_EOL . PHP_EOL; } $message .= 'Lead ontvangen via contactformulier.' . PHP_EOL . PHP_EOL; return $message; } /** * Feedback parsing */ function ecb_parse_email_author_from_content( $post_id ) { $post = get_post( $post_id ); if ( ! $post || empty( $post->post_content ) ) { return array( 'email' => '', 'author' => '', ); } $content = (string) $post->post_content; $email = ''; $author = ''; if ( preg_match( '/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/i', $content, $m ) ) { $email = sanitize_email( $m[0] ); } if ( preg_match( '/(?:Voor\s*[- ]?en\s+achternaam|Naam|Volledige\s+naam)[\s:]*\n([^\n\[]+)/iu', $content, $m ) ) { $author = sanitize_text_field( trim( $m[1] ) ); } return array( 'email' => $email, 'author' => $author, ); } function ecb_get_feedback_content_fields( $post_id ) { $fields = array( '_feedback_author_email' => get_post_meta( $post_id, '_feedback_author_email', true ), '_feedback_author' => get_post_meta( $post_id, '_feedback_author', true ), '_feedback_ip' => get_post_meta( $post_id, '_feedback_ip', true ), '_feedback_all_fields' => array( 'entry_permalink' => get_permalink( $post_id ), ), ); if ( class_exists( 'Grunion_Contact_Form_Plugin' ) ) { $parsed = Grunion_Contact_Form_Plugin::parse_fields_from_content( $post_id ); if ( ! empty( $parsed ) && is_array( $parsed ) ) { $fields = array_merge( $fields, $parsed ); } } if ( empty( $fields['_feedback_author_email'] ) || empty( $fields['_feedback_author'] ) ) { $from_content = ecb_parse_email_author_from_content( $post_id ); if ( ! empty( $from_content['email'] ) ) { $fields['_feedback_author_email'] = $from_content['email']; } if ( ! empty( $from_content['author'] ) ) { $fields['_feedback_author'] = $from_content['author']; } } return $fields; } /** * Custom brochure mail + redirect * Hook: grunion_pre_message_sent( $post_id, $all_values, $extra_values ) */ function ecb_send_email_and_set_redirect( $post_id, $all_values, $extra_values ) { global $wpdb; static $ecb_email_sent_for = array(); ecb_debug( 'grunion_pre_message_sent fired', array( 'post_id' => $post_id, 'all_keys' => is_array( $all_values ) ? array_keys( $all_values ) : array(), 'extra_keys' => is_array( $extra_values ) ? array_keys( $extra_values ) : array(), 'referer' => wp_get_referer(), ) ); if ( ! empty( $ecb_email_sent_for[ $post_id ] ) ) { ecb_debug( 'Mail skipped: already sent in this request', array( 'post_id' => $post_id ) ); return; } $table_name = ecb_get_table_name(); $request_uri = ''; $referer = wp_get_referer(); if ( $referer ) { $request_uri = wp_parse_url( $referer, PHP_URL_PATH ); } if ( empty( $request_uri ) && $post_id ) { $page_path = wp_parse_url( get_permalink( $post_id ), PHP_URL_PATH ); if ( ! empty( $page_path ) ) { $request_uri = $page_path; } } if ( empty( $request_uri ) && ! empty( $_SERVER['REQUEST_URI'] ) ) { $request_uri = wp_parse_url( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ), PHP_URL_PATH ); } $request_uri = untrailingslashit( (string) $request_uri ); if ( '' === $request_uri ) { ecb_debug( 'Mail aborted: empty request_uri', array( 'post_id' => $post_id ) ); return; } $ecb = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE url LIKE %s ORDER BY id ASC LIMIT 1", '%' . $wpdb->esc_like( $request_uri ) . '%' ) ); if ( ! $ecb ) { ecb_debug( 'Mail aborted: no ECB row matched', array( 'request_uri' => $request_uri ) ); return; } $body = ecb_prepare_email_content_html( $ecb->email_body ); $labels = array_map( 'trim', explode( ',', (string) $ecb->labels ) ); $labels_filtered = array_map( 'get_input_name', $labels ); $values_map = ecb_extract_values_map( $all_values, $extra_values ); $email = ecb_find_email_in_values_map( $values_map ); ecb_debug( 'Mail values resolved', array( 'post_id' => $post_id, 'request_uri' => $request_uri, 'values_keys' => array_keys( $values_map ), 'email_detected' => ecb_mask_email( $email ), ) ); foreach ( $labels_filtered as $label_key => $label_value ) { foreach ( $values_map as $field_key => $field_value ) { if ( false !== strpos( strtolower( (string) $field_key ), strtolower( $label_value ) ) && ! empty( $labels[ $label_key ] ) ) { $body = str_replace( $labels[ $label_key ], ecb_email_safe_value( $field_value ), $body ); } } } if ( empty( $email ) || ! is_email( $email ) ) { ecb_debug( 'Mail aborted: no valid recipient email found', array( 'post_id' => $post_id ) ); return; } $attachments = array(); $pdf_path = ecb_pdf_path_from_url( (string) $ecb->filepath ); if ( $pdf_path ) { $attachments[] = $pdf_path; } $mail_headers = array( 'Content-Type: text/html; charset=UTF-8', 'From: De Kritische Belegger ', ); $html_email = ecb_build_email_html( $body, (string) $ecb->subject ); $mail_result = wp_mail( $email, sanitize_text_field( (string) $ecb->subject ), $html_email, $mail_headers, $attachments ); ecb_debug( 'wp_mail result', array( 'post_id' => $post_id, 'recipient' => ecb_mask_email( $email ), 'mail_result' => $mail_result ? 'true' : 'false', 'attachments' => $attachments, ) ); $ecb_email_sent_for[ $post_id ] = true; if ( ! empty( $ecb->redirect_url ) ) { if ( ! isset( $GLOBALS['ecb_redirect_for_post'] ) || ! is_array( $GLOBALS['ecb_redirect_for_post'] ) ) { $GLOBALS['ecb_redirect_for_post'] = array(); } $GLOBALS['ecb_redirect_for_post'][ $post_id ] = esc_url_raw( $ecb->redirect_url ); ecb_debug( 'Redirect stored', array( 'post_id' => $post_id, 'redirect_url' => (string) $ecb->redirect_url, ) ); } } /** * Trello sync */ function ecb_send_to_trello( $post_id, $entry_values = array(), $fields = array() ) { static $ecb_trello_sent_for = array(); ecb_debug( 'ecb_send_to_trello called', array( 'post_id' => $post_id, 'entry_keys' => is_array( $entry_values ) ? array_keys( $entry_values ) : array(), 'fields_cnt' => is_array( $fields ) ? count( $fields ) : 0, ) ); if ( ! empty( $ecb_trello_sent_for[ $post_id ] ) ) { ecb_debug( 'Trello skipped: already sent in this request', array( 'post_id' => $post_id ) ); return; } $post = get_post( $post_id ); $extra_fields = get_post_meta( $post_id, '_feedback_extra_fields', true ); $content_fields = ecb_get_feedback_content_fields( $post_id ); $email = isset( $content_fields['_feedback_author_email'] ) ? sanitize_email( trim( (string) $content_fields['_feedback_author_email'] ) ) : ''; $author = isset( $content_fields['_feedback_author'] ) ? sanitize_text_field( trim( (string) $content_fields['_feedback_author'] ) ) : ''; $values_map = array(); if ( is_array( $extra_fields ) && ! empty( $extra_fields ) ) { foreach ( $extra_fields as $k => $v ) { $label = preg_replace( '#^\d+_#', '', (string) $k ); $values_map[ $label ] = is_array( $v ) ? implode( ', ', array_map( 'sanitize_text_field', $v ) ) : sanitize_text_field( (string) $v ); } } elseif ( is_array( $entry_values ) && ! empty( $entry_values ) ) { foreach ( $entry_values as $k => $v ) { $values_map[ (string) $k ] = is_array( $v ) ? implode( ', ', array_map( 'sanitize_text_field', $v ) ) : sanitize_text_field( (string) $v ); } } if ( empty( $email ) ) { $email = ecb_find_email_in_values_map( $values_map ); } if ( empty( $author ) ) { $author = ecb_find_author_in_values_map( $values_map ); } ecb_debug( 'Trello source resolved', array( 'post_exists' => $post ? 'yes' : 'no', 'values_keys' => array_keys( $values_map ), 'email_detected' => ecb_mask_email( $email ), 'author_detected' => $author, ) ); if ( empty( $values_map ) || empty( $email ) || ! is_email( $email ) ) { ecb_debug( 'Trello aborted: no usable values or email', array( 'post_id' => $post_id, 'email' => ecb_mask_email( $email ), ) ); return; } $submitted_url = ''; if ( ! empty( $content_fields['_feedback_all_fields']['entry_permalink'] ) ) { $submitted_url = $content_fields['_feedback_all_fields']['entry_permalink']; } elseif ( $post ) { $submitted_url = get_permalink( $post_id ); } $submitted_time = $post ? get_the_date( 'j M Y', $post ) . ' om ' . get_the_date( 'H:i', $post ) : current_time( 'j M Y' ) . ' om ' . current_time( 'H:i' ); $message = ecb_build_trello_message_from_map( $values_map, $email, $author, $submitted_url, $submitted_time ); $utm_source = $post ? get_post_meta( $post->ID, 'ga_utm_source', true ) : ''; $utm_medium = $post ? get_post_meta( $post->ID, 'ga_utm_medium', true ) : ''; $utm_campaign = $post ? get_post_meta( $post->ID, 'ga_utm_campaign', true ) : ''; $utm_content = $post ? get_post_meta( $post->ID, 'ga_utm_content', true ) : ''; $utm_term = $post ? get_post_meta( $post->ID, 'ga_utm_term', true ) : ''; $utm_map = array( 'UTM source' => $utm_source, 'UTM medium' => $utm_medium, 'UTM campaign' => $utm_campaign, 'UTM term' => $utm_term, 'UTM content' => $utm_content, ); foreach ( $utm_map as $label => $value ) { $value = sanitize_text_field( (string) $value ); if ( '' !== $value ) { $message .= $label . ' = ' . $value . PHP_EOL . PHP_EOL; } } $trello = new Trello_Helper(); $list_id = '5e7a114bf527f1475473160a'; $boards_ids = array( 'zZtCmSLO', 'IhByvCVH', '7wSvbEPa', 'PcNkUCbL', 'bdzE8sRk', 'Qn7S1KzH', 'lEtf9rfj', 'rOlPwxcI', 'PTY0cYFh', 'vKKDwYaf', 'hnrId7Jr' ); $card_exists = false; foreach ( $boards_ids as $board_id ) { $cards = $trello->request( 'GET', "/1/boards/{$board_id}/cards" ); ecb_debug( 'Trello board scan', array( 'board_id' => $board_id, 'cards_type' => gettype( $cards ), 'cards_count' => is_array( $cards ) ? count( $cards ) : 0, ) ); if ( ! is_array( $cards ) ) { continue; } foreach ( $cards as $card ) { if ( empty( $card->desc ) || empty( $card->id ) ) { continue; } if ( false !== strpos( (string) $card->desc, $email ) ) { $card_exists = true; $comment_response = $trello->request( 'POST', '/1/cards/' . $card->id . '/actions/comments', array( 'text' => $message, ) ); ecb_debug( 'Trello comment response', array( 'board_id' => $board_id, 'card_id' => $card->id, 'response_type' => gettype( $comment_response ), 'email' => ecb_mask_email( $email ), ) ); break; } } if ( $card_exists ) { break; } } if ( ! $card_exists ) { $create_response = $trello->request( 'POST', '/1/cards/', array( 'name' => ! empty( $author ) ? $author : $email, 'desc' => $message, 'pos' => 'top', 'idList' => $list_id, ) ); ecb_debug( 'Trello create response', array( 'list_id' => $list_id, 'response_type' => gettype( $create_response ), 'email' => ecb_mask_email( $email ), 'author' => $author, ) ); } $ecb_trello_sent_for[ $post_id ] = true; } function ecb_handle_feedback_post_inserted( $feedback_post_id, $is_spam, $entry_values, $fields ) { ecb_debug( 'grunion_after_feedback_post_inserted fired', array( 'post_id' => $feedback_post_id, 'is_spam' => $is_spam ? 'yes' : 'no', 'entry_keys' => is_array( $entry_values ) ? array_keys( $entry_values ) : array(), 'fields_cnt' => is_array( $fields ) ? count( $fields ) : 0, ) ); if ( $is_spam ) { ecb_debug( 'Feedback ignored because marked as spam', array( 'post_id' => $feedback_post_id ) ); return; } ecb_send_to_trello( $feedback_post_id, $entry_values, $fields ); } function ecb_handle_wp_mail_failed( $wp_error ) { if ( ! is_wp_error( $wp_error ) ) { return; } ecb_debug( 'wp_mail_failed fired', array( 'error_code' => $wp_error->get_error_code(), 'messages' => $wp_error->get_error_messages(), ) ); } add_action( 'grunion_pre_message_sent', 'ecb_send_email_and_set_redirect', 10, 3 ); add_action( 'grunion_after_feedback_post_inserted', 'ecb_handle_feedback_post_inserted', 10, 4 ); add_action( 'wp_mail_failed', 'ecb_handle_wp_mail_failed' );