Автоматическое сжатие изображений в поле 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;
    }