Ogni dimensione dell'immagine personalizzata nella directory di caricamento personalizzata?


11

Voglio caricare le dimensioni delle mie immagini personalizzate in cartelle personalizzate. La cartella dovrebbe avere il nome della larghezza selezionata. Per esempio:

Se aggiungo queste dimensioni personalizzate ...

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

Sarebbe bello che le immagini caricate siano caricate in questo modo:

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

È possibile? Ho scoperto solo che posso cambiare la cartella di caricamento globale con il filtro upload_dir .

Risposte:


21

Philipp, tutto è possibile se ci pensi. Puoi risolvere il tuo problema estendendo la classe dell'editor di immagini di WordPress.

Nota Sto usando WordPress 3.7 - Non ho controllato nessuno dei codici seguenti nelle versioni precedenti e nell'ultima versione 3.8.


Nozioni di base di Image Editor

WordPress ha due classi integrate che gestiscono la manipolazione delle immagini:

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

Queste due classi si estendono WP_Image_Editorperché utilizzano entrambe un motore di immagine diverso (rispettivamente GD e ImageMagick) per caricare, ridimensionare, comprimere e salvare le immagini.

Per impostazione predefinita, WordPress proverà a utilizzare prima il motore ImageMagick, che necessita di un'estensione PHP, perché è generalmente preferito al motore GD predefinito di PHP. La maggior parte dei server condivisi non ha l'estensione ImageMagick abilitata però.


Aggiungi un editor di immagini

Per decidere quale motore utilizzare, WordPress chiama una funzione interna __wp_image_editor_choose()(situata in /wp-includes/media.php). Questa funzione scorre in tutti i motori per vedere quale motore può gestire la richiesta.

La funzione ha anche un filtro chiamato wp_image_editorsche ti consente di aggiungere altri editor di immagini in questo modo:

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

    return $editors;
}

Nota che stiamo anteponendo la nostra classe di editor di immagini personalizzata in WP_Image_Editor_Custommodo che WordPress controllerà se il nostro motore può gestire il ridimensionamento prima di testare altri motori.


Creazione del nostro editor di immagini

Ora scriveremo il nostro editor di immagini in modo da poter decidere da soli i nomi dei file. Il nome del file è gestito dal metodo WP_Image_Editor::generate_filename()(entrambi i motori ereditano questo metodo), quindi dovremmo sovrascriverlo nella nostra classe personalizzata.

Poiché prevediamo solo di cambiare i nomi dei file, dovremmo estendere uno dei motori esistenti in modo da non dover reinventare la ruota. Estenderò WP_Image_Editor_GDnel mio esempio, poiché probabilmente non hai abilitato l'estensione ImageMagick. Tuttavia, il codice è intercambiabile per una configurazione di ImageMagick. È possibile aggiungere entrambi se si prevede di utilizzare il tema su diverse configurazioni.

// 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 maggior parte del codice sopra è stato copiato direttamente dalla WP_Image_Editorclasse e commentato per tua comodità. L'unica modifica effettiva è che il suffisso è ora un prefisso.

In alternativa, potresti semplicemente chiamare parent::generate_filename()e usare un mb_str_replace()per cambiare il suffisso in un prefisso, ma ho pensato che sarebbe stato più propenso a sbagliare.


Salvataggio di nuovi percorsi per i metadati

Dopo il caricamento image.jpg, la cartella dei caricamenti è simile alla seguente:

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

Fin qui tutto bene. Tuttavia, quando si chiamano funzioni di base come wp_get_attachment_image_src(), noteremo che tutte le dimensioni dell'immagine sono memorizzate come image.jpgsenza il nuovo percorso della directory.

Possiamo aggirare questo problema salvando la nuova struttura di cartelle nei metadati dell'immagine (dove sono memorizzati i nomi dei file). Le piste di dati attraverso i vari filtri ( wp_generate_attachment_metadatatra gli altri) prima di essere inseriti nel database, ma dal momento che stiamo già implementando un editor di immagini su misura, siamo in grado di tornare indietro alla fonte dei metadati dimensioni dell'immagine: WP_Image_Editor::multi_resize(). Genera array come questo:

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

Sovrascriveremo il multi_resize()metodo nella nostra classe personalizzata:

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

Come puoi vedere, non mi sono preoccupato di sostituire alcun codice. Chiamo solo il metodo parent e lascio che generi i metadati. Quindi eseguo il ciclo attraverso l'array risultante e modifico il filevalore per ogni dimensione.

Ora wp_get_attachment_image_src($att_id, array(300, 300))ritorna 2013/12/300x300/image.jpg. Evviva!


Pensieri finali

Spero che questo abbia fornito una buona base per approfondire. Tuttavia, si noti che se un'immagine è più piccola della dimensione specificata (ad es. 280x300), il suffisso generato (prefisso nel nostro caso) e le dimensioni dell'immagine sono 280x300, non 300x300. Se carichi molte immagini più piccole, otterrai molte cartelle diverse.

Una buona soluzione sarebbe o utilizzare per lo spezzone formato come un nome di cartella ( small, medium, eccetera) o espandere il codice a dimensioni tondi fino alla dimensione dell'immagine preferita vicina.

Hai notato che vuoi usare solo la larghezza come nome di directory. Attenzione però: plugin o temi potrebbero generare due dimensioni diverse con la stessa larghezza ma altezze diverse.

Inoltre, puoi rimuovere le cartelle anno / mese disabilitando "Organizza i miei caricamenti in cartelle basate su mese e anno" in Impostazioni> Media o manipolando generate_filenameulteriormente.

Spero che questo ti aiuti. In bocca al lupo!


3
Che risposta! : D Bravo uomo!
Philipp Kühn,

1
Prego! Supponevo che tu avessi almeno un po 'di esperienza nei filtri OOP e WP, ma se c'è qualcosa che non capisci ancora, sentiti libero di chiedere. Grazie per la generosità!
Robbert,

2
@Robbert Francamente, questo è geniale. Mi stavo strappando i capelli per la mancanza di azione e ganci del filtro nel sistema di caricamento dei media. Sembra ovvio in retrospettiva, ma semplicemente non mi era venuto in mente di ignorare del tutto gli editor di immagini. In questo modo si risolvono così tanti problemi in un colpo solo.
Jonathan Fingland,

1
@JonathanFingland Ah, devo ammettere che dovevo andare molto lontano nella tana del coniglio per questo. Felice di essere di aiuto!
Robbert,

Piccola nota - nell'ultima pace del codice (funzione pubblica multi_resize ($ dimensioni)) la parola chiave "pubblico" rende il sito Web inattivo. Basta rimuoverlo ed è di nuovo su. 2k17 e la tua risposta è ancora fantastica, grazie !!
Paradosso

3

La risposta di @ Robbert è stata una risorsa divina nei miei sforzi per memorizzare dimensioni alternative generate da WordPress in directory separate. Il mio codice cambia anche la directory di upload in ./media, quindi assicurati di modificare queste righe se non lo desideri. Non è una risposta esatta alla domanda del primo poster, ma offre una soluzione alternativa allo stesso problema:

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

Funziona senza problemi secondo i miei test, anche se non ho provato a controllare come funziona con i plug-in della galleria / media popolari.

bonus correlati: un'utilità non elaborata per eliminare tutte le miniature generate da WordPress delete_deprecated_thumbs.php


1

Ho guardato queste parti del codice WordPress e temo di non avere buone notizie.

Ci sono 2 classi:

  • WP_Image_Editor_GD
  • WP_Image_Editor_Imagick,

entrambi estendono la WP_Image_Editorclasse astratta .

Queste classi stanno implementando il multi_resizemetodo, che viene utilizzato per generare più immagini da una caricata.

La brutta notizia è che non ci sono hook di filtro, che potremmo usare per modificare il percorso di destinazione per i file appena creati.


È un peccato. Volevo implementare il simpatico Imager.js ma probabilmente non funzionerà senza quello.
Philipp Kühn,

Sembra che Imager.js renda le immagini invisibili ai bot (Google, Facebook, ecc.), Quindi sconsiglio di usarlo (a meno che tu non aggiunga anche manualmente un noscripttag)
fregante

Hmm no, non la penso così. Normalmente usi img-tags con un src di un'immagine. E si aggiunge inoltre un data-tag con una sintassi di altre immagini-dimensioni: <img src="http://placehold.it/260" data-src="http://placehold.it/{width}" />. E poi lo script controlla quale dimensione ha l'img e carica la migliore dimensione dell'immagine per quello.
Philipp Kühn,

@ PhilippKühn Anche io sono deluso. La tua idea è stata abbastanza chiara e volevo usarla per riordinare la directory dei caricamenti (eliminare le miniature inutilizzate dopo che il cambio di tema è doloroso ...)
Krzysiek Dróżdż

@ KrzysiekDróżdż Ehi, penso di averlo capito. Guarda la mia risposta qui sotto. Con questa soluzione puoi anche ordinare via ftp le immagini in base al nome del file e rimuovere facilmente le dimensioni dell'immagine inutilizzate.
Philipp Kühn,

1

Ok, penso di averlo capito! Non perfetto ma va bene per questo, lo desideravo. Per me è importante solo la larghezza di un'immagine. L'altezza è inutile per me. Soprattutto per l'implementazione di Imager.js l'altezza nell'URL dell'immagine è inquietante.

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

Con questo codice i nomi dei file sono come:

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

E ' non è possibile aggiungere una sottocartella per i nomi dei file, perché se posso aggiungere immagini in un post / pagina sempre la fonte originale sarà usato al posto. E anche la rimozione di queste immagini durante l'eliminazione non funzionerà. Non sono sicuro del perché.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.