Panel AJAX in widget not working

I’m writing a plugin to allow a csv upload via an upload button and AJAX in the panel in Kirby v2. For some reason the ajax request always goes to /panel/login instead of the route I’m looking for. Here’s the key parts of the plugin:

# site/plugins/csv-importer/csv-importer.php
namespace Kirby\Plugins\CSVImporter;

use Response;
use Dir;

if (!function_exists('panel')) return;

// Load widget
kirby()->set('widget', 'csv-importer', __DIR__ . DS . 'widgets' . DS . 'csv-importer');

    'pattern' => 'csv/import',
    'method' => 'POST',
    'action' => function() {

And after my html form in the widget template:

# site/plugins/csv-importer/template.php
    $.ajax('/panel/csv/import', {
        method: 'post',
        data: $form.serialize()
    .done(function(data) {
        console.log('post successful');
        console.log('data', data);

When I try to upload a CSV, the console shows me it was successful, but it tried to go to a different url:

post successful
data { ... url: "http://example.loc:3000/panel/login"}

Then it doesn’t complete and I have to login again if I change pages. Is my panel route not working? Does it need a CSRF passed? Thanks so much!

Your route shouldn’t contain the panel part. Make it something like


If you use the panel route, the router kicks in.

Ah! That helps, along with the beginning / on both the route and the ajax call. I’m not getting logged out anymore. Thank you!

Now it’s just giving a 404 not found with the ajax to /api/csv/import. Of course when I visit the url directly, outside the panel, it shouldn’t work because its not a POST method and it’s not through the panel, right? I don’t know how else to test.


I think you should probably also remove the leading slash, at least from the route, I have never used them in routes.

OK, I’ve removed that leading slash from the route. I’m thinking that adding the leading slash to the ajax request makes Kirby think I’m not asking for a panel route, which is probably why I get the 404. Otherwise I continue to get redirected to the /panel/login url via ajax.

From the console:

I don’t quite understand why this needs panel()->routes(), instead of just using $kirby->routes(), but then I haven’t done this stuff in a while…

I was trying to add another layer of security so the route couldn’t be accessed outside of the panel, but I think the following line will work just as well:

if(class_exists('Panel') && site()->user()) {...

Still not working. I’m watching the headers and seeing the kirby_session_auth=deleted after my ajax call. From what I’m reading in the forums this seems like something is interrupting the session fingerprinting?

Figured it out–I was calling csrf() in a hidden form field which was invalidating the current panel csrf. To get the current csrf I’m now using the following which I can see matches the body tag’s csrf.

<input type="hidden" name="csrf" value="<?= s::get('kirby_panel_csrf') ?>">

@texnixe maybe this deserves a new thread (but I don’t know how to split it). The panel ajax file upload is working well. Finally I’d like to use that progress bar that moves from the left to right at the top of the panel sometimes when a page is loading. Could I access that with JS?

app.isLoading() (true/false) starts/stops the progress bar.

1 Like