Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

edgarkosul's avatar

How to move Blade string manipulation logic into a Livewire component?

In my Livewire component, I'm displaying a list of articles, and currently, I'm truncating the body field in my Blade template like this:

<p>{{ Illuminate\Support\Str::of(strip_tags($article->body))->limit(300) }}</p>

However, I'd like to move this logic from the Blade template into the Livewire component so that the data is already processed when passed to the view.

Here's the simplified version of my Livewire component:

<?php

namespace App\Livewire;

use Livewire\Component;
use App\Models\Article as Model;
use Illuminate\Support\Str;

class Article extends Component
{
    public function render()
    {
        return view('livewire.article', [
            'articles' => Model::paginate(6),
        ]);
    }
}

Question: What’s the best way to handle this kind of data manipulation in the Livewire component before sending it to the view? Should I process each article’s body field directly in the render() method, or is there a more efficient approach in Livewire?

Thanks for any guidance!

0 likes
23 replies
Snapey's avatar

personally, I would probably create an accessor method on the model to return the truncated body, and then in the view {{ $model->shortBody }}

edgarkosul's avatar

@Snapey Thank you for your response! Do you think this approach is correct for solving the issue? Here's what I did:

I didn't use an accessor because I would lose the ability to retrieve the full version of the body attribute. Instead, I created a method in the model:

public function shortBody()
{
    return Str::of(strip_tags(app(MarkdownRenderer::class)->toHtml($this->body)))
               ->limit(300, preserveWords: true);
}

Does this seem like a good solution?

Snapey's avatar

@edgarkosul

because I would lose the ability to retrieve the full version of the body attribute

That is ABSOLUTELY a false assumption.

You create an accessor with a different name so $model->body and $model->shortBody return different content.

But making a method works almost as well.

naden's avatar

It is possible, but hacky:

$articles = Article::paginate(6);

$articles->setCollection(
        $articles->getCollection()->map(function($article) {
                $article->body = str($article->body)->words(15);
                return $article;
        })
);
tykus's avatar

@naden the Paginator has a through method which allow mapping over the Collection of items:

$articles = Article::paginate(6)
    ->through(function($article) {
        $article->body = str($article->body)->words(15);
        return $article;
    });

As ever, there is more than one way to solve a problem, and I would echo @snapey above; the Accessor approach would also be my preference.

naden's avatar

@tykus nice1 and yes definitely would not do it that way

Snapey's avatar

@naden not a good idea to pointlessly loop over the collection.

naden's avatar

@Snapey I already wrote that it is hacky and I would not recommend doing that... so what is the point of your reply here?

Snapey's avatar

@naden they already loop in the view, no point in looping in controller also. Plus you forgot to strip tags which is important to not end up with unclosed html

naden's avatar

@Snapey no, this is just simplified and shows, what is possible not what is best practice.

MouteeSabouni's avatar

For this, I would suggest you create an accessor in your Article.php model, as it will automatically be called by Eloquent when attempting to retrieve the value of the body attribute. It would look something like this:

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str
 
class Article extends Model
{
    protected function shortBody(): Attribute
    {
        return Attribute::make(
            get: fn (string $value, array $attributes) => Str::of(strip_tags($attributes['body']))->limit(300), 
        );
    }
}

That way, you can simply change your code in blade to this:

<p>{{ $article->short_body }}</p>
MouteeSabouni's avatar
Level 11

One more thing I forgot to mention, you can also use the str helper function instead of Str::of and importing Illuminate\Support\Str at the top, I think.

    return Attribute::make(
            get: fn (string $value, array $attributes) => str(strip_tags($attributes['body']))->limit(300), 
    );
2 likes
jaseofspades88's avatar

Using an accessor on your model means you encapsulate all of the formatting to a specific function but it also means you don't risk duplicating the same functionality if you decide to put it on your Livewire component now, and then next week elsewhere.

I would also point out that Stringable has a stripTags method on it too, to help clean up your string manipulation.

edgarkosul's avatar

I still can't figure out how to get the accessor to specifically reference the body field in its getter.

The shortBody accessor doesn't seem to recognize the body field, but if I name it Body, it works just fine, though it messes up access to the full version.

I couldn't find anything in the Laravel docs to clear this up either.

MouteeSabouni's avatar

@edgarkosul I think the code I wrote for you above will work just fine. First, I just named the method body(), but of course, that way, you won't be able to access the full string of the body attribute.

Now, I named it shortBody(), and I passed the body attribute to it via the attributes array, which contains an array of all the model's current attributes.

MouteeSabouni's avatar

@edgarkosul Why don'y you simple use this approach?

    public function shortBody(): string
    {
        return str(strip_tags($this->body))->limit(300);
    }

That way, you just simply use $article->shortBody() in your blade.

Please or to participate in this conversation.