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

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

694 lines 18.3 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 use Elementor\Modules\Promotions\Controls\Promotion_Control;
11
12 /**
13 * Elementor testimonial widget.
14 *
15 * Elementor widget that displays customer testimonials that show social proof.
16 *
17 * @since 1.0.0
18 */
19 class Widget_Testimonial extends Widget_Base {
20
21 /**
22 * Get widget name.
23 *
24 * Retrieve testimonial widget name.
25 *
26 * @since 1.0.0
27 * @access public
28 *
29 * @return string Widget name.
30 */
31 public function get_name() {
32 return 'testimonial';
33 }
34
35 /**
36 * Get widget title.
37 *
38 * Retrieve testimonial widget title.
39 *
40 * @since 1.0.0
41 * @access public
42 *
43 * @return string Widget title.
44 */
45 public function get_title() {
46 return esc_html__( 'Testimonial', 'elementor' );
47 }
48
49 /**
50 * Get widget icon.
51 *
52 * Retrieve testimonial widget icon.
53 *
54 * @since 1.0.0
55 * @access public
56 *
57 * @return string Widget icon.
58 */
59 public function get_icon() {
60 return 'eicon-testimonial';
61 }
62
63 /**
64 * Get widget keywords.
65 *
66 * Retrieve the list of keywords the widget belongs to.
67 *
68 * @since 2.1.0
69 * @access public
70 *
71 * @return array Widget keywords.
72 */
73 public function get_keywords() {
74 return [ 'testimonial', 'blockquote' ];
75 }
76
77 protected function is_dynamic_content(): bool {
78 return false;
79 }
80
81 /**
82 * Get style dependencies.
83 *
84 * Retrieve the list of style dependencies the widget requires.
85 *
86 * @since 3.24.0
87 * @access public
88 *
89 * @return array Widget style dependencies.
90 */
91 public function get_style_depends(): array {
92 return [ 'widget-testimonial' ];
93 }
94
95 public function has_widget_inner_wrapper(): bool {
96 return ! Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
97 }
98
99 /**
100 * Get widget upsale data.
101 *
102 * Retrieve the widget promotion data.
103 *
104 * @since 3.18.0
105 * @access protected
106 *
107 * @return array Widget promotion data.
108 */
109 protected function get_upsale_data() {
110 return [
111 'condition' => ! Utils::has_pro(),
112 'image' => esc_url( ELEMENTOR_ASSETS_URL . 'images/go-pro.svg' ),
113 'image_alt' => esc_attr__( 'Upgrade', 'elementor' ),
114 'description' => esc_html__( 'Use interesting masonry layouts and other overlay features with Elementor\'s Pro Gallery widget.', 'elementor' ),
115 'upgrade_url' => esc_url( 'https://go.elementor.com/go-pro-testimonial-widget/' ),
116 'upgrade_text' => esc_html__( 'Upgrade Now', 'elementor' ),
117 ];
118 }
119
120 /**
121 * Register testimonial widget controls.
122 *
123 * Adds different input fields to allow the user to change and customize the widget settings.
124 *
125 * @since 3.1.0
126 * @access protected
127 */
128 protected function register_controls() {
129 $this->start_controls_section(
130 'section_testimonial',
131 [
132 'label' => esc_html__( 'Testimonial', 'elementor' ),
133 ]
134 );
135
136 $this->add_control(
137 'testimonial_content',
138 [
139 'label' => esc_html__( 'Content', 'elementor' ),
140 'type' => Controls_Manager::TEXTAREA,
141 'dynamic' => [
142 'active' => true,
143 ],
144 'rows' => '10',
145 'default' => esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor' ),
146 ]
147 );
148
149 $this->add_control(
150 'testimonial_image',
151 [
152 'label' => esc_html__( 'Choose Image', 'elementor' ),
153 'type' => Controls_Manager::MEDIA,
154 'dynamic' => [
155 'active' => true,
156 ],
157 'default' => [
158 'url' => Utils::get_placeholder_image_src(),
159 ],
160 ]
161 );
162
163 $this->add_group_control(
164 Group_Control_Image_Size::get_type(),
165 [
166 'name' => 'testimonial_image', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `testimonial_image_size` and `testimonial_image_custom_dimension`.
167 'default' => 'full',
168 ]
169 );
170
171 $this->add_control(
172 'testimonial_name',
173 [
174 'label' => esc_html__( 'Name', 'elementor' ),
175 'type' => Controls_Manager::TEXT,
176 'dynamic' => [
177 'active' => true,
178 ],
179 'ai' => [
180 'active' => false,
181 ],
182 'default' => esc_html__( 'John Doe', 'elementor' ),
183 ]
184 );
185
186 $this->add_control(
187 'testimonial_job',
188 [
189 'label' => esc_html__( 'Title', 'elementor' ),
190 'type' => Controls_Manager::TEXT,
191 'dynamic' => [
192 'active' => true,
193 ],
194 'ai' => [
195 'active' => false,
196 ],
197 'default' => esc_html__( 'Designer', 'elementor' ),
198 ]
199 );
200
201 $this->add_control(
202 'link',
203 [
204 'label' => esc_html__( 'Link', 'elementor' ),
205 'type' => Controls_Manager::URL,
206 'dynamic' => [
207 'active' => true,
208 ],
209 ]
210 );
211
212 $this->add_control(
213 'testimonial_image_position',
214 [
215 'label' => esc_html__( 'Image Position', 'elementor' ),
216 'type' => Controls_Manager::CHOOSE,
217 'default' => 'aside',
218 'options' => [
219 'aside' => [
220 'title' => esc_html__( 'Aside', 'elementor' ),
221 'icon' => 'eicon-h-align-left',
222 ],
223 'top' => [
224 'title' => esc_html__( 'Top', 'elementor' ),
225 'icon' => 'eicon-v-align-top',
226 ],
227 ],
228 'toggle' => false,
229 'condition' => [
230 'testimonial_image[url]!' => '',
231 ],
232 'separator' => 'before',
233 'classes' => 'elementor-control-start-end',
234 'style_transfer' => true,
235 ]
236 );
237
238 $this->add_responsive_control(
239 'testimonial_alignment',
240 [
241 'label' => esc_html__( 'Alignment', 'elementor' ),
242 'type' => Controls_Manager::CHOOSE,
243 'default' => 'center',
244 'options' => [
245 'start' => [
246 'title' => esc_html__( 'Start', 'elementor' ),
247 'icon' => 'eicon-text-align-left',
248 ],
249 'center' => [
250 'title' => esc_html__( 'Center', 'elementor' ),
251 'icon' => 'eicon-text-align-center',
252 ],
253 'end' => [
254 'title' => esc_html__( 'End', 'elementor' ),
255 'icon' => 'eicon-text-align-right',
256 ],
257 ],
258 'classes' => 'elementor-control-start-end',
259 'selectors_dictionary' => [
260 'left' => is_rtl() ? 'end' : 'start',
261 'right' => is_rtl() ? 'start' : 'end',
262 ],
263 'selectors' => [
264 '{{WRAPPER}} .elementor-testimonial-wrapper' => 'text-align: {{VALUE}}',
265 ],
266 'style_transfer' => true,
267 ]
268 );
269
270 $this->end_controls_section();
271
272 // Content.
273 $this->start_controls_section(
274 'section_style_testimonial_content',
275 [
276 'label' => esc_html__( 'Content', 'elementor' ),
277 'tab' => Controls_Manager::TAB_STYLE,
278 ]
279 );
280
281 $this->add_control(
282 'content_content_color',
283 [
284 'label' => esc_html__( 'Text Color', 'elementor' ),
285 'type' => Controls_Manager::COLOR,
286 'global' => [
287 'default' => Global_Colors::COLOR_TEXT,
288 ],
289 'default' => '',
290 'selectors' => [
291 '{{WRAPPER}} .elementor-testimonial-content' => 'color: {{VALUE}};',
292 ],
293 ]
294 );
295
296 $this->add_group_control(
297 Group_Control_Typography::get_type(),
298 [
299 'name' => 'content_typography',
300 'global' => [
301 'default' => Global_Typography::TYPOGRAPHY_TEXT,
302 ],
303 'selector' => '{{WRAPPER}} .elementor-testimonial-content',
304 ]
305 );
306
307 $this->add_group_control(
308 Group_Control_Text_Shadow::get_type(),
309 [
310 'name' => 'content_shadow',
311 'selector' => '{{WRAPPER}} .elementor-testimonial-content',
312 ]
313 );
314
315 $this->end_controls_section();
316
317 // Image.
318 $this->start_controls_section(
319 'section_style_testimonial_image',
320 [
321 'label' => esc_html__( 'Image', 'elementor' ),
322 'tab' => Controls_Manager::TAB_STYLE,
323 'condition' => [
324 'testimonial_image[url]!' => '',
325 ],
326 ]
327 );
328
329 $this->add_responsive_control(
330 'image_size',
331 [
332 'label' => esc_html__( 'Image Resolution', 'elementor' ),
333 'type' => Controls_Manager::SLIDER,
334 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
335 'range' => [
336 'px' => [
337 'min' => 20,
338 'max' => 200,
339 ],
340 ],
341 'selectors' => [
342 '{{WRAPPER}} .elementor-testimonial-wrapper .elementor-testimonial-image img' => 'width: {{SIZE}}{{UNIT}};height: {{SIZE}}{{UNIT}};',
343 ],
344 ]
345 );
346
347 $this->add_group_control(
348 Group_Control_Border::get_type(),
349 [
350 'name' => 'image_border',
351 'selector' => '{{WRAPPER}} .elementor-testimonial-wrapper .elementor-testimonial-image img',
352 'separator' => 'before',
353 ]
354 );
355
356 $this->add_responsive_control(
357 'image_border_radius',
358 [
359 'label' => esc_html__( 'Border Radius', 'elementor' ),
360 'type' => Controls_Manager::DIMENSIONS,
361 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
362 'selectors' => [
363 '{{WRAPPER}} .elementor-testimonial-wrapper .elementor-testimonial-image img' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
364 ],
365 ]
366 );
367
368 $this->end_controls_section();
369
370 // Name.
371 $this->start_controls_section(
372 'section_style_testimonial_name',
373 [
374 'label' => esc_html__( 'Name', 'elementor' ),
375 'tab' => Controls_Manager::TAB_STYLE,
376 ]
377 );
378
379 $this->add_control(
380 'name_text_color',
381 [
382 'label' => esc_html__( 'Text Color', 'elementor' ),
383 'type' => Controls_Manager::COLOR,
384 'global' => [
385 'default' => Global_Colors::COLOR_PRIMARY,
386 ],
387 'default' => '',
388 'selectors' => [
389 '{{WRAPPER}} .elementor-testimonial-name' => 'color: {{VALUE}};',
390 ],
391 ]
392 );
393
394 $this->add_group_control(
395 Group_Control_Typography::get_type(),
396 [
397 'name' => 'name_typography',
398 'global' => [
399 'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
400 ],
401 'selector' => '{{WRAPPER}} .elementor-testimonial-name',
402 ]
403 );
404
405 $this->add_group_control(
406 Group_Control_Text_Shadow::get_type(),
407 [
408 'name' => 'name_shadow',
409 'selector' => '{{WRAPPER}} .elementor-testimonial-name',
410 ]
411 );
412
413 $this->end_controls_section();
414
415 // Job.
416 $this->start_controls_section(
417 'section_style_testimonial_job',
418 [
419 'label' => esc_html__( 'Title', 'elementor' ),
420 'tab' => Controls_Manager::TAB_STYLE,
421 ]
422 );
423
424 $this->add_control(
425 'job_text_color',
426 [
427 'label' => esc_html__( 'Text Color', 'elementor' ),
428 'type' => Controls_Manager::COLOR,
429 'global' => [
430 'default' => Global_Colors::COLOR_SECONDARY,
431 ],
432 'default' => '',
433 'selectors' => [
434 '{{WRAPPER}} .elementor-testimonial-job' => 'color: {{VALUE}};',
435 ],
436 ]
437 );
438
439 $this->add_group_control(
440 Group_Control_Typography::get_type(),
441 [
442 'name' => 'job_typography',
443 'global' => [
444 'default' => Global_Typography::TYPOGRAPHY_SECONDARY,
445 ],
446 'selector' => '{{WRAPPER}} .elementor-testimonial-job',
447 ]
448 );
449
450 $this->add_group_control(
451 Group_Control_Text_Shadow::get_type(),
452 [
453 'name' => 'job_shadow',
454 'selector' => '{{WRAPPER}} .elementor-testimonial-job',
455 ]
456 );
457
458 $this->end_controls_section();
459 }
460
461 /**
462 * Render testimonial widget output on the frontend.
463 *
464 * Written in PHP and used to generate the final HTML.
465 *
466 * @since 1.0.0
467 * @access protected
468 */
469 protected function render() {
470 $settings = $this->get_settings_for_display();
471
472 $has_content = ! empty( $settings['testimonial_content'] );
473 $has_image = ! empty( $settings['testimonial_image']['url'] );
474 $has_name = ! empty( $settings['testimonial_name'] );
475 $has_job = ! empty( $settings['testimonial_job'] );
476
477 if ( ! $has_content && ! $has_image && ! $has_name && ! $has_job ) {
478 return;
479 }
480
481 $this->add_render_attribute( 'wrapper', 'class', 'elementor-testimonial-wrapper' );
482
483 $this->add_render_attribute( 'meta', 'class', 'elementor-testimonial-meta' );
484
485 if ( $settings['testimonial_image']['url'] ) {
486 $this->add_render_attribute( 'meta', 'class', 'elementor-has-image' );
487 }
488
489 if ( $settings['testimonial_image_position'] ) {
490 $this->add_render_attribute( 'meta', 'class', 'elementor-testimonial-image-position-' . $settings['testimonial_image_position'] );
491 }
492
493 if ( ! empty( $settings['link']['url'] ) ) {
494 $this->add_link_attributes( 'link', $settings['link'] );
495 }
496 ?>
497 <div <?php $this->print_render_attribute_string( 'wrapper' ); ?>>
498 <?php
499 if ( $has_content ) :
500 $this->add_render_attribute( 'testimonial_content', 'class', 'elementor-testimonial-content' );
501 $this->add_inline_editing_attributes( 'testimonial_content' );
502 ?>
503 <div <?php $this->print_render_attribute_string( 'testimonial_content' ); ?>><?php echo wp_kses_post( $settings['testimonial_content'] ); ?></div>
504 <?php endif; ?>
505
506 <?php if ( $has_image || $has_name || $has_job ) : ?>
507 <div <?php $this->print_render_attribute_string( 'meta' ); ?>>
508 <div class="elementor-testimonial-meta-inner">
509 <?php if ( $has_image ) : ?>
510 <div class="elementor-testimonial-image">
511 <?php
512 $image_html = Group_Control_Image_Size::get_attachment_image_html( $settings, 'testimonial_image' );
513 if ( ! empty( $settings['link']['url'] ) ) :
514 $image_html = '<a ' . $this->get_render_attribute_string( 'link' ) . '>' . $image_html . '</a>';
515 endif;
516 echo wp_kses_post( $image_html );
517 ?>
518 </div>
519 <?php endif; ?>
520
521 <?php if ( $has_name || $has_job ) : ?>
522 <div class="elementor-testimonial-details">
523 <?php
524 if ( $has_name ) :
525 $this->add_render_attribute( 'testimonial_name', 'class', 'elementor-testimonial-name' );
526 $this->add_inline_editing_attributes( 'testimonial_name', 'none' );
527
528 if ( ! empty( $settings['link']['url'] ) ) :
529 ?>
530 <a <?php $this->print_render_attribute_string( 'testimonial_name' ); ?> <?php $this->print_render_attribute_string( 'link' ); ?>><?php echo wp_kses_post( $settings['testimonial_name'] ); ?></a>
531 <?php
532 else :
533 ?>
534 <div <?php $this->print_render_attribute_string( 'testimonial_name' ); ?>><?php echo wp_kses_post( $settings['testimonial_name'] ); ?></div>
535 <?php
536 endif;
537 endif; ?>
538 <?php
539 if ( $has_job ) :
540 $this->add_render_attribute( 'testimonial_job', 'class', 'elementor-testimonial-job' );
541
542 $this->add_inline_editing_attributes( 'testimonial_job', 'none' );
543
544 if ( ! empty( $settings['link']['url'] ) ) :
545 ?>
546 <a <?php $this->print_render_attribute_string( 'testimonial_job' ); ?> <?php $this->print_render_attribute_string( 'link' ); ?>><?php echo wp_kses_post( $settings['testimonial_job'] ); ?></a>
547 <?php
548 else :
549 ?>
550 <div <?php $this->print_render_attribute_string( 'testimonial_job' ); ?>><?php echo wp_kses_post( $settings['testimonial_job'] ); ?></div>
551 <?php
552 endif;
553 endif; ?>
554 </div>
555 <?php endif; ?>
556 </div>
557 </div>
558 <?php endif; ?>
559 </div>
560 <?php
561 }
562
563 /**
564 * Render testimonial widget output in the editor.
565 *
566 * Written as a Backbone JavaScript template and used to generate the live preview.
567 *
568 * @since 2.9.0
569 * @access protected
570 */
571 public function render_markdown(): string {
572 $settings = $this->get_settings_for_display();
573
574 $content = Utils::html_to_plain_text( $settings['testimonial_content'] ?? '' );
575 $name = Utils::html_to_plain_text( $settings['testimonial_name'] ?? '' );
576 $job = Utils::html_to_plain_text( $settings['testimonial_job'] ?? '' );
577
578 if ( empty( $content ) && empty( $name ) ) {
579 return '';
580 }
581
582 $md = '';
583
584 if ( ! empty( $content ) ) {
585 $md = '> "' . $content . '"';
586 }
587
588 $attribution = array_filter( [ $name, $job ] );
589
590 if ( ! empty( $attribution ) ) {
591 $md .= "\n>\n> -- " . implode( ', ', $attribution );
592 }
593
594 return $md;
595 }
596
597 protected function content_template() {
598 ?>
599 <#
600 if ( '' === settings.testimonial_content && '' === settings.testimonial_image.url && '' === settings.testimonial_name && '' === settings.testimonial_job ) {
601 return;
602 }
603
604 var image = {
605 id: settings.testimonial_image.id,
606 url: settings.testimonial_image.url,
607 size: settings.testimonial_image_size,
608 dimension: settings.testimonial_image_custom_dimension,
609 model: view.getEditModel()
610 };
611 var imageUrl = false, hasImage = '';
612
613 if ( '' !== settings.testimonial_image.url ) {
614 imageUrl = elementor.imagesManager.getImageUrl( image );
615 hasImage = ' elementor-has-image';
616
617 var imageHtml = '<img src="' + _.escape( imageUrl ) + '" alt="testimonial" />';
618 if ( settings.link?.url ) {
619 imageHtml = '<a href="' + elementor.helpers.sanitizeUrl( settings.link?.url ) + '">' + imageHtml + '</a>';
620 }
621 }
622
623 var testimonial_image_position = settings.testimonial_image_position ? ' elementor-testimonial-image-position-' + settings.testimonial_image_position : '';
624 #>
625 <div class="elementor-testimonial-wrapper">
626 <# if ( '' !== settings.testimonial_content ) {
627 view.addRenderAttribute( 'testimonial_content', {
628 'data-binding-type': 'content',
629 'data-binding-setting': 'testimonial_content',
630 'data-binding-config': JSON.stringify({
631 'testimonial_content': {
632 editType: "text"
633 }
634 })
635 } );
636 view.addRenderAttribute( 'testimonial_content', 'class', 'elementor-testimonial-content' );
637
638 view.addInlineEditingAttributes( 'testimonial_content' );
639 #>
640 <div {{{ view.getRenderAttributeString( 'testimonial_content' ) }}}>{{ settings.testimonial_content }}</div>
641 <# } #>
642 <div class="elementor-testimonial-meta{{ hasImage }}{{ testimonial_image_position }}">
643 <div class="elementor-testimonial-meta-inner">
644 <# if ( imageUrl ) { #>
645 <div class="elementor-testimonial-image">{{{ imageHtml }}}</div>
646 <# } #>
647 <div class="elementor-testimonial-details">
648 <?php $this->render_testimonial_description(); ?>
649 </div>
650 </div>
651 </div>
652 </div>
653 <?php
654 }
655
656 protected function render_testimonial_description() {
657 ?>
658 <#
659 if ( '' !== settings.testimonial_name ) {
660 view.addRenderAttribute( 'testimonial_name', 'class', 'elementor-testimonial-name' );
661
662 view.addInlineEditingAttributes( 'testimonial_name', 'none' );
663
664 if ( settings.link?.url ) {
665 #>
666 <a href="{{ elementor.helpers.sanitizeUrl( settings.link?.url ) }}" {{{ view.getRenderAttributeString( 'testimonial_name' ) }}}>{{ settings.testimonial_name }}</a>
667 <#
668 } else {
669 #>
670 <div {{{ view.getRenderAttributeString( 'testimonial_name' ) }}}>{{ settings.testimonial_name }}</div>
671 <#
672 }
673 }
674
675 if ( '' !== settings.testimonial_job ) {
676 view.addRenderAttribute( 'testimonial_job', 'class', 'elementor-testimonial-job' );
677
678 view.addInlineEditingAttributes( 'testimonial_job', 'none' );
679
680 if ( settings.link?.url ) {
681 #>
682 <a href="{{ elementor.helpers.sanitizeUrl( settings.link?.url ) }}" {{{ view.getRenderAttributeString( 'testimonial_job' ) }}}>{{ settings.testimonial_job }}</a>
683 <#
684 } else {
685 #>
686 <div {{{ view.getRenderAttributeString( 'testimonial_job' ) }}}>{{ settings.testimonial_job }}</div>
687 <#
688 }
689 }
690 #>
691 <?php
692 }
693 }
694