PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.2
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.2
4.9.2 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 All 200 releases
← All changes | includes/Editors/Elementor/Widget/Basic/FAQ.php +216 -32 4.5.04.9.2 View file →
@@ -15,8 +15,9 @@
15 15 use WPDeveloper\BetterDocs\Editors\Elementor\Helper;
16 16 use Elementor\Group_Control_Border;
17 17 use Elementor\Group_Control_Typography;
18 18 use WPDeveloper\BetterDocs\Editors\Elementor\BaseWidget;
19 +use WPDeveloper\BetterDocs\FrontEnd\WooProductFAQ as WooFAQRenderer;
19 20
20 21 class FAQ extends BaseWidget {
21 22
22 23 public function get_name() {
@@ -70,8 +71,34 @@
70 71 'label_block' => true
71 72 ]
72 73 );
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 +
74 101 $this->add_control(
75 102 'faq_layout_section',
76 103 [
77 104 'label' => __( 'FAQ Section', 'betterdocs' ),
@@ -114,9 +141,9 @@
114 141 'h5' => __( 'H5', 'betterdocs' ),
115 142 'h6' => __( 'H6', 'betterdocs' )
116 143 ],
117 144 'condition' => [
118 - 'faq_layout_selection' => ['layout-1', 'layout-2', 'layout-3']
145 + 'faq_layout_selection' => [ 'layout-1', 'layout-2', 'layout-3' ]
119 146 ]
120 147 ]
121 148 );
122 149
@@ -121,39 +148,80 @@
121 148 );
122 149
123 150 $terms = betterdocs()->container->get( Helper::class )->get_faq_terms();
124 151
125 - $this->add_control(
126 - 'select_specific_faq',
127 - [
128 - 'label' => __( 'Include FAQ Groups', 'betterdocs' ),
129 - 'label_block' => true,
130 - 'type' => Controls_Manager::SELECT2,
131 - 'options' => $terms,
132 - 'multiple' => true,
133 - 'default' => '',
134 - 'select2options' => [
135 - 'placeholder' => __( 'Include FAQ Groups', 'betterdocs' ),
136 - 'allowClear' => true
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 + ]
137 204 ]
138 - ]
139 - );
205 + );
140 206
141 - $this->add_control(
142 - 'exclude_specific_faq',
143 - [
144 - 'label' => __( 'Exclude FAQ Groups', 'betterdocs' ),
145 - 'label_block' => true,
146 - 'type' => Controls_Manager::SELECT2,
147 - 'options' => $terms,
148 - 'multiple' => true,
149 - 'default' => '',
150 - 'select2options' => [
151 - 'placeholder' => __( 'Exclude FAQ Groups', 'betterdocs' ),
152 - 'allowClear' => true
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 + ]
153 221 ]
154 - ]
155 - );
222 + );
223 + }
156 224
157 225 $this->end_controls_section();
158 226
159 227 /**
@@ -267,8 +335,30 @@
267 335 ]
268 336 ]
269 337 );
270 338
339 + $this->add_control(
340 + 'faq_box_title_background_color',
341 + [
342 + 'label' => esc_html__( 'Background Color', 'betterdocs' ),
343 + 'type' => Controls_Manager::COLOR,
344 + 'selectors' => [
345 + '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-title' => 'background-color:{{VALUE}};'
346 + ]
347 + ]
348 + );
349 +
350 + $this->add_control(
351 + 'faq_box_title_background_color_hover',
352 + [
353 + 'label' => esc_html__( 'Background Hover Color', 'betterdocs' ),
354 + 'type' => Controls_Manager::COLOR,
355 + 'selectors' => [
356 + '{{WRAPPER}} .betterdocs-faq-wrapper .betterdocs-faq-inner-wrapper .betterdocs-faq-title:hover' => 'background-color:{{VALUE}};'
357 + ]
358 + ]
359 + );
360 +
271 361 $this->add_group_control(
272 362 Group_Control_Typography::get_type(),
273 363 [
274 364 'name' => 'faq_box_title_typography',
@@ -311,8 +401,44 @@
311 401 ]
312 402 ]
313 403 );
314 404
405 + $this->add_control(
406 + 'faq_box_title_background_color_layout_4',
407 + [
408 + 'label' => esc_html__( 'Background Color', 'betterdocs' ),
409 + 'type' => Controls_Manager::COLOR,
410 + 'selectors' => [
411 + '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab' => 'background-color:{{VALUE}};',
412 + '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-tab' => 'background-color:{{VALUE}};'
413 + ]
414 + ]
415 + );
416 +
417 + $this->add_control(
418 + 'faq_box_title_background_color_hover_layout_4',
419 + [
420 + 'label' => esc_html__( 'Background Hover Color', 'betterdocs' ),
421 + 'type' => Controls_Manager::COLOR,
422 + 'selectors' => [
423 + '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab:hover' => 'background-color:{{VALUE}};',
424 + '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-tab:hover' => 'background-color:{{VALUE}};'
425 + ]
426 + ]
427 + );
428 +
429 + $this->add_control(
430 + 'faq_box_title_background_color_active_layout_4',
431 + [
432 + 'label' => esc_html__( 'Active Background Color', 'betterdocs' ),
433 + 'type' => Controls_Manager::COLOR,
434 + 'selectors' => [
435 + '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-tab-wrapper .betterdocs-faq-tab.active' => 'background-color:{{VALUE}};',
436 + '{{WRAPPER}} .betterdocs-faq-wrapper.betterdocs-faq-layout-4 .betterdocs-faq-inner-wrapper .betterdocs-faq-list-wrapper .betterdocs-faq-tab.active' => 'background-color:{{VALUE}};'
437 + ]
438 + ]
439 + );
440 +
315 441 $this->add_group_control(
316 442 Group_Control_Typography::get_type(),
317 443 [
318 444 'name' => 'faq_box_title_typography_layout_4',
@@ -802,12 +928,46 @@
802 928
803 929 protected function render_callback() {
804 930 $control_values = $this->get_settings_for_display();
805 931
806 - $specific_faqs = ! empty( $control_values['select_specific_faq'] ) ? implode( ',', $control_values['select_specific_faq'] ) : '';
932 + $taxonomy = sanitize_key( $control_values['faq_taxonomy'] ?? 'betterdocs_faq_category' );
807 933
808 - $faqs_exclude = ! empty( $control_values['exclude_specific_faq'] ) ? implode( ',', $control_values['exclude_specific_faq'] ) : '';
934 + if ( $taxonomy === 'product_assignments' ) {
935 + if ( ElementorPlugin::instance()->editor->is_edit_mode() ) {
936 + // Editor preview: show all product FAQ terms so the layout can be styled.
937 + betterdocs()->views->get(
938 + 'layouts/faq',
939 + [
940 + 'enable' => true,
941 + 'have_posts' => true,
942 + 'layout' => $control_values['faq_layout_selection'],
943 + 'shortcode_attr' => [
944 + 'group_exclude' => '',
945 + 'groups' => '',
946 + 'class' => 'betterdocs-faq-' . $control_values['faq_layout_selection'],
947 + 'faq_heading' => $control_values['faq_layout_section'],
948 + 'faq_section_title_tag' => $control_values['faq_section_title_tag'],
949 + 'faq_group_title_tag' => $control_values['faq_group_title_tag'],
950 + 'faq_taxonomy' => 'betterdocs_product_faq_category',
951 + ]
952 + ]
953 + );
954 + $this->render_editor_script();
955 + } else {
956 + $this->render_product_assignments( $control_values['faq_layout_selection'] );
957 + }
809 958
959 + return;
960 + }
961 +
962 + if ( $taxonomy === 'betterdocs_product_faq_category' ) {
963 + $specific_faqs = ! empty( $control_values['select_specific_product_faq'] ) ? implode( ',', $control_values['select_specific_product_faq'] ) : '';
964 + $faqs_exclude = ! empty( $control_values['exclude_specific_product_faq'] ) ? implode( ',', $control_values['exclude_specific_product_faq'] ) : '';
965 + } else {
966 + $specific_faqs = ! empty( $control_values['select_specific_faq'] ) ? implode( ',', $control_values['select_specific_faq'] ) : '';
967 + $faqs_exclude = ! empty( $control_values['exclude_specific_faq'] ) ? implode( ',', $control_values['exclude_specific_faq'] ) : '';
968 + }
969 +
810 970 betterdocs()->views->get(
811 971 'layouts/faq',
812 972 [
813 973 'enable' => true,
@@ -818,9 +978,10 @@
818 978 'class' => 'betterdocs-faq-' . $control_values['faq_layout_selection'],
819 979 'groups' => $specific_faqs,
820 980 'faq_heading' => $control_values['faq_layout_section'],
821 981 'faq_section_title_tag' => $control_values['faq_section_title_tag'],
822 - 'faq_group_title_tag' => $control_values['faq_group_title_tag']
982 + 'faq_group_title_tag' => $control_values['faq_group_title_tag'],
983 + 'faq_taxonomy' => $taxonomy
823 984 ]
824 985 ]
825 986 );
826 987
@@ -826,8 +987,31 @@
826 987
827 988 if ( ElementorPlugin::instance()->editor->is_edit_mode() ) {
828 989 $this->render_editor_script();
829 990 }
991 + }
992 +
993 + private function render_product_assignments( $layout ) {
994 + if ( ! class_exists( 'WooCommerce' ) || ! is_product() ) {
995 + return;
996 + }
997 +
998 + // In theme-builder templates, the widget can render outside the loop,
999 + // so get_the_ID() can be 0 — fall back to the queried product.
1000 + $product_id = get_the_ID();
1001 + if ( ! $product_id ) {
1002 + $product_id = get_queried_object_id();
1003 + }
1004 + if ( ! $product_id ) {
1005 + return;
1006 + }
1007 +
1008 + /** @var WooFAQRenderer $renderer */
1009 + $renderer = betterdocs()->container->get( WooFAQRenderer::class );
1010 +
1011 + // This widget is the explicit placement; don't also inject into the tab/summary.
1012 + $renderer->suppress_auto_placement();
1013 + $renderer->render_for_product( $product_id, $layout );
830 1014 }
831 1015
832 1016 protected function render_editor_script() {
833 1017 ?>