Skip to content

Commit f6c9157

Browse files
committed
feat: new Feedzy Loop block
1 parent 44c9900 commit f6c9157

File tree

10 files changed

+851
-0
lines changed

10 files changed

+851
-0
lines changed

includes/feedzy-rss-feeds.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ function () {
278278
function () {
279279
if ( function_exists( 'register_block_type' ) ) {
280280
Feedzy_Rss_Feeds_Gutenberg_Block::get_instance();
281+
Feedzy_Rss_Feeds_Loop_Block::get_instance();
281282
}
282283
}
283284
);
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
<?php
2+
/**
3+
* Class for functionalities related to Loop block.
4+
*
5+
* Defines the functions that need to be used for Loop block,
6+
* and REST router.
7+
*
8+
* @package feedzy-rss-feeds
9+
* @subpackage feedzy-rss-feeds/includes/guteneberg
10+
* @author Themeisle <[email protected]>
11+
*/
12+
class Feedzy_Rss_Feeds_Loop_Block {
13+
14+
/**
15+
* A reference to an instance of this class.
16+
*
17+
* @var Feedzy_Rss_Feeds_Loop_Block The one Feedzy_Rss_Feeds_Loop_Block instance.
18+
*/
19+
private static $instance;
20+
21+
/**
22+
* Instance of Feedzy_Rss_Feeds_Admin class.
23+
*
24+
* @var Feedzy_Rss_Feeds_Admin $admin The Feedzy_Rss_Feeds_Admin instance.
25+
*/
26+
private $admin;
27+
28+
/**
29+
* Feedzy RSS Feeds plugin version.
30+
*
31+
* @var string $version The current version of the plugin.
32+
*/
33+
protected $version;
34+
35+
/**
36+
* Returns an instance of this class.
37+
*/
38+
public static function get_instance() {
39+
if ( null === self::$instance ) {
40+
self::$instance = new Feedzy_Rss_Feeds_Loop_Block();
41+
}
42+
return self::$instance;
43+
}
44+
45+
/**
46+
* Initializes the plugin by setting filters and administration functions.
47+
*/
48+
private function __construct() {
49+
$this->version = Feedzy_Rss_Feeds::get_version();
50+
$this->admin = Feedzy_Rss_Feeds::instance()->get_admin();
51+
add_action( 'init', array( $this, 'register_block' ) );
52+
add_filter( 'feedzy_loop_item', array( $this, 'apply_magic_tags' ), 10, 2 );
53+
}
54+
55+
/**
56+
* Register Block
57+
*/
58+
public function register_block() {
59+
$metadata_file = trailingslashit( FEEDZY_ABSPATH ) . '/build/loop/block.json';
60+
register_block_type_from_metadata(
61+
$metadata_file,
62+
array(
63+
'render_callback' => array( $this, 'render_callback' ),
64+
)
65+
);
66+
67+
wp_set_script_translations( 'feedzy-rss-feeds-loop-editor-script', 'feedzy-rss-feeds' );
68+
69+
// Pass in REST URL
70+
wp_localize_script(
71+
'feedzy-rss-feeds-loop-editor-script',
72+
'feedzyloopjs',
73+
array(
74+
'defaultImage' => esc_url( FEEDZY_ABSURL . 'img/feedzy.svg' ),
75+
'isPro' => feedzy_is_pro(),
76+
)
77+
);
78+
}
79+
80+
/**
81+
* Render Callback
82+
*
83+
* @param array $attributes The block attributes.
84+
* @param string $content The block content.
85+
* @return string The block content.
86+
*/
87+
public function render_callback( $attributes, $content ) {
88+
$content = empty( $content ) ? ( $attributes['innerBlocksContent'] ?? '' ) : $content;
89+
$is_preview = isset( $attributes['innerBlocksContent'] ) && ! empty( $attributes['innerBlocksContent'] );
90+
91+
if ( isset( $attributes['feed']['type'] ) && 'group' === $attributes['feed']['type'] && isset( $attributes['feed']['source'] ) && is_numeric( $attributes['feed']['source'] ) ) {
92+
$group = $attributes['feed']['source'];
93+
$value = get_post_meta( $group, 'feedzy_category_feed', true );
94+
$value = trim( $value );
95+
$value = !empty( $value ) ? explode( ',', $value ) : array();
96+
$feed_urls = ( count( $value ) === 1 ) ? esc_url( $value[0] ) : $value;
97+
}
98+
99+
if ( isset( $attributes['feed']['type'] ) && 'url' === $attributes['feed']['type'] && isset( $attributes['feed']['source'] ) && is_array( $attributes['feed']['source'] ) ) {
100+
$value = $attributes['feed']['source'];
101+
$feed_urls = ( count( $value ) === 1 ) ? esc_url( $value[0] ) : $value;
102+
}
103+
104+
if ( empty( $feed_urls ) ) {
105+
return '<div>' . esc_html__( 'No feeds to display', 'feedzy-rss-feeds' ) . '</div>';
106+
}
107+
108+
$column_count = isset($attributes['layout']) && isset($attributes['layout']['columnCount']) && !empty($attributes['layout']['columnCount']) ? $attributes['layout']['columnCount'] : 1;
109+
110+
$default_query = array(
111+
'max' => 5,
112+
'sort' => 'default',
113+
'refresh' => '12_hours',
114+
);
115+
116+
$query = isset( $attributes['query'] ) ? wp_parse_args( $attributes['query'], $default_query ) : $default_query;
117+
118+
$options = array(
119+
'max' => $query['max'],
120+
'sort' => $query['sort'],
121+
'offset' => 0,
122+
'target' => '_blank',
123+
'keywords_ban' => '',
124+
'columns' => '1',
125+
'thumb' => 'auto',
126+
'default' => '',
127+
'title' => '',
128+
'meta' => 'yes',
129+
'multiple_meta' => 'no',
130+
'summary' => 'yes',
131+
'summarylength' => '',
132+
);
133+
134+
$sizes = array(
135+
'width' => 300,
136+
'height' => 300,
137+
);
138+
139+
$feed = $this->admin->fetch_feed( $feed_urls, $query['refresh'], $options );
140+
141+
if ( isset( $feed->error ) && ! empty( $feed->error ) ) {
142+
return '<div>' . esc_html__( 'An error occurred while fetching the feed.', 'feedzy-rss-feeds' ) . '</div>';
143+
}
144+
145+
$sizes = apply_filters( 'feedzy_thumb_sizes', $sizes, $feed_urls );
146+
$feed_items = apply_filters( 'feedzy_get_feed_array', array(), $options, $feed, $feed_urls, $sizes );
147+
$loop = '';
148+
149+
foreach ($feed_items as $key => $item) {
150+
$loop .= apply_filters( 'feedzy_loop_item', $content, $item );
151+
}
152+
153+
return sprintf(
154+
'<div %1$s>%2$s</div>',
155+
$wrapper_attributes = get_block_wrapper_attributes( array(
156+
'class' => 'feedzy-loop-columns-' . $column_count,
157+
) ),
158+
$loop
159+
);
160+
}
161+
162+
/**
163+
* Magic Tags Replacement.
164+
*
165+
* @param string $content The content.
166+
*
167+
* @return string The content.
168+
*/
169+
public function apply_magic_tags( $content, $item ) {
170+
$pattern = '/\{\{feedzy_([^}]+)\}\}/';
171+
$content = str_replace( FEEDZY_ABSURL . 'img/feedzy.svg', '{{feedzy_image}}', $content );
172+
173+
return preg_replace_callback( $pattern, function( $matches ) use ( $item ) {
174+
return isset( $matches[1] ) ? $this->get_value( $matches[1], $item ) : '';
175+
}, $content );
176+
}
177+
178+
/**
179+
* Get Dynamic Value.
180+
*
181+
* @param string $key The key.
182+
* @param array $item Feed item.
183+
*
184+
* @return string The value.
185+
*/
186+
public function get_value( $key, $item ) {
187+
switch ( $key ) {
188+
case 'title':
189+
return isset( $item['item_title'] ) ? $item['item_title'] : '';
190+
case 'url':
191+
return isset( $item['item_url'] ) ? $item['item_url'] : '';
192+
case 'date':
193+
$item_date = isset( $item['item_date'] ) ? wp_date( get_option( 'date_format' ), $item['item_date'] ) : '';
194+
return $item_date;
195+
case 'time':
196+
$item_date = isset( $item['item_date'] ) ? wp_date( get_option( 'time_format' ), $item['item_date'] ) : '';
197+
return $item_date;
198+
case 'datetime':
199+
$item_date = isset( $item['item_date'] ) ? wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $item['item_date'] ) : '';
200+
return $item_date;
201+
case 'author':
202+
if ( isset( $item['item_author'] ) && is_string( $item['item_author'] ) ) {
203+
return $item['item_author'];
204+
} elseif ( isset( $item['item_author'] ) && is_object( $item['item_author'] ) ) {
205+
return $item['item_author']->get_name();
206+
}
207+
return '';
208+
case 'description':
209+
return isset( $item['item_description'] ) ? $item['item_description'] : '';
210+
case 'content':
211+
return isset( $item['item_content'] ) ? $item['item_content'] : '';
212+
case 'meta':
213+
return isset( $item['item_meta'] ) ? $item['item_meta'] : '';
214+
case 'categories':
215+
return isset( $item['item_categories'] ) ? $item['item_categories'] : '';
216+
case 'image':
217+
$settings = apply_filters( 'feedzy_get_settings', array() );
218+
if ( $settings && ! empty( $settings['general']['default-thumbnail-id'] ) ) {
219+
$default_img = wp_get_attachment_image_src( $settings['general']['default-thumbnail-id'], 'full' );
220+
$default_img = ! empty( $default_img ) ? reset( $default_img ) : '';
221+
} else {
222+
$default_img = FEEDZY_ABSURL . 'img/feedzy.svg';
223+
}
224+
225+
return isset( $item['item_img_path'] ) ? $item['item_img_path'] : $default_img;
226+
case 'media':
227+
return isset( $item['item_media']['src'] ) ? $item['item_media']['src'] : '';
228+
case 'price':
229+
return isset( $item['item_price'] ) ? $item['item_price'] : '';
230+
case 'source':
231+
return isset( $item['item_source'] ) ? $item['item_source'] : '';
232+
default:
233+
return '';
234+
}
235+
}
236+
}

js/FeedzyLoop/block.json

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{
2+
"$schema": "https://schemas.wp.org/trunk/block.json",
3+
"apiVersion": 3,
4+
"name": "feedzy-rss-feeds/loop",
5+
"version": "1.0.0",
6+
"title": "Feedzy Loop",
7+
"category": "common",
8+
"icon": "rss",
9+
"keywords": [
10+
"rss",
11+
"feed",
12+
"feedzy"
13+
],
14+
"description": "Display curated RSS content in a dynamic, customizable loop directly in the Block Editor—no coding required.",
15+
"attributes": {
16+
"feed": {
17+
"type": "object",
18+
"properties": {
19+
"type": {
20+
"type": "string",
21+
"enum": [ "url", "group" ],
22+
"default": "url"
23+
},
24+
"source": {
25+
"type": [ "number", "array" ],
26+
"default": ""
27+
}
28+
}
29+
},
30+
"query": {
31+
"type": "object",
32+
"properties": {
33+
"max": {
34+
"type": "number",
35+
"default": 5
36+
},
37+
"sort": {
38+
"type": "string",
39+
"enum": [ "default", "date_desc", "date_asc", "title_desc", "title_asc" ],
40+
"default": "default"
41+
},
42+
"refresh": {
43+
"type": "string",
44+
"enum": [ "1_hours", "3_hours", "12_hours", "1_days", "3_days", "15_days" ],
45+
"default": "12_hours"
46+
}
47+
}
48+
},
49+
"layout": {
50+
"type": "object",
51+
"properties": {
52+
"columnCount": {
53+
"type": "number",
54+
"default": 1
55+
}
56+
}
57+
},
58+
"innerBlocksContent": {
59+
"type": "string",
60+
"default": ""
61+
}
62+
},
63+
"supports": {
64+
"align": [ "wide", "full" ],
65+
"anchor": true,
66+
"ariaLabel": true,
67+
"html": true,
68+
"color": {
69+
"gradients": true,
70+
"heading": true,
71+
"button": true,
72+
"link": true
73+
},
74+
"shadow": true,
75+
"spacing": {
76+
"margin": [ "top", "bottom" ],
77+
"padding": true,
78+
"blockGap": true
79+
},
80+
"dimensions": {
81+
"minHeight": true
82+
},
83+
"typography": {
84+
"fontSize": true,
85+
"lineHeight": true
86+
}
87+
},
88+
"editorScript": "file:./index.js",
89+
"editorStyle": "file:./index.css",
90+
"style": "file:./style-index.css",
91+
"textdomain": "feedzy-rss-block"
92+
}

0 commit comments

Comments
 (0)