Przejdź do treści

Jak stworzyć banner z rekomendacjami w edytorze kodu

Edytor kodu umożliwia tworzenie dynamicznych banerów z rekomendacjami produktów przy użyciu kombinacji HTML, CSS, JavaScript i składni Razor. Z jego pomocą wyświetlisz spersonalizowane rekomendacje produktów bezpośrednio na swojej stronie lub w kampaniach e-mail.

Funkcja „Podgląd na żywo” w bannerach

Nazwy produktów w rekomendacjach zostaną wyświetlone jako ’@products[0]?.Name’, ponieważ obsługujący je kod nie jest przetwarzany bezpośrednio w edytorze .

Jeśli chcesz przetestować banner zawierający rzeczywiste dane produktów, skorzystaj z opcji Podgląd na żywo lub przetestuj banner bezpośrednio na swojej stronie.

Wspierane technologie

Edytor kodu pozwala na użycie następujących technologii:

  • HTML5 – użyj do nadania struktury bannerowi.
  • CSS3 – użyj do nadania indywidualnego wyglądu i responsywności.
  • JavaScript – pozwoli dodać elementy interaktywne i dynamiczne.
  • Składnia Razor – obsługuje logikę rekomendacji po stronie serwera, pozwala na wiązanie danych (data binding) za pomocą bloków „@{}”.

Pobieranie rekomendacji produktowych

Użyj następującego wyrażenia w bloku kodu, który ma wyświetlić rekomendacje:

@{
ExpertSender.Cdp.Common.Interfaces.DynamicContent.IProduct[] products = Model.GetRecommendedProducts(4).ToArray();
}

Ten kod pobiera maksymalnie 4 polecane produkty i zapisuje je w tablicy. Liczbę tę możesz dostosować do wymagań projektu banera.

Dostępne zmienne produktów

W tablicy poniżej znajdziesz zmienne dla każdej cechy produktu:

ZmiennaTypOpisJak stosować?
IdstringUnikalny identyfikator produktuproducts[0].Id
NamestringNazwa / tytuł produktuproducts[0]?.Name
ImageUrlstringAdres URL obrazka przedstawiającego produktproducts[0]?.ImageUrl
UrlstringAdres URL strony produktuproducts[0]?.Url
PriceSstringCena regularna w formacie stringproducts[0]?.PriceS
SalePricestringCena po obniżce w formacie stringproducts[0]?.SalePriceS
OmnibusPriceSstringNecna Omnibus (wymagana przez UE)products[0]?.OmnibusPriceS
CurrencySymbolstringSymbol waluty (€, $, £, etc.)products[0]?.CurrencySymbol

Przykłady użycia

Sprawdź, czy produkt istnieje i wyświetl cenę po obniżce

@if (products[0] != null)
{
    Produkt wyświetli się w tym miejscu
}

Sprawdź, czy cena po obniżce może być wyświetlona

Aby wyświetlić produkty z obniżoną ceną, sprawdź, czy zarówno cena regularna, jak i obniżona są dostępne dla danego produktu.

@if (!string.IsNullOrWhiteSpace(products[0]?.SalePriceS))
{
    @products[0]?.SalePriceS @products[0]?.CurrencySymbol
}
else
{
    @products[0]?.PriceS @products[0]?.CurrencySymbol
}

Wyświetl cenę Omnibus, jeśli jest dostępna

Wyświetlanie ceny Omnibus jest wymagane przez Unię Europejską, gdy polecasz produkty o obniżonej cenie.

@if (!string.IsNullOrWhiteSpace(products[0]?.OmnibusPriceS))
{
   Najniższa cena z 30 dni: @products[0]?.OmnibusPriceS @products[0]?.CurrencySymbol
}

Oblicz i wyświetl obniżkę procentową

@{
    decimal regularPrice = 0;
    decimal salePrice = 0;
    decimal discountPercentage = 0;
    
    if (decimal.TryParse(products[0]?.PriceS, out regularPrice) && 
        decimal.TryParse(products[0]?.SalePriceS, out salePrice) &&
        regularPrice > 0 && salePrice > 0)
    {
        discountPercentage = Math.Round(((regularPrice - salePrice) / regularPrice) * 100, 0);
    }
}

@if (discountPercentage > 0)
{
    -@discountPercentage%
}

Pełna logika wyświetlania cen

Poniżej znajdziesz przykład obsługujący wszystkie scenariusze cenowe:

@if (!string.IsNullOrWhiteSpace(rec2[0]?.SalePriceS))
{
    @rec2[0]?.SalePriceS @rec2[0]?.CurrencySymbol
    @rec2[0]?.PriceS @rec2[0]?.CurrencySymbol

    @if (!string.IsNullOrWhiteSpace(rec2[0]?.OmnibusPriceS))
    {
        @rec2[0]?.OmnibusPriceS @rec2[0]?.CurrencySymbol
    }
}
else
{
    @rec2[0]?.PriceS @rec2[0]?.CurrencySymbol
}

Pętla przez wszystkie produkty

Oto jak przejść przez wszystkie pobrane produkty i wyświetlić ich właściwości:

@{    ExpertSender.Cdp.Common.Interfaces.DynamicContent.IProduct[] products = Model.GetRecommendedProducts(4).ToArray();
}

@for (int i = 0; i < products.Length; i++)
{
    if (products[i] != null)
    {
        @products[i].Id
        @products[i].Name
        @products[i].ImageUrl
        @products[i].Url
        @products[i].PriceS
        @products[i].SalePriceS
        @products[i].OmnibusPriceS
        @products[i].CurrencySymbol
    }
}

Przykładowa struktura banneru

<style>
        .banner-header {
            text-align: center;
            padding: 20px;
            background: white;
        }

        .banner-header h1 {
            color: #2c3e50;
            font-size: 24px;
            margin-bottom: 5px;
            font-weight: 600;
        }

        .banner-header p {
            color: #7f8c8d;
            font-size: 14px;
            margin: 0;
        }

        .expertsender-banner {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 0;
            width: 100%;
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            box-sizing: border-box;
        }

        .banner-title {
            grid-column: 1 / -1;
            text-align: center;
            font-size: 32px;
            color: #2c3e50;
            margin: 40px 0 30px 0;
            font-weight: 300;
            letter-spacing: -0.5px;
        }

        .product-card {
            background: white;
            padding: 30px 20px;
            text-align: center;
            transition: all 0.3s ease;
            position: relative;
            display: flex;
            flex-direction: column;
            height: 520px;
            border-right: 1px solid #f1f3f4;
        }

        .product-card:last-child {
            border-right: none;
        }

        .product-card:hover {
            background: #fafbfc;
            transform: translateY(-2px);
        }

        .discount-badge {
            position: absolute;
            top: 20px;
            right: 20px;
            background: #e74c3c;
            color: white;
            padding: 6px 12px;
            border-radius: 20px;
            font-size: 12px;
            font-weight: 600;
            box-shadow: 0 2px 8px rgba(231, 76, 60, 0.25);
        }

        .product-image {
            width: 220px;
            height: 220px;
            object-fit: cover;
            border-radius: 8px;
            margin: 0 auto 20px auto;
            transition: transform 0.3s ease;
            background: #f8f9fa;
        }

        .product-card:hover .product-image {
            transform: scale(1.02);
        }

        .product-name {
            font-size: 18px;
            font-weight: 500;
            color: #2c3e50;
            margin-bottom: 15px;
            height: 50px;
            overflow: hidden;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            line-height: 1.4;
        }

        .price-section {
            margin-bottom: 25px;
            flex-grow: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
        }

        .current-price {
            font-size: 24px;
            font-weight: 600;
            color: #2c3e50;
            margin-bottom: 5px;
        }

        .sale-price {
            font-size: 24px;
            font-weight: 600;
            color: #e74c3c;
            margin-bottom: 5px;
        }

        .original-price {
            font-size: 16px;
            text-decoration: line-through;
            color: #95a5a6;
        }

        .buy-button {
            background: #2c3e50;
            color: white;
            padding: 12px 32px;
            border: none;
            border-radius: 4px;
            text-decoration: none;
            display: inline-block;
            font-size: 14px;
            font-weight: 500;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-top: auto;
        }

        .buy-button:hover {
            background: #34495e;
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(44, 62, 80, 0.25);
        }

        .code-section {
            margin-top: 40px;
            background: white;
            padding: 30px;
            margin-left: 20px;
            margin-right: 20px;
            border-radius: 8px;
            border: 1px solid #e9ecef;
        }

        .code-section h3 {
            color: #2c3e50;
            margin-bottom: 20px;
            font-size: 18px;
            font-weight: 500;
        }

        .code-block {
            background: #f8f9fa;
            color: #2c3e50;
            padding: 20px;
            border-radius: 6px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 13px;
            line-height: 1.6;
            border: 1px solid #e9ecef;
        }

        @media (max-width: 768px) {
            .product-card {
                border-right: none;
                border-bottom: 1px solid #f1f3f4;
                height: auto;
                min-height: 420px;
            }
            
            .product-card:last-child {
                border-bottom: none;
            }
            
            .banner-title {
                font-size: 28px;
                margin: 30px 0 20px 0;
            }
        }

        @media (max-width: 480px) {
            .expertsender-banner {
                grid-template-columns: 1fr;
            }
            
            .product-image {
                width: 200px;
                height: 200px;
            }
        }
</style>

@{
    ExpertSender.Cdp.Common.Interfaces.DynamicContent.IProduct[] products = Model.GetRecommendedProducts(4).ToArray();
}

<div class="expertsender-banner">
    <h3 class="banner-title">Featured Products</h3>
    @foreach (var product in products)
    {
        <div class="product-card">
            @if (decimal.TryParse(product?.PriceS, out decimal regularPrice) && 
                 decimal.TryParse(product?.SalePriceS, out decimal salePrice) &&
                 regularPrice > 0 && salePrice > 0)
            {
                <div class="discount-badge">@Math.Round(((regularPrice - salePrice) / regularPrice) * 100, 0)% OFF</div>
            }
            
            <img src="@product?.ImageUrl" alt="@product?.Name" class="product-image">
            <div class="product-name">@product?.Name</div>
            
            <div class="price-section">
                @if (!string.IsNullOrWhiteSpace(product?.SalePriceS))
                {
                    <div class="sale-price">@product?.SalePriceS @product?.CurrencySymbol</div>
                    <div class="original-price">@product?.PriceS @product?.CurrencySymbol</div>
                }
                else
                {
                    <div class="current-price">@product?.PriceS @product?.CurrencySymbol</div>
                }
            </div>
            
            <a href="@product?.Url" class="buy-button">Shop Now</a>
        </div>
    }
</div>

Podgląd banneru:

– 25%
Czerwona bluza
Czerwona bluza
127,50 zł
170 zł
Kup teraz
Czerwona koszulka
Czerwona koszulka
80,00 zł
Kup teraz
-15%
Szara bluza
Szara bluza
127,50 zł
150,00 zł
Kup teraz
Szara kolszulka
Szara koszulka
69, 00 zł
Kup teraz

Tabela debugowania danych produktów

Ta tabela jest przydatna do debugowania i sprawdzania cech produktu zwróconych przez silnik rekomendacji.

Wyświetla wszystkie dostępne dane produktu w ustrukturyzowanym formacie iułatwia weryfikację, czy API zwraca oczekiwane informacje.

@{
    ExpertSender.Cdp.Common.Interfaces.DynamicContent.IProduct[] products = Model.GetRecommendedProducts(4).ToArray();
}
<style>
    table.custom-table {
        border-collapse: collapse;
        width: 100%;
    }
    table.custom-table, table.custom-table th, table.custom-table td {
        border: 1px solid black;
    }
    table.custom-table th, table.custom-table td {
        padding: 8px;
    }
</style>

<table class="custom-table">
  <thead>
    <tr>
      <th>Product</th>
      <th>Image</th>
      <th>Name</th>
      <th>Link</th>
      <th>ID</th>
      <th>Regular Price</th>
      <th>Sale Price</th>
      <th>Omnibus Price</th>
    </tr>
  </thead>
  <tbody>
    @foreach (var product in products.Where(p => p != null).Select((p, index) => new { Product = p, Index = index }))
    {
    <tr>
      <td>Product @product.Index</td>
      <td><img src="@product.Product.ImageUrl" alt="Product @product.Index" width="100"/></td>
      <td>@product.Product.Name</td>
      <td><a href="@product.Product.Url">@product.Product.Url</a></td>
      <td>@product.Product.Id</td>
      <td>@product.Product.PriceS @product.Product.CurrencySymbol</td>
      <td>@product.Product.SalePriceS @product.Product.CurrencySymbol</td>
      <td>@product.Product.OmnibusPriceS @product.Product.CurrencySymbol</td>
    </tr>
    }
  </tbody>
</table>

Najlepsze praktyki

  • Aby zapobiec błędom, zawsze używaj operatorów warunkowych null (?.) podczas uzyskiwania dostępu do właściwości produktu.
  • Przed wyświetleniem treści sprawdź, czy występują wartości null lub puste.
  • Stosuj zasady projektowania responsywnego, aby upewnić się, że Twoje banery będą działać na wszystkich urządzeniach.
  • Przetestuj swoje banery przy użyciu różnej liczby zwróconych produktów. API może zwrócić mniej produktów niż żądano.
  • Podczas implementacji weź pod uwagę stany ładowania i stany puste.