Enable plugins to override panel routes

I would like to override a route that’s defined in the panel.
In particular the action for the “search” route in the panel. The way it’s implemented now freezes my apache. Probably because it calls $site->index or something similar and there are too many pages in the content folder. I would like to give my own search results.

At the moment, overriding panel urls is impossible, because the plugins are loaded before the routes. And the routes defined by plugins are merged with the default routes of the panel.

I’ve even tried by giving the panel class my own implementation of “Router”, but the plugins come before a router is set in the panel (therefore my custom router is discarded by the panel).

Giving plugin routes the priority would require a 1 line change in the panel class:

replace

    $this->routes = array_merge($this->routes, require($this->roots->config . DS . 'routes.php'));

with

    $this->routes = array_merge(require($this->roots->config . DS . 'routes.php'), $this->routes);

It should have no side effect with existing plugins. (there are no plugins yet that define a route that would override a panel route, because atm it would make no senso to do so, because it wouldn’t work).

You think a change like this would be possible?

As far as know this is already possible.
Have a look here for example. This one overwrites the default add form / modal for a specific page.

That one works because the patterns are different. "pages/talks/add" doesn’t get overridden by "pages/(:all)/add".
But the pattern for the search api is just "search".

However, reversing the merge like I suggested would mean that your route no longer gets executed because the router finds the general "pages/(:all)/add" route first.

This means that in fact it’s not as simple as reversing the array_merge, but one would have to write some logic.

1 Like

I see. I did a quick test. You can hijackin inernal routes by replacing the placeholder with an appropriate regex.

// toolkit/router.php

// The wildcard patterns supported by the router.
protected $patterns = array(
  '(:num)'     => '(-?[0-9]+)',
  '(:alpha)'   => '([a-zA-Z]+)',
  '(:any)'     => '([a-zA-Z0-9\.\-_%=]+)',
  '(:all)'     => '(.*)',
);

// The optional wildcard patterns supported by the router.
protected $optional = array(
  '/(:num?)'   => '(?:/([0-9]+)',
  '/(:alpha?)' => '(?:/([a-zA-Z]+)',
  '/(:any?)'   => '(?:/([a-zA-Z0-9\.\-_%=]+)',
  '/(:all?)'   => '(?:/(.*)',
);

So this one actually works.

panel()->routes(array(
  array(
    // 'pattern' => 'pages/(:all)/edit',
    'pattern' => 'pages/(.*)/edit',
    'method'  => 'GET',
    'action'  => function() {
      // do stuff
    },
  ),
));

Edit:
I just got it working for the search as well:

panel()->routes(array(
  array(
    // 'pattern' => 'search',
    'pattern' => '(search)',
    'method'  => 'GET|POST',
    'filter'  => array('auth'),
    'action'  => function() {
      // mimic search controller
    },
  ),
));
5 Likes

Oh, that’s clever :slight_smile:

Thanks - I will go that way with "(search)"