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

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