web-dev-qa-db-fra.com

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

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

Ce serait bien les images téléchargées sont téléchargées comme ceci:

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 .

11
Philipp Kühn

Philipp, tout est possible si tu y tiens. 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.


Notions 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 demande.

La fonction dispose également d'un filtre appelé wp_image_editors qui vous permet d'ajouter plusieurs é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 prepending 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éer notre éditeur d'image

Maintenant, nous allons écrire notre propre éditeur d'image afin de pouvoir décider nous-mêmes des 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.

Comme nous ne prévoyons que de changer de nom de fichier, nous devrions étendre l’un des moteurs existants afin de ne pas avoir à réinventer la roue. Je vais prolonger 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é à partir 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 une 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 vers les métadonnées

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

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

Jusqu'ici tout va bien. Toutefois, lorsque vous appelez des fonctions de base telles que wp_get_attachment_image_src(), nous remarquons 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 comme nous mettons déjà en place 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.

wp_get_attachment_image_src($att_id, array(300, 300)) renvoie maintenant 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 beaucoup d'images plus petites, vous aurez beaucoup de dossiers différents.

Une bonne solution consisterait à utiliser la taille de fichier comme nom de dossier (small, medium, etc.) ou à développer le code pour arrondir les tailles à 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 - les plugins ou les thèmes peuvent générer deux tailles différentes avec la même largeur mais des hauteurs différentes.

En outre, 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 ou une année" sous Paramètres> Médias ou en manipulant encore davantage generate_filename.

J'espère que cela t'aides. Bonne chance!

21
Robbert

La réponse de @ Robbert était une ressource divine dans mes efforts pour stocker des tailles alternatives générées 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 offre 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’ai pas essayé de vérifier comment il se comportait avec les plugins populaires gallery/media.

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

3
Arty2

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 prolongeant la classe abstraite WP_Image_Editor.

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.

1
Krzysiek Dróżdż

Ok, je pense que je l'ai eu! 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. Surtout pour implémenter 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 not possible d'ajouter un sous-dossier aux noms de fichiers, car si j'ajoute des images dans un article/une page, la source originale sera toujours utilisée. Et supprimer ces images lors de la suppression ne fonctionnera pas non plus. Je ne sais pas pourquoi.

1
Philipp Kühn