Ich habe nach einer unkomplizierten Möglichkeit gesucht, eine llms.txt für mehrere WordPress-Websites bereitzustellen. Gerade wenn man als Freelancer oder Agentur viele Kundenwebsites betreut, möchte man dafür nicht jedes Mal ein zusätzliches Plugin installieren oder Dateien manuell hochladen.
Also habe ich (ChatGPT 😉) ein kleines PHP-Snippet entwickelt, das genau das übernimmt.
Automatischer Fallback mit manueller Anpassung
Das Prinzip ist einfach:
- Automatischer Fallback: Das Snippet erstellt unter
/llms.txtautomatisch eine Datei mit dem Website-Namen, der Beschreibung, den wichtigsten WordPress-Seiten und einem Link zur Sitemap. - Manuelle Anpassung: Unter Einstellungen → LLMs.txt lässt sich der automatisch generierte Inhalt jederzeit durch eigenen Markdown-Code ersetzen.
- KI-Unterstützung: Wer eine individuelle
llms.txtmöchte, kann sich den Inhalt beispielsweise mit ChatGPT oder Claude erstellen lassen und anschließend einfach einfügen.
Das Snippet unterstützt außerdem die Sitemap-URLs von SEOPress, Yoast SEO und Rank Math.
Braucht man überhaupt eine llms.txt?
Ob und wie stark KI-Systeme eine llms.txt tatsächlich berücksichtigen, ist aktuell noch offen. Einen nachgewiesenen SEO-Vorteil gibt es bisher nicht.
Die Idee dahinter finde ich trotzdem sinnvoll: KI-Systemen eine strukturierte Übersicht über die wichtigsten Inhalte einer Website bereitstellen.
Mein Ansatz ist deshalb pragmatisch: Mit dem automatischen Fallback ist die Datei erst einmal vorhanden. Falls man später mehr Zeit investieren möchte, lässt sich der Inhalt individuell anpassen.
Das PHP-Snippet
Den vollständigen PHP-Code finden Sie hier:
/**
* Dynamic LLMs.txt for WordPress
*
* Erstellt automatisch eine llms.txt unter /llms.txt.
* Optional kann der Inhalt unter Einstellungen → LLMs.txt
* vollständig überschrieben werden.
*
* Unterstützt SEOPress, Yoast SEO und Rank Math.
*
* Version: 1.1
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* 1. LLMs.txt ausliefern
*/
add_action('template_redirect', function () {
// Aktuellen URL-Pfad ermitteln
$request_path = wp_parse_url(
$_SERVER['REQUEST_URI'] ?? '',
PHP_URL_PATH
);
$llms_path = wp_parse_url(
home_url('/llms.txt'),
PHP_URL_PATH
);
// Nur auf /llms.txt reagieren
if (
!is_string($request_path) ||
untrailingslashit($request_path) !== untrailingslashit($llms_path)
) {
return;
}
// Manuelle Eingabe abrufen
$custom_content = get_option('custom_llms_txt_content', '');
// Manuelle Eingabe oder automatischer Fallback
if (
is_string($custom_content) &&
trim($custom_content) !== ''
) {
$content = $custom_content;
} else {
$content = custom_generate_llms_txt();
}
// Eventuellen 404-Status entfernen
global $wp_query;
if (isset($wp_query)) {
$wp_query->is_404 = false;
}
status_header(200);
// Markdown als reine Textantwort ausliefern
header('Content-Type: text/plain; charset=utf-8');
header('X-Content-Type-Options: nosniff');
// Keine unnötige Zwischenspeicherung
header('Cache-Control: no-cache, must-revalidate');
echo $content;
exit;
}, 0);
/**
* 2. Markdown-Text bereinigen
*/
function custom_llms_txt_escape($text) {
$text = wp_strip_all_tags((string) $text);
// Zeilenumbrüche und zusätzliche Leerzeichen entfernen
$text = preg_replace('/\s+/u', ' ', $text);
// Markdown-Sonderzeichen maskieren
$text = str_replace(
array('\\', '[', ']', '#'),
array('\\\\', '\[', '\]', '\#'),
trim($text)
);
return $text;
}
/**
* 3. Prüfen, ob eine Seite auf Noindex steht
*/
function custom_llms_txt_is_noindex($post_id) {
// Passwortgeschützte Inhalte ausschließen
if (post_password_required($post_id)) {
return true;
}
// SEOPress: Individuelle Noindex-Einstellung
if (defined('SEOPRESS_VERSION')) {
$noindex = get_post_meta(
$post_id,
'_seopress_robots_index',
true
);
if ($noindex === 'yes') {
return true;
}
}
// Yoast SEO
if (defined('WPSEO_VERSION')) {
$noindex = get_post_meta(
$post_id,
'_yoast_wpseo_meta-robots-noindex',
true
);
if ((string) $noindex === '1') {
return true;
}
}
// Rank Math
if (defined('RANK_MATH_VERSION')) {
$robots = get_post_meta(
$post_id,
'rank_math_robots',
true
);
if (
is_array($robots) &&
in_array('noindex', $robots, true)
) {
return true;
}
}
return false;
}
/**
* 4. XML-Sitemap-URL ermitteln
*/
function custom_llms_txt_get_sitemap_url() {
// SEOPress
if (defined('SEOPRESS_VERSION')) {
return home_url('/sitemaps.xml');
}
// Yoast SEO und Rank Math
if (
defined('WPSEO_VERSION') ||
defined('RANK_MATH_VERSION')
) {
return home_url('/sitemap_index.xml');
}
// WordPress Standard-Sitemap
return home_url('/wp-sitemap.xml');
}
/**
* 5. Automatische LLMs.txt generieren
*/
function custom_generate_llms_txt() {
// Allgemeine WordPress-Informationen
$site_name = custom_llms_txt_escape(
get_bloginfo('name')
);
$site_description = custom_llms_txt_escape(
get_bloginfo('description')
);
$site_url = home_url('/');
// Titel
$content = "# {$site_name}\n\n";
// Beschreibung
if (!empty($site_description)) {
$content .= "> {$site_description}\n\n";
} else {
$content .= "> Official website of {$site_name}.\n\n";
}
// Startseite
$content .= "## Main Website\n\n";
$content .= "- [Homepage]({$site_url})\n\n";
// Veröffentlichte Seiten abrufen
$pages = get_posts(array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => 50,
'orderby' => array(
'menu_order' => 'ASC',
'title' => 'ASC',
),
'no_found_rows' => true,
'suppress_filters' => false,
));
// ID der statischen Startseite
$front_page_id = (int) get_option('page_on_front');
$page_links = array();
foreach ($pages as $page) {
// Startseite nicht doppelt ausgeben
if ((int) $page->ID === $front_page_id) {
continue;
}
// Noindex und passwortgeschützte Seiten ausschließen
if (custom_llms_txt_is_noindex($page->ID)) {
continue;
}
// Titel und URL
$title = custom_llms_txt_escape(
get_the_title($page->ID)
);
$url = get_permalink($page->ID);
if (empty($title) || empty($url)) {
continue;
}
$page_links[] = "- [{$title}]({$url})";
}
// Seiten ausgeben
if (!empty($page_links)) {
$content .= "## Pages\n\n";
$content .= implode("\n", $page_links);
$content .= "\n\n";
}
// XML-Sitemap
$sitemap_url = custom_llms_txt_get_sitemap_url();
$content .= "## Additional Resources\n\n";
$content .= "- [XML Sitemap]({$sitemap_url})\n";
return $content;
}
/**
* 6. Einstellungsseite registrieren
*/
add_action('admin_menu', function () {
add_options_page(
'LLMs.txt',
'LLMs.txt',
'manage_options',
'custom-llms-txt',
'custom_llms_txt_settings_page'
);
});
/**
* 7. Einstellung registrieren
*/
add_action('admin_init', function () {
register_setting(
'custom_llms_txt_settings',
'custom_llms_txt_content',
array(
'type' => 'string',
'sanitize_callback' => 'custom_llms_txt_sanitize',
'default' => '',
)
);
});
/**
* 8. Markdown-Eingabe bereinigen
*/
function custom_llms_txt_sanitize($input) {
if (!is_string($input)) {
return '';
}
// Zeilenumbrüche vereinheitlichen
$input = str_replace(
array("\r\n", "\r"),
"\n",
$input
);
// Null-Bytes entfernen
$input = str_replace("\0", '', $input);
return trim($input);
}
/**
* 9. Einstellungsseite ausgeben
*/
function custom_llms_txt_settings_page() {
if (!current_user_can('manage_options')) {
return;
}
$content = get_option('custom_llms_txt_content', '');
$llms_url = home_url('/llms.txt');
$is_custom = (
is_string($content) &&
trim($content) !== ''
);
?>
<div class="wrap">
<h1>LLMs.txt</h1>
<p>
Die LLMs.txt wird automatisch aus den
WordPress-Inhalten generiert.
Alternativ kann eine individuelle Markdown-Version
hinterlegt werden.
</p>
<p>
<strong>Aktuelle Datei:</strong>
<a
href="<?php echo esc_url($llms_url); ?>"
target="_blank"
rel="noopener noreferrer"
>
<?php echo esc_html($llms_url); ?>
</a>
</p>
<p>
<strong>Aktiver Modus:</strong>
<?php if ($is_custom) : ?>
Individuelle LLMs.txt
<?php else : ?>
Automatisch generierte LLMs.txt
<?php endif; ?>
</p>
<hr>
<form method="post" action="options.php">
<?php settings_fields('custom_llms_txt_settings'); ?>
<h2>Individuelle LLMs.txt</h2>
<p>
Hier kann eine eigene LLMs.txt im
Markdown-Format hinterlegt werden.
</p>
<p>
<strong>Hinweis:</strong>
Wenn das Feld leer bleibt, wird automatisch
die Standardversion ausgegeben.
Eine manuelle Eingabe ersetzt die
automatische Version vollständig.
</p>
<textarea
name="custom_llms_txt_content"
id="custom_llms_txt_content"
rows="20"
class="large-text code"
spellcheck="false"
placeholder="# Website Name
> Website description
## Main Pages
- [Homepage](https://example.com/)
- [Contact](https://example.com/contact/)"
><?php echo esc_textarea($content); ?></textarea>
<?php submit_button('Änderungen speichern'); ?>
</form>
</div>
<?php
}
Das Snippet lässt sich beispielsweise über das kostenlose Plugin Code Snippets einbinden. Nach der Aktivierung ist die Datei direkt unter ihre-domain.de/llms.txt erreichbar.
Keine zusätzliche Konfiguration, kein weiteres spezialisiertes Plugin und trotzdem die Möglichkeit, den Inhalt jederzeit selbst anzupassen.