Administrer le quatrième format d’images de WordPress

Le sujet des images dans WordPress peut être sensible surtout quand on se préoccupe un peu de son espace disque 😅

Si on laisse de côté les thèmes premium et leur mille formats d’images générés pour pas grand chose (je hais les thèmes premium !) , il faut savoir que lorsqu’on téléverse une image dans WordPress ce dernier va par défaut en créer quatre autres.
Même s’il vous semble que l’administration WordPress vous offre la possibilité de préciser vos tailles d’images : « Taille des miniatures », « Taille moyenne » et « Grande taille », WordPress gère en fait une quatrième taille medium_large qu’il utilise pour les images responsives 🤔

Si vous avez loupé ce détail datant du 22 décembre 2015 (version 4.4 de WordPress), voici l’article qui y fait référence : Responsive Images in WordPress 4.4.

Du coup, en parcourant le code du cœur, il est facile de trouver dans wp-admin/includes/schema.php les deux options qui font référence à la taille de cette image :

// 4.4.0
'medium_large_size_w' => 768,
'medium_large_size_h' => 0,

Je n’ai pas poussé jusqu’à trouver le ticket qui fait référence à ce choix de 768px mais je suis presque sûr que c’est parce que cela correspond à la largeur CSS d’un Ipad 😆
Quel malheur 😥

Comme j’ai pu être mauvaise langue 😜 en disant que je n’avais jamais rien trouvé dans le codex au sujet de ce format, je m’en excuse car tout y est, il suffit d’ouvrir les yeux : Featured Images & Post Thumbnails

Bon bé maintenant qu’on est au courant, il ne reste plus qu’à nous offrir la possibilité de préciser les dimensions maximales (en pixels) à utiliser pour ce fameux format « Medium-large » comme ci-dessous.

La première chose à faire est de rajouter les champs de saisie au bon endroit :

/**
 * Adds a new field into the media settings page to manage
 * the fourth image size: "Medium Large".
 *
 * Introduced by WordPress 4.4, this format has by default a `768px` width
 * and is used for responsive images (through the `srcset` attribute).
 * I know that it's not a good idea to define `srcset` and `size`
 * attributes according to this site breakpoint
 * (cf.: )
 * but as WP handles this format (and uses space disc) without telling us,
 * we should be able to edit it to enjoy it even for one of our breakpoints.
 *
 * If you want to escape this format, you just have to set its width
 * and height to zero ;)
 */
function thistle_add_medium_large_size_settings() {
    add_settings_field(
        'medium_large_size',
        __( 'Large size' ),
        '_thistle_output_medium_large_size_settings',
        'media',
        'default',
        array()
    );
}

function _thistle_output_medium_large_size_settings() {
    ?>
    <fieldset>
        <legend class="screen-reader-text">
            <span><?php _e( 'Large size' ); ?></span>
        </legend>
        <label for="medium_large_size_w"><?php _e( 'Max Width' ); ?></label>
        <input name="medium_large_size_w" type="number" step="1" min="0" id="medium_large_size_w" value="<?php form_option( 'medium_large_size_w' ); ?>" class="small-text" />
        <br>
        <label for="medium_large_size_h"><?php _e( 'Max Height' ); ?></label>
        <input name="medium_large_size_h" type="number" step="1" min="0" id="medium_large_size_h" value="<?php form_option( 'medium_large_size_h' ); ?>" class="small-text" />
    </fieldset>
    <?php
}
add_action( 'admin_init', 'thistle_add_medium_large_size_settings' );

Je l’avoue, j’ai pris une initiative supplémentaire dans mon code 😚

Comme en bon François « Medium-large » ne semble pas avoir d’équivalent, j’ai décidé que ce format s’appellerait maintenant « Grande taille » et que je renommerais le précédent « Grande taille » en « Très grande taille » 🤓

Procédons donc au renommage :

/**
 * Renames "Large" label into "Extra large" via JavaScript 
 * because we can't do it with the help of PHP.
 */
function thistle_rename_large_size_settings() {
    ?>
    <script>
        ( function( window, $, undefined ) {
            if ( typeof $ !== 'undefined' ) {
                $( document ).ready( function () {
                    var $lss = $( '#large_size_w' ).parents('tr');

                    $lss
                        .find('th, legend span')
                            .html('<?php _e( 'Extra large size', YOUR_TEXT_DOMAIN ); ?>');
                } );
            }
        } )( window, window.jQuery );
    </script>
    <?php
}
add_action( 'admin_head-options-media.php', 'thistle_rename_large_size_settings' );

/**
 * Retrieves the names and labels of the default image sizes including
 * the fourth (or fifth) one: "Medium Large".
 * Because we don't have a good translation for "Medium Large" in French,
 * I decided to rename "Large" into "Extra large" and
 * give the "Large" label to the medium_large size.
 *
 * @param array $size_names Array of image sizes and their names. Default values
 *                          include 'Thumbnail', 'Medium', 'Large', 'Full Size'.
 * @return array
 */
function thistle_change_image_size_names( $size_names ) {
    $index = array_search( 'large' , array_keys( $size_names ) );

    $size_names = array_merge( array_slice( $size_names, 0, $index, true), array( 'medium_large' => _( 'Large' ) ), $size_names );
    $size_names['large'] = __( 'Extra large', YOUR_TEXT_DOMAIN );

    return $size_names;
}
add_filter( 'image_size_names_choose', 'thistle_change_image_size_names' );

Je sais que ce choix peut être sujet à un troll monumental mais je l’assume 😎 On aurait aussi pu traduire « Medium-large » par « Taille intermédiaire » mais bon.

Nous y sommes presque.
Quand nous avons ajouté nos champs via add_settings_field, ces derniers se sont placés à la fin de notre page et ce n’est pas vraiment logique par rapport à l’ordre des tailles d’images.

Remettons cela dans le bon ordre :

/**
 * Changes the order of the size settings to have "Medium Large" before
 * "Large" via JavaScript because we can't do it with the help of PHP.
 */
function thistle_change_size_settings_order() {
    ?>
    <script>
        ( function( window, $, undefined ) {
            if ( typeof $ !== 'undefined' ) {
                $( document ).ready( function () {
                    var $lss = $( '#large_size_w' ).parents('tr');
                    var $mlss = $( '#medium_large_size_w' ).parents('tr');

                    $lss
                        .insertAfter($mlss);
                } );
            }
        } )( window, window.jQuery );
    </script>
    <?php
}
add_action( 'admin_head-options-media.php', 'thistle_change_size_settings_order' );

Je ne vous cache pas que l’utilisation de JavaScript pour faire ce genre de choses ne m’enchante jamais mais quand WordPress ne nous laisse pas le choix… 😩

Sauf que, même si nos nouveaux champs se trouvent bien sur notre page d’options et  sont dans le bon ordre, les nouvelles dimensions ne s’enregistrent pas en base de données 🤔
Pour que cela fonctionne, nous devons whitelister celles-ci de la façon suivante :

/**
 * Adds the `medium_large_size_w` and `medium_large_size_h` options
 * to the white list to be authorised to edit them.
 *
 * @param array White list options.
 * @return array.
 */
function thistle_media_whitelist_options( $whitelist_options ) {
    $whitelist_options['media'][] = 'medium_large_size_w';
    $whitelist_options['media'][] = 'medium_large_size_h';
    
    return $whitelist_options;
}
add_filter( 'whitelist_options', 'thistle_media_whitelist_options' );

Voila, c’est fini 😁