管理面板 API:导航与设置(Navigation & settings)

页面摘要: 在 register 中使用 addMenuLink 添加侧边栏链接。使用 addSettingsLink 既可创建新的设置板块(将 section 对象作为第一个参数传入),也可扩展已有的设置板块(传入 section id 字符串)。遗留的 createSettingSection 和 addSettingsLinks 方法已弃用。

插件可以自定义管理面板的导航侧边栏和设置页面,以便访问其功能。本页描述的所有函数都在你插件入口文件的 register 或 bootstrap 生命周期函数中调用。

WARNING

在深入阅读本页概念之前,请确保你已经:

导航侧边栏(菜单链接)

导航侧边栏是管理面板左侧的主菜单。插件可以使用 register 生命周期函数中的 addMenuLink() 方法向此侧边栏添加链接。

添加菜单链接

向导航侧边栏添加链接使用 addMenuLink() 函数,应通过插件的 register() 生命周期函数注册。

菜单链接接受以下参数:

ParameterTypeRequiredDescription
tostring✅链接应指向的路径(相对于管理面板根目录)(见 附加信息)
iconReact.ElementType✅在导航中显示的图标的 React 组件
intlLabelobject✅链接的标签,遵循 React Int'l 约定,包含:
  • id:用于插入本地化标签的 id
  • defaultMessage:链接的默认标签 | | permissions | Array<Permission> | ✅ | 控制链接可见性的权限对象数组。传入 [] 表示无限制。 | | Component | function | ❌ | 返回插件主页面组件动态 import() 的函数。页面模块必须将组件作为 default 导出。如果省略,则不会注册路由(仅标签条目)。 | | position | number | ❌ | 在菜单中的数字位置(数字越小越靠前) | | licenseOnly | boolean | ❌ | 如果为 true,显示一个 ⚡ 图标以表明该功能需要付费许可证(默认:false) | | target | string | ❌ | 标准锚点 target 属性(例如外部链接的 _blank) | | notificationsCount | number | ❌ | 显示在菜单标签旁的徽标计数 | | exact | boolean | ❌ | 活动链接匹配是否应精确匹配 |
NOTE

intlLabel.id 的值应对应于你位于 admin/src/translations/[locale].json 的翻译文件中的键。详见 管理面板本地化。

WARNING

permissions 参数仅控制链接在导航中是否可见。它不会保护页面本身。知道 URL 的用户仍可直接访问该页面。要完全保护插件路由,你还必须在页面组件内部检查权限,并在服务器端使用 actionProvider.registerMany 注册你的 RBAC 操作。有关完整演练,请参阅 插件的管理面板权限 指南。

JavaScript

import PluginIcon from './components/PluginIcon';

export default {
  register(app) {
    // highlight-start
    app.addMenuLink({
      to: `/plugins/my-plugin`,
      icon: PluginIcon,
      intlLabel: {
        id: 'my-plugin.plugin.name',
        defaultMessage: 'My Plugin',
      },
      Component: () => import('./pages/App'),
      permissions: [], // Array of permission objects
      position: 3, // Position in the menu (lower numbers appear first)
      licenseOnly: false, // Set to true to show ⚡ icon for paid features
    });
    // highlight-end

    app.registerPlugin({
      id: 'my-plugin',
      name: 'My Plugin',
    });
  },
};

TypeScript

import PluginIcon from './components/PluginIcon';
import type { StrapiApp } from '@strapi/admin/strapi-admin';

export default {
  register(app: StrapiApp) {
    // highlight-start
    app.addMenuLink({
      to: `/plugins/my-plugin`,
      icon: PluginIcon,
      intlLabel: {
        id: 'my-plugin.plugin.name',
        defaultMessage: 'My Plugin',
      },
      Component: () => import('./pages/App'),
      permissions: [], // Array of permission objects
      position: 3, // Position in the menu (lower numbers appear first)
      licenseOnly: false, // Set to true to show ⚡ icon for paid features
    });
    // highlight-end

    app.registerPlugin({
      id: 'my-plugin',
      name: 'My Plugin',
    });
  },
};
NOTE

Component 所引用的页面模块必须将组件作为 默认导出(例如 admin/src/pages/App.tsx 中的 export default App;)。早期版本的 Strapi 接受返回具名导出的 async 回调,但该模式已弃用,并在运行时会记录警告。请使用 Component: () => import(path),以便动态导入直接解析到模块的默认导出。

设置(Settings)

设置 API 允许插件创建新的设置板块或向现有板块添加链接。设置板块是从导航侧边栏中的 Settings 菜单项可访问的配置页面的分组。

创建新的设置板块

要创建新的设置板块,请调用 addSettingsLink(),并将一个 section 对象({ id, intlLabel })作为第一个参数、一个链接对象数组作为第二个参数。这可以在 register 或 bootstrap 生命周期函数中完成:

JavaScript

export default {
  register(app) {
    // highlight-start
    app.addSettingsLink(
      {
        id: 'my-plugin',
        intlLabel: {
          id: 'my-plugin.settings.section-label',
          defaultMessage: 'My Plugin Settings',
        },
      },
      [
        {
          intlLabel: {
            id: 'my-plugin.settings.general',
            defaultMessage: 'General',
          },
          id: 'general',
          to: 'my-plugin/general',
          Component: () => import('./pages/Settings/General'),
        },
        {
          intlLabel: {
            id: 'my-plugin.settings.advanced',
            defaultMessage: 'Advanced',
          },
          id: 'advanced',
          to: 'my-plugin/advanced',
          Component: () => import('./pages/Settings/Advanced'),
        },
      ],
    );
    // highlight-end

    app.registerPlugin({
      id: 'my-plugin',
      name: 'My Plugin',
    });
  },
};

TypeScript

import type { StrapiApp } from '@strapi/admin/strapi-admin';

export default {
  register(app: StrapiApp) {
    // highlight-start
    app.addSettingsLink(
      {
        id: 'my-plugin',
        intlLabel: {
          id: 'my-plugin.settings.section-label',
          defaultMessage: 'My Plugin Settings',
        },
      },
      [
        {
          intlLabel: {
            id: 'my-plugin.settings.general',
            defaultMessage: 'General',
          },
          id: 'general',
          to: 'my-plugin/general',
          Component: () => import('./pages/Settings/General'),
        },
        {
          intlLabel: {
            id: 'my-plugin.settings.advanced',
            defaultMessage: 'Advanced',
          },
          id: 'advanced',
          to: 'my-plugin/advanced',
          Component: () => import('./pages/Settings/Advanced'),
        },
      ],
    );
    // highlight-end

    app.registerPlugin({
      id: 'my-plugin',
      name: 'My Plugin',
    });
  },
};

当用于创建新的板块时,addSettingsLink() 接受以下参数:

  • 第一个参数是板块配置:

    ParameterTypeRequiredDescription
    idstring✅设置板块的唯一标识符
    intlLabelobject✅板块的本地化标签,遵循 React Int'l 约定,包含:
  • id:用于插入本地化标签的 id
  • defaultMessage:板块的默认标签 |
  • 第二个参数是一个链接对象数组;每个链接对象包含以下内容:

    ParameterTypeRequiredDescription
    idstring✅设置链接的唯一标识符
    tostring✅相对于设置路由的路径(不要包含 settings/ 前缀)(见 附加信息)
    intlLabelobject✅包含 id 和 defaultMessage 的本地化标签对象
    permissionsArray<Permission>✅控制链接可见性的权限对象数组。传入 [] 表示无限制。
    Componentfunction❌返回设置页面组件动态 import() 的函数。页面模块必须将组件作为 default 导出。如果省略,则不会注册路由(仅标签条目)。
    positionnumber❌在板块内的数字位置(数字越小越靠前)
    licenseOnlyboolean❌如果为 true,显示一个 ⚡ 图标(默认:false)
    exactboolean❌活动链接匹配是否应精确匹配
Deprecated: `createSettingSection()`

专用的 app.createSettingSection(section, links) 方法已弃用。它仍然可用(内部委托给 addSettingsLink),但新代码应直接调用 addSettingsLink(section, links)。请参阅 已弃用的方法。

向现有设置板块添加链接

要向现有的设置板块添加链接,请在 bootstrap() 生命周期函数中使用 addSettingsLink(),并将一个 section id 字符串作为第一个参数。第二个参数可以是单个链接对象,也可以是链接对象数组。这两种形式都被同一方法支持。

JavaScript

export default {
  register(app) {
    app.registerPlugin({
      id: 'my-plugin',
      name: 'My Plugin',
    });
  },
  bootstrap(app) {
    // Add a single link to the global settings section
    // highlight-start
    app.addSettingsLink('global', {
      intlLabel: {
        id: 'my-plugin.settings.documentation',
        defaultMessage: 'Documentation',
      },
      id: 'documentation',
      to: 'my-plugin/documentation',
      Component: () => import('./pages/Settings/Documentation'),
      permissions: [],
      licenseOnly: false,
    });
    // highlight-end

    // Add multiple links at once to the global settings section
    // highlight-start
    app.addSettingsLink('global', [
      {
        intlLabel: {
          id: 'my-plugin.settings.general',
          defaultMessage: 'General',
        },
        id: 'general',
        to: 'my-plugin/general',
        Component: () => import('./pages/Settings/General'),
      },
      {
        intlLabel: {
          id: 'my-plugin.settings.advanced',
          defaultMessage: 'Advanced',
        },
        id: 'advanced',
        to: 'my-plugin/advanced',
        Component: () => import('./pages/Settings/Advanced'),
      },
    ]);
    // highlight-end
  },
};

TypeScript

import type { StrapiApp } from '@strapi/admin/strapi-admin';

export default {
  register(app: StrapiApp) {
    app.registerPlugin({
      id: 'my-plugin',
      name: 'My Plugin',
    });
  },
  bootstrap(app: StrapiApp) {
    // Add a single link to the global settings section
    // highlight-start
    app.addSettingsLink('global', {
      intlLabel: {
        id: 'my-plugin.settings.documentation',
        defaultMessage: 'Documentation',
      },
      id: 'documentation',
      to: 'my-plugin/documentation',
      Component: () => import('./pages/Settings/Documentation'),
      permissions: [],
      licenseOnly: false,
    });
    // highlight-end

    // Add multiple links at once to the global settings section
    // highlight-start
    app.addSettingsLink('global', [
      {
        intlLabel: {
          id: 'my-plugin.settings.general',
          defaultMessage: 'General',
        },
        id: 'general',
        to: 'my-plugin/general',
        Component: () => import('./pages/Settings/General'),
      },
      {
        intlLabel: {
          id: 'my-plugin.settings.advanced',
          defaultMessage: 'Advanced',
        },
        id: 'advanced',
        to: 'my-plugin/advanced',
        Component: () => import('./pages/Settings/Advanced'),
      },
    ]);
    // highlight-end
  },
};

addSettingsLink 以 sectionId 字符串作为第一个参数(例如 'global' 或 'permissions')。第二个参数是单个链接对象或链接对象数组,使用与 创建新的设置板块 中 links 数组相同的属性。

Deprecated: `addSettingsLinks()`

复数形式的 app.addSettingsLinks(sectionId, links) 方法已弃用。请改用 addSettingsLink(sectionId, links)(单数)并传入数组;它同时接受单个链接和数组。请参阅 已弃用的方法。

可用的设置板块

Strapi 提供了插件可以扩展的内置设置板块:

  • global:通用应用设置
  • permissions:管理面板设置
NOTE

创建新的设置板块通常在 register 生命周期函数中完成,而向现有设置板块添加链接则在 bootstrap 中完成(因为目标板块可能由另一个插件注册)。两种形式都调用同一个 addSettingsLink() 方法,该方法在 register 的 app 参数上暴露,也作为 bootstrap 参数包中的 addSettingsLink 暴露。

to 的路径约定

to 参数根据上下文的不同表现不同:

Contextto valueFinal URL
addMenuLink/plugins/my-pluginhttp://localhost:1337/admin/plugins/my-plugin
addSettingsLink(带 section 对象)my-plugin/generalhttp://localhost:1337/admin/settings/my-plugin/general
addSettingsLink(带 section id)my-plugin/documentationhttp://localhost:1337/admin/settings/my-plugin/documentation

对于菜单链接,路径相对于管理面板根目录(/admin)。对于设置链接,路径相对于设置路由(/admin/settings)。不要在设置链接路径中包含 settings/ 前缀。

Securing plugin routes

链接上的 permissions 参数仅控制其在导航中的可见性。要完全保护你的插件页面并注册 RBAC 操作,请参阅 插件的管理面板权限 指南。

已弃用的方法

StrapiApp 实例上的以下方法已弃用。它们出于向后兼容仍可使用(两者内部都委托给 addSettingsLink()),但新代码应直接使用 addSettingsLink()。

此前用于在一次调用中注册新的设置板块及其初始链接。

// ❌ Deprecated
app.createSettingSection(
  { id: 'my-plugin', intlLabel: { id: 'my-plugin.settings.section-label', defaultMessage: 'My Plugin Settings' } },
  [{ id: 'general', to: 'my-plugin/general', intlLabel: { id: 'my-plugin.settings.general', defaultMessage: 'General' }, Component: () => import('./pages/Settings/General') }],
);

// ✅ Replacement: pass the section object as the first argument to addSettingsLink
app.addSettingsLink(
  { id: 'my-plugin', intlLabel: { id: 'my-plugin.settings.section-label', defaultMessage: 'My Plugin Settings' } },
  [{ id: 'general', to: 'my-plugin/general', intlLabel: { id: 'my-plugin.settings.general', defaultMessage: 'General' }, Component: () => import('./pages/Settings/General') }],
);

此前用于在一次调用中向现有板块添加多个链接。单数形式的 addSettingsLink() 现在同时接受单个链接对象或数组。

// ❌ Deprecated
app.addSettingsLinks('global', [
  { id: 'general', to: 'my-plugin/general', intlLabel: { id: 'my-plugin.settings.general', defaultMessage: 'General' }, Component: () => import('./pages/Settings/General') },
  { id: 'advanced', to: 'my-plugin/advanced', intlLabel: { id: 'my-plugin.settings.advanced', defaultMessage: 'Advanced' }, Component: () => import('./pages/Settings/Advanced') },
]);

// ✅ Replacement: pass the array to addSettingsLink (singular)
app.addSettingsLink('global', [
  { id: 'general', to: 'my-plugin/general', intlLabel: { id: 'my-plugin.settings.general', defaultMessage: 'General' }, Component: () => import('./pages/Settings/General') },
  { id: 'advanced', to: 'my-plugin/advanced', intlLabel: { id: 'my-plugin.settings.advanced', defaultMessage: 'Advanced' }, Component: () => import('./pages/Settings/Advanced') },
]);
NOTE
  • addSettingsLinks 出于向后兼容仍暴露在 bootstrap 参数包中(与 addSettingsLink、getPlugin 和 registerHook 一同)。
  • createSettingSection 只能通过传入 register(app) 的完整 app 实例访问;它不是 bootstrap 参数包的一部分。
  • 两者内部都委托给 addSettingsLink(),并可能在未来的大版本中被移除。请在方便时进行迁移。