seo audit updated
This commit is contained in:
parent
de22adefb8
commit
0a949e1f34
@ -8,7 +8,8 @@
|
|||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
"sitemap": "node scripts/generate-sitemap.cjs",
|
"sitemap": "node scripts/generate-sitemap.cjs",
|
||||||
"optimize-images": "node scripts/optimize-images.mjs"
|
"optimize-images": "node scripts/optimize-images.mjs",
|
||||||
|
"seo-audit": "node scripts/seo-test-selenium.cjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
|
|||||||
@ -32,9 +32,9 @@ interface Review {
|
|||||||
author_name?: string;
|
author_name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AboutContent() {
|
export default function AboutContent({ initialReviews }: { initialReviews?: Review[] }) {
|
||||||
const [reviews, setReviews] = useState<Review[]>([]);
|
const [reviews, setReviews] = useState<Review[]>(initialReviews || []);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(!initialReviews);
|
||||||
const [expandedReview, setExpandedReview] = useState<number | null>(null);
|
const [expandedReview, setExpandedReview] = useState<number | null>(null);
|
||||||
const [swiperInstance, setSwiperInstance] = useState<any>(null);
|
const [swiperInstance, setSwiperInstance] = useState<any>(null);
|
||||||
|
|
||||||
@ -115,6 +115,8 @@ export default function AboutContent() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (initialReviews) return;
|
||||||
|
|
||||||
async function loadReviews() {
|
async function loadReviews() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/api/reviews");
|
const res = await fetch("/api/reviews");
|
||||||
@ -132,7 +134,7 @@ export default function AboutContent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadReviews();
|
loadReviews();
|
||||||
}, []);
|
}, [initialReviews]);
|
||||||
|
|
||||||
const displayedReviews = reviews.length > 0 && reviews.length < 3
|
const displayedReviews = reviews.length > 0 && reviews.length < 3
|
||||||
? [...reviews, ...reviews, ...reviews]
|
? [...reviews, ...reviews, ...reviews]
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import AboutContent from "./AboutContent";
|
import AboutContent from "./AboutContent";
|
||||||
import ClientOnly from "@/components/ClientOnly";
|
import { getReviews } from "@/utils/getReviews";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "About Antalya Restaurant | Authentic Turkish Dining",
|
title: "About Antalya Restaurant | Authentic Turkish Dining",
|
||||||
description: "Learn about Antalya Restaurant in Ontario - where authentic Turkish flavours, warm hospitality come together for a memorable dining experience.",
|
description: "Learn about Antalya Restaurant in Ontario - where authentic Turkish flavours, warm hospitality come together for a memorable dining experience.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AboutPage() {
|
export default async function AboutPage() {
|
||||||
return (
|
const reviews = await getReviews();
|
||||||
<ClientOnly>
|
return <AboutContent initialReviews={reviews} />;
|
||||||
<AboutContent />
|
|
||||||
</ClientOnly>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,8 +20,8 @@ export async function generateMetadata({ params }: { params: Promise<{ id: strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: `${blog.title} | Antalya Restaurant`,
|
title: blog.metatitle || `${blog.title} | Antalya Restaurant`,
|
||||||
description: blog.excerpt,
|
description: blog.metadesc || blog.excerpt,
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: blog.title,
|
title: blog.title,
|
||||||
description: blog.excerpt,
|
description: blog.excerpt,
|
||||||
|
|||||||
@ -27,8 +27,8 @@ const dmSans = DM_Sans({
|
|||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
metadataBase: new URL("https://antalya.metatronnest.com"),
|
metadataBase: new URL("https://antalya.metatronnest.com"),
|
||||||
title: {
|
title: {
|
||||||
default: "Antalya Restaurant Kitchener - Authentic Turkish cuisine",
|
default: "Antalya Restaurant Kitchener | Authentic Turkish Cuisine",
|
||||||
template: "%s | Antalya Restaurant Kitchener"
|
template: "%s"
|
||||||
},
|
},
|
||||||
description: "Experience the finest authentic Turkish cuisine at Antalya Restaurant Kitchener. Enjoy our delicious kebabs, mezes, and desserts in a warm, inviting atmosphere.",
|
description: "Experience the finest authentic Turkish cuisine at Antalya Restaurant Kitchener. Enjoy our delicious kebabs, mezes, and desserts in a warm, inviting atmosphere.",
|
||||||
keywords: ["Turkish restaurant", "Antalya restaurant", "Turkish cuisine", "kebabs", "meze", "dining", "authentic food", "halal food", "middle eastern food"],
|
keywords: ["Turkish restaurant", "Antalya restaurant", "Turkish cuisine", "kebabs", "meze", "dining", "authentic food", "halal food", "middle eastern food"],
|
||||||
|
|||||||
@ -11,13 +11,16 @@ import BookTable from "@/components/BookTable/BookTable";
|
|||||||
import Footer from "@/components/Footer/Footer";
|
import Footer from "@/components/Footer/Footer";
|
||||||
|
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
import { getReviews } from "@/utils/getReviews";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Best Turkish Restaurant in Ontario | Antalya",
|
title: "Best Turkish Restaurant in Ontario | Antalya",
|
||||||
description: "Enjoy authentic Turkish dining at Antalya with charcoal-grilled kebabs, handcrafted dishes, & warm hospitality for a memorable taste of Turkey.",
|
description: "Enjoy authentic Turkish dining at Antalya with charcoal-grilled kebabs, handcrafted dishes, & warm hospitality for a memorable taste of Turkey.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Home() {
|
export default async function Home() {
|
||||||
|
const reviews = await getReviews();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Hero />
|
<Hero />
|
||||||
@ -26,7 +29,7 @@ export default function Home() {
|
|||||||
<Catering />
|
<Catering />
|
||||||
<Menu />
|
<Menu />
|
||||||
<Gallery />
|
<Gallery />
|
||||||
<Testimonials />
|
<Testimonials initialReviews={reviews} />
|
||||||
<Blogs />
|
<Blogs />
|
||||||
<BookTable />
|
<BookTable />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@ -185,9 +185,9 @@ export default function Catering() {
|
|||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
>
|
>
|
||||||
<motion.div variants={itemVariants} className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'start', gap: '10px' }}>
|
<motion.div variants={itemVariants} className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'start', gap: '10px' }}>
|
||||||
<Image src="/images/dinner.png" alt="Home Gallery Decorative Dinner Icon" width={24} height={24} />
|
<Image src="/images/dinner.png" alt="Home Gallery Decorative Dinner" width={24} height={24} />
|
||||||
<span>CATERING & EVENTS</span>
|
<span>CATERING & EVENTS</span>
|
||||||
<Image src="/images/eat.png" alt="Home Gallery Decorative Cutlery Icon" width={24} height={24} />
|
<Image src="/images/eat.png" alt="Home Gallery Decorative Cutlery" width={24} height={24} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
<motion.h2 variants={itemVariants} className={styles.title}>
|
<motion.h2 variants={itemVariants} className={styles.title}>
|
||||||
|
|||||||
@ -1,10 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
import Navbar from "@/components/Navbar/Navbar";
|
||||||
import dynamic from "next/dynamic";
|
|
||||||
|
|
||||||
const Navbar = dynamic(() => import("@/components/Navbar/Navbar"), {
|
|
||||||
ssr: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function NavbarClient() {
|
export default function NavbarClient() {
|
||||||
return <Navbar />;
|
return <Navbar />;
|
||||||
|
|||||||
@ -29,9 +29,9 @@ interface Review {
|
|||||||
author_name?: string;
|
author_name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Testimonials() {
|
export default function Testimonials({ initialReviews }: { initialReviews?: Review[] }) {
|
||||||
const [reviews, setReviews] = useState<Review[]>([]);
|
const [reviews, setReviews] = useState<Review[]>(initialReviews || []);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(!initialReviews);
|
||||||
const [expandedReview, setExpandedReview] = useState<number | null>(null);
|
const [expandedReview, setExpandedReview] = useState<number | null>(null);
|
||||||
const [swiperInstance, setSwiperInstance] = useState<any>(null);
|
const [swiperInstance, setSwiperInstance] = useState<any>(null);
|
||||||
|
|
||||||
@ -86,6 +86,8 @@ export default function Testimonials() {
|
|||||||
}, [expandedReview, swiperInstance]);
|
}, [expandedReview, swiperInstance]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (initialReviews) return;
|
||||||
|
|
||||||
async function loadReviews() {
|
async function loadReviews() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/api/reviews");
|
const res = await fetch("/api/reviews");
|
||||||
@ -120,7 +122,7 @@ export default function Testimonials() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadReviews();
|
loadReviews();
|
||||||
}, []);
|
}, [initialReviews]);
|
||||||
|
|
||||||
const displayedReviews = reviews.length > 0 && reviews.length < 3
|
const displayedReviews = reviews.length > 0 && reviews.length < 3
|
||||||
? [...reviews, ...reviews, ...reviews]
|
? [...reviews, ...reviews, ...reviews]
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export const blogData = [
|
|||||||
slug: 'the-art-of-turkish-tea',
|
slug: 'the-art-of-turkish-tea',
|
||||||
title: 'The Art of Turkish Tea',
|
title: 'The Art of Turkish Tea',
|
||||||
metatitle: 'The Art of Turkish Tea – Tradition, Taste & Ritual',
|
metatitle: 'The Art of Turkish Tea – Tradition, Taste & Ritual',
|
||||||
metadesc: 'Discover the art of Turkish tea – its history, brewing traditions, cultural significance, and how this cherished daily ritual reflects Turkish hospitality and heritage.',
|
metadesc: 'Discover the art of Turkish tea—its history, brewing traditions, and cultural significance, reflecting daily rituals, warm hospitality, and rich heritage.',
|
||||||
category: 'Culture',
|
category: 'Culture',
|
||||||
date: 'October 15, 2025',
|
date: 'October 15, 2025',
|
||||||
comments: '12 Comments',
|
comments: '12 Comments',
|
||||||
|
|||||||
66
src/utils/getReviews.ts
Normal file
66
src/utils/getReviews.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { blogData } from "./constant";
|
||||||
|
|
||||||
|
export interface Review {
|
||||||
|
text?: string;
|
||||||
|
description?: string;
|
||||||
|
snippet?: string;
|
||||||
|
review_text?: string;
|
||||||
|
body?: string;
|
||||||
|
content?: string;
|
||||||
|
rating: number;
|
||||||
|
profile_photo_url?: string;
|
||||||
|
author_profile_photo_url?: string;
|
||||||
|
user?: {
|
||||||
|
thumbnail?: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
author_name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getReviews(): Promise<Review[]> {
|
||||||
|
const apiKey = "37eb7f83988cfd76ffb5c5af9adc25652efe5607e39997fc7d0e054d690ef25e";
|
||||||
|
const placeId = "ChIJJU4PkTL1K4gRPSWJdlAQ7ko";
|
||||||
|
|
||||||
|
let allReviews: Review[] = [];
|
||||||
|
let nextPageToken: string | null = null;
|
||||||
|
let pageCount = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (pageCount < 3) {
|
||||||
|
pageCount++;
|
||||||
|
const url: string = `https://serpapi.com/search.json?engine=google_maps_reviews&hl=en&api_key=${apiKey}&place_id=${placeId}${nextPageToken ? `&next_page_token=${nextPageToken}` : ""}`;
|
||||||
|
|
||||||
|
const response = await fetch(url, { next: { revalidate: 3600 } });
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.reviews && data.reviews.length > 0) {
|
||||||
|
allReviews = [...allReviews, ...data.reviews];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.serpapi_pagination || !data.serpapi_pagination.next_page_token) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPageToken = data.serpapi_pagination.next_page_token;
|
||||||
|
// No need for delay on server fetch unless we are worried about rate limiting,
|
||||||
|
// but Next.js will cache this.
|
||||||
|
}
|
||||||
|
|
||||||
|
const cleaned = allReviews.filter((r: Review) =>
|
||||||
|
(r.text || r.description || r.snippet || r.review_text || r.body || r.content) &&
|
||||||
|
r.rating >= 4
|
||||||
|
);
|
||||||
|
|
||||||
|
return cleaned;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch reviews on server:", error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user