From 5d22ee70ceb04eb0f5a81ebd507a4487bdd74e8d Mon Sep 17 00:00:00 2001 From: Nerox <150822437+NeroxTGC@users.noreply.github.com> Date: Sun, 20 Oct 2024 11:59:28 +0200 Subject: [PATCH 1/8] Update seo.md Added Other Pages Meta Tags & Structured data and Schema markup --- .../blog/src/content/docs/guides/seo.md | 176 +++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index fa63507c..86d138ca 100644 --- a/opensaas-sh/blog/src/content/docs/guides/seo.md +++ b/opensaas-sh/blog/src/content/docs/guides/seo.md @@ -30,7 +30,181 @@ app SaaSTemplate { Change the above highlighted meta tags to match your app. Wasp will inject these tags into the HTML of your `index.html` file, which is the Landing Page (`app/src/client/landing-page/LandingPage.tsx`), in this case. -This means you **do not** need to rely on a separate app or framework to serve your landing page for SEO purposes. +## Other Pages Meta Tags + +:::note[Important] +By default, all pages will acquire the main Landing Page meta tags. You can set custom meta tags for each page using `react-helmet-async`. +::: + +[React Helmet Async](https://github.com/staylor/react-helmet-async) is a thread-safe fork of React Helmet, serving as the React equivalent to [Next SEO](https://github.com/garmeeh/next-seo) for Next.js applications. If you're familiar with Next SEO, you'll find React Helmet Async follows similar patterns for managing meta tags in React applications. + +The first step is to install it: + +```bash +# Using npm +npm install react-helmet-async + +# Using yarn +yarn add react-helmet-async + +# Using pnpm +pnpm add react-helmet-async +``` + +Next, you need to wrap your main App component (`app/src/client/App.tsx`) with `HelmetProvider`: + +```jsx +//Add the react-helmet-async import +import { Helmet, HelmetProvider } from 'react-helmet-async'; + +//Wrap the main App component +export default function App() { + return ( + + <> +
+ {isAdminDashboard ? ( + + ) : ( + <> + {shouldDisplayAppNavBar && } +
+ +
+ + )} +
+ + +
+ ); +} +``` + +Now, you can set page-specific meta tags. + +```jsx {6-33) +//... +import { Helmet, HelmetProvider } from 'react-helmet-async'; + +export function MyCustomPage() { + return ( +
+ + My Custom Page Title + + + + {/* Open Graph / Facebook */} + + + + + + + {/* Twitter */} + + + + + + +
+ ); +} + +``` + +You can also handle tags like `noindex`/`nofollow`: +```jsx {12} +import { Helmet, HelmetProvider } from 'react-helmet-async'; + +export function MyCustomPage() { + return ( +
+ + My Custom Page Title + + + + //... + + + //... + ); +} +``` + +:::tip[Good SEO practice] +There are certain pages that it is good SEO practice not to index. They are divided into two groups: + +- Pages that do not add value (login, signup, password reset, ....). +- Legal pages: Privacy Policy, Cookies Policy, Terms and Conditions. +- Any other page that you consider should not be indexed (imagine that you create a page exclusively for ADS campaigns and for sure you don't want to receive organic traffic on it!). +::: + +## Structured data and Schema markup + +:::note[Tip] +Crawlers do all the work of analyzing and understanding the content of your pages, and they will thank you if you include structured data to help them understand what your content is about!๐Ÿค—. +::: + +You can add structured data for each page. + +```jsx {14-22} +//... +import { Helmet, HelmetProvider } from 'react-helmet-async'; + +export function MyCustomPage() { + return ( +
+ + My Custom Page Title + + + //... + + + + + //... +``` + + +These resources provide the information needed to get the most out of structured data: +- [Introduction to structured data markup](https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data) +- [General structured data guidelines](https://developers.google.com/search/docs/appearance/structured-data/sd-policies) + +After you have a small notion about them, you can go deeper by adding custom functions depending on your app (FAQs, Rating, Review, Software Application...): +- [ALL structured data functions](https://developers.google.com/search/docs/appearance/structured-data/search-gallery) + +To ensure that they are valid: +- [Google rich results test](https://search.google.com/test/rich-results) +- [Schema validator](https://validator.schema.org/) + +This means you **do not** need to rely on a separate app or framework to serve your pages for SEO purposes. :::tip[Star our Repo on GitHub! ๐ŸŒŸ] We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free! From 3c0883b8b8bcafd3f7982042a021c03000795d86 Mon Sep 17 00:00:00 2001 From: Nerox <150822437+NeroxTGC@users.noreply.github.com> Date: Sun, 20 Oct 2024 12:00:06 +0200 Subject: [PATCH 2/8] Update seo.md --- opensaas-sh/blog/src/content/docs/guides/seo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index 86d138ca..e05435f1 100644 --- a/opensaas-sh/blog/src/content/docs/guides/seo.md +++ b/opensaas-sh/blog/src/content/docs/guides/seo.md @@ -123,7 +123,7 @@ export function MyCustomPage() { } ``` - + You can also handle tags like `noindex`/`nofollow`: ```jsx {12} import { Helmet, HelmetProvider } from 'react-helmet-async'; From 250518909c3c9097dccc2aa904119d2ccf538b05 Mon Sep 17 00:00:00 2001 From: Nerox <150822437+NeroxTGC@users.noreply.github.com> Date: Sun, 20 Oct 2024 12:00:42 +0200 Subject: [PATCH 3/8] Update seo.md Added Other Pages Meta Tags & Structured data and Schema markup --- opensaas-sh/blog/src/content/docs/guides/seo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index e05435f1..a24b6bb8 100644 --- a/opensaas-sh/blog/src/content/docs/guides/seo.md +++ b/opensaas-sh/blog/src/content/docs/guides/seo.md @@ -80,7 +80,7 @@ export default function App() { ); } ``` - + Now, you can set page-specific meta tags. ```jsx {6-33) From 28227e144c79bb53ebeda90697d45ff53c898237 Mon Sep 17 00:00:00 2001 From: Leo Golubyev Date: Fri, 22 Nov 2024 12:36:30 +0100 Subject: [PATCH 4/8] Added Robots.txt & missing Alt attributes --- template/app/public/robots.txt | 6 ++++++ template/app/src/landing-page/components/Testimonials.tsx | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 template/app/public/robots.txt diff --git a/template/app/public/robots.txt b/template/app/public/robots.txt new file mode 100644 index 00000000..ef1378fa --- /dev/null +++ b/template/app/public/robots.txt @@ -0,0 +1,6 @@ +User-agent: * +Allow: / + +Disallow: /admin/ +Disallow: /api/ +Disallow: /auth/ diff --git a/template/app/src/landing-page/components/Testimonials.tsx b/template/app/src/landing-page/components/Testimonials.tsx index cd915b41..32516de7 100644 --- a/template/app/src/landing-page/components/Testimonials.tsx +++ b/template/app/src/landing-page/components/Testimonials.tsx @@ -22,7 +22,11 @@ export default function Testimonials({ testimonials }: { testimonials: Testimoni
- + {`Profile
{testimonial.name}
{testimonial.role}
From e16eeee403192d29047c9bf414a56164f17d541c Mon Sep 17 00:00:00 2001 From: Leo Golubyev Date: Fri, 22 Nov 2024 12:51:54 +0100 Subject: [PATCH 5/8] Update seo.md --- .../blog/src/content/docs/guides/seo.md | 56 ++++--------------- 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index a24b6bb8..92cd8b52 100644 --- a/opensaas-sh/blog/src/content/docs/guides/seo.md +++ b/opensaas-sh/blog/src/content/docs/guides/seo.md @@ -32,46 +32,39 @@ Change the above highlighted meta tags to match your app. Wasp will inject these ## Other Pages Meta Tags -:::note[Important] -By default, all pages will acquire the main Landing Page meta tags. You can set custom meta tags for each page using `react-helmet-async`. +React Helmet Async is a React library that allows you to modify `` directly from your React component, in a dynamic fashion. Therefore, it can also be used to set meta tags. + +:::note +Since Wasp is SPA, React Helmet Async updates `` via client-side JS after initial serve, meaning that web crawlers that don't evaluate JS won't pick up the modifications to the `` you did. ::: -[React Helmet Async](https://github.com/staylor/react-helmet-async) is a thread-safe fork of React Helmet, serving as the React equivalent to [Next SEO](https://github.com/garmeeh/next-seo) for Next.js applications. If you're familiar with Next SEO, you'll find React Helmet Async follows similar patterns for managing meta tags in React applications. The first step is to install it: ```bash # Using npm npm install react-helmet-async - -# Using yarn -yarn add react-helmet-async - -# Using pnpm -pnpm add react-helmet-async ``` Next, you need to wrap your main App component (`app/src/client/App.tsx`) with `HelmetProvider`: ```jsx //Add the react-helmet-async import -import { Helmet, HelmetProvider } from 'react-helmet-async'; +import {HelmetProvider } from 'react-helmet-async'; //Wrap the main App component export default function App() { - return ( + return ( <>
{isAdminDashboard ? ( ) : ( - <> {shouldDisplayAppNavBar && }
- )}
@@ -81,11 +74,11 @@ export default function App() { } ``` -Now, you can set page-specific meta tags. +Now, you can set page-specific meta tags in your React components. ```jsx {6-33) //... -import { Helmet, HelmetProvider } from 'react-helmet-async'; +import { Helmet } from 'react-helmet-async'; export function MyCustomPage() { return ( @@ -97,6 +90,8 @@ export function MyCustomPage() { content='This is the meta description of my page.' /> + + {/* Open Graph / Facebook */} @@ -123,35 +118,13 @@ export function MyCustomPage() { } ``` - -You can also handle tags like `noindex`/`nofollow`: -```jsx {12} -import { Helmet, HelmetProvider } from 'react-helmet-async'; - -export function MyCustomPage() { - return ( -
- - My Custom Page Title - - - - //... - - - //... - ); -} -``` :::tip[Good SEO practice] -There are certain pages that it is good SEO practice not to index. They are divided into two groups: +There are certain pages that it is good SEO practice not to index, for example: - Pages that do not add value (login, signup, password reset, ....). - Legal pages: Privacy Policy, Cookies Policy, Terms and Conditions. -- Any other page that you consider should not be indexed (imagine that you create a page exclusively for ADS campaigns and for sure you don't want to receive organic traffic on it!). +- Situational pages (e.g. page made for a specific campaign). ::: ## Structured data and Schema markup @@ -200,11 +173,6 @@ These resources provide the information needed to get the most out of structured After you have a small notion about them, you can go deeper by adding custom functions depending on your app (FAQs, Rating, Review, Software Application...): - [ALL structured data functions](https://developers.google.com/search/docs/appearance/structured-data/search-gallery) -To ensure that they are valid: -- [Google rich results test](https://search.google.com/test/rich-results) -- [Schema validator](https://validator.schema.org/) - -This means you **do not** need to rely on a separate app or framework to serve your pages for SEO purposes. :::tip[Star our Repo on GitHub! ๐ŸŒŸ] We've packed in a ton of features and love into this SaaS starter, and offer it all to you for free! From 27cba840ca93e182f368ca542ef1399a6a49367f Mon Sep 17 00:00:00 2001 From: Nerox <150822437+NeroxTGC@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:46:36 +0100 Subject: [PATCH 6/8] Update opensaas-sh/blog/src/content/docs/guides/seo.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin ล oลกiฤ‡ --- opensaas-sh/blog/src/content/docs/guides/seo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index 6e817914..4ade47d4 100644 --- a/opensaas-sh/blog/src/content/docs/guides/seo.md +++ b/opensaas-sh/blog/src/content/docs/guides/seo.md @@ -50,7 +50,7 @@ Next, you need to wrap your main App component (`app/src/client/App.tsx`) with ` ```jsx //Add the react-helmet-async import -import {HelmetProvider } from 'react-helmet-async'; +import { HelmetProvider } from 'react-helmet-async'; //Wrap the main App component export default function App() { From c984a062d78cb56eba907ed046022a14c8343f1b Mon Sep 17 00:00:00 2001 From: Nerox <150822437+NeroxTGC@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:46:59 +0100 Subject: [PATCH 7/8] Update opensaas-sh/blog/src/content/docs/guides/seo.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin ล oลกiฤ‡ --- opensaas-sh/blog/src/content/docs/guides/seo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index 4ade47d4..45e65c49 100644 --- a/opensaas-sh/blog/src/content/docs/guides/seo.md +++ b/opensaas-sh/blog/src/content/docs/guides/seo.md @@ -74,7 +74,7 @@ export default function App() { } ``` -Now, you can set page-specific meta tags in your React components. +Now, you can set page-specific meta tags in your React components. ```jsx {6-33) //... From 4ed41ac5c8f67e9f0bdb33693857f7f2fbca5ea3 Mon Sep 17 00:00:00 2001 From: Leo Golubyev Date: Fri, 13 Dec 2024 13:29:41 +0100 Subject: [PATCH 8/8] updated Seo guide --- .../blog/src/content/docs/guides/seo.md | 50 ++++--------------- template/app/public/robots.txt | 3 -- 2 files changed, 10 insertions(+), 43 deletions(-) diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index 45e65c49..80e3c30d 100644 --- a/opensaas-sh/blog/src/content/docs/guides/seo.md +++ b/opensaas-sh/blog/src/content/docs/guides/seo.md @@ -14,7 +14,7 @@ Wasp gives you the ability to add meta tags to your landing page HTML via the `m ```js {8-11} app SaaSTemplate { wasp: { - version: "^0.13.0" + version: "^0.15.0" }, title: "Open SaaS", head: [ @@ -56,7 +56,6 @@ import { HelmetProvider } from 'react-helmet-async'; export default function App() { return ( - <>
{isAdminDashboard ? ( @@ -68,7 +67,6 @@ export default function App() { )}
-
); } @@ -89,8 +87,11 @@ export function MyCustomPage() { name='description' content='This is the meta description of my page.' /> + - + + {/* Robots */} + {/* Open Graph / Facebook */} @@ -130,48 +131,17 @@ There are certain pages that it is good SEO practice not to index, for example: ## Structured data and Schema markup :::note[Tip] -Crawlers do all the work of analyzing and understanding the content of your pages, and they will thank you if you include structured data to help them understand what your content is about!๐Ÿค—. +Crawlers analyze your page content, and including structured data helps them better understand your content. ::: -You can add structured data for each page. - -```jsx {14-22} -//... -import { Helmet, HelmetProvider } from 'react-helmet-async'; - -export function MyCustomPage() { - return ( -
- - My Custom Page Title - - - //... - - +Structured data is a standardized way to provide information about your page. You can learn more about it here: - - //... -``` +- [Full schema hierarchy](https://schema.org/docs/full.html) +To validate your structured data, you can use the following tool: -These resources provide the information needed to get the most out of structured data: -- [Introduction to structured data markup](https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data) -- [General structured data guidelines](https://developers.google.com/search/docs/appearance/structured-data/sd-policies) +- [Schema Validator](https://validator.schema.org/) -After you have a small notion about them, you can go deeper by adding custom functions depending on your app (FAQs, Rating, Review, Software Application...): -- [ALL structured data functions](https://developers.google.com/search/docs/appearance/structured-data/search-gallery) :::tip[Star our Repo on GitHub! ๐ŸŒŸ] diff --git a/template/app/public/robots.txt b/template/app/public/robots.txt index ef1378fa..297e0709 100644 --- a/template/app/public/robots.txt +++ b/template/app/public/robots.txt @@ -1,6 +1,3 @@ User-agent: * Allow: / -Disallow: /admin/ -Disallow: /api/ -Disallow: /auth/