PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.8.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.8.0
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 / CategoryBox.php

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

280 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query,WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- core block query; meta/tax filtering required.
3 // phpcs:disable WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- block exposes user-driven exclusion controls.
4 namespace WPDeveloper\BetterDocs\Editors\BlockEditor\Blocks;
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10
11 use WPDeveloper\BetterDocs\Editors\BlockEditor\Block;
12 use WPDeveloper\BetterDocs\Traits\CategoryBox as CategoryBoxTraits;
13
14 class CategoryBox extends Block {
15 use CategoryBoxTraits;
16
17 protected $editor_styles = [
18 'betterdocs-fontawesome',
19 'betterdocs-blocks-editor',
20 'betterdocs-blocks-category-box'
21 ];
22
23 protected $frontend_styles = [
24 'betterdocs-fontawesome',
25 'betterdocs-blocks-category-box',
26 'betterdocs-docs'
27 ];
28
29 /**
30 * unique name of block
31 * @return string
32 */
33 public function get_name() {
34 return 'categorybox';
35 }
36
37 public function get_default_attributes() {
38 return [
39 'blockId' => '',
40 'categories' => [],
41 'selectKB' => '',
42 'includeCategories' => '',
43 'excludeCategories' => '',
44 'boxPerPage' => 9,
45 'orderBy' => 'doc_category_order',
46 'order' => 'asc',
47 'layout' => 'default',
48 'showIcon' => true,
49 'showTitle' => true,
50 'titleTag' => 'h2',
51 'showCount' => true,
52 'prefix' => '',
53 'suffix' => __( 'Docs', 'betterdocs' ),
54 'suffixSingular' => __( 'Doc', 'betterdocs' ),
55 'colRange' => 3,
56 'TABcolRange' => 2,
57 'MOBcolRange' => 1,
58 'layout4Col' => 4,
59 'showLastUpdatedTime' => true
60 ];
61 }
62
63 public function view_params() {
64 $attributes = &$this->attributes;
65
66 // Sanitize the layout attribute to prevent path traversal (LFI).
67 $attributes['layout'] = sanitize_file_name( $attributes['layout'] );
68
69 $terms_object = [
70 'taxonomy' => 'doc_category',
71 'order' => $attributes['order'],
72 'orderby' => $attributes['orderBy'],
73 'number' => isset( $attributes['boxPerPage'] ) ? $attributes['boxPerPage'] : 5,
74 'hide_empty' => true
75 ];
76
77 if ( 'doc_category_order' === $attributes['orderBy'] ) {
78 // Use betterdocs_order which handles fallback logic automatically
79 $terms_object['orderby'] = 'betterdocs_order';
80 }
81
82 $includes = $this->string_to_array( $attributes['includeCategories'] );
83 $excludes = $this->string_to_array( $attributes['excludeCategories'] );
84 $styles = '';
85
86 if ( ! empty( $includes ) ) {
87 $terms_object['include'] = array_diff( $includes, (array) $excludes );
88 }
89
90 if ( ! empty( $excludes ) ) {
91 $terms_object['exclude'] = $excludes;
92 }
93
94 $_wrapper_classes = [
95 'betterdocs-category-box-wrapper',
96 'betterdocs-blocks-grid',
97 'betterdocs-box-' . $attributes['layout']
98 ];
99
100 $_inner_wrapper_classes = [
101 'betterdocs-category-box-inner-wrapper',
102 'layout-flex',
103 $attributes['layout'] === 'default' ? 'layout-1' : $attributes['layout'],
104 'betterdocs-column-' . $attributes['colRange'],
105 'betterdocs-column-tablet-' . $attributes['TABcolRange'],
106 'betterdocs-column-mobile-' . $attributes['MOBcolRange']
107 ];
108
109 if ( $attributes['layout'] == 'layout-4' ) {
110 $_inner_wrapper_classes = [
111 'betterdocs-category-box-inner-wrapper',
112 'layout-4',
113 'docs-col-4',
114 'single-kb',
115 'betterdocs-categories-folder',
116 'layout-4',
117 'single-kb'
118 ];
119 $column = is_tax( 'doc_category' ) ? 3 : $attributes['layout4Col'];
120 $term_count = $this->get_terms_count_conditionally( $terms_object );
121 $reminder = $term_count % $column;
122 $styles .= "--column: $column;";
123 $styles .= "--count: $term_count;";
124 $styles .= "--reminder: $reminder;";
125 }
126
127 $wrapper_attr = [
128 'class' => $_wrapper_classes
129 ];
130
131 $inner_wrapper_attr = [
132 'class' => $_inner_wrapper_classes,
133 'style' => $styles,
134 'data-column_desktop' => $attributes['colRange'],
135 'data-column_tab' => $attributes['TABcolRange'],
136 'data-column_mobile' => $attributes['MOBcolRange']
137 ];
138
139 $default_multiple_kb = betterdocs()->settings->get( 'multiple_kb' );
140
141 $select_kb = isset( $attributes['selectKB'] ) ? $attributes['selectKB'] : '';
142 if ( is_string( $select_kb ) && $select_kb !== '' ) {
143 $decoded = json_decode( $select_kb, true );
144 $select_kb = is_array( $decoded ) ? $decoded : [];
145 }
146 $kb_slug = is_array( $select_kb ) && isset( $select_kb['value'] ) ? $select_kb['value'] : '';
147
148 if ( is_tax( 'knowledge_base' ) && $default_multiple_kb == 1 ) {
149 $object = get_queried_object();
150 $kb_slug = $object->slug;
151 }
152
153 if ( ! empty( $kb_slug ) && $default_multiple_kb == 1 ) {
154 $terms_object['meta_query'] = [
155 'relation' => 'OR',
156 [
157 'key' => 'doc_category_knowledge_base',
158 'value' => $kb_slug,
159 'compare' => 'LIKE'
160 ]
161 ];
162 }
163
164 $_params = [
165 'wrapper_attr' => $wrapper_attr,
166 'inner_wrapper_attr' => $inner_wrapper_attr,
167 'terms_query_args' => betterdocs()->query->terms_query( $terms_object ),
168 'widget_type' => 'category-box',
169 'multiple_knowledge_base' => ( $default_multiple_kb && ! empty( $kb_slug ) ) ? true : false,
170 'kb_slug' => $kb_slug,
171 'nested_subcategory' => false,
172 'show_header' => true,
173 'show_description' => false,
174 'title_tag' => $this->attributes['titleTag']
175 ];
176
177 if ( $attributes['layout'] === 'layout-2' ) {
178 $_params['count_prefix'] = '';
179 $_params['count_suffix'] = '';
180 $_params['count_suffix_singular'] = '';
181 }
182
183 if ( $attributes['layout'] == 'layout-4' ) {
184 $column = is_tax( 'doc_category' ) ? 3 : $attributes['layout4Col'];
185 $term_count = $this->get_terms_count_conditionally( $terms_object );
186 $reminder = $term_count % $column;
187 $_params['show_icon'] = $this->attributes['showIcon'];
188 $_params['show_count'] = $this->attributes['showCount'];
189 $_params['total_terms'] = $term_count;
190 $_params['reminder'] = $reminder;
191 $_params['category_icon'] = 'folder';
192 $_params['last_update'] = $this->attributes['showLastUpdatedTime'];
193 $_params['taxonomy'] = 'doc_category';
194 $_params['column'] = $column;
195 unset( $_params['inner_wrapper_attr']['data-column_desktop'] ); //not needed for layout 4
196 unset( $_params['inner_wrapper_attr']['data-column_tab'] ); // not needed for layout 4
197 unset( $_params['inner_wrapper_attr']['data-column_mobile'] ); // not needed for layout 4
198 }
199
200 return $_params;
201 }
202
203 public function render( $attributes, $content ) {
204 $_eligible = ( $attributes['layout'] == 'layout-2' || $attributes['layout'] == 'layout-3' || $attributes['layout'] == 'layout-4' );
205
206 if ( $attributes['layout'] == 'layout-4' ) {
207 add_filter( 'betterdocs_layout_filename', [ $this, 'change_to_layout_four' ], 15, 3 );
208 }
209
210 if ( $attributes['layout'] == 'layout-4' && is_tax( 'doc_category' ) ) {
211 add_filter( 'betterdocs_base_terms_args', [ $this, 'render_child_terms' ], 10, 1 );
212 add_filter( 'betterdocs_terms_query_args', [ $this, 'modify_terms_params' ], 10, 2 );
213 }
214
215 $this->add_filter( $_eligible );
216 $this->views( 'layouts/base' );
217 $this->remove_filter( $_eligible );
218
219 if ( $attributes['layout'] == 'layout-4' ) {
220 remove_filter( 'betterdocs_layout_filename', [ $this, 'change_to_layout_four' ], 15, 3 );
221 }
222
223 }
224
225 public function change_to_layout_four() {
226 return 'layout-4';
227 }
228
229 /**
230 * Modify Terms Params Based On Doc Category Page
231 *
232 * @param array $_query_args
233 * @param array $_origin_args
234 * @return bool|array
235 */
236 public function modify_terms_params( $_query_args, $_origin_args ) {
237 $current_category_id = get_queried_object() != null ? get_queried_object()->term_id : '';
238 $count = count( betterdocs()->query->get_all_child_term_ids( 'doc_category', $current_category_id ) );
239 if ( $count == 0 ) {
240 return false;
241 }
242 return $_query_args;
243 }
244
245 /**
246 * Render The Current Block Child Terms On Doc Category Page
247 *
248 * @param array $args
249 * @return array
250 */
251 public function render_child_terms( $args ) {
252 $current_category_id = get_queried_object() != null ? get_queried_object()->term_id : '';
253 $_nested_categories = betterdocs()->query->get_child_term_ids_by_parent_id( 'doc_category', $current_category_id );
254 if ( ! empty( $_nested_categories ) ) {
255 $args['include'] = $_nested_categories;
256 }
257 return $args;
258 }
259
260 /**
261 * Get the term count based on doc_category page or other page
262 *
263 * @param array $term_params
264 *
265 * @return int
266 */
267 public function get_terms_count_conditionally( $term_params ) {
268 $count = 0;
269
270 if ( is_tax( 'doc_category' ) ) {
271 $current_category_id = get_queried_object() != null ? get_queried_object()->term_id : '';
272 $count = count( betterdocs()->query->get_all_child_term_ids( 'doc_category', $current_category_id ) );
273 } else {
274 $count = count( get_terms( $term_params ) );
275 }
276
277 return $count;
278 }
279 }
280