diff --git a/css/settings.css b/css/settings.css index 701904e5..84af6c2b 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..9b87e51a 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' ), ), ) ); @@ -1464,6 +1465,31 @@ function ( $item ) { 'pass' => isset( $_POST['proxy-pass'] ) ? sanitize_text_field( wp_unslash( $_POST['proxy-pass'] ) ) : '', ); break; + case 'schedules': + if ( feedzy_is_pro() ) { + // 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 ) ) { + $cron_timout = defined( 'WP_CRON_LOCK_TIMEOUT' ) ? WP_CRON_LOCK_TIMEOUT : 60; + + foreach ( $custom_schedules as $key => $value ) { + $interval = isset( $value['interval'] ) ? absint( $value['interval'] ) : $cron_timout; + $display = isset( $value['display'] ) ? sanitize_text_field( $value['display'] ) : ''; + + if ( + is_numeric( $interval ) && $cron_timout <= $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 +3159,35 @@ 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 ) { + if ( ! feedzy_is_pro() ) { + return $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/feedzy-schedules.php b/includes/layouts/feedzy-schedules.php new file mode 100644 index 00000000..3ef5a699 --- /dev/null +++ b/includes/layouts/feedzy-schedules.php @@ -0,0 +1,141 @@ + +
+
+
+

+ + + PRO + +

+
+
+
+ + + /> +
+ +
+ + + /> +
+ +
+ + + /> +
+
+ +
+
+
+
+
+ +
+
+
+ +
+ + + + + + + + + + + + $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 e59bf576..0db65848 100644 --- a/includes/layouts/settings.php +++ b/includes/layouts/settings.php @@ -99,6 +99,17 @@ class="" +
  • + + + + PRO + + +
  • - +
    diff --git a/js/feedzy-setting.js b/js/feedzy-setting.js index fc058b02..af059874 100644 --- a/js/feedzy-setting.js +++ b/js/feedzy-setting.js @@ -171,6 +171,27 @@ jQuery(function ($) { initializeAutoCatActions(); + // Disable the Add Schedule button until all fields are filled. + const validateScheduleForm = () => { + 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); @@ -206,6 +227,110 @@ jQuery(function ($) { }); }); + $('#fz-add-schedule').on('click', function (e) { + e.preventDefault(); + + const formElem = document.querySelector('form:has(.fz-form-wrap)'); + if (formElem && formElem.checkValidity() === false) { + formElem.reportValidity(); + return; + } + + const interval = $('#fz-schedule-interval').val(); + const display = $('#fz-schedule-display').val(); + const name = $('#fz-schedule-name').val(); + + if (!interval || !display || !name) { + return; + } + + $('.fz-schedules-table').show(); + const scheduleTable = $('.fz-schedules-table tbody'); + + 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 = $('