From 40ac854cd25b68aaec5343a7cf51e8a31de6f6db Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Tue, 29 Jul 2025 12:06:52 +0530 Subject: [PATCH 1/6] feat: improve feed group UX --- css/settings.css | 23 +++ .../feedzy-rss-feeds-admin-abstract.php | 2 +- includes/admin/feedzy-rss-feeds-admin.php | 174 +++++++++++++++++- includes/feedzy-rss-feeds-activator.php | 30 +++ includes/feedzy-rss-feeds-feed-tweaks.php | 7 +- js/categories.js | 35 ++++ 6 files changed, 266 insertions(+), 5 deletions(-) diff --git a/css/settings.css b/css/settings.css index b21afe773..c056ccf18 100644 --- a/css/settings.css +++ b/css/settings.css @@ -2620,6 +2620,29 @@ li.draggable-item .components-panel__body-toggle.components-button{ color: #050505; } +.validate-feeds-actions { + display: flex;; +} +.validate-feeds-actions .spinner:not(.is-active) { + display: none; +} +.validate-feeds-actions .spinner.is-active { + display: inline-block; +} +.feedzy-preview-list { + padding-left: 15px; +} +.feedzy-preview-list li { + list-style: disc; +} +.feedzy-preview-list li a { + text-decoration: none; +} +.feedzy-preview-list li time { + font-size: 11px; + font-weight: 500; + color: #757575; +} @-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } } diff --git a/includes/abstract/feedzy-rss-feeds-admin-abstract.php b/includes/abstract/feedzy-rss-feeds-admin-abstract.php index 54c983c12..f56ba8c93 100644 --- a/includes/abstract/feedzy-rss-feeds-admin-abstract.php +++ b/includes/abstract/feedzy-rss-feeds-admin-abstract.php @@ -1663,7 +1663,7 @@ private function get_feed_item_filter( $sc, $sizes, $item, $feed_url, $index, $i 'item_url_follow' => isset( $sc['follow'] ) && 'yes' === $sc['follow'] ? 'nofollow' : '', 'item_url_title' => $item->get_title(), 'item_img' => $content_thumb, - 'item_img_path' => $this->feedzy_retrieve_image( $item, $sc ), + 'item_img_path' => isset( $sc['thumb'] ) && ( 'yes' === $sc['thumb'] || 'auto' === $sc['thumb'] ) ? $this->feedzy_retrieve_image( $item, $sc ) : '', 'item_title' => $content_title, 'item_content_class' => 'rss_content', 'item_content_style' => '', diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index 2d3e78568..fe1363b2d 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -897,6 +897,19 @@ public function add_feedzy_post_type_metaboxes() { 'low' ); } + + if ( 'publish' === get_post_status() ) { + add_meta_box( + 'feedzy_category_feeds_preview', + __( 'Feed Preview', 'feedzy-rss-feeds' ), + array( + $this, + 'render_feed_preview', + ), + 'feedzy_categories', + 'side' + ); + } } /** @@ -939,12 +952,118 @@ public function feedzy_category_feed() { ) . '

' . $invalid - . ' -

' . __( 'Learn how to organize feeds in Groups', 'feedzy-rss-feeds' ) . '

+ . ' +
+ + +
'; echo wp_kses( $output, apply_filters( 'feedzy_wp_kses_allowed_html', array() ) ); } + /** + * Render the feed preview metabox. + * + * @return void + */ + public function render_feed_preview() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( isset( $_GET['action'] ) && 'edit' !== $_GET['action'] ) { + return; + } + $feeds = get_post_meta( get_the_ID(), 'feedzy_category_feed', true ); + $feed_urls = $this->normalize_urls( $feeds ); + if ( empty( $feed_urls ) ) { + echo '

' . esc_html__( 'No feeds available for preview.', 'feedzy-rss-feeds' ) . '

'; + return; + } + $shortcode = array( + 'sort' => 'date_desc', + 'thumb' => 'no', + 'max' => 0, + ); + $atts = $this->get_short_code_attributes( $shortcode ); + $atts = $this->sanitize_attr( $atts, $feed_urls ); + $sizes = array( + 'width' => 0, + 'height' => 0, + ); + $feed = $this->fetch_feed( $feed_urls, $atts['refresh'], $atts ); + $feed_items = apply_filters( 'feedzy_get_feed_array', array(), $atts, $feed, $feed_urls, $sizes ); + $total_items = count( $feed_items ); + $count = 0; + + echo wp_kses( + sprintf( + // translators: %s is the total number of items available in the feed. + '' . __( 'Latest 5 feed items out of %s available from', 'feedzy-rss-feeds' ) . '', + $total_items + ), + array( + 'strong' => array(), + ) + ); + + echo '
'; + $content = ''; + echo wp_kses( + $content, + array( + 'ul' => array( + 'class' => array(), + ), + 'li' => array( + 'class' => array(), + ), + 'a' => array( + 'href' => array(), + 'target' => array(), + ), + 'time' => array( + 'datetime' => array(), + 'content' => array(), + ), + 'br' => array(), + ) + ); + echo '
'; + } + + /** + * Get human readable time difference. + * + * @param int $item_publish_time The item publish time. + * + * @return string + */ + private function get_humman_readable_time_diff( $item_publish_time ) { + $array = current_datetime(); + $localtime = $array->getTimestamp() + $array->getOffset(); + + return sprintf( + // translators: %s is the time difference. + __( '%s ago', 'feedzy-rss-feeds' ), + human_time_diff( $item_publish_time, $localtime ) + ); + } + /** * Utility method to save metabox data to * custom post type. @@ -1030,6 +1149,13 @@ public function feedzy_category_columns( $columns ) { $columns['actions'] = __( 'Actions', 'feedzy-rss-feeds' ); } + $new_columns = $this->array_insert_before( 'slug', $columns, 'source', __( 'Source', 'feedzy-rss-feeds' ) ); + if ( $new_columns ) { + $columns = $new_columns; + } else { + $columns['Source'] = __( 'source', 'feedzy-rss-feeds' ); + } + return $columns; } @@ -1074,6 +1200,33 @@ public function manage_feedzy_category_columns( $column, $post_id ) { case 'actions': echo wp_kses_post( sprintf( '', __( 'Click to remove invalid URLs from this category', 'feedzy-rss-feeds' ), $post_id, __( 'Validate & Clean', 'feedzy-rss-feeds' ) ) ); break; + case 'source': + $src = get_post_meta( $post_id, 'feedzy_category_feed', true ); + if ( empty( $src ) ) { + $src = __( 'No Source Configured', 'feedzy-rss-feeds' ); + } else { + $urls = $this->normalize_urls( $src ); + $src = ''; + if ( is_array( $urls ) ) { + + foreach ( $urls as $key => $url ) { + $too_long = 130; + if ( strlen( $src ) > $too_long ) { + $src .= '...'; + break; + } else { + $src .= '' . $url . ''; + if ( count( $urls ) > $key + 1 ) { + $src .= ', '; + } + } + } + } else { + $src .= '' . esc_html( $urls ) . ''; + } + } + echo wp_kses_post( $src ); + break; default: break; } @@ -1709,6 +1862,23 @@ public function ajax() { } wp_send_json_success( array( 'invalid' => count( $invalid ) ) ); break; + case 'validate_feeds_group': + $feeds = isset( $_POST['feeds'] ) ? sanitize_text_field( wp_unslash( $_POST['feeds'] ) ) : ''; + if ( empty( $feeds ) ) { + wp_send_json_error( __( 'No feeds provided for validation.', 'feedzy-rss-feeds' ) ); + } + $feeds = $this->normalize_urls( $feeds ); + if ( ! is_array( $feeds ) ) { + $feeds = array( $feeds ); + } + $valid = $this->get_valid_source_urls( $feeds, '1_mins', false ); + $invalid = array_diff( $feeds, $valid ); + wp_send_json_success( + array( + 'valid' => $valid, + 'invalid' => $invalid, + ) + ); } } diff --git a/includes/feedzy-rss-feeds-activator.php b/includes/feedzy-rss-feeds-activator.php index 495b04f55..dd1e2542f 100644 --- a/includes/feedzy-rss-feeds-activator.php +++ b/includes/feedzy-rss-feeds-activator.php @@ -57,5 +57,35 @@ public static function activate() { ) ); } + self::add_feeds_group(); + } + + /** + * Adds a default feeds group with some popular WordPress-related feeds. + * + * This method checks if a feeds group already exists, and if not, creates one + * with a set of predefined feeds. + * + * @return void + */ + public static function add_feeds_group() { + if ( get_option( '_feedzy_news_group_id', false ) ) { + return; + } + + $group_args = array( + 'post_title' => __( 'News sites', 'feedzy-rss-feeds' ), + 'post_type' => 'feedzy_categories', + 'post_status' => 'publish', + 'post_content' => '', + ); + + $news_group = wp_insert_post( $group_args ); + + $feed_groups = 'https://themeisle.com/blog/feed/, https://wptavern.com/feed/, https://www.wpbeginner.com/feed/, https://wpshout.com/feed/, https://planet.wordpress.org/feed/'; + + add_post_meta( $news_group, 'feedzy_category_feed', $feed_groups ); + + update_option( '_feedzy_news_group_id', $news_group ); } } diff --git a/includes/feedzy-rss-feeds-feed-tweaks.php b/includes/feedzy-rss-feeds-feed-tweaks.php index afd20d879..48d8338e0 100644 --- a/includes/feedzy-rss-feeds-feed-tweaks.php +++ b/includes/feedzy-rss-feeds-feed-tweaks.php @@ -466,10 +466,13 @@ function ( $allowed_html = array() ) { 'value' => array(), 'class' => array(), 'data-feedzy' => array(), + 'placeholder' => array(), + 'rows' => array(), ), 'button' => array( - 'class' => array(), - 'id' => array(), + 'class' => array(), + 'id' => array(), + 'disabled' => array(), ), 'p' => array( 'class' => array(), diff --git a/js/categories.js b/js/categories.js index 6c54f7d55..ff2e441a1 100644 --- a/js/categories.js +++ b/js/categories.js @@ -4,6 +4,7 @@ $(document).ready(function(){ init(); + validateFeeds(); }); function init(){ @@ -33,4 +34,38 @@ }); } + // validate feeds group. + function validateFeeds() { + $('#feedzy_category_feeds textarea[name="feedzy_category_feed"]').on('input', function() { + if ($(this).val().length < 1) { + $('.validate-feeds').attr('disabled', true); + } else { + $('.validate-feeds').attr('disabled', false); + } + }); + + $('#feedzy_category_feeds .button.validate-feeds').on('click', function(e) { + e.preventDefault(); + var button = $(this); + button.attr('disabled', true); + $('#feedzy_category_feeds .spinner').addClass('is-active'); + $.ajax({ + url: ajaxurl, + method: 'POST', + data: { + action: 'feedzy_categories', + _action: 'validate_feeds_group', + security: feedzy.ajax.security, + feeds: $('textarea[name="feedzy_category_feed"]').val() + }, + success: function(data) { + if (data.success) { + $('textarea[name="feedzy_category_feed"]').val(data.data.valid.join(', ')); + $('#feedzy_category_feeds .spinner').removeClass('is-active'); + } + } + }) + }); + } + })(jQuery, feedzy); From d86728f0b02dbaf4f6cd31aa7155b77ddd6c92f0 Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Tue, 29 Jul 2025 14:05:47 +0530 Subject: [PATCH 2/6] refactor: feed preview html --- includes/admin/feedzy-rss-feeds-admin.php | 90 ++++++++++------------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index fe1363b2d..c995a1f6d 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -991,59 +991,47 @@ public function render_feed_preview() { $feed = $this->fetch_feed( $feed_urls, $atts['refresh'], $atts ); $feed_items = apply_filters( 'feedzy_get_feed_array', array(), $atts, $feed, $feed_urls, $sizes ); $total_items = count( $feed_items ); - $count = 0; - echo wp_kses( - sprintf( - // translators: %s is the total number of items available in the feed. - '' . __( 'Latest 5 feed items out of %s available from', 'feedzy-rss-feeds' ) . '', - $total_items - ), - array( - 'strong' => array(), - ) - ); - - echo '
'; - $content = '
    '; - - foreach ( $feed_items as $item ) { - if ( $count > 4 ) { - break; + $max_items_preview_count = 5; + $preview_feed_items = array_slice( $feed_items, 0, $max_items_preview_count ); + ?> + + + +
    +
      + +
    • > + + + +
      + +
    • + %s
      ', - esc_attr( $item['itemAttr'] ), - esc_attr( $item['item_url'] ), - esc_html( $item['item_title'] ), - esc_attr( date_i18n( 'c', $item['item_date'] ) ), - esc_attr( date_i18n( 'Y-m-d', $item['item_date'] ) ), - esc_html( $this->get_humman_readable_time_diff( $item['item_date'] ) ) - ); - ++$count; - } - $content .= '
    '; - echo wp_kses( - $content, - array( - 'ul' => array( - 'class' => array(), - ), - 'li' => array( - 'class' => array(), - ), - 'a' => array( - 'href' => array(), - 'target' => array(), - ), - 'time' => array( - 'datetime' => array(), - 'content' => array(), - ), - 'br' => array(), - ) - ); - echo '
    '; + ?> +
+
+ Date: Thu, 31 Jul 2025 10:28:57 +0530 Subject: [PATCH 3/6] fix: retrive image URL from query params --- includes/abstract/feedzy-rss-feeds-admin-abstract.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/abstract/feedzy-rss-feeds-admin-abstract.php b/includes/abstract/feedzy-rss-feeds-admin-abstract.php index f56ba8c93..d4a1ce84f 100644 --- a/includes/abstract/feedzy-rss-feeds-admin-abstract.php +++ b/includes/abstract/feedzy-rss-feeds-admin-abstract.php @@ -1962,10 +1962,10 @@ public function feedzy_blacklist_images() { */ public function feedzy_image_encode( $img_url ) { // Check if img url is set as an URL parameter. - $parsed_url = wp_parse_url( $img_url ); - if ( isset( $parsed_url['query'] ) ) { - preg_match_all( '/(http|https):\/\/[^ ]+(\.(gif|jpg|jpeg|png|webp|avif))/i', $parsed_url['query'], $matches ); - if ( isset( $matches[0][0] ) && $this->is_image_url( $matches[0][0] ) ) { + $url_tab = wp_parse_url( $img_url ); + if ( isset( $url_tab['query'] ) ) { + preg_match_all( '/(http|https):\/\/[^ ]+(\.gif|\.GIF|\.jpg|\.JPG|\.jpeg|\.JPEG|\.png|\.PNG)/', $url_tab['query'], $matches ); + if ( isset( $matches[0][0] ) ) { $img_url = $matches[0][0]; } } From b9bf74154c634d95e5f8728122eae68edd467a08 Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Wed, 13 Aug 2025 14:33:19 +0530 Subject: [PATCH 4/6] fix: phpunit --- includes/abstract/feedzy-rss-feeds-admin-abstract.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/abstract/feedzy-rss-feeds-admin-abstract.php b/includes/abstract/feedzy-rss-feeds-admin-abstract.php index d4a1ce84f..02cd7214b 100644 --- a/includes/abstract/feedzy-rss-feeds-admin-abstract.php +++ b/includes/abstract/feedzy-rss-feeds-admin-abstract.php @@ -1964,7 +1964,7 @@ public function feedzy_image_encode( $img_url ) { // Check if img url is set as an URL parameter. $url_tab = wp_parse_url( $img_url ); if ( isset( $url_tab['query'] ) ) { - preg_match_all( '/(http|https):\/\/[^ ]+(\.gif|\.GIF|\.jpg|\.JPG|\.jpeg|\.JPEG|\.png|\.PNG)/', $url_tab['query'], $matches ); + preg_match_all( '/(http|https):\/\/[^ ]+(\.gif|\.GIF|\.jpg|\.JPG|\.jpeg|\.JPEG|\.png|\.PNG|\.webp|\.WEBP|\.avif|\.AVIF)/', $url_tab['query'], $matches ); if ( isset( $matches[0][0] ) ) { $img_url = $matches[0][0]; } From 47bd1f7c532031aa0c5d3a1c2c938246418d567e Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Fri, 15 Aug 2025 10:50:10 +0530 Subject: [PATCH 5/6] refactor: clean up code --- includes/admin/feedzy-rss-feeds-admin.php | 7 +------ includes/feedzy-rss-feeds-activator.php | 10 +++++++++- js/categories.js | 8 ++------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/includes/admin/feedzy-rss-feeds-admin.php b/includes/admin/feedzy-rss-feeds-admin.php index c995a1f6d..ce60fbd3a 100644 --- a/includes/admin/feedzy-rss-feeds-admin.php +++ b/includes/admin/feedzy-rss-feeds-admin.php @@ -1138,11 +1138,6 @@ public function feedzy_category_columns( $columns ) { } $new_columns = $this->array_insert_before( 'slug', $columns, 'source', __( 'Source', 'feedzy-rss-feeds' ) ); - if ( $new_columns ) { - $columns = $new_columns; - } else { - $columns['Source'] = __( 'source', 'feedzy-rss-feeds' ); - } return $columns; } @@ -1191,7 +1186,7 @@ public function manage_feedzy_category_columns( $column, $post_id ) { case 'source': $src = get_post_meta( $post_id, 'feedzy_category_feed', true ); if ( empty( $src ) ) { - $src = __( 'No Source Configured', 'feedzy-rss-feeds' ); + $src = __( 'No Source Configured', 'feedzy-rss-feeds' ); } else { $urls = $this->normalize_urls( $src ); $src = ''; diff --git a/includes/feedzy-rss-feeds-activator.php b/includes/feedzy-rss-feeds-activator.php index dd1e2542f..c5ba90846 100644 --- a/includes/feedzy-rss-feeds-activator.php +++ b/includes/feedzy-rss-feeds-activator.php @@ -82,7 +82,15 @@ public static function add_feeds_group() { $news_group = wp_insert_post( $group_args ); - $feed_groups = 'https://themeisle.com/blog/feed/, https://wptavern.com/feed/, https://www.wpbeginner.com/feed/, https://wpshout.com/feed/, https://planet.wordpress.org/feed/'; + $default_feed_urls = array( + 'https://themeisle.com/blog/feed/', + 'https://wptavern.com/feed/', + 'https://www.wpbeginner.com/feed/', + 'https://wpshout.com/feed/', + 'https://planet.wordpress.org/feed/', + ); + + $feed_groups = implode( ', ', array_map( 'esc_url', $default_feed_urls ) ); add_post_meta( $news_group, 'feedzy_category_feed', $feed_groups ); diff --git a/js/categories.js b/js/categories.js index ff2e441a1..5ada6de05 100644 --- a/js/categories.js +++ b/js/categories.js @@ -37,16 +37,12 @@ // validate feeds group. function validateFeeds() { $('#feedzy_category_feeds textarea[name="feedzy_category_feed"]').on('input', function() { - if ($(this).val().length < 1) { - $('.validate-feeds').attr('disabled', true); - } else { - $('.validate-feeds').attr('disabled', false); - } + $('.validate-feeds').attr('disabled', 1 > $(this).val().length ); }); $('#feedzy_category_feeds .button.validate-feeds').on('click', function(e) { e.preventDefault(); - var button = $(this); + const button = $(this); button.attr('disabled', true); $('#feedzy_category_feeds .spinner').addClass('is-active'); $.ajax({ From c814d1533c0f16bf6160e92a130e15df98a2af96 Mon Sep 17 00:00:00 2001 From: girishpanchal30 Date: Fri, 15 Aug 2025 11:04:58 +0530 Subject: [PATCH 6/6] chore: rebase to development --- includes/abstract/feedzy-rss-feeds-admin-abstract.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/abstract/feedzy-rss-feeds-admin-abstract.php b/includes/abstract/feedzy-rss-feeds-admin-abstract.php index 02cd7214b..f56ba8c93 100644 --- a/includes/abstract/feedzy-rss-feeds-admin-abstract.php +++ b/includes/abstract/feedzy-rss-feeds-admin-abstract.php @@ -1962,10 +1962,10 @@ public function feedzy_blacklist_images() { */ public function feedzy_image_encode( $img_url ) { // Check if img url is set as an URL parameter. - $url_tab = wp_parse_url( $img_url ); - if ( isset( $url_tab['query'] ) ) { - preg_match_all( '/(http|https):\/\/[^ ]+(\.gif|\.GIF|\.jpg|\.JPG|\.jpeg|\.JPEG|\.png|\.PNG|\.webp|\.WEBP|\.avif|\.AVIF)/', $url_tab['query'], $matches ); - if ( isset( $matches[0][0] ) ) { + $parsed_url = wp_parse_url( $img_url ); + if ( isset( $parsed_url['query'] ) ) { + preg_match_all( '/(http|https):\/\/[^ ]+(\.(gif|jpg|jpeg|png|webp|avif))/i', $parsed_url['query'], $matches ); + if ( isset( $matches[0][0] ) && $this->is_image_url( $matches[0][0] ) ) { $img_url = $matches[0][0]; } }