Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Correctly Displaying Product Images and Stock

Correctly Displaying Product Images and Stock

~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Two of the practically most important data points are still missing from the detail page: a real product image and current stock – both sit in somewhat unexpected places in the API response.

A product can have MULTIPLE images – that's why media_gallery_entries is an array, not a single field:

"media_gallery_entries": [
  {
    "id": 12,
    "file": "/w/s/wsh12-blue_1.jpg",
    "position": 1,
    "types": ["image", "small_image", "thumbnail"]
  },
  {
    "id": 13,
    "file": "/w/s/wsh12-blue_2.jpg",
    "position": 2,
    "types": []
  }
]

types marks WHAT an image is used for in Magento – "image" is the product page's main image. file is NOT a complete URL, but a relative path we have to assemble ourselves.

Assembling the full image URL

src/api/magentoApi.js
// ... previous code ...

const MEDIA_BASE_URL = import.meta.env.VITE_MAGENTO_MEDIA_URL;

export function getProductImage(product) {
  const mainImage = product.media_gallery_entries?.find((entry) =>
    entry.types?.includes('image')
  );
  const anyImage = product.media_gallery_entries?.[0];
  const entry = mainImage ?? anyImage;

  if (!entry) {
    return null;
  }

  return `${MEDIA_BASE_URL}/catalog/product${entry.file}`;
}
.env
VITE_MAGENTO_BASE_URL=https://YOUR-SHOP.com/rest/V1
VITE_MAGENTO_MEDIA_URL=https://YOUR-SHOP.com/media
VITE_MAGENTO_ACCESS_TOKEN=YOUR_INTEGRATION_ACCESS_TOKEN

We add VITE_MAGENTO_MEDIA_URL as its own variable (instead of deriving it from VITE_MAGENTO_BASE_URL), since some Magento installations configure the media URL differently (e.g. a separate CDN domain) – remember to update .env.example accordingly and restart the dev server.

Achtung: mainImage ?? anyImage is deliberately built as a fallback: not EVERY product in your test shop necessarily has an image marked types: ["image"] – without a fallback, getProductImage() would return null for such products, even though SOME image does exist.

Stock from extension_attributes.stock_item

"extension_attributes": {
  "stock_item": {
    "qty": 42,
    "is_in_stock": true
  }
}
src/api/magentoApi.js
// ... previous code ...

export function getStockInfo(product) {
  const stockItem = product.extension_attributes?.stock_item;
  return {
    inStock: stockItem?.is_in_stock ?? false,
    quantity: stockItem?.qty ?? 0,
  };
}

Achtung: extension_attributes.stock_item is NOT automatically included in the product response in every Magento configuration – by default it is, but some custom ACL/API adjustments can restrict it. If it's missing for you, check under Stores → Configuration → Catalog → Inventory in the admin whether "Manage Stock" is enabled.

ProductDetailPage.jsx: integrating image and stock

src/pages/ProductDetailPage.jsx
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import {
  fetchProductBySku,
  readCustomAttribute,
  getProductImage,
  getStockInfo,
} from '../api/magentoApi';

function ProductDetailPage() {
  const { sku } = useParams();
  const [product, setProduct] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(true);
    async function load() {
      const data = await fetchProductBySku(sku);
      setProduct(data);
      setLoading(false);
    }
    load();
  }, [sku]);

  if (loading) {
    return <p>Loading product...</p>;
  }

  const description = readCustomAttribute(product, 'description');
  const imageUrl = getProductImage(product);
  const { inStock, quantity } = getStockInfo(product);

  return (
    <div>
      {imageUrl && <img src={imageUrl} alt={product.name} width="300" />}
      <h1>{product.name}</h1>
      <p>SKU: {product.sku}</p>
      <p>{product.price} €</p>
      <p>
        {inStock ? `In stock (${quantity} available)` : 'Out of stock'}
      </p>
      {description && (
        <div dangerouslySetInnerHTML={{ __html: description }} />
      )}
    </div>
  );
}

export default ProductDetailPage;

Tipp: The detail page now REALLY shows all essential product data: image, name, SKU, price, stock, and description – a good moment to click through several of your real products and check whether every field looks plausible.