PluginProbe
Elementor Website Builder – more than just a page builder / 3.32.1
Elementor Website Builder – more than just a page builder v3.32.1
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.32.1, at includes/widgets/star-rating.php

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