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 / counter.php

counter.php in Elementor Website Builder – more than just a page builder 4.2.0, at includes/widgets/counter.php

728 lines 17.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 counter widget.
13 *
14 * Elementor widget that displays stats and numbers in an escalating manner.
15 *
16 * @since 1.0.0
17 */
18 class Widget_Counter extends Widget_Base {
19
20 /**
21 * Get widget name.
22 *
23 * Retrieve counter widget name.
24 *
25 * @since 1.0.0
26 * @access public
27 *
28 * @return string Widget name.
29 */
30 public function get_name() {
31 return 'counter';
32 }
33
34 /**
35 * Get widget title.
36 *
37 * Retrieve counter widget title.
38 *
39 * @since 1.0.0
40 * @access public
41 *
42 * @return string Widget title.
43 */
44 public function get_title() {
45 return esc_html__( 'Counter', 'elementor' );
46 }
47
48 /**
49 * Get widget icon.
50 *
51 * Retrieve counter widget icon.
52 *
53 * @since 1.0.0
54 * @access public
55 *
56 * @return string Widget icon.
57 */
58 public function get_icon() {
59 return 'eicon-counter';
60 }
61
62 /**
63 * Retrieve the list of scripts the counter widget depended on.
64 *
65 * Used to set scripts dependencies required to run the widget.
66 *
67 * @since 1.3.0
68 * @access public
69 *
70 * @return array Widget scripts dependencies.
71 */
72 public function get_script_depends() {
73 return [ 'jquery-numerator' ];
74 }
75
76 /**
77 * Get widget keywords.
78 *
79 * Retrieve the list of keywords the widget belongs to.
80 *
81 * @since 2.1.0
82 * @access public
83 *
84 * @return array Widget keywords.
85 */
86 public function get_keywords() {
87 return [ 'counter' ];
88 }
89
90 protected function is_dynamic_content(): bool {
91 return false;
92 }
93
94 /**
95 * Get style dependencies.
96 *
97 * Retrieve the list of style dependencies the widget requires.
98 *
99 * @since 3.24.0
100 * @access public
101 *
102 * @return array Widget style dependencies.
103 */
104 public function get_style_depends(): array {
105 return [ 'widget-counter' ];
106 }
107
108 public function has_widget_inner_wrapper(): bool {
109 return ! Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
110 }
111
112 /**
113 * Register counter widget controls.
114 *
115 * Adds different input fields to allow the user to change and customize the widget settings.
116 *
117 * @since 3.1.0
118 * @access protected
119 */
120 protected function register_controls() {
121 $this->start_controls_section(
122 'section_counter',
123 [
124 'label' => esc_html__( 'Counter', 'elementor' ),
125 ]
126 );
127
128 $this->add_control(
129 'starting_number',
130 [
131 'label' => esc_html__( 'Starting Number', 'elementor' ),
132 'type' => Controls_Manager::NUMBER,
133 'default' => 0,
134 'dynamic' => [
135 'active' => true,
136 ],
137 ]
138 );
139
140 $this->add_control(
141 'ending_number',
142 [
143 'label' => esc_html__( 'Ending Number', 'elementor' ),
144 'type' => Controls_Manager::NUMBER,
145 'default' => 100,
146 'dynamic' => [
147 'active' => true,
148 ],
149 ]
150 );
151
152 $this->add_control(
153 'prefix',
154 [
155 'label' => esc_html__( 'Number Prefix', 'elementor' ),
156 'type' => Controls_Manager::TEXT,
157 'dynamic' => [
158 'active' => true,
159 ],
160 'ai' => [
161 'active' => false,
162 ],
163 'default' => '',
164 ]
165 );
166
167 $this->add_control(
168 'suffix',
169 [
170 'label' => esc_html__( 'Number Suffix', 'elementor' ),
171 'type' => Controls_Manager::TEXT,
172 'dynamic' => [
173 'active' => true,
174 ],
175 'ai' => [
176 'active' => false,
177 ],
178 'default' => '',
179 ]
180 );
181
182 $this->add_control(
183 'duration',
184 [
185 'label' => esc_html__( 'Animation Duration', 'elementor' ) . ' (ms)',
186 'type' => Controls_Manager::NUMBER,
187 'default' => 2000,
188 'min' => 100,
189 'step' => 100,
190 ]
191 );
192
193 $this->add_control(
194 'thousand_separator',
195 [
196 'label' => esc_html__( 'Thousand Separator', 'elementor' ),
197 'type' => Controls_Manager::SWITCHER,
198 'default' => 'yes',
199 'label_on' => esc_html__( 'Show', 'elementor' ),
200 'label_off' => esc_html__( 'Hide', 'elementor' ),
201 ]
202 );
203
204 $this->add_control(
205 'thousand_separator_char',
206 [
207 'label' => esc_html__( 'Separator', 'elementor' ),
208 'type' => Controls_Manager::SELECT,
209 'condition' => [
210 'thousand_separator' => 'yes',
211 ],
212 'options' => [
213 '' => 'Default',
214 '.' => 'Dot',
215 ' ' => 'Space',
216 '_' => 'Underline',
217 "'" => 'Apostrophe',
218 ],
219 ]
220 );
221
222 $this->add_control(
223 'title',
224 [
225 'label' => esc_html__( 'Title', 'elementor' ),
226 'type' => Controls_Manager::TEXT,
227 'label_block' => true,
228 'separator' => 'before',
229 'dynamic' => [
230 'active' => true,
231 ],
232 'default' => esc_html__( 'Cool Number', 'elementor' ),
233 ]
234 );
235
236 $this->add_control(
237 'title_tag',
238 [
239 'label' => esc_html__( 'Title HTML Tag', 'elementor' ),
240 'type' => Controls_Manager::SELECT,
241 'options' => [
242 'h1' => 'H1',
243 'h2' => 'H2',
244 'h3' => 'H3',
245 'h4' => 'H4',
246 'h5' => 'H5',
247 'h6' => 'H6',
248 'div' => 'div',
249 'span' => 'span',
250 'p' => 'p',
251 ],
252 'default' => 'div',
253 'condition' => [
254 'title!' => '',
255 ],
256 ]
257 );
258
259 $this->end_controls_section();
260
261 $this->start_controls_section(
262 'section_counter_style',
263 [
264 'label' => esc_html__( 'Counter', 'elementor' ),
265 'tab' => Controls_Manager::TAB_STYLE,
266 ]
267 );
268
269 $this->add_responsive_control(
270 'title_position',
271 [
272 'label' => esc_html__( 'Title Position', 'elementor' ),
273 'type' => Controls_Manager::CHOOSE,
274 'options' => [
275 'before' => [
276 'title' => esc_html__( 'Before', 'elementor' ),
277 'icon' => 'eicon-v-align-top',
278 ],
279 'after' => [
280 'title' => esc_html__( 'After', 'elementor' ),
281 'icon' => 'eicon-v-align-bottom',
282 ],
283 'start' => [
284 'title' => esc_html__( 'Start', 'elementor' ),
285 'icon' => 'eicon-h-align-left',
286 ],
287 'end' => [
288 'title' => esc_html__( 'End', 'elementor' ),
289 'icon' => 'eicon-h-align-right',
290 ],
291 ],
292 'selectors_dictionary' => [
293 'before' => 'flex-direction: column;',
294 'after' => 'flex-direction: column-reverse;',
295 'start' => 'flex-direction: row;',
296 'end' => 'flex-direction: row-reverse;',
297 ],
298 'selectors' => [
299 '{{WRAPPER}} .elementor-counter' => '{{VALUE}}',
300 ],
301 'classes' => 'elementor-control-start-end',
302 'condition' => [
303 'title!' => '',
304 ],
305 ]
306 );
307
308 $this->add_responsive_control(
309 'title_horizontal_alignment',
310 [
311 'label' => esc_html__( 'Title Horizontal Alignment', 'elementor' ),
312 'type' => Controls_Manager::CHOOSE,
313 'options' => [
314 'start' => [
315 'title' => esc_html__( 'Start', 'elementor' ),
316 'icon' => 'eicon-h-align-left',
317 ],
318 'center' => [
319 'title' => esc_html__( 'Center', 'elementor' ),
320 'icon' => 'eicon-h-align-center',
321 ],
322 'end' => [
323 'title' => esc_html__( 'End', 'elementor' ),
324 'icon' => 'eicon-h-align-right',
325 ],
326 ],
327 'separator' => 'before',
328 'classes' => 'elementor-control-start-end',
329 'selectors' => [
330 '{{WRAPPER}} .elementor-counter-title' => 'justify-content: {{VALUE}};',
331 ],
332 'condition' => [
333 'title!' => '',
334 ],
335 ]
336 );
337
338 $this->add_responsive_control(
339 'title_vertical_alignment',
340 [
341 'label' => esc_html__( 'Title Vertical Alignment', 'elementor' ),
342 'type' => Controls_Manager::CHOOSE,
343 'options' => [
344 'start' => [
345 'title' => esc_html__( 'Top', 'elementor' ),
346 'icon' => 'eicon-v-align-top',
347 ],
348 'center' => [
349 'title' => esc_html__( 'Middle', 'elementor' ),
350 'icon' => 'eicon-v-align-middle',
351 ],
352 'end' => [
353 'title' => esc_html__( 'Bottom', 'elementor' ),
354 'icon' => 'eicon-v-align-bottom',
355 ],
356 ],
357 'selectors' => [
358 '{{WRAPPER}} .elementor-counter-title' => 'align-items: {{VALUE}};',
359 ],
360 'condition' => [
361 'title!' => '',
362 'title_position' => [ 'start', 'end' ],
363 ],
364 ]
365 );
366
367 $this->add_responsive_control(
368 'title_gap',
369 [
370 'label' => esc_html__( 'Title Gap', 'elementor' ),
371 'type' => Controls_Manager::SLIDER,
372 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
373 'selectors' => [
374 '{{WRAPPER}} .elementor-counter' => 'gap: {{SIZE}}{{UNIT}};',
375 ],
376 'condition' => [
377 'title!' => '',
378 'title_position' => [ '', 'before', 'after' ],
379 ],
380 ]
381 );
382
383 $this->add_responsive_control(
384 'number_position',
385 [
386 'label' => esc_html__( 'Number Position', 'elementor' ),
387 'type' => Controls_Manager::CHOOSE,
388 'options' => [
389 'start' => [
390 'title' => esc_html__( 'Start', 'elementor' ),
391 'icon' => 'eicon-h-align-left',
392 ],
393 'center' => [
394 'title' => esc_html__( 'Center', 'elementor' ),
395 'icon' => 'eicon-h-align-center',
396 ],
397 'end' => [
398 'title' => esc_html__( 'End', 'elementor' ),
399 'icon' => 'eicon-h-align-right',
400 ],
401 'stretch' => [
402 'title' => esc_html__( 'Stretch', 'elementor' ),
403 'icon' => 'eicon-grow',
404 ],
405 ],
406 'classes' => 'elementor-control-start-end',
407 'selectors_dictionary' => [
408 'start' => 'text-align: {{VALUE}}; --counter-prefix-grow: 0; --counter-suffix-grow: 1; --counter-number-grow: 0;',
409 'center' => 'text-align: {{VALUE}}; --counter-prefix-grow: 1; --counter-suffix-grow: 1; --counter-number-grow: 0;',
410 'end' => 'text-align: {{VALUE}}; --counter-prefix-grow: 1; --counter-suffix-grow: 0; --counter-number-grow: 0;',
411 'stretch' => '--counter-prefix-grow: 0; --counter-suffix-grow: 0; --counter-number-grow: 1;',
412 ],
413 'selectors' => [
414 '{{WRAPPER}} .elementor-counter-number-wrapper' => '{{VALUE}}',
415 ],
416 'separator' => 'before',
417 ]
418 );
419
420 $this->add_responsive_control(
421 'number_alignment',
422 [
423 'label' => esc_html__( 'Number Alignment', 'elementor' ),
424 'type' => Controls_Manager::CHOOSE,
425 'options' => [
426 'start' => [
427 'title' => esc_html__( 'Start', 'elementor' ),
428 'icon' => 'eicon-text-align-left',
429 ],
430 'center' => [
431 'title' => esc_html__( 'Center', 'elementor' ),
432 'icon' => 'eicon-text-align-center',
433 ],
434 'end' => [
435 'title' => esc_html__( 'End', 'elementor' ),
436 'icon' => 'eicon-text-align-right',
437 ],
438 ],
439 'classes' => 'elementor-control-start-end',
440 'selectors' => [
441 '{{WRAPPER}} .elementor-counter-number' => 'text-align: {{VALUE}};',
442 ],
443 'condition' => [
444 'number_position' => 'stretch',
445 ],
446 ]
447 );
448
449 $this->add_responsive_control(
450 'number_gap',
451 [
452 'label' => esc_html__( 'Number Gap', 'elementor' ),
453 'type' => Controls_Manager::SLIDER,
454 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
455 'selectors' => [
456 '{{WRAPPER}} .elementor-counter-number-wrapper' => 'gap: {{SIZE}}{{UNIT}};',
457 ],
458 'conditions' => [
459 'relation' => 'and',
460 'terms' => [
461 [
462 'name' => 'number_position',
463 'operator' => '!==',
464 'value' => 'stretch',
465 ],
466 [
467 'relation' => 'or',
468 'terms' => [
469 [
470 'name' => 'prefix',
471 'operator' => '!==',
472 'value' => '',
473 ],
474 [
475 'name' => 'suffix',
476 'operator' => '!==',
477 'value' => '',
478 ],
479 ],
480 ],
481 ],
482 ],
483 ]
484 );
485
486 $this->end_controls_section();
487
488 $this->start_controls_section(
489 'section_number',
490 [
491 'label' => esc_html__( 'Number', 'elementor' ),
492 'tab' => Controls_Manager::TAB_STYLE,
493 ]
494 );
495
496 $this->add_control(
497 'number_color',
498 [
499 'label' => esc_html__( 'Text Color', 'elementor' ),
500 'type' => Controls_Manager::COLOR,
501 'global' => [
502 'default' => Global_Colors::COLOR_PRIMARY,
503 ],
504 'selectors' => [
505 '{{WRAPPER}} .elementor-counter-number-wrapper' => 'color: {{VALUE}};',
506 ],
507 ]
508 );
509
510 $this->add_group_control(
511 Group_Control_Typography::get_type(),
512 [
513 'name' => 'typography_number',
514 'global' => [
515 'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
516 ],
517 'selector' => '{{WRAPPER}} .elementor-counter-number-wrapper',
518 ]
519 );
520
521 $this->add_group_control(
522 Group_Control_Text_Stroke::get_type(),
523 [
524 'name' => 'number_stroke',
525 'selector' => '{{WRAPPER}} .elementor-counter-number-wrapper',
526 ]
527 );
528
529 $this->add_group_control(
530 Group_Control_Text_Shadow::get_type(),
531 [
532 'name' => 'number_shadow',
533 'selector' => '{{WRAPPER}} .elementor-counter-number-wrapper',
534 ]
535 );
536
537 $this->end_controls_section();
538
539 $this->start_controls_section(
540 'section_title',
541 [
542 'label' => esc_html__( 'Title', 'elementor' ),
543 'tab' => Controls_Manager::TAB_STYLE,
544 'condition' => [
545 'title!' => '',
546 ],
547 ]
548 );
549
550 $this->add_control(
551 'title_color',
552 [
553 'label' => esc_html__( 'Text Color', 'elementor' ),
554 'type' => Controls_Manager::COLOR,
555 'global' => [
556 'default' => Global_Colors::COLOR_SECONDARY,
557 ],
558 'selectors' => [
559 '{{WRAPPER}} .elementor-counter-title' => 'color: {{VALUE}};',
560 ],
561 'condition' => [
562 'title!' => '',
563 ],
564 ]
565 );
566
567 $this->add_group_control(
568 Group_Control_Typography::get_type(),
569 [
570 'name' => 'typography_title',
571 'global' => [
572 'default' => Global_Typography::TYPOGRAPHY_SECONDARY,
573 ],
574 'selector' => '{{WRAPPER}} .elementor-counter-title',
575 'condition' => [
576 'title!' => '',
577 ],
578 ]
579 );
580
581 $this->add_group_control(
582 Group_Control_Text_Stroke::get_type(),
583 [
584 'name' => 'title_stroke',
585 'selector' => '{{WRAPPER}} .elementor-counter-title',
586 'condition' => [
587 'title!' => '',
588 ],
589 ]
590 );
591
592 $this->add_group_control(
593 Group_Control_Text_Shadow::get_type(),
594 [
595 'name' => 'title_shadow',
596 'selector' => '{{WRAPPER}} .elementor-counter-title',
597 'condition' => [
598 'title!' => '',
599 ],
600 ]
601 );
602
603 $this->end_controls_section();
604 }
605
606 /**
607 * Render counter widget output in the editor.
608 *
609 * Written as a Backbone JavaScript template and used to generate the live preview.
610 *
611 * @since 2.9.0
612 * @access protected
613 */
614 protected function content_template() {
615 ?>
616 <#
617 view.addRenderAttribute( 'elementor-counter', 'class', 'elementor-counter' );
618
619 view.addRenderAttribute( 'counter-number', 'class', 'elementor-counter-number-wrapper' );
620
621 view.addRenderAttribute(
622 'counter',
623 {
624 'class': 'elementor-counter-number',
625 'data-duration': settings.duration,
626 'data-to-value': settings.ending_number,
627 'data-from-value': settings.starting_number,
628 }
629 );
630
631 if ( settings.thousand_separator ) {
632 const delimiter = settings.thousand_separator_char ? settings.thousand_separator_char : ',';
633 view.addRenderAttribute( 'counter', 'data-delimiter', delimiter );
634 }
635
636 view.addRenderAttribute( 'prefix', 'class', 'elementor-counter-number-prefix' );
637
638 view.addRenderAttribute( 'suffix', 'class', 'elementor-counter-number-suffix' );
639
640 view.addRenderAttribute( 'counter-title', 'class', 'elementor-counter-title' );
641
642 view.addInlineEditingAttributes( 'counter-title' );
643
644 const titleTag = elementor.helpers.validateHTMLTag( settings.title_tag );
645 #>
646 <div {{{ view.getRenderAttributeString( 'elementor-counter' ) }}}>
647 <# if ( settings.title ) {
648 #><{{ titleTag }} {{{ view.getRenderAttributeString( 'counter-title' ) }}}>{{{ elementor.helpers.sanitize( settings.title, { ALLOW_DATA_ATTR: false } ) }}}</{{ titleTag }}><#
649 } #>
650 <div {{{ view.getRenderAttributeString( 'counter-number' ) }}}>
651 <span {{{ view.getRenderAttributeString( 'prefix' ) }}}>{{ settings.prefix }}</span>
652 <span {{{ view.getRenderAttributeString( 'counter' ) }}}>{{ settings.starting_number }}</span>
653 <span {{{ view.getRenderAttributeString( 'suffix' ) }}}>{{ settings.suffix }}</span>
654 </div>
655 </div>
656 <?php
657 }
658
659 /**
660 * Render counter widget output on the frontend.
661 *
662 * Written in PHP and used to generate the final HTML.
663 *
664 * @since 1.0.0
665 * @access protected
666 */
667 protected function render() {
668 $settings = $this->get_settings_for_display();
669
670 $this->add_render_attribute( 'elementor-counter', 'class', 'elementor-counter' );
671
672 $this->add_render_attribute( 'counter-number', 'class', 'elementor-counter-number-wrapper' );
673
674 $this->add_render_attribute(
675 'counter',
676 [
677 'class' => 'elementor-counter-number',
678 'data-duration' => $settings['duration'],
679 'data-to-value' => $settings['ending_number'],
680 'data-from-value' => $settings['starting_number'],
681 ]
682 );
683
684 if ( ! empty( $settings['thousand_separator'] ) ) {
685 $delimiter = empty( $settings['thousand_separator_char'] ) ? ',' : $settings['thousand_separator_char'];
686 $this->add_render_attribute( 'counter', 'data-delimiter', $delimiter );
687 }
688
689 $this->add_render_attribute( 'prefix', 'class', 'elementor-counter-number-prefix' );
690
691 $this->add_render_attribute( 'suffix', 'class', 'elementor-counter-number-suffix' );
692
693 $this->add_render_attribute( 'counter-title', 'class', 'elementor-counter-title' );
694
695 $this->add_inline_editing_attributes( 'counter-title' );
696
697 $title_tag = Utils::validate_html_tag( $settings['title_tag'] );
698 ?>
699 <div <?php $this->print_render_attribute_string( 'elementor-counter' ); ?>>
700 <?php
701 if ( $settings['title'] ) :
702 ?><<?php Utils::print_validated_html_tag( $title_tag ); ?> <?php $this->print_render_attribute_string( 'counter-title' ); ?>><?php echo wp_kses_post( $this->get_settings_for_display( 'title' ) ); ?></<?php Utils::print_validated_html_tag( $title_tag ); ?>><?php
703 endif;
704 ?>
705 <div <?php $this->print_render_attribute_string( 'counter-number' ); ?>>
706 <span <?php $this->print_render_attribute_string( 'prefix' ); ?>><?php echo wp_kses_post( $settings['prefix'] ); ?></span>
707 <span <?php $this->print_render_attribute_string( 'counter' ); ?>><?php echo wp_kses_post( $settings['starting_number'] ); ?></span>
708 <span <?php $this->print_render_attribute_string( 'suffix' ); ?>><?php echo wp_kses_post( $settings['suffix'] ); ?></span>
709 </div>
710 </div>
711 <?php
712 }
713
714 public function render_markdown(): string {
715 $settings = $this->get_settings_for_display();
716 $number = $settings['ending_number'] ?? '';
717 $prefix = $settings['prefix'] ?? '';
718 $suffix = $settings['suffix'] ?? '';
719 $title = Utils::html_to_plain_text( $settings['title'] ?? '' );
720 $value = $prefix . $number . $suffix;
721 if ( empty( $value ) && empty( $title ) ) {
722 return '';
723 }
724 $parts = array_filter( [ $value, $title ] );
725 return implode( ' - ', $parts );
726 }
727 }
728