19

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

Vineeth Vijayan
  • 1,215
  • 1
  • 21
  • 33
  • 3
    As per v1.1.7 its not possible. In future it may possible. https://github.com/laravel/nova-issues/issues/461 – Saumini Navaratnam Nov 21 '18 at 05:33
  • @SauminiNavaratnam The question is different than the issue you put in your comment, the question is related to ordering menu items which are shown in the left navbar. The GitHub issue you referred to is related to ordering records under each resource. – Mustafa Ehsan Alokozay Apr 09 '20 at 16:08

9 Answers9

32

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.

Prafulla Kumar Sahu
  • 9,321
  • 11
  • 68
  • 105
13

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

zeidanbm
  • 522
  • 4
  • 15
11

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,
    ]);
 }
Vineeth Vijayan
  • 1,215
  • 1
  • 21
  • 33
  • 1
    I'm using `__()` helper method along with `label()` and `singularLabel()` methods to translate the name of my Nova resources. It seems 2nd solution does not work in this scenario, as my resources are sorted alphabetically as opposed to the order I gave pass into `Nova::resources()`. – TheSETJ Dec 06 '20 at 06:55
4

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';
Cameron
  • 532
  • 3
  • 9
2

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!

Norman Huth
  • 519
  • 5
  • 16
0

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);


0

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.

0

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()
    );
}
-1

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

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 12 '23 at 16:31