Setiap ukuran gambar khusus dalam direktori unggahan khusus?

11

Saya ingin mengunggah ukuran gambar khusus saya di folder khusus. Folder harus memiliki nama lebar yang dipilih. Sebagai contoh:

Jika saya menambahkan ukuran khusus ini ...

add_image_size('custom-1', 300, 9999);
add_image_size('custom-2', 400, 9999);

Alangkah baiknya gambar yang diunggah diunggah seperti ini:

http://www.my-site.com/wp-content/uploads/300/my-image.jpg
http://www.my-site.com/wp-content/uploads/400/my-image.jpg

Apakah ini mungkin? Saya hanya menemukan bahwa saya dapat mengubah folder unggah global dengan filter upload_dir .

Philipp Kühn
sumber

Jawaban:

21

Philipp, apa pun mungkin terjadi jika Anda memutuskan untuk melakukannya. Anda dapat mengatasi masalah Anda dengan memperluas kelas editor gambar WordPress.

Catatan Saya menggunakan WordPress 3.7 - Saya belum memeriksa salah satu kode di bawah ini dalam versi sebelumnya dan dalam rilis 3.8 terbaru.


Dasar-dasar Editor Gambar

WordPress memiliki dua kelas bawaan yang menangani manipulasi gambar:

  • WP_Image_Editor_GD( /wp-includes/class-wp-image-editor-gd.php)
  • WP_Image_Editor_Imagick( /wp-includes/class-wp-image-editor-imagick.php)

Kedua kelas ini diperluas WP_Image_Editorkarena keduanya menggunakan mesin gambar yang berbeda (masing-masing GD dan ImageMagick) untuk memuat, mengubah ukuran, mengompres, dan menyimpan gambar.

Secara default WordPress akan mencoba menggunakan mesin ImageMagick terlebih dahulu, yang membutuhkan ekstensi PHP, karena umumnya lebih disukai daripada mesin GD default PHP. Sebagian besar server bersama tidak memiliki ekstensi ImageMagick diaktifkan.


Tambahkan Editor Gambar

Untuk memutuskan mesin mana yang akan digunakan, WordPress memanggil fungsi internal __wp_image_editor_choose()(terletak di /wp-includes/media.php). Fungsi ini melewati semua mesin untuk melihat mesin mana yang dapat menangani permintaan.

Fungsi ini juga memiliki filter bernama wp_image_editorsyang memungkinkan Anda menambahkan lebih banyak editor gambar seperti:

add_filter("wp_image_editors", "my_wp_image_editors");
function my_wp_image_editors($editors) {
    array_unshift($editors, "WP_Image_Editor_Custom");

    return $editors;
}

Perhatikan kami sedang menambahkan kelas editor gambar khusus kami WP_Image_Editor_Customsehingga WordPress akan memeriksa apakah mesin kami dapat menangani pengubahan ukuran sebelum menguji mesin lain.


Membuat Editor Gambar kami

Sekarang kita akan menulis editor gambar kita sendiri sehingga kita dapat memutuskan nama file untuk diri kita sendiri. Nama file ditangani oleh metode WP_Image_Editor::generate_filename()(kedua mesin mewarisi metode ini), jadi kita harus menimpa itu di kelas kustom kami.

Karena kami hanya berencana mengubah nama file, kami harus memperluas salah satu mesin yang ada sehingga kami tidak perlu menemukan kembali kemudi. Saya akan memperluas WP_Image_Editor_GDdalam contoh saya, karena Anda mungkin tidak memiliki ekstensi ImageMagick diaktifkan. Kode ini dapat dipertukarkan untuk pengaturan ImageMagick. Anda dapat menambahkan keduanya jika Anda berencana menggunakan tema pada pengaturan yang berbeda.

// Include the existing classes first in order to extend them.
require_once ABSPATH.WPINC."/class-wp-image-editor.php";
require_once ABSPATH.WPINC."/class-wp-image-editor-gd.php";

class WP_Image_Editor_Custom extends WP_Image_Editor_GD {
    public function generate_filename($prefix = NULL, $dest_path = NULL, $extension = NULL) {
        // If empty, generate a prefix with the parent method get_suffix().
        if(!$prefix)
            $prefix = $this->get_suffix();

        // Determine extension and directory based on file path.
        $info = pathinfo($this->file);
        $dir  = $info['dirname'];
        $ext  = $info['extension'];

        // Determine image name.
        $name = wp_basename($this->file, ".$ext");

        // Allow extension to be changed via method argument.
        $new_ext = strtolower($extension ? $extension : $ext);

        // Default to $_dest_path if method argument is not set or invalid.
        if(!is_null($dest_path) && $_dest_path = realpath($dest_path))
            $dir = $_dest_path;

        // Return our new prefixed filename.
        return trailingslashit($dir)."{$prefix}/{$name}.{$new_ext}";
    }
}

Sebagian besar kode di atas disalin langsung dari WP_Image_Editorkelas dan berkomentar untuk kenyamanan Anda. Satu-satunya perubahan aktual adalah sufiks sekarang menjadi awalan.

Atau, Anda bisa memanggil parent::generate_filename()dan menggunakan mb_str_replace()untuk mengubah akhiran menjadi awalan, tapi saya pikir itu akan lebih cenderung salah.


Menyimpan jalur baru ke metadata

Setelah mengunggah image.jpg, folder unggahan terlihat seperti ini:

  • 2013/12/150x150/image.jpg
  • 2013/12/300x300/image.jpg
  • 2013/12/image.jpg

Sejauh ini bagus. Namun, ketika memanggil fungsi-fungsi dasar seperti wp_get_attachment_image_src(), kami akan melihat semua ukuran gambar disimpan sebagai image.jpgtanpa jalur direktori baru.

Kami dapat mengatasi masalah ini dengan menyimpan struktur folder baru ke metadata gambar (tempat nama file disimpan). Data berjalan melalui berbagai filter ( wp_generate_attachment_metadataantara lain) sebelum dimasukkan ke dalam database, tapi karena kami sudah menerapkan editor gambar kustom, kami dapat melakukan perjalanan kembali ke sumber gambar ukuran metadata: WP_Image_Editor::multi_resize(). Ini menghasilkan array seperti ini:

Array (
    [thumbnail] => Array (
        [file]      => image.jpg
        [width]     => 150
        [height]    => 150
        [mime-type] => image/jpeg
    )

    [medium] => Array (
        [file]      => image.jpg
        [width]     => 300
        [height]    => 300
        [mime-type] => image/jpeg
    )
)

Kami akan menimpa multi_resize()metode di kelas khusus kami:

function multi_resize($sizes) {
    $sizes = parent::multi_resize($sizes);

    foreach($sizes as $slug => $data)
        $sizes[$slug]['file'] = $data['width']."x".$data['height']."/".$data['file'];

    return $sizes;
}

Seperti yang Anda lihat, saya tidak repot-repot mengganti kode apa pun. Saya hanya memanggil metode induk dan membiarkannya menghasilkan metadata. Lalu saya loop melalui array yang dihasilkan dan menyesuaikan filenilai untuk setiap ukuran.

Sekarang wp_get_attachment_image_src($att_id, array(300, 300))kembali 2013/12/300x300/image.jpg. Hore!


Pikiran terakhir

Saya harap ini memberikan dasar yang bagus untuk Anda uraikan. Namun, harap dicatat jika gambar lebih kecil dari ukuran yang ditentukan (mis. 280x300), akhiran yang dihasilkan (awalan dalam kasus kami) dan ukuran gambar 280x300, bukan 300x300. Jika Anda mengunggah banyak gambar yang lebih kecil, Anda akan mendapatkan banyak folder berbeda.

Sebuah solusi yang baik akan baik menggunakan ukuran siput sebagai nama folder ( small, medium, dan sebagainya) atau memperluas kode untuk ukuran putaran hingga ukuran gambar terdekat disukai.

Anda mencatat bahwa Anda ingin menggunakan hanya lebarnya sebagai nama direktori. Berhati-hatilah - plugin atau tema dapat menghasilkan dua ukuran berbeda dengan lebar yang sama tetapi ketinggian berbeda.

Anda juga dapat menghapus folder tahun / bulan dengan menonaktifkan 'Atur unggahan saya ke dalam folder berbasis bulan dan tahun' di bawah Pengaturan> Media atau dengan memanipulasi generate_filenamelebih jauh.

Semoga ini membantu. Semoga berhasil!

Robbert
sumber
3
Jawaban yang sangat bagus! : D Pria yang baik!
Philipp Kühn
1
Sama-sama! Saya berasumsi Anda setidaknya memiliki sedikit pengalaman filter OOP dan WP, tetapi jika ada sesuatu yang Anda belum mengerti, jangan ragu untuk bertanya. Terima kasih atas hadiahnya!
Robbert
2
@Robbert Frankly, ini brilian. Saya mencabuti rambut saya karena kurangnya tindakan dan filter kait dalam sistem unggah media. Tampak jelas dalam retrospeksi, tetapi tidak terpikir oleh saya untuk menimpa editor gambar sepenuhnya. Melakukan hal itu memecahkan begitu banyak masalah dalam satu gerakan.
Jonathan Fingland
1
@ JonathanFingland Ha, saya akui saya harus pergi jauh ke lubang kelinci untuk yang ini. Senang bisa membantu!
Robbert
Catatan kecil - dalam kedamaian terakhir dari kode (fungsi publik multi_resize ($ ukuran)) kata kunci "publik" membuat situs web turun. Hapus saja dan terserah lagi. 2k17 dan jawaban Anda masih luar biasa, terima kasih !!
Paradoxetion
3

Jawaban @ Robbert adalah sumber daya ilahi dalam upaya saya untuk menyimpan ukuran alternatif yang dihasilkan oleh WordPress di direktori terpisah. Kode saya juga mengubah direktori unggah menjadi ./media jadi pastikan untuk mengedit baris ini jika Anda tidak menginginkannya. Ini bukan jawaban yang tepat untuk pertanyaan poster pertama, tetapi menawarkan solusi alternatif untuk masalah yang sama:

if ( !is_multisite() ) {
    update_option( 'upload_path', 'media' ); //to-do: add to options page
    define( 'UPLOADS', 'media' ); //define UPLOADS dir - REQUIRED
}
//don't “Organize my uploads into month- and year-based folders”
update_option( 'uploads_use_yearmonth_folders', '0' ); // to-do: add to options page

//create a custom WP_Image_Editor that handles the naming of files
function tect_image_editors($editors) {
    array_unshift( $editors, 'WP_Image_Editor_tect' );

    return $editors;
}

add_filter( 'wp_image_editors', 'tect_image_editors' );

require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';

class WP_Image_Editor_tect extends WP_Image_Editor_GD {
    public function multi_resize($sizes) {
        $sizes = parent::multi_resize($sizes);

        $media_dir = trailingslashit( ABSPATH . UPLOADS );

        foreach($sizes as $slug => $data) {
            $default_name = $sizes[ $slug ]['file'];
            $new_name = $slug . '/' . preg_replace( '#-\d+x\d+\.#', '.', $data['file'] );

            if ( !is_dir( $media_dir . $slug ) ) {
                mkdir( $media_dir . $slug );
            }
            //move the thumbnail - perhaps not the smartest way to do it...
            rename ( $media_dir . $default_name, $media_dir . $new_name );

            $sizes[$slug]['file'] = $new_name;
        }

        return $sizes;
    }
}

Bekerja tanpa masalah menurut tes saya, meskipun saya belum mencoba memeriksa bagaimana harganya dengan galeri / plugin media populer.

bonus terkait: utilitas mentah untuk menghapus semua thumbnail yang dihasilkan WordPress delete_deprecated_thumbs.php

Arty2
sumber
1

Saya telah melihat bagian-bagian kode WordPress ini dan saya khawatir saya tidak punya kabar baik.

Ada 2 kelas:

  • WP_Image_Editor_GD
  • WP_Image_Editor_Imagick,

keduanya memperluas WP_Image_Editorkelas abstrak .

Kelas-kelas ini adalah multi_resizemetode implementasi , yang digunakan untuk menghasilkan beberapa gambar dari yang diunggah.

Berita buruknya adalah tidak ada kait filter di sana, yang bisa kita gunakan untuk memodifikasi jalur tujuan untuk file yang baru dibuat.

Krzysiek Dróżdż
sumber
Itu memalukan. Saya ingin menerapkan Imager.js yang bagus tapi itu mungkin tidak akan berhasil tanpa itu.
Philipp Kühn
Sepertinya Imager.js membuat gambar tidak terlihat oleh bot (Google, Facebook, dll), oleh karena itu saya menyarankan untuk tidak menggunakannya (kecuali jika Anda juga secara manual menambahkan noscripttag)
fregante
Hmm tidak, saya kira tidak. Anda biasanya menggunakan img-tag dengan src gambar. Dan Anda menambahkan tambahan data-tag dengan sintaks lainnya gambar-ukuran: <img src="http://placehold.it/260" data-src="http://placehold.it/{width}" />. Dan kemudian skrip memeriksa ukuran img yang mana dan memuat ukuran gambar terbaik untuk itu.
Philipp Kühn
@ PhilippKühn saya kecewa juga. Gagasan Anda cukup rapi dan saya ingin menggunakannya untuk merapikan direktori unggahan (menghapus thumbnail yang tidak terpakai setelah perubahan tema terasa menyakitkan di ...)
Krzysiek Dróżdż
@ KrzysiekDróżdż Hei, saya rasa saya mengerti. Lihatlah jawaban saya di bawah ini. Dengan solusi ini Anda juga dapat mengurutkan melalui ftp gambar berdasarkan nama file dan dengan mudah menghapus ukuran gambar yang tidak digunakan.
Philipp Kühn
1

Ok, saya pikir saya mengerti! Tidak sempurna tapi oke untuk ini saya menginginkannya. Bagi saya hanya lebar gambar yang penting. Tinggi tidak berguna bagi saya. Khusus untuk mengimplementasikan Imager.js ketinggian di url gambar mengganggu.

add_filter('image_make_intermediate_size', 'custom_rename_images');

function custom_rename_images($image) {
    // Split the $image path
    $info = pathinfo($image);
    $dir = $info['dirname'] . '/';
    $ext = '.' . $info['extension'];
    $name = wp_basename($image, '$ext');

    // New Name
    $name_prefix = substr($name, 0, strrpos($name, '-'));
    $size_extension = substr($name, strrpos($name, '-') + 1);
    $image_sizes = explode('x', $size_extension);
    $image_width = $image_sizes[0];
    $new_name = $dir . $image_width . '-' . $name_prefix . $ext;

    // Rename the intermediate size
    $did_it = rename($image, $new_name);

    // Return if successful
    if ($did_it) return $new_name;

    // Return on fail
    return $image;
}

Dengan kode ini, nama berkasnya seperti:

http://www.my-site.com/wp-content/uploads/300-my-image.jpg
http://www.my-site.com/wp-content/uploads/400-my-image.jpg

Ini tidak mungkin untuk menambahkan subfolder untuk nama file, karena jika saya menambahkan gambar di posting / halaman selalu sumber asli akan digunakan sebagai gantinya. Dan menghapus gambar-gambar ini pada penghapusan juga tidak akan berfungsi. Saya tidak yakin mengapa.

Philipp Kühn
sumber