fix seo and first page and 404 page
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
export const metadata = {
|
||||
title: "درباره ما",
|
||||
description:
|
||||
"فیپ یک گروه متخصص در حوزه اینتگریشن و روشهای نوین یکپارچهسازی. ماموریت، چشمانداز و ارزشهای ما.",
|
||||
};
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
/**
|
||||
* پاک کردن کش مقالات وردپرس.
|
||||
* وقتی در وردپرس مقالهای منتشر یا ویرایش شد، این آدرس را با secret فراخوانی کنید
|
||||
* تا کش دانشنامه و مقالهها بدون ریستارت سرور بهروز شود.
|
||||
*
|
||||
* استفاده در وردپرس:
|
||||
* - با پلاگین Webhook یا کد تم: بعد از save_post درخواست به این آدرس بفرست.
|
||||
* - مثال: GET یا POST /api/revalidate?secret=YOUR_REVALIDATE_SECRET
|
||||
* - یا هدر: x-revalidate-secret: YOUR_REVALIDATE_SECRET
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
return handleRevalidate(request);
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
return handleRevalidate(request);
|
||||
}
|
||||
|
||||
async function handleRevalidate(request: NextRequest) {
|
||||
const secret = process.env.REVALIDATE_SECRET;
|
||||
if (!secret) {
|
||||
return NextResponse.json(
|
||||
{ error: "REVALIDATE_SECRET تنظیم نشده است." },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const provided =
|
||||
request.nextUrl.searchParams.get("secret") ??
|
||||
request.headers.get("x-revalidate-secret");
|
||||
if (provided !== secret) {
|
||||
return NextResponse.json({ error: "غیرمجاز" }, { status: 401 });
|
||||
}
|
||||
|
||||
try {
|
||||
revalidateTag("blog-posts");
|
||||
return NextResponse.json({ revalidated: true, now: Date.now() });
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
{ error: "خطا در پاک کردن کش" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,33 @@ interface BlogPostPageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
function stripHtml(html: string): string {
|
||||
return html.replace(/<[^>]*>/g, "").trim();
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: BlogPostPageProps): Promise<Metadata> {
|
||||
const { slug } = await params;
|
||||
const post = await getPostBySlug(slug);
|
||||
if (!post) return { title: "پست یافت نشد" };
|
||||
const title = post.title?.rendered ?? "پست";
|
||||
const excerpt = post.excerpt?.rendered?.replace(/<[^>]*>/g, "").trim().slice(0, 160) ?? "";
|
||||
const titleRaw = post.title?.rendered ?? "پست";
|
||||
const title = stripHtml(titleRaw);
|
||||
const excerpt = stripHtml(post.excerpt?.rendered ?? "").slice(0, 160);
|
||||
const imageUrl = getFeaturedImageUrl(post, "medium_large");
|
||||
return {
|
||||
title,
|
||||
title: titleRaw,
|
||||
description: excerpt,
|
||||
openGraph: {
|
||||
title,
|
||||
description: excerpt,
|
||||
...(imageUrl && { images: [{ url: imageUrl, alt: title }] }),
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title,
|
||||
description: excerpt,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ const PER_PAGE = 9;
|
||||
export const metadata: Metadata = {
|
||||
title: "دانشنامه",
|
||||
description: "مقالات و مطالب فیپ در زمینه یکپارچهسازی، اتوماسیون و بهرهوری سازمانی.",
|
||||
openGraph: {
|
||||
title: "دانشنامه",
|
||||
description: "مقالات و مطالب فیپ در زمینه یکپارچهسازی، اتوماسیون و بهرهوری سازمانی.",
|
||||
},
|
||||
};
|
||||
|
||||
interface BlogPageProps {
|
||||
|
||||
@@ -115,7 +115,7 @@ const faqItems = [
|
||||
]
|
||||
|
||||
export const metadata = {
|
||||
title: 'مشاوره سازمانی | فیپ',
|
||||
title: 'مشاوره سازمانی',
|
||||
description:
|
||||
'مشاوره تخصصی در حوزه اینتگریشن، هوشمندسازی، RAG، Performance و معماری نرمافزار. در سریعترین زمان با شما تماس میگیریم.',
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import './globals.css'
|
||||
import Link from 'next/link'
|
||||
|
||||
export const metadata = {
|
||||
title: '۴۰۴ | صفحه یافت نشد',
|
||||
@@ -8,15 +9,32 @@ export const metadata = {
|
||||
export default function GlobalNotFound() {
|
||||
return (
|
||||
<html lang="fa" dir="rtl" suppressHydrationWarning>
|
||||
<body className="antialiased min-h-svh flex flex-col items-center justify-center gap-6 px-4 bg-background text-foreground">
|
||||
<h1 className="text-4xl font-bold">۴۰۴</h1>
|
||||
<p className="text-muted-foreground">این صفحه وجود ندارد.</p>
|
||||
<a
|
||||
href="/"
|
||||
className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90"
|
||||
>
|
||||
بازگشت به صفحه اصلی
|
||||
</a>
|
||||
<body className="antialiased min-h-svh flex flex-col items-center justify-center px-4 py-20 bg-background text-foreground">
|
||||
<div className="mx-auto max-w-lg w-full text-center">
|
||||
<div className="relative inline-block mb-6">
|
||||
<span
|
||||
className="text-[8rem] md:text-[10rem] font-black leading-none tracking-tighter text-transparent bg-clip-text bg-gradient-to-b from-primary/90 to-primary/50 select-none"
|
||||
aria-hidden
|
||||
>
|
||||
۴۰۴
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-2xl font-bold text-foreground mb-3">
|
||||
صفحه پیدا نشد
|
||||
</h1>
|
||||
<p className="text-muted-foreground mb-10 max-w-sm mx-auto leading-relaxed">
|
||||
به نظر میرسد این آدرس وجود ندارد یا منتقل شده است.
|
||||
</p>
|
||||
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center justify-center gap-2 h-11 px-6 rounded-md bg-primary text-primary-foreground font-medium hover:opacity-90 transition-opacity"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
|
||||
صفحه اصلی
|
||||
</Link>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
||||
+9
-3
@@ -5,10 +5,16 @@ import { ThemeProvider } from "@/components/theme-provider";
|
||||
import { TopProgressBar } from "@/components/top-progress-bar";
|
||||
|
||||
|
||||
const SITE_NAME = "فیپ";
|
||||
const DEFAULT_DESCRIPTION =
|
||||
"فیپ یک سامانه برای ایجاد و طراحی راهکارهای مناسب برای کسب و کار شما است.";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "فیپ",
|
||||
description:
|
||||
"فیپ یک سامانه برای ایجاد و طراحی راهکارهای مناسب برای کسب و کار شما است.",
|
||||
title: {
|
||||
default: `${SITE_NAME} | راهکارهای یکپارچه و هوشمند برای کسبوکار`,
|
||||
template: `%s | ${SITE_NAME}`,
|
||||
},
|
||||
description: DEFAULT_DESCRIPTION,
|
||||
icons: {
|
||||
icon: "/assets/feep-Logo.svg",
|
||||
},
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import type { Metadata } from "next";
|
||||
import { LoginForm } from "@/components/login-form";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "ورود",
|
||||
description: "ورود به حساب فیپ",
|
||||
};
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<div className="container mx-auto flex min-h-screen items-center justify-center px-4 py-16">
|
||||
|
||||
+30
-12
@@ -1,21 +1,39 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Home } from 'lucide-react'
|
||||
|
||||
export const metadata = {
|
||||
title: '۴۰۴',
|
||||
description: 'صفحهای که دنبال آن هستید یافت نشد.',
|
||||
}
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="flex min-h-[60vh] flex-col items-center justify-center gap-6 px-4 text-center">
|
||||
<h1 className="text-4xl font-bold text-foreground">۴۰۴</h1>
|
||||
<p className="text-muted-foreground max-w-md">
|
||||
صفحهای که دنبال آن هستید یافت نشد.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3 justify-center">
|
||||
<Button asChild>
|
||||
<Link href="/">صفحه اصلی</Link>
|
||||
</Button>
|
||||
<Button asChild variant="outline">
|
||||
<Link href="/consulting">مشاوره سازمانی</Link>
|
||||
<section className="min-h-[70vh] flex items-center justify-center px-4 py-20">
|
||||
<div className="mx-auto max-w-lg w-full text-center">
|
||||
<div className="relative inline-block mb-6">
|
||||
<span
|
||||
className="text-[8rem] md:text-[10rem] font-black leading-none tracking-tighter text-transparent bg-clip-text bg-gradient-to-b from-primary/90 to-primary/50 select-none"
|
||||
aria-hidden
|
||||
>
|
||||
۴۰۴
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-2xl font-bold text-foreground mb-3">
|
||||
صفحه پیدا نشد
|
||||
</h1>
|
||||
<p className="text-muted-foreground mb-10 max-w-sm mx-auto leading-relaxed">
|
||||
به نظر میرسد این آدرس وجود ندارد یا منتقل شده است.
|
||||
</p>
|
||||
|
||||
<Button asChild size="lg" className="gap-2">
|
||||
<Link href="/">
|
||||
<Home className="size-5" />
|
||||
صفحه اصلی
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import type { Metadata } from "next";
|
||||
import ContentSection from "@/components/content-1";
|
||||
import Features from "@/components/features-12";
|
||||
import { FeaturedPostsGrid } from "@/components/featured-posts-grid";
|
||||
import { getPosts } from "@/lib/wp-api";
|
||||
import HeroSection from "@/components/hero-section";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
description:
|
||||
"فیپ؛ راهکارهای یکپارچه و هوشمند برای اتصال سیستمها، اتوماسیون فرآیندها و بهرهوری کسبوکار.",
|
||||
};
|
||||
|
||||
const FEATURED_CATEGORY_ID = 3;
|
||||
const FEATURED_POSTS_COUNT = 4;
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import type { Metadata } from "next";
|
||||
import Pricing from "@/components/pricing";
|
||||
import PricingComparator from "@/components/pricing-comparator";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "قیمتگذاری",
|
||||
description: "تعرفه و پلنهای خدمات فیپ. انتخاب مناسب برای کسبوکار شما.",
|
||||
};
|
||||
|
||||
export default function PricingPage() {
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Link as LinkIcon, BarChart3, Share2, Zap, TrendingUp, Workflow } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "راه حلها",
|
||||
description:
|
||||
"راهکارهای فیپ: یکپارچهسازی سیستمها، پنلهای مدیریتی، اتوماسیون فرآیندها و تحلیل داده.",
|
||||
};
|
||||
|
||||
const solutions = [
|
||||
{
|
||||
icon: LinkIcon,
|
||||
|
||||
+8
-1
@@ -1,6 +1,10 @@
|
||||
const WP_API_BASE = "https://wpa.feep.ir/wp-json/wp/v2";
|
||||
const FETCH_TIMEOUT_MS = 15_000;
|
||||
|
||||
/** کش مقالات وردپرس: یک ساعت. با revalidateTag('blog-posts') از API میتوان کش را پاک کرد. */
|
||||
const CACHE_REVALIDATE_SECONDS = 3600;
|
||||
const CACHE_TAG_BLOG = "blog-posts";
|
||||
|
||||
export interface WpMediaSize {
|
||||
source_url: string;
|
||||
width?: number;
|
||||
@@ -86,7 +90,10 @@ async function fetchWithTimeout(
|
||||
const res = await fetch(url, {
|
||||
...options,
|
||||
signal: controller.signal,
|
||||
next: { revalidate: 0 },
|
||||
next: {
|
||||
revalidate: CACHE_REVALIDATE_SECONDS,
|
||||
tags: [CACHE_TAG_BLOG],
|
||||
},
|
||||
});
|
||||
clearTimeout(timeout);
|
||||
return res;
|
||||
|
||||
Reference in New Issue
Block a user