https://twill.io logo
forNestedSlug()
# ❓questions
j
forNestedSlug() does not seem to work properly,
Copy code
public function forNestedSlug(
        string $nestedSlug,
        array $with = [],
        array $withCount = [],
        array $scopes = []
    ): ?TwillModelContract {
        $targetSlug = collect(explode('/', $nestedSlug))->last();

        $targetItem = $this->forSlug($targetSlug, $with, $withCount, $scopes);

        if (!$targetItem || $nestedSlug !== $targetItem->nestedSlug) {
            return null;
        }

        return $targetItem;
    }
When i explode it in my resolveRouteBinding and call forSlug it does work but the slugs in the cms are all wrong:
i
are you using the nested module controller?
What are the slugs looking like in the CMS?
j
Im using class PageController extends BaseModuleController So i guess BaseModuleController
Copy code
namespace App\Http\Controllers\Twill;

use A17\Twill\Http\Controllers\Admin\NestedModuleController as BaseModuleController;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use App\Models\Page;

class PageController extends BaseModuleController
{
    protected $moduleName = 'pages';

    protected function getLocalizedPermalinkBase(): array
    {
        return [
            "en" => "",
            "nl" => "",
        ];
    }

    protected $indexOptions = [
        'reorder' => true,
    ];
    protected $nestedItemsDepth = 6;

    protected function form($id, $item = null): array
    {
        $item = $this->repository->getById($id, $this->formWith, $this->formWithCount);

        $this->permalinkBase = $item->getAncestorsSlug();

        return parent::form($id, $item);
    }

    public function single(Page $page)
    {
        return view("site.pages.show", compact("page"));
    }
}
This is my controller
In my model is have use A17\Twill\Models\Behaviors\HasNesting; as is configured using the CLI
Copy code
public function resolveRouteBinding($slug, $field = null)
    {
        $targetSlug = collect(explode('/', $slug))->last();

        $page = app(PageRepository::class)->forSlug($targetSlug);

        abort_if(! $page, 404);

        return $page;
    }

    // #region routekey
    public function getLocalizedRouteKey($locale)
    {
        return $this->getNestedSlug($locale);
    }
This is currently what i use, i explode it myself to make it somewhat work on the frontend.
$this->permalinkBase = $item->getAncestorsSlug(); Before this was $this->permalinkBase = $item->ancestorsSlug; I was trying some things out.
Any idea what i'm doing wrong or where to look?
Have i made it that bad? 😛
i
sorry @jefsev I haven't been able to focus on this yet. @pboivin implemented this, he may be able to support if he has time
j
Np, ill dig a bit myself also. thanks for everything, really enjoying twill.
i
that's awesome to hear
excited to announce Twill 3 very soon now
p
Hi @jefsev, just to make sure I understand correctly, your issue is that in the CMS (under the title), the urls for nested pages are not shown correctly?
Like
mysite.com/second
instead of
mysite.com/first/second
?
j
dovendi.com/nl//kennisbank double / for no reason but the real problem is nested deeper: this is in the cms: dovendi.com/nl//wat-betaal-ik-voor-een-domeinnaam the correct url is: dovendi.com/nl/kennisbank/veelgestelde-vragen/wat-betaal-ik-voor-een-domeinnaam When using my lang toggle from the twill docs i get for my english slug: dovendi.com/en/kennisbank/veelgestelde-vragen/wat-betaal-ik-voor-een-domeinnaam so it only changed the local that's all which results in a 404
It's partly because i explode it myself $targetSlug = collect(explode('/', $slug))->last(); in my resolveRouteBinding i guess. But if i use forNestedSlug() in my routeBinding all nested slugs result in a 404
p
Ok, a couple things I can think of... I think this was an oversight in NestedModuleController... I think it doesn't include anything special to generate nested slugs in the admin. I think you're on the right track by overriding the
form
method. A quick test I just did
Copy code
php
    protected function form($id, $item = null)
    {
        $data = parent::form($id, $item);

        $data['baseUrl'] = $data['baseUrl'] . $data['item']->ancestorsSlug . '/';

        return $data;
    }
Not 100% sure why you're getting the double slash (//) in the first example
j
: array after form, gives an error for me. GIve me a minute ill test this
Ah i get: Declaration of App\Http\Controllers\Twill\PageController::form($id, $item = null) must be compatible with A17\Twill\Http\Controllers\Admin\ModuleController::form(?int $id, ?A17\Twill\Models\Contracts\TwillModelContract $item = null): array When going to a page in the cms
i
that's because you're on twill 3 so you need to add types in @pboivin example
j
id is type int nut how do i set $item type properly?
p
Strange... looking at your code at the top, I thought you were on Twill 2. Did you upgrade since then?
j
I upgraded a while back
strange thing is my version of protected function form worked without types
p
Try this
Copy code
php
    protected function form(?int $id, ?TwillModelContract $item = null): array
    {
        $data = parent::form($id, $item);

        $data['baseUrl'] = $data['baseUrl'] . $data['item']->ancestorsSlug . '/';

        return $data;
    }
j
Could not check compatibility between App\Http\Controllers\Twill\PageController::form(?int $id, ?App\Http\Controllers\Twill\TwillModelContract $item = null): array and A17\Twill\Http\Controllers\Admin\ModuleController::form(?int $id, ?\
Could not check compatibility between App\Http\Controllers\Twill\PageController::form(?int $id, ?App\Http\Controllers\Twill\TwillModelContract $item = null): array and A17\Twill\Http\Controllers\Admin\ModuleController::form(?int $id, ?A17\Twill\Models\Contracts\TwillModelContract $item = null): array, because class App\Http\Controllers\Twill\TwillModelContract is not available\
p
import TwillModelContract
use A17\Twill\Models\Contracts\TwillModelContract;
j
My man
😛
looks perfect in the cms
p
Awesome! Here's a nice little PR for you if you want to contribute on Github 🙂
j
Oeh
Ah one thing
When i go to EN lang in CMS the nested parts are still in the main lang: dovendi.com/en/veelgestelde-vragen/kennisbank/what-do-i-pay-for-a-domain-name
There is something in the docs:
Copy code
// for a specific locale:
$slug = $item->getAncestorsSlug($lang);
p
Not sure... try this?
Copy code
protected function form($id, $item = null)
    {
        $data = parent::form($id, $item);

        $data['localizedPermalinkBase'] = [
            "en" => $data['item']->ancestorsSlug,
            "nl" => $data['item']->ancestorsSlug,
        ];

        return $data;
    }
j
hehe you almost got me with no types. 🧐 but im sharp today
Hmm, issue stands. Also the lang toggle does not pick up on the translated slug. Don't know if that's connected.
p
The lang toggle seems to work here...
j
For me only when going nl/page/page not nl/page/page/page
Oh wait it's only one page
that's doing that
oh man this is weird.
oke the problem is something else
It's switching the nested part
dovendi.com/nl/veelgestelde-vragen/kennisbank/wat-betaal-ik-voor-een-domeinnaam <-- this page works but the slug is not like i nested it in the cms. The lang toggle works on the wrong slug. This is how it's shown now in the cms. should be dovendi.com/nl/kennisbank/veelgestelde-vragen/wat-betaal-ik-voor-een-domeinnaam <-- this is how i nested it in the cms useing the drag en drop. This is the correct url but the lang toggle does not work and the cms shows the first one where it switched .
en/frequently-asked-questions/knowledge-base/what-do-i-pay-for-a-domain-name <-- wrong slug, works with toggle and shown in cms en/knowledge-base/frequently-asked-questions/what-do-i-pay-for-a-domain-name <-- correct slug how it's nested. lang toggle does not work, not shown in cms as permalink.
i
are you sure your nested tree is correct in db? the nested-set package has a command to verify and fix it.
j
I have to check again. Im currently not on my pc where i can check that. Ill check that after diner, let's hope that fixes the problem. Thx alot @pboivin !
Database is correct is i query the page_slugs table based on parent and parent of parent it is correct. Ill check tomorrow again i was working on a piece of code to get it from the page_slugs table. I think it goes wrong in the page and page_translation table.
i
the parent_is is always correct, I'm talking about the columns added by the nestedset package
j
_lft or _rgt
I have not figured out yet how to fix it using the docs of the nested set package. 🫣
j
thx! Seems fine:
Copy code
array:4 [▼ // resources/views/site/pages/show.blade.php
  "oddness" => 0
  "duplicates" => 0
  "wrong_parent" => 0
  "missing_parent" => 0
]
every page also nested 3 deep which gives the problem returns this.
My biggest problem now is that my language toggle is not getting the proper url when nested 3 deep. the CMS is not that bad.
i
any way you could share a repro? It's hard to debug without knowing exactly how your routes, binding and controllers are setup
j
My hunch was that it's in this since ->ForNestedSlug() don't work so i added $targetSlug = collect(explode('/', $slug))->last(); and use forSlug(); ->ForNestedSlug() results in a 404 for all nested pages:
Copy code
public function resolveRouteBinding($slug, $field = null)
    {
        $targetSlug = collect(explode('/', $slug))->last();

        $page = app(PageRepository::class)->forSlug($targetSlug);

        abort_if(! $page, 404);

        return $page;
    }

    public function getLocalizedRouteKey($locale)
    {
        return $this->getNestedSlug($locale);
    }
Sure, you want a invite to the github repo?
You must have the coolest job that you have so much time to help us all with the your open source project 😎
Copy code
@foreach (LaravelLocalization::getSupportedLocales() as $localeCode => $properties)
                    <a rel="alternate" hreflang="{{ $localeCode }}"
                        href="{{ LaravelLocalization::getLocalizedURL($localeCode, null, [], true) }}"
                        class="block rounded-lg px-4 py-2 text-sm text-gray-500 hover:bg-gray-50 hover:text-gray-700 @if ($localeCode == app()->getLocale()) font-bold @endif">
                        {{ $properties['native'] }}
                    </a>
                @endforeach
Okay so ->forNestedSlug($slug); Only breaks when going more than 2 deep, than it's always a 404. http://127.0.0.1:8000/nl/kennisbank/\
Anyhow, im going to eat. You probably have weekend. Thanks for everything! Ill dig some more.
I added you to the private github repo.
p
Hi @jefsev , I ran into this same issue today. I think this could be caused by a small regression in the
HasNesting::getAncestorsSlug()
method. 3.x: https://github.com/area17/twill/blob/9a172c5ee02b5345e6a868163a6cdf9691cc1309/src/Models/Behaviors/HasNesting.php#L38 2.x: https://github.com/area17/twill/blob/226fdfe435ac1fdd1941979691a97194d9105952/src/Models/Behaviors/HasNesting.php#L41 Overriding the method on my model to the 2.x version seems to solve the issue in my case. I haven't tested this extensively... but I'm curious to know if you explored this further on your end?
j
Hi, i have tried a few things but none of them fixed it. Due to other projects coming up i just added redirects for the broken urls 🫣 But i will definitely try this out and keep you posted, in the coming days i have to add some smalle features to the website so i will try this out. Thx!
p
Cool, thanks!
j
So when i add the following to my model:
Copy code
/**
     * Returns the combined slug for all ancestors of this item.
     *
     * @param string|null $locale
     * @return string
     */
    public function getAncestorsSlug($locale = null)
    {
        return collect($this->ancestors->sortByDesc('position') ?? [])
            ->map(function ($i) use ($locale) { return $i->getSlug($locale); })
            ->implode('/');
    }

    public function resolveRouteBinding($slug, $field = null)
    {
        $page = app(PageRepository::class)->forNestedSlug($slug);

        abort_if(! $page, 404);

        return $page;
    }

    public function getLocalizedRouteKey($locale)
    {
        return $this->getAncestorsSlug($locale);
    }
It fixes the 404 errors for pages going deeper then 2 nested
So thats great already
But however the slug in the CMS is still messed up and the slug in the language toggle is just not translated, it shows the the current locale slug just with /nl/ or /en/ in front of it
Copy code
/**
     * Returns the combined slug for all ancestors of this item.
     *
     * @param string|null $locale
     * @return string
     */
    public function getAncestorsSlug($locale = null)
    {
        return collect($this->ancestors->sortByDesc('position') ?? [])
            ->map(function ($i) use ($locale) { return $i->getSlug($locale); })
            ->implode('/');
    }

    /**
     * Returns the combined slug for this item including all ancestors.
     *
     * @param string|null $locale
     * @return string
     */
    public function getNestedSlug($locale = null)
    {
        return collect([$this->getAncestorsSlug($locale), $this->getSlug($locale)])
            ->filter()
            ->implode('/');
    }

    public function resolveRouteBinding($slug, $field = null)
    {
        $page = app(PageRepository::class)->forNestedSlug($slug);

        abort_if(! $page, 404);

        return $page;
    }

    public function getLocalizedRouteKey($locale)
    {
        return $this->getNestedSlug($locale);
    }
So i moved getAncestorsSlug from twill 2, which you shared to my model. I also moved getNestedSlug to my model as that is relying on the first one. This seems to have fixed the languas toggle for me and the 404 issue with deeper nesting.
Only thing left is the problem that in the CMS the permalink ancestor is always in english also for the dutch locale. So the actual page slug is in the correct locale and the locale code en or nl but everything in between is always in english
Copy code
protected function form(?int $id, ?TwillModelContract $item = null): array
    {
        $item = $this->repository->getById($id, $this->formWith, $this->formWithCount);
 
        $this->permalinkBase = $item->ancestorsSlug;
 
        return parent::form($id, $item);
    }
Probably this part is the issue, i tried a couple things based on previous feedback in this chat but none seem to fix the issue
$item->ancestorsSlug seems to just ignore the locale completely
This issue persist on all levels of nesting
p
Hey @jefsev , thanks for taking the time to dig back into this! I'm glad this fixes the 404 issue for you too. As for the CMS permalink issue, I'm re-reading what I wrote here and I think it doesn't make sense : https://discord.com/channels/811936425858695198/1089991279334662215/1091014635207012403
The locale should be specified for each item:
Copy code
php
    protected function form(?int $id, ?TwillModelContract $item = null): array
    {
        $data = parent::form($id, $item);

        $data['localizedPermalinkBase'] = [
            'en' => $data['item']->getAncestorsSlug('en'),
            'fr' => $data['item']->getAncestorsSlug('fr'),
        ];

        return $data;
    }
j
Okay so that fixed most issue but one thing is strange and a bug. So i have: Kennisbank ( parent ) - Veelgestelde vragen ( parent ) -- Over eerder gebruikte domeinnamen <-- works --- Hoe komen jullie aan domeinnamen <-- works That nesting works now. But The one below which shares the two parents -- Algemene informatie over domeinnamen <-- works --- wat betaal.. <--- broken --- ik ben mijn.. <--- broken So the weird thing is when i drag --Algemene informatie over domeinnamen above -- Over eerder gebruikte domeinnamen than it reverses so always the first one with more nested children the children work and after that all te one with children don't work. For the broken one the ancestors ar in a wrong order so also the page gives 404 on the slug i want a finds it on the bad ordered slug.

https://cdn.discordapp.com/attachments/1089991279334662215/1110664106169618482/Screenshot_2023-05-23_at_22.17.38.png

p
@jefsev Is this a new issue? Like, since you modified
getAncestorsSlug()
?
j
Before the slugs in the CMS were always wrong but the actual slug on the frontend worked. Now i get a 404 because it forces the wrong slug so that's new yes
p
Ok... well, I'm looking at the
->sortByDesc('position')
from the 2.x version and I'm not sure I fully understand it. It came as a community contribution a bit after the
--handleNesting
feature. I forget what the reasoning was behind this fix.
j
the website i'm using is 3.0.0-rc3 if i remeber correctly
not upgrading for the forseeable future due to the DB prefix change 🫣
i
you should definitely upgrade, the db prefix change isn't mandatory and there's even a rector script to update your twill config file to not have to change anything
j
Ah, okay then i will look into that soon. I have not read the everything on it yet but that seems fine than. 🙂
Do you think that will fix the issue stated above?
i
probably not, but it definitely fix other issues
j
Okay, i'd better upgrade before i find those other issues 😛