fm = new FiveNamesLlmTxt_File_Manager(); $this->gen = new FiveNamesLlmTxt_Generator(); $this->history = new FiveNamesLlmTxt_History(); $this->importer = new FiveNamesLlmTxt_Importer(); add_action( 'admin_menu', [ $this, 'register_menu' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); add_action( 'admin_notices', [ $this, 'show_notices' ] ); add_action( 'wp_ajax_fivenames_llmtxt_save', [ $this, 'ajax_save' ] ); add_action( 'wp_ajax_fivenames_llmtxt_preview', [ $this, 'ajax_preview' ] ); add_action( 'wp_ajax_fivenames_llmtxt_restore', [ $this, 'ajax_restore' ] ); add_action( 'wp_ajax_fivenames_llmtxt_import', [ $this, 'ajax_import' ] ); add_action( 'wp_ajax_fivenames_llmtxt_save_raw', [ $this, 'ajax_save_raw' ] ); add_action( 'wp_ajax_fivenames_llmtxt_dismiss_notice', [ $this, 'ajax_dismiss_notice' ] ); } public function register_menu() { add_options_page( __( 'LLMs.txt Settings', '5names-llms-txt-manager' ), __( 'LLMs.txt', '5names-llms-txt-manager' ), 'manage_options', '5names-llms-txt-manager', [ $this, 'render_page' ] ); } public function enqueue_assets( $hook ) { if ( 'settings_page_5names-llms-txt-manager' !== $hook ) return; wp_enqueue_style( 'fivenames-llmtxt-admin', FIVENAMES_LLMTXT_URL . 'admin/llms-admin.css', [], FIVENAMES_LLMTXT_VERSION ); wp_enqueue_script( 'fivenames-llmtxt-admin', FIVENAMES_LLMTXT_URL . 'admin/llms-admin.js', [ 'jquery' ], FIVENAMES_LLMTXT_VERSION, true ); $settings = get_option( 'fivenames_llmtxt_settings', [] ); wp_localize_script( 'fivenames-llmtxt-admin', 'fivenamesLlmtxtData', [ 'nonce' => wp_create_nonce( 'fivenames_llmtxt_nonce' ), 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'sections' => ! empty( $settings['sections'] ) ? $settings['sections'] : [], 'i18n' => [ 'confirmDeleteSection' => __( 'Delete this section and all its links?', '5names-llms-txt-manager' ), 'confirmRestore' => __( 'Overwrite the current llms.txt with this backup? This cannot be undone.', '5names-llms-txt-manager' ), 'saveRawLabel' => __( 'Save source to file', '5names-llms-txt-manager' ), 'saveVisualLabel' => __( 'Save & write to file', '5names-llms-txt-manager' ), 'connectionError' => __( 'Connection error — please try again.', '5names-llms-txt-manager' ), 'importing' => __( 'Importing…', '5names-llms-txt-manager' ), 'importButton' => __( 'Import existing file', '5names-llms-txt-manager' ), 'unknownError' => __( 'Unknown error', '5names-llms-txt-manager' ), 'errorPrefix' => __( 'Error: ', '5names-llms-txt-manager' ), 'restoring' => __( 'Restoring…', '5names-llms-txt-manager' ), 'restoreButton' => __( 'Restore', '5names-llms-txt-manager' ), 'labelPlaceholder' => __( 'Label', '5names-llms-txt-manager' ), 'urlPlaceholder' => __( 'https://...', '5names-llms-txt-manager' ), 'descPlaceholder' => __( 'Short description (optional)', '5names-llms-txt-manager' ), 'removeLink' => __( 'Remove link', '5names-llms-txt-manager' ), 'moveUp' => __( 'Move up', '5names-llms-txt-manager' ), 'moveDown' => __( 'Move down', '5names-llms-txt-manager' ), 'sectionNamePlaceholder' => __( 'Section name (e.g. Competitions)', '5names-llms-txt-manager' ), 'removeSection' => __( 'Remove section', '5names-llms-txt-manager' ), 'addLink' => __( 'Add link', '5names-llms-txt-manager' ), ], ] ); } public function render_page() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Access denied.', '5names-llms-txt-manager' ) ); } $settings = get_option( 'fivenames_llmtxt_settings', [] ); $cpts = $this->gen->get_custom_post_types(); $backups = $this->history->get_backups(); $preview = $this->gen->generate( $settings ); $file_manager = $this->fm; $generator = $this->gen; $raw_content = $this->fm->read(); $has_import_notice = (bool) get_transient( 'fivenames_llmtxt_existing_file_notice' ); $sitemap_provider = $this->gen->detect_sitemap_provider(); $sitemap_url = $this->gen->get_sitemap_url(); include FIVENAMES_LLMTXT_PATH . 'admin/settings-page.php'; } // ── AJAX: opslaan (visueel) ─────────────────────────────────── public function ajax_save() { check_ajax_referer( 'fivenames_llmtxt_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_die(); if ( ! $this->fm->is_writable() ) { wp_send_json_error( [ 'message' => sprintf( /* translators: %s: absolute path to the llms.txt file */ __( 'No write permission for %s.', '5names-llms-txt-manager' ), esc_html( FIVENAMES_LLMTXT_FILE ) ) ] ); } $settings = $this->sanitize_settings( $_POST ); update_option( 'fivenames_llmtxt_settings', $settings ); if ( $this->fm->exists() ) { $this->history->backup( $this->fm->read() ); } $content = $this->gen->generate( $settings ); $written = $this->fm->write( $content ); if ( $written ) { $this->maybe_fire_webhook( $settings ); wp_send_json_success( [ 'message' => sprintf( /* translators: %s: date and time of the save, in UTC */ __( 'Saved & written on %s UTC.', '5names-llms-txt-manager' ), gmdate( 'd-m-Y H:i:s' ) ), 'content' => $content, 'size' => size_format( strlen( $content ) ), ] ); } else { wp_send_json_error( [ 'message' => __( 'Save failed — check the file permissions.', '5names-llms-txt-manager' ) ] ); } } // ── AJAX: opslaan (broncode) ────────────────────────────────── public function ajax_save_raw() { check_ajax_referer( 'fivenames_llmtxt_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_die(); if ( ! $this->fm->is_writable() ) { wp_send_json_error( [ 'message' => sprintf( /* translators: %s: absolute path to the llms.txt file */ __( 'No write permission for %s.', '5names-llms-txt-manager' ), esc_html( FIVENAMES_LLMTXT_FILE ) ) ] ); } $content = isset( $_POST['content'] ) ? wp_strip_all_tags( wp_unslash( $_POST['content'] ) ) : ''; $content = str_replace( [ "\0", "\r\n", "\r" ], [ '', "\n", "\n" ], $content ); if ( $this->fm->exists() ) { $this->history->backup( $this->fm->read() ); } $written = $this->fm->write( $content ); if ( $written ) { $settings = get_option( 'fivenames_llmtxt_settings', [] ); $this->maybe_fire_webhook( $settings ); wp_send_json_success( [ 'message' => sprintf( /* translators: %s: date and time of the save, in UTC */ __( 'Source saved on %s UTC.', '5names-llms-txt-manager' ), gmdate( 'd-m-Y H:i:s' ) ), 'size' => size_format( strlen( $content ) ), ] ); } else { wp_send_json_error( [ 'message' => __( 'Save failed — check the file permissions.', '5names-llms-txt-manager' ) ] ); } } // ── AJAX: voorbeeld ─────────────────────────────────────────── public function ajax_preview() { check_ajax_referer( 'fivenames_llmtxt_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_die(); $settings = $this->sanitize_settings( $_POST ); wp_send_json_success( [ 'content' => $this->gen->generate( $settings ) ] ); } // ── AJAX: herstellen ────────────────────────────────────────── public function ajax_restore() { check_ajax_referer( 'fivenames_llmtxt_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_die(); $index = isset( $_POST['index'] ) ? intval( $_POST['index'] ) : 0; $result = $this->history->restore( $index ); if ( $result ) { wp_send_json_success( [ 'message' => __( 'Backup restored as the active llms.txt.', '5names-llms-txt-manager' ) ] ); } else { wp_send_json_error( [ 'message' => __( 'Restore failed — backup not found.', '5names-llms-txt-manager' ) ] ); } } // ── AJAX: importeer bestaand bestand ────────────────────────── public function ajax_import() { check_ajax_referer( 'fivenames_llmtxt_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_die(); if ( ! $this->fm->exists() ) { wp_send_json_error( [ 'message' => __( 'No existing llms.txt file found.', '5names-llms-txt-manager' ) ] ); } $content = $this->fm->read(); $parsed = $this->importer->parse( $content ); $summary = $this->importer->summarize( $parsed ); // Bestaande webhook-instelling bewaren (staat niet in het bestand). $existing = get_option( 'fivenames_llmtxt_settings', [] ); if ( ! empty( $existing['webhook_url'] ) && empty( $parsed['webhook_url'] ) ) { $parsed['webhook_url'] = $existing['webhook_url']; } update_option( 'fivenames_llmtxt_settings', $parsed ); delete_transient( 'fivenames_llmtxt_existing_file_notice' ); wp_send_json_success( [ 'message' => sprintf( /* translators: %s: summary of what was imported, e.g. "3 sections, 5 links imported." */ __( 'Import successful! %s Reloading page…', '5names-llms-txt-manager' ), $summary ), ] ); } // ── AJAX: verberg activeringsmelding ────────────────────────── public function ajax_dismiss_notice() { check_ajax_referer( 'fivenames_llmtxt_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_die(); delete_transient( 'fivenames_llmtxt_existing_file_notice' ); wp_send_json_success(); } // ── Notices ─────────────────────────────────────────────────── public function show_notices() { if ( ! current_user_can( 'manage_options' ) ) return; // Bestaand-bestand-melding (op alle admin-pagina's). if ( get_transient( 'fivenames_llmtxt_existing_file_notice' ) ) { $settings_url = admin_url( 'options-general.php?page=5names-llms-txt-manager' ); echo '
' . esc_html__( '5Names LLMs.txt Manager:', '5names-llms-txt-manager' ) . ' ';
printf(
/* translators: %s: link to the plugin settings page */
wp_kses( __( 'An /llms.txt file already exists. %s and click Import existing file to load the current content as a starting point.', '5names-llms-txt-manager' ), [ 'code' => [], 'strong' => [] ] ),
'' . esc_html__( 'Go to Settings → LLMs.txt', '5names-llms-txt-manager' ) . ''
);
echo '
';
echo '' . esc_html__( '5Names LLMs.txt Manager:', '5names-llms-txt-manager' ) . ' ';
printf(
/* translators: %s: absolute path to the WordPress root directory */
wp_kses( __( 'The directory %s is not writable. Fix the file permissions (chmod 755).', '5names-llms-txt-manager' ), [ 'strong' => [], 'code' => [] ] ),
'' . esc_html( ABSPATH ) . ''
);
echo '