feat(seo): add smart script extraction and preview for GTM, GA4, Clarity, and GSC
Some checks failed
Deploy Canina / deploy (push) Successful in 32s
E2E Playwright Tests / Run Full E2E & Security Suites (push) Failing after 6s

This commit is contained in:
parsa aghaei 2026-09-02 13:28:06 +03:30
parent 3344fe7f8d
commit 83c19903ab

View File

@ -359,10 +359,10 @@ export default function SeoSettingsPage() {
value={seo.googleSiteVerification || ''}
onChange={(e) => {
let val = e.target.value.trim();
// Auto-extract content if user pasted full <meta name="google-site-verification" content="..." />
const match = val.match(/content=["']([^"']+)["']/);
const match = val.match(/content=["']([^"']+)["']/i);
if (match && match[1]) {
val = match[1];
toast.success('کد تأییدیه گوگل از متاتگ با موفقیت استخراج شد');
}
setSeo({ ...seo, googleSiteVerification: val });
}}
@ -377,7 +377,7 @@ export default function SeoSettingsPage() {
{seo.googleSiteVerification && (
<div className="p-3 bg-gray-50 rounded-xl border border-gray-200 text-[11px] font-mono text-gray-600 space-y-1" dir="ltr">
<span className="text-[10px] text-gray-400 font-sans block text-right font-bold">متاتگ تزریق شده در سایت:</span>
<span className="text-[10px] text-gray-400 font-sans block text-right font-bold">متاتگ تزریق شده در &lt;head&gt; سایت:</span>
<code className="text-blue-700 select-all block break-all">
&lt;meta name="google-site-verification" content="{seo.googleSiteVerification}" /&gt;
</code>
@ -412,7 +412,7 @@ export default function SeoSettingsPage() {
<div className="space-y-2">
<label className="text-xs font-bold text-gray-700 flex items-center justify-between">
<span>شناسه اندازهگیری گوگل آنالیتیکس (Measurement ID)</span>
<span>شناسه اندازهگیری گوگل آنالیتیکس (Measurement ID) یا کل کد اسکریپت</span>
<a
href="https://analytics.google.com"
target="_blank"
@ -426,13 +426,24 @@ export default function SeoSettingsPage() {
<input
type="text"
value={seo.googleAnalyticsId || ''}
onChange={(e) => setSeo({ ...seo, googleAnalyticsId: e.target.value.trim() })}
placeholder="G-XXXXXXXXXX"
onChange={(e) => {
let val = e.target.value.trim();
// Auto-extract G-XXXXX if user pasted full <script> tag or gtag code
const match = val.match(/G-[A-Z0-9]+/i);
if (match) {
val = match[0].toUpperCase();
if (val !== e.target.value.trim()) {
toast.success(`شناسه ${val} به صورت خودکار از اسکریپت استخراج شد`);
}
}
setSeo({ ...seo, googleAnalyticsId: val });
}}
placeholder="مثال: G-FH4LH3WVMX یا کل کد <!-- Google tag (gtag.js) -->..."
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-amber-500 outline-none text-xs font-mono font-bold"
dir="ltr"
/>
<p className="text-[11px] text-gray-400 leading-relaxed">
این شناسه با پیشوند <strong className="text-gray-700">G-</strong> از مسیر Admin &gt; Data Streams در گوگل آنالیتیکس قابل دریافت است.
میتوانید شناسه با پیشوند <strong className="text-gray-700">G-</strong> یا کل کد اسکریپت Google tag را مستقیماً پیست کنید (خودکار استخراج میشود).
</p>
</div>
@ -440,7 +451,7 @@ export default function SeoSettingsPage() {
{seo.googleAnalyticsId && seo.enableGoogleAnalytics !== false ? (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-lg text-xs font-bold bg-amber-50 text-amber-800 border border-amber-200">
<Activity className="w-3.5 h-3.5 text-amber-600 animate-pulse" />
اسکریپت gtag.js فعال و در حال رهگیری است
اسکریپت gtag.js فعال و در &lt;head&gt; لود میشود
</span>
) : (
<span className="text-[11px] text-gray-400 font-medium">
@ -448,6 +459,15 @@ export default function SeoSettingsPage() {
</span>
)}
</div>
{seo.googleAnalyticsId && (
<div className="p-3 bg-gray-50 rounded-xl border border-gray-200 text-[10px] font-mono text-gray-600 space-y-1" dir="ltr">
<span className="text-[10px] text-gray-400 font-sans block text-right font-bold">کد لود شده در سایت:</span>
<code className="text-amber-700 select-all block break-all leading-relaxed">
&lt;script async src="https://www.googletagmanager.com/gtag/js?id={seo.googleAnalyticsId}"&gt;&lt;/script&gt;
</code>
</div>
)}
</div>
{/* Google Tag Manager (GTM) Card */}
@ -477,7 +497,7 @@ export default function SeoSettingsPage() {
<div className="space-y-2">
<label className="text-xs font-bold text-gray-700 flex items-center justify-between">
<span>شناسه کانتینر تگ منیجر (Container ID)</span>
<span>شناسه کانتینر تگ منیجر (Container ID) یا کل اسکریپت</span>
<a
href="https://tagmanager.google.com"
target="_blank"
@ -491,13 +511,24 @@ export default function SeoSettingsPage() {
<input
type="text"
value={seo.googleTagManagerId || ''}
onChange={(e) => setSeo({ ...seo, googleTagManagerId: e.target.value.trim() })}
placeholder="GTM-XXXXXXX"
onChange={(e) => {
let val = e.target.value.trim();
// Auto-extract GTM-XXXXX if user pasted full <script> or <noscript> snippet
const match = val.match(/GTM-[A-Z0-9]+/i);
if (match) {
val = match[0].toUpperCase();
if (val !== e.target.value.trim()) {
toast.success(`شناسه ${val} به صورت خودکار از اسکریپت استخراج شد`);
}
}
setSeo({ ...seo, googleTagManagerId: val });
}}
placeholder="مثال: GTM-XXXXXXX یا کل کد <script>...(dataLayer)...</script>"
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-blue-500 outline-none text-xs font-mono font-bold"
dir="ltr"
/>
<p className="text-[11px] text-gray-400 leading-relaxed">
شناسه با پیشوند <strong className="text-gray-700">GTM-</strong> در بالای داشبورد کانتینر تگ منیجر درج شده است.
میتوانید شناسه با پیشوند <strong className="text-gray-700">GTM-</strong> یا کل کد اسکریپت Head/Body را پیست کنید (خودکار استخراج میشود).
</p>
</div>
@ -505,7 +536,7 @@ export default function SeoSettingsPage() {
{seo.googleTagManagerId && seo.enableGoogleTagManager !== false ? (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-lg text-xs font-bold bg-blue-50 text-blue-800 border border-blue-200">
<Code2 className="w-3.5 h-3.5 text-blue-600" />
کانتینر GTM در Head و Noscript لود میشود
اسکریپت GTM در &lt;head&gt; و تگ noscript در &lt;body&gt; فعال است
</span>
) : (
<span className="text-[11px] text-gray-400 font-medium">
@ -513,6 +544,18 @@ export default function SeoSettingsPage() {
</span>
)}
</div>
{seo.googleTagManagerId && (
<div className="p-3 bg-gray-50 rounded-xl border border-gray-200 text-[10px] font-mono text-gray-600 space-y-1.5" dir="ltr">
<span className="text-[10px] text-gray-400 font-sans block text-right font-bold">تزریق خودکار در &lt;head&gt; و ابتدای &lt;body&gt;:</span>
<code className="text-blue-700 select-all block break-all leading-relaxed">
Head: https://www.googletagmanager.com/gtm.js?id={seo.googleTagManagerId}
</code>
<code className="text-gray-500 select-all block break-all leading-relaxed">
Body: &lt;noscript&gt;&lt;iframe src="...id={seo.googleTagManagerId}"&gt;&lt;/noscript&gt;
</code>
</div>
)}
</div>
{/* Microsoft Clarity Card */}
@ -543,7 +586,7 @@ export default function SeoSettingsPage() {
<div className="space-y-2">
<label className="text-xs font-bold text-gray-700 flex items-center justify-between">
<span>شناسه پروژه کلاریتی (Project ID)</span>
<span>شناسه پروژه کلاریتی (Project ID) یا کل اسکریپت</span>
<a
href="https://clarity.microsoft.com"
target="_blank"
@ -557,17 +600,38 @@ export default function SeoSettingsPage() {
<input
type="text"
value={seo.clarityProjectId || ''}
onChange={(e) => setSeo({ ...seo, clarityProjectId: e.target.value.trim() })}
placeholder="مثال: abcde12345"
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-orange-500 outline-none text-xs font-mono"
onChange={(e) => {
let val = e.target.value.trim();
// Auto-extract Clarity ID if user pasted full script snippet or URL
const scriptMatch = val.match(/["']clarity["']\s*,\s*["']script["']\s*,\s*["']([a-zA-Z0-9]+)["']/i);
const urlMatch = val.match(/clarity\.ms\/tag\/([a-zA-Z0-9]+)/i);
if (scriptMatch && scriptMatch[1]) {
val = scriptMatch[1];
toast.success(`شناسه کلاریتی ${val} با موفقیت استخراج شد`);
} else if (urlMatch && urlMatch[1]) {
val = urlMatch[1];
toast.success(`شناسه کلاریتی ${val} با موفقیت استخراج شد`);
}
setSeo({ ...seo, clarityProjectId: val });
}}
placeholder="مثال: ybybyi7z4p یا کل کد <script>...(clarity)...</script>"
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-orange-500 outline-none text-xs font-mono font-bold"
dir="ltr"
/>
<p className="text-[11px] text-gray-400 leading-relaxed">
ابزار کاملاً رایگان مایکروسافت برای مشاهده رفتار خرید کاربران در صفحه محصول و چکاوت.
میتوانید شناسه پروژه یا کل کد اسکریپت Clarity را پیست کنید (خودکار استخراج میشود).
</p>
</div>
</div>
{seo.clarityProjectId && (
<div className="p-3 bg-gray-50 rounded-xl border border-gray-200 text-[10px] font-mono text-gray-600 space-y-1" dir="ltr">
<span className="text-[10px] text-gray-400 font-sans block text-right font-bold">اسکریپت فعال در سایت:</span>
<code className="text-orange-700 select-all block break-all leading-relaxed">
https://www.clarity.ms/tag/{seo.clarityProjectId}
</code>
</div>
)}
</div>
</div>
</div>