Skip to content

Instantly share code, notes, and snippets.

@j-dexx
Created June 24, 2020 17:11
Show Gist options
  • Save j-dexx/1bc9cab5728a99ffb7c5f1166b5c011d to your computer and use it in GitHub Desktop.
Save j-dexx/1bc9cab5728a99ffb7c5f1166b5c011d to your computer and use it in GitHub Desktop.
Replacing Upload URLs in WYSIWYG Content
<?php
namespace App\Services\Wysiwyg;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\MediaLibrary\ResponsiveImages\ResponsiveImage;
class ResponsiveImageUrlsGenerator
{
private Media $media;
public function __construct(Media $media)
{
$this->media = $media;
}
public function call(): array
{
// responsive is the collection name
$files = $this->media->responsiveImages('responsive')->files;
// Returns the responsive images as width => url
$imageUrls = $files->mapWithKeys(function (ResponsiveImage $responsiveImage) {
return [
$responsiveImage->width() => $responsiveImage->url(),
];
});
// Add the default key to the start
$imageUrls->prepend($this->media->getUrl('responsive'), 'default');
return $imageUrls->toArray();
}
}
<?php
namespace App\Services\Wysiwyg;
use DOMDocument;
use DOMElement;
use Config;
use Illuminate\Support\Collection;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class UploadUrlReplacer
{
private string $htmlContent;
private string $disk;
public function __construct(string $htmlContent, string $disk = 'public')
{
$this->htmlContent = $htmlContent;
$this->disk = $disk;
}
/**
* Done this way because the wysiwyg content isn't technically valid html and DOMDocument seems to try to fix
* e.g. '<figure></figure><ul></ul>' becomes '<figure><ul></ul></figure>'
*/
public function call(): string
{
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($this->htmlContent, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$imageTags = $dom->getElementsByTagName('img');
$newHtmlContent = $this->htmlContent;
foreach ($imageTags as $imageTag) {
$beforeHtml = $dom->saveHTML($imageTag);
$this->updateImageTag($imageTag);
$afterHtml = $dom->saveHTML($imageTag);
if ($beforeHtml && $afterHtml) {
$newHtmlContent = str_replace($beforeHtml, $afterHtml, $newHtmlContent);
}
}
libxml_use_internal_errors(false);
return $newHtmlContent;
}
private function updateImageTag(DOMElement $imageTag): void
{
$imageSrc = $imageTag->getAttribute('src');
$mediaId = $this->mediaId($imageSrc);
$media = Media::findOrFail($mediaId);
$responsiveUrlGenerator = new ResponsiveImageUrlsGenerator($media);
$urls = $responsiveUrlGenerator->call();
$urlCollection = collect($urls);
$defaultUrl = $urlCollection->get('default');
$urlsWithWidths = $urlCollection->filter(function ($value, $key) {
return $key !== 'default';
});
$srcSet = $this->calculateSrcSet($urlsWithWidths);
$imageTag->setAttribute('src', $defaultUrl);
$imageTag->setAttribute('srcset', $srcSet);
}
private function calculateSrcSet(Collection $urls): string
{
return $urls->map(function ($url, $key) {
return $url . ' ' . $key . 'w';
})->implode(', ');
}
private function mediaId(string $imageSrc): string
{
$newImageSrc = $this->stripDiskUrlFromImageSource($imageSrc);
$parts = explode('/', $newImageSrc);
// If the string began with / we get an empty string
$parts = array_values(array_filter($parts));
return $parts[0];
}
private function stripDiskUrlFromImageSource(string $imageSrc): string
{
$url = $this->diskUrl();
if (is_null($url)) {
return $imageSrc;
}
$newSrc = str_replace($url, "", $imageSrc);
return $newSrc;
}
private function diskUrl(): ?string
{
$config = Config::get('filesystems.disks.' . $this->disk . '.url');
return $config;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment