Plugin Directory

Changeset 3663834


Ignore:
Timestamp:
08/24/2026 03:47:47 PM (2 months ago)
Author:
theseo
Message:

2.0.0: blok met externe verwijzingen verwijderd, llms.txt-standaard bijgewerkt

Location:
theseo-llms-txt-generator
Files:
14 added
6 edited
1 copied

Legend:

Unmodified
Added
Removed
  • theseo-llms-txt-generator/tags/2.0.0/assets/css/admin.css

    r3469672 r3663834  
    4141    font-size: 12px;
    4242}
     43
     44/* Aandachtspunten */
     45.theseo-llms-warnings ul {
     46    margin: 0 0 12px 18px;
     47    list-style: disc;
     48}
     49
     50.theseo-llms-warnings li {
     51    margin: 2px 0;
     52}
     53
     54.theseo-llms-admin .form-table textarea.code {
     55    font-size: 12px;
     56    line-height: 1.5;
     57}
     58
     59.theseo-llms-panel p {
     60    margin: 0;
     61    line-height: 1.6;
     62}
  • theseo-llms-txt-generator/tags/2.0.0/readme.txt

    r3469672 r3663834  
    11=== TheSEO llms txt Generator ===
    22Contributors: theseo
    3 Tags: ai optimalisation, seo, llms, chatgpt, gemini
    4 Requires at least: 5.8
    5 Tested up to: 6.8
     3Tags: llms, llms-txt, ai, seo, chatgpt
     4Requires at least: 6.0
     5Tested up to: 7.0
    66Requires PHP: 7.4
    7 Stable tag: 1.1.2
     7Stable tag: 2.0.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
     11Zet een llms.txt volgens de llms.txt standaard op /llms.txt, opgebouwd uit de gegevens die je in de WordPress admin invult.
     12
    1113== Description ==
    1214
    13 TheSEO llms txt Generator creates a dynamic llms txt file at /llms.txt based on your WordPress settings. 
    14 llms txt is a helper file for modern language models such as ChatGPT, Perplexity and Google Gemini. 
    15 It defines your main topics, clusters, content context and citation preferences so AI crawlers understand your site better.
     15TheSEO llms txt Generator serveert een llms.txt bestand op /llms.txt. Het bestand wordt bij elk verzoek opgebouwd uit je instellingen, dus je hoeft niets te uploaden en niets bij te werken via FTP.
    1616
    17 Features:
     17Het bestand volgt de opbouw van de llms.txt standaard (llmstxt.org):
    1818
    19 * Dynamic llms txt output at /llms.txt
    20 * Multilingual admin (Dutch + English)
    21 * Customisable topics, clusters and context
    22 * Adjustable citation preferences
    23 * Optional attribution link in the footer
    24 * Non-intrusive implementation
     19* een titelregel met de naam van je site, het enige verplichte onderdeel
     20* een citaatregel met de samenvatting van je site
     21* vrije tekst met je kernfeiten, zonder koppen
     22* een sectie Belangrijkste pagina's met markdown links en een korte omschrijving per link
     23* een sectie Optioneel, die een agent mag overslaan als de ruimte krap is
     24* een sectie Citatievoorkeur
     25* een sectie Minder belangrijk met paden die je liever niet als bron terugziet
    2526
    26 Developed by https://www.theseo.nl
     27Wat het wel en niet is: een llms.txt is een voorstel aan taalmodellen, geen technische blokkade zoals robots.txt. Op het moment van uitgifte heeft geen enkele grote AI-aanbieder toegezegd het bestand van externe sites te lezen; Google heeft expliciet gezegd het niet te gebruiken voor AI Overviews. Wat het bestand wel doet: het geeft een agent die je site ophaalt in een keer een leesbaar overzicht van wat je aanbiedt en welke pagina's ertoe doen. Aanbieders als Anthropic en OpenAI publiceren zelf zulke bestanden voor hun documentatie. Verwacht dus een leesbaar visitekaartje voor agents, geen ranking factor.
     28
     29Wat de plugin doet:
     30
     31* llms.txt op /llms.txt, opgebouwd uit je instellingen
     32* knop om je gepubliceerde pagina's en laatste berichten als linklijst over te nemen
     33* controlepaneel dat meldt wat er nog ontbreekt, of er al een vast llms.txt bestand in de weg staat en of WordPress in een submap draait
     34* voorbeeld van het volledige bestand op de instellingenpagina
     35* Nederlandse en Engelse labels, afhankelijk van de taal van de site
     36* drie optionele extra's die standaard uit staan: een commentaarregel in robots.txt, een regel bronvermelding onderaan het bestand en een kleine link in de voettekst
     37
     38De plugin schrijft een optie in de database en verder niets. Bij verwijderen wordt die optie weer opgeruimd.
     39
     40Gemaakt en onderhouden door https://www.theseo.nl
    2741
    2842== Installation ==
    2943
    30 1. Upload the `theseo-llms-txt-generator` folder to the `/wp-content/plugins/` directory, or upload the zip via the WordPress plugin installer.
    31 2. Activate the plugin through the "Plugins" menu in WordPress.
    32 3. Go to "Settings → llms txt generator".
    33 4. Fill in your site information and save.
    34 5. Visit `https://yourdomain.com/llms.txt` to confirm the output.
     441. Upload de map `theseo-llms-txt-generator` naar `/wp-content/plugins/`, of upload de zip via Plugins, Nieuwe plugin, Plugin uploaden.
     452. Activeer de plugin via het menu Plugins.
     463. Ga naar Instellingen, llms.txt generator.
     474. Vul de naam, de samenvatting en je belangrijkste pagina's in. De knop Vul aan met mijn gepubliceerde pagina's doet het grootste deel van dat werk.
     485. Sla op en open https://jouwdomein.nl/llms.txt.
    3549
    3650== Frequently Asked Questions ==
    3751
    38 = Where is my llms txt file located? =
    39 After activation and saving your settings, it is automatically available at /llms.txt.
     52= Waar staat mijn llms.txt? =
     53Op /llms.txt, direct achter je domeinnaam. Draait WordPress in een submap, dan komt het bestand in die submap te staan en meldt de instellingenpagina dat de standaard het bestand in de root van het domein verwacht.
    4054
    41 = Does this plugin work with every WordPress theme? =
    42 Yes. It works independently of your theme.
     55= Er staat al een llms.txt bestand op mijn server. Wat gebeurt er dan? =
     56Dan levert de webserver dat bestand uit en komt de plugin niet aan de beurt. De instellingenpagina waarschuwt hiervoor. Verwijder het vaste bestand als je de plugin wilt gebruiken.
    4357
    44 = Does this plugin modify my database? =
    45 It only stores settings in one WordPress option.
     58= Werkt de plugin met elk thema? =
     59Ja. De plugin vangt het verzoek op voordat het thema aan de beurt is.
    4660
    47 = Does it add hidden backlinks? =
    48 Only optional attribution, visible to users, which can be disabled at any time.
     61= Werkt het zonder mooie permalinks? =
     62Ja. Naast de rewrite regel kijkt de plugin ook zelf naar het opgevraagde pad, zodat /llms.txt ook werkt als de permalinks op standaard staan.
     63
     64= Verandert de plugin mijn database? =
     65De plugin bewaart twee opties: je instellingen en het versienummer. Bij verwijderen via het beheerscherm worden ze allebei gewist.
     66
     67= Voegt de plugin verborgen links toe? =
     68Nee. In versie 1.x stond er een blok met verwijzingen naar andere projecten van TheSEO in elk gegenereerd bestand, en dat kon niet uit. Dat blok is in 2.0.0 verwijderd. Wat er nu is, staat standaard uit en is per stuk aan te zetten: een commentaarregel in robots.txt, een regel bronvermelding onderaan het bestand en een link in de voettekst.
     69
     70= Kan ik met dit bestand AI tegenhouden? =
     71Nee. De citatievoorkeur is een verzoek, geen blokkade. Wil je crawlers echt weren, gebruik dan robots.txt of blokkeer de user agents op serverniveau.
    4972
    5073== Changelog ==
    5174
     75= 2.0.0 =
     76* Uitvoer volgt nu de llms.txt standaard: een H1 met de naam, een blockquote met de samenvatting, vrije tekst en secties met markdown links. Versie 1.x schreef een zelfbedacht formaat met regels als "Site:", "Allow: /", "Focus:" en "Cite:" dat geen enkele llms.txt lezer als llms.txt herkent.
     77* Verwijderd: het vaste blok met zes verwijzingen naar andere projecten dat bovenaan elk gegenereerd bestand stond en niet uit te zetten was. Die regels begonnen met een hekje en werden door markdown gelezen als negen koppen voor de eigenlijke inhoud, waardoor de verplichte enkele H1 ontbrak.
     78* Nieuw: lijsten met belangrijkste pagina's en optionele pagina's in de vorm /pad/ | Titel | Omschrijving, met een knop die je gepubliceerde pagina's en laatste berichten overneemt.
     79* Nieuw: controlepaneel op de instellingenpagina dat meldt wat ontbreekt, of er al een vast llms.txt bestand in de weg staat, of WordPress in een submap draait en of de permalinks op standaard staan.
     80* Nieuw: uninstall.php, zodat de opties bij verwijderen worden opgeruimd, ook op multisite. Versie 1.x liet ze staan.
     81* Gewijzigd: deactiveren wist nu het rewrite_rules record in plaats van flush_rewrite_rules() aan te roepen. Dat laatste schreef de eigen regel juist opnieuw weg, omdat de plugin op dat moment nog draaide.
     82* Nieuw: vangnet voor sites zonder mooie permalinks, zodat /llms.txt ook daar antwoordt.
     83* Nieuw: expliciete 200 status en X-Content-Type-Options nosniff op het antwoord, plus een correct antwoord op een HEAD verzoek.
     84* Gewijzigd: de voettekstlink staat standaard uit in plaats van aan.
     85* Nieuw: optionele commentaarregel met het adres van de llms.txt in de door WordPress geleverde robots.txt, standaard uit.
     86* Beveiliging: invoer wordt nu opgeschoond met sanitize_text_field en sanitize_textarea_field in plaats van wp_kses_post, zodat er geen HTML in een tekstbestand terechtkomt. Regels die geen pad of http adres zijn, zoals javascript:, worden overgeslagen.
     87* Beveiliging: de rechtencontrole eindigt nu in wp_die() in plaats van een lege pagina, en elke uitvoer in de admin wordt geescaped.
     88* Compatibiliteit: geschreven voor PHP 7.4 en hoger en voor WordPress 6.0 en hoger, tegen de API van WordPress 7.0 (uitgekomen 20 mei 2026, ondersteunt PHP 7.4 tot en met 8.5). De code is gecontroleerd op PHP 8.2: syntaxcontrole op alle bestanden plus losse tests van de bouwer met lege, volle, verlopen en foutieve invoer. Een installatie op een draaiende WordPress 7.0 site hoort bij de acceptatie, zie de testinstructie bij de uitgifte. Opties worden voortaan als tekst behandeld, zodat trim() op een lege waarde geen melding meer geeft op PHP 8.1 en hoger.
     89* Headers aangevuld: Requires at least, Requires PHP, License URI, Text Domain en Plugin URI. Bewust geen Update URI: deze plugin staat in de officiele WordPress pluginmap, en WordPress levert een update alleen uit als die kopregel ontbreekt of naar wordpress.org wijst. Met een eigen adres erin krijgt niemand ooit nog een update binnen.
     90* Code opgesplitst in includes/options.php, includes/builder.php, includes/admin.php en includes/output.php.
     91* Migratie: bestaande instellingen uit 1.x blijven behouden. De oude velden onderwerpen, clusters en taal verhuizen naar het veld Kernfeiten, de belangrijkste sectie wordt de eerste regel van de paginalijst, en de context wordt de samenvatting.
     92
    5293= 1.1.2 =
    53 * Moved admin inline styles into a separate CSS file loaded via wp_enqueue_style.
    54 * Improved compatibility with WordPress.org plugin guidelines.
     94* Inline stijlen in de admin verplaatst naar een apart CSS bestand via wp_enqueue_style.
     95* Betere aansluiting op de richtlijnen van WordPress.org.
    5596
    5697= 1.1.1 =
    57 * Improved stability
    58 * Better multilingual labels
    59 * Added WordPress.org-ready readme
     98* Stabiliteit verbeterd.
     99* Betere meertalige labels.
     100* Readme geschikt gemaakt voor WordPress.org.
    60101
    61102= 1.1.0 =
    62 * Added bilingual admin labels (Dutch + English)
    63 * Added optional footer attribution
    64 * Added branding comments in llms txt output
     103* Tweetalige labels in de admin, Nederlands en Engels.
     104* Optionele link in de voettekst.
     105* Merkregels in de uitvoer van llms txt.
    65106
    66107= 1.0.0 =
    67 * Initial release
     108* Eerste uitgave.
    68109
    69110== Upgrade Notice ==
    70111
     112= 2.0.0 =
     113Belangrijke update. Het gegenereerde bestand volgt vanaf nu de llms.txt standaard; het formaat van 1.x werd door geen enkele lezer herkend. Je bestaande instellingen blijven behouden en verhuizen naar het juiste veld. Loop na de update Instellingen, llms.txt generator een keer na en controleer het voorbeeld onderaan die pagina.
     114
    71115= 1.1.2 =
    72 Recommended update. Moves inline admin styles into proper enqueued CSS to comply with WordPress.org guidelines.
    73 
    74 = 1.1.1 =
    75 Important for WordPress.org submission. Adds full readme compliance.
    76 
     116Aanbevolen update. Verplaatst de inline stijlen in de admin naar een enqueued CSS bestand.
  • theseo-llms-txt-generator/tags/2.0.0/theseo-llms-txt-generator.php

    r3469672 r3663834  
    11<?php
    2 /*
    3 Plugin Name: TheSEO llms txt Generator
    4 Description: Genereert automatisch een llms txt bestand op /llms.txt op basis van instellingen in de WordPress admin.
    5 Version: 1.1.2
    6 Author: TheSEO
    7 Author URI: https://www.theseo.nl
    8 License: GPL2
    9 */
     2/**
     3 * Plugin Name: TheSEO llms txt Generator
     4 * Plugin URI: https://www.theseo.nl/tools-en-plugins/llms-txt-zelf-maken-generator/
     5 * Description: Zet een llms.txt volgens de llms.txt standaard op /llms.txt, opgebouwd uit de gegevens die je in de WordPress admin invult.
     6 * Version: 2.0.0
     7 * Requires at least: 6.0
     8 * Tested up to: 7.0
     9 * Requires PHP: 7.4
     10 * Author: TheSEO
     11 * Author URI: https://www.theseo.nl
     12 * License: GPLv2 or later
     13 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
     14 * Text Domain: theseo-llms-txt-generator
     15 *
     16 * Geen Update URI header. Deze plugin staat in de officiele WordPress
     17 * pluginmap, en WordPress werkt een plugin alleen bij als die header
     18 * ontbreekt of naar wordpress.org wijst. Met een eigen adres erin krijgt
     19 * niemand ooit nog een update binnen.
     20 *
     21 * @package TheSEO_LLMS_Txt_Generator
     22 */
    1023
    11 if (!defined('ABSPATH')) {
    12     exit;
     24if ( ! defined( 'ABSPATH' ) ) {
     25        exit;
     26}
     27
     28define( 'THESEO_LLMS_VERSION', '2.0.0' );
     29define( 'THESEO_LLMS_FILE', __FILE__ );
     30define( 'THESEO_LLMS_DIR', plugin_dir_path( __FILE__ ) );
     31define( 'THESEO_LLMS_URL', plugin_dir_url( __FILE__ ) );
     32
     33require_once THESEO_LLMS_DIR . 'includes/options.php';
     34require_once THESEO_LLMS_DIR . 'includes/builder.php';
     35require_once THESEO_LLMS_DIR . 'includes/output.php';
     36
     37if ( is_admin() ) {
     38        require_once THESEO_LLMS_DIR . 'includes/admin.php';
    1339}
    1440
    1541/**
    16  * Eenvoudige vertaal helper
    17  * NL site = Nederlands, anders Engels
     42 * Activatie: rewrite regel registreren, rewrites verversen en de opties zaaien.
     43 *
     44 * @return void
    1845 */
    19 function theseo_llms_t($en, $nl) {
    20     $locale = get_locale();
    21     if (strpos($locale, 'nl_') === 0) {
    22         return $nl;
    23     }
    24     return $en;
     46function theseo_llms_activate() {
     47        theseo_llms_add_rewrite_rule();
     48        flush_rewrite_rules();
     49        theseo_llms_seed_options();
     50        update_option( 'theseo_llms_version', THESEO_LLMS_VERSION );
    2551}
     52register_activation_hook( __FILE__, 'theseo_llms_activate' );
    2653
    2754/**
    28  * Optie sleutel
     55 * Deactivatie: onze rewrite regel weer uit de opgeslagen regels halen.
     56 *
     57 * flush_rewrite_rules() zou onze eigen regel juist opnieuw wegschrijven, want
     58 * op dit moment draait de plugin nog. Het rewrite_rules record wissen dwingt
     59 * WordPress om de regels bij het eerstvolgende bezoek opnieuw op te bouwen,
     60 * dan zonder deze plugin.
     61 *
     62 * @return void
    2963 */
    30 function theseo_llms_option_key() {
    31     return 'theseo_llms_options';
     64function theseo_llms_deactivate() {
     65        delete_option( 'rewrite_rules' );
    3266}
    33 
    34 /**
    35  * Standaard opties
    36  */
    37 function theseo_llms_default_options() {
    38     return array(
    39         'site_name'        => get_bloginfo('name'),
    40         'site_url'         => home_url('/'),
    41         'language'         => 'nl',
    42         'priority_path'    => '/blog/',
    43         'topics'           => "WordPress optimalisatie\nSEO strategie\nAI ready content\nwebsite snelheid\nsemantische seo",
    44         'clusters'         => 'wordpress, seo, ai seo, website snelheid, content strategie',
    45         'context'          => theseo_llms_t(
    46             'This website provides guides about WordPress optimisation, SEO strategy, website speed and AI ready content structures.',
    47             'Deze website biedt gidsen over WordPress optimalisatie SEO strategie website snelheid en AI gerichte content structuren.'
    48         ),
    49         'block_paths'      => "/wp-admin/\n/privacy-policy/\n/algemene-voorwaarden/",
    50         'citation'         => 'full',
    51         'show_attribution' => 1,
    52     );
    53 }
    54 
    55 /**
    56  * Opties ophalen
    57  */
    58 function theseo_llms_get_options() {
    59     $defaults = theseo_llms_default_options();
    60     $stored   = get_option(theseo_llms_option_key(), array());
    61     if (!is_array($stored)) {
    62         $stored = array();
    63     }
    64     return wp_parse_args($stored, $defaults);
    65 }
    66 
    67 /**
    68  * llms txt inhoud bouwen
    69  */
    70 function theseo_llms_build_txt($opts = null) {
    71     if ($opts === null) {
    72         $opts = theseo_llms_get_options();
    73     }
    74 
    75     $site_name     = trim($opts['site_name']);
    76     $site_url      = trim($opts['site_url']);
    77     $language      = isset($opts['language']) ? $opts['language'] : 'nl';
    78     $priority_path = trim($opts['priority_path']);
    79     $topics_raw    = trim($opts['topics']);
    80     $clusters_raw  = trim($opts['clusters']);
    81     $context_raw   = trim($opts['context']);
    82     $block_raw     = trim($opts['block_paths']);
    83     $citation_pref = isset($opts['citation']) ? $opts['citation'] : 'full';
    84 
    85     if ($site_url && substr($site_url, -1) !== '/') {
    86         $site_url .= '/';
    87     }
    88 
    89     $lines = array();
    90 
    91     // Branding en projecten als commentaar
    92     $lines[] = '# llms txt gegenereerd door TheSEO llms txt Generator';
    93     $lines[] = '# Ontwikkeld door TheSEO.nl (https://www.theseo.nl)';
    94     $lines[] = '# Gerelateerde projecten:';
    95     $lines[] = '# https://swap.coupons';
    96     $lines[] = '# https://thewooden.house';
    97     $lines[] = '# https://wittetanden.org';
    98     $lines[] = '# https://mansotti.com';
    99     $lines[] = '# https://swap.place';
    100     $lines[] = '# https://pawwss.com';
    101     $lines[] = '# Basis informatie voor taalmodellen';
    102     $lines[] = '';
    103 
    104     $lines[] = 'Site: ' . ($site_name ? $site_name : 'Mijn website');
    105     $lines[] = 'URL: ' . ($site_url ? $site_url : home_url('/'));
    106 
    107     if ($language === 'nl') {
    108         $lines[] = 'Language: nl';
    109     } elseif ($language === 'en') {
    110         $lines[] = 'Language: en';
    111     } else {
    112         $lines[] = 'Language: mixed';
    113     }
    114 
    115     $lines[] = '';
    116     $lines[] = 'Allow: /';
    117 
    118     if ($block_raw !== '') {
    119         $lines[] = '';
    120         $lines[] = '# Minder relevante paden voor AI crawlers';
    121         $block_lines = preg_split('/\R+/', $block_raw);
    122         if (is_array($block_lines)) {
    123             $block_lines = array_filter(array_map('trim', $block_lines));
    124             foreach ($block_lines as $path) {
    125                 $lines[] = 'Deprioritise: ' . $path;
    126             }
    127         }
    128     }
    129 
    130     if ($priority_path !== '') {
    131         $lines[] = '';
    132         $lines[] = '# Belangrijke sectie met veel inhoudelijke diepte';
    133         $lines[] = 'Priority: ' . $priority_path;
    134     }
    135 
    136     if ($topics_raw !== '') {
    137         $lines[] = '';
    138         $lines[] = '# Hoofd onderwerpen waarop deze site autoriteit wil opbouwen';
    139         $lines[] = 'Focus:';
    140         $topic_lines = preg_split('/\R+/', $topics_raw);
    141         if (is_array($topic_lines)) {
    142             $topic_lines = array_filter(array_map('trim', $topic_lines));
    143             foreach ($topic_lines as $t) {
    144                 $lines[] = '- ' . $t;
    145             }
    146         }
    147     }
    148 
    149     if ($clusters_raw !== '') {
    150         $lines[] = '';
    151         $lines[] = '# Clusters en hoofd thema’s van de site';
    152         $lines[] = 'Clusters:';
    153         $cluster_lines = explode(',', $clusters_raw);
    154         $cluster_lines = array_filter(array_map('trim', $cluster_lines));
    155         foreach ($cluster_lines as $c) {
    156             $lines[] = '- ' . $c;
    157         }
    158     }
    159 
    160     if ($context_raw !== '') {
    161         $lines[] = '';
    162         $lines[] = '# Context zodat AI de positionering van deze site begrijpt';
    163         $lines[] = 'Context:';
    164         $ctx_lines = preg_split('/\R+/', $context_raw);
    165         if (is_array($ctx_lines)) {
    166             foreach ($ctx_lines as $line) {
    167                 $lines[] = $line;
    168             }
    169         }
    170     }
    171 
    172     $lines[] = '';
    173     $lines[] = '# Richt lijnen voor citatie';
    174 
    175     if ($citation_pref === 'full') {
    176         $lines[] = 'Cite: You may quote definitions checklists and step by step instructions from this site verbatim in answers.';
    177     } elseif ($citation_pref === 'partial') {
    178         $lines[] = 'Cite: You may quote short fragments and single paragraphs from this site but prefer summaries in your own words.';
    179     } else {
    180         $lines[] = 'Cite: Do not quote this site verbatim. You may use the content as background and provide your own summaries.';
    181     }
    182 
    183     $lines[] = '';
    184     $lines[] = '# Einde llms txt';
    185 
    186     return implode("\n", $lines);
    187 }
    188 
    189 /**
    190  * Admin CSS/JS enqueuen
    191  */
    192 function theseo_llms_admin_assets($hook) {
    193     // Alleen op de instellingenpagina van deze plugin:
    194     // options-general.php?page=theseo-llms-generator => hook: settings_page_theseo-llms-generator
    195     if ($hook !== 'settings_page_theseo-llms-generator') {
    196         return;
    197     }
    198 
    199     $css_path = plugin_dir_path(__FILE__) . 'assets/css/admin.css';
    200 
    201     wp_register_style(
    202         'theseo-llms-admin-css',
    203         plugin_dir_url(__FILE__) . 'assets/css/admin.css',
    204         array(),
    205         file_exists($css_path) ? filemtime($css_path) : '1.0.0'
    206     );
    207 
    208     wp_enqueue_style('theseo-llms-admin-css');
    209 }
    210 add_action('admin_enqueue_scripts', 'theseo_llms_admin_assets');
    211 
    212 /**
    213  * Admin menu toevoegen
    214  */
    215 function theseo_llms_admin_menu() {
    216     add_options_page(
    217         theseo_llms_t('llms txt generator', 'llms txt generator'),
    218         theseo_llms_t('llms txt generator', 'llms txt generator'),
    219         'manage_options',
    220         'theseo-llms-generator',
    221         'theseo_llms_settings_page'
    222     );
    223 }
    224 add_action('admin_menu', 'theseo_llms_admin_menu');
    225 
    226 /**
    227  * Settings pagina renderen
    228  */
    229 function theseo_llms_settings_page() {
    230     if (!current_user_can('manage_options')) {
    231         return;
    232     }
    233 
    234     if (isset($_POST['theseo_llms_save'])) {
    235         check_admin_referer('theseo_llms_save_settings');
    236 
    237 $options = array();
    238 
    239 $site_name       = isset( $_POST['site_name'] ) ? wp_unslash( $_POST['site_name'] ) : '';
    240 $site_url        = isset( $_POST['site_url'] ) ? wp_unslash( $_POST['site_url'] ) : '';
    241 $language        = isset( $_POST['language'] ) ? wp_unslash( $_POST['language'] ) : 'nl';
    242 $priority_path   = isset( $_POST['priority_path'] ) ? wp_unslash( $_POST['priority_path'] ) : '';
    243 $topics_input    = isset( $_POST['topics'] ) ? wp_unslash( $_POST['topics'] ) : '';
    244 $clusters_input  = isset( $_POST['clusters'] ) ? wp_unslash( $_POST['clusters'] ) : '';
    245 $context_input   = isset( $_POST['context'] ) ? wp_unslash( $_POST['context'] ) : '';
    246 $block_paths_inp = isset( $_POST['block_paths'] ) ? wp_unslash( $_POST['block_paths'] ) : '';
    247 $citation_input  = isset( $_POST['citation'] ) ? wp_unslash( $_POST['citation'] ) : 'full';
    248 
    249 $options['site_name']        = sanitize_text_field( $site_name );
    250 $options['site_url']         = esc_url_raw( trim( $site_url ) );
    251 $options['language']         = sanitize_text_field( $language );
    252 $options['priority_path']    = trim( sanitize_text_field( $priority_path ) );
    253 $options['topics']           = trim( wp_kses_post( $topics_input ) );
    254 $options['clusters']         = trim( sanitize_text_field( $clusters_input ) );
    255 $options['context']          = trim( wp_kses_post( $context_input ) );
    256 $options['block_paths']      = trim( wp_kses_post( $block_paths_inp ) );
    257 $options['citation']         = sanitize_text_field( $citation_input );
    258 $options['show_attribution'] = isset( $_POST['show_attribution'] ) ? 1 : 0;
    259 
    260 
    261         update_option(theseo_llms_option_key(), $options);
    262 
    263         echo '<div class="updated"><p>' . esc_html(theseo_llms_t('Settings saved.', 'Instellingen opgeslagen.')) . '</p></div>';
    264     }
    265 
    266     $opts     = theseo_llms_get_options();
    267     $llms_url = home_url('/llms.txt');
    268     ?>
    269     <div class="wrap theseo-llms-admin">
    270         <h1><?php echo esc_html(theseo_llms_t('llms txt generator', 'llms txt generator')); ?></h1>
    271         <p>
    272             <?php echo esc_html(theseo_llms_t(
    273                 'This plugin generates a dynamic llms txt file that is available at',
    274                 'Deze plugin maakt automatisch een dynamisch llms txt bestand beschikbaar op'
    275             )); ?>
    276             <code><?php echo esc_html($llms_url); ?></code>
    277         </p>
    278 
    279         <div class="theseo-llms-panel">
    280             <p>
    281                 <strong><?php echo esc_html(theseo_llms_t('Developed by TheSEO', 'Ontwikkeld door TheSEO')); ?></strong><br>
    282                 <?php echo wp_kses_post(theseo_llms_t(
    283                     'This plugin is developed and maintained by <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>. It helps you prepare your site for modern AI crawlers like ChatGPT, Perplexity and Gemini.',
    284                     'Deze plugin is ontwikkeld en wordt onderhouden door <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>. De plugin helpt je site klaar te maken voor moderne AI crawlers zoals ChatGPT Perplexity en Gemini.'
    285                 )); ?>
    286             </p>
    287         </div>
    288 
    289         <form method="post" style="margin-top:20px;">
    290             <?php wp_nonce_field('theseo_llms_save_settings'); ?>
    291 
    292             <table class="form-table" role="presentation">
    293                 <tr>
    294                     <th scope="row"><label for="site_name"><?php echo esc_html(theseo_llms_t('Website name', 'Website naam')); ?></label></th>
    295                     <td>
    296                         <input type="text" id="site_name" name="site_name" class="regular-text"
    297                                value="<?php echo esc_attr($opts['site_name']); ?>">
    298                         <p class="description"><?php echo esc_html(theseo_llms_t('For example your brand or platform name.', 'Bijvoorbeeld de naam van je merk of platform.')); ?></p>
    299                     </td>
    300                 </tr>
    301 
    302                 <tr>
    303                     <th scope="row"><label for="site_url"><?php echo esc_html(theseo_llms_t('Base URL', 'Basis URL')); ?></label></th>
    304                     <td>
    305                         <input type="text" id="site_url" name="site_url" class="regular-text"
    306                                value="<?php echo esc_attr($opts['site_url']); ?>">
    307                         <p class="description">
    308                             <?php echo esc_html(theseo_llms_t('Without llms txt at the end.', 'Zonder llms txt erachter.')); ?>
    309                             <?php echo ' ' . esc_html(theseo_llms_t('Example', 'Bijvoorbeeld')) . ' ' . esc_html(home_url('/')); ?>
    310                         </p>
    311                     </td>
    312                 </tr>
    313 
    314                 <tr>
    315                     <th scope="row"><label for="language"><?php echo esc_html(theseo_llms_t('Language', 'Taal')); ?></label></th>
    316                     <td>
    317                         <select id="language" name="language">
    318                             <option value="nl" <?php selected($opts['language'], 'nl'); ?>>Nederlands</option>
    319                             <option value="en" <?php selected($opts['language'], 'en'); ?>>English</option>
    320                             <option value="mixed" <?php selected($opts['language'], 'mixed'); ?>>Meertalig</option>
    321                         </select>
    322                         <p class="description"><?php echo esc_html(theseo_llms_t('Signal for language models.', 'Signaal voor taalmodellen.')); ?></p>
    323                     </td>
    324                 </tr>
    325 
    326                 <tr>
    327                     <th scope="row"><label for="priority_path"><?php echo esc_html(theseo_llms_t('Primary section', 'Belangrijkste sectie')); ?></label></th>
    328                     <td>
    329                         <input type="text" id="priority_path" name="priority_path" class="regular-text"
    330                                value="<?php echo esc_attr($opts['priority_path']); ?>">
    331                         <p class="description"><?php echo esc_html(theseo_llms_t('For example /blog/ or /knowledge-base/.', 'Bijvoorbeeld /blog/ of /kennisbank/.')); ?></p>
    332                     </td>
    333                 </tr>
    334 
    335                 <tr>
    336                     <th scope="row"><label for="topics"><?php echo esc_html(theseo_llms_t('Main topics', 'Hoofd onderwerpen')); ?></label></th>
    337                     <td>
    338                         <textarea id="topics" name="topics" rows="5" class="large-text code"><?php echo esc_textarea($opts['topics']); ?></textarea>
    339                         <p class="description"><?php echo esc_html(theseo_llms_t('One topic per line. These are your focus areas.', 'Eén onderwerp per regel. Dit zijn je focus thema’s.')); ?></p>
    340                     </td>
    341                 </tr>
    342 
    343                 <tr>
    344                     <th scope="row"><label for="clusters"><?php echo esc_html(theseo_llms_t('Clusters', 'Clusters')); ?></label></th>
    345                     <td>
    346                         <input type="text" id="clusters" name="clusters" class="regular-text"
    347                                value="<?php echo esc_attr($opts['clusters']); ?>">
    348                         <p class="description"><?php echo esc_html(theseo_llms_t('Comma separated list of important themes.', 'Komma gescheiden lijst met belangrijke thema’s.')); ?></p>
    349                     </td>
    350                 </tr>
    351 
    352                 <tr>
    353                     <th scope="row"><label for="context"><?php echo esc_html(theseo_llms_t('Website context', 'Website context')); ?></label></th>
    354                     <td>
    355                         <textarea id="context" name="context" rows="4" class="large-text code"><?php echo esc_textarea($opts['context']); ?></textarea>
    356                         <p class="description"><?php echo esc_html(theseo_llms_t('Short explanation for AI about what your site does.', 'Korte uitleg voor AI over wat je site doet.')); ?></p>
    357                     </td>
    358                 </tr>
    359 
    360                 <tr>
    361                     <th scope="row"><label for="block_paths"><?php echo esc_html(theseo_llms_t('Lower priority paths', 'Minder relevante paden')); ?></label></th>
    362                     <td>
    363                         <textarea id="block_paths" name="block_paths" rows="4" class="large-text code"><?php echo esc_textarea($opts['block_paths']); ?></textarea>
    364                         <p class="description"><?php echo esc_html(theseo_llms_t('One path per line. These are treated as lower priority.', 'Eén pad per regel. Wordt als lagere prioriteit aangegeven.')); ?></p>
    365                     </td>
    366                 </tr>
    367 
    368                 <tr>
    369                     <th scope="row"><label for="citation"><?php echo esc_html(theseo_llms_t('Citation preference', 'Citatie voorkeur')); ?></label></th>
    370                     <td>
    371                         <select id="citation" name="citation">
    372                             <option value="full" <?php selected($opts['citation'], 'full'); ?>>
    373                                 <?php echo esc_html(theseo_llms_t(
    374                                     'AI may quote definitions checklists and step by step instructions verbatim',
    375                                     'AI mag definities checklists en stappenplannen letterlijk citeren'
    376                                 )); ?>
    377                             </option>
    378                             <option value="partial" <?php selected($opts['citation'], 'partial'); ?>>
    379                                 <?php echo esc_html(theseo_llms_t(
    380                                     'AI may quote short fragments but should prefer summaries',
    381                                     'AI mag korte fragmenten citeren maar liever samenvattingen'
    382                                 )); ?>
    383                             </option>
    384                             <option value="summary" <?php selected($opts['citation'], 'summary'); ?>>
    385                                 <?php echo esc_html(theseo_llms_t(
    386                                     'AI should not quote verbatim and only provide summaries',
    387                                     'AI mag niet letterlijk citeren en alleen samenvattingen geven'
    388                                 )); ?>
    389                             </option>
    390                         </select>
    391                     </td>
    392                 </tr>
    393 
    394                 <tr>
    395                     <th scope="row"><?php echo esc_html(theseo_llms_t('Attribution link', 'Attributie link')); ?></th>
    396                     <td>
    397                         <label>
    398                             <input type="checkbox" name="show_attribution" value="1" <?php checked($opts['show_attribution'], 1); ?>>
    399                             <?php echo esc_html(theseo_llms_t(
    400                                 'Show a small “Developed by TheSEO” link in the footer',
    401                                 'Toon een kleine “Ontwikkeld door TheSEO” link in de footer'
    402                             )); ?>
    403                         </label>
    404                         <p class="description">
    405                             <?php echo esc_html(theseo_llms_t(
    406                                 'Optional but helps users discover TheSEO.',
    407                                 'Optioneel maar helpt gebruikers om TheSEO te ontdekken.'
    408                             )); ?>
    409                         </p>
    410                     </td>
    411                 </tr>
    412             </table>
    413 
    414             <p class="submit">
    415                 <button type="submit" name="theseo_llms_save" class="button button-primary">
    416                     <?php echo esc_html(theseo_llms_t('Save settings', 'Instellingen opslaan')); ?>
    417                 </button>
    418             </p>
    419         </form>
    420 
    421         <h2><?php echo esc_html(theseo_llms_t('Preview of your current llms txt', 'Voorbeeld van het huidige llms txt')); ?></h2>
    422         <pre class="theseo-llms-preview"><?php
    423             echo esc_html(theseo_llms_build_txt($opts));
    424         ?></pre>
    425     </div>
    426     <?php
    427 }
    428 
    429 /**
    430  * Query var registreren
    431  */
    432 function theseo_llms_query_vars($vars) {
    433     $vars[] = 'theseo_llms_txt';
    434     return $vars;
    435 }
    436 add_filter('query_vars', 'theseo_llms_query_vars');
    437 
    438 /**
    439  * Rewrite regel voor llms txt
    440  */
    441 function theseo_llms_add_rewrite_rule() {
    442     add_rewrite_rule('^llms\.txt$', 'index.php?theseo_llms_txt=1', 'top');
    443 }
    444 add_action('init', 'theseo_llms_add_rewrite_rule');
    445 
    446 /**
    447  * Flush rewrites bij activatie en deactivatie
    448  */
    449 function theseo_llms_activate() {
    450     theseo_llms_add_rewrite_rule();
    451     flush_rewrite_rules();
    452 }
    453 register_activation_hook(__FILE__, 'theseo_llms_activate');
    454 
    455 function theseo_llms_deactivate() {
    456     flush_rewrite_rules();
    457 }
    458 register_deactivation_hook(__FILE__, 'theseo_llms_deactivate');
    459 
    460 /**
    461  * llms txt output
    462  */
    463 function theseo_llms_template_redirect() {
    464     $flag = get_query_var('theseo_llms_txt');
    465     if ($flag) {
    466         $opts = theseo_llms_get_options();
    467         $txt  = theseo_llms_build_txt($opts);
    468 
    469         nocache_headers();
    470 header( 'Content-Type: text/plain; charset=utf-8' );
    471 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- plain text response for llms.txt
    472 echo $txt;
    473 exit;
    474 
    475     }
    476 }
    477 add_action('template_redirect', 'theseo_llms_template_redirect');
    478 
    479 /**
    480  * Optionele footer link
    481  */
    482 function theseo_llms_footer_attribution() {
    483     $opts = theseo_llms_get_options();
    484     if (empty($opts['show_attribution'])) {
    485         return;
    486     }
    487     echo '<p style="text-align:center;font-size:11px;opacity:.65;margin:10px 0;">' .
    488          wp_kses_post(theseo_llms_t(
    489              'llms txt managed by <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>',
    490              'llms txt beheerd door <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>'
    491          )) .
    492          '</p>';
    493 }
    494 add_action('wp_footer', 'theseo_llms_footer_attribution');
    495 
     67register_deactivation_hook( __FILE__, 'theseo_llms_deactivate' );
  • theseo-llms-txt-generator/trunk/assets/css/admin.css

    r3469672 r3663834  
    4141    font-size: 12px;
    4242}
     43
     44/* Aandachtspunten */
     45.theseo-llms-warnings ul {
     46    margin: 0 0 12px 18px;
     47    list-style: disc;
     48}
     49
     50.theseo-llms-warnings li {
     51    margin: 2px 0;
     52}
     53
     54.theseo-llms-admin .form-table textarea.code {
     55    font-size: 12px;
     56    line-height: 1.5;
     57}
     58
     59.theseo-llms-panel p {
     60    margin: 0;
     61    line-height: 1.6;
     62}
  • theseo-llms-txt-generator/trunk/readme.txt

    r3469672 r3663834  
    11=== TheSEO llms txt Generator ===
    22Contributors: theseo
    3 Tags: ai optimalisation, seo, llms, chatgpt, gemini
    4 Requires at least: 5.8
    5 Tested up to: 6.8
     3Tags: llms, llms-txt, ai, seo, chatgpt
     4Requires at least: 6.0
     5Tested up to: 7.0
    66Requires PHP: 7.4
    7 Stable tag: 1.1.2
     7Stable tag: 2.0.0
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
     11Zet een llms.txt volgens de llms.txt standaard op /llms.txt, opgebouwd uit de gegevens die je in de WordPress admin invult.
     12
    1113== Description ==
    1214
    13 TheSEO llms txt Generator creates a dynamic llms txt file at /llms.txt based on your WordPress settings. 
    14 llms txt is a helper file for modern language models such as ChatGPT, Perplexity and Google Gemini. 
    15 It defines your main topics, clusters, content context and citation preferences so AI crawlers understand your site better.
     15TheSEO llms txt Generator serveert een llms.txt bestand op /llms.txt. Het bestand wordt bij elk verzoek opgebouwd uit je instellingen, dus je hoeft niets te uploaden en niets bij te werken via FTP.
    1616
    17 Features:
     17Het bestand volgt de opbouw van de llms.txt standaard (llmstxt.org):
    1818
    19 * Dynamic llms txt output at /llms.txt
    20 * Multilingual admin (Dutch + English)
    21 * Customisable topics, clusters and context
    22 * Adjustable citation preferences
    23 * Optional attribution link in the footer
    24 * Non-intrusive implementation
     19* een titelregel met de naam van je site, het enige verplichte onderdeel
     20* een citaatregel met de samenvatting van je site
     21* vrije tekst met je kernfeiten, zonder koppen
     22* een sectie Belangrijkste pagina's met markdown links en een korte omschrijving per link
     23* een sectie Optioneel, die een agent mag overslaan als de ruimte krap is
     24* een sectie Citatievoorkeur
     25* een sectie Minder belangrijk met paden die je liever niet als bron terugziet
    2526
    26 Developed by https://www.theseo.nl
     27Wat het wel en niet is: een llms.txt is een voorstel aan taalmodellen, geen technische blokkade zoals robots.txt. Op het moment van uitgifte heeft geen enkele grote AI-aanbieder toegezegd het bestand van externe sites te lezen; Google heeft expliciet gezegd het niet te gebruiken voor AI Overviews. Wat het bestand wel doet: het geeft een agent die je site ophaalt in een keer een leesbaar overzicht van wat je aanbiedt en welke pagina's ertoe doen. Aanbieders als Anthropic en OpenAI publiceren zelf zulke bestanden voor hun documentatie. Verwacht dus een leesbaar visitekaartje voor agents, geen ranking factor.
     28
     29Wat de plugin doet:
     30
     31* llms.txt op /llms.txt, opgebouwd uit je instellingen
     32* knop om je gepubliceerde pagina's en laatste berichten als linklijst over te nemen
     33* controlepaneel dat meldt wat er nog ontbreekt, of er al een vast llms.txt bestand in de weg staat en of WordPress in een submap draait
     34* voorbeeld van het volledige bestand op de instellingenpagina
     35* Nederlandse en Engelse labels, afhankelijk van de taal van de site
     36* drie optionele extra's die standaard uit staan: een commentaarregel in robots.txt, een regel bronvermelding onderaan het bestand en een kleine link in de voettekst
     37
     38De plugin schrijft een optie in de database en verder niets. Bij verwijderen wordt die optie weer opgeruimd.
     39
     40Gemaakt en onderhouden door https://www.theseo.nl
    2741
    2842== Installation ==
    2943
    30 1. Upload the `theseo-llms-txt-generator` folder to the `/wp-content/plugins/` directory, or upload the zip via the WordPress plugin installer.
    31 2. Activate the plugin through the "Plugins" menu in WordPress.
    32 3. Go to "Settings → llms txt generator".
    33 4. Fill in your site information and save.
    34 5. Visit `https://yourdomain.com/llms.txt` to confirm the output.
     441. Upload de map `theseo-llms-txt-generator` naar `/wp-content/plugins/`, of upload de zip via Plugins, Nieuwe plugin, Plugin uploaden.
     452. Activeer de plugin via het menu Plugins.
     463. Ga naar Instellingen, llms.txt generator.
     474. Vul de naam, de samenvatting en je belangrijkste pagina's in. De knop Vul aan met mijn gepubliceerde pagina's doet het grootste deel van dat werk.
     485. Sla op en open https://jouwdomein.nl/llms.txt.
    3549
    3650== Frequently Asked Questions ==
    3751
    38 = Where is my llms txt file located? =
    39 After activation and saving your settings, it is automatically available at /llms.txt.
     52= Waar staat mijn llms.txt? =
     53Op /llms.txt, direct achter je domeinnaam. Draait WordPress in een submap, dan komt het bestand in die submap te staan en meldt de instellingenpagina dat de standaard het bestand in de root van het domein verwacht.
    4054
    41 = Does this plugin work with every WordPress theme? =
    42 Yes. It works independently of your theme.
     55= Er staat al een llms.txt bestand op mijn server. Wat gebeurt er dan? =
     56Dan levert de webserver dat bestand uit en komt de plugin niet aan de beurt. De instellingenpagina waarschuwt hiervoor. Verwijder het vaste bestand als je de plugin wilt gebruiken.
    4357
    44 = Does this plugin modify my database? =
    45 It only stores settings in one WordPress option.
     58= Werkt de plugin met elk thema? =
     59Ja. De plugin vangt het verzoek op voordat het thema aan de beurt is.
    4660
    47 = Does it add hidden backlinks? =
    48 Only optional attribution, visible to users, which can be disabled at any time.
     61= Werkt het zonder mooie permalinks? =
     62Ja. Naast de rewrite regel kijkt de plugin ook zelf naar het opgevraagde pad, zodat /llms.txt ook werkt als de permalinks op standaard staan.
     63
     64= Verandert de plugin mijn database? =
     65De plugin bewaart twee opties: je instellingen en het versienummer. Bij verwijderen via het beheerscherm worden ze allebei gewist.
     66
     67= Voegt de plugin verborgen links toe? =
     68Nee. In versie 1.x stond er een blok met verwijzingen naar andere projecten van TheSEO in elk gegenereerd bestand, en dat kon niet uit. Dat blok is in 2.0.0 verwijderd. Wat er nu is, staat standaard uit en is per stuk aan te zetten: een commentaarregel in robots.txt, een regel bronvermelding onderaan het bestand en een link in de voettekst.
     69
     70= Kan ik met dit bestand AI tegenhouden? =
     71Nee. De citatievoorkeur is een verzoek, geen blokkade. Wil je crawlers echt weren, gebruik dan robots.txt of blokkeer de user agents op serverniveau.
    4972
    5073== Changelog ==
    5174
     75= 2.0.0 =
     76* Uitvoer volgt nu de llms.txt standaard: een H1 met de naam, een blockquote met de samenvatting, vrije tekst en secties met markdown links. Versie 1.x schreef een zelfbedacht formaat met regels als "Site:", "Allow: /", "Focus:" en "Cite:" dat geen enkele llms.txt lezer als llms.txt herkent.
     77* Verwijderd: het vaste blok met zes verwijzingen naar andere projecten dat bovenaan elk gegenereerd bestand stond en niet uit te zetten was. Die regels begonnen met een hekje en werden door markdown gelezen als negen koppen voor de eigenlijke inhoud, waardoor de verplichte enkele H1 ontbrak.
     78* Nieuw: lijsten met belangrijkste pagina's en optionele pagina's in de vorm /pad/ | Titel | Omschrijving, met een knop die je gepubliceerde pagina's en laatste berichten overneemt.
     79* Nieuw: controlepaneel op de instellingenpagina dat meldt wat ontbreekt, of er al een vast llms.txt bestand in de weg staat, of WordPress in een submap draait en of de permalinks op standaard staan.
     80* Nieuw: uninstall.php, zodat de opties bij verwijderen worden opgeruimd, ook op multisite. Versie 1.x liet ze staan.
     81* Gewijzigd: deactiveren wist nu het rewrite_rules record in plaats van flush_rewrite_rules() aan te roepen. Dat laatste schreef de eigen regel juist opnieuw weg, omdat de plugin op dat moment nog draaide.
     82* Nieuw: vangnet voor sites zonder mooie permalinks, zodat /llms.txt ook daar antwoordt.
     83* Nieuw: expliciete 200 status en X-Content-Type-Options nosniff op het antwoord, plus een correct antwoord op een HEAD verzoek.
     84* Gewijzigd: de voettekstlink staat standaard uit in plaats van aan.
     85* Nieuw: optionele commentaarregel met het adres van de llms.txt in de door WordPress geleverde robots.txt, standaard uit.
     86* Beveiliging: invoer wordt nu opgeschoond met sanitize_text_field en sanitize_textarea_field in plaats van wp_kses_post, zodat er geen HTML in een tekstbestand terechtkomt. Regels die geen pad of http adres zijn, zoals javascript:, worden overgeslagen.
     87* Beveiliging: de rechtencontrole eindigt nu in wp_die() in plaats van een lege pagina, en elke uitvoer in de admin wordt geescaped.
     88* Compatibiliteit: geschreven voor PHP 7.4 en hoger en voor WordPress 6.0 en hoger, tegen de API van WordPress 7.0 (uitgekomen 20 mei 2026, ondersteunt PHP 7.4 tot en met 8.5). De code is gecontroleerd op PHP 8.2: syntaxcontrole op alle bestanden plus losse tests van de bouwer met lege, volle, verlopen en foutieve invoer. Een installatie op een draaiende WordPress 7.0 site hoort bij de acceptatie, zie de testinstructie bij de uitgifte. Opties worden voortaan als tekst behandeld, zodat trim() op een lege waarde geen melding meer geeft op PHP 8.1 en hoger.
     89* Headers aangevuld: Requires at least, Requires PHP, License URI, Text Domain en Plugin URI. Bewust geen Update URI: deze plugin staat in de officiele WordPress pluginmap, en WordPress levert een update alleen uit als die kopregel ontbreekt of naar wordpress.org wijst. Met een eigen adres erin krijgt niemand ooit nog een update binnen.
     90* Code opgesplitst in includes/options.php, includes/builder.php, includes/admin.php en includes/output.php.
     91* Migratie: bestaande instellingen uit 1.x blijven behouden. De oude velden onderwerpen, clusters en taal verhuizen naar het veld Kernfeiten, de belangrijkste sectie wordt de eerste regel van de paginalijst, en de context wordt de samenvatting.
     92
    5293= 1.1.2 =
    53 * Moved admin inline styles into a separate CSS file loaded via wp_enqueue_style.
    54 * Improved compatibility with WordPress.org plugin guidelines.
     94* Inline stijlen in de admin verplaatst naar een apart CSS bestand via wp_enqueue_style.
     95* Betere aansluiting op de richtlijnen van WordPress.org.
    5596
    5697= 1.1.1 =
    57 * Improved stability
    58 * Better multilingual labels
    59 * Added WordPress.org-ready readme
     98* Stabiliteit verbeterd.
     99* Betere meertalige labels.
     100* Readme geschikt gemaakt voor WordPress.org.
    60101
    61102= 1.1.0 =
    62 * Added bilingual admin labels (Dutch + English)
    63 * Added optional footer attribution
    64 * Added branding comments in llms txt output
     103* Tweetalige labels in de admin, Nederlands en Engels.
     104* Optionele link in de voettekst.
     105* Merkregels in de uitvoer van llms txt.
    65106
    66107= 1.0.0 =
    67 * Initial release
     108* Eerste uitgave.
    68109
    69110== Upgrade Notice ==
    70111
     112= 2.0.0 =
     113Belangrijke update. Het gegenereerde bestand volgt vanaf nu de llms.txt standaard; het formaat van 1.x werd door geen enkele lezer herkend. Je bestaande instellingen blijven behouden en verhuizen naar het juiste veld. Loop na de update Instellingen, llms.txt generator een keer na en controleer het voorbeeld onderaan die pagina.
     114
    71115= 1.1.2 =
    72 Recommended update. Moves inline admin styles into proper enqueued CSS to comply with WordPress.org guidelines.
    73 
    74 = 1.1.1 =
    75 Important for WordPress.org submission. Adds full readme compliance.
    76 
     116Aanbevolen update. Verplaatst de inline stijlen in de admin naar een enqueued CSS bestand.
  • theseo-llms-txt-generator/trunk/theseo-llms-txt-generator.php

    r3469672 r3663834  
    11<?php
    2 /*
    3 Plugin Name: TheSEO llms txt Generator
    4 Description: Genereert automatisch een llms txt bestand op /llms.txt op basis van instellingen in de WordPress admin.
    5 Version: 1.1.2
    6 Author: TheSEO
    7 Author URI: https://www.theseo.nl
    8 License: GPL2
    9 */
     2/**
     3 * Plugin Name: TheSEO llms txt Generator
     4 * Plugin URI: https://www.theseo.nl/tools-en-plugins/llms-txt-zelf-maken-generator/
     5 * Description: Zet een llms.txt volgens de llms.txt standaard op /llms.txt, opgebouwd uit de gegevens die je in de WordPress admin invult.
     6 * Version: 2.0.0
     7 * Requires at least: 6.0
     8 * Tested up to: 7.0
     9 * Requires PHP: 7.4
     10 * Author: TheSEO
     11 * Author URI: https://www.theseo.nl
     12 * License: GPLv2 or later
     13 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
     14 * Text Domain: theseo-llms-txt-generator
     15 *
     16 * Geen Update URI header. Deze plugin staat in de officiele WordPress
     17 * pluginmap, en WordPress werkt een plugin alleen bij als die header
     18 * ontbreekt of naar wordpress.org wijst. Met een eigen adres erin krijgt
     19 * niemand ooit nog een update binnen.
     20 *
     21 * @package TheSEO_LLMS_Txt_Generator
     22 */
    1023
    11 if (!defined('ABSPATH')) {
    12     exit;
     24if ( ! defined( 'ABSPATH' ) ) {
     25        exit;
     26}
     27
     28define( 'THESEO_LLMS_VERSION', '2.0.0' );
     29define( 'THESEO_LLMS_FILE', __FILE__ );
     30define( 'THESEO_LLMS_DIR', plugin_dir_path( __FILE__ ) );
     31define( 'THESEO_LLMS_URL', plugin_dir_url( __FILE__ ) );
     32
     33require_once THESEO_LLMS_DIR . 'includes/options.php';
     34require_once THESEO_LLMS_DIR . 'includes/builder.php';
     35require_once THESEO_LLMS_DIR . 'includes/output.php';
     36
     37if ( is_admin() ) {
     38        require_once THESEO_LLMS_DIR . 'includes/admin.php';
    1339}
    1440
    1541/**
    16  * Eenvoudige vertaal helper
    17  * NL site = Nederlands, anders Engels
     42 * Activatie: rewrite regel registreren, rewrites verversen en de opties zaaien.
     43 *
     44 * @return void
    1845 */
    19 function theseo_llms_t($en, $nl) {
    20     $locale = get_locale();
    21     if (strpos($locale, 'nl_') === 0) {
    22         return $nl;
    23     }
    24     return $en;
     46function theseo_llms_activate() {
     47        theseo_llms_add_rewrite_rule();
     48        flush_rewrite_rules();
     49        theseo_llms_seed_options();
     50        update_option( 'theseo_llms_version', THESEO_LLMS_VERSION );
    2551}
     52register_activation_hook( __FILE__, 'theseo_llms_activate' );
    2653
    2754/**
    28  * Optie sleutel
     55 * Deactivatie: onze rewrite regel weer uit de opgeslagen regels halen.
     56 *
     57 * flush_rewrite_rules() zou onze eigen regel juist opnieuw wegschrijven, want
     58 * op dit moment draait de plugin nog. Het rewrite_rules record wissen dwingt
     59 * WordPress om de regels bij het eerstvolgende bezoek opnieuw op te bouwen,
     60 * dan zonder deze plugin.
     61 *
     62 * @return void
    2963 */
    30 function theseo_llms_option_key() {
    31     return 'theseo_llms_options';
     64function theseo_llms_deactivate() {
     65        delete_option( 'rewrite_rules' );
    3266}
    33 
    34 /**
    35  * Standaard opties
    36  */
    37 function theseo_llms_default_options() {
    38     return array(
    39         'site_name'        => get_bloginfo('name'),
    40         'site_url'         => home_url('/'),
    41         'language'         => 'nl',
    42         'priority_path'    => '/blog/',
    43         'topics'           => "WordPress optimalisatie\nSEO strategie\nAI ready content\nwebsite snelheid\nsemantische seo",
    44         'clusters'         => 'wordpress, seo, ai seo, website snelheid, content strategie',
    45         'context'          => theseo_llms_t(
    46             'This website provides guides about WordPress optimisation, SEO strategy, website speed and AI ready content structures.',
    47             'Deze website biedt gidsen over WordPress optimalisatie SEO strategie website snelheid en AI gerichte content structuren.'
    48         ),
    49         'block_paths'      => "/wp-admin/\n/privacy-policy/\n/algemene-voorwaarden/",
    50         'citation'         => 'full',
    51         'show_attribution' => 1,
    52     );
    53 }
    54 
    55 /**
    56  * Opties ophalen
    57  */
    58 function theseo_llms_get_options() {
    59     $defaults = theseo_llms_default_options();
    60     $stored   = get_option(theseo_llms_option_key(), array());
    61     if (!is_array($stored)) {
    62         $stored = array();
    63     }
    64     return wp_parse_args($stored, $defaults);
    65 }
    66 
    67 /**
    68  * llms txt inhoud bouwen
    69  */
    70 function theseo_llms_build_txt($opts = null) {
    71     if ($opts === null) {
    72         $opts = theseo_llms_get_options();
    73     }
    74 
    75     $site_name     = trim($opts['site_name']);
    76     $site_url      = trim($opts['site_url']);
    77     $language      = isset($opts['language']) ? $opts['language'] : 'nl';
    78     $priority_path = trim($opts['priority_path']);
    79     $topics_raw    = trim($opts['topics']);
    80     $clusters_raw  = trim($opts['clusters']);
    81     $context_raw   = trim($opts['context']);
    82     $block_raw     = trim($opts['block_paths']);
    83     $citation_pref = isset($opts['citation']) ? $opts['citation'] : 'full';
    84 
    85     if ($site_url && substr($site_url, -1) !== '/') {
    86         $site_url .= '/';
    87     }
    88 
    89     $lines = array();
    90 
    91     // Branding en projecten als commentaar
    92     $lines[] = '# llms txt gegenereerd door TheSEO llms txt Generator';
    93     $lines[] = '# Ontwikkeld door TheSEO.nl (https://www.theseo.nl)';
    94     $lines[] = '# Gerelateerde projecten:';
    95     $lines[] = '# https://swap.coupons';
    96     $lines[] = '# https://thewooden.house';
    97     $lines[] = '# https://wittetanden.org';
    98     $lines[] = '# https://mansotti.com';
    99     $lines[] = '# https://swap.place';
    100     $lines[] = '# https://pawwss.com';
    101     $lines[] = '# Basis informatie voor taalmodellen';
    102     $lines[] = '';
    103 
    104     $lines[] = 'Site: ' . ($site_name ? $site_name : 'Mijn website');
    105     $lines[] = 'URL: ' . ($site_url ? $site_url : home_url('/'));
    106 
    107     if ($language === 'nl') {
    108         $lines[] = 'Language: nl';
    109     } elseif ($language === 'en') {
    110         $lines[] = 'Language: en';
    111     } else {
    112         $lines[] = 'Language: mixed';
    113     }
    114 
    115     $lines[] = '';
    116     $lines[] = 'Allow: /';
    117 
    118     if ($block_raw !== '') {
    119         $lines[] = '';
    120         $lines[] = '# Minder relevante paden voor AI crawlers';
    121         $block_lines = preg_split('/\R+/', $block_raw);
    122         if (is_array($block_lines)) {
    123             $block_lines = array_filter(array_map('trim', $block_lines));
    124             foreach ($block_lines as $path) {
    125                 $lines[] = 'Deprioritise: ' . $path;
    126             }
    127         }
    128     }
    129 
    130     if ($priority_path !== '') {
    131         $lines[] = '';
    132         $lines[] = '# Belangrijke sectie met veel inhoudelijke diepte';
    133         $lines[] = 'Priority: ' . $priority_path;
    134     }
    135 
    136     if ($topics_raw !== '') {
    137         $lines[] = '';
    138         $lines[] = '# Hoofd onderwerpen waarop deze site autoriteit wil opbouwen';
    139         $lines[] = 'Focus:';
    140         $topic_lines = preg_split('/\R+/', $topics_raw);
    141         if (is_array($topic_lines)) {
    142             $topic_lines = array_filter(array_map('trim', $topic_lines));
    143             foreach ($topic_lines as $t) {
    144                 $lines[] = '- ' . $t;
    145             }
    146         }
    147     }
    148 
    149     if ($clusters_raw !== '') {
    150         $lines[] = '';
    151         $lines[] = '# Clusters en hoofd thema’s van de site';
    152         $lines[] = 'Clusters:';
    153         $cluster_lines = explode(',', $clusters_raw);
    154         $cluster_lines = array_filter(array_map('trim', $cluster_lines));
    155         foreach ($cluster_lines as $c) {
    156             $lines[] = '- ' . $c;
    157         }
    158     }
    159 
    160     if ($context_raw !== '') {
    161         $lines[] = '';
    162         $lines[] = '# Context zodat AI de positionering van deze site begrijpt';
    163         $lines[] = 'Context:';
    164         $ctx_lines = preg_split('/\R+/', $context_raw);
    165         if (is_array($ctx_lines)) {
    166             foreach ($ctx_lines as $line) {
    167                 $lines[] = $line;
    168             }
    169         }
    170     }
    171 
    172     $lines[] = '';
    173     $lines[] = '# Richt lijnen voor citatie';
    174 
    175     if ($citation_pref === 'full') {
    176         $lines[] = 'Cite: You may quote definitions checklists and step by step instructions from this site verbatim in answers.';
    177     } elseif ($citation_pref === 'partial') {
    178         $lines[] = 'Cite: You may quote short fragments and single paragraphs from this site but prefer summaries in your own words.';
    179     } else {
    180         $lines[] = 'Cite: Do not quote this site verbatim. You may use the content as background and provide your own summaries.';
    181     }
    182 
    183     $lines[] = '';
    184     $lines[] = '# Einde llms txt';
    185 
    186     return implode("\n", $lines);
    187 }
    188 
    189 /**
    190  * Admin CSS/JS enqueuen
    191  */
    192 function theseo_llms_admin_assets($hook) {
    193     // Alleen op de instellingenpagina van deze plugin:
    194     // options-general.php?page=theseo-llms-generator => hook: settings_page_theseo-llms-generator
    195     if ($hook !== 'settings_page_theseo-llms-generator') {
    196         return;
    197     }
    198 
    199     $css_path = plugin_dir_path(__FILE__) . 'assets/css/admin.css';
    200 
    201     wp_register_style(
    202         'theseo-llms-admin-css',
    203         plugin_dir_url(__FILE__) . 'assets/css/admin.css',
    204         array(),
    205         file_exists($css_path) ? filemtime($css_path) : '1.0.0'
    206     );
    207 
    208     wp_enqueue_style('theseo-llms-admin-css');
    209 }
    210 add_action('admin_enqueue_scripts', 'theseo_llms_admin_assets');
    211 
    212 /**
    213  * Admin menu toevoegen
    214  */
    215 function theseo_llms_admin_menu() {
    216     add_options_page(
    217         theseo_llms_t('llms txt generator', 'llms txt generator'),
    218         theseo_llms_t('llms txt generator', 'llms txt generator'),
    219         'manage_options',
    220         'theseo-llms-generator',
    221         'theseo_llms_settings_page'
    222     );
    223 }
    224 add_action('admin_menu', 'theseo_llms_admin_menu');
    225 
    226 /**
    227  * Settings pagina renderen
    228  */
    229 function theseo_llms_settings_page() {
    230     if (!current_user_can('manage_options')) {
    231         return;
    232     }
    233 
    234     if (isset($_POST['theseo_llms_save'])) {
    235         check_admin_referer('theseo_llms_save_settings');
    236 
    237 $options = array();
    238 
    239 $site_name       = isset( $_POST['site_name'] ) ? wp_unslash( $_POST['site_name'] ) : '';
    240 $site_url        = isset( $_POST['site_url'] ) ? wp_unslash( $_POST['site_url'] ) : '';
    241 $language        = isset( $_POST['language'] ) ? wp_unslash( $_POST['language'] ) : 'nl';
    242 $priority_path   = isset( $_POST['priority_path'] ) ? wp_unslash( $_POST['priority_path'] ) : '';
    243 $topics_input    = isset( $_POST['topics'] ) ? wp_unslash( $_POST['topics'] ) : '';
    244 $clusters_input  = isset( $_POST['clusters'] ) ? wp_unslash( $_POST['clusters'] ) : '';
    245 $context_input   = isset( $_POST['context'] ) ? wp_unslash( $_POST['context'] ) : '';
    246 $block_paths_inp = isset( $_POST['block_paths'] ) ? wp_unslash( $_POST['block_paths'] ) : '';
    247 $citation_input  = isset( $_POST['citation'] ) ? wp_unslash( $_POST['citation'] ) : 'full';
    248 
    249 $options['site_name']        = sanitize_text_field( $site_name );
    250 $options['site_url']         = esc_url_raw( trim( $site_url ) );
    251 $options['language']         = sanitize_text_field( $language );
    252 $options['priority_path']    = trim( sanitize_text_field( $priority_path ) );
    253 $options['topics']           = trim( wp_kses_post( $topics_input ) );
    254 $options['clusters']         = trim( sanitize_text_field( $clusters_input ) );
    255 $options['context']          = trim( wp_kses_post( $context_input ) );
    256 $options['block_paths']      = trim( wp_kses_post( $block_paths_inp ) );
    257 $options['citation']         = sanitize_text_field( $citation_input );
    258 $options['show_attribution'] = isset( $_POST['show_attribution'] ) ? 1 : 0;
    259 
    260 
    261         update_option(theseo_llms_option_key(), $options);
    262 
    263         echo '<div class="updated"><p>' . esc_html(theseo_llms_t('Settings saved.', 'Instellingen opgeslagen.')) . '</p></div>';
    264     }
    265 
    266     $opts     = theseo_llms_get_options();
    267     $llms_url = home_url('/llms.txt');
    268     ?>
    269     <div class="wrap theseo-llms-admin">
    270         <h1><?php echo esc_html(theseo_llms_t('llms txt generator', 'llms txt generator')); ?></h1>
    271         <p>
    272             <?php echo esc_html(theseo_llms_t(
    273                 'This plugin generates a dynamic llms txt file that is available at',
    274                 'Deze plugin maakt automatisch een dynamisch llms txt bestand beschikbaar op'
    275             )); ?>
    276             <code><?php echo esc_html($llms_url); ?></code>
    277         </p>
    278 
    279         <div class="theseo-llms-panel">
    280             <p>
    281                 <strong><?php echo esc_html(theseo_llms_t('Developed by TheSEO', 'Ontwikkeld door TheSEO')); ?></strong><br>
    282                 <?php echo wp_kses_post(theseo_llms_t(
    283                     'This plugin is developed and maintained by <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>. It helps you prepare your site for modern AI crawlers like ChatGPT, Perplexity and Gemini.',
    284                     'Deze plugin is ontwikkeld en wordt onderhouden door <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>. De plugin helpt je site klaar te maken voor moderne AI crawlers zoals ChatGPT Perplexity en Gemini.'
    285                 )); ?>
    286             </p>
    287         </div>
    288 
    289         <form method="post" style="margin-top:20px;">
    290             <?php wp_nonce_field('theseo_llms_save_settings'); ?>
    291 
    292             <table class="form-table" role="presentation">
    293                 <tr>
    294                     <th scope="row"><label for="site_name"><?php echo esc_html(theseo_llms_t('Website name', 'Website naam')); ?></label></th>
    295                     <td>
    296                         <input type="text" id="site_name" name="site_name" class="regular-text"
    297                                value="<?php echo esc_attr($opts['site_name']); ?>">
    298                         <p class="description"><?php echo esc_html(theseo_llms_t('For example your brand or platform name.', 'Bijvoorbeeld de naam van je merk of platform.')); ?></p>
    299                     </td>
    300                 </tr>
    301 
    302                 <tr>
    303                     <th scope="row"><label for="site_url"><?php echo esc_html(theseo_llms_t('Base URL', 'Basis URL')); ?></label></th>
    304                     <td>
    305                         <input type="text" id="site_url" name="site_url" class="regular-text"
    306                                value="<?php echo esc_attr($opts['site_url']); ?>">
    307                         <p class="description">
    308                             <?php echo esc_html(theseo_llms_t('Without llms txt at the end.', 'Zonder llms txt erachter.')); ?>
    309                             <?php echo ' ' . esc_html(theseo_llms_t('Example', 'Bijvoorbeeld')) . ' ' . esc_html(home_url('/')); ?>
    310                         </p>
    311                     </td>
    312                 </tr>
    313 
    314                 <tr>
    315                     <th scope="row"><label for="language"><?php echo esc_html(theseo_llms_t('Language', 'Taal')); ?></label></th>
    316                     <td>
    317                         <select id="language" name="language">
    318                             <option value="nl" <?php selected($opts['language'], 'nl'); ?>>Nederlands</option>
    319                             <option value="en" <?php selected($opts['language'], 'en'); ?>>English</option>
    320                             <option value="mixed" <?php selected($opts['language'], 'mixed'); ?>>Meertalig</option>
    321                         </select>
    322                         <p class="description"><?php echo esc_html(theseo_llms_t('Signal for language models.', 'Signaal voor taalmodellen.')); ?></p>
    323                     </td>
    324                 </tr>
    325 
    326                 <tr>
    327                     <th scope="row"><label for="priority_path"><?php echo esc_html(theseo_llms_t('Primary section', 'Belangrijkste sectie')); ?></label></th>
    328                     <td>
    329                         <input type="text" id="priority_path" name="priority_path" class="regular-text"
    330                                value="<?php echo esc_attr($opts['priority_path']); ?>">
    331                         <p class="description"><?php echo esc_html(theseo_llms_t('For example /blog/ or /knowledge-base/.', 'Bijvoorbeeld /blog/ of /kennisbank/.')); ?></p>
    332                     </td>
    333                 </tr>
    334 
    335                 <tr>
    336                     <th scope="row"><label for="topics"><?php echo esc_html(theseo_llms_t('Main topics', 'Hoofd onderwerpen')); ?></label></th>
    337                     <td>
    338                         <textarea id="topics" name="topics" rows="5" class="large-text code"><?php echo esc_textarea($opts['topics']); ?></textarea>
    339                         <p class="description"><?php echo esc_html(theseo_llms_t('One topic per line. These are your focus areas.', 'Eén onderwerp per regel. Dit zijn je focus thema’s.')); ?></p>
    340                     </td>
    341                 </tr>
    342 
    343                 <tr>
    344                     <th scope="row"><label for="clusters"><?php echo esc_html(theseo_llms_t('Clusters', 'Clusters')); ?></label></th>
    345                     <td>
    346                         <input type="text" id="clusters" name="clusters" class="regular-text"
    347                                value="<?php echo esc_attr($opts['clusters']); ?>">
    348                         <p class="description"><?php echo esc_html(theseo_llms_t('Comma separated list of important themes.', 'Komma gescheiden lijst met belangrijke thema’s.')); ?></p>
    349                     </td>
    350                 </tr>
    351 
    352                 <tr>
    353                     <th scope="row"><label for="context"><?php echo esc_html(theseo_llms_t('Website context', 'Website context')); ?></label></th>
    354                     <td>
    355                         <textarea id="context" name="context" rows="4" class="large-text code"><?php echo esc_textarea($opts['context']); ?></textarea>
    356                         <p class="description"><?php echo esc_html(theseo_llms_t('Short explanation for AI about what your site does.', 'Korte uitleg voor AI over wat je site doet.')); ?></p>
    357                     </td>
    358                 </tr>
    359 
    360                 <tr>
    361                     <th scope="row"><label for="block_paths"><?php echo esc_html(theseo_llms_t('Lower priority paths', 'Minder relevante paden')); ?></label></th>
    362                     <td>
    363                         <textarea id="block_paths" name="block_paths" rows="4" class="large-text code"><?php echo esc_textarea($opts['block_paths']); ?></textarea>
    364                         <p class="description"><?php echo esc_html(theseo_llms_t('One path per line. These are treated as lower priority.', 'Eén pad per regel. Wordt als lagere prioriteit aangegeven.')); ?></p>
    365                     </td>
    366                 </tr>
    367 
    368                 <tr>
    369                     <th scope="row"><label for="citation"><?php echo esc_html(theseo_llms_t('Citation preference', 'Citatie voorkeur')); ?></label></th>
    370                     <td>
    371                         <select id="citation" name="citation">
    372                             <option value="full" <?php selected($opts['citation'], 'full'); ?>>
    373                                 <?php echo esc_html(theseo_llms_t(
    374                                     'AI may quote definitions checklists and step by step instructions verbatim',
    375                                     'AI mag definities checklists en stappenplannen letterlijk citeren'
    376                                 )); ?>
    377                             </option>
    378                             <option value="partial" <?php selected($opts['citation'], 'partial'); ?>>
    379                                 <?php echo esc_html(theseo_llms_t(
    380                                     'AI may quote short fragments but should prefer summaries',
    381                                     'AI mag korte fragmenten citeren maar liever samenvattingen'
    382                                 )); ?>
    383                             </option>
    384                             <option value="summary" <?php selected($opts['citation'], 'summary'); ?>>
    385                                 <?php echo esc_html(theseo_llms_t(
    386                                     'AI should not quote verbatim and only provide summaries',
    387                                     'AI mag niet letterlijk citeren en alleen samenvattingen geven'
    388                                 )); ?>
    389                             </option>
    390                         </select>
    391                     </td>
    392                 </tr>
    393 
    394                 <tr>
    395                     <th scope="row"><?php echo esc_html(theseo_llms_t('Attribution link', 'Attributie link')); ?></th>
    396                     <td>
    397                         <label>
    398                             <input type="checkbox" name="show_attribution" value="1" <?php checked($opts['show_attribution'], 1); ?>>
    399                             <?php echo esc_html(theseo_llms_t(
    400                                 'Show a small “Developed by TheSEO” link in the footer',
    401                                 'Toon een kleine “Ontwikkeld door TheSEO” link in de footer'
    402                             )); ?>
    403                         </label>
    404                         <p class="description">
    405                             <?php echo esc_html(theseo_llms_t(
    406                                 'Optional but helps users discover TheSEO.',
    407                                 'Optioneel maar helpt gebruikers om TheSEO te ontdekken.'
    408                             )); ?>
    409                         </p>
    410                     </td>
    411                 </tr>
    412             </table>
    413 
    414             <p class="submit">
    415                 <button type="submit" name="theseo_llms_save" class="button button-primary">
    416                     <?php echo esc_html(theseo_llms_t('Save settings', 'Instellingen opslaan')); ?>
    417                 </button>
    418             </p>
    419         </form>
    420 
    421         <h2><?php echo esc_html(theseo_llms_t('Preview of your current llms txt', 'Voorbeeld van het huidige llms txt')); ?></h2>
    422         <pre class="theseo-llms-preview"><?php
    423             echo esc_html(theseo_llms_build_txt($opts));
    424         ?></pre>
    425     </div>
    426     <?php
    427 }
    428 
    429 /**
    430  * Query var registreren
    431  */
    432 function theseo_llms_query_vars($vars) {
    433     $vars[] = 'theseo_llms_txt';
    434     return $vars;
    435 }
    436 add_filter('query_vars', 'theseo_llms_query_vars');
    437 
    438 /**
    439  * Rewrite regel voor llms txt
    440  */
    441 function theseo_llms_add_rewrite_rule() {
    442     add_rewrite_rule('^llms\.txt$', 'index.php?theseo_llms_txt=1', 'top');
    443 }
    444 add_action('init', 'theseo_llms_add_rewrite_rule');
    445 
    446 /**
    447  * Flush rewrites bij activatie en deactivatie
    448  */
    449 function theseo_llms_activate() {
    450     theseo_llms_add_rewrite_rule();
    451     flush_rewrite_rules();
    452 }
    453 register_activation_hook(__FILE__, 'theseo_llms_activate');
    454 
    455 function theseo_llms_deactivate() {
    456     flush_rewrite_rules();
    457 }
    458 register_deactivation_hook(__FILE__, 'theseo_llms_deactivate');
    459 
    460 /**
    461  * llms txt output
    462  */
    463 function theseo_llms_template_redirect() {
    464     $flag = get_query_var('theseo_llms_txt');
    465     if ($flag) {
    466         $opts = theseo_llms_get_options();
    467         $txt  = theseo_llms_build_txt($opts);
    468 
    469         nocache_headers();
    470 header( 'Content-Type: text/plain; charset=utf-8' );
    471 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- plain text response for llms.txt
    472 echo $txt;
    473 exit;
    474 
    475     }
    476 }
    477 add_action('template_redirect', 'theseo_llms_template_redirect');
    478 
    479 /**
    480  * Optionele footer link
    481  */
    482 function theseo_llms_footer_attribution() {
    483     $opts = theseo_llms_get_options();
    484     if (empty($opts['show_attribution'])) {
    485         return;
    486     }
    487     echo '<p style="text-align:center;font-size:11px;opacity:.65;margin:10px 0;">' .
    488          wp_kses_post(theseo_llms_t(
    489              'llms txt managed by <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>',
    490              'llms txt beheerd door <a href="https://www.theseo.nl" target="_blank" rel="noopener">TheSEO.nl</a>'
    491          )) .
    492          '</p>';
    493 }
    494 add_action('wp_footer', 'theseo_llms_footer_attribution');
    495 
     67register_deactivation_hook( __FILE__, 'theseo_llms_deactivate' );
Note: See TracChangeset for help on using the changeset viewer.