diff --git a/opensaas-sh/blog/src/content/docs/guides/seo.md b/opensaas-sh/blog/src/content/docs/guides/seo.md index a98270c9..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: [ @@ -30,7 +30,119 @@ 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 + +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. +::: + + +The first step is to install it: + +```bash +# Using npm +npm install 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 { 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 in your React components. + +```jsx {6-33) +//... +import { Helmet } from 'react-helmet-async'; + +export function MyCustomPage() { + return ( +
+ + My Custom Page Title + + + + + {/* Robots */} + + + + {/* Open Graph / Facebook */} + + + + + + + {/* Twitter */} + + + + + + +
+ ); +} + +``` + +:::tip[Good SEO practice] +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. +- Situational pages (e.g. page made for a specific campaign). +::: + +## Structured data and Schema markup + +:::note[Tip] +Crawlers analyze your page content, and including structured data helps them better understand your content. +::: + +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: + +- [Schema Validator](https://validator.schema.org/) + + :::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! diff --git a/template/app/public/robots.txt b/template/app/public/robots.txt new file mode 100644 index 00000000..297e0709 --- /dev/null +++ b/template/app/public/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / + diff --git a/template/app/src/landing-page/components/Testimonials.tsx b/template/app/src/landing-page/components/Testimonials.tsx index 457e6699..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}