Yeni Modül Oluştur
Modül, modules/{name}/ altında yaşayan bağımsız bir PHP sınıfıdır.
Modüller tema dosyalarını değiştirmeden çalışır — tüm şablonlar modül klasöründe kalır.
Yapay zeka destekli geliştirme:
Tam geliştirici kılavuzunu indirip herhangi bir yapay zeka asistanına (ChatGPT, Claude, Cursor vb.) yükleyin:
github.com/bera65/frisay/blob/main/modules/MODULE_DEVELOPER_GUIDE.md
Yapay zeka bu dosyayı okuduktan sonra modül mimarisini, adlandırma kurallarını, API kalıplarını, güvenlik gereksinimlerini ve yardımcı sınıfları anlar — böylece modülünüzü sade dille tarif edip çalışan kodu çok daha hızlı üretebilirsiniz.
Tam geliştirici kılavuzunu indirip herhangi bir yapay zeka asistanına (ChatGPT, Claude, Cursor vb.) yükleyin:
github.com/bera65/frisay/blob/main/modules/MODULE_DEVELOPER_GUIDE.md
Yapay zeka bu dosyayı okuduktan sonra modül mimarisini, adlandırma kurallarını, API kalıplarını, güvenlik gereksinimlerini ve yardımcı sınıfları anlar — böylece modülünüzü sade dille tarif edip çalışan kodu çok daha hızlı üretebilirsiniz.
Bir Modül Ne Yapabilir?
- Yönetim paneli yapılandırma ekranı (
adminPage()) - Görüntüleme kancaları ile vitrin HTML enjeksiyonu — bkz. Kanca Listesi
- JSON API uç noktaları (
api/{action}.php) $routesile özel mağaza sayfaları- Ödeme yöntemi entegrasyonu (ödeme)
install.sql/uninstall.sqlile veritabanı tabloları
Modül Dosya Şeması
modules/{name}/
{name}.php ← Main class (REQUIRED)
logo.png ← Admin module list icon
install.sql ← Install SQL (optional)
uninstall.sql ← Uninstall SQL (optional)
assets/
templates/
admin/
admin.tpl ← Admin configure page
front/
{hook_name}.tpl ← Storefront hook output
css/
front.css ← Storefront styles
admin.css ← Admin styles
js/
front.js ← Storefront scripts
admin.js ← Admin scripts
img/ ← Images
api/
{action}.php ← API endpoint files
front/
{page}.php ← Custom store route file
Adlandırma Kuralları (Kritik)
| Öğe | Kural | Örnek |
|---|---|---|
| Klasör adı | Küçük harf, tire kullanılabilir | my-module |
| Ana dosya | {name}/{name}.php | modules/my-module/my-module.php |
| PHP sınıfı | PascalCase + Module | my-module → MyModuleModule |
| Yönetim URL'si | Admin::url() + ADMIN_URI ile | Admin::url('module-my-module') |
| API URL'si | Modül yönlendiricisi ile | /api/module.php?m=my-module&action=save |
$name özelliği | Klasör adıyla birebir eşleşmeli | public string $name = 'my-module'; |
ModuleBase — Temel Özellikler
| Özellik | Amaç |
|---|---|
$displayHooks | Desteklenen kancalar: hook_name => description |
$defaultDisplayHooks | install() sırasında otomatik atanan kancalar |
$apiActions | action => api/file.php eşlemesi |
$routes | slug => front/page.php özel mağaza sayfaları |
$frontStylesheets / $frontScripts | assets/ altındaki vitrin CSS/JS dosya adları. Boş = hiçbir şey yüklenmez (dosyaları açıkça listelemelisiniz veya head.assets kullanın) |
$adminStylesheets / $adminScripts | Yalnızca modül yönetim yapılandırma sayfasındaki varlıklar |
$isPayment | true → ödeme adımında ödeme yöntemi olarak kaydeder |
$paymentMethodId | orders.payment_method içinde saklanan değer |
$paysBeforeOrder | true → sipariş oluşturulmadan önce ödeme (sanal POS) |
Varlık yükleme (v2.5.0+): Boş
$frontStylesheets / $frontScripts
artık assets/css veya assets/js içindeki her dosyayı otomatik yüklemez.
İhtiyacınız olan her dosyayı bildirin, örn. ['front.css'].
renderFrontTemplate — Önemli Kural
Değişkenleri doğrudan global Smarty'ye atamak yerine her zaman
$this->renderFrontTemplate('hook_name', $vars) kullanın. Bu, izole bir alt şablonda
render eder ve $isLoggedIn veya $cart gibi global değişkenleri
kirletmez.
- Şablon yolu:
assets/templates/front/{name}.tpl - HTML dizesi döndürür — temada
{$hooks.footer nofilter}ile çıktılanır
Yönetim Yapılandırması
- URL:
Admin::url('module-{name}')— asla/admin/yolunu sabit yazmayın (yolconfig/env.phpiçindekiADMIN_URI'den gelir) - Şablon:
assets/templates/admin/admin.tpl - Yönetim görüntüleme kancaları:
admin_*kancaları içinrenderAdminDisplayHook($hook, $context)uygulayın — bkz. Kanca Listesi - İsteğe bağlı kenar çubuğu bağlantısı:
boot()içinde$this->registerAdminMenuLink('Label', 'catalog', 95) - Tüm POST formları
$adminTokendeğerinihash_equals()ile doğrulamak zorundadır
API Uç Noktaları
- URL:
POST /api/module.php?m={name}&action={action} - Vitrin API'leri
$_SESSION['csrf_token']doğrulamalıdır —header.tpliçindeki global JScsrfTokenkullanın - Vitrin AJAX'ında CSRF jetonu olarak yönetim veya cron jetonu kullanmayın
/modules/{name}/api/*.phpdosyalarına doğrudan erişim engellenir (403) — her zamanapi/module.phpüzerinden yönlendirin- Cron işleri:
'cron' => 'api/cron.php'olarak kaydedin ve/api/module.php?m={name}&action=cron&token=...kullanın
Kurulumdan Sonra
- Gerekli dosyalarla
modules/{name}/klasörünü oluşturun - Yönetim → Modüller sayfasına gidin — modül listede görünür
- Kur'a tıklayın —
defaultDisplayHooksotomatik atanır - Gerekirse modül detay sayfasında kanca atamalarını ayarlayın
- Kurulumdan sonra modül varsayılan olarak aktiftir
Güvenlik Kontrol Listesi
- Dosya koruması:
if (!defined('IN_SCRIPT') && !defined('IN_ADMIN')) exit; - Yönetim formları:
hash_equals($adminToken, $postToken) - Mağaza API: oturumdaki
csrfTokendoğrulayın - SQL: her zaman
DB::execute($sql, [$param])ile hazırlanmış ifadeler kullanın - Kullanıcı girdisi:
trim,strip_tags, Smarty|escape - Kanca şablonlarında satır içi
<script>kullanmayın —assets/js/+data-api-urlkullanın - Tema veya çekirdek dosyalarını değiştirmeyin
Referans Modüller
| Modül | Ne öğrenilir |
|---|---|
whatsapp | Basit alt bilgi kancası + SQL |
newsletter | API + alt bilgi formu + CSRF kalıbı |
reviews | Ürün sekmeleri + API + teslimat sonrası davet cron |
question | Ürün sekmeleri + giriş gerektiren API + bot koruması |
slider | Yönetim CRUD + görsel yükleme |
bankwire | Ödeme + sipariş onay kancası |
sanalpos | paysBeforeOrder + front route |
recaptcha | form.captcha.validate + auth/contact görüntüleme kancaları |
alert | product.updated + order.placed + stok gelince formu |
abandoned-cart | cart.changed takibi + hatırlatma cron |
facebook-pixel | head.top / footer / product_detail takibi |
instagram-gallery | home_bottom görüntüleme kancası |
export-excel | admin_header yönetim görüntüleme kancası |
product-set | Ürün setleri + product.updated |
PHP 7.4 uyumluluğu:
match, str_starts_with(),
adlandırılmış argümanlar veya birleşik tipler kullanmayın. Bunun yerine switch ve strpos() kullanın.
PHP
<?php
if (!defined('IN_SCRIPT') && !defined('IN_ADMIN')) {
exit;
}
require_once dirname(__DIR__, 2) . '/core/ModuleBase.php';
class MyModuleModule extends ModuleBase
{
// ── Identity (REQUIRED) ───────────────────────────────
public string $name = 'my-module'; // must match folder name
public string $title = 'My Module';
public string $version = '1.0.0';
public string $description = 'Short description';
public string $author = 'FriSay';
// ── Display hooks ─────────────────────────────────────
public array $displayHooks = [
'footer' => 'Adds HTML to the footer area',
];
public array $defaultDisplayHooks = ['footer'];
// ── CSS/JS (empty = load nothing — list files explicitly) ─
public array $frontStylesheets = ['front.css'];
public array $frontScripts = [];
public array $adminStylesheets = ['admin.css'];
public array $adminScripts = [];
// ── API endpoints ─────────────────────────────────────
public array $apiActions = [
'save' => 'api/save.php',
];
// ── Custom store routes: site.com/{slug} ────────────
public array $routes = [
// 'my-page' => 'front/page.php',
];
// ── REQUIRED: install / uninstall ─────────────────────
public function install(): bool
{
return $this->runSqlFile('install.sql');
// No database table: return true;
}
public function uninstall(): bool
{
return $this->runSqlFile('uninstall.sql');
}
// ── Optional: runs when module is loaded ──────────────
public function boot(): void
{
Module::registerHook('order.placed', function (array $order): void {
// Run after order is created
});
}
// ── Admin configure page (Admin::url('module-my-module')) ────
public function adminPage(): void
{
global $smarty, $adminToken;
$flash = '';
if (Tools::isSubmit('saveMyModule')) {
$postToken = (string) Tools::getValue('token');
if (hash_equals($adminToken, $postToken)) {
Settings::set('MY_MODULE_SETTING', trim((string) Tools::getValue('setting')));
$flash = 'Saved';
} else {
$flash = 'Invalid request';
}
}
$smarty->assign([
'setting' => Settings::get('MY_MODULE_SETTING'),
'flash' => $flash,
]);
}
// ── Storefront hook output ────────────────────────────
public function renderDisplayHook(string $hook, array $context = []): ?string
{
if ($hook !== 'footer') {
return null;
}
$html = $this->renderFrontTemplate('footer', [
'message' => Settings::get('MY_MODULE_SETTING'),
]);
return $html !== '' ? $html : null;
}
}
admin.tpl (Smarty)
{* assets/templates/admin/admin.tpl *}
{if $flash}
<div class="alert alert-info">{$flash|escape}</div>
{/if}
<form method="post" class="admin-panel p-3" style="max-width:400px">
<input type="hidden" name="saveMyModule" value="1">
<input type="hidden" name="token" value="{$adminToken}">
<label class="form-label">Setting value</label>
<input type="text" name="setting" class="form-control" value="{$setting|escape}">
<button type="submit" class="btn btn-dark mt-3">Save</button>
</form>
api/save.php — Vitrin API kalıbı
<?php
if (!defined('IN_SCRIPT')) {
exit;
}
header('Content-Type: application/json; charset=utf-8');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Method not allowed']);
exit;
}
// Store CSRF — use global csrfToken in JS, NOT admin/cron tokens
$token = Tools::getValue('token') ?: ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? '');
if (!hash_equals($_SESSION['csrf_token'] ?? '', (string) $token)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'Invalid request']);
exit;
}
$result = MyModuleModule::doSomething((string) Tools::getValue('field'));
echo json_encode($result);
front.js — Vitrinden AJAX çağrısı
// csrfToken is defined in header.tpl — do not hardcode tokens in templates
$(document).on('submit', '.my-module-form', function (e) {
e.preventDefault();
var $form = $(this);
$.ajax({
url: $form.data('api-url'),
method: 'POST',
dataType: 'json',
data: {
token: typeof csrfToken !== 'undefined' ? csrfToken : '',
field: $.trim($form.find('[name="field"]').val())
}
});
});
Ödeme modülü (havale / banka transferi tipi)
<?php
public bool $isPayment = true;
public string $paymentMethodId = 'bank_transfer';
public string $paymentMethodLabel = 'Bank Transfer';
public bool $paysBeforeOrder = false;
// order_payment.tpl — radio value must match $paymentMethodId
public function processPayment(array $order): array
{
return [
'success' => true,
'redirect' => '',
'message' => '',
];
}
Yapay zeka istem şablonu — ChatGPT / Claude / Cursor'a yapıştırın
FriSay e-commerce project — write a module.
Rules: follow ALL rules in MODULE_DEVELOPER_GUIDE.md
PHP 7.4 compatible. Extend ModuleBase. Do NOT modify theme or core files.
Module info:
- name (slug): {my-module}
- title: {Display Name}
- description: {what it does}
Features:
- Display hooks: {footer, product_tab, ...}
- API actions: {action => description}
- Payment module: {yes/no}
- Database tables: {schema if any}
- Admin settings: {Settings keys or table fields}
Files to generate:
1. modules/{name}/{name}.php
2. install.sql / uninstall.sql (if needed)
3. assets/templates/admin/admin.tpl
4. assets/templates/front/{hook}.tpl (one per hook)
5. assets/css/, assets/js/ (if needed)
6. api/{action}.php (if needed)
7. front/{page}.php (if route needed)
Reference modules: whatsapp, newsletter, reviews, question, bankwire, sanalpos
Yardımcı sınıflar — yaygın kullanım
<?php
// Settings (use UPPERCASE keys with module prefix)
Settings::get('DOMAIN'); // site URL — NOT 'domain'
Settings::get('SITE_NAME');
Settings::set('MY_MODULE_KEY', 'value');
// Database
DB::getRowSafe('table', 'id = ?', [$id]);
DB::insert('table', ['col' => 'value']);
DB::update('table', ['col' => 'v'], 'id = :where_id', ['where_id' => $id]);
DB::execute('DELETE FROM table WHERE id = ?', [$id]);
// Store data
$product = Product::getById($idProduct); // includes 'url' field
$images = Product::getImages($idProduct);
$cart = Cart::getSummary();
$isFav = Favorite::isFavorite($idProduct);
// Customer
Customer::isLoggedIn();
Customer::getId();
Customer::getCurrent();
// Tools
Tools::displayPrice(99.90); // ₺99,90
Tools::createSlug('ana sayfa'); // ana-sayfa
Tools::maskName('John Smith'); // J** S****
// Admin URL
Admin::url('module-my-module'); // https://site.com/admin/module-my-module
// Pagination
$pagination = Pagination::build($total, $page, 30, Admin::url('module-my-module'));
// Mail
Mail::send($to, $subject, $bodyHtml);