Update (seo)

Add (lqip)
This commit is contained in:
2023-09-25 02:41:40 +08:00
parent ef9c5a1407
commit 3aa6367e83
20 changed files with 163 additions and 38 deletions

View File

@@ -5,12 +5,22 @@
use App\Http\Controllers\Controller;
use App\Models\Category;
use App\Models\Post;
use Artesaos\SEOTools\Facades\SEOTools;
use Illuminate\Http\Request;
class FrontListController extends Controller
{
public function index(Request $request)
{
$title = 'Latest News from EchoScoop';
SEOTools::metatags();
SEOTools::twitter();
SEOTools::opengraph();
SEOTools::jsonLd();
SEOTools::setTitle($title, false);
$posts = Post::where('status', 'publish')->orderBy('published_at', 'desc')->simplePaginate(10) ?? collect();
return view('front.post_list', compact('posts'));
@@ -22,6 +32,14 @@ public function category(Request $request, $category_slug)
$posts = $category?->posts()->where('status', 'publish')->orderBy('published_at', 'desc')->simplePaginate(10) ?? collect();
$title = $category->name.' News from EchoScoop';
SEOTools::metatags();
SEOTools::twitter();
SEOTools::opengraph();
SEOTools::jsonLd();
SEOTools::setTitle($title, false);
return view('front.post_list', compact('category', 'posts'));
}
}

View File

@@ -4,6 +4,9 @@
use App\Http\Controllers\Controller;
use App\Models\Post;
use Artesaos\SEOTools\Facades\JsonLdMulti;
use Artesaos\SEOTools\Facades\OpenGraph;
use Artesaos\SEOTools\Facades\SEOMeta;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Http\Request;
use Symfony\Component\DomCrawler\Crawler;
@@ -25,6 +28,46 @@ public function index(Request $request, $slug)
$content = $this->injectTableOfContents($content);
$content = $this->injectFeaturedImage($post, $content);
$post_description = $post->excerpt.' '.$post->title.' by EchoScoop.';
SEOMeta::setTitle($post->title, false);
SEOMeta::setDescription($post_description);
SEOMeta::addMeta('article:published_time', $post->published_at->format('Y-m-d'), 'property');
SEOMeta::addMeta('article:section', $post->category->name, 'property');
SEOMeta::setRobots('INDEX, FOLLOW, MAX-IMAGE-PREVIEW:LARGE, MAX-SNIPPET:-1, MAX-VIDEO-PREVIEW:-1');
OpenGraph::setDescription($post_description);
OpenGraph::setTitle($post->title);
OpenGraph::setUrl(url()->current());
OpenGraph::addProperty('type', 'article');
OpenGraph::addProperty('locale', 'en_US');
OpenGraph::addImage($post->featured_image_cdn);
$jsonld_multi = JsonLdMulti::newJsonLd();
$jsonld_multi->setTitle($post->title)
->setDescription($post_description)
->setType('Article')
->addValue('headline', $post->title)
->addImage($post->featured_image_cdn)
->addValue('author', [
'type' => 'Person',
'name' => $post->author->name,
'url' => config('app.url'),
])
->addValue('publisher', [
'type' => 'Organization',
'name' => 'EchoScoop',
'logo' => [
'type' => 'ImageObject',
'url' => asset('echoscoop-logo-512x512.png'),
],
])
->addValue('datePublished', $post->published_at->format('Y-m-d'))
->addValue('dateCreated', $post->created_at->format('Y-m-d'))
->addValue('dateModified', $post->updated_at->format('Y-m-d'))
->addValue('description', $post_description)
->addValue('articleBody', trim(preg_replace('/\s\s+/', ' ', strip_tags($content))));
return view('front.single_post', compact('post', 'content'));
}
@@ -32,22 +75,23 @@ private function injectBootstrapClasses($content)
{
$crawler = new Crawler($content);
// Handle Headings
$crawler->filter('h1')->each(function (Crawler $node) {
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' display-6 fw-bolder mt-3 mb-4'));
});
$crawler->filter('h2')->each(function (Crawler $node) {
$node->getNode(0)->setAttribute('class', trim($node->attr('class').'h4 mb-3'));
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' h4 mb-3'));
});
$crawler->filter('h3')->each(function (Crawler $node) {
$node->getNode(0)->setAttribute('class', trim($node->attr('class').'h6 mb-2'));
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' h6 mb-3'));
});
// Handle Paragraphs
$crawler->filter('p')->each(function (Crawler $pNode) {
$precedingHeaders = $pNode->previousAll()->filter('h2');
// If there are no preceding <h2> tags, just process the <p>
if (! $precedingHeaders->count()) {
$existingClasses = $pNode->attr('class');
$newClasses = trim($existingClasses.' mt-2 mb-4');
@@ -70,12 +114,18 @@ private function injectBootstrapClasses($content)
}
});
// Handle Lists
$crawler->filter('ul')->each(function (Crawler $node) {
$node->getNode(0)->setAttribute('class', trim($node->attr('class').'py-2'));
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' py-2'));
});
$crawler->filter('ol')->each(function (Crawler $node) {
$node->getNode(0)->setAttribute('class', trim($node->attr('class').'py-2'));
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' py-2'));
});
// Handle Tables
$crawler->filter('table')->each(function (Crawler $node) {
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' table table-bordered mb-4'));
});
// Convert the modified DOM back to string
@@ -117,16 +167,16 @@ private function injectTableOfContents($html)
private function injectFeaturedImage($post, $content)
{
if (! is_empty($post->featured_image)) {
if (! empty($post->featured_image)) {
$featured_image_alt = strtolower($post->short_title);
$featured_image_alt_caps = strtoupper($post->short_title);
$featured_image = "<div class=\"w-100 d-flex justify-content-center\"><figure class=\"text-center\"><img decoding=\"async\" class=\"img-fluid rounded mb-2 shadow\" src=\"{$post->featured_image_cdn}\" alt=\"{$featured_image_alt}\"><figcaption class=\"text-secondary small\">{$featured_image_alt_caps}</figcaption></figure></div>";
// Update the HTML structure
$featured_image = "<div class=\"w-100 d-flex justify-content-center\"><figure class=\"text-center\"><img decoding=\"async\" class=\"img-fluid rounded mb-2 shadow lqip-blur\" src=\"{$post->featured_image_lqip_cdn}\" data-src=\"{$post->featured_image_cdn}\" alt=\"{$featured_image_alt}\"><figcaption class=\"text-secondary small\">{$featured_image_alt_caps}</figcaption></figure></div>";
$content = preg_replace('/(<\/h1>)/', '$1'.$featured_image, $content, 1);
}
return $content;
}
}

View File

@@ -208,7 +208,9 @@ public static function handle($post)
$yPosition += $fontSize + $padding;
}
$filename = $post->slug.'-'.epoch_now_timestamp().'.jpg';
$epoch_now_timestamp = epoch_now_timestamp();
$filename = $post->slug.'-'.$epoch_now_timestamp.'.jpg';
$ok = OSSUploader::uploadFile('r2', 'post_images/', $filename, (string) $canvas->stream('jpeg'));
@@ -216,18 +218,20 @@ public static function handle($post)
// Clone the main image for LQIP version
$lqipImage = clone $canvas;
// Create the LQIP version of the image
$lqipImage->fit(10, 10, function ($constraint) {
$constraint->aspectRatio();
});
// Apply blur
$lqipImage->blur(5); // Adjust to the desired blur level
$lqipImage->encode('jpg', 5);
// Pixelate the image
$lqipImage->pixelate(30); // Adjust this value based on the desired pixelation level
// Encode the image to a low-quality JPG
$lqipImage->encode('webp', 5);
// LQIP filename
$lqip_filename = $post->slug.'-'.epoch_now_timestamp().'_lqip.jpg';
$lqip_filename = $post->slug.'-'.$epoch_now_timestamp.'_lqip.webp';
// Upload the LQIP version using OSSUploader
$lqip_ok = OSSUploader::uploadFile('r2', 'post_images/', $lqip_filename, (string) $lqipImage->stream('jpeg'));
$lqip_ok = OSSUploader::uploadFile('r2', 'post_images/', $lqip_filename, (string) $lqipImage->stream('webp'));
if ($ok && $lqip_ok) {

View File

@@ -69,9 +69,9 @@ public function getFeaturedImageLqipCdnAttribute()
$extension = pathinfo($this->featured_image, PATHINFO_EXTENSION);
// Append "_lqip" before the extension to create the LQIP image URL
$lqipFeaturedImage = str_replace(".{$extension}", "_lqip.{$extension}", $this->featured_image);
$lqipFeaturedImage = str_replace(".{$extension}", '_lqip.webp', $this->featured_image);
return 'https://'.Storage::disk('r2')->url($lqipFeaturedImage);
return 'https://'.Storage::disk('r2')->url($lqipFeaturedImage).'?a=bc';
}