Advanced Custom Fields (ACF) - Wiederholbare Felder und Styling

Advanced Custom Fields (ACF) - Wiederholbare Felder und Styling

Zuletzt überprüft: 22. September 2026
7 Min. Lesezeit
Fallstudie
Full-Stack-Entwickler
In der professionellen WordPress-Theme-Entwicklung gehört das Plugin Advanced Custom Fields (ACF Pro) zum festen Standard. Das Repeater Field (wiederholbares Feld) ist dabei eine der vielseitigsten Funktionen: Es erlaubt Redakteuren, beliebig viele strukturierte Einträge wie Team-Profile, FAQ-Akkordeons, Leistungsmerkmale oder Konferenz-Agenden direkt im Beitragseditor zu pflegen, ohne dafür separate Custom Post Types anlegen zu müssen.

Im Frontend stehen Entwickler jedoch regelmäßig vor der Herausforderung, diese dynamischen Zeilen gestalterisch zu variieren. Häufig verlangt das Screendesign ein sogenanntes Zick-Zack-Muster (Bild links, Text rechts im ersten Block; Bild rechts, Text links im zweiten Block) oder wechselnde Hintergrundfarben zur visuellen Rhythmisierung.

In dieser technischen Anleitung zeigen wir Ihnen, wie Sie die have_rows()-Schleife sauber strukturieren, wie Sie den Modulo-Operator in PHP und moderne CSS-Pseudoklassen :nth-child() gezielt einsetzen und wie Sie teure Performance-Fallen in der WordPress-Datenbank vermeiden.

#Das Datenmodell hinter dem ACF Repeater

Um sauberen und performanten Code zu schreiben, müssen Entwickler verstehen, wie WordPress und ACF die Werte auf Datenbankebene ablegen. WordPress speichert Beitragsmetadaten in der relationalen Tabelle wp_postmeta als einfache Schlüssel-Wert-Paare.

Wenn Sie ein Repeater-Feld mit dem Bezeichner leistungs_merkmale anlegen, das zwei Unterfelder (titel und beschreibung) enthält, und der Redakteur 4 Zeilen speichert, erzeugt ACF folgende Einträge:

  1. Einen Zähler-Datensatz: leistungs_merkmale mit dem Wert 4.
  2. Einträge für Zeile 0: leistungs_merkmale_0_titel und leistungs_merkmale_0_beschreibung.
  3. Einträge für Zeile 1: leistungs_merkmale_1_titel und leistungs_merkmale_1_beschreibung.
  4. …sowie interne Referenzschlüssel für die Felddefinitionen (_leistungs_merkmale_0_titel).

Für 10 Zeilen mit jeweils 3 Unterfeldern entstehen somit über 60 Zeilen in der Tabelle wp_postmeta. Bei unbedachter Nutzung in Schleifen kann dies zu spürbaren Verzögerungen führen, wenn WordPress viele Datenbankabfragen nacheinander absetzt.

#Die Standard-Schleife: have_rows() und the_row()

Die empfohlene Methode zur Ausgabe eines Repeater-Felds nutzt die Funktionen have_rows() und the_row():

<?php if ( have_rows('leistungs_merkmale') ) : ?>
    <section class="features-repeater-section">
        <div class="container">
            <div class="features-grid">
                <?php while ( have_rows('leistungs_merkmale') ) : the_row(); 
                    $titel = get_sub_field('titel');
                    $text  = get_sub_field('beschreibung');
                    $icon  = get_sub_field('symbol');
                ?>
                    <div class="feature-card">
                        <?php if ( ! empty( $icon ) ) : ?>
                            <div class="feature-icon">
                                <?php echo wp_get_attachment_image( $icon['id'], 'thumbnail' ); ?>
                            </div>
                        <?php endif; ?>
                        <h3><?php echo esc_html( $titel ); ?></h3>
                        <div class="feature-body">
                            <?php echo wp_kses_post( $text ); ?>
                        </div>
                    </div>
                <?php endwhile; ?>
            </div>
        </div>
    </section>
<?php endif; ?>

Wichtig: Verwenden Sie innerhalb der Repeater-Schleife niemals get_field(), sondern immer get_sub_field(). Nur get_sub_field() greift auf den internen Zeiger zu, der durch the_row() für die aktuelle Iteration gesetzt wurde.

#Dynamisches Styling in PHP: Zähler und Modulo-Operator

Wenn Sie Zeilen basierend auf ihrer Position mit unterschiedlichen CSS-Klassen versehen oder HTML-Elemente umstellen möchten, liefert PHP präzise Kontrollmöglichkeiten.

#Nutzung der integrierten Funktion get_row_index()

Anstatt vor der Schleife manuell eine Variable wie $i = 0; zu deklarieren und hochzuzählen, stellt ACF die Hilfsfunktion get_row_index() bereit. Sie liefert die Nummer der aktuellen Zeile zurück, beginnend bei 1:

<?php if ( have_rows('prozess_schritte') ) : ?>
    <div class="timeline-container">
        <?php while ( have_rows('prozess_schritte') ) : the_row(); 
            $index = get_row_index();
            $ist_gerade = ( $index % 2 === 0 );
            $layout_klasse = $ist_gerade ? 'layout-reversed' : 'layout-standard';
        ?>
            <article class="timeline-item <?php echo esc_attr( $layout_klasse ); ?>">
                <div class="step-badge">Schritt 0<?php echo (int) $index; ?></div>
                <div class="step-content">
                    <h3><?php echo esc_html( get_sub_field('schritt_titel') ); ?></h3>
                    <p><?php echo esc_html( get_sub_field('schritt_text') ); ?></p>
                </div>
            </article>
        <?php endwhile; ?>
    </div>
<?php endif; ?>

#Modulo-Muster im Praxiseinsatz

Der Modulo-Operator (%) ermittelt den mathematischen Rest einer Ganzzahldivision:

  • Abwechselnde Zeilen (A/B-Muster): $index % 2 === 0 (jede gerade Zeile).
  • Hervorhebung jedes dritten Elements in einem Grid: $index % 3 === 0 (z.B. Premium-Karten).
  • Sonderbehandlung des ersten Elements: $index === 1 für einen dominanten Hero-Eintrag.

#Styling im Stylesheet: Moderne CSS-Selektoren

Gute Webarchitektur trennt Struktur von Präsentation. Wann immer eine Designänderung rein visueller Natur ist (z.B. Hintergrundfarben, Ausrichtungen oder Abstände), sollte dies direkt im Stylesheet über CSS abgebildet werden. Dadurch bleibt das PHP-Markup schlank und wartungsfreundlich.

#Pseudoklasse :nth-child()

Moderne CSS-Spezifikationen bieten extrem flexible Pseudoklassen:

/* Abwechselnde Hintergrundfarben für Zebra-Tabellen oder Zeilen */
.timeline-container .timeline-item:nth-child(even) {
  background-color: #f1f5f9;
}

/* Flexbox-Richtung bei geraden Zeilen umkehren (Zick-Zack-Layout) */
.timeline-container .timeline-item:nth-child(even) {
  flex-direction: row-reverse;
}

/* Jedes dritte Element im CSS Grid farblich hervorheben */
.features-grid .feature-card:nth-child(3n) {
  border: 2px solid #0284c7;
  box-shadow: 0 10px 25px -5px rgba(2, 132, 199, 0.1);
}

/* Das letzte Element der Liste gezielt ansprechen */
.timeline-container .timeline-item:last-child .divider-line {
  display: none;
}

#Wann PHP unverzichtbar bleibt

Trotz der Stärke von CSS gibt es Fälle, in denen die PHP-Logik zwingend erforderlich ist:

  1. Unterschiedliche HTML-Elemente: Wenn ungerade Elemente ein <section>-Tag und gerade Zeilen ein <aside>-Tag nutzen.
  2. Dynamisches Einbinden von Sub-Templates: Wenn abhängig von der Position separate Template-Parts über get_template_part() geladen werden.
  3. Strukturierte Daten (Schema.org): Wenn für SEO-Zwecke numerische Positionsangaben in JSON-LD-Scripts ausgegeben werden müssen.

#Performance-Optimierung bei großen Datenmengen

Wächst ein Repeater-Feld auf mehr als 30 bis 50 Zeilen an, kann die Ladezeit der Seite leiden. Da jedes get_sub_field() im Hintergrund Metadaten abfragt, steigen die CPU- und Speicherauslastung des PHP-Prozesses.

#1. Alle Daten auf einmal mit get_field() laden

Statt der iterativen while(have_rows())-Schleife kann es bei sehr großen Datenmengen effizienter sein, das gesamte Repeater-Feld als verschachteltes PHP-Array einzulesen:

$alle_schritte = get_field('prozess_schritte');

if ( ! empty( $alle_schritte ) && is_array( $alle_schritte ) ) {
    foreach ( $alle_schritte as $position => $schritt ) {
        $titel = $schritt['schritt_titel'] ?? '';
        $text  = $schritt['schritt_text'] ?? '';
        $nummer = $position + 1;
        // Verarbeitung ohne wiederholte get_sub_field()-Funktionsaufrufe
    }
}

#2. HTML-Ausgabe im Transients-Cache sichern

Wenn sich der Inhalt des Repeaters selten ändert, empfiehlt sich das Zwischenspeichern des fertig gerenderten HTML-Blocks mithilfe der WordPress Transients API:

function wppoland_render_prozess_cached( int $post_id ): void {
    $cache_key = 'wppoland_prozess_html_' . $post_id;
    $output = get_transient( $cache_key );

    if ( false === $output ) {
        ob_start();
        if ( have_rows('prozess_schritte', $post_id) ) {
            echo '<div class="timeline-container">';
            while ( have_rows('prozess_schritte', $post_id) ) {
                the_row();
                // HTML-Ausgabe...
            }
            echo '</div>';
        }
        $output = ob_get_clean();
        // 24 Stunden im Cache vorhalten
        set_transient( $cache_key, $output, DAY_IN_SECONDS );
    }

    echo $output;
}

// Cache bei Beitragsaktualisierung invalidieren
add_action('save_post', function (int $post_id): void {
    delete_transient('wppoland_prozess_html_' . $post_id);
});

Mit dieser Architektur wird die Datenbankabfrage nur ein einziges Mal pro Tag ausgeführt; alle folgenden Besucher erhalten die fertige HTML-Struktur verzögerungsfrei aus dem Cache.

#Häufig gestellte Fragen (FAQ)

#Worin liegt der Unterschied zwischen get_row_index() und einem manuellen Zähler?

Die Funktion get_row_index() ist eine native ACF-Methode, die automatisch die 1-basierte Nummer der aktuellen Zeile liefert. Dadurch entfällt die Notwendigkeit, vor der Schleife eine Zählervariable wie $i = 0 zu definieren und im Schleifenkörper manuell zu inkrementieren.

#Sollte man für Farbwechsel eher PHP oder CSS verwenden?

Für rein optische Anpassungen (wie alternierende Zeilenfarben oder das Umkehren von Flexbox-Richtungen) ist CSS :nth-child(even) die sauberere und performantere Lösung. PHP-Modulo sollte nur verwendet werden, wenn sich die HTML-Verschachtelung ändert oder verschiedene Vorlagendateien geladen werden müssen.

#Wie werden Bilder im Repeater-Feld performant ausgegeben?

Stellen Sie den Rückgabewert des Bild-Unterfelds in ACF auf Bild-ID ein. Nutzen Sie im Template wp_get_attachment_image($image_id, 'medium_large'), um responsive srcset-Attribute, Bilddimensionen und natives Browser-Lazy-Loading automatisch zu generieren.

#Warum reagiert meine Seite bei vielen Repeater-Zeilen träge?

Da ACF jedes Unterfeld als eigenständigen Eintrag in der Tabelle wp_postmeta speichert, entstehen bei 50 Zeilen schnell hunderte Einzeldaten. Dies lässt sich durch das Zwischenspeichern des gerenderten HTML via Transients API oder den Wechsel zu relationalen Custom Tables beheben.

#Fazit

Das ACF Repeater Field bietet Entwicklern die perfekte Balance zwischen redaktionellem Komfort und technischer Gestaltungsfreiheit. Durch die Kombination von have_rows(), der Indizierungsfunktion get_row_index() und modernen CSS-Selektoren lassen sich anspruchsvolle Layouts sauber und wartbar umsetzen.

Benötigen Sie Unterstützung bei der Entwicklung maßgeschneiderter WordPress-Themes mit Advanced Custom Fields oder möchten Sie Ihre bestehende Architektur auf maximale Geschwindigkeit optimieren? Entdecken Sie unsere Leistungen für professionelle WordPress-Entwicklung oder buchen Sie eine gezielte WordPress-Wartung.

Nächster Schritt

Machen Sie aus dem Artikel eine echte Umsetzung

Dieser Block stärkt die interne Verlinkung und führt Nutzer gezielt zum nächsten sinnvollen Schritt im Service- und Content-System.

Soll das Thema auf Ihrer Website umgesetzt werden?

Wenn Sie aus dem Artikel konkrete Maßnahmen für Website, Relaunch oder Weiterentwicklung ableiten wollen, definiere ich den Scope und setze ihn um.

Relevanter Cluster

Weitere WordPress-Dienste und Wissensbasis entdecken

Stärken Sie Ihr Unternehmen mit professionellem technischen Support in den Kernbereichen des WordPress-Ökosystems.

Ähnliche Artikel