tabs.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <?php
  2. namespace Elementor;
  3. if ( ! defined( 'ABSPATH' ) ) {
  4. exit; // Exit if accessed directly.
  5. }
  6. /**
  7. * Elementor tabs widget.
  8. *
  9. * Elementor widget that displays vertical or horizontal tabs with different
  10. * pieces of content.
  11. *
  12. * @since 1.0.0
  13. */
  14. class Widget_Tabs extends Widget_Base {
  15. /**
  16. * Get widget name.
  17. *
  18. * Retrieve tabs widget name.
  19. *
  20. * @since 1.0.0
  21. * @access public
  22. *
  23. * @return string Widget name.
  24. */
  25. public function get_name() {
  26. return 'tabs';
  27. }
  28. /**
  29. * Get widget title.
  30. *
  31. * Retrieve tabs widget title.
  32. *
  33. * @since 1.0.0
  34. * @access public
  35. *
  36. * @return string Widget title.
  37. */
  38. public function get_title() {
  39. return __( 'Tabs', 'elementor' );
  40. }
  41. /**
  42. * Get widget icon.
  43. *
  44. * Retrieve tabs widget icon.
  45. *
  46. * @since 1.0.0
  47. * @access public
  48. *
  49. * @return string Widget icon.
  50. */
  51. public function get_icon() {
  52. return 'eicon-tabs';
  53. }
  54. /**
  55. * Get widget keywords.
  56. *
  57. * Retrieve the list of keywords the widget belongs to.
  58. *
  59. * @since 2.1.0
  60. * @access public
  61. *
  62. * @return array Widget keywords.
  63. */
  64. public function get_keywords() {
  65. return [ 'tabs', 'accordion', 'toggle' ];
  66. }
  67. /**
  68. * Register tabs widget controls.
  69. *
  70. * Adds different input fields to allow the user to change and customize the widget settings.
  71. *
  72. * @since 1.0.0
  73. * @access protected
  74. */
  75. protected function _register_controls() {
  76. $this->start_controls_section(
  77. 'section_tabs',
  78. [
  79. 'label' => __( 'Tabs', 'elementor' ),
  80. ]
  81. );
  82. $repeater = new Repeater();
  83. $repeater->add_control(
  84. 'tab_title',
  85. [
  86. 'label' => __( 'Title & Content', 'elementor' ),
  87. 'type' => Controls_Manager::TEXT,
  88. 'default' => __( 'Tab Title', 'elementor' ),
  89. 'placeholder' => __( 'Tab Title', 'elementor' ),
  90. 'label_block' => true,
  91. ]
  92. );
  93. $repeater->add_control(
  94. 'tab_content',
  95. [
  96. 'label' => __( 'Content', 'elementor' ),
  97. 'default' => __( 'Tab Content', 'elementor' ),
  98. 'placeholder' => __( 'Tab Content', 'elementor' ),
  99. 'type' => Controls_Manager::WYSIWYG,
  100. 'show_label' => false,
  101. ]
  102. );
  103. $this->add_control(
  104. 'tabs',
  105. [
  106. 'label' => __( 'Tabs Items', 'elementor' ),
  107. 'type' => Controls_Manager::REPEATER,
  108. 'fields' => $repeater->get_controls(),
  109. 'default' => [
  110. [
  111. 'tab_title' => __( 'Tab #1', 'elementor' ),
  112. 'tab_content' => __( '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.', 'elementor' ),
  113. ],
  114. [
  115. 'tab_title' => __( 'Tab #2', 'elementor' ),
  116. 'tab_content' => __( '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.', 'elementor' ),
  117. ],
  118. ],
  119. 'title_field' => '{{{ tab_title }}}',
  120. ]
  121. );
  122. $this->add_control(
  123. 'view',
  124. [
  125. 'label' => __( 'View', 'elementor' ),
  126. 'type' => Controls_Manager::HIDDEN,
  127. 'default' => 'traditional',
  128. ]
  129. );
  130. $this->add_control(
  131. 'type',
  132. [
  133. 'label' => __( 'Type', 'elementor' ),
  134. 'type' => Controls_Manager::SELECT,
  135. 'default' => 'horizontal',
  136. 'options' => [
  137. 'horizontal' => __( 'Horizontal', 'elementor' ),
  138. 'vertical' => __( 'Vertical', 'elementor' ),
  139. ],
  140. 'prefix_class' => 'elementor-tabs-view-',
  141. 'separator' => 'before',
  142. ]
  143. );
  144. $this->end_controls_section();
  145. $this->start_controls_section(
  146. 'section_tabs_style',
  147. [
  148. 'label' => __( 'Tabs', 'elementor' ),
  149. 'tab' => Controls_Manager::TAB_STYLE,
  150. ]
  151. );
  152. $this->add_control(
  153. 'navigation_width',
  154. [
  155. 'label' => __( 'Navigation Width', 'elementor' ),
  156. 'type' => Controls_Manager::SLIDER,
  157. 'default' => [
  158. 'unit' => '%',
  159. ],
  160. 'range' => [
  161. '%' => [
  162. 'min' => 10,
  163. 'max' => 50,
  164. ],
  165. ],
  166. 'selectors' => [
  167. '{{WRAPPER}} .elementor-tabs-wrapper' => 'width: {{SIZE}}{{UNIT}}',
  168. ],
  169. 'condition' => [
  170. 'type' => 'vertical',
  171. ],
  172. ]
  173. );
  174. $this->add_control(
  175. 'border_width',
  176. [
  177. 'label' => __( 'Border Width', 'elementor' ),
  178. 'type' => Controls_Manager::SLIDER,
  179. 'default' => [
  180. 'size' => 1,
  181. ],
  182. 'range' => [
  183. 'px' => [
  184. 'min' => 0,
  185. 'max' => 10,
  186. ],
  187. ],
  188. 'selectors' => [
  189. '{{WRAPPER}} .elementor-tab-title, {{WRAPPER}} .elementor-tab-title:before, {{WRAPPER}} .elementor-tab-title:after, {{WRAPPER}} .elementor-tab-content, {{WRAPPER}} .elementor-tabs-content-wrapper' => 'border-width: {{SIZE}}{{UNIT}};',
  190. ],
  191. ]
  192. );
  193. $this->add_control(
  194. 'border_color',
  195. [
  196. 'label' => __( 'Border Color', 'elementor' ),
  197. 'type' => Controls_Manager::COLOR,
  198. 'selectors' => [
  199. '{{WRAPPER}} .elementor-tab-mobile-title, {{WRAPPER}} .elementor-tab-desktop-title.elementor-active, {{WRAPPER}} .elementor-tab-title:before, {{WRAPPER}} .elementor-tab-title:after, {{WRAPPER}} .elementor-tab-content, {{WRAPPER}} .elementor-tabs-content-wrapper' => 'border-color: {{VALUE}};',
  200. ],
  201. ]
  202. );
  203. $this->add_control(
  204. 'background_color',
  205. [
  206. 'label' => __( 'Background Color', 'elementor' ),
  207. 'type' => Controls_Manager::COLOR,
  208. 'selectors' => [
  209. '{{WRAPPER}} .elementor-tab-desktop-title.elementor-active' => 'background-color: {{VALUE}};',
  210. '{{WRAPPER}} .elementor-tabs-content-wrapper' => 'background-color: {{VALUE}};',
  211. ],
  212. ]
  213. );
  214. $this->add_control(
  215. 'heading_title',
  216. [
  217. 'label' => __( 'Title', 'elementor' ),
  218. 'type' => Controls_Manager::HEADING,
  219. 'separator' => 'before',
  220. ]
  221. );
  222. $this->add_control(
  223. 'tab_color',
  224. [
  225. 'label' => __( 'Color', 'elementor' ),
  226. 'type' => Controls_Manager::COLOR,
  227. 'selectors' => [
  228. '{{WRAPPER}} .elementor-tab-title' => 'color: {{VALUE}};',
  229. ],
  230. 'scheme' => [
  231. 'type' => Scheme_Color::get_type(),
  232. 'value' => Scheme_Color::COLOR_1,
  233. ],
  234. ]
  235. );
  236. $this->add_control(
  237. 'tab_active_color',
  238. [
  239. 'label' => __( 'Active Color', 'elementor' ),
  240. 'type' => Controls_Manager::COLOR,
  241. 'selectors' => [
  242. '{{WRAPPER}} .elementor-tab-title.elementor-active' => 'color: {{VALUE}};',
  243. ],
  244. 'scheme' => [
  245. 'type' => Scheme_Color::get_type(),
  246. 'value' => Scheme_Color::COLOR_4,
  247. ],
  248. ]
  249. );
  250. $this->add_group_control(
  251. Group_Control_Typography::get_type(),
  252. [
  253. 'name' => 'tab_typography',
  254. 'selector' => '{{WRAPPER}} .elementor-tab-title',
  255. 'scheme' => Scheme_Typography::TYPOGRAPHY_1,
  256. ]
  257. );
  258. $this->add_control(
  259. 'heading_content',
  260. [
  261. 'label' => __( 'Content', 'elementor' ),
  262. 'type' => Controls_Manager::HEADING,
  263. 'separator' => 'before',
  264. ]
  265. );
  266. $this->add_control(
  267. 'content_color',
  268. [
  269. 'label' => __( 'Color', 'elementor' ),
  270. 'type' => Controls_Manager::COLOR,
  271. 'selectors' => [
  272. '{{WRAPPER}} .elementor-tab-content' => 'color: {{VALUE}};',
  273. ],
  274. 'scheme' => [
  275. 'type' => Scheme_Color::get_type(),
  276. 'value' => Scheme_Color::COLOR_3,
  277. ],
  278. ]
  279. );
  280. $this->add_group_control(
  281. Group_Control_Typography::get_type(),
  282. [
  283. 'name' => 'content_typography',
  284. 'selector' => '{{WRAPPER}} .elementor-tab-content',
  285. 'scheme' => Scheme_Typography::TYPOGRAPHY_3,
  286. ]
  287. );
  288. $this->end_controls_section();
  289. }
  290. /**
  291. * Render tabs widget output on the frontend.
  292. *
  293. * Written in PHP and used to generate the final HTML.
  294. *
  295. * @since 1.0.0
  296. * @access protected
  297. */
  298. protected function render() {
  299. $tabs = $this->get_settings_for_display( 'tabs' );
  300. $id_int = substr( $this->get_id_int(), 0, 3 );
  301. ?>
  302. <div class="elementor-tabs" role="tablist">
  303. <div class="elementor-tabs-wrapper">
  304. <?php
  305. foreach ( $tabs as $index => $item ) :
  306. $tab_count = $index + 1;
  307. $tab_title_setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $index );
  308. $this->add_render_attribute( $tab_title_setting_key, [
  309. 'id' => 'elementor-tab-title-' . $id_int . $tab_count,
  310. 'class' => [ 'elementor-tab-title', 'elementor-tab-desktop-title' ],
  311. 'data-tab' => $tab_count,
  312. 'tabindex' => $id_int . $tab_count,
  313. 'role' => 'tab',
  314. 'aria-controls' => 'elementor-tab-content-' . $id_int . $tab_count,
  315. ] );
  316. ?>
  317. <div <?php echo $this->get_render_attribute_string( $tab_title_setting_key ); ?>><?php echo $item['tab_title']; ?></div>
  318. <?php endforeach; ?>
  319. </div>
  320. <div class="elementor-tabs-content-wrapper">
  321. <?php
  322. foreach ( $tabs as $index => $item ) :
  323. $tab_count = $index + 1;
  324. $tab_content_setting_key = $this->get_repeater_setting_key( 'tab_content', 'tabs', $index );
  325. $tab_title_mobile_setting_key = $this->get_repeater_setting_key( 'tab_title_mobile', 'tabs', $tab_count );
  326. $this->add_render_attribute( $tab_content_setting_key, [
  327. 'id' => 'elementor-tab-content-' . $id_int . $tab_count,
  328. 'class' => [ 'elementor-tab-content', 'elementor-clearfix' ],
  329. 'data-tab' => $tab_count,
  330. 'role' => 'tabpanel',
  331. 'aria-labelledby' => 'elementor-tab-title-' . $id_int . $tab_count,
  332. ] );
  333. $this->add_render_attribute( $tab_title_mobile_setting_key, [
  334. 'class' => [ 'elementor-tab-title', 'elementor-tab-mobile-title' ],
  335. 'tabindex' => $id_int . $tab_count,
  336. 'data-tab' => $tab_count,
  337. 'role' => 'tab',
  338. ] );
  339. $this->add_inline_editing_attributes( $tab_content_setting_key, 'advanced' );
  340. ?>
  341. <div <?php echo $this->get_render_attribute_string( $tab_title_mobile_setting_key ); ?>><?php echo $item['tab_title']; ?></div>
  342. <div <?php echo $this->get_render_attribute_string( $tab_content_setting_key ); ?>><?php echo $this->parse_text_editor( $item['tab_content'] ); ?></div>
  343. <?php endforeach; ?>
  344. </div>
  345. </div>
  346. <?php
  347. }
  348. /**
  349. * Render tabs widget output in the editor.
  350. *
  351. * Written as a Backbone JavaScript template and used to generate the live preview.
  352. *
  353. * @since 1.0.0
  354. * @access protected
  355. */
  356. protected function _content_template() {
  357. ?>
  358. <div class="elementor-tabs" role="tablist">
  359. <#
  360. if ( settings.tabs ) {
  361. var tabindex = view.getIDInt().toString().substr( 0, 3 );
  362. #>
  363. <div class="elementor-tabs-wrapper">
  364. <#
  365. _.each( settings.tabs, function( item, index ) {
  366. var tabCount = index + 1;
  367. #>
  368. <div id="elementor-tab-title-{{ tabindex + tabCount }}" class="elementor-tab-title elementor-tab-desktop-title" tabindex="{{ tabindex + tabCount }}" data-tab="{{ tabCount }}" role="tab" aria-controls="elementor-tab-content-{{ tabindex + tabCount }}">{{{ item.tab_title }}}</div>
  369. <# } ); #>
  370. </div>
  371. <div class="elementor-tabs-content-wrapper">
  372. <#
  373. _.each( settings.tabs, function( item, index ) {
  374. var tabCount = index + 1,
  375. tabContentKey = view.getRepeaterSettingKey( 'tab_content', 'tabs',index );
  376. view.addRenderAttribute( tabContentKey, {
  377. 'id': 'elementor-tab-content-' + tabindex + tabCount,
  378. 'class': [ 'elementor-tab-content', 'elementor-clearfix', 'elementor-repeater-item-' + item._id ],
  379. 'data-tab': tabCount,
  380. 'role' : 'tabpanel',
  381. 'aria-labelledby' : 'elementor-tab-title-' + tabindex + tabCount
  382. } );
  383. view.addInlineEditingAttributes( tabContentKey, 'advanced' );
  384. #>
  385. <div class="elementor-tab-title elementor-tab-mobile-title" data-tab="{{ tabCount }}" role="tab">{{{ item.tab_title }}}</div>
  386. <div {{{ view.getRenderAttributeString( tabContentKey ) }}}>{{{ item.tab_content }}}</div>
  387. <# } ); #>
  388. </div>
  389. <# } #>
  390. </div>
  391. <?php
  392. }
  393. }