PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 1.3.4
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v1.3.4
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 / class-betterdocs-docs-post-type.php

class-betterdocs-docs-post-type.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 1.3.4, at includes/class-betterdocs-docs-post-type.php

597 lines 23.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Register docs post type and taxonomies.
4 *
5 * @link https://wpdeveloper.net
6 * @since 1.0.0
7 *
8 * @package BetterDocs
9 * @subpackage BetterDocs/includes
10 */
11
12 use function YoastSEO_Vendor\GuzzleHttp\json_decode;
13
14 /**
15 * Register docs post type and taxonomies class.
16 *
17 *
18 * Also maintains the unique identifier of this plugin as well as the current
19 * version of the plugin.
20 *
21 * @since 1.0.0
22 * @package BetterDocs
23 * @subpackage BetterDocs/includes
24 * @author WPDeveloper <support@wpdeveloper.net>
25 */
26 class BetterDocs_Docs_Post_Type {
27 public static $post_type = 'docs';
28 public static $menu_position = 5;
29 public static $category = 'doc_category';
30 public static $tag = 'doc_tag';
31 public static $docs_archive;
32 public static $docs_slug;
33 public static $cat_slug;
34
35 /**
36 *
37 * Initialize the class and start calling our hooks and filters
38 *
39 * @since 1.0.0
40 *
41 */
42 public static function init() {
43 self::$docs_archive = self::get_docs_archive();
44 self::$docs_slug = self::get_docs_slug();
45 self::$cat_slug = self::docs_category_slug();
46 add_action('init', array(__CLASS__, 'register_post'));
47 add_filter('rest_api_allowed_post_types', array(__CLASS__, 'rest_api_allowed_post_types'));
48 add_action('admin_head', array(__CLASS__, 'admin_order_terms'));
49 $alphabetically_order_term = BetterDocs_DB::get_settings('alphabetically_order_term');
50 if ( $alphabetically_order_term != 1 ) {
51 add_action('init', array(__CLASS__, 'front_end_order_terms'));
52 }
53 // doc category taxonomy media upload hooks
54 add_action('doc_category_add_form_fields', array(__CLASS__, 'add_doc_category_meta'), 10, 2);
55 add_action('doc_category_edit_form_fields', array(__CLASS__, 'update_doc_category_meta'), 10, 2);
56 add_action('created_doc_category', array(__CLASS__, 'save_doc_category_meta'), 10, 2);
57 add_action('edited_doc_category', array(__CLASS__, 'updated_doc_category_meta'), 10, 2);
58 add_action('admin_enqueue_scripts', array(__CLASS__, 'load_media'));
59 add_action('admin_footer', array(__CLASS__, 'add_script'));
60 }
61
62 public static function get_docs_slug() {
63
64 $builtin_doc_page = BetterDocs_DB::get_settings('builtin_doc_page');
65 $docs_slug = BetterDocs_DB::get_settings('docs_slug');
66 $docs_page = BetterDocs_DB::get_settings('docs_page');
67
68 // $disable_root_slug = BetterDocs_DB::get_settings('disable_root_slug');
69 // if ( $disable_root_slug == 1 ) {
70 // $docs_post_slug = '';
71 // }
72
73 if ( $builtin_doc_page == 1 && $docs_slug ) {
74
75 $docs_post_slug = $docs_slug;
76
77 } elseif ( $builtin_doc_page != 1 && $docs_page ) {
78
79 $post_info = get_post( $docs_page );
80 $docs_post_slug = $post_info->post_name;
81
82 } else {
83
84 $docs_post_slug = 'docs';
85
86 }
87
88 return $docs_post_slug;
89 }
90
91 public static function get_docs_archive() {
92
93 $builtin_doc_page = BetterDocs_DB::get_settings('builtin_doc_page');
94 $docs_slug = BetterDocs_DB::get_settings('docs_slug');
95 $docs_page = BetterDocs_DB::get_settings('docs_page');
96
97 if ( $builtin_doc_page == 1 && $docs_slug ) {
98
99 $docs_post_slug = $docs_slug;
100
101 } elseif ( $builtin_doc_page != 1 && $docs_page ) {
102
103 $post_info = get_post( $docs_page );
104 $docs_post_slug = $post_info->post_name;
105
106 } else {
107
108 $docs_post_slug = 'docs';
109
110 }
111
112 return $docs_post_slug;
113 }
114
115 public static function docs_category_slug() {
116
117 $category_slug = BetterDocs_DB::get_settings('category_slug');
118 if( empty ( $category_slug ) ) {
119 $category_slug = 'docs-category';
120 }
121 return $category_slug;
122 }
123
124 /**
125 *
126 * Register post type and taxonomies
127 *
128 * @since 1.0.0
129 *
130 */
131 public static function register_post() {
132
133 $singular_name = BetterDocs_DB::get_settings('breadcrumb_doc_title');
134
135
136 /**
137 * Register category taxonomy
138 */
139 $category_labels = array(
140 'name' => esc_html__('Docs Categories', 'betterdocs'),
141 'singular_name' => esc_html__('Docs Category', 'betterdocs'),
142 'all_items' => esc_html__('Docs Categories', 'betterdocs'),
143 'parent_item' => esc_html__('Parent Docs Category', 'betterdocs'),
144 'parent_item_colon'=> esc_html__('Parent Docs Category:', 'betterdocs'),
145 'edit_item' => esc_html__('Edit Category', 'betterdocs'),
146 'update_item' => esc_html__('Update Category', 'betterdocs'),
147 'add_new_item' => esc_html__('Add New Docs Category', 'betterdocs'),
148 'new_item_name' => esc_html__('New Docs Name', 'betterdocs'),
149 'menu_name' => esc_html__('Categories', 'betterdocs')
150 );
151
152 $category_args = array(
153 'hierarchical' => true,
154 'public' => true,
155 'labels' => $category_labels,
156 'show_ui' => true,
157 'show_admin_column' => true,
158 'query_var' => true,
159 'show_in_rest' => true,
160 'has_archive' => true,
161 );
162
163 $category_args['rewrite'] = apply_filters( 'betterdocs_category_rewrite', array( 'slug' => self::$cat_slug, 'with_front' => false ));
164
165 register_taxonomy( self::$category, array( self::$post_type ), $category_args );
166
167
168 /**
169 * Register post type
170 */
171 $labels = array(
172 'name' => ($singular_name) ? $singular_name : 'Docs',
173 'singular_name' => ($singular_name) ? $singular_name : 'Docs',
174 'menu_name' => esc_html__('BetterDocs', 'betterdocs'),
175 'name_admin_bar' => esc_html__('Docs', 'betterdocs'),
176 'add_new' => esc_html__('Add New', 'betterdocs'),
177 'add_new_item' => esc_html__('Add New Docs', 'betterdocs'),
178 'new_item' => esc_html__('New Docs', 'betterdocs'),
179 'edit_item' => esc_html__('Edit Docs', 'betterdocs'),
180 'view_item' => esc_html__('View Docs', 'betterdocs'),
181 'all_items' => esc_html__('All Docs', 'betterdocs'),
182 'search_items' => esc_html__('Search Docs', 'betterdocs'),
183 'parent_item_colorn' => null,
184 'not_found' => esc_html__('No docs found', 'betterdocs'),
185 'not_found_in_trash' => esc_html__('No docs found in trash', 'betterdocs')
186 );
187
188 $betterdocs_articles_caps = apply_filters( 'betterdocs_articles_caps', 'edit_posts', 'article_roles' );
189
190 $args = array(
191 'labels' => $labels,
192 'description' => esc_html__('Add new doc from here', 'betterdocs'),
193 'public' => true,
194 'public_queryable' => true,
195 'exclude_from_search' => false,
196 'show_ui' => true,
197 'show_in_menu' => false,
198 'show_in_admin_bar' => $betterdocs_articles_caps,
199 'query_var' => true,
200 'capability_type' => 'post',
201 'hierarchical' => true,
202 'menu_position' => self::$menu_position,
203 'show_in_rest' => true,
204 'menu_icon' => BETTERDOCS_ADMIN_URL . '/assets/img/betterdocs-icon-white.svg', 100,
205 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'author', 'revisions', 'custom-fields', 'comments')
206 );
207
208 $builtin_doc_page = BetterDocs_DB::get_settings('builtin_doc_page');
209
210 if ( $builtin_doc_page == 'off' ) {
211
212 $args['has_archive'] = false;
213
214 } else {
215
216 $args['has_archive'] = self::$docs_archive;
217
218 }
219
220
221 $args['rewrite'] = apply_filters('betterdocs_docs_rewrite', array( 'slug' => self::$docs_archive, 'with_front' => false ));
222
223 register_post_type(self::$post_type, $args);
224
225 flush_rewrite_rules();
226
227 /**
228 * Register tag taxonomy
229 */
230 $tags_labels = array(
231 'name' => esc_html__('Docs Tags', 'betterdocs'),
232 'singular_name' => esc_html__('Tag', 'betterdocs'),
233 'search_items' => esc_html__('Search Tags', 'betterdocs'),
234 'popular_items' => esc_html__('Popular Tags', 'betterdocs'),
235 'all_items' => esc_html__('All Tags', 'betterdocs'),
236 'parent_item' => null,
237 'parent_item_colon' => null,
238 'edit_item' => esc_html__('Edit Tag', 'betterdocs'),
239 'update_item' => esc_html__('Update Tag', 'betterdocs'),
240 'add_new_item' => esc_html__('Add New Tag', 'betterdocs'),
241 'new_item_name' => esc_html__('New Tag Name', 'betterdocs'),
242 'separate_items_with_commas' => esc_html__('Separate tags with commas', 'betterdocs'),
243 'add_or_remove_items' => esc_html__('Add or remove tags', 'betterdocs'),
244 'choose_from_most_used' => esc_html__('Choose from the most used tags', 'betterdocs'),
245 'menu_name' => esc_html__('Tags', 'betterdocs'),
246 );
247
248 $tag_args = array(
249 'hierarchical' => true,
250 'labels' => $tags_labels,
251 'show_ui' => true,
252 'update_count_callback' => '_update_post_term_count',
253 'show_admin_column' => true,
254 'query_var' => true,
255 'show_in_rest' => true
256 );
257
258 $tag_slug = BetterDocs_DB::get_settings('tag_slug');
259
260 if ($tag_slug) {
261 $tag_args['rewrite'] = array('slug' => $tag_slug, 'with_front' => false);
262 } else {
263 $tag_args['rewrite'] = array('slug' => 'docs-tag', 'with_front' => false);
264 }
265
266 register_taxonomy(self::$tag, array(self::$post_type), $tag_args);
267
268 }
269
270 /**
271 * Added post type to allowed for rest api
272 *
273 * @param array $post_types Get the docs post types.
274 * @return array
275 *
276 * @since 1.0.0
277 *
278 */
279 public static function rest_api_allowed_post_types($post_types) {
280 $post_types[] = self::$post_type;
281
282 return $post_types;
283 }
284
285 /**
286 * load media for taxonomy category image
287 *
288 * @since 1.0.0
289 */
290 public static function load_media() {
291 wp_enqueue_media();
292 }
293
294 /**
295 * Default the taxonomy's terms' order if it's not set.
296 *
297 * @param string $tax_slug The taxonomy's slug.
298 */
299 public static function default_term_order($tax_slug) {
300 $terms = get_terms($tax_slug, array('hide_empty' => false));
301 $order = self::get_max_taxonomy_order($tax_slug);
302 foreach ($terms as $term) {
303 if (!get_term_meta($term->term_id, 'doc_category_order', true)) {
304 update_term_meta($term->term_id, 'doc_category_order', $order);
305 $order++;
306 }
307 }
308 }
309
310 /**
311 * Order the terms on the admin side.
312 */
313 public static function admin_order_terms() {
314 $screen = function_exists('get_current_screen') ? get_current_screen() : '';
315 if (in_array($screen->id, array('toplevel_page_betterdocs-admin', 'betterdocs_page_betterdocs-settings'))) {
316 self::default_term_order('doc_category');
317 }
318
319 if (!isset($_GET['orderby']) && !empty($screen) && !empty($screen->base) && $screen->base === 'edit-tags' && $screen->taxonomy === 'doc_category') {
320 self::default_term_order($screen->taxonomy);
321 add_filter('terms_clauses', array(__CLASS__, 'set_tax_order'), 10, 3);
322 }
323 }
324
325 /**
326 * Get the maximum doc_category_order for this taxonomy. This will be applied to terms that don't have a tax position.
327 */
328 private static function get_max_taxonomy_order($tax_slug) {
329 global $wpdb;
330 $max_term_order = $wpdb->get_col(
331 $wpdb->prepare(
332 "SELECT MAX( CAST( tm.meta_value AS UNSIGNED ) )
333 FROM $wpdb->terms t
334 JOIN $wpdb->term_taxonomy tt ON t.term_id = tt.term_id AND tt.taxonomy = '%s'
335 JOIN $wpdb->termmeta tm ON tm.term_id = t.term_id WHERE tm.meta_key = 'doc_category_order'",
336 $tax_slug
337 )
338 );
339 $max_term_order = is_array($max_term_order) ? current($max_term_order) : 0;
340 return (int) $max_term_order === 0 || empty($max_term_order) ? 1 : (int) $max_term_order + 1;
341 }
342
343 /**
344 * Re-Order the taxonomies based on the doc_category_order value.
345 *
346 * @param array $pieces Array of SQL query clauses.
347 * @param array $taxonomies Array of taxonomy names.
348 * @param array $args Array of term query args.
349 */
350 public static function set_tax_order($pieces, $taxonomies, $args) {
351 foreach ($taxonomies as $taxonomy) {
352 global $wpdb;
353 if ($taxonomy === 'doc_category') {
354 $join_statement = " LEFT JOIN $wpdb->termmeta AS term_meta ON t.term_id = term_meta.term_id AND term_meta.meta_key = 'doc_category_order'";
355
356 if (!self::does_substring_exist($pieces['join'], $join_statement)) {
357 $pieces['join'] .= $join_statement;
358 }
359 $pieces['orderby'] = 'ORDER BY CAST( term_meta.meta_value AS UNSIGNED )';
360 }
361 }
362 return $pieces;
363 }
364
365 /**
366 * Order the taxonomies on the front end.
367 */
368 public static function front_end_order_terms() {
369 if (!is_admin()) {
370 add_filter('terms_clauses', array(__CLASS__, 'set_tax_order'), 10, 3);
371 }
372 }
373
374 /**
375 * Check if a substring exists inside a string.
376 *
377 * @param string $string The main string (haystack) we're searching in.
378 * @param string $substring The substring we're searching for.
379 *
380 * @return bool True if substring exists, else false.
381 */
382 protected static function does_substring_exist($string, $substring) {
383 return strstr($string, $substring) !== false;
384 }
385
386 /**
387 * Default the taxonomy's terms' order if it's not set.
388 *
389 * @param string $tax_slug The taxonomy's slug.
390 */
391 public static function get_manage_docs() {
392 $terms = get_terms('knowledge_base', array('hide_empty' => false));
393 if($terms) {
394 echo '<select name="term_meta[knowledge_base]" id="knowledge_base">';
395 echo '<option> ' . esc_html__('Select an option') . ' </option>';
396 foreach ($terms as $term) {
397 echo '<option value="' . $term->slug . '">' . $term->name . '</option>';
398 }
399 echo '</select>';
400 }
401 }
402
403 /**
404 * Add a form field in the new category page
405 *
406 * @since 1.0.0
407 */
408 public static function add_doc_category_meta($taxonomy) { ?>
409 <?php
410 do_action( 'betterdocs_doc_category_add_form_before' );
411 ?>
412 <div class="form-field term-group">
413 <label for="doc-category-order"><?php esc_html_e('Order', 'betterdocs'); ?></label>
414 <input type="number" id="doc-category-order" style="width:100px" name="term_meta[order]" value="">
415 </div>
416 <div class="form-field term-group">
417 <label for="doc-category-image-id"><?php esc_html_e('Category Icon', 'betterdocs'); ?></label>
418 <input type="hidden" id="doc-category-image-id" name="term_meta[image-id]" class="custom_media_url" value="">
419 <div id="doc-category-image-wrapper">
420 <?php echo '<img src="' . BETTERDOCS_ADMIN_URL . 'assets/img/betterdocs-cat-icon.svg" alt="">'; ?>
421 </div>
422 <p>
423 <input type="button" class="button button-secondary betterdocs_tax_media_button"
424 id="betterdocs_tax_media_button" name="betterdocs_tax_media_button"
425 value="<?php esc_html_e('Add Image', 'betterdocs'); ?>" />
426 <input type="button" class="button button-secondary doc_tax_media_remove" id="doc_tax_media_remove"
427 name="doc_tax_media_remove"
428 value="<?php esc_html_e('Remove Image', 'betterdocs'); ?>" />
429 </p>
430 </div>
431 <?php
432 }
433
434 /**
435 * Save the form field
436 *
437 * @since 1.0.0
438 */
439 public static function save_doc_category_meta($term_id) {
440 if (isset($_POST['term_meta'])) {
441 $term_meta = get_option("doc_category_$term_id");
442 $cat_keys = array_keys($_POST['term_meta']);
443 foreach ($cat_keys as $key) {
444 if (isset($_POST['term_meta'][$key])) {
445 add_term_meta($term_id, "doc_category_$key", $_POST['term_meta'][$key]);
446 $term_meta[$key] = $_POST['term_meta'][$key];
447 }
448 }
449 }
450 if ( isset($_POST['doc_category_kb']) ) {
451 $doc_category_kb = $_POST['doc_category_kb'];
452 update_term_meta($term_id, "doc_category_knowledge_base", $doc_category_kb);
453 }
454 }
455
456 /**
457 * Edit the form field
458 *
459 * @since 1.0.0
460 */
461 public static function update_doc_category_meta($term, $taxonomy) { ?>
462 <?php
463 $term_meta = get_option("doc_category_$term->term_id");
464 $cat_order = get_term_meta($term->term_id, 'doc_category_order', true);
465 $cat_icon_id = get_term_meta($term->term_id, 'doc_category_image-id', true);
466
467 do_action( 'betterdocs_doc_category_update_form_before', $term );
468
469 ?>
470
471 <tr class="form-field term-group-wrap">
472 <th scope="row">
473 <label for="doc-category-id"><?php esc_html_e('Category Id', 'betterdocs'); ?></label>
474 </th>
475 <td>
476 <input type="text" id="doc-category-id" style="width:100px" name="" value="<?php echo $_GET["tag_ID"] ?>" readonly>
477 </td>
478 </tr>
479 <tr class="form-field term-group-wrap">
480 <th scope="row">
481 <label for="doc-category-order"><?php esc_html_e('Order', 'betterdocs'); ?></label>
482 </th>
483 <td>
484 <input type="number" id="doc-category-order" style="width:100px" name="term_meta[order]"
485 value="<?php echo $cat_order ? $cat_order : ''; ?>">
486 </td>
487 </tr>
488 <tr class="form-field term-group-wrap batterdocs-cat-media-upload">
489 <th scope="row">
490 <label for="doc-category-image-id"><?php esc_html_e('Image', 'betterdocs'); ?></label>
491 </th>
492 <td>
493 <input type="hidden" id="doc-category-image-id" name="term_meta[image-id]" value="<?php echo $cat_icon_id; ?>">
494 <div id="doc-category-image-wrapper">
495 <?php
496 if ( $cat_icon_id ) {
497 echo wp_get_attachment_image( $cat_icon_id, 'thumbnail' );
498 } else {
499 echo '<img src="' . BETTERDOCS_ADMIN_URL . 'assets/img/betterdocs-cat-icon.svg" alt="">';
500 }
501 ?>
502 </div>
503 <p>
504 <input type="button" class="button button-secondary betterdocs_tax_media_button"
505 id="betterdocs_tax_media_button" name="betterdocs_tax_media_button"
506 value="<?php esc_html_e('Add Image', 'betterdocs'); ?>" />
507 <input type="button" class="button button-secondary doc_tax_media_remove" id="doc_tax_media_remove"
508 name="doc_tax_media_remove"
509 value="<?php esc_html_e('Remove Image', 'betterdocs'); ?>" />
510 </p>
511 </td>
512 </tr>
513 <?php
514 }
515
516 /*
517 * Update the form field value
518 *
519 * @since 1.0.0
520 */
521 public static function updated_doc_category_meta( $term_id ) {
522 if ( isset($_POST['term_meta']) ) {
523 $cat_keys = array_keys($_POST['term_meta']);
524 foreach ($cat_keys as $key) {
525 if (isset($_POST['term_meta'][$key])) {
526 update_term_meta($term_id, "doc_category_$key", $_POST['term_meta'][$key]);
527 }
528 }
529 }
530 if ( isset($_POST['doc_category_kb']) ) {
531 $doc_category_kb = $_POST['doc_category_kb'];
532 update_term_meta($term_id, "doc_category_knowledge_base", $doc_category_kb);
533 }
534 }
535
536 /*
537 * Add script
538 *
539 * @since 1.0.0
540 */
541 public static function add_script() {
542 global $current_screen;
543 if($current_screen->id == 'edit-doc_category'){
544 ?>
545 <script>
546 jQuery(document).ready(function($) {
547 function betterdocs_media_upload(button_class) {
548 var _custom_media = true,
549 _betterdocs_send_attachment = wp.media.editor.send.attachment;
550 $('body').on('click', button_class, function(e) {
551 var button_id = '#' + $(this).attr('id');
552 var send_attachment_bkp = wp.media.editor.send.attachment;
553 var button = $(button_id);
554 _custom_media = true;
555 wp.media.editor.send.attachment = function(props, attachment) {
556 if (_custom_media) {
557 $('#doc-category-image-id').val(attachment.id);
558 $('#doc-category-image-wrapper').html(
559 '<img class="custom_media_image" src="" style="margin:0;padding:0;max-height:100px;float:none;" />'
560 );
561 $('#doc-category-image-wrapper .custom_media_image').attr('src', attachment
562 .url).css('display', 'block');
563 } else {
564 return _betterdocs_send_attachment.apply(button_id, [props, attachment]);
565 }
566 }
567 wp.media.editor.open(button);
568 return false;
569 });
570 }
571 betterdocs_media_upload('.betterdocs_tax_media_button.button');
572 $('body').on('click', '.doc_tax_media_remove', function() {
573 $('#doc-category-image-id').val('');
574 $('#doc-category-image-wrapper').html(
575 '<img class="custom_media_image" src="" style="margin:0;padding:0;max-height:100px;float:none;" />'
576 );
577 });
578
579 $(document).ajaxComplete(function(event, xhr, settings) {
580 var queryStringArr = settings.data.split('&');
581 if ($.inArray('action=add-tag', queryStringArr) !== -1) {
582 var xml = xhr.responseXML;
583 $response = $(xml).find('term_id').text();
584 if ($response != "") {
585 // Clear the thumb image
586 $('#doc-category-image-wrapper').html('');
587 }
588 }
589 });
590 });
591 </script>
592 <?php }
593 }
594 }
595
596 BetterDocs_Docs_Post_Type::init();
597