• 13-09-2025, 15:11:16
    #1
    İyzico yaklaşık bir ay önce WooCommerce altyapısını kullanan siteler için bir taksit eklentisi yayınladı. Bu eklentiyi sitenize custom tab kullanarak ekleyebilir veya temanızın functions.php dosyasına ekleyerek tüm ürün sayfalarına otomatik olarak yansıtabilirsiniz.

    Ancak, yayınlanan orijinal sürümde bazı eksiklikler bulunuyor:
    • Varyasyonlu ürünlerde yalnızca en düşük fiyat baz alınıyor.
    • KDV hesaplaması yapılmıyor.
    • CSS özelleştirmeleri doğrudan eklenti dosyalarını düzenleyerek yapılabiliyor.
    Bu sebeple, kendi fork’umu oluşturdum ve aşağıdaki geliştirmeleri ekledim.

    Eklediğim özellikler;
    Dinamik Taksit Sistemi
    [dynamic_iyzico_installment] shortcode’u ile varyasyonlu ürünlerde kullanıcı varyasyon seçtikçe fiyat düzenlenir
    Nasıl çalıştığına ilişkin video: https://files.catbox.moe/8ocp9z.mp4

    KDV Hesaplama
    Admin panelinde %20 KDV dahil hesaplama seçeneği ile taksit tutarları doğru şekilde hesaplanır.

    Admin Üzerinden CSS Yönetimi
    Orijinal eklentide CSS düzenlemeleri assets/css/iyzico-installment.css dosyası üzerinden yapılabiliyordu. Bu dosyayı kaldırarak CSS ayarlarını doğrudan admin panelinden değiştirilebilir hale getirdim.
    • Yaptığınız değişiklikler PHP script aracılığıyla hardcoded olarak eklenir.
    • Dilerseniz kendi kullandığım style.css dosyasını fork repo’dan alabilirsiniz.

    Değiştirdiğim şeyler;
    Logo Düzenlemesi
    KuveytTürk kartları için kullanılan “SAĞLAM KART” logosu, KuveytTürk’ün resmi logosu ile değiştirildi.
    Shortcode Kopyala Butonu
    Admin panelindeki “Shortcode Kopyala” butonu yalnızca [iyzico_installment] için çalışıyordu. Bunu tüm mevcut ve ileride eklenecek shortcode’larla uyumlu olacak şekilde güncelledim.

    Oluşturduğum fork: https://github.com/ta2edh/iyzipay-wo...ce-installment
    Release: https://github.com/ta2edh/iyzipay-wo...ment/releases/

    Orijinal repo: https://github.com/iyzico/iyzipay-wo...ce-installment

    Rica
    Bu proje tamamen orijinal repo'da olduğu gibi açık kaynak olarak, topluluğa katkı sağlamak amacıyla geliştirilmiştir.
    Lütfen eklentiyi ücretli olarak satmayın. Destek olmak isteyenler için repo üzerinde katkı (pull request) veya yıldız (⭐) bırakmak yeterlidir.
  • 13-09-2025, 15:55:55
    #2
    Emeğinize sağlık
  • 17-09-2025, 20:41:12
    #3
    Fork, resmi repoya merge edildi. Artık orijinal repoyu kullanabilirsiniz:
    https://github.com/iyzico/iyzipay-wo...ce-installment
  • 28-12-2025, 16:48:25
    #4
    elinize sağlık paytr entegrasyonu var mı
  • 21-02-2026, 23:57:30
    #5
    Selamlar,


    dev sitede denedim çalışmadı, cursor ile değerlendirdiğimde aşağıdaki gibi bir rapor sundu.
    Bilginize.


    # iyzico Installment for WooCommerce — Plugin Review Status Report
    **Plugin:** iyzico Installment (iyzico-installment)
    **Version reviewed:** 1.1.0
    **Review date:** February 21, 2025
    ---
    ## Executive Summary
    | Metric | Value |
    |--------|--------|
    | **Overall Health Score** | **68/100** |
    | **Critical Issues** | 3 |
    | **High Priority** | 5 |
    | **Medium Priority** | 6 |
    | **Low Priority** | 4 |
    The plugin is functionally structured and follows many WordPress/WooCommerce practices (nonces, capability checks, sanitization, escaping, Options API, transients, HPOS declaration). Critical and high-priority issues center on missing dependency checks, broken/inactive features (logger, custom CSS, frontend styles), and one security/logic bug in the logger. Addressing these will significantly improve stability, security, and user experience.
    ---
    ## Detailed Findings
    ### 1. PERFORMANCE
    **Status: ⚠️ Warning**
    #### Issues
    | # | File | Line(s) | Severity | Description | Impact | Recommended fix |
    |---|------|---------|----------|-------------|--------|-----------------|
    | 1 | `includes/class-iyzico-installment-dynamic.php` | 101–241 | Medium | Large inline script in `wp_footer` (140+ lines) on every product page when dynamic installments are enabled | Unnecessary HTML size, no caching of script, harder to maintain | Move JS to a separate file; enqueue with `wp_enqueue_script` and pass data via `wp_localize_script` |
    | 2 | `includes/class-iyzico-installment-dynamic.php` | 314–323 | Low | No caching of API installment response per price/product | Repeated identical requests for same price cause repeated API calls | Cache `getInstallmentInfo()` result in a transient keyed by price (e.g. `iyzico_installment_{price}_{bin}`) with short TTL (e.g. 5–15 min) |
    | 3 | `includes/class-iyzico-installment-settings.php` | 66, 94, 107 | Low | `get_option()` / `update_option()` on every settings read/write | Minor; options are single key | Acceptable; consider single cached property in request if read many times |
    | 4 | `includes/class-iyzico-installment-frontend.php` | 61–92, 174–198 | Medium | Script and localize data enqueued twice when shortcode is used (once in `enqueueScripts`, once in `renderShortcode`) | Duplicate script/localize on shortcode pages | Enqueue only once; e.g. set a static flag or check `wp_script_is('iyzico-installment', 'enqueued')` before enqueuing in shortcode |
    #### Best practices followed
    - Conditional script/style loading (admin only on settings page; frontend when product/shortcode).
    - Transients used for API status and rate limiting.
    - No N+1 or custom SQL; no database schema.
    - `nocache_headers()` in AJAX response for dynamic installment (appropriate for dynamic content).
    #### Recommendations
    - Add transient caching for installment API responses by price (and BIN if used).
    - Move dynamic installment inline script to a dedicated JS file and use `wp_localize_script`.
    - Avoid double enqueue of the same script when shortcode is used.
    ---
    ### 2. SECURITY
    **Status: ✅ Pass (with minor notes)**
    #### Issues
    | # | File | Line(s) | Severity | Description | Impact | Recommended fix |
    |---|------|---------|----------|-------------|--------|-----------------|
    | 1 | `includes/class-iyzico-installment-dynamic.php` | 334 | Low | Rate limit uses `$_SERVER['REMOTE_ADDR']` | Can be spoofed via headers (e.g. X-Forwarded-For) on some hosts | Prefer `wp_get_remote_address()` (WP 6.7+) or a helper that respects proxy headers consistently |
    | 2 | `includes/admin/class-iyzico-installment-admin.php` | 296–307 | Low | API key and secret key printed in HTML `value=""` | Risk if admin pages are cached or logged | Avoid echoing raw secrets; show masked value and “Change” flow, or load via JS for test-only |
    | 3 | `includes/class-iyzico-installment-dynamic.php` | 364–419 | Low | Regex in `_sanitizeCss()` may be too strict and block valid CSS (e.g. `@`, backslash) | Some valid custom CSS might be rejected | Use a safer allowlist (e.g. `wp_strip_all_tags` + blocklist of `javascript:`, `expression(`, etc.) or a dedicated CSS sanitizer |
    #### Best practices followed
    - **Nonces:** All AJAX handlers verify nonce (`iyzico_installment_nonce`, `installment_nonce`).
    - **Capabilities:** Admin AJAX (`ajaxTestApi`) checks `current_user_can('manage_options')`.
    - **Input:** `sanitize_text_field`, `floatval`, `intval`, `wp_unslash` used on `$_POST`/input.
    - **Output:** `esc_html`, `esc_attr`, `esc_url`, `esc_js`, `esc_textarea`, `wp_kses_post`, `wp_json_encode` used appropriately.
    - **Custom CSS:** Admin and dynamic/frontend paths sanitize CSS (strip tags, blocklist dangerous patterns).
    - **SQL:** No raw queries; no `$wpdb->prepare` needed (no custom DB).
    - **Rate limiting:** Present for public `get_installment_options` AJAX.
    - **Credentials:** Stored in options (not in code); API test uses POST credentials.
    #### Recommendations
    - Use `wp_get_remote_address()` (or equivalent) for rate limiting when on WP 6.7+.
    - Avoid echoing API secret in form `value`; use masked display and separate “Test connection” flow.
    ---
    ### 3. WOOCOMMERCE COMPATIBILITY
    **Status: ⚠️ Warning**
    #### Issues
    | # | File | Line(s) | Severity | Description | Impact | Recommended fix |
    |---|------|---------|----------|-------------|--------|-----------------|
    | 1 | `iyzico-installment.php` | — | **Critical** | No runtime check for WooCommerce (or iyzico-woocommerce) before loading | If plugin is active without WooCommerce, calls to `wc_get_product()`, `wc_price()`, `get_woocommerce_currency_symbol()`, `woocommerce_product_tabs` can cause fatals or broken behavior | Add `plugins_loaded` (or similar) check: `if ( ! class_exists( 'WooCommerce' ) ) { add_action( 'admin_notices', ... ); return; }` and only then require plugin files |
    | 2 | `iyzico-installment.php` | — | High | No minimum WooCommerce version check (header says “WC requires at least: 9.3.3”) | Incompatible WC versions may cause subtle bugs | Check `defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '9.3.3', '>=' )` and show notice / bail if not met |
    | 3 | `includes/class-iyzico-installment-frontend.php` | 109–115 | Low | Uses `has_shortcode( $post->post_content, 'iyzico_installment' )` for script loading | Works for simple cases; may miss shortcodes in blocks or other contexts | Consider also checking for `dynamic_iyzico_installment` and block content if needed |
    | 4 | `includes/class-iyzico-installment-hpos.php` | 16–17 | Low | Inconsistent spacing in `if (! defined('ABSPATH') )` | Style only | Use `if ( ! defined( 'ABSPATH' ) )` for consistency with rest of codebase |
    #### Best practices followed
    - **HPOS:** Declares compatibility with `custom_order_tables` via `FeaturesUtil::declare_compatibility` in `before_woocommerce_init`.
    - **Hooks:** Uses `woocommerce_product_tabs` for product tab integration.
    - **APIs:** Uses `wc_get_product()`, `wc_price()`, `get_woocommerce_currency_symbol()`.
    - **Logging:** Uses `wc_get_logger()` where needed (with `function_exists` check).
    - **Product:** Uses global `$product` and `WC_Product` checks on product pages.
    #### Recommendations
    - Add WooCommerce (and optionally iyzico-woocommerce) presence and minimum version check at bootstrap; display admin notice and do not load plugin logic if not met.
    - Keep HPOS declaration and WooCommerce API usage as-is.
    ---
    ### 4. WORDPRESS BEST PRACTICES
    **Status: ⚠️ Warning**
    #### Issues
    | # | File | Line(s) | Severity | Description | Impact | Recommended fix |
    |---|------|---------|----------|-------------|--------|-----------------|
    | 1 | `includes/class-iyzico-installment-frontend.php` | 389–413, 427 | **Critical** | Custom CSS is added with `wp_add_inline_style( 'iyzico-installment', $custom_css )` but no style with handle `iyzico-installment` is ever enqueued (that handle is used for the script) | Admin-defined custom CSS never appears on shortcode/tab frontend | Enqueue a (possibly empty) stylesheet first, e.g. `wp_enqueue_style( 'iyzico-installment', ... )` or a null style, then `wp_add_inline_style( 'iyzico-installment', $custom_css )`; or use a dedicated handle like `iyzico-installment-inline` and enqueue a dummy dependency |
    | 2 | `iyzico-installment.php` + `includes/class-iyzico-installment-frontend.php` | — | **High** | Root `style.css` (plugin styles for `.iyzico-installment-container`, tables, etc.) is never enqueued | Frontend installment blocks may appear unstyled | In `Iyzico_Installment_Frontend::enqueueScripts()` (and when shortcode enqueues assets), add `wp_enqueue_style( 'iyzico-installment-frontend', IYZI_INSTALLMENT_URL . 'style.css', array(), IYZI_INSTALLMENT_VERSION )` (or equivalent path) |
    | 3 | `iyzico-installment.php` | 46 | High | `class-iyzico-installment-logger.php` is required but the class is never instantiated | Dead code; logger not used anywhere | Either remove the require and the logger class file, or instantiate and use the logger for API/errors and fix the logger’s append logic (see Code Quality) |
    | 4 | `includes/admin/class-iyzico-installment-admin.php` | 110–112, 128–130 | Low | Duplicate handling of `enable_dynamic_installments` in `sanitizeSettings()` | Redundant; second block overwrites first | Remove the duplicate block (lines 128–130) |
    | 5 | `includes/class-iyzico-installment-frontend.php` | 427 | — | Inline style attached to script handle | See issue 1 above | Use a proper style handle and enqueue a style first |
    | 6 | i18n | Multiple | Low | Many strings use ALL_CAPS keys (e.g. `IYZICO_INSTALLMENT_OPTIONS`) | Usable with .po/.mo; not human-readable in code | Acceptable; ensure all user-facing strings are in .po files |
    #### Best practices followed
    - **ABSPATH:** All PHP files guard with `if ( ! defined( 'ABSPATH' ) ) exit;`
    - **Options API:** Single option key `iyzico_installment_settings` with `get_option` / `update_option` / `register_setting` and sanitize callback
    - **Assets:** `wp_enqueue_script` / `wp_enqueue_style` with version and dependencies; admin scripts only on settings page
    - **i18n:** Text domain `iyzico-installment`, Domain Path set; `__()`, `esc_html__()`, `esc_attr__()`, etc. used; .po files present
    - **Hooks:** Actions/filters used for menus, settings, shortcodes, tabs, AJAX
    - **No direct DB:** No custom tables or `$wpdb` usage
    - **AJAX:** Uses `admin-ajax.php`, nonce, and appropriate handlers for logged-in and nopriv
    #### Recommendations
    - Enqueue frontend `style.css` and a style handle for custom CSS so both default and custom CSS apply.
    - Either remove or properly integrate the logger and fix its append behavior.
    - Remove duplicate `enable_dynamic_installments` sanitization.
    ---
    ### 5. CODE QUALITY
    **Status: ⚠️ Warning**
    #### Issues
    | # | File | Line(s) | Severity | Description | Impact | Recommended fix |
    |---|------|---------|----------|-------------|--------|-----------------|
    | 1 | `includes/class-iyzico-installment-logger.php` | 56–74 | **Critical** | `put_contents()` overwrites the log file; the `else` branch then reads the file (already overwritten) and writes `existing_content . $log_message`, so the first write loses previous lines and the second write duplicates the current line | Log file often contains only the latest message or duplicated lines; logging unreliable | Always read existing content first (if file exists), then write `existing_content . $log_message` in one `put_contents` call; or use a single append path (e.g. `get_contents` + `put_contents( $path, $existing . $log_message )`) |
    | 2 | `includes/class-iyzico-installment-dynamic.php` | 356 | Medium | Rate limit uses `( $requests + 1 )` when `$requests` can be `false` (first request); in PHP `false + 1 = 1` | Works by accident | Explicit: `$count = is_numeric( $requests ) ? (int) $requests + 1 : 1; set_transient( $transient_key, $count, 60 );` |
    | 3 | `includes/class-iyzico-installment-settings.php` | 51–57 | Low | If `get_option()` returns non-array (e.g. corrupted), `update_option( ..., $this->_defaults )` could reset settings | Edge case | Use `$settings = get_option( self::OPTION_KEY, $this->_defaults );` and if not is_array, set to `$this->_defaults` before update |
    | 4 | Multiple | — | Low | Inconsistent formatting (e.g. `class-iyzico-installment-hpos.php` uses `if (! defined(...)` ) | Readability | Apply WordPress PHP coding standards consistently (spaces after `if`, etc.) |
    | 5 | `assets/js/iyzico-installment.js` | 325 | Low | Table header text hardcoded in JS: `'Taksit Sayısı'`, `'Taksit Tutarı'`, `'Toplam'` | Not translatable when table is rendered client-side | Pass translated strings via `wp_localize_script` and use them in `renderInstallmentTable` (or keep server-rendered table and avoid duplicating strings in JS) |
    | 6 | `includes/class-iyzico-installment-dynamic.php` | 398–410 | Low | `_sanitizeCss()` regex allows limited character set; may block valid CSS (e.g. `@font-face`, `url()`) | Custom CSS might be stripped | Broaden allowlist or rely on blocklist of dangerous tokens only |
    #### Best practices followed
    - **Structure:** Clear class split (Settings, API, Frontend, Admin, Dynamic, HPOS).
    - **PHPDoc:** Classes and many methods documented.
    - **Dependency injection:** Settings and API passed into Frontend/Dynamic/Admin.
    - **Type use:** Use of `floatval`, `intval`, and WC APIs keeps types predictable.
    - **DRY:** Installment table and bank logo logic exist in two places (Frontend + Dynamic) but are consistent; could be centralized in a small helper in a follow-up refactor.
    #### Recommendations
    - Fix logger to true append (read then write in one go).
    - Make rate limit counter handling explicit for first request.
    - Pass table header strings from PHP to JS for translation when rendering via JS.
    - Align formatting with WordPress PHP coding standards.
    ---
    ## Priority Action Items
    ### Critical
    1. **WooCommerce dependency (iyzico-installment.php)**
    Before loading any includes, check `class_exists( 'WooCommerce' )` (and optionally iyzico-woocommerce). If not present, register an `admin_notices` callback and `return` so plugin code does not run.
    2. **Custom CSS not loading (includes/class-iyzico-installment-frontend.php)**
    Enqueue a stylesheet with handle `iyzico-installment` (or a dedicated one for inline), then call `wp_add_inline_style()` with that same handle so admin custom CSS is output on the frontend.
    3. **Logger append bug (includes/class-iyzico-installment-logger.php)**
    Replace the current write logic with: read existing content if file exists, then write `existing_content . $log_message` once. If the logger is not used, remove the require and file instead.
    ### High
    4. **Frontend style.css never enqueued (includes/class-iyzico-installment-frontend.php)**
    In `enqueueScripts()` (and wherever shortcode enqueues assets), add `wp_enqueue_style( 'iyzico-installment-frontend', IYZI_INSTALLMENT_URL . 'style.css', array(), IYZI_INSTALLMENT_VERSION );` (adjust constant if you use a different base URL for assets).
    5. **WooCommerce version check (iyzico-installment.php)**
    After checking WooCommerce exists, add `version_compare( WC_VERSION, '9.3.3', '>=' )`; if false, show notice and do not load plugin logic.
    6. **Logger unused or integrated (iyzico-installment.php)**
    Either remove `require_once ... class-iyzico-installment-logger.php` and the logger file, or instantiate the logger and use it for API/error logging (after fixing the append bug).
    7. **Double enqueue on shortcode (includes/class-iyzico-installment-frontend.php)**
    In `renderShortcode()`, avoid calling `wp_enqueue_script` and `wp_localize_script` again if the script is already enqueued (e.g. check `wp_script_is( 'iyzico-installment', 'enqueued' )`), or centralize enqueue in one place.
    8. **Admin credentials in HTML (includes/admin/class-iyzico-installment-admin.php)**
    Do not echo secret key (and preferably not API key) in plain text in form values; use masked display and “Test connection” with POST body only.
    ### Medium
    9. **Inline script in dynamic (includes/class-iyzico-installment-dynamic.php)**
    Move the footer script to a separate JS file and enqueue it; pass `ajax_url`, `nonce`, `product_id`, prices, etc. via `wp_localize_script`.
    10. **API response caching (includes/class-iyzico-installment-api.php or class-iyzico-installment-dynamic.php)**
    Cache `getInstallmentInfo()` result in a transient (key: e.g. price + BIN) with TTL 5–15 minutes to reduce external API calls.
    11. **Rate limit counter (includes/class-iyzico-installment-dynamic.php)**
    Set transient value explicitly for first request: e.g. `$count = ( $requests !== false && is_numeric( $requests ) ) ? (int) $requests + 1 : 1; set_transient( $transient_key, $count, 60 );`.
    12. **Duplicate sanitization (includes/admin/class-iyzico-installment-admin.php)**
    Remove the second `enable_dynamic_installments` block (lines 128–130) in `sanitizeSettings()`.
    13. **CSS sanitization regex (includes/class-iyzico-installment-dynamic.php)**
    Loosen or replace the strict regex in `_sanitizeCss()` so valid CSS (e.g. `@font-face`, `url()`) is not stripped; keep blocklist of dangerous patterns.
    14. **Remote address for rate limit (includes/class-iyzico-installment-dynamic.php)**
    Use `wp_get_remote_address()` if WordPress version supports it for more reliable IP for rate limiting.
    ---
    ## Code Examples
    ### 1. Logger append fix (Critical)
    **File:** `includes/class-iyzico-installment-logger.php`
    **Current (buggy):**
    ```php
    if ( ! $wp_filesystem->put_contents( $this->_logFile, $log_message, FS_CHMOD_FILE ) ) {
    // fallback...
    } else {
    if ( $wp_filesystem->exists( $this->_logFile ) ) {
    $existing_content = $wp_filesystem->get_contents( $this->_logFile );
    $wp_filesystem->put_contents( $this->_logFile, $existing_content . $log_message, FS_CHMOD_FILE );
    } else {
    $wp_filesystem->put_contents( $this->_logFile, $log_message, FS_CHMOD_FILE );
    }
    }
    ```
    **Recommended:** Always append by reading first, then writing once:
    ```php
    $existing_content = '';
    if ( $wp_filesystem->exists( $this->_logFile ) ) {
    $existing_content = $wp_filesystem->get_contents( $this->_logFile );
    }
    $new_content = $existing_content . $log_message;
    if ( ! $wp_filesystem->put_contents( $this->_logFile, $new_content, FS_CHMOD_FILE ) ) {
    $file_put_contents_result = file_put_contents( $this->_logFile, $log_message, FILE_APPEND );
    if ( false === $file_put_contents_result ) {
    error_log( "Iyzico Logger: Failed to write to log file: {$this->_logFile}" );
    }
    }
    ```
    ### 2. Enqueue frontend style and custom CSS (Critical / High)
    **File:** `includes/class-iyzico-installment-frontend.php`
    **Add in `enqueueScripts()` after script enqueue:**
    ```php
    wp_enqueue_style(
    'iyzico-installment-frontend',
    IYZI_INSTALLMENT_URL . 'style.css',
    array(),
    IYZI_INSTALLMENT_VERSION
    );
    ```
    **Fix custom CSS** by using an enqueued style handle for inline CSS:
    ```php
    // Ensure a style is enqueued so inline CSS is output
    wp_enqueue_style(
    'iyzico-installment-inline',
    IYZI_INSTALLMENT_ASSETS_URL . '/css/iyzico-installment-inline.css', // or a minimal empty file / inline dependency
    array(),
    IYZI_INSTALLMENT_VERSION
    );
    wp_add_inline_style( 'iyzico-installment-inline', $custom_css );
    ```
    (Alternatively, enqueue the same `iyzico-installment-frontend` handle and use `wp_add_inline_style( 'iyzico-installment-frontend', $custom_css );` so one stylesheet carries both base and custom CSS.)
    ### 3. WooCommerce dependency check (Critical)
    **File:** `iyzico-installment.php`
    **Add after constants, before any `require_once`:**
    ```php
    add_action( 'plugins_loaded', function () {
    if ( ! class_exists( 'WooCommerce' ) ) {
    add_action( 'admin_notices', function () {
    echo '<div class="notice notice-error"><p>';
    esc_html_e( 'iyzico Installment requires WooCommerce to be installed and active.', 'iyzico-installment' );
    echo '</p></div>';
    } );
    return;
    }
    if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '9.3.3', '<' ) ) {
    add_action( 'admin_notices', function () {
    echo '<div class="notice notice-warning"><p>';
    esc_html_e( 'iyzico Installment requires WooCommerce 9.3.3 or newer.', 'iyzico-installment' );
    echo '</p></div>';
    } );
    return;
    }
    // Move current require_once and instantiation here (inside the callback)
    }, 5 );
    ```
    Then move all current `require_once` and `$GLOBALS[...]` assignments into that callback so they run only when WooCommerce is present and version is sufficient.
    ---
    ## Compatibility Matrix
    | Component | Version / note |
    |-----------|-----------------|
    | **WordPress** | 6.6+ (header: Requires at least 6.6; Tested up to 6.8) |
    | **WooCommerce** | 9.3.3+ (header: WC requires at least 9.3.3; WC tested up to 9.7.1) |
    | **PHP** | 7.4.33+ |
    | **Plugin conflicts** | Declares dependency on `woocommerce` and `iyzico-woocommerce` in header; no runtime conflict checks found. No custom tables; HPOS declared compatible. |
    ---
    ## Performance Metrics
    | Metric | Estimate / assessment |
    |--------|------------------------|
    | **Database queries per page load** | Low. Options: 1–2 `get_option` (settings), optional 1 `get_transient` (API status / rate limit). No custom tables or heavy queries. |
    | **Memory usage** | Low. No large data structures; API responses are bounded. |
    | **Cache compatibility** | Transients used for API status and rate limit. No full-page cache bypass for installment content; dynamic installment content is appropriate to be non-cached. Consider cache-friendly design if you ever serve static installment blocks. |
    | **External API** | One iyzico API call per installment request; no response caching currently (recommended to add transient cache by price). |
    ---
    ## Summary Table by Category
    | Category | Status | Critical | High | Medium | Low |
    |----------|--------|----------|------|--------|-----|
    | Performance | ⚠️ | 0 | 0 | 2 | 2 |
    | Security | ✅ | 0 | 0 | 0 | 3 |
    | WooCommerce | ⚠️ | 1 | 1 | 0 | 2 |
    | WordPress | ⚠️ | 2 | 2 | 0 | 2 |
    | Code quality | ⚠️ | 1 | 0 | 1 | 4 |
    | **Total** | | **3** | **5** | **6** | **4** |
    ---
    *End of report.*