Share
Trang chủ / Tất cả hướng dẫn / Lập trình WordPress / Viết plugin Regenerate Thumbnail phần 1

Viết plugin Regenerate Thumbnail phần 1

Hướng dẫn viết plugin regenerate thumbnail image cho WordPress. Các file resize của attachment bị mất sẽ tự động được generate lại.

Trong những ngày tiếp theo đây, chúng ta sẽ không làm điều gì mới mẻ, mà chỉ đơn giản là hiện thực lại một plugin đã có tên tuổi, một plugin có hơn 2 triệu lượt tải kể từ khi nó được release lần đầu tiên, một plugin vô cùng cần thiết mỗi khi bạn chuyển đổi theme hoặc làm những điều điên rồi nào đó với cac file thumbnail của bạn. Và đó chính là plugin Regenerate Thumbnail của tác giả Alex Mills.

Mục đích của plugin

Để giảm dung lượng website khi load ở client, môt trong những việc quan trọng nhất là resize kích thước của ảnh cho phù hợp với mục đích hiển thị của nó, nếu bạn chỉ hiển thị ảnh trên một nơi chỉ có kích thước 100×100 thì thật phí nếu bạn đặt vào đó một ảnh có kích thước 1000×1000 rồi dùng css để giới hạn nó lại. Nên giải pháp tốt nhất là bạn resize ảnh trước khi gửi về cho client để họ tải.

Nhưng nên resize lúc nào nhỉ ? Bạn nên nhớ rằng, để check file tồn tại hay không sẽ mất khá nhiều thời gian, đồng thời để kiểm tra, thì bạn phải có link, làm sao bạn get link ra khỏi tất cả những lần request tới file đó ? bạn phải thông qua 1 bước kiểm tra, mất thời gian nhỉ. Vì vậy giải pháp ở đây là sẽ chỉ generate một lần lúc nó được upload lên thôi, còn những lần sau, không có file ư, kệ bạn. hix, giải pháp dù là an toàn, đáp ứng tốc độ nhanh, nhưng lại có phần vô trách nhiệm với người dùng nhỉ. Sẽ ra sao nếu người dùng táy máy và đi xóa hết các file thumbnail ? Chuyện này ít khi xảy ra, nhưng nó sẽ dễ gặp phải hơn nếu bạn đang phải chạy WordPress trên một gói hosting quá giới hạn về dung lượng, ví dụ như 100mb ? Mỗi khi chuyển theme, các theme khác nhau lại generate ra các kích thước khác nhau, còn các file cũ thì sao, không dùng tới, bạn xóa đi, rồi khi bạn đổi lại theme thì sao, các file không được tạo lại. Và bạn bị mất thumbnail.

Mục đích của plugin này là giúp bạn generate lại các file thumbnail mỗi khi nó bị mất.

Yêu cầu

Dưới đây là các yêu cầu của plugin :

  1. Có trang riêng trong menu media để regenerate nhiều file.
  2. Có nút regenerate ở mỗi file ảnh trong trang media list.
  3. Có thể batch generate

Chuẩn bị

Cũng như bao plugin khác, chúng ta sẽ tạo file plugin ở thư mục wp-content\plugins\regenerate-thumbnails . File regenerate-thumbnails.php có header chưa thông tin plugin như sau :

Plugin Name:  Regenerate Thumbnails
Plugin URI:   http://senviet.org
Description:  Allows you to regenerate all thumbnails after changing the thumbnail sizes.
Version:      1.0.0
Author:       nguyenvanduocit
Author URI:   http://nvduoc.senviet.org/

Hôm nay tạm thời bỏ qua phong cách rườm rà và làm biến của mình, nên mình sẽ không sử dụng scbFramework nữa, mà sẽ tự code thuần luôn, không các bạn lại bảo mình không biết code, thì sẽ làm các bạn bớt tin tưởng các bài viết của mình. Nhưng mà thực sự thì thấy lười thật đấy. Dù sao đi nữa, đặt bút rồi thì chúng ta sẽ bắt đầu thôi.

Bây giờ, bạn truy cập vào mục plugins trong dashboard đã có thể thấy plugin của mình hiện lên rồi. Có thể bạn sẽ thấy thông báo update, vì mình đang code lại plugin đã có mà, nên tên của plugin này trùng với plugin đã có trên WordPress.org, vì vậy WordPress sẽ nghĩ rằng plugin của chúng ta là plugin kia, với phiên bản nhỏ hơn, nên sẽ có thông báo update. Vì vậy nhớ là đừng ấn update nhé.

Tạo class

Dù không dùng framework, nhưng chúng ta thích lập trình hướng đối tượng hơn, thứ nhất là có thể tránh được việc đặt trùng tên các hàm với những pluign khác, thứ hai là nó sẽ đẹp hơn nhiều. Vì vậy ta sẽ tạo class là RegenerateThumbnails trong file regenerate-thumbnails.php

class RegenerateThumbnails {}

Các hàm generate thumbnail

Hàm duy nhất mà chúng ta sử dụng ở đây là :

wp_generate_attachment_metadata

Theo WordPress thì hàm này có chức năng tạo ra metadata cho một image, đồng thời nó cũng tạo ra các file thumbnail và các size khác – các size được register bởi theme và plugin.

Signature và ý nghĩa các tham số như sau :

function wp_generate_attachment_metadata( $attachment_id, $file )

Ý nghĩa của các tham số này như sau :

Tham số Mô tả
$attachment_id Id của attachment, là post có post_type là attachment
$file Dường đẫn tới file attachment

Giá trị trả về của hàm này là một array chứa metadata của attachment. Các element của array này có key và ý nghĩa như sau :

Key Ý nghĩa
width Chiều rộng
height chiều cao
file Đường dẫn tương đối của file, tính từ đường dẫn tới thư mục upload
sizes Chứa thông tin của các size được đăng ký bởi plugin, theme bao gồm : file, width, height
image_meta là array chứa thông tin metadata của attachment

Ví dụ

Giờ chúng ta làm qua một ví dụ cho nóng nhé. Chúng ta sẽ generate metadata và thumbnail, cũng như các size ảnh cho attachment có id là 37 bằng đoạn code sau :

$attach_id = 37;
$fullsizepath = get_attached_file( $image->ID );
$attach_data = wp_generate_attachment_metadata( $image->ID, $fullsizepath );
wp_update_attachment_metadata( $attach_id,  $attach_data );

Chúng ta cần gọi hàm get_attached_file để lấy đường dẫn của file attachment, sau đó gọi hàm wp_generate_attachment_metadata để tạo metadata và generate ra các file ảnh đã resize, cuối cùng là update các thông tin vừa generate vào database.

Viết phương thức regenerate

Tất cả các tính năng trong yêu cầu đều có một thao tác giống nhau là generate metadata, vì vậy việc đầu tiên ta cần làm là viết phương thức này trước. Trong class RegenerateThumbnails chúng ta có phương thức requenerate như sau :

public function regenerate($attachmentId){

	if(!current_user_can('manage_options')){
		return new WP_Error('NOT_PERMISSION', 'Only admin can regenerate image.');
	}
	$post = get_post($attachmentId);
	if(!$post){
		return new WP_Error('POST_NOT_EXIST', 'This postId is not exist.');
	}
	if('attachment' != $post->post_type || !preg_match('!^image/!', get_post_mime_type( $post ) ) ){
		return new WP_Error('NOT_SUPPORT', 'This plugin is only support for image attachment');
	}

	$fullSizePath = get_attached_file( $post->ID );
	if(!file_exists($fullSizePath)){
		return new WP_Error('NOT_DISPLAYABLE', 'This attachment\'s file is not displayable');
	}
	if(!function_exists('wp_generate_attachment_metadata')){
		include( ABSPATH . 'wp-admin/includes/image.php' );
	}
	$metaData = wp_generate_attachment_metadata( $post->ID, $fullSizePath );
	if(is_wp_error($metaData)){
		return $metaData;
	}
	if ( empty( $metaData ) ){
		return new WP_Error('UNKNOW_ERRORR', 'Unknown error !');
	}
	wp_update_attachment_metadata( $post->ID, $metaData );
	return true;;
}

Phương thức này chỉ có một tham số duy nhất là ID của attachment.

Chúng ta chỉ cho phép admin được quyền regenerate vì vậy đầu tiên chúng ta sẽ kiểm tra xem user này có quyền chỉnh sửa option hay không bằng current_user_can(‘manage_options’). manage_options là capability chỉ dành cho admin.

Tiếp theo ta sẽ kiểm tra xem :

  1. id mà user cung cấp có khớp với bài post nào trong database hay không ?
  2. Bài post đó có phải là attachment hay không ?
  3. attachment có phải là image hay không ?
  4. File attachment có tồn tại hay không ?

Nếu mọi thứ ổn thỏa thì chúng ta đã có được id và filepath của attachment, viết tiếp theo là gọi hàm wp_generate_attachment_metadata mà thôi, tuy nhiên hàm này được định nghĩa trong file image.php, file này không phải lúc nào cũng được load. Vì vậy mình cần phải check thêm xem function này có tồn tại không, nên không thì cần include file image.php vào.

Test

Để kiểm tra xem phương thức này có hoạt động hay không, thì chúng ta sẽ thử generate cho một attachment nào đó. Đầu tiên mình sẽ upload một file ảnh lên phần media và lấy id của nó. Sau đó kiểm tra ở thư mục upload sẽ thấy nó tạo ra các file với kích thước khác nhau. Giờ mình sẽ delete các file đã được resize này, giữ lại file gốc.

Sau đó thêm đoạn code này vào cuối file regenerate-thumbnails.php, thay số 4 bằng id mà bnaj lấy được lúc nảy :

add_action('init', 'RT_Init');
function RT_Init(){
	$RegenerateThumbnail = new RegenerateThumbnail();
	$result = $RegenerateThumbnail->regenerate(4);
	var_dump($result);
	wp_die();
}

Giờ vào dashboard và refresh lại. rồi vào thư mục upload để kiểm tra, bạn sẽ thấy các file resize đã được tạo lại như lúc đầu. Như vậy là hàm này đúng. Bước tiếp theo là cần hiện thực các tính năng theo yêu cầu, chủ yếu là xử lý ajax.

Viết tính năng generate ở trang media

Tính năng này sẽ thêm vào một nút “Regenerate meta” ở trang upload.php, khi ấn vào đây, thì plugin sẽ regenerate thumbnail và các size cho ảnh.

Thêm nút regenerate

Chúng ta sẽ thêm nút đó vào giống như sau :

Action link
Action link

Có một hook ở đây là media_row_actions. Hook này sẽ truyền vào cho callback function ba tham số :

Tên Mô tả
$actions Array các đoạn code html của các action
$post Chứa thông tin của post
$detached False nếu attachment chưa được attach vào bất cứ post nào

Code cuối cùng như sau :

public function add_media_row_action( $actions, $post ) {
	if ( !preg_match( '!^image/!', get_post_mime_type( $post ) ) || ! current_user_can( 'manage_options' ) ) {
		return $actions;
	}
	$actions['regenerate_thumbnails'] = '<a data-id="'.$post->ID.'" class="regenerate_thumbnail" href="#" title="' . esc_attr( __( "Regenerate the thumbnails for this single image", 'regenerate-thumbnails' ) ) . '">' . __( 'Regenerate Thumbnails', 'regenerate-thumbnails' ) . '</a>';

	return $actions;
}

Giờ ta cần code js để handle sự kiện click vào link này, bằng cách add một file javascript vào trang upload.php. Bạn tạo file inline.php vào thư mục js với nội dung như sau :

(
    function($){
        $( document ).ready(function() {
            $(document).on('click', '.regenerate_thumbnail', function(){
                alert('Clicked');
            });
        });
    }
)(jQuery);

Giờ ta cần add file này vào phần header của trang upload.php bằng method sau :

public function add_inline_script(){
	$inlineFile = plugins_url('js/inline.js', __FILE__ );
	echo "<script src='".$inlineFile."'></script>";
}

Ta cần phải gọi phương thức này chính xác tại header của page upload.php, ta có thể sử dụng hook admin_head-{$hook_suffix} như sau :

add_action( 'admin_head-upload.php', array( $this, 'add_inline_script' ) );

Generate khi nhận request từ ajax

Giờ ta sẽ sửa file inline.js để thay vì hiển thị alert thì sẽ tạo một request lên server :

$.ajax({
    method: "POST",
    url: ajaxurl ,
    data: {
        action:'regeneratethumbnail',
        attachmentId: postId
    }
 }).success(function( data ) {
        alert(data.message );
});

Cũng cần phải handler từ trong WordPress để bắt ajax request này :

add_action( 'wp_ajax_regeneratethumbnail', array( $this, 'ajax_handler' ) );

Phương thức ajax_handler như sau :

public function ajax_handler(){
	wp_send_json(array('success'=>true,'message'=>'success'));
}

Khi bạn click vào link ‘Generate thumbnails’ trên mỗi item trong media litst trong phần media thì sẽ có một http request được gửi lên server, server sẽ hồi đáp lại một message là “success”, javascript sẽ alert message này lên. Tiếp theo ta cần sửa lại để nó thực hiện việc regenerate.

Nội dung của phương thức ajax_handler sẽ thay đổi thành như sau :

public function ajax_handler(){
	if(!isset($_POST['attachmentId'])){
		wp_send_json(array('success'=>false, 'message'=>'Your have to provice the attachment ID.'));
	}
	$attachmentId = abs($_POST['attachmentId']);
	$result = $this->regenerate($attachmentId);
	if(is_wp_error($result)){
		wp_send_json(array('success'=>false, 'message'=>$result->get_error_message()));

	}
	wp_send_json(array('success'=>true,'message'=>'generate success'));
}

Giờ phương thức này sẽ handle attachment được post lên từ javascript, kiểm tra giá trị của nó và gọi phương thức \RegenerateThumbnail::regenerate để generate lại metadata, file thumbnail và resize cảnh về các kích thước đã được register bởi theme, plugin.

Test

Để test thì bạn upload một file ảnh lên, và vào trang media ( upload.php ) để xem danh sách file, Chọn một file nào đó và xem path dấn đến file của nó, xóa hết các file được resize từ file này. Sau đó bạn vào lại trang media, và lick vào link “generate thumbnail”. Giờ hãy kiểm tra lại thư mục upload, nếu bạn thấy xuất hiện lại các file có tên trùng với file bạn vừa xóa lúc náy nghĩa là bạn đã thành công rồi.

Lời kết

Trong phần đầu tiên này, chúng ta đã có thể cơn bản tạo ra được một plugin cho phép regenerate thumbnail và crop của một attachment dạng image rất nhanh chóng thông qua giao diện của trang media ( upload.php ). ở phần tiếp theo, chúng ta sẽ tìm hiểu về cách tạo batch regenerate. Mời các bạn tiếp tục theo dõi