First Strapi SEO plugin
It's been a long time since I've posted an article and I can say that I missed it! Today, I am very happy to announce the release of the first Strapi SEO plugin!
Why?
It's true, why make an SEO plugin? I could have improved our FoodAdvisor demo application or updated our outdated tutorials on v4!
More seriously, many of you ask how to properly manage your content so that it is SEO friendly. Indeed, Strapi does not generate views as a traditional CMS would. It is therefore difficult to have the feeling of having a direct impact on SEO. On Strapi, which is a Headless CMS, you only have access to the data. What concerns the front-end, i.e, the formatting which must please the search engine, is another distinct part that the content manager/editor does not have direct access to.
However, ensuring that your content is SEO friendly can and should be done upstream, during creation. It would therefore be interesting for you to be able to ensure that your content meets a few SEO criteria in order to rank on the SERP. Well, this is what this article is all about!
Disclaimer: This plugin has been developed internally but many other SEO plugins will emerge on our marketplace. It's up to you to use the one that best suits your needs. In any case, know that the ExFabrica dev team is currently working on another SEO plugin that works differently but can be combined with the one I'm about to present to you, which is just awesome!
Key Features of the Strapi SEO Plugin
The Strapi SEO plugin is packed with powerful features to help you optimize your content effectively:
- Meta Tags Management: Easily manage meta titles, descriptions, and keywords directly within your content types.
- Social Media Integration: Support for Open Graph and Twitter Card metadata improves how your content appears when shared on platforms like Facebook and Twitter.
- Automatic XML Sitemap Generation: The plugin automatically generates and updates your sitemap, helping search engines index your content efficiently.
- Structured Data Implementation: Implement schema markup using JSON-LD to enable rich snippets in search results, enhancing visibility and click-through rates.
- Redirect Management: A built-in system allows you to handle redirects, manage broken links, and maintain your site's SEO value.
These features work together to provide a comprehensive SEO toolkit within your Strapi CMS, simplifying the optimization process and ensuring your content is search engine friendly.
How it works
The SEO plugin is divided into 2 parts:
Settings page This page will detect if you have a
seo
component in ashared
category (shared.seo
). For the v1 of this plugin, it was easier to define a classic and simple architecture in order to be able to reiterate more easily for a v2. Theshared
category means that it is a category of components containing components that can be shared among all the content-types of your application, which is the case of an SEO component.If such a component is not detected, then it will automatically import it inside your Strapi project.
Otherwise, the plugin will list the Content-Types of your application with or without the SEO component. You will then be able to add your component for each Content-Type, being careful to name it:
seo
and include it at the first level (root) of your CT.
- Modal in Content Manager It will then be possible for you from the content manager to have an SEO menu that will appear on the right in the right-links section when you have started to fill in your SEO component.
IMAGE
This menu contains 4 things:
- Browser preview button
This will open a modal containing a SERP preview of your content based on the metaTitle
and metaDescription
fields. You can see the web and mobile preview :)
- Social preview button
This will open a modal containing a Facebook or Twitter preview card based on your metaSocial
components in your content.
- A Summary of your SEO results
This allows you to quickly take a look at the results of SEO checks on your content. Note that you have to click on "SEE DETAILS" to update it.
- SEO Checks
The SEE DETAILS link button will open a modal containing all the SEO checks on your content. You'll be able to see what you can improve or fix for your content to be SEO friendly as it should be!
How was it created?
This part is for curious developers who wish to know how the plugin was developed. Before you start, know that you can find the source code on the official GitHub repository as well as its npm package page. I won't detail each file of the plugin but I want to introduce the basics of creating a simple plugin so that you can more easily create your own!
I redirect you to the documentation to learn more about the basics of plugin development.
It all starts with the following command:
1strapi generate
It will run a fully interactive CLI to generate APIs, controllers, content-types, plugins, policies, middlewares and services.
What interests us here is the creation of a plugin! Simply choose the name, and activate the plugin in the ./config/plugins.js
file of your Strapi application:
1module.exports = {
2 // ...
3 seo: {
4 enabled: true,
5 resolve: "./src/plugins/seo", // Folder of your plugin
6 },
7 // ...
8};
Server (back-end)
I needed for this plugin to have in the front some information from the back-end of Strapi. To do this, you just need to create routes in the back-end part of your plugin that will use controllers and services to fetch this information.
So I defined the following routes for the SEO plugin:
1// ./server/routes/index.js
2
3module.exports = [
4 {
5 method: "GET",
6 path: "/component",
7 handler: "seo.findSeoComponent",
8 config: {
9 auth: false,
10 policies: [],
11 },
12 },
13 {
14 method: "POST",
15 path: "/component",
16 handler: "seo.createSeoComponent",
17 config: {
18 auth: false,
19 policies: [],
20 },
21 },
22 {
23 method: "GET",
24 path: "/content-types",
25 handler: "seo.findContentTypes",
26 config: {
27 auth: false,
28 policies: [],
29 },
30 },
31];
Let's look in detail at the first route. The handler is the findComponent
action of the seo
controller:
1// ./server/controllers/index.js
2const seo = require("./seo");
3
4module.exports = {
5 seo,
6};
1// ./server/controllers/seo.js
2module.exports = {
3 // ...
4 findSeoComponent(ctx) {
5 ctx.body = strapi.plugin('seo').service('seo').getSeoComponent();
6 },
7 // ...
This action directly uses a function present in the seo
service:
1// ./server/services/index.js
2const seo = require("./seo");
3
4module.exports = {
5 seo,
6};
1// ./server/services/seo.js
2module.exports = ({ strapi }) => ({
3 // ...
4 getSeoComponent() {
5 const seoComponent = strapi.components['shared.seo'];
6 return seoComponent
7 ? { attributes: seoComponent.attributes, category: seoComponent.category }
8 : null;
9 },
10 // ...
11}
This service allows me to have access to the strapi
object containing a lot of information about my project, such as whether the shared.seo
component exists in my whole project.
Once the back-end is ready, all I have to do in the front-end (./admin/src/...
) of the plugin is to call this route to get the desired information.
1// ./admin/src/utils/api.js
2// ...
3const fetchSeoComponent = async () => {
4 try {
5 const data = await request(`/seo/component`, { method: "GET" });
6 return data;
7 } catch (error) {
8 return null;
9 }
10};
11// ...
Voila, this is how I can get information about my Strapi application in the front-end of my plugin! Simple isn't it?
Learn more about plugin development on our v4 documentation
Admin (front-end)
The admin panel is a React application that can embed other React applications. These other React applications are the admin parts of each Strapi plugin. As for the front-end, you must first start with the entry point: ./admin/src/index.js
.
This file will allow you to define more or less the behavior of your plugin. We can see several things:
1register(app) {
2 app.addMenuLink({
3 to: `/plugins/${pluginId}`,
4 icon: PluginIcon,
5 intlLabel: {
6 id: `${pluginId}.plugin.name`,
7 defaultMessage: 'SEO',
8 },
9 Component: async () => {
10 const component = await import('./pages/App');
11
12 return component;
13 },
14 });
15 app.registerPlugin({
16 id: pluginId,
17 initializer: Initializer,
18 isReady: false,
19 name,
20 });
21 },
First of all, there is a register function. This function is called to load the plugin, even before the app is actually bootstrapped. It takes the running Strapi application as an argument (app
).
Here it tells the admin to display a link in the Strapi menu for the plugin with a certain Icon, name, etc...
Then we find the bootstrap function:
1bootstrap(app) {
2 app.injectContentManagerComponent('editView', 'right-links', {
3 name: 'SeoChecker',
4 Component: SeoChecker,
5 });
6 },
This will expose the bootstrap function, executed after all the plugins are registered. Here we inject into the content manager a component that I created: SeoChecker
. This component contains the button opening the modal containing all the SEO checks in the content manager. I let you look at the code for more details.
Also, I redirect you to our documentation concerning the injection zones API.
Note: Know that it is possible to customize the admin using the injection zones API without having to generate a plugin. To do this, simply use the bootstrap function in your ./src/admin/app.js
file of your Strapi project to inject the components you want.
This is what was done on our demo FoodAdvisor, I redirect you to this file.
Back to our plugin!
The last part reffers to the translation management of your plugin:
1async registerTrads({ locales }) {
2 const importedTrads = await Promise.all(
3 locales.map((locale) => {
4 return import(`./translations/${locale}.json`)
5 .then(({ default: data }) => {
6 return {
7 data: prefixPluginTranslations(data, pluginId),
8 locale,
9 };
10 })
11 .catch(() => {
12 return {
13 data: {},
14 locale,
15 };
16 });
17 })
18 );
19
20 return Promise.resolve(importedTrads);
21 },
You will be able in the ./admin/src/translations
folder to add the translations you want. This plugin has been translated into French only for now. Feel free to add any other translations :)
For the rest, it is very simple React code, the beginning is in the file ./admin/src/pages/HomePage
. This file will contain the front-end of the plugin's Settings page. Then the part located in the content manager is managed by the SeoChecker
component.
I don't think it's useful in this article to go deeper into the code. If you are more curious then I leave you the freedom to look at the source code of the plugin and do not hesitate to give any feedback or to directly contribute to the plugin, you are more than welcome!
Troubleshooting Common Issues
While the Strapi SEO plugin is designed to integrate smoothly with your Strapi project, you may encounter some common issues. Here are solutions to help you resolve them.
Missing SEO Data in API Responses
If SEO data isn't appearing in your API responses, it's likely due to missing populate parameters in your queries. To include all SEO-related data, adjust your API requests:
1?populate=seo.metaImage,seo.metaSocial
For a more permanent solution, modify your controller to automatically include SEO data:
1module.exports = createCoreController('api::yourcontenttype.yourcontenttype', ({ strapi }) => ({
2 async find(ctx) {
3 const populateList = [
4 'seo.metaImage',
5 'seo.metaSocial'
6 ];
7
8 ctx.query.populate = populateList.join(',');
9 const content = await super.find(ctx);
10 return content;
11 }
12}));
Data Population Problems
If you experience issues like image URLs not displaying correctly or social metadata not appearing:
- Check Media Configurations: Ensure your media settings are correct, especially in production environments, to include proper backend URL prefixes.
- Verify Social Metadata Fields: Make sure all required fields in the social metadata section are filled out and that image paths are valid.
- Avoid Duplicate Records: Be cautious with multiple saves to prevent duplicate entries in your database.
Compatibility Concerns
To prevent compatibility issues between the SEO plugin and Strapi:
- Verify Versions Before Installation: Ensure the plugin version is compatible with your Strapi version.
- Update Dependencies: Keep both Strapi and the plugin updated to the latest stable versions.
- Test Before Upgrading: When planning to upgrade Strapi, test the plugin in a development environment to identify potential conflicts.
For additional support, visit the Strapi SEO Plugin GitHub Issues Page or join the Strapi Community Forum.
Conclusion and Next Steps
The Strapi SEO plugin provides a robust solution for optimizing your content's visibility in search engines, directly within your headless CMS workflow. By integrating SEO practices into your content creation process, you can improve your search rankings and reach a wider audience.
To get started with the Strapi SEO plugin:
- Install the Plugin: Download it from the Strapi Marketplace or the GitHub repository and follow the installation steps outlined earlier.
- Configure SEO Settings: Use the settings page to customize the SEO component and add it to your content types.
- Optimize Your Content: Leverage the plugin's features to manage meta tags, structured data, and preview your content's appearance in SERPs and on social media.
- Monitor and Improve: Regularly use the analysis tools to assess your content and make improvements based on the recommendations.
Additional Resources:
- Official Strapi Documentation: Explore detailed guides on plugin development and SEO best practices.
- Strapi Community Forum: Join discussions with other developers and share your experiences.
- Video Tutorials: Check out Strapi's video library for practical implementation tips.
By integrating the Strapi SEO plugin into your workflow and following best practices, you'll be well-equipped to enhance your website's search engine performance and visibility. Happy optimizing!
See you next time!
Maxime started to code in 2015 and quickly joined the Growth team of Strapi. He particularly likes to create useful content for the awesome Strapi community. Send him a meme on Twitter to make his day: @MaxCastres