چند سال پیش، در یک پروژه فروشگاهی با بیست هزار محصول، مدیر سایت شکایت داشت که کتابخانه رسانه پیشخوان، هفت دقیقه طول می‌کشد تا باز شود. وقتی به سراغ دیتابیس رفتم، متوجه شدم از بیست هزار تصویر محصول، بیست هزار فایل هم به‌عنوان «attachment» ثبت شده، ولی متادیتای تصویر برای نیمی از آن‌ها وجود ندارد. یعنی هر بار که کتابخانه رسانه باز می‌شود، وردپرس برای هر تصویر، یک کوئری جداگانه به جدول wp_postmeta می‌زند تا اندازه‌ها را پیدا کند، و نتیجه‌ای هم نمی‌گیرد. بازسازی متادیتا با یک اسکریپت ساده، زمان بارگذاری را از هفت دقیقه به بیست ثانیه کاهش داد. آن پروژه به من یاد داد که مدیریت رسانه در وردپرس، فقط آپلود و نمایش نیست؛ یک لایه داده‌ای کامل با متادیتا، اندازه‌ها، و روابط است که اگر بی‌نظم بماند، بزرگ‌ترین بدهی فنی سایت می‌شود.

در این مقاله، تجربه‌ام از کار با توابع رسانه وردپرس را با شما به اشتراک می‌گذارم. اگر با مفاهیم پایه آشنا نیستید، وردپرس چیست و چگونه شروع کنیم و نحوه استفاده از توابع وردپرس در پروژه‌ها پیش‌نیاز این مقاله است. مکمل این مقاله توابع کار با فایل و توابع تصویر شاخص است.

رسانه در وردپرس: بیش از یک فایل

در وردپرس، هر تصویر یا فایل آپلود‌شده، دو موجودیت جداگانه است:

  • فایل فیزیکی: در پوشه wp-content/uploads/ ذخیره می‌شود و روی دیسک سرور است.
  • ضمیمه (Attachment): یک ردیف در جدول wp_posts با نوع attachment که به فایل اشاره می‌کند.

رابطه این دو، از طریق متادیتا برقرار می‌شود. اگر این ساختار را درک کنید، درک توابع رسانه بسیار ساده‌تر می‌شود. راهنمای کامل در توابع داده‌های نوشته و ساختار فایل‌های قالب استاندارد.

در وردپرس، «تصویر» یعنی یک ردیف در دیتابیس، حتی اگر فایلش گم شده باشد. این نکته، ریشه بسیاری از باگ‌های کتابخانه رسانه است.

دریافت اطلاعات یک ضمیمه

توابع پایه برای دریافت اطلاعات ضمیمه:

$attachment_id = 123;

// شیء کامل ضمیمه
$attachment = get_post( $attachment_id );

// فیلدهای کلیدی
echo $attachment->post_title;         // عنوان
echo $attachment->post_mime_type;     // نوع فایل
echo $attachment->post_parent;        // نوشته والد
echo $attachment->guid;               // آدرس فایل

// اطلاعات فایل
$file_path = get_attached_file( $attachment_id );
$file_url  = wp_get_attachment_url( $attachment_id );

// نوع MIME
$mime = get_post_mime_type( $attachment_id );

نکته: guid برای ضمیمه‌ها، آدرس فایل است ولی در وردپرس، «guid» جایگاه قانونی URL نیست؛ برای URL واقعی، از wp_get_attachment_url استفاده کنید. راهنمای کامل در توابع مدیریت رسانه‌ها و توابع متادیتا.

نمایش تصویر با wp_get_attachment_image

تابع اصلی برای نمایش تصویر، wp_get_attachment_image است:

echo wp_get_attachment_image(
    $attachment_id,
    "medium",
    false,
    array(
        "class"   => "my-image",
        "loading" => "lazy",
        "alt"     => esc_attr( get_post_meta( $attachment_id, "_wp_attachment_image_alt", true ) ),
    )
);

پارامترهای کلیدی: یک — اندازه: thumbnail، medium، large، full یا اندازه سفارشی. دو — پارامتر سوم: آیکون برای فایل‌های غیرتصویری. سه — پارامتر چهارم: ویژگی‌های HTML.

مزیت این تابع نسبت به چاپ مستقیم تگ <img>: یک — srcset خودکار: وردپرس به‌طور خودکار srcset و sizes اضافه می‌کند. دو — alt از متادیتا: اگر alt در متادیتا باشد، به‌طور خودکار اعمال می‌شود. سه — سازگاری با افزونه‌ها: افزونه‌های بهینه‌سازی تصویر می‌توانند این خروجی را فیلتر کنند. راهنمای کامل در سئوی تصویر چیست و قالب ریسپانسیو چیست.

دریافت URL تصویر در اندازه‌های مختلف

برای گرفتن URL تصویر در یک اندازه مشخص:

// URL تصویر در اندازه medium
$url = wp_get_attachment_image_url( $attachment_id, "medium" );

// URL تصویر در اندازه سفارشی
$url_custom = wp_get_attachment_image_url( $attachment_id, "card-thumb" );

// آرایه کامل اطلاعات
$src = wp_get_attachment_image_src( $attachment_id, "large" );
// $src = array( url, width, height, is_intermediate );

// srcset برای ریسپانسیو
$srcset = wp_get_attachment_image_srcset( $attachment_id, "large" );
$sizes  = wp_get_attachment_image_sizes( $attachment_id, "large" );

نکته مهم: اگر اندازه سفارشی تعریف کرده‌اید ولی تصویر قدیمی است، این تابع ممکن است false برگرداند. راه‌حل: بازسازی تصاویر با افزونه مثل Regenerate Thumbnails. راهنمای کامل در بهترین افزونه‌های بهینه‌سازی تصویر و فشرده‌سازی تصاویر سایت.

دریافت متادیتای تصویر

متادیتای تصویر، شامل اندازه‌ها، ابعاد و اطلاعات EXIF است:

$metadata = wp_get_attachment_metadata( $attachment_id );

echo $metadata["width"];      // عرض اصلی
echo $metadata["height"];     // ارتفاع اصلی
echo $metadata["file"];       // مسیر نسبی فایل
echo $metadata["filesize"];   // حجم فایل (در نسخه‌های جدید)
echo $metadata["image_meta"]; // اطلاعات EXIF
$sizes = $metadata["sizes"];  // آرایه اندازه‌ها

// دسترسی به یک اندازه خاص
if ( isset( $sizes["medium"] ) ) {
    echo $sizes["medium"]["width"];
    echo $sizes["medium"]["file"];
}

نکته: متادیتای تصویر در wp_postmeta با کلید _wp_attachment_metadata ذخیره می‌شود. اگر متادیتا خراب یا گم شده باشد، راه‌حل بازسازی با wp_generate_attachment_metadata است:

require_once ABSPATH . "wp-admin/includes/image.php";
$metadata = wp_generate_attachment_metadata( $attachment_id, get_attached_file( $attachment_id ) );
wp_update_attachment_metadata( $attachment_id, $metadata );

راهنمای متادیتا در توابع متادیتا و کار با متاباکس‌ها.

آپلود تصویر با wp_handle_upload

برای آپلود فایل از front-end یا افزونه اختصاصی:

function myplugin_upload_media() {
    // بررسی نانس
    if ( ! isset( $_POST["myplugin_nonce"] ) || 
         ! wp_verify_nonce( $_POST["myplugin_nonce"], "myplugin_upload" ) ) {
        wp_die( "درخواست نامعتبر" );
    }
    
    // بررسی دسترسی
    if ( ! current_user_can( "upload_files" ) ) {
        wp_die( "دسترسی غیرمجاز" );
    }
    
    // آپلود فایل
    require_once ABSPATH . "wp-admin/includes/file.php";
    require_once ABSPATH . "wp-admin/includes/image.php";
    require_once ABSPATH . "wp-admin/includes/media.php";
    
    $attachment_id = media_handle_upload( "myfile", 0 );
    
    if ( is_wp_error( $attachment_id ) ) {
        wp_die( "خطا: " . esc_html( $attachment_id->get_error_message() ) );
    }
    
    wp_send_json_success( array( "id" => $attachment_id ) );
}

نکته حیاتی: تابع media_handle_upload، هم فایل را آپلود می‌کند، هم ضمیمه می‌سازد، هم متادیتا را تولید می‌کند. این تابع، جایگزین تمیزتری برای wp_handle_upload + wp_insert_attachment است. راهنمای کامل در توابع کار با فایل.

ساخت ضمیمه دستی

گاهی نیاز داریم فایلی که قبلاً آپلود شده را به‌عنوان ضمیمه ثبت کنیم:

$file_path = WP_CONTENT_DIR . "/uploads/2024/01/my-image.jpg";
$file_url  = content_url( "/uploads/2024/01/my-image.jpg" );
$file_type = wp_check_filetype( basename( $file_path ), null );

$attachment = array(
    "guid"           => $file_url,
    "post_mime_type" => $file_type["type"],
    "post_title"     => sanitize_file_name( basename( $file_path ) ),
    "post_content"   => "",
    "post_status"    => "inherit",
);

$attachment_id = wp_insert_attachment( $attachment, $file_path );

if ( ! is_wp_error( $attachment_id ) ) {
    require_once ABSPATH . "wp-admin/includes/image.php";
    $metadata = wp_generate_attachment_metadata( $attachment_id, $file_path );
    wp_update_attachment_metadata( $attachment_id, $metadata );
}

نکته: post_status برای ضمیمه‌ها معمولاً inherit است، یعنی وضعیت ارثی از نوشته والد. راهنمای کامل در توابع ایجاد و حذف نوشته.

حذف ضمیمه

حذف ضمیمه، با wp_delete_attachment انجام می‌شود:

wp_delete_attachment( $attachment_id, true );
// پارامتر دوم true = حذف فایل فیزیکی هم

نکته: اگر پارامتر دوم را false بگذارید، فقط ردیف دیتابیس حذف می‌شود ولی فایل روی دیسک می‌ماند. در اکثر پروژه‌ها، می‌خواهید فایل هم حذف شود. راهنمای حذف با بررسی دسترسی در PHP امن در وردپرس.

لیست رسانه‌های یک نوشته

برای دریافت تمام فایل‌های ضمیمه یک نوشته:

$attachments = get_attached_media( "image", $post_id );

foreach ( $attachments as $attachment ) {
    echo wp_get_attachment_image( $attachment->ID, "thumbnail" );
}

نوع اول: image، video، audio، یا نوع MIME مشخص. راهنمای کامل در توابع مدیریت رسانه‌ها.

گالری تصویر

وردپرس از دو روش گالری پشتیبانی می‌کند: شورت‌کد قدیمی و بلوک گالری گوتنبرگ. دریافت گالری یک نوشته:

// دریافت تصاویر گالری از محتوای نوشته
$gallery_images = get_post_gallery_images( $post_id );

foreach ( $gallery_images as $image_url ) {
    printf( "<img src="%s" />", esc_url( $image_url ) );
}

نکته: get_post_gallery_images شورت‌کد گالری را می‌خواند. برای گالری گوتنبرگ، باید بلوک را پارس کنید. راهنمای گوتنبرگ در گوتنبرگ و آینده ویرایش محتوا و ساخت بلوک سفارشی گوتنبرگ.

ساختار کلاس‌محور برای گالری سفارشی

در پروژه‌های جدی، گالری سفارشی با کلاس اختصاصی:

class My_Plugin_Gallery {
    public static function render( $attachments, $columns = 3 ) {
        if ( empty( $attachments ) ) {
            return;
        }
        
        echo "<div class="my-gallery grid-cols-" . intval( $columns ) . "">";
        
        foreach ( $attachments as $attachment ) {
            $image = wp_get_attachment_image(
                $attachment->ID,
                "large",
                false,
                array( "class" => "gallery-item" )
            );
            
            $url = wp_get_attachment_url( $attachment->ID );
            
            printf(
                "<a href="%s" class="gallery-link" data-id="%d">%s</a>",
                esc_url( $url ),
                (int) $attachment->ID,
                $image
            );
        }
        
        echo "</div>";
    }
}

مزیت این ساختار: امکان سفارشی‌سازی کامل، escape امن، و یک نقطه دسترسی برای کل پروژه. الگوهای مشابه در کدنویسی اختصاصی افزونه و اصول کدنویسی تمیز.

اندازه‌های تصویر

وردپرس به‌طور پیش‌فرض چند اندازه تصویر می‌سازد. می‌توانید اندازه سفارشی اضافه کنید:

add_action( "after_setup_theme", function() {
    add_image_size( "card-thumb", 400, 260, true );    // برش دقیق
    add_image_size( "hero-image", 1600, 800, true );
    add_image_size( "square-thumb", 300, 300, true );
} );

نکته: پارامتر چهارم (true): برش دقیق (crop). بدون آن، تصویر با حفظ نسبت در حداکثر ابعاد ذخیره می‌شود. بازسازی: پس از افزودن اندازه جدید، تصاویر قبلی باید بازسازی شوند. راهنمای کامل در توابع تصویر شاخص و افزونه‌های بهینه‌سازی تصویر.

حذف اندازه‌های اضافه

اگر می‌خواهید اندازه‌های پیش‌فرض وردپرس را حذف کنید (برای کاهش فضای دیسک):

add_filter( "intermediate_image_sizes", function( $sizes ) {
    return array_intersect( $sizes, array( "thumbnail", "medium", "large" ) );
} );

// یا غیرفعال کردن کامل
add_filter( "intermediate_image_sizes", "__return_empty_array" );

نکته مهم: قبل از حذف اندازه، مطمئن شوید که هیچ‌جای سایت از آن استفاده نمی‌کند. یک تجربه میدانی: در پروژه‌ای، مدیر سایت اندازه medium_large را حذف کرد و بعد از دو هفته، متوجه شد که بخشی از پست‌ها به آن اشاره می‌کنند و تصاویر نمایش داده نمی‌شوند. راهنمای حذف اندازه در بهینه‌سازی کد وردپرس.

کار با رسانه‌ها در گوتنبرگ

در ویرایشگر گوتنبرگ، آپلود تصویر مستقیم انجام می‌شود و نیازی به کد نیست. اما در افزونه‌های اختصاصی، می‌توانید از کتابخانه رسانه وردپرس استفاده کنید:

// در جاوااسکریپت پیشخوان
var mediaFrame = wp.media({
    title: "انتخاب تصویر",
    button: { text: "انتخاب" },
    multiple: false,
});

mediaFrame.on( "select", function() {
    var attachment = mediaFrame.state().get( "selection" ).first().toJSON();
    console.log( attachment.url );
});

mediaFrame.open();

راهنمای کامل در ساخت بلوک سفارشی گوتنبرگ و گوتنبرگ و آینده ویرایش محتوا.

امنیت در مدیریت رسانه

پنج قاعده الزامی:

  1. بررسی MIME واقعی فایل: پسوند کافی نیست، باید MIME واقعی چک شود. راهنمای کامل در اعتبارسنجی داده‌ها.
  2. محدودیت حجم فایل: در فایل wp-config.php و در تنظیمات سرور. راهنمای کاهش مصرف منابع هاست.
  3. بررسی دسترسی در آپلود: current_user_can( "upload_files" ).
  4. نانس در فرم آپلود: خطر CSRF. راهنمای نانس وردپرس.
  5. پاک‌سازی نام فایل: sanitize_file_name برای جلوگیری از Path Traversal.
$safe_name = sanitize_file_name( $_FILES["myfile"]["name"] );

// بررسی MIME واقعی
$finfo = finfo_open( FILEINFO_MIME_TYPE );
$mime = finfo_file( $finfo, $_FILES["myfile"]["tmp_name"] );
finfo_close( $finfo );

$allowed = array( "image/jpeg", "image/png", "image/webp" );
if ( ! in_array( $mime, $allowed, true ) ) {
    wp_die( "نوع فایل مجاز نیست" );
}

راهنمای کامل در PHP امن در وردپرس، پاک‌سازی داده‌ها و امنیت وردپرس برای مبتدیان.

بهینه‌سازی رسانه

پرتکرارترین کاربرد توابع رسانه در پروژه‌های حرفه‌ای، بهینه‌سازی است. سه گام:

  1. فشرده‌سازی فایل‌های موجود: فشرده‌سازی تصاویر سایت و افزونه‌های بهینه‌سازی تصویر.
  2. انتخاب فرمت مناسب: بهترین فرمت تصویر وب و WebP یا JPEG.
  3. اصلاح اندازه‌ها: استفاده از srcset و اندازه‌های مناسب.

راهنمای کل بهینه‌سازی در بهینه‌سازی سرعت سایت و افزایش سرعت سایت وردپرسی.

متادیتای EXIF و حریم خصوصی

تصاویر دوربین، اطلاعات EXIF شامل موقعیت مکانی GPS دارند. وردپرس به‌طور پیش‌فرض این اطلاعات را نگه می‌دارد. اگر می‌خواهید حذف کنید:

add_filter( "wp_read_image_metadata", function( $metadata, $file ) {
    unset( $metadata["latitude"] );
    unset( $metadata["longitude"] );
    unset( $metadata["GPS"] );
    return $metadata;
}, 10, 2 );

راهنمای حریم خصوصی در امنیت وردپرس.

مدیریت گالری ووکامرس

در ووکامرس، گالری محصول با توابع اختصاصی مدیریت می‌شود:

$product = wc_get_product( $product_id );
$gallery_ids = $product->get_gallery_image_ids();

foreach ( $gallery_ids as $image_id ) {
    echo wp_get_attachment_image( $image_id, "woocommerce_thumbnail" );
}

راهنمای کامل در سفارشی‌سازی صفحه محصول ووکامرس و افزونه‌های کاربردی ووکامرس.

پاک‌سازی رسانه‌های بدون استفاده

در سایت‌های چندساله، رسانه‌های بدون استفاده، بخش بزرگی از فضای دیسک را می‌خورند:

function myplugin_find_unused_media() {
    global $wpdb;
    
    $sql = "
        SELECT p.ID
        FROM {$wpdb->posts} p
        WHERE p.post_type = "attachment"
          AND p.post_parent = 0
          AND p.ID NOT IN (
              SELECT meta_value FROM {$wpdb->postmeta}
              WHERE meta_key = "_thumbnail_id"
          )
        LIMIT 100
    ";
    
    return $wpdb->get_col( $sql );
}

نکته: این کوئری ساده، فقط تصاویر شاخص را چک می‌کند. یک راه‌حل کامل، نیاز به جستجوی محتوا دارد. راهنمای کامل در پاک‌سازی دیتابیس وردپرس، بهینه‌سازی کوئری‌های MySQL و توابع کوئری سفارشی.

اشتباهات رایج

جمع‌بندی

توابع مدیریت رسانه در وردپرس، چهار گروه اصلی دارند: دریافت (get_post، get_attached_media، wp_get_attachment_url)، نمایش (wp_get_attachment_image، wp_get_attachment_image_src)، ثبت (wp_insert_attachment، media_handle_upload)، و حذف (wp_delete_attachment). سه اصل را در پایان تاکید می‌کنم: اول، همیشه از wp_get_attachment_image به‌جای چاپ مستقیم تگ <img> استفاده کنید. دوم، امنیت آپلود را با نانس، بررسی دسترسی و MIME واقعی جدی بگیرید. سوم، رسانه‌های بدون استفاده را دوره‌ای پاک‌سازی کنید.

اگر امروز یک کار در این مسیر انجام می‌دهید: به کتابخانه رسانه سایت خود نگاه کنید و ببینید آیا تعداد تصاویر بدون متادیتا زیاد است. اگر بله، یک اسکریپت بازسازی متادیتا بنویسید. اگر تجربه‌ای از یک باگ در مدیریت رسانه دارید که با تابع درست حل شد، در دیدگاه‌ها بنویسید — همان گزارش‌های واقعی، این راهنما را برای توسعه‌دهنده بعدی دقیق‌تر می‌کند. 🖼️