PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.44
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.44
51.1.86 51.1.84 51.1.85 51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 All 40 releases
king-addons / includes / widgets / Review_Schema / Review_Schema.php

Review_Schema.php in King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder 51.1.44, at includes/widgets/Review_Schema/Review_Schema.php

472 lines 13.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Review Schema Widget (Free).
4 *
5 * @package King_Addons
6 */
7
8 namespace King_Addons;
9
10 use Elementor\Controls_Manager;
11 use Elementor\Group_Control_Border;
12 use Elementor\Group_Control_Box_Shadow;
13 use Elementor\Group_Control_Typography;
14 use Elementor\Widget_Base;
15
16 if (!defined('ABSPATH')) {
17 exit;
18 }
19
20 /**
21 * Renders a review/rating block with JSON-LD schema.
22 */
23 class Review_Schema extends Widget_Base
24 {
25 /**
26 * Widget slug.
27 *
28 * @return string
29 */
30 public function get_name(): string
31 {
32 return 'king-addons-review-schema';
33 }
34
35 /**
36 * Widget title.
37 *
38 * @return string
39 */
40 public function get_title(): string
41 {
42 return esc_html__('Review Schema', 'king-addons');
43 }
44
45 /**
46 * Widget icon.
47 *
48 * @return string
49 */
50 public function get_icon(): string
51 {
52 return 'king-addons-icon king-addons-review-schema';
53 }
54
55 /**
56 * Style dependencies.
57 *
58 * @return array<int, string>
59 */
60 public function get_style_depends(): array
61 {
62 return [
63 KING_ADDONS_ASSETS_UNIQUE_KEY . '-review-schema-style',
64 ];
65 }
66
67 /**
68 * Script dependencies.
69 *
70 * @return array<int, string>
71 */
72 public function get_script_depends(): array
73 {
74 return [
75 KING_ADDONS_ASSETS_UNIQUE_KEY . '-review-schema-script',
76 ];
77 }
78
79 /**
80 * Categories.
81 *
82 * @return array<int, string>
83 */
84 public function get_categories(): array
85 {
86 return ['king-addons'];
87 }
88
89 /**
90 * Keywords.
91 *
92 * @return array<int, string>
93 */
94 public function get_keywords(): array
95 {
96 return ['review', 'rating', 'schema', 'seo'];
97 }
98
99 /**
100 * Register controls.
101 *
102 * @return void
103 */
104 public function register_controls(): void
105 {
106 $this->register_content_controls();
107 $this->register_style_controls();
108 $this->register_pro_notice_controls();
109 }
110
111 /**
112 * Render widget output.
113 *
114 * @return void
115 */
116 public function render(): void
117 {
118 $settings = $this->get_settings_for_display();
119 $rating = (float) ($settings['kng_rating']['size'] ?? 0);
120 if ($rating <= 0) {
121 return;
122 }
123
124 $item_name = $settings['kng_item_name'] ?? '';
125 $author = $settings['kng_author'] ?? '';
126 $title = $settings['kng_title'] ?? '';
127 $body = $settings['kng_body'] ?? '';
128 $date = $settings['kng_date'] ?? '';
129 $stars_html = $this->render_stars($rating);
130
131 $schema = $this->build_schema($settings);
132 ?>
133 <div class="king-addons-review">
134 <div class="king-addons-review__header">
135 <div class="king-addons-review__item"><?php echo esc_html($item_name); ?></div>
136 <div class="king-addons-review__rating" aria-label="<?php echo esc_attr($rating); ?>">
137 <?php echo $stars_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
138 <span class="king-addons-review__rating-value"><?php echo esc_html(number_format($rating, 1)); ?>/5</span>
139 </div>
140 </div>
141 <?php if (!empty($title)) : ?>
142 <div class="king-addons-review__title"><?php echo esc_html($title); ?></div>
143 <?php endif; ?>
144 <?php if (!empty($body)) : ?>
145 <div class="king-addons-review__body"><?php echo wp_kses_post($body); ?></div>
146 <?php endif; ?>
147 <div class="king-addons-review__meta">
148 <?php if (!empty($author)) : ?>
149 <span class="king-addons-review__author"><?php echo esc_html($author); ?></span>
150 <?php endif; ?>
151 <?php if (!empty($date)) : ?>
152 <span class="king-addons-review__date"><?php echo esc_html(date_i18n(get_option('date_format'), strtotime((string) $date))); ?></span>
153 <?php endif; ?>
154 </div>
155 <script type="application/ld+json">
156 <?php echo wp_json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
157 </script>
158 </div>
159 <?php
160 }
161
162 /**
163 * Content controls.
164 *
165 * @return void
166 */
167 protected function register_content_controls(): void
168 {
169 $this->start_controls_section(
170 'kng_content_section',
171 [
172 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Review', 'king-addons'),
173 'tab' => Controls_Manager::TAB_CONTENT,
174 ]
175 );
176
177 $this->add_control(
178 'kng_item_name',
179 [
180 'label' => esc_html__('Item Name', 'king-addons'),
181 'type' => Controls_Manager::TEXT,
182 'default' => esc_html__('Product or Service', 'king-addons'),
183 ]
184 );
185
186 $this->add_control(
187 'kng_author',
188 [
189 'label' => esc_html__('Author', 'king-addons'),
190 'type' => Controls_Manager::TEXT,
191 'default' => esc_html__('John Doe', 'king-addons'),
192 ]
193 );
194
195 $this->add_control(
196 'kng_rating',
197 [
198 'label' => esc_html__('Rating', 'king-addons'),
199 'type' => Controls_Manager::SLIDER,
200 'size_units' => ['custom'],
201 'range' => [
202 'custom' => [
203 'min' => 0,
204 'max' => 5,
205 'step' => 0.1,
206 ],
207 ],
208 'default' => [
209 'size' => 4.5,
210 'unit' => 'custom',
211 ],
212 ]
213 );
214
215 $this->add_control(
216 'kng_title',
217 [
218 'label' => esc_html__('Review Title', 'king-addons'),
219 'type' => Controls_Manager::TEXT,
220 'default' => esc_html__('Great quality and support', 'king-addons'),
221 ]
222 );
223
224 $this->add_control(
225 'kng_body',
226 [
227 'label' => esc_html__('Review Body', 'king-addons'),
228 'type' => Controls_Manager::WYSIWYG,
229 'default' => esc_html__('The product exceeded expectations and the support team was responsive.', 'king-addons'),
230 ]
231 );
232
233 $this->add_control(
234 'kng_date',
235 [
236 'label' => esc_html__('Review Date', 'king-addons'),
237 'type' => Controls_Manager::DATE_TIME,
238 ]
239 );
240
241 $this->end_controls_section();
242 }
243
244 /**
245 * Style controls.
246 *
247 * @return void
248 */
249 protected function register_style_controls(): void
250 {
251 $this->start_controls_section(
252 'kng_style_section',
253 [
254 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Card', 'king-addons'),
255 'tab' => Controls_Manager::TAB_STYLE,
256 ]
257 );
258
259 $this->add_group_control(
260 Group_Control_Typography::get_type(),
261 [
262 'name' => 'kng_item_typo',
263 'selector' => '{{WRAPPER}} .king-addons-review__item',
264 ]
265 );
266
267 $this->add_control(
268 'kng_item_color',
269 [
270 'label' => esc_html__('Item Color', 'king-addons'),
271 'type' => Controls_Manager::COLOR,
272 'selectors' => [
273 '{{WRAPPER}} .king-addons-review__item' => 'color: {{VALUE}};',
274 ],
275 ]
276 );
277
278 $this->add_group_control(
279 Group_Control_Typography::get_type(),
280 [
281 'name' => 'kng_title_typo',
282 'selector' => '{{WRAPPER}} .king-addons-review__title',
283 ]
284 );
285
286 $this->add_control(
287 'kng_title_color',
288 [
289 'label' => esc_html__('Title Color', 'king-addons'),
290 'type' => Controls_Manager::COLOR,
291 'selectors' => [
292 '{{WRAPPER}} .king-addons-review__title' => 'color: {{VALUE}};',
293 ],
294 ]
295 );
296
297 $this->add_group_control(
298 Group_Control_Typography::get_type(),
299 [
300 'name' => 'kng_body_typo',
301 'selector' => '{{WRAPPER}} .king-addons-review__body',
302 ]
303 );
304
305 $this->add_control(
306 'kng_body_color',
307 [
308 'label' => esc_html__('Body Color', 'king-addons'),
309 'type' => Controls_Manager::COLOR,
310 'selectors' => [
311 '{{WRAPPER}} .king-addons-review__body' => 'color: {{VALUE}};',
312 ],
313 ]
314 );
315
316 $this->add_group_control(
317 Group_Control_Typography::get_type(),
318 [
319 'name' => 'kng_meta_typo',
320 'selector' => '{{WRAPPER}} .king-addons-review__meta',
321 ]
322 );
323
324 $this->add_control(
325 'kng_meta_color',
326 [
327 'label' => esc_html__('Meta Color', 'king-addons'),
328 'type' => Controls_Manager::COLOR,
329 'selectors' => [
330 '{{WRAPPER}} .king-addons-review__meta' => 'color: {{VALUE}};',
331 ],
332 ]
333 );
334
335 $this->add_group_control(
336 Group_Control_Border::get_type(),
337 [
338 'name' => 'kng_card_border',
339 'selector' => '{{WRAPPER}} .king-addons-review',
340 ]
341 );
342
343 $this->add_group_control(
344 Group_Control_Box_Shadow::get_type(),
345 [
346 'name' => 'kng_card_shadow',
347 'selector' => '{{WRAPPER}} .king-addons-review',
348 ]
349 );
350
351 $this->add_control(
352 'kng_card_radius',
353 [
354 'label' => esc_html__('Border Radius', 'king-addons'),
355 'type' => Controls_Manager::SLIDER,
356 'size_units' => ['px', '%'],
357 'range' => [
358 'px' => ['min' => 0, 'max' => 40],
359 '%' => ['min' => 0, 'max' => 100],
360 ],
361 'selectors' => [
362 '{{WRAPPER}} .king-addons-review' => 'border-radius: {{SIZE}}{{UNIT}};',
363 ],
364 ]
365 );
366
367 $this->add_responsive_control(
368 'kng_card_padding',
369 [
370 'label' => esc_html__('Padding', 'king-addons'),
371 'type' => Controls_Manager::DIMENSIONS,
372 'size_units' => ['px', 'em'],
373 'selectors' => [
374 '{{WRAPPER}} .king-addons-review' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
375 ],
376 ]
377 );
378
379 $this->end_controls_section();
380 }
381
382 /**
383 * Pro notice.
384 *
385 * @return void
386 */
387 public function register_pro_notice_controls(): void
388 {
389 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
390 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'review-schema', [
391 'Aggregate rating with count',
392 'Multiple reviews and layout options',
393 'Custom star icons and animations',
394 'Schema type selection (Product/LocalBusiness)',
395 ]);
396 }
397 }
398
399 /**
400 * Render stars.
401 *
402 * @param float $rating Rating.
403 *
404 * @return string
405 */
406 protected function render_stars(float $rating): string
407 {
408 $full = floor($rating);
409 $half = ($rating - $full) >= 0.5;
410 $html = '<span class="king-addons-review__stars" aria-hidden="true">';
411 for ($i = 1; $i <= 5; $i++) {
412 if ($i <= $full) {
413 $html .= '<span class="king-addons-review__star is-full">�
414 </span>';
415 } elseif ($half && $i === ($full + 1)) {
416 $html .= '<span class="king-addons-review__star is-half">�
417 </span>';
418 } else {
419 $html .= '<span class="king-addons-review__star is-empty">☆</span>';
420 }
421 }
422 $html .= '</span>';
423 return $html;
424 }
425
426 /**
427 * Build schema for single review.
428 *
429 * @param array<string, mixed> $settings Settings.
430 *
431 * @return array<string, mixed>
432 */
433 protected function build_schema(array $settings): array
434 {
435 $rating = (float) ($settings['kng_rating']['size'] ?? 0);
436 $author = $settings['kng_author'] ?? '';
437 $item_name = $settings['kng_item_name'] ?? '';
438 $title = $settings['kng_title'] ?? '';
439 $body = $settings['kng_body'] ?? '';
440 $date = !empty($settings['kng_date']) ? date_i18n('c', strtotime((string) $settings['kng_date'])) : '';
441
442 return [
443 '@context' => 'https://schema.org',
444 '@type' => 'Review',
445 'itemReviewed' => [
446 '@type' => 'Thing',
447 'name' => $item_name,
448 ],
449 'author' => [
450 '@type' => 'Person',
451 'name' => $author,
452 ],
453 'datePublished' => $date,
454 'name' => $title,
455 'reviewBody' => wp_strip_all_tags($body),
456 'reviewRating' => [
457 '@type' => 'Rating',
458 'ratingValue' => number_format($rating, 1, '.', ''),
459 'bestRating' => '5',
460 'worstRating' => '1',
461 ],
462 ];
463 }
464 }
465
466
467
468
469
470
471
472