238 lines
8.5 KiB
PHP
238 lines
8.5 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Created by Reliese Model.
|
|
*/
|
|
|
|
namespace App\Models;
|
|
|
|
use AlAminFirdows\LaravelEditorJs\Facades\LaravelEditorJs;
|
|
use Carbon\Carbon;
|
|
use GrahamCampbell\Markdown\Facades\Markdown;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Spatie\Feed\Feedable;
|
|
use Spatie\Feed\FeedItem;
|
|
use Symfony\Component\DomCrawler\Crawler;
|
|
|
|
/**
|
|
* Class Post
|
|
*
|
|
* @property int $id
|
|
* @property string|null $title
|
|
* @property string|null $slug
|
|
* @property string|null $excerpt
|
|
* @property int|null $author_id
|
|
* @property string $featured_image
|
|
* @property string $editor
|
|
* @property array|null $body
|
|
* @property string $post_format
|
|
* @property int $comment_count
|
|
* @property int $likes_count
|
|
* @property string $status
|
|
* @property Carbon|null $created_at
|
|
* @property Carbon|null $updated_at
|
|
* @property Author|null $author
|
|
* @property Collection|PostCategory[] $post_categories
|
|
*/
|
|
class Post extends Model implements Feedable
|
|
{
|
|
protected $table = 'posts';
|
|
|
|
protected $casts = [
|
|
'author_id' => 'int',
|
|
'body' => 'json',
|
|
'comment_count' => 'int',
|
|
'likes_count' => 'int',
|
|
'featured' => 'bool',
|
|
'publish_date' => 'datetime',
|
|
];
|
|
|
|
protected $fillable = [
|
|
'title',
|
|
'slug',
|
|
'cliffhanger',
|
|
'excerpt',
|
|
'author_id',
|
|
'featured_image',
|
|
'editor',
|
|
'body',
|
|
'post_format',
|
|
'comment_count',
|
|
'likes_count',
|
|
'status',
|
|
'featured',
|
|
'publish_date',
|
|
];
|
|
|
|
protected $appends = [
|
|
//'html_body',
|
|
];
|
|
|
|
public function author()
|
|
{
|
|
return $this->belongsTo(Author::class);
|
|
}
|
|
|
|
public function post_categories()
|
|
{
|
|
return $this->hasMany(PostCategory::class);
|
|
}
|
|
|
|
public function post_category()
|
|
{
|
|
return $this->hasOne(PostCategory::class);
|
|
}
|
|
|
|
public function getHtmlBodyAttribute()
|
|
{
|
|
if (! is_empty($this->body)) {
|
|
if ($this->editor == 'editorjs') {
|
|
return LaravelEditorJs::render(json_encode($this->body));
|
|
} elseif ($this->editor == 'markdown') {
|
|
//dd($this->body);
|
|
|
|
$html = Markdown::convert($this->body)->getContent();
|
|
|
|
//dd($html);
|
|
|
|
$html = str_replace('\\n', "\n", $html);
|
|
|
|
$crawler = new Crawler($html);
|
|
|
|
$firstHeaderProcessed = false;
|
|
|
|
$crawler->filter('h1, h2, h3, h4, h5, h6')->each(function (Crawler $node) use (&$firstHeaderProcessed) {
|
|
$element = $node->getNode(0);
|
|
|
|
// Create a new h3 element
|
|
$newElement = $element->ownerDocument->createElement('h3');
|
|
|
|
// Copy attributes from the old header element to the new h3 element
|
|
foreach ($element->attributes as $attribute) {
|
|
$newElement->setAttribute($attribute->name, $attribute->value);
|
|
}
|
|
|
|
// Add the 'fw-bold' class to the new h3 element
|
|
$existingClasses = $element->getAttribute('class');
|
|
$newClass = 'fw-bold';
|
|
$updatedClasses = ($existingClasses ? $existingClasses.' ' : '').$newClass;
|
|
$newElement->setAttribute('class', $updatedClasses);
|
|
|
|
// Move child nodes from the old header element to the new h3 element
|
|
while ($element->firstChild) {
|
|
$newElement->appendChild($element->firstChild);
|
|
}
|
|
|
|
// Replace the old header element with the new h3 element in the DOM
|
|
$element->parentNode->replaceChild($newElement, $element);
|
|
|
|
// Only for the first header
|
|
if (! $firstHeaderProcessed) {
|
|
$firstHeaderProcessed = true;
|
|
|
|
$nextSibling = $newElement->nextSibling;
|
|
while ($nextSibling) {
|
|
if ($nextSibling->nodeType === XML_ELEMENT_NODE) {
|
|
if ($nextSibling->nodeName === 'p' && ($nextSibling->getElementsByTagName('img')->length > 0 || $nextSibling->getElementsByTagName('figure')->length > 0)) {
|
|
// Remove <p> if it contains an <img> or <figure> directly
|
|
$nextSibling->parentNode->removeChild($nextSibling);
|
|
break;
|
|
} elseif ($nextSibling->nodeName === 'img' || $nextSibling->nodeName === 'figure') {
|
|
// Direct <img> or <figure> without wrapping <p>
|
|
$newElement->parentNode->removeChild($nextSibling);
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
$nextSibling = $nextSibling->nextSibling;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Modify the DOM by wrapping the <img> tags inside a <figure> and adding the desired structure
|
|
$crawler->filter('img')->each(function (Crawler $node) {
|
|
$imgElement = $node->getNode(0);
|
|
|
|
// Update the class of the <img>
|
|
$existingClasses = $imgElement->getAttribute('class');
|
|
$newClasses = 'img-fluid rounded-2 shadow-sm mb-2';
|
|
$updatedClasses = ($existingClasses ? $existingClasses.' ' : '').$newClasses;
|
|
$imgElement->setAttribute('class', $updatedClasses);
|
|
|
|
// Create a new <figure> element
|
|
$figureElement = new \DOMElement('figure');
|
|
$imgElement->parentNode->insertBefore($figureElement, $imgElement);
|
|
|
|
// Move the <img> inside the <figure>
|
|
$figureElement->appendChild($imgElement);
|
|
$figureElement->setAttribute('class', 'image');
|
|
|
|
// Create a new <footer> element inside <figure> without directly setting its content
|
|
$footerElement = $imgElement->ownerDocument->createElement('footer');
|
|
$figureElement->appendChild($footerElement);
|
|
|
|
// Add the content to <footer> using createTextNode to ensure special characters are handled
|
|
$footerText = $imgElement->ownerDocument->createTextNode($imgElement->getAttribute('alt'));
|
|
$footerElement->appendChild($footerText);
|
|
|
|
// Set the class attribute for <footer>
|
|
$footerElement->setAttribute('class', 'image-caption');
|
|
});
|
|
|
|
|
|
// Add Bootstrap 5 styling to tables
|
|
$crawler->filter('table')->each(function (Crawler $node) {
|
|
$tableElement = $node->getNode(0);
|
|
$existingClasses = $tableElement->getAttribute('class');
|
|
$newClass = 'table';
|
|
$updatedClasses = ($existingClasses ? $existingClasses.' ' : '').$newClass;
|
|
$tableElement->setAttribute('class', $updatedClasses);
|
|
});
|
|
|
|
// Convert the modified DOM back to HTML
|
|
$updatedHtml = '';
|
|
foreach ($crawler as $domElement) {
|
|
$updatedHtml .= $domElement->ownerDocument->saveHTML($domElement);
|
|
}
|
|
|
|
return $updatedHtml;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
public function getFeaturedImageLqipAttribute()
|
|
{
|
|
$featuredImage = $this->featured_image;
|
|
|
|
// Get the extension of the original featured image
|
|
$extension = pathinfo($featuredImage, PATHINFO_EXTENSION);
|
|
|
|
// Append "_lqip" before the extension to create the LQIP image URL
|
|
return str_replace(".{$extension}", "_lqip.{$extension}", $featuredImage);
|
|
}
|
|
|
|
public function toFeedItem(): FeedItem
|
|
{
|
|
return FeedItem::create()
|
|
->id($this->id)
|
|
->title($this->title)
|
|
->summary($this->excerpt)
|
|
->updated($this->publish_date)
|
|
->link(route('home.country.post', ['country' => $this->post_category?->category?->country_locale_slug, 'post_slug' => $this->slug]))
|
|
->authorName($this->author->name);
|
|
}
|
|
|
|
public static function getFeedItems()
|
|
{
|
|
return Post::where('status', 'publish')->latest()->get();
|
|
}
|
|
}
|