ACF repeater fields - Hvordan style spesifikke rader?

ACF repeater fields - Hvordan style spesifikke rader?

Sist verifisert: 22. september 2026
8 min lesetid
Casestudie
Full-stack-utvikler

Feltet Repeater i Advanced Custom Fields (ACF Pro) er en hjørnestein i moderne WordPress-utvikling. Det gir innholdsforvaltere full fleksibilitet til å administrere lister med modulære elementer, som teamoversikter, prisplaner, arrangementstidslinjer eller kundeanbefalinger, uten å måtte opprette egne tilpassede innleggstyper (Custom Post Types) for hvert minste delinnhold.

Når designere utarbeider skreddersydde layouter, oppstår det nesten alltid et behov for differensiert visning. Typiske eksempler er sikksakk-oppsett der bilde og tekst bytter plass for hver rad, alternerende bakgrunnsfarger (“sebra-striper”), eller spesielle visuelle uttrykk for den første eller siste modulen i rekken.

I denne veiledningen går vi grundig gjennom hvordan du implementerer dette teknisk i malfilene dine, hvordan ACF lagrer data i databasen, og hvordan du trekker en fornuftig grense mellom PHP-styrt logikk og moderne CSS-egenskaper.

#Hvordan ACF Repeater lagres i WordPress-databasen

For å skrive ren og skalerbar kode er det nyttig å forstå hva som skjer i kulissene i MySQL. WordPress har ingen relasjonelle under-tabeller for metafelt. ACF løser dette ved å lagre hvert enkelt underfelt som en separat rad i tabellen wp_postmeta:

  1. Tellerrad: En metanøkkel med repeternavnet, for eksempel prosjekt_faser, som inneholder antallet rader (f.eks. 4).
  2. Underfelt: Hver kolonne og rad lagres som en unik rad, f.eks. prosjekt_faser_0_tittel, prosjekt_faser_0_tekst, prosjekt_faser_1_tittel, og så videre. Merk at den interne databasereferansen er 0-basert.
  3. Definisjonsnøkler: Skjulte rader med prefikset _ som knytter feltene til de respektive feltnøklene i ACF (field_61b...).

Dersom en repeater har 10 rader med 5 underfelt hver, genereres det over 50 rader i postmeta-tabellen. Å være bevisst på dette forhindrer uheldige arkitekturvalg, som overdreven nesting av repeatere inne i repeatere, noe som kan gi unødig belastning på databasespørringene.

#Standardoppsettet: have_rows() og the_row()

Den etablerte måten å hente ut verdier fra et repetert felt er å bruke ACFs innebygde iterasjonsmetoder:

<?php if ( have_rows( 'prosjekt_faser' ) ) : ?>
    <div class="faser-oversikt">
        <?php while ( have_rows( 'prosjekt_faser' ) ) : the_row(); 
            // Hent ut data for gjeldende rad
            $tittel = get_sub_field( 'tittel' );
            $beskrivelse = get_sub_field( 'beskrivelse' );
            $ikon = get_sub_field( 'ikon' );
        ?>
            <article class="fase-kort">
                <?php if ( ! empty( $ikon ) ) : ?>
                    <div class="fase-ikon">
                        <?php echo wp_get_attachment_image( $ikon['id'], 'thumbnail' ); ?>
                    </div>
                <?php endif; ?>
                <div class="fase-tekst">
                    <h3><?php echo esc_html( $tittel ); ?></h3>
                    <p><?php echo esc_html( $beskrivelse ); ?></p>
                </div>
            </article>
        <?php endwhile; ?>
    </div>
<?php endif; ?>

Legg merke til bruken av get_sub_field(). En hyppig feil blant ferske utviklere er å benytte standardfunksjonen get_field() inne i while-løkken. Dette vil enten returnere ingenting eller hente en global verdi fra innlegget, fordi den mangler pekerkonteksten som the_row() etablerer.

#Betinget formatering med PHP: get_row_index() og modulo

Når designet krever vesentlige endringer i selve HTML-strukturen, for eksempel at bilde og tekst bytter plassering i DOM-strukturen, er det nødvendig med logikk på serversiden.

#Den innebygde funksjonen get_row_index()

Tidligere var det vanlig å opprette en manuell tellevariabel $i = 0 før løkken. ACF har imidlertid en egen hjelpefunksjon for dette: get_row_index(). Denne returnerer radens gjeldende posisjon, og starter på 1:

<?php if ( have_rows( 'leveranse_steg' ) ) : ?>
    <section class="steg-seksjon">
        <?php while ( have_rows( 'leveranse_steg' ) ) : the_row(); 
            $rad_nummer = get_row_index();
            $er_partall = ( $rad_nummer % 2 === 0 );
            $oppsett_klasse = $er_partall ? 'layout-omvendt' : 'layout-normal';
            
            $steg_navn = get_sub_field( 'steg_navn' );
            $detaljer = get_sub_field( 'detaljer' );
        ?>
            <div class="steg-element <?php echo esc_attr( $oppsett_klasse ); ?>" data-steg="<?php echo esc_attr( (string) $rad_nummer ); ?>">
                <div class="steg-teller">
                    <span><?php echo esc_html( (string) $rad_nummer ); ?></span>
                </div>
                <div class="steg-innhold">
                    <h4><?php echo esc_html( $steg_navn ); ?></h4>
                    <div class="tekst-omrade">
                        <?php echo wp_kses_post( $detaljer ); ?>
                    </div>
                </div>
            </div>
        <?php endwhile; ?>
    </section>
<?php endif; ?>

Modulo-operatøren (%) beregner resten etter heltallsdivisjon med 2. Hvis resultatet er 0, er raden et partall. Dermed kan du legge til CSS-klassen layout-omvendt, som for eksempel styrer flex-direction: row-reverse i stilarket.

#Spesialbehandling av første og siste element

Av og til ønsker man at den første raden skal vises som en fremhevet “hero”-seksjon, eller at den siste raden skal ha en spesiell avslutningskant. Ved å telle totalt antall elementer kan vi enkelt identifisere ytterpunktene:

<?php
$alle_rader = get_field( 'leveranse_steg' );
$totalt_antall = is_array( $alle_rader ) ? count( $alle_rader ) : 0;

if ( have_rows( 'leveranse_steg' ) ) :
    while ( have_rows( 'leveranse_steg' ) ) : the_row();
        $gjeldende = get_row_index();
        $klasser = [ 'steg-rad' ];

        if ( $gjeldende === 1 ) {
            $klasser[] = 'forste-steg-fremhevet';
        }
        if ( $gjeldende === $totalt_antall ) {
            $klasser[] = 'siste-steg-avslutning';
        }
?>
    <div class="<?php echo esc_attr( implode( ' ', $klasser ) ); ?>">
        <!-- Innhold for raden -->
    </div>
<?php
    endwhile;
endif;

#Når bør du heller overlate stylingen til CSS?

Å blande for mye visuell formatering inn i PHP-malene gjør kildekoden tyngre å vedlikeholde. Dersom forskjellen mellom radene kun handler om bakgrunnsfarger, rammestiler eller små justeringer av marger, er det langt mer hensiktsmessig å bruke CSS.

Moderne CSS håndterer dette elegant med pseudoklassen :nth-child:

/* Sebrastriper uten PHP-innsats */
.faser-oversikt .fase-kort:nth-child(even) {
    background-color: #f1f5f9;
    border-left: 4px solid #2563eb;
}

.faser-oversikt .fase-kort:nth-child(odd) {
    background-color: #ffffff;
    border-left: 4px solid #94a3b8;
}

/* Fremhev det første elementet */
.faser-oversikt .fase-kort:first-child {
    border-top: 2px solid #2563eb;
}

#Tommelfingerregel for valg av metode

  1. Bruk CSS (:nth-child): Når endringene utelukkende er kosmetiske farger, fonter, rammer eller animasjonsforsinkelser. Dette sparer serveren for logikk og holder malfilene konsise.
  2. Bruk PHP (get_row_index): Når radene krever distinkt HTML-markup, betinget lasting av script, eller forskjellige bildestørrelser med unike srcset-attributter.

#Ytelsestiltak for store datamengder

På nettsteder med høy trafikk og store repetisjonsfelter kan gjentatte kall til get_sub_field() medføre merkbar overhead. Her er to velprøvde grep:

#Direkte array-utlesing

Dersom du ikke trenger å endre det globale WordPress-miljøet underveis, kan du hente hele matrisen direkte med get_field():

<?php
$punkter = get_field( 'kundeliste' );

if ( ! empty( $punkter ) && is_array( $punkter ) ) {
    echo '<div class="kunde-matrise">';
    foreach ( $punkter as $indeks => $punkt ) {
        $er_partall = ( $indeks % 2 === 0 );
        $navn = esc_html( $punkt['firmanavn'] ?? '' );
        $logo = $punkt['logo'] ?? null;
        
        echo '<div class="kunde-celle ' . ( $er_partall ? 'mork' : 'lys' ) . '">';
        echo '<span>' . $navn . '</span>';
        echo '</div>';
    }
    echo '</div>';
}

Dette reduserer mengden intern tilstandssporing i ACF og øker render-hastigheten i templates.

#Caching av ferdig HTML med Transients

Dersom innholdet sjelden endres av redaktørene, kan den genererte HTML-koden lagres i WordPress Transients API:

<?php
$post_id = get_the_ID();
$transient_nokkel = 'wppoland_repeater_html_' . $post_id;
$output = get_transient( $transient_nokkel );

if ( false === $output ) {
    ob_start();
    // Utfør have_rows() her
    $output = ob_get_clean();
Dette sikrer at serveren leverer ferdig HTML umiddelbart uten å måtte behandle metafelt på nytt ved hver sidevisning.

## Nøstede underfelt og ACF i WP REST API

I mange moderne applikasjoner, spesielt innen hodeløs WordPress (Headless CMS) med Astro eller Next.js, konsumeres repeater-data via WordPress sitt REST-API eller GraphQL.

### Eksponering i REST API

Når du definerer et repeater-felt i ACF-grensesnittet, bør du aktivere alternativet "Show in REST API". Feltet vil da bli tilgjengelig som en matrise av objekter under nøkkelen `acf`:

```json
{
  "id": 1024,
  "acf": {
    "prosjekt_faser": [
      {
        "tittel": "Analyse og arkitektur",
        "beskrivelse": "Kartlegging av tekniske krav og datamodeller",
        "ikon": 452
      },
      {
        "tittel": "Utvikling og integrasjon",
        "beskrivelse": "Programmering av kjernelogikk og REST-endepunkter",
        "ikon": 453
      }
    ]
  }
}

I et frontend-rammeverk som Astro itererer du over listen med ren JavaScript (map), og håndterer partall eller oddetall direkte i komponentmalen uten å belaste WordPress-serveren i det hele tatt:

---
const { faser } = Astro.props;
---
<div class="faser-gitter">
  {faser.map((fase, indeks) => (
    <article class={`fase-kort ${indeks % 2 === 0 ? 'partall' : 'oddetall'}`}>
      <h3>{fase.tittel}</h3>
      <p>{fase.beskrivelse}</p>
    </article>
  ))}
</div>

Dette mønsteret flytter all presentasjonslogikk ut til klientsiden eller den statiske byggeprosessen, noe som gir ekstremt raske responstider for sluttbrukerne.

#Ofte stilte spørsmål om ACF Repeater

#Starter get_row_index() på 0 eller 1?

I Advanced Custom Fields starter get_row_index() alltid tellingen på 1. Hvis du har behov for en 0-basert indeks, trekker du enkelt fra 1: $null_indeks = get_row_index() - 1.

#Hva er forskjellen mellom get_row_index() og get_row_layout()?

get_row_index() returnerer det numeriske radnummeret til feltet. get_row_layout() brukes derimot kun i felttypen Flexible Content for å identifisere navnet på layout-oppsettet som er valgt for den aktuelle raden.

#Hvor mange rader kan en ACF Repeater inneholde før det blir tregt?

Som en generell retningslinje bør du unngå mer enn 30 til 50 rader per innlegg med komplekse underfelt. Dersom du trenger hundrevis av elementer, er det arkitektonisk bedre å opprette en egen Custom Post Type med paginering og databaseindekser.

Strukturert bruk av ACF Repeater gir et stabilt fundament for innholdsrike og fleksible nettsider. Har bedriften din behov for avansert frontend-arkitektur, skreddersydde blokker eller ytelsesoptimalisering, bistår våre rådgivere gjerne gjennom vår tjeneste for WordPress-utvikling.

Neste steg

Gjør artikkelen om til faktisk implementering

Denne blokken styrker intern lenking og sender leseren videre til de mest relevante tjenestene og innholdet.

Vil du få dette implementert på nettstedet ditt?

Hvis du vil gjøre kunnskapen i artikkelen om til konkrete forbedringer, redesign eller en tydelig leveranseplan, kan jeg ta det videre.

Relevant klynge

Utforsk andre WordPress-tjenester og kunnskapsbase

Styrk virksomheten din med profesjonell teknisk støtte innen kjerneområdene i WordPress-økosystemet.

Relaterte artikler