strlen( $end ) && substr( $text, -strlen( $end ) ) === $end; }; return '' !== $domain && ( $domain === $site || $ends( $site, '.' . $domain ) || $ends( $domain, '.' . $site ) ); } /** * Address the replies of customers go to. * * @return string */ public static function reply_to() { $email = (string) Settings::get( 'mail_reply_to' ); return is_email( $email ) ? $email : (string) get_option( 'admin_email' ); } /** * Accent color of the emails. * * @return string */ public static function color() { $color = (string) Settings::get( 'mail_color' ); return preg_match( '/^#[0-9a-f]{6}$/i', $color ) ? $color : '#0e4a37'; } /** * Address of the logo: the one chosen, else the logo or icon of the site, else "". * * @return string */ public static function logo() { $logo = (string) Settings::get( 'mail_logo' ); if ( '' !== $logo && wp_http_validate_url( $logo ) ) { return $logo; } $custom = (int) get_theme_mod( 'custom_logo' ); $url = $custom ? wp_get_attachment_image_url( $custom, 'medium' ) : ''; return $url ? (string) $url : (string) get_site_icon_url( 128 ); } /** * Sends an email to a customer. * * @param string $to Address. * @param string $subject Subject. * @param string $text Text, with blank lines between paragraphs. * @param array $extra automatic: an automatic email such as a confirmation; table: rows of * name, quantity, price and amount with a total; after: text below it; * attachments: paths of files. * @return bool */ public static function customer( $to, $subject, $text, array $extra = array() ) { $headers = array(); if ( ! empty( $extra['automatic'] ) ) { // Out-of-office replies and mailing robots leave automatic emails alone. $headers[] = 'Auto-Submitted: auto-generated'; } $headers[] = 'Reply-To: ' . str_replace( array( '"', '<', '>', ',' ), '', self::from_name() ) . ' <' . self::reply_to() . '>'; return self::send( $to, $subject, self::customer_html( $text, $extra ), self::plain( $text, $extra ), $headers, (array) ( $extra['attachments'] ?? array() ) ); } /** * Sends an email to the owner or a team member. * * @param string|string[] $to Addresses. * @param string $subject Subject. * @param array $content title, text, facts (label => value), items (list of name, * text and url), button (url, label), second (url, label), note. * @return bool */ public static function owner( $to, $subject, array $content ) { $text = trim( implode( "\n\n", array_filter( array( (string) ( $content['title'] ?? '' ), (string) ( $content['text'] ?? '' ), implode( "\n", array_map( static function ( $label, $value ) { return $label . ': ' . $value; }, array_keys( (array) ( $content['facts'] ?? array() ) ), (array) ( $content['facts'] ?? array() ) ) ), implode( "\n", array_map( static function ( $item ) { return '• ' . trim( $item['name'] . ' ' . ( $item['text'] ?? '' ) ) . ( ! empty( $item['url'] ) ? "\n " . $item['url'] : '' ); }, (array) ( $content['items'] ?? array() ) ) ), isset( $content['button'] ) ? $content['button']['label'] . ': ' . $content['button']['url'] : '', (string) ( $content['note'] ?? '' ), ) ) ) ); return self::send( $to, $subject, self::owner_html( $content ), $text, array() ); } /** * Sends HTML with a plain text part. * * @param string|string[] $to Addresses. * @param string $subject Subject. * @param string $html HTML. * @param string $plain Text. * @param string[] $headers More headers. * @param string[] $attachments Paths of files. * @return bool */ private static function send( $to, $subject, $html, $plain, array $headers, array $attachments = array() ) { $use_html = (bool) Settings::get( 'mail_html' ); $from = self::from_email(); $headers[] = 'Content-Type: ' . ( $use_html ? 'text/html' : 'text/plain' ) . '; charset=UTF-8'; $name = static function () { return self::from_name(); }; $address = static function ( $current ) use ( $from ) { return '' !== $from ? $from : $current; }; $alternative = static function ( $mailer ) use ( $plain ) { $mailer->AltBody = $plain; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- PHPMailer. }; add_filter( 'wp_mail_from_name', $name ); add_filter( 'wp_mail_from', $address ); if ( $use_html ) { add_action( 'phpmailer_init', $alternative ); } $sent = wp_mail( $to, $subject, $use_html ? $html : $plain, $headers, $attachments ); remove_filter( 'wp_mail_from_name', $name ); remove_filter( 'wp_mail_from', $address ); remove_action( 'phpmailer_init', $alternative ); return (bool) $sent; } /** * The plain text of an email to a customer. * * @param string $text Text. * @param array $extra Table and text after it. * @return string */ private static function plain( $text, array $extra ) { $parts = array( trim( (string) $text ) ); if ( ! empty( $extra['table']['rows'] ) ) { $lines = array(); foreach ( $extra['table']['rows'] as $row ) { $lines[] = $row['quantity'] . ' × ' . $row['name'] . ', ' . $row['price'] . ': ' . $row['amount']; } $lines[] = $extra['table']['total_label'] . ': ' . $extra['table']['total']; $parts[] = implode( "\n", $lines ); } $parts[] = trim( (string) ( $extra['after'] ?? '' ) ); $parts[] = trim( (string) Settings::get( 'mail_signature' ) ); return implode( "\n\n", array_filter( $parts, 'strlen' ) ); } /** * Paragraphs of a text as HTML, with links. * * @param string $text Text. * @param string $style Style of each paragraph. * @return string */ public static function paragraphs( $text, $style ) { $html = ''; foreach ( preg_split( '/\R{2,}/u', trim( (string) $text ) ) as $paragraph ) { if ( '' === trim( $paragraph ) ) { continue; } $escaped = nl2br( esc_html( trim( $paragraph ) ), false ); $escaped = (string) preg_replace_callback( '~\bhttps?://[^\s<]+[^\s<.,;:!?)]~u', static function ( $url ) { return '' . $url[0] . ''; }, $escaped ); $html .= '
' . $escaped . '
'; } return $html; } /** * The HTML of an email to a customer. * * @param string $text Text. * @param array $extra Table and text after it. * @return string */ public static function customer_html( $text, array $extra = array() ) { $color = self::color(); $logo = self::logo(); $business = Ai::business(); $font = "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif"; $paragraph = 'margin:0 0 16px;font-size:15px;line-height:1.6;color:#1f2a24;'; $cell = 'padding:10px 0;border-bottom:1px solid #e6e9e6;font-size:14px;color:#1f2a24;'; $signature = trim( (string) Settings::get( 'mail_signature' ) ); $preheader = wp_html_excerpt( (string) preg_replace( '/\s+/u', ' ', (string) $text ), 110, '…' ); ob_start(); ?>
|