Paginering er en af de mest oversete brugeroplevelsesdetaljer i en webshop. Traditionel paginering (side 1, 2, 3...) bryder browsingflowet og kræver fuld sidegenindlæsning. Ajax Load More løser det ved at indlæse nye produkter direkte i siden uden reload.
Det her er ikke teori. Vi har bygget og kørt den her løsning i produktion på danske WooCommerce-webshops, blandt andet med en "vis flere"-knap på en webshop vi driver, og guiden her er den opskrift vi selv bruger. Vi deler både koden, de SEO-faldgruber vi har lært at undgå, og de små fejl der oftest spænder ben. Vores mål er at du kan implementere en løsning der både føles hurtig for brugeren og er korrekt for søgemaskiner.
Hvad er Ajax Load More?
Ajax Load More er en teknik (og et populært WordPress-plugin) der bruger Ajax-kald til at hente og indsætte nyt indhold i siden uden fuld sidegenindlæsning. I en WooCommerce-kontekst betyder det at brugeren kan browse flere produkter med et klik på "Vis flere" eller med automatisk infinite scroll.
Fordele ved Ajax Load More i en webshop
- Bedre brugeroplevelse: Ingen irriterende sidegenindlæsninger. Browsing føles hurtig og glidende.
- Lavere bounce rate: Brugere der nemt kan se flere produkter, forlader sjældnere siden.
- Højere engagement: Flere sete produkter giver flere potentielle tilføjelser til kurven.
- Hurtigere opfattet hastighed: Kun nye produkter indlæses, ikke hele siden.
Metode 1: Ajax Load More-plugin (ingen kode)
Det nemmeste er at bruge Ajax Load More-pluginet (gratis med premium add-ons). Her er opsætningen:
- Installér og aktivér "Ajax Load More" fra WordPress plugin-repository.
- Køb og installér WooCommerce-add-on'en (påkrævet for WooCommerce-integration).
- Gå til Ajax Load More, Settings og konfigurér grundindstillinger.
- Tilføj shortcode til din shop-side eller brug pluginets template integration.
Grundlæggende shortcode
[ajax_load_more post_type="product" posts_per_page="12"
orderby="date" order="DESC"
button_label="Vis flere produkter"
button_loading_label="Indlæser..."
transition="fade" transition_speed="300"]
Med WooCommerce-specifik template
[ajax_load_more woocommerce="true"
posts_per_page="12"
button_label="Vis flere produkter"
images_loaded="true"
css_classes="woocommerce columns-3"]
Metode 2: Custom implementering (fuld kontrol)
Pluginet er fint til at komme hurtigt i gang, men når vi bygger til kunder, laver vi løsningen custom. Det giver fuld kontrol over markup, performance og hvordan knappen spiller sammen med tema og filtre, og vi undgår at trække et helt plugin ind for én funktion. Det er den løsning vi gennemgår herunder. Bemærk at koden bruger en nonce til at sikre Ajax-kaldet mod misbrug (CSRF). Her er den komplette opsætning:
Trin 1: PHP, registrér Ajax endpoint
// functions.php eller custom plugin
add_action('wp_ajax_load_more_products', 'load_more_products_handler');
add_action('wp_ajax_nopriv_load_more_products', 'load_more_products_handler');
function load_more_products_handler() {
// Verificér nonce (sikkerhed)
check_ajax_referer('load_more_nonce', 'nonce');
$paged = isset($_POST['page']) ? intval($_POST['page']) : 1;
$per_page = isset($_POST['per_page']) ? intval($_POST['per_page']) : 12;
$category = isset($_POST['category']) ? sanitize_text_field(wp_unslash($_POST['category'])) : '';
$args = array(
'post_type' => 'product',
'posts_per_page' => $per_page,
'paged' => $paged,
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
// Respektér WooCommerces synlighed, så load more matcher selve shoppen.
// Tilføj 'outofstock' til terms hvis din shop skjuler udsolgte varer.
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'product_visibility',
'field' => 'name',
'terms' => array('exclude-from-catalog'),
'operator' => 'NOT IN',
),
),
);
if ($category) {
$args['tax_query'][] = array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $category,
);
}
$query = new WP_Query($args);
if ($query->have_posts()) {
ob_start();
while ($query->have_posts()) {
$query->the_post();
wc_get_template_part('content', 'product');
}
$html = ob_get_clean();
wp_reset_postdata();
wp_send_json_success(array(
'html' => $html,
'has_more' => $paged < $query->max_num_pages,
));
} else {
wp_send_json_success(array(
'html' => '',
'has_more' => false,
));
}
}
Trin 2: Enqueue og localize scripts
Vigtigt: Du skal bruge wp_localize_script til at give JavaScript adgang til Ajax-URL'en og din nonce. Uden dette virker Ajax-kaldet ikke.
// functions.php
function enqueue_load_more_scripts() {
if (is_shop() || is_product_category()) {
wp_enqueue_script(
'load-more-products',
get_template_directory_uri() . '/assets/js/load-more.js',
array('jquery'),
'1.0.0',
true
);
wp_localize_script('load-more-products', 'wc_ajax_params', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('load_more_nonce'),
));
}
}
add_action('wp_enqueue_scripts', 'enqueue_load_more_scripts');
En vigtig note om nonce og caching: Nonces beskytter mod misbrug, men de udløber typisk efter 12 til 24 timer. Kører din side med fuld sidecaching, kan en cachet side ende med en udløbet nonce, så Ajax-kaldet fejler for nogle besøgende. Da dette endpoint kun returnerer offentlige produktdata, er der ingen reel CSRF-risiko, og du kan derfor vælge at droppe nonce-tjekket på stærkt cachede sider. Beholder du det, så sørg for at "vis flere"-knappen ikke ligger på en fuldt cachet side, eller hent en frisk nonce via et separat, ucachet kald.
Trin 3: JavaScript, Load More-funktionalitet
// assets/js/load-more.js
(function($) {
let currentPage = 1;
const perPage = 12;
let isLoading = false;
$('#load-more-btn').on('click', function(e) {
e.preventDefault();
if (isLoading) return;
isLoading = true;
const $btn = $(this);
$btn.text('Indlæser...').prop('disabled', true);
currentPage++;
$.ajax({
url: wc_ajax_params.ajax_url,
type: 'POST',
data: {
action: 'load_more_products',
nonce: wc_ajax_params.nonce,
page: currentPage,
per_page: perPage,
category: $btn.data('category') || '',
},
success: function(response) {
if (response.success && response.data.html) {
$('ul.products').append(response.data.html);
if (!response.data.has_more) {
$btn.fadeOut();
} else {
$btn.text('Vis flere produkter').prop('disabled', false);
}
}
isLoading = false;
},
error: function() {
$btn.text('Fejl, prøv igen').prop('disabled', false);
isLoading = false;
}
});
});
})(jQuery);
SEO-overvejelser
Det er her vi ser flest fejl, også i løsninger der ellers virker fint for brugeren. Ajax Load More kan påvirke din SEO hvis det implementeres forkert. Googlebot scroller ikke og klikker ikke på "Vis flere"-knapper, så indhold der kun er tilgængeligt via Ajax, risikerer ikke at blive indekseret. Vi følger Googles officielle anbefalinger for paginering:
Crawlbare pagineringslinks (progressiv forbedring)
Behold altid standard WooCommerce-paginering med rigtige <a href>-links i din HTML-kildekode. Ajax Load More skal være en forbedring ovenpå, ikke en erstatning. Google indekserer primært URL'er det finder i <a href>-tags, så de crawlbare links sikrer at alle dine produkter kan findes.
Brug selv-refererende canonicals (ikke canonical til side 1)
Dette er den hyppigste SEO-fejl ved paginering. Hver pagineret side (side 2, 3, 4...) skal have en selv-refererende canonical, altså side 2 canonicaliserer til side 2. Peg IKKE alle paginerede sider mod side 1. Gør du det, fortæller du Google at det skal ignorere alt efter side 1, hvilket kan gøre produkterne på de dybere sider forældreløse og uindekserede.
Undgå noindex på paginerede sider
Lad være med at sætte noindex på dine paginerede sider. Over tid holder Google op med at crawle noindexede sider og følger dermed ikke deres links, så produkter der kun er linket fra dybe sider, kan forsvinde fra indekset.
rel="next" og rel="prev" er ikke længere nødvendige
Google annoncerede i 2019 at de ikke længere bruger rel="next" og rel="prev" som signal. Har du dem allerede, gør de ingen skade (Bing bruger dem stadig), men du behøver ikke tilføje dem på nye sider. Brug i stedet din tid på crawlbare links og korrekte canonicals.
Unikke produkt-URL'er
Hvert produkt skal have sin egen permanente URL, uanset om det blev indlæst via Ajax eller traditionel paginering. Link altid til den kanoniske produkt-URL.
Vil du dykke dybere ned i det tekniske, så se vores guide til teknisk SEO.
Kompatibilitet med produktfiltre
Ajax Load More skal geninitialiseres når brugeren ændrer filtre. Her er et eksempel med YITH WooCommerce Ajax Product Filter:
// Lyt efter filterændringer
$(document).on('yith-wcan-ajax-filtered', function() {
// Reset page counter
currentPage = 1;
// Opdatér Load More-knap
$('#load-more-btn').show().text('Vis flere produkter');
// Hent aktive filtre til næste Ajax-kald
activeFilters = getCurrentFilters();
});
De fleste populære filter-plugins som YITH, WooCommerce Product Filter by WooBeWoo og FacetWP har lignende JavaScript-events du kan lytte på.
Performance-optimering
- Lazy load billeder: Brug
loading="lazy"på produktbilleder i Ajax-responsen for at spare båndbredde. Se vores guide til billedoptimering. - Preload næste side: Hent næste side i baggrunden når brugeren nærmer sig bunden, så indlæsningen føles øjeblikkelig.
- Caching: Cache Ajax-responses server-side med Transients API for at reducere databaseforespørgsler.
- Minimér response-størrelse: Send kun den HTML der er nødvendig, ikke hele sidens markup.
Hastighed påvirker både brugeroplevelse og SEO. Se hvordan det hænger sammen med dine Core Web Vitals.
Fejlfinding: Almindelige problemer
Det er de samme håndfulde fejl der går igen, når vi sætter Ajax Load More op. Her er dem vi oftest støder på, og hvordan vi løser dem:
Ajax-kaldet returnerer 0 eller en fejl
Den hyppigste årsag er en manglende eller forkert nonce, eller at wp_localize_script ikke kører. Tjek at wc_ajax_params faktisk er defineret i frontenden (kig i browserens konsol), og at nonce-navnet matcher mellem PHP og JavaScript.
Produkter vises ikke korrekt
Tjek at du bruger wc_get_template_part('content', 'product') i dit Ajax-endpoint. Hvis dit tema bruger en custom product loop, skal du referere til den template i stedet.
Billeder mangler eller er forkert størrelse
Sørg for at WooCommerce-billedstørrelserne er konfigurerede. Kør evt. "Regenerate Thumbnails" efter ændringer.
Load More-knap forsvinder ikke
Tjek at din Ajax-handler returnerer has_more: false korrekt. Sammenlign $paged med $query->max_num_pages.
Konflikter med page builders
Elementor, Divi og WPBakery har egne product loop-elementer der kan konflikte med Ajax Load More. Brug plugin-specifikke hooks til integration, eller implementér Load More direkte i page builderens custom widget.
Anbefaling: Load More-knap vs. infinite scroll
Vi får ofte spørgsmålet om vi ikke bare skal lave infinite scroll i stedet. Vores erfaring er klar: vi vælger næsten altid Load More-knappen frem for infinite scroll i webshops. Infinite scroll lyder tiltalende, men giver i praksis flere problemer:
- Brugeren kan ikke nå footeren (med kontaktinfo, links osv.).
- Det er sværere for brugeren at vende tilbage til et specifikt produkt.
- Det kan føles overvældende for brugere der leder efter noget bestemt.
- Tilgængelighed er bedre med en eksplicit knap.
Uanset metode er det vigtigste at indholdet også findes via crawlbare URL'er, så hverken brugere eller søgemaskiner går glip af produkter.
Vil du have hjælp til at optimere din WooCommerce-shop? Se vores e-commerce services eller kontakt os for en uforpligtende snak om din webshops performance og brugeroplevelse.
