The best and most secure way to achieve this is by using your Grav plugin to create a custom Admin route and controller, rather than linking directly to a raw PHP script. This leverages Grav’s built-in security and architecture.
Here is a breakdown of the recommended approach, which answers your questions.
The Better Way: Create a Custom Admin Route and Controller (Recommended)
Directly linking to a standalone PHP file is discouraged in a CMS environment like Grav because it bypasses the system’s authentication and initialization process, posing a security risk.
1. Where to Put Your PHP Script Logic (Controller)
Your server-related PHP tasks should be integrated into your plugin’s main PHP file (your-plugin-name.php) or a dedicated class file within your plugin. You will use Grav’s Event Hooks to execute this logic.
- Location:
user/plugins/your-plugin-name/your-plugin-name.php
2. What Would the URL / “Route” Be? Where to Define That?
You define the route and the logic that handles it within your plugin’s main PHP class.
A. Add the Navigation Link and Define the Route
Use the onAdminMenu() event in your plugin to register your new navigation item. This will automatically add the link to the Admin sidebar.
In user/plugins/your-plugin-name/your-plugin-name.php:
PHP
<?php
namespace Grav\Plugin;
use Grav\Common\Plugin;
use Grav\Common\Uri;
class YourPluginNamePlugin extends Plugin
{
/**
* @return array
*/
public static function getSubscribedEvents()
{
return [
'onAdminMenu' => ['onAdminMenu', 0],
'onPagesInitialized' => ['onPagesInitialized', 0],
];
}
public function onAdminMenu()
{
// Add a new item to the Admin sidebar navigation
$this->grav['twig']->plugins_hooked_nav['PLUGIN_YOUR_PLUGIN_NAME.MENU_TITLE'] = [
'route' => 'server-tasks', // <-- This is your custom route segment
'icon' => 'fa-tasks', // Use a FontAwesome icon
'authorize' => 'admin.super', // Restrict access to SuperUsers
'label' => 'Server Tasks',
];
}
// ... (Your custom link in the Twig template is now easier)
}
- Custom Route: The route you’ve defined is
server-tasks. The full Admin URL will be /admin/server-tasks.
B. Handle the Route and Execute the Task
Use the onPagesInitialized() event to intercept the request when a user visits your custom Admin URL and execute your PHP task logic.
In user/plugins/your-plugin-name/your-plugin-name.php (inside the YourPluginNamePlugin class):
PHP
public function onPagesInitialized()
{
// Only proceed if we are in the Admin and the custom route is requested
if ($this->isAdmin()) {
/** @var Uri $uri */
$uri = $this->grav['uri'];
// Check if the Admin path matches your custom route
if ($uri->path() == '/admin/server-tasks') {
// Prevent Grav from trying to look up a page based on this URL
$this->grav['admin']->disablePages();
// ----------------------------------------------------
// **EXECUTE YOUR SERVER TASK LOGIC HERE**
// ----------------------------------------------------
$output = $this->runServerTask();
// You can output the result directly or render a Twig template
echo "<h1>Server Task Report</h1><pre>" . htmlspecialchars($output) . "</pre>";
// Stop further Grav processing after outputting
exit();
}
}
}
protected function runServerTask()
{
// Your PHP script logic to perform server tasks goes here.
// E.g., executing a command-line utility:
// $result = shell_exec('php /path/to/your/cli/script.php');
return "Server task executed successfully.";
}
3. Updating the Twig Template (nav-quick-tray.html.twig)
Since you registered the menu item with onAdminMenu(), Grav’s Admin plugin will automatically render it in the sidebar. You typically do not need to manually override the entire nav-quick-tray.html.twig template just to add the link, unless you want to place it in a very specific custom location within that template.
If you must use a link within your custom nav-quick-tray.html.twig partial, you can use the route you defined:
Twig
<a href="{{ url('server-tasks') }}" class="button">
<i class="fa fa-fw fa-tasks"></i>
<span>Server Tasks</span>
</a>