getTimestamp(), 'weekly', self::HOOK ); } /** * Whether the week goes to Telegram too. * * @return bool */ private static function telegram() { return Settings::get( 'telegram_weekly' ) && Notifier::telegram_ready(); } /** * Cron callback. Stays quiet when nothing happened for two weeks. */ public function send_scheduled() { // The advice of the week is written before it goes out. if ( Ai::enabled() ) { Ai_Coach::refresh(); } $data = self::data(); if ( 0 === $data['current']['leads'] && 0 === $data['previous']['leads'] && 0 === ( $data['current']['clicks']['_total'] ?? 0 ) ) { return; } if ( Settings::get( 'digest_enabled' ) ) { self::send( $data ); } if ( self::telegram() ) { self::send_telegram(); } } /** * Sends the week in a few sentences to Telegram. * * @return true|\WP_Error */ public static function send_telegram() { $switched = function_exists( 'switch_to_locale' ) && switch_to_locale( Ai::team_locale() ); $text = Insights::telegram( Insights::week(), Ai_Coach::current() ); if ( $switched ) { restore_previous_locale(); } return Notifier::send_telegram( Settings::get( 'telegram_token' ), Settings::get( 'telegram_chat_id' ), $text ); } /** * Recipients: the configured list, or the site admin. * * @return string[] */ public static function recipients() { $list = array_filter( array_map( 'trim', explode( ',', (string) Settings::get( 'digest_recipients' ) ) ), 'is_email' ); return $list ? array_values( $list ) : array( get_option( 'admin_email' ) ); } /** * Numbers for the last seven days and the seven days before. * * @return array */ public static function data() { $current = Reports::breakdown( '7d', 'channel', 'first' ); $previous = self::previous_week(); return array( /** This filter is documented in includes/admin/class-leads-page.php */ 'current' => array_merge( Reports::empty_row(), (array) apply_filters( 'dealroot_report_totals', Reports::totals( $current ), '7d', 'channel' ) ), 'previous' => $previous, 'channels' => array_slice( $current, 0, 5, true ), 'insights' => Insights::week(), 'coach' => Ai_Coach::current(), ); } /** * Lead count for days 8 to 14 ago. * * @return array */ private static function previous_week() { $result = Leads::query( array( 'from' => gmdate( 'Y-m-d H:i:s', time() - 14 * DAY_IN_SECONDS ), 'to' => gmdate( 'Y-m-d H:i:s', time() - 7 * DAY_IN_SECONDS ), 'per_page' => 1, ) ); return array( 'leads' => $result['total'] ); } /** * Builds and sends the email. * * @param array|null $data Prepared numbers. * @return bool */ public static function send( $data = null ) { $data = $data ? $data : self::data(); $current = $data['current']; $site = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); /* translators: %s: site name. */ $subject = sprintf( __( 'Your leads this week – %s', 'dealroot' ), $site ); $switched = function_exists( 'switch_to_locale' ) && switch_to_locale( Ai::team_locale() ); ob_start(); self::render( $data, $site ); $body = (string) ob_get_clean(); if ( $switched ) { restore_previous_locale(); } /** * Filters the weekly email before it is sent. * * @param array $email to, subject, body. * @param array $data Numbers. */ $email = apply_filters( 'dealroot_digest_email', array( 'to' => self::recipients(), 'subject' => $subject, 'body' => $body, ), $data ); return wp_mail( $email['to'], $email['subject'], $email['body'], array( 'Content-Type: text/html; charset=UTF-8' ) ); } /** * Email HTML. Inline styles because mail clients ignore stylesheets. * * @param array $data Numbers. * @param string $site Site name. */ private static function render( array $data, $site ) { $current = $data['current']; $delta = $current['leads'] - $data['previous']['leads']; $clicks = (int) ( $current['clicks']['_total'] ?? 0 ); $cell = 'padding:8px 12px;border-bottom:1px solid #eee;'; ?>