Chaque taille d'image personnalisée dans le répertoire de téléchargement personnalisé?

10

Je souhaite télécharger mes tailles d'image personnalisées dans des dossiers personnalisés. Le dossier devrait avoir le nom de la largeur sélectionnée. Par exemple:

Si j'ajoute ces tailles personnalisées ...

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

Il serait bien que les images téléchargées soient téléchargées comme suit:

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

Est-ce possible? J'ai seulement constaté que je pouvais changer le dossier de téléchargement global avec le filtre upload_dir .

    
posée Philipp Kühn 08.12.2013 - 22:29

4 réponses

20

Philipp, tout est possible si vous le souhaitez. Vous pouvez résoudre votre problème en élargissant la classe d’éditeur d’images WordPress.

Remarque: j'utilise WordPress 3.7. Je n'ai vérifié aucun des codes ci-dessous dans les versions précédentes et dans la dernière version 3.8.


Principes de base de l'éditeur d'images

WordPress a deux classes intégrées qui gèrent la manipulation d'images:

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

Ces deux classes étendent WP_Image_Editor car elles utilisent toutes deux un moteur d'image différent (GD et ImageMagick respectivement) pour charger, redimensionner, compresser et enregistrer des images.

Par défaut, WordPress essaiera d’abord d’utiliser le moteur ImageMagick, qui nécessite une extension PHP, car il est généralement préféré au moteur GD par défaut de PHP. L'extension ImageMagick n'est toutefois pas activée sur la plupart des serveurs partagés.


Ajouter un éditeur d'image

Pour choisir le moteur à utiliser, WordPress appelle une fonction interne __wp_image_editor_choose() (située dans /wp-includes/media.php ). Cette fonction parcourt tous les moteurs pour voir quel moteur peut traiter la requête.

La fonction dispose également d'un filtre appelé wp_image_editors qui vous permet d'ajouter d'autres éditeurs d'image, comme ceci:

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

    return $editors;
}

Notez que nous sommes en attente notre classe d'éditeur d'image personnalisée WP_Image_Editor_Custom afin que WordPress vérifie si notre moteur peut gérer le redimensionnement avant de tester d'autres moteurs.


Création de notre éditeur d'images

Nous allons maintenant écrire notre propre éditeur d'image afin de pouvoir choisir nous-même les noms de fichiers. Le nom de fichier est géré par la méthode WP_Image_Editor::generate_filename() (les deux moteurs héritent de cette méthode), nous devrions donc l'écraser dans notre classe personnalisée.

Puisque nous ne prévoyons que de changer de nom de fichier, nous devrions étendre l'un des moteurs existants pour ne pas avoir à réinventer la roue. J'étendrai WP_Image_Editor_GD dans mon exemple, car l'extension ImageMagick n'est probablement pas activée. Le code est toutefois interchangeable pour une configuration ImageMagick. Vous pouvez ajouter les deux si vous prévoyez d'utiliser le thème dans différentes configurations.

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

La plupart du code ci-dessus a été directement copié de la classe WP_Image_Editor et commenté pour votre commodité. Le seul changement effectif est que le suffixe est maintenant un préfixe.

Alternativement, vous pouvez simplement appeler parent::generate_filename() et utiliser un mb_str_replace() pour changer le suffixe en préfixe, mais j’ai pensé que cela serait plus enclin à aller mal.


Enregistrement de nouveaux chemins d'accès aux métadonnées

Après avoir téléchargé image.jpg , le dossier des téléchargements ressemble à ceci:

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

Jusqu'ici tout va bien. Cependant, lorsque vous appelez des fonctions de base telles que wp_get_attachment_image_src() , nous remarquerons que toutes les tailles d’image sont stockées sous le nom image.jpg sans le nouveau chemin de répertoire.

Nous pouvons contourner ce problème en enregistrant la nouvelle structure de dossiers dans les métadonnées de l'image (où sont stockés les noms de fichiers). Les données passent par différents filtres ( wp_generate_attachment_metadata , entre autres) avant d'être insérées dans la base de données, mais puisque nous implémentons déjà un éditeur d'image personnalisé, nous pouvons revenir à la source des métadonnées de taille d'image: WP_Image_Editor::multi_resize() . Il génère des tableaux comme celui-ci:

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

Nous allons écraser la méthode multi_resize() dans notre classe personnalisée:

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

Comme vous pouvez le constater, je n’ai pas pris la peine de remplacer le code. J'appelle simplement la méthode parente et la laisse générer les métadonnées. Ensuite, je parcoure le tableau résultant et ajuste la valeur file pour chaque taille.

Maintenant, wp_get_attachment_image_src($att_id, array(300, 300)) renvoie 2013/12/300x300/image.jpg . Hourra!


Dernières pensées

J'espère que cela vous a fourni une bonne base de travail. Toutefois, veuillez noter que si une image est plus petite que la taille spécifiée (par exemple 280x300), le suffixe généré (préfixe dans notre cas) et la taille des images sont 280x300 et non 300x300. Si vous téléchargez de nombreuses images plus petites, vous obtiendrez de nombreux dossiers différents.

Une bonne solution consiste à utiliser le slug de taille comme nom de dossier ( small , medium , etc.) ou à développer le code pour arrondir la taille à la taille d'image préférée la plus proche.

Vous avez indiqué que vous souhaitiez utiliser uniquement la largeur en tant que nom de répertoire. Soyez averti cependant: des plugins ou des thèmes peuvent générer deux tailles différentes avec la même largeur mais des hauteurs différentes.

De plus, vous pouvez supprimer les dossiers année / mois en désactivant l'option "Organiser mes téléchargements dans des dossiers basés sur un mois et une année" sous Paramètres > Media ou en manipulant generate_filename encore plus loin.

J'espère que cela aide. Bonne chance!

    
réponse donnée Robbert 13.12.2013 - 14:59
3

@ La réponse de Robbert était une ressource divine dans mes efforts pour stocker des formats alternatifs générés par WordPress dans des répertoires distincts. Mon code modifie également le répertoire de téléchargement en ./media. Veillez donc à modifier ces lignes si vous ne le souhaitez pas. Ce n'est pas une réponse exacte à la question de la première affiche, mais une solution alternative au même problème:

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

Fonctionne sans problème selon mes tests, bien que je n’aie pas essayé de vérifier comment il se comportait avec les plugins populaires Gallery / Media.

bonus lié: un utilitaire brut permettant de supprimer toutes les vignettes générées par WordPress delete_deprecated_thumbs.php

    
réponse donnée Arty2 06.03.2014 - 15:13
1

J'ai consulté ces parties du code WordPress et j'ai bien peur de ne pas avoir de bonnes nouvelles.

Il y a 2 classes:

  • WP_Image_Editor_GD
  • WP_Image_Editor_Imagick ,

les deux extensions abstraites WP_Image_Editor class.

Ces classes implémentent la méthode multi_resize , utilisée pour générer plusieurs images à partir d'une image téléchargée.

La très mauvaise nouvelle est qu’il ne contient aucun crochet de filtre, que nous pourrions utiliser pour modifier le chemin de destination des fichiers nouvellement créés.

    
réponse donnée Krzysiek Dróżdż 12.12.2013 - 12:26
1

Ok, je pense que je l’ai compris! Pas parfait, mais d'accord pour ça, je le voulais. Pour moi, seule la largeur d'une image est importante. La taille est inutile pour moi. En particulier pour la mise en œuvre de Imager.js , la hauteur dans l'URL de l'image est inquiétante.

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

Avec ce code, les noms de fichiers sont comme:

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

Il est impossible d'ajouter un sous-dossier aux noms de fichiers, car si j'ajoute des images dans un message / une page, la source d'origine sera toujours utilisée. Et supprimer ces images lors de la suppression ne fonctionnera pas non plus. Je ne sais pas pourquoi.

    
réponse donnée Philipp Kühn 13.12.2013 - 13:21

Lire d'autres questions sur les étiquettes