'', 'thumbor_filters' => '', 'thumbor_secret_key' => '', ); $options = get_option('wp_thumbor_options', $defaults); return wp_parse_args($options, $defaults); } /** * Vérifie si la transformation Thumbor doit être désactivée pour l'appelant. * Par exemple, si l'appel provient du plugin Optimize More (pour éviter des getimagesize sur une URL Thumbor). * * @return bool */ function wp_thumbor_should_skip_transform() { $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10); foreach ($trace as $frame) { if (isset($frame['file']) && stripos($frame['file'], 'optimize-more') !== false) { return true; } } return false; } /** * Ajoute un menu de réglages dans l'administration de WordPress. */ function wp_thumbor_admin_menu() { add_options_page( 'Réglages WP Thumbor Integration', 'WP Thumbor Integration', 'manage_options', 'wp-thumbor-integration', 'wp_thumbor_settings_page' ); } add_action('admin_menu', 'wp_thumbor_admin_menu'); /** * Affiche la page de réglages du plugin dans l'administration. */ function wp_thumbor_settings_page() { if (!current_user_can('manage_options')) { wp_die(__('Vous n\'avez pas l\'autorisation d\'accéder à cette page.')); } // Sauvegarde des réglages lors de la soumission du formulaire. if (isset($_POST['wp_thumbor_nonce']) && wp_verify_nonce($_POST['wp_thumbor_nonce'], 'wp_thumbor_save_settings')) { $options = array(); $options['thumbor_base_url'] = isset($_POST['thumbor_base_url']) ? esc_url_raw(trim($_POST['thumbor_base_url'])) : ''; $options['thumbor_filters'] = isset($_POST['thumbor_filters']) ? sanitize_text_field(trim($_POST['thumbor_filters'])) : ''; $options['thumbor_secret_key'] = isset($_POST['thumbor_secret_key']) ? sanitize_text_field(trim($_POST['thumbor_secret_key'])) : ''; update_option('wp_thumbor_options', $options); echo '

Les paramètres ont été mis à jour.

'; } $options = wp_thumbor_get_options(); ?>

WP Thumbor Integration - Réglages

Thumbor Base URL

Entrez l'URL de base de votre serveur Thumbor (sans barre oblique finale).

Filtres Thumbor

Entrez la liste des filtres à appliquer, séparés par des virgules, sans le préfixe "filters:" ni le suffixe ":/".

Clé secrète Thumbor

Entrez la clé secrète pour signer les URLs Thumbor. Laissez vide pour utiliser l'endpoint "unsafe".

intval($matches[1]), 'height' => intval($matches[2])); } return false; } /** * Transforme l'URL d'une image en ajoutant l'endpoint Thumbor (signé si clé secrète renseignée), * les options de redimensionnement et les filtres configurés. * * Le format généré est : * {thumbor_base_url}/{endpoint}/[width]x[height]/[filters:...]/{url} * * Si aucune dimension n'est précisée, la partie redimensionnement est omise. * * @param string $url L'URL originale de l'image. * @param int|null $width La largeur souhaitée (provenant éventuellement des attributs HTML). * @param int|null $height La hauteur souhaitée. * @return string L'URL transformée. */ function wp_thumbor_transform_url($url, $width = null, $height = null) { // Ne pas transformer dans l'administration if (is_admin()) { return $url; } // Si l'appel provient d'un plugin tiers (ex. Optimize More), on retourne l'URL d'origine if (wp_thumbor_should_skip_transform()) { return $url; } $options = wp_thumbor_get_options(); $thumbor_base_url = isset($options['thumbor_base_url']) ? rtrim($options['thumbor_base_url'], '/') : ''; if (empty($thumbor_base_url)) { return $url; } // Évite une double transformation if (strpos($url, $thumbor_base_url) === 0) { return $url; } // Si aucune dimension n'est fournie via les attributs, tenter d'extraire depuis le nom du fichier if (empty($width) && empty($height)) { $dimensions = wp_thumbor_extract_dimensions_from_url($url); if ($dimensions) { $width = $dimensions['width']; $height = $dimensions['height']; } } // Préparation de la partie redimensionnement if ($width || $height) { $w = $width ? $width : 0; $h = $height ? $height : 0; $resize = $w . 'x' . $h . '/'; } else { $resize = ''; } // Préparation de la partie filtres à partir des réglages $thumbor_filters = isset($options['thumbor_filters']) ? trim($options['thumbor_filters']) : ''; if (!empty($thumbor_filters)) { // Correction apportée ici : utiliser "/" au lieu de ":/" après les filtres. $filterPart = 'filters:' . $thumbor_filters . '/'; } else { $filterPart = ''; } // Construction de la chaîne d'options à signer $path_to_sign = $resize . $filterPart . $url; // Détermine l'endpoint : si une clé secrète est renseignée, on signe, sinon on utilise "unsafe" if (!empty($options['thumbor_secret_key'])) { // Calcul du HMAC-SHA1 en mode binaire $hmac = hash_hmac('sha1', $path_to_sign, $options['thumbor_secret_key'], true); // Encodage en base64 en mode URL-safe (remplacement + -> - et / -> _) $encoded_signature = strtr(base64_encode($hmac), '+/', '-_'); // L'endpoint sécurisé est le code signé $endpoint = $encoded_signature; } else { $endpoint = 'unsafe'; } $transformed_url = $thumbor_base_url . '/' . $endpoint . '/' . $path_to_sign; return $transformed_url; } /** * Filtre l'URL d'une pièce jointe image pour y intégrer Thumbor. */ function wp_thumbor_filter_attachment_url($url, $post_id) { // Si l'appel provient d'un plugin tiers (ex. Optimize More), on retourne l'URL d'origine. if (wp_thumbor_should_skip_transform()) { return $url; } $mime = get_post_mime_type($post_id); if (strpos($mime, 'image/') === 0) { return wp_thumbor_transform_url($url); } return $url; } //add_filter('wp_get_attachment_url', 'wp_thumbor_filter_attachment_url', 10, 2); /** * Parcourt le contenu HTML d'un article et modifie les attributs src, data-src, srcset et data-srcset * des balises en y intégrant les paramètres de redimensionnement (issus des attributs width/height) * et les filtres Thumbor. */ function wp_thumbor_filter_content_images($content) { // Ne pas transformer dans l'administration if (is_admin()) { return $content; } libxml_use_internal_errors(true); $dom = new DOMDocument(); // Conversion pour éviter les problèmes d'encodage $dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8')); $images = $dom->getElementsByTagName('img'); foreach ($images as $img) { // Récupération de la largeur et hauteur si présentes $width = $img->getAttribute('width'); $height = $img->getAttribute('height'); $width = $width ? intval($width) : null; $height = $height ? intval($height) : null; // Transformation de l'attribut "src" si c'est une URL absolue if ($img->hasAttribute('src') && preg_match('/^https?:\/\//', $img->getAttribute('src'))) { $new_src = wp_thumbor_transform_url($img->getAttribute('src'), $width, $height); $img->setAttribute('src', $new_src); } // Transformation de "data-src" pour le lazyload if ($img->hasAttribute('data-src') && preg_match('/^https?:\/\//', $img->getAttribute('data-src'))) { $new_data_src = wp_thumbor_transform_url($img->getAttribute('data-src'), $width, $height); $img->setAttribute('data-src', $new_data_src); } // Traitement de l'attribut "srcset" if ($img->hasAttribute('srcset')) { $srcset = $img->getAttribute('srcset'); $newSrcset = array(); // Chaque élément est séparé par une virgule $srcsetItems = explode(',', $srcset); foreach ($srcsetItems as $item) { $parts = preg_split('/\s+/', trim($item)); if (!empty($parts[0]) && preg_match('/^https?:\/\//', $parts[0])) { $newURL = wp_thumbor_transform_url($parts[0]); // Conserver le descripteur (ex: "1707w") si présent $newSrcset[] = isset($parts[1]) ? $newURL . ' ' . $parts[1] : $newURL; } else { $newSrcset[] = $item; } } $img->setAttribute('srcset', implode(', ', $newSrcset)); } // Traitement de l'attribut "data-srcset" if ($img->hasAttribute('data-srcset')) { $srcset = $img->getAttribute('data-srcset'); $newSrcset = array(); $srcsetItems = explode(',', $srcset); foreach ($srcsetItems as $item) { $parts = preg_split('/\s+/', trim($item)); if (!empty($parts[0]) && preg_match('/^https?:\/\//', $parts[0])) { $newURL = wp_thumbor_transform_url($parts[0]); $newSrcset[] = isset($parts[1]) ? $newURL . ' ' . $parts[1] : $newURL; } else { $newSrcset[] = $item; } } $img->setAttribute('data-srcset', implode(', ', $newSrcset)); } } // On récupère le contenu du pour éviter d'inclure la balise ou $body = $dom->getElementsByTagName('body')->item(0); $new_content = ''; foreach ($body->childNodes as $child) { $new_content .= $dom->saveHTML($child); } return $new_content; } add_filter('the_content', 'wp_thumbor_filter_content_images'); /** * Initialisation du plugin (chargement des traductions, etc.). */ function wp_thumbor_init() { load_plugin_textdomain('wp-thumbor-integration', false, dirname(plugin_basename(__FILE__)) . '/languages/'); } add_action('plugins_loaded', 'wp_thumbor_init');