commit 3ccc362f34dbf7429b323d88b91f96ec8e2db3d2 Author: MrRaph_ Date: Wed Mar 5 10:02:19 2025 +0100 first commit diff --git a/wp-thumbor.php b/wp-thumbor.php new file mode 100644 index 0000000..6281387 --- /dev/null +++ b/wp-thumbor.php @@ -0,0 +1,305 @@ + '', + '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'); +