Skip to content

Commit

Permalink
Rework and expand Plugins Development section (#1922)
Browse files Browse the repository at this point in the history
* Rework plugin creation and setup page

* Clean up intro

* Add WIP plugin structure docs

* Add marketplace guide

* Fix TOC and next nav item

* Improve the create a plugin page further

* Fix the plugin structure files

* Improve the plugin structure section

* Refine wordings and improve the journey

* Fix comment wording in plugin structure

* Fine-tune the Admin Panel and Server API docs

* Fine-tune the plugin creation and structure docs

* Add guide to store and access data from a plugin

* WIP guides

* Fix breadcrumbs

* Improve intro

* Revert "Fix breadcrumbs"

This reverts commit 94124cc.

* Add "pass data" guide

* Add external resources section

* Fix broken link

* Convert "external resources" section to a callout

* Improve plugin middlewares example

* Improve lifecycle functions documentation

* Tweak links to Marketplace

* Remove unused guides links and add additional resources

* Add missing description SEO tags

* Fix blog link

* Clean up TOC to remove duplicates

* Remove Custom Fields from Dev as it's in Plugins

* Display h4s in secondary nav.

* Explain top-level vs. global getters

* Replace "boilerplate" with more accurate descriptions

* Explain hot reloading

* Remove a completed to-do

* Slightly format table

* Break down a sentence that was too long

* Fix bad component naming Tab → TabItem
  • Loading branch information
pwizla authored Dec 19, 2023
1 parent 2dcd3ba commit 437b666
Show file tree
Hide file tree
Showing 14 changed files with 1,132 additions and 119 deletions.
24 changes: 13 additions & 11 deletions docusaurus/docs/dev-docs/api/plugins/admin-panel-api.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
---
sidebar_label: Admin Panel API
pagination_prev: dev-docs/plugins/developing-plugins
pagination_prev: dev-docs/plugins/development/plugin-structure
toc_max_heading_level: 4
---

# Admin Panel API for plugins

A Strapi [plugin](/dev-docs/plugins) can interact with both the [back end](/dev-docs/api/plugins/server-api) or the front end of the Strapi app. The Admin Panel API is about the front end part, i.e. it allows a plugin to customize Strapi's [admin panel](/user-docs/intro).
A Strapi [plugin](/dev-docs/plugins) can interact with both the [back end](/dev-docs/api/plugins/server-api) and the front end of a Strapi application. The Admin Panel API is about the front end part, i.e. it allows a plugin to customize Strapi's [admin panel](/user-docs/intro).

The admin panel is a [React](https://reactjs.org/) application that can embed other React applications. These other React applications are the admin parts of each Strapi plugin.

To create a plugin that interacts with the Admin Panel API:

1. Create an [entry file](#entry-file).
2. Within this file, declare and export a plugin interface that uses the [available actions](#available-actions).
3. Require this plugin interface in a `strapi-admin.js` file at the root of the plugin package folder:
:::prerequisites
You have [created a Strapi plugin](/dev-docs/plugins/development/create-a-plugin).
:::

```js title="[plugin-name]/strapi-admin.js"
The Admin Panel API includes:

'use strict';
- an [entry file](#entry-file) which exports the required interface,
- [lifecycle functions](#lifecycle-functions) and the `registerTrad()` [async function](#async-function),
- and several [specific APIs](#available-actions) for your plugin to interact with the admin panel.

module.exports = require('./admin/src').default;
```
:::note
The whole code for the admin panel part of your plugin could live in the `/strapi-admin.js|ts` or `/admin/src/index.js|ts` file. However, it's recommended to split the code into different folders, just like the [structure](/dev-docs/plugins/development/plugin-structure) created by the `strapi generate plugin` CLI generator command.
:::

## Entry file

Expand Down
91 changes: 58 additions & 33 deletions docusaurus/docs/dev-docs/api/plugins/server-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,29 @@ title: Server API for plugins
sidebar_label: Server API
displayed_sidebar: devDocsSidebar
description: Strapi's Server API for plugins allows a Strapi plugin to customize the back end part (i.e. the server) of your application.
sidebarDepth: 3

---

# Server API for plugins

A Strapi [plugin](/dev-docs/plugins) can interact with the backend or the [frontend](/dev-docs/api/plugins/admin-panel-api) of the Strapi application. The Server API is about the backend part.
A Strapi [plugin](/dev-docs/plugins) can interact with both the back end and the [front end](/dev-docs/api/plugins/admin-panel-api) of a Strapi application. The Server API is about the back-end part, i.e. how the plugin interacts with the server part of a Strapi application.

:::prerequisites
You have [created a Strapi plugin](/dev-docs/plugins/development/create-a-plugin).
:::

The Server API includes:

- an [entry file](#entry-file) which export the required interface,
- [lifecycle functions](#lifecycle-functions),
- a [configuration](#configuration) API,
- the ability to add [cron](#cron) jobs,
- and the ability to [customize all elements of the back-end server](#backend-customization).

Creating and using a plugin interacting with the Server API consists of 2 steps:
Once you have declared and exported the plugin interface, you will be able to [use the plugin interface](#usage).

1. Declare and export the plugin interface within the [`strapi-server.js` entry file](#entry-file)
2. [Use the exported interface](#usage)
:::note
The whole code for the server part of your plugin could live in the `/strapi-server.js|ts` or `/server/index.js|ts` file. However, it's recommended to split the code into different folders, just like the [structure](/dev-docs/plugins/development/plugin-structure) created by the `strapi generate plugin` CLI generator command.
:::

## Entry file

Expand Down Expand Up @@ -81,7 +92,7 @@ module.exports = () => ({

## Configuration

`config` stores the default plugin configuration.
`config` stores the default plugin configuration. It loads and validates the configuration inputted from the user within the [`./config/plugins.js` configuration file](/dev-docs/configurations/plugins).

**Type**: `Object`

Expand Down Expand Up @@ -113,6 +124,10 @@ Once defined, the configuration can be accessed:
- with `strapi.plugin('plugin-name').config('some-key')` for a specific configuration property,
- or with `strapi.config.get('plugin.plugin-name')` for the whole configuration object.

:::tip
Run `yarn strapi console` or `npm run strapi console` to access the strapi object in a live console.
:::

## Cron

The `cron` object allows you to add cron jobs to the Strapi instance.
Expand Down Expand Up @@ -155,6 +170,12 @@ strapi.cron.jobs

## Backend customization

All elements of the back-end server of Strapi can be customized through a plugin using the Server API.

:::prerequisites
To better understand this section, ensure you have read through the [back-end customization](/dev-docs/backend-customization) documentation of a Strapi application.
:::

### Content-types

An object with the [content-types](/dev-docs/backend-customization/models) the plugin provides.
Expand Down Expand Up @@ -461,50 +482,54 @@ An object with the [middlewares](/dev-docs/configurations/middlewares) the plugi

**Example:**

```js title="./src/plugins/my-plugin/strapi-server.js"

"use strict";

module.exports = require('./server');
```
```js title="./src/plugins/my-plugin/server/middlewares/your-middleware.js"

```js title="./src/plugins/my-plugin/server/index.js"

const middlewares = require('./middlewares');
module.exports = () => ({
middlewares,
});
/**
* The your-middleware.js file
* declares a basic middleware function and exports it.
*/
'use strict';
module.exports = async (ctx, next) => {
console.log("your custom logic")
await next();
}
```

```js title="./src/plugins/my-plugin/server/middlewares/index.js"

const middlewareA = require('./middleware-a');
const middlewareB = require('./middleware-b');
/**
* The middleware function previously created
* is imported from its file and
* exported by the middlewares index.
*/
'use strict';
const yourMiddleware = require('./your-middleware');

module.exports = {
middlewareA,
middlewareB,
yourMiddleware
};
```

```js title="./src/plugins/my-plugin/server/middlewares/middleware-a.js"
```js title="./src/plugins/my-plugin/server/register.js"

module.exports = (options, { strapi }) => {
return async (ctx, next) => {
const start = Date.now();
await next();
const delta = Math.ceil(Date.now() - start);
/**
* The middleware is called from
* the plugin's register lifecycle function.
*/
'use strict';
const middlewares = require('./middlewares');

strapi.log.http(`${ctx.method} ${ctx.url} (${delta} ms) ${ctx.status}`);
};
module.exports = ({ strapi }) => {
strapi.server.use(middlewares.yourMiddleware);
};
```

## Usage

Once a plugin is exported and loaded into Strapi, its features are accessible in the code through getters. The Strapi instance (`strapi`) exposes top-level getters and global getters.
Once a plugin is exported and loaded into Strapi, its features are accessible in the code through getters. The Strapi instance (`strapi`) exposes both top-level getters and global getters:

While top-level getters imply chaining functions, global getters are syntactic sugar that allows direct access using a feature's uid:
- top-level getters imply chaining functions<br/>(e.g., `strapi.plugin('the-plugin-name').controller('the-controller-name'`),
- global getters are syntactic sugar that allows direct access using a feature's uid<br/>(e.g., `strapi.controller('plugin::plugin-name.controller-name')`).

```js
// Access an API or a plugin controller using a top-level getter
Expand Down
20 changes: 20 additions & 0 deletions docusaurus/docs/dev-docs/configurations/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ The `./src/index.js` file (or `./src/index.ts` file in a [TypeScript-based](/dev

The functions can be synchronous, asynchronous, or return a promise.

``` mermaid
flowchart TB
A([The Strapi application starts.]) --> B{"register()"}
B -- The Strapi application is setup. --> C
C{"bootstrap()"} -- The Strapi back-end server starts. --> D
D(Request)
D
click B "#register"
click C "#bootstrap"
click D "/dev-docs/backend-customization/requests-responses"
```

## Synchronous function

<Tabs groupId="js-ts">
Expand Down Expand Up @@ -147,6 +159,8 @@ It can be used to:
- load some [environment variables](/dev-docs/configurations/environment)
- register a [custom field](/dev-docs/custom-fields) that would be used only by the current Strapi application.

`register()` is the very first thing that happens when a Strapi application is starting. This happens _before_ any setup process and you don't have any access to database, routes, policies, or any other backend server elements within the `register()` function.

## Bootstrap

The `bootstrap` lifecycle function, found in `./src/index.js` (or in `./src/index.ts`), is called at every server start.
Expand All @@ -157,6 +171,12 @@ It can be used to:
- fill the database with some necessary data
- declare custom conditions for the [Role-Based Access Control (RBAC)](/dev-docs/configurations/rbac) feature

The `bootstrapi()` function is run _before_ the back-end server starts but _after_ the Strapi application has setup, so you have access to anything from the `strapi` object.

:::tip
You can run `yarn strapi console` (or `npm run strapi console`) in the terminal and interact with the `strapi` object.
:::

## Destroy

The `destroy` function, found in `./src/index.js` (or in `./src/index.ts`), is an asynchronous function that runs before the application gets shut down.
Expand Down
80 changes: 21 additions & 59 deletions docusaurus/docs/dev-docs/plugins/developing-plugins.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: Developing plugins
# description: todo
description: Generation introduction about Strapi plugins development
displayed_sidebar: devDocsSidebar
pagination_prev: dev-docs/plugins
pagination_next: dev-docs/api/plugins/admin-panel-api
pagination_next: dev-docs/plugins/development/create-a-plugin
---

# Developing Strapi plugins
Expand All @@ -12,76 +12,38 @@ pagination_next: dev-docs/api/plugins/admin-panel-api
This section is about developing Strapi plugins to use them as local plugins or to submit them to the Marketplace. Not what you're looking for? Read the [plugins introduction](/dev-docs/plugins) and find your use case and recommended section to read from there.
:::

Strapi allows the development of plugins that work exactly like the built-in plugins or 3rd-party plugins available from the Marketplace. Once created, your plugin can be:
Strapi allows the development of plugins that work exactly like the built-in plugins or 3rd-party plugins available from the [Marketplace](https://market.strapi.io). Once created, your plugin can be:

- used as a local plugin, working only with a specific Strapi project,
- or submitted to the [Marketplace](https://market.strapi.io) to be shared with the community.
- or [submitted to the Marketplace](https://market.strapi.io/submit-plugin) to be shared with the community.

The first step to developing a Strapi plugin is to create it using the CLI-based generator. Then you'll be able to leverage the [plugin APIs](#plugin-apis) to add features to your plugin.
👉 To start developing a Strapi plugin:

## Plugin creation

Strapi provides a [command line interface (CLI)](/dev-docs/cli) for creating plugins. To create a plugin:

1. Navigate to the root of a Strapi project.
2. Run `yarn strapi generate` or `npm run strapi generate` in a terminal window to start the interactive CLI.
3. Choose "plugin" from the list, press Enter, and give the plugin a name in kebab-case (e.g. `my-plugin`)
4. Choose either `JavaScript` or `TypeScript` for the plugin language.
5. Create a plugins configuration file if one does not already exist: `./config/plugins.js` or `./config/plugins.ts` for TypeScript projects.
6. Enable the plugin by adding it to the [plugins configurations](/dev-docs/configurations/plugins) file:

<Tabs>
<TabItem value="js" label="JavaScript">

```js title="./config/plugins.js"
module.exports = {
// ...
"my-plugin": {
enabled: true,
resolve: "./src/plugins/my-plugin", // path to plugin folder
},
// ...
};
```

</TabItem>

<TabItem value="ts" label="TypeScript">

```js title=./config/plugins.ts
export default {
// ...
"my-plugin": {
enabled: true,
resolve: "./src/plugins/my-plugin", // path to plugin folder
},
// ...
};
```

</TabItem>
</Tabs>

7. Run `npm install` or `yarn` in the newly-created plugin directory.
8. (_TypeScript-specific_) Run `yarn build` or `npm run build` in the plugin directory. This step transpiles the TypeScript files and outputs the JavaScript files to a `dist` directory that is unique to the plugin.
9. Run `yarn build` or `npm run build` at the project root.
10. Run `yarn develop` or `npm run develop` at the project root.

Plugins created using the preceding directions are located in the `plugins` directory of the application (see [project structure](/dev-docs/project-structure)).

:::note
During plugin development it is helpful to use the `--watch-admin` flag to toggle hot reloading of the admin panel. See the [Admin panel customization](/dev-docs/admin-panel-customization) documentation for more details. (TypeScript specific) While developing your plugin, you can run `yarn develop --watch-admin` or `npm run develop -- --watch-admin` in the plugin directory to watch the changes to the TypeScript server files. From 4.15.1 this is no longer required.
:::
1. [Create a plugin](/dev-docs/plugins/development/create-a-plugin) using the CLI-based generator.
2. Learn more about the [structure of a plugin](/dev-docs/plugins/development/plugin-structure).
3. Get an overview of the [plugin APIs](#plugin-apis) to add features to your plugin.
4. Read some [guides](#guides) based on your use case(s).

## Plugin APIs

Strapi provides the following programmatic APIs for plugins to hook into some of Strapi's features:

<CustomDocCardsWrapper>
<CustomDocCard emoji="" title="Server API" description="Use the Server API to have your plugin interact with the backend server of Strapi." link="/dev-docs/api/plugins/server-api" />
<CustomDocCard emoji="" title="Admin Panel API" description="Use the Admin Panel API to have your plugin interact with the admin panel of Strapi." link="/dev-docs/api/plugins/admin-panel-api" />
<CustomDocCard emoji="" title="Server API" description="Use the Server API to have your plugin interact with the backend server of Strapi." link="/dev-docs/api/plugins/server-api" />
</CustomDocCardsWrapper>

:::strapi Custom fields plugins
Plugins can also be used to add [custom fields](/dev-docs/custom-fields) to Strapi.
:::

## Guides

<CustomDocCard small emoji="💁" title="How to store and access data from a Strapi plugin" description="" link="/dev-docs/plugins/guides/store-and-access-data" />
<CustomDocCard small emoji="💁" title="How to pass data from the backend server to the admin panel with a plugin" description="" link="/dev-docs/plugins/guides/pass-data-from-server-to-admin" />

<br />

:::strapi Additional resources
The Strapi blog features a [tutorial series](https://strapi.io/blog/how-to-create-a-strapi-v4-plugin-server-customization-4-6) about creating a Strapi v4 'Todo' plugin. The [contributors documentation](https://contributor.strapi.io/) can also include additional information useful while developing a Strapi plugin.
:::
Loading

1 comment on commit 437b666

@vercel
Copy link

@vercel vercel bot commented on 437b666 Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

documentation – ./

documentation-git-main-strapijs.vercel.app
documentation-strapijs.vercel.app
docs-vercel-v4.strapi.io

Please sign in to comment.