seo done
parent
04fdf51e7b
commit
5501a66957
|
@ -60,7 +60,14 @@ export const generateMetadata = async ({ params }) => {
|
|||
};
|
||||
|
||||
|
||||
|
||||
export const viewport = {
|
||||
width: 'device-width',
|
||||
initialScale: 1,
|
||||
maximumScale: 1,
|
||||
userScalable: false,
|
||||
// Also supported but less commonly used
|
||||
// interactiveWidget: 'resizes-visual',
|
||||
}
|
||||
|
||||
export default async function LocaleLayout({
|
||||
children,
|
||||
|
|
|
@ -83,17 +83,90 @@ const gql_static = `
|
|||
query Products($locale:I18NLocaleCode,$start:Int,$limit:Int) {
|
||||
products(locale: $locale, pagination: { start: $start, limit: $limit }) {
|
||||
slug
|
||||
category {
|
||||
slug
|
||||
}
|
||||
brand {
|
||||
slug
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
`
|
||||
|
||||
const gql_metadata = `
|
||||
query Products($locale:I18NLocaleCode,$slug:String!) {
|
||||
products(filters: { slug: { eqi: $slug } }, locale: $locale) {
|
||||
seo {
|
||||
id
|
||||
metaTitle
|
||||
metaDescription
|
||||
metaRobots
|
||||
canonicalURL
|
||||
metaImage {
|
||||
documentId
|
||||
alternativeText
|
||||
url
|
||||
}
|
||||
openGraph {
|
||||
id
|
||||
ogTitle
|
||||
ogDescription
|
||||
ogUrl
|
||||
ogType
|
||||
ogImage {
|
||||
documentId
|
||||
alternativeText
|
||||
url
|
||||
}
|
||||
}
|
||||
structuredData
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
export async function generateMetadata({ params }) {
|
||||
const { locale, slug } = await params;
|
||||
|
||||
// Fetch product SEO data from Strapi GraphQL API
|
||||
const data = await graphql(gql_metadata, {
|
||||
locale,
|
||||
slug,
|
||||
});
|
||||
|
||||
const productSEO = data?.products?.[0]?.seo;
|
||||
if (productSEO) {
|
||||
return {
|
||||
title: productSEO.metaTitle,
|
||||
description: productSEO.metaDescription,
|
||||
robots: productSEO.metaRobots || 'index, follow',
|
||||
// canonical: productSEO.canonicalURL || `https://adhorizonintl.com/product/${slug}`,
|
||||
alternates: {
|
||||
canonical: productSEO.canonicalURL || `https://adhorizonintl.com/product/${slug}`,
|
||||
languages: {
|
||||
'en': `https://adhorizonintl.com/product/${slug}`,
|
||||
'ar-OM': `https://adhorizonintl.com/ar-OM/product/${slug}`,
|
||||
},
|
||||
},
|
||||
openGraph: {
|
||||
title: productSEO.openGraph.ogTitle || productSEO.metaTitle,
|
||||
description: productSEO.openGraph.ogDescription || productSEO.metaDescription,
|
||||
url: productSEO.openGraph.ogUrl || `https://adhorizonintl.com/product/${slug}`,
|
||||
type: productSEO.openGraph.ogType || 'website',
|
||||
images: [
|
||||
{
|
||||
url: productSEO.openGraph.ogImage.url,
|
||||
alt: productSEO.openGraph.ogImage.alternativeText || 'Product Image',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: productSEO.metaTitle,
|
||||
description: productSEO.metaDescription,
|
||||
images: [productSEO.metaImage?.url],
|
||||
},
|
||||
// structuredData: productSEO.structuredData,
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function generateStaticParams() {
|
||||
|
@ -104,11 +177,9 @@ export async function generateStaticParams() {
|
|||
})
|
||||
const params = [];
|
||||
products.forEach((product) => {
|
||||
params.push({ category: product.category.slug, slug: product.slug })
|
||||
params.push({ category: product.brand.slug, slug: product.slug })
|
||||
params.push({ slug: product.slug })
|
||||
})
|
||||
return params;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,5 +1,114 @@
|
|||
import CategoriesData from "src/view/Categories";
|
||||
|
||||
|
||||
const gql_metadata = `
|
||||
query CategoriesAndBrands($locale:I18NLocaleCode,$slug:String!) {
|
||||
categories(filters: { slug: { eqi: $slug } }, locale: $locale) {
|
||||
seo {
|
||||
id
|
||||
metaTitle
|
||||
metaDescription
|
||||
metaRobots
|
||||
canonicalURL
|
||||
metaImage {
|
||||
documentId
|
||||
alternativeText
|
||||
url
|
||||
}
|
||||
openGraph {
|
||||
id
|
||||
ogTitle
|
||||
ogDescription
|
||||
ogUrl
|
||||
ogType
|
||||
ogImage {
|
||||
documentId
|
||||
alternativeText
|
||||
url
|
||||
}
|
||||
}
|
||||
structuredData
|
||||
}
|
||||
}
|
||||
brands(filters: { slug: { eqi: $slug } }, locale: $locale) {
|
||||
seo {
|
||||
id
|
||||
metaTitle
|
||||
metaDescription
|
||||
metaRobots
|
||||
canonicalURL
|
||||
metaImage {
|
||||
documentId
|
||||
alternativeText
|
||||
url
|
||||
}
|
||||
openGraph {
|
||||
id
|
||||
ogTitle
|
||||
ogDescription
|
||||
ogUrl
|
||||
ogType
|
||||
ogImage {
|
||||
documentId
|
||||
alternativeText
|
||||
url
|
||||
}
|
||||
}
|
||||
structuredData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
`
|
||||
export async function generateMetadata({ params }) {
|
||||
const { locale, slug } = await params;
|
||||
|
||||
// Fetch product SEO data from Strapi GraphQL API
|
||||
const data = await graphql(gql_metadata, {
|
||||
locale,
|
||||
slug,
|
||||
});
|
||||
|
||||
const productSEO = data?.categories?.[0]?.seo || data?.brands?.[0]?.seo;
|
||||
if (productSEO) {
|
||||
return {
|
||||
title: productSEO.metaTitle,
|
||||
description: productSEO.metaDescription,
|
||||
robots: productSEO.metaRobots || 'index, follow',
|
||||
// canonical: productSEO.canonicalURL || `https://adhorizonintl.com/product/${slug}`,
|
||||
alternates: {
|
||||
canonical: productSEO.canonicalURL || `https://adhorizonintl.com/products/${slug}`,
|
||||
languages: {
|
||||
'en': `https://adhorizonintl.com/products/${slug}`,
|
||||
'ar-OM': `https://adhorizonintl.com/ar-OM/products/${slug}`,
|
||||
},
|
||||
},
|
||||
openGraph: {
|
||||
title: productSEO.openGraph.ogTitle || productSEO.metaTitle,
|
||||
description: productSEO.openGraph.ogDescription || productSEO.metaDescription,
|
||||
url: productSEO.openGraph.ogUrl || `https://adhorizonintl.com/products/${slug}`,
|
||||
type: productSEO.openGraph.ogType || 'website',
|
||||
images: [
|
||||
{
|
||||
url: productSEO.openGraph.ogImage.url,
|
||||
alt: productSEO.openGraph.ogImage.alternativeText || 'Product Image',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: productSEO.metaTitle,
|
||||
description: productSEO.metaDescription,
|
||||
images: [productSEO.metaImage?.url],
|
||||
},
|
||||
// structuredData: productSEO.structuredData,
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
const CategoryPage = async ({ params }) => {
|
||||
const _params = await params;
|
||||
return (
|
||||
|
|
|
@ -73,7 +73,7 @@ export default function ProductCard({ product }) {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Link href={`/products/${brand?.slug || category?.slug || 'horizon'}/${slug}`.toLowerCase()}
|
||||
<Link href={`/product/${slug}`.toLowerCase()}
|
||||
className={`w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors ${locale === "en" ? "flex-row" : "flex-row-reverse"}`}>
|
||||
{t("Utils.moreDetail")}
|
||||
<ChevronRight className="h-4 w-4 ml-2" />
|
||||
|
|
|
@ -84,7 +84,7 @@ const Navbar = ({ items }) => {
|
|||
}
|
||||
${theme == 1 ? "bg-gray-100 " : " "}`}
|
||||
>
|
||||
<div className={`w-full ${locale === "en" ? "rtl" : "ltr"} px-4 py-4`}>
|
||||
{/* <div className={`w-full ${locale === "en" ? "rtl" : "ltr"} px-4 py-4`}>
|
||||
<div className="flex">
|
||||
|
||||
<button onClick={changeLocale} className="mr-2 w-fit px-3 p-2 text-sm bg-white flex rounded-xl ">
|
||||
|
@ -92,7 +92,7 @@ const Navbar = ({ items }) => {
|
|||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className={`w-full flex p-2 ${locale === "en" ? "ltr" : "rtl"} `}>
|
||||
|
||||
<div className="size-[75px] relative p-1 bg-white rounded-lg flex flex-col items-center rounded-tl-2xl justify-center my-auto">
|
||||
|
@ -177,9 +177,9 @@ const Navbar = ({ items }) => {
|
|||
|
||||
{/* <Link href={"/"} className="w-full"> */}
|
||||
<div className=" w-full mx-1 flex items-center ">
|
||||
<button onClick={changeLocale} className="mr-2 w-fit px-3 p-2 h-fit text-sm bg-white flex rounded-xl ">
|
||||
{/* <button onClick={changeLocale} className="mr-2 w-fit px-3 p-2 h-fit text-sm bg-white flex rounded-xl ">
|
||||
<p className="mb-0">{locale === "en" ? "العربیه" : "English"}</p>
|
||||
</button>
|
||||
</button> */}
|
||||
</div>
|
||||
<div className=" ">
|
||||
<Image
|
||||
|
|
Loading…
Reference in New Issue