k(), 'info_block' => ( new InfoBlocks() )->get_next(), 'icons' => $this->get_icons_url(), ], ]; $template = ( new Templates\Summary() )->set_args( $args ); /** * Filters the summaries email template. * * @since 1.5.4 * * @param Templates\Summary $template Default summaries email template. */ $template = apply_filters( 'wpforms_emails_summaries_template', $template ); $content = $template->get(); if ( Helpers::is_plain_text_template() ) { $content = wpautop( $content ); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $content; exit; } /** * Get next cron occurrence date. * * @since 1.5.4 * * @return int */ protected function get_first_cron_date_gmt(): int { $date = absint( strtotime( 'next monday 2pm' ) - ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ); return $date ? $date : time(); } /** * Add custom Email Summaries cron schedule. * * @since 1.5.4 * * @param array $schedules WP cron schedules. * * @return array */ public function add_weekly_cron_schedule( $schedules ) { $schedules['wpforms_email_summaries_weekly'] = [ // Make sure the cron job runs on Monday at 2pm. 'interval' => $this->get_first_cron_date_gmt() - time(), 'display' => esc_html__( 'Weekly WPForms Email Summaries', 'wpforms-lite' ), ]; return $schedules; } /** * Email Summaries cron callback. * * @since 1.5.4 */ public function cron() { $entries = $this->get_entries(); // Email won't be sent if there are no form entries. if ( empty( $entries ) ) { return; } $notification = new NotificationBlocks(); $notification_block = $notification->get_block(); $info_blocks = new InfoBlocks(); $next_block = $info_blocks->get_next(); $args = [ 'body' => [ 'overview' => $this->get_calculation_overview( $entries ), 'entries' => $this->format_trends_for_display( $entries ), 'has_trends' => $this->entries_has_trends( $entries ), 'notification_block' => $notification_block, 'info_block' => $next_block, 'icons' => $this->get_icons_url(), ], ]; $template = ( new Templates\Summary() )->set_args( $args ); /** This filter is documented in preview() method above. */ $template = apply_filters( 'wpforms_emails_summaries_template', $template ); $content = $template->get(); if ( ! $content ) { return; } $parsed_home_url = wp_parse_url( home_url() ); $site_domain = $parsed_home_url['host']; if ( is_multisite() && isset( $parsed_home_url['path'] ) ) { $site_domain .= $parsed_home_url['path']; } $subject = sprintf( /* translators: %s - site domain. */ esc_html__( 'Your Weekly WPForms Summary for %s', 'wpforms-lite' ), $site_domain ); /** * Filters the summaries email subject. * * @since 1.5.4 * * @param string $subject Default summaries email subject. */ $subject = apply_filters( 'wpforms_emails_summaries_cron_subject', $subject ); /** * Filters the summaries recipient email address. * * @since 1.5.4 * * @param string $option Default summaries recipient email address. */ $to_email = apply_filters( 'wpforms_emails_summaries_cron_to_email', get_option( 'admin_email' ) ); $sent = ( new Mailer() ) ->template( $template ) ->subject( $subject ) ->to_email( $to_email ) ->send(); if ( $sent === true ) { $info_blocks->register_sent( $next_block ); // Cache the notification block shown to avoid showing it again in the future. $notification->maybe_remember_shown_block( $notification_block ); } } /** * Get form entries. * * @since 1.5.4 * * @return array */ protected function get_entries(): array { // The return value is intentionally left empty, as each email summary // depending on the plugin edition Lite/Pro will have different implementation. return []; } /** * Get calculation overview. * * @since 1.8.8 * * @param array $entries Form entries. * * @return array */ private function get_calculation_overview( $entries ): array { // Check if the entries array is empty. if ( empty( $entries ) ) { return []; } // Get the sum of 'count' index in all entries. $sum_current = array_sum( array_column( $entries, 'count' ) ); // Choose a specific 'form_id' to check if 'count_previous_week' index exists. $sample_form_id = key( $entries ); // Check if 'count_previous_week' index doesn't exist and return early. if ( ! isset( $entries[ $sample_form_id ]['count_previous_week'] ) ) { return []; } // Get the sum of 'count_previous_week' index in all entries. $sum_previous_week = array_sum( array_column( $entries, 'count_previous_week' ) ); // Check if the sum of counts from the previous week is 0. // If so, return the sum of counts from the current week and trends as "+100%". if ( $sum_previous_week === 0 ) { return [ 'total' => $sum_current, 'trends' => $this->format_trends_for_display( $sum_current === 0 ? 0 : 100 ), ]; } // Calculate trends based on the sum of counts from the current week and the previous week. $trends = round( ( $sum_current - $sum_previous_week ) / $sum_previous_week * 100 ); // Return an array with the total and trends. return [ 'total' => $sum_current, 'trends' => $this->format_trends_for_display( $trends ), ]; } /** * Register Action Scheduler task to fetch and cache Info Blocks. * * @since 1.6.4 * * @param \WPForms\Tasks\Task[] $tasks List of task classes. * * @return array */ public static function register_fetch_info_blocks_task( $tasks ): array { $tasks[] = FetchInfoBlocksTask::class; return $tasks; } /** * Deregister Action Scheduler task to fetch and cache Info Blocks. * * @since 1.6.4 */ public function deregister_fetch_info_blocks_task() { if ( ! $this->is_disabled() ) { return; } // Deregister the task. ( new FetchInfoBlocksTask() )->cancel(); // Delete last run time record. delete_option( FetchInfoBlocksTask::LAST_RUN ); // Remove the cache file if it exists. $file_name = ( new InfoBlocks() )->get_cache_file_path(); if ( file_exists( $file_name ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.unlink_unlink @unlink( $file_name ); } } /** * Check if the current request is a preview for the summaries email template. * * @since 1.8.8 * * @return bool */ private function is_preview(): bool { // Leave if the current user can't access. if ( ! wpforms_current_user_can() ) { return false; } // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized // Leave early if nonce verification failed. if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), Preview::PREVIEW_NONCE_NAME ) ) { return false; } // Leave early if preview is not requested. if ( ! isset( $_GET['wpforms_email_preview'], $_GET['wpforms_email_template'] ) ) { return false; } // Leave early if preview is not requested for the summaries template. if ( $_GET['wpforms_email_template'] !== 'summary' ) { return false; } // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized return true; } /** * Format entries trends for display. * * This function takes an array of entries and formats the 'trends' value for display. * * @since 1.8.8 * * @param array|int $input Input data to format. * * @return array|string */ private function format_trends_for_display( $input ) { // If input is a numeric value, format and return it. if ( is_numeric( $input ) ) { return sprintf( '%s%s%%', $input >= 0 ? '+' : '', $input ); } // Loop through entries and format 'trends' values. foreach ( $input as &$form ) { // Leave early if 'trends' index doesn't exist. if ( ! isset( $form['trends'] ) ) { continue; } // Add percent sign to trends and + sign if value greater than zero. $form['trends'] = sprintf( '%s%s%%', $form['trends'] >= 0 ? '+' : '', $form['trends'] ); } return $input; } /** * Check if trends can be displayed for the given entries. * * @since 1.8.8 * * @param array $entries The entries data. * * @return bool */ private function entries_has_trends( array $entries ): bool { // Return false if entries array is empty. if ( empty( $entries ) ) { return false; } // Check if at least one array item has the 'trends' key. foreach ( $entries as $entry ) { if ( isset( $entry['trends'] ) ) { return true; } } return false; } /** * Get icons URL. * Primarily used in the HTML version of the email template. * * @since 1.8.8 * * @return array */ private function get_icons_url(): array { $base_url = WPFORMS_PLUGIN_URL . 'assets/images/email/'; return [ 'overview' => $base_url . 'icon-overview.png', 'upward' => $base_url . 'icon-upward.png', 'downward' => $base_url . 'icon-downward.png', 'notification_block' => $base_url . 'notification-block-icon.png', 'info_block' => $base_url . 'info-block-icon.png', ]; } }