From ec4029e1c25a7a890c2c73f090dc6a42ed82ad3c Mon Sep 17 00:00:00 2001 From: Soare Robert-Daniel Date: Thu, 14 Aug 2025 11:53:33 +0300 Subject: [PATCH 1/4] feat: add email frequency --- includes/admin/feedzy-rss-feeds-admin.php | 2 +- includes/admin/feedzy-rss-feeds-import.php | 9 ++- includes/admin/feedzy-rss-feeds-log.php | 41 +++++++++- .../admin/feedzy-rss-feeds-task-manager.php | 81 +++++++++++++++---- includes/layouts/feedzy-email-report.php | 27 ++++++- includes/layouts/settings.php | 5 +- includes/views/misc-view.php | 41 ++++++++++ 7 files changed, 177 insertions(+), 29 deletions(-) diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index 2d3e78568..a90468fb8 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -1275,8 +1275,8 @@ private function save_settings() { return; } $post_tab = isset( $_POST['tab'] ) ? sanitize_text_field( wp_unslash( $_POST['tab'] ) ) : ''; - $settings = apply_filters( 'feedzy_get_settings', array() ); + switch ( $post_tab ) { case 'general': $auto_categories_raw = array(); diff --git a/includes/admin/feedzy-rss-feeds-import.php b/includes/admin/feedzy-rss-feeds-import.php index b1609ff8f..05ffed0a2 100644 --- a/includes/admin/feedzy-rss-feeds-import.php +++ b/includes/admin/feedzy-rss-feeds-import.php @@ -3248,14 +3248,15 @@ public function integration_tabs( $tabs ) { public function save_tab_settings( $settings, $tab ) { if ( ! isset( $_POST['nonce'] ) || - ! wp_verify_nonce( sanitize_text_field( wp_unslash( 'nonce' ) ), $tab ) + ! wp_verify_nonce( sanitize_text_field( $_POST['nonce'] ), $tab ) ) { return array(); } - + if ( 'misc' === $tab ) { - $settings['canonical'] = isset( $_POST['canonical'] ) ? absint( $_POST['canonical'] ) : 0; - $settings['general']['rss-feeds'] = isset( $_POST['rss-feeds'] ) ? absint( $_POST['rss-feeds'] ) : ''; + $settings['canonical'] = isset( $_POST['canonical'] ) ? absint( $_POST['canonical'] ) : 0; + $settings['general']['rss-feeds'] = isset( $_POST['rss-feeds'] ) ? absint( $_POST['rss-feeds'] ) : ''; + $settings['logs']['email_frequency'] = isset( $_POST['logs-email-frequency'] ) ? sanitize_text_field( wp_unslash( $_POST['logs-email-frequency'] ) ) : ''; } return $settings; diff --git a/includes/admin/feedzy-rss-feeds-log.php b/includes/admin/feedzy-rss-feeds-log.php index 1d4990281..6c0a35c37 100644 --- a/includes/admin/feedzy-rss-feeds-log.php +++ b/includes/admin/feedzy-rss-feeds-log.php @@ -16,6 +16,7 @@ class Feedzy_Rss_Feeds_Log { /** * Option key for storing log statistics. * + * @since 5.1.0 * @var string Option key for storing log statistics. */ const STATS_OPTION_KEY = 'feedzy_log_stats'; @@ -23,6 +24,7 @@ class Feedzy_Rss_Feeds_Log { /** * Debug level. * + * @since 5.1.0 * @var int Debug level. */ const DEBUG = 100; @@ -30,6 +32,7 @@ class Feedzy_Rss_Feeds_Log { /** * Info level. * + * @since 5.1.0 * @var int Info level. */ const INFO = 200; @@ -37,6 +40,7 @@ class Feedzy_Rss_Feeds_Log { /** * Warning level. * + * @since 5.1.0 * @var int Warning level. */ const WARNING = 300; @@ -44,6 +48,7 @@ class Feedzy_Rss_Feeds_Log { /** * Error level. * + * @since 5.1.0 * @var int Error level. */ const ERROR = 400; @@ -51,6 +56,7 @@ class Feedzy_Rss_Feeds_Log { /** * Ignore level. * + * @since 5.1.0 * @var int Ignore level. */ const NONE = 500; @@ -58,6 +64,7 @@ class Feedzy_Rss_Feeds_Log { /** * Log file name. * + * @since 5.1.0 * @var string Default log name. */ const FILE_NAME = 'feedzy'; @@ -65,6 +72,7 @@ class Feedzy_Rss_Feeds_Log { /** * Log file extension. * + * @since 5.1.0 * @var string Log file extension. */ const FILE_EXT = '.jsonl'; @@ -72,6 +80,7 @@ class Feedzy_Rss_Feeds_Log { /** * Default max file size. * + * @since 5.1.0 * @var int Default max file size in bytes (50MB). */ const DEFAULT_MAX_FILE_SIZE = 50 * 1024 * 1024; @@ -79,6 +88,7 @@ class Feedzy_Rss_Feeds_Log { /** * Default max files. * + * @since 5.1.0 * @var int Default max number of log files. */ const DEFAULT_MAX_FILES = 3; @@ -86,6 +96,7 @@ class Feedzy_Rss_Feeds_Log { /** * Log levels. * + * @since 5.1.0 * @var array Log levels. */ private static $levels = array( @@ -95,6 +106,12 @@ class Feedzy_Rss_Feeds_Log { self::ERROR => 'error', ); + /** + * Priorities mapping. + * + * @since 5.1.0 + * @var array Priorities mapping. + */ const PRIORITIES_MAPPING = array( 'debug' => self::DEBUG, 'info' => self::INFO, @@ -106,6 +123,7 @@ class Feedzy_Rss_Feeds_Log { /** * The single instance of the class. * + * @since 5.1.0 * @var ?self The single instance of the class. */ private static $instance = null; @@ -113,6 +131,7 @@ class Feedzy_Rss_Feeds_Log { /** * The path to the log file. * + * @since 5.1.0 * @var string The path to the log file. */ private $filepath; @@ -120,6 +139,7 @@ class Feedzy_Rss_Feeds_Log { /** * The WordPress filesystem instance. * + * @since 5.1.0 * @var \WP_Filesystem_Base|null The WordPress filesystem instance. */ private $filesystem; @@ -127,6 +147,7 @@ class Feedzy_Rss_Feeds_Log { /** * The context for the logger. * + * @since 5.1.0 * @var array The context for the logger. */ private $context = array(); @@ -134,6 +155,7 @@ class Feedzy_Rss_Feeds_Log { /** * The minimum log level threshold for logging messages. * + * @since 5.1.0 * @var int The minimum log level threshold. */ public $level_threshold = self::ERROR; @@ -141,6 +163,7 @@ class Feedzy_Rss_Feeds_Log { /** * Whether to retain error messages for import run errors meta. * + * @since 5.1.0 * @var string[] */ private $error_messages_accumulator = array(); @@ -148,6 +171,7 @@ class Feedzy_Rss_Feeds_Log { /** * Whether to retain error messages for import run errors meta. * + * @since 5.1.0 * @var bool Whether to retain error messages. */ private $retain_error_messages = false; @@ -155,13 +179,23 @@ class Feedzy_Rss_Feeds_Log { /** * Whether email reports can be sent. * + * @since 5.1.0 * @var bool Whether email reports can be sent. */ public $can_send_email = false; + /** + * The email frequency for sending reports. + * + * @since 5.1.0 + * @var string + */ + public $email_frequency = 'weekly'; + /** * The email address to send reports to. * + * @since 5.1.0 * @var string The email address to send reports to. */ public $to_email = ''; @@ -233,7 +267,7 @@ private function setup_log_directory() { * @return void */ private function init_saved_settings() { - $feedzy_settings = get_option( 'feedzy-settings', array() ); + $feedzy_settings = apply_filters( 'feedzy_get_settings', array() ); if ( ! isset( $feedzy_settings['logs'] ) ) { return; } @@ -242,8 +276,9 @@ private function init_saved_settings() { $this->level_threshold = self::PRIORITIES_MAPPING[ $feedzy_settings['logs']['level'] ]; } - $this->can_send_email = isset( $feedzy_settings['logs']['send_email_report'] ) && $feedzy_settings['logs']['send_email_report']; - $this->to_email = isset( $feedzy_settings['logs']['email'] ) ? sanitize_email( $feedzy_settings['logs']['email'] ) : ''; + $this->can_send_email = isset( $feedzy_settings['logs']['send_email_report'] ) && $feedzy_settings['logs']['send_email_report']; + $this->to_email = isset( $feedzy_settings['logs']['email'] ) ? sanitize_email( $feedzy_settings['logs']['email'] ) : ''; + $this->email_frequency = isset( $feedzy_settings['logs']['email_frequency'] ) ? sanitize_text_field( $feedzy_settings['logs']['email_frequency'] ) : 'weekly'; } /** diff --git a/includes/admin/feedzy-rss-feeds-task-manager.php b/includes/admin/feedzy-rss-feeds-task-manager.php index 482b91dbb..bce538701 100644 --- a/includes/admin/feedzy-rss-feeds-task-manager.php +++ b/includes/admin/feedzy-rss-feeds-task-manager.php @@ -3,11 +3,12 @@ * Register and manage scheduled tasks for Feedzy RSS Feeds. * * @package Feedzy_Rss_Feeds_Task_Manager - * @version 5.1.0 */ /** * Class Feedzy_Rss_Feeds_Task_Manager. + * + * @since 5.1.0 */ class Feedzy_Rss_Feeds_Task_Manager { @@ -22,19 +23,23 @@ public function register_actions() { 'task_feedzy_send_error_report', array( $this, 'send_error_report' ) ); + + add_action( + 'update_option_feedzy-settings', + array( $this, 'maybe_reschedule_email_report' ), + 10, + 3 + ); add_action( 'task_feedzy_cleanup_logs', - function () { - Feedzy_Rss_Feeds_Log::get_instance()->should_clean_logs(); - } + array( $this, 'check_and_clean_logs' ) ); add_action( 'init', function () { - $this->schedule_weekly_tasks(); - $this->schedule_hourly_tasks(); + $this->schedule_tasks(); } ); } @@ -45,7 +50,22 @@ function () { * @since 5.1.0 * @return void */ - public function schedule_weekly_tasks() { + public function schedule_tasks() { + if ( + false === Feedzy_Rss_Feeds_Util_Scheduler::is_scheduled( 'task_feedzy_cleanup_logs' ) + ) { + Feedzy_Rss_Feeds_Util_Scheduler::schedule_event( time(), 'hourly', 'task_feedzy_cleanup_logs' ); + } + $this->schedule_email_report(); + } + + /** + * Schedule daily tasks. + * + * @since 5.1.0 + * @return void + */ + public function schedule_email_report() { $log_instance = Feedzy_Rss_Feeds_Log::get_instance(); if ( @@ -54,24 +74,55 @@ public function schedule_weekly_tasks() { ) { return; } - - Feedzy_Rss_Feeds_Util_Scheduler::schedule_event( time(), 'weekly', 'task_feedzy_send_error_report' ); + + $frequency = $log_instance->email_frequency; + if ( ! in_array( $frequency, array( 'daily', 'weekly' ), true ) ) { + $frequency = 'weekly'; + } + + Feedzy_Rss_Feeds_Util_Scheduler::schedule_event( time(), $frequency, 'task_feedzy_send_error_report' ); } /** - * Schedule daily tasks. + * When feedzy settings are updated, ensure the error report schedule matches the new frequency. * * @since 5.1.0 + * @param array $old_value Previous option value. + * @param array $value New option value. + * @param string $option Option name (unused). * @return void */ - public function schedule_hourly_tasks() { - if ( - false !== Feedzy_Rss_Feeds_Util_Scheduler::is_scheduled( 'task_feedzy_cleanup_logs' ) - ) { + public function maybe_reschedule_email_report( $old_value, $value, $option ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + + $old_freq = isset( $old_value['logs']['email_frequency'] ) ? sanitize_text_field( $old_value['logs']['email_frequency'] ) : ''; + $new_freq = isset( $value['logs']['email_frequency'] ) ? sanitize_text_field( $value['logs']['email_frequency'] ) : ''; + + if ( $old_freq === $new_freq ) { return; } + + Feedzy_Rss_Feeds_Util_Scheduler::clear_scheduled_hook( 'task_feedzy_send_error_report' ); + + if ( ! in_array( $new_freq, array( 'daily', 'weekly' ), true ) ) { + $new_freq = 'weekly'; + } + + $send_reports = ! empty( $value['logs']['send_email_report'] ); + $to_email = isset( $value['logs']['email'] ) ? sanitize_email( $value['logs']['email'] ) : ''; + + if ( $send_reports && ! empty( $to_email ) ) { + Feedzy_Rss_Feeds_Util_Scheduler::schedule_event( time(), $new_freq, 'task_feedzy_send_error_report' ); + } + } - Feedzy_Rss_Feeds_Util_Scheduler::schedule_event( time(), 'hourly', 'task_feedzy_cleanup_logs' ); + /** + * Check and clean logs if necessary. + * + * @since 5.1.0 + * @return void + */ + public function check_and_clean_logs() { + Feedzy_Rss_Feeds_Log::get_instance()->should_clean_logs(); } /** diff --git a/includes/layouts/feedzy-email-report.php b/includes/layouts/feedzy-email-report.php index e32a6e34c..b77d2b249 100644 --- a/includes/layouts/feedzy-email-report.php +++ b/includes/layouts/feedzy-email-report.php @@ -11,10 +11,17 @@ } // Extract variables that should be available -$site_name = isset( $site_name ) ? $site_name : get_bloginfo( 'name' ); -$generated_date = isset( $generated_date ) ? $generated_date : date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ); -$stats = isset( $stats ) ? $stats : array(); -$logs_entries = isset( $logs_entries ) ? $logs_entries : array(); +$site_name = isset( $site_name ) ? $site_name : get_bloginfo( 'name' ); +$generated_date = isset( $generated_date ) ? $generated_date : date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ); +$stats = isset( $stats ) ? $stats : array(); +$logs_entries = isset( $logs_entries ) ? $logs_entries : array(); +$see_all_logs_link = add_query_arg( + array( + 'page' => 'feedzy-settings', + 'tab' => 'logs', + ), + admin_url( 'admin.php' ) +); ?> @@ -29,6 +36,9 @@ .timestamp { color: #6c757d; font-size: 0.9em; } .level { font-weight: bold; color: #dc3545; } .context { color: #6c757d; font-style: italic; font-size: 0.9em; margin-top: 5px; } + .logs-link { text-align: center; margin-top: 20px; } + .logs-link a { color: #0073aa; text-decoration: none; font-weight: bold; } + .logs-link a:hover { text-decoration: underline; } @@ -72,6 +82,7 @@

+
@@ -89,5 +100,13 @@ + + diff --git a/includes/layouts/settings.php b/includes/layouts/settings.php index f3c1162f8..a22136c4c 100644 --- a/includes/layouts/settings.php +++ b/includes/layouts/settings.php @@ -360,10 +360,11 @@ class="fz-switch-toggle" class="form-label" > - ()
- +
+ +
+
+
+
+
+ + free_settings['logs'], $this->free_settings['logs']['email_frequency'] ) ? $this->free_settings['logs']['email_frequency'] : ''; + + $registered_schedules = wp_get_schedules(); + $schedules = array(); + + if ( isset( $registered_schedules['weekly'] ) ) { + $schedules['weekly'] = $registered_schedules['weekly']; + } + + if ( isset( $registered_schedules['daily'] ) ) { + $schedules['daily'] = $registered_schedules['daily']; + } + + ?> + +
+
+
+
From 2622e600a4aa23b7be86fbbd74eb4390fc3db39b Mon Sep 17 00:00:00 2001 From: Soare Robert-Daniel Date: Thu, 14 Aug 2025 11:59:47 +0300 Subject: [PATCH 2/4] chore: formatting --- includes/admin/feedzy-rss-feeds-import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/admin/feedzy-rss-feeds-import.php b/includes/admin/feedzy-rss-feeds-import.php index 05ffed0a2..9f3111a72 100644 --- a/includes/admin/feedzy-rss-feeds-import.php +++ b/includes/admin/feedzy-rss-feeds-import.php @@ -3252,7 +3252,7 @@ public function save_tab_settings( $settings, $tab ) { ) { return array(); } - + if ( 'misc' === $tab ) { $settings['canonical'] = isset( $_POST['canonical'] ) ? absint( $_POST['canonical'] ) : 0; $settings['general']['rss-feeds'] = isset( $_POST['rss-feeds'] ) ? absint( $_POST['rss-feeds'] ) : ''; From e6662bea34d23e3e3c77324b3a8037508c85ad17 Mon Sep 17 00:00:00 2001 From: Soare Robert-Daniel Date: Thu, 14 Aug 2025 12:06:31 +0300 Subject: [PATCH 3/4] fix: E2E --- tests/e2e/specs/logger.spec.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/e2e/specs/logger.spec.js b/tests/e2e/specs/logger.spec.js index 6d6f14eb7..1eb7e97b0 100644 --- a/tests/e2e/specs/logger.spec.js +++ b/tests/e2e/specs/logger.spec.js @@ -18,9 +18,7 @@ test.describe('Logger', () => { page.locator('select[name="logs-logging-level"]') ).toBeVisible(); - await expect( - page.getByText('Report errors via email (Once') - ).toBeVisible(); + await expect(page.getByText('Report errors via email')).toBeVisible(); }); test('check logs tabs', async ({ page, admin }) => { From e9f2935dc48efb954b4c14928dfc251289f70c96 Mon Sep 17 00:00:00 2001 From: Soare Robert-Daniel Date: Mon, 18 Aug 2025 12:19:17 +0300 Subject: [PATCH 4/4] chore: review --- includes/admin/feedzy-rss-feeds-task-manager.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/includes/admin/feedzy-rss-feeds-task-manager.php b/includes/admin/feedzy-rss-feeds-task-manager.php index bce538701..a6843684c 100644 --- a/includes/admin/feedzy-rss-feeds-task-manager.php +++ b/includes/admin/feedzy-rss-feeds-task-manager.php @@ -28,7 +28,7 @@ public function register_actions() { 'update_option_feedzy-settings', array( $this, 'maybe_reschedule_email_report' ), 10, - 3 + 2 ); add_action( @@ -89,11 +89,9 @@ public function schedule_email_report() { * @since 5.1.0 * @param array $old_value Previous option value. * @param array $value New option value. - * @param string $option Option name (unused). * @return void */ - public function maybe_reschedule_email_report( $old_value, $value, $option ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable - + public function maybe_reschedule_email_report( $old_value, $value ) { $old_freq = isset( $old_value['logs']['email_frequency'] ) ? sanitize_text_field( $old_value['logs']['email_frequency'] ) : ''; $new_freq = isset( $value['logs']['email_frequency'] ) ? sanitize_text_field( $value['logs']['email_frequency'] ) : '';