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

11

Je souhaite télécharger mes tailles d'image personnalisées dans des dossiers personnalisés. Le dossier doit 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 que les images téléchargées soient 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 .

Philipp Kühn
la source

Réponses:

21

Philipp, tout est possible si vous y pensez. Vous pouvez résoudre votre problème en étendant la classe de l'éditeur d'images WordPress.

Remarque J'utilise WordPress 3.7 - Je n'ai vérifié aucun du code ci-dessous dans les versions antérieures et dans la dernière version 3.8.


Notions de base sur 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 s'étendent WP_Image_Editorcar elles utilisent toutes deux un moteur d'image différent (respectivement GD et ImageMagick) 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. La plupart des serveurs partagés n'ont pas l'extension ImageMagick activée.


Ajouter un éditeur d'images

Pour décider quel 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 a également un filtre appelé wp_image_editorsqui vous permet d'ajouter plus d'éditeurs d'images 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 ajoutons notre classe d'édition d'image personnalisée WP_Image_Editor_Customafin 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

Maintenant, nous allons écrire notre propre éditeur d'images afin que nous puissions 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 devons donc remplacer cela dans notre classe personnalisée.

Comme nous ne prévoyons que de changer les noms de fichiers, nous devons étendre l'un des moteurs existants afin de ne pas avoir à réinventer la roue. Je vais développer WP_Image_Editor_GDdans mon exemple, car vous n'avez probablement pas l'extension ImageMagick activée. Le code est cependant interchangeable pour une configuration ImageMagick. Vous pouvez ajouter les deux si vous prévoyez d'utiliser le thème sur 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 WP_Image_Editorclasse et commenté pour votre commodité. Le seul changement réel 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 ce serait plus enclin à mal tourner.


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

Après le téléchargement 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 comme wp_get_attachment_image_src(), nous remarquerons que toutes les tailles d'image sont stockées comme image.jpgsans le nouveau chemin de répertoire.

Nous pouvons contourner ce problème en enregistrant la nouvelle structure de dossiers dans les métadonnées d'image (où les noms de fichiers sont stockés). Les données à travers différents filtres court ( wp_generate_attachment_metadataentre autres) avant d' être insérés dans la base de données, mais étant donné que nous mettons en œuvre déjà un éditeur d'image personnalisée, nous pouvons voyager à la source de métadonnées de taille de l' 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 remplacerons la multi_resize()méthode 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 voir, je n'ai pas pris la peine de remplacer le code. J'appelle simplement la méthode parent et je la laisse générer les métadonnées. Ensuite, je passe en revue le tableau résultant et ajuste la filevaleur pour chaque taille.

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


Dernières pensées

J'espère que cela vous a fourni une bonne base pour développer. Cependant, 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 les tailles d'image sont 280x300, pas 300x300. Si vous téléchargez un grand nombre d'images plus petites, vous obtiendrez de nombreux dossiers différents.

Une bonne solution serait d'utiliser soit la limace de taille comme un nom de dossier ( small, medium, etc.) ou d' étendre le code à des tailles rondes jusqu'à la taille d'image préférée le plus proche.

Vous avez noté que vous souhaitez utiliser uniquement la largeur comme 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.

De plus, vous pouvez supprimer les dossiers année / mois en désactivant «Organiser mes téléchargements dans des dossiers mensuels et annuels» sous Paramètres> Média ou en manipulant generate_filenameencore plus.

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

Robbert
la source
3
Quelle réponse! : D Gentil homme!
Philipp Kühn
1
Vous êtes les bienvenus! Je supposais que vous avez au moins un peu d'expérience en matière de filtrage OOP et WP, mais s'il y a quelque chose que vous ne comprenez pas encore, n'hésitez pas à demander. Merci pour la générosité!
Robbert
2
@Robbert Franchement, c'est génial. J'arrachais mes cheveux au manque d'action et aux crochets de filtre dans le système de téléchargement des médias. Cela semble évident rétrospectivement, mais il ne m'était tout simplement pas venu à l'esprit de remplacer entièrement les éditeurs d'images. Cela résout tellement de problèmes d'un seul coup.
Jonathan Fingland du
1
@JonathanFingland Ha, j'avoue que je devais aller loin dans le terrier du lapin pour celui-ci. Heureux d'avoir pu aider!
Robbert
Petite note - dans la dernière paix de code (fonction publique multi_resize ($ tailles)) le mot-clé "public" rend le site Web en panne. Retirez-le et c'est à nouveau. 2k17 et votre réponse est toujours géniale, merci !!
Paradoxetion du
3

@ 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 séparés. Mon code change également le répertoire de téléchargement en ./media alors assurez-vous de 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 aucun problème selon mes tests, même si je n'ai pas essayé de vérifier comment cela se passe avec les plugins galerie / média populaires.

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

Arty2
la source
1

J'ai regardé ces parties du code WordPress et je crains de ne pas avoir de bonnes nouvelles.

Il y a 2 classes:

  • WP_Image_Editor_GD
  • WP_Image_Editor_Imagick,

les deux étendent la WP_Image_Editorclasse abstraite .

Ces classes implémentent une multi_resizeméthode, qui est utilisée pour générer plusieurs images à partir d'une téléchargée.

La très mauvaise nouvelle est qu'il n'y a aucun crochet de filtre là-dedans, que nous pourrions utiliser pour modifier le chemin de destination des fichiers nouvellement créés.

Krzysiek Dróżdż
la source
C'est une honte. Je voulais implémenter le joli Imager.js mais cela ne fonctionnera probablement pas sans cela.
Philipp Kühn
Il semble que Imager.js rend les images invisibles aux bots (Google, Facebook, etc.), donc je déconseille de l'utiliser (sauf si vous ajoutez également une noscriptbalise manuellement )
fregante
Hmm non je ne pense pas. Vous utilisez normalement img-tags avec un src d'une image. Et vous ajoutez en plus une étiquette de données avec une syntaxe d'autres images-tailles: <img src="http://placehold.it/260" data-src="http://placehold.it/{width}" />. Et puis le script vérifie la taille de l'img et charge la meilleure taille d'image pour cela.
Philipp Kühn
@ PhilippKühn Je suis déçu aussi. Votre idée était plutôt soignée et je voulais l'utiliser pour ranger le répertoire des téléchargements (supprimer les vignettes inutilisées après un changement de thème est
pénible
@ KrzysiekDróżdż Hé, je pense que je l'ai. Regardez ma réponse ci-dessous. Avec cette solution, vous pouvez également trier via ftp les images par nom de fichier et supprimer facilement les tailles d'image inutilisées.
Philipp Kühn
1

Ok, je pense que je l'ai! Pas parfait mais correct pour cela, je le voulais. Pour moi, seule la largeur d'une image est importante. La hauteur est inutile pour moi. Surtout pour implémenter Imager.js, la hauteur dans l'url de l'image est dérangeante.

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 n'est pas possible d'ajouter un sous-dossier aux noms de fichiers, car si j'ajoute des images dans une publication / page, la source d'origine sera toujours utilisée à la place. Et la suppression de ces images lors de la suppression ne fonctionnera pas non plus. Je ne sais pas pourquoi.

Philipp Kühn
la source