15%

Tüm Hosting Hizmetlerinde %15 indirim

Becerilerini test et ve herhangi bir hosting planında İndirim kazan

Kodu kullanın:

Skills
Başlayın
22.10.2024

WordPress Actions Açıklandı: Hooks API için Eksiksiz Geliştirici Rehberi

WordPress Actions, geliştiricilerin çekirdek dosyalara hiç dokunmadan WordPress istek yaşam döngüsü boyunca tam olarak tanımlanmış noktalarda özel işlevler çalıştırmasına olanak tanıyan Hooks API’nin temel bir bileşenidir. Bir action hook tetiklendiğinde, o hook’a kayıtlı her işlev öncelik sırasına göre çalışır; bu da modüler, sürdürülebilir ve güncellemeye karşı güvenli özelleştirme sağlar.

Bir eklenti geliştiriyor, tema tasarlıyor veya VPS Hosting ortamında kendi barındırdığınız bir WordPress kurulumunu yönetiyorsanız, Actions konusunda uzmanlaşmak zorunludur. Bunlar, WordPress’in yalnızca üçüncü taraflar için bir genişletme aracı olarak değil, mimarisinin kurulduğu birincil mekanizmadır.

WordPress Actions Arka Planda Nasıl Çalışır

WordPress, tüm kayıtlı hook’ları — hem action’ları hem de filter’ları — depolayan $wp_filter adlı global bir kayıt defteri tutar. do_action() çağrıldığında, WordPress o hook’un $wp_filter içindeki girişini arar, kayıtlı callback’leri önceliğe göre sıralar ve bunları sırayla çalıştırır.

Pek çok eğitimin üzerinden geçtiği kritik ayrım: Actions, tetikle ve unut mantığıyla çalışır. Callback’leri çalıştırır ancak döndürülen değerleri atar. Verileri yakalamak ve değiştirmek istiyorsanız, bu Actions’ın değil Filters’ın işidir. İkisini karıştırmak, WordPress eklenti geliştirmede en yaygın mimari hatalardan biridir.

Çalıştırma akışı şu şekildedir:

  1. WordPress çekirdeği (veya bir eklenti/tema) do_action( 'hook_name', ...$args ) çağırır.
  2. WordPress, $wp_filter içinden hook_name hook’una kayıtlı tüm callback’leri çözümler.
  3. Callback’ler $priority değerlerine göre sıralanır (artan sırada — düşük sayılar önce tetiklenir).
  4. Her callback, sağlanan argümanlarla çağrılır.
  5. Döndürülen değerler sessizce göz ardı edilir.
  6. do_action() döndükten sonra çalıştırma, kaynak kodda devam eder.

Bu mimari, init gibi erken bir hook’a kayıtlı kötü yazılmış bir callback’in tüm isteği engelleyebileceği anlamına gelir. Hook callback’lerini her zaman üretime dağıtmadan önce hazırlık ortamında profilleyin.

add_action() ile Actions Kaydetme

add_action() işlevi, bir PHP callable’ı adlandırılmış bir action hook’una kaydeder. Tam imzası şöyledir:

add_action( string $hook_name, callable $callback, int $priority = 10, int $accepted_args = 1 ): true

Parametreler açıklandı:

  • $hook_name — Action hook’unun tam dize tanımlayıcısı (örn. wp_login, save_post).
  • $callback — Geçerli herhangi bir PHP callable: adlandırılmış bir işlev, anonim bir işlev, statik bir yöntem array( 'MyClass', 'method' ) veya bir nesne yöntemi array( $object, 'method' ).
  • $priority — Aynı hook üzerindeki diğer callback’lere göre çalıştırma sırası. Varsayılan 10. Aynı önceliğe sahip callback’ler kayıt sırasına göre çalışır.
  • $accepted_argsdo_action() içinden callback’inize kaç argüman iletileceği. Varsayılan 1. Bunu doğru ayarlamazsanız callback’iniz kesilmiş argüman listeleri alır.

Temel Örnek: wp_login Hook’una Bağlanma

function notify_admin_on_login( string $user_login, WP_User $user ): void {
    $admin_email = get_option( 'admin_email' );
    $subject     = 'Login Alert: ' . $user_login;
    $message     = sprintf(
        'User "%s" (ID: %d) logged in at %s.',
        $user_login,
        $user->ID,
        current_time( 'mysql' )
    );
    wp_mail( $admin_email, $subject, $message );
}

// wp_login passes two arguments: $user_login (string) and $user (WP_User object)
add_action( 'wp_login', 'notify_admin_on_login', 10, 2 );

accepted_args değerinin 2 olarak ayarlandığına dikkat edin. Bunu atlayıp varsayılan 1 değerini bırakmak, callback’inizin yalnızca $user_login alması ve WP_User nesnesini hiç görmemesi anlamına gelir — izlemesi son derece güç sessiz bir hata.

Nesne Yöntemleri ve Closure Kullanımı

Modern WordPress geliştirme, mantığı sınıflar içinde kapsüllemeyi tercih eder:

class My_Plugin {

    public function __construct() {
        add_action( 'init', array( $this, 'register_post_types' ) );
        add_action( 'save_post', array( $this, 'handle_save' ), 20, 3 );
    }

    public function register_post_types(): void {
        register_post_type( 'product', array( /* args */ ) );
    }

    public function handle_save( int $post_id, WP_Post $post, bool $update ): void {
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }
        // Custom save logic here
    }
}

new My_Plugin();

Anonim closure’lar da çalışır, ancak PHP anonim işlev referanslarını güvenilir biçimde karşılaştıramadığından daha sonra remove_action() ile kaldırılamazlar. Kaydı silme ihtiyacı duyduğunuzda adlandırılmış yöntemler kullanın.

remove_action() ile Actions Kaldırma

remove_action() kullanarak diğer eklentiler veya temalar tarafından eklenenler dahil herhangi bir callback’in kaydını silebilirsiniz. Öncelik, add_action() içinde kullanılanla tam olarak eşleşmelidir:

remove_action( 'wp_head', 'wp_generator' ); // Removes WordPress version meta tag

Nesne yöntemleri için aynı nesne örneğine bir referansa ihtiyacınız vardır:

// Inside a plugin that exposes its instance
global $my_plugin_instance;
remove_action( 'save_post', array( $my_plugin_instance, 'handle_save' ), 20 );

Yaygın bir tuzak: remove_action() çağrısını orijinal add_action() çalışmadan önce yapmak. Kaldırma işleminizi her zaman hedef eklenti yüklendikten sonra tetiklenen bir action’a bağlayın — genellikle plugins_loaded veya after_setup_theme.

WordPress Çekirdek Action Hook’ları Referansı

Aşağıdaki tablo, en işlevsel açıdan önemli action hook’larını, tetiklenme bağlamlarını ve pratik kullanım durumlarını kapsamaktadır.

Hook AdıNe Zaman TetiklenirTipik Kullanım Durumlarıİletilen Argümanlar
muplugins_loadedZorunlu eklentiler yüklendiErken önyükleme, sabitler0
plugins_loadedTüm eklentiler yüklendiEklentiler arası uyumluluk kontrolleri0
initWP yüklendikten sonra, başlıklardan önceCPT’leri, taksonomileri, yeniden yazma kurallarını kaydet0
wp_loadedinit sonrası, her şey yüklendiREST API kaydı, geç başlatma görevleri0
wp_enqueue_scriptsÖn uç varlık yüklemeTemalar ve eklentiler için CSS/JS sıraya alma0
wp_head<head> etiketi içindeMeta etiketler, satır içi stiller, analitik kod parçacıkları0
wp_footer</body> öncesiErtelenmiş betikler, izleme pikselleri0
admin_initYönetici sayfası yüklenirSettings API kaydı, yetenek kontrolleri0
admin_enqueue_scriptsYönetici varlık yüklemeYalnızca yöneticiye özel CSS/JS sıraya alma1 ($hook_suffix)
save_postGönderi kaydedildi veya güncellendiMeta güncellemeleri, harici API senkronizasyonu, bildirimler3
wp_loginKullanıcı kimlik doğrulaması yaparDenetim günlüğü, oturum yönetimi2
user_registerYeni kullanıcı oluşturulduHoş geldiniz e-postaları, CRM senkronizasyonu, rol ataması1 ($user_id)
wp_logoutKullanıcı oturumu kapatırOturum temizleme, analitik olaylar1 ($user_id)
switch_themeAktif tema değişirÖnbellek temizleme, seçenek geçişi2
wp_trash_postGönderi çöp kutusuna taşındıİlgili verilerin temizlenmesi, harici senkronizasyon1 ($post_id)
rest_api_initREST API başlatılırÖzel REST rotalarını kaydet0
template_redirectŞablon yüklenmeden önceYönlendirmeler, erişim kontrolü0

do_action() ile do_action_ref_array(): Her Birinin Uygulandığı Durumlar

Her iki işlev de bir action hook’u tetikler, ancak argümanların nasıl iletildiği konusunda farklılık gösterirler.

do_action()

Standart işlev. Argümanlar değer olarak iletilir — callback’ler kopyaları alır.

do_action( 'my_plugin_after_import', $import_id, $result_count, $errors );

do_action_ref_array()

Argümanlar bir dizi olarak iletilir ve bu dizideki nesneler referans olarak iletilir (PHP nesneleri, PHP 5’ten bu yana varsayılan olarak her zaman referans benzeridir). Bu, öncelikle eski uyumluluk için veya callback’lerin paylaşılan bir veri yapısını değiştirmesine açıkça ihtiyaç duyduğunuzda kullanışlıdır.

$context = array(
    'post_id' => 42,
    'meta'    => array(),
);

do_action_ref_array( 'my_plugin_process_context', array( &$context ) );

// $context['meta'] may now be populated by hooked callbacks

Pratik rehberlik: Modern PHP’de (7.4+), nesneler için iki işlev arasındaki davranışsal fark minimaldir. Varsayılan olarak do_action() kullanın. do_action_ref_array() yalnızca bunu açıkça bekleyen eski kodlarla entegrasyon sağlarken veya referans olarak iletilen bir ilkel değeri (tamsayı gibi) callback’lerin değiştirmesine ihtiyaç duyduğunuzda tercih edin.

Özel Action Hook’ları Oluşturma ve Belgeleme

Başkaları tarafından genişletilmesi amaçlanan bir eklenti veya tema geliştirirken kendi action hook’larınızı tanımlamalısınız. Bu, üçüncü taraflara iç yapınıza doğrudan erişim vermeden bir API yüzeyi sunmanın yoludur.

/**
 * Fires after a custom import process completes.
 *
 * @since 1.0.0
 *
 * @param int   $import_id    The ID of the completed import batch.
 * @param int   $record_count Total number of records processed.
 * @param array $errors       Array of WP_Error objects, empty on full success.
 */
do_action( 'my_plugin_import_complete', $import_id, $record_count, $errors );

Hook’larınızı her zaman do_action() çağrısının hemen üstüne bir DocBlock ile belgeleyin. Bu, WordPress geliştirici belgelendirme oluşturucusunu besleyen şeydir ve eklentinizi profesyonel düzeye taşır. Üçüncü taraf geliştiriciler daha sonra temiz bir şekilde bağlanabilir:

add_action( 'my_plugin_import_complete', function( int $import_id, int $count, array $errors ) {
    if ( ! empty( $errors ) ) {
        // Log errors to an external monitoring service
        error_log( "Import {$import_id} completed with " . count( $errors ) . ' errors.' );
    }
}, 10, 3 );

Actions ile Filters: Kesin Bir Karşılaştırma

Bu, tüm WordPress Hooks API’sindeki en önemli kavramsal ayrımdır.

BoyutActionsFilters
Birincil amaçBelirli bir noktada yan etkileri çalıştırVerileri yakala ve değiştir
Döndürülen değerTamamen göz ardı edilir(Değiştirilmiş) değeri döndürmesi gerekir
Çekirdek işlevdo_action()apply_filters()
Kayıtadd_action()add_filter()
Tipik kullanımE-posta gönderme, DB’ye yazma, varlık sıraya almaGönderi içeriğini değiştirme, sorgu argümanlarını düzenleme
Kısa devre yapabilir mi?Hayır (tüm callback’ler her zaman çalışır)Hayır (ancak callback içinde erken dönebilir)
Veri değiştirmeAmaçlanan desen değilTemel amaç

Temel mimari kural: add_filter() kullanıyor ancak callback’inizden bir değer döndürmüyorsanız bir hata oluşturdunuz — filtrelenen değer bağlama göre null veya false olacaktır. Tersine, add_action() kullanıyor ve bir dönüş değerine güveniyorsanız API’yi yanlış kullanıyorsunuz demektir.

Öncelik Çakışmaları ve Çalıştırma Sırası

Öncelik yönetimi, karmaşık eklenti ekosistemlerinde kritik hale gelir. WooCommerce, bir önbellekleme eklentisi ve özel kodunuzun hepsinin save_post hook’una bağlandığı bir senaryoyu düşünün:

// WooCommerce hooks at priority 10 (default)
// Your inventory sync needs WooCommerce data to already be saved
add_action( 'save_post_product', 'sync_inventory_to_erp', 99 );

// A cache purge should happen last, after all data is written
add_action( 'save_post', 'purge_varnish_cache', 9999 );

Bilinmesi gereken uç durumlar:

  • Negatif öncelikler WordPress’te geçerlidir. add_action( 'init', 'my_func', -1 ), 0 veya 10 önceliğindeki her şeyden önce tetiklenir.
  • Aynı öncelik, birden fazla callbackadd_action() çağrıldığı sırayla çalışırlar. Eklenti yükleme sırası (dosya adına göre alfabetik olarak veya Plugin Order eklentileri tarafından belirlenir) bu nedenle davranışı etkiler.
  • Özyinelemeli hook’lar — bir hook için callback içinde aynı hook için do_action() çağırmak teknik olarak mümkündür ancak sonsuz döngüler oluşturur. WordPress buna karşı koruma sağlamaz.
  • Geç hook kaydıinit zaten tetiklendikten sonra add_action( 'init', ... ) çağırırsanız, callback’iniz o istekte hiçbir zaman çalışmaz. Bu, koşullu olarak çalışan kodlarda sık görülen bir hata kaynağıdır.

Gerçek Dünya Üretim Desenleri

Desen 1: Ayrıştırılmış Olay Sistemi

Modüller arasında doğrudan işlev çağrılarından kaçınarak eklenti bileşenlerini ayırmak için özel action’lar kullanın:

// In your order processing module
do_action( 'my_shop_order_paid', $order_id, $payment_method, $amount );

// In your email module (separate file, no direct dependency)
add_action( 'my_shop_order_paid', 'send_payment_confirmation_email', 10, 3 );

// In your analytics module (separate file, no direct dependency)
add_action( 'my_shop_order_paid', 'track_conversion_event', 20, 3 );

Bu desen, sipariş işleme koduna dokunmadan analitik modülünü tamamen devre dışı bırakabileceğiniz anlamına gelir.

Desen 2: Koşullu Hook Kaydı

Hook’ları üst düzeyde koşulsuz olarak kaydetmekten kaçının. Bunları ihtiyaç duydukları bağlama göre kapsamlandırın:

add_action( 'admin_init', function() {
    // Only register these hooks in the admin context
    add_action( 'admin_enqueue_scripts', 'my_plugin_admin_assets' );
    add_action( 'save_post', 'my_plugin_validate_custom_fields', 10, 2 );
} );

Desen 3: Callback İçinde remove_action() ile Tek Seferlik Actions

function my_plugin_run_once(): void {
    // Do something that must only happen once per request
    update_option( 'my_plugin_initialized', true );

    // Deregister itself to prevent re-execution if the hook fires again
    remove_action( 'wp_loaded', 'my_plugin_run_once' );
}

add_action( 'wp_loaded', 'my_plugin_run_once' );

Yönetilen Ortamlarda Performans Değerlendirmeleri

Yüksek trafikli WordPress kurulumlarında — ister VPS Hosting planında ister Dedicated Server üzerinde çalışıyor olsun — kötü optimize edilmiş hook’ların kümülatif maliyeti ölçülebilir düzeydedir.

Kullanılacak profilleme araçları:

  • Query Monitor eklentisi: Tetiklenen her hook’u, çalışan her callback’i ve callback başına çalıştırma süresini gösterir.
  • Xdebug + KCacheGrind: Callback çalıştırma yollarının derinlemesine profillemesi için.
  • New Relic APM: Üretim düzeyinde hook performansı izleme için.

Optimizasyon ilkeleri:

  • Pahalı işlemleri (veritabanı sorguları, HTTP istekleri, dosya G/Ç) her sayfa yüklemesinde tetiklenen hook’lardan (init, wp_head) yalnızca gerektiğinde tetiklenen hook’lara (save_post, user_register) taşıyın.
  • Hook callback’leri içindeki pahalı hesaplamaların sonuçlarını önbelleğe almak için geçici değerleri veya nesne önbelleğini kullanın.
  • Eklenti yükleme zamanında yüzlerce add_action() çağrısını koşulsuz olarak kaydetmekten kaçının. Hook’ları yalnızca ilgili yönetici sayfası veya bağlam aktif olduğunda geç kaydedin.
  • OPcache etkin sunucularda (tüm düzgün yapılandırılmış PHP ortamlarında olması gerektiği gibi), hook kaydının kendisinin ek yükü ihmal edilebilir düzeydedir — maliyet, callback’lerin *ne yaptığında* değil, kayıtta değildir.

Kendi WordPress yığınınızı yönetiyorsanız, sunucunuzun PHP 8.1+ ile OPcache, bir bytecode önbelleği ve Redis veya Memcached gibi bir nesne önbelleği çalıştırmasını sağlamak, hook önceliklerini mikro optimize etmekten çok daha büyük bir performans etkisine sahip olacaktır.

Eklenti ve Tema Geliştirme Bağlamında WordPress Actions

WordPress.org deposu veya ticari dağıtım için tasarlanmış bir eklenti geliştirirken, Hooks API kullanımınız doğrudan kod kalitesini ve uyumluluk puanlarını belirler.

Üretim kalitesinde hook kullanımı için en iyi uygulamalar:

  • Otomatik kaydetmelerde pahalı mantık çalıştırmaktan kaçınmak için save_post callback’leri içinde her zaman DOING_AUTOSAVE kontrol edin.
  • Kullanıcı tarafından gönderilen verileri işleyen herhangi bir hook callback’i içinde nonce’ları ve yetkileri doğrulayın. Hook’un kendisinin güvenlik sağladığına asla güvenmeyin.
  • Aynı işlev birden fazla hook’a kayıtlıyken hangi hook’un callback’inizi tetiklediğini belirlemek için current_action() kullanın.
  • Çakışmaları önlemek için özel hook adlarınızı ad alanına alın: my_plugin_event_name, event_name değil.
  • Geliştiricilerin bir hook’un ne zaman tanıtıldığını ve ne zaman kullanımdan kaldırılabileceğini bilmesi için belgelerinizde hook’larınızı sürümlendirin.

VPS Control Panels ile altyapıya WordPress dağıtan ekipler için, dağıtımdan önce hook etkileşimlerini güvenli bir şekilde test etmek amacıyla üretimi yansıtan hazırlık ortamları sürdürmek zorunludur.

WordPress Kurulumunuzu Özel Actions ile Birlikte Güvence Altına Alma

Harici verileri işleyen, kimlik doğrulama olaylarını yöneten veya dosya sistemiyle etkileşime giren özel action hook’ları güvenlik yüzeyi alanı oluşturur. Hook geliştirmenizi düzgün güvenliği sağlanmış bir barındırma ortamıyla eşleştirin.

WordPress kurulumunuzun HTTPS kullandığından emin olun — kullanıcı kimlik doğrulaması veya form gönderimleri işleyen herhangi bir site için bir SSL Sertifikası zorunludur. wp_login veya user_register üzerinde tetiklenen hook callback’leri, kablo üzerinden hassas verileri işler; TLS olmadan, PHP kodunuz ne kadar iyi yazılmış olursa olsun bu veriler açığa çıkar.

Ayrıca, eklentiniz action callback’leri içinde wp_mail() kullanıyorsa (bildirimler için yaygın bir desen), sunucunuzun posta yapılandırması ve itibarı teslim edilebilirliği doğrudan etkiler. Sunucu düzeyindeki sendmail kullanımına güvenmek yerine uygun SPF, DKIM ve DMARC kayıtlarına sahip özel bir E-posta Hosting çözümü düşünün.

Teknik Karar Matrisi ve Temel Çıkarımlar

Herhangi bir projede WordPress Actions uygularken bu kontrol listesini kullanın:

Hook kaydı:

  • Hook birden fazla argüman ilettiğinde $accepted_args değerini açıkça ayarlayın
  • Öncelik değerlerini bilinçli kullanın — varsayılan dışı önceliklerin neden seçildiğini belgeleyin
  • Hook’ları sınıf yapıcıları veya özel register_hooks() yöntemleri içinde kaydedin, asla bir eklenti dosyasının global kapsamında değil
  • Hook kaydını ihtiyaç duyulduğu bağlama göre kapsamlandırın (yönetici, ön uç, REST API)

Callback uygulaması:

  • İlgili yerlerde her zaman DOING_AUTOSAVE, DOING_CRON ve wp_is_json_request() kontrol edin
  • Herhangi bir kullanıcı girdisini işlemeden önce check_admin_referer() veya check_ajax_referer() ile nonce’ları doğrulayın
  • do_action() çağrısından dönen değerlere asla güvenmeyin — veri geri almanız gerekiyorsa filter kullanın
  • Bir callback birden fazla hook’a hizmet ettiğinde current_action() kullanın

Özel hook tasarımı:

  • Tüm özel hook adlarını eklenti/tema önekiyle ad alanına alın
  • Her özel hook’u do_action() çağrısının üstüne tam bir DocBlock ile belgeleyin
  • İç durumu gereksiz yere açığa çıkarmadan hook’u kullanışlı kılacak kadar argüman iletin
  • Belirli bir nedeniniz olmadıkça do_action_ref_array() yerine do_action() tercih edin

Performans ve bakım:

  • Üretime dağıtmadan önce hook callback’lerini Query Monitor ile profilleyin
  • Her istekte tetiklenen hook’lar içinde veritabanı sorgularından kaçının
  • Uygulamanızla çakışan üçüncü taraf hook’ları temizlemek için remove_action() kullanın
  • Hook etkileşimlerini üretim altyapısını yansıtan bir hazırlık ortamında test edin

SSS

WordPress’te add_action() ile add_filter() arasındaki fark nedir?

add_action(), çalıştırmanın belirli bir noktasında yan etkileri gerçekleştirmek için bir callback kaydeder — döndürülen değer atılır. add_filter(), bir değeri almak, değiştirmek ve döndürmek için bir callback kaydeder. Birini diğerinin uygun olduğu yerde kullanmak işlevsel bir hatadır: değer döndürmeyen bir filter callback’i, filtrelenen veriyi geçersiz kılar.

add_action() callback’im neden tetiklenmiyor?

En yaygın nedenler şunlardır: (1) hook adı yanlış yazılmış, (2) add_action() hook mevcut istekte zaten tetiklendikten sonra çağrılıyor, (3) $accepted_args çok düşük ve callback yanlış veri alarak sessiz bir PHP hatasına neden oluyor, veya (4) callback içindeki koşullu bir kontrol çalıştırmayı engelliyor. Hook’un tetiklenip tetiklenmediğini ve callback’inizin kayıtlı olup olmadığını doğrulamak için Query Monitor kullanın.

Başka bir action callback’i içinde add_action() kullanabilir miyim?

Evet, ve bu yaygın bir desendir. Örneğin, bağımlılıkların mevcut olduğundan emin olmak için plugins_loaded veya init içinde hook’ları kaydetmek. Ancak, kaydın etkili olması için iç hook’un dış hook’tan sonra tetiklenmesi gerekir.

$priority parametresi aslında neyi kontrol eder?

Aynı hook’a kayıtlı birden fazla callback’in çalıştırılma sırasını kontrol eder. Düşük sayılar önce tetiklenir. Varsayılan değer 10‘dir. Geçerli değerler negatif tamsayıları içerir. İki callback aynı önceliği paylaştığında, add_action() aracılığıyla kayıt edildikleri sırayla çalışırlar.

Üçüncü taraf bir eklenti tarafından eklenen bir action’ı güvenli bir şekilde nasıl kaldırabilirim?

remove_action() çağrınızı eklenti yüklendikten sonra tetiklenen bir action’a bağlayın — genellikle yüksek öncelikli plugins_loaded veya after_setup_theme. Orijinal add_action() çağrısında kullanılan tam hook adı, callback referansı ve önceliği eşleştirmeniz gerekir. Nesne yöntemleri için aynı nesne örneğine erişim gerekir; saygın eklentiler bunu global bir değişken veya statik bir get_instance() yöntemi aracılığıyla sunar.

15%

Tüm Hosting Hizmetlerinde %15 indirim

Becerilerini test et ve herhangi bir hosting planında İndirim kazan

Kodu kullanın:

Skills
Başlayın