Xử lý hình ảnh phát sinh trong WordPress

Xử lý hình ảnh phát sinh trong WordPress

Đối với một số theme bạn thực hiện với đoạn code sau

<?php
// Ngăn WP tạo thêm size cho tất cả ảnh khi upload
add_filter( ‘intermediate_image_sizes_advanced’, function( $sizes ) {
// Xóa hết size mặc định
return [];
});

// Chỉ generate size khi ảnh được chọn làm Featured Image
function ww_featured_image_generate_sizes( $metadata, $attachment_id ) {
$is_featured = false;

// Kiểm tra xem ảnh này có đang được chọn làm Featured Image của post nào không
$args = array(
‘post_type’ => ‘any’,
‘meta_key’ => ‘_thumbnail_id’,
‘meta_value’ => $attachment_id,
‘posts_per_page’ => 1,
);
$posts = get_posts( $args );

if ( ! empty( $posts ) ) {
$is_featured = true;
}

// Nếu đúng là Featured Image thì generate lại các size mặc định
if ( $is_featured ) {
require_once ABSPATH . ‘wp-admin/includes/image.php’;
$file = get_attached_file( $attachment_id );
$metadata = wp_generate_attachment_metadata( $attachment_id, $file );
wp_update_attachment_metadata( $attachment_id, $metadata );
}

return $metadata;
}
add_filter( ‘wp_generate_attachment_metadata’, ‘ww_featured_image_generate_sizes’, 10, 2 );

Trong đó:

  • 10 → là priority (độ ưu tiên) của filter:  Mặc định là 10. Số càng nhỏ thì hook chạy càng sớm, số càng lớn thì chạy muộn. Ví dụ: add_filter( …, …, 5 ) thì sẽ chạy trước add_filter( …, …, 10 ).
  • 2 → là số lượng arguments (tham số) mà filter function sẽ nhận: Hook intermediate_image_sizes_advanced trong WordPress trả về 2 tham số: $sizes → danh sách kích thước ảnh trung gian (mảng). $metadata → metadata của ảnh đang xử lý (bao gồm đường dẫn file gốc). Nếu bạn để 1 thì function chỉ nhận $sizes thôi. Để 2 thì function nhận đủ cả $sizes và $metadata.

Tóm lại:

  • Gắn filter với priority = 10 (mức mặc định).
  • Hàm callback sẽ nhận đủ 2 tham số từ hook.

Cách kiểm tra

1. Cài mã vào functions.php của child theme.

2. Clear cache (nếu dùng object cache/CDN).

3. Test 1 — Upload 1 ảnh mới (không gán làm featured):

  • Sau upload, kiểm tra trong thư mục /wp-content/uploads/yyyy/mm/ xem có file resized (150×150, 300×200…) hay không. Kết quả mong muốn: Chỉ có file gốc (ví dụ img.jpg) — không có img-150×150.jpg.

4. Test 2 — Set ảnh đó làm Featured Image cho 1 post:

  • Sau khi set featured, kiểm tra lại folder: WP phải sinh ra các bản resized (thumbnail, medium, large, và các sizes custom theme).
  • Kiểm tra trong Media Library -> File URL và kiểm tra metadata: sẽ có sizes với các keys.

5. Nếu dùng regenerates / plugin tối ưu ảnh: tắt chúng trong lúc test vì chúng có thể tự sinh/ sửa metadata.

Với đoạn code trên nếu không hoạt động hãy thử code plugin sau:

<?php
/**
* Plugin Name: Generate Image Sizes Only For Featured Image (Robust)
* Description: Prevent WP from generating image sizes on upload. Only generate sizes when an attachment becomes a post’s featured image — using a custom generator that bypasses other filters.
* Version: 1.0
* Author: 110site
*/

if ( ! defined( ‘ABSPATH’ ) ) {
exit;
}

class WW_Featured_Image_Generator_Robust {

public static function init() {
// Chặn WP tự động tạo các size khi upload
add_filter( ‘intermediate_image_sizes_advanced’, array( __CLASS__, ‘block_intermediate_on_upload’ ), 9999 );

// Bắt các sự kiện đặt featured image bằng nhiều cách (classic, Gutenberg, REST)
add_action( ‘set_post_thumbnail’, array( __CLASS__, ‘on_set_post_thumbnail’ ), 10, 2 );
add_action( ‘added_post_meta’, array( __CLASS__, ‘on_added_post_meta’ ), 10, 4 );
add_action( ‘updated_post_meta’, array( __CLASS__, ‘on_updated_post_meta’ ), 10, 4 );

// (tùy) admin notice để biết plugin active
add_action( ‘admin_notices’, array( __CLASS__, ‘admin_notice’ ) );
}

/**
* Luôn trả về rỗng để chặn WP tạo ảnh resized mặc định khi upload.
*/
public static function block_intermediate_on_upload( $sizes ) {
// luôn chặn để tránh WP auto-generate
return array();
}

/**
* Khi featured image được thiết lập bằng set_post_thumbnail()
*/
public static function on_set_post_thumbnail( $post_id, $attachment_id ) {
self::maybe_generate_sizes( $attachment_id );
}

/**
* Khi meta _thumbnail_id được thêm hoặc cập nhật (bắt Gutenberg/REST)
*/
public static function on_added_post_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
if ( ‘_thumbnail_id’ === $meta_key ) {
self::maybe_generate_sizes( (int) $meta_value );
}
}
public static function on_updated_post_meta( $meta_id, $object_id, $meta_key, $meta_value ) {
if ( ‘_thumbnail_id’ === $meta_key ) {
self::maybe_generate_sizes( (int) $meta_value );
}
}

/**
* Kiểm tra nếu attachment chưa có sizes thì generate
*/
protected static function maybe_generate_sizes( $attachment_id ) {
if ( empty( $attachment_id ) ) {
return;
}

$meta = wp_get_attachment_metadata( $attachment_id );
if ( ! empty( $meta ) && ! empty( $meta[‘sizes’] ) ) {
self::log( “Attachment $attachment_id already has sizes. Skipping.” );
return;
}

self::generate_sizes_manual( $attachment_id );
}

/**
* Tự tạo các bản resized cho attachment (bypass wp_generate_attachment_metadata)
*/
protected static function generate_sizes_manual( $attachment_id ) {
$file = get_attached_file( $attachment_id );
if ( ! $file || ! file_exists( $file ) ) {
self::log( “File not found for attachment $attachment_id: $file” );
return;
}

// tăng timeout/memory tạm
@set_time_limit( 0 );
@ini_set( ‘memory_limit’, ‘512M’ );

// kiểm tra image editor
$editor = wp_get_image_editor( $file );
if ( is_wp_error( $editor ) ) {
self::log( “Image editor error for $file: ” . $editor->get_error_message() );
return;
}

$size_orig = $editor->get_size();
if ( empty( $size_orig ) || empty( $size_orig[‘width’] ) ) {
// fallback: getimagesize
$info = @getimagesize( $file );
if ( $info ) {
$size_orig = array( ‘width’ => $info[0], ‘height’ => $info[1] );
} else {
self::log( “Cannot determine original image size for $file” );
return;
}
}

$upload_dir = wp_get_upload_dir();
$relative = ltrim( str_replace( trailingslashit( $upload_dir[‘basedir’] ), ”, $file ), ‘/’ );

$metadata = array(
‘file’ => $relative,
‘width’ => (int) $size_orig[‘width’],
‘height’ => (int) $size_orig[‘height’],
‘sizes’ => array(),
‘image_meta’ => wp_read_image_metadata( $file ),
);

// Lấy tên các size đã đăng ký
$sizes_to_make = self::get_registered_image_sizes(); // array name => array(width,height,crop)

foreach ( $sizes_to_make as $name => $s ) {
$w = (int) $s[‘width’];
$h = (int) $s[‘height’];
$crop = ! empty( $s[‘crop’] );

// bỏ qua các size vô nghĩa
if ( $w <= 0 && $h <= 0 ) {
continue;
}

// Nếu requested size lớn hơn ảnh gốc và uploader không cho phóng to, skip
if ( $w > $metadata[‘width’] && $h > $metadata[‘height’] ) {
// một số site vẫn muốn upscale, nhưng ta skip để tránh ảnh mờ
continue;
}

// Tạo size bằng hàm WP helper
$res = image_make_intermediate_size( $file, $w, $h, $crop );
if ( $res && isset( $res[‘file’] ) ) {
$metadata[‘sizes’][ $name ] = array(
‘file’ => $res[‘file’],
‘width’ => isset( $res[‘width’] ) ? (int) $res[‘width’] : $w,
‘height’ => isset( $res[‘height’] ) ? (int) $res[‘height’] : $h,
‘mime-type’ => get_post_mime_type( $attachment_id ),
);
self::log( “Created size $name for attachment $attachment_id -> ” . $res[‘file’] );
} else {
self::log( “Failed to create size $name for $attachment_id (maybe original smaller than target).” );
}
}

// Cập nhật metadata
wp_update_attachment_metadata( $attachment_id, $metadata );
self::log( “Updated metadata for attachment $attachment_id.” );
}

/**
* Trả về danh sách các size đã đăng ký (bao gồm default & add_image_size)
* Kết quả: name => array(‘width’=>..,’height’=>..,’crop’=>..)
*/
protected static function get_registered_image_sizes() {
global $_wp_additional_image_sizes;

$sizes = array();

$registered = get_intermediate_image_sizes(); // tên các size

foreach ( $registered as $size ) {
if ( in_array( $size, array( ‘thumbnail’, ‘medium’, ‘large’, ‘medium_large’, ‘post-thumbnail’ ), true ) ) {
$w = (int) get_option( “{$size}_size_w”, 0 );
$h = (int) get_option( “{$size}_size_h”, 0 );
$crop = false;
if ( ‘thumbnail’ === $size || ‘post-thumbnail’ === $size ) {
$crop = (bool) get_option( ‘thumbnail_crop’, 0 );
}
$sizes[ $size ] = array( ‘width’ => $w, ‘height’ => $h, ‘crop’ => $crop );
} elseif ( isset( $_wp_additional_image_sizes[ $size ] ) ) {
$sizes[ $size ] = array(
‘width’ => (int) $_wp_additional_image_sizes[ $size ][‘width’],
‘height’ => (int) $_wp_additional_image_sizes[ $size ][‘height’],
‘crop’ => ! empty( $_wp_additional_image_sizes[ $size ][‘crop’] ),
);
}
}

return $sizes;
}

protected static function log( $msg ) {
if ( defined( ‘WP_DEBUG’ ) && WP_DEBUG ) {
error_log( ‘[WW-FEATURED-ROBUST] ‘ . $msg );
}
}

public static function admin_notice() {
if ( ! current_user_can( ‘manage_options’ ) ) {
return;
}
// Uncomment to show a small admin notice
// echo ‘<div class=”notice notice-info is-dismissible”><p>WW Featured Image Generator (robust) is active.</p></div>’;
}
}

WW_Featured_Image_Generator_Robust::init();

Hướng dẫn cài & kiểm tra

1/ Tạo plugin: tạo thư mục /wp-content/plugins/generate-featured-only/, tạo file generate-featured-only.php, dán code ở trên.

2/ Kích hoạt plugin từ Dashboard → Plugins.

3/ Tắt tạm plugin nén ảnh (ShortPixel/Smush/Imagify) nếu bạn đang bật — để tránh xung đột lúc test.

4/ Test upload: upload 1 ảnh mới qua Media → Add New.

  • Kiểm tra thư mục /wp-content/uploads/YYYY/MM/ trên server: kết quả mong muốn: chỉ có file gốc (ví dụ photo.jpg) — không có file photo-150×150.jpg…

5/ Test set Featured Image: vào 1 post → Set Featured Image bằng ảnh vừa upload.

  • Sau khi set, kiểm tra folder /uploads/ — plugin phải tạo ra các bản resized theo các size đã đăng ký (thumbnail, medium, large hoặc các custom sizes của theme).

6/ Xem metadata: vào Media Library → click vào ảnh → kiểm tra phần File URL & Attachment Details. Bạn cũng có thể var_dump( wp_get_attachment_metadata($id) ) tạm trong code để debug.

7/ Kiểm tra logs: nếu không thấy resized xuất hiện, bật WP_DEBUG và WP_DEBUG_LOG trong wp-config.php:

define(‘WP_DEBUG’, true);
define(‘WP_DEBUG_LOG’, true);
define(‘WP_DEBUG_DISPLAY’, false);

Sau đó xem file wp-content/debug.log (hoặc server error_log) để đọc các thông báo của plugin.

Nguyên nhân thường gặp nếu vẫn không hoạt động (và cách khắc phục)

  • Image editor không có (GD/Imagick) → wp_get_image_editor() trả lỗi. Kiểm tra với host hoặc phpinfo; yêu cầu ít nhất một trong hai.
  • Quyền ghi (file permissions): thư mục wp-content/uploads phải writable bởi webserver (owner/www-data, mode 755/775). Nếu không, WP không thể lưu file mới.
  • Plugin khác can thiệp: một số plugin “image optimization” hoặc “disable media generation” có thể gây xung đột. Tạm disable các plugin liên quan rồi test.
  • Theme quá kì lạ: nếu theme dùng các kích thước tùy biến được tạo động khác, hãy chắc theme đã add_image_size() trước khi bạn set featured — plugin lấy kích thước dựa trên get_intermediate_image_sizes().
  • Ảnh quá lớn gây OOM/timeout: tăng tạm memory_limit và max_execution_time hoặc resize ảnh trước khi upload.

Hoặc đơn giản bạn loại trừ hình ảnh ngay từ trước khi upload bằng cách đặt tên cho file hình. Ví dụ ở đây tôi để file hình có featured thì code như sau:

<?php
if ( ! defined( ‘ABSPATH’ ) ) exit;

// Filter chặn image sizes nếu file upload không có “featured” trong tên
add_filter( ‘intermediate_image_sizes_advanced’, function( $sizes, $metadata ) {
$file = isset( $metadata[‘file’] ) ? $metadata[‘file’] : ”;
if ( strpos( strtolower( $file ), ‘featured’ ) === false ) {
return []; // không tạo size
}
return $sizes; // tạo bình thường
}, 10, 2 );

Kết quả nhận được:

  • Khi upload ảnh bình thường (dùng trong bài viết) → đặt tên file như hình.jpg → WordPress không tạo thêm file resize.
  • Khi upload ảnh muốn làm Featured Image → đặt tên file như featured-hình.jpg → WordPress sẽ generate đủ các size mà theme cần.

Hãy thử ngay và xem kết quả nhé!

24/7

                       hỗ trợ zalo cong dong web
Liên hệ
Hỗ trợ 24/7