Кожен розмір зображення у власному каталозі завантаження?


11

Я хочу завантажити власні розміри зображень у спеціальні папки. Папка повинна мати ім'я вибраної ширини. Наприклад:

Якщо я додаю ці власні розміри ...

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

Було б добре, що завантажені зображення завантажуються так:

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

Чи можливо це? Я лише виявив, що можу змінити глобальну папку завантаження за допомогою фільтра upload_dir .

Відповіді:


21

Філіппе, все можливе, якщо ти налаштовуєшся на це. Ви можете вирішити свою проблему, розширивши клас редактора зображень WordPress.

Примітка. Я використовую WordPress 3.7 - я не перевіряв жодного з наведених нижче кодів у попередніх версіях та в останній версії 3.8.


Основи редактора зображень

У WordPress є два вбудовані класи, які обробляють зображення:

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

Ці два класи поширюються, WP_Image_Editorоскільки обидва використовують інший механізм зображення (GD та ImageMagick відповідно) для завантаження, зміни розміру, стискання та збереження зображень.

За замовчуванням WordPress спершу спробує використати двигун ImageMagick, якому потрібне розширення PHP, оскільки він, як правило, кращий перед двигуном GD за замовчуванням PHP. У більшості спільних серверів не ввімкнено розширення ImageMagick.


Додайте редактор зображень

Щоб вирішити, який двигун використовувати, WordPress викликає внутрішню функцію __wp_image_editor_choose()(розташовану в /wp-includes/media.php). Ця функція проходить через усі двигуни, щоб побачити, який двигун може обробити запит.

У функції також є фільтр під назвою, wp_image_editorsякий дозволяє додавати більше редакторів зображень на зразок:

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

    return $editors;
}

Зверніть увагу , що ми випереджаючи наш користувальницький клас редактора зображень , WP_Image_Editor_Customтак що WordPress перевірятиме , якщо наш двигун може обробляти зміна розміру перед тестуванням інших двигунів.


Створення нашого редактора зображень

Тепер ми запишемо власний редактор зображень, щоб ми могли самі вирішувати назви файлів. Ім'я файлів обробляється методом WP_Image_Editor::generate_filename()(обидва двигуни успадковують цей метод), тому нам слід перезаписати це в нашому спеціальному класі.

Оскільки ми плануємо лише змінити імена файлів, нам слід розширити один із існуючих двигунів, щоб нам не довелося винаходити колесо. Я продовжую WP_Image_Editor_GDв своєму прикладі, оскільки у вас, ймовірно, не ввімкнено розширення ImageMagick. Код є взаємозамінним для налаштування ImageMagick. Ви можете додати обидва, якщо плануєте використовувати тему в різних налаштуваннях.

// 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}";
    }
}

Більшість наведених вище кодів було скопійовано безпосередньо з WP_Image_Editorкласу та прокоментовано для вашої зручності. Єдина фактична зміна полягає в тому, що суфікс тепер є префіксом.

Крім того, ви можете просто зателефонувати parent::generate_filename()та використати a, mb_str_replace()щоб змінити суфікс на префікс, але я вважав, що це буде більш схильне піти не так.


Збереження нових шляхів до метаданих

Після завантаження image.jpgпапка завантажень виглядає приблизно так:

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

Все йде нормально. Однак при виклику основних функцій, як-от wp_get_attachment_image_src(), ми помітимо, що всі розміри зображень зберігаються як image.jpgбез нового шляху до каталогу.

Ми можемо вирішити цю проблему, зберігаючи нову структуру папок у метадані зображення (де зберігаються назви файлів). Траси даних через різні фільтри ( wp_generate_attachment_metadataсеред інших), перш ніж вставити в базу даних, але так як ми вже реалізуємо користувальницькі редактор зображень, ми можемо повернутися назад до джерела метаданих розміру зображення: WP_Image_Editor::multi_resize(). Він генерує такі масиви:

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
    )
)

Ми перезапишемо multi_resize()метод у нашому спеціальному класі:

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;
}

Як бачите, я не заважав замінювати будь-який код. Я просто закликаю батьківський метод і нехай він генерує метадані. Потім я перебираю отриманий масив і коригую fileзначення для кожного розміру.

Тепер wp_get_attachment_image_src($att_id, array(300, 300))повертається 2013/12/300x300/image.jpg. Ура!


Заключні думки

Я сподіваюсь, що це стало гарною основою для вашої роботи. Однак, зверніть увагу, якщо зображення менше вказаного розміру (наприклад, 280x300), згенерований суфікс (у нашому випадку префікс) та розміри зображення - 280x300, а не 300x300. Якщо ви завантажите багато менших зображень, ви отримаєте безліч різних папок.

Хороше рішення було б використовувати або кулі розміру в якості імені папки ( small, medium, і так далі) або розширити код для круглих розмірів до найближчого кращого розміру зображення.

Ви зазначили, що хочете використовувати саме ширину як ім'я каталогу. Але будьте попереджені - плагіни або теми можуть генерувати два різних розміри з однаковою шириною, але різної висоти.

Крім того, ви можете видалити папки року / місяця, відключивши "Впорядкувати мої завантаження в папки на місяць та рік" у розділі Налаштування> Медіа або generate_filenameще більше маніпулюючи .

Сподіваюсь, це допомагає. Удачі!


3
Яка відповідь! : D Гарний чоловік!
Philipp Kühn

1
Ласкаво просимо! Я припускав, що у вас є хоча б трохи досвіду фільтра OOP та WP, але якщо ви ще нічого не розумієте, запитайте. Дякую за щедрість!
Роберт

2
@ Роберт Чесно кажучи, це геніально. Я виривав волосся у зв'язку з відсутністю дії та гачками фільтру в системі завантаження медіа. Це здається очевидним в ретроспективі, але мені просто не спало на думку повністю редагувати графічні редактори. Це вирішує стільки проблем одним махом.
Джонатан Фінгленд

1
@JonathanFingland Ha, я визнаю, що для цього я повинен був зайти далеко за кролячим отвором. Радий допомогти!
Роберт

Невелика примітка - з останнього коду (загальнодоступна функція multi_resize ($ розміри)) ключове слово "public" призупиняє веб-сайт. Просто вийміть її, і вона знову встане. 2k17, і ваша відповідь все ще приголомшлива, дякую !!
Парадоксація

3

@ Відповідь Роберта була божественним ресурсом у моїх намаганнях зберігати альтернативні розміри, створені WordPress, в окремих каталогах. Мій код також змінює каталог завантажень на ./media, тому обов'язково відредагуйте ці рядки, якщо цього не хочете. Це не точна відповідь на запитання першого афіші, але пропонує альтернативне рішення тієї ж проблеми:

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;
    }
}

Згідно з моїми тестами, це працює без проблем, хоча я не намагався перевірити, як вона працює з популярними галереями / медіа-плагінами.

пов’язаний бонус: необроблена утиліта для видалення всіх створених WordPress ескізів delete_deprecated_thumbs.php


1

Я переглянув ці частини WordPress-коду і боюся, що у мене немає хороших новин.

Є 2 класи:

  • WP_Image_Editor_GD
  • WP_Image_Editor_Imagick,

обидва розширення абстрактного WP_Image_Editorкласу.

Ці класи - multi_resizeметод реалізації , який використовується для генерації декількох зображень із завантаженого.

Дійсно погана новина полягає в тому, що там немає жодних фільтр-гаків, які ми могли б використовувати для зміни шляху призначення для новостворених файлів.


Це ганьба. Я хотів реалізувати приємний Imager.js, але це, мабуть, не вийде.
Philipp Kühn

Схоже, Imager.js робить зображення невидимими для ботів (Google, Facebook тощо), тому я б радив не використовувати його (якщо ви також не додаєте noscriptтег вручну )
fregante

Хм ні, я не думаю. Зазвичай ви використовуєте img-теги з src зображення. І додати додатково дата-тег з синтаксисом інших образів-розмірів: <img src="http://placehold.it/260" data-src="http://placehold.it/{width}" />. Потім сценарій перевіряє, який розмір має img, і завантажує найкращий розмір зображення для цього.
Філіп Кюн

@ PhilippKühn Я теж розчарований. Ваша ідея була досить акуратною, і я хотів використати її, щоб привести в порядок каталог завантажень (видалення невикористаних ескізів після зміни теми болить у ...)
Krzysiek Dróżdż

@ KrzysiekDróżdż Ей, я думаю, я це отримав. Подивіться на мою відповідь нижче. За допомогою цього рішення ви також можете сортувати зображення через ftp за назвою файлу та легко видаляти невикористані розміри зображень.
Philipp Kühn

1

Гаразд, я думаю, я це отримав! Не ідеально, але гаразд для цього я цього хотів. Для мене важлива лише ширина зображення. Висота для мене марна. Спеціально для впровадження Imager.js висота в URL- адресі зображення заважає.

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;
}

З цим кодом назви файлів виглядають так:

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

Це НЕ можливо додати вкладений в імена файлів, тому що якщо я розміщувати зображення в запису / сторінках завжди першоджерело буде використовуватися замість цього. І видалити ці зображення при видаленні також не вийде. Я не впевнений, чому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.