You are here

class LazyFilter in Lazy-load 8.3

Same name and namespace in other branches
  1. 8 src/Plugin/Filter/LazyFilter.php \Drupal\lazy\Plugin\Filter\LazyFilter
  2. 8.2 src/Plugin/Filter/LazyFilter.php \Drupal\lazy\Plugin\Filter\LazyFilter

Provides a filter to lazy-load images.

Plugin annotation


@Filter(
  id = "lazy_filter",
  title = @Translation("Lazy-load images and iframes"),
  description = @Translation("Only selected tags will be lazy-loaded in activated text-formats."),
  type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE,
  settings = {
    "image" = TRUE,
    "iframe" = TRUE,
  },
  weight = 20
)

Hierarchy

Expanded class hierarchy of LazyFilter

File

src/Plugin/Filter/LazyFilter.php, line 29

Namespace

Drupal\lazy\Plugin\Filter
View source
class LazyFilter extends FilterBase implements ContainerFactoryPluginInterface {

  /**
   * The configuration factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The Lazy-load service.
   *
   * @var \Drupal\lazy\Lazy
   */
  protected $lazyLoad;

  /**
   * Constructs a LazyFilter object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory.
   * @param \Drupal\lazy\Lazy $lazy_load
   *   The Lazy-load service.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory, Lazy $lazy_load) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->configFactory = $config_factory;
    $this->lazyLoad = $lazy_load;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('config.factory'), $container
      ->get('lazy'));
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $form['info'] = [
      '#markup' => $this
        ->t('Lazy-load filter can be enabled for images and iframes.'),
    ];
    $form['image'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Enable for images (%img tags)', [
        '%img' => '<img>',
      ]),
      "#description" => $this
        ->t('This option only applies to inline-images. If <em>Embed media</em> filter is enabled, the images embedded from media library would use the the selected view mode settings.'),
      '#default_value' => $this->settings['image'],
      '#return_value' => TRUE,
    ];
    $form['iframe'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Enable for iframes (%iframe tags)', [
        '%iframe' => '<iframe>',
      ]),
      '#default_value' => $this->settings['iframe'],
      '#return_value' => TRUE,
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function setConfiguration(array $configuration) {
    parent::setConfiguration($configuration);
    if ($configuration['status'] && !empty($configuration['settings']) && $configuration['settings']['image'] == FALSE && $configuration['settings']['iframe'] == FALSE) {
      $this->status = FALSE;
      $this
        ->messenger()
        ->addWarning($this
        ->t('Lazy-loading is not enabled. The filter configuration needs to be enabled for either of the IMG or IFRAME tags.'));
    }
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function process($text, $langcode) : FilterProcessResult {
    $result = new FilterProcessResult($text);
    if ($this->status && ($this->settings['image'] || $this->settings['iframe']) && $this->lazyLoad
      ->isPathAllowed() && ($lazy_settings = $this->configFactory
      ->get('lazy.settings')
      ->get())) {
      $html_dom = Html::load($text);
      $xpath = new \DOMXPath($html_dom);

      /** @var \DOMElement $node */
      foreach ($xpath
        ->query('//img | //iframe') as $node) {
        $classes = empty($node
          ->getAttribute('class')) ? [] : explode(' ', $node
          ->getAttribute('class'));
        $parent_classes = empty($node->parentNode
          ->getAttribute('class')) ? [] : explode(' ', $node->parentNode
          ->getAttribute('class'));

        // Get original source value.
        $src = $node
          ->getAttribute('src');

        // Check which tags are enabled in text-format settings.
        $enabled_tags = [
          'img' => $this->settings['image'],
          'iframe' => $this->settings['iframe'],
        ];
        foreach ($enabled_tags as $tag => $status) {

          // Act only on the elements that are enabled under "Lazy-load images
          // and iframes" in filter settings.
          if ($node->tagName === $tag && $enabled_tags[$node->tagName]) {

            // Check if the element, or its parent has a skip class.
            if (in_array($lazy_settings['skipClass'], $classes, TRUE) || in_array($lazy_settings['skipClass'], $parent_classes, TRUE)) {

              // Leave this node unchanged.
              continue;
            }
            if ($lazy_settings['preferNative']) {

              // Set required attribute `loading="lazy"`.
              $node
                ->setAttribute('loading', 'lazy');
            }
            else {

              // Add Lazysizes selector class name to element attributes.
              $classes[] = $lazy_settings['lazysizes']['lazyClass'];
              $classes = array_unique($classes);
              $node
                ->setAttribute('class', implode(' ', $classes));

              // Change source attribute from `src` to `data-src`, or whatever
              // is defined in Lazysizes configuration for `srcAttr` at
              // /admin/config/content/lazy.
              $opt_src = $lazy_settings['lazysizes']['srcAttr'] !== 'src' ? $lazy_settings['lazysizes']['srcAttr'] : 'data-filterlazy-src';
              $node
                ->removeAttribute('src');
              $node
                ->setAttribute($opt_src, $src);

              // If the default placeholder defined, it would be used in `src`
              // attribute.
              if ($lazy_settings['placeholderSrc']) {
                $node
                  ->setAttribute('src', $lazy_settings['placeholderSrc']);
              }
            }
          }
        }
      }
      $result
        ->setProcessedText(Html::serialize($html_dom));
    }
    return $result;
  }

  /**
   * {@inheritdoc}
   */
  public function tips($long = FALSE) {
    $tags = [
      'img' => $this->settings['image'],
      'iframe' => $this->settings['iframe'],
    ];
    $options = [
      '%img' => '<img>',
      '%iframe' => '<iframe>',
    ];
    $skip_class = $this->configFactory
      ->get('lazy.settings')
      ->get('skipClass');
    $skip_help = $this
      ->t('If you want certain elements skip lazy-loading, add <code>%skip_class</code> class name.', [
      '%skip_class' => $skip_class,
    ]);
    if (!empty($tags)) {
      if ($tags['img'] && $tags['iframe']) {
        return $this
          ->t('Lazy-loading is enabled for both %img and %iframe tags.', $options) . ' ' . $skip_help;
      }
      if ($tags['img']) {
        return $this
          ->t('Lazy-loading is enabled for %img tags.', $options) . ' ' . $skip_help;
      }
      if ($tags['iframe']) {
        return $this
          ->t('Lazy-loading is enabled for %iframe tags.', $options) . ' ' . $skip_help;
      }
    }
    return $this
      ->t('Lazy-loading is not enabled.');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
FilterBase::$provider public property The name of the provider that owns this filter.
FilterBase::$settings public property An associative array containing the configured settings of this filter.
FilterBase::$status public property A Boolean indicating whether this filter is enabled.
FilterBase::$weight public property The weight of this filter compared to others in a filter collection.
FilterBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies 1
FilterBase::defaultConfiguration public function Gets default configuration for this plugin. Overrides ConfigurableInterface::defaultConfiguration
FilterBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
FilterBase::getDescription public function Returns the administrative description for this filter plugin. Overrides FilterInterface::getDescription
FilterBase::getHTMLRestrictions public function Returns HTML allowed by this filter's configuration. Overrides FilterInterface::getHTMLRestrictions 4
FilterBase::getLabel public function Returns the administrative label for this filter plugin. Overrides FilterInterface::getLabel
FilterBase::getType public function Returns the processing type of this filter plugin. Overrides FilterInterface::getType
FilterBase::prepare public function Prepares the text for processing. Overrides FilterInterface::prepare
FilterInterface::TYPE_HTML_RESTRICTOR constant HTML tag and attribute restricting filters to prevent XSS attacks.
FilterInterface::TYPE_MARKUP_LANGUAGE constant Non-HTML markup language filters that generate HTML.
FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE constant Irreversible transformation filters.
FilterInterface::TYPE_TRANSFORM_REVERSIBLE constant Reversible transformation filters.
LazyFilter::$configFactory protected property The configuration factory.
LazyFilter::$lazyLoad protected property The Lazy-load service.
LazyFilter::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
LazyFilter::process public function Performs the filter processing. Overrides FilterInterface::process
LazyFilter::setConfiguration public function Sets the configuration for this plugin instance. Overrides FilterBase::setConfiguration
LazyFilter::settingsForm public function Generates a filter's settings form. Overrides FilterBase::settingsForm
LazyFilter::tips public function Generates a filter's tip. Overrides FilterBase::tips
LazyFilter::__construct public function Constructs a LazyFilter object. Overrides FilterBase::__construct
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.