-
Notifications
You must be signed in to change notification settings - Fork 0
Improve PortalJS template's SEO features #19
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
base: main
Are you sure you want to change the base?
Improve PortalJS template's SEO features #19
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThe SEO configuration was extensively revised to reflect the "PortalJS frontend template," updating all metadata, Open Graph, and Twitter card properties. Additional meta and link tags were added for improved semantic coverage. A new web application manifest file was introduced, defining app metadata and icon resources for a more native-like experience. New React components were added to provide structured JSON-LD data for the homepage, organizations, individual organization, dataset, group, search, and resource pages, replacing manual head elements in their respective main page components. Error handling was added when fetching datasets for individual organizations, and dataset page validation was introduced. Changes
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
next-seo.config.js (1)
47-57
: Redundant meta tags – Next-SEO already outputs them
og:image:width
,og:image:height
, andog:locale
are automatically emitted
fromopenGraph.images
andopenGraph.locale
. Duplicating them clutters the
head and can confuse parsers if values diverge in future edits.
Consider pruning these three entries fromadditionalMetaTags
.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
public/apple-touch-icon.png
is excluded by!**/*.png
public/favicon.ico
is excluded by!**/*.ico
public/images/portaljs-frontend.png
is excluded by!**/*.png
📒 Files selected for processing (2)
next-seo.config.js
(1 hunks)public/site.webmanifest
(1 hunks)
🔇 Additional comments (1)
next-seo.config.js (1)
60-72
: Verify that the manifest link path matches build outputThe link tag points to
/site.webmanifest
, which is fine as long as the file
lives underpublic/
(Next.js copies it to the root). If the location changes,
adjust thehref
accordingly.
"start_url": "/", | ||
"display": "standalone", | ||
"background_color": "#ffffff", | ||
"theme_color": "#3F59B1", | ||
"icons": [ | ||
{ | ||
"src": "/apple-touch-icon.png", | ||
"sizes": "180x180", | ||
"type": "image/png" | ||
} | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add larger & maskable icons + scope for full PWA compliance
Lighthouse will flag the manifest because it only declares a 180×180 icon. Modern browsers expect at least one 192×192 and one 512×512 icon marked purpose: "any maskable"
.
Adding a "scope"
(usually the same as start_url
) avoids fallback to the origin root when the user navigates.
"start_url": "/",
+ "scope": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#3F59B1",
"icons": [
+ {
+ "src": "/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "any maskable"
+ },
+ {
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "any maskable"
+ },
{
"src": "/apple-touch-icon.png",
"sizes": "180x180",
"type": "image/png"
}
]
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"start_url": "/", | |
"display": "standalone", | |
"background_color": "#ffffff", | |
"theme_color": "#3F59B1", | |
"icons": [ | |
{ | |
"src": "/apple-touch-icon.png", | |
"sizes": "180x180", | |
"type": "image/png" | |
} | |
] | |
"start_url": "/", | |
"scope": "/", | |
"display": "standalone", | |
"background_color": "#ffffff", | |
"theme_color": "#3F59B1", | |
"icons": [ | |
{ | |
"src": "/android-chrome-192x192.png", | |
"sizes": "192x192", | |
"type": "image/png", | |
"purpose": "any maskable" | |
}, | |
{ | |
"src": "/android-chrome-512x512.png", | |
"sizes": "512x512", | |
"type": "image/png", | |
"purpose": "any maskable" | |
}, | |
{ | |
"src": "/apple-touch-icon.png", | |
"sizes": "180x180", | |
"type": "image/png" | |
} | |
] |
🤖 Prompt for AI Agents
In public/site.webmanifest around lines 4 to 14, the manifest currently only
includes a 180x180 icon and lacks a scope property. To fix this, add additional
icons with sizes 192x192 and 512x512, each including the property "purpose":
"any maskable" to support modern PWA requirements. Also, add a "scope" property
with the same value as "start_url" ("/") to define the navigation scope and
avoid fallback to the origin root.
next-seo.config.js
Outdated
const url = "https://portaljs-cloud-frontend-template.vercel.app/"; | ||
const imageUrl = `${url}images/portaljs-frontend.png`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix double-slash bug in generated imageUrl
and canonical URL
Because url
already ends with /
, interpolating ${url}images/...
produces
…vercel.app//images/…
(note the double slash), which some crawlers treat as a
different asset. Remove the trailing slash or add it when concatenating.
-const url = "https://portaljs-cloud-frontend-template.vercel.app/";
-const imageUrl = `${url}images/portaljs-frontend.png`;
+const url = "https://portaljs-cloud-frontend-template.vercel.app";
+const imageUrl = `${url}/images/portaljs-frontend.png`;
Remember to update canonical
and openGraph.url
to use the amended url
.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const url = "https://portaljs-cloud-frontend-template.vercel.app/"; | |
const imageUrl = `${url}images/portaljs-frontend.png`; | |
// next-seo.config.js | |
- const url = "https://portaljs-cloud-frontend-template.vercel.app/"; | |
- const imageUrl = `${url}images/portaljs-frontend.png`; | |
+ const url = "https://portaljs-cloud-frontend-template.vercel.app"; | |
+ const imageUrl = `${url}/images/portaljs-frontend.png`; | |
// Don't forget to update `canonical` and `openGraph.url` to use the new `url` constant. |
🤖 Prompt for AI Agents
In next-seo.config.js around lines 7 to 8, the base URL ends with a trailing
slash causing double slashes when concatenated with paths, leading to incorrect
URLs. Remove the trailing slash from the `url` constant or adjust the
concatenation to avoid double slashes. Also, update the `canonical` and
`openGraph.url` fields to use the corrected base URL without the trailing slash
to ensure consistent and correct URLs throughout the configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
pages/index.tsx (1)
2-2
: Remove unused import.The
Head
import fromnext/head
is no longer needed since SEO metadata is now handled by theHomePageStructuredData
component.-import Head from "next/head";
components/schema/HomePageStructuredData.tsx (1)
7-10
: Ensure URL consistency in structured data.There's an inconsistency in URL usage:
nextSeoConfig.canonical
for the url prop and${url}/favicon.ico
for the logo prop. Consider using the same base URL reference for consistency.<LogoJsonLd - url={nextSeoConfig.canonical} + url={url} logo={`${url}/favicon.ico`} />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
components/schema/HomePageStructuredData.tsx
(1 hunks)next-seo.config.js
(1 hunks)pages/index.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- next-seo.config.js
🧰 Additional context used
🧬 Code Graph Analysis (2)
components/schema/HomePageStructuredData.tsx (1)
next-seo.config.js (2)
url
(7-7)url
(7-7)
pages/index.tsx (1)
components/schema/HomePageStructuredData.tsx (1)
HomePageStructuredData
(4-40)
🔇 Additional comments (3)
pages/index.tsx (1)
8-8
: Excellent SEO consolidation approach!Great architectural decision to centralize SEO metadata and structured data into a dedicated component. This improves maintainability and ensures consistent SEO implementation across the application.
Also applies to: 43-43
components/schema/HomePageStructuredData.tsx (2)
4-40
: Comprehensive structured data implementation!Excellent implementation of JSON-LD structured data covering multiple SEO aspects:
- Logo and branding information
- Breadcrumb navigation
- Webpage metadata
- Site search functionality
This will significantly improve the site's SEO performance and search engine understanding.
29-37
: Verify the search endpoint exists.The
SiteLinksSearchBoxJsonLd
assumes a search endpoint at/search?q={search_term_string}
. Ensure this search route is implemented in your application.#!/bin/bash # Description: Check if search endpoint/page exists in the codebase # Expected: Find search page implementation or API route # Search for search-related pages and API routes fd -e tsx -e ts -e js | xargs rg -l "search.*query|q.*search" | head -10 # Look for search page specifically fd -t f -e tsx -e ts "search" pages/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
pages/organizations.tsx (1)
1-1
: Remove unused import.The
Head
import from "next/head" is no longer needed since the explicit<Head>
components have been replaced with the structured data component.-import Head from "next/head";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
components/schema/HomePageStructuredData.tsx
(1 hunks)components/schema/OrganizationPageStructuredData.tsx
(1 hunks)pages/organizations.tsx
(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- components/schema/OrganizationPageStructuredData.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- components/schema/HomePageStructuredData.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
pages/organizations.tsx (1)
components/schema/OrganizationPageStructuredData.tsx (1)
OrganizationPageStructuredData
(4-50)
🔇 Additional comments (2)
pages/organizations.tsx (2)
9-9
: Excellent SEO improvement with structured data component.The addition of
OrganizationPageStructuredData
component is a great improvement for SEO. This provides comprehensive structured data markup including JSON-LD, breadcrumbs, and other SEO metadata in a consistent and maintainable way.Also applies to: 28-28
28-28
: ```shell
#!/bin/bashLocate and display next-seo.config files to verify exports of
url
andnextSeoConfig
echo "Searching for next-seo.config.* files at project root..."
find . -maxdepth 1 -type f -name "next-seo.config.*"echo -e "\nDisplaying contents of found config file(s) (up to 200 lines each)..."
for file in $(find . -maxdepth 1 -type f -name "next-seo.config.*"); do
echo "==== $file ===="
sed -n '1,200p' "$file"
done</details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
pages/search.tsx (1)
2-2
: Remove unused import.The
Head
import fromnext/head
is no longer used since SEO metadata is now handled by theSearchPageStructuredData
component.-import Head from "next/head";
components/schema/SearchPageStructuredData.tsx (1)
6-7
: Improve title and description for better SEO.The current title "Search page" is generic and the description concatenation creates awkward phrasing ("Browse through multiple datasets available on Search page").
Consider this improvement:
-const title = "Search page" -const description = "Browse through multiple datasets available on " + title +const title = "Search Datasets" +const description = "Browse and search through our comprehensive collection of datasets"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
components/schema/OrganizationPageStructuredData.tsx
(1 hunks)components/schema/SearchPageStructuredData.tsx
(1 hunks)pages/search.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- components/schema/OrganizationPageStructuredData.tsx
🧰 Additional context used
🧬 Code Graph Analysis (2)
pages/search.tsx (1)
components/schema/SearchPageStructuredData.tsx (1)
SearchPageStructuredData
(5-57)
components/schema/SearchPageStructuredData.tsx (1)
next-seo.config.js (2)
title
(3-3)description
(4-5)
🪛 Biome (1.9.4)
components/schema/SearchPageStructuredData.tsx
[error] 44-44: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (8)
pages/search.tsx (2)
13-13
: LGTM! Good architectural improvement.The import of
SearchPageStructuredData
component centralizes SEO metadata management, which improves maintainability and consistency.
50-50
: LGTM! Proper structured data integration.The placement of
SearchPageStructuredData
at the top level of the component is correct for SEO metadata injection.components/schema/SearchPageStructuredData.tsx (6)
8-14
: LGTM! Proper JSON-LD structure for DataCatalog.The JSON-LD object correctly implements the schema.org DataCatalog specification with appropriate context, type, and metadata properties.
17-20
: LGTM! Correct logo structured data implementation.The LogoJsonLd component properly associates the logo with the search page URL for enhanced SEO.
21-26
: LGTM! Well-configured NextSeo component.The NextSeo configuration properly sets canonical URL, title, description, and spreads the shared SEO config for consistency.
27-40
: LGTM! Proper breadcrumb structured data.The BreadcrumbJsonLd correctly defines the navigation hierarchy with proper position indices and item URLs.
41-45
: Acknowledge legitimate use of dangerouslySetInnerHTML for JSON-LD.The static analysis tool flagged the use of
dangerouslySetInnerHTML
, but this is a legitimate and standard practice for injecting JSON-LD structured data. The content is controlled (not user-generated) and properly JSON-stringified, making it safe from XSS attacks.The implementation follows established patterns for structured data injection and poses no security risk in this context.
46-54
: LGTM! Excellent site search box implementation.The SiteLinksSearchBoxJsonLd properly configures the search functionality with the correct URL pattern and query parameter mapping for enhanced search engine integration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
components/schema/OrganizationIndividualPageStructuredData.tsx (1)
20-31
: Consider adding the current organization to breadcrumbs.The breadcrumb structure only shows Home → Organizations, but it should include the current organization as the final item for better navigation context.
Apply this diff to add the current organization to breadcrumbs:
<BreadcrumbJsonLd itemListElements={[ { position: 1, name: 'Home', item: url, }, { position: 2, name: 'Organizations', item: `${url}/organizations`, }, + { + position: 3, + name: title, + item: orgUrl, + }, ]} />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
components/schema/OrganizationIndividualPageStructuredData.tsx
(1 hunks)pages/[org]/index.tsx
(3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
components/schema/OrganizationIndividualPageStructuredData.tsx (1)
next-seo.config.js (2)
title
(3-3)description
(4-5)
🔇 Additional comments (3)
pages/[org]/index.tsx (3)
15-15
: LGTM! Good SEO architecture improvement.The import of the structured data component aligns with the PR's objective to improve SEO features by centralizing metadata management.
32-50
: Excellent error handling implementation.The try-catch blocks around dataset fetching prevent the page from breaking when individual datasets fail to load, and filtering out null values ensures only valid datasets are passed to the component.
88-88
: Good replacement of manual Head elements.Using the structured data component centralizes SEO metadata management and provides consistent JSON-LD markup across the application.
return ( | ||
<> | ||
<LogoJsonLd | ||
url={`${url}/@${title}`} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL construction needs proper encoding and correction.
Multiple issues with URL construction:
- Using
title
directly in URLs without encoding can cause issues if the title contains special characters - The breadcrumb Organizations URL is incorrect - should point to
/organizations
not/@${title}
Apply this diff to fix URL construction:
+ const encodedOrgName = encodeURIComponent(org.name || org.title || '')
+ const orgUrl = `${url}/@${encodedOrgName}`
+
return (
<>
<LogoJsonLd
- url={`${url}/@${title}`}
+ url={orgUrl}
logo={org.image_display_url || `${url}/favicon.ico`}
/>
<NextSeo
- canonical={`${url}/@${title}`}
+ canonical={orgUrl}
title={title}
description={description}
{...nextSeoConfig}
/>
<BreadcrumbJsonLd
itemListElements={[
{
position: 1,
name: 'Home',
item: url,
},
{
position: 2,
name: 'Organizations',
- item: `${url}/@${title}`,
+ item: `${url}/organizations`,
},
]}
/>
<WebPageJsonLd
- id={`${url}/@${title}#webpage`}
- url={`${url}/@${title}`}
+ id={`${orgUrl}#webpage`}
+ url={orgUrl}
name={title}
description={description}
/>
Also applies to: 14-14, 29-29, 34-35
🤖 Prompt for AI Agents
In components/schema/OrganizationIndividualPageStructuredData.tsx at lines 10,
14, 29, and 34-35, the URL construction uses the raw title without encoding and
incorrectly sets the Organizations breadcrumb URL. Fix this by encoding the
title using encodeURIComponent before inserting it into URLs and correct the
Organizations breadcrumb URL to point to '/organizations' instead of using the
title.
const title = org.name || org.title | ||
const description = org.notes || "Organizations page of " + org |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix title logic and description fallback.
The current implementation has two issues:
- Using
org.name || org.title
may not be optimal for SEO titles - The description fallback will stringify the org object as "[object Object]"
Apply this diff to fix both issues:
- const title = org.name || org.title
- const description = org.notes || "Organizations page of " + org
+ const title = org.title || org.name || 'Organization'
+ const description = org.notes || `Learn more about ${org.title || org.name || 'this organization'} and explore their datasets.`
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const title = org.name || org.title | |
const description = org.notes || "Organizations page of " + org | |
const title = org.title || org.name || 'Organization' | |
const description = org.notes || `Learn more about ${org.title || org.name || 'this organization'} and explore their datasets.` |
🤖 Prompt for AI Agents
In components/schema/OrganizationIndividualPageStructuredData.tsx around lines 5
to 6, the title logic uses org.name || org.title which may not be optimal for
SEO, and the description fallback concatenates a string with the org object
causing it to stringify as "[object Object]". Fix this by prioritizing org.title
over org.name for the title, and update the description fallback to use a
meaningful string such as "Organizations page of " plus org.title or org.name
instead of the org object directly.
import nextSeoConfig, { url } from "@/next-seo.config"; | ||
import { BreadcrumbJsonLd, LogoJsonLd, NextSeo, WebPageJsonLd, SiteLinksSearchBoxJsonLd } from "next-seo"; | ||
|
||
export function OrganizationIndividualPageStructuredData({ org }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add TypeScript types for better type safety.
The org
parameter lacks type definitions, which reduces type safety and IDE support.
Apply this diff to add proper typing:
-export function OrganizationIndividualPageStructuredData({ org }) {
+interface Organization {
+ name?: string;
+ title?: string;
+ notes?: string;
+ image_display_url?: string;
+}
+
+export function OrganizationIndividualPageStructuredData({ org }: { org: Organization }) {
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export function OrganizationIndividualPageStructuredData({ org }) { | |
interface Organization { | |
name?: string; | |
title?: string; | |
notes?: string; | |
image_display_url?: string; | |
} | |
export function OrganizationIndividualPageStructuredData({ org }: { org: Organization }) { |
🤖 Prompt for AI Agents
In components/schema/OrganizationIndividualPageStructuredData.tsx at line 4, the
org parameter lacks TypeScript type definitions, reducing type safety and IDE
support. Define an appropriate interface or type for the org parameter
reflecting its expected structure, then update the function signature to include
this type for org. This will improve type safety and developer experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
components/schema/DatasetPageStructuredData.tsx
(1 hunks)components/schema/OrganizationIndividualPageStructuredData.tsx
(1 hunks)pages/[org]/[dataset]/index.tsx
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- components/schema/OrganizationIndividualPageStructuredData.tsx
🧰 Additional context used
🧬 Code Graph Analysis (2)
pages/[org]/[dataset]/index.tsx (1)
components/schema/DatasetPageStructuredData.tsx (1)
DatasetPageStructuredData
(4-42)
components/schema/DatasetPageStructuredData.tsx (1)
next-seo.config.js (2)
title
(3-3)description
(4-5)
🔇 Additional comments (2)
pages/[org]/[dataset]/index.tsx (2)
91-91
: Excellent refactoring to centralize SEO metadata.The replacement of manual Head elements with the structured data component improves maintainability and consistency across the application.
44-48
: Consider URL encoding consistency in organization name validation.The validation compares the raw organization name with the URL parameter, but URL parameters are typically encoded. This could cause mismatches if the organization name contains special characters.
Run the following script to check how organization names with special characters are handled in the routing:
#!/bin/bash # Description: Check for organization names with special characters and URL encoding patterns # Expected: Find examples of how organization names are encoded in URLs # Search for organization name usage in routing or URL construction rg -A 3 -B 3 "org.*name.*encodeURI|encodeURI.*org.*name" # Search for organization parameter handling rg -A 5 -B 5 "params.*org|org.*params" # Look for existing URL encoding patterns in the codebase rg -A 3 "encodeURIComponent|decodeURIComponent"
return ( | ||
<> | ||
<LogoJsonLd | ||
url={`${url}/@${owner_org}/${title}`} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement URL encoding for title to prevent invalid URLs.
The title
variable is directly used in URL construction without encoding, which could create invalid URLs if the title contains special characters or spaces.
+ const encodedTitle = encodeURIComponent(title);
+ const encodedOwnerOrg = encodeURIComponent(owner_org);
+ const datasetUrl = `${url}/@${encodedOwnerOrg}/${encodedTitle}`;
- url={`${url}/@${owner_org}/${title}`}
+ url={datasetUrl}
- canonical={`${url}/@${owner_org}/${title}`}
+ canonical={datasetUrl}
- item: `${url}/@${owner_org}/${title}`
+ item: datasetUrl
- id={`${url}/@${owner_org}/${title}#webpage`}
- url={`${url}/@${owner_org}/${title}`}
+ id={`${datasetUrl}#webpage`}
+ url={datasetUrl}
Also applies to: 15-15, 30-30, 35-36
🤖 Prompt for AI Agents
In components/schema/DatasetPageStructuredData.tsx at lines 11, 15, 30, and
35-36, the title variable is used directly in URL construction without encoding,
which can cause invalid URLs if the title contains special characters or spaces.
Fix this by applying URL encoding (e.g., using encodeURIComponent) to the title
variable wherever it is included in the URL string to ensure the URLs are valid
and safe.
import nextSeoConfig, { url } from "@/next-seo.config"; | ||
import { BreadcrumbJsonLd, LogoJsonLd, NextSeo, WebPageJsonLd, SiteLinksSearchBoxJsonLd, DatasetJsonLd } from "next-seo"; | ||
|
||
export function DatasetPageStructuredData({ dataset }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add TypeScript interface for better type safety.
The component lacks proper TypeScript typing for the dataset
prop, which could lead to runtime errors if the expected properties are missing.
+interface Dataset {
+ title?: string;
+ name: string;
+ notes?: string;
+ organization: {
+ name: string;
+ };
+}
+
+interface DatasetPageStructuredDataProps {
+ dataset: Dataset;
+}
+
-export function DatasetPageStructuredData({ dataset }) {
+export function DatasetPageStructuredData({ dataset }: DatasetPageStructuredDataProps) {
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export function DatasetPageStructuredData({ dataset }) { | |
interface Dataset { | |
title?: string; | |
name: string; | |
notes?: string; | |
organization: { | |
name: string; | |
}; | |
} | |
interface DatasetPageStructuredDataProps { | |
dataset: Dataset; | |
} | |
-export function DatasetPageStructuredData({ dataset }) { | |
+export function DatasetPageStructuredData({ dataset }: DatasetPageStructuredDataProps) { | |
// …rest of component | |
} |
🤖 Prompt for AI Agents
In components/schema/DatasetPageStructuredData.tsx at line 4, the
DatasetPageStructuredData component lacks TypeScript typing for its dataset
prop. Define a TypeScript interface describing the expected shape of the dataset
object with all required properties, then update the component's props to use
this interface for type safety and to prevent runtime errors.
if ("@" + dataset.organization.name !== orgName) { | ||
return { | ||
notFound: true, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add null safety for organization property access.
The validation assumes dataset.organization.name
exists without checking if dataset.organization
is null or undefined, which could cause a runtime error.
- if ("@" + dataset.organization.name !== orgName) {
+ if (!dataset.organization || "@" + dataset.organization.name !== orgName) {
return {
notFound: true,
};
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if ("@" + dataset.organization.name !== orgName) { | |
return { | |
notFound: true, | |
}; | |
} | |
if (!dataset.organization || "@" + dataset.organization.name !== orgName) { | |
return { | |
notFound: true, | |
}; | |
} |
🤖 Prompt for AI Agents
In pages/[org]/[dataset]/index.tsx around lines 44 to 48, the code accesses
dataset.organization.name without verifying if dataset.organization is null or
undefined, risking a runtime error. Add a null check to ensure
dataset.organization exists before accessing its name property, and handle the
case where it does not by returning notFound or an appropriate fallback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
pages/groups/index.tsx (1)
1-1
: Remove unused import.Based on the AI summary, the explicit
<Head>
component was removed and replaced with the structured data component, making this import unused.-import Head from "next/head";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
components/schema/DatasetPageStructuredData.tsx
(1 hunks)components/schema/GroupPageStructuredData.tsx
(1 hunks)pages/groups/index.tsx
(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- components/schema/GroupPageStructuredData.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- components/schema/DatasetPageStructuredData.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
pages/groups/index.tsx (1)
components/schema/GroupPageStructuredData.tsx (1)
GroupPageStructuredData
(4-50)
🔇 Additional comments (1)
pages/groups/index.tsx (1)
10-10
: LGTM! Well-structured SEO implementation.The addition of
GroupPageStructuredData
component follows the established pattern for centralizing SEO metadata and JSON-LD markup. The component provides comprehensive structured data including logo, breadcrumbs, webpage metadata, and site links search box, which should improve the page's SEO performance.Also applies to: 29-29
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
pages/[org]/[dataset]/r/[resourceId].tsx (1)
10-10
: Remove unused import.The
Head
import from "next/head" is no longer used after switching to the structured data component.-import Head from "next/head";
pages/groups/[groupName].tsx (1)
2-2
: Remove unused import.The
Head
import is no longer needed after the structured data refactoring.-import Head from "next/head";
components/schema/ResourcePageStructuredData.tsx (1)
2-2
: Remove unused import.
DatasetJsonLd
is imported but not used in this component.-import { BreadcrumbJsonLd, LogoJsonLd, NextSeo, DatasetJsonLd } from "next-seo"; +import { BreadcrumbJsonLd, LogoJsonLd, NextSeo } from "next-seo";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
components/schema/DatasetPageStructuredData.tsx
(1 hunks)components/schema/GroupIndividualPageStructuredData.tsx
(1 hunks)components/schema/ResourcePageStructuredData.tsx
(1 hunks)pages/[org]/[dataset]/r/[resourceId].tsx
(2 hunks)pages/groups/[groupName].tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- components/schema/DatasetPageStructuredData.tsx
🧰 Additional context used
🧬 Code Graph Analysis (4)
pages/[org]/[dataset]/r/[resourceId].tsx (1)
components/schema/ResourcePageStructuredData.tsx (1)
ResourcePageStructuredData
(5-63)
pages/groups/[groupName].tsx (1)
components/schema/GroupIndividualPageStructuredData.tsx (1)
GroupIndividualPageStructuredData
(4-47)
components/schema/GroupIndividualPageStructuredData.tsx (1)
next-seo.config.js (2)
title
(3-3)description
(4-5)
components/schema/ResourcePageStructuredData.tsx (1)
next-seo.config.js (2)
title
(3-3)description
(4-5)
🪛 Biome (1.9.4)
components/schema/ResourcePageStructuredData.tsx
[error] 59-59: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (10)
pages/[org]/[dataset]/r/[resourceId].tsx (2)
14-14
: LGTM! Clean import structure.The import of
ResourcePageStructuredData
is correctly added to support the SEO refactoring.
83-83
: Excellent SEO enhancement!The replacement of manual
<Head>
metadata with the structured data component centralizes SEO metadata management and adds rich JSON-LD schema markup for better search engine visibility.pages/groups/[groupName].tsx (2)
14-14
: LGTM! Proper import for structured data.The import aligns with the SEO refactoring pattern across the application.
73-73
: Great SEO improvement!Replacing manual head metadata with the structured data component provides better SEO and rich results support.
components/schema/GroupIndividualPageStructuredData.tsx (2)
4-8
: LGTM! Well-structured component design.The component properly constructs URLs, titles, and descriptions from the group props and follows the established pattern for structured data components.
10-44
: Excellent structured data implementation!The component properly implements LogoJsonLd, NextSeo, BreadcrumbJsonLd, and WebPageJsonLd for comprehensive SEO support.
components/schema/ResourcePageStructuredData.tsx (4)
5-8
: LGTM! Clean component structure.The component properly constructs resource-specific URLs and descriptions from the props.
10-17
: Excellent DataDownload schema implementation!The JSON-LD structure correctly represents the resource as a DataDownload with appropriate Schema.org properties.
21-54
: Comprehensive SEO implementation!The component properly implements LogoJsonLd, NextSeo, and BreadcrumbJsonLd with correct URL structures and navigation hierarchy.
55-60
: I’ll locate and inspect the actual page file that passesresource
into this component to see how it’s fetched and whether any sanitization is applied:#!/bin/bash set -e # Find the page importing ResourcePageStructuredData PAGE=$(rg -l "ResourcePageStructuredData" -g "*.tsx" | grep "pages/" | head -n1) echo "Inspecting page: $PAGE" echo; echo "---- Top of File (1–200) ----" sed -n '1,200p' "$PAGE" echo; echo "---- Data-Fetching Functions ----" rg -n "export async function get" -A5 "$PAGE"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
components/schema/ResourcePageStructuredData.tsx (1)
55-60
: Address the security concern with dangerouslySetInnerHTML.While the static analysis tool flagged this as a security risk, the JSON.stringify usage with controlled data should be safe. However, consider using the DatasetJsonLd component from next-seo for consistency.
Since you're already importing
DatasetJsonLd
(line 2) but not using it, consider replacing the custom Script with the next-seo component:- <Script - id="datadownload-jsonld" - type="application/ld+json" - strategy="afterInteractive" - dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} - /> + <DatasetJsonLd + name={resource.name} + description={description} + images={[]} + />Alternatively, if you need the DataDownload schema specifically, add input sanitization:
- dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} + dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, '\\u003c') }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
components/schema/DatasetPageStructuredData.tsx
(1 hunks)components/schema/GroupIndividualPageStructuredData.tsx
(1 hunks)components/schema/GroupPageStructuredData.tsx
(1 hunks)components/schema/OrganizationIndividualPageStructuredData.tsx
(1 hunks)components/schema/OrganizationPageStructuredData.tsx
(1 hunks)components/schema/ResourcePageStructuredData.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- components/schema/GroupPageStructuredData.tsx
- components/schema/GroupIndividualPageStructuredData.tsx
- components/schema/DatasetPageStructuredData.tsx
- components/schema/OrganizationPageStructuredData.tsx
- components/schema/OrganizationIndividualPageStructuredData.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
components/schema/ResourcePageStructuredData.tsx (1)
next-seo.config.js (2)
title
(3-3)description
(4-5)
🪛 Biome (1.9.4)
components/schema/ResourcePageStructuredData.tsx
[error] 59-59: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (3)
components/schema/ResourcePageStructuredData.tsx (3)
1-3
: LGTM! Clean and appropriate imports.The imports are well-structured and include all necessary dependencies for the SEO and structured data functionality.
10-17
: Well-structured JSON-LD schema implementation.The DataDownload schema follows schema.org specifications correctly and includes appropriate properties for a resource download. The structure aligns well with SEO best practices.
19-54
: Excellent use of next-seo components for structured data.The implementation correctly uses LogoJsonLd, NextSeo, and BreadcrumbJsonLd components with proper hierarchical breadcrumb structure. The canonical URL and SEO metadata configuration is well-implemented.
export function ResourcePageStructuredData({ resource, orgName, dataset }) { | ||
const title = resource.name || "Resource" | ||
const resourceUrl = `${url}/@${orgName}/${dataset}/r/${resource.id}` | ||
const description = resource.description || "Resource page of " + title |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add TypeScript type definitions for better type safety.
The component props lack TypeScript type definitions, which could lead to runtime errors and reduces developer experience.
Consider adding interface definitions:
+interface ResourcePageStructuredDataProps {
+ resource: {
+ id: string;
+ name?: string;
+ description?: string;
+ format?: string;
+ url?: string;
+ };
+ orgName: string;
+ dataset: string;
+}
+
-export function ResourcePageStructuredData({ resource, orgName, dataset }) {
+export function ResourcePageStructuredData({ resource, orgName, dataset }: ResourcePageStructuredDataProps) {
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export function ResourcePageStructuredData({ resource, orgName, dataset }) { | |
const title = resource.name || "Resource" | |
const resourceUrl = `${url}/@${orgName}/${dataset}/r/${resource.id}` | |
const description = resource.description || "Resource page of " + title | |
interface ResourcePageStructuredDataProps { | |
resource: { | |
id: string; | |
name?: string; | |
description?: string; | |
format?: string; | |
url?: string; | |
}; | |
orgName: string; | |
dataset: string; | |
} | |
export function ResourcePageStructuredData( | |
{ resource, orgName, dataset }: ResourcePageStructuredDataProps | |
) { | |
const title = resource.name || "Resource" | |
const resourceUrl = `${url}/@${orgName}/${dataset}/r/${resource.id}` | |
const description = resource.description || "Resource page of " + title | |
// …rest of the function | |
} |
🤖 Prompt for AI Agents
In components/schema/ResourcePageStructuredData.tsx around lines 5 to 8, the
component props are missing TypeScript type definitions, which reduces type
safety. Define an interface for the props specifying the types for resource,
orgName, and dataset, then update the function signature to use this interface
for better type checking and developer experience.
@Datopian-Shreyas I'm not sure if this is working as expected. I have tested preview deployment using Google's rish results tester and on number of pages it doesn't show any structured data except the breadcrumb, for example, see resource page result: https://search.google.com/test/rich-results/result?id=PB_Grxz1y6s7MCe5BLrv4g Similarly, I tested using meta tags tool for dataset page this time and I would expect to see title and description of the dataset but it uses generic meta title and description: |
Hey @anuveyatsu, Im not sure why this is happening.. |
Summary by CodeRabbit