Restoran Siteleri Neden Bir Şablondan Fazlasina Ihtiyac Duyar

JekCMS'i geliştirmeden once uc yil boyunca küçük restoran sahiplerine freelance calistim. Desen hep ayniydi: birisi bir WordPress temasi satin aliyor, menuler, rezervasyonlar ve galeriler için on bes eklenti kuruyor, alti ay sonra site dokuz saniyede yuklendigi ve eklentilerin yarisi güncelleme catismasi verdigi için beni ariyordu. Istanbul'daki bir musterimin sadece yemek menusu gostermek ve masa rezervasyonu almak için 23 aktif eklentisi olan bir WordPress sitesi vardi. Barinma masrafi, dort saniyenin altinda yanitlama süresi saglamayan paylaşımli bir sunucu için bile ayda 40 dolardi.

Bu deneyim, JekCMS'de restoran sitelerini nasıl ele aldigimizi sekillendirdi. Bir restoranin ihtiyac duydugu her sey — menuler, rezervasyonlar, galeriler, haritalar, yapisal veri — admin paneli ve tek bir tema üzerinden halledilir. Eklenti yok. Alti ay sonra bozulan ucuncu taraf bagimliliklari yok.

Bu rehber, sifirdan bir restoran web sitesi oluşturmanin her adimini anlatiyor. Gecen ay Izmir'deki bir deniz urunleri restorani için teslim ettigimiz bir projeden gerçek kodlar kullanacagim.

Adim 1: Tema Secimi ve Ilk Kurulum

JekCMS, sektore odakli birkac tema ile birlikte gelir. Restoranlar için Starter Business temasi en uygunudur cunku hizmet listelemeleri (menu kategorileri olarak yeniden kullaniriz), galeri modulu ve özel alanli iletisim formu için yerlesik destek icerir.

JekCMS'i kurduktan sonra Admin > Ayarlar > Genel bolumune gidin ve temel bilgileri doldurun:

  • Site Adi: Restoran adiniz
  • Slogan: Kisa bir açıklama (ornegin, "1998'den Beri Taze Ege Deniz Urunleri")
  • Logo: Her boyutta net gorunum için SVG formatinda yukleyin
  • Favicon: 32x32 PNG veya SVG

URL yapısı için duz tutmanizi oneriyorum. config/config.php icinde:

<?php
// Temiz URL yapısı - /page/ on eki yok
define('URL_STRUCTURE', 'flat');

// Rezervasyon yönetimi için saat dilimi
date_default_timezone_set('Europe/Istanbul');

Adim 2: Menu Ogeleri Icin Veritabani Kurulumu

JekCMS, tekrarlanabilir içerik bloklari için services tablosunu kullanir. Bir restoran için bunu menu sistemi olarak yeniden kullaniriz. Zaten sahip oldugunuz tablo yapısı:

-- services tablosu (menu_items olarak kullanilir)
-- id, title, description, image, price, category_id, sort_order, status

-- Diyet etiketleri için özel alan ekliyoruz
ALTER TABLE services ADD COLUMN tags VARCHAR(255) DEFAULT NULL;
ALTER TABLE services ADD COLUMN price DECIMAL(8,2) DEFAULT NULL;

tags sutunu virgule ayrilmis diyet etiketlerini saklar: "vegan,glutensiz,baharatli". Bunlari on yuzde her yemegin yaninda küçük rozet simgeleri gostermek için ayririz.

Menu kategorileri (Baslangiclar, Ana Yemekler, Tatlilar, Icecekler) için mevcut service_categories tablosunu kullaniriz:

INSERT INTO service_categories (name, slug, sort_order) VALUES
('Baslangiclar', 'starters', 1),
('Ana Yemekler', 'main-courses', 2),
('Tatlilar', 'desserts', 3),
('Icecekler', 'drinks', 4);

Adim 3: Menu Gorunumunu Oluşturma

Menu sayfasi, cogu restoran sitesinin bozuldugu yerdir. Ya statik bir PDF gosterirler (SEO ve mobil için berbat) ya da yuklenmesi sonsuza kadar suren siskin bir JavaScript tablosu kullanirlar. Bizim yaklasimimiz: minimum CSS ile sunucu tarafinda oluşturulan HTML.

pages/menu.php dosyasini oluşturun:

<?php
$categories = $db->fetchAll(
    "SELECT * FROM service_categories WHERE status = 'active' ORDER BY sort_order"
);

foreach ($categories as $cat):
    $items = $db->fetchAll(
        "SELECT * FROM services WHERE category_id = ? AND status = 'active' ORDER BY sort_order",
        [$cat['id']]
    );
    if (empty($items)) continue;
?>
<section class="menu-category" id="category-<?= $cat['slug'] ?>">
    <h2><?= htmlspecialchars($cat['name']) ?></h2>
    <div class="menu-grid">
        <?php foreach ($items as $item): ?>
        <div class="menu-item">
            <div class="menu-item-info">
                <h3><?= htmlspecialchars($item['title']) ?></h3>
                <p><?= htmlspecialchars($item['description']) ?></p>
            </div>
            <span class="menu-item-price">&#8378;<?= number_format($item['price'], 2) ?></span>
        </div>
        <?php endforeach; ?>
    </div>
</section>
<?php endforeach; ?>

Bu grid için CSS basittir. Her .menu-item masaustunde iki sutunlu CSS Grid kullanir ve mobilde tek sutuna iner. JavaScript framework gerekmiyor.

Adim 4: Sunucu Tarafli Dogrulama ile Rezervasyon Formu

Online rezervasyonlar, restoran sahiplerinden en cok istenen özelliktir. Bunu JekCMS iletisim formu sistemi üzerinden özel alanlarla hallediyoruz.

Sunucu tarafindaki işleyici, contact_messages tablosuna eklemeden once her seyi doğrular:

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_POST['form_type'] === 'reservation') {
    verify_csrf_token($_POST['csrf_token'] ?? '');

    $name = sanitize_text($_POST['guest_name'] ?? '');
    $phone = sanitize_text($_POST['phone'] ?? '');
    $date = $_POST['date'] ?? '';
    $time = $_POST['time'] ?? '';
    $guests = (int)($_POST['guests'] ?? 1);

    $errors = [];
    if (strlen($name) < 2) $errors[] = 'Gecerli bir isim girin.';
    if (!preg_match('/^[0-9+\-\s]{7,15}$/', $phone)) $errors[] = 'Gecerli telefon girin.';
    if (strtotime($date) < strtotime('today')) $errors[] = 'Gecmis tarih secilemez.';

    if (empty($errors)) {
        $db->insert('contact_messages', [
            'name' => $name,
            'phone' => $phone,
            'subject' => 'Rezervasyon: ' . $date . ' ' . $time,
            'message' => "Tarih: $date
Saat: $time
Kisi: $guests",
            'type' => 'reservation',
            'status' => 'unread'
        ]);
        redirect(SITE_URL . '/reservation?success=1');
    }
}

Insanlarin takildigi bir detay: redirect() cagrisi herhangi bir HTML ciktisindan once yapilmalidir. POST işleyicisi dosyanin basinda, header.php dahil edilmeden once oturur. HTML oluşturulmaya basladiktan sonra koyarsaniz, korkunc "Headers already sent" hatasini alirsiniz.

Adim 5: AVIF/WebP Destekli Galeri

Restoran sahipleri yemeklerini, yemek alanlarini ve mutfaklarini sergilemeyi severler. JekCMS, galeri görsellerini yüklemede otomatik AVIF ve WebP donusumu ile gallery tablosu üzerinden yonetir.

Bir restoran sahibi admin paneli üzerinden imza yemeginin 4MB'lik JPEG'ini yuklediginde, JekCMS otomatik olarak:

  1. Bir AVIF surumu oluşturur (%80 kalitede genellikle 200-400KB)
  2. Bir WebP yedek surum oluşturur (%85 kalitede 300-500KB)
  3. Uc küçük resim boyutu uretir: 400x400, 800x800 ve 1600x1600
  4. Disk alani kazanmak için orijinal JPEG'i siler

Galeri gorunumu, format pazarligi için <picture> elemanini kullanir. Bu, tarayıcınin destekledigi en verimli formati otomatik olarak secmesini sağlar.

Adim 6: Sayfa Hizini Oldurmeden Google Maps

Google Maps'i standart yontemle (iframe) gomme, sayfa agirliginiza 800KB+ ekler ve oluşturmayi engeller. Bir restoran sitesi için harita konumunuzu gostermek için vardir — baslangic sayfasiyla birlikte yuklenmesine gerek yoktur.

Yaklasimimiz: tembel yuklenen statik bir harita görseli gosterin ve yalnizca kullanıcı tikladiginda interaktif haritaya gecin. Bu teknik, Izmir musterimiz için First Contentful Paint'te 1.2 saniye kazandirdi. Statik görsel AVIF formatinda 45KB iken Maps iframe'i ve JavaScript paketi 800KB+ tutuyor.

Adim 7: Yerel Isletme Schema Markup

Arama motorlari, restoranlar için zengin sonuçlar gostermek için yapisal veriye ihtiyac duyar — yildiz degerlendirmeleri, çalışma saatleri, fiyat araligi, mutfak turu. JekCMS bunu output_schema() fonksiyonu araciligiyla otomatik olarak cikarir, ancak restoranlar için genisletiyoruz.

Google'in restoran zengin sonuçlari için baktigi temel alanlar servesCuisine, priceRange, openingHoursSpecification ve acceptsReservations alanlaridir. Bunlardan herhangi birini kacirmak, geliştirilmis arama kartina hak kazanamayacaginiz anlamina gelir.

Adim 8: Mobil Optimizasyon

Restoran web sitesi ziyaretcilerinin %72'si mobil cihazlardan gelir (sekiz restoran musterimizin analizlerine dayanarak). Özellikle menu sayfasinin küçük ekranlarda kusursuz çalışmasi gerekir.

Aldigimiz temel mobil kararlar:

  • Yapisan kategori navigasyonu: Menu sayfasinin ustunde, siz kayarken mevcut kategoriyi vurgulayan yatay kaydırma cubugu. IntersectionObserver ile uygulanmistir — scroll olay dinleyicileri yok.
  • Dokunarak arama telefon numarasi: Baslik satirdaki telefon numarasi her zaman bir tel: linkidir. Mobilde doğrudan arama uygulamasini tetikler.
  • Alt CTA cubugu: "Ara" ve "Rezervasyon" butonlari olan, altta sabit bir cubuk, yalnizca 768px altindaki mobil ekranlarda görünür.
  • Yazi boyutlari: Menu oge adlari 18px, açıklamalar 15px, fiyatlar 20px kalin. Zum yapmadan okunabilir.

Adim 9: Performans Sonuclari

Izmir deniz urunleri restoran sitesini yayina aldiktan sonra hem mobil hem masaustunde PageSpeed Insights calistirdik:

  • Mobil Performans: 91 (eski WordPress sitelerinde 34'tu)
  • Masaustu Performans: 97
  • First Contentful Paint: Mobilde 1.1s, masaustunde 0.6s
  • Largest Contentful Paint: Mobilde 1.8s, masaustunde 0.9s
  • Toplam sayfa agirligi (menu sayfasi): 380KB (WordPress'te 4.2MB'dan dustu)
  • Istekler: 12 (87'den dustu)

En büyük kazanclar uc seyden geldi: jQuery ve eklenti JavaScript'ini ortadan kaldirmak (1.8MB kazandirdi), tum görselleri AVIF'e dönüştürmek (2.1MB kazandirdi) ve Google Maps gomme işlemini tembel yüklemek (ilk yüklemede 800KB kazandirdi).

Sirada Ne Var

Bu, temel kurulumu kapsar. Bir sonraki yazida, WhatsApp entegrasyonu ile online siparis sistemi eklemeyi anlatacagim — ilk ay icinde uc restoran musterimizin talep ettigi bir özellik. Model, siparis ozetini WhatsApp Business API üzerinden gonderen sepet benzeri bir arayuzle ayni iletisim formu altyapısıni kullanir.

Bir restoran sitesi oluşturuyorsaniz ve bu adimlardan herhangi biri hakkinda sorulariniz varsa, GitHub'da bir sorun acin veya iletisim formumuz araciligiyla bize ulasin.