WordPress Medya Kütüphanesini Kullanıcıya Göre Kısıtlama
Çok kullanıcılı bir WordPress sitesi yönetirken en sık karşılaşılan sorunlardan biri medya kütüphanesinin kontrolden çıkmasıdır. Editörler başkasının yüklediği görselleri siliyor, yazarlar birbirinin dosyalarını görüyor, müşteriler başka müşterilerin logolarına erişiyor. Bu kaos ortamını düzeltmek için genellikle ek eklenti kurulur ama aslında birkaç satır functions.php kodu bu sorunu tamamen çözer.
Sorunun Tam Olarak Ne Olduğunu Anlamak
WordPress’in varsayılan davranışı şudur: Medya kütüphanesi herkese açıktır. Yani editor rolündeki bir kullanıcı, administrator dahil tüm kullanıcıların yüklediği dosyaları görür, düzenleyebilir, hatta silebilir. Küçük bir kişisel blog için bu sorun değil. Ama şu senaryoları düşünün:
- Birden fazla yazar barındıran bir haber sitesi
- Her müşterinin kendi içeriklerini yönettiği bir ajans kurulumu
- WooCommerce’de her satıcının kendi ürün görsellerini yüklediği bir çoklu satıcı mağazası
- Farklı departmanların içerik ürettiği kurumsal bir intranet
Bu senaryoların hepsinde medya kütüphanesi karmaşası ciddi bir sorun haline gelir. Hem güvenlik hem de kullanılabilirlik açısından her kullanıcının sadece kendi yüklediği dosyaları görmesi gerekir.
Temel Yaklaşım: ajax_query_attachments_args Filtresi
WordPress medya kütüphanesi sorgulamalarını AJAX üzerinden yapar. Bu sorguya müdahale etmenin en temiz yolu ajax_query_attachments_args filtresini kullanmaktır.
// functions.php'ye ekle
function restrict_media_library_to_current_user( $query ) {
if ( ! current_user_can( 'administrator' ) ) {
$query['author'] = get_current_user_id();
}
return $query;
}
add_filter( 'ajax_query_attachments_args', 'restrict_media_library_to_current_user' );
Bu kod son derece basit ama çok etkilidir. Yönetici olmayan her kullanıcı medya kütüphanesini açtığında sadece kendi yüklediği dosyaları görür. Administrator rolündekiler ise tüm kütüphaneye erişmeye devam eder.
Ancak bu tek başına yetmez. AJAX filtresi sadece medya kütüphanesi popup’ını etkiler. Doğrudan medya yönetim sayfasına (/wp-admin/upload.php) giden kullanıcı hâlâ tüm dosyaları görebilir.
upload.php Sayfasını da Kısıtlamak
// Medya listesi sayfasını da kısıtla
function restrict_media_library_list_table( $query ) {
global $pagenow;
if ( 'upload.php' !== $pagenow ) {
return $query;
}
if ( current_user_can( 'administrator' ) ) {
return $query;
}
$query->set( 'author', get_current_user_id() );
return $query;
}
add_action( 'pre_get_posts', 'restrict_media_library_list_table' );
pre_get_posts aksiyonu ana WP_Query nesnesine müdahale eder. upload.php sayfasını kontrol edip sadece o sayfada devreye giriyoruz. Bu sayede diğer sorgular etkilenmez.
Çoklu Rol Desteği
Gerçek dünya projelerinde roller daha karmaşık olabilir. Belki editor rolündeki kullanıcılar tüm medyayı görebilmeli ama author rolündekiler sadece kendinkini görebilmeli. Hatta bazen özel roller tanımlanmış olur.
// Rol bazlı gelişmiş medya kısıtlaması
function advanced_media_library_restriction( $query ) {
// Yöneticiler ve editörler tümünü görür
$unrestricted_roles = array( 'administrator', 'editor' );
$current_user = wp_get_current_user();
$user_roles = (array) $current_user->roles;
// Kullanıcının kısıtlanmamış rollerinden biri var mı?
$has_unrestricted_role = array_intersect( $unrestricted_roles, $user_roles );
if ( empty( $has_unrestricted_role ) ) {
$query['author'] = get_current_user_id();
}
return $query;
}
add_filter( 'ajax_query_attachments_args', 'advanced_media_library_restriction' );
function advanced_media_list_restriction( $query ) {
global $pagenow;
if ( 'upload.php' !== $pagenow ) {
return $query;
}
$unrestricted_roles = array( 'administrator', 'editor' );
$current_user = wp_get_current_user();
$user_roles = (array) $current_user->roles;
$has_unrestricted = array_intersect( $unrestricted_roles, $user_roles );
if ( empty( $has_unrestricted ) ) {
$query->set( 'author', get_current_user_id() );
}
return $query;
}
add_action( 'pre_get_posts', 'advanced_media_list_restriction' );
Bu yaklaşımda $unrestricted_roles dizisini projenize göre kolayca özelleştirebilirsiniz. İstediğiniz rolleri ekleyip çıkarabilirsiniz.
Dosya Sahipliğini Değiştirmeyi Engellemek
Kısıtlama yaptınız, kullanıcılar artık sadece kendi dosyalarını görüyor. Peki ya bir kullanıcı başka bir kullanıcının ek kimliğini bilerek direkt URL ile düzenlemeye çalışırsa? Bunun için de önlem almak gerekir.
// Başkasının medyasını düzenlemeyi engelle
function prevent_unauthorized_media_edit( $caps, $cap, $user_id, $args ) {
if ( 'edit_post' !== $cap && 'delete_post' !== $cap ) {
return $caps;
}
if ( empty( $args[0] ) ) {
return $caps;
}
$post = get_post( $args[0] );
if ( ! $post || 'attachment' !== $post->post_type ) {
return $caps;
}
// Administrator kontrolü
if ( user_can( $user_id, 'administrator' ) ) {
return $caps;
}
// Sahiplik kontrolü
if ( (int) $post->post_author !== (int) $user_id ) {
$caps[] = 'do_not_allow';
}
return $caps;
}
add_filter( 'user_has_cap', 'prevent_unauthorized_media_edit', 10, 4 );
Bu fonksiyon user_has_cap filtresini kullanır. WordPress bir kullanıcının bir şeyi yapıp yapamayacağını kontrol ettiğinde bu filtreden geçer. Eğer işlem bir attachment üzerindeyse ve kullanıcı o attachment’ın sahibi değilse do_not_allow kapasitesini ekliyoruz. Bu, WordPress’e “bu kullanıcının bu işlemi yapmasına izin verme” demektir.
WooCommerce Senaryosu: Satıcı Bazlı Medya Kısıtlaması
Dolio gibi çoklu satıcı sitelerinde ya da WooCommerce kullanan ajans projelerinde her satıcının/müşterinin medyası izole olmalıdır. Burada genellikle kullanıcı meta verisi üzerinden gruplandırma yapılır.
// WooCommerce veya ajans senaryosu için müşteri grubu bazlı kısıtlama
function agency_media_restriction_ajax( $query ) {
if ( current_user_can( 'administrator' ) || current_user_can( 'editor' ) ) {
return $query;
}
$current_user_id = get_current_user_id();
$client_group = get_user_meta( $current_user_id, 'client_group_id', true );
if ( ! empty( $client_group ) ) {
// Aynı gruptaki tüm kullanıcıları bul
$group_users = get_users( array(
'meta_key' => 'client_group_id',
'meta_value' => $client_group,
'fields' => 'ID',
) );
if ( ! empty( $group_users ) ) {
$query['author__in'] = $group_users;
} else {
$query['author'] = $current_user_id;
}
} else {
$query['author'] = $current_user_id;
}
return $query;
}
add_filter( 'ajax_query_attachments_args', 'agency_media_restriction_ajax' );
Bu kodda client_group_id adında bir user meta anahtarı kullanıyoruz. Aynı gruba ait kullanıcılar birbirlerinin medyasını görebilir ama diğer grupların dosyalarına erişemez. Kullanıcıları gruba atarken şöyle bir yardımcı fonksiyon kullanabilirsiniz:
// Kullanıcıya grup ata
function assign_user_to_client_group( $user_id, $group_id ) {
if ( ! is_numeric( $user_id ) || ! is_numeric( $group_id ) ) {
return false;
}
return update_user_meta( $user_id, 'client_group_id', absint( $group_id ) );
}
// Kullanım örneği
// assign_user_to_client_group( 15, 3 ); // User ID 15'i grup 3'e ata
Medya Yükleme Sayısını Sınırlamak
Kısıtlamayı bir adım daha ileri götürelim. Belki kullanıcıların yükleyebileceği maksimum dosya sayısını da sınırlamak istiyorsunuz. Özellikle hosting maliyetlerini kontrol altında tutmak için bu çok işe yarar.
// Kullanıcı başına maksimum yükleme limiti
function limit_user_media_upload_count( $file ) {
// Adminler için limit yok
if ( current_user_can( 'administrator' ) ) {
return $file;
}
$user_id = get_current_user_id();
$max_uploads = 50; // Kullanıcı başına maksimum dosya sayısı
// Kullanıcıya özel limit varsa onu kullan
$custom_limit = get_user_meta( $user_id, 'max_media_uploads', true );
if ( ! empty( $custom_limit ) && is_numeric( $custom_limit ) ) {
$max_uploads = absint( $custom_limit );
}
// Mevcut yükleme sayısını al
$upload_count = count_user_posts( $user_id, 'attachment' );
if ( $upload_count >= $max_uploads ) {
$file['error'] = sprintf(
'Maksimum yükleme limitine (%d dosya) ulaştınız. Yeni dosya yüklemek için mevcut dosyalardan bazılarını silin.',
$max_uploads
);
}
return $file;
}
add_filter( 'wp_handle_upload_prefilter', 'limit_user_media_upload_count' );
Bu kodu özelleştirmenin güzel bir yolu da kullanıcı meta verisiyle bireysel limitler tanımlamaktır. Admin panelinden bir kullanıcının profiline girip max_media_uploads meta değerini 100 olarak ayarlarsanız o kullanıcı 100 dosya yükleyebilir. Değer yoksa varsayılan 50 limit uygulanır.
Admin Çubuğuna Medya Sayısı Göstergesi Eklemek
Kullanıcıların kaç dosya yüklediğini görmesi için admin çubuğuna küçük bir gösterge ekleyebiliriz. Bu hem kullanıcı deneyimini iyileştirir hem de limit aşımından önce kullanıcıları uyarır.
// Admin çubuğuna medya sayacı ekle
function add_media_count_to_admin_bar( $wp_admin_bar ) {
if ( ! is_admin() || current_user_can( 'administrator' ) ) {
return;
}
$user_id = get_current_user_id();
$upload_count = count_user_posts( $user_id, 'attachment' );
$max_uploads = get_user_meta( $user_id, 'max_media_uploads', true ) ?: 50;
$percentage = ( $upload_count / $max_uploads ) * 100;
$color = $percentage >= 90 ? '#ff4444' : ( $percentage >= 70 ? '#ffaa00' : '#46b450' );
$wp_admin_bar->add_node( array(
'id' => 'media-usage',
'title' => sprintf(
'<span style="color:%s">Medya: %d/%d</span>',
$color,
$upload_count,
$max_uploads
),
'href' => admin_url( 'upload.php' ),
) );
}
add_action( 'admin_bar_menu', 'add_media_count_to_admin_bar', 100 );
Kullanıcı limitin %90’ını aştığında kırmızı renk gösterilir, %70-90 arası sarı, altında yeşil. Kullanıcılar ne kadar alan kullandıklarını her an görebilir.
Gerçek Dünya Sorun Giderme
Bu kısıtlamaları uyguladıktan sonra birkaç yaygın sorunla karşılaşabilirsiniz:
Gutenberg blok editöründe medya seçimi çalışmıyor: Gutenberg kendi REST API sorgularını kullanır. Bu yüzden ajax_query_attachments_args bazen yetmez. REST API’ye de müdahale etmeniz gerekebilir:
// Gutenberg REST API medya sorgusunu da kısıtla
function restrict_rest_media_query( $args, $request ) {
if ( ! isset( $request['post'] ) ) {
return $args;
}
if ( current_user_can( 'administrator' ) || current_user_can( 'editor' ) ) {
return $args;
}
$args['author'] = get_current_user_id();
return $args;
}
add_filter( 'rest_attachment_query', 'restrict_rest_media_query', 10, 2 );
Öne çıkan görsel seçimi çalışmıyor: Bazı tema ve eklentilerde öne çıkan görsel seçerken kısıtlama sorunu yaşanabilir. ajax_query_attachments_args filtresinde hangi bağlamda çağrıldığınızı kontrol edin.
Kullanıcı başkasının attachment ID’sini URL’den çağırıyor: prevent_unauthorized_media_edit fonksiyonu bunu engelliyor olmalı. Eğer yine de sorun yaşıyorsanız template_redirect üzerinde ek kontrol ekleyin.
Tüm Kodu Bir Arada Kullanmak
Gerçek bir projede bu fonksiyonları genellikle ayrı bir dosyada toplar ve functions.php‘den include edersiniz. Dosya yapısı şöyle olabilir:
# Tema dosya yapısı
your-theme/
├── functions.php
├── inc/
│ ├── media-restrictions.php <-- Tüm medya kısıtlama kodları
│ ├── custom-roles.php
│ └── helpers.php
// functions.php içinde
require_once get_template_directory() . '/inc/media-restrictions.php';
Bu yaklaşım kodun bakımını kolaylaştırır. Medya kısıtlama mantığını değiştirmeniz gerektiğinde tek bir dosyaya bakarsınız.
Kısıtlamaları Test Etmek
Kodu yazdıktan sonra test etmek için şu adımları izleyin:
- Tarayıcınızda farklı kullanıcı oturumlarıyla giriş yapın (bir tarayıcıda yönetici, başka bir tarayıcıda normal kullanıcı)
- Normal kullanıcı olarak
/wp-admin/upload.phpadresine gidin, sadece kendi yüklemelerini görüyor mu? - Gönderi düzenleme sayfasında medya kütüphanesini açın, popup’ta da kısıtlama çalışıyor mu?
- Başka bir kullanıcının attachment ID’sini alıp
/wp-admin/post.php?post=XXX&action=editşeklinde URL’e yazın, hata alıyor mu? - Yükleme limitine ulaşan bir kullanıcı hesabıyla dosya yüklemeye çalışın, hata mesajı görünüyor mu?
Hataları wp-content/debug.log dosyasından takip etmek için wp-config.php‘de debug modunu açmayı unutmayın:
// wp-config.php debug ayarları (sadece test ortamında!)
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Performans Açısından Dikkat Edilmesi Gerekenler
pre_get_posts içinde yapılan sorgular yoğun trafik altında yük yaratabilir. Özellikle büyük medya kütüphanelerinde author parametresiyle yapılan filtrelemelerin indekslendiğinden emin olun. WordPress wp_posts tablosundaki post_author sütunu zaten indekslidir ama çok kullanıcılı büyük sitelerde aşağıdaki ek optimizasyonu düşünebilirsiniz:
- Transient kullanarak kullanıcı rol kontrollerini önbelleğe alın
count_user_posts()fonksiyonu her çağrıda veritabanı sorgusu çalıştırır; bunu object cache ile sarmalayın- WP Object Cache kullanıyorsanız (Redis, Memcached) grup bazlı kullanıcı listelerini önbellekte tutun
Sonuç
WordPress medya kütüphanesi kısıtlaması, çok kullanıcılı sitelerin olmazsa olmaz bir güvenlik ve kullanılabilirlik gereksinimi. Eklenti kurmak yerine functions.php’ye eklediğiniz birkaç fonksiyon bu işi tamamen halleder ve sitenize gereksiz eklenti yükü bindirmez.
Özetlemek gerekirse kullandığımız yaklaşımlar şöyle:
- ajax_query_attachments_args: Medya kütüphanesi popup’ını kısıtlar
- pre_get_posts: upload.php sayfasını kısıtlar
- user_has_cap: Yetkisiz düzenleme ve silme işlemlerini engeller
- wp_handle_upload_prefilter: Yükleme limitini uygular
- rest_attachment_query: Gutenberg REST API sorgularını kısıtlar
Her projenin gereksinimleri farklıdır. Basit bir yazar/editör sitesi için sadece ilk iki fonksiyon yeterli olabilir. Ajans kurulumları veya WooCommerce çoklu satıcı siteleri için grup bazlı kısıtlama ve limit yönetimi şart haline gelir. Kodu ihtiyacınıza göre sadeleştirin ya da genişletin; temel mantık değişmeyecektir.
