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

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

995 lines 37.8 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;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit; // Exit if accessed directly
7 }
8
9 use Elementor\Controls_Manager;
10 use Elementor\Api as ElementorAPI;
11 use Elementor\Plugin as ElementorPlugin;
12 use WPDeveloper\BetterDocs\Core\Settings;
13 use WPDeveloper\BetterDocs\Utils\Enqueue;
14 use WPDeveloper\BetterDocs\Editors\Elementor\Helper;
15 use WPDeveloper\BetterDocs\Editors\Elementor\SingleDocs;
16 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\ToC;
17 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\DocAuthor;
18 use WPDeveloper\BetterDocs\Editors\Elementor\DocsArchive;
19 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Title;
20 use WPDeveloper\BetterDocs\Editors\Elementor\Tags\TitleTag;
21 use WPDeveloper\BetterDocs\Editors\Elementor\TemplateSource;
22 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Content;
23 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\DocDate;
24 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Sidebar;
25 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\DocShare;
26 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Feedback;
27 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Basic\FAQ;
28 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Reactions;
29 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Navigation;
30 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\CodeSnippet;
31 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\ArchiveList;
32 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\PrintButton;
33 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Breadcrumbs;
34 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\ReadingTime;
35 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\ArticleSummary;
36 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Basic\SearchForm;
37 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Basic\CategoryBox;
38 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Basic\CategoryGrid;
39 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Basic\CategorySlateLayout;
40 use WPDeveloper\BetterDocs\Editors\Elementor\Conditions\ArchiveCondition;
41 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\Tags;
42 use WPDeveloper\BetterDocs\Editors\Elementor\Widget\CategoryArchiveHeader;
43
44 class Elementor extends BaseEditor {
45 protected $is_elementor_active = false;
46 protected $is_elementor_pro_active = false;
47 protected static $is_templates_added = false;
48
49 /**
50 * Elementor plugin class
51 * @var ElementorPlugin
52 */
53 protected $elementor;
54
55 /**
56 * Elementor Helper class
57 * @var Helper
58 */
59 protected $helper;
60
61 public function __construct( Settings $settings, Enqueue $enqueue, Helper $helper ) {
62 parent::__construct( $settings, $enqueue );
63
64 $this->helper = $helper;
65 $this->is_elementor_active = betterdocs()->helper->is_plugin_active( 'elementor/elementor.php' );
66 $this->is_elementor_pro_active = betterdocs()->helper->is_plugin_active( 'elementor-pro/elementor-pro.php' );
67
68 if ( ! $this->is_elementor_active || ! class_exists( ElementorPlugin::class ) ) {
69 return;
70 }
71
72 $this->elementor = ElementorPlugin::instance();
73 }
74
75 public function init() {
76 if ( ! $this->is_elementor_active || $this->elementor == null ) {
77 return;
78 }
79
80 add_action( 'wp_enqueue_scripts', [$this, 'enqueue_scripts'] );
81
82 add_action( 'elementor/elements/categories_registered', [$this, 'register_widget_category'] );
83 add_action( 'elementor/widgets/register', [$this, 'register_basic_widgets'] );
84
85 add_action( 'elementor/editor/before_enqueue_scripts', [$this, 'editor_enqueue_scripts'] );
86 add_filter( 'elementor/editor/localize_settings', [$this, 'promote_pro_elements'] );
87
88 add_filter( 'elementor/theme/need_override_location', [$this, 'override_location'], 10, 2 );
89 add_action( 'betterdocs/elementor/widgets/query', [$this, 'betterdocs_query'], 10, 2 );
90 add_filter( 'betterdocs_base_terms_args', [$this, 'handle_editor_mode_terms_args'], 10, 1 );
91
92 if ( $this->is_elementor_pro_active ) {
93 add_action( 'elementor/dynamic_tags/register', [$this, 'register_basic_tags'] );
94 add_action( 'elementor/widgets/register', [$this, 'register_theme_builder_widgets'] );
95 add_action( 'elementor/theme/register_conditions', [$this, 'register_conditions'] );
96
97 //(Conflict Fix)Solves the issue with plugin - Sticky Header Effects for Elementor(Plugin)
98 if ( ! did_action( 'elementor/documents/register' ) ) {
99 add_action( 'elementor/documents/register', [$this, 'register_documents'] );
100 } else {
101 $this->elementor->documents->register_document_type( 'docs', SingleDocs::get_class_full_name() );
102 $this->elementor->documents->register_document_type( 'doc-archive', DocsArchive::get_class_full_name() );
103 }
104 }
105
106 $this->betterdocs_init();
107 }
108
109 public function editor_enqueue_scripts() {
110 betterdocs()->assets->enqueue( 'betterdocs-el-icon', 'elementor/css/betterdocs-el-icon.css' );
111 }
112
113 public function register_documents( $documents_manager ) {
114 $documents_manager->register_document_type( 'docs', SingleDocs::get_class_full_name() );
115 $documents_manager->register_document_type( 'doc-archive', DocsArchive::get_class_full_name() );
116 }
117
118 public function override_location( $need_override_location, $location ) {
119 if ( is_singular( ['docs'] ) && 'single' === $location ) {
120 $need_override_location = true;
121 }
122
123 return $need_override_location;
124 }
125
126 /**
127 * Query Controls
128 *
129 */
130 public function betterdocs_query( $wb, $taxonomy ) {
131 $wb->start_controls_section(
132 'eael_section_post__filters',
133 [
134 'label' => __( 'Query', 'betterdocs' )
135 ]
136 );
137
138 $default_multiple_kb = $this->multiple_kb_status();
139
140 if ( $default_multiple_kb && $taxonomy != 'knowledge_base' ) {
141 $multiple_kb_terms = $this->get_kb_terms( true, false );
142 $default_slug = count( $multiple_kb_terms ) > 0 ? array_keys( $multiple_kb_terms )[0] : '';
143
144 $wb->add_control(
145 'selected_knowledge_base',
146 [
147 'label' => __( 'Knowledge Bases', 'betterdocs' ),
148 'label_block' => true,
149 'type' => Controls_Manager::SELECT2,
150 'options' => $multiple_kb_terms,
151 'multiple' => false,
152 'default' => '',
153 'select2options' => [
154 'placeholder' => __( 'All Knowledge Base', 'betterdocs' ),
155 'allowClear' => true
156 ]
157 ]
158 );
159 }
160
161 if ( $wb->get_name() === 'betterdocs-category-grid' ) {
162 $wb->add_control(
163 'grid_query_heading',
164 [
165 'label' => __( 'Category Grid', 'betterdocs' ),
166 'type' => Controls_Manager::HEADING
167 ]
168 );
169 }
170
171 $wb->add_control(
172 'include',
173 [
174 'label' => __( 'Include', 'betterdocs' ),
175 'label_block' => true,
176 'type' => Controls_Manager::SELECT2,
177 'options' => $this->helper->get_terms( $taxonomy, 'term_id' ),
178 'multiple' => true,
179 'default' => []
180 ]
181 );
182
183 $wb->add_control(
184 'exclude',
185 [
186 'label' => __( 'Exclude', 'betterdocs' ),
187 'type' => Controls_Manager::SELECT2,
188 'options' => $this->helper->get_terms( $taxonomy, 'term_id' ),
189 'label_block' => true,
190 'post_type' => '',
191 'multiple' => true
192 ]
193 );
194
195 if ( $wb->get_name() === 'betterdocs-category-grid' ) {
196 $wb->add_control(
197 'grid_per_page',
198 [
199 'label' => __( 'Grid Per Page', 'betterdocs' ),
200 'type' => Controls_Manager::NUMBER,
201 'default' => '8'
202 ]
203 );
204 } else if ( $wb->get_name() !== 'betterdocs-sidebar' ) {
205 $wb->add_control(
206 'box_per_page',
207 [
208 'label' => $wb->get_name() == 'betterdocs-tab-view-list'
209 ? __( 'Tabs Per Page', 'betterdocs' )
210 : __( 'Box Per Page', 'betterdocs' ),
211 'type' => Controls_Manager::NUMBER,
212 'default' => '8'
213 ]
214 );
215 }
216
217 $wb->add_control(
218 'offset',
219 [
220 'label' => __( 'Offset', 'betterdocs' ),
221 'type' => Controls_Manager::NUMBER,
222 'default' => '0'
223 ]
224 );
225
226 // difference between betterdocs-sidebar and betterdocs-category-grid is the default order
227 if ( $wb->get_name() === 'betterdocs-sidebar' ) {
228 $wb->add_control(
229 'orderby',
230 [
231 'label' => __( 'Terms Order By', 'betterdocs' ),
232 'type' => Controls_Manager::SELECT,
233 'options' => [
234 'none' => __( 'No order', 'betterdocs' ),
235 'name' => __( 'Name', 'betterdocs' ),
236 'slug' => __( 'Slug', 'betterdocs' ),
237 'term_group' => __( 'Term Group', 'betterdocs' ),
238 'term_id' => __( 'Term ID', 'betterdocs' ),
239 'id' => __( 'ID', 'betterdocs' ),
240 'description' => __( 'Description', 'betterdocs' ),
241 'parent' => __( 'Parent', 'betterdocs' ),
242 'betterdocs_order' => __( 'BetterDocs Order', 'betterdocs' )
243 ],
244 'default' => $this->settings->get( 'terms_orderby', 'betterdocs_order' )
245 ]
246 );
247
248 $wb->add_control(
249 'order',
250 [
251 'label' => __( 'Terms Order', 'betterdocs' ),
252 'type' => Controls_Manager::SELECT,
253 'options' => [
254 'ASC' => 'Ascending',
255 'DESC' => 'Descending'
256 ],
257 'default' => $this->settings->get( 'terms_order', 'ASC' ),
258 'condition' => [
259 'orderby!' => 'betterdocs_order'
260 ]
261
262 ]
263 );
264
265 $wb->add_control(
266 'post_orderby',
267 [
268 'label' => __( 'Docs Order By', 'betterdocs' ),
269 'type' => Controls_Manager::SELECT,
270 'options' => $this->helper->orderby_options(),
271 'default' => 'date'
272 ]
273 );
274
275 $wb->add_control(
276 'post_order',
277 [
278 'label' => __( 'Docs Order', 'betterdocs' ),
279 'type' => Controls_Manager::SELECT,
280 'options' => [
281 'asc' => 'Ascending',
282 'desc' => 'Descending'
283 ],
284 'default' => 'asc',
285 'condition' => [
286 'post_orderby!' => 'betterdocs_order'
287 ]
288 ]
289 );
290 } else {
291 $wb->add_control(
292 'orderby',
293 [
294 'label' => __( 'Order By', 'betterdocs' ),
295 'type' => Controls_Manager::SELECT,
296 'options' => [
297 'none' => __( 'No order', 'betterdocs' ),
298 'name' => __( 'Name', 'betterdocs' ),
299 'slug' => __( 'Slug', 'betterdocs' ),
300 'term_group' => __( 'Term Group', 'betterdocs' ),
301 'term_id' => __( 'Term ID', 'betterdocs' ),
302 'id' => __( 'ID', 'betterdocs' ),
303 'description' => __( 'Description', 'betterdocs' ),
304 'parent' => __( 'Parent', 'betterdocs' ),
305 'betterdocs_order' => __( 'BetterDocs Order', 'betterdocs' )
306 ],
307 'default' => 'name'
308 ]
309 );
310
311 $wb->add_control(
312 'order',
313 [
314 'label' => __( 'Order', 'betterdocs' ),
315 'type' => Controls_Manager::SELECT,
316 'options' => [
317 'ASC' => 'Ascending',
318 'DESC' => 'Descending'
319 ],
320 'default' => 'ASC',
321 'condition' => [
322 'orderby!' => 'betterdocs_order'
323 ]
324
325 ]
326 );
327 }
328
329 if ( $wb->get_name() === 'betterdocs-category-grid' || $wb->get_name() === 'betterdocs-category-slate-layout' ) {
330 $wb->add_control(
331 'grid_posts_query_heading',
332 [
333 'label' => __( 'Grid List Posts', 'betterdocs' ),
334 'type' => Controls_Manager::HEADING,
335 'separator' => 'before'
336 ]
337 );
338
339 $wb->add_control(
340 'post_per_page',
341 [
342 'label' => __( 'Post Per Page', 'betterdocs' ),
343 'type' => Controls_Manager::NUMBER,
344 'default' => '6'
345 ]
346 );
347
348 $wb->add_control(
349 'post_orderby',
350 [
351 'label' => __( 'Order By', 'betterdocs' ),
352 'type' => Controls_Manager::SELECT,
353 'options' => $this->helper->orderby_options(),
354 'default' => 'betterdocs_order'
355 ]
356 );
357
358 $wb->add_control(
359 'post_order',
360 [
361 'label' => __( 'Order', 'betterdocs' ),
362 'type' => Controls_Manager::SELECT,
363 'options' => [
364 'asc' => 'Ascending',
365 'desc' => 'Descending'
366 ],
367 'default' => 'asc',
368 'condition' => [
369 'post_orderby!' => 'betterdocs_order'
370 ]
371 ]
372 );
373 }
374
375 if ( $wb->get_name() === 'betterdocs-category-grid' ) {
376 $wb->add_control(
377 'nested_subcategory',
378 [
379 'label' => __( 'Enable Nested Subcategory', 'betterdocs' ),
380 'type' => Controls_Manager::SWITCHER,
381 'label_on' => __( 'Yes', 'betterdocs' ),
382 'label_off' => __( 'No', 'betterdocs' ),
383 'return_value' => 'true',
384 'default' => false
385 ]
386 );
387
388 $wb->add_control(
389 'subcategory_per_grid',
390 [
391 'label' => __( 'Subcategory Per Grid', 'betterdocs' ),
392 'type' => Controls_Manager::NUMBER,
393 'default' => '2',
394 'condition' => [
395 'nested_subcategory' => 'true'
396 ]
397 ]
398 );
399
400 $wb->add_control(
401 'post_per_subcat',
402 [
403 'label' => __( 'Post Per Subcategory', 'betterdocs' ),
404 'type' => Controls_Manager::NUMBER,
405 'default' => '6',
406 'condition' => [
407 'nested_subcategory' => 'true'
408 ]
409 ]
410 );
411 }
412
413 if ( $wb->get_name() === 'betterdocs-category-box' ) {
414 $wb->add_control(
415 'nested_subcategory',
416 [
417 'label' => __( 'Nested Subcategory', 'betterdocs' ),
418 'type' => Controls_Manager::SWITCHER,
419 'label_on' => __( 'Yes', 'betterdocs' ),
420 'label_off' => __( 'No', 'betterdocs' ),
421 'return_value' => 'true',
422 'default' => 'true',
423 ]
424 );
425
426 $wb->add_control(
427 'show_dynamic_categories_in_doc_category_template',
428 [
429 'label' => __( 'Show Categories Dynamically', 'betterdocs' ),
430 'type' => Controls_Manager::SWITCHER,
431 'label_on' => __( 'Yes', 'betterdocs' ),
432 'label_off' => __( 'No', 'betterdocs' ),
433 'return_value' => 'true',
434 'default' => 'true',
435 ]
436 );
437
438 $wb->add_control(
439 'show_dynamic_categories_in_doc_category_template_description',
440 [
441 'type' => Controls_Manager::RAW_HTML,
442 'raw' => __( "Note: This option is only applicable for BetterDocs Category Archive page. If enabled, this will show the Categories dynamically in your BetterDocs Category Archive page.", 'betterdocs' ),
443 'content_classes' => 'elementor-panel-alert elementor-panel-alert-info'
444 ]
445 );
446 }
447
448 if ( $wb->get_name() === 'betterdocs-sidebar' ) {
449 $wb->add_control(
450 'nested_subcategory',
451 [
452 'label' => __( 'Nested Subcategory', 'betterdocs' ),
453 'type' => Controls_Manager::SWITCHER,
454 'label_on' => __( 'Yes', 'betterdocs' ),
455 'label_off' => __( 'No', 'betterdocs' ),
456 'return_value' => 'true',
457 'default' => ( $this->settings->get( 'archive_nested_subcategory' ) == 1 ) ? 'true' : ''
458 ]
459 );
460 }
461
462 if ( $wb->get_name() === 'betterdocs-tab-view-list' ) {
463 $wb->add_control(
464 'tab_posts_query_heading',
465 [
466 'label' => __( 'Tab List Posts', 'betterdocs' ),
467 'type' => Controls_Manager::HEADING,
468 'separator' => 'before'
469 ]
470 );
471
472 $wb->add_control(
473 'tab_box_per_tabs',
474 [
475 'label' => __( 'Box Per Tabs', 'betterdocs' ),
476 'type' => Controls_Manager::NUMBER,
477 'default' => '10'
478 ]
479 );
480
481 $wb->add_control(
482 'post_per_tab',
483 [
484 'label' => __( 'Posts Per Tab', 'betterdocs' ),
485 'type' => Controls_Manager::NUMBER,
486 'default' => '10'
487 ]
488 );
489
490 $wb->add_control(
491 'tab_list_posts_orderby',
492 [
493 'label' => __( 'Posts Order By', 'betterdocs' ),
494 'type' => Controls_Manager::SELECT,
495 'options' => [
496 'name' => __( 'Name', 'betterdocs' ),
497 'slug' => __( 'Slug', 'betterdocs' ),
498 'term_group' => __( 'Term Group', 'betterdocs' ),
499 'term_id' => __( 'Term ID', 'betterdocs' ),
500 'id' => __( 'ID', 'betterdocs' ),
501 'description' => __( 'Description', 'betterdocs' ),
502 'parent' => __( 'Parent', 'betterdocs' ),
503 'betterdocs_order' => __( 'BetterDocs Order', 'betterdocs' )
504 ],
505 'default' => 'name'
506 ]
507 );
508
509 $wb->add_control(
510 'tab_list_order',
511 [
512 'label' => __( 'Order', 'betterdocs' ),
513 'type' => Controls_Manager::SELECT,
514 'options' => [
515 'ASC' => 'Ascending',
516 'DESC' => 'Descending'
517 ],
518 'default' => 'ASC'
519
520 ]
521 );
522
523 $wb->add_control(
524 'nested_subcategory_tab_list',
525 [
526 'label' => __( 'Nested Subcategory', 'betterdocs' ),
527 'type' => Controls_Manager::SWITCHER,
528 'label_on' => __( 'Yes', 'betterdocs' ),
529 'label_off' => __( 'No', 'betterdocs' ),
530 'return_value' => 'true',
531 'default' => 'true'
532 ]
533 );
534
535 $wb->add_control(
536 'nested_posts_per_page',
537 [
538 'label' => __( 'Posts Per Page', 'betterdocs' ),
539 'type' => Controls_Manager::NUMBER,
540 'default' => '-1',
541 'condition' => [
542 'nested_subcategory_tab_list' => 'true'
543 ]
544 ]
545 );
546
547 $wb->add_control(
548 'nested_sub_cat_order',
549 [
550 'label' => __( 'Nested Subcategory Order', 'betterdocs' ),
551 'type' => Controls_Manager::SELECT,
552 'options' => [
553 'ASC' => 'Ascending',
554 'DESC' => 'Descending'
555 ],
556 'default' => 'ASC',
557 'condition' => [
558 'nested_subcategory_tab_list' => 'true'
559 ]
560 ]
561 );
562
563 $wb->add_control(
564 'nested_sub_cat_orderby',
565 [
566 'label' => __( 'Nested Subcategory Order By', 'betterdocs' ),
567 'type' => Controls_Manager::SELECT,
568 'options' => [
569 'none' => __( 'No order', 'betterdocs' ),
570 'name' => __( 'Name', 'betterdocs' ),
571 'slug' => __( 'Slug', 'betterdocs' ),
572 'term_group' => __( 'Term Group', 'betterdocs' ),
573 'term_id' => __( 'Term ID', 'betterdocs' ),
574 'id' => __( 'ID', 'betterdocs' ),
575 'description' => __( 'Description', 'betterdocs' ),
576 'parent' => __( 'Parent', 'betterdocs' ),
577 'betterdocs_order' => __( 'BetterDocs Order', 'betterdocs' )
578 ],
579 'default' => 'name',
580 'condition' => [
581 'nested_subcategory_tab_list' => 'true'
582 ]
583 ]
584 );
585 }
586
587 $wb->end_controls_section();
588 }
589
590 public function multiple_kb_status() {
591 if ( $this->settings->get( 'multiple_kb' ) == 1 ) {
592 return 'true';
593 }
594
595 return '';
596 }
597
598 public function get_kb_terms( $prettify = false, $term_id = true ) {
599 $args = [
600 'taxonomy' => 'knowledge_base',
601 'hide_empty' => true,
602 'parent' => 0
603 ];
604
605 $terms_query_args = betterdocs()->query->terms_query( $args );
606 $terms = betterdocs()->query->get_terms( $terms_query_args );
607
608 if ( is_wp_error( $terms ) ) {
609 return [];
610 }
611
612 if ( $prettify ) {
613 $pretty_taxonomies = [];
614
615 foreach ( $terms as $term ) {
616 $pretty_taxonomies[$term_id ? $term->term_id : $term->slug] = $term->name;
617 }
618
619 return $pretty_taxonomies;
620 }
621
622 return $terms;
623 }
624
625 public function register_basic_tags( $module ) {
626 $module->register( new TitleTag );
627 }
628
629 /**
630 * Handle editor mode for terms query args
631 *
632 * @param array $args Terms query arguments
633 * @return array Modified arguments
634 */
635 public function handle_editor_mode_terms_args( $args ) {
636 // Only modify if we're in Elementor editor mode
637 if ( $this->elementor && $this->elementor->editor->is_edit_mode() ) {
638 // Show empty categories in editor mode for better preview
639 $args['hide_empty'] = false;
640 }
641
642 return $args;
643 }
644
645 public function register_basic_widgets( $widgets_manager ) {
646 foreach ( $this->basic_widget_lists() as $value ) {
647 $widgets_manager->register( new $value );
648 }
649 }
650
651 /**
652 *
653 * Mange all widget for single docs
654 *
655 * @return string[]
656 * @since 1.3.0
657 */
658 private function basic_widget_lists() {
659 $widget_arr = [
660 'betterdocs-elementor-search-form' => SearchForm::class,
661 'betterdocs-elementor-category-grid' => CategoryGrid::class,
662 'betterdocs-elementor-category-box' => CategoryBox::class,
663 'betterdocs-elementor-category-slate' => CategorySlateLayout::class,
664 'betterdocs-faq-widget' => FAQ::class,
665 'betterdocs-code-snippet' => CodeSnippet::class
666 ];
667
668 return $widget_arr;
669 }
670
671 public function register_widget_category( $elements_manager ) {
672 $elements_manager->add_category( 'betterdocs-elements', [
673 'title' => __( 'BetterDocs', 'betterdocs' ),
674 'icon' => 'font'
675 ], 1 );
676 }
677
678 public function promote_pro_elements( $config ) {
679 if ( $this->is_pro_active ) {
680 return $config;
681 }
682
683 $promotion_widgets = [];
684
685 if ( isset( $config['promotionWidgets'] ) ) {
686 $promotion_widgets = $config['promotionWidgets'];
687 }
688
689 $combine_array = array_merge( $promotion_widgets, [
690 [
691 'name' => 'betterdocs-multiple-kb',
692 'title' => __( 'BetterDocs Multiple KB', 'betterdocs' ),
693 'icon' => 'betterdocs-icon-category-box',
694 'categories' => '["docs-archive"]'
695 ]
696 ] );
697
698 $config['promotionWidgets'] = $combine_array;
699
700 return $config;
701 }
702
703 public function is_templates() {
704 if ( $this->is_elementor_active && $this->is_elementor_pro_active ) {
705 $post_id = get_the_ID();
706 if ( $this->elementor->editor->is_edit_mode() || (
707 get_post_meta( $post_id, '_elementor_template_type', true )
708 && $this->elementor->documents->get( $post_id )->is_built_with_elementor()
709 ) ) {
710 return true;
711 }
712 }
713
714 return null;
715 }
716
717 public function enqueue_scripts() {
718 $assets = betterdocs()->assets;
719
720 /**
721 * Widget's CSS
722 */
723 $assets->register( 'betterdocs-el-category-grid', 'elementor/css/category-grid.css' );
724 $assets->register( 'betterdocs-el-category-box', 'elementor/css/category-box.css' );
725 $assets->register( 'betterdocs-el-articles-list', 'elementor/css/articles-list.css' );
726 $assets->register( 'betterdocs-el-navigation', 'elementor/css/navigation.css' );
727 $assets->register( 'betterdocs-code-snippet', 'public/css/code-snippet.css' );
728
729 /**
730 * Widget's JS
731 */
732 $assets->register( 'betterdocs-el-category-grid', 'elementor/js/category-grid.js', ['jquery', 'betterdocs-category-toggler'] );
733 $assets->register( 'betterdocs-code-snippet', 'public/js/code-snippet.js', ['jquery'] );
734
735 /**
736 * Localize This In Order To Know If This Block Is Arriving From Betterdocs Templates Or Not
737 */
738 betterdocs()->assets->localize( 'betterdocs-el-category-grid', 'betterdocsCategoryGridConfig', [
739 'is_betterdocs_templates' => betterdocs()->helper->is_templates() ? true : false
740 ] );
741
742 if ( betterdocs()->helper->is_el_templates() == true ) {
743 $assets->enqueue( 'betterdocs-elementor-editor', 'elementor/css/betterdocs-el-edit.css' );
744
745 if ( ! $this->is_pro_active ) {
746 $assets->enqueue( 'betterdocs-elementor-editor', 'elementor/js/editor.js', ['jquery'] );
747 }
748 }
749
750 do_action( 'betterdocs_elementor_enqueue_scripts', $this );
751 }
752
753 public function register_theme_builder_widgets( $widgets_manager ) {
754 foreach ( $this->builder_widget_list() as $value ) {
755 if ( class_exists( $value ) ) {
756 $widgets_manager->register( new $value );
757 }
758 }
759 }
760
761 /**
762 * Mange all widget for single docs
763 *
764 * @return array<string>
765 * @since 1.3.0
766 */
767 public function builder_widget_list() {
768 return apply_filters( 'betterdocs_elementor_pro_widgets', [
769 'betterdocs-elementor-toc' => ToC::class,
770 'betterdocs-elementor-title' => Title::class,
771 'betterdocs-elementor-sidebar' => Sidebar::class,
772 'betterdocs-elementor-content' => Content::class,
773 'betterdocs-elementor-doc-date' => DocDate::class,
774 'betterdocs-elementor-doc-share' => DocShare::class,
775 'betterdocs-elementor-feedback' => Feedback::class,
776 'betterdocs-elementor-reactions' => Reactions::class,
777 'betterdocs-article-summary' => ArticleSummary::class,
778 'betterdocs-elementor-navigation' => Navigation::class,
779 'betterdocs-elementor-breadcrumbs' => Breadcrumbs::class,
780 'betterdocs-elementor-category-archive-list' => ArchiveList::class,
781 'betteredocs-elementor-reading-time' => ReadingTime::class,
782 'betterdocs-print-button' => PrintButton::class,
783 'betterdocs-elementor-doc-author' => DocAuthor::class,
784 'betteredocs-elementor-doc-category-archive-header' => CategoryArchiveHeader::class,
785 'betterdocs-elementor-tags' => Tags::class
786 ] );
787 }
788
789 /**
790 * @param \ElementorPro\Modules\ThemeBuilder\Classes\Conditions_Manager $conditions_manager
791 */
792 public function register_conditions( $conditions_manager ) {
793 $betterdocs_condition = betterdocs()->container->get( ArchiveCondition::class );
794 $conditions_manager->get_condition( 'general' )->register_sub_condition( $betterdocs_condition );
795 }
796
797 public function betterdocs_init() {
798 add_action( 'elementor/init', [$this, 'register_template_instance'], 20 );
799
800 static $is_done = false;
801 if ( defined( 'Elementor\Api::LIBRARY_OPTION_KEY' ) && ! $is_done ) {
802 $is_done = true;
803 add_filter( 'option_' . ElementorAPI::LIBRARY_OPTION_KEY, [$this, 'prepend_categories'] );
804 }
805
806 add_action( 'elementor/ajax/register_actions', [$this, 'modified_ajax_action'], 20 );
807
808 if ( defined( 'ELEMENTOR_VERSION' ) && version_compare( ELEMENTOR_VERSION, '3.10.0', '>=' ) && ! self::$is_templates_added ) {
809 self::$is_templates_added = true;
810 add_filter( 'http_response', [$this, 'http_response_modify_for_bd_template'], 10, 3 );
811 } elseif ( defined( 'ELEMENTOR_VERSION' ) && version_compare( ELEMENTOR_VERSION, '3.5.0', '>=' ) && ! self::$is_templates_added ) {
812 self::$is_templates_added = true;
813 add_filter( 'option_' . ElementorAPI::LIBRARY_OPTION_KEY, [$this, 'added_bd_template'] );
814 }
815 }
816
817 /**
818 * Added BetterDocs template with Elementor core templates list
819 *
820 * @param $response
821 * @param $parsed_args
822 * @param $url
823 *
824 * @return mixed
825 * @since 2.3.5
826 */
827 public function http_response_modify_for_bd_template( $response, $parsed_args, $url ) {
828 if ( $url === \Elementor\TemplateLibrary\Source_Remote::API_TEMPLATES_URL ) {
829 $templates_list = json_decode( wp_remote_retrieve_body( $response ), true );
830 $bd_templates = $this->get_templates();
831
832 if ( ! empty( $bd_templates ) ) {
833 $templates_list = array_merge( (array) $templates_list, (array) $bd_templates );
834 }
835
836 $response['body'] = json_encode( $templates_list );
837 }
838
839 return $response;
840 }
841
842 public function register_template_instance() {
843 $this->elementor->templates_manager->register_source( TemplateSource::class );
844 }
845
846 public function prepend_categories( $library_data ) {
847 $categories = $this->template_categories();
848 if ( ! empty( $categories ) ) {
849 $library_data['types_data']['block']['categories'] = array_merge(
850 $categories,
851 isset( $library_data['types_data']['block']['categories'] ) ? $library_data['types_data']['block']['categories'] : []
852 );
853 }
854 return $library_data;
855 }
856
857 public function template_categories() {
858 return [
859 'Single Docs',
860 'Docs Archive'
861 ];
862 }
863
864 /**
865 * Added BetterDocs template with Elementor core templates list
866 *
867 * added_template
868 *
869 * @param $templates_list array elementor template list
870 *
871 * @return array
872 * @since 2.0.7
873 *
874 */
875 public function added_bd_template( array $templates_list ) {
876 $templates = $this->get_templates();
877
878 if ( ! empty( $templates ) ) {
879 $templates_list['templates'] = array_merge( $templates_list['templates'], $templates );
880 }
881
882 return $templates_list;
883 }
884
885 /**
886 * get_templates
887 *
888 * Get Better docs template list and cache this list
889 *
890 * @return array|mixed
891 * @since 2.0.0
892 */
893 public function get_templates() {
894 $_cache_key = 'betterdocs_template_library_' . betterdocs()->version;
895 $source = new TemplateSource;
896 $local_ids = array_column( $source->get_local_templates(), 'template_id' );
897 $templates = get_transient( $_cache_key );
898
899 if ( ! $templates ) {
900 // Only cache remote templates — local templates are always appended fresh below
901 $all_templates = $source->get_items();
902 $remote_only = array_values( array_filter( $all_templates, function ( $t ) use ( $local_ids ) {
903 return ! in_array( $t['template_id'], $local_ids, true );
904 } ) );
905
906 if ( ! empty( $remote_only ) ) {
907 $remote_only = array_map( function ( $template ) {
908 $template['id'] = $template['template_id'];
909 $template['tmpl_created'] = $template['date'];
910 $template['tags'] = json_encode( $template['tags'] );
911 $template['is_pro'] = $template['isPro'];
912 $template['access_level'] = $template['accessLevel'];
913 $template['popularity_index'] = $template['popularityIndex'];
914 $template['trend_index'] = $template['trendIndex'];
915 $template['has_page_settings'] = $template['hasPageSettings'];
916
917 return $template;
918 }, $remote_only );
919
920 set_transient( $_cache_key, $remote_only, WEEK_IN_SECONDS );
921 $templates = $remote_only;
922 } else {
923 $templates = [];
924 }
925 } else {
926 // Strip any local templates that may have been cached in a previous version
927 $templates = array_values( array_filter( $templates, function ( $t ) use ( $local_ids ) {
928 $id = isset( $t['template_id'] ) ? $t['template_id'] : ( isset( $t['id'] ) ? $t['id'] : '' );
929 return ! in_array( $id, $local_ids, true );
930 } ) );
931 }
932
933 // Always append local templates fresh so they are never stale-cached
934 $local_templates = array_map( function ( $template ) {
935 $template['id'] = $template['template_id'];
936 $template['tmpl_created'] = $template['date'];
937 $template['tags'] = json_encode( $template['tags'] );
938 $template['is_pro'] = $template['isPro'];
939 $template['access_level'] = $template['accessLevel'];
940 $template['popularity_index'] = $template['popularityIndex'];
941 $template['trend_index'] = $template['trendIndex'];
942 $template['has_page_settings'] = $template['hasPageSettings'];
943
944 return $template;
945 }, $source->get_local_templates() );
946
947 return array_merge( $templates, $local_templates );
948 }
949
950 public function modified_ajax_action( $ajax ) {
951 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Elementor's own ajax handler verifies nonce upstream.
952 if ( ! isset( $_REQUEST['actions'] ) ) {
953 return;
954 }
955
956 // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Elementor's ajax handler verifies nonce; raw JSON is structure-validated below.
957 $raw_actions = wp_unslash( $_REQUEST['actions'] );
958 $actions = json_decode( $raw_actions, true );
959 if ( ! is_array( $actions ) ) {
960 return;
961 }
962 $data = false;
963
964 foreach ( $actions as $id => $action_data ) {
965 if ( ! isset( $action_data['get_template_data'] ) ) {
966 $data = $action_data;
967 }
968 }
969
970 if ( ! $data ) {
971 return;
972 }
973
974 if ( ! isset( $data['data'] ) ) {
975 return;
976 }
977
978 $data = $data['data'];
979
980 if ( empty( $data['template_id'] ) ) {
981 return;
982 }
983
984 if ( false === strpos( $data['template_id'], 'betterdocs_' ) ) {
985 return;
986 }
987 $ajax->register_ajax_action( 'get_template_data', [$this, 'get_template_data'] );
988 }
989
990 public function get_template_data( $args ) {
991 $source = new TemplateSource;
992 return $source->get_data( $args );
993 }
994 }
995