Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved seo docs page #297

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 114 additions & 2 deletions opensaas-sh/blog/src/content/docs/guides/seo.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand All @@ -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 `<head>` 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 `<head>` via client-side JS after initial serve, meaning that web crawlers that don't evaluate JS won't pick up the modifications to the `<head>` 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 (
<HelmetProvider>
<div className='min-h-screen dark:text-white dark:bg-boxdark-2'>
{isAdminDashboard ? (
<Outlet />
) : (
{shouldDisplayAppNavBar && <AppNavBar />}
<div className='mx-auto max-w-7xl sm:px-6 lg:px-8'>
<Outlet />
</div>
)}
</div>
<CookieConsentBanner />
</HelmetProvider>
);
}
```

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 (
<div>
<Helmet>
<title>My Custom Page Title</title>
<meta
name='description'
content='This is the meta description of my page.'
/>

<link rel='canonical' href='https://example.com/my-custom-page' />

{/* Robots */}
<meta name="robots" content="index, nollow" />


{/* Open Graph / Facebook */}
<meta property='og:type' content='website' />
<meta property='og:url' content='https://example.com/my-custom-page' />
<meta property='og:title' content='My Custom Page Title' />
<meta
property='og:description'
content='This is the Open Graph description of my page.'
/>
<meta property='og:image' content='https://example.com/my-custom-page-og-image.jpg' />

{/* Twitter */}
<meta name='twitter:card' content='summary_large_image' />
<meta name='twitter:url' content='https://example.com/my-custom-page' />
<meta name='twitter:title' content='My Custom Page Title' />
<meta
name='twitter:description'
content='This is the Twitter description of my page.'
/>
<meta name='twitter:image' content='https://example.com/my-custom-page-twitter-image.jpg' />
</Helmet>
</div>
);
}

```

:::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!
Expand Down
3 changes: 3 additions & 0 deletions template/app/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
User-agent: *
Allow: /

6 changes: 5 additions & 1 deletion template/app/src/landing-page/components/Testimonials.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export default function Testimonials({ testimonials }: { testimonials: Testimoni
</blockquote>
<figcaption className='mt-6 text-base text-white'>
<a href={testimonial.socialUrl} className='flex items-center gap-x-2'>
<img src={testimonial.avatarSrc} loading='lazy' className='h-12 w-12 rounded-full' />
<img
src={testimonial.avatarSrc}
alt={`Profile picture of ${testimonial.name}`}
className='h-12 w-12 rounded-full'
/>
<div>
<div className='font-semibold hover:underline'>{testimonial.name}</div>
<div className='mt-1'>{testimonial.role}</div>
Expand Down