Автоматическое сжатие изображений в поле content [MODX]

09 Февраля 2023
php

Задача: сделать чтобы все изображения, загруженные в поле content, обрезались до заданных размеров и выводились пользователю, само поле content, при этом, не заменяется новыми изображениями.

В данном примере, мы будем использовать:

  1. Плагин с событием OnLoadWebDocument

  2. Пакет для обработки изображений pThumb

  3. Скрипт ленивой загрузки изображений lazysizes

Разобьем весь код на части:

  1. Создаем плагин с событием OnLoadWebDocument, названием любым, например OnLoadWebDocument

    В поле код плагина помещаем следующий код:

    $eventName=$modx->event->name;
    switch($eventName) {
        case 'OnLoadWebDocument':
            // код события
        break;
    }
    
  2. В код события помещаем следующий код:

    • Если id шаблона не 1, то выходим

      $template=$modx->resource->template;
      if((int)$template!==1){
          break;
      }
      
    • Если контент пустой, то выходим

      $content=$modx->resource->content;
      $content=mb_convert_encoding(html_entity_decode($content), 'HTML-ENTITIES', 'UTF-8');
      if(!$content){
          break;
      }
      
    • Берем контент, оборачиваем как страницу html, парсим, если изображений не найдено, то выходим

      $doc=new DOMDocument();
      $doc->encoding="utf-8";
      $doc->recover=true;
      $doc->strictErrorChecking=false;
      $doc->loadHTML('<html>'.$content.'</html>', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
      $images=$doc->getElementsByTagName('img');
      if(count($images)==0){
          break;
      }
      
    • Задаем настройки для изображений, максимальную ширину, изображение по умолчанию

      $maxwidthimg=740;
      $defaultimg='/assets/img/icon-loading.svg';
      
    • Проходимся цикром по всем изображениям, берем только те у которых есть src и он не равен изображению по умолчанию, добавляем класс lazyload и атрибут data-src, задаем ширину для изображения

      foreach($images as $image){
          $src=$image->getAttribute('src');
          if(!$src){
              continue;
          }
      
          if($src==$defaultimg){
              continue;
          }
          
          $newsrc=$modx->runSnippet('pThumb', array(
              'input' => $src,
              'options' => 'w='.$maxwidthimg.'&f=jpg&q=90',
          ));
          if(!$newsrc){
              continue;
          }
          
          $image->setAttribute('data-src',$newsrc);
          $image->setAttribute('src',$defaultimg);
          
          $class=$image->getAttribute('class');
          $classarray=explode(',',$class);
          $classarray[]='lazyload';
          $newclass=implode(' ',$classarray);
          $image->setAttribute('class',$newclass);
          
          $width=$image->getAttribute('width');
          if((int)$width>$maxwidthimg){
              $image->setAttribute('width','100%');
              $image->removeAttribute('height');
          }
      }
      
    • Сохраняем полученный результат и заменяем наш контент новым, убирая обертку html

      $modx->resource->content=str_replace(array('<html>','</html>'),'',$doc->saveHTML());
      
  3. В итоге получаем следующий год:

    $eventName=$modx->event->name;
    switch($eventName) {
        case 'OnLoadWebDocument':
            
            $maxwidthimg=740;
            $defaultimg='/assets/img/icon-loading.svg';
            
            $template=$modx->resource->template;
            if((int)$template!==1){
                break;
            }
    
            $content=$modx->resource->content;
            $content=mb_convert_encoding(html_entity_decode($content), 'HTML-ENTITIES', 'UTF-8');
            if(!$content){
                break;
            }
    
            $doc=new DOMDocument();
            $doc->encoding="utf-8";
            $doc->recover=true;
            $doc->strictErrorChecking=false;
            $doc->loadHTML(''.$content.'', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
            
            $images=$doc->getElementsByTagName('img');
            if(count($images)==0){
                break;
            }
            foreach($images as $image){
                $src=$image->getAttribute('src');
                if(!$src){
                    continue;
                }
    
                if($src==$defaultimg){
                    continue;
                }
                
                $newsrc=$modx->runSnippet('pThumb', array(
                    'input' => $src,
                    'options' => 'w='.$maxwidthimg.'&f=jpg&q=90',
                ));
                if(!$newsrc){
                    continue;
                }
                
                $image->setAttribute('data-src',$newsrc);
                $image->setAttribute('src',$defaultimg);
                
                $class=$image->getAttribute('class');
                $classarray=explode(',',$class);
                $classarray[]='lazyload';
                $newclass=implode(' ',$classarray);
                $image->setAttribute('class',$newclass);
                
                $width=$image->getAttribute('width');
                if((int)$width>$maxwidthimg){
                    $image->setAttribute('width','100%');
                    $image->removeAttribute('height');
                }
            }
                
            $modx->resource->content=str_replace(array('',''),'',$doc->saveHTML());
        break;
    }