Katalog ve Ürün Sayfaları
Genel kataloğun tamamını üç view taşır; zor iş, JavaScript'in hemen değiştirmeyeceği bir fiyat yazmaktır.
Genel Bakış
Katalog, bir temanın aynı sayıyı iki kez ürettiği tek bölümdür: sunucu ilk boyama için yazar, tarayıcı faturalama butonu her hareket ettiğinde yeniden yazar. Bir kuruş fark, sayfanın titremesidir.
Tutarlar çevrilmiş ve promosyonu çözülmüş gelir, yani view'a hiçbir fiyat mantığı ait değildir.
Yapı
Üç view, tek fiyat mekanizması. Kategori sayfası iki düzen taşır ve aralarında çalışma anında seçer. Fiyatlı ürün yoksa aşağıdaki dalların hepsi atlanır.
| View | Cevap verdiği | Ana veri |
|---|---|---|
views/products/category | Her kategori adresi, üst ve yaprak | $mode, $tabs ya da $cards artı $plans, $billing_cycles, $price_mode |
views/products/software | Mağaza kökü ve her mağaza kategorisi | $products, $filters, $page_size, $total_count |
views/products/detail | Tek bir yazılım ürününün kendi sayfası | $product, $prices, $gallery, $included, $versions, $faq |
$plans bekler ve $billing_cycles'ı üst kapsamdan okur, ikisini birden geçin.
features yerine specs ve chips bekler.
Adım Adım
İki Kategori Modunu da Karşılayın
İçerik bloğunun içindeki ilk iş $mode'a dallanmak olsun.
- tabs: her çocuk bir yapraktır, sayfa alt aile sekmeleri ve pano başına bir ızgara gösterir. Her
$tabskaydı kendi başlığını, meta'sını, hero arka planını ve planlarını taşır. - drilldown: kategorinin hem alt kategorileri hem kendi planları vardır —
$cardsve$plans. - Faturalama butonunu yalnız değiştirilecek bir şey varken gösterin:
{if $billing_cycles|@count > 1}.
Planı Basın, Fiyat Mantığını Değil
- Kart öğesine
plan-card, yatay yerleşimdeplan-rowsınıfını verin. - Aşağıdaki sözleşmedeki
data-*özniteliklerini ekleyin. - Tükendi durumu için harekete geçirici mesajı
$plan.in_stockile değiştirin; kartı gizlemeyin. $plan.link'i geldiği gibi kullanın.
Fiyatı İki Kez, Aynı Şekilde Yazın
Sunucu sayfa boş kalmasın diye yazar, script üzerine yazar; ikisi aynı string'i üretmek zorundadır.
- Sunucu değerini şu düğüme basın:
<span data-role="price-now">{$plan.price_now}</span>. - Aylık son ekini yanına basın, dönem toplamında gizleyin:
{if $plan.is_period}d-none{/if}. - Türetilmiş figürleri boş bırakın — onlar script'in işi.
- Sayfa bağlamını sarmalayıcıya koyun.
Kategorinin Yerleşim Tercihine Uyun
Bir kategori ızgara yerine yatay satır isteyebilir; tercih $layout olarak gelir.
- Tek bir yerde, include'da dallanın: ya satır ya ızgara, asla yarı dönüşmüş bir kart değil.
- Izgara planında
featuresvardır; satır planındaspecsvechipsvardır,featuresyoktur. value|labelçifti taşımayan özellik metninde her satır çipe dönüşür ve özellik sütunları boş çıkar. Bu bir hata değil, veridir.
Referans
Tek Bir Planın Şekli
public static function catalog_plans(int $categoryId, string $type, string $layout = 'grid'): array;
// $categoryId ürünleri istenen kategori
// $type ürün türü, yapılandırma adresinin kullandığı parçanın aynısı
// $layout 'grid' ya da 'rows'; dönen HER planın ŞEKLİNİ değiştirir
$plan = [
'id' => 18, // ürün id'si
'title' => 'Starter',
'tagline' => 'İlk siteniz için',
'popular' => true, // ürünün kendi seçeneklerinden
'in_stock' => true, // '' stok sınırsız demek, 0 tükendi demek
'prices' => [ // YALNIZ gerçekten fiyatı olan döngüler
'monthly' => 4.90,
'annual' => 49.00,
],
'currency' => 'USD', // görüntü kodu, data-currency özniteliği için
'currency_id' => 2, // görüntü para birimi id'si, biçimlendirici kullanır
'link' => '/configure/hosting/18',
'features' => ['10 GB disk', '1 alan adı'],
];
// $layout = 'rows' iken son anahtar yerine iki anahtar gelir:
// 'specs' => [['value' => '10 GB', 'label' => 'Disk'], ...] kıyaslanabilir sütunlar
// 'chips' => ['Ücretsiz taşıma', ...] düz satırlar
İlk Boyama Fiyatı Nasıl Üretilir
public static function seed_plan_prices(array &$plans, string $cycle, bool $periodMode): void;
// $cycle bu sayfanın varsayılan faturalama döngüsü
// $periodMode true tam dönem toplamını basar, false aylık karşılığını basar
//
// Her plana iki anahtar ekler:
// price_now şablonun bastığı biçimlenmiş string
// is_period o string bir dönem toplamı mı ("/ay" son ekini o belirler)
//
// $cycle için fiyatı olmayan plan sıfır değil, price_now = '' alır.
// Aylık fiyatı olmayan plan, $periodMode false olsa bile dönem moduna zorlanır.
public static function plan_cycles(array $tabs): array;
// [['key' => 'monthly', 'label' => 'Aylık'], ['key' => 'annual', 'label' => 'Yıllık']]
// Yalnız sayfadaki en az bir planın gerçekten fiyatladığı döngüler. Sabit gösterim sırası.
public static function price_monthly_equivalent(): bool;
// $periodMode'un arkasındaki GENEL ayar. Kurulumun tema yapılandırmasında yaşar,
// temanızın kendi ayar şemasında DEĞİL, yani bir tema onu zorlayamaz.
data-* Sözleşmesi
Birini yeniden adlandırın, fiyat sessizce güncellenmeyi bırakır. İşleyici data-billing taşıyan her öğeyi grup, içindeki her .plan-card ve .plan-row öğesini kart sayar.
$default_cycle'dan açılış döngüsü ve grup seçicisi; geçiş butonu onu değiştirir.
$price_mode'dan monthly ya da period. Sayfa değeri, tema ayarı değil.
|default:'' ile — fiyatsız döngü sıfır değil boş kalsın.
price-now, price-suffix, price-was, savings, cycle-total, cycle-mo, currency-label.
Faturalama Geçişi Sözleşmesi
Buton seçtiği döngüyü data-cycle içinde taşır, asla data-billing içinde değil: işleyici en yakın data-billing atasını arar, o özniteliği taşıyan buton kendi grubu olur.
monthly, quarterly, semiannually, annual, biennial, triennial. $c.key'den, etiketi $c.label'dan yazın.
Örnek
// controllers/website/products.php, drilldown dalı
$plans = Products::catalog_plans($categoryId, $kind, $layout);
// Genel ayar, tersine çevrilmiş: aylık karşılık AÇIK ise dönem modu KAPALI.
$period_mode = !Theme::price_monthly_equivalent();
// Sayfanın varsayılan döngüsünde her plana price_now + is_period yazar.
Products::seed_plan_prices($plans, $default_cycle, $period_mode);
$this->addData("mode", "drilldown");
$this->addData("plans", $plans);
$this->addData("cards", $cards);
$this->addData("layout", $layout);
$this->addData("billing_cycles", Products::plan_cycles([['plans' => $plans]]));
$this->addData("default_cycle", $default_cycle);
$this->addData("price_mode", $period_mode ? "period" : "monthly");
{* Bölüm sarmalayıcısı, fiyat script'inin okuduğu sayfa düzeyi bağlamı taşır. *}
<section data-billing="{$default_cycle}" data-currency="{$selected_currency_code}" data-price-mode="{$price_mode}">
{if $layout == 'rows'}
{include file='components/plan-rows.tpl' plans=$plans billing_cycles=$billing_cycles}
{else}
{include file='components/plan-grid.tpl' plans=$plans billing_cycles=$billing_cycles}
{/if}
</section>
{* components/plan-grid.tpl, tek bir kartın fiyat bandı *}
<div class="card plan-card{if !$plan.in_stock} plan-soldout{/if}"
data-currency="{$plan.currency}"
data-monthly="{$plan.prices.monthly|default:''}"
data-annual="{$plan.prices.annual|default:''}"
data-biennial="{$plan.prices.biennial|default:''}">
<div class="plan-price price-band">
{* Script doldurur. Sunucuda bilerek boş. *}
<del class="price-was num-tabular d-none" data-role="price-was"></del>
<span class="badge d-none" data-role="savings"></span>
{* Sunucu basar ki ilk boyama hiç boş kalmasın, sonra script yüklemede
AYNI string ile üzerine yazar. *}
<span class="price-now num-tabular" data-role="price-now">{$plan.price_now|default:''}</span>
<span class="{if $plan.is_period}d-none{/if}" data-role="price-suffix">{lang key='website/products/category-per-month'}</span>
{* Döngü başına bir satır; toplamlar script'in işi. *}
{foreach $billing_cycles as $c}
<tr data-cycle="{$c.key}">
<td>{$c.label}</td>
<td data-role="cycle-total"></td>
<td data-role="cycle-mo"></td>
</tr>
{/foreach}
</div>
</div>
Tuzaklar
toFixed(2) saklanan double'ı düzeltmesiz yuvarlar, sunucu biçimlendiricisi yarımı çifte yuvarlar, PHP'nin yuvarlaması önce kayan nokta düzeltmesi yapar. Üçü beşle biten değerlerde ayrışır: 237.905 iki farklı string olur ve sayfa zıplar. Tohumlama yardımcısı sprintf('%.2f') ile ön yuvarlar; siz de aynısını yapın.
Panel seçimi list_template seçeneğine yazar (2 = düz); sayfa ise layout okur ve rows bekler. Aralarında eşleme yok, düz seçilmiş kategori yine ızgara görünür; ana sayfa rafı ikisini de okur.
Sistem geneli bir seçenektir, tema ayarları şemasından bilerek çıkarılmıştır. Onu $price_mode üzerinden okuyun ve kendi manifestinize benzeri bir anahtar eklemeyin.
Kategorinin zengin metin gövdesi ham çıkar; içindeki senkron bir üçüncü parti etiketi ayrıştırmayı durdurur. Ana fiyat kurtulur çünkü onu sunucu yazmıştır, türetilmiş figürler bekler.
Plan listeleri cache'lenir; stok işareti cache okunduktan sonra tazelenir. $plan.in_stock'u güncel, gerisini bir saate kadar eski kabul edin; ikisini karıştıran bir parçayı cache'lemeyin.
İlgili Makaleler
Geri bildiriminiz için teşekkürler!
Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.