From d6396760a7b0d7c4132ff36f2619dd17f7c83807 Mon Sep 17 00:00:00 2001 From: RaduCristianPopescu <119046336+RaduCristianPopescu@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:03:23 +0300 Subject: [PATCH 1/5] feat: added a new tab for schedules --- css/settings.css | 34 ++++++- includes/admin/feedzy-rss-feeds-admin.php | 43 ++++++++ includes/feedzy-rss-feeds.php | 1 + includes/layouts/settings.php | 119 +++++++++++++++++++++- js/feedzy-setting.js | 52 ++++++++++ 5 files changed, 247 insertions(+), 2 deletions(-) diff --git a/css/settings.css b/css/settings.css index 701904e5..bf2a72b8 100644 --- a/css/settings.css +++ b/css/settings.css @@ -2947,4 +2947,36 @@ button.feedzy-action-button { #feedzy-validate-feed .dashicons { font-size: 20px; -} \ No newline at end of file +} + +.fz-schedule-counter { + text-align: right; + margin-bottom: 10px; + color: #757575; + font-size: 13px; +} + + .fz-schedules-table { + border-collapse: collapse; +} + +.fz-schedules-table th { + font-weight: 600; + background: #f6f7f7; +} + +.fz-schedules-table td { + padding: 10px; +} + +.fz-schedule-attributes { + color: #050505; +} + +.fz-delete-schedule.fz-is-destructive { + background: #dc3545; + border-color: #dc3545; + color: #ffffff; + font-size: 12px; + padding: 4px 12px; +} diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index f943e3c5..7596ee98 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -1464,6 +1464,23 @@ function ( $item ) { 'pass' => isset( $_POST['proxy-pass'] ) ? sanitize_text_field( wp_unslash( $_POST['proxy-pass'] ) ) : '', ); break; + case 'schedules': + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $custom_schedules = isset( $_POST['fz-custom-schedule-interval'] ) ? (array) wp_unslash( $_POST['fz-custom-schedule-interval'] ) : array(); + $settings['custom_schedules'] = array(); + if ( ! empty( $custom_schedules ) ) { + foreach ( $custom_schedules as $key => $value ) { + $interval = isset( $value['interval'] ) ? absint( $value['interval'] ) : 0; + $display = isset( $value['display'] ) ? sanitize_text_field( $value['display'] ) : ''; + if ( ! empty( $interval ) && ! empty( $display ) ) { + $settings['custom_schedules'][ $key ] = array( + 'interval' => $interval, + 'display' => $display, + ); + } + } + } + break; default: $settings = apply_filters( 'feedzy_save_tab_settings', $settings, $post_tab ); } @@ -3133,6 +3150,32 @@ public function validate_feed() { } } + /** + * Append custom schedules to the existing schedules. + * + * @since 5.1.0 + * @param array $schedules Existing schedules. + * @return array Modified schedules with custom schedules appended. + */ + public function append_custom_cron_schedules( $schedules ) { + + $saved_settings = apply_filters( 'feedzy_get_settings', array() ); + if ( ! empty( $saved_settings['custom_schedules'] ) || ! is_array( $saved_settings['custom_schedules'] ) ) { + $custom_schedules = $saved_settings['custom_schedules']; + + foreach ( $custom_schedules as $key => $value ) { + if ( ! empty( $value['interval'] ) && ! empty( $value['display'] ) ) { + $schedules[ $key ] = array( + 'interval' => intval( $value['interval'] ), + 'display' => sanitize_text_field( $value['display'] ), + ); + } + } + } + + return $schedules; + } + /** * Add slugs for internal cron schedules. * diff --git a/includes/feedzy-rss-feeds.php b/includes/feedzy-rss-feeds.php index 028bd85c..f7232a98 100644 --- a/includes/feedzy-rss-feeds.php +++ b/includes/feedzy-rss-feeds.php @@ -206,6 +206,7 @@ private function define_admin_hooks() { self::$instance->loader->add_action( 'wp_ajax_feedzy_validate_feed', self::$instance->admin, 'validate_feed' ); self::$instance->loader->add_action( 'wp_ajax_feedzy_dashboard_subscribe', self::$instance->admin, 'feedzy_dashboard_subscribe' ); self::$instance->loader->add_filter( 'feedzy_internal_cron_schedule_slugs', self::$instance->admin, 'internal_cron_schedule_slugs', 10, 1 ); + self::$instance->loader->add_filter( 'cron_schedules', self::$instance->admin, 'append_custom_cron_schedules' ); // do not load this with the loader as this will need a corresponding remove_filter also. add_filter( 'update_post_metadata', array( self::$instance->admin, 'validate_category_feeds' ), 10, 5 ); diff --git a/includes/layouts/settings.php b/includes/layouts/settings.php index e59bf576..979857f9 100644 --- a/includes/layouts/settings.php +++ b/includes/layouts/settings.php @@ -32,6 +32,11 @@ $email_error_enabled = isset( $settings['logs'], $settings['logs']['send_email_report'] ) ? $settings['logs']['send_email_report'] : 0; $email_error_address_placeholder = ( ! empty( $email_error_address ) ) ? $email_error_address : get_option( 'admin_email' ); + $custom_schedules = array(); + if ( isset( $settings['custom_schedules'] ) && is_array( $settings['custom_schedules'] ) ) { + $custom_schedules = $settings['custom_schedules']; + } + if ( 'logs' === $active_tab ) { $logs_type = isset( $_REQUEST['logs_type'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['logs_type'] ) ) : null;// phpcs:ignore WordPress.Security.NonceVerification $logs = Feedzy_Rss_Feeds_Log::get_instance()->get_recent_logs( 50, $logs_type ); @@ -99,6 +104,14 @@ class="" +
  • + + + +
  • +
    +
    +
    +

    + +

    +
    +
    +
    + + +
    + +
    + + +
    + +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    + + + + + + + + + + + + $schedule ) : + $interval_seconds = $schedule['interval']; + $interval_display = $interval_seconds . ' (' . human_time_diff( 0, $interval_seconds ) . ')'; + ?> + + + + + + + + + + + + + + + +
    + + + + + + + +
    +
    + +
    + - +
    diff --git a/js/feedzy-setting.js b/js/feedzy-setting.js index fc058b02..1f70abda 100644 --- a/js/feedzy-setting.js +++ b/js/feedzy-setting.js @@ -206,6 +206,58 @@ jQuery(function ($) { }); }); + $('#fz-add-schedule').on('click', function (e) { + e.preventDefault(); + + const interval = $('#fz-schedule-interval').val(); + const display = $('#fz-schedule-display').val(); + const name = $('#fz-schedule-name').val(); + + if (!interval || !display || !name) { + return; + } + + const scheduleTable = $('.fz-schedules-table tbody'); + + const newRow = $(` + + + ${name} + + + ${interval} + + + ${display} + + + + + + + + `); + + scheduleTable.append(newRow); + + $('#fz-schedule-interval').val(''); + $('#fz-schedule-display').val(''); + $('#fz-schedule-name').val(''); + }); + + $(document).on('click', '.fz-delete-schedule', function (e) { + e.preventDefault(); + + const $button = $(this); + const $row = $button.closest('tr'); + + $row.fadeOut(300, function () { + $(this).remove(); + }); + }); + /** * Toggle visibility of the email error address field based on email error enabled checkbox. */ From e8dcbe2431a4b453f90b49617ad9947c0ee5507a Mon Sep 17 00:00:00 2001 From: RaduCristianPopescu <119046336+RaduCristianPopescu@users.noreply.github.com> Date: Thu, 14 Aug 2025 17:09:56 +0300 Subject: [PATCH 2/5] fix: issues --- css/settings.css | 4 +- includes/admin/feedzy-rss-feeds-admin.php | 3 +- includes/layouts/settings.php | 13 +++- js/feedzy-setting.js | 73 ++++++++++++++++------- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/css/settings.css b/css/settings.css index bf2a72b8..84af6c2b 100644 --- a/css/settings.css +++ b/css/settings.css @@ -2955,8 +2955,8 @@ button.feedzy-action-button { color: #757575; font-size: 13px; } - - .fz-schedules-table { + +.fz-schedules-table { border-collapse: collapse; } diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index 7596ee98..3e7ac3a0 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -231,6 +231,7 @@ public function enqueue_styles_admin() { 'media_iframe_button' => __( 'Set default image', 'feedzy-rss-feeds' ), 'action_btn_text_1' => __( 'Choose image', 'feedzy-rss-feeds' ), 'action_btn_text_2' => __( 'Replace image', 'feedzy-rss-feeds' ), + 'delete_btn_label' => __( 'Delete', 'feedzy-rss-feeds' ), ), ) ); @@ -3160,7 +3161,7 @@ public function validate_feed() { public function append_custom_cron_schedules( $schedules ) { $saved_settings = apply_filters( 'feedzy_get_settings', array() ); - if ( ! empty( $saved_settings['custom_schedules'] ) || ! is_array( $saved_settings['custom_schedules'] ) ) { + if ( ! empty( $saved_settings['custom_schedules'] ) && is_array( $saved_settings['custom_schedules'] ) ) { $custom_schedules = $saved_settings['custom_schedules']; foreach ( $custom_schedules as $key => $value ) { diff --git a/includes/layouts/settings.php b/includes/layouts/settings.php index 979857f9..390715df 100644 --- a/includes/layouts/settings.php +++ b/includes/layouts/settings.php @@ -533,21 +533,28 @@ class="form-control" - +
    - +
    - +
    - - - - - `); + const newRow = $('').attr('data-schedule', name); + + const nameCell = $('') + .addClass('fz-schedule-attributes') + .append($('').text(name)); + + const intervalCell = $('') + .addClass('fz-schedule-attributes') + .text(interval); + const displayCell = $('') + .addClass('fz-schedule-attributes') + .text(display); + + const deleteButton = $(' +
    + + + + + +
    +
    +
    + +
    + + + + + + + + + + + + $schedule ) : + $interval_seconds = $schedule['interval']; + $interval_display = $interval_seconds . ' (' . human_time_diff( 0, $interval_seconds ) . ')'; + ?> + + + + + + + + + + + + + + + +
    + + + + + + + +
    +
    +
    + \ No newline at end of file diff --git a/includes/layouts/settings.php b/includes/layouts/settings.php index 390715df..0db65848 100644 --- a/includes/layouts/settings.php +++ b/includes/layouts/settings.php @@ -32,11 +32,6 @@ $email_error_enabled = isset( $settings['logs'], $settings['logs']['send_email_report'] ) ? $settings['logs']['send_email_report'] : 0; $email_error_address_placeholder = ( ! empty( $email_error_address ) ) ? $email_error_address : get_option( 'admin_email' ); - $custom_schedules = array(); - if ( isset( $settings['custom_schedules'] ) && is_array( $settings['custom_schedules'] ) ) { - $custom_schedules = $settings['custom_schedules']; - } - if ( 'logs' === $active_tab ) { $logs_type = isset( $_REQUEST['logs_type'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['logs_type'] ) ) : null;// phpcs:ignore WordPress.Security.NonceVerification $logs = Feedzy_Rss_Feeds_Log::get_instance()->get_recent_logs( 50, $logs_type ); @@ -110,6 +105,9 @@ class="" class="" > + + PRO + -
    -
    -
    -

    - -

    -
    -
    -
    - - -
    - -
    - - -
    - -
    - - -
    -
    - -
    -
    -
    -
    -
    - -
    -
    - -
    - - - - - - - - - - - - $schedule ) : - $interval_seconds = $schedule['interval']; - $interval_display = $interval_seconds . ' (' . human_time_diff( 0, $interval_seconds ) . ')'; - ?> - - - - - - - - - - - - - - - -
    - - - - - - - -
    -
    - -
    - { + const interval = $('#fz-schedule-interval').val().trim(); + const display = $('#fz-schedule-display').val().trim(); + const name = $('#fz-schedule-name').val().trim(); + const button = $('#fz-add-schedule'); + + const isValid = interval && display && name; + button.prop('disabled', !isValid); + button.toggleClass('disabled', !isValid); + }; + + // Initial validation check. + validateScheduleForm(); + + // Add event listeners to schedule form inputs. + $('#fz-schedule-interval, #fz-schedule-display, #fz-schedule-name').on( + 'input keyup', + validateScheduleForm + ); + $('#feedzy-delete-log-file').on('click', function (e) { e.preventDefault(); const _this = $(this); @@ -223,6 +244,7 @@ jQuery(function ($) { return; } + $('.fz-schedules-table').show(); const scheduleTable = $('.fz-schedules-table tbody'); const newRow = $('').attr('data-schedule', name); @@ -275,9 +297,16 @@ jQuery(function ($) { scheduleTable.append(newRow); + // Update counter + const currentCount = scheduleTable.children().length; + $('.fz-schedule-counter').text(`${currentCount} items`); + $('#fz-schedule-interval').val(''); $('#fz-schedule-display').val(''); $('#fz-schedule-name').val(''); + + // Re-validate form after clearing fields + validateScheduleForm(); }); $(document).on('click', '.fz-delete-schedule', function (e) { @@ -285,9 +314,20 @@ jQuery(function ($) { const $button = $(this); const $row = $button.closest('tr'); + const scheduleTable = $('.fz-schedules-table tbody'); $row.fadeOut(300, function () { $(this).remove(); + + // Update counter + const currentCount = scheduleTable.children().length; + $('.fz-schedule-counter').text(`${currentCount} items`); + + // Show empty state and hide table if no schedules left + if (currentCount === 0) { + $('.fz-schedules-table').hide(); + $('.fz-empty-state').show(); + } }); }); From 8b553ae0c2fa33cb29001254397daeaef203b0f6 Mon Sep 17 00:00:00 2001 From: Soare Robert-Daniel Date: Thu, 14 Aug 2025 18:02:02 +0300 Subject: [PATCH 5/5] chore: pro display --- includes/layouts/feedzy-schedules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/layouts/feedzy-schedules.php b/includes/layouts/feedzy-schedules.php index 6b7f8abc..3ef5a699 100644 --- a/includes/layouts/feedzy-schedules.php +++ b/includes/layouts/feedzy-schedules.php @@ -76,7 +76,7 @@ class="form-block" >