Heray-Was-Here
Server : Apache
System : Linux dal-shared-66.hostwindsdns.com 4.18.0-513.24.1.lve.1.el8.x86_64 #1 SMP Thu May 9 15:10:09 UTC 2024 x86_64
User : krnuyqrm ( 1183)
PHP Version : 7.4.33
Disable Function : NONE
Directory :  /var/softaculous/sitepad/editor/site-data/plugins/documentor/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //var/softaculous/sitepad/editor/site-data/plugins/documentor/documentor.php
<?php
/**
 * Plugin Name:  Documentor
 * Description:  Online Documentation Engine for WordPress
 * Version:	  1.0.0
 * Author:	   softaculous
 * Author URI:   https://softaculous.com
 * License:	  GPLv2 or later
 * License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:  documentor
 *
 * @package documentor
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

define('DOCUMENTOR_VERSION', '1.0.0');
define('DOCUMENTOR_DIR', dirname(__FILE__));
define('DOCUMENTOR_URL', plugins_url('', __FILE__));


function documentor_autoloader($class){
	
	if(!preg_match('/^Documentor\\\(.*)/is', $class, $m)){
		return;
	}
	
	$m[1] = str_replace('\\', '/', $m[1]);
	
	// Loading the file
	if(file_exists(DOCUMENTOR_DIR.'/includes/'.strtolower($m[1]).'.php')){
		include_once(DOCUMENTOR_DIR.'/includes/'.strtolower($m[1]).'.php');
	}
}

spl_autoload_register(__NAMESPACE__.'\documentor_autoloader');

/**
 * Documentor class
 *
 * @class Documentor The class that holds the entire Documentor plugin
 */
class Documentor {
	/**
	 * The single class instance.
	 *
	 * @var $instance
	 */
	private static $instance = null;

	/**
	 * Path to the plugin directory
	 *
	 * @var $plugin_path
	 */
	public $plugin_path;

	/**
	 * URL to the plugin directory
	 *
	 * @var $plugin_url
	 */
	public $plugin_url;

	/**
	 * Theme templates directory path
	 *
	 * @var $theme_dir_path
	 */
	public $theme_dir_path;

	/**
	 * Path to template folder
	 *
	 * @var $theme_dir_path
	 */
	public $template_path;

	/**
	 * Post type name for documents
	 *
	 * @var $post_type
	 */
	public $post_type = 'docs';

	/**
	 * Current Page - is Docs Archive. Will be changed from Template Loader class
	 *
	 * @var $post_type
	 */
	public $is_archive = false;

	/**
	 * Current Page - is Docs Single. Will be changed from Template Loader class
	 *
	 * @var $post_type
	 */
	public $is_single = false;

	/*
	* @var $version 
	*/
	public $version = '1.0.1';
	
	/**
	 * Main Instance
	 * Ensures only one instance of this class exists in memory at any one time.
	 */
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
			self::$instance->plugin_init();
		}
		return self::$instance;
	}

	/**
	 * Plugin init.
	 */
	public function plugin_init() {
		$this->plugin_path	= plugin_dir_path( __FILE__ );
		$this->plugin_url	 = plugin_dir_url( __FILE__ );
		$this->theme_dir_path = 'documentor/';
		$this->template_path  = $this->plugin_path . '/templates/';

		$this->include_dependencies();

		$this->maybe_setup();

		$this->add_image_sizes();
		
		// Update checker
		add_action('plugins_loaded', array( $this, 'update_check'));
		
		// load textdomain.
		load_plugin_textdomain( 'documentor', false, basename( dirname( __FILE__ ) ) . '/languages' );

		// custom post type register.
		add_action( 'init', array( $this, 'register_post_type' ) );

		// Loads frontend scripts and styles.
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );

		register_deactivation_hook( __FILE__, array( $this, 'deactivation_hook' ) );
		register_activation_hook( __FILE__, array( $this, 'activation_hook' ) );
	}

	/**
	 * Activation hook.
	 */
	public function activation_hook() {
		$author = get_role( 'author' );
		$admin  = get_role( 'administrator' );

		/* Add documentor manager role */
		$documentor_manager = add_role( 'documentor_manager', __( 'Documentor Manager', 'documentor' ), $author->capabilities );

		$full_cap = array(
			'read_doc',
			'read_private_doc',
			'read_private_docs',
			'edit_doc',
			'edit_docs',
			'edit_others_docs',
			'edit_private_docs',
			'edit_published_docs',
			'delete_doc',
			'delete_docs',
			'delete_others_docs',
			'delete_private_docs',
			'delete_published_docs',
			'publish_docs',
		);

		/**
		 * Add full capacities to admin and docs manager roles
		 */
		foreach ( $full_cap as $cap ) {
			if ( null !== $admin ) {
				$admin->add_cap( $cap );
			}
			if ( null !== $documentor_manager ) {
				$documentor_manager->add_cap( $cap );
			}
		}

		// Create Docs page if not created.
		$settings = get_option( 'documentor_settings', array() );
		if ( ! $settings || ! $settings['docs_page_id'] ) {
			$documentor_page = wp_insert_post(
				array(
					'post_title'  => 'Docs',
					'post_type'   => 'page',
					'post_author' => get_current_user_id(),
					'post_status' => 'publish',
					'post_name'   => 'docs',
				)
			);

			if ( ! is_wp_error( $documentor_page ) ) {
				$settings['docs_page_id'] = $documentor_page;

				update_option( 'documentor_settings', $settings );
			}
		}

		// need to flush rules to reset permalinks.
		add_option( 'documentor_setup', 'pending' );
		
		// Enable for pagelayer as well
		$pl = get_option('pl_support_ept');
		
		if(empty($pl)){
			$pl = ['post', 'page'];
		}
		
		if(defined('PAGELAYER_VERSION') && !in_array($this->post_type, $pl)){
			$pl[] = $this->post_type;
			update_option('pl_support_ept', $pl);
		}
		
		include_once documentor()->plugin_path.'includes/template.php';
		
		documentor_import_template_content( json_decode(documentor_get_conf(),true), documentor_get_content());

	}

	/**
	 * Deactivation hook.
	 */
	public function deactivation_hook() {
		/* Deactivation actions */
	}

	/**
	 * Update checker hook.
	 */
	public function update_check() {
		/* Update checker hook */

		$current_version = get_option('documentor_version');
		$version = (int) str_replace('.', '', $current_version);

		// No update required
		if($current_version == $this->version){
			return true;
		}
		
		if($version < 101){
			
			$args = array(
				'post_type' => 'pagelayer-template',
				'post_status' => array('publish'),
				'meta_query' => array(
					array(
						'key' => 'documentor_imported_content',
					)
				)
			);
			
			$query = new WP_Query($args);

			if(empty($query->posts)){
				include_once documentor()->plugin_path.'includes/template.php';
				documentor_import_template_content( json_decode(documentor_get_conf(),true), documentor_get_content());
			}
		}
		
		// Save the new Version
		update_option('documentor_version', $this->version);
	}

	/**
	 * Maybe run setup code and rewrite rules.
	 */
	public function maybe_setup() {
		$documentor_archive_id = documentor()->get_option( 'docs_page_id', 'documentor_settings', false );
		$docs_page			= $documentor_archive_id ? get_post( $documentor_archive_id ) : false;
		$slug				 = $docs_page ? get_post_field( 'post_name', $docs_page ) : 'docs';

		if (
			get_option( 'documentor_setup', false ) === 'pending' ||
			get_option( 'documentor_current_slug', 'docs' ) !== $slug
		) {
			add_action( 'init', 'flush_rewrite_rules', 11, 0 );
			add_action( 'admin_init', 'flush_rewrite_rules', 11, 0 );

			delete_option( 'documentor_setup' );
			update_option( 'documentor_current_slug', $slug );
		}
	}

	/**
	 * Add image sizes.
	 */
	public function add_image_sizes() {
		// custom image sizes.
		add_image_size( 'documentor_archive_sm', 20, 20, true );
		add_image_size( 'documentor_archive', 40, 40, true );
		add_filter( 'image_size_names_choose', array( $this, 'image_size_names_choose' ) );
	}

	/**
	 * Custom image sizes
	 *
	 * @param array $sizes - registered image sizes.
	 *
	 * @return array
	 */
	public function image_size_names_choose( $sizes ) {
		return array_merge(
			$sizes,
			array(
				'documentor_archive_sm' => esc_html__( 'Archive Thumbnail Small (Documentor)', 'documentor' ),
				'documentor_archive'	=> esc_html__( 'Archive Thumbnail (Documentor)', 'documentor' ),
			)
		);
	}

	/**
	 * Include dependencies
	 */
	public function include_dependencies() {
		include_once documentor()->plugin_path . 'includes/class-template-loader.php';
		include_once documentor()->plugin_path . 'includes/class-walker-docs.php';
		include_once documentor()->plugin_path . 'includes/class-suggestion.php';

		if ( is_admin() ) {
			include_once documentor()->plugin_path . 'includes/admin/class-admin.php';
		}

		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
			include_once documentor()->plugin_path . 'includes/class-ajax.php';
		}
	}

	/**
	 * Enqueue admin scripts
	 *
	 * Allows plugin assets to be loaded.
	 *
	 * @uses wp_enqueue_script()
	 * @uses wp_localize_script()
	 * @uses wp_enqueue_style
	 */
	public function enqueue_scripts() {
		
		$deps = array( 'jquery' );
		wp_register_style( 'documentor', documentor()->plugin_url . 'assets/css/style.min.css', array(), $this->version );

		if(get_post_type() === 'docs'){
			wp_enqueue_style('documentor');
		}

		if( documentor()->get_option( 'show_anchor_links', 'documentor_single', true ) ) {
			wp_register_script( 'anchor-js', documentor()->plugin_url . 'assets/vendor/anchor/anchor.min.js', array(),  $this->version, true );
			$deps[] = 'anchor-js';
		}
		
		wp_register_script( 'documentor', documentor()->plugin_url . 'assets/js/script.min.js', $deps, $this->version, true );
	
		if ( ! ( $this->is_archive || $this->is_single ) ) {
			return;
		}
		
		wp_style_add_data( 'documentor', 'rtl', 'replace' );
		wp_style_add_data( 'documentor', 'suffix', '.min' );

		if ( documentor()->get_option( 'show_anchor_links', 'documentor_single', true ) ) {
			wp_enqueue_script( 'anchor-js');
		}
		wp_enqueue_script( 'documentor' );
		wp_localize_script(
			'documentor',
			'documentor_vars',
			array(
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'documentor-ajax' ),
			)
		);

		// Custom script for AJAX.
		$ajax	  = documentor()->get_option( 'ajax', 'documentor_single', true );
		$custom_js = documentor()->get_option( 'ajax_custom_js', 'documentor_single', '' );
		if ( $ajax && $custom_js ) {
			wp_add_inline_script(
				'documentor',
				'
				(function ($) {
					$(document).on("documentor_ajax_loaded", function (event, new_page) {
						' . $custom_js . '
					});
				}(jQuery));
			'
			);
		}

		if ( $ajax && $this->is_single) {
			wp_add_inline_script('documentor', 'jQuery(".pagelayer-content").addClass("documentor-single-ajax");');
		}
	}

	/**
	 * Register the post type
	 *
	 * @return void
	 */
	public function register_post_type() {
		$documentor_archive_id = documentor()->get_option( 'docs_page_id', 'documentor_settings', false );
		$docs_page			= $documentor_archive_id ? get_post( $documentor_archive_id ) : false;

		$labels = array(
			'name'			   => $docs_page ? get_the_title( $docs_page ) : _x( 'Documentor', 'Post Type General Name', 'documentor' ),
			'singular_name'	  => _x( 'Doc', 'Post Type Singular Name', 'documentor' ),
			'menu_name'		  => __( 'Documentation', 'documentor' ),
			'parent_item_colon'  => __( 'Parent Doc', 'documentor' ),
			'all_items'		  => __( 'All Documentations', 'documentor' ),
			'view_item'		  => __( 'View Documentation', 'documentor' ),
			'add_new_item'	   => __( 'Add Documentation', 'documentor' ),
			'add_new'			=> __( 'Add New', 'documentor' ),
			'edit_item'		  => __( 'Edit Documentation', 'documentor' ),
			'update_item'		=> __( 'Update Documentation', 'documentor' ),
			'search_items'	   => __( 'Search Documentation', 'documentor' ),
			'not_found'		  => __( 'Not documentation found', 'documentor' ),
			'not_found_in_trash' => __( 'Not found in Trash', 'documentor' ),
		);

		$rewrite = array(
			'slug'	   => $docs_page ? get_post_field( 'post_name', $docs_page ) : 'docs',
			'with_front' => false,
			'pages'	  => true,
			'feeds'	  => true,
		);

		$args = array(
			'labels'			  => $labels,
			'supports'			=> array( 'title', 'editor', 'thumbnail', 'revisions', 'page-attributes', 'comments' ),
			'hierarchical'		=> true,
			'public'			  => true,
			'show_ui'			 => true,
			'show_in_menu'		=> false,
			'show_in_nav_menus'   => true,
			'show_in_admin_bar'   => true,
			'menu_position'	   => 5,
			'menu_icon'		   => 'dashicons-media-document',
			'can_export'		  => true,
			'has_archive'		 => $docs_page ? urldecode( get_page_uri( $documentor_archive_id ) ) : 'docs',
			'exclude_from_search' => false,
			'publicly_queryable'  => true,
			'show_in_rest'		=> true,
			'rewrite'			 => $rewrite,
			'map_meta_cap'		=> true,
			'capability_type'	 => array( 'doc', 'docs' ),
		);

		register_post_type( $this->post_type, $args );

		register_taxonomy(
		'docs_hub', 
		$this->post_type,
		[
			'label' => esc_html__('Document Hubs', 'documentor'),
			'labels' => [
			    	'menu_name' => esc_html__('Document Hub', 'documentor'),
			    	'search_items' => esc_html__('Search Hubs', 'documentor'),
			    	'add_new_item' => esc_html__('Add New Hub', 'documentor'), 
			    	'new_item_name' => esc_html__('New Hub Name', 'documentor'),
			    	'all_items' => esc_html__('All Hubs', 'documentor'),
			    	'edit_item' => esc_html__('Edit Hub', 'documentor'),
			    	'update_item' => esc_html__('Update Hub', 'documentor'),
					'back_to_items' => esc_html__('&larr; Back to Hubs', 'documentor'),
		   	],
			'rewrite' => [
				'slug' => 'docs_hub',
				'with_front' => false,
			],
			'hierarchical' => true,
			'publicly_queryable' => true,
			'show_in_nav_menus' => false,
			'show_in_rest' => true,
			'show_admin_column' => true,
			'meta_box_cb' => '\Documentor\FrontEnd::doc_hub_radio_metabox'
		]);

		register_taxonomy(
			'docs_category',
			$this->post_type,
			array(
				'label'			  => esc_html__( 'Docs Categories', 'documentor' ),
				'labels'			 => array(
					'menu_name' => esc_html__( 'Categories', 'documentor' ),
				),
				'rewrite'			=> array(
					'slug' => 'docs-category',
				),
				'hierarchical'	   => false,
				'publicly_queryable' => false,
				'show_in_nav_menus'  => false,
				'show_in_rest'	   => true,
				'show_admin_column'  => true,
			)
		);
	}

	/**
	 * Get the value of a settings field
	 *
	 * @param string $option settings field name.
	 * @param string $section the section name this field belongs to.
	 * @param string $default default text if it's not found.
	 *
	 * @return mixed
	 */
	public function get_option( $option, $section, $default = '' ) {

		$options = get_option( $section );

		if ( isset( $options[ $option ] ) ) {
			return 'off' === $options[ $option ] ? false : ( 'on' === $options[ $option ] ? true : $options[ $option ] );
		}

		return $default;
	}

	/**
	 * Get template part or docs templates
	 * Looks at the theme directory first
	 *
	 * @param string $name template file name.
	 * @param string $data template data.
	 */
	public function get_template_part( $name, $data = array() ) {
		$name = (string) $name;

		// lookup at documentor/name.php.
		$template = locate_template(
			array(
				documentor()->theme_dir_path . "{$name}.php",
			)
		);

		// fallback to plugin default template.
		if ( ! $template && $name && file_exists( documentor()->template_path . "{$name}.php" ) ) {
			$template = documentor()->template_path . "{$name}.php";
		}

		if ( $template ) {
			$this->load_template( $template, $data );
		}
	}

	/**
	 * Load template with additional data.
	 *
	 * @param string $template_path - template path.
	 * @param array  $template_data - template data array.
	 */
	public function load_template( $template_path, $template_data ) {
		if ( isset( $template_data ) && is_array( $template_data ) ) {
			// phpcs:ignore
			extract( $template_data );
		}

		if ( file_exists( $template_path ) ) {
			include $template_path;
		}
	}

	/**
	 * Is Archive
	 *
	 * @return bool
	 */
	public function is_archive() {
		return $this->is_archive;
	}

	/**
	 * Is Single
	 *
	 * @return bool
	 */
	public function is_single() {
		return $this->is_single;
	}

	/**
	 * Get current document ID
	 *
	 * @return int
	 */
	public function get_current_doc_id() {
		global $post;

		if ( $post->post_parent ) {
			$ancestors = get_post_ancestors( $post->ID );
			$root	  = count( $ancestors ) - 1;
			$parent	= $ancestors[ $root ];
		} else {
			$parent = $post->ID;
		}

		return apply_filters( 'documentor_current_doc_id', $parent );
	}

	/**
	 * Get document page title
	 *
	 * @return string
	 */
	public function get_docs_page_title() {
		$title		= esc_html__( 'Documentation', 'documentor' );
		$docs_page_id = documentor()->get_option( 'docs_page_id', 'documentor_settings' );

		if ( $docs_page_id ) {
			$title = get_the_title( $docs_page_id );
		}

		return apply_filters( 'documentor_page_title', $title );
	}

	/**
	 * Get document page content
	 *
	 * @return string
	 */
	public function get_docs_page_content() {
		$content	  = '';
		$docs_page_id = documentor()->get_option( 'docs_page_id', 'documentor_settings' );

		if ( $docs_page_id ) {
			$content = get_post_field( 'post_content', $docs_page_id );
		}

		return apply_filters( 'documentor_page_content', $content );
	}

	/**
	 * Get breadcrumbs array
	 *
	 * @return array
	 */
	public function get_breadcrumbs_array() {
		global $post;

		$result	   = array();
		$docs_page_id = documentor()->get_option( 'docs_page_id', 'documentor_settings' );

		$result[] = array(
			'label'	=> __( 'Home', 'documentor' ),
			'url'	  => home_url( '/' ),
		);
		
		// Get the root ancestor to find the hub
		$ancestors = get_ancestors($post->ID, 'docs');
		$root_ancestor = !empty($ancestors) ? $ancestors[count($ancestors)-1] : $post->ID;
		
		// Get hub term from root ancestor
		$docs_hub = wp_get_object_terms($root_ancestor, 'docs_hub');
		
		if(!empty($docs_hub) && !empty($docs_hub[0]) && $docs_hub[0] instanceof \WP_Term){
			// Use the linked hub page URL instead of taxonomy URL
			$hub_page_id = get_term_meta($docs_hub[0]->term_id, 'documentor_hub_page_id', true);
			$hub_url = !empty($hub_page_id) ? get_permalink($hub_page_id) : get_term_link($docs_hub[0]);
			
			$result[] = array(
				'label' => !empty($docs_hub[0]->name) ? $docs_hub[0]->name : __( 'Docs', 'documentor' ),
				'url'   => $hub_url,
			);

		} else if ( $docs_page_id ) {
			$result[] = array(
				'label' => get_the_title( $docs_page_id ) ? get_the_title( $docs_page_id ) : __( 'Docs', 'documentor' ),
				'url'   => get_permalink( $docs_page_id ),
			);
		}

		if ( 'docs' === $post->post_type && $post->post_parent ) {
			$parent_id   = $post->post_parent;
			$temp_crumbs = array();

			while ( $parent_id ) {
				$page		  = get_post( $parent_id );
				$temp_crumbs[] = array(
					'label'	=> get_the_title( $page->ID ),
					'url'	  => get_permalink( $page->ID ),
				);
				$parent_id	 = $page->post_parent;
			}

			$temp_crumbs = array_reverse( $temp_crumbs );
			
			// Add current post
			$temp_crumbs[] = array(
				'label'	=> get_the_title( $post->ID ),
			);
			
			foreach ( $temp_crumbs as $crumb ) {
				$result[] = $crumb;
			}
		}

		return apply_filters( 'documentor_breadcrumbs_array', $result );
	}

	/**
	 * Next doc ID for the current doc page
	 *
	 * @return int
	 */
	public function get_next_adjacent_doc_id() {
		global $post, $wpdb;

		$parent = pagelayer_is_live() || wp_doing_ajax('adjacent_links') ? '0' : $post->post_parent;
		$menu_order = pagelayer_is_live() || wp_doing_ajax('adjacent_links') ? 1 : $post->menu_order;

		$next_query = "SELECT ID FROM $wpdb->posts
		WHERE post_parent = $parent and post_type = 'docs' and post_status = 'publish' and menu_order > $menu_order
		ORDER BY menu_order ASC
		LIMIT 0, 1";

		// phpcs:ignore
		return (int) $wpdb->get_var( $next_query );
	}

	/**
	 * Previous doc ID for the current doc page
	 *
	 * @return int
	 */
	public function get_previous_adjacent_doc_id() {
		global $post, $wpdb;

		$parent = pagelayer_is_live()  || wp_doing_ajax('adjacent_links') ? '0' : $post->post_parent;
		$menu_order = pagelayer_is_live() || wp_doing_ajax('adjacent_links') ? 1 : $post->menu_order;

		$prev_query = "SELECT ID FROM $wpdb->posts
		WHERE post_parent = $parent and post_type = 'docs' and post_status = 'publish' and menu_order < $menu_order
		ORDER BY menu_order DESC
		LIMIT 0, 1";

		// phpcs:ignore
		return (int) $wpdb->get_var( $prev_query );
	}

} // Documentor

/**
 * Initialize the plugin
 *
 * @return \Documentor
 */
function documentor() {
	return Documentor::instance();
}
documentor();
	
// To find posts when we submit /docs/space/arctile-name instead of /docs/space/category/arctile-name
add_filter('request', 'documentor_query_vars');
function documentor_query_vars($vars){// Handle direct links
	//print_r($vars);die();
	
	$doc = documentor();
	
	// Pagelayer draft edit requests can come through a linked hub page URL like:
	// /hub-page/?post_type=docs&p=172&pagelayer-live=1
	// In that case WordPress receives both the docs post ID and the hub page slug.
	// Strip the page query vars so the docs post can resolve by ID.
	if(
		!empty($vars['post_type']) &&
		$vars['post_type'] === $doc->post_type &&
		!empty($vars['p']) &&
		!empty($vars['pagename'])
	){
		$hub_page = get_page_by_path(sanitize_text_field(wp_unslash($vars['pagename'])));

		if($hub_page instanceof \WP_Post){
			$linked_hub_id = get_post_meta($hub_page->ID, '_documentor_linked_hub_id', true);

			if(!empty($linked_hub_id)){
				unset($vars['pagename']);
				$vars['p'] = (int) $vars['p'];
				return $vars;
			}
		}
	}

	// When search is submitted from a hub page (e.g., /hub-page/?s=word&post_type=docs),
	// the pagename (from page rewrite) conflicts with post_type=docs (from query param),
	// causing a 404. Strip pagename so WordPress handles it as a proper docs search.
	if(
		!empty($vars['s']) &&
		!empty($vars['post_type']) &&
		$vars['post_type'] === $doc->post_type &&
		!empty($vars['pagename'])
	){
		$hub_page = get_page_by_path($vars['pagename']);

		if($hub_page instanceof \WP_Post){
			$linked_hub_id = get_post_meta($hub_page->ID, '_documentor_linked_hub_id', true);

			if(!empty($linked_hub_id)){
				$vars['documentor_search_hub'] = (int) $linked_hub_id;
				unset($vars['pagename']);
				unset($vars['name']);
				return $vars;
			}
		}
	}

	// Handle hub-based URLs: /hub-slug/doc-name
	if(!empty($vars['docs_hub']) && !empty($vars['name']) && empty($vars['post_type'])){
		$vars['post_type'] = documentor()->post_type;
	}

	// Must be docs
	if(empty($vars['post_type']) || $vars['post_type'] != documentor()->post_type || empty($vars['name'])){
		return $vars;
	}
	
	if(!empty($_GET['debug'])){
		//print_r($vars);die();
	}
	
	$docs_archive_id = documentor()->get_option( 'docs_page_id', 'documentor_settings', false );
	$permalink = get_permalink($docs_archive_id);
	
	$docs = explode('/', $vars['docs']);
	
	// Find the post by name only (no tax_query, as hub may be on ancestor)
	$args = array(
		'name'		=> $vars['name'],
		'post_type'   => 'docs',
		'post_status' => 'publish',
		'numberposts' => 10
	);
	
	$posts = get_posts($args);
	//print_r($post);
	
	// Did we get it ?
	if(empty($posts)){
		
		// Ok lets try to see if we get with another method
		$tmp = explode('/', str_replace('_', '-', $vars['name']));
		$args['name'] = $tmp[count($tmp)-1];
		$posts = get_posts($args);	
		
		// If we still didnt get it, then lets return original vars
		if(empty($posts)){
			return $vars;
		}
		
	}

	// If we have hub context, filter posts by checking hub inheritance
	if(!empty($vars['docs_hub']) && count($posts) > 0){
		$hub_matched = array();
		foreach($posts as $p){
			$post_hub = documentor_get_post_hub($p->ID);
			if($post_hub && $post_hub->slug === $vars['docs_hub']){
				$hub_matched[] = $p;
			}
		}
		if(!empty($hub_matched)){
			$posts = $hub_matched;
		}
	}
	
	$post = $posts[0];
	
	// If we have 2 parts, then find the closest as well
	if(count($docs) > 1){
		
		// If we found more than 1 results
		foreach($posts as $p){
			
			$url = get_permalink($p);			
			$_section = trim(str_replace($permalink, '', $url), '/');
			$parts = explode('/', $_section);
			
			if($parts[0] == $docs[0]){
				$post = $p;
				break;
			}
			
		}
		
	}

	if(!empty($_GET['debug'])){
		//print_r($post);die();
	}
	
	// For hub-based URLs, skip redirect logic and just resolve the post
	if(!empty($vars['docs_hub'])){
		// This bypasses all slug resolution and tells WordPress exactly which post to load by ID.
		$vars['p'] = $post->ID;
		unset($vars['name']);
		unset($vars['docs']);

		return $vars;
	}
	
	$url = get_permalink($post);
	$_section = trim(str_replace($permalink, '', $url), '/');
	//echo $url."\n";
	//echo $_section.' - '.$vars['name']."\n";die();
	
	// If the LINK is not same as the original, then redirect
	if($_section != trim($vars['name'], '/')){
		//die('redirecting !');
		wp_redirect($url.(!empty($_SERVER['QUERY_STRING']) ? '?'. sanitize_text_field(wp_unslash($_SERVER['QUERY_STRING'])) : ''));
		die();
	}
	
	$section = get_page_uri($post);
	//echo $section."\n";
	
	$vars['name'] = $vars['docs'] = trim($section, '/');
	//print_r($vars);
	//die($section);
	
	return $vars;
}

/**
 * Get the docs_hub term for a post, checking ancestors if not directly assigned.
 *
 * @param int $post_id Post ID
 * @return WP_Term|null The hub term or null if not found
 */
function documentor_get_post_hub($post_id){
	// Check if post has docs_hub directly
	$terms = wp_get_post_terms($post_id, 'docs_hub');
	if(!empty($terms) && !is_wp_error($terms)){
		return $terms[0];
	}
	
	// Walk up ancestors to find hub
	$ancestors = get_ancestors($post_id, 'docs');
	if(!empty($ancestors) && is_array($ancestors)){
		foreach($ancestors as $ancestor_id){
			$terms = wp_get_post_terms($ancestor_id, 'docs_hub');
			if(!empty($terms) && !is_wp_error($terms)){
				return $terms[0];
			}
		}
	}
	
	return null;
}

// No pagelayer content template should render
add_action( 'template_redirect', 'documentor_no_pagelayer_content', 101);
function documentor_no_pagelayer_content(){
	global $wp_query, $pagelayer;
	
	$docs = documentor();
	
	if(empty($wp_query->query['post_type']) || $wp_query->query['post_type'] !== $docs->post_type || !is_search()){
		return;
	}
	
	$pagelayer->template_post = null;
		
}

//Show pagination
add_action('pre_get_posts', 'documentor_show_posts');
function documentor_show_posts($query){
	if((is_admin() && !wp_doing_ajax()) || !$query->is_main_query()){
		return;
	}

	$is_hub_page = false;

	// Check if this is a physical Page secretly linked to a Hub
	if($query->is_page()){
		$page_id = $query->get_queried_object_id();
		$meta = get_post_meta($page_id, '_documentor_linked_hub_id', true);
		if(!empty($meta)){
			$is_hub_page = true;
		}
	}

	if($query->is_tax('docs_hub') || $is_hub_page){
		// Force WP to treat this as the Docs Archive
		$query->set('post_type', array('docs'));
		$query->query_vars['post_type'] = array('docs');

		// Tell WordPress this is NOT a standard page anymore
		$query->set('page_id', '');
		$query->set('pagename', '');
		$query->set('name', '');

		// Force the Archive boolean flags
		$query->is_post_type_archive = true;
		$query->is_archive = true;
		$query->is_singular = false;
		$query->is_page = false;
	}

	//Return if the action is not 'search'
	if(!($query->is_search())){
		return;
	}
	
	if(@$query->query['post_type'] !== documentor()->post_type){
		return;
	}
	
	$query->query_vars['posts_per_page'] = 50;
	$query->query_vars['paged'] = (get_query_var('paged') ? get_query_var('paged') : 1);
}

// All post types are editable by Pagelayer
add_filter('pagelayer_supported_post_type', 'documentor_supported_post_type', 10, 1);
function documentor_supported_post_type($types){
	if(!in_array('docs', $types)){
		$types[] = 'docs';
	}
	return $types;
}

// Add shortcode in Pagelayer shortcode loader
// Loads the shortcodes
add_action( 'pagelayer_load_custom_widgets', 'documentor_load_shortcodes' );
function documentor_load_shortcodes(){
	include_once documentor()->plugin_path.'includes/shortcode_functions.php';
	include_once documentor()->plugin_path.'includes/shortcodes.php';
}

// Load editor js and css
add_action( 'pagelayer_custom_editor_enqueue', 'documentor_custom_editor_enqueue' );
function documentor_custom_editor_enqueue(){
	global $wp_query, $pagelayer;
	
	$docs = documentor();
	
	// Enqueue JS
	wp_register_script('documentor-editor', documentor()->plugin_url.'assets/js/widgets.js', array('jquery'), documentor()->version);
	wp_enqueue_script('documentor-editor');

	if(empty($wp_query->query['post_type']) || !($wp_query->query['post_type'] == $docs->post_type || $wp_query->query['post_type'] == $pagelayer->builder['name'])){
		return;
	}
	
	// Enqueue frontend js and CSS
	wp_enqueue_style( 'documentor');

	if ( documentor()->get_option( 'show_anchor_links', 'documentor_single', true ) ) {
		wp_enqueue_script( 'anchor-js');
	}

	wp_enqueue_script( 'documentor' );
}

// Load editor js and css
add_action( 'pagelayer_live_body_head', 'documentor_icon_enqueue' );
function documentor_icon_enqueue(){
	echo '<link rel="stylesheet" href="'.esc_url(documentor()->plugin_url).'assets/css/documentor-icon.css">';
}

add_action('wp_head', '\Documentor\FrontEnd::override_pagelayer_return_url', 1000);

add_action('init', 'documentor_languages');
function documentor_languages(){
	global $pagelayer;

	$lang = @file_get_contents( documentor()->plugin_url .'/languages/en.json');
	$lang = @json_decode($lang, true);

	foreach($lang as $k => $v){
		
		if(!isset($pagelayer->l[$k])){
			$pagelayer->l[$k] = $v;
		}
	}
}

// Adds rewrite rules so that doc hub urls could load docs in place of 404.
function documentor_add_doc_hub_rewrite_rules(){
	$terms = get_terms([
		'taxonomy' => 'docs_hub',
		'hide_empty' => false
	]);

	if(empty($terms) || is_wp_error($terms)){
		return;
	}

	$term_slugs = wp_list_pluck($terms, 'slug');
	
	//print_r($term_slugs);die();
	$regex = '^(' . implode('|', $term_slugs) . ')/(.+?)/?$';

	add_rewrite_rule($regex, 'index.php?post_type=docs&name=$matches[2]&docs=$matches[2]&docs_hub=$matches[1]', 'top');
}
add_action('init', 'documentor_add_doc_hub_rewrite_rules');

add_filter('post_type_link', '\Documentor\FrontEnd::filter_mixed_docs_permalink', 10002, 2);

// This is the line hidden inside /wp-includes/general-template.php
add_filter('document_title_parts', '\Documentor\FrontEnd::display_page_title');

// Change the visual page header title for Hubs
add_filter('post_type_archive_title', '\Documentor\FrontEnd::override_archive_title');

// Force all hub links to use the clean page URL instead of the Taxonomy URL
add_filter('term_link', '\Documentor\FrontEnd::bridge_hub_links', 10, 3);

// Redirect anyone who visits the Hub URL to the page linked to it
add_action('template_redirect', '\Documentor\FrontEnd::bridge_hub_redirect');

add_action('pagelayer_builder_template_redirect', '\Documentor\FrontEnd::load_hubs_template', 20);

add_filter('pagelayer_remove_meta_boxes', '\Documentor\FrontEnd::remove_pl_hub_metabox');

/**
 * Flush rewrite rules when doc hub assignment changes.
 *
 * Only flushes when:
 * - A hub is first assigned to a doc (0 -> hub_id)
 * - Hub is changed (hub_id_a -> hub_id_b)
 * - Hub is removed (hub_id -> 0)
 *
 * @param array  $terms      - An array of object term IDs or slugs.
 * @param int    $tt_ids     - term taxonomy ID
 * @param string $taxonomy   - taxonomy slug
 * @param int    $object_id  - post ID
 * @param bool   $append     - Whether to append new terms to the old terms.
 * @param array  $old_tt_ids - previous term taxonomy IDs
 */
function documentor_flush_on_hub_assignment($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids){
	if('docs_hub' !== $taxonomy){
		return;
	}
	
	// Making sure we are doing it only for the a docs post type
	$post = get_post($object_id);
	if(empty($post) || $post->post_type !== 'docs'){
		return;
	}
	
	$new_hub_id = !empty($tt_ids) ? intval($tt_ids[0]) : 0;
	$old_hub_id = !empty($old_tt_ids) ? intval($old_tt_ids[0]) : 0;
	
	// Flush only if the hub has been changed
	if($new_hub_id !== $old_hub_id){
		flush_rewrite_rules();
	}
}
	
// Flush rewrite rules when doc hub assignment changes.
add_action('set_object_terms', 'documentor_flush_on_hub_assignment', 10, 6);

Hry