define_constants(); $this->includes(); $this->init_hooks(); } /** * Define plugin constants. */ private function define_constants() { define('FULGID_AICOGU_PATH', plugin_dir_path(__FILE__)); define('FULGID_AICOGU_URL', plugin_dir_url(__FILE__)); define('FULGID_AICOGU_BASE', plugin_basename(__FILE__)); } /** * Include required files. */ private function includes() { // Admin interface require_once FULGID_AICOGU_PATH . 'admin/class-admin.php'; // Core functionality require_once FULGID_AICOGU_PATH . 'includes/class-activator.php'; require_once FULGID_AICOGU_PATH . 'includes/class-deactivator.php'; require_once FULGID_AICOGU_PATH . 'includes/class-content-analyzer.php'; require_once FULGID_AICOGU_PATH . 'includes/class-file-manager.php'; require_once FULGID_AICOGU_PATH . 'includes/class-seo-integrator.php'; } /** * Initialize hooks. */ private function init_hooks() { register_activation_hook(__FILE__, array('FULGID_AICOGU_Activator', 'activate')); register_deactivation_hook(__FILE__, array('FULGID_AICOGU_Deactivator', 'deactivate')); // Admin hooks add_action('admin_menu', array($this, 'add_menu_page')); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts')); // Plugin functionality hooks add_action('save_post', array($this, 'schedule_file_regeneration'), 10, 3); add_action('fulgid_aicogu_regenerate_file', array($this, 'regenerate_file')); // Add rewrite rules for serving llms.txt add_action('init', array($this, 'add_rewrite_rules')); add_filter('query_vars', array($this, 'add_query_vars')); add_filter('redirect_canonical', array($this, 'prevent_llms_txt_redirect'), 10, 2); add_action('template_redirect', array($this, 'handle_llms_txt_request')); // Plugin action links add_filter('plugin_action_links_' . FULGID_AICOGU_BASE, array($this, 'add_plugin_action_links')); } /** * Add admin menu page. */ public function add_menu_page() { add_menu_page( esc_html__('llms.txt generator', 'ai-content-guide-llms-text-generator'), esc_html__('llms.txt generator', 'ai-content-guide-llms-text-generator'), 'manage_options', 'ai-content-guide-llms-text-generator', array($this, 'display_admin_page'), 'dashicons-format-aside', 30 ); } /** * Display admin page. */ public function display_admin_page() { if (!current_user_can('manage_options')) { wp_die(__('You do not have sufficient permissions to access this page.')); } require_once FULGID_AICOGU_PATH . 'admin/partials/admin-display.php'; } /** * Enqueue admin scripts and styles. * * @param string $hook The current admin page. */ public function enqueue_admin_scripts($hook) { if ('toplevel_page_ai-content-guide-llms-text-generator' !== $hook) { return; } wp_enqueue_style( 'fulgid-aicogu-admin', FULGID_AICOGU_URL . 'admin/css/admin.css', array(), FULGID_AICOGU_VERSION ); wp_enqueue_script( 'fulgid-aicogu-admin', FULGID_AICOGU_URL . 'admin/js/admin.js', array('jquery'), FULGID_AICOGU_VERSION, true ); wp_localize_script( 'fulgid-aicogu-admin', 'fulgidAicoguParams', array( 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('fulgid-aicogu-nonce'), 'i18n' => array( 'regenerating' => esc_html__('Regenerating file...', 'ai-content-guide-llms-text-generator'), 'error' => esc_html__('An error occurred.', 'ai-content-guide-llms-text-generator'), 'success' => esc_html__('File regenerated successfully!', 'ai-content-guide-llms-text-generator') ) ) ); } /** * Schedule file regeneration when a post is saved. * * @param int $post_id Post ID. * @param WP_Post $post Post object. * @param bool $update Whether this is an existing post being updated. */ public function schedule_file_regeneration($post_id, $post, $update) { // Skip auto-saves and revisions if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) { return; } // Check if post type should be included in llms.txt $settings = get_option('fulgid_aicogu_settings', array()); $included_post_types = isset($settings['post_types']) ? $settings['post_types'] : array('post', 'page'); if (!in_array($post->post_type, $included_post_types)) { return; } // Schedule regeneration if not already scheduled if (!wp_next_scheduled('fulgid_aicogu_regenerate_file')) { wp_schedule_single_event(time() + 300, 'fulgid_aicogu_regenerate_file'); } } /** * Regenerate the llms.txt file. */ public function regenerate_file() { $content_analyzer = new FULGID_AICOGU_Content_Analyzer(); $file_manager = new FULGID_AICOGU_File_Manager(); // Get content $content = $content_analyzer->analyze_site_content(); // Generate and save file $file_manager->generate_file($content); } /** * Add rewrite rules for serving llms.txt file. */ public function add_rewrite_rules() { add_rewrite_rule( '^llms\.txt$', 'index.php?fulgid_aicogu_llms_txt=1', 'top' ); // Add rule for llms-full.txt add_rewrite_rule( '^llms-full\.txt$', 'index.php?fulgid_aicogu_llms_full_txt=1', 'top' ); } /** * Add custom query variables. * * @param array $vars Query variables. * @return array */ public function add_query_vars($vars) { $vars[] = 'fulgid_aicogu_llms_txt'; $vars[] = 'fulgid_aicogu_llms_full_txt'; return $vars; } /** * Prevent WordPress from redirecting llms.txt URLs. * * @param string $redirect_url The redirect URL. * @param string $requested_url The requested URL. * @return string|false */ public function prevent_llms_txt_redirect($redirect_url, $requested_url) { // Debug logging (remove in production) if (defined('WP_DEBUG') && WP_DEBUG) { error_log("LLMS.txt Redirect Debug - Requested: {$requested_url}, Redirect: {$redirect_url}"); } // Check if WordPress is trying to redirect TO a trailing slash version of llms.txt // Only prevent redirects when the destination has a trailing slash if (preg_match('/\/llms(-full)?\.txt\/$/', $redirect_url)) { if (defined('WP_DEBUG') && WP_DEBUG) { error_log("LLMS.txt Redirect - Prevented redirect for: {$requested_url}"); } return false; // Prevent redirect } return $redirect_url; } /** * Handle requests for llms.txt and llms-full.txt. */ public function handle_llms_txt_request() { $file_manager = new FULGID_AICOGU_File_Manager(); if (get_query_var('fulgid_aicogu_llms_txt')) { $file_manager = new FULGID_AICOGU_File_Manager(); $content = $file_manager->get_file_content(); header('Content-Type: text/markdown'); // For markdown content, we need to be careful with escaping to preserve formatting // while still ensuring security echo wp_kses($content, array( // Allow only specific markdown-related HTML 'h1' => array(), 'h2' => array(), 'h3' => array(), 'p' => array(), 'a' => array('href' => array(), 'title' => array()), 'ul' => array(), 'ol' => array(), 'li' => array(), 'blockquote' => array(), 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(), 'br' => array(), )); exit; } // Handle llms-full.txt requests if (get_query_var('fulgid_aicogu_llms_full_txt')) { $content = $file_manager->get_full_file_content(); header('Content-Type: text/markdown'); // For markdown content, we need to be careful with escaping to preserve formatting // while still ensuring security echo wp_kses($content, array( // Allow only specific markdown-related HTML 'h1' => array(), 'h2' => array(), 'h3' => array(), 'p' => array(), 'a' => array('href' => array(), 'title' => array()), 'ul' => array(), 'ol' => array(), 'li' => array(), 'blockquote' => array(), 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(), 'br' => array(), )); exit; } } /** * Add plugin action links. * * @param array $links Plugin action links. * @return array */ public function add_plugin_action_links($links) { $plugin_links = array( '' . esc_html__('Settings', 'ai-content-guide-llms-text-generator') . '', ); return array_merge($plugin_links, $links); } } // Initialize the plugin function fulgid_aicogu_init() { FULGID_AICOGU_Content_Guide::get_instance(); } add_action('plugins_loaded', 'fulgid_aicogu_init');