Child-Theme in WordPress
Warum, wann & wie (mit Copy-Paste-Code)
Ein Child-Theme schützt deine Anpassungen vor Theme-Updates. Du arbeitest weiterhin mit dem Original-Theme (Parent), aber deine Änderungen liegen sauber im Child – und bleiben auch nach Updates erhalten.
Wann lohnt sich ein Child-Theme?
Unbedingt sinnvoll, wenn du:
-
PHP-Snippets hinzufügen willst (Functions/Filter/Hooks),
-
Template-Dateien überschreiben möchtest (z. B.
single.php
,header.php
, WooCommerce-Templates), -
eigene CSS/JS dauerhaft führen willst,
-
kleinere Theme-Bugs „hotfixen“ musst,
-
Update-Sicherheit brauchst (Corporate/Webshops/Verzeichnisse).
Nicht zwingend nötig, wenn du:
-
nur wenige CSS-Regeln per Customizer/„Zusätzliches CSS“ pflegst,
-
ein Block-Theme (FSE) nutzt und alles in der site.json/theme.json bzw. im Editor löst,
-
ausschließlich Page-Builder (Elementor/Divi) ohne Code verwendest.
Daumenregel: Sobald du PHP anfasst oder Dateien überschreiben willst → Child-Theme verwenden.
Ordner & Dateien anlegen
Am Beispiel des „Findus“-Themes
Pfad: wp-content/themes/DEIN-PARENT-THEME-child
1) style.css
(Pflicht, Header ist entscheidend)
/*
Theme Name: Findus Child /* <– Name frei wählbar */
Template: findus /* <– exakter Ordnername des Parent-Themes */
Description: Child-Theme für Findus
Author: DeinName
Version: 1.0.0
Text Domain: findus-child
*/
Wichtig:
Template:
muss genau dem Ordnernamen des Parent-Themes entsprechen (z. B.astra
,hello-elementor
,twentytwentyfour
,findus
).
2) functions.php
(Parent-Styles laden + Platz für Snippets)
<?php
/**
* Basis-Setup fürs Child-Theme
*/
// Parent-CSS laden
add_action(‚wp_enqueue_scripts‘, function () {
// Parent-Stylesheet
wp_enqueue_style(‚parent-style‘, get_template_directory_uri() . ‚/style.css‘, [], null);
// Optional: eigenes Child-CSS (style.css)
wp_enqueue_style(‚child-style‘, get_stylesheet_uri(), [‚parent-style‘], null);
});
Kein
?>
ans Dateiende schreiben. So vermeidest du „Headers already sent“-Fehler.
Aktivieren (Backend)
Design → Themes → „Findus Child“ (oder dein Name) Aktivieren.
Quick-Start: Snippets, die man oft braucht
A) Featured Image & Galerie korrekt setzen (z. B. für Verzeichnis/Job-Listings)
// 1) Erstes Galerie-Bild als Beitragsbild (Featured) setzen
add_action(’save_post_job_listing‘, function($post_id, $post, $update){
if (defined(‚DOING_AUTOSAVE‘) && DOING_AUTOSAVE) return;
if ($post->post_type !== ‚job_listing‘) return;
if (has_post_thumbnail($post_id)) return;
$gallery = get_post_meta($post_id, ‚_job_gallery_images‘, true);
if (is_string($gallery)) { $gallery = maybe_unserialize($gallery); }
if (is_array($gallery) && !empty($gallery)) {
$first_id = intval(reset($gallery));
if ($first_id) { set_post_thumbnail($post_id, $first_id); }
}
}, 10, 3);
// 2) Galerie-Anhänge sauber dem Beitrag zuordnen (post_parent setzen)
add_action(’save_post_job_listing‘, function($post_id){
$gallery = get_post_meta($post_id, ‚_job_gallery_images‘, true);
if (is_string($gallery)) { $gallery = maybe_unserialize($gallery); }
if (is_array($gallery)) {
foreach ($gallery as $img_id) {
$att = get_post($img_id);
if ($att && (int)$att->post_parent === 0) {
wp_update_post([‚ID‘ => $img_id, ‚post_parent‘ => $post_id]);
}
}
}
});
Passe
job_listing
und den Meta-Key_job_gallery_images
bei Bedarf an dein Setup an.
B) Duplikate beim Upload verhindern (MD5-Hash-Check)
// Identische Bild-Uploads blocken
add_filter(‚wp_handle_upload_prefilter‘, function ($file) {
if (!isset($file[‚tmp_name‘]) || !is_readable($file[‚tmp_name‘])) return $file;
$contents = @file_get_contents($file[‚tmp_name‘]);
if ($contents === false) return $file;
$hash = md5($contents);
// Bereits ein Anhang mit gleichem Hash vorhanden?
$existing = get_posts([
‚post_type‘ => ‚attachment‘,
‚posts_per_page‘ => 1,
‚fields‘ => ‚ids‘,
‚meta_key‘ => ‚_file_md5‘,
‚meta_value‘ => $hash,
’no_found_rows‘ => true,
’suppress_filters‘ => true,
]);
if (!empty($existing)) {
$url = wp_get_attachment_url($existing[0]);
$file[‚error‘] = sprintf(
__(‚Dieses Bild existiert bereits. Verwende das vorhandene: %s‘, ‚findus-child‘),
$url ? esc_url($url) : “
);
return $file;
}
// Hash nach erfolgreichem Upload speichern
add_filter(‚wp_generate_attachment_metadata‘, function ($metadata, $attachment_id) use ($hash) {
update_post_meta($attachment_id, ‚_file_md5‘, $hash);
return $metadata;
}, 10, 2);
return $file;
});
C) Admin-Werkzeug: bestehenden Medien MD5 verpassen (100 pro Klick)
// Werkzeuge → Medien-Hashes: vorhandene Anhänge nach-hashen
add_action(‚admin_menu‘, function () {
add_management_page(‚Medien-Hashes‘,’Medien-Hashes‘,’manage_options‘,’media-hashes‘, function(){
if (!current_user_can(‚manage_options‘)) return;
$done = 0; $log = [];
if (isset($_POST[‚run_hash‘]) && check_admin_referer(‚run_media_hash‘)) {
$ids = get_posts([
‚post_type‘ => ‚attachment‘,
‚posts_per_page‘ => 100,
‚fields‘ => ‚ids‘,
‚meta_query‘ => [[‚key‘ => ‚_file_md5‘, ‚compare‘ => ‚NOT EXISTS‘]],
]);
foreach ($ids as $aid) {
$path = get_attached_file($aid);
if ($path && file_exists($path) && is_readable($path)) {
$hash = md5_file($path);
if ($hash) { update_post_meta($aid, ‚_file_md5‘, $hash); $done++; $log[] = „ID {$aid}: Hash gesetzt“; }
}
}
}
$remaining = new WP_Query([
‚post_type‘ => ‚attachment‘,
‚posts_per_page‘ => 1,
‚meta_query‘ => [[‚key‘ => ‚_file_md5‘, ‚compare‘ => ‚NOT EXISTS‘]],
‚fields‘ => ‚ids‘,
]);
echo ‚<div class=“wrap“><h1>Medien-Hashes</h1>‘;
echo ‚<p>Noch ohne Hash: <strong>‘ . intval($remaining->found_posts) . ‚</strong></p>‘;
if ($done) echo ‚<p><strong>‘ . $done . ‚</strong> Anhänge in diesem Lauf verarbeitet.</p>‘;
if ($log) { echo ‚<pre style=“max-height:260px;overflow:auto;background:#f7f7f7;padding:10px;border:1px solid #ddd;“>‘;
foreach ($log as $l) echo esc_html($l) . „\n“; echo ‚</pre>‘; }
echo ‚<form method=“post“>‘; wp_nonce_field(‚run_media_hash‘);
submit_button(‚Jetzt 100 Dateien hashen‘,’primary‘,’run_hash‘,false);
echo ‚</form></div>‘;
});
});
Plesk/Hosting: so erstellst du die Dateien
-
Plesk → Files →
httpdocs/wp-content/themes/
-
Neuen Ordner:
DEINPARENT-child
(z. B.findus-child
) -
„+ Create File“ →
style.css
undfunctions.php
anlegen, Inhalte einfügen -
WP-Backend → Design → Themes → Child aktivieren
Häufige Fehler & schnelle Lösungen
-
„Stylesheet fehlt / Child wird nicht angezeigt“
→style.css
fehlt oder Header unvollständig.Template:
muss exakt dem Parent-Ordnernamen entsprechen. -
Weiße Seite / „Es gab einen kritischen Fehler“ nach Code-Einbau
→ Infunctions.php
Klammern/Kommas prüfen, kein?>
ans Ende, keine „smarten“ Anführungszeichen.
→ Notfall: Ordner kurz in Plesk umbenennen (z. B.findus-child.off
) → WP fällt aufs Parent zurück. -
WooCommerce-bezogene Theme-Widgets crashen im Editor
→ WooCommerce aktivieren oder Widget entfernen oder Fallback-Funktion im Child bereitstellen.
ZIP-Vorlage (Hochladen unter „Design → Theme hinzufügen“)
Für den Fall, dass du das Child-Theme nicht manuell über Plesk/FTP anlegen möchtest, kannst du dir den Ordner mit den zwei Dateien (style.css
und functions.php
) einfach als ZIP verpacken und im WordPress-Backend hochladen.
Konkret:
-
Auf deinem Rechner einen Ordner anlegen →
findus-child
-
Darin zwei Dateien:
-
style.css
(mit dem Header, woTemplate: findus
drinsteht) -
functions.php
(mit dem Code zum Laden der Styles)
-
-
Diesen Ordner rechtsklick → Zippen →
findus-child.zip
-
In WordPress: Design → Themes → Hinzufügen → Theme hochladen →
findus-child.zip
auswählen. -
Danach unter Design → Themes aktivieren.
findus-child/
├─ style.css
└─ functions.php
Bonus: Wann zusätzlich nützlich?
-
Mehrsprachigkeit/Übersetzungen (kleine Template-Anpassungen)
-
WooCommerce (Template-Overrides im Child)
-
Performance/Tracking (eigene Skripte sauber laden)
-
Sicherheits-Hooks (z. B. Upload-Filter, Login-Anpassungen)
0 Kommentare