config = $config; $this->dispatcher = $dispatcher; } /** * Add image placeholders to image src * * @param string $content Content to be processed * @return string */ public function replaceSrcImageWithSrcPlaceholders(string $content): string { if ($this->isNotTheFrontEnd()) { return $content; } if ($this->hasAlreadyLazyLoadedIn($content)) { return $content; } /** * This is a pretty simple regex, but it works * * @var string */ return \preg_replace_callback( '#]+?)src=[\'"]?([^\'"\s>]+)[\'"]?([^>]*)>#', fn(array $matches) => $this->replaceAttributes($matches), $content ); } /** * @param array $matches * @return string */ private function replaceAttributes(array $matches) { /** * Replace srcset, sizes and src attributes */ $content = \str_replace( ['srcset', 'sizes'], ['data-lazy-srcset', 'data-sizes'], \sprintf( '', $matches[1], $this->getImagePlaceholder(), $matches[2], $matches[3] ) ); return $this->appendNoscript($matches, $content); } /** * @param array $matches * @param string $content * @return string */ private function appendNoscript(array $matches, string $content): string { $content .= \sprintf( '', $matches[ 1 ], $matches[ 2 ], $matches[ 3 ] ); return $content; } /** * @return string */ private function getImagePlaceholder() { return $this->dispatcher->filter( static::PLACEHOLDER_FILTER_EVENT_NAME, $this->config->get('lazyload-custom-placeholder', static::DEFAULT_PLACEHOLDER) ); } /** * @param string $content * @return bool */ private function hasAlreadyLazyLoadedIn(string $content): bool { return false !== \strpos($content, 'data-lazy-src'); } /** * @return bool */ private function isNotTheFrontEnd(): bool { return \is_feed() || \is_preview(); } }