it-swarm.com.de

Jede benutzerdefinierte Bildgröße im benutzerdefinierten Upload-Verzeichnis?

Ich möchte meine benutzerdefinierten Bildgrößen in benutzerdefinierte Ordner hochladen. Der Ordner sollte den Namen der ausgewählten Breite haben. Zum Beispiel:

Wenn ich diese benutzerdefinierten Größen hinzufüge ...

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

Es wäre schön, wenn die hochgeladenen Bilder so hochgeladen würden:

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

Ist das möglich? Ich habe nur festgestellt, dass ich den globalen Upload-Ordner mit dem Filter upload_dir ändern kann.

11
Philipp Kühn

Philipp, alles ist möglich, wenn du es dir vorstellst. Sie können Ihr Problem lösen, indem Sie die WordPress-Bildbearbeitungsklasse erweitern.

Hinweis: Ich verwende WordPress 3.7. - Ich habe in früheren Versionen und in der neuesten Version 3.8 keinen der folgenden Codes überprüft.


Grundlagen des Bildeditors

WordPress verfügt über zwei integrierte Klassen, die die Bildbearbeitung übernehmen:

  • WP_Image_Editor_Gd (/wp-includes/class-wp-image-editor-Gd.php)
  • WP_Image_Editor_Imagick (/wp-includes/class-wp-image-editor-imagick.php)

Diese beiden Klassen erweitern WP_Image_Editor, da beide eine unterschiedliche Image-Engine (Gd bzw. ImageMagick) zum Laden, Ändern der Größe, Komprimieren und Speichern von Bildern verwenden.

Standardmäßig versucht WordPress zuerst, die ImageMagick-Engine zu verwenden, die eine PHP -Erweiterung benötigt, da sie im Allgemeinen der Standard-Gd-Engine von PHP vorgezogen wird. Bei den meisten freigegebenen Servern ist die ImageMagick-Erweiterung jedoch nicht aktiviert.


Fügen Sie einen Bildeditor hinzu

Um zu entscheiden, welche Engine verwendet werden soll, ruft WordPress eine interne Funktion __wp_image_editor_choose() auf (die sich in /wp-includes/media.php befindet). Diese Funktion durchläuft alle Suchmaschinen, um festzustellen, welche Suchmaschine die Anfrage bearbeiten kann.

Die Funktion hat auch einen Filter namens wp_image_editors, mit dem Sie weitere Bildbearbeitungsprogramme hinzufügen können:

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

    return $editors;
}

Beachten Sie, dass wir vor unserer benutzerdefinierten Bildeditor-Klasse WP_Image_Editor_Custom sind, damit WordPress überprüft, ob unsere Engine Größenänderungen verarbeiten kann, bevor andere Engines getestet werden.


Erstellen unseres Bildeditors

Jetzt schreiben wir unseren eigenen Bildeditor, damit wir die Dateinamen selbst bestimmen können. Der Dateiname wird von der Methode WP_Image_Editor::generate_filename() behandelt (beide Engines erben diese Methode), daher sollten wir diese in unserer benutzerdefinierten Klasse überschreiben.

Da wir nur vorhaben, Dateinamen zu ändern, sollten wir eine der vorhandenen Engines erweitern, damit wir das Rad nicht neu erfinden müssen. Ich werde WP_Image_Editor_Gd in meinem Beispiel erweitern, da Sie wahrscheinlich die ImageMagick-Erweiterung nicht aktiviert haben. Der Code ist jedoch für ein ImageMagick-Setup austauschbar. Sie können beides hinzufügen, wenn Sie das Thema in verschiedenen Setups verwenden möchten.

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

Der größte Teil des obigen Codes wurde direkt aus der Klasse WP_Image_Editor kopiert und zur Vereinfachung kommentiert. Die einzige tatsächliche Änderung besteht darin, dass das Suffix jetzt ein Präfix ist.

Alternativ könnten Sie einfach parent::generate_filename() aufrufen und eine mb_str_replace() verwenden, um das Suffix in ein Präfix zu ändern, aber ich dachte mir, das würde eher schief gehen.


Neue Pfade zu Metadaten speichern

Nach dem Hochladen von image.jpg sieht der Upload-Ordner folgendermaßen aus:

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

So weit, ist es gut. Wenn Sie jedoch grundlegende Funktionen wie wp_get_attachment_image_src() aufrufen, werden alle Bildgrößen als image.jpg ohne den neuen Verzeichnispfad gespeichert.

Sie können dieses Problem umgehen, indem Sie die neue Ordnerstruktur in den Bildmetadaten speichern (in denen die Dateinamen gespeichert sind). Die Daten durchlaufen verschiedene Filter (ua wp_generate_attachment_metadata), bevor sie in die Datenbank eingefügt werden. Da wir jedoch bereits einen benutzerdefinierten Bildeditor implementieren, können wir zur Quelle der Bildgrößen-Metadaten zurückkehren: WP_Image_Editor::multi_resize(). Es generiert Arrays wie dieses:

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

Wir werden die multi_resize() -Methode in unserer benutzerdefinierten Klasse überschreiben:

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

Wie Sie sehen, habe ich keinen Code ausgetauscht. Ich rufe einfach die übergeordnete Methode auf und lasse sie die Metadaten generieren. Dann durchlaufe ich das resultierende Array und passe den Wert file für jede Größe an.

Jetzt gibt wp_get_attachment_image_src($att_id, array(300, 300))2013/12/300x300/image.jpg zurück. Hurra!


Abschließende Gedanken

Ich hoffe, das war eine gute Grundlage, auf der Sie näher eingehen können. Beachten Sie jedoch, dass bei Bildern, die kleiner als die angegebene Größe sind (z. B. 280 x 300), das generierte Suffix (in unserem Fall das Präfix) und die Bildgrößen 280 x 300 und nicht 300 x 300 sind. Wenn Sie viele kleinere Bilder hochladen, erhalten Sie viele verschiedene Ordner.

Eine gute Lösung wäre, entweder den Größenblock als Ordnernamen (small, medium usw.) zu verwenden oder den Code auf runde Größen bis zur nächstbevorzugten Bildgröße zu erweitern.

Sie haben festgestellt, dass Sie nur die Breite als Verzeichnisnamen verwenden möchten. Seien Sie jedoch gewarnt - Plugins oder Designs können zwei verschiedene Größen mit derselben Breite, aber unterschiedlicher Höhe generieren.

Sie können die Jahr/Monat-Ordner auch entfernen, indem Sie unter "Einstellungen"> "Medien" die Option "Meine Uploads in monatlichen und jahresbasierten Ordnern organisieren" deaktivieren oder generate_filename weiter bearbeiten.

Hoffe das hilft. Viel Glück!

21
Robbert

@ Robberts Antwort war eine göttliche Ressource in meinen Bemühungen, alternative Größen, die von WordPress generiert wurden, in separaten Verzeichnissen zu speichern. Mein Code ändert auch das Upload-Verzeichnis in ./media, also stellen Sie sicher, dass Sie diese Zeilen bearbeiten, wenn Sie das nicht möchten. Es ist keine exakte Antwort auf die Frage des ersten Posters, bietet aber eine alternative Lösung für dasselbe Problem:

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

Funktioniert nach meinen Tests problemlos, obwohl ich nicht versucht habe zu überprüfen, wie es mit den gängigen Galerie-/Medien-Plugins abläuft.

verwandter Bonus: ein Rohprogramm zum Löschen aller in WordPress generierten Thumbnails delete_deprecated_thumbs.php

3
Arty2

Ich habe mir diese Teile des WordPress-Codes angesehen und fürchte, ich habe keine guten Nachrichten.

Es gibt 2 Klassen:

  • WP_Image_Editor_Gd
  • WP_Image_Editor_Imagick,

beide erweitern die abstrakte Klasse WP_Image_Editor.

Diese Klassen implementieren die Methode multi_resize, mit der aus einem hochgeladenen mehrere Bilder generiert werden.

Die wirklich schlechte Nachricht ist, dass es keine Filter-Hooks gibt, mit denen wir den Zielpfad für neu erstellte Dateien ändern könnten.

1

Ok, ich glaube ich habe es verstanden! Nicht perfekt, aber okay, dafür wollte ich es. Für mich ist nur die Breite eines Bildes wichtig. Größe ist für mich nutzlos. Besonders für die Implementierung von Imager.js ist die Höhe der Bild-URL störend.

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

Mit diesem Code lauten die Dateinamen wie folgt:

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

Es ist nicht möglich, einen Unterordner zu den Dateinamen hinzuzufügen, da beim Hinzufügen von Bildern in einem Beitrag/einer Seite immer die Originalquelle verwendet wird. Das Entfernen dieser Bilder beim Löschen funktioniert ebenfalls nicht. Ich bin mir nicht sicher warum.

1
Philipp Kühn