Add (tint)
@@ -15,11 +15,11 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
$schedule->command('sitemap:generate')->daily();
|
||||
$schedule->command('sitemap:generate')->daily()->name('sitemap-generate-daily');
|
||||
|
||||
$schedule->call(function () {
|
||||
BrowseAndWriteWithAIJob::dispatch()->onQueue('default')->onConnection('default');
|
||||
})->dailyAt('00:00');
|
||||
})->everySixHours()->name('write-a-job-6hrs');
|
||||
|
||||
$schedule->call(function () {
|
||||
$future_post = Post::whereNotNull('published_at')->where('status', 'future')->where('published_at', '>=', now())->orderBy('published_at', 'ASC')->first();
|
||||
@@ -28,7 +28,7 @@ protected function schedule(Schedule $schedule): void
|
||||
PublishIndexPostJob::dispatch($future_post->id)->onQueue('default')->onConnection('default');
|
||||
}
|
||||
|
||||
})->everyMinute();
|
||||
})->everyMinute()->name('schedule-future-post');
|
||||
|
||||
}
|
||||
|
||||
|
||||
171
app/Helpers/FirstParty/ImageGen/ImageGen.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers\FirstParty\ImageGen;
|
||||
|
||||
use Image;
|
||||
|
||||
class ImageGen
|
||||
{
|
||||
public static function getMainImage($url, $width, $height)
|
||||
{
|
||||
$canvas = self::getBaseImage($url, 2.0, $width, $height);
|
||||
|
||||
$canvas = self::setImageTint($canvas, $width, $height);
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
|
||||
public static function getOpenGraphImage($url, $width, $height, $title = 'Title', $description = 'Description', $website = 'WWW.FUTUREWALKER.CO')
|
||||
{
|
||||
$canvas = self::getBaseImage($url, 2.0, $width, $height);
|
||||
|
||||
$canvas = self::setImageTint($canvas, $width, $height);
|
||||
|
||||
$canvas = self::setOgTint($canvas, $width, $height);
|
||||
|
||||
$canvas = self::setOgText($canvas, $title, $description, $website);
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
|
||||
private static function setOgText($canvas, $title, $description, $website)
|
||||
{
|
||||
$bold_font = resource_path('fonts/RobotoCondensed/RobotoCondensed-Bold.ttf');
|
||||
$font_color = '#ffffff'; // White color for the text
|
||||
|
||||
// Define font sizes
|
||||
$font_size_title = 65; // Size of the title text
|
||||
$font_size_description = 28; // Size of the description text
|
||||
$font_size_website = 28; // Size of the website text
|
||||
|
||||
// Define positions
|
||||
$title_position_y = $canvas->height() - 145; // Position for the title at one-third the height
|
||||
$description_position_y = $canvas->height() - 30;
|
||||
$website_position_y = $canvas->height() - 30;
|
||||
|
||||
// Title - wrapped to 2 lines if necessary, with ellipsis if there is excess text
|
||||
$wrappedTitle = wordwrap($title, 35, "\n", true); // Wrap the title
|
||||
$lines = explode("\n", $wrappedTitle); // Split the title into lines
|
||||
|
||||
// Adjust these variables as needed
|
||||
$lineHeight = 65; // The height of a line of text, adjust as needed for line spacing
|
||||
$titleStartPositionY = $title_position_y; // Starting Y position for the title, adjust if needed
|
||||
|
||||
// Check if there are more than 2 lines after wrapping
|
||||
if (count($lines) > 2) {
|
||||
$lines = array_slice($lines, 0, 2); // Keep only the first two lines
|
||||
$secondLine = &$lines[1]; // Reference to the second line
|
||||
// Check if the second line can fit an ellipsis; if not, trim the text
|
||||
if (strlen($secondLine) > 32) {
|
||||
$secondLine = substr($secondLine, 0, 32) . '...'; // Trim and add ellipsis
|
||||
} else {
|
||||
// Add ellipsis directly if there's enough space
|
||||
$secondLine .= '...';
|
||||
}
|
||||
}
|
||||
|
||||
// Now, render each line individually with adjusted line spacing
|
||||
foreach ($lines as $index => $line) {
|
||||
$currentLineY = $titleStartPositionY + ($index * $lineHeight);
|
||||
$canvas->text($line, 30, $currentLineY, function($font) use ($bold_font, $font_color, $font_size_title) {
|
||||
$font->file($bold_font);
|
||||
$font->size($font_size_title);
|
||||
$font->color($font_color);
|
||||
$font->align('left'); // Align text to the left
|
||||
$font->valign('bottom'); // Align text to the top of the current line position
|
||||
});
|
||||
}
|
||||
|
||||
// Description - justified to the left, below the title
|
||||
$canvas->text($description, 30, $description_position_y, function($font) use ($bold_font, $font_color, $font_size_description) {
|
||||
$font->file($bold_font);
|
||||
$font->size($font_size_description);
|
||||
$font->color($font_color);
|
||||
$font->align('left'); // Align text to the left
|
||||
$font->valign('bottom'); // Align text to the top (as it is below the title)
|
||||
});
|
||||
|
||||
// Website - justified to the right, at the bottom of the image
|
||||
$canvas->text($website, $canvas->width() - 30, $website_position_y, function($font) use ($bold_font, $font_color, $font_size_website) {
|
||||
$font->file($bold_font);
|
||||
$font->size($font_size_website);
|
||||
$font->color($font_color);
|
||||
$font->align('right'); // Align text to the right
|
||||
$font->valign('bottom'); // Align text to the bottom
|
||||
});
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static function setOgTint($canvas, $width, $height)
|
||||
{
|
||||
|
||||
$og_tint = Image::make(resource_path("images/tints/caption-bg.png"));
|
||||
|
||||
// Stretch the image to the given width and height
|
||||
$og_tint->resize($width, $height);
|
||||
|
||||
$canvas->insert($og_tint, 'top-left', 0, 0);
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
|
||||
private static function setImageTint($canvas, $width, $height)
|
||||
{
|
||||
/// ADD TINT
|
||||
// Define the directory path
|
||||
$directoryPath = resource_path('images/tints');
|
||||
|
||||
// Search for files starting with 'tint-' and count them
|
||||
$tintFilesCount = count(glob($directoryPath . '/tint-*'));
|
||||
|
||||
$tint_image = Image::make(resource_path("images/tints/tint-" . rand(1, $tintFilesCount) . ".png"));
|
||||
|
||||
// Stretch the image to the given width and height
|
||||
$tint_image->resize($width, $height);
|
||||
|
||||
$canvas->insert($tint_image, 'top-left', 0, 0);
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
|
||||
private static function getBaseImage($url, $scale = 1.8, $width = 1007, $height = 567)
|
||||
{
|
||||
$original_image = Image::make($url);
|
||||
|
||||
// Determine which dimension (width or height) is larger
|
||||
if ($original_image->width() > $original_image->height()) {
|
||||
// Width is larger, resize by width
|
||||
$original_image->resize($width, null, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
$constraint->upsize(); // Prevent upscaling
|
||||
});
|
||||
} else {
|
||||
// Height is larger or equal, resize by height
|
||||
$original_image->resize(null, $height, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
$constraint->upsize(); // Prevent upscaling
|
||||
});
|
||||
}
|
||||
|
||||
// Scale the image by 1.5x
|
||||
$scaled_width = $original_image->width() * $scale;
|
||||
$scaled_height = $original_image->height() * $scale;
|
||||
$original_image->resize($scaled_width, $scaled_height);
|
||||
|
||||
// Create an empty canvas
|
||||
$canvas = Image::canvas($width, $height);
|
||||
|
||||
// Calculate the position to center the scaled image
|
||||
$x = ($canvas->width() - $scaled_width) / 2;
|
||||
$y = ($canvas->height() - $scaled_height) / 2;
|
||||
|
||||
// Paste the scaled image onto the canvas at the center position
|
||||
|
||||
$canvas->insert($original_image, 'top-left', (int) $x, (int) $y);
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
}
|
||||
@@ -78,14 +78,14 @@ public function index(Request $request, $category_slug, $slug)
|
||||
OpenGraph::setUrl(url()->current());
|
||||
OpenGraph::addProperty('type', 'article');
|
||||
OpenGraph::addProperty('locale', 'en_US');
|
||||
OpenGraph::addImage($post->featured_image_cdn);
|
||||
OpenGraph::addImage($post->featured_og_image);
|
||||
|
||||
$jsonld_multi = JsonLdMulti::newJsonLd();
|
||||
$jsonld_multi->setTitle($post->title)
|
||||
->setDescription($post_description)
|
||||
->setType('Article')
|
||||
->addValue('headline', $post->title)
|
||||
->addImage($post->featured_image_cdn)
|
||||
->addImage($post->featured_og_image)
|
||||
->addValue('author', [
|
||||
'type' => 'Person',
|
||||
'name' => 'FutureWalker',
|
||||
@@ -96,7 +96,7 @@ public function index(Request $request, $category_slug, $slug)
|
||||
'name' => 'FutureWalker',
|
||||
'logo' => [
|
||||
'type' => 'ImageObject',
|
||||
'url' => asset('FutureWalker-logo-512x512.png'),
|
||||
'url' => asset('images/icons/icon-512x512.png'),
|
||||
],
|
||||
])
|
||||
->addValue('datePublished', $post->published_at->format('Y-m-d'))
|
||||
|
||||
@@ -6,9 +6,21 @@
|
||||
use Illuminate\Http\Request;
|
||||
use LaravelFreelancerNL\LaravelIndexNow\Facades\IndexNow;
|
||||
use LaravelGoogleIndexing;
|
||||
use App\Helpers\FirstParty\ImageGen\ImageGen;
|
||||
|
||||
|
||||
class TestController extends Controller
|
||||
{
|
||||
public function imageGen(Request $request)
|
||||
{
|
||||
$image_url = 'https://cdn.futurewalker.co/post_images_2/whats-next-for-openai-after-ceo-sam-altmans-ouster-1700439234754.jpg';
|
||||
|
||||
$canvas = ImageGen::getOpenGraphImage($image_url, 'What’s Next for OpenAI After CEO Sam Altman’s Ouster What’s Next for OpenAI After CEO Sam Altman’s Ouster', '20 NOV • OPENAI • SAM ALTMAN • 3 min read ');
|
||||
|
||||
return response($canvas->encode('jpeg'))
|
||||
->header('Content-Type', 'image/jpeg');
|
||||
}
|
||||
|
||||
public function indexing(Request $request)
|
||||
{
|
||||
$url = $request->input('url');
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs\Tasks;
|
||||
|
||||
use App\Helpers\FirstParty\ImageGen\ImageGen;
|
||||
use App\Helpers\FirstParty\OpenAI\OpenAI;
|
||||
use App\Helpers\FirstParty\OSSUploader\OSSUploader;
|
||||
use App\Jobs\SchedulePublishPost;
|
||||
@@ -184,6 +185,7 @@ private static function setPostImage($post)
|
||||
|
||||
$image_content = $image_response->body();
|
||||
|
||||
|
||||
// Get the size of the image content in KB
|
||||
$imageSizeInKb = strlen($image_response->body()) / 1024;
|
||||
|
||||
@@ -192,49 +194,20 @@ private static function setPostImage($post)
|
||||
continue;
|
||||
}
|
||||
|
||||
$canvas_width = 1080;
|
||||
$canvas_height = 608;
|
||||
$post_description = strtoupper(now()->format('j M')) . " • " . $post->main_keyword . " • " . markdown_min_read($post->body);
|
||||
|
||||
$thumb_width = 540;
|
||||
$thumb_height = 78;
|
||||
$image = ImageGen::getMainImage($image_content, 1007, 567);
|
||||
$og_image = ImageGen::getOpenGraphImage($image_content, 1007, 567, $post->title, $post_description);
|
||||
|
||||
// Create an image from the fetched content
|
||||
$image = Image::make($image_content);
|
||||
|
||||
// Check if the image is wider than it is tall (landscape orientation)
|
||||
if ($image->width() > $image->height()) {
|
||||
// Resize the image to fill the canvas width while maintaining aspect ratio
|
||||
$image->resize($canvas_width, null, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
});
|
||||
} else {
|
||||
// Resize the image to fill the canvas height while maintaining aspect ratio
|
||||
$image->resize(null, $canvas_height, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
});
|
||||
}
|
||||
|
||||
// Fit the image to the canvas size, without gaps
|
||||
$image->fit($canvas_width, $canvas_height, function ($constraint) {
|
||||
$constraint->upsize();
|
||||
});
|
||||
|
||||
// Create a thumbnail by cloning the original image and resizing it
|
||||
$thumb = clone $image;
|
||||
$thumb->resize($thumb_width, $thumb_height, function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
$constraint->upsize();
|
||||
});
|
||||
|
||||
// Create a image filename
|
||||
$epoch_now_timestamp = epoch_now_timestamp();
|
||||
$filename = $post->slug.'-'.$epoch_now_timestamp.'.jpg';
|
||||
$thumb_filename = $post->slug.'-'.$epoch_now_timestamp.'_thumb.jpg';
|
||||
$og_filename = $post->slug.'-'.$epoch_now_timestamp.'_og.jpg';
|
||||
|
||||
OSSUploader::uploadFile('r2', 'post_images_2/', $filename, (string) $image->stream('jpeg', 75));
|
||||
OSSUploader::uploadFile('r2', 'post_images_2/', $thumb_filename, (string) $thumb->stream('jpeg', 50));
|
||||
OSSUploader::uploadFile('r2', 'post_images/', $filename, (string) $image->stream('jpeg', 75));
|
||||
OSSUploader::uploadFile('r2', 'post_images/', $og_filename, (string) $og_image->stream('jpeg', 75));
|
||||
|
||||
$post->featured_image = 'post_images_2/'.$filename;
|
||||
$post->featured_image = 'post_images/'.$filename;
|
||||
$post->image_ref_url = $image_ref_url;
|
||||
|
||||
$image->destroy();
|
||||
|
||||
@@ -49,12 +49,24 @@ public static function handle(NewsSerpResult $news_serp_result, $serp_counts = 1
|
||||
continue;
|
||||
}
|
||||
|
||||
// check timestamp
|
||||
$serp_timestamp = Carbon::parse($serp_item->timestamp);
|
||||
if(!$serp_timestamp->isBetween(now()->subHours(6), now()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
$blacklist_keywords = config('platform.global.blacklist_keywords_serp');
|
||||
|
||||
$blacklist_domains = config('platform.global.blacklist_domains_serp');
|
||||
|
||||
$skipItem = false;
|
||||
|
||||
|
||||
|
||||
|
||||
foreach ($blacklist_domains as $domain) {
|
||||
if (str_contains($serp_item->domain, $domain)) {
|
||||
$skipItem = true;
|
||||
|
||||
@@ -81,7 +81,7 @@ protected function featuredImage(): Attribute
|
||||
);
|
||||
}
|
||||
|
||||
protected function getFeaturedThumbImageAttribute()
|
||||
protected function getFeaturedOgImageAttribute()
|
||||
{
|
||||
$value = $this->featured_image;
|
||||
|
||||
@@ -91,10 +91,9 @@ protected function getFeaturedThumbImageAttribute()
|
||||
// Extract the file extension
|
||||
$extension = pathinfo($value, PATHINFO_EXTENSION);
|
||||
|
||||
// Construct the thumbnail filename by appending '_thumb' before the extension
|
||||
$thumbnail = str_replace(".{$extension}", "_thumb.{$extension}", $value);
|
||||
$og = str_replace(".{$extension}", "_og.{$extension}", $value);
|
||||
|
||||
return $thumbnail;
|
||||
return $og;
|
||||
|
||||
// Return the full URL to the thumbnail image
|
||||
//return Storage::disk('r2')->url($thumbnail);
|
||||
|
||||
@@ -29,6 +29,9 @@ public function boot(): void
|
||||
});
|
||||
|
||||
$this->routes(function () {
|
||||
Route::middleware('web')
|
||||
->prefix('tests')
|
||||
->group(base_path('routes/tests.php'));
|
||||
Route::middleware('api')
|
||||
->prefix('api')
|
||||
->group(base_path('routes/api.php'));
|
||||
@@ -36,9 +39,6 @@ public function boot(): void
|
||||
Route::middleware('web')
|
||||
->group(base_path('routes/web.php'));
|
||||
|
||||
Route::middleware('web')
|
||||
->prefix('tests')
|
||||
->group(base_path('routes/tests.php'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
BIN
resources/.DS_Store
vendored
Normal file
BIN
resources/fonts/.DS_Store
vendored
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-Black.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-BlackItalic.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-Bold.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-BoldItalic.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-ExtraBold.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-ExtraLight.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-Italic.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-Light.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-LightItalic.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-Medium.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-MediumItalic.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-Regular.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-SemiBold.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-Thin.ttf
Normal file
BIN
resources/fonts/RobotoCondensed/RobotoCondensed-ThinItalic.ttf
Normal file
BIN
resources/images/.DS_Store
vendored
Normal file
BIN
resources/images/tints/.DS_Store
vendored
Normal file
BIN
resources/images/tints/caption-bg.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
resources/images/tints/tint-1.png
Normal file
|
After Width: | Height: | Size: 758 KiB |
BIN
resources/images/tints/tint-10.png
Normal file
|
After Width: | Height: | Size: 772 KiB |
BIN
resources/images/tints/tint-11.png
Normal file
|
After Width: | Height: | Size: 636 KiB |
BIN
resources/images/tints/tint-12.png
Normal file
|
After Width: | Height: | Size: 357 KiB |
BIN
resources/images/tints/tint-2.png
Normal file
|
After Width: | Height: | Size: 599 KiB |
BIN
resources/images/tints/tint-3.png
Normal file
|
After Width: | Height: | Size: 570 KiB |
BIN
resources/images/tints/tint-4.png
Normal file
|
After Width: | Height: | Size: 951 KiB |
BIN
resources/images/tints/tint-5.png
Normal file
|
After Width: | Height: | Size: 1022 KiB |
BIN
resources/images/tints/tint-6.png
Normal file
|
After Width: | Height: | Size: 939 KiB |
BIN
resources/images/tints/tint-7.png
Normal file
|
After Width: | Height: | Size: 611 KiB |
BIN
resources/images/tints/tint-8.png
Normal file
|
After Width: | Height: | Size: 958 KiB |
BIN
resources/images/tints/tint-9.png
Normal file
|
After Width: | Height: | Size: 563 KiB |
@@ -60,7 +60,7 @@
|
||||
<a class="text-white mx-3 font-family-roboto-condensed text-uppercase"
|
||||
href="{{ route('front.home') }}">Home</a>
|
||||
@foreach ($categories as $category)
|
||||
<a href="#"
|
||||
<a href="{{ route('front.category', ['category_slug' => $category->slug]) }}"
|
||||
class="text-white mx-3 font-family-roboto-condensed text-uppercase">{{ $category->name }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="position-sticky" style="top: 2rem;">
|
||||
<div class="position-sticky" style="top: 8rem;">
|
||||
@include('front.partials.sidebar')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<div>
|
||||
@foreach ($post->keywords as $keyword)
|
||||
@if ($keyword == $post->main_keyword)
|
||||
<span class="badge text-bg-dark me-1">{{ $keyword }}</span>
|
||||
<h2 class="badge text-bg-dark me-1 small">{{ $keyword }}</h2>
|
||||
@else
|
||||
<span class="badge text-bg-light border me-1">{{ $keyword }}</span>
|
||||
<h2 class="badge text-bg-light border me-1 small">{{ $keyword }}</h2>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<div class="card mb-3 border-0 shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-bold mb-2">Quick News Bite:</div>
|
||||
<h3 class="small fw-bold mb-2">Quick News Bite:</h3>
|
||||
<div><small>{{ $post->bites }}</small></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,7 +48,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="position-sticky" style="top: 2rem;">
|
||||
<div class="position-sticky" style="top: 8rem;">
|
||||
@include('front.partials.sidebar')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<div class="col-12 col-md-10 col-lg-8">
|
||||
<div class="display-6 fw-bold font-family-roboto-condensed mb-2">Your future depends<wbr> on today's
|
||||
news.</div>
|
||||
<div class="h4 fw-normal mb-4">In the fast-evolving world of AI and tech, staying updated is not
|
||||
<h1 class="h4 fw-normal mb-4">In the fast-evolving world of AI and tech, staying updated is not
|
||||
optional—it's critical for your future success. Stay updated with daily news from
|
||||
<strong>FutureWalker</strong>.
|
||||
</div>
|
||||
</h1>
|
||||
<a href="#latest-news" class="btn btn-primary px-4 rounded-pill text-decoration-none">Start reading now</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,7 +108,7 @@ class="btn btn-primary px-4 rounded-pill text-decoration-none">Discover More
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-4 mb-3">
|
||||
<div class="position-sticky" style="top: 2rem;">
|
||||
<div class="position-sticky" style="top: 8rem;">
|
||||
@include('front.partials.sidebar')
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
| be assigned to the "web" middleware group. Make something great!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::get('/image_gen', [App\Http\Controllers\Tests\TestController::class, 'imageGen']);
|
||||
|
||||
|
||||
Route::get('/incomplete/post', function (Request $request) {
|
||||
|
||||
$post = Post::find(1);
|
||||
|
||||