Skip to content

Commit bb454f8

Browse files
feat: add feed validation in the loop block
1 parent 5f980c6 commit bb454f8

File tree

2 files changed

+127
-20
lines changed

2 files changed

+127
-20
lines changed

includes/gutenberg/feedzy-rss-feeds-loop-block.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public function register_block() {
7373
array(
7474
'imagepath' => esc_url( FEEDZY_ABSURL . 'img/' ),
7575
'defaultImage' => esc_url( FEEDZY_ABSURL . 'img/feedzy.svg' ),
76+
'url' => admin_url( 'admin-ajax.php' ),
77+
'nonce' => wp_create_nonce( FEEDZY_BASEFILE ),
7678
'isPro' => feedzy_is_pro(),
7779
)
7880
);

js/FeedzyLoop/placeholder.js

Lines changed: 125 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
* WordPress dependencies.
44
*/
55
import { __ } from '@wordpress/i18n';
6-
6+
import { useState } from '@wordpress/element';
77
import {
88
BaseControl,
99
Button,
1010
Placeholder,
1111
Spinner,
12+
Notice,
1213
} from '@wordpress/components';
13-
1414
import { useSelect } from '@wordpress/data';
15-
1615
import { store as coreStore } from '@wordpress/core-data';
1716

1817
/**
@@ -21,6 +20,9 @@ import { store as coreStore } from '@wordpress/core-data';
2120
import FeedControl from './components/FeedControl';
2221

2322
const BlockPlaceholder = ({ attributes, setAttributes, onSaveFeed }) => {
23+
const [isValidating, setIsValidating] = useState(false);
24+
const [validationResults, setValidationResults] = useState([]);
25+
2426
const { categories, isLoading } = useSelect((select) => {
2527
const { getEntityRecords, isResolving } = select(coreStore);
2628

@@ -33,20 +35,132 @@ const BlockPlaceholder = ({ attributes, setAttributes, onSaveFeed }) => {
3335
};
3436
}, []);
3537

38+
const handleLoadFeed = async () => {
39+
if (!attributes?.feed?.source) {
40+
return;
41+
}
42+
43+
setIsValidating(true);
44+
setValidationResults([]);
45+
46+
const isCategory = categories.some(
47+
(cat) => cat.id === attributes.feed.source
48+
);
49+
50+
if (isCategory && 'group' === attributes.feed.type) {
51+
onSaveFeed();
52+
setIsValidating(false);
53+
return;
54+
}
55+
56+
try {
57+
const formData = new FormData();
58+
formData.append('action', 'feedzy_validate_feed');
59+
formData.append('feed_url', attributes.feed.source);
60+
formData.append('nonce', window.feedzyData?.nonce);
61+
62+
const response = await fetch(window.feedzyData?.url, {
63+
method: 'POST',
64+
body: formData,
65+
});
66+
67+
const data = await response.json();
68+
69+
if (data.success && data.data?.results) {
70+
const results = data.data.results;
71+
setValidationResults(results);
72+
73+
const hasErrors = results.some(
74+
(result) => result.status === 'error'
75+
);
76+
77+
if (!hasErrors) {
78+
onSaveFeed();
79+
}
80+
} else if (!data.success) {
81+
setValidationResults([
82+
{
83+
status: 'error',
84+
message:
85+
data.data?.message ||
86+
__('Validation failed', 'feedzy-rss-feeds'),
87+
},
88+
]);
89+
}
90+
} catch (error) {
91+
setValidationResults([
92+
{
93+
status: 'error',
94+
message: __(
95+
'Failed to validate feed. Please check your connection and try again.',
96+
'feedzy-rss-feeds'
97+
),
98+
},
99+
]);
100+
} finally {
101+
setIsValidating(false);
102+
}
103+
};
104+
105+
const handleFeedChange = (value) => {
106+
setAttributes({ feed: value });
107+
setValidationResults([]);
108+
};
109+
110+
const renderValidationResults = () => {
111+
if (!validationResults || validationResults.length === 0) {
112+
return null;
113+
}
114+
115+
return (
116+
<div
117+
className="feedzy-validation-results"
118+
style={{
119+
display: 'flex',
120+
flexDirection: 'column',
121+
gap: '10px',
122+
marginTop: '15px',
123+
}}
124+
>
125+
{validationResults.map((result, index) => (
126+
<Notice
127+
key={`result-${index}`}
128+
status={result.status}
129+
isDismissible={false}
130+
>
131+
{result.url && (
132+
<>
133+
<strong>{result.url}</strong>
134+
<br />
135+
</>
136+
)}
137+
{result.message}
138+
</Notice>
139+
))}
140+
</div>
141+
);
142+
};
143+
36144
return (
37145
<Placeholder
38146
key="placeholder"
39147
icon="rss"
40148
label={__('Feedzy RSS Feeds', 'feedzy-rss-feeds')}
41149
>
42-
{isLoading && (
150+
{(isLoading || isValidating) && (
43151
<div key="loading" className="wp-block-embed is-loading">
44152
<Spinner />
45-
<p>{__('Fetching…', 'feedzy-rss-feeds')}</p>
153+
<p>
154+
{isValidating
155+
? __(
156+
'Validating and fetching feed…',
157+
'feedzy-rss-feeds')
158+
: __('Loading…', 'feedzy-rss-feeds')}
159+
</p>
46160
</div>
47161
)}
48162

49-
{!isLoading && (
163+
{!isLoading && !isValidating && (
50164
<>
51165
<BaseControl
52166
label={__('Feed Source', 'feedzy-rss-feeds')}
@@ -60,9 +174,11 @@ const BlockPlaceholder = ({ attributes, setAttributes, onSaveFeed }) => {
60174
value: category.id,
61175
})),
62176
]}
63-
onChange={(value) => setAttributes({ feed: value })}
177+
onChange={handleFeedChange}
64178
/>
65179

180+
{renderValidationResults()}
181+
66182
<p>
67183
{__(
68184
'Enter the full URL of the feed source you wish to display here, or select a Feed Group. Also you can add multiple URLs separated with a comma. You can manage your feed groups from',
@@ -81,22 +197,11 @@ const BlockPlaceholder = ({ attributes, setAttributes, onSaveFeed }) => {
81197
<div>
82198
<Button
83199
variant="primary"
84-
onClick={() => {
85-
if (attributes?.feed?.source) {
86-
onSaveFeed();
87-
}
88-
}}
200+
onClick={handleLoadFeed}
201+
disabled={!attributes?.feed?.source}
89202
>
90203
{__('Load Feed', 'feedzy-rss-feeds')}
91204
</Button>
92-
93-
<Button
94-
variant="link"
95-
href="https://validator.w3.org/feed/"
96-
target="_blank"
97-
>
98-
{__('Validate', 'feedzy-rss-feeds')}
99-
</Button>
100205
</div>
101206
</>
102207
)}

0 commit comments

Comments
 (0)