PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.6.1
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.6.1
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
betterdocs / includes / Editors / Elementor / Widget / Basic / FAQ.php

FAQ.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.6.1, at includes/Editors/Elementor/Widget/Basic/FAQ.php

1,034 lines 35.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\Editors\Elementor\Widget\Basic;
4
5 use Elementor\Widget_Base;
6
7 // If this file is called directly, abort.
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 use Elementor\Group_Control_Background;
13 use Elementor\Plugin as ElementorPlugin;
14 use Elementor\Controls_Manager;
15 use WPDeveloper\BetterDocs\Editors\Elementor\Helper;
16 use Elementor\Group_Control_Border;
17 use Elementor\Group_Control_Typography;
18 use WPDeveloper\BetterDocs\Editors\Elementor\BaseWidget;
19 use WPDeveloper\BetterDocs\FrontEnd\WooProductFAQ as WooFAQRenderer;
20
21 class FAQ extends BaseWidget {
22
23 public function get_name() {
24 return 'betterdocs-faq';
25 }
26
27 public function get_title() {
28 return __( 'BetterDocs FAQ', 'betterdocs' );
29 }
30
31 public function get_custom_help_url() {
32 return 'http://betterdocs.co/docs/betterdocs-faq-builder-in-elementor/';
33 }
34
35 public function get_icon() {
36 return 'betterdocs-icon-faq';
37 }
38
39 public function get_categories() {
40 return [ 'betterdocs-elements' ];
41 }
42
43 public function get_keywords() {
44 return [ 'betterdocs-elements', 'betterdocs', 'docs', 'faq', 'FAQ', 'betterdocs-faq' ];
45 }
46
47 public function get_style_depends() {
48 return [ 'betterdocs-faq' ];
49 }
50
51 protected function register_controls() {
52 $this->start_controls_section(
53 'faq_section_controls',
54 [
55 'label' => __( 'Layout Options', 'betterdocs' )
56 ]
57 );
58
59 $this->add_control(
60 'faq_layout_selection',
61 [
62 'label' => __( 'Select Layout', 'betterdocs' ),
63 'type' => Controls_Manager::SELECT2,
64 'options' => [
65 'layout-3' => __( 'Abstract Layout', 'betterdocs' ),
66 'layout-1' => __( 'Modern Layout', 'betterdocs' ),
67 'layout-2' => __( 'Classic Layout', 'betterdocs' ),
68 'layout-4' => __( 'Tab Layout', 'betterdocs' )
69 ],
70 'default' => 'layout-1',
71 'label_block' => true
72 ]
73 );
74
75 if ( class_exists( 'WooCommerce' ) ) {
76 $this->add_control(
77 'faq_taxonomy',
78 [
79 'label' => __( 'FAQ Type', 'betterdocs' ),
80 'type' => Controls_Manager::SELECT,
81 'options' => [
82 'betterdocs_faq_category' => __( 'General FAQ', 'betterdocs' ),
83 'betterdocs_product_faq_category' => __( 'Product FAQ', 'betterdocs' ),
84 'product_assignments' => __( 'Product Assignments', 'betterdocs' ),
85 ],
86 'default' => 'betterdocs_faq_category',
87 ]
88 );
89
90 $this->add_control(
91 'faq_product_assignments_note',
92 [
93 'type' => Controls_Manager::RAW_HTML,
94 'raw' => __( 'Groups are resolved automatically per product: a per-product assignment is shown if set, otherwise the groups assigned to the product’s categories. Manage assignments on each group in FAQ Builder → WooCommerce → Product FAQ Groups.', 'betterdocs' ),
95 'content_classes' => 'elementor-control-field-description',
96 'condition' => [ 'faq_taxonomy' => 'product_assignments' ],
97 ]
98 );
99 }
100
101 $this->add_control(
102 'faq_layout_section',
103 [
104 'label' => __( 'FAQ Section', 'betterdocs' ),
105 'type' => Controls_Manager::TEXT,
106 'dynamic' => [
107 'active' => true
108 ],
109 'default' => __( 'Frequently Asked Questions', 'betterdocs' )
110 ]
111 );
112
113 $this->add_control(
114 'faq_section_title_tag',
115 [
116 'label' => __( 'Section Title Tag', 'betterdocs' ),
117 'type' => Controls_Manager::SELECT,
118 'default' => 'h2',
119 'options' => [
120 'h1' => __( 'H1', 'betterdocs' ),
121 'h2' => __( 'H2', 'betterdocs' ),
122 'h3' => __( 'H3', 'betterdocs' ),
123 'h4' => __( 'H4', 'betterdocs' ),
124 'h5' => __( 'H5', 'betterdocs' ),
125 'h6' => __( 'H6', 'betterdocs' )
126 ]
127 ]
128 );
129
130 $this->add_control(
131 'faq_group_title_tag',
132 [
133 'label' => __( 'Group Title Tag', 'betterdocs' ),
134 'type' => Controls_Manager::SELECT,
135 'default' => 'h3',
136 'options' => [
137 'h1' => __( 'H1', 'betterdocs' ),
138 'h2' => __( 'H2', 'betterdocs' ),
139 'h3' => __( 'H3', 'betterdocs' ),
140 'h4' => __( 'H4', 'betterdocs' ),
141 'h5' => __( 'H5', 'betterdocs' ),
142 'h6' => __( 'H6', 'betterdocs' )
143 ],
144 'condition' => [
145 'faq_layout_selection' => [ 'layout-1', 'layout-2', 'layout-3' ]
146 ]
147 ]
148 );
149
150 $terms = betterdocs()->container->get( Helper::class )->get_faq_terms();
151
152 // General FAQ include/exclude — shown always when WooCommerce is off,
153 // or conditioned on FAQ Type = General FAQ when WooCommerce is on.
154 $general_include_args = [
155 'label' => __( 'Include FAQ Groups', 'betterdocs' ),
156 'label_block' => true,
157 'type' => Controls_Manager::SELECT2,
158 'options' => $terms,
159 'multiple' => true,
160 'default' => '',
161 'select2options' => [
162 'placeholder' => __( 'Include FAQ Groups', 'betterdocs' ),
163 'allowClear' => true
164 ]
165 ];
166 $general_exclude_args = [
167 'label' => __( 'Exclude FAQ Groups', 'betterdocs' ),
168 'label_block' => true,
169 'type' => Controls_Manager::SELECT2,
170 'options' => $terms,
171 'multiple' => true,
172 'default' => '',
173 'select2options' => [
174 'placeholder' => __( 'Exclude FAQ Groups', 'betterdocs' ),
175 'allowClear' => true
176 ]
177 ];
178
179 if ( class_exists( 'WooCommerce' ) ) {
180 $general_include_args['condition'] = [ 'faq_taxonomy' => 'betterdocs_faq_category' ];
181 $general_exclude_args['condition'] = [ 'faq_taxonomy' => 'betterdocs_faq_category' ];
182 }
183
184 $this->add_control( 'select_specific_faq', $general_include_args );
185 $this->add_control( 'exclude_specific_faq', $general_exclude_args );
186
187 if ( class_exists( 'WooCommerce' ) ) {
188 $product_terms = betterdocs()->query->get_faq_terms( [], 'betterdocs_product_faq_category' );
189
190 $this->add_control(
191 'select_specific_product_faq',
192 [
193 'label' => __( 'Include Product FAQ Groups', 'betterdocs' ),
194 'label_block' => true,
195 'type' => Controls_Manager::SELECT2,
196 'options' => $product_terms,
197 'multiple' => true,
198 'default' => '',
199 'condition' => [ 'faq_taxonomy' => 'betterdocs_product_faq_category' ],
200 'select2options' => [
201 'placeholder' => __( 'Include Product FAQ Groups', 'betterdocs' ),
202 'allowClear' => true
203 ]
204 ]
205 );
206
207 $this->add_control(
208 'exclude_specific_product_faq',
209 [
210 'label' => __( 'Exclude Product FAQ Groups', 'betterdocs' ),
211 'label_block' => true,
212 'type' => Controls_Manager::SELECT2,
213 'options' => $product_terms,
214 'multiple' => true,
215 'default' => '',
216 'condition' => [ 'faq_taxonomy' => 'betterdocs_product_faq_category' ],
217 'select2options' => [
218 'placeholder' => __( 'Exclude Product FAQ Groups', 'betterdocs' ),
219 'allowClear' => true
220 ]
221 ]
222 );
223 }
224
225 $this->end_controls_section();
226
227 /**
228 * ----------------------------------------------------------
229 * Section: Container Section Settings
230 * ----------------------------------------------------------
231 */
232 $this->start_controls_section(
233 'section_faq_container_section',
234 [
235 'label' => __( 'Container Section', 'betterdocs' ),
236 'tab' => Controls_Manager::TAB_STYLE,
237 ]
238 );
239
240 $this->add_responsive_control(
241 'section_faq_container_section_padding',
242 [
243 'label' => __( 'Padding', 'betterdocs' ),
244 'type' => Controls_Manager::DIMENSIONS,
245 'size_units' => [ 'px', 'em', '%' ],
246 'selectors' => [
247 '{{WRAPPER}} .betterdocs-faq-wrapper' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
248 ]
249 ]
250 );
251
252 $this->add_responsive_control(
253 'section_faq_container_section_margin', // Legacy control id but new control
254 [
255 'label' => __( 'Margin', 'betterdocs' ),
256 'type' => Controls_Manager::DIMENSIONS,
257 'size_units' => [ 'px', '%', 'em' ],
258 'selectors' => [
259 '{{WRAPPER}} .betterdocs-faq-wrapper' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
260 ]
261 ]
262 );
263
264 $this->add_group_control(
265 Group_Control_Background::get_type(),
266 [
267 'name' => 'section_faq_container_section_background',
268 'types' => [ 'classic', 'gradient' ],
269 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper'
270 ]
271 );
272
273 $this->end_controls_section();
274
275 /******* Common Section Style For Both Layouts *******/
276
277 $this->start_controls_section(
278 'faq_section_style',
279 [
280 'label' => __( 'FAQ Section Title', 'betterdocs' ),
281 'tab' => Controls_Manager::TAB_STYLE
282 ]
283 );
284
285 $this->add_control(
286 'faq_layout_section_title_color',
287 [
288 'label' => esc_html__( 'Text Color', 'betterdocs' ),
289 'type' => Controls_Manager::COLOR,
290 'selectors' => [
291 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-section-title' => 'color:{{VALUE}};'
292 ]
293 ]
294 );
295
296 $this->add_group_control(
297 Group_Control_Typography::get_type(),
298 [
299 'name' => 'faq_layout_section_title_typography',
300 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-section-title'
301 ]
302 );
303
304 $this->end_controls_section();
305
306 $this->start_controls_section(
307 'faq_box_title_section',
308 [
309 'label' => __( 'FAQ Group Title', 'betterdocs' ),
310 'tab' => Controls_Manager::TAB_STYLE,
311 'condition' => [
312 'faq_layout_selection' => ['layout-1', 'layout-2', 'layout-3']
313 ]
314 ]
315 );
316
317 $this->add_control(
318 'faq_box_title_color',
319 [
320 'label' => esc_html__( 'Title Color', 'betterdocs' ),
321 'type' => Controls_Manager::COLOR,
322 'selectors' => [
323 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-title .betterdocs-faq-title-tag' => 'color:{{VALUE}};'
324 ]
325 ]
326 );
327
328 $this->add_control(
329 'faq_box_title_color_hover',
330 [
331 'label' => esc_html__( 'Title Hover Color', 'betterdocs' ),
332 'type' => Controls_Manager::COLOR,
333 'selectors' => [
334 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-title .betterdocs-faq-title-tag:hover' => 'color:{{VALUE}};'
335 ]
336 ]
337 );
338
339 $this->add_group_control(
340 Group_Control_Typography::get_type(),
341 [
342 'name' => 'faq_box_title_typography',
343 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-title .betterdocs-faq-title-tag'
344 ]
345 );
346
347 $this->end_controls_section();
348
349 $this->start_controls_section(
350 'faq_box_title_section_layout_4',
351 [
352 'label' => __( 'FAQ Group Title', 'betterdocs' ),
353 'tab' => Controls_Manager::TAB_STYLE,
354 'condition' => [
355 'faq_layout_selection' => ['layout-4']
356 ]
357 ]
358 );
359
360 $this->add_control(
361 'faq_box_title_color_layout_4',
362 [
363 'label' => esc_html__( 'Title Color', 'betterdocs' ),
364 'type' => Controls_Manager::COLOR,
365 'selectors' => [
366 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab .faq-tab-title, .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-tab .faq-tab-title' => 'color:{{VALUE}};'
367 ]
368 ]
369 );
370
371 $this->add_control(
372 'faq_box_title_color_hover_layout_4',
373 [
374 'label' => esc_html__( 'Title Hover Color', 'betterdocs' ),
375 'type' => Controls_Manager::COLOR,
376 'selectors' => [
377 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab .faq-tab-title:hover' => 'color:{{VALUE}};',
378 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-tab .faq-tab-title:hover' => 'color:{{VALUE}};'
379 ]
380 ]
381 );
382
383 $this->add_group_control(
384 Group_Control_Typography::get_type(),
385 [
386 'name' => 'faq_box_title_typography_layout_4',
387 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab .faq-tab-title, .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-tab .faq-tab-title'
388 ]
389 );
390
391 $this->end_controls_section();
392
393 $this->start_controls_section(
394 'faq_box_style_section',
395 [
396 'label' => __( 'FAQ List', 'betterdocs' ),
397 'tab' => Controls_Manager::TAB_STYLE,
398 'condition' => [
399 'faq_layout_selection' => ['layout-1', 'layout-2', 'layout-3']
400 ]
401 ]
402 );
403
404 $this->add_responsive_control(
405 'faq_box_padding',
406 [
407 'label' => __( 'Padding', 'betterdocs' ),
408 'type' => Controls_Manager::DIMENSIONS,
409 'size_units' => [ 'px', '%', 'em' ],
410 'selectors' => [
411 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
412 ]
413 ]
414 );
415
416 $this->add_responsive_control(
417 'faq_box_margin',
418 [
419 'label' => __( 'Margin', 'betterdocs' ),
420 'type' => Controls_Manager::DIMENSIONS,
421 'size_units' => [ 'px', '%', 'em' ],
422 'selectors' => [
423 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
424 ]
425 ]
426 );
427
428 $this->add_group_control(
429 Group_Control_Typography::get_type(),
430 [
431 'name' => 'faq_box_typography',
432 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-post-name'
433 ]
434 );
435
436 $this->add_control(
437 'faq_box_term_title_color',
438 [
439 'label' => esc_html__( 'Color', 'betterdocs' ),
440 'type' => Controls_Manager::COLOR,
441 'selectors' => [
442 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-post-name' => 'color:{{VALUE}};'
443 ]
444 ]
445 );
446
447 $this->start_controls_tabs( 'faq_tabs' );
448
449 // Normal State Tab
450 $this->start_controls_tab(
451 'faq_box_normal',
452 [ 'label' => esc_html__( 'Normal', 'betterdocs' ) ]
453 );
454
455 $this->add_group_control(
456 Group_Control_Border::get_type(),
457 [
458 'name' => 'faq_box_border_normal',
459 'label' => esc_html__( 'Border', 'betterdocs' ),
460 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post'
461 ]
462 );
463
464 $this->add_group_control(
465 Group_Control_Background::get_type(),
466 [
467 'name' => 'faq_box_background_normal',
468 'label' => esc_html__( 'Background', 'betterdocs' ),
469 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post'
470 ]
471 );
472
473 $this->end_controls_tab();
474
475 // Hover State Tab
476 $this->start_controls_tab(
477 'faq_box_hover',
478 [ 'label' => esc_html__( 'Hover', 'betterdocs' ) ]
479 );
480
481 $this->add_group_control(
482 Group_Control_Border::get_type(),
483 [
484 'name' => 'faq_box_border_hover',
485 'label' => esc_html__( 'Border', 'betterdocs' ),
486 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post:hover'
487 ]
488 );
489
490 $this->add_group_control(
491 Group_Control_Background::get_type(),
492 [
493 'name' => 'faq_box_background_hover',
494 'label' => esc_html__( 'Background', 'betterdocs' ),
495 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post:hover'
496 ]
497 );
498
499 $this->end_controls_tab();
500
501 $this->end_controls_tabs();
502
503 $this->end_controls_section();
504
505 $this->start_controls_section(
506 'faq_box_style_section_layout_4',
507 [
508 'label' => __( 'FAQ List', 'betterdocs' ),
509 'tab' => Controls_Manager::TAB_STYLE,
510 'condition' => [
511 'faq_layout_selection' => ['layout-4']
512 ]
513 ]
514 );
515
516 $this->add_responsive_control(
517 'faq_box_padding_layout_4',
518 [
519 'label' => __( 'Padding', 'betterdocs' ),
520 'type' => Controls_Manager::DIMENSIONS,
521 'size_units' => [ 'px', '%', 'em' ],
522 'selectors' => [
523 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
524 ]
525 ]
526 );
527
528 $this->add_responsive_control(
529 'faq_box_margin_layout_4',
530 [
531 'label' => __( 'Margin', 'betterdocs' ),
532 'type' => Controls_Manager::DIMENSIONS,
533 'size_units' => [ 'px', '%', 'em' ],
534 'selectors' => [
535 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
536 ]
537 ]
538 );
539
540 $this->add_group_control(
541 Group_Control_Typography::get_type(),
542 [
543 'name' => 'faq_box_typography_layout_4',
544 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-post-name'
545 ]
546 );
547
548 $this->add_control(
549 'faq_box_term_title_color_layout_4',
550 [
551 'label' => esc_html__( 'Color', 'betterdocs' ),
552 'type' => Controls_Manager::COLOR,
553 'selectors' => [
554 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-post-name' => 'color:{{VALUE}};'
555 ]
556 ]
557 );
558
559 $this->start_controls_tabs( 'faq_tabs_layout_4' );
560
561 // Normal State Tab
562 $this->start_controls_tab(
563 'faq_box_normal_layout_4',
564 [ 'label' => esc_html__( 'Normal', 'betterdocs' ) ]
565 );
566
567 $this->add_group_control(
568 Group_Control_Border::get_type(),
569 [
570 'name' => 'faq_box_border_normal_layout_4',
571 'label' => esc_html__( 'Border', 'betterdocs' ),
572 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group'
573 ]
574 );
575
576 $this->add_group_control(
577 Group_Control_Background::get_type(),
578 [
579 'name' => 'faq_box_background_normal_layout_4',
580 'label' => esc_html__( 'Background', 'betterdocs' ),
581 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group'
582 ]
583 );
584
585 $this->end_controls_tab();
586
587 // Hover State Tab
588 $this->start_controls_tab(
589 'faq_box_hover_layout_4',
590 [ 'label' => esc_html__( 'Hover', 'betterdocs' ) ]
591 );
592
593 $this->add_group_control(
594 Group_Control_Border::get_type(),
595 [
596 'name' => 'faq_box_border_hover_layout_4',
597 'label' => esc_html__( 'Border', 'betterdocs' ),
598 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group:hover'
599 ]
600 );
601
602 $this->add_group_control(
603 Group_Control_Background::get_type(),
604 [
605 'name' => 'faq_box_background_hover_layout_4',
606 'label' => esc_html__( 'Background', 'betterdocs' ),
607 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group:hover'
608 ]
609 );
610
611 $this->end_controls_tab();
612
613 $this->end_controls_tabs();
614
615 $this->end_controls_section();
616
617 $this->start_controls_section(
618 'faq_box_content_section',
619 [
620 'label' => __( 'FAQ Content', 'betterdocs' ),
621 'tab' => Controls_Manager::TAB_STYLE,
622 'condition' => [
623 'faq_layout_selection' => ['layout-1', 'layout-2', 'layout-3']
624 ]
625 ]
626 );
627
628 $this->add_responsive_control(
629 'faq_box_content_section_padding',
630 [
631 'label' => __( 'Padding', 'betterdocs' ),
632 'type' => Controls_Manager::DIMENSIONS,
633 'size_units' => [ 'px', '%', 'em' ],
634 'selectors' => [
635 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-main-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
636 ]
637 ]
638 );
639
640 $this->add_responsive_control(
641 'faq_box_content_section_margin',
642 [
643 'label' => __( 'Margin', 'betterdocs' ),
644 'type' => Controls_Manager::DIMENSIONS,
645 'size_units' => [ 'px', '%', 'em' ],
646 'selectors' => [
647 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-main-content' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
648 ]
649 ]
650 );
651
652 $this->add_group_control(
653 Group_Control_Background::get_type(),
654 [
655 'name' => 'faq_box_content_section_background',
656 'label' => esc_html__( 'Background', 'betterdocs' ),
657 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-main-content'
658 ]
659 );
660
661 $this->add_group_control(
662 Group_Control_Typography::get_type(),
663 [
664 'name' => 'faq_box_content_section_typography',
665 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-main-content'
666 ]
667 );
668
669 $this->add_control(
670 'faq_box_content_section_color',
671 [
672 'label' => esc_html__( 'Color', 'betterdocs' ),
673 'type' => Controls_Manager::COLOR,
674 'selectors' => [
675 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-main-content' => 'color:{{VALUE}};'
676 ]
677 ]
678 );
679
680 $this->end_controls_section();
681
682 $this->start_controls_section(
683 'faq_box_content_section_layout_4',
684 [
685 'label' => __( 'FAQ Content', 'betterdocs' ),
686 'tab' => Controls_Manager::TAB_STYLE,
687 'condition' => [
688 'faq_layout_selection' => ['layout-4']
689 ]
690 ]
691 );
692
693 $this->add_responsive_control(
694 'faq_box_content_section_padding_layout_4',
695 [
696 'label' => __( 'Padding', 'betterdocs' ),
697 'type' => Controls_Manager::DIMENSIONS,
698 'size_units' => [ 'px', '%', 'em' ],
699 'selectors' => [
700 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group .betterdocs-faq-main-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
701 ]
702 ]
703 );
704
705 $this->add_responsive_control(
706 'faq_box_content_section_margin_layout_4',
707 [
708 'label' => __( 'Margin', 'betterdocs' ),
709 'type' => Controls_Manager::DIMENSIONS,
710 'size_units' => [ 'px', '%', 'em' ],
711 'selectors' => [
712 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group .betterdocs-faq-main-content' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};'
713 ]
714 ]
715 );
716
717 $this->add_group_control(
718 Group_Control_Background::get_type(),
719 [
720 'name' => 'faq_box_content_section_background_layout_4',
721 'label' => esc_html__( 'Background', 'betterdocs' ),
722 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group.active'
723 ]
724 );
725
726 $this->add_group_control(
727 Group_Control_Typography::get_type(),
728 [
729 'name' => 'faq_box_content_section_typography_layout_4',
730 'selector' => '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group .betterdocs-faq-main-content'
731 ]
732 );
733
734 $this->add_control(
735 'faq_box_content_section_color_layout_4',
736 [
737 'label' => esc_html__( 'Color', 'betterdocs' ),
738 'type' => Controls_Manager::COLOR,
739 'selectors' => [
740 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-list-content .betterdocs-faq-list li .betterdocs-faq-group .betterdocs-faq-main-content' => 'color:{{VALUE}};'
741 ]
742 ]
743 );
744
745 $this->end_controls_section();
746
747 $this->start_controls_section(
748 'faq_box_content_icon',
749 [
750 'label' => __( 'FAQ List Icon', 'betterdocs' ),
751 'tab' => Controls_Manager::TAB_STYLE,
752 'condition' => [
753 'faq_layout_selection' => ['layout-1', 'layout-2', 'layout-3']
754 ]
755 ]
756 );
757
758 $this->add_responsive_control(
759 'faq_box_content_icon_height',
760 [
761 'label' => esc_html__( 'Icon Height', 'betterdocs' ),
762 'type' => Controls_Manager::SLIDER,
763 'size_units' => [ 'px', '%', 'em' ],
764 'range' => [
765 'px' => [
766 'max' => 500
767 ]
768 ],
769 'selectors' => [
770 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconplus' => 'height:{{SIZE}}{{UNIT}}; max-height: {{SIZE}}{{UNIT}};',
771 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconminus' => 'height:{{SIZE}}{{UNIT}}; max-height: {{SIZE}}{{UNIT}};'
772 ]
773 ]
774 );
775
776 $this->add_responsive_control(
777 'faq_box_content_icon_width',
778 [
779 'label' => esc_html__( 'Icon Width', 'betterdocs' ),
780 'type' => Controls_Manager::SLIDER,
781 'size_units' => [ 'px', '%', 'em' ],
782 'range' => [
783 'px' => [
784 'max' => 500
785 ]
786 ],
787 'selectors' => [
788 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconplus' => 'width:{{SIZE}}{{UNIT}}; max-width: {{SIZE}}{{UNIT}};',
789 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconminus' => 'width:{{SIZE}}{{UNIT}}; max-width: {{SIZE}}{{UNIT}};'
790 ]
791 ]
792 );
793
794 $this->add_control(
795 'faq_box_content_icon_color',
796 [
797 'label' => esc_html__( 'Icon Color', 'betterdocs' ),
798 'type' => Controls_Manager::COLOR,
799 'selectors' => [
800 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconplus path' => 'fill:{{VALUE}} ! important;',
801 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconminus path' => 'fill:{{VALUE}} ! important;',
802 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconplus g' => 'stroke:{{VALUE}} ! important;',
803 '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-list > li .betterdocs-faq-group .betterdocs-faq-post .betterdocs-faq-iconminus g' => 'stroke:{{VALUE}} ! important;'
804 ]
805 ]
806 );
807
808 $this->end_controls_section();
809
810 $this->start_controls_section(
811 'faq_group_icon_layout_4',
812 [
813 'label' => __( 'FAQ Group Icon', 'betterdocs' ),
814 'tab' => Controls_Manager::TAB_STYLE,
815 'condition' => [
816 'faq_layout_selection' => ['layout-4']
817 ]
818 ]
819 );
820
821 $this->add_responsive_control(
822 'faq_box_content_icon_height_layout_4',
823 [
824 'label' => esc_html__( 'Icon Height', 'betterdocs' ),
825 'type' => Controls_Manager::SLIDER,
826 'size_units' => [ 'px', '%', 'em' ],
827 'range' => [
828 'px' => [
829 'max' => 500
830 ]
831 ],
832 'selectors' => [
833 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab .faq-tab-icon svg' => 'height:{{SIZE}}{{UNIT}}; max-height: {{SIZE}}{{UNIT}};',
834 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab img' => 'height:{{SIZE}}{{UNIT}}; max-height: {{SIZE}}{{UNIT}};',
835 ]
836 ]
837 );
838
839 $this->add_responsive_control(
840 'faq_box_content_icon_width_layout_4',
841 [
842 'label' => esc_html__( 'Icon Width', 'betterdocs' ),
843 'type' => Controls_Manager::SLIDER,
844 'size_units' => [ 'px', '%', 'em' ],
845 'range' => [
846 'px' => [
847 'max' => 500
848 ]
849 ],
850 'selectors' => [
851 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab .faq-tab-icon svg' => 'width:{{SIZE}}{{UNIT}}; max-width: {{SIZE}}{{UNIT}};',
852 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab img' => 'width:{{SIZE}}{{UNIT}}; max-width: {{SIZE}}{{UNIT}};'
853 ]
854 ]
855 );
856
857 $this->add_control(
858 'faq_box_content_icon_color_layout_4',
859 [
860 'label' => esc_html__( 'Icon Color', 'betterdocs' ),
861 'type' => Controls_Manager::COLOR,
862 'selectors' => [
863 '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab .faq-tab-icon svg g path' => 'fill:{{VALUE}} ! important;'
864 ]
865 ]
866 );
867
868 $this->end_controls_section();
869 }
870
871 protected function render_callback() {
872 $control_values = $this->get_settings_for_display();
873
874 $taxonomy = sanitize_key( $control_values['faq_taxonomy'] ?? 'betterdocs_faq_category' );
875
876 if ( $taxonomy === 'product_assignments' ) {
877 if ( ElementorPlugin::instance()->editor->is_edit_mode() ) {
878 // Editor preview: show all product FAQ terms so the layout can be styled.
879 betterdocs()->views->get(
880 'layouts/faq',
881 [
882 'enable' => true,
883 'have_posts' => true,
884 'layout' => $control_values['faq_layout_selection'],
885 'shortcode_attr' => [
886 'group_exclude' => '',
887 'groups' => '',
888 'class' => 'betterdocs-faq-' . $control_values['faq_layout_selection'],
889 'faq_heading' => $control_values['faq_layout_section'],
890 'faq_section_title_tag' => $control_values['faq_section_title_tag'],
891 'faq_group_title_tag' => $control_values['faq_group_title_tag'],
892 'faq_taxonomy' => 'betterdocs_product_faq_category',
893 ]
894 ]
895 );
896 $this->render_editor_script();
897 } else {
898 $this->render_product_assignments( $control_values['faq_layout_selection'] );
899 }
900
901 return;
902 }
903
904 if ( $taxonomy === 'betterdocs_product_faq_category' ) {
905 $specific_faqs = ! empty( $control_values['select_specific_product_faq'] ) ? implode( ',', $control_values['select_specific_product_faq'] ) : '';
906 $faqs_exclude = ! empty( $control_values['exclude_specific_product_faq'] ) ? implode( ',', $control_values['exclude_specific_product_faq'] ) : '';
907 } else {
908 $specific_faqs = ! empty( $control_values['select_specific_faq'] ) ? implode( ',', $control_values['select_specific_faq'] ) : '';
909 $faqs_exclude = ! empty( $control_values['exclude_specific_faq'] ) ? implode( ',', $control_values['exclude_specific_faq'] ) : '';
910 }
911
912 betterdocs()->views->get(
913 'layouts/faq',
914 [
915 'enable' => true,
916 'have_posts' => true,
917 'layout' => $control_values['faq_layout_selection'],
918 'shortcode_attr' => [
919 'group_exclude' => $faqs_exclude,
920 'class' => 'betterdocs-faq-' . $control_values['faq_layout_selection'],
921 'groups' => $specific_faqs,
922 'faq_heading' => $control_values['faq_layout_section'],
923 'faq_section_title_tag' => $control_values['faq_section_title_tag'],
924 'faq_group_title_tag' => $control_values['faq_group_title_tag'],
925 'faq_taxonomy' => $taxonomy
926 ]
927 ]
928 );
929
930 if ( ElementorPlugin::instance()->editor->is_edit_mode() ) {
931 $this->render_editor_script();
932 }
933 }
934
935 private function render_product_assignments( $layout ) {
936 if ( ! class_exists( 'WooCommerce' ) || ! is_product() ) {
937 return;
938 }
939
940 // In theme-builder templates, the widget can render outside the loop,
941 // so get_the_ID() can be 0 — fall back to the queried product.
942 $product_id = get_the_ID();
943 if ( ! $product_id ) {
944 $product_id = get_queried_object_id();
945 }
946 if ( ! $product_id ) {
947 return;
948 }
949
950 /** @var WooFAQRenderer $renderer */
951 $renderer = betterdocs()->container->get( WooFAQRenderer::class );
952
953 // This widget is the explicit placement; don't also inject into the tab/summary.
954 $renderer->suppress_auto_placement();
955 $renderer->render_for_product( $product_id, $layout );
956 }
957
958 protected function render_editor_script() {
959 ?>
960 <script>
961 jQuery(document).ready(function($) {
962 const $tabs = $(".betterdocs-faq-tab");
963 const $mobileTabs = $(".betterdocs-faq-list-wrapper .betterdocs-faq-tab");
964 const $contents = $(".betterdocs-faq-list-content");
965
966 $tabs.on("click", function () {
967 const termId = $(this).data("term-id");
968
969 // Remove active class from all tabs and hide all contents
970 $tabs.removeClass("active");
971 $contents.hide().removeClass("active");
972
973 // Reset all icons to default state
974 $(".betterdocs-faq-iconplus").show();
975 $(".betterdocs-faq-iconminus").hide();
976
977 // Add active class to the clicked tab and show the corresponding content
978 $(this).addClass("active");
979 $contents.filter(`[data-term-id="${termId}"]`).show().addClass("active");
980
981 // Toggle icons for the active tab
982 $(this).find(".betterdocs-faq-iconplus").hide();
983 $(this).find(".betterdocs-faq-iconminus").show();
984 });
985
986 // Trigger click on the first tab to show the first content by default
987 if ($tabs.length > 0) {
988 $tabs.first().trigger("click").addClass("active");
989
990 const $mobileFirstTab = $mobileTabs.first();
991 $mobileFirstTab.addClass("active");
992 $mobileFirstTab.find(".betterdocs-faq-iconplus").hide();
993 $mobileFirstTab.find(".betterdocs-faq-iconminus").show();
994 }
995
996 $('.betterdocs-faq-post').on('click', function(e) {
997 var current_node = $(this);
998 var active_list = $('.betterdocs-faq-group.active');
999
1000 if( ! current_node.parent().hasClass('active') ) {
1001 current_node.parent().addClass('active');
1002 current_node.children('svg').toggle();
1003 current_node.next().slideDown();
1004 }
1005
1006 for( let node of active_list ) {
1007 if( $(node).hasClass('active') ) {
1008 $(node).removeClass('active');
1009 $(node).children('.betterdocs-faq-post').children('svg').toggle();
1010 $(node).children('.betterdocs-faq-main-content').slideUp();
1011 }
1012 }
1013 });
1014
1015 $('.betterdocs-faq-post-layout-2').on('click', function(e) {
1016 var current_node = $(this);
1017
1018 if( ! current_node.parent().hasClass('active') ) {
1019 current_node.parent().addClass('active');
1020 current_node.children('.betterdocs-faq-post-layout-2-icon-group').children('svg').toggle();
1021 current_node.next().slideDown();
1022 } else {
1023 current_node.parent().removeClass('active');
1024 current_node.children('.betterdocs-faq-post-layout-2-icon-group').children('svg').toggle();
1025 current_node.next().slideUp();
1026 }
1027
1028 });
1029 });
1030 </script>
1031 <?php
1032 }
1033 }
1034