PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.1
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.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 / BlockEditor / Blocks / FAQ.php

FAQ.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.1, at includes/Editors/BlockEditor/Blocks/FAQ.php

186 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WPDeveloper\BetterDocs\Editors\BlockEditor\Blocks;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8
9 use WPDeveloper\BetterDocs\Editors\BlockEditor\Block;
10 use WPDeveloper\BetterDocs\FrontEnd\WooProductFAQ as WooFAQRenderer;
11
12 class FAQ extends Block {
13 protected $editor_scripts = [
14 'betterdocs-faq',
15 'betterdocs-blocks-editor'
16 ];
17
18 protected $editor_styles = [
19 'betterdocs-faq',
20 'betterdocs-blocks-editor'
21 ];
22
23 protected $frontend_styles = [
24 'betterdocs-faq'
25 ];
26
27 protected $frontend_scripts = [
28 'betterdocs-faq'
29 ];
30
31 /**
32 * unique name of block
33 * @return string
34 */
35 public function get_name() {
36 return 'faq';
37 }
38
39 public function get_default_attributes() {
40 return [
41 'blockId' => '',
42 'resOption' => 'Desktop',
43 'blockRoot' => 'better_docs',
44 'blockMeta' => null,
45 'faqLayout' => 'layout-1',
46 'faqSectionText' => 'Frequently Asked Questions',
47 'faqSectionTitleTag' => 'h2',
48 'faqGroupTitleTag' => 'h3',
49 'faqSectionTitleColor' => null,
50 // JSON string of `[{value:int, label:string}]`; a bare id array (`[5]`) is also accepted since 4.9.0.
51 'includeFaqGroup' => '',
52 'excludeFaqGroup' => '',
53 'faqGroupTitleColor' => null,
54 'faqGroupTitleHoverColor' => null,
55 'faqListColor' => null,
56 'faqContentColor' => null,
57 'faqIconColor' => null,
58 'faqGroupTitleTypography' => null,
59 'faqPerPage' => 9,
60
61 'showButtonIcon' => true,
62 'buttonColor' => '#528ffe',
63 'faqTaxonomy' => 'betterdocs_faq_category'
64 ];
65 }
66
67 public function render( $attributes, $content ) {
68 if ( ( $this->attributes['faqTaxonomy'] ?? '' ) === 'product_assignments' ) {
69 $this->render_product_assignments();
70 return;
71 }
72
73 add_filter( 'betterdocs_header_layout_sequence', [ $this, 'header_sequence' ], 10, 4 );
74 $this->views( 'layouts/faq' );
75 remove_filter( 'betterdocs_header_layout_sequence', [ $this, 'header_sequence' ], 10 );
76 }
77
78 private function render_product_assignments() {
79 if ( ! class_exists( 'WooCommerce' ) || ! is_product() ) {
80 return;
81 }
82
83 // In FSE templates, top-level blocks render outside the loop, so
84 // get_the_ID() can be 0 — fall back to the queried product.
85 $product_id = get_the_ID();
86 if ( ! $product_id ) {
87 $product_id = get_queried_object_id();
88 }
89 if ( ! $product_id ) {
90 return;
91 }
92
93 /** @var WooFAQRenderer $renderer */
94 $renderer = betterdocs()->container->get( WooFAQRenderer::class );
95
96 // This block is the explicit placement; don't also inject into the tab/summary.
97 $renderer->suppress_auto_placement();
98 $renderer->render_for_product( $product_id, $this->attributes['faqLayout'] ?? null );
99 }
100
101 /**
102 * Flatten a group-selection attribute into a comma separated list of term ids.
103 *
104 * The attribute is a JSON string. The editor writes
105 * `[{"value":5,"label":"Install"}]`; REST clients and other programmatic
106 * writers commonly write the bare form `[5]`. Both are accepted — before
107 * 4.9.0 the bare form flattened to an empty string, which
108 * `Query::faq_terms_query_args()` reads as "no filter", so every group
109 * rendered and the block warned on every view.
110 *
111 * @since 4.9.0 Bare ids are accepted alongside `{ value, label }` objects;
112 * ids are cast with `absint()` and de-duplicated.
113 *
114 * @param mixed $json JSON encoded list of term ids or `{ value, label }` objects.
115 *
116 * @return string Comma separated term ids, or '' when there is nothing to filter by.
117 */
118 public function get_groups_ids( $json ) {
119 $data = is_string( $json ) ? json_decode( $json, true ) : $json;
120 $ids = array_filter( self::normalize_id_list( $data ), 'is_numeric' );
121 $ids = array_unique( array_map( 'absint', $ids ) );
122
123 return implode( ',', $ids );
124 }
125
126 public function view_params() {
127 $attributes = &$this->attributes;
128
129 // Sanitize the layout attribute to prevent path traversal (LFI).
130 $attributes['faqLayout'] = sanitize_file_name( $attributes['faqLayout'] );
131 $exclude = $this->get_groups_ids( $attributes['excludeFaqGroup'] );
132 $include = $this->get_groups_ids( $attributes['includeFaqGroup'] );
133 $taxonomy = sanitize_key( $attributes['faqTaxonomy'] ?? 'betterdocs_faq_category' );
134
135 $terms_query = betterdocs()->query->faq_terms_query_args( $include, $exclude, [], $taxonomy );
136
137 return wp_parse_args(
138 [
139 'enable' => true,
140 'have_posts' => true,
141 'widget' => $this,
142 'layout' => $attributes['faqLayout'],
143 'terms_query_args' => $terms_query,
144 'shortcode_attr' => [
145 'group_exclude' => $exclude,
146 'class' => 'betterdocs-faq-' . $attributes['faqLayout'] . ' ' . $attributes['blockId'],
147 'groups' => $include,
148 'is_gutenberg' => true,
149 'faq_heading' => $attributes['faqSectionText'],
150 'faq_section_title_tag' => $attributes['faqSectionTitleTag'],
151 'faq_group_title_tag' => $attributes['faqGroupTitleTag'],
152 'faq_section_title_color' => $attributes['faqSectionTitleColor'],
153 'include_faq_group' => $this->string_to_array( $attributes['includeFaqGroup'] ),
154 'exclude_faq_group' => $this->string_to_array( $attributes['excludeFaqGroup'] ),
155 'faq_group_title_color' => $attributes['faqGroupTitleColor'],
156 'faq_group_title_hover_color' => $attributes['faqGroupTitleHoverColor'],
157 'faq_list_color' => $attributes['faqListColor'],
158 'faq_content_color' => $attributes['faqContentColor'],
159 'faq_icon_color' => $attributes['faqIconColor'],
160 'faq_group_title_typography' => $attributes['faqGroupTitleTypography'],
161 'faq_per_page' => $attributes['faqPerPage'],
162 'show_button_icon' => $attributes['showButtonIcon'],
163 'button_icon_position' => $attributes['faqLayout'] == 'layout-1' || $attributes['faqLayout'] == 'layout-3' || $attributes['faqLayout'] == 'layout-4' ? 'after' : 'before',
164 'button_color' => $attributes['buttonColor'],
165 'faq_taxonomy' => $taxonomy,
166 // Per-block order; empty falls back to the global FAQ order.
167 'order' => isset( $attributes['faqOrder'] ) ? $attributes['faqOrder'] : ''
168 ]
169
170 ]
171 );
172 }
173
174 public function header_sequence( $_layout_sequence, $layout, $widget_type, $_defined_vars ) {
175 $_new_layout_sequence = [
176 [
177 'class' => 'betterdocs-category-title-counts',
178 'sequence' => [ 'category_title', 'category_counts' ]
179 ],
180 'category_description'
181 ];
182
183 return $_new_layout_sequence;
184 }
185 }
186