testimonial.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. <?php
  2. namespace Elementor;
  3. if ( ! defined( 'ABSPATH' ) ) {
  4. exit; // Exit if accessed directly.
  5. }
  6. /**
  7. * Elementor testimonial widget.
  8. *
  9. * Elementor widget that displays customer testimonials that show social proof.
  10. *
  11. * @since 1.0.0
  12. */
  13. class Widget_Testimonial extends Widget_Base {
  14. /**
  15. * Get widget name.
  16. *
  17. * Retrieve testimonial widget name.
  18. *
  19. * @since 1.0.0
  20. * @access public
  21. *
  22. * @return string Widget name.
  23. */
  24. public function get_name() {
  25. return 'testimonial';
  26. }
  27. /**
  28. * Get widget title.
  29. *
  30. * Retrieve testimonial widget title.
  31. *
  32. * @since 1.0.0
  33. * @access public
  34. *
  35. * @return string Widget title.
  36. */
  37. public function get_title() {
  38. return __( 'Testimonial', 'elementor' );
  39. }
  40. /**
  41. * Get widget icon.
  42. *
  43. * Retrieve testimonial widget icon.
  44. *
  45. * @since 1.0.0
  46. * @access public
  47. *
  48. * @return string Widget icon.
  49. */
  50. public function get_icon() {
  51. return 'eicon-testimonial';
  52. }
  53. /**
  54. * Get widget keywords.
  55. *
  56. * Retrieve the list of keywords the widget belongs to.
  57. *
  58. * @since 2.1.0
  59. * @access public
  60. *
  61. * @return array Widget keywords.
  62. */
  63. public function get_keywords() {
  64. return [ 'testimonial', 'blockquote' ];
  65. }
  66. /**
  67. * Register testimonial widget controls.
  68. *
  69. * Adds different input fields to allow the user to change and customize the widget settings.
  70. *
  71. * @since 1.0.0
  72. * @access protected
  73. */
  74. protected function _register_controls() {
  75. $this->start_controls_section(
  76. 'section_testimonial',
  77. [
  78. 'label' => __( 'Testimonial', 'elementor' ),
  79. ]
  80. );
  81. $this->add_control(
  82. 'testimonial_content',
  83. [
  84. 'label' => __( 'Content', 'elementor' ),
  85. 'type' => Controls_Manager::TEXTAREA,
  86. 'dynamic' => [
  87. 'active' => true,
  88. ],
  89. 'rows' => '10',
  90. 'default' => 'Click edit button to change this text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.',
  91. ]
  92. );
  93. $this->add_control(
  94. 'testimonial_image',
  95. [
  96. 'label' => __( 'Choose Image', 'elementor' ),
  97. 'type' => Controls_Manager::MEDIA,
  98. 'default' => [
  99. 'url' => Utils::get_placeholder_image_src(),
  100. ],
  101. ]
  102. );
  103. $this->add_group_control(
  104. Group_Control_Image_Size::get_type(),
  105. [
  106. 'name' => 'testimonial_image', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `testimonial_image_size` and `testimonial_image_custom_dimension`.
  107. 'default' => 'full',
  108. 'separator' => 'none',
  109. ]
  110. );
  111. $this->add_control(
  112. 'testimonial_name',
  113. [
  114. 'label' => __( 'Name', 'elementor' ),
  115. 'type' => Controls_Manager::TEXT,
  116. 'dynamic' => [
  117. 'active' => true,
  118. ],
  119. 'default' => 'John Doe',
  120. ]
  121. );
  122. $this->add_control(
  123. 'testimonial_job',
  124. [
  125. 'label' => __( 'Job', 'elementor' ),
  126. 'type' => Controls_Manager::TEXT,
  127. 'dynamic' => [
  128. 'active' => true,
  129. ],
  130. 'default' => 'Designer',
  131. ]
  132. );
  133. $this->add_control(
  134. 'link',
  135. [
  136. 'label' => __( 'Link to', 'elementor' ),
  137. 'type' => Controls_Manager::URL,
  138. 'placeholder' => __( 'https://your-link.com', 'elementor' ),
  139. ]
  140. );
  141. $this->add_control(
  142. 'testimonial_image_position',
  143. [
  144. 'label' => __( 'Image Position', 'elementor' ),
  145. 'type' => Controls_Manager::SELECT,
  146. 'default' => 'aside',
  147. 'options' => [
  148. 'aside' => __( 'Aside', 'elementor' ),
  149. 'top' => __( 'Top', 'elementor' ),
  150. ],
  151. 'condition' => [
  152. 'testimonial_image[url]!' => '',
  153. ],
  154. 'separator' => 'before',
  155. 'style_transfer' => true,
  156. ]
  157. );
  158. $this->add_control(
  159. 'testimonial_alignment',
  160. [
  161. 'label' => __( 'Alignment', 'elementor' ),
  162. 'type' => Controls_Manager::CHOOSE,
  163. 'default' => 'center',
  164. 'options' => [
  165. 'left' => [
  166. 'title' => __( 'Left', 'elementor' ),
  167. 'icon' => 'fa fa-align-left',
  168. ],
  169. 'center' => [
  170. 'title' => __( 'Center', 'elementor' ),
  171. 'icon' => 'fa fa-align-center',
  172. ],
  173. 'right' => [
  174. 'title' => __( 'Right', 'elementor' ),
  175. 'icon' => 'fa fa-align-right',
  176. ],
  177. ],
  178. 'label_block' => false,
  179. 'style_transfer' => true,
  180. ]
  181. );
  182. $this->add_control(
  183. 'view',
  184. [
  185. 'label' => __( 'View', 'elementor' ),
  186. 'type' => Controls_Manager::HIDDEN,
  187. 'default' => 'traditional',
  188. ]
  189. );
  190. $this->end_controls_section();
  191. // Content.
  192. $this->start_controls_section(
  193. 'section_style_testimonial_content',
  194. [
  195. 'label' => __( 'Content', 'elementor' ),
  196. 'tab' => Controls_Manager::TAB_STYLE,
  197. ]
  198. );
  199. $this->add_control(
  200. 'content_content_color',
  201. [
  202. 'label' => __( 'Text Color', 'elementor' ),
  203. 'type' => Controls_Manager::COLOR,
  204. 'scheme' => [
  205. 'type' => Scheme_Color::get_type(),
  206. 'value' => Scheme_Color::COLOR_3,
  207. ],
  208. 'default' => '',
  209. 'selectors' => [
  210. '{{WRAPPER}} .elementor-testimonial-content' => 'color: {{VALUE}};',
  211. ],
  212. ]
  213. );
  214. $this->add_group_control(
  215. Group_Control_Typography::get_type(),
  216. [
  217. 'name' => 'content_typography',
  218. 'scheme' => Scheme_Typography::TYPOGRAPHY_3,
  219. 'selector' => '{{WRAPPER}} .elementor-testimonial-content',
  220. ]
  221. );
  222. $this->end_controls_section();
  223. // Image.
  224. $this->start_controls_section(
  225. 'section_style_testimonial_image',
  226. [
  227. 'label' => __( 'Image', 'elementor' ),
  228. 'tab' => Controls_Manager::TAB_STYLE,
  229. 'condition' => [
  230. 'testimonial_image[url]!' => '',
  231. ],
  232. ]
  233. );
  234. $this->add_control(
  235. 'image_size',
  236. [
  237. 'label' => __( 'Image Size', 'elementor' ),
  238. 'type' => Controls_Manager::SLIDER,
  239. 'size_units' => [ 'px' ],
  240. 'range' => [
  241. 'px' => [
  242. 'min' => 20,
  243. 'max' => 200,
  244. ],
  245. ],
  246. 'selectors' => [
  247. '{{WRAPPER}} .elementor-testimonial-wrapper .elementor-testimonial-image img' => 'width: {{SIZE}}{{UNIT}};height: {{SIZE}}{{UNIT}};',
  248. ],
  249. ]
  250. );
  251. $this->add_group_control(
  252. Group_Control_Border::get_type(),
  253. [
  254. 'name' => 'image_border',
  255. 'selector' => '{{WRAPPER}} .elementor-testimonial-wrapper .elementor-testimonial-image img',
  256. 'separator' => 'before',
  257. ]
  258. );
  259. $this->add_control(
  260. 'image_border_radius',
  261. [
  262. 'label' => __( 'Border Radius', 'elementor' ),
  263. 'type' => Controls_Manager::DIMENSIONS,
  264. 'size_units' => [ 'px', '%' ],
  265. 'selectors' => [
  266. '{{WRAPPER}} .elementor-testimonial-wrapper .elementor-testimonial-image img' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
  267. ],
  268. ]
  269. );
  270. $this->end_controls_section();
  271. // Name.
  272. $this->start_controls_section(
  273. 'section_style_testimonial_name',
  274. [
  275. 'label' => __( 'Name', 'elementor' ),
  276. 'tab' => Controls_Manager::TAB_STYLE,
  277. ]
  278. );
  279. $this->add_control(
  280. 'name_text_color',
  281. [
  282. 'label' => __( 'Text Color', 'elementor' ),
  283. 'type' => Controls_Manager::COLOR,
  284. 'scheme' => [
  285. 'type' => Scheme_Color::get_type(),
  286. 'value' => Scheme_Color::COLOR_1,
  287. ],
  288. 'default' => '',
  289. 'selectors' => [
  290. '{{WRAPPER}} .elementor-testimonial-name' => 'color: {{VALUE}};',
  291. ],
  292. ]
  293. );
  294. $this->add_group_control(
  295. Group_Control_Typography::get_type(),
  296. [
  297. 'name' => 'name_typography',
  298. 'scheme' => Scheme_Typography::TYPOGRAPHY_1,
  299. 'selector' => '{{WRAPPER}} .elementor-testimonial-name',
  300. ]
  301. );
  302. $this->end_controls_section();
  303. // Job.
  304. $this->start_controls_section(
  305. 'section_style_testimonial_job',
  306. [
  307. 'label' => __( 'Job', 'elementor' ),
  308. 'tab' => Controls_Manager::TAB_STYLE,
  309. ]
  310. );
  311. $this->add_control(
  312. 'job_text_color',
  313. [
  314. 'label' => __( 'Text Color', 'elementor' ),
  315. 'type' => Controls_Manager::COLOR,
  316. 'scheme' => [
  317. 'type' => Scheme_Color::get_type(),
  318. 'value' => Scheme_Color::COLOR_2,
  319. ],
  320. 'default' => '',
  321. 'selectors' => [
  322. '{{WRAPPER}} .elementor-testimonial-job' => 'color: {{VALUE}};',
  323. ],
  324. ]
  325. );
  326. $this->add_group_control(
  327. Group_Control_Typography::get_type(),
  328. [
  329. 'name' => 'job_typography',
  330. 'scheme' => Scheme_Typography::TYPOGRAPHY_2,
  331. 'selector' => '{{WRAPPER}} .elementor-testimonial-job',
  332. ]
  333. );
  334. $this->end_controls_section();
  335. }
  336. /**
  337. * Render testimonial widget output on the frontend.
  338. *
  339. * Written in PHP and used to generate the final HTML.
  340. *
  341. * @since 1.0.0
  342. * @access protected
  343. */
  344. protected function render() {
  345. $settings = $this->get_settings_for_display();
  346. $this->add_render_attribute( 'wrapper', 'class', 'elementor-testimonial-wrapper' );
  347. if ( $settings['testimonial_alignment'] ) {
  348. $this->add_render_attribute( 'wrapper', 'class', 'elementor-testimonial-text-align-' . $settings['testimonial_alignment'] );
  349. }
  350. $this->add_render_attribute( 'meta', 'class', 'elementor-testimonial-meta' );
  351. if ( $settings['testimonial_image']['url'] ) {
  352. $this->add_render_attribute( 'meta', 'class', 'elementor-has-image' );
  353. }
  354. if ( $settings['testimonial_image_position'] ) {
  355. $this->add_render_attribute( 'meta', 'class', 'elementor-testimonial-image-position-' . $settings['testimonial_image_position'] );
  356. }
  357. $has_content = ! ! $settings['testimonial_content'];
  358. $has_image = ! ! $settings['testimonial_image']['url'];
  359. $has_name = ! ! $settings['testimonial_name'];
  360. $has_job = ! ! $settings['testimonial_job'];
  361. if ( ! $has_content && ! $has_image && ! $has_name && ! $has_job ) {
  362. return;
  363. }
  364. if ( ! empty( $settings['link']['url'] ) ) {
  365. $this->add_render_attribute( 'link', 'href', $settings['link']['url'] );
  366. if ( $settings['link']['is_external'] ) {
  367. $this->add_render_attribute( 'link', 'target', '_blank' );
  368. }
  369. if ( ! empty( $settings['link']['nofollow'] ) ) {
  370. $this->add_render_attribute( 'link', 'rel', 'nofollow' );
  371. }
  372. }
  373. ?>
  374. <div <?php echo $this->get_render_attribute_string( 'wrapper' ); ?>>
  375. <?php
  376. if ( $has_content ) :
  377. $this->add_render_attribute( 'testimonial_content', 'class', 'elementor-testimonial-content' );
  378. $this->add_inline_editing_attributes( 'testimonial_content' );
  379. ?>
  380. <div <?php echo $this->get_render_attribute_string( 'testimonial_content' ); ?>><?php echo $settings['testimonial_content']; ?></div>
  381. <?php endif; ?>
  382. <?php if ( $has_image || $has_name || $has_job ) : ?>
  383. <div <?php echo $this->get_render_attribute_string( 'meta' ); ?>>
  384. <div class="elementor-testimonial-meta-inner">
  385. <?php if ( $has_image ) : ?>
  386. <div class="elementor-testimonial-image">
  387. <?php
  388. $image_html = Group_Control_Image_Size::get_attachment_image_html( $settings, 'testimonial_image' );
  389. if ( ! empty( $settings['link']['url'] ) ) :
  390. $image_html = '<a ' . $this->get_render_attribute_string( 'link' ) . '>' . $image_html . '</a>';
  391. endif;
  392. echo $image_html;
  393. ?>
  394. </div>
  395. <?php endif; ?>
  396. <?php if ( $has_name || $has_job ) : ?>
  397. <div class="elementor-testimonial-details">
  398. <?php
  399. if ( $has_name ) :
  400. $this->add_render_attribute( 'testimonial_name', 'class', 'elementor-testimonial-name' );
  401. $this->add_inline_editing_attributes( 'testimonial_name', 'none' );
  402. $testimonial_name_html = $settings['testimonial_name'];
  403. if ( ! empty( $settings['link']['url'] ) ) :
  404. $testimonial_name_html = '<a ' . $this->get_render_attribute_string( 'link' ) . '>' . $testimonial_name_html . '</a>';
  405. endif;
  406. ?>
  407. <div <?php echo $this->get_render_attribute_string( 'testimonial_name' ); ?>><?php echo $testimonial_name_html; ?></div>
  408. <?php endif; ?>
  409. <?php
  410. if ( $has_job ) :
  411. $this->add_render_attribute( 'testimonial_job', 'class', 'elementor-testimonial-job' );
  412. $this->add_inline_editing_attributes( 'testimonial_job', 'none' );
  413. $testimonial_job_html = $settings['testimonial_job'];
  414. if ( ! empty( $settings['link']['url'] ) ) :
  415. $testimonial_job_html = '<a ' . $this->get_render_attribute_string( 'link' ) . '>' . $testimonial_job_html . '</a>';
  416. endif;
  417. ?>
  418. <div <?php echo $this->get_render_attribute_string( 'testimonial_job' ); ?>><?php echo $testimonial_job_html; ?></div>
  419. <?php endif; ?>
  420. </div>
  421. <?php endif; ?>
  422. </div>
  423. </div>
  424. <?php endif; ?>
  425. </div>
  426. <?php
  427. }
  428. /**
  429. * Render testimonial widget output in the editor.
  430. *
  431. * Written as a Backbone JavaScript template and used to generate the live preview.
  432. *
  433. * @since 1.0.0
  434. * @access protected
  435. */
  436. protected function _content_template() {
  437. ?>
  438. <#
  439. var image = {
  440. id: settings.testimonial_image.id,
  441. url: settings.testimonial_image.url,
  442. size: settings.testimonial_image_size,
  443. dimension: settings.testimonial_image_custom_dimension,
  444. model: view.getEditModel()
  445. };
  446. var imageUrl = false, hasImage = '';
  447. if ( '' !== settings.testimonial_image.url ) {
  448. imageUrl = elementor.imagesManager.getImageUrl( image );
  449. hasImage = ' elementor-has-image';
  450. var imageHtml = '<img src="' + imageUrl + '" alt="testimonial" />';
  451. if ( settings.link.url ) {
  452. imageHtml = '<a href="' + settings.link.url + '">' + imageHtml + '</a>';
  453. }
  454. }
  455. var testimonial_alignment = settings.testimonial_alignment ? ' elementor-testimonial-text-align-' + settings.testimonial_alignment : '';
  456. var testimonial_image_position = settings.testimonial_image_position ? ' elementor-testimonial-image-position-' + settings.testimonial_image_position : '';
  457. #>
  458. <div class="elementor-testimonial-wrapper{{ testimonial_alignment }}">
  459. <# if ( '' !== settings.testimonial_content ) {
  460. view.addRenderAttribute( 'testimonial_content', 'class', 'elementor-testimonial-content' );
  461. view.addInlineEditingAttributes( 'testimonial_content' );
  462. #>
  463. <div {{{ view.getRenderAttributeString( 'testimonial_content' ) }}}>{{{ settings.testimonial_content }}}</div>
  464. <# } #>
  465. <div class="elementor-testimonial-meta{{ hasImage }}{{ testimonial_image_position }}">
  466. <div class="elementor-testimonial-meta-inner">
  467. <# if ( imageUrl ) { #>
  468. <div class="elementor-testimonial-image">{{{ imageHtml }}}</div>
  469. <# } #>
  470. <div class="elementor-testimonial-details">
  471. <# if ( '' !== settings.testimonial_name ) {
  472. view.addRenderAttribute( 'testimonial_name', 'class', 'elementor-testimonial-name' );
  473. view.addInlineEditingAttributes( 'testimonial_name', 'none' );
  474. var testimonialNameHtml = settings.testimonial_name;
  475. if ( settings.link.url ) {
  476. testimonialNameHtml = '<a href="' + settings.link.url + '">' + testimonialNameHtml + '</a>';
  477. }
  478. #>
  479. <div {{{ view.getRenderAttributeString( 'testimonial_name' ) }}}>{{{ testimonialNameHtml }}}</div>
  480. <# } #>
  481. <# if ( '' !== settings.testimonial_job ) {
  482. view.addRenderAttribute( 'testimonial_job', 'class', 'elementor-testimonial-job' );
  483. view.addInlineEditingAttributes( 'testimonial_job', 'none' );
  484. var testimonialJobHtml = settings.testimonial_job;
  485. if ( settings.link.url ) {
  486. testimonialJobHtml = '<a href="' + settings.link.url + '">' + testimonialJobHtml + '</a>';
  487. }
  488. #>
  489. <div {{{ view.getRenderAttributeString( 'testimonial_job' ) }}}>{{{ testimonialJobHtml }}}</div>
  490. <# } #>
  491. </div>
  492. </div>
  493. </div>
  494. </div>
  495. <?php
  496. }
  497. }