cviebrock / eloquent-sluggable

Easy creation of slugs for your Eloquent models in Laravel
MIT License
3.91k stars 461 forks source link

Conditionally force new slug #582

Closed rezaffm closed 2 years ago

rezaffm commented 2 years ago

Hi,

Thanks again for this awesome package, I use it quite a lot.

Just one question, let's say we have a model that is saved with some kind of auto generated title like "Auto Draft" which then has a slug like "auto-draft", "auto-draft-2" et cetera as slug and the corresponding status which is always "auto-draft".

I was trying to find a solution by hooking into Eloquent Events to force an auto creation of the Slug once it starts with "auto-draft", but had no success.

I know there is:

SlugService::createSlug($post, 'slug', $value);

That I could for instance hook into the eloquent updating event but I was wondering if there might be a better solution?

Thank You

cviebrock commented 2 years ago

Apologies for the slow response. I'm just trying to clarify what you want to achieve.

When your model is saved in a draft state, it gets a slug of auto-draft (based on the title and status at the time of saving), right? And more draft models get incrementing slugs like auto-draft-2, etc..

But what you want to do is ... what exactly? Have those draft models not slugged? If you want to only slug models once they are in a non-draft state, you could use the events:

Post::registerModelEvent('slugging', static function($post) {
    if ($post->status === 'draft') {
        // the model won't be slugged
        return false;
    }
});

If you want to have different slug sources depending on the status, you might be best served with a custom getter on the model, and then use that as your source. Something like:

class Post extends Model
{
    use Sluggable;

    public function sluggable(): array
    {
        return [
            'slug' => [
                'source' => 'slugTitle'
            ]
        ];
    }

    public function getSlugTitleAttribute()
    {
        if ($this->status === 'draft') {
           return 'DRAFT POST ' . $this->title;
        }
        return $this->title;
    }

}

If you need something else ... sorry for not understanding your question. If it's not too late, maybe you can clarify for me?

Thanks!

rezaffm commented 2 years ago

Hey, thanks for your answer pal.

I think I described a bit too difficult what I wanted to achieve.

The Posts work as follows: You create a post and to make it auto savable, a "dummy" post is created with the following props:

Title: Untitled status: auto-draft slug: untitled

Now my question was, if I set a new Title, for instance "Blog Post", is there an elegant way to force the re-slugging of the post.

I finally went another way, that the form is filled with no slug at all, so the user has to type in a new slug (actually it is created from the title) which then overwrites the slug.

Still, if there is a nice way to achieve that, this could be helpful.

cviebrock commented 2 years ago

Ah, I think I get it. You would probably best handle this with the events:

Post::registerModelEvent('slugging', static function($post) {
    if ($post->status === 'auto-draft') {
        // the model won't be slugged
        return false;
    }
});

When the Post is finally saved, then the slug should get auto-generated. This would require that the slug field in your table be nullable, which might not be ideal in some scenarios.

You could also (thinking out loud here ... untested), do something like give it a random slug for when you are auto-saving in auto-draft mode. Then, when you do a "real" save, clear out the slug field just before saving. A few more steps though.

Your solution seems pretty good too. Instead of making the user enter a slug manually, you could use the SlugService::createSlug method and an AJAX call to suggest a slug for them once they've filled in the title field.

I'll close this story now, as I think you're probably good to go. Again, sorry for the very slow response.

rezaffm commented 2 years ago

No worries, thanks for taking care.