PluginProbe
WebberZone Top 10 — Popular Posts / 4.3.4
WebberZone Top 10 — Popular Posts v4.3.4
4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 All 117 releases
top-10 / includes / frontend / blocks / class-blocks.php

class-blocks.php in WebberZone Top 10 — Popular Posts 4.3.4, at includes/frontend/blocks/class-blocks.php

485 lines 13.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Blocks class.
4 *
5 * @package WebberZone\Top_Ten\Frontend\Blocks
6 */
7
8 namespace WebberZone\Top_Ten\Frontend\Blocks;
9
10 use WebberZone\Top_Ten\Admin\Settings;
11 use WebberZone\Top_Ten\Counter;
12 use WebberZone\Top_Ten\Frontend\Styles_Handler;
13 use WebberZone\Top_Ten\Util\Hook_Registry;
14
15 if ( ! defined( 'WPINC' ) ) {
16 die;
17 }
18
19 /**
20 * Blocks class.
21 *
22 * @since 3.3.0
23 */
24 class Blocks {
25
26 /**
27 * Register blocks with WordPress.
28 */
29 public function __construct() {
30 Hook_Registry::add_action( 'init', array( $this, 'register_blocks' ) );
31 Hook_Registry::add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
32 Hook_Registry::add_filter( 'block_editor_rest_api_preload_paths', array( $this, 'add_custom_preload_paths' ) );
33 }
34
35 /**
36 * Registers the block using the metadata loaded from the `block.json` file.
37 * Behind the scenes, it registers also all assets so they can be enqueued
38 * through the block editor in the corresponding context.
39 *
40 * @since 3.1.0
41 */
42 public function register_blocks() {
43 // Define an array of blocks with their paths and optional render callbacks.
44 $blocks = array(
45 'popular-posts' => array(
46 'path' => __DIR__ . '/build/popular-posts/',
47 'render_callback' => array( $this, 'render_block_popular_posts' ),
48 ),
49 'post-count' => array(
50 'path' => __DIR__ . '/build/post-count/',
51 'render_callback' => array( $this, 'render_block_post_count' ),
52 ),
53 );
54
55 /**
56 * Filters the blocks registered by the plugin.
57 *
58 * @since 4.0.0
59 *
60 * @param array $blocks Array of blocks registered by the plugin.
61 */
62 $blocks = apply_filters( 'tptn_register_blocks', $blocks );
63
64 // Loop through each block and register it.
65 foreach ( $blocks as $block_name => $block_data ) {
66 $args = array();
67
68 // If a render callback is provided, add it to the args.
69 if ( isset( $block_data['render_callback'] ) ) {
70 $args['render_callback'] = $block_data['render_callback'];
71 }
72
73 register_block_type( $block_data['path'], $args );
74 }
75 }
76
77 /**
78 * Renders the `top-10/popular-posts` block on server.
79 *
80 * @since 3.0.0
81 * @param array $attributes The block attributes.
82 *
83 * @return string Returns the post content with popular posts added.
84 */
85 public static function render_block_popular_posts( $attributes ) {
86
87 $attributes['extra_class'] = isset( $attributes['className'] ) ? esc_attr( $attributes['className'] ) : '';
88
89 $defaults = array_merge(
90 \tptn_settings_defaults(),
91 \tptn_get_settings(),
92 array(
93 'is_block' => 1,
94 )
95 );
96
97 $arguments = wp_parse_args( $attributes, $defaults );
98
99 if ( isset( $attributes['other_attributes'] ) ) {
100 $arguments = wp_parse_args( $attributes['other_attributes'], $arguments );
101 }
102
103 /**
104 * Filters arguments passed to get_tptn for the block.
105 *
106 * @since 3.0.0
107 *
108 * @param array $arguments Top 10 block options array.
109 * @param array $attributes Block attributes array.
110 */
111 $arguments = apply_filters( 'tptn_block_options', $arguments, $attributes );
112
113 // Enqueue the stylesheet for the selected style for this block.
114 $style_array = Styles_Handler::get_style( $arguments['tptn_styles'] );
115
116 if ( ! empty( $style_array['name'] ) ) {
117 $style = $style_array['name'];
118 $extra_css = $style_array['extra_css'];
119 $is_rtl = is_rtl();
120 $handle = "tptn-style-{$style}";
121
122 $already_enqueued = wp_style_is( $handle, 'enqueued' );
123
124 wp_register_style(
125 $handle,
126 plugins_url( Styles_Handler::get_stylesheet_path( $style, $is_rtl ), TOP_TEN_PLUGIN_FILE ),
127 array(),
128 TOP_TEN_VERSION
129 );
130 wp_enqueue_style( $handle );
131
132 if ( ! $already_enqueued && ! empty( $extra_css ) ) {
133 wp_add_inline_style( $handle, $extra_css );
134 }
135 }
136
137 return \WebberZone\Top_Ten\Frontend\Display::pop_posts( $arguments );
138 }
139
140 /**
141 * Renders the `core/post-title` block on the server.
142 *
143 * @since 4.0.0
144 *
145 * @param array $attributes Block attributes.
146 * @param string $content Block default content.
147 * @param \WP_Block $block Block instance.
148 *
149 * @return string Returns the post count.
150 */
151 public static function render_block_post_count( $attributes, $content, $block ) {
152 if ( ! isset( $block->context['postId'] ) ) {
153 return '';
154 }
155 $output = '';
156 $args = array();
157
158 $post_id = absint( $block->context['postId'] );
159 $counter = isset( $attributes['counter'] ) ? $attributes['counter'] : 'total';
160 $blog_id = isset( $attributes['blogId'] ) ? $attributes['blogId'] : get_current_blog_id();
161 $from_date = isset( $attributes['fromDate'] ) ? $attributes['fromDate'] : '';
162 $to_date = isset( $attributes['toDate'] ) ? $attributes['toDate'] : '';
163 $text_before = isset( $attributes['textBefore'] ) ? $attributes['textBefore'] : '';
164 $text_after = isset( $attributes['textAfter'] ) ? $attributes['textAfter'] : '';
165 $text_advanced = isset( $attributes['textAdvanced'] ) ? $attributes['textAdvanced'] : '';
166 $advanced_mode = isset( $attributes['advancedMode'] ) ? $attributes['advancedMode'] : false;
167 $svg_code = isset( $attributes['svgCode'] ) ? $attributes['svgCode'] : '';
168 $svg_icon_size = isset( $attributes['svgIconSize'] ) ? $attributes['svgIconSize'] : '1';
169 $svg_icon_size_unit = isset( $attributes['svgIconSizeUnit'] ) ? $attributes['svgIconSizeUnit'] : 'em';
170 $svg_padding_values = isset( $attributes['svgPaddingValues'] ) ? $attributes['svgPaddingValues'] : array( 0, 0, 0, 0 );
171 $svg_padding_units = isset( $attributes['svgPaddingUnits'] ) ? $attributes['svgPaddingUnits'] : array( 'px', 'px', 'px', 'px' );
172 $svg_icon_location = isset( $attributes['svgIconLocation'] ) ? $attributes['svgIconLocation'] : 'before';
173
174 $args['format_number'] = isset( $attributes['numberFormat'] ) ? $attributes['numberFormat'] : false;
175
176 if ( ! empty( $from_date ) ) {
177 $args['from_date'] = $from_date;
178 }
179 if ( ! empty( $to_date ) ) {
180 $args['to_date'] = $to_date;
181 }
182
183 $counter = Counter::get_post_count_only( $post_id, $counter, $blog_id, $args );
184
185 $classes = array();
186 $classes[] = 'wp-block-tptn-post-count';
187 $classes[] = 'tptn-post-count';
188
189 if ( isset( $attributes['textAlign'] ) ) {
190 $classes[] = 'has-text-align-' . $attributes['textAlign'];
191 }
192 if ( isset( $attributes['style']['elements']['link']['color']['text'] ) ) {
193 $classes[] = 'has-link-color';
194 }
195
196 if ( ! $advanced_mode ) {
197 $output = sprintf(
198 '%1$s%2$s%3$s',
199 wp_kses_post( (string) $text_before ),
200 esc_html( (string) $counter ),
201 wp_kses_post( (string) $text_after )
202 );
203 } elseif ( ! empty( $text_advanced ) ) {
204 $classes[] = 'tptn-advanced-mode';
205 $output = $text_advanced;
206
207 foreach ( array( 'total', 'daily', 'overall' ) as $type ) {
208 if ( false !== strpos( $text_advanced, "%{$type}count%" ) ) {
209 $count = Counter::get_post_count_only( $post_id, $type, $blog_id, $args );
210
211 $output = str_replace(
212 "%{$type}count%",
213 (string) $count,
214 $output
215 );
216 }
217 }
218 }
219
220 $output = sprintf(
221 '<span class="tptn-post-count-text">%s</span>',
222 $output
223 );
224
225 // Add the icon to the output.
226 $icon = '';
227 if ( ! empty( $svg_code ) ) {
228 $padding_style = sprintf(
229 'padding:%s%s %s%s %s%s %s%s;',
230 esc_attr( $svg_padding_values[0] ),
231 esc_attr( $svg_padding_units[0] ),
232 esc_attr( $svg_padding_values[1] ),
233 esc_attr( $svg_padding_units[1] ),
234 esc_attr( $svg_padding_values[2] ),
235 esc_attr( $svg_padding_units[2] ),
236 esc_attr( $svg_padding_values[3] ),
237 esc_attr( $svg_padding_units[3] )
238 );
239
240 $svg_style = sprintf(
241 'width: %1$s%2$s; height: %1$s%2$s; %3$s',
242 esc_attr( $svg_icon_size ),
243 esc_attr( $svg_icon_size_unit ),
244 $padding_style
245 );
246
247 $svg_style = esc_attr( $svg_style );
248
249 if ( preg_match( '/<svg[^>]*style="([^"]*)"/i', $svg_code, $matches ) ) {
250 $existing_style = $matches[1];
251 $new_style = $svg_style . $existing_style;
252
253 $svg_code_with_style = preg_replace( '/(<svg[^>]*style=")[^"]*(")/i', '${1}' . $new_style . '${2}', $svg_code, 1 );
254 } else {
255 $svg_code_with_style = preg_replace( '/<svg /', '<svg style="' . $svg_style . '" ', $svg_code, 1 );
256 }
257
258 $icon = sprintf(
259 '<span class="tptn-post-count-icon">%1$s</span>',
260 wp_kses( $svg_code_with_style, self::get_allowed_svg_tags() )
261 );
262 $icon = '<span class="tptn-post-count-icon">' . $svg_code_with_style . '</span>';
263 }
264 if ( ! empty( $icon ) ) {
265 if ( 'before' === $svg_icon_location ) {
266 $output = $icon . $output;
267 } else {
268 $output = $output . $icon;
269 }
270 }
271
272 $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => implode( ' ', $classes ) ) );
273
274 return sprintf(
275 '<span %1$s>%2$s</span>',
276 $wrapper_attributes,
277 wp_kses( $output, self::get_allowed_svg_tags() )
278 );
279 }
280
281 /**
282 * Get allowed SVG tags for wp_kses.
283 *
284 * @since 4.0.0
285 *
286 * @return array Allowed SVG tags and attributes.
287 */
288 private static function get_allowed_svg_tags() {
289 $allowed_tags = wp_kses_allowed_html( 'post' );
290
291 $svg_tags = array(
292 'svg' => array(
293 'class' => true,
294 'aria-hidden' => true,
295 'aria-labelledby' => true,
296 'role' => true,
297 'xmlns' => true,
298 'width' => true,
299 'height' => true,
300 'fill' => true,
301 'id' => true,
302 'data-name' => true,
303 'viewbox' => true,
304 'style' => true,
305 ),
306 'g' => array(
307 'fill' => true,
308 'stroke-width' => true,
309 'stroke-linecap' => true,
310 'stroke-linejoin' => true,
311 'id' => true,
312 ),
313 'defs' => array(),
314 'style' => array(
315 'type' => true,
316 ),
317 'line' => array(
318 'class' => true,
319 'x1' => true,
320 'y1' => true,
321 'x2' => true,
322 'y2' => true,
323 'fill' => true,
324 'stroke' => true,
325 'stroke-width' => true,
326 'stroke-miterlimit' => true,
327 ),
328 'path' => array(
329 'class' => true,
330 'd' => true,
331 'fill' => true,
332 'stroke' => true,
333 'stroke-linecap' => true,
334 'stroke-linejoin' => true,
335 'stroke-width' => true,
336 ),
337 'polygon' => array(
338 'class' => true,
339 'points' => true,
340 'fill' => true,
341 'stroke' => true,
342 'stroke-width' => true,
343 'stroke-linecap' => true,
344 'stroke-linejoin' => true,
345 'stroke-miterlimit' => true,
346 ),
347 'polyline' => array(
348 'class' => true,
349 'points' => true,
350 'fill' => true,
351 'stroke' => true,
352 'stroke-width' => true,
353 'stroke-linecap' => true,
354 'stroke-linejoin' => true,
355 'stroke-miterlimit' => true,
356 ),
357 'circle' => array(
358 'class' => true,
359 'cx' => true,
360 'cy' => true,
361 'r' => true,
362 'fill' => true,
363 'stroke' => true,
364 'stroke-width' => true,
365 ),
366 'rect' => array(
367 'class' => true,
368 'x' => true,
369 'y' => true,
370 'width' => true,
371 'height' => true,
372 'rx' => true,
373 'ry' => true,
374 'fill' => true,
375 'stroke' => true,
376 'stroke-width' => true,
377 ),
378 'ellipse' => array(
379 'class' => true,
380 'cx' => true,
381 'cy' => true,
382 'rx' => true,
383 'ry' => true,
384 'fill' => true,
385 'stroke' => true,
386 'stroke-width' => true,
387 ),
388 'use' => array(
389 'class' => true,
390 'xlink:href' => true,
391 ),
392 'text' => array(
393 'class' => true,
394 'x' => true,
395 'y' => true,
396 'dy' => true,
397 'text-anchor' => true,
398 'fill' => true,
399 ),
400 'tspan' => array(
401 'class' => true,
402 'x' => true,
403 'y' => true,
404 'dy' => true,
405 'text-anchor' => true,
406 'fill' => true,
407 ),
408 'symbol' => array(
409 'id' => true,
410 'viewBox' => true,
411 'preserveAspectRatio' => true,
412 ),
413 'clipPath' => array(
414 'id' => true,
415 ),
416 'mask' => array(
417 'id' => true,
418 ),
419 'image' => array(
420 'x' => true,
421 'y' => true,
422 'width' => true,
423 'height' => true,
424 'xlink:href' => true,
425 ),
426 'foreignObject' => array(
427 'x' => true,
428 'y' => true,
429 'width' => true,
430 'height' => true,
431 ),
432 );
433
434 return array_merge( $allowed_tags, $svg_tags );
435 }
436
437 /**
438 * Enqueue scripts and styles for the block editor.
439 *
440 * @since 3.1.0
441 */
442 public static function enqueue_block_editor_assets() {
443
444 $styles = Settings::get_styles();
445 $file_prefix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
446
447 foreach ( $styles as $style ) {
448
449 $style_array = Styles_Handler::get_style( $style['id'] );
450
451 if ( ! empty( $style_array['name'] ) ) {
452 $style = $style_array['name'];
453 $extra_css = $style_array['extra_css'];
454
455 $base_path = 'includes/frontend/css/';
456 if ( false !== strpos( $style, '-pro' ) ) {
457 $base_path = 'includes/pro/frontend/css/';
458 }
459
460 wp_enqueue_style(
461 "popular-posts-block-editor-{$style}",
462 plugins_url( "{$base_path}{$style}{$file_prefix}.css", TOP_TEN_PLUGIN_FILE ),
463 array( 'wp-edit-blocks' ),
464 TOP_TEN_VERSION
465 );
466 wp_add_inline_style( "popular-posts-block-editor-{$style}", $extra_css );
467 }
468 }
469 }
470
471 /**
472 * Add custom preload paths for the REST API.
473 *
474 * @since 4.0.0
475 *
476 * @param array $preload_paths Existing preload paths.
477 * @return array Modified preload paths.
478 */
479 public static function add_custom_preload_paths( $preload_paths ) {
480 $preload_paths[] = '/wp/v2/top-10/v1/counter';
481
482 return $preload_paths;
483 }
484 }
485