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

584 lines 13.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 * 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 'start' => [
219 'title' => esc_html__( 'Start', 'elementor' ),
220 'icon' => 'eicon-text-align-left',
221 ],
222 'center' => [
223 'title' => esc_html__( 'Center', 'elementor' ),
224 'icon' => 'eicon-text-align-center',
225 ],
226 'end' => [
227 'title' => esc_html__( 'End', '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 'classes' => 'elementor-control-start-end',
236 'classes_dictionary' => [
237 'left' => is_rtl() ? 'end' : 'start',
238 'right' => is_rtl() ? 'start' : 'end',
239 ],
240 'selectors_dictionary' => [
241 'left' => is_rtl() ? 'end' : 'start',
242 'right' => is_rtl() ? 'start' : 'end',
243 ],
244 'prefix_class' => 'elementor-star-rating%s--align-',
245 'selectors' => [
246 '{{WRAPPER}}' => 'text-align: {{VALUE}}',
247 ],
248 ]
249 );
250
251 $this->end_controls_section();
252
253 $this->start_controls_section(
254 'section_title_style',
255 [
256 'label' => esc_html__( 'Title', 'elementor' ),
257 'tab' => Controls_Manager::TAB_STYLE,
258 'condition' => [
259 'title!' => '',
260 ],
261 ]
262 );
263
264 $this->add_control(
265 'title_color',
266 [
267 'label' => esc_html__( 'Text Color', 'elementor' ),
268 'type' => Controls_Manager::COLOR,
269 'global' => [
270 'default' => Global_Colors::COLOR_TEXT,
271 ],
272 'selectors' => [
273 '{{WRAPPER}} .elementor-star-rating__title' => 'color: {{VALUE}}',
274 ],
275 ]
276 );
277
278 $this->add_group_control(
279 Group_Control_Typography::get_type(),
280 [
281 'name' => 'title_typography',
282 'selector' => '{{WRAPPER}} .elementor-star-rating__title',
283 'global' => [
284 'default' => Global_Typography::TYPOGRAPHY_TEXT,
285 ],
286 ]
287 );
288
289 $this->add_group_control(
290 Group_Control_Text_Shadow::get_type(),
291 [
292 'name' => 'title_shadow',
293 'selector' => '{{WRAPPER}} .elementor-star-rating__title',
294 ]
295 );
296
297 $this->add_responsive_control(
298 'title_gap',
299 [
300 'label' => esc_html__( 'Gap', 'elementor' ),
301 'type' => Controls_Manager::SLIDER,
302 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
303 'range' => [
304 'px' => [
305 'max' => 50,
306 ],
307 'em' => [
308 'min' => 0,
309 'max' => 5,
310 ],
311 'rem' => [
312 'min' => 0,
313 'max' => 5,
314 ],
315 ],
316 'selectors' => [
317 '{{WRAPPER}}:not(.elementor-star-rating--align-justify) .elementor-star-rating__title' => 'margin-inline-end: {{SIZE}}{{UNIT}}',
318 ],
319 ]
320 );
321
322 $this->end_controls_section();
323
324 $this->start_controls_section(
325 'section_stars_style',
326 [
327 'label' => esc_html__( 'Stars', 'elementor' ),
328 'tab' => Controls_Manager::TAB_STYLE,
329 ]
330 );
331
332 $this->add_responsive_control(
333 'icon_size',
334 [
335 'label' => esc_html__( 'Size', 'elementor' ),
336 'type' => Controls_Manager::SLIDER,
337 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
338 'range' => [
339 'px' => [
340 'max' => 100,
341 ],
342 'em' => [
343 'min' => 0,
344 'max' => 10,
345 ],
346 'rem' => [
347 'min' => 0,
348 'max' => 10,
349 ],
350 ],
351 'selectors' => [
352 '{{WRAPPER}} .elementor-star-rating' => 'font-size: {{SIZE}}{{UNIT}}',
353 ],
354 ]
355 );
356
357 $this->add_responsive_control(
358 'icon_space',
359 [
360 'label' => esc_html__( 'Spacing', 'elementor' ),
361 'type' => Controls_Manager::SLIDER,
362 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
363 'range' => [
364 'px' => [
365 'max' => 50,
366 ],
367 'em' => [
368 'min' => 0,
369 'max' => 5,
370 ],
371 'rem' => [
372 'min' => 0,
373 'max' => 5,
374 ],
375 ],
376 'selectors' => [
377 '{{WRAPPER}} .elementor-star-rating i:not(:last-of-type)' => 'margin-inline-end: {{SIZE}}{{UNIT}}',
378 ],
379 ]
380 );
381
382 $this->add_control(
383 'stars_color',
384 [
385 'label' => esc_html__( 'Color', 'elementor' ),
386 'type' => Controls_Manager::COLOR,
387 'selectors' => [
388 '{{WRAPPER}} .elementor-star-rating i:before' => 'color: {{VALUE}}',
389 ],
390 'separator' => 'before',
391 ]
392 );
393
394 $this->add_control(
395 'stars_unmarked_color',
396 [
397 'label' => esc_html__( 'Unmarked Color', 'elementor' ),
398 'type' => Controls_Manager::COLOR,
399 'selectors' => [
400 '{{WRAPPER}} .elementor-star-rating i' => 'color: {{VALUE}}',
401 ],
402 ]
403 );
404
405 $this->end_controls_section();
406 }
407
408 /**
409 * @since 2.3.0
410 * @access protected
411 */
412 protected function get_rating() {
413 $settings = $this->get_settings_for_display();
414 $rating_scale = (int) $settings['rating_scale'];
415 $rating = min( (float) $settings['rating'], $rating_scale );
416
417 return [ $rating, $rating_scale ];
418 }
419
420 /**
421 * Print the actual stars and calculate their filling.
422 *
423 * Rating type is float to allow stars-count to be a fraction.
424 * Floored-rating type is int, to represent the rounded-down stars count.
425 * In the `for` loop, the index type is float to allow comparing with the rating value.
426 *
427 * @since 2.3.0
428 * @access protected
429 */
430 protected function render_stars( $icon ) {
431 $rating_data = $this->get_rating();
432 $rating = (float) $rating_data[0];
433 $floored_rating = floor( $rating );
434 $stars_html = '';
435
436 for ( $stars = 1.0; $stars <= $rating_data[1]; $stars++ ) {
437 if ( $stars <= $floored_rating ) {
438 $stars_html .= '<i class="elementor-star-full" aria-hidden="true">' . $icon . '</i>';
439 } elseif ( $floored_rating + 1 === $stars && $rating !== $floored_rating ) {
440 $stars_html .= '<i class="elementor-star-' . ( $rating - $floored_rating ) * 10 . '" aria-hidden="true">' . $icon . '</i>';
441 } else {
442 $stars_html .= '<i class="elementor-star-empty" aria-hidden="true">' . $icon . '</i>';
443 }
444 }
445
446 Utils::print_unescaped_internal_string( $stars_html );
447 }
448
449 /**
450 * @since 2.3.0
451 * @access protected
452 */
453 protected function render() {
454 $settings = $this->get_settings_for_display();
455 $rating_data = $this->get_rating();
456 $textual_rating = sprintf(
457 /* translators: 1: Rating value. 2: Rating scale. */
458 esc_html__( 'Rated %1$s out of %2$s', 'elementor' ),
459 $rating_data[0],
460 $rating_data[1]
461 );
462 $icon = '&#xE934;';
463
464 if ( 'star_fontawesome' === $settings['star_style'] ) {
465 if ( 'outline' === $settings['unmarked_star_style'] ) {
466 $icon = '&#xE933;';
467 }
468 } elseif ( 'star_unicode' === $settings['star_style'] ) {
469 $icon = '&#9733;';
470
471 if ( 'outline' === $settings['unmarked_star_style'] ) {
472 $icon = '&#9734;';
473 }
474 }
475
476 $this->add_render_attribute( 'icon_wrapper', [
477 'class' => 'elementor-star-rating',
478 'itemtype' => 'http://schema.org/Rating',
479 'itemscope' => '',
480 'itemprop' => 'reviewRating',
481 ] );
482 ?>
483 <div class="elementor-star-rating__wrapper">
484 <?php if ( ! Utils::is_empty( $settings['title'] ) ) : ?>
485 <div class="elementor-star-rating__title"><?php echo esc_html( $settings['title'] ); ?></div>
486 <?php endif; ?>
487 <div <?php $this->print_render_attribute_string( 'icon_wrapper' ); ?>>
488 <?php $this->render_stars( $icon ); ?>
489 <span itemprop="ratingValue" class="elementor-screen-only"><?php echo esc_html( $textual_rating ); ?></span>
490 </div>
491 </div>
492 <?php
493 }
494
495 public function render_markdown(): string {
496 $settings = $this->get_settings_for_display();
497 $title = Utils::html_to_plain_text( $settings['title'] ?? '' );
498 $rating = floatval( $settings['rating'] ?? 0 );
499 $scale = intval( $settings['rating_scale'] ?? 5 );
500
501 if ( empty( $rating ) ) {
502 return '';
503 }
504
505 $full_stars = intval( floor( $rating ) );
506 $empty_stars = $scale - $full_stars;
507 $stars = str_repeat( '�
508 ', $full_stars ) . str_repeat( '', max( 0, $empty_stars ) );
509
510 $md = $stars . ' ' . $rating . '/' . $scale;
511
512 if ( ! empty( $title ) ) {
513 $md .= "\n\n" . $title;
514 }
515
516 return $md;
517 }
518
519 /**
520 * @since 2.9.0
521 * @access protected
522 */
523 protected function content_template() {
524 ?>
525 <#
526 var getRating = function() {
527 var ratingScale = parseInt( settings.rating_scale, 10 ),
528 rating = settings.rating > ratingScale ? ratingScale : settings.rating;
529
530 return [ rating, ratingScale ];
531 },
532 ratingData = getRating(),
533 rating = ratingData[0],
534 textualRating = 'Rated ' + ratingData[0] + ' out of ' + ratingData[1],
535 renderStars = function( icon ) {
536 var starsHtml = '',
537 flooredRating = Math.floor( rating );
538
539 for ( var stars = 1; stars <= ratingData[1]; stars++ ) {
540 if ( stars <= flooredRating ) {
541 starsHtml += '<i class="elementor-star-full" aria-hidden="true">' + icon + '</i>';
542 } else if ( flooredRating + 1 === stars && rating !== flooredRating ) {
543 starsHtml += '<i class="elementor-star-' + ( rating - flooredRating ).toFixed( 1 ) * 10 + '" aria-hidden="true">' + icon + '</i>';
544 } else {
545 starsHtml += '<i class="elementor-star-empty" aria-hidden="true">' + icon + '</i>';
546 }
547 }
548
549 return starsHtml;
550 },
551 icon = '&#xE934;';
552
553 if ( 'star_fontawesome' === settings.star_style ) {
554 if ( 'outline' === settings.unmarked_star_style ) {
555 icon = '&#xE933;';
556 }
557 } else if ( 'star_unicode' === settings.star_style ) {
558 icon = '&#9733;';
559
560 if ( 'outline' === settings.unmarked_star_style ) {
561 icon = '&#9734;';
562 }
563 }
564
565 view.addRenderAttribute( 'iconWrapper', 'class', 'elementor-star-rating' );
566 view.addRenderAttribute( 'iconWrapper', 'itemtype', 'http://schema.org/Rating' );
567 view.addRenderAttribute( 'iconWrapper', 'itemscope', '' );
568 view.addRenderAttribute( 'iconWrapper', 'itemprop', 'reviewRating' );
569
570 var stars = renderStars( icon );
571 #>
572 <div class="elementor-star-rating__wrapper">
573 <# if ( ! _.isEmpty( settings.title ) ) { #>
574 <div class="elementor-star-rating__title">{{ settings.title }}</div>
575 <# } #>
576 <div {{{ view.getRenderAttributeString( 'iconWrapper' ) }}} >
577 {{{ stars }}}
578 <span itemprop="ratingValue" class="elementor-screen-only">{{ textualRating }}</span>
579 </div>
580 </div>
581 <?php
582 }
583 }
584