Vineeth  Vijayan
Vineeth Vijayan

Reputation: 1275

Laravel Nova - Reorder left navigation menu items

In default the ordering of left menu items is in alphabetical order.

My client wants to order those menus manually. Any idea how to make it possible?

enter image description here

Go to answer

Upvotes: 20

Views: 15542

Answers (10)

Gazzer
Gazzer

Reputation: 4656

This is an quick and 'dirty' solution but it seems to work within groups. Put spaces in front of the names. They don't appear in the menus but are used for ordering.

public static function label(): string
{
    return ' Banana'; //two
}

public static function label(): string
{
    return 'Apple'; //three
}

public static function label(): string
{
    return '  Capybara'; //one
}

Upvotes: 0

user22364552
user22364552

Reputation: 1

please use methods and pass the request on them instead of hard-coding the $priority

Upvotes: -1

Maksim Gerasimenko
Maksim Gerasimenko

Reputation: 53

Before add to resource static property

 public static $priority = 1;

Then in NovaServiceProvider replace resource method

protected function resources()
{
    $namespace = app()->getNamespace();
    $resources = [];

    foreach ((new Finder)->in(app_path('Nova'))->files() as $resource) {
        $resource = $namespace.str_replace(
                ['/', '.php'],
                ['\\', ''],
                Str::after($resource->getPathname(), app_path().DIRECTORY_SEPARATOR)
            );

        if (is_subclass_of($resource, Resource::class) &&
            ! (new \ReflectionClass($resource))->isAbstract()) {
            $resources[] = $resource;
        }
    }

    Nova::resources(
        collect($resources)->sort(function ($a, $b) {
            return $a::$priority > $b::$priority;
        })->all()
    );
}

Upvotes: 0

Marek Gralikowski
Marek Gralikowski

Reputation: 1058

If You wondering how to sort groups using a custom sort algorithm here is the clean solution.

In NovaServiceProvider in boot() method just add a custom callback.

$order = array_flip(['Modules', 'Localization', 'Other', 'Settings']);

Nova::mainMenu(static function (Request $request, Menu $menu) use ($order): Menu {

    $resources = $menu->items->firstWhere('name', 'Resources');

    $resources->items = $resources->items->sort(
        fn (MenuGroup $a, MenuGroup $b): int => ($order[$a->name] ?? INF) <=> ($order[$b->name] ?? INF)
    );

    return $menu;
});

Using $order array you can easily control the position of every specific group. Groups that are not included in this array will be moved to the end of the menu. This behavior can be changed to a moving to the beginning by replacing INF with -INF.

Upvotes: 0

Prafulla Kumar Sahu
Prafulla Kumar Sahu

Reputation: 9703

You can do it in

App\Providers\NovaServiceProvider.php

add a method resources() and register the resources manually like

 protected function resources()
    {
        Nova::resources([
            User::class,
            Post::class,
        ]);
    }

Alternate

There is another way mentioned in this gist, this seems good too, but official documentation has no mention of it yet.

Resource

<?php

namespace App\Nova;

class User extends Resource
{
    /**
     * The model the resource corresponds to.
     *
     * @var string
     */
    public static $model = 'App\\User';

    /**
     * Custom priority level of the resource.
     *
     * @var int
     */
    public static $priority = 1;

    // ...
}

and in NovaServiceProvider

<?php

namespace App\Providers;

use Laravel\Nova\Nova;
use Laravel\Nova\Cards\Help;
use Illuminate\Support\Facades\Gate;
use Laravel\Nova\NovaApplicationServiceProvider;

class NovaServiceProvider extends NovaApplicationServiceProvider
{
   /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        Nova::sortResourcesBy(function ($resource) {
            return $resource::$priority ?? 99999;
        });
    }
}

This way you set priority of resource and based on priority you render the resource.

Upvotes: 32

Vineeth  Vijayan
Vineeth Vijayan

Reputation: 1275

There are two ways to achieve this:

  1. By setting priority to Resource
  2. Ordering Resource models in NovaServiceProvider

1. Priority Method

  • Add priority as in the following code in Resource model:
      public static $priority = 2;
    
  • Then update NovaServiceProvider like this:
    public function boot()
    {
        Nova::sortResourcesBy(function ($resource) {
            return $resource::$priority ?? 9999;
        });
    }
    

2. Ordering Resource models in NovaServiceProvider

In NovaServiceProvider, order Resource models like this:

protected function resources()
{
    Nova::resources([
        User::class,
        Post::class,
    ]);
 }

Upvotes: 12

Ibrahim Bakhsh
Ibrahim Bakhsh

Reputation: 47

to sort the groups:

add this to your resources:

    public static function groupOrder() {
            return 9999999;
        }

you can overwrite it by adding it to any member resource to downgrade it's order in the navigation tree:

    public static function groupOrder() {
            return 5;
        }

add this before returning at the end of resourcemanager (i hope i shouldn't have to overwrite this at this place):

    $arrSort = [];
    foreach ($navigation as $group => $resources) {
          $resourcesGruoupOrders = [];
          foreach ($resources as $aResource) {
                $resourcesGruoupOrders[] = $aResource::groupOrder();
          }
          $arrSort[] = min($resourcesGruoupOrders);
    }
          $navigation = json_decode(json_encode($navigation), true);
          array_multisort($navigation, SORT_ASC, SORT_NUMERIC, $arrSort);


Upvotes: 0

zeidanbm
zeidanbm

Reputation: 532

A cleaner way and tested on latest Nova 3.x. Also, this has been added to Nova since version 2.10+ All you need to do is add a static property on your nova classes. For example Clients will be:

/**
 * The side nav menu order.
 *
 * @var int
 */
public static $priority = 2;

Then after that you can use the NovaServiceProvider to tell nova to use your custom ordering. You can place the code in the boot method

public function boot()
{
    Nova::sortResourcesBy(function ($resource) {
        return $resource::$priority ?? 9999;
    });
}

**Reference Nova Private Repo

Upvotes: 14

Norman Huth
Norman Huth

Reputation: 568

Change /nova/resources/navigation.blade.php {{ $group }} to following:

{!! $group !!}

Now you can easily sort the groups as follows:

public static $group = '<span class="hidden">20</span>Music';

or

public static $group = '<span class="hidden">30</span>User';

Attention: You must convert special characters in the title!


With the links, it's a bit other.... First Method: dirty and ugly

You can change

{{ $resource::label() }}

to

{{ substr($resource::label(), 1) }}

Then you can sort the links by the first letter of the resource name.

  • AUser
  • BAlbum
  • CContact

Or a better Method for Links crate app/Nova/CustomResource.php:

<?php

namespace App\Nova;

use Illuminate\Support\Str;

abstract class CustomResource extends Resource
{
    public static $label = '';

    /**
     * @return string
     */
    public static function label()
    {
        if(static::$label) {
            return static::$label;
        }
        return Str::plural(Str::title(Str::snake(class_basename(get_called_class()), ' ')));
    }
}

Change /nova/resources/navigation.blade.php

{!!  $resource::label()  !!}

And in the Nova resource, extends this custom resource and You can use public static $label:

class Lyric extends CustomResource
{
    public static $label = '<span class="hidden">10</span>Lyrics';

     public static function singularLabel()
    {
        return __('Lyric');
    }

Attention: You must convert special characters in the title!

Upvotes: 2

Cameron
Cameron

Reputation: 554

you can use grouping if that helps. I know it's not a 100% fix but maybe it will help a bit.

public static $group = 'Admin';

Upvotes: 4

Related Questions