PluginProbe
Elementor Website Builder – more than just a page builder / 3.22.3
Elementor Website Builder – more than just a page builder v3.22.3
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / widgets / star-rating.php

star-rating.php in Elementor Website Builder – more than just a page builder 3.22.3, at includes/widgets/star-rating.php

536 lines 12.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
9 use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
10
11 /**
12 * Elementor star rating widget.
13 *
14 * Elementor widget that displays star rating.
15 *
16 * @since 2.3.0
17 */
18 class Widget_Star_Rating extends Widget_Base {
19
20 /**
21 * Get widget name.
22 *
23 * Retrieve star rating widget name.
24 *
25 * @since 2.3.0
26 * @access public
27 *
28 * @return string Widget name.
29 */
30 public function get_name() {
31 return 'star-rating';
32 }
33
34 /**
35 * Get widget title.
36 *
37 * Retrieve star rating widget title.
38 *
39 * @since 2.3.0
40 * @access public
41 *
42 * @return string Widget title.
43 */
44 public function get_title() {
45 return esc_html__( 'Star Rating', 'elementor' );
46 }
47
48 /**
49 * Get widget icon.
50 *
51 * Retrieve star rating widget icon.
52 *
53 * @since 2.3.0
54 * @access public
55 *
56 * @return string Widget icon.
57 */
58 public function get_icon() {
59 return 'eicon-rating';
60 }
61
62 /**
63 * Get widget keywords.
64 *
65 * Retrieve the list of keywords the widget belongs to.
66 *
67 * @since 2.3.0
68 * @access public
69 *
70 * @return array Widget keywords.
71 */
72 public function get_keywords() {
73 return [ 'star', 'rating', 'rate', 'review' ];
74 }
75
76 protected function is_dynamic_content(): bool {
77 return false;
78 }
79
80 /**
81 * Hide widget from panel.
82 *
83 * Hide the star rating widget from the panel.
84 *
85 * @since 3.17.0
86 * @return bool
87 */
88 public function show_in_panel(): bool {
89 return false;
90 }
91
92 /**
93 * Register star rating widget controls.
94 *
95 * Adds different input fields to allow the user to change and customize the widget settings.
96 *
97 * @since 3.1.0
98 * @access protected
99 */
100 protected function register_controls() {
101 $this->start_controls_section(
102 'section_rating',
103 [
104 'label' => esc_html__( 'Star Rating', 'elementor' ),
105 ]
106 );
107
108 if ( Plugin::$instance->widgets_manager->get_widget_types( 'rating' ) ) {
109 $this->add_deprecation_message(
110 '3.17.0',
111 esc_html__(
112 'You are currently editing a Star Rating widget in its old version. Drag a new Rating widget onto your page to use a newer version, providing better capabilities.',
113 'elementor'
114 ),
115 'rating'
116 );
117 }
118
119 $this->add_control(
120 'rating_scale',
121 [
122 'label' => esc_html__( 'Rating Scale', 'elementor' ),
123 'type' => Controls_Manager::SELECT,
124 'options' => [
125 '5' => '0-5',
126 '10' => '0-10',
127 ],
128 'default' => '5',
129 ]
130 );
131
132 $this->add_control(
133 'rating',
134 [
135 'label' => esc_html__( 'Rating', 'elementor' ),
136 'type' => Controls_Manager::NUMBER,
137 'min' => 0,
138 'max' => 10,
139 'step' => 0.1,
140 'default' => 5,
141 'dynamic' => [
142 'active' => true,
143 ],
144 ]
145 );
146
147 $this->add_control(
148 'star_style',
149 [
150 'label' => esc_html__( 'Icon', 'elementor' ),
151 'type' => Controls_Manager::SELECT,
152 'options' => [
153 'star_fontawesome' => 'Font Awesome',
154 'star_unicode' => 'Unicode',
155 ],
156 'default' => 'star_fontawesome',
157 'render_type' => 'template',
158 'prefix_class' => 'elementor--star-style-',
159 'separator' => 'before',
160 ]
161 );
162
163 $this->add_control(
164 'unmarked_star_style',
165 [
166 'label' => esc_html__( 'Unmarked Style', 'elementor' ),
167 'type' => Controls_Manager::CHOOSE,
168 'options' => [
169 'solid' => [
170 'title' => esc_html__( 'Solid', 'elementor' ),
171 'icon' => 'eicon-star',
172 ],
173 'outline' => [
174 'title' => esc_html__( 'Outline', 'elementor' ),
175 'icon' => 'eicon-star-o',
176 ],
177 ],
178 'default' => 'solid',
179 ]
180 );
181
182 $this->add_control(
183 'title',
184 [
185 'label' => esc_html__( 'Title', 'elementor' ),
186 'type' => Controls_Manager::TEXT,
187 'separator' => 'before',
188 'dynamic' => [
189 'active' => true,
190 ],
191 ]
192 );
193
194 $this->add_responsive_control(
195 'align',
196 [
197 'label' => esc_html__( 'Alignment', 'elementor' ),
198 'type' => Controls_Manager::CHOOSE,
199 'options' => [
200 'left' => [
201 'title' => esc_html__( 'Left', 'elementor' ),
202 'icon' => 'eicon-text-align-left',
203 ],
204 'center' => [
205 'title' => esc_html__( 'Center', 'elementor' ),
206 'icon' => 'eicon-text-align-center',
207 ],
208 'right' => [
209 'title' => esc_html__( 'Right', 'elementor' ),
210 'icon' => 'eicon-text-align-right',
211 ],
212 'justify' => [
213 'title' => esc_html__( 'Justified', 'elementor' ),
214 'icon' => 'eicon-text-align-justify',
215 ],
216 ],
217 'prefix_class' => 'elementor-star-rating%s--align-',
218 'selectors' => [
219 '{{WRAPPER}}' => 'text-align: {{VALUE}}',
220 ],
221 ]
222 );
223
224 $this->end_controls_section();
225
226 $this->start_controls_section(
227 'section_title_style',
228 [
229 'label' => esc_html__( 'Title', 'elementor' ),
230 'tab' => Controls_Manager::TAB_STYLE,
231 'condition' => [
232 'title!' => '',
233 ],
234 ]
235 );
236
237 $this->add_control(
238 'title_color',
239 [
240 'label' => esc_html__( 'Text Color', 'elementor' ),
241 'type' => Controls_Manager::COLOR,
242 'global' => [
243 'default' => Global_Colors::COLOR_TEXT,
244 ],
245 'selectors' => [
246 '{{WRAPPER}} .elementor-star-rating__title' => 'color: {{VALUE}}',
247 ],
248 ]
249 );
250
251 $this->add_group_control(
252 Group_Control_Typography::get_type(),
253 [
254 'name' => 'title_typography',
255 'selector' => '{{WRAPPER}} .elementor-star-rating__title',
256 'global' => [
257 'default' => Global_Typography::TYPOGRAPHY_TEXT,
258 ],
259 ]
260 );
261
262 $this->add_group_control(
263 Group_Control_Text_Shadow::get_type(),
264 [
265 'name' => 'title_shadow',
266 'selector' => '{{WRAPPER}} .elementor-star-rating__title',
267 ]
268 );
269
270 $this->add_responsive_control(
271 'title_gap',
272 [
273 'label' => esc_html__( 'Gap', 'elementor' ),
274 'type' => Controls_Manager::SLIDER,
275 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
276 'range' => [
277 'px' => [
278 'max' => 50,
279 ],
280 'em' => [
281 'min' => 0,
282 'max' => 5,
283 ],
284 'rem' => [
285 'min' => 0,
286 'max' => 5,
287 ],
288 ],
289 'selectors' => [
290 'body:not(.rtl) {{WRAPPER}}:not(.elementor-star-rating--align-justify) .elementor-star-rating__title' => 'margin-right: {{SIZE}}{{UNIT}}',
291 'body.rtl {{WRAPPER}}:not(.elementor-star-rating--align-justify) .elementor-star-rating__title' => 'margin-left: {{SIZE}}{{UNIT}}',
292 ],
293 ]
294 );
295
296 $this->end_controls_section();
297
298 $this->start_controls_section(
299 'section_stars_style',
300 [
301 'label' => esc_html__( 'Stars', 'elementor' ),
302 'tab' => Controls_Manager::TAB_STYLE,
303 ]
304 );
305
306 $this->add_responsive_control(
307 'icon_size',
308 [
309 'label' => esc_html__( 'Size', 'elementor' ),
310 'type' => Controls_Manager::SLIDER,
311 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
312 'range' => [
313 'px' => [
314 'max' => 100,
315 ],
316 'em' => [
317 'min' => 0,
318 'max' => 10,
319 ],
320 'rem' => [
321 'min' => 0,
322 'max' => 10,
323 ],
324 ],
325 'selectors' => [
326 '{{WRAPPER}} .elementor-star-rating' => 'font-size: {{SIZE}}{{UNIT}}',
327 ],
328 ]
329 );
330
331 $this->add_responsive_control(
332 'icon_space',
333 [
334 'label' => esc_html__( 'Spacing', 'elementor' ),
335 'type' => Controls_Manager::SLIDER,
336 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
337 'range' => [
338 'px' => [
339 'max' => 50,
340 ],
341 'em' => [
342 'min' => 0,
343 'max' => 5,
344 ],
345 'rem' => [
346 'min' => 0,
347 'max' => 5,
348 ],
349 ],
350 'selectors' => [
351 'body:not(.rtl) {{WRAPPER}} .elementor-star-rating i:not(:last-of-type)' => 'margin-right: {{SIZE}}{{UNIT}}',
352 'body.rtl {{WRAPPER}} .elementor-star-rating i:not(:last-of-type)' => 'margin-left: {{SIZE}}{{UNIT}}',
353 ],
354 ]
355 );
356
357 $this->add_control(
358 'stars_color',
359 [
360 'label' => esc_html__( 'Color', 'elementor' ),
361 'type' => Controls_Manager::COLOR,
362 'selectors' => [
363 '{{WRAPPER}} .elementor-star-rating i:before' => 'color: {{VALUE}}',
364 ],
365 'separator' => 'before',
366 ]
367 );
368
369 $this->add_control(
370 'stars_unmarked_color',
371 [
372 'label' => esc_html__( 'Unmarked Color', 'elementor' ),
373 'type' => Controls_Manager::COLOR,
374 'selectors' => [
375 '{{WRAPPER}} .elementor-star-rating i' => 'color: {{VALUE}}',
376 ],
377 ]
378 );
379
380 $this->end_controls_section();
381 }
382
383 /**
384 * @since 2.3.0
385 * @access protected
386 */
387 protected function get_rating() {
388 $settings = $this->get_settings_for_display();
389 $rating_scale = (int) $settings['rating_scale'];
390 $rating = (float) $settings['rating'] > $rating_scale ? $rating_scale : $settings['rating'];
391
392 return [ $rating, $rating_scale ];
393 }
394
395 /**
396 * Print the actual stars and calculate their filling.
397 *
398 * Rating type is float to allow stars-count to be a fraction.
399 * Floored-rating type is int, to represent the rounded-down stars count.
400 * In the `for` loop, the index type is float to allow comparing with the rating value.
401 *
402 * @since 2.3.0
403 * @access protected
404 */
405 protected function render_stars( $icon ) {
406 $rating_data = $this->get_rating();
407 $rating = (float) $rating_data[0];
408 $floored_rating = floor( $rating );
409 $stars_html = '';
410
411 for ( $stars = 1.0; $stars <= $rating_data[1]; $stars++ ) {
412 if ( $stars <= $floored_rating ) {
413 $stars_html .= '<i class="elementor-star-full">' . $icon . '</i>';
414 } elseif ( $floored_rating + 1 === $stars && $rating !== $floored_rating ) {
415 $stars_html .= '<i class="elementor-star-' . ( $rating - $floored_rating ) * 10 . '">' . $icon . '</i>';
416 } else {
417 $stars_html .= '<i class="elementor-star-empty">' . $icon . '</i>';
418 }
419 }
420
421 return $stars_html;
422 }
423
424 /**
425 * @since 2.3.0
426 * @access protected
427 */
428 protected function render() {
429 $settings = $this->get_settings_for_display();
430 $rating_data = $this->get_rating();
431 $textual_rating = $rating_data[0] . '/' . $rating_data[1];
432 $icon = '&#xE934;';
433
434 if ( 'star_fontawesome' === $settings['star_style'] ) {
435 if ( 'outline' === $settings['unmarked_star_style'] ) {
436 $icon = '&#xE933;';
437 }
438 } elseif ( 'star_unicode' === $settings['star_style'] ) {
439 $icon = '&#9733;';
440
441 if ( 'outline' === $settings['unmarked_star_style'] ) {
442 $icon = '&#9734;';
443 }
444 }
445
446 $this->add_render_attribute( 'icon_wrapper', [
447 'class' => 'elementor-star-rating',
448 'title' => $textual_rating,
449 'itemtype' => 'http://schema.org/Rating',
450 'itemscope' => '',
451 'itemprop' => 'reviewRating',
452 ] );
453
454 $schema_rating = '<span itemprop="ratingValue" class="elementor-screen-only">' . $textual_rating . '</span>';
455 $stars_element = '<div ' . $this->get_render_attribute_string( 'icon_wrapper' ) . '>' . $this->render_stars( $icon ) . ' ' . $schema_rating . '</div>';
456 ?>
457
458 <div class="elementor-star-rating__wrapper">
459 <?php if ( ! Utils::is_empty( $settings['title'] ) ) : ?>
460 <div class="elementor-star-rating__title"><?php echo esc_html( $settings['title'] ); ?></div>
461 <?php endif;
462 // PHPCS - $stars_element contains an HTML string that cannot be escaped. ?>
463 <?php echo $stars_element; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
464 </div>
465 <?php
466 }
467
468 /**
469 * @since 2.9.0
470 * @access protected
471 */
472 protected function content_template() {
473 ?>
474 <#
475 var getRating = function() {
476 var ratingScale = parseInt( settings.rating_scale, 10 ),
477 rating = settings.rating > ratingScale ? ratingScale : settings.rating;
478
479 return [ rating, ratingScale ];
480 },
481 ratingData = getRating(),
482 rating = ratingData[0],
483 textualRating = ratingData[0] + '/' + ratingData[1],
484 renderStars = function( icon ) {
485 var starsHtml = '',
486 flooredRating = Math.floor( rating );
487
488 for ( var stars = 1; stars <= ratingData[1]; stars++ ) {
489 if ( stars <= flooredRating ) {
490 starsHtml += '<i class="elementor-star-full">' + icon + '</i>';
491 } else if ( flooredRating + 1 === stars && rating !== flooredRating ) {
492 starsHtml += '<i class="elementor-star-' + ( rating - flooredRating ).toFixed( 1 ) * 10 + '">' + icon + '</i>';
493 } else {
494 starsHtml += '<i class="elementor-star-empty">' + icon + '</i>';
495 }
496 }
497
498 return starsHtml;
499 },
500 icon = '&#xE934;';
501
502 if ( 'star_fontawesome' === settings.star_style ) {
503 if ( 'outline' === settings.unmarked_star_style ) {
504 icon = '&#xE933;';
505 }
506 } else if ( 'star_unicode' === settings.star_style ) {
507 icon = '&#9733;';
508
509 if ( 'outline' === settings.unmarked_star_style ) {
510 icon = '&#9734;';
511 }
512 }
513
514 view.addRenderAttribute( 'iconWrapper', 'class', 'elementor-star-rating' );
515 view.addRenderAttribute( 'iconWrapper', 'itemtype', 'http://schema.org/Rating' );
516 view.addRenderAttribute( 'iconWrapper', 'title', textualRating );
517 view.addRenderAttribute( 'iconWrapper', 'itemscope', '' );
518 view.addRenderAttribute( 'iconWrapper', 'itemprop', 'reviewRating' );
519
520 var stars = renderStars( icon );
521 #>
522
523 <div class="elementor-star-rating__wrapper">
524 <# if ( ! _.isEmpty( settings.title ) ) { #>
525 <div class="elementor-star-rating__title">{{ settings.title }}</div>
526 <# } #>
527 <div {{{ view.getRenderAttributeString( 'iconWrapper' ) }}} >
528 {{{ stars }}}
529 <span itemprop="ratingValue" class="elementor-screen-only">{{ textualRating }}</span>
530 </div>
531 </div>
532
533 <?php
534 }
535 }
536